Skip to content

Commit 7679e0a

Browse files
committed
Suspend system when lid is closed and all external monitors are disconnected
1 parent 59936d7 commit 7679e0a

File tree

1 file changed

+94
-8
lines changed

1 file changed

+94
-8
lines changed

ClamshellMode/main.c

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#include <shlobj.h>
44
#include <stdio.h>
55
#include <io.h>
6+
#include <Dbt.h>
7+
#include <initguid.h>
8+
#include <Ntddvdeo.h>
69

710
#pragma comment(lib, "powrprof.lib")
811

@@ -96,7 +99,7 @@ static void SetLidAction(const BOOL sleep) {
9699
}
97100
}
98101

99-
static BOOL ExternalDisplayConnected(const WCHAR* internalDisplayDeviceID) {
102+
static BOOL ExternalDisplayConnected() {
100103
DISPLAY_DEVICE device = { .cb = sizeof(DISPLAY_DEVICE) };
101104
DWORD i = 0;
102105

@@ -105,7 +108,7 @@ static BOOL ExternalDisplayConnected(const WCHAR* internalDisplayDeviceID) {
105108
DWORD j = 0;
106109

107110
while (EnumDisplayDevicesW(device.DeviceName, j++, &device2, 0) != 0) {
108-
if (wcscmp(device2.DeviceID, internalDisplayDeviceID) == 0) {
111+
if (wcscmp(device2.DeviceID, INTERNAL_DISPLAY_ID) == 0) {
109112
continue;
110113
}
111114
if (device2.StateFlags & DISPLAY_DEVICE_ACTIVE) {
@@ -117,6 +120,24 @@ static BOOL ExternalDisplayConnected(const WCHAR* internalDisplayDeviceID) {
117120
return FALSE;
118121
}
119122

123+
static BOOL HasAnyActiveDisplays() {
124+
DISPLAY_DEVICE device = { .cb = sizeof(DISPLAY_DEVICE) };
125+
DWORD i = 0;
126+
127+
while (EnumDisplayDevicesW(NULL, i++, &device, 0) != 0) {
128+
DISPLAY_DEVICE device2 = { .cb = sizeof(DISPLAY_DEVICE) };
129+
DWORD j = 0;
130+
131+
while (EnumDisplayDevicesW(device.DeviceName, j++, &device2, 0) != 0) {
132+
if (device2.StateFlags & DISPLAY_DEVICE_ACTIVE) {
133+
return TRUE;
134+
}
135+
}
136+
}
137+
138+
return FALSE;
139+
}
140+
120141
static void PopulateDisplayDevices(HWND hComboBox) {
121142
DISPLAY_DEVICE device = { .cb = sizeof(DISPLAY_DEVICE) };
122143
DWORD i = 0;
@@ -131,11 +152,22 @@ static void PopulateDisplayDevices(HWND hComboBox) {
131152
}
132153
}
133154

155+
static void HandleDisplayChange() {
156+
if (ExternalDisplayConnected()) {
157+
SetLidAction(FALSE);
158+
}
159+
else {
160+
SetLidAction(TRUE);
161+
}
162+
}
163+
134164
static LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
135165
static NOTIFYICONDATA nid = { 0 };
136166
static HWND hComboBox = NULL;
137167
static HICON hIcon = NULL; // Icon handle for reuse
138168

169+
static DWORD lidState = 1;
170+
139171
switch (msg) {
140172
case WM_CREATE:
141173
hIcon = LoadIconW(GetModuleHandleW(L"shell32.dll"), MAKEINTRESOURCEW(284));
@@ -157,7 +189,9 @@ static LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPAR
157189
if (_waccess(iniPath, 0) == -1) {
158190
PostMessageW(hwnd, WM_COMMAND, ID_TRAY_SET_DISPLAY, 0);
159191
}
160-
192+
else {
193+
HandleDisplayChange();
194+
}
161195
}
162196
break;
163197

@@ -193,11 +227,38 @@ static LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPAR
193227
break;
194228

195229
case WM_DISPLAYCHANGE:
196-
if (ExternalDisplayConnected(INTERNAL_DISPLAY_ID)) {
197-
SetLidAction(FALSE);
230+
HandleDisplayChange();
231+
break;
232+
233+
case WM_POWERBROADCAST:
234+
if (wParam == PBT_POWERSETTINGCHANGE) {
235+
POWERBROADCAST_SETTING* pbs = (POWERBROADCAST_SETTING*)lParam;
236+
if (IsEqualGUID(&pbs->PowerSetting, &GUID_LIDSWITCH_STATE_CHANGE)) {
237+
lidState = *(DWORD*)pbs->Data;
238+
printf("Lid state: %d\n", lidState);
239+
}
198240
}
199-
else {
241+
break;
242+
243+
case WM_DEVICECHANGE:
244+
if (wParam == DBT_DEVICEREMOVECOMPLETE) // handle device removal
245+
{
246+
PDEV_BROADCAST_HDR pHdr = (PDEV_BROADCAST_HDR)lParam;
247+
248+
if (pHdr->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) // if device is not monitor
249+
{
250+
break;
251+
}
252+
if (HasAnyActiveDisplays()) { // if any monitor is active
253+
break;
254+
}
255+
if (lidState != 0) { // if lid is not closed
256+
break;
257+
}
258+
259+
printf("Suspending\n");
200260
SetLidAction(TRUE);
261+
SetSuspendState(FALSE, FALSE, FALSE);
201262
}
202263
break;
203264

@@ -284,7 +345,20 @@ static LRESULT CALLBACK DisplayWindowProcedure(HWND hwnd, UINT msg, WPARAM wPara
284345

285346
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, int nCmdShow)
286347
{
287-
HANDLE mutex = CreateMutexW(NULL, TRUE, L"Global\\ClamshellMode");
348+
#if NDEBUG == 0
349+
AllocConsole();
350+
FILE* file;
351+
freopen_s(&file, "CONOUT$", "w", stdout);
352+
freopen_s(&file, "CONIN$", "r", stdin);
353+
freopen_s(&file, "CONOUT$", "w", stderr);
354+
#endif
355+
356+
HWND hwnd = NULL;
357+
HANDLE mutex = NULL;
358+
HPOWERNOTIFY hLidNotify = NULL;
359+
HDEVNOTIFY hDeviceNotify = NULL;
360+
361+
mutex = CreateMutexW(NULL, TRUE, L"Global\\ClamshellMode");
288362
if (GetLastError() == ERROR_ALREADY_EXISTS || mutex == NULL) {
289363
return 1;
290364
}
@@ -307,16 +381,28 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine,
307381
wc.hIcon = LoadIconW(GetModuleHandleW(L"shell32.dll"), MAKEINTRESOURCEW(284)); // Set the icon for display window
308382
RegisterClassW(&wc);
309383

310-
HWND hwnd = CreateWindowExW(0, className, WINDOW_NAME,
384+
hwnd = CreateWindowExW(0, className, WINDOW_NAME,
311385
0, CW_USEDEFAULT, CW_USEDEFAULT,
312386
0, 0, NULL, NULL, hInstance, NULL);
313387

388+
389+
hLidNotify = RegisterPowerSettingNotification(hwnd, &GUID_LIDSWITCH_STATE_CHANGE, DEVICE_NOTIFY_WINDOW_HANDLE);
390+
391+
DEV_BROADCAST_DEVICEINTERFACE filter = { 0 };
392+
filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
393+
filter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
394+
filter.dbcc_classguid = GUID_DEVINTERFACE_MONITOR;
395+
hDeviceNotify = RegisterDeviceNotificationW(hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE);
396+
314397
MSG msg = { 0 };
315398
while (GetMessageW(&msg, NULL, 0, 0)) {
316399
TranslateMessage(&msg);
317400
DispatchMessageW(&msg);
318401
}
319402

403+
UnregisterPowerSettingNotification(hLidNotify);
404+
UnregisterDeviceNotification(hDeviceNotify);
405+
320406
CloseHandle(mutex);
321407
return 0;
322408
}

0 commit comments

Comments
 (0)