Skip to content

Commit 472ce3e

Browse files
committed
backport f640edebf0074f231c1c0a24273536738eb18e28
1 parent 6d212e8 commit 472ce3e

6 files changed

Lines changed: 258 additions & 79 deletions

File tree

src/java.desktop/windows/native/libawt/windows/Devices.cpp

Lines changed: 97 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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

159190
BOOL 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,

src/java.desktop/windows/native/libawt/windows/Devices.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
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
@@ -47,8 +47,11 @@ static BOOL UpdateInstance(JNIEnv *env);
4747
class InstanceAccess {
4848
public:
4949
INLINE InstanceAccess() { devices = Devices::GetInstance(); }
50-
INLINE ~InstanceAccess() { devices->Release(); }
50+
INLINE ~InstanceAccess() { if (devices != NULL) devices->Release(); }
5151
Devices* operator->() { return devices; }
52+
INLINE AwtWin32GraphicsDevice* Device(int index, BOOL adjust = TRUE) {
53+
return devices == NULL ? NULL : devices->GetDevice(index, adjust);
54+
}
5255
private:
5356
Devices* devices;
5457
// prevent bad things like copying or getting address of

src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1996, 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
@@ -65,7 +65,7 @@
6565
#include <java_awt_Toolkit.h>
6666
#include <java_awt_event_InputMethodEvent.h>
6767

68-
extern void initScreens(JNIEnv *env);
68+
extern BOOL initScreens(JNIEnv *env);
6969
extern "C" void awt_dnd_initialize();
7070
extern "C" void awt_dnd_uninitialize();
7171
extern "C" void awt_clipboard_uninitialize(JNIEnv *env);
@@ -157,6 +157,78 @@ extern "C" JNIEXPORT jboolean JNICALL AWTIsHeadless() {
157157
}
158158

159159
#define IDT_AWT_MOUSECHECK 0x101
160+
#define IDT_AWT_DISPLAYCHANGE 0x102
161+
162+
#define AWT_DISPLAYCHANGE_RETRY_DELAY 250
163+
#define AWT_DISPLAYCHANGE_RETRY_LIMIT 20
164+
165+
class DisplayChangeHandler {
166+
public:
167+
static BOOL Handle(JNIEnv *env, HWND hWnd) {
168+
// Reinitialize screens
169+
if (!initScreens(env)) {
170+
OnDisplayChangeFailed(hWnd);
171+
return FALSE;
172+
}
173+
174+
OnDisplayChangeSucceeded(hWnd);
175+
176+
// Notify Java side - call WToolkit.displayChanged()
177+
jclass clazz = env->FindClass("sun/awt/windows/WToolkit");
178+
DASSERT(clazz != NULL);
179+
if (!clazz) throw std::bad_alloc();
180+
env->CallStaticVoidMethod(clazz, AwtToolkit::displayChangeMID);
181+
182+
return !env->ExceptionCheck();
183+
}
184+
185+
static void Reset(HWND hWnd) {
186+
::KillTimer(hWnd, IDT_AWT_DISPLAYCHANGE);
187+
retryCount = 0;
188+
}
189+
190+
static void ScheduleFromSessionChange(HWND hWnd) {
191+
if (!recoveryPending) {
192+
return;
193+
}
194+
Reset(hWnd);
195+
Schedule(hWnd);
196+
}
197+
198+
private:
199+
static void OnDisplayChangeFailed(HWND hWnd) {
200+
recoveryPending = TRUE;
201+
Schedule(hWnd);
202+
}
203+
204+
static void OnDisplayChangeSucceeded(HWND hWnd) {
205+
recoveryPending = FALSE;
206+
Reset(hWnd);
207+
}
208+
209+
static void Schedule(HWND hWnd) {
210+
if (retryCount >= AWT_DISPLAYCHANGE_RETRY_LIMIT) {
211+
Reset(hWnd);
212+
J2dRlsTraceLn(J2D_TRACE_ERROR,
213+
"AwtToolkit: Display change retry limit exceeded.");
214+
return;
215+
}
216+
217+
retryCount++;
218+
if (::SetTimer(hWnd, IDT_AWT_DISPLAYCHANGE,
219+
AWT_DISPLAYCHANGE_RETRY_DELAY, NULL) == 0) {
220+
Reset(hWnd);
221+
J2dRlsTraceLn(J2D_TRACE_ERROR,
222+
"AwtToolkit: Failed to schedule display change retry.");
223+
}
224+
}
225+
226+
static int retryCount;
227+
static BOOL recoveryPending;
228+
};
229+
230+
int DisplayChangeHandler::retryCount = 0;
231+
BOOL DisplayChangeHandler::recoveryPending = FALSE;
160232

161233
static LPCTSTR szAwtToolkitClassName = TEXT("SunAwtToolkit");
162234

@@ -1004,6 +1076,14 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message,
10041076
}
10051077

10061078
case WM_TIMER: {
1079+
if (wParam == IDT_AWT_DISPLAYCHANGE) {
1080+
if (DisplayChangeHandler::Handle(env, hWnd)) {
1081+
GetInstance().m_displayChanged = TRUE;
1082+
::PostMessage(HWND_BROADCAST, WM_PALETTEISCHANGING, NULL, NULL);
1083+
}
1084+
return 0;
1085+
}
1086+
10071087
// 6479820. Should check if a window is in manual resizing process: skip
10081088
// sending any MouseExit/Enter events while inside resize-loop.
10091089
// Note that window being in manual moving process could still
@@ -1245,18 +1325,11 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message,
12451325
return tk.m_inputMethodData;
12461326
}
12471327
case WM_DISPLAYCHANGE: {
1248-
// Reinitialize screens
1249-
initScreens(env);
1250-
1251-
// Notify Java side - call WToolkit.displayChanged()
1252-
jclass clazz = env->FindClass("sun/awt/windows/WToolkit");
1253-
DASSERT(clazz != NULL);
1254-
if (!clazz) throw std::bad_alloc();
1255-
env->CallStaticVoidMethod(clazz, AwtToolkit::displayChangeMID);
1256-
1257-
GetInstance().m_displayChanged = TRUE;
1258-
1259-
::PostMessage(HWND_BROADCAST, WM_PALETTEISCHANGING, NULL, NULL);
1328+
DisplayChangeHandler::Reset(hWnd);
1329+
if (DisplayChangeHandler::Handle(env, hWnd)) {
1330+
GetInstance().m_displayChanged = TRUE;
1331+
::PostMessage(HWND_BROADCAST, WM_PALETTEISCHANGING, NULL, NULL);
1332+
}
12601333
break;
12611334
}
12621335
/* Session management */
@@ -1341,6 +1414,9 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message,
13411414
activate
13421415
? JNI_TRUE
13431416
: JNI_FALSE, reason);
1417+
if (activate) {
1418+
DisplayChangeHandler::ScheduleFromSessionChange(hWnd);
1419+
}
13441420
}
13451421
break;
13461422
}

0 commit comments

Comments
 (0)