11/*
2- * Copyright (c) 2001, 2024 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2001, 2026 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
@@ -113,47 +113,78 @@ static BOOL IsValidMonitor(HMONITOR hMon)
113113 return TRUE ;
114114}
115115
116- // Callback for CountMonitors below
117- static BOOL WINAPI clb_fCountMonitors (HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorCounter)
116+
117+ // Callback for CollectMonitors below
118+ static BOOL WINAPI clb_fCollectMonitors (HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorData)
118119{
119- if (IsValidMonitor (hMon)) {
120- (*((int *)lpMonitorCounter))++;
120+ MonitorData* pMonitorData = (MonitorData *)lpMonitorData;
121+
122+ if (!IsValidMonitor (hMon)) {
123+ return TRUE ;
124+ }
125+
126+ if (pMonitorData->monitorCounter == pMonitorData->monitorLimit ) {
127+ TRY ;
128+
129+ int newMonitorLimit = pMonitorData->monitorLimit * 2 ;
130+ HMONITOR * newMonitors =
131+ (HMONITOR *)SAFE_SIZE_ARRAY_REALLOC (
132+ safe_Realloc, pMonitorData->hmpMonitors ,
133+ newMonitorLimit, sizeof (HMONITOR )
134+ );
135+ pMonitorData->hmpMonitors = newMonitors;
136+ pMonitorData->monitorLimit = newMonitorLimit;
137+
138+ CATCH_BAD_ALLOC_RET (FALSE );
121139 }
122140
141+ pMonitorData->hmpMonitors [pMonitorData->monitorCounter ] = hMon;
142+ pMonitorData->monitorCounter ++;
143+
123144 return TRUE ;
124145}
125146
126- int WINAPI CountMonitors ( void )
147+ static HMONITOR * CollectMonitors ( int * numScreens )
127148{
128- int monitorCounter = 0 ;
129- ::EnumDisplayMonitors (NULL , NULL , clb_fCountMonitors, (LPARAM )&monitorCounter);
130- return monitorCounter;
131- }
149+ const int initialMonitorLimit = 4 ;
132150
133- // Callback for CollectMonitors below
134- static BOOL WINAPI clb_fCollectMonitors (HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorData)
135- {
136- MonitorData* pMonitorData = (MonitorData *)lpMonitorData;
137- if ((pMonitorData->monitorCounter < pMonitorData->monitorLimit ) && (IsValidMonitor (hMon))) {
138- pMonitorData->hmpMonitors [pMonitorData->monitorCounter ] = hMon;
139- pMonitorData->monitorCounter ++;
151+ *numScreens = 0 ;
152+
153+ MonitorData data;
154+ data.monitorCounter = 0 ;
155+ data.monitorLimit = initialMonitorLimit;
156+
157+ TRY ;
158+
159+ data.hmpMonitors = (HMONITOR *)SAFE_SIZE_ARRAY_ALLOC (safe_Malloc,
160+ initialMonitorLimit, sizeof (HMONITOR ));
161+ CATCH_BAD_ALLOC_RET (NULL );
162+
163+ if (!::EnumDisplayMonitors (NULL , NULL , clb_fCollectMonitors, (LPARAM )&data)) {
164+ free (data.hmpMonitors );
165+ return NULL ;
140166 }
141167
142- return TRUE ;
168+ *numScreens = data.monitorCounter ;
169+ return data.hmpMonitors ;
143170}
144171
145- static int WINAPI CollectMonitors ( HMONITOR * hmpMonitors, int nNum )
172+ int WINAPI CountMonitors ( )
146173{
147- if (NULL != hmpMonitors) {
148- MonitorData monitorData;
149- monitorData.monitorCounter = 0 ;
150- monitorData.monitorLimit = nNum;
151- monitorData.hmpMonitors = hmpMonitors;
152- ::EnumDisplayMonitors (NULL , NULL , clb_fCollectMonitors, (LPARAM )&monitorData);
153- return monitorData.monitorCounter ;
154- } else {
155- return 0 ;
174+ int numScreens = 0 ;
175+ HMONITOR * monHds = CollectMonitors (&numScreens);
176+ free (monHds);
177+ return numScreens;
178+ }
179+
180+ static BOOL AreSameMonitorInfo (LPMONITORINFOEX oldInfo, LPMONITORINFOEX newInfo)
181+ {
182+ if (oldInfo == NULL || newInfo == NULL ) {
183+ return FALSE ;
156184 }
185+
186+ return oldInfo->dwFlags == newInfo->dwFlags
187+ && ::lstrcmp (oldInfo->szDevice , newInfo->szDevice ) == 0 ;
157188}
158189
159190BOOL WINAPI MonitorBounds (HMONITOR hmMonitor, RECT * rpBounds)
@@ -202,17 +233,26 @@ BOOL Devices::UpdateInstance(JNIEnv *env)
202233{
203234 J2dTraceLn (J2D_TRACE_INFO , " Devices::UpdateInstance" );
204235
205- int numScreens = CountMonitors ();
206- HMONITOR *monHds = (HMONITOR *)SAFE_SIZE_ARRAY_ALLOC (safe_Malloc,
207- numScreens, sizeof (HMONITOR ));
208- if (numScreens != CollectMonitors (monHds, numScreens)) {
236+ int numScreens = 0 ;
237+ HMONITOR *monHds = CollectMonitors (&numScreens);
238+ if (monHds == NULL ) {
209239 J2dRlsTraceLn (J2D_TRACE_ERROR ,
210- " Devices::UpdateInstance: Failed to get all " \
240+ " Devices::UpdateInstance: Failed to get " \
211241 " monitor handles." );
212242 free (monHds);
213243 return FALSE ;
214244 }
215245
246+ if (numScreens == 0 ) {
247+ CriticalSection::Lock l (arrayLock);
248+ if (theInstance != NULL ) {
249+ J2dRlsTraceLn (J2D_TRACE_ERROR ,
250+ " Devices::UpdateInstance: No valid monitor handles." );
251+ free (monHds);
252+ return FALSE ;
253+ }
254+ }
255+
216256 Devices *newDevices = new Devices (numScreens);
217257 // This way we know that the array will not be disposed of
218258 // at least until we replaced it with a new one.
@@ -238,18 +278,26 @@ BOOL Devices::UpdateInstance(JNIEnv *env)
238278 theInstance = newDevices;
239279
240280 if (oldDevices) {
241- // Invalidate the devices with indexes out of the new set of
242- // devices. This doesn't cover all cases when the device
243- // might should be invalidated (like if it's not the last device
244- // that was removed), but it will have to do for now.
245281 int oldNumScreens = oldDevices->GetNumDevices ();
246- int newNumScreens = theInstance->GetNumDevices ();
247- J2dTraceLn (J2D_TRACE_VERBOSE , " Invalidating removed devices" );
248- for (int i = newNumScreens; i < oldNumScreens; i++) {
249- // removed device, needs to be invalidated
282+ J2dTraceLn (J2D_TRACE_VERBOSE , " Invalidating changed devices" );
283+ for (int i = 0 ; i < oldNumScreens; i++) {
284+ AwtWin32GraphicsDevice *oldDevice =
285+ oldDevices->GetDevice (i, FALSE );
286+ AwtWin32GraphicsDevice *newDevice =
287+ theInstance->GetDevice (i, FALSE );
288+ BOOL changed = (newDevice == NULL )
289+ || !AreSameMonitorInfo (
290+ (LPMONITORINFOEX ) oldDevice->GetMonitorInfo (),
291+ (LPMONITORINFOEX ) newDevice->GetMonitorInfo ());
292+
293+ if (!changed) {
294+ newDevice->TransferJavaDevice (env, oldDevice);
295+ continue ;
296+ }
297+
250298 J2dTraceLn1 (J2D_TRACE_WARNING ,
251- " Devices::UpdateInstance: device removed : %d" , i);
252- oldDevices-> GetDevice (i) ->Invalidate (env);
299+ " Devices::UpdateInstance: device changed : %d" , i);
300+ oldDevice ->Invalidate (env);
253301 }
254302 // Now that we have a new array in place, remove this (possibly the
255303 // last) reference to the old instance.
@@ -342,6 +390,12 @@ AwtWin32GraphicsDevice *Devices::GetDevice(int index, BOOL adjust)
342390 J2dTraceLn2 (J2D_TRACE_INFO ,
343391 " Devices::GetDevice index=%d adjust?=%d" ,
344392 index, adjust);
393+ if (numDevices <= 0 ) {
394+ J2dTraceLn (J2D_TRACE_WARNING ,
395+ " Devices::GetDevice: " \
396+ " no devices, returning NULL." );
397+ return NULL ;
398+ }
345399 if (index < 0 || index >= numDevices) {
346400 if (!adjust) {
347401 J2dTraceLn1 (J2D_TRACE_WARNING ,
0 commit comments