diff --git a/buildSrc/src/main/kotlin/runIdeaTaskBase.kt b/buildSrc/src/main/kotlin/runIdeaTaskBase.kt index edee5d70..ba827033 100644 --- a/buildSrc/src/main/kotlin/runIdeaTaskBase.kt +++ b/buildSrc/src/main/kotlin/runIdeaTaskBase.kt @@ -59,14 +59,49 @@ public fun Project.createRunIdeaTask( "-Didea.is.internal=true", "--add-exports=java.base/jdk.internal.vm=ALL-UNNAMED", "--add-opens=java.desktop/java.awt=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt.dnd.peer=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt.event=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt.image=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt.peer=ALL-UNNAMED", "--add-opens=java.desktop/sun.font=ALL-UNNAMED", "--add-opens=java.desktop/sun.awt=ALL-UNNAMED", + "--add-opens=java.desktop/sun.awt.image=ALL-UNNAMED", + "--add-opens=java.desktop/sun.java2d=ALL-UNNAMED", "--add-opens=java.desktop/sun.swing=ALL-UNNAMED", "--add-opens=java.desktop/javax.swing=ALL-UNNAMED", "--add-opens=java.desktop/javax.swing.text.html=ALL-UNNAMED", "--add-opens=java.desktop/javax.swing.plaf.basic=ALL-UNNAMED", "--add-opens=java.base/java.lang=ALL-UNNAMED", "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED", + "--add-opens=java.base/java.lang=ALL-UNNAMED", + "--add-opens=java.base/java.text=ALL-UNNAMED", + "--add-opens=java.base/java.time=ALL-UNNAMED", + "--add-opens=java.base/java.util=ALL-UNNAMED", + "--add-opens=java.base/jdk.internal.vm=ALL-UNNAMED", + "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt.event=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt.peer=ALL-UNNAMED", + "--add-opens=java.desktop/javax.swing=ALL-UNNAMED", + "--add-opens=java.desktop/javax.swing.plaf.basic=ALL-UNNAMED", + "--add-opens=java.desktop/javax.swing.text.html=ALL-UNNAMED", + "--add-opens=java.desktop/sun.awt=ALL-UNNAMED", + "--add-opens=java.desktop/sun.awt.image=ALL-UNNAMED", + "--add-opens=java.desktop/sun.awt.windows=ALL-UNNAMED", + "--add-opens=java.desktop/sun.font=ALL-UNNAMED", + "--add-opens=java.desktop/sun.java2d=ALL-UNNAMED", + "--add-opens=java.desktop/sun.lwawt=ALL-UNNAMED", + "--add-opens=java.desktop/sun.lwawt.macosx=ALL-UNNAMED", + "--add-opens=java.desktop/sun.swing=ALL-UNNAMED", + "--add-opens=java.desktop/com.apple.eawt=ALL-UNNAMED", + "--add-opens=java.desktop/com.apple.eawt.event=ALL-UNNAMED", + "--add-opens=java.desktop/com.apple.laf=ALL-UNNAMED", + "--add-opens=jdk.attach/sun.tools.attach=ALL-UNNAMED", + "--add-opens=jdk.internal.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED", + "--add-opens=jdk.jdi/com.sun.tools.jdi=ALL-UNNAMED", + "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED", + "--add-opens=java.desktop/java.awt.image=ALL-UNNAMED", + "--add-opens=jcef/org.cef=ALL-UNNAMED", ) if (isIdeVersionAtLeast(ideaPath, "212")) { // appeared in 211, became default in 212, mandatory in 221 diff --git a/gradle.properties b/gradle.properties index f2a7398d..cd524f7b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -27,7 +27,7 @@ intellijPluginVersion=1.3.0 javassistVersion=3.28.0-GA kotlinVersion=1.6.10 mockitoKotlinVersion=4.0.0 -projectorClientVersion=67b2cd9f +projectorClientVersion=336b3e2c projectorClientGroup=com.github.JetBrains.projector-client targetJvm=11 jetbrainsMonoVersion=2.242 diff --git a/projector-agent/src/main/kotlin/org/jetbrains/projector/agent/GraphicsInterceptor.kt b/projector-agent/src/main/kotlin/org/jetbrains/projector/agent/GraphicsInterceptor.kt index 57c1b3e6..7598612f 100644 --- a/projector-agent/src/main/kotlin/org/jetbrains/projector/agent/GraphicsInterceptor.kt +++ b/projector-agent/src/main/kotlin/org/jetbrains/projector/agent/GraphicsInterceptor.kt @@ -33,14 +33,12 @@ import org.jetbrains.projector.server.ProjectorServer import org.jetbrains.projector.server.service.ProjectorDrawEventQueue import org.jetbrains.projector.server.service.ProjectorFontProvider import org.jetbrains.projector.util.loading.UseProjectorLoader -import org.jetbrains.projector.util.loading.unprotect import org.jetbrains.projector.util.logging.Logger -import sun.awt.NullComponentPeer import sun.java2d.SunGraphics2D import java.awt.* -import java.awt.peer.ComponentPeer import java.beans.PropertyChangeListener import javax.swing.JComponent +import javax.swing.SwingUtilities @UseProjectorLoader internal object GraphicsInterceptor { @@ -65,6 +63,13 @@ internal object GraphicsInterceptor { ProjectorFontProvider.isAgent = true } + internal fun getPWindow(component: Component): PWindow? { + val parentWindow = getParentWindow(component) ?: return null + return pWindows.getOrPut(parentWindow.id()) { PWindow(parentWindow, isAgent = true) } + } + + private fun getOrPutWindow(component: Component): PWindow = getPWindow(component)!! + @Suppress("unused", "PLATFORM_CLASS_MAPPED_TO_KOTLIN", "UNUSED_PARAMETER") // Integer is needed because this function is used via reflection @JvmStatic @@ -75,12 +80,11 @@ internal object GraphicsInterceptor { paintToOffscreenInProgress = true - val parentWindow = getParentWindow(comp) - val pWindow = pWindows.getOrPut(parentWindow.id()) { PWindow(parentWindow, isAgent = true) } + val pWindow = getOrPutWindow(comp) currentQueue = ProjectorDrawEventQueue(ServerDrawCommandsEvent.Target.Onscreen(pWindow.id)) - paintingConstraint = calculateComponentPositionInsideWindow(comp, parentWindow).let { + paintingConstraint = calculateComponentPositionInsideWindow(comp, pWindow.target).let { Point( it.x + x.toInt(), it.y + y.toInt() @@ -220,21 +224,18 @@ internal object GraphicsInterceptor { val location = window.locationOnScreen val mouseLocation = PMouseInfoPeer.lastMouseCoords val targetComp = (window as Container).findComponentAt(mouseLocation - location) ?: return - pWindows[window.id()]!!.cursor = targetComp.cursor + pWindows[window.id()]!!.apply { + cursor = targetComp.cursor + fakeChildren.forEach { + it.cursor = targetComp.cursor + } + } } } - private fun getParentWindow(comp: Component): Component { - var currComp = comp - val peerField = Component::class.java.getDeclaredField("peer") - peerField.unprotect() - var peer = peerField.get(currComp) as ComponentPeer - while (peer is NullComponentPeer) { - currComp = currComp.parent - peer = peerField.get(currComp) as ComponentPeer - } - - return currComp + private fun getParentWindow(comp: Component) = when (comp) { + is Window -> comp + else -> SwingUtilities.getWindowAncestor(comp) } private fun copyArgs(args: Array): Array { diff --git a/projector-agent/src/main/kotlin/org/jetbrains/projector/agent/MainAgent.kt b/projector-agent/src/main/kotlin/org/jetbrains/projector/agent/MainAgent.kt index 905d563a..b4281c36 100644 --- a/projector-agent/src/main/kotlin/org/jetbrains/projector/agent/MainAgent.kt +++ b/projector-agent/src/main/kotlin/org/jetbrains/projector/agent/MainAgent.kt @@ -26,10 +26,12 @@ package org.jetbrains.projector.agent import javassist.ClassPool import javassist.LoaderClassPath +import org.jetbrains.projector.awt.service.WindowSystemHelper import org.jetbrains.projector.util.loading.ProjectorClassLoaderSetup import org.jetbrains.projector.util.loading.UseProjectorLoader import org.jetbrains.projector.util.loading.unprotect import org.jetbrains.projector.util.logging.Logger +import java.awt.Component import java.lang.instrument.Instrumentation import java.lang.reflect.Method @@ -85,6 +87,11 @@ public object MainAgent { ) logger.info { "agentmain finish" } + + WindowSystemHelper.instance = object : WindowSystemHelper { + + override fun getParentWindow(component: Component) = GraphicsInterceptor.getPWindow(component) + } } } } diff --git a/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/PWindow.kt b/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/PWindow.kt index c969a218..cc4eda09 100644 --- a/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/PWindow.kt +++ b/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/PWindow.kt @@ -28,18 +28,21 @@ import org.jetbrains.annotations.TestOnly import org.jetbrains.projector.awt.data.Direction import org.jetbrains.projector.awt.image.PGraphics2D import org.jetbrains.projector.awt.image.PGraphicsEnvironment -import org.jetbrains.projector.awt.peer.PWindowPeer import org.jetbrains.projector.awt.peer.PWindowPeer.Companion.getVisibleWindowBoundsIfNeeded import org.jetbrains.projector.awt.service.ImageCacher +import org.jetbrains.projector.awt.service.WindowSystemHelper import org.jetbrains.projector.util.logging.Logger import sun.awt.AWTAccessor import java.awt.* import java.awt.event.ComponentEvent import java.awt.event.WindowEvent -import java.awt.peer.ComponentPeer import java.lang.ref.WeakReference import java.util.* import java.util.concurrent.atomic.AtomicInteger +import javax.swing.JComponent +import javax.swing.SwingUtilities +import javax.swing.event.AncestorEvent +import javax.swing.event.AncestorListener import kotlin.math.abs import kotlin.math.min @@ -87,10 +90,7 @@ class PWindow private constructor(val target: Component, private val isAgent: Bo } val parentWindow: PWindow? - get() = when (target) { - is Window -> target.owner?.let { (AWTAccessor.getComponentAccessor().getPeer(it) as? PWindowPeer)?.pWindow } - else -> null - } + get() = WindowSystemHelper.instance.getParentWindow(target) /** ImageIds of icons. */ var icons: List? = null @@ -102,13 +102,41 @@ class PWindow private constructor(val target: Component, private val isAgent: Bo else -> null } + val thisWindow: Component? + get() = when (target) { + is Window -> target + else -> SwingUtilities.getWindowAncestor(target) + } + + val bounds: Rectangle + get() = when (target) { + is Window -> target.bounds + else -> { + if (target.isShowing) { + val locationInWindow = SwingUtilities.convertPoint(target, Point(0, 0), null) + Rectangle(locationInWindow.x, locationInWindow.y, target.width, target.height) + } else { + target.bounds + } + } + } + + val isFakeWindow: Boolean + get() = target !is Window + + private val mutableFakeChildren = mutableSetOf() + + val fakeChildren: Set + get() = mutableFakeChildren + + init { updateIcons() } private val self by lazy { WeakReference(this) } - var cursor: Cursor? = target.cursor + var cursor: Cursor? = thisWindow?.cursor init { synchronized(weakWindows) { @@ -123,6 +151,25 @@ class PWindow private constructor(val target: Component, private val isAgent: Bo graphics = graphicsOverride ?: PGraphics2D(target, Descriptor(id)) updateGraphics() + + if (isFakeWindow) { + parentWindow?.mutableFakeChildren?.add(this@PWindow) + if (target is JComponent) { + target.addAncestorListener(object : AncestorListener { + + override fun ancestorAdded(event: AncestorEvent) { + parentWindow?.mutableFakeChildren?.add(this@PWindow) + } + + override fun ancestorRemoved(event: AncestorEvent) { + parentWindow?.mutableFakeChildren?.remove(this@PWindow) + } + + override fun ancestorMoved(event: AncestorEvent) { + } + }) + } + } } fun transferNativeFocus() { @@ -304,11 +351,27 @@ class PWindow private constructor(val target: Component, private val isAgent: Bo synchronized(weakWindows) { weakWindows.removeIf { it.get() == window } } + window.fakeChildren.forEach { it.dispose() } + window.parentWindow?.mutableFakeChildren?.remove(window) + } + + @JvmStatic + @Suppress("unused") + fun disposeWindow(target: Component) { + synchronized(weakWindows) { + weakWindows.filter { it.get()?.target == target }.forEach { + it.get()?.dispose() + } + } } fun getWindow(windowId: Int): PWindow? = windows.find { it.id == windowId } fun getWindow(window: Window): PWindow? = windows.find { it.target === window } + @JvmStatic + @Suppress("unused") + fun getWindow(target: Component): PWindow? = weakWindows.find { it.get()?.target == target }?.get() + @TestOnly fun createWithGraphicsOverride(target: Component, isAgent: Boolean, graphicsOverride: Graphics2D?): PWindow { return PWindow(target, isAgent, graphicsOverride) diff --git a/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/image/PGraphics2D.kt b/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/image/PGraphics2D.kt index ba89a96e..73d8a15f 100644 --- a/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/image/PGraphics2D.kt +++ b/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/image/PGraphics2D.kt @@ -136,12 +136,12 @@ class PGraphics2D private constructor( constructor(component: Component, target: PWindow.Descriptor) : this( drawEventQueue = DrawEventQueue.createOnScreen(target), - transform = component.graphicsConfiguration.defaultTransform, // from Graphics2D "Default Rendering Attributes" java doc + transform = component.graphicsConfiguration?.defaultTransform ?: AffineTransform(), // from Graphics2D "Default Rendering Attributes" java doc backgroundColor = component.background, // from Graphics2D "Default Rendering Attributes" java doc paint = component.foreground, // from Graphics2D "Default Rendering Attributes" java doc foregroundColor = component.foreground, // from Graphics2D "Default Rendering Attributes" java doc font = component.font, - device = component.graphicsConfiguration.device + device = component.graphicsConfiguration?.device ?: GraphicsEnvironment.getLocalGraphicsEnvironment().defaultScreenDevice ) private constructor( @@ -539,13 +539,16 @@ class PGraphics2D private constructor( } override fun clearRect(x: Int, y: Int, width: Int, height: Int) { - val c = composite - val p = getPaint() - composite = AlphaComposite.Src - color = background - fillRect(x, y, width, height) - setPaint(p) - composite = c + if (width <= 0 || height <= 0) return + + paintShape { + clearRect( + x = x.toDouble(), + y = y.toDouble(), + width = width.toDouble(), + height = height.toDouble(), + ) + } } private fun paintRoundRect(paintType: AwtPaintType, x: Int, y: Int, width: Int, height: Int, arcWidth: Int, arcHeight: Int) { diff --git a/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/peer/PComponentPeer.kt b/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/peer/PComponentPeer.kt index 2cc5ee00..3f499509 100644 --- a/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/peer/PComponentPeer.kt +++ b/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/peer/PComponentPeer.kt @@ -155,6 +155,7 @@ abstract class PComponentPeer(target: Component, private val isFocusable: Boolea } pWindow.cursor = cursorUnderMouse + pWindow.fakeChildren.forEach { it.cursor = cursorUnderMouse } } override fun requestFocus( diff --git a/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/service/DrawEventQueue.kt b/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/service/DrawEventQueue.kt index 62ce7752..4d63a87c 100644 --- a/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/service/DrawEventQueue.kt +++ b/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/service/DrawEventQueue.kt @@ -59,6 +59,7 @@ interface DrawEventQueue { fun drawLine(x1: Int, y1: Int, x2: Int, y2: Int) fun paintRect(paintType: AwtPaintType, x: Double, y: Double, width: Double, height: Double) fun paintRoundRect(paintType: AwtPaintType, x: Int, y: Int, width: Int, height: Int, arcWidth: Int, arcHeight: Int) + fun clearRect(x: Double, y: Double, width: Double, height: Double) fun paintOval(paintType: AwtPaintType, x: Int, y: Int, width: Int, height: Int) fun paintArc(paintType: AwtPaintType, x: Int, y: Int, width: Int, height: Int, startAngle: Int, arcAngle: Int) fun drawPolyline(points: List>) diff --git a/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/service/WindowSystemHelper.kt b/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/service/WindowSystemHelper.kt new file mode 100644 index 00000000..e5d45c41 --- /dev/null +++ b/projector-awt/src/main/kotlin/org/jetbrains/projector/awt/service/WindowSystemHelper.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019-2022, JetBrains s.r.o. and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. JetBrains designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact JetBrains, Na Hrebenech II 1718/10, Prague, 14000, Czech Republic + * if you need additional information or have any questions. + */ +package org.jetbrains.projector.awt.service + +import org.jetbrains.projector.awt.PWindow +import java.awt.Component + +interface WindowSystemHelper { + + fun getParentWindow(component: Component): PWindow? + + companion object { + + lateinit var instance: WindowSystemHelper + } +} diff --git a/projector-server/src/main/kotlin/org/jetbrains/projector/server/CommonQueueEventSender.kt b/projector-server/src/main/kotlin/org/jetbrains/projector/server/CommonQueueEventSender.kt index f727d451..90ad3af0 100644 --- a/projector-server/src/main/kotlin/org/jetbrains/projector/server/CommonQueueEventSender.kt +++ b/projector-server/src/main/kotlin/org/jetbrains/projector/server/CommonQueueEventSender.kt @@ -25,17 +25,14 @@ package org.jetbrains.projector.server -import org.jetbrains.projector.awt.peer.PComponentPeer +import org.jetbrains.projector.awt.service.WindowSystemHelper import org.jetbrains.projector.common.EventSender import org.jetbrains.projector.common.event.BrowserShowEventPart import org.jetbrains.projector.common.event.ServerEventPart import org.jetbrains.projector.common.protocol.toClient.ServerBrowserEvent import org.jetbrains.projector.common.protocol.toClient.ServerEvent import org.jetbrains.projector.util.loading.UseProjectorLoader -import sun.awt.AWTAccessor import java.awt.Component -import java.awt.peer.ComponentPeer -import javax.swing.SwingUtilities @UseProjectorLoader class CommonQueueEventSender : EventSender { @@ -53,9 +50,5 @@ class CommonQueueEventSender : EventSender { } private val Component.pWindowId: Int? - get() = let { - val root = SwingUtilities.getRoot(it) ?: return@let null - val peer = AWTAccessor.getComponentAccessor().getPeer(root) as? PComponentPeer ?: return@let null - peer.pWindow.id - } + get() = WindowSystemHelper.instance.getParentWindow(this)?.id } diff --git a/projector-server/src/main/kotlin/org/jetbrains/projector/server/HeadlessInitializer.kt b/projector-server/src/main/kotlin/org/jetbrains/projector/server/HeadlessInitializer.kt index 173e8179..80fb764a 100644 --- a/projector-server/src/main/kotlin/org/jetbrains/projector/server/HeadlessInitializer.kt +++ b/projector-server/src/main/kotlin/org/jetbrains/projector/server/HeadlessInitializer.kt @@ -28,11 +28,18 @@ package org.jetbrains.projector.server import org.jetbrains.projector.awt.PToolkit import org.jetbrains.projector.awt.font.PFontManager import org.jetbrains.projector.awt.image.PGraphicsEnvironment +import org.jetbrains.projector.awt.peer.PWindowPeer +import org.jetbrains.projector.awt.service.WindowSystemHelper import org.jetbrains.projector.server.ProjectorServer.Companion.ENABLE_PROPERTY_NAME import org.jetbrains.projector.util.loading.unprotect +import sun.awt.AWTAccessor import sun.font.FontManagerFactory +import java.awt.Component import java.awt.GraphicsEnvironment import java.awt.Toolkit +import java.awt.Window +import java.awt.peer.ComponentPeer +import javax.swing.SwingUtilities internal fun setupGraphicsEnvironment() { val classes = GraphicsEnvironment::class.java.declaredClasses @@ -62,6 +69,16 @@ internal fun setupFontManager() { } } +internal fun setupWindowHelper() { + WindowSystemHelper.instance = object : WindowSystemHelper { + + override fun getParentWindow(component: Component) = when (component) { + is Window -> component.owner + else -> SwingUtilities.getWindowAncestor(component) + }?.let { (AWTAccessor.getComponentAccessor().getPeer(it) as? PWindowPeer)?.pWindow } + } +} + internal fun setupRepaintManager() { // todo: when we do smth w/ RepaintManager, IDEA crashes. // Maybe it's because AppContext is used. diff --git a/projector-server/src/main/kotlin/org/jetbrains/projector/server/ProjectorLauncher.kt b/projector-server/src/main/kotlin/org/jetbrains/projector/server/ProjectorLauncher.kt index 6f34deed..0fa02352 100644 --- a/projector-server/src/main/kotlin/org/jetbrains/projector/server/ProjectorLauncher.kt +++ b/projector-server/src/main/kotlin/org/jetbrains/projector/server/ProjectorLauncher.kt @@ -99,6 +99,7 @@ object ProjectorLauncher { setupToolkit() setupFontManager() setupRepaintManager() + setupWindowHelper() } private fun initializeHeadless() { diff --git a/projector-server/src/main/kotlin/org/jetbrains/projector/server/ProjectorServer.kt b/projector-server/src/main/kotlin/org/jetbrains/projector/server/ProjectorServer.kt index c4f4e263..b7d6700b 100644 --- a/projector-server/src/main/kotlin/org/jetbrains/projector/server/ProjectorServer.kt +++ b/projector-server/src/main/kotlin/org/jetbrains/projector/server/ProjectorServer.kt @@ -37,6 +37,7 @@ import org.jetbrains.projector.awt.peer.PComponentPeer import org.jetbrains.projector.awt.peer.PDesktopPeer import org.jetbrains.projector.awt.peer.PMouseInfoPeer import org.jetbrains.projector.common.misc.Do +import org.jetbrains.projector.common.protocol.data.CommonRectangle import org.jetbrains.projector.common.protocol.data.ImageData import org.jetbrains.projector.common.protocol.data.ImageId import org.jetbrains.projector.common.protocol.data.UserKeymap @@ -301,7 +302,7 @@ class ProjectorServer private constructor( icons = window.icons?.map { it as ImageId }, isShowing = window.target.isShowing, zOrder = i, - bounds = window.target.shiftBounds(PGraphicsEnvironment.defaultDevice.clientShift), + bounds = window.shifted(), headerHeight = window.headerHeight, cursorType = window.cursor?.type?.toCursorType(), resizable = window.resizable, @@ -362,7 +363,7 @@ class ProjectorServer private constructor( PMouseInfoPeer.lastMouseCoords.setLocation(shiftedMessage.x, shiftedMessage.y) - val window = PWindow.getWindow(message.windowId)?.target + val window = PWindow.getWindow(message.windowId)?.thisWindow PMouseInfoPeer.lastWindowUnderMouse = window window ?: return@invokeLater @@ -872,6 +873,15 @@ class ProjectorServer private constructor( } } + private fun PWindow.shifted(): CommonRectangle { + val shift = when { + isFakeWindow -> SwingUtilities.getWindowAncestor(target)?.insets?.let { java.awt.Point(it.left, it.top) } ?: java.awt.Point() + else -> PGraphicsEnvironment.defaultDevice.clientShift + } + + return bounds.shift(shift) + } + private fun resize(width: Int, height: Int) { val ge = GraphicsEnvironment.getLocalGraphicsEnvironment() if (ge is PGraphicsEnvironment) { diff --git a/projector-server/src/main/kotlin/org/jetbrains/projector/server/service/ProjectorDrawEventQueue.kt b/projector-server/src/main/kotlin/org/jetbrains/projector/server/service/ProjectorDrawEventQueue.kt index 44fabe7f..813427f8 100644 --- a/projector-server/src/main/kotlin/org/jetbrains/projector/server/service/ProjectorDrawEventQueue.kt +++ b/projector-server/src/main/kotlin/org/jetbrains/projector/server/service/ProjectorDrawEventQueue.kt @@ -129,6 +129,15 @@ class ProjectorDrawEventQueue(private val target: ServerDrawCommandsEvent.Target build() } + override fun clearRect(x: Double, y: Double, width: Double, height: Double) { + events.add( + ServerClearRectEvent( + x = x, y = y, width = width, height = height + ) + ) + build() + } + override fun paintOval(paintType: AwtPaintType, x: Int, y: Int, width: Int, height: Int) { events.add(ServerPaintOvalEvent(paintType.toPaintType(), x = x, y = y, width = width, height = height)) build() diff --git a/projector-server/src/main/kotlin/org/jetbrains/projector/server/util/Convert.kt b/projector-server/src/main/kotlin/org/jetbrains/projector/server/util/Convert.kt index 7ee67fef..368e65d5 100644 --- a/projector-server/src/main/kotlin/org/jetbrains/projector/server/util/Convert.kt +++ b/projector-server/src/main/kotlin/org/jetbrains/projector/server/util/Convert.kt @@ -59,6 +59,7 @@ val PWindow.windowType: WindowType get() = when { "IdeFrameImpl" in target::class.java.simpleName -> WindowType.IDEA_WINDOW target.let { it is Window && it.type == Window.Type.POPUP } -> WindowType.POPUP + isFakeWindow -> WindowType.FAKE_WINDOW else -> WindowType.WINDOW }