mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-10 13:00:29 +03:00
WindowServer: Convert entire API to be message-based.
One big step towards userspace WindowServer. :^)
This commit is contained in:
parent
ef4e9860fd
commit
f529b845ec
Notes:
sideshowbarker
2024-07-19 15:45:25 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/f529b845ecd
@ -7,7 +7,6 @@
|
||||
#include <assert.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <LibC/gui.h>
|
||||
#include "Terminal.h"
|
||||
#include <Kernel/KeyCode.h>
|
||||
#include <LibGUI/GApplication.h>
|
||||
|
@ -76,11 +76,21 @@ struct GUI_ServerMessage {
|
||||
DidSetApplicationMenubar,
|
||||
DidAddMenuItem,
|
||||
DidAddMenuSeparator,
|
||||
DidCreateWindow,
|
||||
DidDestroyWindow,
|
||||
DidGetWindowTitle,
|
||||
DidGetWindowRect,
|
||||
DidGetWindowBackingStore,
|
||||
};
|
||||
Type type { Invalid };
|
||||
int window_id { -1 };
|
||||
size_t text_length;
|
||||
char text[256];
|
||||
|
||||
union {
|
||||
struct {
|
||||
GUI_Rect rect;
|
||||
} window;
|
||||
struct {
|
||||
GUI_Rect rect;
|
||||
} paint;
|
||||
@ -102,6 +112,13 @@ struct GUI_ServerMessage {
|
||||
int menu_id;
|
||||
unsigned identifier;
|
||||
} menu;
|
||||
struct {
|
||||
void* backing_store_id;
|
||||
GUI_Size size;
|
||||
size_t bpp;
|
||||
size_t pitch;
|
||||
RGBA32* pixels;
|
||||
} backing;
|
||||
};
|
||||
};
|
||||
|
||||
@ -116,18 +133,36 @@ struct GUI_ClientMessage {
|
||||
SetApplicationMenubar,
|
||||
AddMenuItem,
|
||||
AddMenuSeparator,
|
||||
CreateWindow,
|
||||
DestroyWindow,
|
||||
SetWindowTitle,
|
||||
GetWindowTitle,
|
||||
SetWindowRect,
|
||||
GetWindowRect,
|
||||
InvalidateRect,
|
||||
DidFinishPainting,
|
||||
GetWindowBackingStore,
|
||||
ReleaseWindowBackingStore,
|
||||
SetGlobalCursorTracking,
|
||||
};
|
||||
Type type { Invalid };
|
||||
int window_id { -1 };
|
||||
size_t text_length;
|
||||
char text[256];
|
||||
int value { 0 };
|
||||
|
||||
union {
|
||||
struct {
|
||||
int menubar_id;
|
||||
int menu_id;
|
||||
unsigned identifier;
|
||||
unsigned text_length;
|
||||
char text[256];
|
||||
} menu;
|
||||
struct {
|
||||
GUI_Rect rect;
|
||||
} window;
|
||||
struct {
|
||||
void* backing_store_id;
|
||||
} backing;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -2133,7 +2133,6 @@ void Process::finalize()
|
||||
{
|
||||
ASSERT(current == g_finalizer);
|
||||
|
||||
destroy_all_menus();
|
||||
destroy_all_windows();
|
||||
m_fds.clear();
|
||||
m_tty = nullptr;
|
||||
|
@ -219,24 +219,10 @@ public:
|
||||
int sys$read_tsc(dword* lsw, dword* msw);
|
||||
int sys$chmod(const char* pathname, mode_t);
|
||||
|
||||
int gui$create_window(const GUI_WindowParameters*);
|
||||
int gui$destroy_window(int window_id);
|
||||
int gui$get_window_backing_store(int window_id, GUI_WindowBackingStoreInfo*);
|
||||
int gui$release_window_backing_store(void* backing_store_id);
|
||||
int gui$invalidate_window(int window_id, const GUI_Rect*);
|
||||
int gui$notify_paint_finished(int window_id, const GUI_Rect*);
|
||||
int gui$get_window_title(int window_id, char* buffer, size_t size);
|
||||
int gui$set_window_title(int window_id, const char* title, size_t size);
|
||||
int gui$get_window_rect(int window_id, GUI_Rect*);
|
||||
int gui$set_window_rect(int window_id, const GUI_Rect*);
|
||||
int gui$set_global_cursor_tracking_enabled(int window_id, bool enabled);
|
||||
|
||||
DisplayInfo set_video_resolution(int width, int height);
|
||||
|
||||
static void initialize();
|
||||
static void initialize_gui_statics();
|
||||
int make_window_id();
|
||||
void destroy_all_menus();
|
||||
void destroy_all_windows();
|
||||
|
||||
void crash() NORETURN;
|
||||
@ -408,12 +394,8 @@ private:
|
||||
|
||||
RetainPtr<Region> m_display_framebuffer_region;
|
||||
|
||||
HashMap<int, OwnPtr<WSWindow>> m_windows;
|
||||
Vector<RetainPtr<GraphicsBitmap>> m_retained_backing_stores;
|
||||
|
||||
Vector<GUI_ServerMessage> m_gui_events;
|
||||
Lock m_gui_events_lock;
|
||||
int m_next_window_id { 1 };
|
||||
|
||||
dword m_wakeup_requested { false };
|
||||
bool m_has_used_fpu { false };
|
||||
|
@ -16,262 +16,11 @@ void Process::initialize_gui_statics()
|
||||
new WSMessageLoop;
|
||||
}
|
||||
|
||||
int Process::make_window_id()
|
||||
{
|
||||
int new_id = m_next_window_id++;
|
||||
while (!new_id || m_windows.contains(new_id)) {
|
||||
new_id = m_next_window_id++;
|
||||
if (new_id < 0)
|
||||
new_id = 1;
|
||||
}
|
||||
return new_id;
|
||||
}
|
||||
|
||||
static void wait_for_gui_server()
|
||||
{
|
||||
// FIXME: Time out after a while and return an error.
|
||||
while (!WSMessageLoop::the().running())
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
int Process::gui$create_window(const GUI_WindowParameters* user_params)
|
||||
{
|
||||
wait_for_gui_server();
|
||||
|
||||
if (!validate_read_typed(user_params))
|
||||
return -EFAULT;
|
||||
|
||||
auto params = *user_params;
|
||||
Rect rect = params.rect;
|
||||
|
||||
if (rect.is_empty())
|
||||
return -EINVAL;
|
||||
|
||||
ProcessPagingScope scope(WSMessageLoop::the().server_process());
|
||||
|
||||
int window_id = make_window_id();
|
||||
if (!window_id)
|
||||
return -ENOMEM;
|
||||
|
||||
auto window = make<WSWindow>(*this, window_id);
|
||||
if (!window)
|
||||
return -ENOMEM;
|
||||
|
||||
window->set_title(params.title);
|
||||
window->set_rect(rect);
|
||||
|
||||
m_windows.set(window_id, move(window));
|
||||
#ifdef LOG_GUI_SYSCALLS
|
||||
dbgprintf("%s<%u> gui$create_window: %d with rect {%d,%d %dx%d}\n", name().characters(), pid(), window_id, rect.x(), rect.y(), rect.width(), rect.height());
|
||||
#endif
|
||||
return window_id;
|
||||
}
|
||||
|
||||
int Process::gui$destroy_window(int window_id)
|
||||
{
|
||||
#ifdef LOG_GUI_SYSCALLS
|
||||
dbgprintf("%s<%u> gui$destroy_window (window_id=%d)\n", name().characters(), pid(), window_id);
|
||||
#endif
|
||||
if (window_id < 0)
|
||||
return -EINVAL;
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end())
|
||||
return -EBADWINDOW;
|
||||
auto message = make<WSMessage>(WSMessage::WM_DestroyWindow);
|
||||
WSMessageLoop::the().post_message((*it).value.leak_ptr(), move(message));
|
||||
m_windows.remove(window_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::gui$get_window_backing_store(int window_id, GUI_WindowBackingStoreInfo* info)
|
||||
{
|
||||
#ifdef LOG_GUI_SYSCALLS
|
||||
dbgprintf("%s<%u> gui$get_window_backing_store (window_id=%d, info=%p)\n", name().characters(), pid(), window_id, info);
|
||||
#endif
|
||||
if (!validate_write_typed(info))
|
||||
return -EFAULT;
|
||||
if (window_id < 0)
|
||||
return -EINVAL;
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end())
|
||||
return -EBADWINDOW;
|
||||
auto& window = *(*it).value;
|
||||
WSWindowLocker locker(window);
|
||||
auto* backing_store = window.backing();
|
||||
#ifdef BACKING_STORE_DEBUG
|
||||
dbgprintf("%s<%u> +++ %p[%d] (%dx%d)\n", name().characters(), pid(), backing_store, backing_store->width(), backing_store->height());
|
||||
#endif
|
||||
m_retained_backing_stores.append(backing_store);
|
||||
info->backing_store_id = backing_store;
|
||||
info->bpp = sizeof(RGBA32);
|
||||
info->pitch = backing_store->pitch();
|
||||
info->size = backing_store->size();
|
||||
info->pixels = reinterpret_cast<RGBA32*>(backing_store->client_region()->laddr().as_ptr());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::gui$release_window_backing_store(void* backing_store_id)
|
||||
{
|
||||
for (size_t i = 0; i < m_retained_backing_stores.size(); ++i) {
|
||||
if (m_retained_backing_stores[i].ptr() == backing_store_id) {
|
||||
#ifdef BACKING_STORE_DEBUG
|
||||
auto* backing_store = m_retained_backing_stores[i].ptr();
|
||||
dbgprintf("%s<%u> --- %p (%dx%d)\n", name().characters(), pid(), backing_store, backing_store->width(), backing_store->height());
|
||||
#endif
|
||||
m_retained_backing_stores.remove(i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EBADBACKING;
|
||||
}
|
||||
|
||||
int Process::gui$invalidate_window(int window_id, const GUI_Rect* a_rect)
|
||||
{
|
||||
if (window_id < 0)
|
||||
return -EINVAL;
|
||||
if (a_rect && !validate_read_typed(a_rect))
|
||||
return -EFAULT;
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end())
|
||||
return -EBADWINDOW;
|
||||
#ifdef LOG_GUI_SYSCALLS
|
||||
if (!a_rect)
|
||||
dbgprintf("%s<%u> gui$invalidate_window (window_id=%d, rect=(entire))\n", name().characters(), pid(), window_id);
|
||||
else
|
||||
dbgprintf("%s<%u> gui$invalidate_window (window_id=%d, rect={%d,%d %dx%d})\n", name().characters(), pid(), window_id, a_rect->location.x, a_rect->location.y, a_rect->size.width, a_rect->size.height);
|
||||
#endif
|
||||
auto& window = *(*it).value;
|
||||
Rect rect;
|
||||
if (a_rect)
|
||||
rect = *a_rect;
|
||||
WSMessageLoop::the().post_message(&window, make<WSClientWantsToPaintMessage>(rect));
|
||||
WSMessageLoop::the().server_process().request_wakeup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::gui$notify_paint_finished(int window_id, const GUI_Rect* a_rect)
|
||||
{
|
||||
if (window_id < 0)
|
||||
return -EINVAL;
|
||||
if (a_rect && !validate_read_typed(a_rect))
|
||||
return -EFAULT;
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end())
|
||||
return -EBADWINDOW;
|
||||
#ifdef LOG_GUI_SYSCALLS
|
||||
if (!a_rect)
|
||||
dbgprintf("%s<%u> gui$notify_paint_finished (window_id=%d, rect=(entire))\n", name().characters(), pid(), window_id);
|
||||
else
|
||||
dbgprintf("%s<%u> gui$notify_paint_finished (window_id=%d, rect={%d,%d %dx%d})\n", name().characters(), pid(), window_id, a_rect->location.x, a_rect->location.y, a_rect->size.width, a_rect->size.height);
|
||||
#endif
|
||||
auto& window = *(*it).value;
|
||||
Rect rect;
|
||||
if (a_rect)
|
||||
rect = *a_rect;
|
||||
WSMessageLoop::the().post_message(&window, make<WSClientFinishedPaintMessage>(rect));
|
||||
WSMessageLoop::the().server_process().request_wakeup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::gui$get_window_title(int window_id, char* buffer, size_t size)
|
||||
{
|
||||
if (window_id < 0)
|
||||
return -EINVAL;
|
||||
if (!validate_write(buffer, size))
|
||||
return -EFAULT;
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end())
|
||||
return -EBADWINDOW;
|
||||
auto& window = *(*it).value;
|
||||
String title;
|
||||
{
|
||||
WSWindowLocker locker(window);
|
||||
title = window.title();
|
||||
}
|
||||
if (title.length() > size)
|
||||
return -ERANGE;
|
||||
memcpy(buffer, title.characters(), title.length());
|
||||
return title.length();
|
||||
|
||||
}
|
||||
|
||||
int Process::gui$set_window_title(int window_id, const char* title, size_t size)
|
||||
{
|
||||
if (window_id < 0)
|
||||
return -EINVAL;
|
||||
if (!validate_read(title, size))
|
||||
return -EFAULT;
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end())
|
||||
return -EBADWINDOW;
|
||||
auto& window = *(*it).value;
|
||||
String new_title(title, size);
|
||||
WSMessageLoop::the().post_message(&window, make<WSSetWindowTitleMessage>(move(new_title)));
|
||||
WSMessageLoop::the().server_process().request_wakeup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::gui$get_window_rect(int window_id, GUI_Rect* rect)
|
||||
{
|
||||
if (window_id < 0)
|
||||
return -EINVAL;
|
||||
if (!validate_write_typed(rect))
|
||||
return -EFAULT;
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end())
|
||||
return -EBADWINDOW;
|
||||
auto& window = *(*it).value;
|
||||
{
|
||||
WSWindowLocker locker(window);
|
||||
*rect = window.rect();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::gui$set_window_rect(int window_id, const GUI_Rect* rect)
|
||||
{
|
||||
if (window_id < 0)
|
||||
return -EINVAL;
|
||||
if (!validate_read_typed(rect))
|
||||
return -EFAULT;
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end())
|
||||
return -EBADWINDOW;
|
||||
auto& window = *(*it).value;
|
||||
Rect new_rect = *rect;
|
||||
WSMessageLoop::the().post_message(&window, make<WSSetWindowRectMessage>(new_rect));
|
||||
WSMessageLoop::the().server_process().request_wakeup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::gui$set_global_cursor_tracking_enabled(int window_id, bool enabled)
|
||||
{
|
||||
if (window_id < 0)
|
||||
return -EINVAL;
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end())
|
||||
return -EBADWINDOW;
|
||||
auto& window = *(*it).value;
|
||||
WSWindowLocker locker(window);
|
||||
window.set_global_cursor_tracking_enabled(enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Process::destroy_all_menus()
|
||||
void Process::destroy_all_windows()
|
||||
{
|
||||
if (!WSMessageLoop::the().running())
|
||||
return;
|
||||
WSWindowManager::the().destroy_all_menus(*this);
|
||||
}
|
||||
|
||||
void Process::destroy_all_windows()
|
||||
{
|
||||
for (auto& it : m_windows) {
|
||||
auto message = make<WSMessage>(WSMessage::WM_DestroyWindow);
|
||||
it.value->notify_process_died(Badge<Process>());
|
||||
WSMessageLoop::the().post_message(it.value.leak_ptr(), move(message));
|
||||
}
|
||||
m_windows.clear();
|
||||
WSMessageLoop::the().notify_client_died(gui_client_id());
|
||||
}
|
||||
|
||||
DisplayInfo Process::set_video_resolution(int width, int height)
|
||||
|
@ -195,30 +195,8 @@ static dword handle(RegisterDump& regs, dword function, dword arg1, dword arg2,
|
||||
return sync();
|
||||
case Syscall::SC_unlink:
|
||||
return current->sys$unlink((const char*)arg1);
|
||||
case Syscall::SC_gui_create_window:
|
||||
return current->gui$create_window((const GUI_WindowParameters*)arg1);
|
||||
case Syscall::SC_gui_destroy_window:
|
||||
return current->gui$destroy_window((int)arg1);
|
||||
case Syscall::SC_gui_get_window_backing_store:
|
||||
return current->gui$get_window_backing_store((int)arg1, (GUI_WindowBackingStoreInfo*)arg2);
|
||||
case Syscall::SC_gui_release_window_backing_store:
|
||||
return current->gui$release_window_backing_store((void*)arg1);
|
||||
case Syscall::SC_gui_invalidate_window:
|
||||
return current->gui$invalidate_window((int)arg1, (const GUI_Rect*)arg2);
|
||||
case Syscall::SC_gui_set_window_title:
|
||||
return current->gui$set_window_title((int)arg1, (const char*)arg2, (size_t)arg3);
|
||||
case Syscall::SC_gui_get_window_title:
|
||||
return current->gui$get_window_title((int)arg1, (char*)arg2, (size_t)arg3);
|
||||
case Syscall::SC_gui_set_window_rect:
|
||||
return current->gui$set_window_rect((int)arg1, (const GUI_Rect*)arg2);
|
||||
case Syscall::SC_gui_get_window_rect:
|
||||
return current->gui$get_window_rect((int)arg1, (GUI_Rect*)arg2);
|
||||
case Syscall::SC_read_tsc:
|
||||
return current->sys$read_tsc((dword*)arg1, (dword*)arg2);
|
||||
case Syscall::SC_gui_notify_paint_finished:
|
||||
return current->gui$notify_paint_finished((int)arg1, (const GUI_Rect*)arg2);
|
||||
case Syscall::SC_gui_set_global_cursor_tracking_enabled:
|
||||
return current->gui$set_global_cursor_tracking_enabled((int)arg1, (bool)arg2);
|
||||
case Syscall::SC_rmdir:
|
||||
return current->sys$rmdir((const char*)arg1);
|
||||
case Syscall::SC_chmod:
|
||||
|
@ -71,17 +71,6 @@
|
||||
__ENUMERATE_SYSCALL(unlink) \
|
||||
__ENUMERATE_SYSCALL(poll) \
|
||||
__ENUMERATE_SYSCALL(read_tsc) \
|
||||
__ENUMERATE_SYSCALL(gui_create_window) \
|
||||
__ENUMERATE_SYSCALL(gui_destroy_window) \
|
||||
__ENUMERATE_SYSCALL(gui_get_window_backing_store) \
|
||||
__ENUMERATE_SYSCALL(gui_release_window_backing_store) \
|
||||
__ENUMERATE_SYSCALL(gui_invalidate_window) \
|
||||
__ENUMERATE_SYSCALL(gui_get_window_title) \
|
||||
__ENUMERATE_SYSCALL(gui_set_window_title) \
|
||||
__ENUMERATE_SYSCALL(gui_get_window_rect) \
|
||||
__ENUMERATE_SYSCALL(gui_set_window_rect) \
|
||||
__ENUMERATE_SYSCALL(gui_notify_paint_finished) \
|
||||
__ENUMERATE_SYSCALL(gui_set_global_cursor_tracking_enabled) \
|
||||
__ENUMERATE_SYSCALL(rmdir) \
|
||||
__ENUMERATE_SYSCALL(chmod) \
|
||||
__ENUMERATE_SYSCALL(usleep) \
|
||||
|
@ -57,7 +57,6 @@ cp -v ../Userland/more mnt/bin/more
|
||||
cp -v ../Userland/rm mnt/bin/rm
|
||||
cp -v ../Userland/rmdir mnt/bin/rmdir
|
||||
cp -v ../Userland/cp mnt/bin/cp
|
||||
cp -v ../Userland/guitest mnt/bin/guitest
|
||||
cp -v ../Userland/guitest2 mnt/bin/guitest2
|
||||
cp -v ../Userland/sysctl mnt/bin/sysctl
|
||||
cp -v ../Userland/pape mnt/bin/pape
|
||||
|
@ -41,7 +41,6 @@ LIBC_OBJS = \
|
||||
ioctl.o \
|
||||
math.o \
|
||||
utime.o \
|
||||
gui.o \
|
||||
sys/select.o \
|
||||
poll.o \
|
||||
locale.o \
|
||||
|
70
LibC/gui.cpp
70
LibC/gui.cpp
@ -1,70 +0,0 @@
|
||||
#include "gui.h"
|
||||
#include <Kernel/GUITypes.h>
|
||||
#include <Kernel/Syscall.h>
|
||||
#include <errno.h>
|
||||
|
||||
int gui_create_window(const GUI_WindowParameters* params)
|
||||
{
|
||||
int rc = syscall(SC_gui_create_window, params);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int gui_destroy_window(int window_id)
|
||||
{
|
||||
int rc = syscall(SC_gui_destroy_window, window_id);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int gui_invalidate_window(int window_id, const GUI_Rect* rect)
|
||||
{
|
||||
int rc = syscall(SC_gui_invalidate_window, window_id, rect);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int gui_get_window_backing_store(int window_id, GUI_WindowBackingStoreInfo* info)
|
||||
{
|
||||
int rc = syscall(SC_gui_get_window_backing_store, window_id, info);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int gui_release_window_backing_store(void* backing_store_id)
|
||||
{
|
||||
int rc = syscall(SC_gui_release_window_backing_store, backing_store_id);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int gui_get_window_title(int window_id, char* buffer, size_t size)
|
||||
{
|
||||
int rc = syscall(SC_gui_get_window_title, window_id, buffer, size);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int gui_set_window_title(int window_id, const char* title, size_t length)
|
||||
{
|
||||
int rc = syscall(SC_gui_set_window_title, window_id, title, length);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int gui_get_window_rect(int window_id, GUI_Rect* rect)
|
||||
{
|
||||
int rc = syscall(SC_gui_get_window_rect, window_id, rect);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int gui_set_window_rect(int window_id, const GUI_Rect* rect)
|
||||
{
|
||||
int rc = syscall(SC_gui_set_window_rect, window_id, rect);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int gui_notify_paint_finished(int window_id, const GUI_Rect* rect)
|
||||
{
|
||||
int rc = syscall(SC_gui_notify_paint_finished, window_id, rect);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
||||
|
||||
int gui_set_global_cursor_tracking_enabled(int window_id, bool enabled)
|
||||
{
|
||||
int rc = syscall(SC_gui_set_global_cursor_tracking_enabled, window_id, enabled);
|
||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||
}
|
21
LibC/gui.h
21
LibC/gui.h
@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <Kernel/GUITypes.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
int gui_create_window(const GUI_WindowParameters*);
|
||||
int gui_destroy_window(int window_id);
|
||||
int gui_invalidate_window(int window_id, const GUI_Rect*);
|
||||
int gui_notify_paint_finished(int window_id, const GUI_Rect*);
|
||||
int gui_get_window_backing_store(int window_id, GUI_WindowBackingStoreInfo*);
|
||||
int gui_release_window_backing_store(void* backing_store_id);
|
||||
int gui_get_window_title(int window_id, char*, size_t);
|
||||
int gui_set_window_title(int window_id, const char*, size_t);
|
||||
int gui_get_window_rect(int window_id, GUI_Rect*);
|
||||
int gui_set_window_rect(int window_id, const GUI_Rect*);
|
||||
int gui_set_global_cursor_tracking_enabled(int window_id, bool);
|
||||
|
||||
__END_DECLS
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <LibC/string.h>
|
||||
#include <LibC/time.h>
|
||||
#include <LibC/sys/select.h>
|
||||
#include <LibC/gui.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
#include <LibGUI/GAction.h>
|
||||
#include <LibGUI/GMenu.h>
|
||||
#include <LibGUI/GEventLoop.h>
|
||||
#include <LibC/gui.h>
|
||||
#include <AK/HashMap.h>
|
||||
|
||||
static HashMap<int, GMenu*>& all_menus()
|
||||
@ -44,9 +43,9 @@ int GMenu::realize_menu()
|
||||
{
|
||||
GUI_ClientMessage request;
|
||||
request.type = GUI_ClientMessage::Type::CreateMenu;
|
||||
ASSERT(m_name.length() < sizeof(request.menu.text));
|
||||
strcpy(request.menu.text, m_name.characters());
|
||||
request.menu.text_length = m_name.length();
|
||||
ASSERT(m_name.length() < sizeof(request.text));
|
||||
strcpy(request.text, m_name.characters());
|
||||
request.text_length = m_name.length();
|
||||
auto response = GEventLoop::main().sync_request(request, GUI_ServerMessage::Type::DidCreateMenu);
|
||||
m_menu_id = response.menu.menu_id;
|
||||
|
||||
@ -66,9 +65,9 @@ int GMenu::realize_menu()
|
||||
request.type = GUI_ClientMessage::Type::AddMenuItem;
|
||||
request.menu.menu_id = m_menu_id;
|
||||
request.menu.identifier = i;
|
||||
ASSERT(action.text().length() < sizeof(request.menu.text));
|
||||
strcpy(request.menu.text, action.text().characters());
|
||||
request.menu.text_length = action.text().length();
|
||||
ASSERT(action.text().length() < sizeof(request.text));
|
||||
strcpy(request.text, action.text().characters());
|
||||
request.text_length = action.text().length();
|
||||
GEventLoop::main().sync_request(request, GUI_ServerMessage::Type::DidAddMenuItem);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include <LibGUI/GMenuBar.h>
|
||||
#include <LibGUI/GEventLoop.h>
|
||||
#include <LibC/gui.h>
|
||||
|
||||
GMenuBar::GMenuBar()
|
||||
{
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include "GEventLoop.h"
|
||||
#include "GWidget.h"
|
||||
#include <SharedGraphics/GraphicsBitmap.h>
|
||||
#include <LibC/gui.h>
|
||||
#include <LibC/stdio.h>
|
||||
#include <LibC/stdlib.h>
|
||||
#include <LibC/unistd.h>
|
||||
@ -56,15 +55,15 @@ void GWindow::show()
|
||||
if (m_window_id)
|
||||
return;
|
||||
|
||||
GUI_WindowParameters wparams;
|
||||
wparams.rect = m_rect_when_windowless;
|
||||
wparams.background_color = 0xffc0c0;
|
||||
strcpy(wparams.title, m_title_when_windowless.characters());
|
||||
m_window_id = gui_create_window(&wparams);
|
||||
if (m_window_id < 0) {
|
||||
perror("gui_create_window");
|
||||
exit(1);
|
||||
}
|
||||
GUI_ClientMessage request;
|
||||
request.type = GUI_ClientMessage::Type::CreateWindow;
|
||||
request.window_id = m_window_id;
|
||||
request.window.rect = m_rect_when_windowless;
|
||||
ASSERT(m_title_when_windowless.length() < sizeof(request.text));
|
||||
strcpy(request.text, m_title_when_windowless.characters());
|
||||
request.text_length = m_title_when_windowless.length();
|
||||
auto response = GEventLoop::main().sync_request(request, GUI_ServerMessage::Type::DidCreateWindow);
|
||||
m_window_id = response.window_id;
|
||||
|
||||
windows().set(m_window_id, this);
|
||||
update();
|
||||
@ -75,55 +74,68 @@ void GWindow::hide()
|
||||
if (!m_window_id)
|
||||
return;
|
||||
windows().remove(m_window_id);
|
||||
int rc = gui_destroy_window(m_window_id);
|
||||
if (rc < 0) {
|
||||
perror("gui_destroy_window");
|
||||
exit(1);
|
||||
}
|
||||
GUI_ClientMessage request;
|
||||
request.type = GUI_ClientMessage::Type::DestroyWindow;
|
||||
request.window_id = m_window_id;
|
||||
ASSERT(m_title_when_windowless.length() < sizeof(request.text));
|
||||
strcpy(request.text, m_title_when_windowless.characters());
|
||||
request.text_length = m_title_when_windowless.length();
|
||||
GEventLoop::main().post_message_to_server(request);
|
||||
}
|
||||
|
||||
void GWindow::set_title(String&& title)
|
||||
{
|
||||
m_title_when_windowless = title;
|
||||
if (m_window_id) {
|
||||
int rc = gui_set_window_title(m_window_id, title.characters(), title.length());
|
||||
if (rc < 0) {
|
||||
perror("gui_set_window_title");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
m_title_when_windowless = move(title);
|
||||
if (!m_window_id)
|
||||
return;
|
||||
|
||||
GUI_ClientMessage request;
|
||||
request.type = GUI_ClientMessage::Type::SetWindowTitle;
|
||||
request.window_id = m_window_id;
|
||||
ASSERT(m_title_when_windowless.length() < sizeof(request.text));
|
||||
strcpy(request.text, m_title_when_windowless.characters());
|
||||
request.text_length = m_title_when_windowless.length();
|
||||
GEventLoop::main().post_message_to_server(request);
|
||||
}
|
||||
|
||||
String GWindow::title() const
|
||||
{
|
||||
if (m_window_id) {
|
||||
char buffer[256];
|
||||
int rc = gui_get_window_title(m_window_id, buffer, sizeof(buffer));
|
||||
ASSERT(rc >= 0);
|
||||
return String(buffer, rc);
|
||||
}
|
||||
return m_title_when_windowless;
|
||||
if (!m_window_id)
|
||||
return m_title_when_windowless;
|
||||
|
||||
GUI_ClientMessage request;
|
||||
request.type = GUI_ClientMessage::Type::GetWindowTitle;
|
||||
request.window_id = m_window_id;
|
||||
ASSERT(m_title_when_windowless.length() < sizeof(request.text));
|
||||
strcpy(request.text, m_title_when_windowless.characters());
|
||||
request.text_length = m_title_when_windowless.length();
|
||||
auto response = GEventLoop::main().sync_request(request, GUI_ServerMessage::Type::DidGetWindowTitle);
|
||||
return String(response.text, response.text_length);
|
||||
}
|
||||
|
||||
Rect GWindow::rect() const
|
||||
{
|
||||
if (m_window_id) {
|
||||
GUI_Rect buffer;
|
||||
int rc = gui_get_window_rect(m_window_id, &buffer);
|
||||
ASSERT(rc >= 0);
|
||||
return buffer;
|
||||
}
|
||||
return m_rect_when_windowless;
|
||||
if (!m_window_id)
|
||||
return m_rect_when_windowless;
|
||||
|
||||
GUI_ClientMessage request;
|
||||
request.type = GUI_ClientMessage::Type::GetWindowRect;
|
||||
request.window_id = m_window_id;
|
||||
auto response = GEventLoop::main().sync_request(request, GUI_ServerMessage::Type::DidGetWindowRect);
|
||||
ASSERT(response.window_id == m_window_id);
|
||||
return response.window.rect;
|
||||
}
|
||||
|
||||
void GWindow::set_rect(const Rect& a_rect)
|
||||
{
|
||||
m_rect_when_windowless = a_rect;
|
||||
if (m_window_id) {
|
||||
GUI_Rect rect = a_rect;
|
||||
int rc = gui_set_window_rect(m_window_id, &rect);
|
||||
ASSERT(rc == 0);
|
||||
}
|
||||
if (!m_window_id)
|
||||
return;
|
||||
GUI_ClientMessage request;
|
||||
request.type = GUI_ClientMessage::Type::SetWindowRect;
|
||||
request.window_id = m_window_id;
|
||||
request.window.rect = a_rect;
|
||||
GEventLoop::main().post_message_to_server(request);
|
||||
}
|
||||
|
||||
void GWindow::event(GEvent& event)
|
||||
@ -158,9 +170,11 @@ void GWindow::event(GEvent& event)
|
||||
rect = m_main_widget->rect();
|
||||
m_main_widget->event(*make<GPaintEvent>(rect));
|
||||
if (m_window_id) {
|
||||
GUI_Rect gui_rect = rect;
|
||||
int rc = gui_notify_paint_finished(m_window_id, &gui_rect);
|
||||
ASSERT(rc == 0);
|
||||
GUI_ClientMessage message;
|
||||
message.type = GUI_ClientMessage::Type::DidFinishPainting;
|
||||
message.window_id = m_window_id;
|
||||
message.window.rect = rect;
|
||||
GEventLoop::main().post_message_to_server(message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -209,9 +223,11 @@ void GWindow::update(const Rect& a_rect)
|
||||
}
|
||||
m_pending_paint_event_rects.append(a_rect);
|
||||
|
||||
GUI_Rect rect = a_rect;
|
||||
int rc = gui_invalidate_window(m_window_id, a_rect.is_null() ? nullptr : &rect);
|
||||
ASSERT(rc == 0);
|
||||
GUI_ClientMessage request;
|
||||
request.type = GUI_ClientMessage::Type::InvalidateRect;
|
||||
request.window_id = m_window_id;
|
||||
request.window.rect = a_rect;
|
||||
GEventLoop::main().post_message_to_server(request);
|
||||
}
|
||||
|
||||
void GWindow::set_main_widget(GWidget* widget)
|
||||
@ -255,5 +271,12 @@ void GWindow::set_global_cursor_tracking_widget(GWidget* widget)
|
||||
if (widget == m_global_cursor_tracking_widget.ptr())
|
||||
return;
|
||||
m_global_cursor_tracking_widget = widget ? widget->make_weak_ptr() : nullptr;
|
||||
gui_set_global_cursor_tracking_enabled(m_window_id, widget != nullptr);
|
||||
|
||||
GUI_ClientMessage request;
|
||||
request.type = GUI_ClientMessage::Type::SetGlobalCursorTracking;
|
||||
request.window_id = m_window_id;
|
||||
request.value = widget != nullptr;
|
||||
// FIXME: What if the cursor moves out of our interest range before the server can handle this?
|
||||
// Maybe there could be a response that includes the current cursor location as of enabling.
|
||||
GEventLoop::main().post_message_to_server(request);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
#ifdef USERLAND
|
||||
#include <LibGUI/GWidget.h>
|
||||
#include <LibGUI/GWindow.h>
|
||||
#include <LibC/gui.h>
|
||||
#include <LibGUI/GEventLoop.h>
|
||||
#include <LibC/stdio.h>
|
||||
#include <LibC/errno.h>
|
||||
#include <LibC/string.h>
|
||||
@ -26,15 +26,13 @@ Painter::Painter(GraphicsBitmap& bitmap)
|
||||
Painter::Painter(GWidget& widget)
|
||||
: m_font(&widget.font())
|
||||
{
|
||||
GUI_WindowBackingStoreInfo backing;
|
||||
int rc = gui_get_window_backing_store(widget.window()->window_id(), &backing);
|
||||
if (rc < 0) {
|
||||
perror("gui_get_window_backing_store");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
m_backing_store_id = backing.backing_store_id;
|
||||
GUI_ClientMessage request;
|
||||
request.type = GUI_ClientMessage::Type::GetWindowBackingStore;
|
||||
request.window_id = widget.window()->window_id();
|
||||
auto response = GEventLoop::main().sync_request(request, GUI_ServerMessage::DidGetWindowBackingStore);
|
||||
m_backing_store_id = response.backing.backing_store_id;
|
||||
|
||||
m_target = GraphicsBitmap::create_wrapper(backing.size, backing.pixels);
|
||||
m_target = GraphicsBitmap::create_wrapper(response.backing.size, response.backing.pixels);
|
||||
ASSERT(m_target);
|
||||
m_window = widget.window();
|
||||
m_translation.move_by(widget.window_relative_rect().location());
|
||||
@ -55,11 +53,10 @@ Painter::~Painter()
|
||||
#ifdef USERLAND
|
||||
m_target = nullptr;
|
||||
if (m_backing_store_id) {
|
||||
int rc = gui_release_window_backing_store(m_backing_store_id);
|
||||
if (rc < 0) {
|
||||
perror("gui_release_window_backing_store");
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
GUI_ClientMessage request;
|
||||
request.type = GUI_ClientMessage::Type::ReleaseWindowBackingStore;
|
||||
request.backing.backing_store_id = m_backing_store_id;
|
||||
GEventLoop::main().post_message_to_server(request);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
1
Userland/.gitignore
vendored
1
Userland/.gitignore
vendored
@ -22,7 +22,6 @@ mkdir
|
||||
touch
|
||||
sync
|
||||
more
|
||||
guitest
|
||||
guitest2
|
||||
sysctl
|
||||
rm
|
||||
|
@ -19,7 +19,6 @@ OBJS = \
|
||||
mkdir.o \
|
||||
touch.o \
|
||||
more.o \
|
||||
guitest.o \
|
||||
guitest2.o \
|
||||
sysctl.o \
|
||||
pape.o \
|
||||
@ -52,7 +51,6 @@ APPS = \
|
||||
touch \
|
||||
sync \
|
||||
more \
|
||||
guitest \
|
||||
guitest2 \
|
||||
sysctl \
|
||||
pape \
|
||||
@ -147,9 +145,6 @@ sync: sync.o
|
||||
more: more.o
|
||||
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
|
||||
|
||||
guitest: guitest.o
|
||||
$(LD) -o $@ $(LDFLAGS) $< ../LibC/LibC.a
|
||||
|
||||
guitest2: guitest2.o
|
||||
$(LD) -o $@ $(LDFLAGS) $< ../LibGUI/LibGUI.a ../LibC/LibC.a
|
||||
|
||||
|
@ -1,94 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <Kernel/Syscall.h>
|
||||
#include <SharedGraphics/GraphicsBitmap.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
#include <LibC/gui.h>
|
||||
|
||||
static void paint(GraphicsBitmap& bitmap, int width, int height);
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
GUI_WindowParameters wparams;
|
||||
wparams.rect = { { 100, 100 }, { 120, 120 } };
|
||||
wparams.background_color = 0xffc0c0;
|
||||
strcpy(wparams.title, "GUI test app");
|
||||
int window_id = gui_create_window(&wparams);
|
||||
if (window_id < 0) {
|
||||
perror("gui_create_window");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd = open("/dev/gui_events", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// NOTE: We never release the backing store. This is just a simple app. :^)
|
||||
GUI_WindowBackingStoreInfo backing;
|
||||
int rc = gui_get_window_backing_store(window_id, &backing);
|
||||
if (rc < 0) {
|
||||
perror("gui_get_window_backing_store");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto bitmap = GraphicsBitmap::create_wrapper(backing.size, backing.pixels);
|
||||
|
||||
dbgprintf("(Client) window backing %ux%u @ %p\n", backing.size.width, backing.size.height, backing.pixels);
|
||||
|
||||
paint(*bitmap, backing.size.width, backing.size.height);
|
||||
|
||||
rc = gui_invalidate_window(window_id, nullptr);
|
||||
if (rc < 0) {
|
||||
perror("gui_invalidate_window");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
GUI_ServerMessage message;
|
||||
ssize_t nread = read(fd, &message, sizeof(message));
|
||||
if (nread < 0) {
|
||||
perror("read");
|
||||
return 1;
|
||||
}
|
||||
dbgprintf("(%d) ", getpid());
|
||||
assert(nread == sizeof(message));
|
||||
switch (message.type) {
|
||||
case GUI_ServerMessage::Type::Paint: dbgprintf("WID=%x Paint [%d,%d %dx%d]\n", message.window_id, message.paint.rect.location.x, message.paint.rect.location.y, message.paint.rect.size.width, message.paint.rect.size.height); break;
|
||||
case GUI_ServerMessage::Type::MouseDown: dbgprintf("WID=%x MouseDown %d,%d\n", message.window_id, message.mouse.position.x, message.mouse.position.y); break;
|
||||
case GUI_ServerMessage::Type::MouseUp: dbgprintf("WID=%x MouseUp %d,%d\n", message.window_id, message.mouse.position.x, message.mouse.position.y); break;
|
||||
case GUI_ServerMessage::Type::MouseMove: dbgprintf("WID=%x MouseMove %d,%d\n", message.window_id, message.mouse.position.x, message.mouse.position.y); break;
|
||||
case GUI_ServerMessage::Type::WindowActivated: dbgprintf("WID=%x WindowActivated\n", message.window_id); break;
|
||||
case GUI_ServerMessage::Type::WindowDeactivated: dbgprintf("WID=%x WindowDeactivated\n", message.window_id); break;
|
||||
case GUI_ServerMessage::Type::WindowCloseRequest: return 0;
|
||||
}
|
||||
|
||||
if (message.type == GUI_ServerMessage::Type::Paint) {
|
||||
paint(*bitmap, backing.size.width, backing.size.height);
|
||||
gui_notify_paint_finished(window_id, nullptr);
|
||||
}
|
||||
|
||||
if (message.type == GUI_ServerMessage::Type::MouseDown) {
|
||||
gui_invalidate_window(window_id, nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void paint(GraphicsBitmap& bitmap, int width, int height)
|
||||
{
|
||||
byte r = rand() % 255;
|
||||
byte g = rand() % 255;
|
||||
byte b = rand() % 255;
|
||||
Color color(r, g, b);
|
||||
Painter painter(bitmap);
|
||||
painter.fill_rect({0, 0, width, height}, color);
|
||||
painter.draw_text({0, 0, width, height}, "Hello World!", TextAlignment::Center, Color::Black);
|
||||
}
|
@ -9,12 +9,8 @@ class WSMessage {
|
||||
public:
|
||||
enum Type {
|
||||
Invalid = 0,
|
||||
WM_ClientWantsToPaint,
|
||||
WM_ClientFinishedPaint,
|
||||
WM_SetWindowTitle,
|
||||
WM_SetWindowRect,
|
||||
WM_DeferredCompose,
|
||||
WM_DestroyWindow,
|
||||
WM_ClientDisconnected,
|
||||
MouseMove,
|
||||
MouseDown,
|
||||
MouseUp,
|
||||
@ -33,6 +29,17 @@ public:
|
||||
APIDestroyMenuRequest,
|
||||
APIAddMenuItemRequest,
|
||||
APIAddMenuSeparatorRequest,
|
||||
APICreateWindowRequest,
|
||||
APIDestroyWindowRequest,
|
||||
APISetWindowTitleRequest,
|
||||
APIGetWindowTitleRequest,
|
||||
APISetWindowRectRequest,
|
||||
APIGetWindowRectRequest,
|
||||
APIInvalidateRectRequest,
|
||||
APIDidFinishPaintingNotification,
|
||||
APIGetWindowBackingStoreRequest,
|
||||
APIReleaseWindowBackingStoreRequest,
|
||||
APISetGlobalCursorTrackingRequest,
|
||||
__End_API_Client_Requests,
|
||||
};
|
||||
|
||||
@ -50,6 +57,20 @@ private:
|
||||
Type m_type { Invalid };
|
||||
};
|
||||
|
||||
class WSClientDisconnectedNotification : public WSMessage {
|
||||
public:
|
||||
explicit WSClientDisconnectedNotification(int client_id)
|
||||
: WSMessage(WM_ClientDisconnected)
|
||||
, m_client_id(client_id)
|
||||
{
|
||||
}
|
||||
|
||||
int client_id() const { return m_client_id; }
|
||||
|
||||
private:
|
||||
int m_client_id { 0 };
|
||||
};
|
||||
|
||||
class WSAPIClientRequest : public WSMessage {
|
||||
public:
|
||||
WSAPIClientRequest(Type type, int client_id)
|
||||
@ -64,6 +85,20 @@ private:
|
||||
int m_client_id { 0 };
|
||||
};
|
||||
|
||||
class WSAPISetGlobalCursorTrackingRequest : public WSAPIClientRequest {
|
||||
public:
|
||||
WSAPISetGlobalCursorTrackingRequest(int client_id, bool value)
|
||||
: WSAPIClientRequest(WSMessage::APISetGlobalCursorTrackingRequest, client_id)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
bool value() const { return m_value; }
|
||||
|
||||
private:
|
||||
bool m_value { false };
|
||||
};
|
||||
|
||||
class WSAPICreateMenubarRequest : public WSAPIClientRequest {
|
||||
public:
|
||||
WSAPICreateMenubarRequest(int client_id)
|
||||
@ -179,58 +214,170 @@ private:
|
||||
int m_menu_id { 0 };
|
||||
};
|
||||
|
||||
class WSClientFinishedPaintMessage final : public WSMessage {
|
||||
class WSAPISetWindowTitleRequest final : public WSAPIClientRequest {
|
||||
public:
|
||||
explicit WSClientFinishedPaintMessage(const Rect& rect = Rect())
|
||||
: WSMessage(WSMessage::WM_ClientFinishedPaint)
|
||||
, m_rect(rect)
|
||||
{
|
||||
}
|
||||
|
||||
const Rect& rect() const { return m_rect; }
|
||||
private:
|
||||
Rect m_rect;
|
||||
};
|
||||
|
||||
class WSSetWindowTitleMessage final : public WSMessage {
|
||||
public:
|
||||
explicit WSSetWindowTitleMessage(String&& title)
|
||||
: WSMessage(WSMessage::WM_SetWindowTitle)
|
||||
explicit WSAPISetWindowTitleRequest(int client_id, int window_id, String&& title)
|
||||
: WSAPIClientRequest(WSMessage::APISetWindowTitleRequest, client_id)
|
||||
, m_client_id(client_id)
|
||||
, m_window_id(window_id)
|
||||
, m_title(move(title))
|
||||
{
|
||||
}
|
||||
|
||||
int client_id() const { return m_client_id; }
|
||||
int window_id() const { return m_window_id; }
|
||||
String title() const { return m_title; }
|
||||
|
||||
private:
|
||||
int m_client_id { 0 };
|
||||
int m_window_id { 0 };
|
||||
String m_title;
|
||||
};
|
||||
|
||||
class WSSetWindowRectMessage final : public WSMessage {
|
||||
class WSAPIGetWindowTitleRequest final : public WSAPIClientRequest {
|
||||
public:
|
||||
explicit WSSetWindowRectMessage(const Rect& rect)
|
||||
: WSMessage(WSMessage::WM_SetWindowRect)
|
||||
explicit WSAPIGetWindowTitleRequest(int client_id, int window_id)
|
||||
: WSAPIClientRequest(WSMessage::APIGetWindowTitleRequest, client_id)
|
||||
, m_client_id(client_id)
|
||||
, m_window_id(window_id)
|
||||
{
|
||||
}
|
||||
|
||||
int client_id() const { return m_client_id; }
|
||||
int window_id() const { return m_window_id; }
|
||||
|
||||
private:
|
||||
int m_client_id { 0 };
|
||||
int m_window_id { 0 };
|
||||
};
|
||||
|
||||
class WSAPISetWindowRectRequest final : public WSAPIClientRequest {
|
||||
public:
|
||||
explicit WSAPISetWindowRectRequest(int client_id, int window_id, const Rect& rect)
|
||||
: WSAPIClientRequest(WSMessage::APISetWindowRectRequest, client_id)
|
||||
, m_client_id(client_id)
|
||||
, m_window_id(window_id)
|
||||
, m_rect(rect)
|
||||
{
|
||||
}
|
||||
|
||||
int client_id() const { return m_client_id; }
|
||||
int window_id() const { return m_window_id; }
|
||||
Rect rect() const { return m_rect; }
|
||||
|
||||
private:
|
||||
int m_client_id { 0 };
|
||||
int m_window_id { 0 };
|
||||
Rect m_rect;
|
||||
};
|
||||
|
||||
class WSAPIGetWindowRectRequest final : public WSAPIClientRequest {
|
||||
public:
|
||||
explicit WSAPIGetWindowRectRequest(int client_id, int window_id)
|
||||
: WSAPIClientRequest(WSMessage::APIGetWindowRectRequest, client_id)
|
||||
, m_client_id(client_id)
|
||||
, m_window_id(window_id)
|
||||
{
|
||||
}
|
||||
|
||||
int client_id() const { return m_client_id; }
|
||||
int window_id() const { return m_window_id; }
|
||||
|
||||
private:
|
||||
int m_client_id { 0 };
|
||||
int m_window_id { 0 };
|
||||
};
|
||||
|
||||
class WSAPICreateWindowRequest : public WSAPIClientRequest {
|
||||
public:
|
||||
WSAPICreateWindowRequest(int client_id, const Rect& rect, const String& title)
|
||||
: WSAPIClientRequest(WSMessage::APICreateWindowRequest, client_id)
|
||||
, m_rect(rect)
|
||||
, m_title(title)
|
||||
{
|
||||
}
|
||||
|
||||
Rect rect() const { return m_rect; }
|
||||
String title() const { return m_title; }
|
||||
|
||||
private:
|
||||
Rect m_rect;
|
||||
String m_title;
|
||||
};
|
||||
|
||||
class WSClientWantsToPaintMessage final : public WSMessage {
|
||||
class WSAPIDestroyWindowRequest : public WSAPIClientRequest {
|
||||
public:
|
||||
explicit WSClientWantsToPaintMessage(const Rect& rect = Rect())
|
||||
: WSMessage(WSMessage::WM_ClientWantsToPaint)
|
||||
WSAPIDestroyWindowRequest(int client_id, int window_id)
|
||||
: WSAPIClientRequest(WSMessage::APIDestroyWindowRequest, client_id)
|
||||
, m_window_id(window_id)
|
||||
{
|
||||
}
|
||||
|
||||
int window_id() const { return m_window_id; }
|
||||
|
||||
private:
|
||||
int m_window_id { 0 };
|
||||
};
|
||||
|
||||
class WSAPIInvalidateRectRequest final : public WSAPIClientRequest {
|
||||
public:
|
||||
explicit WSAPIInvalidateRectRequest(int client_id, int window_id, const Rect& rect)
|
||||
: WSAPIClientRequest(WSMessage::APIInvalidateRectRequest, client_id)
|
||||
, m_window_id(window_id)
|
||||
, m_rect(rect)
|
||||
{
|
||||
}
|
||||
|
||||
const Rect& rect() const { return m_rect; }
|
||||
int window_id() const { return m_window_id; }
|
||||
Rect rect() const { return m_rect; }
|
||||
|
||||
private:
|
||||
friend class WSWindowManager;
|
||||
int m_window_id { 0 };
|
||||
Rect m_rect;
|
||||
};
|
||||
|
||||
class WSAPIGetWindowBackingStoreRequest final : public WSAPIClientRequest {
|
||||
public:
|
||||
explicit WSAPIGetWindowBackingStoreRequest(int client_id, int window_id)
|
||||
: WSAPIClientRequest(WSMessage::APIGetWindowBackingStoreRequest, client_id)
|
||||
, m_window_id(window_id)
|
||||
{
|
||||
}
|
||||
|
||||
int window_id() const { return m_window_id; }
|
||||
|
||||
private:
|
||||
int m_window_id { 0 };
|
||||
};
|
||||
|
||||
class WSAPIReleaseWindowBackingStoreRequest final : public WSAPIClientRequest {
|
||||
public:
|
||||
explicit WSAPIReleaseWindowBackingStoreRequest(int client_id, int backing_store_id)
|
||||
: WSAPIClientRequest(WSMessage::APIReleaseWindowBackingStoreRequest, client_id)
|
||||
, m_backing_store_id(backing_store_id)
|
||||
{
|
||||
}
|
||||
|
||||
int backing_store_id() const { return m_backing_store_id; }
|
||||
|
||||
private:
|
||||
int m_backing_store_id { 0 };
|
||||
};
|
||||
|
||||
class WSAPIDidFinishPaintingNotification final : public WSAPIClientRequest {
|
||||
public:
|
||||
explicit WSAPIDidFinishPaintingNotification(int client_id, int window_id, const Rect& rect)
|
||||
: WSAPIClientRequest(WSMessage::APIDidFinishPaintingNotification, client_id)
|
||||
, m_window_id(window_id)
|
||||
, m_rect(rect)
|
||||
{
|
||||
}
|
||||
|
||||
int window_id() const { return m_window_id; }
|
||||
Rect rect() const { return m_rect; }
|
||||
|
||||
private:
|
||||
int m_window_id { 0 };
|
||||
Rect m_rect;
|
||||
};
|
||||
|
||||
|
@ -89,6 +89,7 @@ void WSMessageLoop::post_message(WSMessageReceiver* receiver, OwnPtr<WSMessage>&
|
||||
dbgprintf("WSMessageLoop::post_message: {%u} << receiver=%p, message=%p (type=%u)\n", m_queued_messages.size(), receiver, message.ptr(), message->type());
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (message->type() == WSMessage::WM_ClientFinishedPaint) {
|
||||
auto& invalidation_message = static_cast<WSClientFinishedPaintMessage&>(*message);
|
||||
for (auto& queued_message : m_queued_messages) {
|
||||
@ -118,6 +119,7 @@ void WSMessageLoop::post_message(WSMessageReceiver* receiver, OwnPtr<WSMessage>&
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_queued_messages.append({ receiver, move(message) });
|
||||
|
||||
@ -262,8 +264,18 @@ void WSMessageLoop::drain_keyboard()
|
||||
}
|
||||
}
|
||||
|
||||
void WSMessageLoop::notify_client_died(int client_id)
|
||||
{
|
||||
LOCKER(m_lock);
|
||||
post_message(&WSWindowManager::the(), make<WSClientDisconnectedNotification>(client_id));
|
||||
}
|
||||
|
||||
ssize_t WSMessageLoop::on_receive_from_client(int client_id, const byte* data, size_t size)
|
||||
{
|
||||
// FIXME: This should not be necessary.. why is this necessary?
|
||||
while (!running())
|
||||
Scheduler::yield();
|
||||
|
||||
LOCKER(m_lock);
|
||||
ASSERT(size == sizeof(GUI_ClientMessage));
|
||||
auto& message = *reinterpret_cast<const GUI_ClientMessage*>(data);
|
||||
@ -281,15 +293,53 @@ ssize_t WSMessageLoop::on_receive_from_client(int client_id, const byte* data, s
|
||||
post_message(&WSWindowManager::the(), make<WSAPIAddMenuToMenubarRequest>(client_id, message.menu.menubar_id, message.menu.menu_id));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::CreateMenu:
|
||||
ASSERT(message.menu.text_length < sizeof(message.menu.text));
|
||||
post_message(&WSWindowManager::the(), make<WSAPICreateMenuRequest>(client_id, String(message.menu.text, message.menu.text_length)));
|
||||
ASSERT(message.text_length < sizeof(message.text));
|
||||
post_message(&WSWindowManager::the(), make<WSAPICreateMenuRequest>(client_id, String(message.text, message.text_length)));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::DestroyMenu:
|
||||
post_message(&WSWindowManager::the(), make<WSAPIDestroyMenuRequest>(client_id, message.menu.menu_id));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::AddMenuItem:
|
||||
ASSERT(message.menu.text_length < sizeof(message.menu.text));
|
||||
post_message(&WSWindowManager::the(), make<WSAPIAddMenuItemRequest>(client_id, message.menu.menu_id, message.menu.identifier, String(message.menu.text, message.menu.text_length)));
|
||||
ASSERT(message.text_length < sizeof(message.text));
|
||||
post_message(&WSWindowManager::the(), make<WSAPIAddMenuItemRequest>(client_id, message.menu.menu_id, message.menu.identifier, String(message.text, message.text_length)));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::CreateWindow:
|
||||
ASSERT(message.text_length < sizeof(message.text));
|
||||
post_message(&WSWindowManager::the(), make<WSAPICreateWindowRequest>(client_id, message.window.rect, String(message.text, message.text_length)));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::DestroyWindow:
|
||||
post_message(&WSWindowManager::the(), make<WSAPIDestroyWindowRequest>(client_id, message.window_id));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::SetWindowTitle:
|
||||
ASSERT(message.text_length < sizeof(message.text));
|
||||
post_message(&WSWindowManager::the(), make<WSAPISetWindowTitleRequest>(client_id, message.window_id, String(message.text, message.text_length)));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::GetWindowTitle:
|
||||
ASSERT(message.text_length < sizeof(message.text));
|
||||
post_message(&WSWindowManager::the(), make<WSAPIGetWindowTitleRequest>(client_id, message.window_id));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::SetWindowRect:
|
||||
post_message(&WSWindowManager::the(), make<WSAPISetWindowRectRequest>(client_id, message.window_id, message.window.rect));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::GetWindowRect:
|
||||
post_message(&WSWindowManager::the(), make<WSAPIGetWindowRectRequest>(client_id, message.window_id));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::InvalidateRect:
|
||||
post_message(&WSWindowManager::the(), make<WSAPIInvalidateRectRequest>(client_id, message.window_id, message.window.rect));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::DidFinishPainting:
|
||||
post_message(&WSWindowManager::the(), make<WSAPIDidFinishPaintingNotification>(client_id, message.window_id, message.window.rect));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::GetWindowBackingStore:
|
||||
post_message(&WSWindowManager::the(), make<WSAPIGetWindowBackingStoreRequest>(client_id, message.window_id));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::ReleaseWindowBackingStore:
|
||||
post_message(&WSWindowManager::the(), make<WSAPIReleaseWindowBackingStoreRequest>(client_id, (int)message.backing.backing_store_id));
|
||||
break;
|
||||
case GUI_ClientMessage::Type::SetGlobalCursorTracking:
|
||||
post_message(&WSWindowManager::the(), make<WSAPISetGlobalCursorTrackingRequest>(client_id, message.value));
|
||||
break;
|
||||
}
|
||||
server_process().request_wakeup();
|
||||
return size;
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ public:
|
||||
ssize_t on_receive_from_client(int client_id, const byte*, size_t);
|
||||
|
||||
static Process* process_from_client_id(int client_id);
|
||||
void notify_client_died(int client_id);
|
||||
|
||||
private:
|
||||
void wait_for_message();
|
||||
|
@ -83,10 +83,6 @@ void WSWindow::on_message(WSMessage& message)
|
||||
gui_event.window_id = window_id();
|
||||
|
||||
switch (message.type()) {
|
||||
case WSMessage::WM_ClientWantsToPaint:
|
||||
gui_event.type = GUI_ServerMessage::Type::Paint;
|
||||
gui_event.paint.rect = static_cast<WSClientWantsToPaintMessage&>(message).rect();
|
||||
break;
|
||||
case WSMessage::MouseMove:
|
||||
gui_event.type = GUI_ServerMessage::Type::MouseMove;
|
||||
gui_event.mouse.position = static_cast<WSMouseEvent&>(message).position();
|
||||
@ -121,18 +117,6 @@ void WSWindow::on_message(WSMessage& message)
|
||||
gui_event.key.ctrl = static_cast<WSKeyEvent&>(message).ctrl();
|
||||
gui_event.key.shift = static_cast<WSKeyEvent&>(message).shift();
|
||||
break;
|
||||
case WSMessage::WM_ClientFinishedPaint:
|
||||
WSWindowManager::the().invalidate(*this, static_cast<WSClientFinishedPaintMessage&>(message).rect());
|
||||
return;
|
||||
case WSMessage::WM_SetWindowRect:
|
||||
set_rect(static_cast<WSSetWindowRectMessage&>(message).rect());
|
||||
return;
|
||||
case WSMessage::WM_SetWindowTitle:
|
||||
set_title(static_cast<WSSetWindowTitleMessage&>(message).title());
|
||||
return;
|
||||
case WSMessage::WM_DestroyWindow:
|
||||
delete this;
|
||||
return;
|
||||
case WSMessage::WindowActivated:
|
||||
gui_event.type = GUI_ServerMessage::Type::WindowActivated;
|
||||
break;
|
||||
|
@ -734,8 +734,26 @@ void WSWindowManager::on_message(WSMessage& message)
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.is_client_request())
|
||||
if (message.is_client_request()) {
|
||||
handle_client_request(static_cast<WSAPIClientRequest&>(message));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type() == WSMessage::WM_ClientDisconnected) {
|
||||
int client_id = static_cast<WSClientDisconnectedNotification&>(message).client_id();
|
||||
dbgprintf("[WM] Client disconnected: %d\n", client_id);
|
||||
|
||||
destroy_all_menus(*WSMessageLoop::process_from_client_id(client_id));
|
||||
Vector<int> windows_belonging_to_client;
|
||||
for (auto& it : m_windows_by_id) {
|
||||
if (it.value->process()->gui_client_id() == client_id)
|
||||
windows_belonging_to_client.append(it.value->window_id());
|
||||
}
|
||||
for (int window_id : windows_belonging_to_client) {
|
||||
m_windows_by_id.remove(window_id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WSWindowManager::handle_client_request(WSAPIClientRequest& request)
|
||||
@ -864,6 +882,132 @@ void WSWindowManager::handle_client_request(WSAPIClientRequest& request)
|
||||
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
|
||||
break;
|
||||
}
|
||||
case WSMessage::APISetWindowTitleRequest: {
|
||||
int window_id = static_cast<WSAPISetWindowTitleRequest&>(request).window_id();
|
||||
auto it = m_windows_by_id.find(window_id);
|
||||
if (it == m_windows_by_id.end()) {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
auto& window = *(*it).value;
|
||||
window.set_title(static_cast<WSAPISetWindowTitleRequest&>(request).title());
|
||||
break;
|
||||
}
|
||||
case WSMessage::APIGetWindowTitleRequest: {
|
||||
int window_id = static_cast<WSAPIGetWindowTitleRequest&>(request).window_id();
|
||||
auto it = m_windows_by_id.find(window_id);
|
||||
if (it == m_windows_by_id.end()) {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
auto& window = *(*it).value;
|
||||
GUI_ServerMessage response;
|
||||
response.type = GUI_ServerMessage::Type::DidGetWindowTitle;
|
||||
response.window_id = window.window_id();
|
||||
ASSERT(window.title().length() < sizeof(response.text));
|
||||
strcpy(response.text, window.title().characters());
|
||||
response.text_length = window.title().length();
|
||||
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
|
||||
break;
|
||||
}
|
||||
case WSMessage::APISetWindowRectRequest: {
|
||||
int window_id = static_cast<WSAPISetWindowRectRequest&>(request).window_id();
|
||||
auto it = m_windows_by_id.find(window_id);
|
||||
if (it == m_windows_by_id.end()) {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
auto& window = *(*it).value;
|
||||
window.set_rect(static_cast<WSAPISetWindowRectRequest&>(request).rect());
|
||||
break;
|
||||
}
|
||||
case WSMessage::APIGetWindowRectRequest: {
|
||||
int window_id = static_cast<WSAPIGetWindowRectRequest&>(request).window_id();
|
||||
auto it = m_windows_by_id.find(window_id);
|
||||
if (it == m_windows_by_id.end()) {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
auto& window = *(*it).value;
|
||||
GUI_ServerMessage response;
|
||||
response.type = GUI_ServerMessage::Type::DidGetWindowRect;
|
||||
response.window_id = window.window_id();
|
||||
response.window.rect = window.rect();
|
||||
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
|
||||
break;
|
||||
}
|
||||
case WSMessage::APICreateWindowRequest: {
|
||||
int window_id = m_next_window_id++;
|
||||
auto window = make<WSWindow>(*WSMessageLoop::process_from_client_id(request.client_id()), window_id);
|
||||
window->set_title(static_cast<WSAPICreateWindowRequest&>(request).title());
|
||||
window->set_rect(static_cast<WSAPICreateWindowRequest&>(request).rect());
|
||||
m_windows_by_id.set(window_id, move(window));
|
||||
GUI_ServerMessage response;
|
||||
response.type = GUI_ServerMessage::Type::DidCreateWindow;
|
||||
response.window_id = window_id;
|
||||
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
|
||||
break;
|
||||
}
|
||||
case WSMessage::APIDestroyWindowRequest: {
|
||||
int window_id = static_cast<WSAPIGetWindowRectRequest&>(request).window_id();
|
||||
auto it = m_windows_by_id.find(window_id);
|
||||
if (it == m_windows_by_id.end()) {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
auto& window = *(*it).value;
|
||||
invalidate(window);
|
||||
m_windows_by_id.remove(it);
|
||||
break;
|
||||
}
|
||||
case WSMessage::APIInvalidateRectRequest: {
|
||||
int window_id = static_cast<WSAPIInvalidateRectRequest&>(request).window_id();
|
||||
auto it = m_windows_by_id.find(window_id);
|
||||
if (it == m_windows_by_id.end()) {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
GUI_ServerMessage response;
|
||||
response.type = GUI_ServerMessage::Type::Paint;
|
||||
response.window_id = window_id;
|
||||
response.paint.rect = static_cast<WSAPIInvalidateRectRequest&>(request).rect();
|
||||
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
|
||||
break;
|
||||
}
|
||||
case WSMessage::APIDidFinishPaintingNotification: {
|
||||
int window_id = static_cast<WSAPIDidFinishPaintingNotification&>(request).window_id();
|
||||
auto it = m_windows_by_id.find(window_id);
|
||||
if (it == m_windows_by_id.end()) {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
auto& window = *(*it).value;
|
||||
invalidate(window, static_cast<WSAPIDidFinishPaintingNotification&>(request).rect());
|
||||
break;
|
||||
}
|
||||
case WSMessage::APIGetWindowBackingStoreRequest: {
|
||||
int window_id = static_cast<WSAPIGetWindowBackingStoreRequest&>(request).window_id();
|
||||
auto it = m_windows_by_id.find(window_id);
|
||||
if (it == m_windows_by_id.end()) {
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
auto& window = *(*it).value;
|
||||
auto* backing_store = window.backing();
|
||||
|
||||
// FIXME: It shouldn't work this way!
|
||||
backing_store->retain();
|
||||
|
||||
GUI_ServerMessage response;
|
||||
response.type = GUI_ServerMessage::Type::DidGetWindowBackingStore;
|
||||
response.window_id = window_id;
|
||||
response.backing.backing_store_id = backing_store;
|
||||
response.backing.bpp = sizeof(RGBA32);
|
||||
response.backing.pitch = backing_store->pitch();
|
||||
response.backing.size = backing_store->size();
|
||||
response.backing.pixels = reinterpret_cast<RGBA32*>(backing_store->client_region()->laddr().as_ptr());
|
||||
WSMessageLoop::the().post_message_to_client(request.client_id(), response);
|
||||
break;
|
||||
}
|
||||
case WSMessage::APIReleaseWindowBackingStoreRequest: {
|
||||
int backing_store_id = static_cast<WSAPIReleaseWindowBackingStoreRequest&>(request).backing_store_id();
|
||||
// FIXME: It shouldn't work this way!
|
||||
auto* backing_store = (GraphicsBitmap*)backing_store_id;
|
||||
backing_store->release();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -103,6 +103,7 @@ private:
|
||||
Color m_dragging_window_border_color2;
|
||||
Color m_dragging_window_title_color;
|
||||
|
||||
HashMap<int, OwnPtr<WSWindow>> m_windows_by_id;
|
||||
HashTable<WSWindow*> m_windows;
|
||||
InlineLinkedList<WSWindow> m_windows_in_order;
|
||||
|
||||
@ -144,8 +145,9 @@ private:
|
||||
Lockable<bool> m_flash_flush;
|
||||
bool m_buffers_are_flipped { false };
|
||||
|
||||
int m_next_menubar_id = 100;
|
||||
int m_next_menu_id = 900;
|
||||
int m_next_menubar_id { 100 };
|
||||
int m_next_menu_id { 100 };
|
||||
int m_next_window_id { 1982 };
|
||||
|
||||
OwnPtr<WSMenu> m_system_menu;
|
||||
Color m_menu_selection_color;
|
||||
|
Loading…
Reference in New Issue
Block a user