diff --git a/xbanan/Base.cpp b/xbanan/Base.cpp index 6bf0cc0..671cf88 100644 --- a/xbanan/Base.cpp +++ b/xbanan/Base.cpp @@ -445,6 +445,65 @@ void send_exposure_recursive(WINDOW wid) 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(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(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(); + info.transient_for = window.platform_window.ptr(); + } +transitient_for_done: + + return info; +} + static BAN::ErrorOr map_window(Client& client_info, WINDOW wid) { auto& object = *g_objects[wid]; @@ -457,7 +516,17 @@ static BAN::ErrorOr map_window(Client& client_info, WINDOW wid) if (window.parent == g_root.windowId) { 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; diff --git a/xbanan/Platform.h b/xbanan/Platform.h index b73e692..fe7cb88 100644 --- a/xbanan/Platform.h +++ b/xbanan/Platform.h @@ -9,6 +9,13 @@ struct PlatformWindow virtual ~PlatformWindow() = default; }; +enum class WindowType +{ + Popup, + Normal, + Utility, +}; + // initialize, poll_events, create_window and invalidate are required struct PlatformOps { @@ -17,7 +24,7 @@ struct PlatformOps /* Handle pending events */ void (*poll_events)(void*); /* Create a window with given size */ - BAN::ErrorOr> (*create_window)(WINDOW wid, uint32_t width, uint32_t height); + BAN::ErrorOr> (*create_window)(PlatformWindow* parent, WindowType, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height); /* Invaldate part of a window */ 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 */ diff --git a/xbanan/SDL2/sdl2.cpp b/xbanan/SDL2/sdl2.cpp index 023c182..50eaa1b 100644 --- a/xbanan/SDL2/sdl2.cpp +++ b/xbanan/SDL2/sdl2.cpp @@ -92,26 +92,7 @@ static bool sdl2_initialize(uint32_t* display_w, uint32_t* display_h) return true; } -static bool sdl2_init_window(SDLWindow& window, 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> sdl2_create_window(WINDOW wid, uint32_t width, uint32_t height) +static BAN::ErrorOr> sdl2_create_window(PlatformWindow* parent, WindowType type, WINDOW wid, int32_t x, int32_t y, uint32_t width, uint32_t height) { auto window = TRY(BAN::UniqPtr::create()); @@ -119,16 +100,51 @@ static BAN::ErrorOr> sdl2_create_window(WINDOW wid, window->width = width; window->height = height; - const auto flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_UTILITY; - window->window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags); + if (parent == nullptr) + x = y = SDL_WINDOWPOS_UNDEFINED; + else + { + auto& sdl_parent = *static_cast(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) { dwarnln("Could not create SDL window: {}", SDL_GetError()); 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); + } + + 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())); diff --git a/xbanan/banan-os/banan-os.cpp b/xbanan/banan-os/banan-os.cpp index d0d222b..5fa0c4b 100644 --- a/xbanan/banan-os/banan-os.cpp +++ b/xbanan/banan-os/banan-os.cpp @@ -38,8 +38,13 @@ static void bananos_poll_events(void* window) banan_window.window->poll_events(); } -static BAN::ErrorOr> bananos_create_window(WINDOW wid, uint32_t width, uint32_t height) +static BAN::ErrorOr> 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::create()); auto attributes = LibGUI::Window::default_attributes; diff --git a/xbanan/main.cpp b/xbanan/main.cpp index b630666..7cb565b 100644 --- a/xbanan/main.cpp +++ b/xbanan/main.cpp @@ -252,6 +252,11 @@ int main() APPEND_ATOM_CUSTOM(WM_DELETE_WINDOW); APPEND_ATOM_CUSTOM(_NET_WM_STATE); 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 MUST(initialize_keymap());