Add initial support for window types
This makes popup windows work much better
This commit is contained in:
@@ -445,6 +445,65 @@ void send_exposure_recursive(WINDOW wid)
|
|||||||
MUST(window.send_event(event, ExposureMask));
|
MUST(window.send_event(event, ExposureMask));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PlatformWindowInfo
|
||||||
|
{
|
||||||
|
PlatformWindow* transient_for;
|
||||||
|
WindowType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
static PlatformWindowInfo get_plaform_window_info(const Object::Window& window)
|
||||||
|
{
|
||||||
|
static const CARD32 ATOM = g_atoms_name_to_id["ATOM"_sv];
|
||||||
|
static const CARD32 WINDOW = g_atoms_name_to_id["WINDOW"_sv];
|
||||||
|
static const CARD32 WM_TRANSIENT_FOR = g_atoms_name_to_id["WM_TRANSIENT_FOR"_sv];
|
||||||
|
static const CARD32 _NET_WM_WINDOW_TYPE = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE"_sv];
|
||||||
|
static const CARD32 _NET_WM_WINDOW_TYPE_DIALOG = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_DIALOG"_sv];
|
||||||
|
static const CARD32 _NET_WM_WINDOW_TYPE_NORMAL = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_NORMAL"_sv];
|
||||||
|
static const CARD32 _NET_WM_WINDOW_TYPE_SPLASH = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_SPLASH"_sv];
|
||||||
|
static const CARD32 _NET_WM_WINDOW_TYPE_UTILITY = g_atoms_name_to_id["_NET_WM_WINDOW_TYPE_UTILITY"_sv];
|
||||||
|
|
||||||
|
PlatformWindowInfo info {
|
||||||
|
.transient_for = nullptr,
|
||||||
|
.type = WindowType::Normal,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (auto it = window.properties.find(_NET_WM_WINDOW_TYPE); it != window.properties.end())
|
||||||
|
{
|
||||||
|
if (it->value.type != ATOM || it->value.data.size() != sizeof(CARD32))
|
||||||
|
goto wm_window_type_done;
|
||||||
|
|
||||||
|
const CARD32 type = *reinterpret_cast<const CARD32*>(it->value.data.data());
|
||||||
|
if (type == _NET_WM_WINDOW_TYPE_NORMAL)
|
||||||
|
info.type = WindowType::Normal;
|
||||||
|
else if (type == _NET_WM_WINDOW_TYPE_SPLASH || type == _NET_WM_WINDOW_TYPE_UTILITY || type == _NET_WM_WINDOW_TYPE_DIALOG)
|
||||||
|
info.type = WindowType::Utility;
|
||||||
|
else
|
||||||
|
info.type = WindowType::Popup;
|
||||||
|
}
|
||||||
|
wm_window_type_done:
|
||||||
|
|
||||||
|
if (auto it = window.properties.find(WM_TRANSIENT_FOR); it != window.properties.end())
|
||||||
|
{
|
||||||
|
if (it->value.type != WINDOW || it->value.data.size() != sizeof(CARD32))
|
||||||
|
goto transitient_for_done;
|
||||||
|
|
||||||
|
const CARD32 wid = *reinterpret_cast<const CARD32*>(it->value.data.data());
|
||||||
|
|
||||||
|
auto it2 = g_objects.find(wid);
|
||||||
|
if (it2 == g_objects.end())
|
||||||
|
goto transitient_for_done;
|
||||||
|
if (it2->value->type != Object::Type::Window)
|
||||||
|
goto transitient_for_done;
|
||||||
|
|
||||||
|
// FIXME: support child windows
|
||||||
|
auto& window = it2->value->object.get<Object::Window>();
|
||||||
|
info.transient_for = window.platform_window.ptr();
|
||||||
|
}
|
||||||
|
transitient_for_done:
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
||||||
{
|
{
|
||||||
auto& object = *g_objects[wid];
|
auto& object = *g_objects[wid];
|
||||||
@@ -457,7 +516,17 @@ static BAN::ErrorOr<void> map_window(Client& client_info, WINDOW wid)
|
|||||||
if (window.parent == g_root.windowId)
|
if (window.parent == g_root.windowId)
|
||||||
{
|
{
|
||||||
ASSERT(!window.platform_window);
|
ASSERT(!window.platform_window);
|
||||||
window.platform_window = TRY(g_platform_ops.create_window(wid, window.width, window.height));
|
|
||||||
|
auto info = get_plaform_window_info(window);
|
||||||
|
window.platform_window = TRY(g_platform_ops.create_window(
|
||||||
|
info.transient_for,
|
||||||
|
info.type,
|
||||||
|
wid,
|
||||||
|
window.x,
|
||||||
|
window.y,
|
||||||
|
window.width,
|
||||||
|
window.height
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
window.mapped = true;
|
window.mapped = true;
|
||||||
|
|||||||
@@ -9,6 +9,13 @@ struct PlatformWindow
|
|||||||
virtual ~PlatformWindow() = default;
|
virtual ~PlatformWindow() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class WindowType
|
||||||
|
{
|
||||||
|
Popup,
|
||||||
|
Normal,
|
||||||
|
Utility,
|
||||||
|
};
|
||||||
|
|
||||||
// initialize, poll_events, create_window and invalidate are required
|
// initialize, poll_events, create_window and invalidate are required
|
||||||
struct PlatformOps
|
struct PlatformOps
|
||||||
{
|
{
|
||||||
@@ -17,7 +24,7 @@ struct PlatformOps
|
|||||||
/* Handle pending events */
|
/* Handle pending events */
|
||||||
void (*poll_events)(void*);
|
void (*poll_events)(void*);
|
||||||
/* Create a window with given size */
|
/* Create a window with given size */
|
||||||
BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> (*create_window)(WINDOW wid, uint32_t width, uint32_t height);
|
BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> (*create_window)(PlatformWindow* parent, WindowType, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||||
/* Invaldate part of a window */
|
/* Invaldate part of a window */
|
||||||
void (*invalidate)(PlatformWindow*, const uint32_t* pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
|
void (*invalidate)(PlatformWindow*, const uint32_t* pixels, uint32_t x, uint32_t y, uint32_t width, uint32_t height);
|
||||||
/* Request resize of a window, can be async */
|
/* Request resize of a window, can be async */
|
||||||
|
|||||||
@@ -92,26 +92,7 @@ static bool sdl2_initialize(uint32_t* display_w, uint32_t* display_h)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sdl2_init_window(SDLWindow& window, uint32_t width, uint32_t height)
|
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl2_create_window(PlatformWindow* parent, WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height)
|
||||||
{
|
|
||||||
window.renderer = SDL_CreateRenderer(window.window, -1, SDL_RENDERER_ACCELERATED);
|
|
||||||
if (window.renderer == nullptr)
|
|
||||||
{
|
|
||||||
dwarnln("Could not create SDL renderer: {}\n", SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
window.texture = SDL_CreateTexture(window.renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
|
|
||||||
if (window.texture == nullptr)
|
|
||||||
{
|
|
||||||
dwarnln("Could not create SDL texture: {}\n", SDL_GetError());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl2_create_window(WINDOW wid, uint32_t width, uint32_t height)
|
|
||||||
{
|
{
|
||||||
auto window = TRY(BAN::UniqPtr<SDLWindow>::create());
|
auto window = TRY(BAN::UniqPtr<SDLWindow>::create());
|
||||||
|
|
||||||
@@ -119,16 +100,51 @@ static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> sdl2_create_window(WINDOW wid,
|
|||||||
window->width = width;
|
window->width = width;
|
||||||
window->height = height;
|
window->height = height;
|
||||||
|
|
||||||
const auto flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_UTILITY;
|
if (parent == nullptr)
|
||||||
window->window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags);
|
x = y = SDL_WINDOWPOS_UNDEFINED;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto& sdl_parent = *static_cast<SDLWindow*>(parent);
|
||||||
|
int parent_x, parent_y;
|
||||||
|
SDL_GetWindowPosition(sdl_parent.window, &parent_x, &parent_y);
|
||||||
|
x += parent_x;
|
||||||
|
y += parent_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flags;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case WindowType::Popup:
|
||||||
|
flags = SDL_WINDOW_BORDERLESS | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR | SDL_WINDOW_UTILITY;
|
||||||
|
break;
|
||||||
|
case WindowType::Utility:
|
||||||
|
flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_UTILITY;
|
||||||
|
break;
|
||||||
|
case WindowType::Normal:
|
||||||
|
flags = SDL_WINDOW_RESIZABLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
window->window = SDL_CreateWindow("", x, y, width, height, flags);
|
||||||
if (window->window == nullptr)
|
if (window->window == nullptr)
|
||||||
{
|
{
|
||||||
dwarnln("Could not create SDL window: {}", SDL_GetError());
|
dwarnln("Could not create SDL window: {}", SDL_GetError());
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sdl2_init_window(*window, width, height))
|
window->renderer = SDL_CreateRenderer(window->window, -1, SDL_RENDERER_ACCELERATED);
|
||||||
|
if (window->renderer == nullptr)
|
||||||
|
{
|
||||||
|
dwarnln("Could not create SDL renderer: {}", SDL_GetError());
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
window->texture = SDL_CreateTexture(window->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||||
|
if (window->texture == nullptr)
|
||||||
|
{
|
||||||
|
dwarnln("Could not create SDL texture: {}", SDL_GetError());
|
||||||
|
return BAN::Error::from_errno(EFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
TRY(s_window_map.insert(SDL_GetWindowID(window->window), window.ptr()));
|
TRY(s_window_map.insert(SDL_GetWindowID(window->window), window.ptr()));
|
||||||
|
|
||||||
|
|||||||
@@ -38,8 +38,13 @@ static void bananos_poll_events(void* window)
|
|||||||
banan_window.window->poll_events();
|
banan_window.window->poll_events();
|
||||||
}
|
}
|
||||||
|
|
||||||
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> bananos_create_window(WINDOW wid, uint32_t width, uint32_t height)
|
static BAN::ErrorOr<BAN::UniqPtr<PlatformWindow>> bananos_create_window(PlatformWindow* parent, WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height)
|
||||||
{
|
{
|
||||||
|
(void)parent;
|
||||||
|
(void)type;
|
||||||
|
(void)x;
|
||||||
|
(void)y;
|
||||||
|
|
||||||
auto window = TRY(BAN::UniqPtr<BananWindow>::create());
|
auto window = TRY(BAN::UniqPtr<BananWindow>::create());
|
||||||
|
|
||||||
auto attributes = LibGUI::Window::default_attributes;
|
auto attributes = LibGUI::Window::default_attributes;
|
||||||
|
|||||||
@@ -252,6 +252,11 @@ int main()
|
|||||||
APPEND_ATOM_CUSTOM(WM_DELETE_WINDOW);
|
APPEND_ATOM_CUSTOM(WM_DELETE_WINDOW);
|
||||||
APPEND_ATOM_CUSTOM(_NET_WM_STATE);
|
APPEND_ATOM_CUSTOM(_NET_WM_STATE);
|
||||||
APPEND_ATOM_CUSTOM(_NET_WM_STATE_FULLSCREEN);
|
APPEND_ATOM_CUSTOM(_NET_WM_STATE_FULLSCREEN);
|
||||||
|
APPEND_ATOM_CUSTOM(_NET_WM_WINDOW_TYPE);
|
||||||
|
APPEND_ATOM_CUSTOM(_NET_WM_WINDOW_TYPE_DIALOG);
|
||||||
|
APPEND_ATOM_CUSTOM(_NET_WM_WINDOW_TYPE_NORMAL);
|
||||||
|
APPEND_ATOM_CUSTOM(_NET_WM_WINDOW_TYPE_SPLASH);
|
||||||
|
APPEND_ATOM_CUSTOM(_NET_WM_WINDOW_TYPE_UTILITY);
|
||||||
#undef APPEND_ATOM_CUSTOM
|
#undef APPEND_ATOM_CUSTOM
|
||||||
|
|
||||||
MUST(initialize_keymap());
|
MUST(initialize_keymap());
|
||||||
|
|||||||
Reference in New Issue
Block a user