1341 lines
52 KiB
C
1341 lines
52 KiB
C
// Native Session 0 desktop/window manager. DWM owns window policy, composition, and visible cursor presentation.
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ntlite/desktop.h>
|
|
#include <ntlite/exception.h>
|
|
#include <ntlite/internal/session_control.h>
|
|
#include <ntlite/port.h>
|
|
#include <ntlite/security.h>
|
|
#include <ntlite/service_control.h>
|
|
#include <ntlite/syscall.h>
|
|
|
|
#define DWM_EVENT_AUTO_RESET 0u
|
|
#define DWM_DESKTOP_BACKLOG 16u
|
|
#define DWM_MAX_WINDOWS 1024u
|
|
#define DWM_MAX_CLIENT_WINDOWS 128u
|
|
#define DWM_DESKTOP_COLOR 0x00202020u
|
|
#define DWM_WINDOW_COLOR 0x00303030u
|
|
#define DWM_BORDER_COLOR 0x00606060u
|
|
#define DWM_FOCUS_BORDER_COLOR 0x00D0D0D0u
|
|
|
|
typedef struct DWM_CLIENT DWM_CLIENT;
|
|
typedef struct DWM_WINDOW DWM_WINDOW;
|
|
typedef struct DWM_SURFACE_BINDING DWM_SURFACE_BINDING;
|
|
|
|
struct DWM_CLIENT {
|
|
SYS_HANDLE Endpoint;
|
|
uint32_t ProcessId;
|
|
uint32_t WindowCount;
|
|
DWM_CLIENT* Next;
|
|
};
|
|
|
|
struct DWM_SURFACE_BINDING {
|
|
DWM_WINDOW* Window;
|
|
SYS_HANDLE Surface;
|
|
void* Base;
|
|
SYS_SURFACE_DESC Desc;
|
|
SYS_HANDLE StopEvent;
|
|
SYS_HANDLE Thread;
|
|
};
|
|
|
|
struct DWM_WINDOW {
|
|
NTL_WINDOW_ID Id;
|
|
DWM_CLIENT* Owner;
|
|
DISPLAY_RECT Bounds;
|
|
uint32_t Visible;
|
|
uint32_t PointerMode;
|
|
uint32_t Destroying;
|
|
DWM_SURFACE_BINDING* Surface;
|
|
DWM_WINDOW* Lower;
|
|
DWM_WINDOW* Higher;
|
|
};
|
|
|
|
typedef struct DWM_STATE {
|
|
volatile uint32_t Running;
|
|
SYS_HANDLE Mutex;
|
|
SYS_HANDLE DirtyEvent;
|
|
SYS_HANDLE DisplayManager;
|
|
SYS_HANDLE SessionEndpoint;
|
|
SYS_HANDLE DesktopListener;
|
|
SYS_HANDLE CompositionSurface;
|
|
void* CompositionBase;
|
|
uint32_t CompositionPitch;
|
|
int32_t Width;
|
|
int32_t Height;
|
|
uint64_t NextWindowId;
|
|
uint32_t WindowCount;
|
|
DWM_CLIENT* Clients;
|
|
DWM_WINDOW* Bottom;
|
|
DWM_WINDOW* Top;
|
|
DWM_WINDOW* Focused;
|
|
DWM_WINDOW* PointerWindow;
|
|
DWM_WINDOW* Captured;
|
|
DISPLAY_RECT Dirty;
|
|
uint32_t DirtyValid;
|
|
int32_t PointerX;
|
|
int32_t PointerY;
|
|
uint32_t PointerButtons;
|
|
uint32_t CursorVisible;
|
|
} DWM_STATE;
|
|
|
|
typedef struct DWM_CLIENT_THREAD_CONTEXT {
|
|
DWM_CLIENT* Client;
|
|
} DWM_CLIENT_THREAD_CONTEXT;
|
|
|
|
static DWM_STATE gDwm;
|
|
|
|
// Terminates DWM without relying on a compiler runtime return path.
|
|
static void DwmExit(int code) {
|
|
for (;;) SysExitProcess(code);
|
|
}
|
|
|
|
// Sets a best-effort diagnostic name for the current DWM thread.
|
|
static void DwmSetCurrentThreadName(const char* name) {
|
|
SYS_SET_THREAD_NAME_REQUEST request;
|
|
memset(&request, 0, sizeof(request));
|
|
request.Size = sizeof(request);
|
|
request.ThreadHandle = SYS_HANDLE_INVALID;
|
|
request.Name = SysSvFromCstr(name);
|
|
(void)SysSetThreadName(&request);
|
|
}
|
|
|
|
// Acquires the DWM policy/composition mutex.
|
|
static KSTATUS DwmLock(void) {
|
|
if (gDwm.Mutex == SYS_HANDLE_INVALID) return NTLSTATUS_INVALID_PARAMETER;
|
|
return SysWait(gDwm.Mutex, SYS_WAIT_FLAG_NONE);
|
|
}
|
|
|
|
// Releases the DWM policy/composition mutex.
|
|
static void DwmUnlock(void) {
|
|
if (gDwm.Mutex != SYS_HANDLE_INVALID) (void)SysReleaseMutex(gDwm.Mutex);
|
|
}
|
|
|
|
// Clips one screen rectangle without relying on signed 32-bit addition.
|
|
static bool DwmClipScreenRect(const DISPLAY_RECT* input, DISPLAY_RECT* output) {
|
|
if (!input || !output || input->W <= 0 || input->H <= 0) return false;
|
|
int64_t x0 = input->X;
|
|
int64_t y0 = input->Y;
|
|
int64_t x1 = x0 + input->W;
|
|
int64_t y1 = y0 + input->H;
|
|
if (x0 < 0) x0 = 0;
|
|
if (y0 < 0) y0 = 0;
|
|
if (x1 > gDwm.Width) x1 = gDwm.Width;
|
|
if (y1 > gDwm.Height) y1 = gDwm.Height;
|
|
if (x0 >= x1 || y0 >= y1) return false;
|
|
output->X = (int32_t)x0;
|
|
output->Y = (int32_t)y0;
|
|
output->W = (int32_t)(x1 - x0);
|
|
output->H = (int32_t)(y1 - y0);
|
|
return true;
|
|
}
|
|
|
|
// Intersects two rectangles using widened arithmetic.
|
|
static bool DwmIntersectRect(const DISPLAY_RECT* a, const DISPLAY_RECT* b, DISPLAY_RECT* output) {
|
|
if (!a || !b || !output || a->W <= 0 || a->H <= 0 || b->W <= 0 || b->H <= 0) return false;
|
|
int64_t ax1 = (int64_t)a->X + a->W;
|
|
int64_t ay1 = (int64_t)a->Y + a->H;
|
|
int64_t bx1 = (int64_t)b->X + b->W;
|
|
int64_t by1 = (int64_t)b->Y + b->H;
|
|
int64_t x0 = a->X > b->X ? a->X : b->X;
|
|
int64_t y0 = a->Y > b->Y ? a->Y : b->Y;
|
|
int64_t x1 = ax1 < bx1 ? ax1 : bx1;
|
|
int64_t y1 = ay1 < by1 ? ay1 : by1;
|
|
if (x0 >= x1 || y0 >= y1) return false;
|
|
output->X = (int32_t)x0;
|
|
output->Y = (int32_t)y0;
|
|
output->W = (int32_t)(x1 - x0);
|
|
output->H = (int32_t)(y1 - y0);
|
|
return true;
|
|
}
|
|
|
|
// Adds one screen-space rectangle to the coarse dirty union while the DWM mutex is held.
|
|
static void DwmDirtyLocked(const DISPLAY_RECT* rect) {
|
|
DISPLAY_RECT clipped;
|
|
if (!DwmClipScreenRect(rect, &clipped)) return;
|
|
if (!gDwm.DirtyValid) {
|
|
gDwm.Dirty = clipped;
|
|
gDwm.DirtyValid = 1u;
|
|
} else {
|
|
int32_t x0 = gDwm.Dirty.X < clipped.X ? gDwm.Dirty.X : clipped.X;
|
|
int32_t y0 = gDwm.Dirty.Y < clipped.Y ? gDwm.Dirty.Y : clipped.Y;
|
|
int64_t aX1 = (int64_t)gDwm.Dirty.X + gDwm.Dirty.W;
|
|
int64_t aY1 = (int64_t)gDwm.Dirty.Y + gDwm.Dirty.H;
|
|
int64_t bX1 = (int64_t)clipped.X + clipped.W;
|
|
int64_t bY1 = (int64_t)clipped.Y + clipped.H;
|
|
int32_t x1 = (int32_t)(aX1 > bX1 ? aX1 : bX1);
|
|
int32_t y1 = (int32_t)(aY1 > bY1 ? aY1 : bY1);
|
|
gDwm.Dirty.X = x0;
|
|
gDwm.Dirty.Y = y0;
|
|
gDwm.Dirty.W = x1 - x0;
|
|
gDwm.Dirty.H = y1 - y0;
|
|
}
|
|
(void)SysSignalEvent(gDwm.DirtyEvent);
|
|
}
|
|
|
|
// Finds one connection-owned window while the DWM mutex is held.
|
|
static DWM_WINDOW* DwmFindOwnedWindowLocked(DWM_CLIENT* client, NTL_WINDOW_ID id) {
|
|
if (!client || id == 0) return (DWM_WINDOW*)0;
|
|
for (DWM_WINDOW* window = gDwm.Bottom; window; window = window->Higher)
|
|
if (window->Id == id && window->Owner == client && !window->Destroying) return window;
|
|
return (DWM_WINDOW*)0;
|
|
}
|
|
|
|
// Returns the topmost visible window containing one screen-space point.
|
|
static DWM_WINDOW* DwmHitTestLocked(int32_t x, int32_t y) {
|
|
for (DWM_WINDOW* window = gDwm.Top; window; window = window->Lower) {
|
|
if (!window->Visible || window->Destroying) continue;
|
|
int64_t right = (int64_t)window->Bounds.X + window->Bounds.W;
|
|
int64_t bottom = (int64_t)window->Bounds.Y + window->Bounds.H;
|
|
if ((int64_t)x >= window->Bounds.X && (int64_t)x < right &&
|
|
(int64_t)y >= window->Bounds.Y && (int64_t)y < bottom)
|
|
return window;
|
|
}
|
|
return (DWM_WINDOW*)0;
|
|
}
|
|
|
|
// Removes one window from the z-order while the DWM mutex is held.
|
|
static void DwmUnlinkWindowLocked(DWM_WINDOW* window) {
|
|
if (!window) return;
|
|
if (window->Lower) window->Lower->Higher = window->Higher;
|
|
else if (gDwm.Bottom == window) gDwm.Bottom = window->Higher;
|
|
if (window->Higher) window->Higher->Lower = window->Lower;
|
|
else if (gDwm.Top == window) gDwm.Top = window->Lower;
|
|
window->Lower = (DWM_WINDOW*)0;
|
|
window->Higher = (DWM_WINDOW*)0;
|
|
}
|
|
|
|
// Inserts one window at the top of the z-order while the DWM mutex is held.
|
|
static void DwmLinkTopLocked(DWM_WINDOW* window) {
|
|
if (!window) return;
|
|
window->Lower = gDwm.Top;
|
|
window->Higher = (DWM_WINDOW*)0;
|
|
if (gDwm.Top) gDwm.Top->Higher = window;
|
|
else gDwm.Bottom = window;
|
|
gDwm.Top = window;
|
|
}
|
|
|
|
// Inserts one window at the bottom of the z-order while the DWM mutex is held.
|
|
static void DwmLinkBottomLocked(DWM_WINDOW* window) {
|
|
if (!window) return;
|
|
window->Lower = (DWM_WINDOW*)0;
|
|
window->Higher = gDwm.Bottom;
|
|
if (gDwm.Bottom) gDwm.Bottom->Lower = window;
|
|
else gDwm.Top = window;
|
|
gDwm.Bottom = window;
|
|
}
|
|
|
|
// Sends one private focus/capture transition request to RSSRV.
|
|
static KSTATUS DwmSetSessionAuthority(uint32_t operation, bool enabled) {
|
|
if (gDwm.SessionEndpoint == SYS_HANDLE_INVALID) return NTLSTATUS_INVALID_HANDLE;
|
|
NTL_SESSION_DWM_REQUEST request;
|
|
memset(&request, 0, sizeof(request));
|
|
request.Size = sizeof(request);
|
|
request.Version = NTL_SESSION_DWM_PROTOCOL_VERSION;
|
|
request.Operation = operation;
|
|
request.Flags = NTL_SESSION_DWM_FLAG_NONE;
|
|
request.Enabled = enabled ? 1u : 0u;
|
|
|
|
NTL_SESSION_DWM_REPLY reply;
|
|
memset(&reply, 0, sizeof(reply));
|
|
SYS_PORT_MESSAGE_INFO info;
|
|
memset(&info, 0, sizeof(info));
|
|
info.Size = sizeof(info);
|
|
SYS_CALL_PORT_REQUEST call;
|
|
memset(&call, 0, sizeof(call));
|
|
call.Size = sizeof(call);
|
|
call.EndpointHandle = gDwm.SessionEndpoint;
|
|
call.Flags = SYS_PORT_FLAG_NONE;
|
|
call.RequestPayload = &request;
|
|
call.RequestLength = sizeof(request);
|
|
call.ReplyPayload = &reply;
|
|
call.ReplyCapacity = sizeof(reply);
|
|
call.ReplyInfoOut = &info;
|
|
call.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
|
|
KSTATUS status = SysCallPort(&call);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (info.Type != SYS_PORT_MESSAGE_REPLY || info.HandleCount != 0 || info.PayloadLength != sizeof(reply) ||
|
|
reply.Size != sizeof(reply) || reply.Version != NTL_SESSION_DWM_PROTOCOL_VERSION ||
|
|
reply.Operation != operation || reply.Flags != NTL_SESSION_DWM_FLAG_NONE)
|
|
return NTLSTATUS_FAILURE;
|
|
return reply.Status;
|
|
}
|
|
|
|
// Changes the internal focused window only after RSSRV accepts desktop keyboard focus.
|
|
static KSTATUS DwmFocusWindowLocked(DWM_WINDOW* window) {
|
|
if (!window || !window->Visible || window->Destroying) return NTLSTATUS_INVALID_PARAMETER;
|
|
if (gDwm.Focused == window) return NTLSTATUS_SUCCESS;
|
|
KSTATUS status = DwmSetSessionAuthority(NTL_SESSION_DWM_OP_SET_KEYBOARD_FOCUS, true);
|
|
if (!KSUCCESS(status)) return status;
|
|
DWM_WINDOW* previous = gDwm.Focused;
|
|
gDwm.Focused = window;
|
|
if (previous) DwmDirtyLocked(&previous->Bounds);
|
|
DwmDirtyLocked(&window->Bounds);
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Releases RSSRV keyboard focus only when DWM currently owns it through this focused window.
|
|
static void DwmReleaseFocusLocked(DWM_WINDOW* window) {
|
|
if (!window || gDwm.Focused != window) return;
|
|
(void)DwmSetSessionAuthority(NTL_SESSION_DWM_OP_SET_KEYBOARD_FOCUS, false);
|
|
gDwm.Focused = (DWM_WINDOW*)0;
|
|
DwmDirtyLocked(&window->Bounds);
|
|
}
|
|
|
|
// Updates the desktop pointer-focus grant to match DWM hit testing.
|
|
static void DwmSetPointerWindowLocked(DWM_WINDOW* window) {
|
|
if (gDwm.Captured) return;
|
|
if (gDwm.PointerWindow == window) return;
|
|
bool enable = window != (DWM_WINDOW*)0;
|
|
if (!KSUCCESS(DwmSetSessionAuthority(NTL_SESSION_DWM_OP_SET_POINTER_FOCUS, enable))) return;
|
|
gDwm.PointerWindow = window;
|
|
}
|
|
|
|
// Acquires RSSRV pointer capture for one DWM window.
|
|
static KSTATUS DwmCaptureWindowLocked(DWM_WINDOW* window) {
|
|
if (!window || !window->Visible || window->Destroying) return NTLSTATUS_INVALID_PARAMETER;
|
|
if (gDwm.Captured == window) return NTLSTATUS_SUCCESS;
|
|
KSTATUS status = DwmSetSessionAuthority(NTL_SESSION_DWM_OP_SET_POINTER_CAPTURE, true);
|
|
if (!KSUCCESS(status)) return status;
|
|
gDwm.Captured = window;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Releases RSSRV pointer capture only when the supplied window owns it.
|
|
static KSTATUS DwmReleaseCaptureLocked(DWM_WINDOW* window) {
|
|
if (!window || gDwm.Captured != window) return NTLSTATUS_ACCESS_DENIED;
|
|
KSTATUS status = DwmSetSessionAuthority(NTL_SESSION_DWM_OP_SET_POINTER_CAPTURE, false);
|
|
if (!KSUCCESS(status)) return status;
|
|
gDwm.Captured = (DWM_WINDOW*)0;
|
|
DWM_WINDOW* hit = DwmHitTestLocked(gDwm.PointerX, gDwm.PointerY);
|
|
DwmSetPointerWindowLocked(hit);
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Resolves the currently authorized visible cursor policy while the DWM mutex is held.
|
|
static void DwmResolveCursorLocked(int32_t* xOut, int32_t* yOut, bool* visibleOut) {
|
|
int32_t x = gDwm.PointerX;
|
|
int32_t y = gDwm.PointerY;
|
|
DWM_WINDOW* policyWindow = gDwm.Captured ? gDwm.Captured : gDwm.Focused;
|
|
uint32_t mode = policyWindow ? policyWindow->PointerMode : NTL_DESKTOP_POINTER_FREE;
|
|
|
|
if (policyWindow && mode == NTL_DESKTOP_POINTER_RELATIVE_LOCKED) {
|
|
x = policyWindow->Bounds.X + policyWindow->Bounds.W / 2;
|
|
y = policyWindow->Bounds.Y + policyWindow->Bounds.H / 2;
|
|
} else if (policyWindow && mode == NTL_DESKTOP_POINTER_CONFINED) {
|
|
int64_t right = (int64_t)policyWindow->Bounds.X + policyWindow->Bounds.W;
|
|
int64_t bottom = (int64_t)policyWindow->Bounds.Y + policyWindow->Bounds.H;
|
|
if (x < policyWindow->Bounds.X) x = policyWindow->Bounds.X;
|
|
if (y < policyWindow->Bounds.Y) y = policyWindow->Bounds.Y;
|
|
if ((int64_t)x >= right) x = (int32_t)(right - 1);
|
|
if ((int64_t)y >= bottom) y = (int32_t)(bottom - 1);
|
|
}
|
|
|
|
if (x < 0) x = 0;
|
|
if (y < 0) y = 0;
|
|
if (x >= gDwm.Width) x = gDwm.Width - 1;
|
|
if (y >= gDwm.Height) y = gDwm.Height - 1;
|
|
*xOut = x;
|
|
*yOut = y;
|
|
*visibleOut = mode != NTL_DESKTOP_POINTER_RELATIVE_LOCKED;
|
|
}
|
|
|
|
// Applies the currently resolved visible cursor state through DWM's DisplayManager capability.
|
|
static void DwmApplyCursorLocked(void) {
|
|
int32_t x = 0;
|
|
int32_t y = 0;
|
|
bool visible = true;
|
|
DwmResolveCursorLocked(&x, &y, &visible);
|
|
|
|
SYS_DISPLAY_MANAGER_CURSOR_REQUEST request;
|
|
memset(&request, 0, sizeof(request));
|
|
request.Size = sizeof(request);
|
|
request.ManagerHandle = gDwm.DisplayManager;
|
|
request.Flags = SYS_DISPLAY_MANAGER_CURSOR_FLAG_NONE;
|
|
if ((visible ? 1u : 0u) != gDwm.CursorVisible)
|
|
request.Flags = visible ? SYS_DISPLAY_MANAGER_CURSOR_FLAG_SHOW : SYS_DISPLAY_MANAGER_CURSOR_FLAG_HIDE;
|
|
request.X = x;
|
|
request.Y = y;
|
|
if (KSUCCESS(SysSetDisplayManagerCursor(&request))) gDwm.CursorVisible = visible ? 1u : 0u;
|
|
}
|
|
|
|
// Sends one nonblocking desktop input event while the DWM mutex keeps client/window lifetime stable.
|
|
static void DwmSendClientEventLocked(DWM_WINDOW* window,
|
|
uint32_t type,
|
|
const NTL_SESSION_DWM_EVENT* source) {
|
|
if (!window || !window->Owner || window->Owner->Endpoint == SYS_HANDLE_INVALID || !source) return;
|
|
NTL_DESKTOP_EVENT event;
|
|
memset(&event, 0, sizeof(event));
|
|
event.Size = sizeof(event);
|
|
event.Version = NTL_DESKTOP_PROTOCOL_VERSION;
|
|
event.Type = type;
|
|
event.Flags = NTL_DESKTOP_FLAG_NONE;
|
|
event.WindowId = window->Id;
|
|
event.PointerX = source->PointerX - window->Bounds.X;
|
|
event.PointerY = source->PointerY - window->Bounds.Y;
|
|
event.Key = source->Key;
|
|
event.Mouse = source->Mouse;
|
|
|
|
SYS_SEND_PORT_REQUEST send;
|
|
memset(&send, 0, sizeof(send));
|
|
send.Size = sizeof(send);
|
|
send.EndpointHandle = window->Owner->Endpoint;
|
|
send.Flags = SYS_PORT_FLAG_NONE;
|
|
send.Payload = &event;
|
|
send.PayloadLength = sizeof(event);
|
|
send.TimeoutMilliseconds = 0;
|
|
(void)SysSendPort(&send);
|
|
}
|
|
|
|
// Observes logical pointer motion for hit testing, click-to-focus, z-order, and visible cursor policy.
|
|
static void DwmObserveMouseLocked(const NTL_SESSION_DWM_EVENT* event) {
|
|
if (!event) return;
|
|
uint32_t previousButtons = gDwm.PointerButtons;
|
|
gDwm.PointerX = event->PointerX;
|
|
gDwm.PointerY = event->PointerY;
|
|
gDwm.PointerButtons = event->Mouse.buttons;
|
|
|
|
DWM_WINDOW* hit = gDwm.Captured ? gDwm.Captured : DwmHitTestLocked(gDwm.PointerX, gDwm.PointerY);
|
|
if (!gDwm.Captured) DwmSetPointerWindowLocked(hit);
|
|
|
|
uint32_t pressed = event->Mouse.buttons & ~previousButtons;
|
|
if (pressed && hit && hit->Visible) {
|
|
if (hit != gDwm.Top) {
|
|
DwmDirtyLocked(&hit->Bounds);
|
|
DwmUnlinkWindowLocked(hit);
|
|
DwmLinkTopLocked(hit);
|
|
DwmDirtyLocked(&hit->Bounds);
|
|
}
|
|
(void)DwmFocusWindowLocked(hit);
|
|
}
|
|
DwmApplyCursorLocked();
|
|
}
|
|
|
|
// Consumes RSSRV observer/delivery notifications and translates desktop-routed input to client windows.
|
|
static void DwmSessionInputThread(uintptr_t argument) {
|
|
(void)argument;
|
|
DwmSetCurrentThreadName("dwm.session.input");
|
|
|
|
while (gDwm.Running) {
|
|
NTL_SESSION_DWM_EVENT event;
|
|
SYS_PORT_MESSAGE_INFO info;
|
|
memset(&event, 0, sizeof(event));
|
|
memset(&info, 0, sizeof(info));
|
|
info.Size = sizeof(info);
|
|
SYS_RECEIVE_PORT_REQUEST receive;
|
|
memset(&receive, 0, sizeof(receive));
|
|
receive.Size = sizeof(receive);
|
|
receive.EndpointHandle = gDwm.SessionEndpoint;
|
|
receive.Flags = SYS_PORT_FLAG_NONE;
|
|
receive.Payload = &event;
|
|
receive.PayloadCapacity = sizeof(event);
|
|
receive.InfoOut = &info;
|
|
receive.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
|
|
KSTATUS status = SysReceivePort(&receive);
|
|
if (status == NTLSTATUS_PORT_DISCONNECTED || !KSUCCESS(status)) break;
|
|
if (info.Type != SYS_PORT_MESSAGE_NOTIFICATION || info.HandleCount != 0 ||
|
|
info.PayloadLength != sizeof(event) || event.Size != sizeof(event) ||
|
|
event.Version != NTL_SESSION_DWM_PROTOCOL_VERSION || event.Flags != NTL_SESSION_DWM_FLAG_NONE)
|
|
continue;
|
|
|
|
if (!KSUCCESS(DwmLock())) continue;
|
|
if (event.Type == NTL_SESSION_DWM_EVENT_OBSERVE_MOUSE) {
|
|
DwmObserveMouseLocked(&event);
|
|
} else if (event.Type == NTL_SESSION_DWM_EVENT_DELIVER_KEY) {
|
|
if (gDwm.Focused) DwmSendClientEventLocked(gDwm.Focused, NTL_DESKTOP_EVENT_KEY, &event);
|
|
} else if (event.Type == NTL_SESSION_DWM_EVENT_DELIVER_MOUSE) {
|
|
DWM_WINDOW* target = gDwm.Captured ? gDwm.Captured : gDwm.PointerWindow;
|
|
if (target) DwmSendClientEventLocked(target, NTL_DESKTOP_EVENT_MOUSE, &event);
|
|
}
|
|
DwmUnlock();
|
|
}
|
|
SysExitThread(0);
|
|
}
|
|
|
|
// Fills one composition rectangle with one XRGB color.
|
|
static void DwmFillCompositionRect(const DISPLAY_RECT* rect, uint32_t color) {
|
|
DISPLAY_RECT clipped;
|
|
if (!DwmClipScreenRect(rect, &clipped)) return;
|
|
uint8_t* base = (uint8_t*)gDwm.CompositionBase;
|
|
for (int32_t y = 0; y < clipped.H; ++y) {
|
|
uint32_t* row = (uint32_t*)(base + (size_t)(clipped.Y + y) * gDwm.CompositionPitch) + clipped.X;
|
|
for (int32_t x = 0; x < clipped.W; ++x) row[x] = color;
|
|
}
|
|
}
|
|
|
|
// Draws the dirty pieces of one one-pixel window border.
|
|
static void DwmDrawWindowBorder(const DWM_WINDOW* window, const DISPLAY_RECT* dirty, uint32_t color) {
|
|
if (!window || !dirty || window->Bounds.W <= 0 || window->Bounds.H <= 0) return;
|
|
DISPLAY_RECT edges[4] = {
|
|
{ window->Bounds.X, window->Bounds.Y, window->Bounds.W, 1 },
|
|
{ window->Bounds.X, window->Bounds.Y + window->Bounds.H - 1, window->Bounds.W, 1 },
|
|
{ window->Bounds.X, window->Bounds.Y, 1, window->Bounds.H },
|
|
{ window->Bounds.X + window->Bounds.W - 1, window->Bounds.Y, 1, window->Bounds.H }
|
|
};
|
|
for (uint32_t i = 0; i < 4u; ++i) {
|
|
DISPLAY_RECT clipped;
|
|
if (DwmIntersectRect(&edges[i], dirty, &clipped)) DwmFillCompositionRect(&clipped, color);
|
|
}
|
|
}
|
|
|
|
// Copies the visible portion of one client surface into the full-screen composition surface.
|
|
static void DwmCopyWindowSurface(const DWM_WINDOW* window, const DISPLAY_RECT* dirty) {
|
|
if (!window || !dirty || !window->Surface || !window->Surface->Base) return;
|
|
DISPLAY_RECT overlap;
|
|
if (!DwmIntersectRect(&window->Bounds, dirty, &overlap)) return;
|
|
|
|
int32_t sx = overlap.X - window->Bounds.X;
|
|
int32_t sy = overlap.Y - window->Bounds.Y;
|
|
int32_t width = overlap.W;
|
|
int32_t height = overlap.H;
|
|
if (sx < 0 || sy < 0) return;
|
|
if ((uint32_t)sx >= window->Surface->Desc.Width || (uint32_t)sy >= window->Surface->Desc.Height) return;
|
|
if ((uint64_t)(uint32_t)sx + (uint32_t)width > window->Surface->Desc.Width)
|
|
width = (int32_t)(window->Surface->Desc.Width - (uint32_t)sx);
|
|
if ((uint64_t)(uint32_t)sy + (uint32_t)height > window->Surface->Desc.Height)
|
|
height = (int32_t)(window->Surface->Desc.Height - (uint32_t)sy);
|
|
if (width <= 0 || height <= 0) return;
|
|
|
|
uint8_t* destinationBase = (uint8_t*)gDwm.CompositionBase;
|
|
const uint8_t* sourceBase = (const uint8_t*)window->Surface->Base;
|
|
for (int32_t y = 0; y < height; ++y) {
|
|
uint32_t* destination = (uint32_t*)(destinationBase +
|
|
(size_t)(overlap.Y + y) * gDwm.CompositionPitch) + overlap.X;
|
|
const uint32_t* source = (const uint32_t*)(sourceBase +
|
|
(size_t)(sy + y) * window->Surface->Desc.PitchBytes) + sx;
|
|
memcpy(destination, source, (size_t)width * sizeof(uint32_t));
|
|
}
|
|
}
|
|
|
|
// Rebuilds one dirty screen-space rectangle from bottom to top while the DWM mutex is held.
|
|
static void DwmComposeLocked(const DISPLAY_RECT* dirty) {
|
|
if (!dirty) return;
|
|
DwmFillCompositionRect(dirty, DWM_DESKTOP_COLOR);
|
|
for (DWM_WINDOW* window = gDwm.Bottom; window; window = window->Higher) {
|
|
if (!window->Visible || window->Destroying) continue;
|
|
DISPLAY_RECT overlap;
|
|
if (!DwmIntersectRect(&window->Bounds, dirty, &overlap)) continue;
|
|
DwmFillCompositionRect(&overlap, DWM_WINDOW_COLOR);
|
|
DwmCopyWindowSurface(window, dirty);
|
|
DwmDrawWindowBorder(window, dirty, window == gDwm.Focused ? DWM_FOCUS_BORDER_COLOR : DWM_BORDER_COLOR);
|
|
}
|
|
}
|
|
|
|
// Rebuilds and physically presents dirty regions from DWM's private composition surface.
|
|
static void DwmCompositorThread(uintptr_t argument) {
|
|
(void)argument;
|
|
DwmSetCurrentThreadName("dwm.compositor");
|
|
while (gDwm.Running) {
|
|
KSTATUS status = SysWait(gDwm.DirtyEvent, SYS_WAIT_FLAG_NONE);
|
|
if (!KSUCCESS(status) || !gDwm.Running) break;
|
|
|
|
DISPLAY_RECT dirty;
|
|
memset(&dirty, 0, sizeof(dirty));
|
|
if (!KSUCCESS(DwmLock())) continue;
|
|
if (!gDwm.DirtyValid) {
|
|
DwmUnlock();
|
|
continue;
|
|
}
|
|
dirty = gDwm.Dirty;
|
|
gDwm.DirtyValid = 0;
|
|
memset(&gDwm.Dirty, 0, sizeof(gDwm.Dirty));
|
|
DwmComposeLocked(&dirty);
|
|
DwmUnlock();
|
|
|
|
(void)SysCommitSurface(gDwm.CompositionSurface, &dirty, 1u, 0);
|
|
(void)SysPresentDisplayManagerSurface(gDwm.DisplayManager, gDwm.CompositionSurface, &dirty, 1u);
|
|
}
|
|
SysExitThread(0);
|
|
}
|
|
|
|
// Waits for client commits and converts them into coarse window-sized compositor damage.
|
|
static void DwmSurfaceWatcherThread(uintptr_t argument) {
|
|
DWM_SURFACE_BINDING* binding = (DWM_SURFACE_BINDING*)argument;
|
|
DwmSetCurrentThreadName("dwm.surface.watch");
|
|
if (!binding) SysExitThread(1);
|
|
|
|
SYS_HANDLE waits[2] = { binding->Surface, binding->StopEvent };
|
|
for (;;) {
|
|
uint32_t signaled = 0;
|
|
SYS_WAIT_MANY_REQUEST wait;
|
|
memset(&wait, 0, sizeof(wait));
|
|
wait.Size = sizeof(wait);
|
|
wait.Flags = SYS_WAIT_FLAG_NONE;
|
|
wait.Handles = waits;
|
|
wait.Count = 2u;
|
|
wait.SignaledIndexOut = &signaled;
|
|
wait.TimeoutMilliseconds = SYS_WAIT_TIMEOUT_INFINITE;
|
|
KSTATUS status = SysWaitMany(&wait);
|
|
if (!KSUCCESS(status) || signaled == 1u) break;
|
|
if (signaled != 0u) continue;
|
|
|
|
if (!KSUCCESS(DwmLock())) continue;
|
|
if (binding->Window && !binding->Window->Destroying && binding->Window->Surface == binding)
|
|
DwmDirtyLocked(&binding->Window->Bounds);
|
|
DwmUnlock();
|
|
}
|
|
SysExitThread(0);
|
|
}
|
|
|
|
// Tears down one detached surface binding after it is no longer reachable from a window.
|
|
static void DwmStopSurfaceBinding(DWM_SURFACE_BINDING* binding) {
|
|
if (!binding) return;
|
|
if (binding->StopEvent != SYS_HANDLE_INVALID) (void)SysSignalEvent(binding->StopEvent);
|
|
if (binding->Thread != SYS_HANDLE_INVALID) {
|
|
(void)SysWait(binding->Thread, SYS_WAIT_FLAG_NONE);
|
|
(void)SysCloseHandle(binding->Thread);
|
|
}
|
|
if (binding->Base) (void)SysUnmapSurface(binding->Base);
|
|
if (binding->StopEvent != SYS_HANDLE_INVALID) (void)SysCloseHandle(binding->StopEvent);
|
|
if (binding->Surface != SYS_HANDLE_INVALID) (void)SysCloseHandle(binding->Surface);
|
|
free(binding);
|
|
}
|
|
|
|
// Creates a read-only DWM mapping around one transferred client surface capability.
|
|
static KSTATUS DwmCreateSurfaceBinding(DWM_WINDOW* window,
|
|
SYS_HANDLE surface,
|
|
DWM_SURFACE_BINDING** bindingOut) {
|
|
if (!window || surface == SYS_HANDLE_INVALID || !bindingOut) return NTLSTATUS_INVALID_PARAMETER;
|
|
*bindingOut = (DWM_SURFACE_BINDING*)0;
|
|
|
|
DWM_SURFACE_BINDING* binding = (DWM_SURFACE_BINDING*)malloc(sizeof(*binding));
|
|
if (!binding) {
|
|
(void)SysCloseHandle(surface);
|
|
return NTLSTATUS_NO_MEMORY;
|
|
}
|
|
memset(binding, 0, sizeof(*binding));
|
|
binding->Window = window;
|
|
binding->Surface = surface;
|
|
binding->StopEvent = SYS_HANDLE_INVALID;
|
|
binding->Thread = SYS_HANDLE_INVALID;
|
|
|
|
KSTATUS status = SysQuerySurface(surface, &binding->Desc);
|
|
if (!KSUCCESS(status) || binding->Desc.Format != SYS_SURFACE_FORMAT_XRGB8888 ||
|
|
binding->Desc.Width == 0 || binding->Desc.Height == 0) {
|
|
DwmStopSurfaceBinding(binding);
|
|
return KSUCCESS(status) ? NTLSTATUS_NOT_SUPPORTED : status;
|
|
}
|
|
uint32_t pitch = 0;
|
|
status = SysMapSurface(surface, SYS_SURFACE_MAP_READ, &binding->Base, &pitch);
|
|
if (!KSUCCESS(status)) {
|
|
DwmStopSurfaceBinding(binding);
|
|
return status;
|
|
}
|
|
if (pitch != binding->Desc.PitchBytes) {
|
|
DwmStopSurfaceBinding(binding);
|
|
return NTLSTATUS_FAILURE;
|
|
}
|
|
status = SysCreateEvent(DWM_EVENT_AUTO_RESET, 0u, &binding->StopEvent);
|
|
if (!KSUCCESS(status)) {
|
|
DwmStopSurfaceBinding(binding);
|
|
return status;
|
|
}
|
|
*bindingOut = binding;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Starts one prepared surface watcher after the binding has been installed into its window.
|
|
static KSTATUS DwmStartSurfaceBinding(DWM_SURFACE_BINDING* binding) {
|
|
if (!binding || !binding->Window) return NTLSTATUS_INVALID_PARAMETER;
|
|
SYS_CREATE_THREAD_REQUEST create;
|
|
memset(&create, 0, sizeof(create));
|
|
create.Size = sizeof(create);
|
|
create.Entry = (uintptr_t)DwmSurfaceWatcherThread;
|
|
create.Argument = (uintptr_t)binding;
|
|
create.Priority = 1u;
|
|
create.Flags = SYS_CREATE_THREAD_FLAG_NONE;
|
|
create.ThreadHandleOut = &binding->Thread;
|
|
return SysCreateThread(&create);
|
|
}
|
|
|
|
// Validates one top-level window rectangle without requiring it to remain fully on-screen.
|
|
static KSTATUS DwmValidateWindowBounds(const DISPLAY_RECT* bounds) {
|
|
if (!bounds || bounds->W <= 0 || bounds->H <= 0 ||
|
|
(uint32_t)bounds->W > SYS_SURFACE_MAX_DIMENSION || (uint32_t)bounds->H > SYS_SURFACE_MAX_DIMENSION)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Copies current window state into one desktop reply while the DWM mutex is held.
|
|
static void DwmFillWindowReplyLocked(const DWM_WINDOW* window, NTL_DESKTOP_REPLY* reply) {
|
|
if (!window || !reply) return;
|
|
reply->WindowId = window->Id;
|
|
reply->Bounds = window->Bounds;
|
|
reply->Visible = window->Visible;
|
|
reply->Focused = gDwm.Focused == window ? 1u : 0u;
|
|
reply->Captured = gDwm.Captured == window ? 1u : 0u;
|
|
reply->HasSurface = window->Surface ? 1u : 0u;
|
|
if (window->Surface) {
|
|
reply->SurfaceWidth = window->Surface->Desc.Width;
|
|
reply->SurfaceHeight = window->Surface->Desc.Height;
|
|
}
|
|
}
|
|
|
|
// Destroys one connection-owned window and returns its detached binding for blocking teardown outside the mutex.
|
|
static DWM_SURFACE_BINDING* DwmDestroyWindowLocked(DWM_WINDOW* window) {
|
|
if (!window || window->Destroying) return (DWM_SURFACE_BINDING*)0;
|
|
window->Destroying = 1u;
|
|
DwmDirtyLocked(&window->Bounds);
|
|
if (gDwm.Focused == window) DwmReleaseFocusLocked(window);
|
|
if (gDwm.Captured == window) (void)DwmReleaseCaptureLocked(window);
|
|
if (gDwm.PointerWindow == window) {
|
|
gDwm.PointerWindow = (DWM_WINDOW*)0;
|
|
(void)DwmSetSessionAuthority(NTL_SESSION_DWM_OP_SET_POINTER_FOCUS, false);
|
|
}
|
|
DwmUnlinkWindowLocked(window);
|
|
if (window->Owner && window->Owner->WindowCount) window->Owner->WindowCount--;
|
|
if (gDwm.WindowCount) gDwm.WindowCount--;
|
|
DWM_SURFACE_BINDING* binding = window->Surface;
|
|
window->Surface = (DWM_SURFACE_BINDING*)0;
|
|
if (!gDwm.Captured) {
|
|
DWM_WINDOW* hit = DwmHitTestLocked(gDwm.PointerX, gDwm.PointerY);
|
|
DwmSetPointerWindowLocked(hit);
|
|
}
|
|
return binding;
|
|
}
|
|
|
|
// Handles one validated desktop request and owns any transferred surface handle supplied with it.
|
|
static KSTATUS DwmHandleDesktopRequest(DWM_CLIENT* client,
|
|
const NTL_DESKTOP_REQUEST* request,
|
|
SYS_HANDLE transferredHandle,
|
|
NTL_DESKTOP_REPLY* reply) {
|
|
if (!client || !request || !reply) {
|
|
if (transferredHandle != SYS_HANDLE_INVALID) (void)SysCloseHandle(transferredHandle);
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
KSTATUS status = NTLSTATUS_SUCCESS;
|
|
DWM_SURFACE_BINDING* detached = (DWM_SURFACE_BINDING*)0;
|
|
DWM_WINDOW* freeWindow = (DWM_WINDOW*)0;
|
|
|
|
if (request->Operation == NTL_DESKTOP_OP_ATTACH_SURFACE) {
|
|
DWM_WINDOW* window = (DWM_WINDOW*)0;
|
|
if (!KSUCCESS(DwmLock())) {
|
|
(void)SysCloseHandle(transferredHandle);
|
|
return NTLSTATUS_FAILURE;
|
|
}
|
|
window = DwmFindOwnedWindowLocked(client, request->WindowId);
|
|
DwmUnlock();
|
|
if (!window) {
|
|
(void)SysCloseHandle(transferredHandle);
|
|
return NTLSTATUS_NOT_FOUND;
|
|
}
|
|
|
|
DWM_SURFACE_BINDING* binding = (DWM_SURFACE_BINDING*)0;
|
|
status = DwmCreateSurfaceBinding(window, transferredHandle, &binding);
|
|
if (!KSUCCESS(status)) return status;
|
|
|
|
status = DwmLock();
|
|
if (!KSUCCESS(status)) {
|
|
DwmStopSurfaceBinding(binding);
|
|
return status;
|
|
}
|
|
if (window->Destroying || window->Owner != client) {
|
|
DwmUnlock();
|
|
DwmStopSurfaceBinding(binding);
|
|
return NTLSTATUS_OBJECT_DEAD;
|
|
}
|
|
detached = window->Surface;
|
|
window->Surface = binding;
|
|
DwmDirtyLocked(&window->Bounds);
|
|
DwmFillWindowReplyLocked(window, reply);
|
|
DwmUnlock();
|
|
|
|
status = DwmStartSurfaceBinding(binding);
|
|
if (!KSUCCESS(status)) {
|
|
if (KSUCCESS(DwmLock())) {
|
|
if (window->Surface == binding) window->Surface = (DWM_SURFACE_BINDING*)0;
|
|
DwmDirtyLocked(&window->Bounds);
|
|
DwmUnlock();
|
|
}
|
|
DwmStopSurfaceBinding(binding);
|
|
}
|
|
if (detached) DwmStopSurfaceBinding(detached);
|
|
return status;
|
|
}
|
|
|
|
if (transferredHandle != SYS_HANDLE_INVALID) {
|
|
(void)SysCloseHandle(transferredHandle);
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
status = DwmLock();
|
|
if (!KSUCCESS(status)) return status;
|
|
DWM_WINDOW* window = request->WindowId ? DwmFindOwnedWindowLocked(client, request->WindowId) : (DWM_WINDOW*)0;
|
|
|
|
switch (request->Operation) {
|
|
case NTL_DESKTOP_OP_CREATE_WINDOW: {
|
|
status = DwmValidateWindowBounds(&request->Bounds);
|
|
if (!KSUCCESS(status)) break;
|
|
if (gDwm.WindowCount >= DWM_MAX_WINDOWS || client->WindowCount >= DWM_MAX_CLIENT_WINDOWS) {
|
|
status = NTLSTATUS_LIMIT_REACHED;
|
|
break;
|
|
}
|
|
window = (DWM_WINDOW*)malloc(sizeof(*window));
|
|
if (!window) {
|
|
status = NTLSTATUS_NO_MEMORY;
|
|
break;
|
|
}
|
|
memset(window, 0, sizeof(*window));
|
|
window->Owner = client;
|
|
window->Bounds = request->Bounds;
|
|
window->PointerMode = NTL_DESKTOP_POINTER_FREE;
|
|
window->Id = gDwm.NextWindowId++;
|
|
if (window->Id == 0) window->Id = gDwm.NextWindowId++;
|
|
DwmLinkTopLocked(window);
|
|
gDwm.WindowCount++;
|
|
client->WindowCount++;
|
|
DwmFillWindowReplyLocked(window, reply);
|
|
break;
|
|
}
|
|
case NTL_DESKTOP_OP_DESTROY_WINDOW:
|
|
if (!window) {
|
|
status = NTLSTATUS_NOT_FOUND;
|
|
break;
|
|
}
|
|
detached = DwmDestroyWindowLocked(window);
|
|
freeWindow = window;
|
|
break;
|
|
case NTL_DESKTOP_OP_SET_BOUNDS:
|
|
if (!window) {
|
|
status = NTLSTATUS_NOT_FOUND;
|
|
break;
|
|
}
|
|
status = DwmValidateWindowBounds(&request->Bounds);
|
|
if (!KSUCCESS(status)) break;
|
|
DwmDirtyLocked(&window->Bounds);
|
|
window->Bounds = request->Bounds;
|
|
DwmDirtyLocked(&window->Bounds);
|
|
if (!gDwm.Captured) DwmSetPointerWindowLocked(DwmHitTestLocked(gDwm.PointerX, gDwm.PointerY));
|
|
DwmApplyCursorLocked();
|
|
DwmFillWindowReplyLocked(window, reply);
|
|
break;
|
|
case NTL_DESKTOP_OP_SET_VISIBLE:
|
|
if (!window) {
|
|
status = NTLSTATUS_NOT_FOUND;
|
|
break;
|
|
}
|
|
if (request->Value > 1u) {
|
|
status = NTLSTATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
if (window->Visible != request->Value) {
|
|
DwmDirtyLocked(&window->Bounds);
|
|
window->Visible = request->Value;
|
|
if (!window->Visible) {
|
|
DwmReleaseFocusLocked(window);
|
|
if (gDwm.Captured == window) (void)DwmReleaseCaptureLocked(window);
|
|
if (gDwm.PointerWindow == window) {
|
|
gDwm.PointerWindow = (DWM_WINDOW*)0;
|
|
(void)DwmSetSessionAuthority(NTL_SESSION_DWM_OP_SET_POINTER_FOCUS, false);
|
|
}
|
|
}
|
|
if (!gDwm.Captured) DwmSetPointerWindowLocked(DwmHitTestLocked(gDwm.PointerX, gDwm.PointerY));
|
|
DwmApplyCursorLocked();
|
|
}
|
|
DwmFillWindowReplyLocked(window, reply);
|
|
break;
|
|
case NTL_DESKTOP_OP_RAISE_WINDOW:
|
|
if (!window) {
|
|
status = NTLSTATUS_NOT_FOUND;
|
|
break;
|
|
}
|
|
if (window != gDwm.Top) {
|
|
DwmDirtyLocked(&window->Bounds);
|
|
DwmUnlinkWindowLocked(window);
|
|
DwmLinkTopLocked(window);
|
|
DwmDirtyLocked(&window->Bounds);
|
|
}
|
|
DwmFillWindowReplyLocked(window, reply);
|
|
break;
|
|
case NTL_DESKTOP_OP_LOWER_WINDOW:
|
|
if (!window) {
|
|
status = NTLSTATUS_NOT_FOUND;
|
|
break;
|
|
}
|
|
if (window != gDwm.Bottom) {
|
|
DwmDirtyLocked(&window->Bounds);
|
|
DwmUnlinkWindowLocked(window);
|
|
DwmLinkBottomLocked(window);
|
|
DwmDirtyLocked(&window->Bounds);
|
|
}
|
|
DwmFillWindowReplyLocked(window, reply);
|
|
break;
|
|
case NTL_DESKTOP_OP_REQUEST_FOCUS:
|
|
if (!window) {
|
|
status = NTLSTATUS_NOT_FOUND;
|
|
break;
|
|
}
|
|
status = DwmFocusWindowLocked(window);
|
|
if (KSUCCESS(status)) DwmFillWindowReplyLocked(window, reply);
|
|
DwmApplyCursorLocked();
|
|
break;
|
|
case NTL_DESKTOP_OP_REQUEST_CAPTURE:
|
|
if (!window) {
|
|
status = NTLSTATUS_NOT_FOUND;
|
|
break;
|
|
}
|
|
status = DwmCaptureWindowLocked(window);
|
|
if (KSUCCESS(status)) DwmFillWindowReplyLocked(window, reply);
|
|
DwmApplyCursorLocked();
|
|
break;
|
|
case NTL_DESKTOP_OP_RELEASE_CAPTURE:
|
|
if (!window) {
|
|
status = NTLSTATUS_NOT_FOUND;
|
|
break;
|
|
}
|
|
status = DwmReleaseCaptureLocked(window);
|
|
if (KSUCCESS(status)) DwmFillWindowReplyLocked(window, reply);
|
|
DwmApplyCursorLocked();
|
|
break;
|
|
case NTL_DESKTOP_OP_SET_POINTER_MODE:
|
|
if (!window) {
|
|
status = NTLSTATUS_NOT_FOUND;
|
|
break;
|
|
}
|
|
if (request->Value > NTL_DESKTOP_POINTER_RELATIVE_LOCKED) {
|
|
status = NTLSTATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
if (gDwm.Focused != window && gDwm.Captured != window) {
|
|
status = NTLSTATUS_ACCESS_DENIED;
|
|
break;
|
|
}
|
|
window->PointerMode = request->Value;
|
|
DwmApplyCursorLocked();
|
|
DwmFillWindowReplyLocked(window, reply);
|
|
break;
|
|
case NTL_DESKTOP_OP_DETACH_SURFACE:
|
|
if (!window) {
|
|
status = NTLSTATUS_NOT_FOUND;
|
|
break;
|
|
}
|
|
detached = window->Surface;
|
|
window->Surface = (DWM_SURFACE_BINDING*)0;
|
|
DwmDirtyLocked(&window->Bounds);
|
|
DwmFillWindowReplyLocked(window, reply);
|
|
break;
|
|
case NTL_DESKTOP_OP_QUERY_WINDOW:
|
|
if (!window) {
|
|
status = NTLSTATUS_NOT_FOUND;
|
|
break;
|
|
}
|
|
DwmFillWindowReplyLocked(window, reply);
|
|
break;
|
|
default:
|
|
status = NTLSTATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
DwmUnlock();
|
|
if (detached) DwmStopSurfaceBinding(detached);
|
|
if (freeWindow) free(freeWindow);
|
|
return status;
|
|
}
|
|
|
|
// Sends one fixed desktop reply for a client request.
|
|
static void DwmReplyDesktop(SYS_HANDLE endpoint,
|
|
uint32_t messageId,
|
|
const NTL_DESKTOP_REQUEST* request,
|
|
KSTATUS status,
|
|
NTL_DESKTOP_REPLY* reply) {
|
|
if (!reply) return;
|
|
reply->Size = sizeof(*reply);
|
|
reply->Version = NTL_DESKTOP_PROTOCOL_VERSION;
|
|
reply->Operation = request ? request->Operation : 0u;
|
|
reply->Flags = NTL_DESKTOP_FLAG_NONE;
|
|
reply->Status = status;
|
|
|
|
SYS_REPLY_PORT_REQUEST send;
|
|
memset(&send, 0, sizeof(send));
|
|
send.Size = sizeof(send);
|
|
send.EndpointHandle = endpoint;
|
|
send.MessageId = messageId;
|
|
send.Flags = SYS_PORT_FLAG_NONE;
|
|
send.Payload = reply;
|
|
send.PayloadLength = sizeof(*reply);
|
|
(void)SysReplyPort(&send);
|
|
}
|
|
|
|
// Destroys every window owned by a disconnected client before releasing the client record.
|
|
static void DwmDestroyClientWindows(DWM_CLIENT* client) {
|
|
if (!client) return;
|
|
for (;;) {
|
|
DWM_WINDOW* window = (DWM_WINDOW*)0;
|
|
DWM_SURFACE_BINDING* binding = (DWM_SURFACE_BINDING*)0;
|
|
if (!KSUCCESS(DwmLock())) break;
|
|
for (DWM_WINDOW* candidate = gDwm.Bottom; candidate; candidate = candidate->Higher) {
|
|
if (candidate->Owner == client && !candidate->Destroying) {
|
|
window = candidate;
|
|
break;
|
|
}
|
|
}
|
|
if (window) binding = DwmDestroyWindowLocked(window);
|
|
DwmUnlock();
|
|
if (!window) break;
|
|
if (binding) DwmStopSurfaceBinding(binding);
|
|
free(window);
|
|
}
|
|
}
|
|
|
|
// Removes one client from the DWM client list while the DWM mutex is held.
|
|
static void DwmRemoveClientLocked(DWM_CLIENT* client) {
|
|
if (!client) return;
|
|
DWM_CLIENT** link = &gDwm.Clients;
|
|
while (*link) {
|
|
if (*link == client) {
|
|
*link = client->Next;
|
|
client->Next = (DWM_CLIENT*)0;
|
|
return;
|
|
}
|
|
link = &(*link)->Next;
|
|
}
|
|
}
|
|
|
|
// Serves one desktop client connection and enforces per-connection window ownership.
|
|
static void DwmClientThread(uintptr_t argument) {
|
|
DWM_CLIENT_THREAD_CONTEXT* context = (DWM_CLIENT_THREAD_CONTEXT*)argument;
|
|
DWM_CLIENT* client = context ? context->Client : (DWM_CLIENT*)0;
|
|
free(context);
|
|
DwmSetCurrentThreadName("dwm.client");
|
|
if (!client) SysExitThread(1);
|
|
|
|
while (gDwm.Running) {
|
|
NTL_DESKTOP_REQUEST request;
|
|
SYS_HANDLE handles[1] = { SYS_HANDLE_INVALID };
|
|
SYS_PORT_MESSAGE_INFO info;
|
|
memset(&request, 0, sizeof(request));
|
|
memset(&info, 0, sizeof(info));
|
|
info.Size = sizeof(info);
|
|
SYS_RECEIVE_PORT_REQUEST receive;
|
|
memset(&receive, 0, sizeof(receive));
|
|
receive.Size = sizeof(receive);
|
|
receive.EndpointHandle = client->Endpoint;
|
|
receive.Flags = SYS_PORT_FLAG_NONE;
|
|
receive.Payload = &request;
|
|
receive.PayloadCapacity = sizeof(request);
|
|
receive.HandlesOut = handles;
|
|
receive.HandleCapacity = 1u;
|
|
receive.InfoOut = &info;
|
|
receive.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
|
|
KSTATUS status = SysReceivePort(&receive);
|
|
if (status == NTLSTATUS_PORT_DISCONNECTED || !KSUCCESS(status)) break;
|
|
|
|
bool attach = request.Operation == NTL_DESKTOP_OP_ATTACH_SURFACE;
|
|
bool envelopeValid = info.Type == SYS_PORT_MESSAGE_REQUEST && info.PayloadLength == sizeof(request) &&
|
|
request.Size == sizeof(request) && request.Version == NTL_DESKTOP_PROTOCOL_VERSION &&
|
|
request.Flags == NTL_DESKTOP_FLAG_NONE && request.Reserved == 0 &&
|
|
info.HandleCount == (attach ? 1u : 0u);
|
|
NTL_DESKTOP_REPLY reply;
|
|
memset(&reply, 0, sizeof(reply));
|
|
if (!envelopeValid) {
|
|
if (info.HandleCount && handles[0] != SYS_HANDLE_INVALID) (void)SysCloseHandle(handles[0]);
|
|
DwmReplyDesktop(client->Endpoint, info.MessageId, &request, NTLSTATUS_INVALID_PARAMETER, &reply);
|
|
continue;
|
|
}
|
|
|
|
SYS_HANDLE transferred = attach ? handles[0] : SYS_HANDLE_INVALID;
|
|
status = DwmHandleDesktopRequest(client, &request, transferred, &reply);
|
|
DwmReplyDesktop(client->Endpoint, info.MessageId, &request, status, &reply);
|
|
}
|
|
|
|
DwmDestroyClientWindows(client);
|
|
if (KSUCCESS(DwmLock())) {
|
|
DwmRemoveClientLocked(client);
|
|
DwmUnlock();
|
|
}
|
|
(void)SysDisconnectPort(client->Endpoint);
|
|
(void)SysCloseHandle(client->Endpoint);
|
|
free(client);
|
|
SysExitThread(0);
|
|
}
|
|
|
|
// Accepts public desktop connections and gives each connection one policy worker.
|
|
static void DwmDesktopListenerThread(uintptr_t argument) {
|
|
(void)argument;
|
|
DwmSetCurrentThreadName("dwm.listen");
|
|
while (gDwm.Running) {
|
|
SYS_HANDLE endpoint = SYS_HANDLE_INVALID;
|
|
SYS_PORT_CONNECTION_INFO connection;
|
|
memset(&connection, 0, sizeof(connection));
|
|
connection.Size = sizeof(connection);
|
|
SYS_ACCEPT_PORT_REQUEST accept;
|
|
memset(&accept, 0, sizeof(accept));
|
|
accept.Size = sizeof(accept);
|
|
accept.ListenerHandle = gDwm.DesktopListener;
|
|
accept.Flags = SYS_PORT_ACCEPT_FLAG_NONE;
|
|
accept.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
|
|
accept.EndpointHandleOut = &endpoint;
|
|
accept.ConnectionInfoOut = &connection;
|
|
KSTATUS status = SysAcceptPort(&accept);
|
|
if (!KSUCCESS(status)) break;
|
|
|
|
DWM_CLIENT* client = (DWM_CLIENT*)malloc(sizeof(*client));
|
|
DWM_CLIENT_THREAD_CONTEXT* context = (DWM_CLIENT_THREAD_CONTEXT*)malloc(sizeof(*context));
|
|
if (!client || !context) {
|
|
free(client);
|
|
free(context);
|
|
(void)SysDisconnectPort(endpoint);
|
|
(void)SysCloseHandle(endpoint);
|
|
continue;
|
|
}
|
|
memset(client, 0, sizeof(*client));
|
|
client->Endpoint = endpoint;
|
|
client->ProcessId = connection.ClientProcessId;
|
|
context->Client = client;
|
|
|
|
status = DwmLock();
|
|
if (!KSUCCESS(status)) {
|
|
free(context);
|
|
free(client);
|
|
(void)SysDisconnectPort(endpoint);
|
|
(void)SysCloseHandle(endpoint);
|
|
continue;
|
|
}
|
|
client->Next = gDwm.Clients;
|
|
gDwm.Clients = client;
|
|
DwmUnlock();
|
|
|
|
SYS_CREATE_THREAD_REQUEST create;
|
|
memset(&create, 0, sizeof(create));
|
|
create.Size = sizeof(create);
|
|
create.Entry = (uintptr_t)DwmClientThread;
|
|
create.Argument = (uintptr_t)context;
|
|
create.Priority = 1u;
|
|
create.Flags = SYS_CREATE_THREAD_FLAG_NONE;
|
|
status = SysCreateThread(&create);
|
|
if (!KSUCCESS(status)) {
|
|
if (KSUCCESS(DwmLock())) {
|
|
DwmRemoveClientLocked(client);
|
|
DwmUnlock();
|
|
}
|
|
free(context);
|
|
free(client);
|
|
(void)SysDisconnectPort(endpoint);
|
|
(void)SysCloseHandle(endpoint);
|
|
}
|
|
}
|
|
SysExitThread(0);
|
|
}
|
|
|
|
// Accepts init's private service-control connection.
|
|
static KSTATUS DwmAcceptControl(SYS_HANDLE listener, SYS_HANDLE* endpointOut) {
|
|
if (listener == SYS_HANDLE_INVALID || !endpointOut) return NTLSTATUS_INVALID_PARAMETER;
|
|
SYS_ACCEPT_PORT_REQUEST accept;
|
|
memset(&accept, 0, sizeof(accept));
|
|
accept.Size = sizeof(accept);
|
|
accept.ListenerHandle = listener;
|
|
accept.Flags = SYS_PORT_ACCEPT_FLAG_NONE;
|
|
accept.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
|
|
accept.EndpointHandleOut = endpointOut;
|
|
return SysAcceptPort(&accept);
|
|
}
|
|
|
|
// Connects to RSSRV's init-delegated private Session 0 control listener.
|
|
static KSTATUS DwmConnectSession(SYS_HANDLE listener, SYS_HANDLE* endpointOut) {
|
|
if (listener == SYS_HANDLE_INVALID || !endpointOut) return NTLSTATUS_INVALID_PARAMETER;
|
|
SYS_CONNECT_PORT_REQUEST connect;
|
|
memset(&connect, 0, sizeof(connect));
|
|
connect.Size = sizeof(connect);
|
|
connect.ListenerHandle = listener;
|
|
connect.Flags = SYS_PORT_CONNECT_FLAG_NONE;
|
|
connect.EndpointHandleOut = endpointOut;
|
|
return SysConnectPort(&connect);
|
|
}
|
|
|
|
// Reports DWM readiness and delegates its public desktop listener to init for namespace publication.
|
|
static KSTATUS DwmSendReady(SYS_HANDLE endpoint, SYS_HANDLE desktopListener) {
|
|
if (endpoint == SYS_HANDLE_INVALID || desktopListener == SYS_HANDLE_INVALID)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
NTL_SERVICE_CONTROL_MESSAGE message;
|
|
memset(&message, 0, sizeof(message));
|
|
message.Size = sizeof(message);
|
|
message.Version = NTL_SERVICE_CONTROL_VERSION;
|
|
message.Operation = NTL_SERVICE_CONTROL_READY;
|
|
message.ExportCount = 1u;
|
|
message.Status = NTLSTATUS_SUCCESS;
|
|
|
|
SYS_PORT_HANDLE_TRANSFER transfer;
|
|
transfer.Handle = desktopListener;
|
|
transfer.DesiredRights = SYS_RIGHT_TRANSFER | SYS_RIGHT_QUERY | SYS_PORT_RIGHT_CONNECT;
|
|
transfer.Flags = SYS_PORT_TRANSFER_FLAG_NONE;
|
|
|
|
SYS_SEND_PORT_REQUEST send;
|
|
memset(&send, 0, sizeof(send));
|
|
send.Size = sizeof(send);
|
|
send.EndpointHandle = endpoint;
|
|
send.Flags = SYS_PORT_FLAG_NONE;
|
|
send.Payload = &message;
|
|
send.PayloadLength = sizeof(message);
|
|
send.Handles = &transfer;
|
|
send.HandleCount = 1u;
|
|
send.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
|
|
return SysSendPort(&send);
|
|
}
|
|
|
|
// Waits until init requests service stop or disconnects the private control port.
|
|
static void DwmControlLoop(SYS_HANDLE endpoint) {
|
|
for (;;) {
|
|
NTL_SERVICE_CONTROL_MESSAGE message;
|
|
SYS_PORT_MESSAGE_INFO info;
|
|
memset(&message, 0, sizeof(message));
|
|
memset(&info, 0, sizeof(info));
|
|
info.Size = sizeof(info);
|
|
|
|
SYS_RECEIVE_PORT_REQUEST receive;
|
|
memset(&receive, 0, sizeof(receive));
|
|
receive.Size = sizeof(receive);
|
|
receive.EndpointHandle = endpoint;
|
|
receive.Payload = &message;
|
|
receive.PayloadCapacity = sizeof(message);
|
|
receive.InfoOut = &info;
|
|
receive.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
|
|
KSTATUS status = SysReceivePort(&receive);
|
|
if (status == NTLSTATUS_PORT_DISCONNECTED || !KSUCCESS(status)) return;
|
|
if (info.Type != SYS_PORT_MESSAGE_NOTIFICATION || info.HandleCount != 0 ||
|
|
info.PayloadLength != sizeof(message) || message.Size != sizeof(message) ||
|
|
message.Version != NTL_SERVICE_CONTROL_VERSION || message.ExportCount != 0 ||
|
|
message.Reserved[0] != 0 || message.Reserved[1] != 0 || message.Reserved[2] != 0)
|
|
continue;
|
|
if (message.Operation == NTL_SERVICE_CONTROL_STOP) return;
|
|
}
|
|
}
|
|
|
|
// Creates DWM's private full-screen composition surface and CPU mapping.
|
|
static KSTATUS DwmCreateCompositionSurface(void) {
|
|
SYS_CREATE_SURFACE_REQUEST create;
|
|
memset(&create, 0, sizeof(create));
|
|
create.Size = sizeof(create);
|
|
create.Width = (uint32_t)gDwm.Width;
|
|
create.Height = (uint32_t)gDwm.Height;
|
|
create.Format = SYS_SURFACE_FORMAT_XRGB8888;
|
|
create.Flags = SYS_SURFACE_FLAG_NONE;
|
|
create.HandleOut = &gDwm.CompositionSurface;
|
|
KSTATUS status = SysCreateSurface(&create);
|
|
if (!KSUCCESS(status)) return status;
|
|
return SysMapSurface(gDwm.CompositionSurface, SYS_SURFACE_MAP_READ | SYS_SURFACE_MAP_WRITE,
|
|
&gDwm.CompositionBase, &gDwm.CompositionPitch);
|
|
}
|
|
|
|
// Creates the public desktop listener owned by this DWM instance.
|
|
static KSTATUS DwmCreateDesktopListener(void) {
|
|
SYS_CREATE_PORT_REQUEST create;
|
|
memset(&create, 0, sizeof(create));
|
|
create.Size = sizeof(create);
|
|
create.Flags = SYS_PORT_FLAG_NONE;
|
|
create.Backlog = DWM_DESKTOP_BACKLOG;
|
|
create.HandleOut = &gDwm.DesktopListener;
|
|
return SysCreatePort(&create);
|
|
}
|
|
|
|
// Starts one retained DWM worker and returns its waitable thread capability.
|
|
static KSTATUS DwmStartThread(uintptr_t entry, const char* name, SYS_HANDLE* threadOut) {
|
|
(void)name;
|
|
if (!entry || !threadOut) return NTLSTATUS_INVALID_PARAMETER;
|
|
*threadOut = SYS_HANDLE_INVALID;
|
|
SYS_CREATE_THREAD_REQUEST create;
|
|
memset(&create, 0, sizeof(create));
|
|
create.Size = sizeof(create);
|
|
create.Entry = entry;
|
|
create.Priority = 1u;
|
|
create.Flags = SYS_CREATE_THREAD_FLAG_NONE;
|
|
create.ThreadHandleOut = threadOut;
|
|
return SysCreateThread(&create);
|
|
}
|
|
|
|
// Starts the Session 0 DWM service with no namespace-admin or modeset authority.
|
|
void _start(void) {
|
|
KSTATUS status = NtlInitializeExceptionRuntime();
|
|
if (!KSUCCESS(status)) DwmExit(1);
|
|
DwmSetCurrentThreadName("dwm.main");
|
|
|
|
SYS_SECURITY_CONTEXT_INFO security;
|
|
memset(&security, 0, sizeof(security));
|
|
security.Size = sizeof(security);
|
|
status = SysQuerySecurityContext(SYS_SECURITY_CONTEXT_CURRENT, &security);
|
|
if (!KSUCCESS(status) || security.EffectivePrivileges != 0 || security.DelegablePrivileges != 0 ||
|
|
security.ServiceClaims != 0 || security.DelegableServiceClaims != 0)
|
|
DwmExit(2);
|
|
|
|
SYS_HANDLE controlListener = SysGetStartupCapability(SYS_STARTUP_CAP_SERVICE_CONTROL);
|
|
SYS_HANDLE displayManager = SysGetStartupCapability(SYS_STARTUP_CAP_DISPLAY_MANAGER);
|
|
SYS_HANDLE sessionListener = SysGetStartupCapability(SYS_STARTUP_CAP_SESSION_CONTROL);
|
|
if (controlListener == SYS_HANDLE_INVALID || displayManager == SYS_HANDLE_INVALID ||
|
|
sessionListener == SYS_HANDLE_INVALID)
|
|
DwmExit(3);
|
|
|
|
memset(&gDwm, 0, sizeof(gDwm));
|
|
gDwm.Mutex = SYS_HANDLE_INVALID;
|
|
gDwm.DirtyEvent = SYS_HANDLE_INVALID;
|
|
gDwm.DisplayManager = displayManager;
|
|
gDwm.SessionEndpoint = SYS_HANDLE_INVALID;
|
|
gDwm.DesktopListener = SYS_HANDLE_INVALID;
|
|
gDwm.CompositionSurface = SYS_HANDLE_INVALID;
|
|
gDwm.NextWindowId = 1u;
|
|
gDwm.CursorVisible = 1u;
|
|
|
|
SYS_DISPLAY_INFO displayInfo;
|
|
memset(&displayInfo, 0, sizeof(displayInfo));
|
|
status = SysQueryDisplayManagerInfo(displayManager, &displayInfo);
|
|
if (!KSUCCESS(status) || displayInfo.Mode.Width == 0 || displayInfo.Mode.Height == 0 ||
|
|
displayInfo.Mode.Format != DisplayPixelFormatX8R8G8B8)
|
|
DwmExit(4);
|
|
gDwm.Width = (int32_t)displayInfo.Mode.Width;
|
|
gDwm.Height = (int32_t)displayInfo.Mode.Height;
|
|
gDwm.PointerX = gDwm.Width / 2;
|
|
gDwm.PointerY = gDwm.Height / 2;
|
|
|
|
status = SysCreateMutex(&gDwm.Mutex);
|
|
if (!KSUCCESS(status)) DwmExit(5);
|
|
status = SysCreateEvent(DWM_EVENT_AUTO_RESET, 0u, &gDwm.DirtyEvent);
|
|
if (!KSUCCESS(status)) DwmExit(5);
|
|
status = DwmCreateCompositionSurface();
|
|
if (!KSUCCESS(status)) DwmExit(5);
|
|
status = DwmCreateDesktopListener();
|
|
if (!KSUCCESS(status)) DwmExit(5);
|
|
status = DwmConnectSession(sessionListener, &gDwm.SessionEndpoint);
|
|
(void)SysCloseHandle(sessionListener);
|
|
if (!KSUCCESS(status)) DwmExit(5);
|
|
|
|
SYS_HANDLE controlEndpoint = SYS_HANDLE_INVALID;
|
|
status = DwmAcceptControl(controlListener, &controlEndpoint);
|
|
(void)SysCloseHandle(controlListener);
|
|
if (!KSUCCESS(status)) DwmExit(6);
|
|
|
|
gDwm.Running = 1u;
|
|
SYS_HANDLE compositorThread = SYS_HANDLE_INVALID;
|
|
SYS_HANDLE inputThread = SYS_HANDLE_INVALID;
|
|
SYS_HANDLE listenerThread = SYS_HANDLE_INVALID;
|
|
status = DwmStartThread((uintptr_t)DwmCompositorThread, "dwm.compositor", &compositorThread);
|
|
if (!KSUCCESS(status)) DwmExit(7);
|
|
status = DwmStartThread((uintptr_t)DwmSessionInputThread, "dwm.session.input", &inputThread);
|
|
if (!KSUCCESS(status)) DwmExit(7);
|
|
status = DwmStartThread((uintptr_t)DwmDesktopListenerThread, "dwm.listen", &listenerThread);
|
|
if (!KSUCCESS(status)) DwmExit(7);
|
|
|
|
if (KSUCCESS(DwmLock())) {
|
|
DISPLAY_RECT whole = { 0, 0, gDwm.Width, gDwm.Height };
|
|
DwmDirtyLocked(&whole);
|
|
DwmApplyCursorLocked();
|
|
DwmUnlock();
|
|
}
|
|
|
|
status = DwmSendReady(controlEndpoint, gDwm.DesktopListener);
|
|
if (!KSUCCESS(status)) DwmExit(8);
|
|
|
|
DwmControlLoop(controlEndpoint);
|
|
gDwm.Running = 0u;
|
|
(void)SysSignalEvent(gDwm.DirtyEvent);
|
|
(void)SysDisconnectPort(gDwm.SessionEndpoint);
|
|
(void)SysDisconnectPort(controlEndpoint);
|
|
(void)SysCloseHandle(gDwm.DesktopListener);
|
|
(void)SysWait(compositorThread, SYS_WAIT_FLAG_NONE);
|
|
(void)SysWait(inputThread, SYS_WAIT_FLAG_NONE);
|
|
(void)SysCloseHandle(compositorThread);
|
|
(void)SysCloseHandle(inputThread);
|
|
(void)SysCloseHandle(listenerThread);
|
|
DwmExit(0);
|
|
}
|