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+
120141static 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+
134164static 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
285346int 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