Skip to content
This repository has been archived by the owner on Mar 26, 2024. It is now read-only.

PRJ-57 Draw notifications and floating toolbar on top of client markdown/JCEF component #121

Open
wants to merge 5 commits into
base: jcef
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions buildSrc/src/main/kotlin/runIdeaTaskBase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -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<Any?>): Array<Any?> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -85,6 +87,11 @@ public object MainAgent {
)

logger.info { "agentmain finish" }

WindowSystemHelper.instance = object : WindowSystemHelper {

override fun getParentWindow(component: Component) = GraphicsInterceptor.getPWindow(component)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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<ComponentPeer>(it) as? PWindowPeer)?.pWindow }
else -> null
}
get() = WindowSystemHelper.instance.getParentWindow(target)

/** ImageIds of icons. */
var icons: List<Any>? = null
Expand All @@ -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<PWindow>()

val fakeChildren: Set<PWindow>
get() = mutableFakeChildren


init {
updateIcons()
}

private val self by lazy { WeakReference(this) }

var cursor: Cursor? = target.cursor
var cursor: Cursor? = thisWindow?.cursor

init {
synchronized(weakWindows) {
Expand All @@ -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() {
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor Author

@ARTI1208 ARTI1208 Mar 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I remeber well component.graphicsConfiguration will be null for fake windows. Wanted to recheck today but due to disk problems didn't

)

private constructor(
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Pair<Int, Int>>)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
}
Loading