Преглед изворни кода

Merge remote-tracking branch 'origin/master' into serenity-keys

faissaloo пре 6 година
родитељ
комит
b635c3db54
100 измењених фајлова са 2753 додато и 1057 уклоњено
  1. 0 1
      .clang-format
  2. 2 0
      .gitignore
  3. 1 1
      .travis.yml
  4. 47 8
      AK/AKString.h
  5. 13 0
      AK/Badge.h
  6. 67 0
      AK/Bitmap.h
  7. 1 9
      AK/BufferStream.h
  8. 16 16
      AK/ByteBuffer.h
  9. 12 6
      AK/ELF/ELFImage.cpp
  10. 17 12
      AK/ELF/ELFImage.h
  11. 12 14
      AK/ELF/ELFLoader.cpp
  12. 5 6
      AK/ELF/ELFLoader.h
  13. 441 445
      AK/ELF/exec_elf.h
  14. 1 1
      AK/FileSystemPath.cpp
  15. 3 3
      AK/FileSystemPath.h
  16. 12 0
      AK/IterationDecision.h
  17. 4 8
      AK/MappedFile.cpp
  18. 2 3
      AK/MappedFile.h
  19. 12 14
      AK/PrintfImplementation.h
  20. 49 0
      AK/Queue.h
  21. 2 0
      AK/QuickSort.h
  22. 25 4
      AK/RetainPtr.h
  23. 15 8
      AK/Retained.h
  24. 24 0
      AK/ScopeGuard.h
  25. 2 2
      AK/SinglyLinkedList.h
  26. 1 0
      AK/StdLibExtras.h
  27. 44 25
      AK/String.cpp
  28. 8 8
      AK/StringBuilder.cpp
  29. 6 6
      AK/StringBuilder.h
  30. 4 0
      AK/StringImpl.cpp
  31. 26 1
      AK/StringView.cpp
  32. 39 2
      AK/StringView.h
  33. 2 0
      AK/Tests/.gitignore
  34. 12 0
      AK/Tests/Makefile
  35. 68 0
      AK/Tests/TestHelpers.h
  36. 43 0
      AK/Tests/TestQueue.cpp
  37. 59 0
      AK/Tests/TestString.cpp
  38. 15 12
      AK/Time.h
  39. 2 5
      AK/Types.h
  40. 26 0
      AK/ValueRestorer.h
  41. 17 0
      AK/Vector.h
  42. 4 5
      Applications/About/main.cpp
  43. 2 2
      Applications/Downloader/main.cpp
  44. 13 13
      Applications/FileManager/DirectoryView.cpp
  45. 6 7
      Applications/FileManager/DirectoryView.h
  46. 34 34
      Applications/FileManager/main.cpp
  47. 11 11
      Applications/FontEditor/FontEditor.cpp
  48. 3 3
      Applications/FontEditor/GlyphMapWidget.cpp
  49. 16 16
      Applications/IRCClient/IRCAppWindow.cpp
  50. 2 2
      Applications/IRCClient/IRCChannel.cpp
  51. 7 4
      Applications/IRCClient/IRCChannelMemberListModel.cpp
  52. 1 2
      Applications/IRCClient/IRCChannelMemberListModel.h
  53. 31 23
      Applications/IRCClient/IRCClient.cpp
  54. 16 9
      Applications/IRCClient/IRCLogBufferModel.cpp
  55. 1 2
      Applications/IRCClient/IRCLogBufferModel.h
  56. 3 3
      Applications/IRCClient/IRCWindow.cpp
  57. 1 2
      Applications/IRCClient/IRCWindow.h
  58. 7 5
      Applications/IRCClient/IRCWindowListModel.cpp
  59. 1 2
      Applications/IRCClient/IRCWindowListModel.h
  60. 1 1
      Applications/IRCClient/main.cpp
  61. 15 14
      Applications/Launcher/main.cpp
  62. 3 0
      Applications/PaintBrush/.gitignore
  63. 55 0
      Applications/PaintBrush/BucketTool.cpp
  64. 14 0
      Applications/PaintBrush/BucketTool.h
  65. 28 0
      Applications/PaintBrush/Makefile
  66. 60 0
      Applications/PaintBrush/PaintableWidget.cpp
  67. 42 0
      Applications/PaintBrush/PaintableWidget.h
  68. 131 0
      Applications/PaintBrush/PaletteWidget.cpp
  69. 21 0
      Applications/PaintBrush/PaletteWidget.h
  70. 48 0
      Applications/PaintBrush/PenTool.cpp
  71. 19 0
      Applications/PaintBrush/PenTool.h
  72. 9 0
      Applications/PaintBrush/Tool.cpp
  73. 18 0
      Applications/PaintBrush/Tool.h
  74. 64 0
      Applications/PaintBrush/ToolboxWidget.cpp
  75. 13 0
      Applications/PaintBrush/ToolboxWidget.h
  76. 58 0
      Applications/PaintBrush/main.cpp
  77. 2 2
      Applications/ProcessManager/MemoryStatsWidget.cpp
  78. 85 45
      Applications/ProcessManager/ProcessModel.cpp
  79. 4 5
      Applications/ProcessManager/ProcessModel.h
  80. 24 24
      Applications/ProcessManager/main.cpp
  81. 5 5
      Applications/Taskbar/TaskbarButton.cpp
  82. 9 13
      Applications/Taskbar/TaskbarWindow.cpp
  83. 2 2
      Applications/Taskbar/WindowList.cpp
  84. 1 1
      Applications/Taskbar/main.cpp
  85. 1 0
      Applications/Terminal/.gitignore
  86. 314 109
      Applications/Terminal/Terminal.cpp
  87. 23 6
      Applications/Terminal/Terminal.h
  88. 80 39
      Applications/Terminal/main.cpp
  89. 18 18
      Applications/TextEditor/main.cpp
  90. 0 1
      Base/etc/LookupServer.ini
  91. 1 0
      Base/etc/hosts
  92. 1 0
      Base/home/anon/Terminal.ini
  93. 2 2
      Base/home/anon/WindowManager.ini
  94. BIN
      Base/res/icons/16x16/app-demo.png
  95. BIN
      Base/res/icons/paintbrush/bucket.png
  96. BIN
      Base/res/icons/paintbrush/pen.png
  97. 3 0
      Demos/Fire/.gitignore
  98. 236 0
      Demos/Fire/Fire.cpp
  99. 22 0
      Demos/Fire/Makefile
  100. 5 5
      Demos/HelloWorld/main.cpp

+ 0 - 1
.clang-format

@@ -10,4 +10,3 @@ IndentPPDirectives: AfterHash
 BreakBeforeBraces: Custom
 BraceWrapping:
     AfterFunction: true
-    AfterEnum: true

+ 2 - 0
.gitignore

@@ -12,3 +12,5 @@ Toolchain/Tarballs
 Toolchain/Build
 Toolchain/Local
 .vscode
+compile_commands.json
+.clang_complete

+ 1 - 1
.travis.yml

@@ -16,7 +16,7 @@ notifications:
 before_install:
 - sudo apt-get update
 - sudo apt-get install -y libmpfr-dev libmpc-dev libgmp-dev
-- sudo apt-get install -y e2fsprogs qemu-system-i386
+- sudo apt-get install -y e2fsprogs qemu-system-i386 qemu-utils
 
 script:
 - cd Toolchain

+ 47 - 8
AK/AKString.h

@@ -10,15 +10,38 @@
 
 namespace AK {
 
+// String is a convenience wrapper around StringImpl, suitable for passing
+// around as a value type. It's basically the same as passing around a
+// RetainPtr<StringImpl>, with a bit of syntactic sugar.
+//
+// Note that StringImpl is an immutable object that cannot shrink or grow.
+// Its allocation size is snugly tailored to the specific string it contains.
+// Copying a String is very efficient, since the internal StringImpl is
+// retainable and so copying only requires modifying the retain count.
+//
+// There are three main ways to construct a new String:
+//
+//     s = String("some literal");
+//
+//     s = String::format("%d little piggies", m_piggies);
+//
+//     StringBuilder builder;
+//     builder.append("abc");
+//     builder.append("123");
+//     s = builder.to_string();
+
 class String {
 public:
     ~String() {}
 
     String() {}
 
-    String(StringView view)
-        : m_impl(StringImpl::create(view.characters(), view.length()))
+    String(const StringView& view)
     {
+        if (view.m_impl)
+            m_impl = *view.m_impl;
+        else
+            m_impl = StringImpl::create(view.characters(), view.length());
     }
 
     String(const String& other)
@@ -36,7 +59,7 @@ public:
     {
     }
 
-    String(const char* cstring, ssize_t length, ShouldChomp shouldChomp = NoChomp)
+    String(const char* cstring, int length, ShouldChomp shouldChomp = NoChomp)
         : m_impl(StringImpl::create(cstring, length, shouldChomp))
     {
     }
@@ -67,7 +90,7 @@ public:
     };
 
     static String repeated(char, int count);
-    bool matches(const String& pattern, CaseSensitivity = CaseSensitivity::CaseInsensitive) const;
+    bool matches(const StringView& pattern, CaseSensitivity = CaseSensitivity::CaseInsensitive) const;
 
     int to_int(bool& ok) const;
     unsigned to_uint(bool& ok) const;
@@ -86,6 +109,7 @@ public:
         return m_impl->to_uppercase();
     }
 
+    Vector<String> split_limit(char separator, int limit) const;
     Vector<String> split(char separator) const;
     String substring(int start, int length) const;
 
@@ -94,20 +118,35 @@ public:
 
     bool is_null() const { return !m_impl; }
     bool is_empty() const { return length() == 0; }
-    ssize_t length() const { return m_impl ? m_impl->length() : 0; }
+    int length() const { return m_impl ? m_impl->length() : 0; }
     const char* characters() const { return m_impl ? m_impl->characters() : nullptr; }
-    char operator[](ssize_t i) const
+    char operator[](int i) const
     {
         ASSERT(m_impl);
         return (*m_impl)[i];
     }
 
-    bool ends_with(const String&) const;
+    bool starts_with(const StringView&) const;
+    bool ends_with(const StringView&) const;
 
     bool operator==(const String&) const;
     bool operator!=(const String& other) const { return !(*this == other); }
     bool operator<(const String&) const;
 
+    bool operator==(const char* cstring) const
+    {
+        if (is_null())
+            return !cstring;
+        if (!cstring)
+            return false;
+        return !strcmp(characters(), cstring);
+    }
+
+    bool operator!=(const char* cstring) const
+    {
+        return !(*this == cstring);
+    }
+
     String isolated_copy() const;
 
     static String empty();
@@ -146,7 +185,7 @@ public:
     StringView view() const { return { characters(), length() }; }
 
 private:
-    bool match_helper(const String& mask) const;
+    bool match_helper(const StringView& mask) const;
     RetainPtr<StringImpl> m_impl;
 };
 

+ 13 - 0
AK/Badge.h

@@ -1,7 +1,20 @@
 #pragma once
 
+namespace AK {
+
 template<typename T>
 class Badge {
     friend T;
     Badge() {}
+
+    Badge(const Badge&) = delete;
+    Badge& operator=(const Badge&) = delete;
+
+    Badge(Badge&&) = delete;
+    Badge& operator=(Badge&&) = delete;
 };
+
+}
+
+using AK::Badge;
+

+ 67 - 0
AK/Bitmap.h

@@ -20,6 +20,11 @@ public:
         return Bitmap(size, default_value);
     }
 
+    static Bitmap create()
+    {
+        return Bitmap();
+    }
+
     ~Bitmap()
     {
         if (m_owned)
@@ -45,12 +50,74 @@ public:
     byte* data() { return m_data; }
     const byte* data() const { return m_data; }
 
+    void grow(int size, bool default_value)
+    {
+        ASSERT(size > m_size);
+
+        auto previous_size_bytes = size_in_bytes();
+        auto previous_size = m_size;
+        auto previous_data = m_data;
+
+        m_size = size;
+        m_data = reinterpret_cast<byte*>(kmalloc(size_in_bytes()));
+
+        fill(default_value);
+
+        if (previous_data != nullptr) {
+            memcpy(m_data, previous_data, previous_size_bytes);
+
+            if ((previous_size % 8) != 0) {
+                if (default_value)
+                    m_data[previous_size_bytes - 1] |= (0xff >> (previous_size % 8));
+                else
+                    m_data[previous_size_bytes - 1] &= ~(0xff >> (previous_size % 8));
+            }
+
+            kfree(previous_data);
+        }
+    }
+
     void fill(bool value)
     {
         memset(m_data, value ? 0xff : 0x00, size_in_bytes());
     }
 
+    int find_first_set() const
+    {
+        int i = 0;
+        while (i < m_size / 8 && m_data[i] == 0x00)
+            i++;
+
+        int j = 0;
+        for (j = i * 8; j < m_size; j++)
+            if (get(j))
+                return j;
+
+        return -1;
+    }
+
+    int find_first_unset() const
+    {
+        int i = 0;
+        while (i < m_size / 8 && m_data[i] == 0xff)
+            i++;
+
+        int j = 0;
+        for (j = i * 8; j < m_size; j++)
+            if (!get(j))
+                return j;
+
+        return -1;
+    }
+
 private:
+    explicit Bitmap()
+        : m_size(0)
+        , m_owned(true)
+    {
+        m_data = nullptr;
+    }
+
     explicit Bitmap(int size, bool default_value)
         : m_size(size)
         , m_owned(true)

+ 1 - 9
AK/BufferStream.h

@@ -36,15 +36,7 @@ public:
         m_buffer[m_offset++] = (byte)(value >> 24) & 0xffu;
     }
 
-    void operator<<(const char* str)
-    {
-        ssize_t len = strlen(str);
-        ASSERT(len >= 0);
-        for (ssize_t i = 0; i < len; ++i)
-            m_buffer[m_offset++] = str[i];
-    }
-
-    void operator<<(const String& value)
+    void operator<<(const StringView& value)
     {
         for (ssize_t i = 0; i < value.length(); ++i)
             m_buffer[m_offset++] = value[i];

+ 16 - 16
AK/ByteBuffer.h

@@ -100,12 +100,12 @@ public:
         return *this;
     }
 
-    static ByteBuffer create_uninitialized(ssize_t size) { return ByteBuffer(ByteBufferImpl::create_uninitialized(size)); }
-    static ByteBuffer create_zeroed(ssize_t size) { return ByteBuffer(ByteBufferImpl::create_zeroed(size)); }
-    static ByteBuffer copy(const void* data, ssize_t size) { return ByteBuffer(ByteBufferImpl::copy(data, size)); }
-    static ByteBuffer wrap(const void* data, ssize_t size) { return ByteBuffer(ByteBufferImpl::wrap(data, size)); }
-    static ByteBuffer wrap(void* data, ssize_t size) { return ByteBuffer(ByteBufferImpl::wrap(data, size)); }
-    static ByteBuffer adopt(void* data, ssize_t size) { return ByteBuffer(ByteBufferImpl::adopt(data, size)); }
+    static ByteBuffer create_uninitialized(int size) { return ByteBuffer(ByteBufferImpl::create_uninitialized(size)); }
+    static ByteBuffer create_zeroed(int size) { return ByteBuffer(ByteBufferImpl::create_zeroed(size)); }
+    static ByteBuffer copy(const void* data, int size) { return ByteBuffer(ByteBufferImpl::copy(data, size)); }
+    static ByteBuffer wrap(const void* data, int size) { return ByteBuffer(ByteBufferImpl::wrap(data, size)); }
+    static ByteBuffer wrap(void* data, int size) { return ByteBuffer(ByteBufferImpl::wrap(data, size)); }
+    static ByteBuffer adopt(void* data, int size) { return ByteBuffer(ByteBufferImpl::adopt(data, size)); }
 
     ~ByteBuffer() { clear(); }
     void clear() { m_impl = nullptr; }
@@ -114,18 +114,18 @@ public:
     bool operator!() const { return is_null(); }
     bool is_null() const { return m_impl == nullptr; }
 
-    byte& operator[](ssize_t i)
+    byte& operator[](int i)
     {
         ASSERT(m_impl);
         return (*m_impl)[i];
     }
-    byte operator[](ssize_t i) const
+    byte operator[](int i) const
     {
         ASSERT(m_impl);
         return (*m_impl)[i];
     }
     bool is_empty() const { return !m_impl || m_impl->is_empty(); }
-    ssize_t size() const { return m_impl ? m_impl->size() : 0; }
+    int size() const { return m_impl ? m_impl->size() : 0; }
 
     byte* data() { return pointer(); }
     const byte* data() const { return pointer(); }
@@ -133,8 +133,8 @@ public:
     byte* pointer() { return m_impl ? m_impl->pointer() : nullptr; }
     const byte* pointer() const { return m_impl ? m_impl->pointer() : nullptr; }
 
-    byte* offset_pointer(ssize_t offset) { return m_impl ? m_impl->offset_pointer(offset) : nullptr; }
-    const byte* offset_pointer(ssize_t offset) const { return m_impl ? m_impl->offset_pointer(offset) : nullptr; }
+    byte* offset_pointer(int offset) { return m_impl ? m_impl->offset_pointer(offset) : nullptr; }
+    const byte* offset_pointer(int offset) const { return m_impl ? m_impl->offset_pointer(offset) : nullptr; }
 
     void* end_pointer() { return m_impl ? m_impl->end_pointer() : nullptr; }
     const void* end_pointer() const { return m_impl ? m_impl->end_pointer() : nullptr; }
@@ -147,13 +147,13 @@ public:
     }
 
     // NOTE: trim() does not reallocate.
-    void trim(ssize_t size)
+    void trim(int size)
     {
         if (m_impl)
             m_impl->trim(size);
     }
 
-    ByteBuffer slice(ssize_t offset, ssize_t size) const
+    ByteBuffer slice(int offset, int size) const
     {
         if (is_null())
             return {};
@@ -164,7 +164,7 @@ public:
         return copy(offset_pointer(offset), size);
     }
 
-    void grow(ssize_t size)
+    void grow(int size)
     {
         if (!m_impl)
             m_impl = ByteBufferImpl::create_uninitialized(size);
@@ -204,7 +204,7 @@ inline ByteBufferImpl::ByteBufferImpl(const void* data, int size, ConstructionMo
     m_owned = true;
 }
 
-inline ByteBufferImpl::ByteBufferImpl(void* data, ssize_t size, ConstructionMode mode)
+inline ByteBufferImpl::ByteBufferImpl(void* data, int size, ConstructionMode mode)
     : m_data(static_cast<byte*>(data))
     , m_size(size)
 {
@@ -215,7 +215,7 @@ inline ByteBufferImpl::ByteBufferImpl(void* data, ssize_t size, ConstructionMode
     }
 }
 
-inline void ByteBufferImpl::grow(ssize_t size)
+inline void ByteBufferImpl::grow(int size)
 {
     ASSERT(size > m_size);
     ASSERT(m_owned);

+ 12 - 6
AK/ELF/ELFImage.cpp

@@ -14,12 +14,18 @@ ELFImage::~ELFImage()
 static const char* object_file_type_to_string(Elf32_Half type)
 {
     switch (type) {
-    case ET_NONE: return "None";
-    case ET_REL: return "Relocatable";
-    case ET_EXEC: return "Executable";
-    case ET_DYN: return "Shared object";
-    case ET_CORE: return "Core";
-    default: return "(?)";
+    case ET_NONE:
+        return "None";
+    case ET_REL:
+        return "Relocatable";
+    case ET_EXEC:
+        return "Executable";
+    case ET_DYN:
+        return "Shared object";
+    case ET_CORE:
+        return "Core";
+    default:
+        return "(?)";
     }
 }
 

+ 17 - 12
AK/ELF/ELFImage.h

@@ -1,9 +1,9 @@
 #pragma once
 
-#include <AK/OwnPtr.h>
-#include <AK/HashMap.h>
 #include <AK/AKString.h>
 #include <AK/ELF/exec_elf.h>
+#include <AK/HashMap.h>
+#include <AK/OwnPtr.h>
 
 class ELFImage {
 public:
@@ -27,7 +27,7 @@ public:
         {
         }
 
-        ~Symbol() { }
+        ~Symbol() {}
 
         const char* name() const { return m_image.table_string(m_sym.st_name); }
         unsigned section_index() const { return m_sym.st_shndx; }
@@ -51,13 +51,13 @@ public:
             , m_program_header_index(program_header_index)
         {
         }
-        ~ProgramHeader() { }
+        ~ProgramHeader() {}
 
         unsigned index() const { return m_program_header_index; }
         dword type() const { return m_program_header.p_type; }
         dword flags() const { return m_program_header.p_flags; }
         dword offset() const { return m_program_header.p_offset; }
-        LinearAddress laddr() const { return LinearAddress(m_program_header.p_vaddr); }
+        VirtualAddress vaddr() const { return VirtualAddress(m_program_header.p_vaddr); }
         dword size_in_memory() const { return m_program_header.p_memsz; }
         dword size_in_image() const { return m_program_header.p_filesz; }
         dword alignment() const { return m_program_header.p_align; }
@@ -65,6 +65,7 @@ public:
         bool is_writable() const { return flags() & PF_W; }
         bool is_executable() const { return flags() & PF_X; }
         const char* raw_data() const { return m_image.raw_data(m_program_header.p_offset); }
+
     private:
         const ELFImage& m_image;
         const Elf32_Phdr& m_program_header;
@@ -79,7 +80,7 @@ public:
             , m_section_index(sectionIndex)
         {
         }
-        ~Section() { }
+        ~Section() {}
 
         const char* name() const { return m_image.section_header_table_string(m_section_header.sh_name); }
         unsigned type() const { return m_section_header.sh_type; }
@@ -109,15 +110,19 @@ public:
     const Section section(unsigned) const;
     const ProgramHeader program_header(unsigned const) const;
 
-    template<typename F> void for_each_section(F) const;
-    template<typename F> void for_each_section_of_type(unsigned, F) const;
-    template<typename F> void for_each_symbol(F) const;
-    template<typename F> void for_each_program_header(F) const;
+    template<typename F>
+    void for_each_section(F) const;
+    template<typename F>
+    void for_each_section_of_type(unsigned, F) const;
+    template<typename F>
+    void for_each_symbol(F) const;
+    template<typename F>
+    void for_each_program_header(F) const;
 
     bool is_executable() const { return header().e_type == ET_EXEC; }
     bool is_relocatable() const { return header().e_type == ET_REL; }
 
-    LinearAddress entry() const { return LinearAddress(header().e_entry); }
+    VirtualAddress entry() const { return VirtualAddress(header().e_entry); }
 
 private:
     bool parse_header();
@@ -158,7 +163,7 @@ template<typename F>
 inline void ELFImage::for_each_symbol(F func) const
 {
     for (unsigned i = 0; i < symbol_count(); ++i) {
-        if (func(symbol(i)) == IterationDecision::Abort)
+        if (func(symbol(i)) == IterationDecision::Break)
             break;
     }
 }

+ 12 - 14
AK/ELF/ELFLoader.cpp

@@ -1,6 +1,6 @@
 #include "ELFLoader.h"
-#include <AK/kstdio.h>
 #include <AK/QuickSort.h>
+#include <AK/kstdio.h>
 
 //#define ELFLOADER_DEBUG
 
@@ -30,33 +30,31 @@ bool ELFLoader::load()
 bool ELFLoader::layout()
 {
     bool failed = false;
-    m_image.for_each_program_header([&] (const ELFImage::ProgramHeader& program_header) {
+    m_image.for_each_program_header([&](const ELFImage::ProgramHeader& program_header) {
         if (program_header.type() != PT_LOAD)
             return;
 #ifdef ELFLOADER_DEBUG
-        kprintf("PH: L%x %u r:%u w:%u\n", program_header.laddr().get(), program_header.size_in_memory(), program_header.is_readable(), program_header.is_writable());
+        kprintf("PH: L%x %u r:%u w:%u\n", program_header.vaddr().get(), program_header.size_in_memory(), program_header.is_readable(), program_header.is_writable());
 #endif
         if (program_header.is_writable()) {
             alloc_section_hook(
-                program_header.laddr(),
+                program_header.vaddr(),
                 program_header.size_in_memory(),
                 program_header.alignment(),
                 program_header.is_readable(),
                 program_header.is_writable(),
-                String::format("elf-alloc-%s%s", program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : "")
-            );
-            memcpy(program_header.laddr().as_ptr(), program_header.raw_data(), program_header.size_in_image());
+                String::format("elf-alloc-%s%s", program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : ""));
+            memcpy(program_header.vaddr().as_ptr(), program_header.raw_data(), program_header.size_in_image());
         } else {
             map_section_hook(
-                program_header.laddr(),
+                program_header.vaddr(),
                 program_header.size_in_memory(),
                 program_header.alignment(),
                 program_header.offset(),
                 program_header.is_readable(),
                 program_header.is_writable(),
                 program_header.is_executable(),
-                String::format("elf-map-%s%s%s", program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : "", program_header.is_executable() ? "x" : "")
-            );
+                String::format("elf-map-%s%s%s", program_header.is_readable() ? "r" : "", program_header.is_writable() ? "w" : "", program_header.is_executable() ? "x" : ""));
         }
     });
     return !failed;
@@ -65,7 +63,7 @@ bool ELFLoader::layout()
 char* ELFLoader::symbol_ptr(const char* name)
 {
     char* found_ptr = nullptr;
-    m_image.for_each_symbol([&] (const ELFImage::Symbol symbol) {
+    m_image.for_each_symbol([&](const ELFImage::Symbol symbol) {
         if (symbol.type() != STT_FUNC)
             return IterationDecision::Continue;
         if (strcmp(symbol.name(), name))
@@ -74,7 +72,7 @@ char* ELFLoader::symbol_ptr(const char* name)
             found_ptr = (char*)symbol.value();
         else
             ASSERT_NOT_REACHED();
-        return IterationDecision::Abort;
+        return IterationDecision::Break;
     });
     return found_ptr;
 }
@@ -83,11 +81,11 @@ String ELFLoader::symbolicate(dword address) const
 {
     if (m_sorted_symbols.is_empty()) {
         m_sorted_symbols.ensure_capacity(m_image.symbol_count());
-        m_image.for_each_symbol([this] (auto& symbol) {
+        m_image.for_each_symbol([this](auto& symbol) {
             m_sorted_symbols.append({ symbol.value(), symbol.name() });
             return IterationDecision::Continue;
         });
-        quick_sort(m_sorted_symbols.begin(), m_sorted_symbols.end(), [] (auto& a, auto& b) {
+        quick_sort(m_sorted_symbols.begin(), m_sorted_symbols.end(), [](auto& a, auto& b) {
             return a.address < b.address;
         });
     }

+ 5 - 6
AK/ELF/ELFLoader.h

@@ -5,7 +5,7 @@
 #include <AK/OwnPtr.h>
 #include <AK/Vector.h>
 #if defined(KERNEL)
-#include <Kernel/LinearAddress.h>
+#    include <Kernel/VirtualAddress.h>
 #endif
 #include <AK/ELF/ELFImage.h>
 
@@ -16,9 +16,9 @@ public:
 
     bool load();
 #if defined(KERNEL)
-    Function<void*(LinearAddress, size_t, size_t, bool, bool, const String&)> alloc_section_hook;
-    Function<void*(LinearAddress, size_t, size_t, size_t, bool r, bool w, bool x, const String&)> map_section_hook;
-    LinearAddress entry() const { return m_image.entry(); }
+    Function<void*(VirtualAddress, size_t, size_t, bool, bool, const String&)> alloc_section_hook;
+    Function<void*(VirtualAddress, size_t, size_t, size_t, bool r, bool w, bool x, const String&)> map_section_hook;
+    VirtualAddress entry() const { return m_image.entry(); }
 #endif
     char* symbol_ptr(const char* name);
 
@@ -34,7 +34,7 @@ private:
     char* area_for_section_name(const char*);
 
     struct PtrAndSize {
-        PtrAndSize() { }
+        PtrAndSize() {}
         PtrAndSize(char* p, unsigned s)
             : ptr(p)
             , size(s)
@@ -52,4 +52,3 @@ private:
     };
     mutable Vector<SortedSymbol> m_sorted_symbols;
 };
-

Разлика између датотеке није приказан због своје велике величине
+ 441 - 445
AK/ELF/exec_elf.h


+ 1 - 1
AK/FileSystemPath.cpp

@@ -5,7 +5,7 @@
 
 namespace AK {
 
-FileSystemPath::FileSystemPath(const String& s)
+FileSystemPath::FileSystemPath(const StringView& s)
     : m_string(s)
 {
     m_is_valid = canonicalize();

+ 3 - 3
AK/FileSystemPath.h

@@ -7,12 +7,12 @@ namespace AK {
 class FileSystemPath {
 public:
     FileSystemPath() {}
-    explicit FileSystemPath(const String&);
+    explicit FileSystemPath(const StringView&);
 
     bool is_valid() const { return m_is_valid; }
-    String string() const { return m_string; }
+    const String& string() const { return m_string; }
 
-    String basename() const { return m_basename; }
+    const String& basename() const { return m_basename; }
 
     const Vector<String>& parts() const { return m_parts; }
 

+ 12 - 0
AK/IterationDecision.h

@@ -0,0 +1,12 @@
+#pragma once
+
+namespace AK {
+
+enum class IterationDecision {
+    Continue,
+    Break,
+};
+
+}
+
+using AK::IterationDecision;

+ 4 - 8
AK/MappedFile.cpp

@@ -9,11 +9,10 @@
 
 namespace AK {
 
-MappedFile::MappedFile(const String& file_name)
-    : m_file_name(file_name)
+MappedFile::MappedFile(const StringView& file_name)
 {
     m_size = PAGE_SIZE;
-    m_fd = open(m_file_name.characters(), O_RDONLY | O_CLOEXEC);
+    m_fd = open(file_name.characters(), O_RDONLY | O_CLOEXEC);
 
     if (m_fd != -1) {
         struct stat st;
@@ -26,7 +25,7 @@ MappedFile::MappedFile(const String& file_name)
     }
 
 #ifdef DEBUG_MAPPED_FILE
-    dbgprintf("MappedFile{%s} := { m_fd=%d, m_size=%u, m_map=%p }\n", m_file_name.characters(), m_fd, m_size, m_map);
+    dbgprintf("MappedFile{%s} := { m_fd=%d, m_size=%u, m_map=%p }\n", file_name.characters(), m_fd, m_size, m_map);
 #endif
 }
 
@@ -44,15 +43,13 @@ void MappedFile::unmap()
     ASSERT(rc == 0);
     rc = close(m_fd);
     ASSERT(rc == 0);
-    m_file_name = {};
     m_size = 0;
     m_fd = -1;
     m_map = (void*)-1;
 }
 
 MappedFile::MappedFile(MappedFile&& other)
-    : m_file_name(move(other.m_file_name))
-    , m_size(other.m_size)
+    : m_size(other.m_size)
     , m_fd(other.m_fd)
     , m_map(other.m_map)
 {
@@ -66,7 +63,6 @@ MappedFile& MappedFile::operator=(MappedFile&& other)
     if (this == &other)
         return *this;
     unmap();
-    swap(m_file_name, other.m_file_name);
     swap(m_size, other.m_size);
     swap(m_fd, other.m_fd);
     swap(m_map, other.m_map);

+ 2 - 3
AK/MappedFile.h

@@ -1,13 +1,13 @@
 #pragma once
 
-#include "AKString.h"
+#include "StringView.h"
 
 namespace AK {
 
 class MappedFile {
 public:
     MappedFile() {}
-    explicit MappedFile(const String& file_name);
+    explicit MappedFile(const StringView& file_name);
     MappedFile(MappedFile&&);
     ~MappedFile();
 
@@ -21,7 +21,6 @@ public:
     size_t size() const { return m_size; }
 
 private:
-    String m_file_name;
     size_t m_size { 0 };
     int m_fd { -1 };
     void* m_map { (void*)-1 };

+ 12 - 14
AK/printf.cpp → AK/PrintfImplementation.h

@@ -1,17 +1,15 @@
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned int dword;
-typedef long long unsigned int qword;
+#pragma once
 
-[[gnu::always_inline]] inline size_t strlen(const char* str)
-{
-    size_t len = 0;
-    while (*(str++))
-        ++len;
-    return len;
-}
+#include <AK/Types.h>
+#include <stdarg.h>
 
-static constexpr const char* h = "0123456789abcdef";
+static constexpr const char* printf_hex_digits = "0123456789abcdef";
+
+#ifdef __serenity__
+extern "C" size_t strlen(const char*);
+#else
+#include <string.h>
+#endif
 
 template<typename PutChFunc, typename T>
 [[gnu::always_inline]] inline int print_hex(PutChFunc putch, char*& bufptr, T number, byte fields)
@@ -20,7 +18,7 @@ template<typename PutChFunc, typename T>
     byte shr_count = fields * 4;
     while (shr_count) {
         shr_count -= 4;
-        putch(bufptr, h[(number >> shr_count) & 0x0F]);
+        putch(bufptr, printf_hex_digits[(number >> shr_count) & 0x0F]);
         ++ret;
     }
     return ret;
@@ -180,7 +178,7 @@ template<typename PutChFunc>
 }
 
 template<typename PutChFunc>
-[[gnu::always_inline]] inline int printf_internal(PutChFunc putch, char* buffer, const char*& fmt, char*& ap)
+[[gnu::always_inline]] inline int printf_internal(PutChFunc putch, char* buffer, const char*& fmt, va_list ap)
 {
     const char* p;
 

+ 49 - 0
AK/Queue.h

@@ -0,0 +1,49 @@
+#pragma once
+
+#include <AK/OwnPtr.h>
+#include <AK/SinglyLinkedList.h>
+#include <AK/Vector.h>
+
+namespace AK {
+
+template<typename T>
+class Queue {
+public:
+    Queue() { }
+    ~Queue() { }
+
+    int size() const { return m_size; }
+    bool is_empty() const { return m_size == 0; }
+
+    void enqueue(T&& value)
+    {
+        if (m_segments.is_empty() || m_segments.last()->size() >= segment_size)
+            m_segments.append(make<Vector<T, segment_size>>());
+        m_segments.last()->append(move(value));
+        ++m_size;
+    }
+
+    T dequeue()
+    {
+        ASSERT(!is_empty());
+        auto value = move((*m_segments.first())[m_index_into_first++]);
+        if (m_index_into_first == segment_size) {
+            m_segments.take_first();
+            m_index_into_first = 0;
+        }
+        --m_size;
+        return value;
+    }
+
+private:
+    static const int segment_size = 1000;
+
+    SinglyLinkedList<OwnPtr<Vector<T, segment_size>>> m_segments;
+    int m_index_into_first { 0 };
+    int m_size { 0 };
+};
+
+}
+
+using AK::Queue;
+

+ 2 - 0
AK/QuickSort.h

@@ -1,5 +1,7 @@
 #pragma once
 
+#include <AK/StdLibExtras.h>
+
 namespace AK {
 
 template<typename T>

+ 25 - 4
AK/RetainPtr.h

@@ -103,20 +103,41 @@ public:
         return *this;
     }
 
-    RetainPtr& operator=(T* ptr)
+    template<typename U>
+    RetainPtr& operator=(const Retained<U>& other)
+    {
+        if (m_ptr != other.ptr())
+            release_if_not_null(m_ptr);
+        m_ptr = const_cast<T*>(other.ptr());
+        ASSERT(m_ptr);
+        retain_if_not_null(m_ptr);
+        return *this;
+    }
+
+    template<typename U>
+    RetainPtr& operator=(const RetainPtr<U>& other)
+    {
+        if (m_ptr != other.ptr())
+            release_if_not_null(m_ptr);
+        m_ptr = const_cast<T*>(other.ptr());
+        retain_if_not_null(m_ptr);
+        return *this;
+    }
+
+    RetainPtr& operator=(const T* ptr)
     {
         if (m_ptr != ptr)
             release_if_not_null(m_ptr);
-        m_ptr = ptr;
+        m_ptr = const_cast<T*>(ptr);
         retain_if_not_null(m_ptr);
         return *this;
     }
 
-    RetainPtr& operator=(T& object)
+    RetainPtr& operator=(const T& object)
     {
         if (m_ptr != &object)
             release_if_not_null(m_ptr);
-        m_ptr = &object;
+        m_ptr = const_cast<T*>(&object);
         retain_if_not_null(m_ptr);
         return *this;
     }

+ 15 - 8
AK/Retained.h

@@ -44,16 +44,10 @@ public:
     {
         m_ptr->retain();
     }
-    RETURN_TYPESTATE(unconsumed)
-    Retained(T& object)
-        : m_ptr(&object)
-    {
-        m_ptr->retain();
-    }
     template<typename U>
     RETURN_TYPESTATE(unconsumed)
-    Retained(U& object)
-        : m_ptr(&static_cast<T&>(object))
+    Retained(const U& object)
+        : m_ptr(&const_cast<T&>(static_cast<const T&>(object)))
     {
         m_ptr->retain();
     }
@@ -200,6 +194,19 @@ public:
         return m_ptr;
     }
 
+    CALLABLE_WHEN(unconsumed)
+    operator T&()
+    {
+        ASSERT(m_ptr);
+        return *m_ptr;
+    }
+    CALLABLE_WHEN(unconsumed)
+    operator const T&() const
+    {
+        ASSERT(m_ptr);
+        return *m_ptr;
+    }
+
 private:
     Retained() {}
 

+ 24 - 0
AK/ScopeGuard.h

@@ -0,0 +1,24 @@
+#pragma once
+
+namespace AK {
+
+template<typename Callback>
+class ScopeGuard {
+public:
+    ScopeGuard(Callback callback)
+        : m_callback(move(callback))
+    {
+    }
+
+    ~ScopeGuard()
+    {
+        m_callback();
+    }
+
+private:
+    Callback m_callback;
+};
+
+}
+
+using AK::ScopeGuard;

+ 2 - 2
AK/SinglyLinkedList.h

@@ -9,7 +9,7 @@ class SinglyLinkedList {
 private:
     struct Node {
         explicit Node(T&& v)
-            : value(v)
+            : value(move(v))
         {
         }
         T value;
@@ -66,7 +66,7 @@ public:
     {
         ASSERT(m_head);
         auto* prev_head = m_head;
-        T value = first();
+        T value = move(first());
         if (m_tail == m_head)
             m_tail = nullptr;
         m_head = m_head->next;

+ 1 - 0
AK/StdLibExtras.h

@@ -292,4 +292,5 @@ using AK::IsSame;
 using AK::max;
 using AK::min;
 using AK::move;
+using AK::RemoveConst;
 using AK::swap;

+ 44 - 25
AK/String.cpp

@@ -1,7 +1,7 @@
 #include "AKString.h"
 #include "StdLibExtras.h"
 #include "StringBuilder.h"
-#include <LibC/stdarg.h>
+#include <stdarg.h>
 
 namespace AK {
 
@@ -68,22 +68,27 @@ StringView String::substring_view(int start, int length) const
 }
 
 Vector<String> String::split(const char separator) const
+{
+    return split_limit(separator, 0);
+}
+
+Vector<String> String::split_limit(const char separator, int limit) const
 {
     if (is_empty())
         return {};
 
     Vector<String> v;
-    ssize_t substart = 0;
-    for (ssize_t i = 0; i < length(); ++i) {
+    int substart = 0;
+    for (int i = 0; i < length() && (v.size() + 1) != limit; ++i) {
         char ch = characters()[i];
         if (ch == separator) {
-            ssize_t sublen = i - substart;
+            int sublen = i - substart;
             if (sublen != 0)
                 v.append(substring(substart, sublen));
             substart = i + 1;
         }
     }
-    ssize_t taillen = length() - substart;
+    int taillen = length() - substart;
     if (taillen != 0)
         v.append(substring(substart, taillen));
     if (characters()[length() - 1] == separator)
@@ -97,21 +102,21 @@ Vector<StringView> String::split_view(const char separator) const
         return {};
 
     Vector<StringView> v;
-    ssize_t substart = 0;
-    for (ssize_t i = 0; i < length(); ++i) {
+    int substart = 0;
+    for (int i = 0; i < length(); ++i) {
         char ch = characters()[i];
         if (ch == separator) {
-            ssize_t sublen = i - substart;
+            int sublen = i - substart;
             if (sublen != 0)
                 v.append(substring_view(substart, sublen));
             substart = i + 1;
         }
     }
-    ssize_t taillen = length() - substart;
+    int taillen = length() - substart;
     if (taillen != 0)
         v.append(substring_view(substart, taillen));
     if (characters()[length() - 1] == separator)
-        v.append(empty().view());
+        v.append(empty());
     return v;
 }
 
@@ -126,7 +131,7 @@ int String::to_int(bool& ok) const
 {
     bool negative = false;
     int value = 0;
-    ssize_t i = 0;
+    int i = 0;
 
     if (is_null()) {
         ok = false;
@@ -153,7 +158,7 @@ int String::to_int(bool& ok) const
 unsigned String::to_uint(bool& ok) const
 {
     unsigned value = 0;
-    for (ssize_t i = 0; i < length(); ++i) {
+    for (int i = 0; i < length(); ++i) {
         if (characters()[i] < '0' || characters()[i] > '9') {
             ok = false;
             return 0;
@@ -175,7 +180,18 @@ String String::format(const char* fmt, ...)
     return builder.to_string();
 }
 
-bool String::ends_with(const String& str) const
+bool String::starts_with(const StringView& str) const
+{
+    if (str.is_empty())
+        return true;
+    if (is_empty())
+        return false;
+    if (str.length() > length())
+        return false;
+    return !memcmp(characters(), str.characters(), str.length());
+}
+
+bool String::ends_with(const StringView& str) const
 {
     if (str.is_empty())
         return true;
@@ -196,27 +212,28 @@ String String::repeated(char ch, int count)
     return *impl;
 }
 
-bool String::matches(const String& mask, CaseSensitivity case_sensitivity) const
+bool String::matches(const StringView& mask, CaseSensitivity case_sensitivity) const
 {
     if (case_sensitivity == CaseSensitivity::CaseInsensitive) {
         String this_lower = this->to_lowercase();
-        String mask_lower = mask.to_lowercase();
+        String mask_lower = String(mask).to_lowercase();
         return this_lower.match_helper(mask_lower);
     }
 
     return match_helper(mask);
 }
 
-bool String::match_helper(const String& mask) const
+bool String::match_helper(const StringView& mask) const
 {
-    if (is_null() || mask.is_null())
+    if (is_null())
         return false;
 
     const char* string_ptr = characters();
     const char* mask_ptr = mask.characters();
+    const char* mask_end = mask_ptr + mask.length();
 
     // Match string against mask directly unless we hit a *
-    while ((*string_ptr) && (*mask_ptr != '*')) {
+    while ((*string_ptr) && (mask_ptr < mask_end) && (*mask_ptr != '*')) {
         if ((*mask_ptr != *string_ptr) && (*mask_ptr != '?'))
             return false;
         mask_ptr++;
@@ -227,27 +244,29 @@ bool String::match_helper(const String& mask) const
     const char* mp = nullptr;
 
     while (*string_ptr) {
-        if (*mask_ptr == '*') {
+        if ((mask_ptr < mask_end) && (*mask_ptr == '*')) {
             // If we have only a * left, there is no way to not match.
-            if (!*++mask_ptr)
+            if (++mask_ptr == mask_end)
                 return true;
             mp = mask_ptr;
             cp = string_ptr + 1;
-        } else if ((*mask_ptr == *string_ptr) || (*mask_ptr == '?')) {
+        } else if ((mask_ptr < mask_end) && ((*mask_ptr == *string_ptr) || (*mask_ptr == '?'))) {
             mask_ptr++;
             string_ptr++;
-        } else {
+        } else if ((cp != nullptr) && (mp != nullptr)) {
             mask_ptr = mp;
             string_ptr = cp++;
+        } else {
+            break;
         }
     }
 
     // Handle any trailing mask
-    while (*mask_ptr == '*')
+    while ((mask_ptr < mask_end) && (*mask_ptr == '*'))
         mask_ptr++;
 
-    // If we 'ate' all of the mask then we match.
-    return !*mask_ptr;
+    // If we 'ate' all of the mask and the string then we match.
+    return (mask_ptr == mask_end) && !*string_ptr;
 }
 
 }

+ 8 - 8
AK/StringBuilder.cpp

@@ -1,22 +1,22 @@
-#include "StringBuilder.h"
-#include "printf.cpp"
+#include <AK/PrintfImplementation.h>
 #include <AK/StdLibExtras.h>
-#include <LibC/stdarg.h>
+#include <AK/StringBuilder.h>
+#include <stdarg.h>
 
 namespace AK {
 
-inline void StringBuilder::will_append(ssize_t size)
+inline void StringBuilder::will_append(int size)
 {
     if ((m_length + size) > m_buffer.size())
-        m_buffer.grow(max((ssize_t)16, m_buffer.size() * 2 + size));
+        m_buffer.grow(max((int)16, m_buffer.size() * 2 + size));
 }
 
-StringBuilder::StringBuilder(ssize_t initial_capacity)
+StringBuilder::StringBuilder(int initial_capacity)
 {
     m_buffer.grow(initial_capacity);
 }
 
-void StringBuilder::append(const String& str)
+void StringBuilder::append(const StringView& str)
 {
     if (str.is_empty())
         return;
@@ -25,7 +25,7 @@ void StringBuilder::append(const String& str)
     m_length += str.length();
 }
 
-void StringBuilder::append(const char* characters, ssize_t length)
+void StringBuilder::append(const char* characters, int length)
 {
     if (!length)
         return;

+ 6 - 6
AK/StringBuilder.h

@@ -2,18 +2,18 @@
 
 #include "AKString.h"
 #include "Vector.h"
-#include <LibC/stdarg.h>
+#include <stdarg.h>
 
 namespace AK {
 
 class StringBuilder {
 public:
-    explicit StringBuilder(ssize_t initial_capacity = 16);
+    explicit StringBuilder(int initial_capacity = 16);
     ~StringBuilder() {}
 
-    void append(const String&);
+    void append(const StringView&);
     void append(char);
-    void append(const char*, ssize_t);
+    void append(const char*, int);
     void appendf(const char*, ...);
     void appendvf(const char*, va_list);
 
@@ -21,10 +21,10 @@ public:
     ByteBuffer to_byte_buffer();
 
 private:
-    void will_append(ssize_t);
+    void will_append(int);
 
     ByteBuffer m_buffer;
-    ssize_t m_length { 0 };
+    int m_length { 0 };
 };
 
 }

+ 4 - 0
AK/StringImpl.cpp

@@ -3,6 +3,10 @@
 #include "StdLibExtras.h"
 #include "kmalloc.h"
 
+#ifndef __serenity__
+#include <new>
+#endif
+
 //#define DEBUG_STRINGIMPL
 
 #ifdef DEBUG_STRINGIMPL

+ 26 - 1
AK/StringView.cpp

@@ -3,6 +3,13 @@
 
 namespace AK {
 
+StringView::StringView(const String& string)
+    : m_impl(string.impl())
+    , m_characters(string.characters())
+    , m_length(string.length())
+{
+}
+
 Vector<StringView> StringView::split_view(const char separator) const
 {
     if (is_empty())
@@ -23,7 +30,7 @@ Vector<StringView> StringView::split_view(const char separator) const
     if (taillen != 0)
         v.append(substring_view(substart, taillen));
     if (characters()[length() - 1] == separator)
-        v.append(String::empty().view());
+        v.append(String::empty());
     return v;
 }
 
@@ -35,6 +42,24 @@ StringView StringView::substring_view(int start, int length) const
     return { m_characters + start, length };
 }
 
+StringView StringView::substring_view_starting_from_substring(const StringView& substring) const
+{
+    const char* remaining_characters = substring.characters();
+    ASSERT(remaining_characters >= m_characters);
+    ASSERT(remaining_characters <= m_characters + m_length);
+    int remaining_length = m_length - (remaining_characters - m_characters);
+    return { remaining_characters, remaining_length };
+}
+
+StringView StringView::substring_view_starting_after_substring(const StringView& substring) const
+{
+    const char* remaining_characters = substring.characters() + substring.length();
+    ASSERT(remaining_characters >= m_characters);
+    ASSERT(remaining_characters <= m_characters + m_length);
+    int remaining_length = m_length - (remaining_characters - m_characters);
+    return { remaining_characters, remaining_length };
+}
+
 unsigned StringView::to_uint(bool& ok) const
 {
     unsigned value = 0;

+ 39 - 2
AK/StringView.h

@@ -5,6 +5,7 @@
 namespace AK {
 
 class String;
+class StringImpl;
 
 class StringView {
 public:
@@ -27,7 +28,9 @@ public:
                 ++m_length;
         }
     }
+    StringView(const String& string);
 
+    bool is_null() const { return !m_characters; }
     bool is_empty() const { return m_length == 0; }
     const char* characters() const { return m_characters; }
     int length() const { return m_length; }
@@ -37,12 +40,46 @@ public:
     Vector<StringView> split_view(char) const;
     unsigned to_uint(bool& ok) const;
 
-    bool operator==(const char* cstring) const { return !strcmp(m_characters, cstring); }
-    bool operator!=(const char* cstring) const { return strcmp(m_characters, cstring); }
+    // Create a new substring view of this string view, starting either at the beginning of
+    // the given substring view, or after its end, and continuing until the end of this string
+    // view (that is, for the remaining part of its length). For example,
+    //
+    //    StringView str { "foobar" };
+    //    StringView substr = str.substring_view(1, 2);  // "oo"
+    //    StringView substr_from = str.substring_view_starting_from_substring(subst);  // "oobar"
+    //    StringView substr_after = str.substring_view_starting_after_substring(subst);  // "bar"
+    //
+    // Note that this only works if the string view passed as an argument is indeed a substring
+    // view of this string view, such as one created by substring_view() and split_view(). It
+    // does not work for arbitrary strings; for example declaring substr in the example above as
+    //
+    //     StringView substr { "oo" };
+    //
+    // would not work.
+    StringView substring_view_starting_from_substring(const StringView& substring) const;
+    StringView substring_view_starting_after_substring(const StringView& substring) const;
+
+    bool operator==(const char* cstring) const
+    {
+        if (is_null())
+            return !cstring;
+        if (!cstring)
+            return false;
+        int other_length = strlen(cstring);
+        if (m_length != other_length)
+            return false;
+        return !memcmp(m_characters, cstring, m_length);
+    }
+    bool operator!=(const char* cstring) const
+    {
+        return !(*this == cstring);
+    }
 
     bool operator==(const String&) const;
 
 private:
+    friend class String;
+    const StringImpl* m_impl { nullptr };
     const char* m_characters { nullptr };
     int m_length { 0 };
 };

+ 2 - 0
AK/Tests/.gitignore

@@ -0,0 +1,2 @@
+TestString
+TestQueue

+ 12 - 0
AK/Tests/Makefile

@@ -0,0 +1,12 @@
+all: TestString TestQueue
+
+CXXFLAGS = -std=c++17 -Wall -Wextra
+
+TestString: TestString.cpp ../String.cpp ../StringImpl.cpp ../StringBuilder.cpp ../StringView.cpp TestHelpers.h
+	$(CXX) $(CXXFLAGS) -I../ -I../../ -o $@ TestString.cpp ../String.cpp ../StringImpl.cpp ../StringBuilder.cpp ../StringView.cpp
+
+TestQueue: TestQueue.cpp ../String.cpp ../StringImpl.cpp ../StringBuilder.cpp ../StringView.cpp TestHelpers.h
+	$(CXX) $(CXXFLAGS) -I../ -I../../ -o $@ TestQueue.cpp ../String.cpp ../StringImpl.cpp ../StringBuilder.cpp ../StringView.cpp
+
+clean:
+	rm -f TestString TestQueue

+ 68 - 0
AK/Tests/TestHelpers.h

@@ -0,0 +1,68 @@
+#pragma once
+
+#include <stdio.h>
+#include <AK/AKString.h>
+
+#define LOG_FAIL(cond) \
+    fprintf(stderr, "\033[31;1mFAIL\033[0m: " #cond "\n")
+
+#define LOG_PASS(cond) \
+    fprintf(stderr, "\033[32;1mPASS\033[0m: " #cond "\n")
+
+#define LOG_FAIL_EQ(cond, expected_value, actual_value) \
+    fprintf(stderr, "\033[31;1mFAIL\033[0m: " #cond " should be " #expected_value ", got "); \
+    stringify_for_test(actual_value); \
+    fprintf(stderr, "\n")
+
+#define LOG_PASS_EQ(cond, expected_value) \
+    fprintf(stderr, "\033[32;1mPASS\033[0m: " #cond " should be " #expected_value " and it is\n")
+
+#define EXPECT_EQ(expr, expected_value) \
+    do { \
+        auto result = (expr); \
+        if (!(result == expected_value)) { \
+            LOG_FAIL_EQ(expr, expected_value, result); \
+        } else { \
+            LOG_PASS_EQ(expr, expected_value); \
+        } \
+    } while(0)
+
+#define EXPECT(cond) \
+    do { \
+        if (!(cond)) { \
+            LOG_FAIL(cond); \
+        } else { \
+            LOG_PASS(cond); \
+        } \
+    } while(0)
+
+inline void stringify_for_test(int value)
+{
+    fprintf(stderr, "%d", value);
+}
+
+inline void stringify_for_test(unsigned value)
+{
+    fprintf(stderr, "%u", value);
+}
+
+inline void stringify_for_test(const char* value)
+{
+    fprintf(stderr, "%s", value);
+}
+
+inline void stringify_for_test(char value)
+{
+    fprintf(stderr, "%c", value);
+}
+
+inline void stringify_for_test(const AK::String& string)
+{
+    stringify_for_test(string.characters());
+}
+
+inline void stringify_for_test(const AK::StringImpl& string)
+{
+    stringify_for_test(string.characters());
+}
+

+ 43 - 0
AK/Tests/TestQueue.cpp

@@ -0,0 +1,43 @@
+#include "TestHelpers.h"
+#include <AK/AKString.h>
+#include <AK/Queue.h>
+
+int main()
+{
+    EXPECT(Queue<int>().is_empty());
+    EXPECT(Queue<int>().size() == 0);
+
+    Queue<int> ints;
+    ints.enqueue(1);
+    ints.enqueue(2);
+    ints.enqueue(3);
+    EXPECT_EQ(ints.size(), 3);
+    EXPECT_EQ(ints.dequeue(), 1);
+    EXPECT_EQ(ints.size(), 2);
+    EXPECT_EQ(ints.dequeue(), 2);
+    EXPECT_EQ(ints.size(), 1);
+    EXPECT_EQ(ints.dequeue(), 3);
+    EXPECT_EQ(ints.size(), 0);
+
+    Queue<String> strings;
+    strings.enqueue("ABC");
+    strings.enqueue("DEF");
+    EXPECT_EQ(strings.size(), 2);
+    EXPECT_EQ(strings.dequeue(), "ABC");
+    EXPECT_EQ(strings.dequeue(), "DEF");
+    EXPECT(strings.is_empty());
+
+    for (int i = 0; i < 10000; ++i) {
+        strings.enqueue(String::format("%d", i));
+        EXPECT_EQ(strings.size(), i + 1);
+    }
+
+    for (int i = 0; i < 10000; ++i) {
+        bool ok;
+        EXPECT_EQ(strings.dequeue().to_int(ok), i);
+    }
+
+    EXPECT(strings.is_empty());
+
+    return 0;
+}

+ 59 - 0
AK/Tests/TestString.cpp

@@ -0,0 +1,59 @@
+#include "TestHelpers.h"
+#include <AK/AKString.h>
+
+int main()
+{
+    EXPECT(String().is_null());
+    EXPECT(String().is_empty());
+    EXPECT(!String().characters());
+
+    EXPECT(!String("").is_null());
+    EXPECT(String("").is_empty());
+    EXPECT(String("").characters());
+
+    EXPECT(String("").impl() == String::empty().impl());
+
+    String test_string = "ABCDEF";
+    EXPECT(!test_string.is_empty());
+    EXPECT(!test_string.is_null());
+    EXPECT_EQ(test_string.length(), 6);
+    EXPECT_EQ(test_string.length(), (int)strlen(test_string.characters()));
+    EXPECT(test_string.characters());
+    EXPECT(!strcmp(test_string.characters(), "ABCDEF"));
+
+    EXPECT(test_string == "ABCDEF");
+    EXPECT(test_string != "ABCDE");
+    EXPECT(test_string != "ABCDEFG");
+
+    EXPECT_EQ(test_string[0], 'A');
+    EXPECT_EQ(test_string[1], 'B');
+
+    EXPECT(test_string.starts_with("AB"));
+    EXPECT(test_string.starts_with("ABCDEF"));
+    EXPECT(!test_string.starts_with("DEF"));
+
+    EXPECT(test_string.ends_with("EF"));
+    EXPECT(test_string.ends_with("ABCDEF"));
+    EXPECT(!test_string.ends_with("ABC"));
+
+    auto test_string_copy = test_string;
+    EXPECT_EQ(test_string, test_string_copy);
+    EXPECT_EQ(test_string.characters(), test_string_copy.characters());
+
+    auto test_string_move = move(test_string_copy);
+    EXPECT_EQ(test_string, test_string_move);
+    EXPECT(test_string_copy.is_null());
+
+    EXPECT_EQ(String::repeated('x', 0), "");
+    EXPECT_EQ(String::repeated('x', 1), "x");
+    EXPECT_EQ(String::repeated('x', 2), "xx");
+
+    bool ok;
+    EXPECT(String("123").to_int(ok) == 123 && ok);
+    EXPECT(String("-123").to_int(ok) == -123 && ok);
+
+    EXPECT(String("ABC").to_lowercase() == "abc");
+    EXPECT(String("AbC").to_uppercase() == "ABC");
+
+    return 0;
+}

+ 15 - 12
AK/Time.h

@@ -3,25 +3,28 @@
 namespace AK {
 
 template<typename TimevalType>
-inline void timeval_sub(const TimevalType* a, const TimevalType* b, TimevalType* result)
+inline void timeval_sub(const TimevalType& a, const TimevalType& b, TimevalType& result)
 {
-    result->tv_sec = a->tv_sec - b->tv_sec;
-    result->tv_usec = a->tv_usec - b->tv_usec;
-    if (result->tv_usec < 0) {
-        --result->tv_sec;
-        result->tv_usec += 1000000;
+    result.tv_sec = a.tv_sec - b.tv_sec;
+    result.tv_usec = a.tv_usec - b.tv_usec;
+    if (result.tv_usec < 0) {
+        --result.tv_sec;
+        result.tv_usec += 1000000;
     }
 }
 
 template<typename TimevalType>
-inline void timeval_add(const TimevalType* a, const TimevalType* b, TimevalType* result)
+inline void timeval_add(const TimevalType& a, const TimevalType& b, TimevalType& result)
 {
-    result->tv_sec = a->tv_sec + b->tv_sec;
-    result->tv_usec = a->tv_usec + b->tv_usec;
-    if (result->tv_usec > 1000000) {
-        ++result->tv_sec;
-        result->tv_usec -= 1000000;
+    result.tv_sec = a.tv_sec + b.tv_sec;
+    result.tv_usec = a.tv_usec + b.tv_usec;
+    if (result.tv_usec > 1000000) {
+        ++result.tv_sec;
+        result.tv_usec -= 1000000;
     }
 }
 
 }
+
+using AK::timeval_add;
+using AK::timeval_sub;

+ 2 - 5
AK/Types.h

@@ -1,5 +1,7 @@
 #pragma once
 
+#include <AK/IterationDecision.h>
+
 #ifdef __serenity__
 typedef unsigned char byte;
 typedef unsigned short word;
@@ -48,11 +50,6 @@ constexpr unsigned KB = 1024;
 constexpr unsigned MB = KB * KB;
 constexpr unsigned GB = KB * KB * KB;
 
-enum class IterationDecision {
-    Continue,
-    Abort
-};
-
 namespace std {
 typedef decltype(nullptr) nullptr_t;
 }

+ 26 - 0
AK/ValueRestorer.h

@@ -0,0 +1,26 @@
+#pragma once
+
+namespace AK {
+
+template<typename T>
+class ValueRestorer {
+public:
+    ValueRestorer(T& variable)
+        : m_variable(variable)
+        , m_saved_value(variable)
+    {
+    }
+
+    ~ValueRestorer()
+    {
+        m_variable = m_saved_value;
+    }
+
+private:
+    T& m_variable;
+    T m_saved_value;
+};
+
+}
+
+using AK::ValueRestorer;

+ 17 - 0
AK/Vector.h

@@ -4,6 +4,10 @@
 #include <AK/StdLibExtras.h>
 #include <AK/kmalloc.h>
 
+#ifndef __serenity__
+#include <new>
+#endif
+
 namespace AK {
 
 template<typename T, int inline_capacity = 0>
@@ -294,6 +298,19 @@ public:
         m_capacity = new_capacity;
     }
 
+    void shift_left(int count)
+    {
+        ASSERT(count <= m_size);
+        if (count == m_size) {
+            clear();
+            return;
+        }
+        for (int i = 0; i < m_size - count; ++i) {
+            at(i) = move(at(i + count));
+        }
+        m_size -= count;
+    }
+
     void resize(int new_size)
     {
         if (new_size == size())

+ 4 - 5
Applications/About/main.cpp

@@ -1,10 +1,9 @@
 #include <LibGUI/GApplication.h>
-#include <LibGUI/GWindow.h>
-#include <LibGUI/GLabel.h>
-#include <LibGUI/GButton.h>
 #include <LibGUI/GBoxLayout.h>
+#include <LibGUI/GButton.h>
 #include <LibGUI/GDesktop.h>
-#include <stdio.h>
+#include <LibGUI/GLabel.h>
+#include <LibGUI/GWindow.h>
 #include <sys/utsname.h>
 
 int main(int argc, char** argv)
@@ -50,7 +49,7 @@ int main(int argc, char** argv)
     quit_button->set_text("Okay");
     quit_button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
     quit_button->set_preferred_size({ 100, 20 });
-    quit_button->on_click = [] (GButton&) {
+    quit_button->on_click = [](GButton&) {
         GApplication::the().quit(0);
     };
 

+ 2 - 2
Applications/Downloader/main.cpp

@@ -1,7 +1,7 @@
-#include <LibGUI/GApplication.h>
 #include <LibCore/CHttpRequest.h>
 #include <LibCore/CHttpResponse.h>
 #include <LibCore/CNetworkJob.h>
+#include <LibGUI/GApplication.h>
 #include <stdio.h>
 
 int main(int argc, char** argv)
@@ -13,7 +13,7 @@ int main(int argc, char** argv)
     request.set_path("/");
 
     auto job = request.schedule();
-    job->on_finish = [&job] (bool success) {
+    job->on_finish = [&job](bool success) {
         if (!success) {
             dbgprintf("on_finish: request failed :(\n");
             return;

+ 13 - 13
Applications/FileManager/DirectoryView.cpp

@@ -1,8 +1,8 @@
 #include "DirectoryView.h"
-#include <LibGUI/GSortingProxyModel.h>
 #include <AK/FileSystemPath.h>
-#include <unistd.h>
+#include <LibGUI/GSortingProxyModel.h>
 #include <stdio.h>
+#include <unistd.h>
 
 void DirectoryView::handle_activation(const GModelIndex& index)
 {
@@ -58,28 +58,28 @@ DirectoryView::DirectoryView(GWidget* parent)
 
     m_item_view->set_model_column(GDirectoryModel::Column::Name);
 
-    m_item_view->on_model_notification = [this] (const GModelNotification& notification) {
+    m_item_view->on_model_notification = [this](const GModelNotification& notification) {
         if (notification.type() == GModelNotification::Type::ModelUpdated) {
             set_status_message(String::format("%d item%s (%u byte%s)",
-                                              model().row_count(),
-                                              model().row_count() != 1 ? "s" : "",
-                                              model().bytes_in_files(),
-                                              model().bytes_in_files() != 1 ? "s" : ""));
+                model().row_count(),
+                model().row_count() != 1 ? "s" : "",
+                model().bytes_in_files(),
+                model().bytes_in_files() != 1 ? "s" : ""));
 
             if (on_path_change)
                 on_path_change(model().path());
         }
     };
 
-    m_model->on_thumbnail_progress = [this] (int done, int total) {
+    m_model->on_thumbnail_progress = [this](int done, int total) {
         if (on_thumbnail_progress)
             on_thumbnail_progress(done, total);
     };
 
-    m_item_view->on_activation = [&] (const GModelIndex& index) {
+    m_item_view->on_activation = [&](const GModelIndex& index) {
         handle_activation(index);
     };
-    m_table_view->on_activation = [&] (auto& index) {
+    m_table_view->on_activation = [&](auto& index) {
         auto& filter_model = (GSortingProxyModel&)*m_table_view->model();
         handle_activation(filter_model.map_to_target(index));
     };
@@ -108,7 +108,7 @@ void DirectoryView::set_view_mode(ViewMode mode)
     ASSERT_NOT_REACHED();
 }
 
-void DirectoryView::add_path_to_history(const String& path)
+void DirectoryView::add_path_to_history(const StringView& path)
 {
     if (m_path_history_position < m_path_history.size())
         m_path_history.resize(m_path_history_position + 1);
@@ -117,13 +117,13 @@ void DirectoryView::add_path_to_history(const String& path)
     m_path_history_position = m_path_history.size() - 1;
 }
 
-void DirectoryView::open(const String& path)
+void DirectoryView::open(const StringView& path)
 {
     add_path_to_history(path);
     model().open(path);
 }
 
-void DirectoryView::set_status_message(const String& message)
+void DirectoryView::set_status_message(const StringView& message)
 {
     if (on_status_message)
         on_status_message(message);

+ 6 - 7
Applications/FileManager/DirectoryView.h

@@ -12,7 +12,7 @@ public:
     explicit DirectoryView(GWidget* parent);
     virtual ~DirectoryView() override;
 
-    void open(const String& path);
+    void open(const StringView& path);
     String path() const { return model().path(); }
     void open_parent_directory();
     void open_previous_directory();
@@ -22,12 +22,11 @@ public:
 
     void refresh();
 
-    Function<void(const String&)> on_path_change;
-    Function<void(String)> on_status_message;
+    Function<void(const StringView&)> on_path_change;
+    Function<void(const StringView&)> on_status_message;
     Function<void(int done, int total)> on_thumbnail_progress;
 
-    enum ViewMode
-    {
+    enum ViewMode {
         Invalid,
         List,
         Icon
@@ -41,14 +40,14 @@ private:
 
     void handle_activation(const GModelIndex&);
 
-    void set_status_message(const String&);
+    void set_status_message(const StringView&);
 
     ViewMode m_view_mode { Invalid };
 
     Retained<GDirectoryModel> m_model;
     int m_path_history_position { 0 };
     Vector<String> m_path_history;
-    void add_path_to_history(const String& path);
+    void add_path_to_history(const StringView& path);
 
     GTableView* m_table_view { nullptr };
     GItemView* m_item_view { nullptr };

+ 34 - 34
Applications/FileManager/main.cpp

@@ -1,25 +1,25 @@
-#include <LibGUI/GWindow.h>
-#include <LibGUI/GWidget.h>
-#include <LibGUI/GBoxLayout.h>
-#include <LibGUI/GApplication.h>
-#include <LibGUI/GStatusBar.h>
-#include <LibGUI/GTextEditor.h>
-#include <LibGUI/GToolBar.h>
-#include <LibGUI/GMenuBar.h>
+#include "DirectoryView.h"
+#include <AK/FileSystemPath.h>
+#include <LibCore/CUserInfo.h>
 #include <LibGUI/GAction.h>
-#include <LibGUI/GLabel.h>
+#include <LibGUI/GApplication.h>
+#include <LibGUI/GBoxLayout.h>
+#include <LibGUI/GFileSystemModel.h>
 #include <LibGUI/GInputBox.h>
+#include <LibGUI/GLabel.h>
+#include <LibGUI/GMenuBar.h>
 #include <LibGUI/GMessageBox.h>
 #include <LibGUI/GProgressBar.h>
-#include <LibGUI/GTreeView.h>
-#include <LibGUI/GFileSystemModel.h>
 #include <LibGUI/GSplitter.h>
-#include <LibCore/CUserInfo.h>
-#include <AK/FileSystemPath.h>
-#include <unistd.h>
+#include <LibGUI/GStatusBar.h>
+#include <LibGUI/GTextEditor.h>
+#include <LibGUI/GToolBar.h>
+#include <LibGUI/GTreeView.h>
+#include <LibGUI/GWidget.h>
+#include <LibGUI/GWindow.h>
 #include <signal.h>
 #include <stdio.h>
-#include "DirectoryView.h"
+#include <unistd.h>
 
 int main(int argc, char** argv)
 {
@@ -76,24 +76,24 @@ int main(int argc, char** argv)
         directory_view->open(location_textbox->text());
     };
 
-    file_system_model->on_selection_changed = [&] (auto& index) {
+    file_system_model->on_selection_changed = [&](auto& index) {
         auto path = file_system_model->path(index);
         if (directory_view->path() == path)
             return;
         directory_view->open(path);
     };
 
-    auto open_parent_directory_action = GAction::create("Open parent directory", { Mod_Alt, Key_Up }, GraphicsBitmap::load_from_file("/res/icons/16x16/open-parent-directory.png"), [directory_view] (const GAction&) {
+    auto open_parent_directory_action = GAction::create("Open parent directory", { Mod_Alt, Key_Up }, GraphicsBitmap::load_from_file("/res/icons/16x16/open-parent-directory.png"), [directory_view](const GAction&) {
         directory_view->open_parent_directory();
     });
 
-    auto mkdir_action = GAction::create("New directory...", GraphicsBitmap::load_from_file("/res/icons/16x16/mkdir.png"), [&] (const GAction&) {
+    auto mkdir_action = GAction::create("New directory...", GraphicsBitmap::load_from_file("/res/icons/16x16/mkdir.png"), [&](const GAction&) {
         GInputBox input_box("Enter name:", "New directory", window);
         if (input_box.exec() == GInputBox::ExecOK && !input_box.text_value().is_empty()) {
             auto new_dir_path = FileSystemPath(String::format("%s/%s",
-                directory_view->path().characters(),
-                input_box.text_value().characters()
-            )).string();
+                                                   directory_view->path().characters(),
+                                                   input_box.text_value().characters()))
+                                    .string();
             int rc = mkdir(new_dir_path.characters(), 0777);
             if (rc < 0) {
                 GMessageBox::show(String::format("mkdir(\"%s\") failed: %s", new_dir_path.characters(), strerror(errno)), "Error", GMessageBox::Type::Error, window);
@@ -106,7 +106,7 @@ int main(int argc, char** argv)
     RetainPtr<GAction> view_as_table_action;
     RetainPtr<GAction> view_as_icons_action;
 
-    view_as_table_action = GAction::create("Table view", { Mod_Ctrl, KeyCode::Key_L }, GraphicsBitmap::load_from_file("/res/icons/16x16/table-view.png"), [&] (const GAction&) {
+    view_as_table_action = GAction::create("Table view", { Mod_Ctrl, KeyCode::Key_L }, GraphicsBitmap::load_from_file("/res/icons/16x16/table-view.png"), [&](const GAction&) {
         directory_view->set_view_mode(DirectoryView::ViewMode::List);
         view_as_icons_action->set_checked(false);
         view_as_table_action->set_checked(true);
@@ -114,7 +114,7 @@ int main(int argc, char** argv)
     view_as_table_action->set_checkable(true);
     view_as_table_action->set_checked(false);
 
-    view_as_icons_action = GAction::create("Icon view", { Mod_Ctrl, KeyCode::Key_I }, GraphicsBitmap::load_from_file("/res/icons/16x16/icon-view.png"), [&] (const GAction&) {
+    view_as_icons_action = GAction::create("Icon view", { Mod_Ctrl, KeyCode::Key_I }, GraphicsBitmap::load_from_file("/res/icons/16x16/icon-view.png"), [&](const GAction&) {
         directory_view->set_view_mode(DirectoryView::ViewMode::Icon);
         view_as_table_action->set_checked(false);
         view_as_icons_action->set_checked(true);
@@ -122,20 +122,20 @@ int main(int argc, char** argv)
     view_as_icons_action->set_checkable(true);
     view_as_icons_action->set_checked(true);
 
-    auto copy_action = GAction::create("Copy", GraphicsBitmap::load_from_file("/res/icons/16x16/edit-copy.png"), [] (const GAction&) {
+    auto copy_action = GAction::create("Copy", GraphicsBitmap::load_from_file("/res/icons/16x16/edit-copy.png"), [](const GAction&) {
         dbgprintf("'Copy' action activated!\n");
     });
 
-    auto delete_action = GAction::create("Delete", GraphicsBitmap::load_from_file("/res/icons/16x16/delete.png"), [] (const GAction&) {
+    auto delete_action = GAction::create("Delete", GraphicsBitmap::load_from_file("/res/icons/16x16/delete.png"), [](const GAction&) {
         dbgprintf("'Delete' action activated!\n");
     });
 
-    auto go_back_action = GAction::create("Go Back", GraphicsBitmap::load_from_file("/res/icons/16x16/go-back.png"), [directory_view] (const GAction&) {
+    auto go_back_action = GAction::create("Go Back", GraphicsBitmap::load_from_file("/res/icons/16x16/go-back.png"), [directory_view](const GAction&) {
         dbgprintf("'Go Back' action activated!\n");
         directory_view->open_previous_directory();
     });
 
-    auto go_forward_action = GAction::create("Go Forward", GraphicsBitmap::load_from_file("/res/icons/16x16/go-forward.png"), [directory_view] (const GAction&) {
+    auto go_forward_action = GAction::create("Go Forward", GraphicsBitmap::load_from_file("/res/icons/16x16/go-forward.png"), [directory_view](const GAction&) {
         dbgprintf("'Go Forward' action activated!\n");
         directory_view->open_next_directory();
     });
@@ -143,7 +143,7 @@ int main(int argc, char** argv)
     auto menubar = make<GMenuBar>();
 
     auto app_menu = make<GMenu>("File Manager");
-    app_menu->add_action(GAction::create("Quit", { Mod_Alt, Key_F4 }, [] (const GAction&) {
+    app_menu->add_action(GAction::create("Quit", { Mod_Alt, Key_F4 }, [](const GAction&) {
         GApplication::the().quit(0);
         return;
     }));
@@ -167,7 +167,7 @@ int main(int argc, char** argv)
     menubar->add_menu(move(go_menu));
 
     auto help_menu = make<GMenu>("Help");
-    help_menu->add_action(GAction::create("About", [] (const GAction&) {
+    help_menu->add_action(GAction::create("About", [](const GAction&) {
         dbgprintf("FIXME: Implement Help/About\n");
     }));
     menubar->add_menu(move(help_menu));
@@ -187,7 +187,7 @@ int main(int argc, char** argv)
     main_toolbar->add_action(*view_as_icons_action);
     main_toolbar->add_action(*view_as_table_action);
 
-    directory_view->on_path_change = [window, location_textbox, &file_system_model, tree_view, &go_forward_action, &go_back_action, directory_view] (const String& new_path) {
+    directory_view->on_path_change = [window, location_textbox, &file_system_model, tree_view, &go_forward_action, &go_back_action, directory_view](const String& new_path) {
         window->set_title(String::format("File Manager: %s", new_path.characters()));
         location_textbox->set_text(new_path);
         file_system_model->set_selected_index(file_system_model->index(new_path));
@@ -195,15 +195,15 @@ int main(int argc, char** argv)
         tree_view->update();
 
         go_forward_action->set_enabled(directory_view->path_history_position()
-                                       < directory_view->path_history_size() - 1);
+            < directory_view->path_history_size() - 1);
         go_back_action->set_enabled(directory_view->path_history_position() > 0);
     };
 
-    directory_view->on_status_message = [statusbar] (String message) {
-        statusbar->set_text(move(message));
+    directory_view->on_status_message = [statusbar](const StringView& message) {
+        statusbar->set_text(message);
     };
 
-    directory_view->on_thumbnail_progress = [&] (int done, int total) {
+    directory_view->on_thumbnail_progress = [&](int done, int total) {
         if (done == total) {
             progressbar->set_visible(false);
             return;

+ 11 - 11
Applications/FontEditor/FontEditor.cpp

@@ -1,13 +1,13 @@
 #include "FontEditor.h"
-#include "GlyphMapWidget.h"
 #include "GlyphEditorWidget.h"
-#include <LibGUI/GPainter.h>
+#include "GlyphMapWidget.h"
 #include <LibGUI/GButton.h>
-#include <LibGUI/GLabel.h>
-#include <LibGUI/GTextBox.h>
 #include <LibGUI/GCheckBox.h>
-#include <LibGUI/GSpinBox.h>
 #include <LibGUI/GGroupBox.h>
+#include <LibGUI/GLabel.h>
+#include <LibGUI/GPainter.h>
+#include <LibGUI/GSpinBox.h>
+#include <LibGUI/GTextBox.h>
 #include <stdlib.h>
 
 FontEditorWidget::FontEditorWidget(const String& path, RetainPtr<Font>&& edited_font, GWidget* parent)
@@ -52,7 +52,7 @@ FontEditorWidget::FontEditorWidget(const String& path, RetainPtr<Font>&& edited_
     auto* save_button = new GButton(this);
     save_button->set_text("Save");
     save_button->set_relative_rect({ 5, 300, 105, 20 });
-    save_button->on_click = [this] (GButton&) {
+    save_button->on_click = [this](GButton&) {
         dbgprintf("write to file: '%s'\n", m_path.characters());
         m_edited_font->write_to_file(m_path);
     };
@@ -60,7 +60,7 @@ FontEditorWidget::FontEditorWidget(const String& path, RetainPtr<Font>&& edited_
     auto* quit_button = new GButton(this);
     quit_button->set_text("Quit");
     quit_button->set_relative_rect({ 110, 300, 105, 20 });
-    quit_button->on_click = [] (GButton&) {
+    quit_button->on_click = [](GButton&) {
         exit(0);
     };
 
@@ -91,25 +91,25 @@ FontEditorWidget::FontEditorWidget(const String& path, RetainPtr<Font>&& edited_
         demo_label_2->update();
     };
 
-    m_glyph_editor_widget->on_glyph_altered = [this, update_demo] (byte glyph) {
+    m_glyph_editor_widget->on_glyph_altered = [this, update_demo](byte glyph) {
         m_glyph_map_widget->update_glyph(glyph);
         update_demo();
     };
 
-    m_glyph_map_widget->on_glyph_selected = [this, info_label, width_spinbox] (byte glyph) {
+    m_glyph_map_widget->on_glyph_selected = [this, info_label, width_spinbox](byte glyph) {
         m_glyph_editor_widget->set_glyph(glyph);
         width_spinbox->set_value(m_edited_font->glyph_width(m_glyph_map_widget->selected_glyph()));
         info_label->set_text(String::format("0x%b (%c)", glyph, glyph));
     };
 
-    fixed_width_checkbox->on_checked = [this, width_spinbox, update_demo] (bool checked) {
+    fixed_width_checkbox->on_checked = [this, width_spinbox, update_demo](bool checked) {
         m_edited_font->set_fixed_width(checked);
         width_spinbox->set_value(m_edited_font->glyph_width(m_glyph_map_widget->selected_glyph()));
         m_glyph_editor_widget->update();
         update_demo();
     };
 
-    width_spinbox->on_change = [this, update_demo] (int value) {
+    width_spinbox->on_change = [this, update_demo](int value) {
         m_edited_font->set_glyph_width(m_glyph_map_widget->selected_glyph(), value);
         m_glyph_editor_widget->update();
         m_glyph_map_widget->update_glyph(m_glyph_map_widget->selected_glyph());

+ 3 - 3
Applications/FontEditor/GlyphMapWidget.cpp

@@ -44,7 +44,8 @@ Rect GlyphMapWidget::get_outer_rect(byte glyph) const
         row * (font().glyph_height() + m_vertical_spacing) + 1,
         font().max_glyph_width() + m_horizontal_spacing,
         font().glyph_height() + m_horizontal_spacing
-    }.translated(frame_thickness(), frame_thickness());
+    }
+        .translated(frame_thickness(), frame_thickness());
 }
 
 void GlyphMapWidget::update_glyph(byte glyph)
@@ -71,8 +72,7 @@ void GlyphMapWidget::paint_event(GPaintEvent& event)
                 outer_rect.x() + m_horizontal_spacing / 2,
                 outer_rect.y() + m_vertical_spacing / 2,
                 font().max_glyph_width(),
-                font().glyph_height()
-            );
+                font().glyph_height());
             if (glyph == m_selected_glyph) {
                 painter.fill_rect(outer_rect, Color::from_rgb(0x84351a));
                 painter.draw_glyph(inner_rect.location(), glyph, Color::White);

+ 16 - 16
Applications/IRCClient/IRCAppWindow.cpp

@@ -1,16 +1,16 @@
 #include "IRCAppWindow.h"
 #include "IRCWindow.h"
 #include "IRCWindowListModel.h"
+#include <LibGUI/GAction.h>
 #include <LibGUI/GApplication.h>
-#include <LibGUI/GStackWidget.h>
-#include <LibGUI/GTableView.h>
 #include <LibGUI/GBoxLayout.h>
-#include <LibGUI/GToolBar.h>
-#include <LibGUI/GAction.h>
+#include <LibGUI/GInputBox.h>
 #include <LibGUI/GMenu.h>
 #include <LibGUI/GMenuBar.h>
-#include <LibGUI/GInputBox.h>
 #include <LibGUI/GSplitter.h>
+#include <LibGUI/GStackWidget.h>
+#include <LibGUI/GTableView.h>
+#include <LibGUI/GToolBar.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -36,7 +36,7 @@ void IRCAppWindow::update_title()
 
 void IRCAppWindow::setup_client()
 {
-    m_client.aid_create_window = [this] (void* owner, IRCWindow::Type type, const String& name) {
+    m_client.aid_create_window = [this](void* owner, IRCWindow::Type type, const String& name) {
         return &create_window(owner, type, name);
     };
     m_client.aid_get_active_window = [this] {
@@ -45,7 +45,7 @@ void IRCAppWindow::setup_client()
     m_client.aid_update_window_list = [this] {
         m_window_list->model()->update();
     };
-    m_client.on_nickname_changed = [this] (const String&) {
+    m_client.on_nickname_changed = [this](const String&) {
         update_title();
     };
 
@@ -64,33 +64,33 @@ void IRCAppWindow::setup_client()
 
 void IRCAppWindow::setup_actions()
 {
-    m_join_action = GAction::create("Join channel", GraphicsBitmap::load_from_file("/res/icons/16x16/irc-join.png"), [&] (auto&) {
+    m_join_action = GAction::create("Join channel", GraphicsBitmap::load_from_file("/res/icons/16x16/irc-join.png"), [&](auto&) {
         GInputBox input_box("Enter channel name:", "Join channel", this);
         if (input_box.exec() == GInputBox::ExecOK && !input_box.text_value().is_empty())
             m_client.handle_join_action(input_box.text_value());
     });
 
-    m_part_action = GAction::create("Part from channel", GraphicsBitmap::load_from_file("/res/icons/16x16/irc-part.png"), [] (auto&) {
+    m_part_action = GAction::create("Part from channel", GraphicsBitmap::load_from_file("/res/icons/16x16/irc-part.png"), [](auto&) {
         printf("FIXME: Implement part action\n");
     });
 
-    m_whois_action = GAction::create("Whois user", GraphicsBitmap::load_from_file("/res/icons/16x16/irc-whois.png"), [&] (auto&) {
+    m_whois_action = GAction::create("Whois user", GraphicsBitmap::load_from_file("/res/icons/16x16/irc-whois.png"), [&](auto&) {
         GInputBox input_box("Enter nickname:", "IRC WHOIS lookup", this);
         if (input_box.exec() == GInputBox::ExecOK && !input_box.text_value().is_empty())
             m_client.handle_whois_action(input_box.text_value());
     });
 
-    m_open_query_action = GAction::create("Open query", GraphicsBitmap::load_from_file("/res/icons/16x16/irc-open-query.png"), [&] (auto&) {
+    m_open_query_action = GAction::create("Open query", GraphicsBitmap::load_from_file("/res/icons/16x16/irc-open-query.png"), [&](auto&) {
         GInputBox input_box("Enter nickname:", "Open IRC query with...", this);
         if (input_box.exec() == GInputBox::ExecOK && !input_box.text_value().is_empty())
             m_client.handle_open_query_action(input_box.text_value());
     });
 
-    m_close_query_action = GAction::create("Close query", GraphicsBitmap::load_from_file("/res/icons/16x16/irc-close-query.png"), [] (auto&) {
+    m_close_query_action = GAction::create("Close query", GraphicsBitmap::load_from_file("/res/icons/16x16/irc-close-query.png"), [](auto&) {
         printf("FIXME: Implement close-query action\n");
     });
 
-    m_change_nick_action = GAction::create("Change nickname", GraphicsBitmap::load_from_file("/res/icons/16x16/irc-nick.png"), [this] (auto&) {
+    m_change_nick_action = GAction::create("Change nickname", GraphicsBitmap::load_from_file("/res/icons/16x16/irc-nick.png"), [this](auto&) {
         GInputBox input_box("Enter nickname:", "Change nickname", this);
         if (input_box.exec() == GInputBox::ExecOK && !input_box.text_value().is_empty())
             m_client.handle_change_nick_action(input_box.text_value());
@@ -101,7 +101,7 @@ void IRCAppWindow::setup_menus()
 {
     auto menubar = make<GMenuBar>();
     auto app_menu = make<GMenu>("IRC Client");
-    app_menu->add_action(GAction::create("Quit", { Mod_Alt, Key_F4 }, [] (const GAction&) {
+    app_menu->add_action(GAction::create("Quit", { Mod_Alt, Key_F4 }, [](const GAction&) {
         dbgprintf("Terminal: Quit menu activated!\n");
         GApplication::the().quit(0);
         return;
@@ -120,7 +120,7 @@ void IRCAppWindow::setup_menus()
     menubar->add_menu(move(server_menu));
 
     auto help_menu = make<GMenu>("Help");
-    help_menu->add_action(GAction::create("About", [] (const GAction&) {
+    help_menu->add_action(GAction::create("About", [](const GAction&) {
         dbgprintf("FIXME: Implement Help/About\n");
     }));
     menubar->add_menu(move(help_menu));
@@ -156,7 +156,7 @@ void IRCAppWindow::setup_widgets()
     m_window_list->set_activates_on_selection(true);
     m_window_list->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
     m_window_list->set_preferred_size({ 100, 0 });
-    m_window_list->on_activation = [this] (auto& index) {
+    m_window_list->on_activation = [this](auto& index) {
         auto& window = m_client.window_at(index.row());
         m_container->set_active_widget(&window);
         window.clear_unread_count();

+ 2 - 2
Applications/IRCClient/IRCChannel.cpp

@@ -1,6 +1,6 @@
 #include "IRCChannel.h"
-#include "IRCClient.h"
 #include "IRCChannelMemberListModel.h"
+#include "IRCClient.h"
 #include <stdio.h>
 #include <time.h>
 
@@ -37,7 +37,7 @@ void IRCChannel::add_member(const String& name, char prefix)
 
 void IRCChannel::remove_member(const String& name)
 {
-    m_members.remove_first_matching([&] (auto& member) { return name == member.name; });
+    m_members.remove_first_matching([&](auto& member) { return name == member.name; });
 }
 
 void IRCChannel::add_message(char prefix, const String& name, const String& text, Color color)

+ 7 - 4
Applications/IRCClient/IRCChannelMemberListModel.cpp

@@ -25,7 +25,8 @@ int IRCChannelMemberListModel::column_count(const GModelIndex&) const
 String IRCChannelMemberListModel::column_name(int column) const
 {
     switch (column) {
-    case Column::Name: return "Name";
+    case Column::Name:
+        return "Name";
     }
     ASSERT_NOT_REACHED();
 }
@@ -33,7 +34,8 @@ String IRCChannelMemberListModel::column_name(int column) const
 GModel::ColumnMetadata IRCChannelMemberListModel::column_metadata(int column) const
 {
     switch (column) {
-    case Column::Name: return { 70, TextAlignment::CenterLeft };
+    case Column::Name:
+        return { 70, TextAlignment::CenterLeft };
     }
     ASSERT_NOT_REACHED();
 }
@@ -42,10 +44,11 @@ GVariant IRCChannelMemberListModel::data(const GModelIndex& index, Role role) co
 {
     if (role == Role::Display) {
         switch (index.column()) {
-        case Column::Name: return m_channel.member_at(index.row());
+        case Column::Name:
+            return m_channel.member_at(index.row());
         }
     }
-    return { };
+    return {};
 }
 
 void IRCChannelMemberListModel::update()

+ 1 - 2
Applications/IRCClient/IRCChannelMemberListModel.h

@@ -7,8 +7,7 @@ class IRCChannel;
 
 class IRCChannelMemberListModel final : public GModel {
 public:
-    enum Column
-    {
+    enum Column {
         Name
     };
     static Retained<IRCChannelMemberListModel> create(IRCChannel& channel) { return adopt(*new IRCChannelMemberListModel(channel)); }

+ 31 - 23
Applications/IRCClient/IRCClient.cpp

@@ -1,16 +1,16 @@
 #include "IRCClient.h"
 #include "IRCChannel.h"
-#include "IRCQuery.h"
 #include "IRCLogBuffer.h"
+#include "IRCQuery.h"
 #include "IRCWindow.h"
 #include "IRCWindowListModel.h"
 #include <LibCore/CNotifier.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
 #include <arpa/inet.h>
-#include <unistd.h>
+#include <netinet/in.h>
 #include <stdio.h>
+#include <sys/socket.h>
 #include <time.h>
+#include <unistd.h>
 
 #define IRC_DEBUG
 
@@ -43,7 +43,7 @@ IRCClient::~IRCClient()
 {
 }
 
-void IRCClient::set_server(const String &hostname, int port)
+void IRCClient::set_server(const String& hostname, int port)
 {
     m_hostname = hostname;
     m_port = port;
@@ -112,7 +112,8 @@ void IRCClient::process_line(ByteBuffer&& line)
         InStartOfParameter,
         InParameter,
         InTrailingParameter,
-    } state = Start;
+    } state
+        = Start;
 
     for (int i = 0; i < line.size(); ++i) {
         char ch = line[i];
@@ -216,8 +217,7 @@ void IRCClient::handle(const Message& msg)
     printf("IRCClient::execute: prefix='%s', command='%s', arguments=%d\n",
         msg.prefix.characters(),
         msg.command.characters(),
-        msg.arguments.size()
-    );
+        msg.arguments.size());
 
     int i = 0;
     for (auto& arg : msg.arguments) {
@@ -231,16 +231,26 @@ void IRCClient::handle(const Message& msg)
 
     if (is_numeric) {
         switch (numeric) {
-        case RPL_WHOISCHANNELS: return handle_rpl_whoischannels(msg);
-        case RPL_ENDOFWHOIS: return handle_rpl_endofwhois(msg);
-        case RPL_WHOISOPERATOR: return handle_rpl_whoisoperator(msg);
-        case RPL_WHOISSERVER: return handle_rpl_whoisserver(msg);
-        case RPL_WHOISUSER: return handle_rpl_whoisuser(msg);
-        case RPL_WHOISIDLE: return handle_rpl_whoisidle(msg);
-        case RPL_TOPICWHOTIME: return handle_rpl_topicwhotime(msg);
-        case RPL_TOPIC: return handle_rpl_topic(msg);
-        case RPL_NAMREPLY: return handle_rpl_namreply(msg);
-        case RPL_ENDOFNAMES: return handle_rpl_endofnames(msg);
+        case RPL_WHOISCHANNELS:
+            return handle_rpl_whoischannels(msg);
+        case RPL_ENDOFWHOIS:
+            return handle_rpl_endofwhois(msg);
+        case RPL_WHOISOPERATOR:
+            return handle_rpl_whoisoperator(msg);
+        case RPL_WHOISSERVER:
+            return handle_rpl_whoisserver(msg);
+        case RPL_WHOISUSER:
+            return handle_rpl_whoisuser(msg);
+        case RPL_WHOISIDLE:
+            return handle_rpl_whoisidle(msg);
+        case RPL_TOPICWHOTIME:
+            return handle_rpl_topicwhotime(msg);
+        case RPL_TOPIC:
+            return handle_rpl_topic(msg);
+        case RPL_NAMREPLY:
+            return handle_rpl_namreply(msg);
+        case RPL_ENDOFNAMES:
+            return handle_rpl_endofnames(msg);
         }
     }
 
@@ -441,7 +451,7 @@ void IRCClient::handle_rpl_topic(const Message& msg)
         return;
     auto& channel_name = msg.arguments[1];
     auto& topic = msg.arguments[2];
-    ensure_channel(channel_name).handle_topic({ }, topic);
+    ensure_channel(channel_name).handle_topic({}, topic);
     // FIXME: Handle RPL_TOPICWHOTIME so we can know who set it and when.
 }
 
@@ -502,8 +512,7 @@ void IRCClient::handle_rpl_whoisuser(const Message& msg)
         nick.characters(),
         username.characters(),
         host.characters(),
-        realname.characters()
-    ));
+        realname.characters()));
 }
 
 void IRCClient::handle_rpl_whoisidle(const Message& msg)
@@ -541,8 +550,7 @@ void IRCClient::handle_rpl_topicwhotime(const Message& msg)
             tm->tm_mday,
             tm->tm_hour,
             tm->tm_min,
-            tm->tm_sec
-        );
+            tm->tm_sec);
     }
     ensure_channel(channel_name).add_message(String::format("*** (set by %s at %s)", nick.characters(), setat.characters()), Color::Blue);
 }

+ 16 - 9
Applications/IRCClient/IRCLogBufferModel.cpp

@@ -1,8 +1,8 @@
 #include "IRCLogBufferModel.h"
 #include "IRCLogBuffer.h"
+#include <SharedGraphics/Font.h>
 #include <stdio.h>
 #include <time.h>
-#include <SharedGraphics/Font.h>
 
 IRCLogBufferModel::IRCLogBufferModel(Retained<IRCLogBuffer>&& log_buffer)
     : m_log_buffer(move(log_buffer))
@@ -26,9 +26,12 @@ int IRCLogBufferModel::column_count(const GModelIndex&) const
 String IRCLogBufferModel::column_name(int column) const
 {
     switch (column) {
-    case Column::Timestamp: return "Time";
-    case Column::Name: return "Name";
-    case Column::Text: return "Text";
+    case Column::Timestamp:
+        return "Time";
+    case Column::Name:
+        return "Name";
+    case Column::Text:
+        return "Text";
     }
     ASSERT_NOT_REACHED();
 }
@@ -36,9 +39,12 @@ String IRCLogBufferModel::column_name(int column) const
 GModel::ColumnMetadata IRCLogBufferModel::column_metadata(int column) const
 {
     switch (column) {
-    case Column::Timestamp: return { 60, TextAlignment::CenterLeft };
-    case Column::Name: return { 70, TextAlignment::CenterRight, &Font::default_bold_font() };
-    case Column::Text: return { 800, TextAlignment::CenterLeft };
+    case Column::Timestamp:
+        return { 60, TextAlignment::CenterLeft };
+    case Column::Name:
+        return { 70, TextAlignment::CenterRight, &Font::default_bold_font() };
+    case Column::Text:
+        return { 800, TextAlignment::CenterLeft };
     }
     ASSERT_NOT_REACHED();
 }
@@ -56,7 +62,8 @@ GVariant IRCLogBufferModel::data(const GModelIndex& index, Role role) const
             if (entry.sender.is_empty())
                 return String::empty();
             return String::format("<%c%s>", entry.prefix ? entry.prefix : ' ', entry.sender.characters());
-        case Column::Text: return entry.text;
+        case Column::Text:
+            return entry.text;
         }
     }
     if (role == Role::ForegroundColor) {
@@ -65,7 +72,7 @@ GVariant IRCLogBufferModel::data(const GModelIndex& index, Role role) const
         if (index.column() == Column::Text)
             return m_log_buffer->at(index.row()).color;
     }
-    return { };
+    return {};
 }
 
 void IRCLogBufferModel::update()

+ 1 - 2
Applications/IRCClient/IRCLogBufferModel.h

@@ -6,8 +6,7 @@ class IRCLogBuffer;
 
 class IRCLogBufferModel final : public GModel {
 public:
-    enum Column
-    {
+    enum Column {
         Timestamp = 0,
         Name,
         Text,

+ 3 - 3
Applications/IRCClient/IRCWindow.cpp

@@ -1,13 +1,13 @@
 #include "IRCWindow.h"
-#include "IRCClient.h"
 #include "IRCChannel.h"
 #include "IRCChannelMemberListModel.h"
+#include "IRCClient.h"
 #include "IRCLogBufferModel.h"
 #include <LibGUI/GBoxLayout.h>
+#include <LibGUI/GSplitter.h>
 #include <LibGUI/GTableView.h>
-#include <LibGUI/GTextEditor.h>
 #include <LibGUI/GTextBox.h>
-#include <LibGUI/GSplitter.h>
+#include <LibGUI/GTextEditor.h>
 
 IRCWindow::IRCWindow(IRCClient& client, void* owner, Type type, const String& name, GWidget* parent)
     : GWidget(parent)

+ 1 - 2
Applications/IRCClient/IRCWindow.h

@@ -11,8 +11,7 @@ class GTextEditor;
 
 class IRCWindow : public GWidget {
 public:
-    enum Type
-    {
+    enum Type {
         Server,
         Channel,
         Query,

+ 7 - 5
Applications/IRCClient/IRCWindowListModel.cpp

@@ -1,7 +1,7 @@
 #include "IRCWindowListModel.h"
-#include "IRCWindow.h"
-#include "IRCClient.h"
 #include "IRCChannel.h"
+#include "IRCClient.h"
+#include "IRCWindow.h"
 #include <stdio.h>
 #include <time.h>
 
@@ -27,7 +27,8 @@ int IRCWindowListModel::column_count(const GModelIndex&) const
 String IRCWindowListModel::column_name(int column) const
 {
     switch (column) {
-    case Column::Name: return "Name";
+    case Column::Name:
+        return "Name";
     }
     ASSERT_NOT_REACHED();
 }
@@ -35,7 +36,8 @@ String IRCWindowListModel::column_name(int column) const
 GModel::ColumnMetadata IRCWindowListModel::column_metadata(int column) const
 {
     switch (column) {
-    case Column::Name: return { 70, TextAlignment::CenterLeft };
+    case Column::Name:
+        return { 70, TextAlignment::CenterLeft };
     }
     ASSERT_NOT_REACHED();
 }
@@ -64,7 +66,7 @@ GVariant IRCWindowListModel::data(const GModelIndex& index, Role role) const
         }
         }
     }
-    return { };
+    return {};
 }
 
 void IRCWindowListModel::update()

+ 1 - 2
Applications/IRCClient/IRCWindowListModel.h

@@ -8,8 +8,7 @@ class IRCWindow;
 
 class IRCWindowListModel final : public GModel {
 public:
-    enum Column
-    {
+    enum Column {
         Name,
     };
 

+ 1 - 1
Applications/IRCClient/main.cpp

@@ -1,6 +1,6 @@
+#include "IRCAppWindow.h"
 #include "IRCClient.h"
 #include <LibGUI/GApplication.h>
-#include "IRCAppWindow.h"
 #include <stdio.h>
 
 int main(int argc, char** argv)

+ 15 - 14
Applications/Launcher/main.cpp

@@ -1,16 +1,16 @@
-#include <SharedGraphics/GraphicsBitmap.h>
-#include <LibGUI/GWindow.h>
-#include <LibGUI/GWidget.h>
-#include <LibGUI/GButton.h>
+#include <LibCore/CConfigFile.h>
+#include <LibCore/CUserInfo.h>
 #include <LibGUI/GApplication.h>
 #include <LibGUI/GBoxLayout.h>
-#include <LibCore/CConfigFile.h>
-#include <sys/wait.h>
+#include <LibGUI/GButton.h>
+#include <LibGUI/GWidget.h>
+#include <LibGUI/GWindow.h>
+#include <SharedGraphics/GraphicsBitmap.h>
+#include <errno.h>
 #include <signal.h>
-#include <unistd.h>
 #include <stdio.h>
-#include <errno.h>
-#include <LibCore/CUserInfo.h>
+#include <sys/wait.h>
+#include <unistd.h>
 
 static GWindow* make_launcher_window();
 
@@ -47,7 +47,7 @@ public:
         set_icon(GraphicsBitmap::load_from_file(icon_path));
         set_preferred_size({ 50, 50 });
         set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
-        on_click = [this] (GButton&) {
+        on_click = [this](GButton&) {
             pid_t child_pid = fork();
             if (!child_pid) {
                 int rc = execl(m_executable_path.characters(), m_executable_path.characters(), nullptr);
@@ -55,7 +55,8 @@ public:
                     perror("execl");
             }
         };
-    } virtual ~LauncherButton() { }
+    }
+    virtual ~LauncherButton() {}
 
 private:
     String m_executable_path;
@@ -78,9 +79,9 @@ GWindow* make_launcher_window()
 
     for (auto& group : config->groups()) {
         new LauncherButton(config->read_entry(group, "Name", group),
-                           config->read_entry(group, "Icon", ""),
-                           config->read_entry(group, "Path", ""),
-                           widget);
+            config->read_entry(group, "Icon", ""),
+            config->read_entry(group, "Path", ""),
+            widget);
     }
 
     return window;

+ 3 - 0
Applications/PaintBrush/.gitignore

@@ -0,0 +1,3 @@
+*.o
+*.d
+PaintBrush

+ 55 - 0
Applications/PaintBrush/BucketTool.cpp

@@ -0,0 +1,55 @@
+#include "BucketTool.h"
+#include "PaintableWidget.h"
+#include <AK/Queue.h>
+#include <AK/SinglyLinkedList.h>
+#include <LibGUI/GPainter.h>
+#include <SharedGraphics/GraphicsBitmap.h>
+#include <stdio.h>
+
+BucketTool::BucketTool()
+{
+}
+
+BucketTool::~BucketTool()
+{
+}
+
+static void flood_fill(GraphicsBitmap& bitmap, const Point& start_position, Color target_color, Color fill_color)
+{
+    ASSERT(bitmap.format() == GraphicsBitmap::Format::RGB32);
+
+    Queue<Point> queue;
+    queue.enqueue(Point(start_position));
+    while (!queue.is_empty()) {
+        auto position = queue.dequeue();
+
+        if (bitmap.get_pixel<GraphicsBitmap::Format::RGB32>(position.x(), position.y()) != target_color)
+            continue;
+        bitmap.set_pixel<GraphicsBitmap::Format::RGB32>(position.x(), position.y(), fill_color);
+
+        if (position.x() != 0)
+            queue.enqueue(position.translated(-1, 0));
+
+        if (position.x() != bitmap.width() - 1)
+            queue.enqueue(position.translated(1, 0));
+
+        if (position.y() != 0)
+            queue.enqueue(position.translated(0, -1));
+
+        if (position.y() != bitmap.height() - 1)
+            queue.enqueue(position.translated(0, 1));
+    }
+}
+
+void BucketTool::on_mousedown(PaintableWidget& paintable_widget, GMouseEvent& event)
+{
+    if (!paintable_widget.rect().contains(event.position()))
+        return;
+
+    GPainter painter(paintable_widget.bitmap());
+    auto target_color = paintable_widget.bitmap().get_pixel(event.x(), event.y());
+
+    flood_fill(paintable_widget.bitmap(), event.position(), target_color, paintable_widget.color_for(event));
+
+    paintable_widget.update();
+}

+ 14 - 0
Applications/PaintBrush/BucketTool.h

@@ -0,0 +1,14 @@
+#pragma once
+
+#include "Tool.h"
+
+class BucketTool final : public Tool {
+public:
+    BucketTool();
+    virtual ~BucketTool() override;
+
+    virtual void on_mousedown(PaintableWidget&, GMouseEvent&) override;
+
+private:
+    virtual const char* class_name() const override { return "BucketTool"; }
+};

+ 28 - 0
Applications/PaintBrush/Makefile

@@ -0,0 +1,28 @@
+include ../../Makefile.common
+
+OBJS = \
+    PaintableWidget.o \
+    PaletteWidget.o \
+    ToolboxWidget.o \
+    Tool.o \
+    PenTool.o \
+    BucketTool.o \
+    main.o
+
+APP = PaintBrush
+
+DEFINES += -DUSERLAND
+
+all: $(APP)
+
+$(APP): $(OBJS)
+	$(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lgui -lcore -lc
+
+.cpp.o:
+	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
+
+-include $(OBJS:%.o=%.d)
+
+clean:
+	@echo "CLEAN"; rm -f $(APP) $(OBJS) *.d
+

+ 60 - 0
Applications/PaintBrush/PaintableWidget.cpp

@@ -0,0 +1,60 @@
+#include "PaintableWidget.h"
+#include "Tool.h"
+#include <LibGUI/GPainter.h>
+#include <SharedGraphics/GraphicsBitmap.h>
+
+static PaintableWidget* s_the;
+
+PaintableWidget& PaintableWidget::the()
+{
+    return *s_the;
+}
+
+PaintableWidget::PaintableWidget(GWidget* parent)
+    : GWidget(parent)
+{
+    ASSERT(!s_the);
+    s_the = this;
+    set_fill_with_background_color(true);
+    set_background_color(Color::MidGray);
+    m_bitmap = GraphicsBitmap::create(GraphicsBitmap::Format::RGB32, { 600, 400 });
+    m_bitmap->fill(Color::White);
+}
+
+PaintableWidget::~PaintableWidget()
+{
+}
+
+void PaintableWidget::paint_event(GPaintEvent& event)
+{
+    GPainter painter(*this);
+    painter.add_clip_rect(event.rect());
+    painter.blit({ 0, 0 }, *m_bitmap, m_bitmap->rect());
+}
+
+Color PaintableWidget::color_for(const GMouseEvent& event)
+{
+    if (event.buttons() & GMouseButton::Left)
+        return m_primary_color;
+    if (event.buttons() & GMouseButton::Right)
+        return m_secondary_color;
+    ASSERT_NOT_REACHED();
+}
+
+void PaintableWidget::mousedown_event(GMouseEvent& event)
+{
+    if (m_tool)
+        m_tool->on_mousedown(*this, event);
+}
+
+void PaintableWidget::mouseup_event(GMouseEvent& event)
+{
+    if (m_tool)
+        m_tool->on_mouseup(*this, event);
+}
+
+void PaintableWidget::mousemove_event(GMouseEvent& event)
+{
+    if (m_tool)
+        m_tool->on_mousemove(*this, event);
+}

+ 42 - 0
Applications/PaintBrush/PaintableWidget.h

@@ -0,0 +1,42 @@
+#pragma once
+
+#include <LibGUI/GWidget.h>
+
+class Tool;
+
+class PaintableWidget final : public GWidget {
+public:
+    static PaintableWidget& the();
+
+    explicit PaintableWidget(GWidget* parent);
+    virtual ~PaintableWidget() override;
+
+    virtual const char* class_name() const override { return "PaintableWidget"; }
+
+    Color primary_color() const { return m_primary_color; }
+    Color secondary_color() const { return m_secondary_color; }
+
+    void set_primary_color(Color color) { m_primary_color = color; }
+    void set_secondary_color(Color color) { m_secondary_color = color; }
+
+    void set_tool(Tool* tool) { m_tool = tool; }
+    Tool* tool() { return m_tool; }
+
+    Color color_for(const GMouseEvent&);
+
+    GraphicsBitmap& bitmap() { return *m_bitmap; }
+    const GraphicsBitmap& bitmap() const { return *m_bitmap; }
+
+private:
+    virtual void paint_event(GPaintEvent&) override;
+    virtual void mousedown_event(GMouseEvent&) override;
+    virtual void mouseup_event(GMouseEvent&) override;
+    virtual void mousemove_event(GMouseEvent&) override;
+
+    RetainPtr<GraphicsBitmap> m_bitmap;
+
+    Color m_primary_color { Color::Black };
+    Color m_secondary_color { Color::White };
+
+    Tool* m_tool { nullptr };
+};

+ 131 - 0
Applications/PaintBrush/PaletteWidget.cpp

@@ -0,0 +1,131 @@
+#include "PaletteWidget.h"
+#include "PaintableWidget.h"
+#include <LibGUI/GBoxLayout.h>
+
+class ColorWidget : public GFrame {
+public:
+    explicit ColorWidget(Color color, PaletteWidget& palette_widget, GWidget* parent)
+        : GFrame(parent)
+        , m_palette_widget(palette_widget)
+        , m_color(color)
+    {
+        set_frame_thickness(2);
+        set_frame_shadow(FrameShadow::Sunken);
+        set_frame_shape(FrameShape::Container);
+    }
+
+    virtual ~ColorWidget() override
+    {
+    }
+
+    virtual void mousedown_event(GMouseEvent& event) override
+    {
+        if (event.button() == GMouseButton::Left)
+            m_palette_widget.set_primary_color(m_color);
+        else if (event.button() == GMouseButton::Right)
+            m_palette_widget.set_secondary_color(m_color);
+    }
+
+private:
+    PaletteWidget& m_palette_widget;
+    Color m_color;
+};
+
+PaletteWidget::PaletteWidget(PaintableWidget& paintable_widget, GWidget* parent)
+    : GFrame(parent)
+    , m_paintable_widget(paintable_widget)
+{
+    set_frame_shape(FrameShape::Panel);
+    set_frame_shadow(FrameShadow::Raised);
+    set_frame_thickness(0);
+    set_fill_with_background_color(true);
+    set_background_color(Color::LightGray);
+
+    set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
+    set_preferred_size({ 0, 34 });
+
+    m_secondary_color_widget = new GFrame(this);
+    m_secondary_color_widget->set_frame_thickness(2);
+    m_secondary_color_widget->set_frame_shape(FrameShape::Container);
+    m_secondary_color_widget->set_frame_shadow(FrameShadow::Sunken);
+    m_secondary_color_widget->set_relative_rect({ 2, 2, 60, 31 });
+    m_secondary_color_widget->set_fill_with_background_color(true);
+    set_secondary_color(paintable_widget.secondary_color());
+
+    m_primary_color_widget = new GFrame(this);
+    m_primary_color_widget->set_frame_thickness(2);
+    m_primary_color_widget->set_frame_shape(FrameShape::Container);
+    m_primary_color_widget->set_frame_shadow(FrameShadow::Sunken);
+    Rect rect { 0, 0, 38, 15 };
+    rect.center_within(m_secondary_color_widget->relative_rect());
+    m_primary_color_widget->set_relative_rect(rect);
+    m_primary_color_widget->set_fill_with_background_color(true);
+    set_primary_color(paintable_widget.primary_color());
+
+    auto* color_container = new GWidget(this);
+    color_container->set_relative_rect(m_secondary_color_widget->relative_rect().right() + 2, 2, 500, 32);
+    color_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
+    color_container->layout()->set_spacing(1);
+
+    auto* top_color_container = new GWidget(color_container);
+    top_color_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
+    top_color_container->layout()->set_spacing(1);
+
+    auto* bottom_color_container = new GWidget(color_container);
+    bottom_color_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
+    bottom_color_container->layout()->set_spacing(1);
+
+    auto add_color_widget = [&] (GWidget* container, Color color) {
+        auto* color_widget = new ColorWidget(color, *this, container);
+        color_widget->set_fill_with_background_color(true);
+        color_widget->set_background_color(color);
+    };
+
+    add_color_widget(top_color_container, Color::from_rgb(0x000000));
+    add_color_widget(top_color_container, Color::from_rgb(0x808080));
+    add_color_widget(top_color_container, Color::from_rgb(0x800000));
+    add_color_widget(top_color_container, Color::from_rgb(0x808000));
+    add_color_widget(top_color_container, Color::from_rgb(0x008000));
+    add_color_widget(top_color_container, Color::from_rgb(0x008080));
+    add_color_widget(top_color_container, Color::from_rgb(0x000080));
+    add_color_widget(top_color_container, Color::from_rgb(0x800080));
+    add_color_widget(top_color_container, Color::from_rgb(0x808040));
+    add_color_widget(top_color_container, Color::from_rgb(0x004040));
+    add_color_widget(top_color_container, Color::from_rgb(0x0080ff));
+    add_color_widget(top_color_container, Color::from_rgb(0x004080));
+    add_color_widget(top_color_container, Color::from_rgb(0x8000ff));
+    add_color_widget(top_color_container, Color::from_rgb(0x804000));
+
+    add_color_widget(bottom_color_container, Color::from_rgb(0xffffff));
+    add_color_widget(bottom_color_container, Color::from_rgb(0xc0c0c0));
+    add_color_widget(bottom_color_container, Color::from_rgb(0xff0000));
+    add_color_widget(bottom_color_container, Color::from_rgb(0xffff00));
+    add_color_widget(bottom_color_container, Color::from_rgb(0x00ff00));
+    add_color_widget(bottom_color_container, Color::from_rgb(0x00ffff));
+    add_color_widget(bottom_color_container, Color::from_rgb(0x0000ff));
+    add_color_widget(bottom_color_container, Color::from_rgb(0xff00ff));
+    add_color_widget(bottom_color_container, Color::from_rgb(0xffff80));
+    add_color_widget(bottom_color_container, Color::from_rgb(0x00ff80));
+    add_color_widget(bottom_color_container, Color::from_rgb(0x80ffff));
+    add_color_widget(bottom_color_container, Color::from_rgb(0x8080ff));
+    add_color_widget(bottom_color_container, Color::from_rgb(0xff0080));
+    add_color_widget(bottom_color_container, Color::from_rgb(0xff8040));
+}
+
+PaletteWidget::~PaletteWidget()
+{
+}
+
+void PaletteWidget::set_primary_color(Color color)
+{
+    m_paintable_widget.set_primary_color(color);
+    m_primary_color_widget->set_background_color(color);
+    m_primary_color_widget->update();
+}
+
+void PaletteWidget::set_secondary_color(Color color)
+{
+    m_paintable_widget.set_secondary_color(color);
+    m_secondary_color_widget->set_background_color(color);
+    m_secondary_color_widget->update();
+}

+ 21 - 0
Applications/PaintBrush/PaletteWidget.h

@@ -0,0 +1,21 @@
+#pragma once
+
+#include <LibGUI/GFrame.h>
+
+class PaintableWidget;
+
+class PaletteWidget final : public GFrame {
+public:
+    explicit PaletteWidget(PaintableWidget&, GWidget* parent);
+    virtual ~PaletteWidget() override;
+
+    virtual const char* class_name() const override { return "PaletteWidget"; }
+
+    void set_primary_color(Color);
+    void set_secondary_color(Color);
+
+private:
+    PaintableWidget& m_paintable_widget;
+    GFrame* m_primary_color_widget { nullptr };
+    GFrame* m_secondary_color_widget { nullptr };
+};

+ 48 - 0
Applications/PaintBrush/PenTool.cpp

@@ -0,0 +1,48 @@
+#include "PenTool.h"
+#include "PaintableWidget.h"
+#include <LibGUI/GPainter.h>
+
+PenTool::PenTool()
+{
+}
+
+PenTool::~PenTool()
+{
+}
+
+void PenTool::on_mousedown(PaintableWidget& paintable_widget, GMouseEvent& event)
+{
+    if (event.button() != GMouseButton::Left && event.button() != GMouseButton::Right)
+        return;
+
+    GPainter painter(paintable_widget.bitmap());
+    painter.set_pixel(event.position(), paintable_widget.color_for(event));
+    paintable_widget.update({ event.position(), { 1, 1 } });
+    m_last_drawing_event_position = event.position();
+}
+
+void PenTool::on_mouseup(PaintableWidget&, GMouseEvent& event)
+{
+    if (event.button() == GMouseButton::Left || event.button() == GMouseButton::Right)
+        m_last_drawing_event_position = { -1, -1 };
+}
+
+void PenTool::on_mousemove(PaintableWidget& paintable_widget, GMouseEvent& event)
+{
+    if (!paintable_widget.rect().contains(event.position()))
+        return;
+
+    if (event.buttons() & GMouseButton::Left || event.buttons() & GMouseButton::Right) {
+        GPainter painter(paintable_widget.bitmap());
+
+        if (m_last_drawing_event_position != Point(-1, -1)) {
+            painter.draw_line(m_last_drawing_event_position, event.position(), paintable_widget.color_for(event));
+            paintable_widget.update();
+        } else {
+            painter.set_pixel(event.position(), paintable_widget.color_for(event));
+            paintable_widget.update({ event.position(), { 1, 1 } });
+        }
+
+        m_last_drawing_event_position = event.position();
+    }
+}

+ 19 - 0
Applications/PaintBrush/PenTool.h

@@ -0,0 +1,19 @@
+#pragma once
+
+#include "Tool.h"
+#include <SharedGraphics/Point.h>
+
+class PenTool final : public Tool {
+public:
+    PenTool();
+    virtual ~PenTool() override;
+
+    virtual void on_mousedown(PaintableWidget&, GMouseEvent&) override;
+    virtual void on_mousemove(PaintableWidget&, GMouseEvent&) override;
+    virtual void on_mouseup(PaintableWidget&, GMouseEvent&) override;
+
+private:
+    virtual const char* class_name() const override { return "PenTool"; }
+
+    Point m_last_drawing_event_position { -1, -1 };
+};

+ 9 - 0
Applications/PaintBrush/Tool.cpp

@@ -0,0 +1,9 @@
+#include "Tool.h"
+
+Tool::Tool()
+{
+}
+
+Tool::~Tool()
+{
+}

+ 18 - 0
Applications/PaintBrush/Tool.h

@@ -0,0 +1,18 @@
+#pragma once
+
+class GMouseEvent;
+class PaintableWidget;
+
+class Tool {
+public:
+    virtual ~Tool();
+
+    virtual const char* class_name() const = 0;
+
+    virtual void on_mousedown(PaintableWidget&, GMouseEvent&) { }
+    virtual void on_mousemove(PaintableWidget&, GMouseEvent&) { }
+    virtual void on_mouseup(PaintableWidget&, GMouseEvent&) { }
+
+protected:
+    Tool();
+};

+ 64 - 0
Applications/PaintBrush/ToolboxWidget.cpp

@@ -0,0 +1,64 @@
+#include "ToolboxWidget.h"
+#include "BucketTool.h"
+#include "PaintableWidget.h"
+#include "PenTool.h"
+#include <LibGUI/GBoxLayout.h>
+#include <LibGUI/GButton.h>
+#include <SharedGraphics/PNGLoader.h>
+
+class ToolButton final : public GButton {
+public:
+    ToolButton(const String& name, GWidget* parent, OwnPtr<Tool>&& tool)
+        : GButton(parent)
+        , m_tool(move(tool))
+    {
+        set_tooltip(name);
+    }
+
+    const Tool& tool() const { return *m_tool; }
+    Tool& tool() { return *m_tool; }
+
+private:
+    OwnPtr<Tool> m_tool;
+};
+
+ToolboxWidget::ToolboxWidget(GWidget* parent)
+    : GFrame(parent)
+{
+    set_background_color(Color::LightGray);
+    set_fill_with_background_color(true);
+
+    set_frame_thickness(1);
+    set_frame_shape(FrameShape::Panel);
+    set_frame_shadow(FrameShadow::Raised);
+
+    set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
+    set_preferred_size({ 48, 0 });
+
+    set_layout(make<GBoxLayout>(Orientation::Vertical));
+    layout()->set_margins({ 4, 4, 4, 4 });
+
+    auto add_tool = [&](const StringView& name, const StringView& icon_name, OwnPtr<Tool>&& tool) {
+        auto* button = new ToolButton(name, this, move(tool));
+        button->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
+        button->set_preferred_size({ 0, 32 });
+        button->set_checkable(true);
+        button->set_exclusive(true);
+
+        button->set_icon(load_png(String::format("/res/icons/paintbrush/%s.png", icon_name.characters())));
+
+        button->on_checked = [button](auto checked) {
+            if (checked)
+                PaintableWidget::the().set_tool(&button->tool());
+            else
+                PaintableWidget::the().set_tool(nullptr);
+        };
+    };
+
+    add_tool("Pen", "pen", make<PenTool>());
+    add_tool("Bucket Fill", "bucket", make<BucketTool>());
+}
+
+ToolboxWidget::~ToolboxWidget()
+{
+}

+ 13 - 0
Applications/PaintBrush/ToolboxWidget.h

@@ -0,0 +1,13 @@
+#pragma once
+
+#include <LibGUI/GFrame.h>
+
+class ToolboxWidget final : public GFrame {
+public:
+    explicit ToolboxWidget(GWidget* parent);
+    virtual ~ToolboxWidget() override;
+
+    virtual const char* class_name() const override { return "ToolboxWidget"; }
+
+private:
+};

+ 58 - 0
Applications/PaintBrush/main.cpp

@@ -0,0 +1,58 @@
+#include "PaintableWidget.h"
+#include "PaletteWidget.h"
+#include "ToolboxWidget.h"
+#include <LibGUI/GAction.h>
+#include <LibGUI/GApplication.h>
+#include <LibGUI/GBoxLayout.h>
+#include <LibGUI/GMenu.h>
+#include <LibGUI/GMenuBar.h>
+#include <LibGUI/GWindow.h>
+
+int main(int argc, char** argv)
+{
+    GApplication app(argc, argv);
+
+    auto* window = new GWindow;
+    window->set_title("PaintBrush");
+    window->set_rect(100, 100, 640, 480);
+
+    auto* horizontal_container = new GWidget(nullptr);
+    window->set_main_widget(horizontal_container);
+    horizontal_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
+    horizontal_container->layout()->set_spacing(0);
+
+    auto* toolbox_widget = new ToolboxWidget(horizontal_container);
+
+    auto* vertical_container = new GWidget(horizontal_container);
+    vertical_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
+    vertical_container->layout()->set_spacing(0);
+
+    auto* paintable_widget = new PaintableWidget(vertical_container);
+    auto* palette_widget = new PaletteWidget(*paintable_widget, vertical_container);
+
+    window->show();
+
+    auto menubar = make<GMenuBar>();
+    auto app_menu = make<GMenu>("PaintBrush");
+    app_menu->add_action(GAction::create("Quit", { Mod_Alt, Key_F4 }, [](const GAction&) {
+        GApplication::the().quit(0);
+        return;
+    }));
+    menubar->add_menu(move(app_menu));
+
+    auto file_menu = make<GMenu>("File");
+    menubar->add_menu(move(file_menu));
+
+    auto edit_menu = make<GMenu>("Edit");
+    menubar->add_menu(move(edit_menu));
+
+    auto help_menu = make<GMenu>("Help");
+    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));
+
+    return app.exec();
+}

+ 2 - 2
Applications/ProcessManager/MemoryStatsWidget.cpp

@@ -1,8 +1,8 @@
 #include "MemoryStatsWidget.h"
 #include "GraphWidget.h"
-#include <LibGUI/GPainter.h>
 #include <LibGUI/GBoxLayout.h>
 #include <LibGUI/GLabel.h>
+#include <LibGUI/GPainter.h>
 #include <SharedGraphics/StylePainter.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -21,7 +21,7 @@ MemoryStatsWidget::MemoryStatsWidget(GraphWidget& graph, GWidget* parent)
     layout()->set_margins({ 0, 8, 0, 0 });
     layout()->set_spacing(3);
 
-    auto build_widgets_for_label = [this] (const String& description) -> GLabel* {
+    auto build_widgets_for_label = [this](const String& description) -> GLabel* {
         auto* container = new GWidget(this);
         container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
         container->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);

+ 85 - 45
Applications/ProcessManager/ProcessModel.cpp

@@ -2,8 +2,8 @@
 #include "GraphWidget.h"
 #include <LibCore/CFile.h>
 #include <fcntl.h>
-#include <stdio.h>
 #include <pwd.h>
+#include <stdio.h>
 
 ProcessModel::ProcessModel(GraphWidget& graph)
     : m_graph(graph)
@@ -42,34 +42,56 @@ int ProcessModel::column_count(const GModelIndex&) const
 String ProcessModel::column_name(int column) const
 {
     switch (column) {
-    case Column::Icon: return "";
-    case Column::PID: return "PID";
-    case Column::State: return "State";
-    case Column::User: return "User";
-    case Column::Priority: return "Pr";
-    case Column::Linear: return "Linear";
-    case Column::Physical: return "Physical";
-    case Column::CPU: return "CPU";
-    case Column::Name: return "Name";
-    case Column::Syscalls: return "Syscalls";
-    default: ASSERT_NOT_REACHED();
+    case Column::Icon:
+        return "";
+    case Column::PID:
+        return "PID";
+    case Column::State:
+        return "State";
+    case Column::User:
+        return "User";
+    case Column::Priority:
+        return "Pr";
+    case Column::Virtual:
+        return "Virtual";
+    case Column::Physical:
+        return "Physical";
+    case Column::CPU:
+        return "CPU";
+    case Column::Name:
+        return "Name";
+    case Column::Syscalls:
+        return "Syscalls";
+    default:
+        ASSERT_NOT_REACHED();
     }
 }
 
 GModel::ColumnMetadata ProcessModel::column_metadata(int column) const
 {
     switch (column) {
-    case Column::Icon: return { 16, TextAlignment::CenterLeft };
-    case Column::PID: return { 32, TextAlignment::CenterRight };
-    case Column::State: return { 75, TextAlignment::CenterLeft };
-    case Column::Priority: return { 16, TextAlignment::CenterLeft };
-    case Column::User: return { 50, TextAlignment::CenterLeft };
-    case Column::Linear: return { 65, TextAlignment::CenterRight };
-    case Column::Physical: return { 65, TextAlignment::CenterRight };
-    case Column::CPU: return { 32, TextAlignment::CenterRight };
-    case Column::Name: return { 140, TextAlignment::CenterLeft };
-    case Column::Syscalls: return { 60, TextAlignment::CenterRight };
-    default: ASSERT_NOT_REACHED();
+    case Column::Icon:
+        return { 16, TextAlignment::CenterLeft };
+    case Column::PID:
+        return { 32, TextAlignment::CenterRight };
+    case Column::State:
+        return { 75, TextAlignment::CenterLeft };
+    case Column::Priority:
+        return { 16, TextAlignment::CenterLeft };
+    case Column::User:
+        return { 50, TextAlignment::CenterLeft };
+    case Column::Virtual:
+        return { 65, TextAlignment::CenterRight };
+    case Column::Physical:
+        return { 65, TextAlignment::CenterRight };
+    case Column::CPU:
+        return { 32, TextAlignment::CenterRight };
+    case Column::Name:
+        return { 140, TextAlignment::CenterLeft };
+    case Column::Syscalls:
+        return { 60, TextAlignment::CenterRight };
+    default:
+        ASSERT_NOT_REACHED();
     }
 }
 
@@ -87,10 +109,14 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const
 
     if (role == Role::Sort) {
         switch (index.column()) {
-        case Column::Icon: return 0;
-        case Column::PID: return process.current_state.pid;
-        case Column::State: return process.current_state.state;
-        case Column::User: return process.current_state.user;
+        case Column::Icon:
+            return 0;
+        case Column::PID:
+            return process.current_state.pid;
+        case Column::State:
+            return process.current_state.state;
+        case Column::User:
+            return process.current_state.user;
         case Column::Priority:
             if (process.current_state.priority == "Idle")
                 return 0;
@@ -102,23 +128,32 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const
                 return 3;
             ASSERT_NOT_REACHED();
             return 3;
-        case Column::Linear: return (int)process.current_state.linear;
-        case Column::Physical: return (int)process.current_state.physical;
-        case Column::CPU: return process.current_state.cpu_percent;
-        case Column::Name: return process.current_state.name;
+        case Column::Virtual:
+            return (int)process.current_state.virtual_size;
+        case Column::Physical:
+            return (int)process.current_state.physical_size;
+        case Column::CPU:
+            return process.current_state.cpu_percent;
+        case Column::Name:
+            return process.current_state.name;
         // FIXME: GVariant with unsigned?
-        case Column::Syscalls: return (int)process.current_state.syscalls;
+        case Column::Syscalls:
+            return (int)process.current_state.syscalls;
         }
         ASSERT_NOT_REACHED();
-        return { };
+        return {};
     }
 
     if (role == Role::Display) {
         switch (index.column()) {
-        case Column::Icon: return *m_generic_process_icon;
-        case Column::PID: return process.current_state.pid;
-        case Column::State: return process.current_state.state;
-        case Column::User: return process.current_state.user;
+        case Column::Icon:
+            return *m_generic_process_icon;
+        case Column::PID:
+            return process.current_state.pid;
+        case Column::State:
+            return process.current_state.state;
+        case Column::User:
+            return process.current_state.user;
         case Column::Priority:
             if (process.current_state.priority == "Idle")
                 return String::empty();
@@ -129,16 +164,21 @@ GVariant ProcessModel::data(const GModelIndex& index, Role role) const
             if (process.current_state.priority == "Normal")
                 return *m_normal_priority_icon;
             return process.current_state.priority;
-        case Column::Linear: return pretty_byte_size(process.current_state.linear);
-        case Column::Physical: return pretty_byte_size(process.current_state.physical);
-        case Column::CPU: return process.current_state.cpu_percent;
-        case Column::Name: return process.current_state.name;
+        case Column::Virtual:
+            return pretty_byte_size(process.current_state.virtual_size);
+        case Column::Physical:
+            return pretty_byte_size(process.current_state.physical_size);
+        case Column::CPU:
+            return process.current_state.cpu_percent;
+        case Column::Name:
+            return process.current_state.name;
         // FIXME: It's weird that GVariant doesn't support unsigned ints. Should it?
-        case Column::Syscalls: return (int)process.current_state.syscalls;
+        case Column::Syscalls:
+            return (int)process.current_state.syscalls;
         }
     }
 
-    return { };
+    return {};
 }
 
 void ProcessModel::update()
@@ -181,9 +221,9 @@ void ProcessModel::update()
         ASSERT(ok);
         state.state = parts[7];
         state.name = parts[11];
-        state.linear = parts[12].to_uint(ok);
+        state.virtual_size = parts[12].to_uint(ok);
         ASSERT(ok);
-        state.physical = parts[13].to_uint(ok);
+        state.physical_size = parts[13].to_uint(ok);
         ASSERT(ok);
         sum_nsched += nsched;
         {

+ 4 - 5
Applications/ProcessManager/ProcessModel.h

@@ -11,8 +11,7 @@ class GraphWidget;
 
 class ProcessModel final : public GModel {
 public:
-    enum Column
-    {
+    enum Column {
         Icon = 0,
         Name,
         CPU,
@@ -20,7 +19,7 @@ public:
         Priority,
         User,
         PID,
-        Linear,
+        Virtual,
         Physical,
         Syscalls,
         __Count
@@ -48,8 +47,8 @@ private:
         String state;
         String user;
         String priority;
-        size_t linear;
-        size_t physical;
+        size_t virtual_size;
+        size_t physical_size;
         unsigned syscalls;
         float cpu_percent;
     };

+ 24 - 24
Applications/ProcessManager/main.cpp

@@ -1,20 +1,20 @@
+#include "GraphWidget.h"
+#include "MemoryStatsWidget.h"
+#include "ProcessTableView.h"
 #include <LibCore/CTimer.h>
-#include <LibGUI/GWindow.h>
-#include <LibGUI/GWidget.h>
-#include <LibGUI/GBoxLayout.h>
+#include <LibGUI/GAction.h>
 #include <LibGUI/GApplication.h>
-#include <LibGUI/GToolBar.h>
-#include <LibGUI/GMenuBar.h>
+#include <LibGUI/GBoxLayout.h>
 #include <LibGUI/GGroupBox.h>
-#include <LibGUI/GAction.h>
-#include <LibGUI/GTabWidget.h>
 #include <LibGUI/GLabel.h>
-#include <unistd.h>
-#include <stdio.h>
+#include <LibGUI/GMenuBar.h>
+#include <LibGUI/GTabWidget.h>
+#include <LibGUI/GToolBar.h>
+#include <LibGUI/GWidget.h>
+#include <LibGUI/GWindow.h>
 #include <signal.h>
-#include "ProcessTableView.h"
-#include "MemoryStatsWidget.h"
-#include "GraphWidget.h"
+#include <stdio.h>
+#include <unistd.h>
 
 int main(int argc, char** argv)
 {
@@ -46,7 +46,7 @@ int main(int argc, char** argv)
     cpu_graph->set_max(100);
     cpu_graph->set_text_color(Color::Green);
     cpu_graph->set_graph_color(Color::from_rgb(0x00bb00));
-    cpu_graph->text_formatter = [] (int value, int) {
+    cpu_graph->text_formatter = [](int value, int) {
         return String::format("%d%%", value);
     };
 
@@ -58,7 +58,7 @@ int main(int argc, char** argv)
     auto* memory_graph = new GraphWidget(memory_graph_group_box);
     memory_graph->set_text_color(Color::Cyan);
     memory_graph->set_graph_color(Color::from_rgb(0x00bbbb));
-    memory_graph->text_formatter = [] (int value, int max) {
+    memory_graph->text_formatter = [](int value, int max) {
         return String::format("%d / %d KB", value, max);
     };
 
@@ -78,19 +78,19 @@ int main(int argc, char** argv)
         memory_stats_widget->refresh();
     });
 
-    auto kill_action = GAction::create("Kill process", GraphicsBitmap::load_from_file("/res/icons/kill16.png"), [process_table_view] (const GAction&) {
+    auto kill_action = GAction::create("Kill process", GraphicsBitmap::load_from_file("/res/icons/kill16.png"), [process_table_view](const GAction&) {
         pid_t pid = process_table_view->selected_pid();
         if (pid != -1)
             kill(pid, SIGKILL);
     });
 
-    auto stop_action = GAction::create("Stop process", GraphicsBitmap::load_from_file("/res/icons/stop16.png"), [process_table_view] (const GAction&) {
+    auto stop_action = GAction::create("Stop process", GraphicsBitmap::load_from_file("/res/icons/stop16.png"), [process_table_view](const GAction&) {
         pid_t pid = process_table_view->selected_pid();
         if (pid != -1)
             kill(pid, SIGSTOP);
     });
 
-    auto continue_action = GAction::create("Continue process", GraphicsBitmap::load_from_file("/res/icons/continue16.png"), [process_table_view] (const GAction&) {
+    auto continue_action = GAction::create("Continue process", GraphicsBitmap::load_from_file("/res/icons/continue16.png"), [process_table_view](const GAction&) {
         pid_t pid = process_table_view->selected_pid();
         if (pid != -1)
             kill(pid, SIGCONT);
@@ -102,7 +102,7 @@ int main(int argc, char** argv)
 
     auto menubar = make<GMenuBar>();
     auto app_menu = make<GMenu>("Process Manager");
-    app_menu->add_action(GAction::create("Quit", { Mod_Alt, Key_F4 }, [] (const GAction&) {
+    app_menu->add_action(GAction::create("Quit", { Mod_Alt, Key_F4 }, [](const GAction&) {
         GApplication::the().quit(0);
         return;
     }));
@@ -115,25 +115,25 @@ int main(int argc, char** argv)
     menubar->add_menu(move(process_menu));
 
     auto frequency_menu = make<GMenu>("Frequency");
-    frequency_menu->add_action(GAction::create("0.25 sec", [refresh_timer] (auto&) {
+    frequency_menu->add_action(GAction::create("0.25 sec", [refresh_timer](auto&) {
         refresh_timer->restart(250);
     }));
-    frequency_menu->add_action(GAction::create("0.5 sec", [refresh_timer] (auto&) {
+    frequency_menu->add_action(GAction::create("0.5 sec", [refresh_timer](auto&) {
         refresh_timer->restart(500);
     }));
-    frequency_menu->add_action(GAction::create("1 sec", [refresh_timer] (auto&) {
+    frequency_menu->add_action(GAction::create("1 sec", [refresh_timer](auto&) {
         refresh_timer->restart(1000);
     }));
-    frequency_menu->add_action(GAction::create("3 sec", [refresh_timer] (auto&) {
+    frequency_menu->add_action(GAction::create("3 sec", [refresh_timer](auto&) {
         refresh_timer->restart(3000);
     }));
-    frequency_menu->add_action(GAction::create("5 sec", [refresh_timer] (auto&) {
+    frequency_menu->add_action(GAction::create("5 sec", [refresh_timer](auto&) {
         refresh_timer->restart(5000);
     }));
     menubar->add_menu(move(frequency_menu));
 
     auto help_menu = make<GMenu>("Help");
-    help_menu->add_action(GAction::create("About", [] (const GAction&) {
+    help_menu->add_action(GAction::create("About", [](const GAction&) {
         dbgprintf("FIXME: Implement Help/About\n");
     }));
     menubar->add_menu(move(help_menu));

+ 5 - 5
Applications/Taskbar/TaskbarButton.cpp

@@ -1,8 +1,8 @@
 #include "TaskbarButton.h"
-#include <WindowServer/WSAPITypes.h>
 #include <LibGUI/GAction.h>
-#include <LibGUI/GMenu.h>
 #include <LibGUI/GEventLoop.h>
+#include <LibGUI/GMenu.h>
+#include <WindowServer/WSAPITypes.h>
 
 static void set_window_minimized_state(const WindowIdentifier& identifier, bool minimized)
 {
@@ -34,13 +34,13 @@ GMenu& TaskbarButton::ensure_menu()
 {
     if (!m_menu) {
         m_menu = make<GMenu>("");
-        m_menu->add_action(GAction::create("Minimize", [this] (auto&) {
+        m_menu->add_action(GAction::create("Minimize", [this](auto&) {
             set_window_minimized_state(m_identifier, true);
         }));
-        m_menu->add_action(GAction::create("Unminimize", [this] (auto&) {
+        m_menu->add_action(GAction::create("Unminimize", [this](auto&) {
             set_window_minimized_state(m_identifier, false);
         }));
-        m_menu->add_action(GAction::create("Close", [this] (auto&) {
+        m_menu->add_action(GAction::create("Close", [this](auto&) {
             dbgprintf("FIXME: Close!\n");
         }));
     }

+ 9 - 13
Applications/Taskbar/TaskbarWindow.cpp

@@ -1,11 +1,11 @@
 #include "TaskbarWindow.h"
 #include "TaskbarButton.h"
-#include <LibGUI/GWindow.h>
-#include <LibGUI/GDesktop.h>
-#include <LibGUI/GEventLoop.h>
 #include <LibGUI/GBoxLayout.h>
 #include <LibGUI/GButton.h>
+#include <LibGUI/GDesktop.h>
+#include <LibGUI/GEventLoop.h>
 #include <LibGUI/GFrame.h>
+#include <LibGUI/GWindow.h>
 #include <WindowServer/WSAPITypes.h>
 #include <stdio.h>
 
@@ -19,7 +19,7 @@ TaskbarWindow::TaskbarWindow()
 
     on_screen_rect_change(GDesktop::the().rect());
 
-    GDesktop::the().on_rect_change = [this] (const Rect& rect) { on_screen_rect_change(rect); };
+    GDesktop::the().on_rect_change = [this](const Rect& rect) { on_screen_rect_change(rect); };
 
     auto* widget = new GFrame;
     widget->set_fill_with_background_color(true);
@@ -31,7 +31,7 @@ TaskbarWindow::TaskbarWindow()
     widget->set_frame_shadow(FrameShadow::Raised);
     set_main_widget(widget);
 
-    WindowList::the().aid_create_button = [this] (auto& identifier) {
+    WindowList::the().aid_create_button = [this](auto& identifier) {
         return create_button(identifier);
     };
 }
@@ -70,8 +70,7 @@ void TaskbarWindow::wm_event(GWMEvent& event)
         auto& removed_event = static_cast<GWMWindowRemovedEvent&>(event);
         dbgprintf("WM_WindowRemoved: client_id=%d, window_id=%d\n",
             removed_event.client_id(),
-            removed_event.window_id()
-        );
+            removed_event.window_id());
 #endif
         WindowList::the().remove_window(identifier);
         update();
@@ -83,8 +82,7 @@ void TaskbarWindow::wm_event(GWMEvent& event)
         dbgprintf("WM_WindowRectChanged: client_id=%d, window_id=%d, rect=%s\n",
             changed_event.client_id(),
             changed_event.window_id(),
-            changed_event.rect().to_string().characters()
-        );
+            changed_event.rect().to_string().characters());
 #endif
         break;
     }
@@ -94,8 +92,7 @@ void TaskbarWindow::wm_event(GWMEvent& event)
         dbgprintf("WM_WindowIconChanged: client_id=%d, window_id=%d, icon_path=%s\n",
             changed_event.client_id(),
             changed_event.window_id(),
-            changed_event.icon_path().characters()
-        );
+            changed_event.icon_path().characters());
 #endif
         if (auto* window = WindowList::the().window(identifier)) {
             window->set_icon_path(changed_event.icon_path());
@@ -113,8 +110,7 @@ void TaskbarWindow::wm_event(GWMEvent& event)
             changed_event.title().characters(),
             changed_event.rect().to_string().characters(),
             changed_event.is_active(),
-            changed_event.is_minimized()
-        );
+            changed_event.is_minimized());
 #endif
         if (!should_include_window(changed_event.window_type()))
             break;

+ 2 - 2
Applications/Taskbar/WindowList.cpp

@@ -1,6 +1,6 @@
 #include "WindowList.h"
-#include <WindowServer/WSAPITypes.h>
 #include <LibGUI/GEventLoop.h>
+#include <WindowServer/WSAPITypes.h>
 
 WindowList& WindowList::the()
 {
@@ -25,7 +25,7 @@ Window& WindowList::ensure_window(const WindowIdentifier& identifier)
         return *it->value;
     auto window = make<Window>(identifier);
     window->set_button(aid_create_button(identifier));
-    window->button()->on_click = [window = window.ptr(), identifier] (GButton&) {
+    window->button()->on_click = [window = window.ptr(), identifier](GButton&) {
         WSAPI_ClientMessage message;
         if (window->is_minimized() || !window->is_active()) {
             message.type = WSAPI_ClientMessage::Type::WM_SetActiveWindow;

+ 1 - 1
Applications/Taskbar/main.cpp

@@ -1,5 +1,5 @@
-#include <LibGUI/GApplication.h>
 #include "TaskbarWindow.h"
+#include <LibGUI/GApplication.h>
 
 int main(int argc, char** argv)
 {

+ 1 - 0
Applications/Terminal/.gitignore

@@ -1,3 +1,4 @@
 *.o
 *.d
 Terminal
+compile_commands.json

+ 314 - 109
Applications/Terminal/Terminal.cpp

@@ -1,19 +1,19 @@
 #include "Terminal.h"
 #include "XtermColors.h"
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
 #include <AK/AKString.h>
-#include <AK/StringBuilder.h>
-#include <SharedGraphics/Font.h>
-#include <LibGUI/GPainter.h>
 #include <AK/StdLibExtras.h>
+#include <AK/StringBuilder.h>
+#include <Kernel/KeyCode.h>
 #include <LibGUI/GApplication.h>
+#include <LibGUI/GPainter.h>
 #include <LibGUI/GWindow.h>
-#include <Kernel/KeyCode.h>
+#include <SharedGraphics/Font.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/ioctl.h>
+#include <unistd.h>
 
 //#define TERMINAL_DEBUG
 byte Terminal::Attribute::default_foreground_color = 7;
@@ -30,8 +30,8 @@ Terminal::Terminal(int ptm_fd, RetainPtr<CConfigFile> config)
 
     dbgprintf("Terminal: Load config file from %s\n", m_config->file_name().characters());
     m_cursor_blink_timer.set_interval(m_config->read_num_entry("Text",
-                                                               "CursorBlinkInterval",
-                                                               500));
+        "CursorBlinkInterval",
+        500));
     m_cursor_blink_timer.on_timeout = [this] {
         m_cursor_blink_state = !m_cursor_blink_state;
         update_cursor();
@@ -43,7 +43,7 @@ Terminal::Terminal(int ptm_fd, RetainPtr<CConfigFile> config)
     else
         set_font(Font::load_from_file(font_entry));
 
-    m_notifier.on_ready_to_read = [this]{
+    m_notifier.on_ready_to_read = [this] {
         byte buffer[BUFSIZ];
         ssize_t nread = read(m_ptm_fd, buffer, sizeof(buffer));
         if (nread < 0) {
@@ -65,37 +65,48 @@ Terminal::Terminal(int ptm_fd, RetainPtr<CConfigFile> config)
     m_line_height = font().glyph_height() + m_line_spacing;
 
     set_size(m_config->read_num_entry("Window", "Width", 80),
-             m_config->read_num_entry("Window", "Height", 25));
+        m_config->read_num_entry("Window", "Height", 25));
 }
 
-Terminal::Line::Line(word columns)
-    : length(columns)
+Terminal::Line::Line(word length)
 {
-    characters = new byte[length];
-    attributes = new Attribute[length];
-    memset(characters, ' ', length);
+    set_length(length);
 }
 
 Terminal::Line::~Line()
 {
-    delete [] characters;
-    delete [] attributes;
+    delete[] characters;
+    delete[] attributes;
+}
+
+void Terminal::Line::set_length(word new_length)
+{
+    if (m_length == new_length)
+        return;
+    auto* new_characters = new byte[new_length];
+    auto* new_attributes = new Attribute[new_length];
+    memset(new_characters, ' ', new_length);
+    delete[] characters;
+    delete[] attributes;
+    characters = new_characters;
+    attributes = new_attributes;
+    m_length = new_length;
 }
 
 void Terminal::Line::clear(Attribute attribute)
 {
     if (dirty) {
-        memset(characters, ' ', length);
-        for (word i = 0 ; i < length; ++i)
+        memset(characters, ' ', m_length);
+        for (word i = 0; i < m_length; ++i)
             attributes[i] = attribute;
         return;
     }
-    for (unsigned i = 0 ; i < length; ++i) {
+    for (unsigned i = 0; i < m_length; ++i) {
         if (characters[i] != ' ')
             dirty = true;
         characters[i] = ' ';
     }
-    for (unsigned i = 0 ; i < length; ++i) {
+    for (unsigned i = 0; i < m_length; ++i) {
         if (attributes[i] != attribute)
             dirty = true;
         attributes[i] = attribute;
@@ -104,10 +115,6 @@ void Terminal::Line::clear(Attribute attribute)
 
 Terminal::~Terminal()
 {
-    for (int i = 0; i < m_rows; ++i)
-        delete m_lines[i];
-    delete [] m_lines;
-    free(m_horizontal_tabs);
 }
 
 void Terminal::clear()
@@ -137,6 +144,35 @@ static inline Color lookup_color(unsigned color)
     return Color::from_rgb(xterm_colors[color]);
 }
 
+void Terminal::escape$h_l(bool should_set, bool question_param, const ParamVector& params)
+{
+    int mode = 2;
+    if (params.size() > 0) {
+        mode = params[0];
+    }
+    if (!question_param) {
+        switch (mode) {
+            // FIXME: implement *something* for this
+        default:
+            unimplemented_escape();
+            break;
+        }
+    } else {
+        switch (mode) {
+        case 25:
+            // Hide cursor command, but doesn't need to be run (for now, because
+            // we don't do inverse control codes anyways)
+            if (should_set)
+                dbgprintf("Terminal: Hide Cursor escapecode recieved. Not needed: ignored.\n");
+            else
+                dbgprintf("Terminal: Show Cursor escapecode recieved. Not needed: ignored.\n");
+            break;
+        default:
+            break;
+        }
+    }
+}
+
 void Terminal::escape$m(const ParamVector& params)
 {
     if (params.is_empty()) {
@@ -243,7 +279,7 @@ void Terminal::escape$t(const ParamVector& params)
 {
     if (params.size() < 1)
         return;
-    dbgprintf("FIXME: escape$t: Ps: %u\n", params[0]);
+    dbgprintf("FIXME: escape$t: Ps: %u (param count: %d)\n", params[0], params.size());
 }
 
 void Terminal::escape$r(const ParamVector& params)
@@ -254,7 +290,13 @@ void Terminal::escape$r(const ParamVector& params)
         top = params[0];
     if (params.size() >= 2)
         bottom = params[1];
-    dbgprintf("FIXME: escape$r: Set scrolling region: %u-%u\n", top, bottom);
+    if ((bottom - top) < 2 || bottom > m_rows || top < 0) {
+        dbgprintf("Error: escape$r: scrolling region invalid: %u-%u\n", top, bottom);
+        return;
+    }
+    m_scroll_region_top = top - 1;
+    m_scroll_region_bottom = bottom - 1;
+    set_cursor(0, 0);
 }
 
 void Terminal::escape$H(const ParamVector& params)
@@ -330,6 +372,15 @@ void Terminal::escape$G(const ParamVector& params)
     set_cursor(m_cursor_row, new_column);
 }
 
+void Terminal::escape$b(const ParamVector& params)
+{
+    if (params.size() < 1)
+        return;
+
+    for (unsigned i = 0; i < params[0]; ++i)
+        put_character_at(m_cursor_row, m_cursor_column++, m_last_char);
+}
+
 void Terminal::escape$d(const ParamVector& params)
 {
     int new_row = 1;
@@ -373,7 +424,10 @@ void Terminal::escape$K(const ParamVector& params)
         }
         break;
     case 2:
-        unimplemented_escape();
+        // Clear the complete line
+        for (int i = 0; i < m_columns; ++i) {
+            put_character_at(m_cursor_row, i, ' ');
+        }
         break;
     default:
         unimplemented_escape();
@@ -389,9 +443,8 @@ void Terminal::escape$J(const ParamVector& params)
     switch (mode) {
     case 0:
         // Clear from cursor to end of screen.
-        for (int i = m_cursor_column; i < m_columns; ++i) {
+        for (int i = m_cursor_column; i < m_columns; ++i)
             put_character_at(m_cursor_row, i, ' ');
-        }
         for (int row = m_cursor_row + 1; row < m_rows; ++row) {
             for (int column = 0; column < m_columns; ++column) {
                 put_character_at(row, column, ' ');
@@ -399,8 +452,14 @@ void Terminal::escape$J(const ParamVector& params)
         }
         break;
     case 1:
-        // FIXME: Clear from cursor to beginning of screen.
-        unimplemented_escape();
+        /// Clear from cursor to beginning of screen
+        for (int i = m_cursor_column - 1; i >= 0; --i)
+            put_character_at(m_cursor_row, i, ' ');
+        for (int row = m_cursor_row - 1; row >= 0; --row) {
+            for (int column = 0; column < m_columns; ++column) {
+                put_character_at(row, column, ' ');
+            }
+        }
         break;
     case 2:
         clear();
@@ -415,6 +474,42 @@ void Terminal::escape$J(const ParamVector& params)
     }
 }
 
+void Terminal::escape$S(const ParamVector& params)
+{
+    int count = 1;
+    if (params.size() >= 1)
+        count = params[0];
+
+    for (word i = 0; i < count; i++)
+        scroll_up();
+}
+
+void Terminal::escape$T(const ParamVector& params)
+{
+    int count = 1;
+    if (params.size() >= 1)
+        count = params[0];
+
+    for (word i = 0; i < count; i++)
+        scroll_down();
+}
+
+void Terminal::escape$L(const ParamVector& params)
+{
+    int count = 1;
+    if (params.size() >= 1)
+        count = params[0];
+    invalidate_cursor();
+    for (; count > 0; --count) {
+        m_lines.insert(m_cursor_row + m_scroll_region_top, make<Line>(m_columns));
+        if (m_scroll_region_bottom + 1 < m_lines.size())
+            m_lines.remove(m_scroll_region_bottom + 1);
+        else
+            m_lines.remove(m_lines.size() - 1);
+    }
+    m_need_full_flush = true;
+}
+
 void Terminal::escape$M(const ParamVector& params)
 {
     int count = 1;
@@ -426,12 +521,38 @@ void Terminal::escape$M(const ParamVector& params)
         return;
     }
 
-    int max_count = m_rows - m_cursor_row;
+    int max_count = m_rows - (m_scroll_region_top + m_cursor_row);
     count = min(count, max_count);
 
-    dbgprintf("Delete %d line(s) starting from %d\n", count, m_cursor_row);
-    // FIXME: Implement.
-    ASSERT_NOT_REACHED();
+    for (int c = count; c > 0; --c) {
+        m_lines.remove(m_cursor_row + m_scroll_region_top);
+        if (m_scroll_region_bottom < m_lines.size())
+            m_lines.insert(m_scroll_region_bottom, make<Line>(m_columns));
+        else
+            m_lines.append(make<Line>(m_columns));
+    }
+}
+
+void Terminal::escape$P(const ParamVector& params)
+{
+    int num = 1;
+    if (params.size() >= 1)
+        num = params[0];
+
+    if (num == 0)
+        num = 1;
+
+    auto& line = this->line(m_cursor_row);
+
+    // Move n characters of line to the left
+    for (int i = m_cursor_column; i < line.m_length - num; i++)
+        line.characters[i] = line.characters[i + num];
+
+    // Fill remainder of line with blanks
+    for (int i = line.m_length - num; i < line.m_length; i++)
+        line.characters[i] = ' ';
+
+    line.dirty = true;
 }
 
 void Terminal::execute_xterm_command()
@@ -457,42 +578,122 @@ void Terminal::execute_xterm_command()
 
 void Terminal::execute_escape_sequence(byte final)
 {
+    bool question_param = false;
     m_final = final;
-    auto paramparts = String::copy(m_parameters).split(';');
     ParamVector params;
+
+    if (m_parameters.size() > 0 && m_parameters[0] == '?') {
+        question_param = true;
+        m_parameters.remove(0);
+    }
+    auto paramparts = String::copy(m_parameters).split(';');
     for (auto& parampart : paramparts) {
         bool ok;
         unsigned value = parampart.to_uint(ok);
         if (!ok) {
+            // FIXME: Should we do something else?
             m_parameters.clear_with_capacity();
             m_intermediates.clear_with_capacity();
-            // FIXME: Should we do something else?
             return;
         }
         params.append(value);
     }
+
+#if defined(TERMINAL_DEBUG)
+    dbgprintf("Terminal::execute_escape_sequence: Handled final '%c'\n", final);
+    dbgprintf("Params: ");
+    for (auto& p : params) {
+        dbgprintf("%d ", p);
+    }
+    dbgprintf("\b\n");
+#endif
+
     switch (final) {
-    case 'A': escape$A(params); break;
-    case 'B': escape$B(params); break;
-    case 'C': escape$C(params); break;
-    case 'D': escape$D(params); break;
-    case 'H': escape$H(params); break;
-    case 'J': escape$J(params); break;
-    case 'K': escape$K(params); break;
-    case 'M': escape$M(params); break;
-    case 'G': escape$G(params); break;
-    case 'X': escape$X(params); break;
-    case 'd': escape$d(params); break;
-    case 'm': escape$m(params); break;
-    case 's': escape$s(params); break;
-    case 'u': escape$u(params); break;
-    case 't': escape$t(params); break;
-    case 'r': escape$r(params); break;
+    case 'A':
+        escape$A(params);
+        break;
+    case 'B':
+        escape$B(params);
+        break;
+    case 'C':
+        escape$C(params);
+        break;
+    case 'D':
+        escape$D(params);
+        break;
+    case 'H':
+        escape$H(params);
+        break;
+    case 'J':
+        escape$J(params);
+        break;
+    case 'K':
+        escape$K(params);
+        break;
+    case 'M':
+        escape$M(params);
+        break;
+    case 'P':
+        escape$P(params);
+        break;
+    case 'S':
+        escape$S(params);
+        break;
+    case 'T':
+        escape$T(params);
+        break;
+    case 'L':
+        escape$L(params);
+        break;
+    case 'G':
+        escape$G(params);
+        break;
+    case 'X':
+        escape$X(params);
+        break;
+    case 'b':
+        escape$b(params);
+        break;
+    case 'd':
+        escape$d(params);
+        break;
+    case 'm':
+        escape$m(params);
+        break;
+    case 's':
+        escape$s(params);
+        break;
+    case 'u':
+        escape$u(params);
+        break;
+    case 't':
+        escape$t(params);
+        break;
+    case 'r':
+        escape$r(params);
+        break;
+    case 'l':
+        escape$h_l(true, question_param, params);
+        break;
+    case 'h':
+        escape$h_l(false, question_param, params);
+        break;
     default:
         dbgprintf("Terminal::execute_escape_sequence: Unhandled final '%c'\n", final);
         break;
     }
 
+#if defined(TERMINAL_DEBUG)
+    dbgprintf("\n");
+    for (auto& line : m_lines) {
+        dbgprintf("Terminal: Line: ");
+        for (int i = 0; i < line->length; i++) {
+            dbgprintf("%c", line->characters[i]);
+        }
+        dbgprintf("\n");
+    }
+#endif
+
     m_parameters.clear_with_capacity();
     m_intermediates.clear_with_capacity();
 }
@@ -500,7 +701,7 @@ void Terminal::execute_escape_sequence(byte final)
 void Terminal::newline()
 {
     word new_row = m_cursor_row;
-    if (m_cursor_row == (rows() - 1)) {
+    if (m_cursor_row == m_scroll_region_bottom) {
         scroll_up();
     } else {
         ++new_row;
@@ -512,11 +713,17 @@ void Terminal::scroll_up()
 {
     // NOTE: We have to invalidate the cursor first.
     invalidate_cursor();
-    delete m_lines[0];
-    for (word row = 1; row < rows(); ++row)
-        m_lines[row - 1] = m_lines[row];
-    m_lines[m_rows - 1] = new Line(m_columns);
-    ++m_rows_to_scroll_backing_store;
+    m_lines.remove(m_scroll_region_top);
+    m_lines.insert(m_scroll_region_bottom, make<Line>(m_columns));
+    m_need_full_flush = true;
+}
+
+void Terminal::scroll_down()
+{
+    // NOTE: We have to invalidate the cursor first.
+    invalidate_cursor();
+    m_lines.remove(m_scroll_region_bottom);
+    m_lines.insert(m_scroll_region_top, make<Line>(m_columns));
     m_need_full_flush = true;
 }
 
@@ -531,7 +738,7 @@ void Terminal::set_cursor(unsigned a_row, unsigned a_column)
     invalidate_cursor();
     m_cursor_row = row;
     m_cursor_column = column;
-    if (column != columns() - 1)
+    if (column != columns() - 1u)
         m_stomp = false;
     invalidate_cursor();
 }
@@ -541,11 +748,11 @@ void Terminal::put_character_at(unsigned row, unsigned column, byte ch)
     ASSERT(row < rows());
     ASSERT(column < columns());
     auto& line = this->line(row);
-    if ((line.characters[column] == ch) && (line.attributes[column] == m_current_attribute))
-        return;
     line.characters[column] = ch;
     line.attributes[column] = m_current_attribute;
     line.dirty = true;
+
+    m_last_char = ch;
 }
 
 void Terminal::on_char(byte ch)
@@ -628,7 +835,16 @@ void Terminal::on_char(byte ch)
         }
         return;
     case '\a':
-        sysbeep();
+        if (m_should_beep)
+            sysbeep();
+        else {
+            m_visual_beep_timer.restart(200);
+            m_visual_beep_timer.set_single_shot(true);
+            m_visual_beep_timer.on_timeout = [this] {
+                force_repaint();
+            };
+            force_repaint();
+        }
         return;
     case '\t': {
         for (unsigned i = m_cursor_column; i < columns(); ++i) {
@@ -700,39 +916,43 @@ void Terminal::set_size(word columns, word rows)
     if (columns == m_columns && rows == m_rows)
         return;
 
-    if (m_lines) {
-        for (size_t i = 0; i < m_rows; ++i)
-            delete m_lines[i];
-        delete m_lines;
+#if defined(TERMINAL_DEBUG)
+    dbgprintf("Terminal: RESIZE to: %d rows\n", rows);
+#endif
+
+    if (rows > m_rows) {
+        while (m_lines.size() < rows)
+            m_lines.append(make<Line>(columns));
+    } else {
+        m_lines.resize(rows);
     }
 
+    for (int i = 0; i < rows; ++i)
+        m_lines[i]->set_length(columns);
+
     m_columns = columns;
     m_rows = rows;
 
+    m_scroll_region_top = 0;
+    m_scroll_region_bottom = rows - 1;
+
     m_cursor_row = 0;
     m_cursor_column = 0;
     m_saved_cursor_row = 0;
     m_saved_cursor_column = 0;
 
-    if (m_horizontal_tabs)
-        free(m_horizontal_tabs);
-    m_horizontal_tabs = static_cast<byte*>(malloc(columns));
+    m_horizontal_tabs.resize(columns);
     for (unsigned i = 0; i < columns; ++i)
         m_horizontal_tabs[i] = (i % 8) == 0;
     // Rightmost column is always last tab on line.
     m_horizontal_tabs[columns - 1] = 1;
 
-    m_lines = new Line*[rows];
-    for (size_t i = 0; i < rows; ++i)
-        m_lines[i] = new Line(columns);
-
     m_pixel_width = (frame_thickness() * 2) + (m_inset * 2) + (m_columns * font().glyph_width('x'));
     m_pixel_height = (frame_thickness() * 2) + (m_inset * 2) + (m_rows * (font().glyph_height() + m_line_spacing)) - m_line_spacing;
 
     set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
     set_preferred_size({ m_pixel_width, m_pixel_height });
 
-    m_rows_to_scroll_backing_store = 0;
     m_needs_background_fill = true;
     force_repaint();
 
@@ -760,11 +980,11 @@ Rect Terminal::row_rect(word row)
 
 bool Terminal::Line::has_only_one_background_color() const
 {
-    if (!length)
+    if (!m_length)
         return true;
     // FIXME: Cache this result?
     auto color = attributes[0].background_color;
-    for (size_t i = 1; i < length; ++i) {
+    for (size_t i = 1; i < m_length; ++i) {
         if (attributes[i].background_color != color)
             return false;
     }
@@ -816,6 +1036,11 @@ void Terminal::keydown_event(GKeyEvent& event)
     case KeyCode::Key_End:
         write(m_ptm_fd, "\033[F", 3);
         break;
+    case KeyCode::Key_RightShift:
+        // Prevent RightShift from being sent to whatever's running in the
+        // terminal. Prevents `~@` (null) character from being sent after every
+        // character entered with right shift.
+        break;
     default:
         write(m_ptm_fd, &ch, 1);
         break;
@@ -823,45 +1048,28 @@ void Terminal::keydown_event(GKeyEvent& event)
 }
 
 void Terminal::paint_event(GPaintEvent& event)
-{   
+{
     GFrame::paint_event(event);
 
     GPainter painter(*this);
 
-    if (m_needs_background_fill) {
-        m_needs_background_fill = false;
+    if (m_visual_beep_timer.is_active())
+        painter.fill_rect(frame_inner_rect(), Color::Red);
+    else
         painter.fill_rect(frame_inner_rect(), Color(Color::Black).with_alpha(255 * m_opacity));
-    }
-
-    if (m_rows_to_scroll_backing_store && m_rows_to_scroll_backing_store < m_rows) {
-        int first_scanline = m_inset;
-        int second_scanline = m_inset + (m_rows_to_scroll_backing_store * m_line_height);
-        int num_rows_to_memcpy = m_rows - m_rows_to_scroll_backing_store;
-        int scanlines_to_copy = (num_rows_to_memcpy * m_line_height) - m_line_spacing;
-        memcpy(
-            painter.target()->scanline(first_scanline),
-            painter.target()->scanline(second_scanline),
-            scanlines_to_copy * painter.target()->pitch()
-        );
-        line(max(0, m_cursor_row - m_rows_to_scroll_backing_store)).dirty = true;
-    }
-    m_rows_to_scroll_backing_store = 0;
-
     invalidate_cursor();
 
     for (word row = 0; row < m_rows; ++row) {
         auto& line = this->line(row);
-        if (!line.dirty)
-            continue;
-        line.dirty = false;
         bool has_only_one_background_color = line.has_only_one_background_color();
-        if (has_only_one_background_color) {
+        if (m_visual_beep_timer.is_active())
+            painter.fill_rect(row_rect(row), Color::Red);
+        else if (has_only_one_background_color)
             painter.fill_rect(row_rect(row), lookup_color(line.attributes[0].background_color).with_alpha(255 * m_opacity));
-        }
         for (word column = 0; column < m_columns; ++column) {
+            char ch = line.characters[column];
             bool should_reverse_fill_for_cursor = m_cursor_blink_state && m_in_active_window && row == m_cursor_row && column == m_cursor_column;
             auto& attribute = line.attributes[column];
-            char ch = line.characters[column];
             auto character_rect = glyph_rect(row, column);
             if (!has_only_one_background_color || should_reverse_fill_for_cursor) {
                 auto cell_rect = character_rect.inflated(0, m_line_spacing);
@@ -877,9 +1085,6 @@ void Terminal::paint_event(GPaintEvent& event)
         auto cell_rect = glyph_rect(m_cursor_row, m_cursor_column).inflated(0, m_line_spacing);
         painter.draw_rect(cell_rect, lookup_color(line(m_cursor_row).attributes[m_cursor_column].foreground_color));
     }
-
-    if (m_belling)
-        painter.draw_rect(frame_inner_rect(), Color::Red);
 }
 
 void Terminal::set_window_title(const String& title)

+ 23 - 6
Applications/Terminal/Terminal.h

@@ -26,6 +26,9 @@ public:
     void apply_size_increments_to_window(GWindow&);
 
     void set_opacity(float);
+    float opacity() { return m_opacity; };
+    bool should_beep() { return m_should_beep; }
+    void set_should_beep(bool sb) { m_should_beep = sb; };
 
     RetainPtr<CConfigFile> config() const { return m_config; }
 
@@ -39,6 +42,7 @@ private:
     virtual const char* class_name() const override { return "Terminal"; }
 
     void scroll_up();
+    void scroll_down();
     void newline();
     void set_cursor(unsigned row, unsigned column);
     void put_character_at(unsigned row, unsigned column, byte ch);
@@ -57,14 +61,20 @@ private:
     void escape$J(const ParamVector&);
     void escape$K(const ParamVector&);
     void escape$M(const ParamVector&);
+    void escape$P(const ParamVector&);
     void escape$G(const ParamVector&);
     void escape$X(const ParamVector&);
+    void escape$b(const ParamVector&);
     void escape$d(const ParamVector&);
     void escape$m(const ParamVector&);
     void escape$s(const ParamVector&);
     void escape$u(const ParamVector&);
     void escape$t(const ParamVector&);
     void escape$r(const ParamVector&);
+    void escape$S(const ParamVector&);
+    void escape$T(const ParamVector&);
+    void escape$L(const ParamVector&);
+    void escape$h_l(bool, bool, const ParamVector&);
 
     void clear();
 
@@ -118,10 +128,11 @@ private:
         ~Line();
         void clear(Attribute);
         bool has_only_one_background_color() const;
+        void set_length(word);
         byte* characters { nullptr };
         Attribute* attributes { nullptr };
         bool dirty { false };
-        word length { 0 };
+        word m_length { 0 };
     };
     Line& line(size_t index)
     {
@@ -129,7 +140,10 @@ private:
         return *m_lines[index];
     }
 
-    Line** m_lines { nullptr };
+    Vector<OwnPtr<Line>> m_lines;
+
+    int m_scroll_region_top { 0 };
+    int m_scroll_region_bottom { 0 };
 
     word m_columns { 0 };
     word m_rows { 0 };
@@ -140,13 +154,14 @@ private:
     byte m_saved_cursor_column { 0 };
     bool m_stomp { false };
 
+    bool m_should_beep { false };
+
     Attribute m_current_attribute;
 
     void execute_escape_sequence(byte final);
     void execute_xterm_command();
 
-    enum EscapeState
-    {
+    enum EscapeState {
         Normal,
         ExpectBracket,
         ExpectParameter,
@@ -162,13 +177,12 @@ private:
     Vector<byte> m_intermediates;
     Vector<byte> m_xterm_param1;
     Vector<byte> m_xterm_param2;
+    Vector<bool> m_horizontal_tabs;
     byte m_final { 0 };
-    byte* m_horizontal_tabs { nullptr };
     bool m_belling { false };
 
     int m_pixel_width { 0 };
     int m_pixel_height { 0 };
-    int m_rows_to_scroll_backing_store { 0 };
 
     int m_inset { 2 };
     int m_line_spacing { 4 };
@@ -190,5 +204,8 @@ private:
     int m_glyph_width { 0 };
 
     CTimer m_cursor_blink_timer;
+    CTimer m_visual_beep_timer;
     RetainPtr<CConfigFile> m_config;
+
+    byte m_last_char { 0 };
 };

+ 80 - 39
Applications/Terminal/main.cpp

@@ -1,23 +1,26 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <sys/ioctl.h>
-#include <sys/select.h>
-#include <pwd.h>
 #include "Terminal.h"
 #include <Kernel/KeyCode.h>
-#include <LibGUI/GApplication.h>
-#include <LibGUI/GWidget.h>
-#include <LibGUI/GWindow.h>
-#include <LibGUI/GMenuBar.h>
+#include <LibCore/CUserInfo.h>
 #include <LibGUI/GAction.h>
+#include <LibGUI/GApplication.h>
+#include <LibGUI/GBoxLayout.h>
 #include <LibGUI/GFontDatabase.h>
+#include <LibGUI/GGroupBox.h>
+#include <LibGUI/GMenuBar.h>
+#include <LibGUI/GRadioButton.h>
 #include <LibGUI/GSlider.h>
-#include <LibCore/CUserInfo.h>
+#include <LibGUI/GWidget.h>
+#include <LibGUI/GWindow.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <unistd.h>
 
 static void make_shell(int ptm_fd)
 {
@@ -36,7 +39,7 @@ static void make_shell(int ptm_fd)
         }
 
         // NOTE: It's okay if this fails.
-        (void) ioctl(0, TIOCNOTTY);
+        (void)ioctl(0, TIOCNOTTY);
 
         close(0);
         close(1);
@@ -78,6 +81,54 @@ static void make_shell(int ptm_fd)
     }
 }
 
+GWindow* create_settings_window(Terminal& terminal, RetainPtr<CConfigFile> config)
+{
+    auto* window = new GWindow;
+    window->set_title("Terminal Settings");
+    window->set_rect(50, 50, 200, 140);
+
+    auto* settings = new GWidget;
+    window->set_main_widget(settings);
+    settings->set_fill_with_background_color(true);
+    settings->set_layout(make<GBoxLayout>(Orientation::Vertical));
+    settings->layout()->set_margins({ 4, 4, 4, 4 });
+
+    auto* radio_container = new GGroupBox("Bell Mode", settings);
+    radio_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
+    radio_container->layout()->set_margins({ 6, 16, 6, 6 });
+    radio_container->set_fill_with_background_color(true);
+    radio_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
+    radio_container->set_preferred_size({ 100, 70 });
+
+    auto* sysbell_radio = new GRadioButton("Use (Audible) System Bell", radio_container);
+    auto* visbell_radio = new GRadioButton("Use (Visual) Terminal Bell", radio_container);
+    sysbell_radio->set_checked(terminal.should_beep());
+    visbell_radio->set_checked(!terminal.should_beep());
+    sysbell_radio->on_checked = [&terminal](const bool checked) {
+        terminal.set_should_beep(checked);
+    };
+
+    auto* slider_container = new GGroupBox("Background Opacity", settings);
+    slider_container->set_layout(make<GBoxLayout>(Orientation::Vertical));
+    slider_container->layout()->set_margins({ 6, 16, 6, 6 });
+    slider_container->set_fill_with_background_color(true);
+    slider_container->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
+    slider_container->set_preferred_size({ 100, 50 });
+    auto* slider = new GSlider(slider_container);
+    slider->set_fill_with_background_color(true);
+    slider->set_background_color(Color::LightGray);
+
+    slider->on_value_changed = [&terminal, &config](int value) {
+        float opacity = value / 100.0;
+        terminal.set_opacity(opacity);
+    };
+
+    slider->set_range(0, 100);
+    slider->set_value(terminal.opacity() * 100.0);
+
+    return window;
+}
+
 int main(int argc, char** argv)
 {
     GApplication app(argc, argv);
@@ -106,23 +157,9 @@ int main(int argc, char** argv)
     terminal.apply_size_increments_to_window(*window);
     window->show();
     window->set_icon_path("/res/icons/16x16/app-terminal.png");
+    terminal.set_should_beep(config->read_bool_entry("Window", "AudibleBeep", false));
 
-    auto* opacity_adjustment_window = new GWindow;
-    opacity_adjustment_window->set_title("Adjust opacity");
-    opacity_adjustment_window->set_rect(50, 50, 200, 100);
-
-    auto* slider = new GSlider(nullptr);
-    opacity_adjustment_window->set_main_widget(slider);
-    slider->set_fill_with_background_color(true);
-    slider->set_background_color(Color::LightGray);
-
-    slider->on_value_changed = [&terminal, &config] (int value) {
-        float opacity = value / 100.0;
-        terminal.set_opacity(opacity);
-    };
-
-    slider->set_range(0, 100);
-    slider->set_value(100);
+    WeakPtr<GWindow> settings_window;
 
     auto new_opacity = config->read_num_entry("Window", "Opacity", 255);
     terminal.set_opacity((float)new_opacity / 255.0);
@@ -130,10 +167,14 @@ int main(int argc, char** argv)
     auto menubar = make<GMenuBar>();
 
     auto app_menu = make<GMenu>("Terminal");
-    app_menu->add_action(GAction::create("Adjust opacity...", [opacity_adjustment_window] (const GAction&) {
-        opacity_adjustment_window->show();
-    }));
-    app_menu->add_action(GAction::create("Quit", { Mod_Alt, Key_F4 }, [] (const GAction&) {
+    app_menu->add_action(GAction::create("Settings...",
+        [&settings_window, &terminal, &config](const GAction&) {
+            if (!settings_window)
+                settings_window = create_settings_window(terminal, config)->make_weak_ptr();
+            settings_window->show();
+            settings_window->move_to_front();
+        }));
+    app_menu->add_action(GAction::create("Quit", { Mod_Alt, Key_F4 }, [](const GAction&) {
         dbgprintf("Terminal: Quit menu activated!\n");
         GApplication::the().quit(0);
         return;
@@ -141,8 +182,8 @@ int main(int argc, char** argv)
     menubar->add_menu(move(app_menu));
 
     auto font_menu = make<GMenu>("Font");
-    GFontDatabase::the().for_each_fixed_width_font([&] (const String& font_name) {
-                                                       font_menu->add_action(GAction::create(font_name, [&terminal, &config] (const GAction& action) {
+    GFontDatabase::the().for_each_fixed_width_font([&](const StringView& font_name) {
+        font_menu->add_action(GAction::create(font_name, [&terminal, &config](const GAction& action) {
             terminal.set_font(GFontDatabase::the().get_by_name(action.text()));
             auto metadata = GFontDatabase::the().get_metadata_by_name(action.text());
             config->write_entry("Text", "Font", metadata.path);
@@ -153,7 +194,7 @@ int main(int argc, char** argv)
     menubar->add_menu(move(font_menu));
 
     auto help_menu = make<GMenu>("Help");
-    help_menu->add_action(GAction::create("About", [] (const GAction&) {
+    help_menu->add_action(GAction::create("About", [](const GAction&) {
         dbgprintf("FIXME: Implement Help/About\n");
     }));
     menubar->add_menu(move(help_menu));

+ 18 - 18
Applications/TextEditor/main.cpp

@@ -1,21 +1,21 @@
-#include <LibGUI/GWindow.h>
-#include <LibGUI/GWidget.h>
-#include <LibGUI/GBoxLayout.h>
+#include <AK/StringBuilder.h>
+#include <LibCore/CFile.h>
+#include <LibGUI/GAction.h>
 #include <LibGUI/GApplication.h>
+#include <LibGUI/GBoxLayout.h>
 #include <LibGUI/GFilePicker.h>
+#include <LibGUI/GFontDatabase.h>
+#include <LibGUI/GMenuBar.h>
 #include <LibGUI/GMessageBox.h>
 #include <LibGUI/GStatusBar.h>
-#include <LibGUI/GToolBar.h>
-#include <LibGUI/GMenuBar.h>
 #include <LibGUI/GTextEditor.h>
-#include <LibGUI/GAction.h>
-#include <LibGUI/GFontDatabase.h>
-#include <LibCore/CFile.h>
-#include <AK/StringBuilder.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <signal.h>
+#include <LibGUI/GToolBar.h>
+#include <LibGUI/GWidget.h>
+#include <LibGUI/GWindow.h>
 #include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
 
 void open_sesame(GWindow& window, GTextEditor& editor, const String& path)
 {
@@ -57,7 +57,7 @@ int main(int argc, char** argv)
         open_sesame(*window, *text_editor, path);
     }
 
-    auto new_action = GAction::create("New document", { Mod_Ctrl, Key_N }, GraphicsBitmap::load_from_file("/res/icons/16x16/new.png"), [] (const GAction&) {
+    auto new_action = GAction::create("New document", { Mod_Ctrl, Key_N }, GraphicsBitmap::load_from_file("/res/icons/16x16/new.png"), [](const GAction&) {
         dbgprintf("FIXME: Implement File/New\n");
     });
 
@@ -69,14 +69,14 @@ int main(int argc, char** argv)
         }
     });
 
-    auto save_action = GAction::create("Save document", { Mod_Ctrl, Key_S }, GraphicsBitmap::load_from_file("/res/icons/16x16/save.png"), [&] (const GAction&) {
+    auto save_action = GAction::create("Save document", { Mod_Ctrl, Key_S }, GraphicsBitmap::load_from_file("/res/icons/16x16/save.png"), [&](const GAction&) {
         dbgprintf("Writing document to '%s'\n", path.characters());
         text_editor->write_to_file(path);
     });
 
     auto menubar = make<GMenuBar>();
     auto app_menu = make<GMenu>("Text Editor");
-    app_menu->add_action(GAction::create("Quit", { Mod_Alt, Key_F4 }, [] (const GAction&) {
+    app_menu->add_action(GAction::create("Quit", { Mod_Alt, Key_F4 }, [](const GAction&) {
         GApplication::the().quit(0);
         return;
     }));
@@ -99,8 +99,8 @@ int main(int argc, char** argv)
     menubar->add_menu(move(edit_menu));
 
     auto font_menu = make<GMenu>("Font");
-    GFontDatabase::the().for_each_fixed_width_font([&] (const String& font_name) {
-        font_menu->add_action(GAction::create(font_name, [text_editor] (const GAction& action) {
+    GFontDatabase::the().for_each_fixed_width_font([&](const StringView& font_name) {
+        font_menu->add_action(GAction::create(font_name, [text_editor](const GAction& action) {
             text_editor->set_font(GFontDatabase::the().get_by_name(action.text()));
             text_editor->update();
         }));
@@ -108,7 +108,7 @@ int main(int argc, char** argv)
     menubar->add_menu(move(font_menu));
 
     auto help_menu = make<GMenu>("Help");
-    help_menu->add_action(GAction::create("About", [] (const GAction&) {
+    help_menu->add_action(GAction::create("About", [](const GAction&) {
         dbgprintf("FIXME: Implement Help/About\n");
     }));
     menubar->add_menu(move(help_menu));

+ 0 - 1
Base/etc/LookupServer.ini

@@ -1,3 +1,2 @@
 [DNS]
 IPAddress=8.8.8.8
-

+ 1 - 0
Base/etc/hosts

@@ -0,0 +1 @@
+127.0.0.1	localhost

+ 1 - 0
Base/home/anon/Terminal.ini

@@ -1,2 +1,3 @@
 [Window]
 Opacity=255
+AudibleBeep=0

+ 2 - 2
Base/home/anon/WindowManager.ini

@@ -1,5 +1,5 @@
 [Screen]
-Width=1080
+Width=1024
 Height=768
 
 [Cursor]
@@ -36,4 +36,4 @@ MenuSelectionColor=132,53,26
 DoubleClickSpeed=250
 
 [Background]
-Mode=center
+Mode=scaled

BIN
Base/res/icons/16x16/app-demo.png


BIN
Base/res/icons/paintbrush/bucket.png


BIN
Base/res/icons/paintbrush/pen.png


+ 3 - 0
Demos/Fire/.gitignore

@@ -0,0 +1,3 @@
+Fire
+*.o
+*.d

+ 236 - 0
Demos/Fire/Fire.cpp

@@ -0,0 +1,236 @@
+/* Fire.cpp - a (classic) graphics demo for Serenity, by pd.
+ * heavily based on the Fabien Sanglard's article:
+ * http://fabiensanglard.net/doom_fire_psx/index.html
+ *
+ * Future directions:
+ *  [X] This does suggest the need for a palletized graphics surface. Thanks kling!
+ *  [X] alternate column updates, or vertical interlacing. this would certainly alter
+ *      the effect, but the update load would be halved.
+ *  [/] scaled blit
+ *  [ ] dithering?
+ *  [X] inlining rand()
+ *  [/] precalculating and recycling random data
+ *  [ ] rework/expand palette
+ *  [ ] switch to use tsc values for perf check
+ *  [ ] handle mouse events differently for smoother painting (queue)
+ *  [ ] handle fire bitmap edges better
+*/
+
+#include <LibGUI/GApplication.h>
+#include <LibGUI/GLabel.h>
+#include <LibGUI/GPainter.h>
+#include <LibGUI/GWidget.h>
+#include <LibGUI/GWindow.h>
+#include <SharedGraphics/GraphicsBitmap.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define FIRE_WIDTH 320
+#define FIRE_HEIGHT 168
+#define FIRE_MAX 29
+
+const Color palette[] = {
+    Color(0x07, 0x07, 0x07), Color(0x1F, 0x07, 0x07), Color(0x2F, 0x0F, 0x07),
+    Color(0x47, 0x0F, 0x07), Color(0x57, 0x17, 0x07), Color(0x67, 0x1F, 0x07),
+    Color(0x77, 0x1F, 0x07), Color(0x9F, 0x2F, 0x07), Color(0xAF, 0x3F, 0x07),
+    Color(0xBF, 0x47, 0x07), Color(0xC7, 0x47, 0x07), Color(0xDF, 0x4F, 0x07),
+    Color(0xDF, 0x57, 0x07), Color(0xD7, 0x5F, 0x07), Color(0xD7, 0x5F, 0x07),
+    Color(0xD7, 0x67, 0x0F), Color(0xCF, 0x6F, 0x0F), Color(0xCF, 0x7F, 0x0F),
+    Color(0xCF, 0x87, 0x17), Color(0xC7, 0x87, 0x17), Color(0xC7, 0x8F, 0x17),
+    Color(0xC7, 0x97, 0x1F), Color(0xBF, 0x9F, 0x1F), Color(0xBF, 0xA7, 0x27),
+    Color(0xBF, 0xAF, 0x2F), Color(0xB7, 0xAF, 0x2F), Color(0xB7, 0xB7, 0x37),
+    Color(0xCF, 0xCF, 0x6F), Color(0xEF, 0xEF, 0xC7), Color(0xFF, 0xFF, 0xFF)
+};
+
+/* Random functions...
+ * These are from musl libc's prng/rand.c
+*/
+static uint64_t seed;
+
+void my_srand(unsigned s)
+{
+    seed = s - 1;
+}
+
+static int my_rand(void)
+{
+    seed = 6364136223846793005ULL * seed + 1;
+    return seed >> 33;
+}
+
+/*
+ * Fire Widget
+*/
+class Fire : public GWidget {
+public:
+    explicit Fire(GWidget* parent = nullptr);
+    virtual ~Fire() override;
+    void set_stat_label(GLabel* l) { stats = l; };
+
+private:
+    RetainPtr<GraphicsBitmap> bitmap;
+    GLabel* stats;
+
+    virtual void paint_event(GPaintEvent&) override;
+    virtual void timer_event(CTimerEvent&) override;
+    virtual void mousedown_event(GMouseEvent& event) override;
+    virtual void mousemove_event(GMouseEvent& event) override;
+    virtual void mouseup_event(GMouseEvent& event) override;
+
+    bool dragging;
+    int timeAvg;
+    int cycles;
+    int phase;
+};
+
+Fire::Fire(GWidget* parent)
+    : GWidget(parent)
+{
+    bitmap = GraphicsBitmap::create(GraphicsBitmap::Format::Indexed8, { 320, 200 });
+
+    /* Initialize fire palette */
+    for (int i = 0; i < 30; i++)
+        bitmap->set_palette_color(i, palette[i]);
+
+    /* Set remaining entries to white */
+    for (int i = 30; i < 256; i++)
+        bitmap->set_palette_color(i, Color::White);
+
+    dragging = false;
+    timeAvg = 0;
+    cycles = 0;
+    phase = 0;
+
+    my_srand(time(nullptr));
+    stop_timer();
+    start_timer(20);
+
+    /* Draw fire "source" on bottom row of pixels */
+    for (int i = 0; i < FIRE_WIDTH; i++)
+        bitmap->bits(bitmap->height() - 1)[i] = FIRE_MAX;
+
+    /* Set off initital paint event */
+    //update();
+}
+
+Fire::~Fire()
+{
+}
+
+void Fire::paint_event(GPaintEvent& event)
+{
+    CElapsedTimer timer;
+    timer.start();
+
+    GPainter painter(*this);
+    painter.add_clip_rect(event.rect());
+
+    /* Blit it! */
+    painter.draw_scaled_bitmap(event.rect(), *bitmap, bitmap->rect());
+
+    timeAvg += timer.elapsed();
+    cycles++;
+}
+
+void Fire::timer_event(CTimerEvent&)
+{
+    /* Update only even or odd columns per frame... */
+    phase++;
+    if (phase > 1)
+        phase = 0;
+
+    /* Paint our palettized buffer to screen */
+    for (int px = 0 + phase; px < FIRE_WIDTH; px += 2) {
+        for (int py = 1; py < 200; py++) {
+            int rnd = my_rand() % 3;
+
+            /* Calculate new pixel value, don't go below 0 */
+            byte nv = bitmap->bits(py)[px];
+            if (nv > 0)
+                nv -= (rnd & 1);
+
+            /* ...sigh... */
+            int epx = px + (1 - rnd);
+            if (epx < 0)
+                epx = 0;
+            else if (epx > FIRE_WIDTH)
+                epx = FIRE_WIDTH;
+
+            bitmap->bits(py - 1)[epx] = nv;
+        }
+    }
+
+    if ((cycles % 50) == 0) {
+        dbgprintf("%d total cycles. finished 50 in %d ms, avg %d ms\n", cycles, timeAvg, timeAvg / 50);
+        stats->set_text(String::format("%d ms", timeAvg / 50));
+        timeAvg = 0;
+    }
+
+    update();
+}
+
+/*
+ * Mouse handling events
+*/
+void Fire::mousedown_event(GMouseEvent& event)
+{
+    if (event.button() == GMouseButton::Left)
+        dragging = true;
+
+    return GWidget::mousedown_event(event);
+}
+
+/* FIXME: needs to account for the size of the window rect */
+void Fire::mousemove_event(GMouseEvent& event)
+{
+    if (dragging) {
+        if (event.y() >= 2 && event.y() < 398 && event.x() <= 638) {
+            int ypos = event.y() / 2;
+            int xpos = event.x() / 2;
+            bitmap->bits(ypos - 1)[xpos] = FIRE_MAX + 5;
+            bitmap->bits(ypos - 1)[xpos + 1] = FIRE_MAX + 5;
+            bitmap->bits(ypos)[xpos] = FIRE_MAX + 5;
+            bitmap->bits(ypos)[xpos + 1] = FIRE_MAX + 5;
+        }
+    }
+
+    return GWidget::mousemove_event(event);
+}
+
+void Fire::mouseup_event(GMouseEvent& event)
+{
+    if (event.button() == GMouseButton::Left)
+        dragging = false;
+
+    return GWidget::mouseup_event(event);
+}
+
+/*
+ * Main
+*/
+int main(int argc, char** argv)
+{
+    GApplication app(argc, argv);
+
+    auto* window = new GWindow;
+    window->set_should_exit_event_loop_on_close(true);
+    window->set_double_buffering_enabled(false);
+    window->set_title("Fire");
+    window->set_resizable(false);
+    window->set_rect(100, 100, 640, 400);
+
+    auto* fire = new Fire;
+    window->set_main_widget(fire);
+
+    auto* time = new GLabel(fire);
+    time->set_relative_rect({ 0, 4, 40, 10 });
+    time->move_by({ window->width() - time->width(), 0 });
+    time->set_foreground_color(Color::from_rgb(0x444444));
+    fire->set_stat_label(time);
+
+    window->show();
+    window->set_icon_path("/res/icons/16x16/app-demo.png");
+
+    return app.exec();
+}

+ 22 - 0
Demos/Fire/Makefile

@@ -0,0 +1,22 @@
+include ../../Makefile.common
+
+OBJS = \
+    Fire.o
+
+APP = Fire
+
+DEFINES += -DUSERLAND
+
+all: $(APP)
+
+$(APP): $(OBJS)
+	$(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lgui -lcore -lc
+
+.cpp.o:
+	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
+
+-include $(OBJS:%.o=%.d)
+
+clean:
+	@echo "CLEAN"; rm -f $(APP) $(OBJS) *.d
+

+ 5 - 5
Demos/HelloWorld/main.cpp

@@ -1,9 +1,9 @@
 #include <LibGUI/GApplication.h>
-#include <LibGUI/GWindow.h>
-#include <LibGUI/GWidget.h>
-#include <LibGUI/GLabel.h>
-#include <LibGUI/GButton.h>
 #include <LibGUI/GBoxLayout.h>
+#include <LibGUI/GButton.h>
+#include <LibGUI/GLabel.h>
+#include <LibGUI/GWidget.h>
+#include <LibGUI/GWindow.h>
 
 int main(int argc, char** argv)
 {
@@ -27,7 +27,7 @@ int main(int argc, char** argv)
     button->set_text("Good-bye");
     button->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
     button->set_preferred_size({ 0, 20 });
-    button->on_click = [&] (GButton&) {
+    button->on_click = [&](GButton&) {
         app.quit();
     };
 

Неке датотеке нису приказане због велике количине промена