Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,17 @@ Screensavers that behave differently in preview mode probably won't work very we

Tested with various MS/Plus screensavers, including the all-important 3D Maze.

# Usage
## Requirements

Make sure `wine` is installed and you can run `winegcc`.

On Debian/Ubuntu-based systems you will need the Wine and X11 development libraries to compile nightcap, you can install them by running:

0. Make sure `wine` is installed and you can run `winegcc`.
```bash
sudo apt install libwine-dev libx11-dev build-essential
```

# Usage

1. Compile `nightcap.exe`:

Expand Down
27 changes: 25 additions & 2 deletions nightcap.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ void cleanup(int signal) {
BOOL found_child = FALSE;
BOOL CALLBACK EnumChildProc(HWND hwnd, LPARAM lParam) {
found_child = TRUE;
return TRUE;
}

Display *dpy = NULL;
Expand All @@ -56,7 +57,7 @@ void die(const char *format, ...) {
GC gc = XCreateGC(dpy, parent_xwindow, GCForeground, &gc_values);
XTextItem xti = {
.chars = msg,
.nchars = strlen(msg),
.nchars = (int)strlen(msg),
};
XDrawText(dpy, parent_xwindow, gc, 100, 100, &xti, 1);
XFlush(dpy);
Expand Down Expand Up @@ -146,6 +147,27 @@ int main(int argc, char **argv) {
die("CreateProcess failed (%d). Probably the .scr was not found?", GetLastError());
}

// --- Create a Job Object to prevent ghost/zombie processes ---
HANDLE hJob = CreateJobObject(NULL, NULL);
if (hJob == NULL) {
die("CreateJobObject failed (%d)", GetLastError());
}

JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;

if (!SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) {
die("SetInformationJobObject failed (%d)", GetLastError());
}

if (!AssignProcessToJobObject(hJob, pi.hProcess)) {
die("AssignProcessToJobObject failed (%d)", GetLastError());
}

// Clean up the thread handle as it's not needed
CloseHandle(pi.hThread);
// -------------------------------------------------------------

while (!found_child) {
EnumChildWindows(hwnd, EnumChildProc, 0);
Sleep(5);
Expand All @@ -158,7 +180,7 @@ int main(int argc, char **argv) {

int our_xwindow = (uintptr_t)GetPropW(hwnd, whole_window_prop);

int result = XReparentWindow(dpy, our_xwindow, parent_xwindow, 0, 0);
XReparentWindow(dpy, our_xwindow, parent_xwindow, 0, 0);
XFlush(dpy);
ShowWindow(hwnd, SW_SHOW);

Expand All @@ -170,6 +192,7 @@ int main(int argc, char **argv) {
}

TerminateProcess(hProc, 0);
CloseHandle(hJob); // Will also safely close and kill the child process if still alive

return 0;
}
Expand Down