summaryrefslogtreecommitdiff
path: root/WindowServer
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-02-19 01:42:53 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-02-19 01:42:53 +0100
commit9b71307d499924834d029adc91baf9689bfa49fd (patch)
tree910481262bce702d78f3af9a806965a769d4c644 /WindowServer
parentd4973842c913ca79e21f7dd53fe1a4d5720886e3 (diff)
downloadserenity-9b71307d499924834d029adc91baf9689bfa49fd.zip
WindowServer: Support windows with alpha channels. And per-WSWindow opacity.
This patch also adds a Format concept to GraphicsBitmap. For now there are only two formats: RGB32 and RGBA32. Windows with alpha channel have their backing stores created in the RGBA32 format. Use this to make Terminal windows semi-transparent for that comfy rice look. There is one problem here, in that window compositing overdraw incurs multiple passes of blending of the same pixels. This leads to a mismatch in opacity which is obviously not good. I will work on this in a later patch. The alpha blending is currently straight C++. It should be relatively easy to optimize this using SSE instructions. For now I'm just happy with the cute effect. :^)
Diffstat (limited to 'WindowServer')
-rw-r--r--WindowServer/WSAPITypes.h4
-rw-r--r--WindowServer/WSClientConnection.cpp21
-rw-r--r--WindowServer/WSClientConnection.h3
-rw-r--r--WindowServer/WSMessage.h29
-rw-r--r--WindowServer/WSMessageLoop.cpp2
-rw-r--r--WindowServer/WSWindow.cpp7
-rw-r--r--WindowServer/WSWindow.h10
-rw-r--r--WindowServer/WSWindowManager.cpp31
8 files changed, 86 insertions, 21 deletions
diff --git a/WindowServer/WSAPITypes.h b/WindowServer/WSAPITypes.h
index 8f9257c715..3ed1b55077 100644
--- a/WindowServer/WSAPITypes.h
+++ b/WindowServer/WSAPITypes.h
@@ -117,6 +117,7 @@ struct WSAPI_ServerMessage {
size_t bpp;
size_t pitch;
int shared_buffer_id;
+ bool has_alpha_channel;
} backing;
};
};
@@ -142,6 +143,7 @@ struct WSAPI_ClientMessage {
DidFinishPainting,
GetWindowBackingStore,
SetGlobalCursorTracking,
+ SetWindowOpacity,
};
Type type { Invalid };
int window_id { -1 };
@@ -157,6 +159,8 @@ struct WSAPI_ClientMessage {
} menu;
struct {
WSAPI_Rect rect;
+ bool has_alpha_channel;
+ float opacity;
} window;
};
};
diff --git a/WindowServer/WSClientConnection.cpp b/WindowServer/WSClientConnection.cpp
index 841d58a7c9..ad11034333 100644
--- a/WindowServer/WSClientConnection.cpp
+++ b/WindowServer/WSClientConnection.cpp
@@ -79,14 +79,14 @@ void WSClientConnection::post_message(const WSAPI_ServerMessage& message)
ASSERT(nwritten == sizeof(message));
}
-RetainPtr<GraphicsBitmap> WSClientConnection::create_shared_bitmap(const Size& size)
+RetainPtr<GraphicsBitmap> WSClientConnection::create_shared_bitmap(GraphicsBitmap::Format format, const Size& size)
{
RGBA32* buffer;
int shared_buffer_id = create_shared_buffer(m_pid, size.area() * sizeof(RGBA32), (void**)&buffer);
ASSERT(shared_buffer_id >= 0);
ASSERT(buffer);
ASSERT(buffer != (void*)-1);
- return GraphicsBitmap::create_with_shared_buffer(shared_buffer_id, size, buffer);
+ return GraphicsBitmap::create_with_shared_buffer(format, shared_buffer_id, size, buffer);
}
void WSClientConnection::on_message(WSMessage& message)
@@ -236,6 +236,18 @@ void WSClientConnection::handle_request(WSAPIAddMenuSeparatorRequest& request)
post_message(response);
}
+void WSClientConnection::handle_request(WSAPISetWindowOpacityRequest& request)
+{
+ int window_id = request.window_id();
+ auto it = m_windows.find(window_id);
+ if (it == m_windows.end()) {
+ post_error("Bad window ID");
+ return;
+ }
+ auto& window = *(*it).value;
+ window.set_opacity(request.opacity());
+}
+
void WSClientConnection::handle_request(WSAPISetWindowTitleRequest& request)
{
int window_id = request.window_id();
@@ -298,8 +310,10 @@ void WSClientConnection::handle_request(WSAPICreateWindowRequest& request)
{
int window_id = m_next_window_id++;
auto window = make<WSWindow>(*this, window_id);
+ window->set_has_alpha_channel(request.has_alpha_channel());
window->set_title(request.title());
window->set_rect(request.rect());
+ window->set_opacity(request.opacity());
m_windows.set(window_id, move(window));
WSAPI_ServerMessage response;
response.type = WSAPI_ServerMessage::Type::DidCreateWindow;
@@ -364,6 +378,7 @@ void WSClientConnection::handle_request(WSAPIGetWindowBackingStoreRequest& reque
response.backing.bpp = sizeof(RGBA32);
response.backing.pitch = backing_store->pitch();
response.backing.size = backing_store->size();
+ response.backing.has_alpha_channel = backing_store->has_alpha_channel();
response.backing.shared_buffer_id = backing_store->shared_buffer_id();
post_message(response);
}
@@ -419,6 +434,8 @@ void WSClientConnection::on_request(WSAPIClientRequest& request)
return handle_request(static_cast<WSAPIGetWindowBackingStoreRequest&>(request));
case WSMessage::APISetGlobalCursorTrackingRequest:
return handle_request(static_cast<WSAPISetGlobalCursorTrackingRequest&>(request));
+ case WSMessage::APISetWindowOpacityRequest:
+ return handle_request(static_cast<WSAPISetWindowOpacityRequest&>(request));
default:
break;
}
diff --git a/WindowServer/WSClientConnection.h b/WindowServer/WSClientConnection.h
index f2467c14fd..fdcc27adab 100644
--- a/WindowServer/WSClientConnection.h
+++ b/WindowServer/WSClientConnection.h
@@ -22,7 +22,7 @@ public:
static void for_each_client(Function<void(WSClientConnection&)>);
void post_message(const WSAPI_ServerMessage&);
- RetainPtr<GraphicsBitmap> create_shared_bitmap(const Size&);
+ RetainPtr<GraphicsBitmap> create_shared_bitmap(GraphicsBitmap::Format, const Size&);
int client_id() const { return m_client_id; }
WSMenuBar* app_menubar() { return m_app_menubar.ptr(); }
@@ -52,6 +52,7 @@ private:
void handle_request(WSAPIDidFinishPaintingNotification&);
void handle_request(WSAPIGetWindowBackingStoreRequest&);
void handle_request(WSAPISetGlobalCursorTrackingRequest&);
+ void handle_request(WSAPISetWindowOpacityRequest&);
void post_error(const String&);
diff --git a/WindowServer/WSMessage.h b/WindowServer/WSMessage.h
index fdbd67dbe3..0656bc4bd5 100644
--- a/WindowServer/WSMessage.h
+++ b/WindowServer/WSMessage.h
@@ -39,6 +39,7 @@ public:
APIDidFinishPaintingNotification,
APIGetWindowBackingStoreRequest,
APISetGlobalCursorTrackingRequest,
+ APISetWindowOpacityRequest,
__End_API_Client_Requests,
};
@@ -253,6 +254,26 @@ private:
int m_window_id { 0 };
};
+class WSAPISetWindowOpacityRequest final : public WSAPIClientRequest {
+public:
+ explicit WSAPISetWindowOpacityRequest(int client_id, int window_id, float opacity)
+ : WSAPIClientRequest(WSMessage::APISetWindowOpacityRequest, client_id)
+ , m_client_id(client_id)
+ , m_window_id(window_id)
+ , m_opacity(opacity)
+ {
+ }
+
+ int client_id() const { return m_client_id; }
+ int window_id() const { return m_window_id; }
+ float opacity() const { return m_opacity; }
+
+private:
+ int m_client_id { 0 };
+ int m_window_id { 0 };
+ float m_opacity { 0 };
+};
+
class WSAPISetWindowRectRequest final : public WSAPIClientRequest {
public:
explicit WSAPISetWindowRectRequest(int client_id, int window_id, const Rect& rect)
@@ -292,19 +313,25 @@ private:
class WSAPICreateWindowRequest : public WSAPIClientRequest {
public:
- WSAPICreateWindowRequest(int client_id, const Rect& rect, const String& title)
+ WSAPICreateWindowRequest(int client_id, const Rect& rect, const String& title, bool has_alpha_channel, float opacity)
: WSAPIClientRequest(WSMessage::APICreateWindowRequest, client_id)
, m_rect(rect)
, m_title(title)
+ , m_opacity(opacity)
+ , m_has_alpha_channel(has_alpha_channel)
{
}
Rect rect() const { return m_rect; }
String title() const { return m_title; }
+ bool has_alpha_channel() const { return m_has_alpha_channel; }
+ float opacity() const { return m_opacity; }
private:
Rect m_rect;
String m_title;
+ float m_opacity { 0 };
+ bool m_has_alpha_channel { false };
};
class WSAPIDestroyWindowRequest : public WSAPIClientRequest {
diff --git a/WindowServer/WSMessageLoop.cpp b/WindowServer/WSMessageLoop.cpp
index 6cf92b8374..199222a4dd 100644
--- a/WindowServer/WSMessageLoop.cpp
+++ b/WindowServer/WSMessageLoop.cpp
@@ -302,7 +302,7 @@ void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMess
break;
case WSAPI_ClientMessage::Type::CreateWindow:
ASSERT(message.text_length < sizeof(message.text));
- post_message(client, make<WSAPICreateWindowRequest>(client_id, message.window.rect, String(message.text, message.text_length)));
+ post_message(client, make<WSAPICreateWindowRequest>(client_id, message.window.rect, String(message.text, message.text_length), message.window.has_alpha_channel, message.window.opacity));
break;
case WSAPI_ClientMessage::Type::DestroyWindow:
post_message(client, make<WSAPIDestroyWindowRequest>(client_id, message.window_id));
diff --git a/WindowServer/WSWindow.cpp b/WindowServer/WSWindow.cpp
index 8e440e1ec8..61e9073123 100644
--- a/WindowServer/WSWindow.cpp
+++ b/WindowServer/WSWindow.cpp
@@ -44,9 +44,10 @@ void WSWindow::set_rect(const Rect& rect)
m_rect = rect;
if (!m_backing || old_rect.size() != rect.size()) {
if (m_menu)
- m_backing = GraphicsBitmap::create(m_rect.size());
- else if (m_client)
- m_backing = m_client->create_shared_bitmap(m_rect.size());
+ m_backing = GraphicsBitmap::create(GraphicsBitmap::Format::RGB32, m_rect.size());
+ else if (m_client) {
+ m_backing = m_client->create_shared_bitmap(m_has_alpha_channel ? GraphicsBitmap::Format::RGBA32 : GraphicsBitmap::Format::RGB32, m_rect.size());
+ }
}
WSWindowManager::the().notify_rect_changed(*this, old_rect, rect);
diff --git a/WindowServer/WSWindow.h b/WindowServer/WSWindow.h
index 050ec7f63f..3cb02b5a35 100644
--- a/WindowServer/WSWindow.h
+++ b/WindowServer/WSWindow.h
@@ -25,6 +25,9 @@ public:
String title() const { return m_title; }
void set_title(String&&);
+ float opacity() const { return m_opacity; }
+ void set_opacity(float opacity) { m_opacity = opacity; }
+
int x() const { return m_rect.x(); }
int y() const { return m_rect.y(); }
int width() const { return m_rect.width(); }
@@ -59,6 +62,9 @@ public:
void set_global_cursor_tracking_enabled(bool);
bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled; }
+ bool has_alpha_channel() const { return m_has_alpha_channel; }
+ void set_has_alpha_channel(bool value) { m_has_alpha_channel = value; }
+
// For InlineLinkedList.
// FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that.
WSWindow* m_next { nullptr };
@@ -72,9 +78,9 @@ private:
bool m_is_being_dragged { false };
bool m_global_cursor_tracking_enabled { false };
bool m_visible { true };
-
+ bool m_has_alpha_channel { false };
WSMenu* m_menu { nullptr };
-
RetainPtr<GraphicsBitmap> m_backing;
int m_window_id { -1 };
+ float m_opacity { 1 };
};
diff --git a/WindowServer/WSWindowManager.cpp b/WindowServer/WSWindowManager.cpp
index 1772a68346..02154287ef 100644
--- a/WindowServer/WSWindowManager.cpp
+++ b/WindowServer/WSWindowManager.cpp
@@ -144,8 +144,8 @@ WSWindowManager::WSWindowManager()
(void)m_flush_count;
#endif
auto size = m_screen_rect.size();
- m_front_bitmap = GraphicsBitmap::create_wrapper(size, m_screen.scanline(0));
- m_back_bitmap = GraphicsBitmap::create_wrapper(size, m_screen.scanline(size.height()));
+ m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, m_screen.scanline(0));
+ m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, size, m_screen.scanline(size.height()));
m_front_painter = make<Painter>(*m_front_bitmap);
m_back_painter = make<Painter>(*m_back_bitmap);
@@ -170,17 +170,17 @@ WSWindowManager::WSWindowManager()
m_cursor_bitmap_outer = CharacterBitmap::create_from_ascii(cursor_bitmap_outer_ascii, 12, 17);
m_wallpaper_path = "/res/wallpapers/cool.rgb";
- m_wallpaper = GraphicsBitmap::load_from_file(m_wallpaper_path, { 1024, 768 });
+ m_wallpaper = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, m_wallpaper_path, { 1024, 768 });
#ifdef KERNEL
ProcFS::the().add_sys_bool("wm_flash_flush", m_flash_flush);
ProcFS::the().add_sys_string("wm_wallpaper", m_wallpaper_path, [this] {
- m_wallpaper = GraphicsBitmap::load_from_file(m_wallpaper_path, m_screen_rect.size());
+ m_wallpaper = GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, m_wallpaper_path, m_screen_rect.size());
invalidate(m_screen_rect);
});
#endif
- m_menu_selection_color = Color(0x84351a);
+ m_menu_selection_color = Color::from_rgb(0x84351a);
{
byte system_menu_name[] = { 0xf8, 0 };
@@ -242,8 +242,8 @@ void WSWindowManager::set_resolution(int width, int height)
return;
m_screen.set_resolution(width, height);
m_screen_rect = m_screen.rect();
- m_front_bitmap = GraphicsBitmap::create_wrapper({ width, height }, m_screen.scanline(0));
- m_back_bitmap = GraphicsBitmap::create_wrapper({ width, height }, m_screen.scanline(height));
+ m_front_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, { width, height }, m_screen.scanline(0));
+ m_back_bitmap = GraphicsBitmap::create_wrapper(GraphicsBitmap::Format::RGB32, { width, height }, m_screen.scanline(height));
m_front_painter = make<Painter>(*m_front_bitmap);
m_back_painter = make<Painter>(*m_back_bitmap);
m_buffers_are_flipped = false;
@@ -620,10 +620,17 @@ void WSWindowManager::compose()
dbgprintf("[WM] compose #%u (%u rects)\n", ++m_compose_count, dirty_rects.size());
#endif
- auto any_window_contains_rect = [this] (const Rect& r) {
+ auto any_opaque_window_contains_rect = [this] (const Rect& r) {
for (auto* window = m_windows_in_order.head(); window; window = window->next()) {
if (!window->is_visible())
continue;
+ if (window->opacity() < 1.0f)
+ continue;
+ if (window->has_alpha_channel()) {
+ // FIXME: Just because the window has an alpha channel doesn't mean it's not opaque.
+ // Maybe there's some way we could know this?
+ continue;
+ }
if (outer_window_rect(window->rect()).contains(r))
return true;
}
@@ -640,9 +647,8 @@ void WSWindowManager::compose()
};
for (auto& dirty_rect : dirty_rects) {
- if (any_window_contains_rect(dirty_rect)) {
+ if (any_opaque_window_contains_rect(dirty_rect))
continue;
- }
if (!m_wallpaper)
m_back_painter->fill_rect(dirty_rect, m_background_color);
else
@@ -665,7 +671,10 @@ void WSWindowManager::compose()
dirty_rect_in_window_coordinates.set_y(dirty_rect_in_window_coordinates.y() - window.y());
auto dst = window.position();
dst.move_by(dirty_rect_in_window_coordinates.location());
- m_back_painter->blit(dst, *backing, dirty_rect_in_window_coordinates);
+ if (window.opacity() == 1.0f)
+ m_back_painter->blit(dst, *backing, dirty_rect_in_window_coordinates);
+ else
+ m_back_painter->blit_with_opacity(dst, *backing, dirty_rect_in_window_coordinates, window.opacity());
m_back_painter->clear_clip_rect();
}
m_back_painter->clear_clip_rect();