فهرست منبع

Taskbar: Start working on a taskbar app.

I originally thought I would do this inside WindowServer, but let's try to
make it as a standalone app that communicates with WindowServer instead.
That will allow us to use LibGUI. :^)
Andreas Kling 6 سال پیش
والد
کامیت
a22774ee3f

BIN
Applications/Taskbar/About


+ 33 - 0
Applications/Taskbar/Makefile

@@ -0,0 +1,33 @@
+OBJS = \
+    TaskbarWindow.o \
+    TaskbarWidget.o \
+    main.o
+
+APP = Taskbar
+
+STANDARD_FLAGS = -std=c++17 -Wno-sized-deallocation
+WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings -Wimplicit-fallthrough
+FLAVOR_FLAGS = -fno-exceptions -fno-rtti
+OPTIMIZATION_FLAGS = -Os
+INCLUDE_FLAGS = -I../.. -I. -I../../LibC
+
+DEFINES = -DSERENITY -DSANITIZE_PTRS -DUSERLAND
+
+CXXFLAGS = -MMD -MP $(WARNING_FLAGS) $(OPTIMIZATION_FLAGS) $(FLAVOR_FLAGS) $(STANDARD_FLAGS) $(INCLUDE_FLAGS) $(DEFINES)
+CXX = i686-pc-serenity-g++
+LD = i686-pc-serenity-g++
+LDFLAGS = -L../../LibC -L../../LibGUI
+
+all: $(APP)
+
+$(APP): $(OBJS)
+	$(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lgui -lc
+
+.cpp.o:
+	@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
+
+-include $(OBJS:%.o=%.d)
+
+clean:
+	@echo "CLEAN"; rm -f $(APPS) $(OBJS) *.d
+

BIN
Applications/Taskbar/Taskbar


+ 31 - 0
Applications/Taskbar/TaskbarWidget.cpp

@@ -0,0 +1,31 @@
+#include "TaskbarWidget.h"
+#include <LibGUI/GLabel.h>
+#include <LibGUI/GButton.h>
+#include <LibGUI/GBoxLayout.h>
+#include <LibGUI/GPainter.h>
+#include <stdio.h>
+
+TaskbarWidget::TaskbarWidget(GWidget* parent)
+    : GFrame(parent)
+{
+    set_fill_with_background_color(true);
+    set_layout(make<GBoxLayout>(Orientation::Vertical));
+    layout()->set_margins({ 0, 8, 0, 8 });
+    layout()->set_spacing(8);
+
+    set_frame_thickness(1);
+    set_frame_shape(GFrame::Shape::Panel);
+    set_frame_shadow(GFrame::Shadow::Raised);
+}
+
+TaskbarWidget::~TaskbarWidget()
+{
+}
+
+void TaskbarWidget::paint_event(GPaintEvent& event)
+{
+    GFrame::paint_event(event);
+
+    GPainter painter(*this);
+    painter.add_clip_rect(event.rect());
+}

+ 133 - 0
Applications/Taskbar/TaskbarWidget.d

@@ -0,0 +1,133 @@
+TaskbarWidget.o: TaskbarWidget.cpp TaskbarWidget.h ../../LibGUI/GFrame.h \
+ ../../LibGUI/GWidget.h ../../LibGUI/GElapsedTimer.h ../../LibC/time.h \
+ ../../LibC/sys/cdefs.h ../../LibC/sys/types.h ../../LibC/stdint.h \
+ ../../LibGUI/GEvent.h ../../SharedGraphics/Point.h ../../AK/AKString.h \
+ ../../AK/ByteBuffer.h ../../AK/Types.h ../../AK/StdLibExtras.h \
+ ../../LibC/stdlib.h ../../LibC/stddef.h ../../LibC/string.h \
+ ../../AK/Retainable.h ../../AK/Assertions.h ../../LibC/assert.h \
+ ../../AK/RetainPtr.h ../../AK/Retained.h ../../AK/kmalloc.h \
+ ../../AK/StringImpl.h ../../AK/Traits.h ../../AK/kstdio.h \
+ ../../Kernel/kstdio.h ../../Kernel/kprintf.h ../../AK/HashFunctions.h \
+ ../../AK/Vector.h ../../AK/OwnPtr.h ../../SharedGraphics/Rect.h \
+ ../../SharedGraphics/Size.h ../../AK/WeakPtr.h ../../AK/Weakable.h \
+ ../../Kernel/KeyCode.h ../../LibGUI/GObject.h \
+ ../../SharedGraphics/Color.h ../../SharedGraphics/Font.h \
+ ../../AK/MappedFile.h ../../AK/Badge.h ../../LibGUI/GLabel.h \
+ ../../SharedGraphics/TextAlignment.h ../../LibGUI/GButton.h \
+ ../../SharedGraphics/StylePainter.h ../../AK/Function.h \
+ ../../SharedGraphics/GraphicsBitmap.h ../../LibC/SharedBuffer.h \
+ ../../LibGUI/GBoxLayout.h ../../LibGUI/GLayout.h ../../LibGUI/GMargins.h \
+ ../../LibGUI/GPainter.h ../../SharedGraphics/Painter.h \
+ ../../LibC/stdio.h ../../LibC/stdarg.h ../../LibC/limits.h
+
+TaskbarWidget.h:
+
+../../LibGUI/GFrame.h:
+
+../../LibGUI/GWidget.h:
+
+../../LibGUI/GElapsedTimer.h:
+
+../../LibC/time.h:
+
+../../LibC/sys/cdefs.h:
+
+../../LibC/sys/types.h:
+
+../../LibC/stdint.h:
+
+../../LibGUI/GEvent.h:
+
+../../SharedGraphics/Point.h:
+
+../../AK/AKString.h:
+
+../../AK/ByteBuffer.h:
+
+../../AK/Types.h:
+
+../../AK/StdLibExtras.h:
+
+../../LibC/stdlib.h:
+
+../../LibC/stddef.h:
+
+../../LibC/string.h:
+
+../../AK/Retainable.h:
+
+../../AK/Assertions.h:
+
+../../LibC/assert.h:
+
+../../AK/RetainPtr.h:
+
+../../AK/Retained.h:
+
+../../AK/kmalloc.h:
+
+../../AK/StringImpl.h:
+
+../../AK/Traits.h:
+
+../../AK/kstdio.h:
+
+../../Kernel/kstdio.h:
+
+../../Kernel/kprintf.h:
+
+../../AK/HashFunctions.h:
+
+../../AK/Vector.h:
+
+../../AK/OwnPtr.h:
+
+../../SharedGraphics/Rect.h:
+
+../../SharedGraphics/Size.h:
+
+../../AK/WeakPtr.h:
+
+../../AK/Weakable.h:
+
+../../Kernel/KeyCode.h:
+
+../../LibGUI/GObject.h:
+
+../../SharedGraphics/Color.h:
+
+../../SharedGraphics/Font.h:
+
+../../AK/MappedFile.h:
+
+../../AK/Badge.h:
+
+../../LibGUI/GLabel.h:
+
+../../SharedGraphics/TextAlignment.h:
+
+../../LibGUI/GButton.h:
+
+../../SharedGraphics/StylePainter.h:
+
+../../AK/Function.h:
+
+../../SharedGraphics/GraphicsBitmap.h:
+
+../../LibC/SharedBuffer.h:
+
+../../LibGUI/GBoxLayout.h:
+
+../../LibGUI/GLayout.h:
+
+../../LibGUI/GMargins.h:
+
+../../LibGUI/GPainter.h:
+
+../../SharedGraphics/Painter.h:
+
+../../LibC/stdio.h:
+
+../../LibC/stdarg.h:
+
+../../LibC/limits.h:

+ 13 - 0
Applications/Taskbar/TaskbarWidget.h

@@ -0,0 +1,13 @@
+#include <LibGUI/GFrame.h>
+
+class TaskbarWidget final : public GFrame {
+public:
+    TaskbarWidget(GWidget* parent = nullptr);
+    virtual ~TaskbarWidget() override;
+
+    virtual const char* class_name() const override { return "TaskbarWidget"; }
+
+private:
+    virtual void paint_event(GPaintEvent&) override;
+
+};

BIN
Applications/Taskbar/TaskbarWidget.o


+ 29 - 0
Applications/Taskbar/TaskbarWindow.cpp

@@ -0,0 +1,29 @@
+#include "TaskbarWindow.h"
+#include "TaskbarWidget.h"
+#include <LibGUI/GWindow.h>
+#include <LibGUI/GDesktop.h>
+#include <stdio.h>
+
+TaskbarWindow::TaskbarWindow()
+{
+    set_window_type(GWindowType::Taskbar);
+    set_title("Taskbar");
+    set_should_exit_event_loop_on_close(true);
+
+    on_screen_rect_change(GDesktop::the().rect());
+
+    GDesktop::the().on_rect_change = [this] (const Rect& rect) { on_screen_rect_change(rect); };
+
+    auto* widget = new TaskbarWidget;
+    set_main_widget(widget);
+}
+
+TaskbarWindow::~TaskbarWindow()
+{
+}
+
+void TaskbarWindow::on_screen_rect_change(const Rect& rect)
+{
+    Rect new_rect { rect.x(), rect.bottom() - taskbar_height() + 1, rect.width(), taskbar_height() };
+    set_rect(new_rect);
+}

+ 118 - 0
Applications/Taskbar/TaskbarWindow.d

@@ -0,0 +1,118 @@
+TaskbarWindow.o: TaskbarWindow.cpp TaskbarWindow.h ../../LibGUI/GWindow.h \
+ ../../LibGUI/GObject.h ../../AK/Vector.h ../../AK/Assertions.h \
+ ../../LibC/assert.h ../../LibC/sys/cdefs.h ../../AK/OwnPtr.h \
+ ../../AK/StdLibExtras.h ../../LibC/stdlib.h ../../LibC/sys/types.h \
+ ../../LibC/stdint.h ../../LibC/stddef.h ../../LibC/string.h \
+ ../../AK/Types.h ../../AK/Traits.h ../../AK/kstdio.h \
+ ../../Kernel/kstdio.h ../../Kernel/kprintf.h ../../AK/HashFunctions.h \
+ ../../AK/kmalloc.h ../../AK/Weakable.h ../../AK/Retainable.h \
+ ../../AK/RetainPtr.h ../../AK/Retained.h ../../SharedGraphics/Rect.h \
+ ../../SharedGraphics/Point.h ../../AK/AKString.h ../../AK/ByteBuffer.h \
+ ../../AK/StringImpl.h ../../SharedGraphics/Size.h \
+ ../../SharedGraphics/GraphicsBitmap.h ../../SharedGraphics/Color.h \
+ ../../AK/MappedFile.h ../../LibC/SharedBuffer.h ../../AK/WeakPtr.h \
+ ../../LibGUI/GWidget.h ../../LibGUI/GElapsedTimer.h ../../LibC/time.h \
+ ../../LibGUI/GEvent.h ../../Kernel/KeyCode.h ../../SharedGraphics/Font.h \
+ ../../AK/Badge.h TaskbarWidget.h ../../LibGUI/GFrame.h \
+ ../../LibGUI/GDesktop.h ../../AK/Function.h ../../LibC/stdio.h \
+ ../../LibC/stdarg.h ../../LibC/limits.h
+
+TaskbarWindow.h:
+
+../../LibGUI/GWindow.h:
+
+../../LibGUI/GObject.h:
+
+../../AK/Vector.h:
+
+../../AK/Assertions.h:
+
+../../LibC/assert.h:
+
+../../LibC/sys/cdefs.h:
+
+../../AK/OwnPtr.h:
+
+../../AK/StdLibExtras.h:
+
+../../LibC/stdlib.h:
+
+../../LibC/sys/types.h:
+
+../../LibC/stdint.h:
+
+../../LibC/stddef.h:
+
+../../LibC/string.h:
+
+../../AK/Types.h:
+
+../../AK/Traits.h:
+
+../../AK/kstdio.h:
+
+../../Kernel/kstdio.h:
+
+../../Kernel/kprintf.h:
+
+../../AK/HashFunctions.h:
+
+../../AK/kmalloc.h:
+
+../../AK/Weakable.h:
+
+../../AK/Retainable.h:
+
+../../AK/RetainPtr.h:
+
+../../AK/Retained.h:
+
+../../SharedGraphics/Rect.h:
+
+../../SharedGraphics/Point.h:
+
+../../AK/AKString.h:
+
+../../AK/ByteBuffer.h:
+
+../../AK/StringImpl.h:
+
+../../SharedGraphics/Size.h:
+
+../../SharedGraphics/GraphicsBitmap.h:
+
+../../SharedGraphics/Color.h:
+
+../../AK/MappedFile.h:
+
+../../LibC/SharedBuffer.h:
+
+../../AK/WeakPtr.h:
+
+../../LibGUI/GWidget.h:
+
+../../LibGUI/GElapsedTimer.h:
+
+../../LibC/time.h:
+
+../../LibGUI/GEvent.h:
+
+../../Kernel/KeyCode.h:
+
+../../SharedGraphics/Font.h:
+
+../../AK/Badge.h:
+
+TaskbarWidget.h:
+
+../../LibGUI/GFrame.h:
+
+../../LibGUI/GDesktop.h:
+
+../../AK/Function.h:
+
+../../LibC/stdio.h:
+
+../../LibC/stdarg.h:
+
+../../LibC/limits.h:

+ 16 - 0
Applications/Taskbar/TaskbarWindow.h

@@ -0,0 +1,16 @@
+#include <LibGUI/GWindow.h>
+#include <LibGUI/GWidget.h>
+
+class TaskbarWindow final : public GWindow {
+public:
+    TaskbarWindow();
+    virtual ~TaskbarWindow() override;
+
+    int taskbar_height() const { return 20; }
+
+    virtual const char* class_name() const override { return "TaskbarWindow"; }
+
+private:
+    void on_screen_rect_change(const Rect&);
+
+};

BIN
Applications/Taskbar/TaskbarWindow.o


+ 10 - 0
Applications/Taskbar/main.cpp

@@ -0,0 +1,10 @@
+#include <LibGUI/GApplication.h>
+#include "TaskbarWindow.h"
+
+int main(int argc, char** argv)
+{
+    GApplication app(argc, argv);
+    TaskbarWindow window;
+    window.show();
+    return app.exec();
+}

+ 114 - 0
Applications/Taskbar/main.d

@@ -0,0 +1,114 @@
+main.o: main.cpp ../../LibGUI/GApplication.h ../../AK/Badge.h \
+ ../../AK/OwnPtr.h ../../AK/StdLibExtras.h ../../LibC/stdlib.h \
+ ../../LibC/sys/cdefs.h ../../LibC/sys/types.h ../../LibC/stdint.h \
+ ../../LibC/stddef.h ../../LibC/string.h ../../AK/Types.h \
+ ../../AK/Traits.h ../../AK/kstdio.h ../../Kernel/kstdio.h \
+ ../../Kernel/kprintf.h ../../AK/HashFunctions.h ../../AK/HashMap.h \
+ ../../AK/HashTable.h ../../AK/Assertions.h ../../LibC/assert.h \
+ ../../AK/DoublyLinkedList.h ../../LibGUI/GShortcut.h \
+ ../../Kernel/KeyCode.h ../../AK/AKString.h ../../AK/ByteBuffer.h \
+ ../../AK/Retainable.h ../../AK/RetainPtr.h ../../AK/Retained.h \
+ ../../AK/kmalloc.h ../../AK/StringImpl.h ../../AK/Vector.h \
+ TaskbarWindow.h ../../LibGUI/GWindow.h ../../LibGUI/GObject.h \
+ ../../AK/Weakable.h ../../SharedGraphics/Rect.h \
+ ../../SharedGraphics/Point.h ../../SharedGraphics/Size.h \
+ ../../SharedGraphics/GraphicsBitmap.h ../../SharedGraphics/Color.h \
+ ../../AK/MappedFile.h ../../LibC/SharedBuffer.h ../../AK/WeakPtr.h \
+ ../../LibGUI/GWidget.h ../../LibGUI/GElapsedTimer.h ../../LibC/time.h \
+ ../../LibGUI/GEvent.h ../../SharedGraphics/Font.h
+
+../../LibGUI/GApplication.h:
+
+../../AK/Badge.h:
+
+../../AK/OwnPtr.h:
+
+../../AK/StdLibExtras.h:
+
+../../LibC/stdlib.h:
+
+../../LibC/sys/cdefs.h:
+
+../../LibC/sys/types.h:
+
+../../LibC/stdint.h:
+
+../../LibC/stddef.h:
+
+../../LibC/string.h:
+
+../../AK/Types.h:
+
+../../AK/Traits.h:
+
+../../AK/kstdio.h:
+
+../../Kernel/kstdio.h:
+
+../../Kernel/kprintf.h:
+
+../../AK/HashFunctions.h:
+
+../../AK/HashMap.h:
+
+../../AK/HashTable.h:
+
+../../AK/Assertions.h:
+
+../../LibC/assert.h:
+
+../../AK/DoublyLinkedList.h:
+
+../../LibGUI/GShortcut.h:
+
+../../Kernel/KeyCode.h:
+
+../../AK/AKString.h:
+
+../../AK/ByteBuffer.h:
+
+../../AK/Retainable.h:
+
+../../AK/RetainPtr.h:
+
+../../AK/Retained.h:
+
+../../AK/kmalloc.h:
+
+../../AK/StringImpl.h:
+
+../../AK/Vector.h:
+
+TaskbarWindow.h:
+
+../../LibGUI/GWindow.h:
+
+../../LibGUI/GObject.h:
+
+../../AK/Weakable.h:
+
+../../SharedGraphics/Rect.h:
+
+../../SharedGraphics/Point.h:
+
+../../SharedGraphics/Size.h:
+
+../../SharedGraphics/GraphicsBitmap.h:
+
+../../SharedGraphics/Color.h:
+
+../../AK/MappedFile.h:
+
+../../LibC/SharedBuffer.h:
+
+../../AK/WeakPtr.h:
+
+../../LibGUI/GWidget.h:
+
+../../LibGUI/GElapsedTimer.h:
+
+../../LibC/time.h:
+
+../../LibGUI/GEvent.h:
+
+../../SharedGraphics/Font.h:

BIN
Applications/Taskbar/main.o


+ 2 - 0
Kernel/makeall.sh

@@ -34,6 +34,8 @@ $make_cmd -C ../Applications/About clean && \
 $make_cmd -C ../Applications/About && \
 $make_cmd -C ../Applications/IRCClient clean && \
 $make_cmd -C ../Applications/IRCClient && \
+$make_cmd -C ../Applications/Taskbar clean && \
+$make_cmd -C ../Applications/Taskbar && \
 $make_cmd clean &&\
 $make_cmd && \
 sudo ./sync.sh

+ 2 - 0
Kernel/sync.sh

@@ -92,6 +92,8 @@ ln -s IRCClient mnt/bin/irc
 ln -s FileManager mnt/bin/fm
 cp -v ../Servers/LookupServer/LookupServer mnt/bin/LookupServer
 cp -v ../Servers/WindowServer/WindowServer mnt/bin/WindowServer
+cp -v ../Applications/Taskbar/Taskbar mnt/bin/Taskbar
+ln -s Taskbar mnt/bin/tb
 cp -v kernel.map mnt/
 sh sync-local.sh
 sync

+ 4 - 0
LibGUI/GDesktop.cpp

@@ -16,7 +16,11 @@ GDesktop::GDesktop()
 
 void GDesktop::did_receive_screen_rect(Badge<GEventLoop>, const Rect& rect)
 {
+    if (m_rect == rect)
+        return;
     m_rect = rect;
+    if (on_rect_change)
+        on_rect_change(rect);
 }
 
 bool GDesktop::set_wallpaper(const String& path)

+ 3 - 0
LibGUI/GDesktop.h

@@ -2,6 +2,7 @@
 
 #include <AK/AKString.h>
 #include <AK/Badge.h>
+#include <AK/Function.h>
 #include <SharedGraphics/Rect.h>
 
 class GEventLoop;
@@ -17,6 +18,8 @@ public:
     Rect rect() const { return m_rect; }
     void did_receive_screen_rect(Badge<GEventLoop>, const Rect&);
 
+    Function<void(const Rect&)> on_rect_change;
+
 private:
     Rect m_rect;
 };

+ 1 - 0
LibGUI/GEventLoop.cpp

@@ -64,6 +64,7 @@ void GEventLoop::connect_to_server()
     request.greeting.client_pid = getpid();
     auto response = sync_request(request, WSAPI_ServerMessage::Type::Greeting);
     s_server_pid = response.greeting.server_pid;
+    GDesktop::the().did_receive_screen_rect(Badge<GEventLoop>(), response.greeting.screen_rect);
 }
 
 GEventLoop::GEventLoop()

+ 6 - 0
LibGUI/GWindow.cpp

@@ -64,6 +64,7 @@ void GWindow::show()
     request.window.opacity = m_opacity_when_windowless;
     request.window.size_increment = m_size_increment;
     request.window.base_size = m_base_size;
+    request.window.type = (WSAPI_WindowType)m_window_type;
     ASSERT(m_title_when_windowless.length() < (ssize_t)sizeof(request.text));
     strcpy(request.text, m_title_when_windowless.characters());
     request.text_length = m_title_when_windowless.length();
@@ -140,6 +141,11 @@ void GWindow::set_rect(const Rect& a_rect)
     GEventLoop::current().post_message_to_server(request);
 }
 
+void GWindow::set_window_type(GWindowType window_type)
+{
+    m_window_type = window_type;
+}
+
 void GWindow::set_override_cursor(GStandardCursor cursor)
 {
     if (!m_window_id)

+ 8 - 1
LibGUI/GWindow.h

@@ -16,6 +16,12 @@ enum class GStandardCursor {
     ResizeVertical,
 };
 
+enum class GWindowType {
+    Invalid = 0,
+    Normal,
+    Taskbar,
+};
+
 class GWindow : public GObject {
 public:
     GWindow(GObject* parent = nullptr);
@@ -29,6 +35,7 @@ public:
     void set_double_buffering_enabled(bool);
     void set_has_alpha_channel(bool);
     void set_opacity(float);
+    void set_window_type(GWindowType);
 
     int window_id() const { return m_window_id; }
 
@@ -117,6 +124,7 @@ private:
     Vector<Rect> m_pending_paint_event_rects;
     Size m_size_increment;
     Size m_base_size;
+    GWindowType m_window_type { GWindowType::Normal };
     bool m_is_active { false };
     bool m_should_exit_app_on_close { false };
     bool m_has_alpha_channel { false };
@@ -124,4 +132,3 @@ private:
     bool m_modal { false };
     bool m_resizable { true };
 };
-

+ 5 - 5
Servers/WindowServer/WSAPITypes.h

@@ -20,11 +20,10 @@ struct WSAPI_Rect {
     WSAPI_Size size;
 };
 
-struct WSAPI_WindowParameters {
-    WSAPI_Rect rect;
-    Color background_color;
-    unsigned flags { 0 };
-    char title[128];
+enum WSAPI_WindowType {
+    Invalid = 0,
+    Normal,
+    Taskbar,
 };
 
 struct WSAPI_WindowBackingStoreInfo {
@@ -200,6 +199,7 @@ struct WSAPI_ClientMessage {
             bool has_alpha_channel;
             bool modal;
             bool resizable;
+            WSAPI_WindowType type;
             float opacity;
             WSAPI_Size base_size;
             WSAPI_Size size_increment;

+ 13 - 7
Servers/WindowServer/WSClientConnection.cpp

@@ -311,6 +311,7 @@ void WSClientConnection::handle_request(const WSAPISetWindowRectRequest& request
     }
     auto& window = *(*it).value;
     window.set_rect(request.rect());
+    post_paint_request(window, request.rect());
 }
 
 void WSClientConnection::handle_request(const WSAPIGetWindowRectRequest& request)
@@ -370,7 +371,7 @@ void WSClientConnection::handle_request(const WSAPIGetClipboardContentsRequest&)
 void WSClientConnection::handle_request(const WSAPICreateWindowRequest& request)
 {
     int window_id = m_next_window_id++;
-    auto window = make<WSWindow>(*this, window_id, request.is_modal());
+    auto window = make<WSWindow>(*this, request.window_type(), window_id, request.is_modal());
     window->set_has_alpha_channel(request.has_alpha_channel());
     window->set_resizable(request.is_resizable());
     window->set_title(request.title());
@@ -399,6 +400,16 @@ void WSClientConnection::handle_request(const WSAPIDestroyWindowRequest& request
     m_windows.remove(it);
 }
 
+void WSClientConnection::post_paint_request(const WSWindow& window, const Rect& rect)
+{
+    WSAPI_ServerMessage response;
+    response.type = WSAPI_ServerMessage::Type::Paint;
+    response.window_id = window.window_id();
+    response.paint.rect = rect;
+    response.paint.window_size = window.size();
+    post_message(response);
+}
+
 void WSClientConnection::handle_request(const WSAPIInvalidateRectRequest& request)
 {
     int window_id = request.window_id();
@@ -408,12 +419,7 @@ void WSClientConnection::handle_request(const WSAPIInvalidateRectRequest& reques
         return;
     }
     auto& window = *(*it).value;
-    WSAPI_ServerMessage response;
-    response.type = WSAPI_ServerMessage::Type::Paint;
-    response.window_id = window_id;
-    response.paint.rect = request.rect();
-    response.paint.window_size = window.size();
-    post_message(response);
+    post_paint_request(window, request.rect());
 }
 
 void WSClientConnection::handle_request(const WSAPIDidFinishPaintingNotification& request)

+ 1 - 0
Servers/WindowServer/WSClientConnection.h

@@ -37,6 +37,7 @@ public:
     template<typename Callback> void for_each_window(Callback);
 
     void notify_about_new_screen_rect(const Rect&);
+    void post_paint_request(const WSWindow&, const Rect&);
 
 private:
     virtual void on_message(const WSMessage&) override;

+ 5 - 1
Servers/WindowServer/WSMessage.h

@@ -6,6 +6,7 @@
 #include <AK/Types.h>
 #include <Kernel/KeyCode.h>
 #include <WindowServer/WSCursor.h>
+#include <WindowServer/WSWindowType.h>
 
 class WSMessage {
 public:
@@ -408,7 +409,7 @@ private:
 
 class WSAPICreateWindowRequest : public WSAPIClientRequest {
 public:
-    WSAPICreateWindowRequest(int client_id, const Rect& rect, const String& title, bool has_alpha_channel, bool modal, bool resizable, float opacity, const Size& base_size, const Size& size_increment)
+    WSAPICreateWindowRequest(int client_id, const Rect& rect, const String& title, bool has_alpha_channel, bool modal, bool resizable, float opacity, const Size& base_size, const Size& size_increment, WSWindowType window_type)
         : WSAPIClientRequest(WSMessage::APICreateWindowRequest, client_id)
         , m_rect(rect)
         , m_title(title)
@@ -418,6 +419,7 @@ public:
         , m_resizable(resizable)
         , m_size_increment(size_increment)
         , m_base_size(base_size)
+        , m_window_type(window_type)
     {
     }
 
@@ -429,6 +431,7 @@ public:
     float opacity() const { return m_opacity; }
     Size size_increment() const { return m_size_increment; }
     Size base_size() const { return m_base_size; }
+    WSWindowType window_type() const { return m_window_type; }
 
 private:
     Rect m_rect;
@@ -439,6 +442,7 @@ private:
     bool m_resizable { false };
     Size m_size_increment;
     Size m_base_size;
+    WSWindowType m_window_type;
 };
 
 class WSAPIDestroyWindowRequest : public WSAPIClientRequest {

+ 13 - 1
Servers/WindowServer/WSMessageLoop.cpp

@@ -249,6 +249,18 @@ void WSMessageLoop::notify_client_disconnected(int client_id)
     post_message(*client, make<WSClientDisconnectedNotification>(client_id));
 }
 
+static WSWindowType from_api(WSAPI_WindowType api_type)
+{
+    switch (api_type) {
+    case WSAPI_WindowType::Normal:
+        return WSWindowType::Normal;
+    case WSAPI_WindowType::Taskbar:
+        return WSWindowType::Taskbar;
+    default:
+        ASSERT_NOT_REACHED();
+    }
+}
+
 void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessage& message)
 {
     WSClientConnection& client = *WSClientConnection::from_client_id(client_id);
@@ -285,7 +297,7 @@ void WSMessageLoop::on_receive_from_client(int client_id, const WSAPI_ClientMess
         break;
     case WSAPI_ClientMessage::Type::CreateWindow:
         ASSERT(message.text_length < (ssize_t)sizeof(message.text));
-        post_message(client, make<WSAPICreateWindowRequest>(client_id, message.window.rect, String(message.text, message.text_length), message.window.has_alpha_channel, message.window.modal, message.window.resizable, message.window.opacity, message.window.base_size, message.window.size_increment));
+        post_message(client, make<WSAPICreateWindowRequest>(client_id, message.window.rect, String(message.text, message.text_length), message.window.has_alpha_channel, message.window.modal, message.window.resizable, message.window.opacity, message.window.base_size, message.window.size_increment, from_api(message.window.type)));
         break;
     case WSAPI_ClientMessage::Type::DestroyWindow:
         post_message(client, make<WSAPIDestroyWindowRequest>(client_id, message.window_id));

+ 2 - 2
Servers/WindowServer/WSWindow.cpp

@@ -21,9 +21,9 @@ WSWindow::WSWindow(WSMessageReceiver& internal_owner, WSWindowType type)
     WSWindowManager::the().add_window(*this);
 }
 
-WSWindow::WSWindow(WSClientConnection& client, int window_id, bool modal)
+WSWindow::WSWindow(WSClientConnection& client, WSWindowType window_type, int window_id, bool modal)
     : m_client(&client)
-    , m_type(WSWindowType::Normal)
+    , m_type(window_type)
     , m_modal(modal)
     , m_window_id(window_id)
     , m_icon(default_window_icon())

+ 1 - 1
Servers/WindowServer/WSWindow.h

@@ -14,7 +14,7 @@ class WSMouseEvent;
 
 class WSWindow final : public WSMessageReceiver, public InlineLinkedListNode<WSWindow> {
 public:
-    WSWindow(WSClientConnection&, int window_id, bool modal);
+    WSWindow(WSClientConnection&, WSWindowType, int window_id, bool modal);
     WSWindow(WSMessageReceiver&, WSWindowType);
     virtual ~WSWindow() override;
 

+ 9 - 0
Servers/WindowServer/WSWindowManager.cpp

@@ -104,6 +104,8 @@ static inline Rect outer_window_rect(const WSWindow& window)
         return menu_window_rect(window.rect());
     if (window.type() == WSWindowType::WindowSwitcher)
         return window.rect();
+    if (window.type() == WSWindowType::Taskbar)
+        return window.rect();
     ASSERT(window.type() == WSWindowType::Normal);
     return outer_window_rect(window.rect());
 }
@@ -418,6 +420,9 @@ void WSWindowManager::paint_window_frame(const WSWindow& window)
     if (window.type() == WSWindowType::WindowSwitcher)
         return;
 
+    if (window.type() == WSWindowType::Taskbar)
+        return;
+
     auto titlebar_rect = title_bar_rect(window.rect());
     auto titlebar_icon_rect = title_bar_icon_rect(window.rect());
     auto titlebar_inner_rect = title_bar_text_rect(window.rect());
@@ -1179,6 +1184,10 @@ void WSWindowManager::invalidate(const WSWindow& window)
         invalidate(window.rect());
         return;
     }
+    if (window.type() == WSWindowType::Taskbar) {
+        invalidate(window.rect());
+        return;
+    }
     ASSERT_NOT_REACHED();
 }
 

+ 4 - 0
Servers/WindowServer/WSWindowManager.h

@@ -228,6 +228,8 @@ IterationDecision WSWindowManager::for_each_visible_window_from_back_to_front(Ca
         return IterationDecision::Abort;
     if (for_each_visible_window_of_type_from_back_to_front(WSWindowType::Menu, callback) == IterationDecision::Abort)
         return IterationDecision::Abort;
+    if (for_each_visible_window_of_type_from_back_to_front(WSWindowType::Taskbar, callback) == IterationDecision::Abort)
+        return IterationDecision::Abort;
     return for_each_visible_window_of_type_from_back_to_front(WSWindowType::WindowSwitcher, callback);
 }
 
@@ -255,6 +257,8 @@ IterationDecision WSWindowManager::for_each_visible_window_of_type_from_front_to
 template<typename Callback>
 IterationDecision WSWindowManager::for_each_visible_window_from_front_to_back(Callback callback)
 {
+    if (for_each_visible_window_of_type_from_front_to_back(WSWindowType::Taskbar, callback) == IterationDecision::Abort)
+        return IterationDecision::Abort;
     if (for_each_visible_window_of_type_from_front_to_back(WSWindowType::Menu, callback) == IterationDecision::Abort)
         return IterationDecision::Abort;
     if (for_each_visible_window_of_type_from_front_to_back(WSWindowType::Normal, callback) == IterationDecision::Abort)

+ 1 - 0
Servers/WindowServer/WSWindowType.h

@@ -5,4 +5,5 @@ enum class WSWindowType {
     Normal,
     Menu,
     WindowSwitcher,
+    Taskbar,
 };