Merge remote-tracking branch 'origin/master' into serenity-keys
This commit is contained in:
commit
b635c3db54
Notes:
sideshowbarker
2024-07-19 13:35:36 +09:00
Author: https://github.com/faissaloo Commit: https://github.com/SerenityOS/serenity/commit/b635c3db547 Pull-request: https://github.com/SerenityOS/serenity/pull/173 Reviewed-by: https://github.com/awesomekling
527 changed files with 9637 additions and 5614 deletions
|
@ -10,4 +10,3 @@ IndentPPDirectives: AfterHash
|
|||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterFunction: true
|
||||
AfterEnum: true
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -12,3 +12,5 @@ Toolchain/Tarballs
|
|||
Toolchain/Build
|
||||
Toolchain/Local
|
||||
.vscode
|
||||
compile_commands.json
|
||||
.clang_complete
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
AK/Badge.h
13
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
AK/Bitmap.h
67
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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 "(?)";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,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;
|
||||
};
|
||||
|
||||
|
|
1032
AK/ELF/exec_elf.h
1032
AK/ELF/exec_elf.h
File diff suppressed because it is too large
Load diff
|
@ -5,7 +5,7 @@
|
|||
|
||||
namespace AK {
|
||||
|
||||
FileSystemPath::FileSystemPath(const String& s)
|
||||
FileSystemPath::FileSystemPath(const StringView& s)
|
||||
: m_string(s)
|
||||
{
|
||||
m_is_valid = canonicalize();
|
||||
|
|
|
@ -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
AK/IterationDecision.h
Normal file
12
AK/IterationDecision.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
namespace AK {
|
||||
|
||||
enum class IterationDecision {
|
||||
Continue,
|
||||
Break,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::IterationDecision;
|
|
@ -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);
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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
AK/Queue.h
Normal file
49
AK/Queue.h
Normal file
|
@ -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;
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/StdLibExtras.h>
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T>
|
||||
|
|
|
@ -103,20 +103,41 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
RetainPtr& operator=(T* ptr)
|
||||
template<typename U>
|
||||
RetainPtr& operator=(const Retained<U>& other)
|
||||
{
|
||||
if (m_ptr != ptr)
|
||||
if (m_ptr != other.ptr())
|
||||
release_if_not_null(m_ptr);
|
||||
m_ptr = ptr;
|
||||
m_ptr = const_cast<T*>(other.ptr());
|
||||
ASSERT(m_ptr);
|
||||
retain_if_not_null(m_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RetainPtr& operator=(T& object)
|
||||
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 = const_cast<T*>(ptr);
|
||||
retain_if_not_null(m_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
AK/ScopeGuard.h
Normal file
24
AK/ScopeGuard.h
Normal file
|
@ -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;
|
|
@ -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;
|
||||
|
|
|
@ -292,4 +292,5 @@ using AK::IsSame;
|
|||
using AK::max;
|
||||
using AK::min;
|
||||
using AK::move;
|
||||
using AK::RemoveConst;
|
||||
using AK::swap;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
#include "StdLibExtras.h"
|
||||
#include "kmalloc.h"
|
||||
|
||||
#ifndef __serenity__
|
||||
#include <new>
|
||||
#endif
|
||||
|
||||
//#define DEBUG_STRINGIMPL
|
||||
|
||||
#ifdef DEBUG_STRINGIMPL
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
AK/Tests/.gitignore
vendored
Normal file
2
AK/Tests/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
TestString
|
||||
TestQueue
|
12
AK/Tests/Makefile
Normal file
12
AK/Tests/Makefile
Normal file
|
@ -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
AK/Tests/TestHelpers.h
Normal file
68
AK/Tests/TestHelpers.h
Normal file
|
@ -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
AK/Tests/TestQueue.cpp
Normal file
43
AK/Tests/TestQueue.cpp
Normal file
|
@ -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
AK/Tests/TestString.cpp
Normal file
59
AK/Tests/TestString.cpp
Normal file
|
@ -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;
|
||||
}
|
27
AK/Time.h
27
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;
|
||||
|
|
|
@ -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
AK/ValueRestorer.h
Normal file
26
AK/ValueRestorer.h
Normal file
|
@ -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
AK/Vector.h
17
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())
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
#include <LibGUI/GWindow.h>
|
||||
#include <LibGUI/GWidget.h>
|
||||
#include <LibGUI/GBoxLayout.h>
|
||||
#include "DirectoryView.h"
|
||||
#include <AK/FileSystemPath.h>
|
||||
#include <LibCore/CUserInfo.h>
|
||||
#include <LibGUI/GAction.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/GSplitter.h>
|
||||
#include <LibGUI/GStatusBar.h>
|
||||
#include <LibGUI/GTextEditor.h>
|
||||
#include <LibGUI/GToolBar.h>
|
||||
#include <LibGUI/GMenuBar.h>
|
||||
#include <LibGUI/GAction.h>
|
||||
#include <LibGUI/GLabel.h>
|
||||
#include <LibGUI/GInputBox.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/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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
#include "IRCAppWindow.h"
|
||||
#include "IRCWindow.h"
|
||||
#include "IRCWindowListModel.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/GApplication.h>
|
||||
#include <LibGUI/GBoxLayout.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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)); }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -6,8 +6,7 @@ class IRCLogBuffer;
|
|||
|
||||
class IRCLogBufferModel final : public GModel {
|
||||
public:
|
||||
enum Column
|
||||
{
|
||||
enum Column {
|
||||
Timestamp = 0,
|
||||
Name,
|
||||
Text,
|
||||
|
|
|
@ -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/GTableView.h>
|
||||
#include <LibGUI/GTextEditor.h>
|
||||
#include <LibGUI/GTextBox.h>
|
||||
#include <LibGUI/GSplitter.h>
|
||||
#include <LibGUI/GTableView.h>
|
||||
#include <LibGUI/GTextBox.h>
|
||||
#include <LibGUI/GTextEditor.h>
|
||||
|
||||
IRCWindow::IRCWindow(IRCClient& client, void* owner, Type type, const String& name, GWidget* parent)
|
||||
: GWidget(parent)
|
||||
|
|
|
@ -11,8 +11,7 @@ class GTextEditor;
|
|||
|
||||
class IRCWindow : public GWidget {
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
enum Type {
|
||||
Server,
|
||||
Channel,
|
||||
Query,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -8,8 +8,7 @@ class IRCWindow;
|
|||
|
||||
class IRCWindowListModel final : public GModel {
|
||||
public:
|
||||
enum Column
|
||||
{
|
||||
enum Column {
|
||||
Name,
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <LibGUI/GButton.h>
|
||||
#include <LibGUI/GWidget.h>
|
||||
#include <LibGUI/GWindow.h>
|
||||
#include <SharedGraphics/GraphicsBitmap.h>
|
||||
#include <errno.h>
|
||||
#include <LibCore/CUserInfo.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.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
Applications/PaintBrush/.gitignore
vendored
Normal file
3
Applications/PaintBrush/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.o
|
||||
*.d
|
||||
PaintBrush
|
55
Applications/PaintBrush/BucketTool.cpp
Normal file
55
Applications/PaintBrush/BucketTool.cpp
Normal file
|
@ -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
Applications/PaintBrush/BucketTool.h
Normal file
14
Applications/PaintBrush/BucketTool.h
Normal file
|
@ -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
Applications/PaintBrush/Makefile
Normal file
28
Applications/PaintBrush/Makefile
Normal file
|
@ -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
Applications/PaintBrush/PaintableWidget.cpp
Normal file
60
Applications/PaintBrush/PaintableWidget.cpp
Normal file
|
@ -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
Applications/PaintBrush/PaintableWidget.h
Normal file
42
Applications/PaintBrush/PaintableWidget.h
Normal file
|
@ -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
Applications/PaintBrush/PaletteWidget.cpp
Normal file
131
Applications/PaintBrush/PaletteWidget.cpp
Normal file
|
@ -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
Applications/PaintBrush/PaletteWidget.h
Normal file
21
Applications/PaintBrush/PaletteWidget.h
Normal file
|
@ -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
Applications/PaintBrush/PenTool.cpp
Normal file
48
Applications/PaintBrush/PenTool.cpp
Normal file
|
@ -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
Applications/PaintBrush/PenTool.h
Normal file
19
Applications/PaintBrush/PenTool.h
Normal file
|
@ -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
Applications/PaintBrush/Tool.cpp
Normal file
9
Applications/PaintBrush/Tool.cpp
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include "Tool.h"
|
||||
|
||||
Tool::Tool()
|
||||
{
|
||||
}
|
||||
|
||||
Tool::~Tool()
|
||||
{
|
||||
}
|
18
Applications/PaintBrush/Tool.h
Normal file
18
Applications/PaintBrush/Tool.h
Normal file
|
@ -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
Applications/PaintBrush/ToolboxWidget.cpp
Normal file
64
Applications/PaintBrush/ToolboxWidget.cpp
Normal file
|
@ -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
Applications/PaintBrush/ToolboxWidget.h
Normal file
13
Applications/PaintBrush/ToolboxWidget.h
Normal file
|
@ -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
Applications/PaintBrush/main.cpp
Normal file
58
Applications/PaintBrush/main.cpp
Normal file
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#include <LibCore/CTimer.h>
|
||||
#include <LibGUI/GWindow.h>
|
||||
#include <LibGUI/GWidget.h>
|
||||
#include <LibGUI/GBoxLayout.h>
|
||||
#include <LibGUI/GApplication.h>
|
||||
#include <LibGUI/GToolBar.h>
|
||||
#include <LibGUI/GMenuBar.h>
|
||||
#include <LibGUI/GGroupBox.h>
|
||||
#include <LibGUI/GAction.h>
|
||||
#include <LibGUI/GTabWidget.h>
|
||||
#include <LibGUI/GLabel.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include "ProcessTableView.h"
|
||||
#include "MemoryStatsWidget.h"
|
||||
#include "GraphWidget.h"
|
||||
#include "MemoryStatsWidget.h"
|
||||
#include "ProcessTableView.h"
|
||||
#include <LibCore/CTimer.h>
|
||||
#include <LibGUI/GAction.h>
|
||||
#include <LibGUI/GApplication.h>
|
||||
#include <LibGUI/GBoxLayout.h>
|
||||
#include <LibGUI/GGroupBox.h>
|
||||
#include <LibGUI/GLabel.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 <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));
|
||||
|
|
|
@ -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");
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,5 +1,5 @@
|
|||
#include <LibGUI/GApplication.h>
|
||||
#include "TaskbarWindow.h"
|
||||
#include <LibGUI/GApplication.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
|
|
1
Applications/Terminal/.gitignore
vendored
1
Applications/Terminal/.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
*.o
|
||||
*.d
|
||||
Terminal
|
||||
compile_commands.json
|
||||
|
|
|
@ -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 <LibGUI/GApplication.h>
|
||||
#include <LibGUI/GWindow.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <Kernel/KeyCode.h>
|
||||
#include <LibGUI/GApplication.h>
|
||||
#include <LibGUI/GPainter.h>
|
||||
#include <LibGUI/GWindow.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)
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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 <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 <LibGUI/GWidget.h>
|
||||
#include <LibGUI/GWindow.h>
|
||||
#include <LibGUI/GMenuBar.h>
|
||||
#include <LibGUI/GAction.h>
|
||||
#include <LibGUI/GFontDatabase.h>
|
||||
#include <LibGUI/GSlider.h>
|
||||
#include <LibCore/CUserInfo.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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
[DNS]
|
||||
IPAddress=8.8.8.8
|
||||
|
||||
|
|
1
Base/etc/hosts
Normal file
1
Base/etc/hosts
Normal file
|
@ -0,0 +1 @@
|
|||
127.0.0.1 localhost
|
|
@ -1,2 +1,3 @@
|
|||
[Window]
|
||||
Opacity=255
|
||||
AudibleBeep=0
|
||||
|
|
|
@ -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
Normal file
BIN
Base/res/icons/16x16/app-demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
BIN
Base/res/icons/paintbrush/bucket.png
Normal file
BIN
Base/res/icons/paintbrush/bucket.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 334 B |
BIN
Base/res/icons/paintbrush/pen.png
Normal file
BIN
Base/res/icons/paintbrush/pen.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 333 B |
3
Demos/Fire/.gitignore
vendored
Normal file
3
Demos/Fire/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
Fire
|
||||
*.o
|
||||
*.d
|
236
Demos/Fire/Fire.cpp
Normal file
236
Demos/Fire/Fire.cpp
Normal file
|
@ -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
Demos/Fire/Makefile
Normal file
22
Demos/Fire/Makefile
Normal file
|
@ -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
|
||||
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue