mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-3157 Maximized window with custom decorations isn't focused on showing
(cherry picked from commit 62b04983f2)
This commit is contained in:
committed by
alexey.ushakov@jetbrains.com
parent
8549075139
commit
a61a343f45
@@ -786,24 +786,6 @@ AwtFrame::Show()
|
||||
} else {
|
||||
::ShowWindow(hwnd, SW_SHOWMAXIMIZED);
|
||||
}
|
||||
|
||||
// [tav] Workaround for unclear platform behaviour.
|
||||
// When a custom decor frame is being shown maximized at the moment
|
||||
// some another AWT window is still foreground - the frame can go
|
||||
// in background when shown if:
|
||||
// 1) the other AWT window is closed the moment after frame's show
|
||||
// 2) some another maximized window is behind the frame, it steals activation
|
||||
if (HasCustomDecoration()) {
|
||||
HWND fgHWnd = ::GetForegroundWindow();
|
||||
if (fgHWnd != NULL &&
|
||||
GetComponent(fgHWnd) != NULL && // it's awt window
|
||||
IsFocusableWindow() &&
|
||||
IsAutoRequestFocus() &&
|
||||
!::IsWindow(GetModalBlocker(GetHWnd())))
|
||||
{
|
||||
::SetForegroundWindow(GetHWnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_isInputMethodWindow) {
|
||||
// Don't activate input methow window
|
||||
@@ -1438,16 +1420,6 @@ void AwtFrame::_SetState(void *param)
|
||||
|
||||
f->setIconic(iconify);
|
||||
f->setZoomed(zoom);
|
||||
|
||||
// [tav] With custom decor enabled, MS Win will send WM_SIZE msg w/o SIZE_MAXIMIZED param set
|
||||
// before the frame will be shown. The msg handler will drop the maximized state in response.
|
||||
// In order to prevent that, we set the maximized state on the native frame in advance.
|
||||
if (zoom && f->HasCustomDecoration()) {
|
||||
WINDOWPLACEMENT wp;
|
||||
::GetWindowPlacement(f->GetHWnd(), &wp);
|
||||
wp.showCmd = SW_SHOWMAXIMIZED;
|
||||
::SetWindowPlacement(f->GetHWnd(), &wp);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret:
|
||||
|
||||
@@ -2246,7 +2246,16 @@ void AwtWindow::RecalcNonClient()
|
||||
//
|
||||
void AwtWindow::RedrawNonClient()
|
||||
{
|
||||
::SetWindowPos(GetHWnd(), (HWND) NULL, 0, 0, 0, 0, SwpFrameChangeFlags|SWP_ASYNCWINDOWPOS);
|
||||
UINT flags = SwpFrameChangeFlags;
|
||||
if (!HasCustomDecoration()) {
|
||||
// With custom decorations enabled, SetWindowPos call below can cause WM_SIZE message being sent.
|
||||
// If we're coming here from WFramePeer.initialize (as part of 'setResizable' call),
|
||||
// WM_SIZE message processing can happen concurrently with window flags update done as part of
|
||||
// 'setState' call), and lead to inconsistent state.
|
||||
// So, we disable asynchronous processing in case we have custom decorations to avoid the race condition.
|
||||
flags |= SWP_ASYNCWINDOWPOS;
|
||||
}
|
||||
::SetWindowPos(GetHWnd(), (HWND) NULL, 0, 0, 0, 0, flags);
|
||||
}
|
||||
|
||||
int AwtWindow::GetScreenImOn() {
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2021 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Regression test for JBR-3157 Maximized window with custom decorations isn't focused on showing
|
||||
* @key headful
|
||||
* @run main/othervm --add-opens java.desktop/java.awt=ALL-UNNAMED MaximizedCustomDecorationsTest
|
||||
*/
|
||||
|
||||
public class MaximizedCustomDecorationsTest {
|
||||
private static final CompletableFuture<Boolean> frame2Focused = new CompletableFuture<>();
|
||||
private static Robot robot;
|
||||
private static JFrame frame1;
|
||||
private static JFrame frame2;
|
||||
private static JButton button;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
robot = new Robot();
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(MaximizedCustomDecorationsTest::initUI);
|
||||
robot.delay(1000);
|
||||
clickOn(button);
|
||||
frame2Focused.get(5, TimeUnit.SECONDS);
|
||||
} finally {
|
||||
SwingUtilities.invokeAndWait(MaximizedCustomDecorationsTest::disposeUI);
|
||||
}
|
||||
}
|
||||
|
||||
private static void initUI() {
|
||||
frame1 = new JFrame("MaximizedCustomDecorationsTest");
|
||||
button = new JButton("Open maximized frame");
|
||||
button.addActionListener(e -> {
|
||||
frame1.dispose();
|
||||
frame2 = new JFrame("Frame with custom decorations");
|
||||
enableCustomDecorations(frame2);
|
||||
frame2.addWindowFocusListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowGainedFocus(WindowEvent e) {
|
||||
frame2Focused.complete(true);
|
||||
}
|
||||
});
|
||||
frame2.setExtendedState(Frame.MAXIMIZED_BOTH);
|
||||
frame2.setVisible(true);
|
||||
});
|
||||
frame1.add(button);
|
||||
frame1.pack();
|
||||
frame1.setVisible(true);
|
||||
}
|
||||
|
||||
private static void enableCustomDecorations(Window window) {
|
||||
try {
|
||||
Method setHasCustomDecoration = Window.class.getDeclaredMethod("setHasCustomDecoration");
|
||||
setHasCustomDecoration.setAccessible(true);
|
||||
setHasCustomDecoration.invoke(window);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void disposeUI() {
|
||||
if (frame1 != null) frame1.dispose();
|
||||
if (frame2 != null) frame2.dispose();
|
||||
}
|
||||
|
||||
private static void clickAt(int x, int y) {
|
||||
robot.mouseMove(x, y);
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
}
|
||||
|
||||
private static void clickOn(Component component) {
|
||||
Point location = component.getLocationOnScreen();
|
||||
clickAt(location.x + component.getWidth() / 2, location.y + component.getHeight() / 2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user