Squash commits for public release

This commit is contained in:
2025-02-12 09:54:05 -05:00
commit 7118adc514
1108 changed files with 80873 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
import("//build/userland/TEMPLATE.gni")
xOS_executable("launch_server") {
signexec = true
install_path = "System/"
sources = [
"LaunchWatchdog.cpp",
"main.cpp",
]
configs = [ "//build/userland:userland_flags" ]
deplibs = [
"libcxx",
"libfoundation",
]
}

View File

@@ -0,0 +1,41 @@
#pragma once
#include <csignal>
#include <string>
#include <unistd.h>
#include <vector>
namespace LaunchServer {
class Exec {
public:
enum Flags {
None = 0,
RestartOnFail = (1 << 0),
};
Exec(const std::string& path, Flags flag = Flags::None)
: m_path(path)
, m_flags(flag)
{
}
~Exec() = default;
void launch()
{
m_pid = fork();
if (m_pid == 0) {
execlp(m_path.c_str(), m_path.c_str(), NULL);
std::abort();
}
}
bool is_alive() const { return m_pid > 0 && kill(m_pid, 0) == 0; }
private:
std::string m_path;
Flags m_flags;
int m_pid { -1 };
};
}

View File

@@ -0,0 +1,13 @@
#include "LaunchWatchdog.h"
namespace LaunchServer {
LaunchWatchdog* s_LaunchServer_LaunchWatchdog_the = nullptr;
LaunchWatchdog::LaunchWatchdog()
: LFoundation::EventReceiver()
{
s_LaunchServer_LaunchWatchdog_the = this;
}
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include "Exec.h"
#include <iostream>
#include <libfoundation/EventReceiver.h>
#include <vector>
namespace LaunchServer {
class LaunchWatchdog : public LFoundation::EventReceiver {
public:
inline static LaunchWatchdog& the()
{
extern LaunchWatchdog* s_LaunchServer_LaunchWatchdog_the;
return *s_LaunchServer_LaunchWatchdog_the;
}
LaunchWatchdog();
~LaunchWatchdog() = default;
void tick()
{
for (auto& exec : m_execs) {
if (!exec.is_alive()) {
exec.launch();
}
}
}
void add(const Exec& exec) { m_execs.push_back(exec); }
void add(Exec&& exec) { m_execs.push_back(std::move(exec)); }
private:
std::vector<Exec> m_execs;
};
}

View File

@@ -0,0 +1,34 @@
#include "LaunchWatchdog.h"
#include <libfoundation/EventLoop.h>
#include <libfoundation/json/Parser.h>
#include <new>
void load_from_file(LaunchServer::LaunchWatchdog& launch_watchdog)
{
auto json_parser = LFoundation::Json::Parser("/System/launch_server_config.json");
LFoundation::Json::Object* jobj_root = json_parser.object();
if (jobj_root->invalid()) {
std::abort();
}
auto* jdict_root = jobj_root->cast_to<LFoundation::Json::DictObject>();
auto* jlaunch_list = jdict_root->data()["launch"]->cast_to<LFoundation::Json::ListObject>();
for (auto* jobj : jlaunch_list->data()) {
const std::string& strdata = jobj->cast_to<LFoundation::Json::StringObject>()->data();
launch_watchdog.add(LaunchServer::Exec(strdata, LaunchServer::Exec::Flags::RestartOnFail));
}
}
int main(int argc, char** argv)
{
auto* event_loop = new LFoundation::EventLoop();
auto* launch_watchdog = new LaunchServer::LaunchWatchdog();
load_from_file(*launch_watchdog);
launch_watchdog->tick();
event_loop->add(LFoundation::Timer([launch_watchdog] {
launch_watchdog->tick();
},
5000, LFoundation::Timer::Repeat));
return event_loop->run();
}

View File

@@ -0,0 +1,53 @@
import("//build/userland/TEMPLATE.gni")
xOS_executable("window_server") {
signexec = true
install_path = "System/"
sources = [
"src/Components/Base/BaseWindow.cpp",
"src/Components/Elements/Button.cpp",
"src/Components/LoadingScreen/LoadingScreen.cpp",
"src/Components/MenuBar/MenuBar.cpp",
"src/Components/Popup/Popup.cpp",
"src/Devices/Devices.cpp",
"src/Devices/Screen.cpp",
"src/IPC/Connection.cpp",
"src/IPC/ServerDecoder.cpp",
"src/Managers/Compositor.cpp",
"src/Managers/CursorManager.cpp",
"src/Managers/ResourceManager.cpp",
"src/Managers/WindowManager.cpp",
"src/main.cpp",
]
if (device_type == "desktop") {
cflags = [ "-DTARGET_DESKTOP" ]
sources += [
"src/Target/Desktop/Window.cpp",
"src/Target/Desktop/WindowFrame.cpp",
]
}
if (device_type == "mobile") {
cflags = [ "-DTARGET_MOBILE" ]
sources += [
"src/Components/ControlBar/ControlBar.cpp",
"src/Target/Mobile/Window.cpp",
]
}
configs = [ "//build/userland:userland_flags" ]
if (host == "llvm") {
cflags += [ "-flto" ]
}
deplibs = [
"libcxx",
"libfoundation",
"libipc",
"libg",
"libapi",
]
include_dirs = [ "//servers/window_server/src/" ]
}

View File

@@ -0,0 +1,40 @@
#include "BaseWindow.h"
#include "../../Managers/WindowManager.h"
#include <utility>
namespace WinServer {
BaseWindow::BaseWindow(int connection_id, int id, CreateWindowMessage& msg)
: m_id(id)
, m_connection_id(connection_id)
, m_type((WindowType)msg.type())
, m_buffer(msg.buffer_id())
, m_content_bitmap()
, m_bounds(0, 0, 0, 0)
, m_content_bounds(0, 0, 0, 0)
, m_app_name(msg.title().string())
, m_bundle_id(msg.bundle_id().string())
{
}
BaseWindow::BaseWindow(BaseWindow&& win)
: m_id(win.m_id)
, m_connection_id(win.m_connection_id)
, m_buffer(win.m_buffer)
, m_content_bitmap(std::move(win.m_content_bitmap))
, m_bounds(win.m_bounds)
, m_content_bounds(win.m_content_bounds)
, m_app_name(std::move(win.m_app_name))
, m_icon_path(std::move(win.m_icon_path))
, m_bundle_id(std::move(win.m_bundle_id))
{
}
void BaseWindow::set_buffer(int buffer_id, LG::Size sz, LG::PixelBitmapFormat fmt)
{
m_buffer.open(buffer_id);
m_content_bitmap = LG::PixelBitmap(m_buffer.data(), sz.width(), sz.height());
m_content_bitmap.set_format(fmt);
}
} // namespace WinServer

View File

@@ -0,0 +1,92 @@
#pragma once
#include "../../IPC/Connection.h"
#include "../MenuBar/MenuItem.h"
#include <libapi/window_server/MessageContent/MenuBar.h>
#include <libapi/window_server/MessageContent/Window.h>
#include <libfoundation/SharedBuffer.h>
#include <libg/PixelBitmap.h>
#include <libg/Rect.h>
#include <libg/Size.h>
#include <sys/types.h>
#include <utility>
namespace WinServer {
typedef uint32_t WindowEventMask;
enum WindowEvent {
WindowStatus = (1 << 0),
WindowCreation = (1 << 1),
IconChange = (1 << 2),
TitleChange = (1 << 3),
};
class BaseWindow {
public:
BaseWindow(int connection_id, int id, CreateWindowMessage& msg);
BaseWindow(BaseWindow&& win);
~BaseWindow() = default;
void set_buffer(int buffer_id, LG::Size sz, LG::PixelBitmapFormat fmt);
inline int id() const { return m_id; }
inline int connection_id() const { return m_connection_id; }
inline WindowType type() const { return m_type; }
inline WindowEventMask event_mask() const { return m_event_mask; }
inline void set_event_mask(WindowEventMask mask) { m_event_mask = mask; }
inline LFoundation::SharedBuffer<LG::Color>& buffer() { return m_buffer; }
inline LG::PixelBitmap& content_bitmap() { return m_content_bitmap; }
inline const LG::PixelBitmap& content_bitmap() const { return m_content_bitmap; }
inline LG::Rect& content_bounds() { return m_content_bounds; }
inline const LG::Rect& content_bounds() const { return m_content_bounds; }
inline LG::Rect& bounds() { return m_bounds; }
inline const LG::Rect& bounds() const { return m_bounds; }
inline const std::string& app_name() const { return m_app_name; }
inline const std::string& bundle_id() const { return m_bundle_id; }
inline const std::string& app_title() const { return m_app_title; }
inline void set_app_title(const std::string& title) { m_app_title = title, did_app_title_change(); }
virtual void did_app_title_change() { }
inline const std::string& icon_path() const { return m_icon_path; }
inline void set_icon_path(std::string&& name) { m_icon_path = std::move(name), did_icon_path_change(); }
inline void set_icon_path(const std::string& name) { m_icon_path = name, did_icon_path_change(); }
virtual void did_icon_path_change() { }
inline bool visible() const { return m_visible; }
inline void set_visible(bool vis) { m_visible = vis; }
inline void set_needs_display(const LG::Rect& rect) const
{
DisplayMessage msg(connection_id(), rect);
Connection::the().send_async_message(msg);
}
inline void offset_by(int x_offset, int y_offset)
{
bounds().offset_by(x_offset, y_offset);
content_bounds().offset_by(x_offset, y_offset);
}
virtual void did_size_change(const LG::Size& size) { }
protected:
int m_id { -1 };
int m_connection_id { -1 };
bool m_visible { true };
WindowType m_type { WindowType::Standard };
WindowEventMask m_event_mask { 0 };
LG::Rect m_bounds;
LG::Rect m_content_bounds;
LG::PixelBitmap m_content_bitmap;
std::string m_app_name {};
std::string m_app_title {};
std::string m_icon_path {};
std::string m_bundle_id {};
LFoundation::SharedBuffer<LG::Color> m_buffer;
};
} // namespace WinServer

View File

@@ -0,0 +1,21 @@
#include "ControlBar.h"
#include "../../Devices/Screen.h"
#include "../../Managers/Compositor.h"
#include <libg/ImageLoaders/PNGLoader.h>
namespace WinServer {
ControlBar* s_WinServer_ControlBar_the = nullptr;
ControlBar::ControlBar()
: m_bounds(0, Screen::the().bounds().height() - height(), Screen::the().bounds().width(), height())
{
s_WinServer_ControlBar_the = this;
LG::PNG::PNGLoader loader;
m_menu_icon = loader.load_from_file("/res/system/mobile/control.png");
int x = width() / 2 - m_menu_icon.width() / 2;
int y = Screen::the().bounds().height() - height() / 2 - m_menu_icon.height() / 2;
m_button_bounds = LG::Rect(x, y, m_menu_icon.width(), m_menu_icon.height());
}
} // namespace WinServer

View File

@@ -0,0 +1,40 @@
#pragma once
#include <libfoundation/Logger.h>
#include <libg/Context.h>
#include <libg/PixelBitmap.h>
#include <libg/Point.h>
#include <vector>
namespace WinServer {
class ControlBar {
public:
inline static ControlBar& the()
{
extern ControlBar* s_WinServer_ControlBar_the;
return *s_WinServer_ControlBar_the;
}
ControlBar();
static constexpr size_t height() { return 20; }
static constexpr size_t padding() { return 4; }
static constexpr size_t menubar_content_offset() { return 20; }
size_t width() const { return m_bounds.width(); }
LG::Rect& bounds() { return m_bounds; }
const LG::Rect& bounds() const { return m_bounds; }
const LG::Rect& control_button_bounds() const { return m_button_bounds; }
[[gnu::always_inline]] inline void draw(LG::Context& ctx)
{
ctx.draw({ control_button_bounds().min_x(), control_button_bounds().min_y() }, m_menu_icon);
}
private:
LG::Rect m_bounds;
LG::Rect m_button_bounds;
LG::PixelBitmap m_menu_icon;
};
} // namespace WinServer

View File

@@ -0,0 +1,37 @@
#include "Button.h"
#include "../Helpers/TextDrawer.h"
#include <algorithm>
namespace WinServer {
void Button::recalc_dims()
{
size_t new_width = 0;
size_t new_height = 0;
if (m_is_icon_set) {
new_height = m_icon.height();
new_width += m_icon.width();
if (m_title.size()) {
new_width += 4;
}
}
bounds().set_width(new_width + text_width());
bounds().set_height(std::max(new_height, text_height()));
}
size_t Button::text_width()
{
return Helpers::text_width(m_title, font());
}
void Button::display(LG::Context& ctx, LG::Point<int> pt)
{
if (m_is_icon_set) {
ctx.draw(pt, m_icon);
pt.offset_by(m_icon.width() + 4, 0);
}
Helpers::draw_text(ctx, pt, m_title, font());
}
} // namespace WinServer

View File

@@ -0,0 +1,46 @@
#pragma once
#include <libg/Color.h>
#include <libg/Context.h>
#include <string>
namespace WinServer {
class Button {
public:
Button() = default;
~Button() = default;
void display();
void set_title(const std::string& title) { m_title = title, recalc_dims(); }
void set_title(std::string&& title) { m_title = std::move(title), recalc_dims(); }
const std::string& title() const { return m_title; }
void set_font(const LG::Font& font) { m_font = font, recalc_dims(); }
void set_icon(const LG::Glyph& icon) { m_is_icon_set = true, m_icon = icon, recalc_dims(); }
void set_title_color(const LG::Color& color) { m_title_color = color; }
const LG::Color& title_color() const { return m_title_color; }
inline const LG::Font& font() const { return m_font; }
inline LG::Rect& bounds() { return m_bounds; }
inline const LG::Rect& bounds() const { return m_bounds; }
void display(LG::Context& ctx, LG::Point<int> pt);
private:
void recalc_dims();
size_t text_width();
inline size_t text_height() const { return font().size(); }
LG::Rect m_bounds {};
std::string m_title {};
LG::Font m_font { LG::Font::system_font() };
LG::Color m_title_color;
LG::Glyph m_icon;
bool m_is_icon_set { false };
};
} // namespace WinServer

View File

@@ -0,0 +1,30 @@
#pragma once
#include <libg/Color.h>
#include <libg/Context.h>
#include <libg/Font.h>
#include <string_view>
namespace WinServer {
namespace Helpers {
[[gnu::always_inline]] inline static size_t text_width(const std::string_view& text, const LG::Font& f)
{
size_t width = 0;
for (int i = 0; i < text.size(); i++) {
width += f.glyph(text[i]).advance();
}
return width;
}
[[gnu::always_inline]] inline static void draw_text(LG::Context& ctx, LG::Point<int> pt, const std::string_view& text, const LG::Font& f)
{
for (int i = 0; i < text.size(); i++) {
ctx.draw(pt, f.glyph(text[i]));
pt.offset_by(f.glyph(text[i]).advance(), 0);
}
}
} // namespace Helpers
} // namespace WinServer

View File

@@ -0,0 +1,95 @@
#include "LoadingScreen.h"
#include "../Helpers/TextDrawer.h"
#include <libfoundation/Memory.h>
#include <libg/Context.h>
#include <libg/ImageLoaders/PNGLoader.h>
#include <unistd.h>
namespace WinServer {
LoadingScreen* s_WinServer_LoadingScreen_the = nullptr;
LoadingScreen::LoadingScreen()
: m_screen(Screen::the())
{
s_WinServer_LoadingScreen_the = this;
run_intro_animation();
}
void LoadingScreen::display_status_bar(int progress, int out_of)
{
LG::Context ctx(m_screen.write_bitmap());
int widthp = (progress * progress_line_width()) / out_of;
ctx.set_fill_color(LG::Color(20, 20, 20));
ctx.fill_rounded(LG::Rect(m_progress_line_min_x, m_progress_line_min_y, progress_line_width(), progress_line_height()), LG::CornerMask(4));
ctx.set_fill_color(LG::Color::White);
ctx.fill_rounded(LG::Rect(m_progress_line_min_x, m_progress_line_min_y, widthp, progress_line_height()), LG::CornerMask(4));
m_screen.swap_buffers();
}
void LoadingScreen::animation_frame(LG::Context& ctx, LG::Point<int> pt, int cur_frame, int total_frames)
{
// Applying a cubic-easing.
int animation_window = total_frames / m_logo_text.size();
int animation_frames_per_char = 2 * animation_window;
int frame = total_frames - cur_frame;
frame = total_frames - frame * frame * frame / (total_frames * total_frames);
for (int i = 0; i < m_logo_text.size(); i++) {
int end_frame = animation_window * (i + 1);
int start_frame = std::max(0, end_frame - animation_frames_per_char);
// Knowing animation bounds for current char and current frame, we calculate of animation
// at this frame. This data is used to calcualte alpha and offset for the current char.
int animation_progress = std::max(0, std::min(frame - start_frame, animation_frames_per_char));
int alpha = (255 * (animation_progress)) / animation_frames_per_char;
// Offset is calculated based on alpha, maybe we could move out this consts.
pt.offset_by((alpha / 30) - 8, 0);
ctx.set_fill_color(LG::Color(255, 255, 255, alpha));
ctx.draw(pt, m_font.glyph(m_logo_text[i]));
pt.offset_by(m_font.glyph(m_logo_text[i]).advance(), 0);
}
}
void LoadingScreen::run_intro_animation()
{
const int frames = 102; // 1.7s * 60fps
size_t text_height = 64;
size_t text_width = Helpers::text_width(m_logo_text, m_font);
// Preparing area for animation
int animation_spread = 10;
int content_min_x = m_screen.bounds().mid_x() - (text_width / 2);
int content_min_y = m_screen.bounds().mid_y() - ((text_height + progress_line_height()) / 2);
auto animation_rect = LG::Rect({ content_min_x - animation_spread, content_min_y, text_width + 2 * animation_spread, text_height });
LG::Context ctx(m_screen.display_bitmap());
for (int frame = 0; frame < frames; frame++) {
ctx.set_fill_color(LG::Color::Black);
ctx.fill(animation_rect);
animation_frame(ctx, { content_min_x, content_min_y }, frame, frames);
m_screen.swap_buffers();
// Copying current progress to backing storage.
auto* buf1_ptr = reinterpret_cast<uint32_t*>(&m_screen.display_bitmap()[content_min_y][content_min_x]);
auto* buf2_ptr = reinterpret_cast<uint32_t*>(&m_screen.write_bitmap()[content_min_y][content_min_x]);
for (int j = 0; j < text_height; j++) {
LFoundation::fast_copy(buf2_ptr, buf1_ptr, text_width);
buf1_ptr += m_screen.width();
buf2_ptr += m_screen.width();
}
// Going to sleep until the next frame.
usleep(900000 / 60);
}
m_progress_line_min_x = m_screen.bounds().mid_x() - (progress_line_width() / 2);
m_progress_line_min_y = content_min_y + text_height;
}
} // namespace WinServer

View File

@@ -0,0 +1,69 @@
#pragma once
#include "../../Devices/Screen.h"
#include <libg/Color.h>
#include <libg/Context.h>
#include <libg/Font.h>
#include <libg/PixelBitmap.h>
#include <memory>
#include <string_view>
namespace WinServer {
template <typename T, int Cost = 1>
class AfterComponentLoadProgress {
public:
static const int cost = Cost;
static const size_t progress;
};
static size_t total_cost = 0;
template <int Cost>
inline size_t __calc_total_cost()
{
return total_cost += Cost;
}
template <typename T, int Cost>
const size_t AfterComponentLoadProgress<T, Cost>::progress = __calc_total_cost<Cost>();
class LoadingScreen {
public:
inline static LoadingScreen& the()
{
extern LoadingScreen* s_WinServer_LoadingScreen_the;
return *s_WinServer_LoadingScreen_the;
}
inline static void destroy_the()
{
extern LoadingScreen* s_WinServer_LoadingScreen_the;
delete s_WinServer_LoadingScreen_the;
s_WinServer_LoadingScreen_the = nullptr;
}
LoadingScreen();
~LoadingScreen() = default;
template <typename T, int cost = 1>
inline void move_progress() { display_status_bar(AfterComponentLoadProgress<T, cost>::progress, total_cost); }
private:
static constexpr int progress_line_height() { return 4; }
static constexpr int progress_line_width() { return 128; }
void display_status_bar(int current_progress, int max_progress);
void animation_frame(LG::Context& ctx, LG::Point<int> pt, int frame, int total_frames);
void run_intro_animation();
std::string_view m_logo_text { "xOS" };
Screen& m_screen;
int m_progress_line_min_x { 0 };
int m_progress_line_min_y { 0 };
LG::PixelBitmap m_logo;
LG::Font& m_font { LG::Font::system_bold_font(32) };
};
} // namespace WinServer

View File

@@ -0,0 +1,112 @@
#include "MenuBar.h"
#include "../../Managers/Compositor.h"
#include <libg/ImageLoaders/PNGLoader.h>
namespace WinServer {
MenuBar* s_WinServer_MenuBar_the = nullptr;
MenuBar::MenuBar()
: m_background_color(LG::Color::Opaque)
, m_bounds(0, 0, Screen::the().bounds().width(), height())
, m_popup(Popup::the())
{
s_WinServer_MenuBar_the = this;
LG::PNG::PNGLoader loader;
}
void MenuBar::invalidate_widget(BaseWidget* wg)
{
for (int i = 0; i < m_widgets.size(); i++) {
if (m_widgets[i] == wg) {
size_t widget_min_x = widget_start_offset(i);
Compositor::the().invalidate(LG::Rect(widget_min_x, 0, m_widgets[i]->width(), height()));
return;
}
}
}
MenuItemAnswer MenuBar::widget_recieve_mouse_status_change(const CursorManager& cursor_manager, size_t wind)
{
if (wind >= m_widgets.size()) {
return MenuItemAnswer::Bad;
}
MenuItemAnswer answer = MenuItemAnswer::Empty;
size_t widget_min_x = widget_start_offset(wind);
if (cursor_manager.pressed<CursorManager::Params::LeftButton>()) {
answer = m_widgets[wind]->mouse_down(cursor_manager.x() - widget_min_x, cursor_manager.y());
} else {
answer = m_widgets[wind]->mouse_up();
}
if (answer & MenuItemAnswer::Bad) {
return answer;
}
if (answer & MenuItemAnswer::InvalidateMe) {
Compositor::the().invalidate(LG::Rect(widget_min_x, 0, m_widgets[wind]->width(), height()));
}
return answer;
}
MenuItemAnswer MenuBar::panel_item_recieve_mouse_status_change(const CursorManager& cursor_manager, size_t ind)
{
if (!m_menubar_content) {
return MenuItemAnswer::Bad;
}
auto& content = *m_menubar_content;
if (ind >= content.size()) {
return MenuItemAnswer::Bad;
}
MenuItemAnswer answer = MenuItemAnswer::Empty;
size_t item_min_x = panel_item_start_offset(ind);
if (cursor_manager.pressed<CursorManager::Params::LeftButton>()) {
answer = content[ind].mouse_down(cursor_manager.x() - item_min_x, cursor_manager.y());
} else {
answer = content[ind].mouse_up();
}
if (answer & MenuItemAnswer::Bad) {
return answer;
}
if (answer & MenuItemAnswer::InvalidateMe) {
Compositor::the().invalidate(LG::Rect(item_min_x, 0, content[ind].width(), height()));
}
if (answer & MenuItemAnswer::PopupShow) {
popup_will_be_shown(ind);
}
if (answer & MenuItemAnswer::PopupClose) {
popup_will_be_closed();
}
return answer;
}
void MenuBar::invalidate_menubar_panel(Compositor& compositor)
{
if (menubar_content()) {
size_t inv_len = menubar_panel_width(*m_menubar_content);
compositor.invalidate(menubar_panel_bounds());
}
}
void MenuBar::invalidate_menubar_panel()
{
invalidate_menubar_panel(Compositor::the());
}
void MenuBar::set_style(StatusBarStyle ts)
{
set_background_color(ts.color());
if (ts.dark_text()) {
m_text_color = LG::Color::DarkSystemText;
} else {
m_text_color = LG::Color::LightSystemText;
}
}
} // namespace WinServer

View File

@@ -0,0 +1,266 @@
#pragma once
#include "../../Managers/CursorManager.h"
#include "MenuItem.h"
#include "Widgets/BaseWidget.h"
#include <libapi/window_server/MessageContent/MenuBar.h>
#include <libfoundation/EventLoop.h>
#include <libfoundation/Logger.h>
#include <libg/Context.h>
#include <libg/PixelBitmap.h>
#include <libg/Point.h>
#include <vector>
namespace WinServer {
struct PopupContext {
void discard() { opened = false; }
bool opened { false };
int invoker_id { 0 };
};
class WindowManager;
class MenuBar {
friend WindowManager;
public:
inline static MenuBar& the()
{
extern MenuBar* s_WinServer_MenuBar_the;
return *s_WinServer_MenuBar_the;
}
MenuBar();
static constexpr size_t height() { return 24; }
static constexpr size_t padding() { return 8; }
static constexpr size_t menubar_content_offset() { return padding() + 2; }
static constexpr int popup_x_offset() { return -8; }
static constexpr int text_y_offset() { return 2; }
void set_background_color(const LG::Color& clr) { m_background_color = clr; }
void set_style(StatusBarStyle style);
size_t width() const { return m_bounds.width(); }
LG::Rect& bounds() { return m_bounds; }
const LG::Rect& bounds() const { return m_bounds; }
template <class T, class... Args>
T& add_widget(Args&&... args)
{
T* widget = new T(args...);
m_widgets.push_back(widget);
return *widget;
}
inline LFoundation::EventLoop& event_loop() { return LFoundation::EventLoop::the(); }
void invalidate_widget(BaseWidget* wg);
inline bool is_hovered() const { return m_hovered; }
inline PopupContext& popup_context() { return m_popup_context; }
inline const PopupContext& popup_context() const { return m_popup_context; }
inline LG::Rect menubar_panel_bounds() { return LG::Rect(menubar_content_offset() + popup_x_offset(), text_y_offset(), menubar_panel_width(*m_menubar_content) - popup_x_offset(), height() - 3); }
void draw_panel_items(LG::Context& ctx);
void draw_widgets(LG::Context& ctx);
[[gnu::always_inline]] inline void draw(LG::Context& ctx)
{
ctx.set_fill_color(m_background_color);
ctx.fill({ 0, 0, MenuBar::width(), MenuBar::height() });
ctx.set_fill_color(LG::Color::LightSystemOpaque);
if (m_menubar_content) {
draw_panel_items(ctx);
}
draw_widgets(ctx);
}
inline void on_mouse_move(const CursorManager& cursor_manager) { m_hovered = true; }
inline void on_mouse_leave(const CursorManager& cursor_manager) { m_hovered = false; }
void on_mouse_status_change(const CursorManager& cursor_manager);
inline std::vector<MenuDir>* menubar_content() const { return m_menubar_content; }
void set_menubar_content(std::vector<MenuDir>* mc);
void set_menubar_content(std::vector<MenuDir>* mc, Compositor& compositor);
inline void popup_will_be_shown(int invoker_id)
{
auto& content = *m_menubar_content;
popup_context().invoker_id = invoker_id;
m_popup.show({ (int)panel_item_start_offset(invoker_id) + popup_x_offset(), height() + 2 }, content[invoker_id].items());
}
inline void popup_will_be_closed()
{
popup_context().discard();
m_popup.hide();
}
private:
// Widgets
MenuItemAnswer widget_recieve_mouse_status_change(const CursorManager& cursor_manager, size_t wind);
size_t widget_start_offset(size_t index);
int find_widget(int x, int y);
// MenuBar Panel
void invalidate_menubar_panel();
void invalidate_menubar_panel(Compositor& compositor);
MenuItemAnswer panel_item_recieve_mouse_status_change(const CursorManager& cursor_manager, size_t ind);
static inline size_t menubar_panel_width(const std::vector<MenuDir>& items)
{
size_t width = 0;
for (int ind = 0; ind < items.size(); ind++) {
width += padding();
width += items[ind].width();
}
return width;
}
size_t panel_item_start_offset(size_t index);
int find_menubar_panel_item(int x, int y);
LG::Rect m_bounds;
std::vector<MenuDir>* m_menubar_content { nullptr };
std::vector<BaseWidget*> m_widgets;
Popup& m_popup;
PopupContext m_popup_context;
LG::Color m_background_color;
LG::Color m_text_color;
bool m_hovered { false };
};
// Implementation
inline void MenuBar::draw_panel_items(LG::Context& ctx)
{
if (!m_menubar_content) {
return;
}
auto offset = ctx.draw_offset();
size_t start_offset = menubar_content_offset();
auto& content = *m_menubar_content;
for (int ind = 0; ind < content.size(); ind++) {
ctx.set_fill_color(m_text_color);
ctx.set_draw_offset(LG::Point<int>(start_offset, text_y_offset()));
content[ind].draw(ctx);
start_offset += content[ind].width();
start_offset += padding();
}
ctx.set_draw_offset(offset);
}
inline void MenuBar::draw_widgets(LG::Context& ctx)
{
auto offset = ctx.draw_offset();
size_t start_offset = MenuBar::width() - padding();
for (int wind = m_widgets.size() - 1; wind >= 0; wind--) {
ctx.set_fill_color(m_text_color);
start_offset -= padding();
start_offset -= m_widgets[wind]->width();
ctx.set_draw_offset(LG::Point<int>(start_offset, text_y_offset()));
m_widgets[wind]->draw(ctx);
}
ctx.set_draw_offset(offset);
}
inline void MenuBar::on_mouse_status_change(const CursorManager& cursor_manager)
{
// Checking recievers
int target_widget = find_widget(cursor_manager.x(), cursor_manager.y());
if (target_widget >= 0) {
widget_recieve_mouse_status_change(cursor_manager, (size_t)target_widget);
return;
}
int target_panel_item = find_menubar_panel_item(cursor_manager.x(), cursor_manager.y());
if (target_panel_item >= 0) {
panel_item_recieve_mouse_status_change(cursor_manager, (size_t)target_panel_item);
return;
}
}
inline void MenuBar::set_menubar_content(std::vector<MenuDir>* mc)
{
invalidate_menubar_panel();
m_menubar_content = mc;
invalidate_menubar_panel();
popup_will_be_closed();
}
inline void MenuBar::set_menubar_content(std::vector<MenuDir>* mc, Compositor& compositor)
{
invalidate_menubar_panel(compositor);
m_menubar_content = mc;
invalidate_menubar_panel(compositor);
popup_will_be_closed();
}
inline size_t MenuBar::widget_start_offset(size_t index)
{
size_t start_offset = MenuBar::width() - padding();
for (int wind = m_widgets.size() - 1; wind >= (int)index; wind--) {
start_offset -= padding();
start_offset -= m_widgets[wind]->width();
}
return start_offset;
}
inline int MenuBar::find_widget(int x, int y)
{
size_t start_offset = MenuBar::width() - padding();
for (int wind = m_widgets.size() - 1; wind >= 0; wind--) {
start_offset -= padding();
int end_offset = start_offset;
start_offset -= m_widgets[wind]->width();
if (start_offset <= x && x <= end_offset) {
return wind;
}
}
return -1;
}
inline size_t MenuBar::panel_item_start_offset(size_t index)
{
if (!m_menubar_content) {
return 0;
}
auto& content = *m_menubar_content;
size_t start_offset = menubar_content_offset();
for (int ind = 0; ind < index; ind++) {
start_offset += padding();
start_offset += content[ind].width();
}
return start_offset;
}
inline int MenuBar::find_menubar_panel_item(int x, int y)
{
if (!m_menubar_content) {
return -1;
}
auto& content = *m_menubar_content;
size_t start_offset = menubar_content_offset();
for (int ind = 0; ind < content.size(); ind++) {
int end_offset = start_offset + content[ind].width();
if (start_offset <= x && x <= end_offset) {
return ind;
}
start_offset = end_offset + padding();
}
return -1;
}
} // namespace WinServer

View File

@@ -0,0 +1,61 @@
#pragma once
#include "../Helpers/TextDrawer.h"
#include "../Popup/Popup.h"
#include "MenuItemAnswer.h"
#include <libfoundation/Logger.h>
#include <libg/Context.h>
#include <libg/Font.h>
#include <string>
#include <vector>
namespace WinServer {
class MenuDir {
public:
MenuDir(const std::string& title, int id)
: m_title(title)
, m_id(id)
{
}
~MenuDir() = default;
inline void set_font(LG::Font& f) { m_font = f; }
inline void add_item(PopupItem&& item) { m_items.push_back(std::move(item)); }
inline void add_item(const PopupItem& item) { m_items.push_back(item); }
inline int id() const { return m_id; }
inline void set_title(const std::string& title) { m_title = title; }
inline void set_title(std::string&& title) { m_title = std::move(title); }
inline const std::string& title() const { return m_title; }
inline const PopupData& items() const { return m_items; }
inline PopupData& items() { return m_items; }
inline size_t width() const { return Helpers::text_width(m_title, m_font); }
[[gnu::always_inline]] inline void draw(LG::Context& ctx)
{
ctx.set_fill_color(LG::Color::Black);
Helpers::draw_text(ctx, { 0, 6 }, m_title, m_font);
}
inline MenuItemAnswer mouse_down(int x, int y)
{
m_active = true;
return MenuItemAnswer(MenuItemAnswer::InvalidateMe | MenuItemAnswer::PopupShow);
}
inline MenuItemAnswer mouse_up()
{
return MenuItemAnswer::InvalidateMe;
}
private:
int m_id { -1 };
bool m_active { false };
std::string m_title;
LG::Font& m_font { LG::Font::system_font() };
PopupData m_items;
};
} // namespace WinServer

View File

@@ -0,0 +1,14 @@
#pragma once
namespace WinServer {
// Common for widget and panel item.
enum MenuItemAnswer {
Empty = 0x0,
Bad = 0x1, // Bad mark
InvalidateMe = 0x2, // Asks to invalidate menu item
PopupShow = 0x4, // Asks to show popup. MenuBar will call popup_rect()
PopupClose = 0x8, // Asks to close popup.
};
}; // namespace WinServer

View File

@@ -0,0 +1,20 @@
#pragma once
#include "../MenuItemAnswer.h"
#include <libg/Context.h>
namespace WinServer {
class BaseWidget {
public:
BaseWidget() = default;
virtual ~BaseWidget() = default;
size_t height() { return 20; }
virtual size_t width() { return 0; }
virtual void draw(LG::Context& ctx) { }
virtual MenuItemAnswer mouse_down(int x, int y) { return MenuItemAnswer::Empty; }
virtual MenuItemAnswer mouse_up() { return MenuItemAnswer::Empty; }
virtual void popup_rect(LG::Rect& r) { }
};
} // namespace WinServer

View File

@@ -0,0 +1,69 @@
#pragma once
#include "../../../Helpers/TextDrawer.h"
#include "../../MenuBar.h"
#include "../BaseWidget.h"
#include <ctime>
#include <libfoundation/Logger.h>
#include <libg/Font.h>
#define DATA_BUF 32
namespace WinServer {
class Clock : public BaseWidget {
public:
Clock()
{
m_date = static_cast<char*>(malloc(DATA_BUF));
memset(m_date, 0, DATA_BUF);
update_time();
MenuBar::the().event_loop().add(LFoundation::Timer([this] {
this->update_time();
},
5000, LFoundation::Timer::Repeat));
}
~Clock()
{
free(m_date);
}
void update_time()
{
std::time_t new_time = std::time(nullptr);
if (new_time / 60 != cur_time / 60) {
cur_time = new_time;
std::strftime(m_date, DATA_BUF, "%a %R", std::localtime(&cur_time));
MenuBar::the().invalidate_widget(this);
}
}
size_t width() override { return 50; }
void draw(LG::Context& ctx) override
{
size_t twidth = Helpers::text_width(m_date, m_font);
Helpers::draw_text(ctx, { int(width() - twidth) / 2, 6 }, m_date, m_font);
}
MenuItemAnswer mouse_down(int x, int y) override
{
m_clicked = true;
return MenuItemAnswer::InvalidateMe;
}
MenuItemAnswer mouse_up() override
{
m_clicked = false;
return MenuItemAnswer::InvalidateMe;
}
void popup_rect(LG::Rect& r) override { }
private:
bool m_clicked { false };
char* m_date { nullptr };
std::time_t cur_time { 0 };
LG::Font& m_font { LG::Font::system_font() };
};
} // namespace WinServer

View File

@@ -0,0 +1,50 @@
#pragma once
#include "../../../Helpers/TextDrawer.h"
#include "../../MenuBar.h"
#include "../BaseWidget.h"
#include <ctime>
#include <libfoundation/Logger.h>
#include <libg/Font.h>
#include <libg/ImageLoaders/PNGLoader.h>
#define DATA_BUF 32
namespace WinServer {
class ControlPanelToggle : public BaseWidget {
public:
ControlPanelToggle()
{
LG::PNG::PNGLoader loader;
m_icon = loader.load_from_file("/res/system/contol_center.png");
}
~ControlPanelToggle() = default;
constexpr size_t width() override { return 20; }
constexpr size_t height() { return 12; }
void draw(LG::Context& ctx) override
{
ctx.draw({ 4, 4 }, m_icon);
}
MenuItemAnswer mouse_down(int x, int y) override
{
m_clicked = true;
return MenuItemAnswer::InvalidateMe;
}
MenuItemAnswer mouse_up() override
{
m_clicked = false;
return MenuItemAnswer::InvalidateMe;
}
void popup_rect(LG::Rect& r) override { }
private:
LG::PixelBitmap m_icon;
bool m_clicked { false };
};
} // namespace WinServer

View File

@@ -0,0 +1,73 @@
#include "Popup.h"
#include "../../Constants/Colors.h"
#include "../../Managers/WindowManager.h"
#include "../Helpers/TextDrawer.h"
#include <algorithm>
namespace WinServer {
Popup* s_WinServer_Popup_the = nullptr;
Popup::Popup()
{
s_WinServer_Popup_the = this;
}
void Popup::on_set_data()
{
size_t max_width = 0;
size_t max_height = 0;
for (auto& item : m_data) {
max_width = std::max(max_width, Helpers::text_width(item.text, m_font));
max_height += m_font.size() + spacing();
}
max_width = std::max(max_width, min_width());
bounds().set_width(max_width + 2 * spacing());
bounds().set_height(max_height + spacing());
}
void Popup::draw(LG::Context& ctx)
{
if (!visible()) {
return;
}
ctx.set_fill_color(LG::Color::LightSystemOpaque);
ctx.fill_rounded(bounds(), LG::CornerMask(LG::CornerMask::SystemRadius));
ctx.set_fill_color(Color::Shadow);
ctx.draw_box_shading(bounds(), LG::Shading(LG::Shading::Type::Box, 0, LG::Shading::SystemSpread), LG::CornerMask(LG::CornerMask::SystemRadius));
const size_t line_height = (m_font.size() + spacing());
int height = bounds().min_y() + spacing();
for (int i = 0; i < m_data.size(); i++) {
if (i == m_hovered_item) {
ctx.set_fill_color(LG::Color::White);
ctx.fill_rounded(LG::Rect(bounds().min_x() + 4, height - spacing() / 2, bounds().width() - 8, line_height), LG::CornerMask(2));
}
ctx.set_fill_color(LG::Color::DarkSystemText);
Helpers::draw_text(ctx, { bounds().min_x() + spacing(), height }, m_data[i].text, m_font);
height += line_height;
}
}
void Popup::set_preferred_origin(const LG::Point<int>& origin)
{
auto& wm = WindowManager::the();
LG::Point<int> pos;
int x = origin.x();
int y = origin.y();
if (origin.y() + bounds().height() > wm.visible_area().max_y()) {
y = origin.y() - bounds().height();
}
if (origin.x() + bounds().width() > wm.visible_area().max_x()) {
x = origin.x() - bounds().width();
}
pos.set_x(x);
pos.set_y(y);
m_bounds.set_origin(std::move(pos));
}
} // namespace WinServer

View File

@@ -0,0 +1,147 @@
#pragma once
#include "../../Managers/Compositor.h"
#include "../../Managers/CursorManager.h"
#include <functional>
#include <libg/Color.h>
#include <libg/Context.h>
#include <string>
#include <vector>
namespace WinServer {
struct PopupItem {
int id;
std::string text;
std::function<void(int)> callback;
static const int InternalId = -1;
};
using PopupData = std::vector<PopupItem>;
class Popup {
public:
inline static Popup& the()
{
extern Popup* s_WinServer_Popup_the;
return *s_WinServer_Popup_the;
}
Popup();
~Popup() = default;
constexpr int spacing() const { return 8; }
constexpr size_t min_width() const { return 180u; }
void set_preferred_origin(const LG::Point<int>& origin);
inline LG::Rect& bounds() { return m_bounds; }
inline const LG::Rect& bounds() const { return m_bounds; }
inline LG::Rect draw_frame() const
{
const int shadow_spread = LG::Shading::SystemSpread;
return LG::Rect(bounds().min_x() - shadow_spread, bounds().min_y() - shadow_spread, bounds().width() + 2 * shadow_spread, bounds().height() + 2 * shadow_spread);
}
inline void set_visible(bool vis)
{
if (m_visible != vis) {
Compositor::the().invalidate(draw_frame());
}
m_visible = vis;
}
inline bool visible() const { return m_visible; }
void show(const LG::Point<int>& origin, PopupData& data)
{
set_visible(false);
set_data(data);
set_preferred_origin(origin);
set_visible(true);
}
void hide()
{
m_hovered_item = HoveredItem::No;
set_visible(false);
}
void on_set_data();
void set_data(const PopupData& data) { m_data = data, on_set_data(); }
void set_data(PopupData&& data) { m_data = std::move(data), on_set_data(); }
void on_mouse_move(const CursorManager& cursor_manager)
{
// A simple implemetation to get hover effect and clicks.
if (!visible()) {
return;
}
size_t data_size = m_data.size();
const size_t line_height = (m_font.size() + 8);
int prev_hovered_item = m_hovered_item;
int rel_y = cursor_manager.y() - bounds().min_y();
rel_y -= 4; // Offset of the first element;
m_hovered_item = rel_y / line_height;
if (m_hovered_item >= data_size) {
m_hovered_item = HoveredItem::No;
}
if (m_hovered_item != prev_hovered_item && prev_hovered_item != HoveredItem::No) {
Compositor::the().invalidate(LG::Rect(bounds().min_x(), bounds().min_y() + 4 + line_height * prev_hovered_item, bounds().width(), line_height));
}
if (m_hovered_item != prev_hovered_item && m_hovered_item != HoveredItem::No) {
Compositor::the().invalidate(LG::Rect(bounds().min_x(), bounds().min_y() + 4 + line_height * m_hovered_item, bounds().width(), line_height));
}
}
inline void on_mouse_status_change(const CursorManager& cursor_manager)
{
if (m_hovered_item == HoveredItem::No) {
return;
}
if (!visible()) {
return;
}
auto& data = m_data;
if (cursor_manager.pressed<CursorManager::Params::LeftButton>()) {
data[m_hovered_item].callback((int)data[m_hovered_item].id);
hide();
}
}
void on_mouse_leave(const CursorManager& cursor_manager)
{
if (m_hovered_item == HoveredItem::No) {
return;
}
if (!visible()) {
return;
}
const size_t line_height = (m_font.size() + 8);
Compositor::the().invalidate(LG::Rect(bounds().min_x(), bounds().min_y() + 4 + line_height * m_hovered_item, bounds().width(), line_height));
m_hovered_item = HoveredItem::No;
}
void draw(LG::Context& ctx);
private:
enum HoveredItem {
No = -1,
};
LG::Rect m_bounds { 0, 0, 0, 0 };
bool m_visible { false };
PopupData m_data;
int m_hovered_item { HoveredItem::No };
LG::Font& m_font { LG::Font::system_font() };
};
} // namespace WinServer

View File

@@ -0,0 +1,11 @@
#pragma once
namespace WinServer {
enum class ViolationClass {
Ignorable,
Moderate,
Serious,
};
} // namespace WinServer

View File

@@ -0,0 +1,12 @@
#pragma once
#include <sys/types.h>
namespace WinServer {
enum Color {
Shadow = 0xf4000000,
InactiveText = 0x7B7E78,
};
} // namespace WinServer

View File

@@ -0,0 +1,35 @@
#include "Devices.h"
#include <fcntl.h>
#include <libfoundation/Logger.h>
namespace WinServer {
Devices* s_WinServer_Devices_the = nullptr;
Devices::Devices()
{
s_WinServer_Devices_the = this;
m_mouse_fd = open("/dev/mouse", O_RDONLY);
if (m_mouse_fd < 0) {
Logger::debug << "Can't open mouse" << std::endl;
} else {
LFoundation::EventLoop::the().add(
m_mouse_fd, [] {
Devices::the().pump_mouse();
},
nullptr);
}
m_keyboard_fd = open("/dev/kbd", O_RDONLY);
if (m_keyboard_fd < 0) {
Logger::debug << "Can't open keyboard" << std::endl;
} else {
LFoundation::EventLoop::the().add(
m_keyboard_fd, [] {
Devices::the().pump_keyboard();
},
nullptr);
}
}
} // namespace WinServer

View File

@@ -0,0 +1,59 @@
#pragma once
#include "../IPC/Event.h"
#include "../Managers/WindowManager.h"
#include <libfoundation/EventLoop.h>
#include <memory>
namespace WinServer {
class Devices {
public:
inline static Devices& the()
{
extern Devices* s_WinServer_Devices_the;
return *s_WinServer_Devices_the;
}
Devices();
~Devices() = default;
inline void pump_mouse() const
{
LFoundation::EventLoop& el = LFoundation::EventLoop::the();
WindowManager& wm = WindowManager::the();
char buf[512];
int read_cnt = read(m_mouse_fd, buf, sizeof(buf));
if (read_cnt <= 0) {
return;
}
auto* packet_buf = reinterpret_cast<MousePacket*>(buf);
for (int offset = 0, cnt = 0; offset < read_cnt; offset += sizeof(MousePacket), cnt++) {
el.add(wm, new MouseEvent(packet_buf[cnt]));
}
}
inline void pump_keyboard() const
{
LFoundation::EventLoop& el = LFoundation::EventLoop::the();
WindowManager& wm = WindowManager::the();
char buf[512];
int read_cnt = read(m_keyboard_fd, buf, sizeof(buf));
if (read_cnt <= 0) {
return;
}
auto* packet_buf = reinterpret_cast<KeyboardPacket*>(buf);
for (int offset = 0, cnt = 0; offset < read_cnt; offset += sizeof(KeyboardPacket), cnt++) {
el.add(wm, new KeyboardEvent(packet_buf[cnt]));
}
}
private:
int m_mouse_fd;
int m_keyboard_fd;
};
} // namespace WinServer

View File

@@ -0,0 +1,42 @@
#include "Screen.h"
#include "../Managers/Compositor.h"
#include <cstring>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <utility>
namespace WinServer {
Screen* s_WinServer_Screen_the = nullptr;
Screen::Screen()
: m_depth(4)
, m_write_bitmap()
, m_display_bitmap()
{
s_WinServer_Screen_the = this;
m_screen_fd = open("/dev/bga", O_RDWR);
m_bounds = LG::Rect(0, 0, ioctl(m_screen_fd, BGA_GET_WIDTH, 0), ioctl(m_screen_fd, BGA_GET_HEIGHT, 0));
size_t screen_buffer_size = width() * height() * depth();
auto* first_buffer = reinterpret_cast<LG::Color*>(mmap(NULL, 1, PROT_READ | PROT_WRITE, MAP_SHARED, m_screen_fd, 0));
auto* second_buffer = reinterpret_cast<LG::Color*>(reinterpret_cast<uint8_t*>(first_buffer) + screen_buffer_size);
m_display_bitmap = LG::PixelBitmap(first_buffer, width(), height());
m_write_bitmap = LG::PixelBitmap(second_buffer, width(), height());
m_display_bitmap_ptr = &m_display_bitmap;
m_write_bitmap_ptr = &m_write_bitmap;
m_active_buffer = 0;
}
void Screen::swap_buffers()
{
m_write_bitmap_ptr.swap(m_display_bitmap_ptr);
m_active_buffer ^= 1;
ioctl(m_screen_fd, BGA_SWAP_BUFFERS, m_active_buffer);
}
} // namespace WinServer

View File

@@ -0,0 +1,45 @@
#pragma once
#include <libg/Color.h>
#include <libg/PixelBitmap.h>
#include <memory>
namespace WinServer {
class Screen {
public:
inline static Screen& the()
{
extern Screen* s_WinServer_Screen_the;
return *s_WinServer_Screen_the;
}
Screen();
void swap_buffers();
inline size_t width() { return m_bounds.width(); }
inline size_t height() const { return m_bounds.height(); }
inline LG::Rect& bounds() { return m_bounds; }
inline const LG::Rect& bounds() const { return m_bounds; }
inline uint32_t depth() const { return m_depth; }
inline LG::PixelBitmap& write_bitmap() { return *m_write_bitmap_ptr; }
inline const LG::PixelBitmap& write_bitmap() const { return *m_write_bitmap_ptr; }
inline LG::PixelBitmap& display_bitmap() { return *m_display_bitmap_ptr; }
inline const LG::PixelBitmap& display_bitmap() const { return *m_display_bitmap_ptr; }
private:
int m_screen_fd;
LG::Rect m_bounds;
uint32_t m_depth;
int m_active_buffer;
LG::PixelBitmap m_write_bitmap;
LG::PixelBitmap m_display_bitmap;
std::unique_ptr<LG::PixelBitmap> m_write_bitmap_ptr { nullptr };
std::unique_ptr<LG::PixelBitmap> m_display_bitmap_ptr { nullptr };
};
} // namespace WinServer

View File

@@ -0,0 +1,46 @@
#include "Connection.h"
#include "Event.h"
#include <libfoundation/EventLoop.h>
#include <sys/socket.h>
#define WINSERVER_REQUEST_SOCKET_PATH "/tmp/winserver_requests.sock"
#define WINSERVER_REQUEST_SOCKET_PATH_SIZE sizeof(WINSERVER_REQUEST_SOCKET_PATH)
#define WINSERVER_RESPONSE_SOCKET_PATH "/tmp/winserver_response.sock"
#define WINSERVER_RESPONSE_SOCKET_PATH_SIZE sizeof(WINSERVER_RESPONSE_SOCKET_PATH)
namespace WinServer {
Connection* s_WinServer_Connection_the = nullptr;
Connection::Connection()
: m_connection(LIPC::DoubleSidedConnection(socket(PF_LOCAL, 0, 0), socket(PF_LOCAL, 0, 0)))
, m_server_decoder()
, m_client_decoder()
, m_connection_with_clients(m_connection, m_server_decoder, m_client_decoder)
{
s_WinServer_Connection_the = this;
int err1 = bind(m_connection.c2s_fd(), WINSERVER_REQUEST_SOCKET_PATH, WINSERVER_REQUEST_SOCKET_PATH_SIZE);
int err2 = bind(m_connection.s2c_fd(), WINSERVER_RESPONSE_SOCKET_PATH, WINSERVER_RESPONSE_SOCKET_PATH_SIZE);
if (!err1 && !err2) {
LFoundation::EventLoop::the().add(
m_connection.c2s_fd(), [] {
Connection::the().listen();
},
nullptr);
}
}
void Connection::receive_event(std::unique_ptr<LFoundation::Event> event)
{
switch (event->type()) {
case WinServer::Event::Type::SendEvent: {
std::unique_ptr<SendEvent> send_event = std::move(event);
m_connection_with_clients.send_message(*send_event->message());
break;
}
}
}
} // namespace WinServer

View File

@@ -0,0 +1,37 @@
#pragma once
#include "ServerDecoder.h"
#include <libapi/window_server/Connections/WSConnection.h>
#include <libfoundation/EventReceiver.h>
#include <libipc/DoubleSidedConnection.h>
#include <libipc/ServerConnection.h>
namespace WinServer {
class Connection : public LFoundation::EventReceiver {
public:
inline static Connection& the()
{
extern Connection* s_WinServer_Connection_the;
return *s_WinServer_Connection_the;
}
Connection();
inline void listen()
{
m_connection_with_clients.pump_messages();
}
inline bool send_async_message(const Message& msg) const { return m_connection_with_clients.send_message(msg); }
inline int alloc_connection() { return ++m_connections_number; }
void receive_event(std::unique_ptr<LFoundation::Event> event) override;
private:
LIPC::DoubleSidedConnection m_connection;
int m_connections_number { 0 };
ServerConnection<WindowServerDecoder, BaseWindowClientDecoder> m_connection_with_clients;
WindowServerDecoder m_server_decoder;
BaseWindowClientDecoder m_client_decoder;
};
} // namespace WinServer

View File

@@ -0,0 +1,102 @@
#pragma once
#include <libfoundation/Event.h>
#include <libipc/Message.h>
#include <memory>
#include <sys/types.h>
namespace WinServer {
class Event : public LFoundation::Event {
public:
enum Type {
Invalid = 0x1000,
MouseEvent,
KeyboardEvent,
SendEvent,
Other,
};
explicit Event(int type)
: LFoundation::Event(type)
{
}
~Event() = default;
};
struct MousePacket {
int16_t x_offset;
int16_t y_offset;
uint16_t button_states;
int16_t wheel_data;
};
struct KeyboardPacket {
uint32_t key;
};
class MouseEvent : public WinServer::Event {
public:
explicit MouseEvent(const MousePacket& packet)
: WinServer::Event(WinServer::Event::Type::MouseEvent)
, m_packet(packet)
{
}
~MouseEvent() = default;
const MousePacket& packet() const { return m_packet; }
MousePacket& packet() { return m_packet; }
private:
MousePacket m_packet;
};
class KeyboardEvent : public WinServer::Event {
public:
explicit KeyboardEvent(const KeyboardPacket& packet)
: WinServer::Event(WinServer::Event::Type::KeyboardEvent)
, m_packet(packet)
{
}
~KeyboardEvent() = default;
const KeyboardPacket& packet() const { return m_packet; }
KeyboardPacket& packet() { return m_packet; }
private:
KeyboardPacket m_packet;
};
class SendEvent : public WinServer::Event {
public:
explicit SendEvent(Message* msg)
: WinServer::Event(WinServer::Event::Type::SendEvent)
, m_message(msg)
{
}
SendEvent(SendEvent&& ev)
: WinServer::Event(WinServer::Event::Type::SendEvent)
, m_message(std::move(ev.m_message))
{
}
SendEvent& operator=(SendEvent&& ev)
{
m_message = std::move(ev.m_message);
return *this;
}
~SendEvent() = default;
const std::unique_ptr<Message>& message() const { return m_message; }
std::unique_ptr<Message>& message() { return m_message; }
private:
std::unique_ptr<Message> m_message;
};
} // namespace WinServer

View File

@@ -0,0 +1,220 @@
#include "ServerDecoder.h"
#include "../Components/Security/Violations.h"
#include "../Managers/WindowManager.h"
#include "../Target/Generic/Window.h"
namespace WinServer {
std::unique_ptr<Message> WindowServerDecoder::handle(GreetMessage& msg)
{
return new GreetMessageReply(msg.key(), Connection::the().alloc_connection());
}
#ifdef TARGET_DESKTOP
std::unique_ptr<Message> WindowServerDecoder::handle(CreateWindowMessage& msg)
{
auto& wm = WindowManager::the();
auto& compositor = Compositor::the();
int win_id = wm.next_win_id();
auto* window = new Desktop::Window(msg.key(), win_id, msg);
window->set_app_title(msg.title().move_string());
window->set_icon_path(msg.icon_path().move_string());
window->set_style(StatusBarStyle(msg.menubar_style(), msg.color()));
wm.add_window(window);
if (window->type() == WindowType::Standard) {
// After moving windows, we have to invalidate bounds() to make sure that
// the whole window is rendered (coords are changes after move).
wm.move_window(window, 8 * win_id, MenuBar::height() + 8 * win_id);
compositor.invalidate(window->bounds());
}
wm.notify_window_icon_changed(window->id());
wm.notify_window_title_changed(window->id());
return new CreateWindowMessageReply(msg.key(), win_id);
}
#elif TARGET_MOBILE
std::unique_ptr<Message> WindowServerDecoder::handle(CreateWindowMessage& msg)
{
auto& wm = WindowManager::the();
int win_id = wm.next_win_id();
auto* window = new Mobile::Window(msg.key(), win_id, msg);
window->set_style(StatusBarStyle(msg.menubar_style(), msg.color()));
window->set_icon_path(msg.icon_path().move_string());
window->set_style(StatusBarStyle(msg.menubar_style(), msg.color()));
wm.add_window(window);
wm.move_window(window, 0, MenuBar::height());
wm.notify_window_icon_changed(window->id());
wm.notify_window_title_changed(window->id());
return new CreateWindowMessageReply(msg.key(), win_id);
}
#endif
std::unique_ptr<Message> WindowServerDecoder::handle(SetBufferMessage& msg)
{
auto* window = WindowManager::the().window(msg.window_id());
if (!window) {
return nullptr;
}
LG::Size new_size = { msg.bounds().width(), msg.bounds().height() };
window->did_size_change(new_size);
window->set_buffer(msg.buffer_id(), new_size, LG::PixelBitmapFormat(msg.format()));
return nullptr;
}
std::unique_ptr<Message> WindowServerDecoder::handle(DestroyWindowMessage& msg)
{
auto& wm = WindowManager::the();
auto* window = wm.window(msg.window_id());
if (!window) {
wm.on_window_misbehave(*window, ViolationClass::Ignorable);
return new DestroyWindowMessageReply(msg.key(), 1);
}
if (window->connection_id() != msg.key()) {
wm.on_window_misbehave(*window, ViolationClass::Serious);
return new DestroyWindowMessageReply(msg.key(), 1);
}
wm.remove_window(window);
return new DestroyWindowMessageReply(msg.key(), 0);
}
std::unique_ptr<Message> WindowServerDecoder::handle(InvalidateMessage& msg)
{
auto& wm = WindowManager::the();
auto* window = wm.window(msg.window_id());
if (!window) {
return nullptr;
}
auto rect = msg.rect();
rect.offset_by(window->content_bounds().origin());
rect.intersect(window->content_bounds());
Compositor::the().invalidate(rect);
return nullptr;
}
#ifdef TARGET_DESKTOP
std::unique_ptr<Message> WindowServerDecoder::handle(SetTitleMessage& msg)
{
auto& wm = WindowManager::the();
auto* window = wm.window(msg.window_id());
if (!window) {
return nullptr;
}
window->set_app_title(msg.title().string());
auto& compositor = Compositor::the();
compositor.invalidate(compositor.menu_bar().bounds());
wm.notify_window_title_changed(window->id());
return nullptr;
}
#elif TARGET_MOBILE
std::unique_ptr<Message> WindowServerDecoder::handle(SetTitleMessage& msg)
{
return nullptr;
}
#endif
std::unique_ptr<Message> WindowServerDecoder::handle(SetBarStyleMessage& msg)
{
auto& wm = WindowManager::the();
auto* window = wm.window(msg.window_id());
if (!window) {
return nullptr;
}
window->set_style(StatusBarStyle(msg.menubar_style(), msg.color()));
return nullptr;
}
#ifdef TARGET_DESKTOP
std::unique_ptr<Message> WindowServerDecoder::handle(MenuBarCreateMenuMessage& msg)
{
auto& wm = WindowManager::the();
auto* window = wm.window(msg.window_id());
if (!window) {
return new MenuBarCreateMenuMessageReply(msg.key(), -1, 0);
}
int id = window->menubar_content().size();
window->menubar_content().push_back(MenuDir(msg.title().string(), id));
window->on_menubar_change();
return new MenuBarCreateMenuMessageReply(msg.key(), 0, id);
}
std::unique_ptr<Message> WindowServerDecoder::handle(MenuBarCreateItemMessage& msg)
{
auto& wm = WindowManager::the();
auto* window = wm.window(msg.window_id());
if (!window) {
return new MenuBarCreateItemMessageReply(msg.key(), -1);
}
auto menu_id = msg.menu_id();
if (menu_id == 0 || window->menubar_content().size() <= menu_id) {
return new MenuBarCreateItemMessageReply(msg.key(), -2);
}
auto callback = [window, menu_id](int item_id) { LFoundation::EventLoop::the().add(Connection::the(),
new SendEvent(new MenuBarActionMessage(window->connection_id(), window->id(), menu_id, item_id))); };
window->menubar_content()[menu_id].add_item(PopupItem { msg.item_id(), msg.title().string(), callback });
// TODO: Currently we don't redraw popup after a new item was added.
return new MenuBarCreateItemMessageReply(msg.key(), 0);
}
#elif TARGET_MOBILE
std::unique_ptr<Message> WindowServerDecoder::handle(MenuBarCreateMenuMessage& msg)
{
return new MenuBarCreateMenuMessageReply(msg.key(), -100, 0);
}
std::unique_ptr<Message> WindowServerDecoder::handle(MenuBarCreateItemMessage& msg)
{
return new MenuBarCreateItemMessageReply(msg.key(), -100);
}
#endif
std::unique_ptr<Message> WindowServerDecoder::handle(PopupShowMenuMessage& msg)
{
auto& wm = WindowManager::the();
auto* window = wm.window(msg.window_id());
if (!window) {
return new PopupShowMenuMessageReply(msg.key(), -1, -1);
}
std::vector<std::string> res;
for (int i = 0; i < msg.data().vector().size(); i++) {
res.push_back(msg.data().vector()[i].move_string());
}
PopupData popup_data;
int item_id = 0;
int menu_id = 0;
for (auto& title : res) {
auto callback = [window, menu_id](int item_id) { LFoundation::EventLoop::the().add(Connection::the(),
new SendEvent(new PopupActionMessage(window->connection_id(), window->id(), menu_id, item_id))); };
popup_data.push_back(PopupItem { item_id, title, callback });
item_id++;
}
wm.popup().show({ msg.point() }, popup_data);
return new PopupShowMenuMessageReply(msg.key(), 0, 0);
}
std::unique_ptr<Message> WindowServerDecoder::handle(AskBringToFrontMessage& msg)
{
auto& wm = WindowManager::the();
auto* window = wm.window(msg.window_id());
auto* target_window = wm.window(msg.target_window_id());
if (!window || !target_window) {
return nullptr;
}
if (window->type() == WindowType::Homescreen) {
// Only dock can ask for that now.
wm.ask_to_set_active_window(*target_window);
}
return nullptr;
}
} // namespace WinServer

View File

@@ -0,0 +1,26 @@
#pragma once
#include "../Managers/Compositor.h"
#include <libapi/window_server/Connections/WSConnection.h>
namespace WinServer {
class WindowServerDecoder : public BaseWindowServerDecoder {
public:
WindowServerDecoder() = default;
~WindowServerDecoder() = default;
using BaseWindowServerDecoder::handle;
virtual std::unique_ptr<Message> handle(GreetMessage& msg) override;
virtual std::unique_ptr<Message> handle(CreateWindowMessage& msg) override;
virtual std::unique_ptr<Message> handle(DestroyWindowMessage& msg) override;
virtual std::unique_ptr<Message> handle(SetBarStyleMessage& msg) override;
virtual std::unique_ptr<Message> handle(SetTitleMessage& msg) override;
virtual std::unique_ptr<Message> handle(SetBufferMessage& msg) override;
virtual std::unique_ptr<Message> handle(InvalidateMessage& msg) override;
virtual std::unique_ptr<Message> handle(MenuBarCreateMenuMessage& msg) override;
virtual std::unique_ptr<Message> handle(MenuBarCreateItemMessage& msg) override;
virtual std::unique_ptr<Message> handle(PopupShowMenuMessage& msg) override;
virtual std::unique_ptr<Message> handle(AskBringToFrontMessage& msg) override;
};
} // namespace WinServer

View File

@@ -0,0 +1,159 @@
#include "Compositor.h"
#include "../Components/Base/BaseWindow.h"
#include "../Components/ControlBar/ControlBar.h"
#include "../Components/MenuBar/MenuBar.h"
#include "../Components/Popup/Popup.h"
#include "../Devices/Screen.h"
#include "../Managers/CursorManager.h"
#include "../Managers/ResourceManager.h"
#include "../Managers/WindowManager.h"
#include <libfoundation/EventLoop.h>
#include <libfoundation/Memory.h>
#include <libg/Context.h>
namespace WinServer {
Compositor* s_WinServer_Compositor_the = nullptr;
Compositor::Compositor()
: m_cursor_manager(CursorManager::the())
, m_resource_manager(ResourceManager::the())
, m_popup(Popup::the())
, m_menu_bar(MenuBar::the())
#ifdef TARGET_MOBILE
, m_control_bar(ControlBar::the())
#endif // TARGET_MOBILE
{
s_WinServer_Compositor_the = this;
invalidate(Screen::the().bounds());
LFoundation::EventLoop::the().add(LFoundation::Timer([] {
Compositor::the().refresh();
},
1000 / 60, LFoundation::Timer::Repeat));
}
void Compositor::copy_changes_to_second_buffer(const std::vector<LG::Rect>& areas)
{
auto& screen = Screen::the();
for (int i = 0; i < areas.size(); i++) {
auto bounds = areas[i].intersection(screen.bounds());
auto* buf1_ptr = reinterpret_cast<uint32_t*>(&screen.display_bitmap()[bounds.min_y()][bounds.min_x()]);
auto* buf2_ptr = reinterpret_cast<uint32_t*>(&screen.write_bitmap()[bounds.min_y()][bounds.min_x()]);
for (int j = 0; j < bounds.height(); j++) {
LFoundation::fast_copy(buf2_ptr, buf1_ptr, bounds.width());
buf1_ptr += screen.width();
buf2_ptr += screen.width();
}
}
}
[[gnu::flatten]] void Compositor::refresh()
{
if (m_invalidated_areas.empty()) {
return;
}
auto& screen = Screen::the();
auto& wm = WindowManager::the();
auto invalidated_areas = std::move(m_invalidated_areas);
LG::Context ctx(screen.write_bitmap());
auto is_window_area_invalidated = [&](const std::vector<LG::Rect>& areas, const LG::Rect& area) -> bool {
for (int i = 0; i < areas.size(); i++) {
if (area.intersects(areas[i])) {
return true;
}
}
return false;
};
auto draw_wallpaper_for_area = [&](const LG::Rect& area) {
ctx.add_clip(area);
ctx.draw({ 0, 0 }, m_resource_manager.background());
ctx.reset_clip();
};
#ifdef TARGET_DESKTOP
auto draw_window = [&](Desktop::Window& window, const LG::Rect& area) {
ctx.add_clip(area);
ctx.add_clip(window.bounds());
window.frame().draw(ctx);
ctx.draw_rounded(window.content_bounds().origin(), window.content_bitmap(), window.corner_mask());
ctx.reset_clip();
};
#elif TARGET_MOBILE
auto draw_window = [&](Mobile::Window& window, const LG::Rect& area) {
ctx.add_clip(area);
ctx.add_clip(window.bounds());
ctx.draw(window.content_bounds().origin(), window.content_bitmap());
ctx.reset_clip();
};
#endif // TARGET_DESKTOP
auto& windows = wm.windows();
auto top_std_window = windows.rbegin();
#ifdef TARGET_DESKTOP
for (int i = 0; i < invalidated_areas.size(); i++) {
draw_wallpaper_for_area(invalidated_areas[i]);
}
#elif TARGET_MOBILE
// Standard windows could not be transparent in mobile view, thus
// no need to render everything behind the first standard window.
for (auto it = windows.rbegin(); it != windows.rend(); it++) {
top_std_window = it;
}
if (top_std_window == windows.rend() || (*top_std_window)->type() != WindowType::Standard) {
for (int i = 0; i < invalidated_areas.size(); i++) {
draw_wallpaper_for_area(invalidated_areas[i]);
}
}
#endif // TARGET_DESKTOP
for (auto it = top_std_window; it != windows.rend(); it++) {
auto& window = *(*it);
if (window.visible() && is_window_area_invalidated(invalidated_areas, window.bounds())) {
for (int i = 0; i < invalidated_areas.size(); i++) {
draw_window(window, invalidated_areas[i]);
}
}
}
if (m_popup.visible()) {
for (int i = 0; i < invalidated_areas.size(); i++) {
ctx.add_clip(invalidated_areas[i]);
m_popup.draw(ctx);
ctx.reset_clip();
}
}
for (int i = 0; i < invalidated_areas.size(); i++) {
if (m_menu_bar.bounds().intersects(invalidated_areas[i])) {
ctx.add_clip(invalidated_areas[i]);
m_menu_bar.draw(ctx);
ctx.reset_clip();
}
}
#ifdef TARGET_MOBILE
for (int i = 0; i < invalidated_areas.size(); i++) {
ctx.add_clip(invalidated_areas[i]);
m_control_bar.draw(ctx);
ctx.reset_clip();
}
#endif // TARGET_MOBILE
auto mouse_draw_position = m_cursor_manager.draw_position();
auto& current_mouse_bitmap = m_cursor_manager.current_cursor();
for (int i = 0; i < invalidated_areas.size(); i++) {
ctx.add_clip(invalidated_areas[i]);
ctx.draw(mouse_draw_position, current_mouse_bitmap);
ctx.reset_clip();
}
screen.swap_buffers();
copy_changes_to_second_buffer(invalidated_areas);
}
} // namespace WinServer

View File

@@ -0,0 +1,95 @@
#pragma once
#include "../IPC/ServerDecoder.h"
#include <libapi/window_server/Connections/WSConnection.h>
#include <libipc/ServerConnection.h>
#include <vector>
namespace WinServer {
class CursorManager;
class ResourceManager;
class MenuBar;
#ifdef TARGET_MOBILE
class ControlBar;
#endif // TARGET_MOBILE
class Popup;
class Compositor {
public:
inline static Compositor& the()
{
extern Compositor* s_WinServer_Compositor_the;
return *s_WinServer_Compositor_the;
}
Compositor();
void refresh();
void optimized_invalidate_insert(std::vector<LG::Rect>& data, const LG::Rect& inv_area)
{
auto area = inv_area;
bool intersects = false;
int int_index = 0;
for (auto& rect : data) {
if (rect.contains(area)) {
return;
}
}
for (auto& rect : data) {
if (rect.intersects(area)) {
intersects = true;
break;
}
int_index++;
}
if (!intersects) {
data.push_back(area);
return;
}
data[int_index].unite(area);
for (int i = int_index + 1; i < data.size(); i++) {
if (data[int_index].intersects(data[i])) {
data[int_index].unite(data[i]);
std::swap(data[i], data.back());
data.pop_back();
i--;
}
}
}
inline void invalidate(const LG::Rect& area) { optimized_invalidate_insert(m_invalidated_areas, area); }
inline CursorManager& cursor_manager() { return m_cursor_manager; }
inline const CursorManager& cursor_manager() const { return m_cursor_manager; }
inline ResourceManager& resource_manager() { return m_resource_manager; }
inline const ResourceManager& resource_manager() const { return m_resource_manager; }
inline Popup& popup() { return m_popup; }
inline const Popup& popup() const { return m_popup; }
inline MenuBar& menu_bar() { return m_menu_bar; }
inline const MenuBar& menu_bar() const { return m_menu_bar; }
#ifdef TARGET_MOBILE
inline ControlBar& control_bar()
{
return m_control_bar;
}
inline const ControlBar& control_bar() const { return m_control_bar; }
#endif // TARGET_MOBILE
private:
void copy_changes_to_second_buffer(const std::vector<LG::Rect>& areas);
std::vector<LG::Rect> m_invalidated_areas;
MenuBar& m_menu_bar;
Popup& m_popup;
CursorManager& m_cursor_manager;
ResourceManager& m_resource_manager;
#ifdef TARGET_MOBILE
ControlBar& m_control_bar;
#endif // TARGET_MOBILE
};
} // namespace WinServer

View File

@@ -0,0 +1,22 @@
#include "CursorManager.h"
#include <libg/ImageLoaders/PNGLoader.h>
#ifdef TARGET_DESKTOP
#define CURSOR_PATH "/res/system/arrow.png"
#elif TARGET_MOBILE
#define CURSOR_PATH "/res/system/mobile/cursor.png"
#endif
namespace WinServer {
CursorManager* s_WinServer_CursorManager_the = nullptr;
CursorManager::CursorManager()
: m_screen(Screen::the())
{
s_WinServer_CursorManager_the = this;
LG::PNG::PNGLoader loader;
m_std_cursor = loader.load_from_file(CURSOR_PATH);
}
} // namespace WinServer

View File

@@ -0,0 +1,213 @@
#pragma once
#include "../Devices/Screen.h"
#include "../IPC/Event.h"
#include <algorithm>
#include <libg/PixelBitmap.h>
#include <libg/Point.h>
#ifdef TARGET_DESKTOP
#define CURSOR_OFFSET (2)
#elif TARGET_MOBILE
#define CURSOR_OFFSET (6)
#endif
namespace WinServer {
class CursorManager {
public:
enum class Params {
X,
Y,
LeftButton,
RightButton,
OffsetX,
OffsetY,
Wheel,
// Only for getters of conditions changes.
Coords,
Buttons,
};
inline static CursorManager& the()
{
extern CursorManager* s_WinServer_CursorManager_the;
return *s_WinServer_CursorManager_the;
}
CursorManager();
~CursorManager() = default;
inline const LG::PixelBitmap& current_cursor() const { return std_cursor(); }
inline const LG::PixelBitmap& std_cursor() const { return m_std_cursor; }
inline LG::Point<int> draw_position() { return { m_mouse_x - CURSOR_OFFSET, m_mouse_y - CURSOR_OFFSET }; }
inline int x() const
{
return m_mouse_x;
}
inline int y() const { return m_mouse_y; }
template <Params param>
constexpr int get();
template <Params param>
constexpr bool pressed() const;
template <Params param>
constexpr bool is_changed();
inline void clear_changed(uint32_t val = 0) { m_mask_changed_objects = val; }
template <Params param, typename Value>
inline constexpr void set(Value val)
{
if constexpr (param == CursorManager::Params::X) {
val = std::max(std::min(val, (int)m_screen.width() - 1), 0);
m_mouse_offset_x = val - m_mouse_x;
m_mouse_x = val;
set_changed<CursorManager::Params::X>();
} else if constexpr (param == CursorManager::Params::Y) {
val = std::max(std::min(val, (int)m_screen.height() - 1), 0);
m_mouse_offset_y = val - m_mouse_y;
m_mouse_y = val;
set_changed<CursorManager::Params::Y>();
} else if constexpr (param == CursorManager::Params::OffsetX) {
if (val != 0) {
set<CursorManager::Params::X>(m_mouse_x + val);
} else {
m_mouse_offset_x = 0;
}
} else if constexpr (param == CursorManager::Params::OffsetY) {
if (val != 0) {
set<CursorManager::Params::Y>(m_mouse_y + val);
} else {
m_mouse_offset_y = 0;
}
} else if constexpr (param == CursorManager::Params::LeftButton) {
if (m_mouse_left_button_pressed != val) {
set_changed<CursorManager::Params::LeftButton>();
}
m_mouse_left_button_pressed = val;
} else if constexpr (param == CursorManager::Params::RightButton) {
if (m_mouse_right_button_pressed != val) {
set_changed<CursorManager::Params::RightButton>();
}
m_mouse_right_button_pressed = val;
} else if constexpr (param == CursorManager::Params::Wheel) {
if (val != 0) {
set_changed<CursorManager::Params::Wheel>();
}
m_wheel = val;
} else {
[]<bool flag = false>() { static_assert(flag, "Could not call set() with such param!"); }
();
}
}
template <Params param>
inline constexpr void set_changed()
{
if constexpr (param == CursorManager::Params::X) {
m_mask_changed_objects |= CursorManager::ChangedValues::MouseCoords;
} else if constexpr (param == CursorManager::Params::Y) {
m_mask_changed_objects |= CursorManager::ChangedValues::MouseCoords;
} else if constexpr (param == CursorManager::Params::LeftButton) {
m_mask_changed_objects |= CursorManager::ChangedValues::LeftButton;
} else if constexpr (param == CursorManager::Params::RightButton) {
m_mask_changed_objects |= CursorManager::ChangedValues::RightButton;
} else if constexpr (param == CursorManager::Params::Wheel) {
m_mask_changed_objects |= CursorManager::ChangedValues::Wheel;
} else {
[]<bool flag = false>() { static_assert(flag, "Could not set_changed() for the param!"); }
();
}
}
void update_position(MouseEvent* mouse_event)
{
clear_changed();
set<Params::OffsetX>(mouse_event->packet().x_offset);
set<Params::OffsetY>(-mouse_event->packet().y_offset);
set<Params::LeftButton>((mouse_event->packet().button_states & 1));
set<Params::RightButton>((mouse_event->packet().button_states & 2) >> 1);
set<Params::Wheel>(mouse_event->packet().wheel_data);
}
private:
enum ChangedValues {
MouseCoords = 0x1,
LeftButton = 0x2,
RightButton = 0x4,
Wheel = 0x8,
};
int m_mouse_x { 0 };
int m_mouse_y { 0 };
int m_mouse_offset_x { 0 };
int m_mouse_offset_y { 0 };
int m_wheel { 0 };
bool m_mouse_left_button_pressed { false };
bool m_mouse_right_button_pressed { false };
uint32_t m_mask_changed_objects { 0 };
bool m_mouse_changed_button_status { false };
Screen& m_screen;
LG::PixelBitmap m_std_cursor;
};
template <CursorManager::Params param>
inline constexpr int CursorManager::get()
{
if constexpr (param == CursorManager::Params::X) {
return m_mouse_x;
} else if constexpr (param == CursorManager::Params::Y) {
return m_mouse_y;
} else if constexpr (param == CursorManager::Params::OffsetX) {
return m_mouse_offset_x;
} else if constexpr (param == CursorManager::Params::OffsetY) {
return m_mouse_offset_y;
} else if constexpr (param == CursorManager::Params::Wheel) {
return m_wheel;
} else {
[]<bool flag = false>() { static_assert(flag, "Could call get() only for coords-like params!"); }
();
}
}
template <CursorManager::Params param>
inline constexpr bool CursorManager::pressed() const
{
if constexpr (param == CursorManager::Params::LeftButton) {
return m_mouse_left_button_pressed;
} else if constexpr (param == CursorManager::Params::RightButton) {
return m_mouse_right_button_pressed;
} else {
[]<bool flag = false>() { static_assert(flag, "Could call pressed() only for buttons!"); }
();
}
}
template <CursorManager::Params param>
inline constexpr bool CursorManager::is_changed()
{
if constexpr (param == CursorManager::Params::X) {
return (m_mask_changed_objects & CursorManager::ChangedValues::MouseCoords);
} else if constexpr (param == CursorManager::Params::Y) {
return (m_mask_changed_objects & CursorManager::ChangedValues::MouseCoords);
} else if constexpr (param == CursorManager::Params::LeftButton) {
return (m_mask_changed_objects & CursorManager::ChangedValues::LeftButton);
} else if constexpr (param == CursorManager::Params::RightButton) {
return (m_mask_changed_objects & CursorManager::ChangedValues::RightButton);
} else if constexpr (param == CursorManager::Params::Coords) {
return (m_mask_changed_objects & CursorManager::ChangedValues::MouseCoords);
} else if constexpr (param == CursorManager::Params::Buttons) {
return (m_mask_changed_objects & CursorManager::ChangedValues::LeftButton) | (m_mask_changed_objects & CursorManager::ChangedValues::RightButton);
} else if constexpr (param == CursorManager::Params::Wheel) {
return (m_mask_changed_objects & CursorManager::ChangedValues::Wheel);
} else {
[]<bool flag = false>() { static_assert(flag, "Could not call is_changed() for the param!"); }
();
}
}
} // namespace WinServer

View File

@@ -0,0 +1,69 @@
#pragma once
#include "../Components/ControlBar/ControlBar.h"
#include "../Components/LoadingScreen/LoadingScreen.h"
#include "../Components/MenuBar/MenuBar.h"
#include "../Components/MenuBar/Widgets/Clock/Clock.h"
#include "../Components/MenuBar/Widgets/ControlPanelToggle/ControlPanelToggle.h"
#include "../Components/Popup/Popup.h"
#include "../Devices/Devices.h"
#include "../Devices/Screen.h"
#include "../IPC/Connection.h"
#include "Compositor.h"
#include "CursorManager.h"
#include "ResourceManager.h"
#include "WindowManager.h"
#include <cstdlib>
#include <libfoundation/EventLoop.h>
#include <new>
#include <sys/socket.h>
#include <unistd.h>
namespace WinServer {
class InitManager {
public:
InitManager() = delete;
~InitManager() = delete;
static void load_screen()
{
nice(-3);
new WinServer::Screen();
new WinServer::LoadingScreen();
}
template <class T, int Cost = 1, class... Args>
static constexpr inline void load_core_component(Args&&... args)
{
new T(std::forward<Args>(args)...);
WinServer::LoadingScreen::the().move_progress<T, Cost>();
}
template <class T, int Cost = 1, class... Args>
static constexpr inline void add_widget(Args&&... args)
{
WinServer::MenuBar::the().add_widget<T>(std::forward<Args>(args)...);
WinServer::LoadingScreen::the().move_progress<T, Cost>();
}
static inline int launch_app(const char* path, int uid = 0)
{
int pid = fork();
if (!pid) {
setuid(uid);
setgid(uid);
for (int i = 3; i < 32; i++) {
close(i);
}
execlp(path, path, NULL);
std::abort();
}
return pid;
}
private:
};
};

View File

@@ -0,0 +1,15 @@
#include "ResourceManager.h"
#include <libg/ImageLoaders/PNGLoader.h>
namespace WinServer {
ResourceManager* s_WinServer_ResourceManager_the = nullptr;
ResourceManager::ResourceManager()
{
s_WinServer_ResourceManager_the = this;
LG::PNG::PNGLoader loader;
m_background = loader.load_from_file("/res/wallpapers/abstract.png");
}
} // namespace WinServer

View File

@@ -0,0 +1,23 @@
#pragma once
#include <libg/PixelBitmap.h>
#include <libg/Point.h>
namespace WinServer {
class ResourceManager {
public:
inline static ResourceManager& the()
{
extern ResourceManager* s_WinServer_ResourceManager_the;
return *s_WinServer_ResourceManager_the;
}
ResourceManager();
inline const LG::PixelBitmap& background() const { return m_background; }
private:
LG::PixelBitmap m_background;
};
} // namespace WinServer

View File

@@ -0,0 +1,599 @@
#include "WindowManager.h"
#include "../Devices/Screen.h"
#include "../Managers/CursorManager.h"
#include <libapi/window_server/MessageContent/MouseAction.h>
#include <libfoundation/KeyboardMapping.h>
#include <libfoundation/Logger.h>
// #define WM_DEBUG
namespace WinServer {
static PopupData WindowPopupData {};
WindowManager* s_WinServer_WindowManager_the = nullptr;
WindowManager::WindowManager()
: m_screen(Screen::the())
, m_connection(Connection::the())
, m_compositor(Compositor::the())
, m_cursor_manager(CursorManager::the())
, m_event_loop(LFoundation::EventLoop::the())
, m_std_menubar_content()
, m_visible_area(m_screen.bounds())
{
s_WinServer_WindowManager_the = this;
shrink_visible_area(menu_bar().height(), 0);
#ifdef TARGET_DESKTOP
menu_bar().set_background_color(LG::Color::LightSystemOpaque128);
#endif // TARGET_DESKTOP
}
void WindowManager::setup_dock(Window* window)
{
#ifdef TARGET_DESKTOP
window->make_frameless();
window->bounds().set_y(m_screen.bounds().max_y() - window->bounds().height() + 1);
window->content_bounds().set_y(m_screen.bounds().max_y() - window->bounds().height() + 1);
shrink_visible_area(0, window->bounds().height());
#endif // TARGET_DESKTOP
window->set_event_mask(WindowEvent::IconChange | WindowEvent::WindowStatus | WindowEvent::WindowCreation | WindowEvent::TitleChange);
m_dock.set_window(window);
}
void WindowManager::setup_applist(Window* window)
{
#ifdef TARGET_DESKTOP
window->make_frameless();
const size_t coorx = (visible_area().max_x() - window->bounds().width()) / 2;
const size_t coory = visible_area().max_y() - window->bounds().height() - 8;
window->bounds().set_x(coorx);
window->content_bounds().set_x(coorx);
window->bounds().set_y(coory);
window->content_bounds().set_y(coory);
#endif // TARGET_DESKTOP
m_applist.set_window(window);
minimize_window(*window);
}
void WindowManager::add_system_window(Window* window)
{
switch (window->type()) {
case WindowType::Homescreen:
setup_dock(window);
break;
case WindowType::AppList:
setup_applist(window);
break;
default:
break;
}
}
void WindowManager::add_window(Window* window)
{
m_windows.push_back(window);
set_active_window(window);
if (window->type() != WindowType::Standard) {
add_system_window(window);
}
notify_window_creation(window->id());
}
void WindowManager::remove_attention_from_window(Window* window)
{
if (movable_window() == window) {
m_movable_window = nullptr;
}
if (active_window() == window) {
set_active_window(nullptr);
}
if (hovered_window() == window) {
set_hovered_window(nullptr);
}
}
void WindowManager::on_window_became_invisible(Window* window)
{
if (window->type() == WindowType::Standard && active_window() == window) {
#ifdef TARGET_DESKTOP
menu_bar().set_menubar_content(nullptr, m_compositor);
#elif TARGET_MOBILE
menu_bar().set_style(StatusBarStyle::StandardOpaque);
m_compositor.invalidate(menu_bar().bounds());
#endif
}
m_compositor.invalidate(window->bounds());
}
void WindowManager::remove_window(Window* window_ptr)
{
notify_window_status_changed(window_ptr->id(), WindowStatusUpdateType::Removed);
m_windows.erase(std::find(m_windows.begin(), m_windows.end(), window_ptr));
on_window_became_invisible(window_ptr);
remove_attention_from_window(window_ptr);
delete window_ptr;
}
void WindowManager::minimize_window(Window& window)
{
Window* window_ptr = &window;
notify_window_status_changed(window.id(), WindowStatusUpdateType::Minimized);
window.set_visible(false);
m_windows.erase(std::find(m_windows.begin(), m_windows.end(), window_ptr));
m_windows.push_back(window_ptr);
on_window_became_invisible(window_ptr);
remove_attention_from_window(window_ptr);
}
void WindowManager::resize_window(Window& window, const LG::Size& size)
{
window.did_size_change(size);
send_event(new ResizeMessage(window.connection_id(), window.id(), LG::Rect(0, 0, size.width(), size.height())));
m_compositor.invalidate(window.bounds());
}
void WindowManager::maximize_window(Window& window)
{
size_t fullscreen_h = m_screen.height();
fullscreen_h = visible_area().height();
const size_t vertical_borders = Desktop::WindowFrame::std_top_border_size() + Desktop::WindowFrame::std_bottom_border_size();
const size_t horizontal_borders = Desktop::WindowFrame::std_left_border_size() + Desktop::WindowFrame::std_right_border_size();
move_window(&window, -window.bounds().min_x(), -(window.bounds().min_y() - menu_bar().height()));
resize_window(window, { m_screen.width() - horizontal_borders, fullscreen_h - vertical_borders });
}
void WindowManager::start_window_move(Window& window)
{
m_movable_window = &window;
}
WindowManager::Window* WindowManager::top_window_in_view(WindowType type) const
{
for (auto it = m_windows.begin(); it != m_windows.end(); it++) {
auto* window = (*it);
if (window->type() == type) {
return window;
}
}
return nullptr;
}
#ifdef TARGET_DESKTOP
void WindowManager::on_active_window_will_change()
{
if (!m_active_window) {
return;
}
if (m_active_window->type() == WindowType::AppList) {
m_active_window->set_visible(false);
on_window_became_invisible(m_active_window);
}
}
void WindowManager::on_active_window_did_change()
{
}
void WindowManager::bring_system_windows_to_front()
{
if (m_dock.has_value()) {
do_bring_to_front(*m_dock.window());
}
}
void WindowManager::bring_to_front(Window& window)
{
auto* prev_window = top_window_in_view(WindowType::Standard);
do_bring_to_front(window);
bring_system_windows_to_front();
window.set_visible(true);
window.frame().set_active(true);
m_compositor.invalidate(window.bounds());
if (prev_window && prev_window->id() != window.id()) {
prev_window->frame().set_active(false);
prev_window->frame().invalidate(m_compositor);
}
if (window.type() == WindowType::Standard) {
menu_bar().set_menubar_content(&window.menubar_content(), m_compositor);
} else {
menu_bar().set_menubar_content(nullptr, m_compositor);
}
}
#elif TARGET_MOBILE
void WindowManager::on_active_window_will_change()
{
}
void WindowManager::on_active_window_did_change()
{
// If current active_window has become NULL, try to restore the lastest.
if (active_window() == nullptr) {
if (auto top_window = m_windows.begin(); top_window != m_windows.end()) {
m_active_window = *top_window;
}
}
}
void WindowManager::bring_system_windows_to_front()
{
}
void WindowManager::bring_to_front(Window& window)
{
do_bring_to_front(window);
bring_system_windows_to_front();
window.set_visible(true);
m_active_window = &window;
m_compositor.invalidate(window.bounds());
if (window.type() == WindowType::Standard) {
menu_bar().set_style(window.style());
m_compositor.invalidate(menu_bar().bounds());
}
}
#endif
#ifdef TARGET_DESKTOP
bool WindowManager::continue_window_move()
{
if (!movable_window()) {
return false;
}
if (!m_cursor_manager.pressed<CursorManager::Params::LeftButton>()) {
m_movable_window = nullptr;
return true;
}
auto bounds = movable_window()->bounds();
m_compositor.invalidate(movable_window()->bounds());
move_window(movable_window(), m_cursor_manager.get<CursorManager::Params::OffsetX>(), m_cursor_manager.get<CursorManager::Params::OffsetY>());
bounds.unite(movable_window()->bounds());
m_compositor.invalidate(bounds);
return true;
}
#endif // TARGET_DESKTOP
void WindowManager::update_mouse_position(std::unique_ptr<LFoundation::Event> mouse_event)
{
auto invalidate_bounds = m_cursor_manager.current_cursor().bounds();
invalidate_bounds.origin().set(m_cursor_manager.draw_position());
m_compositor.invalidate(invalidate_bounds);
m_cursor_manager.update_position((WinServer::MouseEvent*)mouse_event.get());
invalidate_bounds.origin().set(m_cursor_manager.draw_position());
m_compositor.invalidate(invalidate_bounds);
}
#ifdef TARGET_DESKTOP
void WindowManager::receive_mouse_event(std::unique_ptr<LFoundation::Event> event)
{
update_mouse_position(std::move(event));
if (continue_window_move()) {
return;
}
// Checking and dispatching mouse move for Popup.
if (popup().visible() && popup().bounds().contains(m_cursor_manager.x(), m_cursor_manager.y())) {
popup().on_mouse_move(m_cursor_manager);
if (m_cursor_manager.is_changed<CursorManager::Params::Buttons>()) {
popup().on_mouse_status_change(m_cursor_manager);
}
return;
} else {
popup().on_mouse_leave(m_cursor_manager);
if (m_cursor_manager.pressed<CursorManager::Params::LeftButton>()) {
popup().set_visible(false);
}
}
// Checking and dispatching mouse move for MenuBar.
if (menu_bar().bounds().contains(m_cursor_manager.x(), m_cursor_manager.y())) {
menu_bar().on_mouse_move(m_cursor_manager);
if (m_cursor_manager.is_changed<CursorManager::Params::Buttons>()) {
menu_bar().on_mouse_status_change(m_cursor_manager);
}
return;
} else if (menu_bar().is_hovered()) {
menu_bar().on_mouse_leave(m_cursor_manager);
}
Window* curr_hovered_window = nullptr;
Window* window_under_mouse_ptr = nullptr;
for (auto* window_ptr : m_windows) {
auto& window = *window_ptr;
if (!window.visible()) {
continue;
}
if (window.bounds().contains(m_cursor_manager.x(), m_cursor_manager.y())) {
window_under_mouse_ptr = window_ptr;
break;
}
}
if (m_cursor_manager.pressed<CursorManager::Params::LeftButton>() || m_cursor_manager.pressed<CursorManager::Params::RightButton>()) {
if (!window_under_mouse_ptr && m_active_window) {
menu_bar().set_menubar_content(nullptr, m_compositor);
m_compositor.invalidate(m_active_window->bounds());
m_active_window->frame().set_active(false);
set_active_window(nullptr);
} else if (m_active_window != window_under_mouse_ptr) {
set_active_window(window_under_mouse_ptr);
}
}
if (!window_under_mouse_ptr) {
if (hovered_window()) {
send_event(new MouseLeaveMessage(hovered_window()->connection_id(), hovered_window()->id(), 0, 0));
}
return;
}
auto& window = *window_under_mouse_ptr;
if (window.content_bounds().contains(m_cursor_manager.x(), m_cursor_manager.y())) {
if (window.type() == WindowType::Standard && active_window() != &window) {
curr_hovered_window = nullptr;
} else {
if (m_cursor_manager.is_changed<CursorManager::Params::Coords>()) {
LG::Point<int> point(m_cursor_manager.x(), m_cursor_manager.y());
point.offset_by(-window.content_bounds().origin());
send_event(new MouseMoveMessage(window.connection_id(), window.id(), point.x(), point.y()));
}
curr_hovered_window = &window;
}
} else if (m_cursor_manager.is_changed<CursorManager::Params::LeftButton>() && m_cursor_manager.pressed<CursorManager::Params::LeftButton>()) {
auto tap_point = LG::Point<int>(m_cursor_manager.x() - window.frame().bounds().min_x(), m_cursor_manager.y() - window.frame().bounds().min_y());
window.frame().receive_tap_event(tap_point);
start_window_move(window);
}
if (hovered_window() && hovered_window() != curr_hovered_window) {
send_event(new MouseLeaveMessage(hovered_window()->connection_id(), hovered_window()->id(), 0, 0));
}
set_hovered_window(curr_hovered_window);
if (hovered_window() && m_cursor_manager.is_changed<CursorManager::Params::Buttons>()) {
LG::Point<int> point(m_cursor_manager.x(), m_cursor_manager.y());
point.offset_by(-window.content_bounds().origin());
auto buttons_state = MouseActionState();
if (m_cursor_manager.is_changed<CursorManager::Params::LeftButton>()) {
// TODO: May be remove if?
if (m_cursor_manager.pressed<CursorManager::Params::LeftButton>()) {
buttons_state.set(MouseActionType::LeftMouseButtonPressed);
} else {
buttons_state.set(MouseActionType::LeftMouseButtonReleased);
}
}
send_event(new MouseActionMessage(window.connection_id(), window.id(), buttons_state.state(), point.x(), point.y()));
}
if (hovered_window() && m_cursor_manager.is_changed<CursorManager::Params::Wheel>()) {
auto* window = hovered_window();
auto data = m_cursor_manager.get<CursorManager::Params::Wheel>();
send_event(new MouseWheelMessage(window->connection_id(), window->id(), data, m_cursor_manager.x(), m_cursor_manager.y()));
}
}
#elif TARGET_MOBILE
void WindowManager::receive_mouse_event(std::unique_ptr<LFoundation::Event> event)
{
update_mouse_position(std::move(event));
if (m_compositor.control_bar().control_button_bounds().contains(m_cursor_manager.x(), m_cursor_manager.y()) && active_window()) {
if (m_cursor_manager.pressed<CursorManager::Params::LeftButton>()) {
switch (active_window()->type()) {
case WindowType::Standard:
remove_window(active_window());
break;
case WindowType::AppList:
minimize_window(*active_window());
break;
case WindowType::Homescreen:
default:
break;
}
}
return;
}
// Tap emulation
if (m_cursor_manager.is_changed<CursorManager::Params::Buttons>() && active_window()) {
auto window = active_window();
auto buttons_state = MouseActionState();
LG::Point<int> point(m_cursor_manager.x(), m_cursor_manager.y());
point.offset_by(-window->content_bounds().origin());
if (m_cursor_manager.is_changed<CursorManager::Params::LeftButton>()) {
// TODO: May be remove if?
if (m_cursor_manager.pressed<CursorManager::Params::LeftButton>()) {
buttons_state.set(MouseActionType::LeftMouseButtonPressed);
} else {
buttons_state.set(MouseActionType::LeftMouseButtonReleased);
}
}
send_event(new MouseActionMessage(window->connection_id(), window->id(), buttons_state.state(), point.x(), point.y()));
}
if (active_window()) {
auto window = active_window();
if (m_cursor_manager.pressed<CursorManager::Params::LeftButton>()) {
if (m_cursor_manager.is_changed<CursorManager::Params::Coords>()) {
LG::Point<int> point(m_cursor_manager.x(), m_cursor_manager.y());
point.offset_by(-window->content_bounds().origin());
send_event(new MouseMoveMessage(window->connection_id(), window->id(), point.x(), point.y()));
}
}
}
}
#endif // TARGET_MOBILE
void WindowManager::receive_keyboard_event(std::unique_ptr<LFoundation::Event> event)
{
auto* keyboard_event = reinterpret_cast<KeyboardEvent*>(event.release());
if (active_window()) {
auto window = active_window();
send_event(new KeyboardMessage(window->connection_id(), window->id(), keyboard_event->packet().key));
}
delete keyboard_event;
}
void WindowManager::receive_event(std::unique_ptr<LFoundation::Event> event)
{
switch (event->type()) {
case WinServer::Event::Type::MouseEvent:
receive_mouse_event(std::move(event));
break;
case WinServer::Event::Type::KeyboardEvent:
receive_keyboard_event(std::move(event));
break;
}
}
// Notifiers
bool WindowManager::notify_listner_about_window_creation(const Window& win, int changed_window_id)
{
#ifdef WM_DEBUG
Logger::debug << "notify_listner_about_window_status " << win.id() << " that " << changed_window_id << " " << type << std::endl;
#endif
auto* changed_window_ptr = window(changed_window_id);
if (!changed_window_ptr) {
return false;
}
send_event(new NotifyWindowCreateMessage(win.connection_id(), win.id(), changed_window_ptr->bundle_id(), changed_window_ptr->icon_path(), changed_window_id, changed_window_ptr->type()));
return true;
}
bool WindowManager::notify_listner_about_window_status(const Window& win, int changed_window_id, WindowStatusUpdateType type)
{
#ifdef WM_DEBUG
Logger::debug << "notify_listner_about_window_status " << win.id() << " that " << changed_window_id << " " << type << std::endl;
#endif
auto* changed_window_ptr = window(changed_window_id);
if (!changed_window_ptr) {
return false;
}
send_event(new NotifyWindowStatusChangedMessage(win.connection_id(), win.id(), changed_window_id, (int)type));
return true;
}
bool WindowManager::notify_listner_about_changed_icon(const Window& win, int changed_window_id)
{
#ifdef WM_DEBUG
Logger::debug << "notify_listner_about_changed_icon " << win.id() << " that " << changed_window_id << std::endl;
#endif
auto* changed_window_ptr = window(changed_window_id);
if (!changed_window_ptr) {
return false;
}
send_event(new NotifyWindowIconChangedMessage(win.connection_id(), win.id(), changed_window_id, changed_window_ptr->icon_path()));
return true;
}
bool WindowManager::notify_listner_about_changed_title(const Window& win, int changed_window_id)
{
#ifdef WM_DEBUG
Logger::debug << "notify_listner_about_changed_title " << win.id() << " that " << changed_window_id << std::endl;
#endif
auto* changed_window_ptr = window(changed_window_id);
if (!changed_window_ptr) {
return false;
}
send_event(new NotifyWindowTitleChangedMessage(win.connection_id(), win.id(), changed_window_id, changed_window_ptr->app_title()));
return true;
}
void WindowManager::notify_window_creation(int changed_window_id)
{
for (auto* window_ptr : m_windows) {
auto& window = *window_ptr;
if (window.event_mask() & WindowEvent::WindowCreation) {
notify_listner_about_window_creation(window, changed_window_id);
}
}
}
void WindowManager::notify_window_status_changed(int changed_window_id, WindowStatusUpdateType type)
{
for (auto* window_ptr : m_windows) {
auto& window = *window_ptr;
if (window.event_mask() & WindowEvent::WindowStatus) {
notify_listner_about_window_status(window, changed_window_id, type);
}
}
}
void WindowManager::notify_window_icon_changed(int changed_window_id)
{
for (auto* window_ptr : m_windows) {
auto& window = *window_ptr;
if (window.event_mask() & WindowEvent::IconChange) {
notify_listner_about_changed_icon(window, changed_window_id);
}
}
}
void WindowManager::notify_window_title_changed(int changed_window_id)
{
for (auto* window_ptr : m_windows) {
auto& window = *window_ptr;
if (window.event_mask() & WindowEvent::TitleChange) {
notify_listner_about_changed_title(window, changed_window_id);
}
}
}
#ifdef TARGET_DESKTOP
void WindowManager::on_window_style_change(Window& window)
{
if (window.visible()) {
window.frame().invalidate(m_compositor);
}
}
#elif TARGET_MOBILE
void WindowManager::on_window_style_change(Window& window)
{
if (active_window() == &window && window.type() == WindowType::Standard) {
menu_bar().set_style(window.style());
m_compositor.invalidate(menu_bar().bounds());
}
}
#endif
void WindowManager::on_window_menubar_change(Window& window)
{
if (m_active_window == &window) {
menu_bar().invalidate_menubar_panel(m_compositor);
}
}
void WindowManager::on_window_misbehave(Window& window, ViolationClass viocls)
{
switch (viocls) {
case ViolationClass::Ignorable:
case ViolationClass::Moderate:
break;
case ViolationClass::Serious:
// TODO: Currently we only remove the window, but all apps
// should be stopped with with a signal.
remove_window(&window);
break;
default:
break;
}
}
} // namespace WinServer

View File

@@ -0,0 +1,178 @@
#pragma once
#include "../Components/ControlBar/ControlBar.h"
#include "../Components/MenuBar/MenuBar.h"
#include "../Components/Security/Violations.h"
#include "../Devices/Screen.h"
#include "../IPC/Connection.h"
#include "../IPC/Event.h"
#include "../IPC/ServerDecoder.h"
#include "../Managers/Compositor.h"
#include "../SystemApps/SystemApp.h"
#include "../Target/Generic/Window.h"
#include <algorithm>
#include <libapi/window_server/Connections/WSConnection.h>
#include <libfoundation/EventLoop.h>
#include <libfoundation/EventReceiver.h>
#include <libipc/ServerConnection.h>
#include <list>
#include <vector>
namespace WinServer {
class WindowManager : public LFoundation::EventReceiver {
#ifdef TARGET_DESKTOP
using Window = WinServer::Desktop::Window;
#elif TARGET_MOBILE
using Window = WinServer::Mobile::Window;
#endif
public:
inline static WindowManager& the()
{
extern WindowManager* s_WinServer_WindowManager_the;
return *s_WinServer_WindowManager_the;
}
WindowManager();
void add_window(Window* window);
void remove_window(Window* window);
void resize_window(Window& window, const LG::Size& size);
void close_window(Window& window) { send_event(new WindowCloseRequestMessage(window.connection_id(), window.id())); }
void minimize_window(Window& window);
void maximize_window(Window& window);
template <typename Callback>
void minimize_windows(Callback callback)
{
std::vector<Window*> hided;
for (auto* window : m_windows) {
if (window && window->type() == WindowType::Standard && callback(window)) {
window->set_visible(false);
hided.push_back(window);
on_window_became_invisible(window);
remove_attention_from_window(window);
}
}
for (auto* window : hided) {
m_windows.erase(std::find(m_windows.begin(), m_windows.end(), window));
m_windows.push_back(window);
}
}
Window* top_window_in_view(WindowType type) const;
inline Window* window(int id)
{
for (auto* window : m_windows) {
if (window->id() == id) {
return window;
}
}
return nullptr;
}
inline void move_window(Window* window, int x_offset, int y_offset)
{
y_offset = std::max(y_offset, (int)visible_area().min_y() - (int)Desktop::WindowFrame::std_top_border_frame_size() - window->bounds().min_y());
if (m_dock.has_value()) [[likely]] {
y_offset = std::min(y_offset, (int)(visible_area().max_y() - window->content_bounds().min_y()));
}
window->bounds().offset_by(x_offset, y_offset);
window->content_bounds().offset_by(x_offset, y_offset);
}
inline void do_bring_to_front(Window& window)
{
auto* window_ptr = &window;
m_windows.erase(std::find(m_windows.begin(), m_windows.end(), window_ptr));
m_windows.push_front(window_ptr);
}
void bring_to_front(Window& window);
inline std::list<Window*>& windows() { return m_windows; }
inline const std::list<Window*>& windows() const { return m_windows; }
inline int next_win_id() { return ++m_next_win_id; }
const LG::Rect& visible_area() const { return m_visible_area; }
void shrink_visible_area(int top, int bottom) { m_visible_area.set_y(m_visible_area.min_y() + top), m_visible_area.set_height(m_visible_area.height() - top - bottom); }
void receive_event(std::unique_ptr<LFoundation::Event> event) override;
// Notifiers
bool notify_listner_about_window_creation(const Window& window, int changed_window_id);
bool notify_listner_about_window_status(const Window& window, int changed_window_id, WindowStatusUpdateType type);
bool notify_listner_about_changed_icon(const Window&, int changed_window_id);
bool notify_listner_about_changed_title(const Window&, int changed_window_id);
void notify_window_creation(int changed_window_id);
void notify_window_status_changed(int changed_window_id, WindowStatusUpdateType type);
void notify_window_icon_changed(int changed_window_id);
void notify_window_title_changed(int changed_window_id);
inline void ask_to_set_active_window(Window* win) { set_active_window(win); }
inline void ask_to_set_active_window(Window& win) { set_active_window(win); }
void on_window_misbehave(Window& window, ViolationClass);
void on_window_style_change(Window& win);
void on_window_menubar_change(Window& window);
// Popup & Menubar
inline Popup& popup() { return m_compositor.popup(); }
inline const Popup& popup() const { return m_compositor.popup(); }
inline MenuBar& menu_bar() { return m_compositor.menu_bar(); }
inline const MenuBar& menu_bar() const { return m_compositor.menu_bar(); }
private:
void add_system_window(Window* window);
void bring_system_windows_to_front();
void setup_dock(Window* window);
void setup_applist(Window* window);
void remove_attention_from_window(Window* window);
void start_window_move(Window& window);
bool continue_window_move();
void update_mouse_position(std::unique_ptr<LFoundation::Event> mouse_event);
void receive_mouse_event(std::unique_ptr<LFoundation::Event> event);
void receive_keyboard_event(std::unique_ptr<LFoundation::Event> event);
inline Window* movable_window() { return m_movable_window; }
inline Window* hovered_window() { return m_hovered_window; }
inline void set_hovered_window(Window* win) { m_hovered_window = win; }
inline Window* active_window() { return m_active_window; }
inline void set_active_window(Window* win) { on_active_window_will_change(), bring_to_front(*win), m_active_window = win, on_active_window_did_change(); }
inline void set_active_window(Window& win) { on_active_window_will_change(), bring_to_front(win), m_active_window = &win, on_active_window_did_change(); }
inline void set_active_window(std::nullptr_t) { on_active_window_will_change(), m_active_window = nullptr, on_active_window_did_change(); }
void on_window_became_invisible(Window* window);
void on_active_window_will_change();
void on_active_window_did_change();
inline void send_event(Message* msg) { m_event_loop.add(m_connection, new SendEvent(msg)); }
std::list<Window*> m_windows;
Screen& m_screen;
Connection& m_connection;
Compositor& m_compositor;
CursorManager& m_cursor_manager;
LFoundation::EventLoop& m_event_loop;
std::vector<MenuDir> m_std_menubar_content;
LG::Rect m_visible_area;
SystemApp m_dock;
SystemApp m_applist;
// TODO: implement with std::weak_ptr.
Window* m_movable_window {};
Window* m_active_window {};
Window* m_hovered_window {};
int m_next_win_id { 0 };
};
} // namespace WinServer

View File

@@ -0,0 +1,24 @@
#pragma once
#include "../Target/Generic/Window.h"
namespace WinServer {
class SystemApp {
public:
SystemApp() = default;
~SystemApp() = default;
void set_window(Window* win) { m_window = win; }
Window* window() { return m_window; }
const Window* window() const { return m_window; }
bool has_value() const { return !!m_window; }
operator bool() const { return has_value(); }
private:
bool visible;
Window* m_window {};
};
}

View File

@@ -0,0 +1,76 @@
#include "Window.h"
#include "../../Managers/WindowManager.h"
#include <utility>
namespace WinServer::Desktop {
Window::Window(int connection_id, int id, CreateWindowMessage& msg)
: BaseWindow(connection_id, id, msg)
, m_frame(*this)
{
m_bounds = LG::Rect(0, 0, msg.width() + frame().left_border_size() + frame().right_border_size(), msg.height() + frame().top_border_size() + frame().bottom_border_size());
m_content_bounds = LG::Rect(m_frame.left_border_size(), m_frame.top_border_size(), msg.width(), msg.height());
m_content_bitmap = LG::PixelBitmap(m_buffer.data(), content_bounds().width(), content_bounds().height());
// Creating standard menubar directory entry.
m_menubar_content.push_back(MenuDir(m_app_name, 0));
m_menubar_content[0].add_item(PopupItem { PopupItem::InternalId, "Minimize others", [this](int) { WindowManager::the().minimize_windows([this](Window* win) { return win != this; }); } });
m_menubar_content[0].add_item(PopupItem { PopupItem::InternalId, "Minimize", [this](int) { WindowManager::the().minimize_window(*this); } });
m_menubar_content[0].add_item(PopupItem { PopupItem::InternalId, "Close", [this](int) { WindowManager::the().close_window(*this); } });
}
Window::Window(Window&& win)
: BaseWindow(std::move(win))
, m_frame(*this, std::move(win.m_frame.control_panel_buttons()), std::move(win.m_frame.window_control_buttons()))
, m_corner_mask(std::move(win.m_corner_mask))
, m_menubar_content(std::move(win.m_menubar_content))
{
}
void Window::make_frame()
{
uint32_t x = m_bounds.min_x();
uint32_t y = m_bounds.min_y();
uint32_t content_width = m_content_bounds.width();
uint32_t content_height = m_content_bounds.height();
m_bounds = LG::Rect(x, y, content_width + frame().left_border_size() + frame().right_border_size(), content_height + frame().top_border_size() + frame().bottom_border_size());
m_content_bounds = LG::Rect(x + m_frame.left_border_size(), y + m_frame.top_border_size(), content_width, content_height);
m_frame.set_visible(true);
}
void Window::make_frameless()
{
uint32_t x = m_bounds.min_x();
uint32_t y = m_bounds.min_y();
uint32_t content_width = m_content_bounds.width();
uint32_t content_height = m_content_bounds.height();
m_bounds = LG::Rect(x, y, content_width, content_height);
m_content_bounds = LG::Rect(x, y, content_width, content_height);
m_frame.set_visible(false);
}
void Window::recalc_bounds(const LG::Size& size)
{
m_content_bounds.set_width(size.width());
m_content_bounds.set_height(size.height());
m_bounds.set_width(size.width() + frame().left_border_size() + frame().right_border_size());
m_bounds.set_height(size.height() + frame().top_border_size() + frame().bottom_border_size());
}
void Window::did_size_change(const LG::Size& size)
{
recalc_bounds(size);
}
void Window::on_style_change()
{
WindowManager::the().on_window_style_change(*this);
}
void Window::on_menubar_change()
{
WindowManager::the().on_window_menubar_change(*this);
}
} // namespace WinServer

View File

@@ -0,0 +1,47 @@
#pragma once
#include "../../Components/Base/BaseWindow.h"
#include "../../Components/MenuBar/MenuItem.h"
#include "../../IPC/Connection.h"
#include "WindowFrame.h"
#include <libfoundation/SharedBuffer.h>
#include <libg/PixelBitmap.h>
#include <libg/Rect.h>
#include <sys/types.h>
#include <utility>
namespace WinServer::Desktop {
class Window : public BaseWindow {
public:
Window(int connection_id, int id, CreateWindowMessage& msg);
Window(Window&& win);
inline WindowFrame& frame() { return m_frame; }
inline const WindowFrame& frame() const { return m_frame; }
inline const LG::CornerMask& corner_mask() const { return m_corner_mask; }
inline std::vector<MenuDir>& menubar_content() { return m_menubar_content; }
inline const std::vector<MenuDir>& menubar_content() const { return m_menubar_content; }
void on_menubar_change();
virtual void did_app_title_change() override { m_frame.on_set_app_title(); }
virtual void did_icon_path_change() override { m_frame.on_set_icon(); }
virtual void did_size_change(const LG::Size& size) override;
inline void set_style(StatusBarStyle style) { m_frame.set_style(style), on_style_change(); }
void make_frame();
void make_frameless();
private:
void recalc_bounds(const LG::Size& size);
void on_style_change();
WindowFrame m_frame;
LG::CornerMask m_corner_mask { LG::CornerMask::SystemRadius, LG::CornerMask::NonMasked, LG::CornerMask::Masked };
std::vector<MenuDir> m_menubar_content;
};
} // namespace WinServer

View File

@@ -0,0 +1,232 @@
#include "WindowFrame.h"
#include "../../Components/Elements/Button.h"
#include "../../Managers/WindowManager.h"
#include "Window.h"
#include <libg/Font.h>
#include <libg/ImageLoaders/PNGLoader.h>
#include <libg/Rect.h>
#include <utility>
#define CONTROL_PANEL_CLOSE 0x0
#define CONTROL_PANEL_MAXIMIZE 0x1
#define CONTROL_PANEL_MINIMIZE 0x2
namespace WinServer::Desktop {
static const uint32_t s_close_button_glyph_data[10] = {
0b1100000011,
0b1110000111,
0b0111001110,
0b0011111100,
0b0001111000,
0b0001111000,
0b0011111100,
0b0111001110,
0b1110000111,
0b1100000011,
};
static const uint32_t s_maximise_button_glyph_data[10] = {
0b1111100000,
0b1111000000,
0b1110000000,
0b1100000000,
0b1000000000,
0b0000000001,
0b0000000011,
0b0000000111,
0b0000001111,
0b0000011111
};
static const uint32_t s_minimise_button_glyph_data[10] = {
0b0000000000,
0b0000000000,
0b0000000000,
0b0000000000,
0b0000000000,
0b0000000000,
0b0000000000,
0b0000000000,
0b1111111111,
0b1111111111
};
WindowFrame::WindowFrame(Window& window)
: m_window(window)
, m_window_control_buttons()
, m_control_panel_buttons()
{
set_style(StatusBarStyle::StandardLight);
LG::GlyphMetrics metrics = {
.width = 10,
.height = 10,
.top_bearing = 10,
.left_bearing = 0,
.baseline = 0,
.advance = 10,
.font_size = 10
};
auto* close = new Button();
close->set_icon(LG::Glyph(s_close_button_glyph_data, metrics, LG::Glyph::ConstDataMarker {}));
auto* maximize = new Button();
maximize->set_icon(LG::Glyph(s_maximise_button_glyph_data, metrics, LG::Glyph::ConstDataMarker {}));
auto* minimize = new Button();
minimize->set_icon(LG::Glyph(s_minimise_button_glyph_data, metrics, LG::Glyph::ConstDataMarker {}));
close->set_title_color(LG::Color(196, 128, 128));
m_window_control_buttons.push_back(close);
m_window_control_buttons.push_back(maximize);
m_window_control_buttons.push_back(minimize);
}
WindowFrame::WindowFrame(Window& window, std::vector<Button*>&& control_panel_buttons, std::vector<Button*>&& window_control_buttons)
: m_window(window)
, m_window_control_buttons(std::move(window_control_buttons))
, m_control_panel_buttons(std::move(control_panel_buttons))
{
}
void WindowFrame::on_set_app_title()
{
m_app_title_width = Helpers::text_width(m_window.app_title(), LG::Font::system_font());
if (style().show_text()) {
WinServer::Compositor::the().invalidate(bounds());
}
}
void WindowFrame::add_control(const std::string& title)
{
auto* new_control = new Button();
new_control->set_title(title);
m_control_panel_buttons.push_back(new_control);
WinServer::Compositor::the().invalidate(bounds());
}
void WindowFrame::draw(LG::Context& ctx)
{
if (!visible()) {
return;
}
int x = m_window.bounds().min_x();
int y = m_window.bounds().min_y();
size_t width = m_window.bounds().width();
size_t height = m_window.bounds().height();
int left_x = x + left_border_size();
int right_x = x + width - right_border_size();
int bottom_y = y + height - bottom_border_size();
// Drawing frame and shadings
int shadow_spread = LG::Shading::SystemSpread;
ctx.set_fill_color(style().color());
ctx.fill_rounded(LG::Rect(x + left_border_size(), y + std_top_border_frame_size(), width - 2 * left_border_size(), top_border_size() - std_top_border_frame_size()), LG::CornerMask(4, true, false));
ctx.set_fill_color(Color::Shadow);
const auto shading_rect = LG::Rect(x + left_border_size(), y + std_top_border_frame_size(), width - 2 * left_border_size(), height - std_top_border_frame_size() - std_bottom_border_size());
ctx.draw_box_shading(shading_rect, LG::Shading(LG::Shading::Type::Box, 0, shadow_spread), LG::CornerMask(LG::CornerMask::SystemRadius));
// Drawing labels, icons.
// Drawing positions are calculated using a start of the frame.
ctx.set_fill_color(m_text_colors[(int)active()]);
if (style().show_text()) {
Helpers::draw_text(ctx, { left_x + spacing(), y + text_y_offset() }, m_window.app_title(), LG::Font::system_font());
}
int start_controls_offset = m_app_title_width + 2 * spacing();
int start_controls = left_x + start_controls_offset;
for (int i = 0; i < m_control_panel_buttons.size(); i++) {
m_control_panel_buttons[i]->display(ctx, { start_controls, y + text_y_offset() });
start_controls += spacing() + m_control_panel_buttons[i]->bounds().width();
}
int start_buttons = right_x - spacing() - m_window_control_buttons[0]->bounds().width();
for (int i = 0; i < m_window_control_buttons.size(); i++) {
if (active() && i == 0) {
ctx.set_fill_color(m_window_control_buttons[i]->title_color());
} else {
ctx.set_fill_color(m_text_colors[(int)active()]);
}
m_window_control_buttons[i]->display(ctx, { start_buttons, y + button_y_offset() });
start_buttons += -spacing() - m_window_control_buttons[i]->bounds().width();
}
}
void WindowFrame::invalidate(WinServer::Compositor& compositor) const
{
if (!visible()) {
return;
}
int x = m_window.bounds().min_x();
int y = m_window.bounds().min_y();
size_t width = m_window.bounds().width();
size_t height = m_window.bounds().height();
int right_x = x + width - right_border_size();
int bottom_y = y + height - bottom_border_size();
compositor.invalidate(LG::Rect(x, y, width, top_border_size()));
compositor.invalidate(LG::Rect(x, y, left_border_size(), height));
compositor.invalidate(LG::Rect(right_x, y, right_border_size(), height));
compositor.invalidate(LG::Rect(x, bottom_y, width, bottom_border_size()));
}
void WindowFrame::receive_tap_event(const LG::Point<int>& tap)
{
// Calculating buttons' positions
size_t width = m_window.bounds().width();
int right_x = width - right_border_size();
int start_buttons = right_x - spacing() - m_window_control_buttons[0]->bounds().width();
for (int button_id = 0; button_id < m_window_control_buttons.size(); button_id++) {
auto button_frame = m_window_control_buttons[button_id]->bounds();
button_frame.offset_by(start_buttons, button_y_offset());
if (button_frame.contains(tap)) {
handle_control_panel_tap(button_id);
return;
}
start_buttons += -spacing() - button_frame.width();
}
}
const LG::Rect WindowFrame::bounds() const
{
const auto& bounds = m_window.bounds();
return LG::Rect(bounds.min_x(), bounds.min_y(), bounds.width(), top_border_size());
}
void WindowFrame::handle_control_panel_tap(int button_id)
{
auto& wm = WindowManager::the();
switch (button_id) {
case CONTROL_PANEL_CLOSE:
wm.close_window(m_window);
break;
case CONTROL_PANEL_MAXIMIZE:
wm.maximize_window(m_window);
break;
case CONTROL_PANEL_MINIMIZE:
wm.minimize_window(m_window);
break;
default:
break;
}
}
void WindowFrame::set_style(StatusBarStyle ts)
{
m_style = ts;
if (m_style.dark_text()) {
m_text_colors[0] = Color::InactiveText;
m_text_colors[1] = LG::Color::DarkSystemText;
} else {
m_text_colors[0] = Color::InactiveText;
m_text_colors[1] = LG::Color::LightSystemText;
}
}
void WindowFrame::on_set_icon()
{
}
} // namespace WinServer

View File

@@ -0,0 +1,87 @@
#pragma once
#include "../../Components/Elements/Button.h"
#include "../../Constants/Colors.h"
#include "../../IPC/Event.h"
#include <libapi/window_server/MessageContent/MenuBar.h>
#include <libfoundation/EventReceiver.h>
#include <libg/Context.h>
#include <libg/PixelBitmap.h>
namespace WinServer {
class Compositor;
}
namespace WinServer::Desktop {
class Window;
class WindowFrame {
public:
explicit WindowFrame(Window& window);
WindowFrame(Window& window, std::vector<Button*>&& control_panel_buttons, std::vector<Button*>&& window_control_buttons);
~WindowFrame() = default;
void draw(LG::Context&);
static constexpr size_t std_app_header_size() { return 26; }
static constexpr size_t std_top_border_frame_size() { return 4; }
static constexpr size_t std_top_border_size() { return std_top_border_frame_size() + std_app_header_size(); }
static constexpr size_t std_bottom_border_size() { return 4; }
static constexpr size_t std_left_border_size() { return 4; }
static constexpr size_t std_right_border_size() { return 4; }
inline size_t top_border_size() const { return m_top_border_size; }
inline size_t bottom_border_size() const { return std_bottom_border_size(); }
inline size_t left_border_size() const { return std_left_border_size(); }
inline size_t right_border_size() const { return std_right_border_size(); }
const LG::Rect bounds() const;
void receive_tap_event(const LG::Point<int>& tap);
void on_set_app_title();
void add_control(const std::string& title);
inline std::vector<Button*>& window_control_buttons() { return m_window_control_buttons; }
inline const std::vector<Button*>& window_control_buttons() const { return m_window_control_buttons; }
inline std::vector<Button*>& control_panel_buttons() { return m_control_panel_buttons; }
inline const std::vector<Button*>& control_panel_buttons() const { return m_control_panel_buttons; }
void handle_control_panel_tap(int button_id);
inline StatusBarStyle style() const { return m_style; }
void set_style(StatusBarStyle ts);
void set_visible(bool visible)
{
m_top_border_size = visible ? std_top_border_size() : 0;
m_visible = visible;
}
bool visible() const { return m_visible; }
void set_active(bool active) { m_active = active; }
bool active() const { return m_active; }
void invalidate(WinServer::Compositor& compositor) const;
void on_set_icon();
static constexpr int spacing() { return 8; }
static constexpr int icon_width() { return 12; }
static constexpr int icon_y_offset() { return 7 + std_top_border_frame_size(); }
static constexpr int text_y_offset() { return 9 + std_top_border_frame_size(); }
static constexpr int button_y_offset() { return 8 + std_top_border_frame_size(); }
private:
Window& m_window;
std::vector<Button*> m_window_control_buttons;
std::vector<Button*> m_control_panel_buttons;
LG::Color m_text_colors[2];
LG::Color m_color { LG::Color::LightSystemBackground };
size_t m_top_border_size { std_top_border_size() };
size_t m_app_title_width { 0 };
bool m_visible { true };
bool m_active { true };
StatusBarStyle m_style;
};
} // namespace WinServer

View File

@@ -0,0 +1,14 @@
#pragma once
#include "../Desktop/Window.h"
#include "../Mobile/Window.h"
namespace WinServer {
#ifdef TARGET_DESKTOP
using Window = Desktop::Window;
#elif TARGET_MOBILE
using Window = Mobile::Window;
#endif
} // namespace WinServer

View File

@@ -0,0 +1,25 @@
#include "Window.h"
#include "../../Managers/WindowManager.h"
#include <utility>
namespace WinServer::Mobile {
Window::Window(int connection_id, int id, CreateWindowMessage& msg)
: BaseWindow(connection_id, id, msg)
{
m_bounds = LG::Rect(0, 0, msg.width(), msg.height());
m_content_bounds = LG::Rect(0, 0, msg.width(), msg.height());
m_content_bitmap = LG::PixelBitmap(m_buffer.data(), content_bounds().width(), content_bounds().height());
}
Window::Window(Window&& win)
: BaseWindow(std::move(win))
{
}
void Window::on_style_change()
{
WindowManager::the().on_window_style_change(*this);
}
} // namespace WinServer

View File

@@ -0,0 +1,27 @@
#pragma once
#include "../../Components/Base/BaseWindow.h"
#include "../../Components/MenuBar/MenuItem.h"
#include "../../IPC/Connection.h"
#include <libfoundation/SharedBuffer.h>
#include <libg/PixelBitmap.h>
#include <libg/Rect.h>
#include <sys/types.h>
#include <utility>
namespace WinServer::Mobile {
class Window : public BaseWindow {
public:
Window(int connection_id, int id, CreateWindowMessage& msg);
Window(Window&& win);
inline void set_style(StatusBarStyle ts) { m_style = ts, on_style_change(); }
inline StatusBarStyle style() { return m_style; }
private:
void on_style_change();
StatusBarStyle m_style { StatusBarStyle::StandardLight };
};
} // namespace WinServer

View File

@@ -0,0 +1,32 @@
#include "Managers/InitManager.h"
#ifdef TARGET_DESKTOP
#define LAUNCH_PATH "/System/dock"
#elif TARGET_MOBILE
#define LAUNCH_PATH "/System/homescreen"
#endif
int main()
{
WinServer::InitManager::load_screen();
auto* event_loop = new LFoundation::EventLoop();
WinServer::InitManager::load_core_component<WinServer::Connection>();
WinServer::InitManager::load_core_component<WinServer::CursorManager>();
WinServer::InitManager::load_core_component<WinServer::ResourceManager, 4>();
WinServer::InitManager::load_core_component<WinServer::Popup>();
WinServer::InitManager::load_core_component<WinServer::MenuBar>();
#ifdef TARGET_MOBILE
WinServer::InitManager::load_core_component<WinServer::ControlBar>();
#endif
WinServer::InitManager::load_core_component<WinServer::Compositor>();
WinServer::InitManager::load_core_component<WinServer::WindowManager>();
WinServer::InitManager::load_core_component<WinServer::Devices>();
WinServer::InitManager::add_widget<WinServer::Clock>();
WinServer::InitManager::launch_app(LAUNCH_PATH, 10);
WinServer::LoadingScreen::destroy_the();
return event_loop->run();
}