11/*
2- * Copyright (c) 2001, 2025 , 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
@@ -117,47 +117,78 @@ static BOOL IsValidMonitor(HMONITOR hMon)
117117 return TRUE ;
118118}
119119
120- // Callback for CountMonitors below
121- static BOOL WINAPI clb_fCountMonitors (HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorCounter)
120+
121+ // Callback for CollectMonitors below
122+ static BOOL WINAPI clb_fCollectMonitors (HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorData)
122123{
123- if (IsValidMonitor (hMon)) {
124- (*((int *)lpMonitorCounter))++;
124+ MonitorData* pMonitorData = (MonitorData *)lpMonitorData;
125+
126+ if (!IsValidMonitor (hMon)) {
127+ return TRUE ;
128+ }
129+
130+ if (pMonitorData->monitorCounter == pMonitorData->monitorLimit ) {
131+ TRY;
132+
133+ int newMonitorLimit = pMonitorData->monitorLimit * 2 ;
134+ HMONITOR* newMonitors =
135+ (HMONITOR*)SAFE_SIZE_ARRAY_REALLOC (
136+ safe_Realloc, pMonitorData->hmpMonitors ,
137+ newMonitorLimit, sizeof (HMONITOR)
138+ );
139+ pMonitorData->hmpMonitors = newMonitors;
140+ pMonitorData->monitorLimit = newMonitorLimit;
141+
142+ CATCH_BAD_ALLOC_RET (FALSE );
125143 }
126144
145+ pMonitorData->hmpMonitors [pMonitorData->monitorCounter ] = hMon;
146+ pMonitorData->monitorCounter ++;
147+
127148 return TRUE ;
128149}
129150
130- int WINAPI CountMonitors ( void )
151+ static HMONITOR* CollectMonitors ( int * numScreens )
131152{
132- int monitorCounter = 0 ;
133- ::EnumDisplayMonitors (NULL , NULL , clb_fCountMonitors, (LPARAM)&monitorCounter);
134- return monitorCounter;
135- }
153+ const int initialMonitorLimit = 4 ;
136154
137- // Callback for CollectMonitors below
138- static BOOL WINAPI clb_fCollectMonitors (HMONITOR hMon, HDC hDC, LPRECT rRect, LPARAM lpMonitorData)
139- {
140- MonitorData* pMonitorData = (MonitorData *)lpMonitorData;
141- if ((pMonitorData->monitorCounter < pMonitorData->monitorLimit ) && (IsValidMonitor (hMon))) {
142- pMonitorData->hmpMonitors [pMonitorData->monitorCounter ] = hMon;
143- pMonitorData->monitorCounter ++;
155+ *numScreens = 0 ;
156+
157+ MonitorData data;
158+ data.monitorCounter = 0 ;
159+ data.monitorLimit = initialMonitorLimit;
160+
161+ TRY;
162+
163+ data.hmpMonitors = (HMONITOR*)SAFE_SIZE_ARRAY_ALLOC (safe_Malloc,
164+ initialMonitorLimit, sizeof (HMONITOR));
165+ CATCH_BAD_ALLOC_RET (NULL );
166+
167+ if (!::EnumDisplayMonitors (NULL , NULL , clb_fCollectMonitors, (LPARAM)&data)) {
168+ free (data.hmpMonitors );
169+ return NULL ;
144170 }
145171
146- return TRUE ;
172+ *numScreens = data.monitorCounter ;
173+ return data.hmpMonitors ;
147174}
148175
149- static int WINAPI CollectMonitors (HMONITOR* hmpMonitors, int nNum )
176+ int WINAPI CountMonitors ( )
150177{
151- if (NULL != hmpMonitors) {
152- MonitorData monitorData;
153- monitorData.monitorCounter = 0 ;
154- monitorData.monitorLimit = nNum;
155- monitorData.hmpMonitors = hmpMonitors;
156- ::EnumDisplayMonitors (NULL , NULL , clb_fCollectMonitors, (LPARAM)&monitorData);
157- return monitorData.monitorCounter ;
158- } else {
159- return 0 ;
178+ int numScreens = 0 ;
179+ HMONITOR* monHds = CollectMonitors (&numScreens);
180+ free (monHds);
181+ return numScreens;
182+ }
183+
184+ static BOOL AreSameMonitorInfo (LPMONITORINFOEX oldInfo, LPMONITORINFOEX newInfo)
185+ {
186+ if (oldInfo == NULL || newInfo == NULL ) {
187+ return FALSE ;
160188 }
189+
190+ return oldInfo->dwFlags == newInfo->dwFlags
191+ && ::lstrcmp (oldInfo->szDevice , newInfo->szDevice ) == 0 ;
161192}
162193
163194BOOL WINAPI MonitorBounds (HMONITOR hmMonitor, RECT* rpBounds)
@@ -206,17 +237,26 @@ BOOL Devices::UpdateInstance(JNIEnv *env)
206237{
207238 J2dTraceLn (J2D_TRACE_INFO, " Devices::UpdateInstance" );
208239
209- int numScreens = CountMonitors ();
210- HMONITOR *monHds = (HMONITOR *)SAFE_SIZE_ARRAY_ALLOC (safe_Malloc,
211- numScreens, sizeof (HMONITOR));
212- if (numScreens != CollectMonitors (monHds, numScreens)) {
240+ int numScreens = 0 ;
241+ HMONITOR *monHds = CollectMonitors (&numScreens);
242+ if (monHds == NULL ) {
213243 J2dRlsTraceLn (J2D_TRACE_ERROR,
214- " Devices::UpdateInstance: Failed to get all " \
244+ " Devices::UpdateInstance: Failed to get " \
215245 " monitor handles." );
216246 free (monHds);
217247 return FALSE ;
218248 }
219249
250+ if (numScreens == 0 ) {
251+ CriticalSection::Lock l (arrayLock);
252+ if (theInstance != NULL ) {
253+ J2dRlsTraceLn (J2D_TRACE_ERROR,
254+ " Devices::UpdateInstance: No valid monitor handles." );
255+ free (monHds);
256+ return FALSE ;
257+ }
258+ }
259+
220260 Devices *newDevices = new Devices (numScreens);
221261 // This way we know that the array will not be disposed of
222262 // at least until we replaced it with a new one.
@@ -242,18 +282,26 @@ BOOL Devices::UpdateInstance(JNIEnv *env)
242282 theInstance = newDevices;
243283
244284 if (oldDevices) {
245- // Invalidate the devices with indexes out of the new set of
246- // devices. This doesn't cover all cases when the device
247- // might should be invalidated (like if it's not the last device
248- // that was removed), but it will have to do for now.
249285 int oldNumScreens = oldDevices->GetNumDevices ();
250- int newNumScreens = theInstance->GetNumDevices ();
251- J2dTraceLn (J2D_TRACE_VERBOSE, " Invalidating removed devices" );
252- for (int i = newNumScreens; i < oldNumScreens; i++) {
253- // removed device, needs to be invalidated
286+ J2dTraceLn (J2D_TRACE_VERBOSE, " Invalidating changed devices" );
287+ for (int i = 0 ; i < oldNumScreens; i++) {
288+ AwtWin32GraphicsDevice *oldDevice =
289+ oldDevices->GetDevice (i, FALSE );
290+ AwtWin32GraphicsDevice *newDevice =
291+ theInstance->GetDevice (i, FALSE );
292+ BOOL changed = (newDevice == NULL )
293+ || !AreSameMonitorInfo (
294+ (LPMONITORINFOEX) oldDevice->GetMonitorInfo (),
295+ (LPMONITORINFOEX) newDevice->GetMonitorInfo ());
296+
297+ if (!changed) {
298+ newDevice->TransferJavaDevice (env, oldDevice);
299+ continue ;
300+ }
301+
254302 J2dTraceLn (J2D_TRACE_WARNING,
255- " Devices::UpdateInstance: device removed : %d" , i);
256- oldDevices-> GetDevice (i) ->Invalidate (env);
303+ " Devices::UpdateInstance: device changed : %d" , i);
304+ oldDevice ->Invalidate (env);
257305 }
258306 // Now that we have a new array in place, remove this (possibly the
259307 // last) reference to the old instance.
@@ -346,6 +394,12 @@ AwtWin32GraphicsDevice *Devices::GetDevice(int index, BOOL adjust)
346394 J2dTraceLn (J2D_TRACE_INFO,
347395 " Devices::GetDevice index=%d adjust?=%d" ,
348396 index, adjust);
397+ if (numDevices <= 0 ) {
398+ J2dTraceLn (J2D_TRACE_WARNING,
399+ " Devices::GetDevice: " \
400+ " no devices, returning NULL." );
401+ return NULL ;
402+ }
349403 if (index < 0 || index >= numDevices) {
350404 if (!adjust) {
351405 J2dTraceLn (J2D_TRACE_WARNING,
0 commit comments