Skip to content
This repository was archived by the owner on Mar 26, 2024. It is now read-only.
Draft
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
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ intellijPluginVersion=1.1.2
javassistVersion=3.27.0-GA
kotlinVersion=1.5.20
mockitoKotlinVersion=3.2.0
projectorClientVersion=042060cb
projectorClientVersion=6ceeb326
projectorClientGroup=com.github.JetBrains.projector-client
targetJvm=11
# Give JitPack some time to build projector-client:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@

package org.jetbrains.projector.server

import com.intellij.openapi.application.invokeAndWaitIfNeeded
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.command.executeCommand
import com.intellij.openapi.editor.EditorFactory
import org.jetbrains.projector.awt.PClipboard
import org.jetbrains.projector.awt.PToolkit
import org.jetbrains.projector.awt.PWindow
Expand Down Expand Up @@ -111,6 +115,8 @@ class ProjectorServer private constructor(

private val markdownQueue = ConcurrentLinkedQueue<ServerMarkdownEvent>()

private val speculativeQueue = ConcurrentLinkedQueue<Pair<SpeculativeEvent, String>>()

private var windowColorsEvent: ServerWindowColorsEvent? = null

private val ideaColors = IdeColors { colors ->
Expand Down Expand Up @@ -255,7 +261,7 @@ class ProjectorServer private constructor(
private fun isClipboardChanged(current: ServerClipboardEvent?) = lastClipboardEvent != current

@OptIn(ExperimentalStdlibApi::class)
private fun createDataToSend(): List<ServerEvent> {
private fun createDataToSend(): List<FilterableEvent<*>> {
val clipboardEvent = when (isAgent) {
false -> PClipboard.extractLastContents()?.toServerClipboardEvent().let(::listOfNotNull)
true -> {
Expand Down Expand Up @@ -313,17 +319,26 @@ class ProjectorServer private constructor(

val markdownEvents = extractData(markdownQueue)

val commandsCount = caretInfoEvents.size +
newImagesCopy.size + clipboardEvent.size + drawCommands.size + windowSetChangedEvent.size + markdownEvents.size + 1
val speculativeEvents = extractData(speculativeQueue).map {
FilterableEvent(it.first) { _, settings -> it.second == settings.address }
}

val commandsCount = caretInfoEvents.size + newImagesCopy.size + clipboardEvent.size + drawCommands.size +
windowSetChangedEvent.size + markdownEvents.size + speculativeEvents.size + 1

fun toFilterableEvent(event: ServerEvent): FilterableEvent<*> {
return FilterableEvent(event) { _, _ -> true }
}

val allEvents = buildList(commandsCount) {
addAll(caretInfoEvents)
addAll(newImagesCopy)
addAll(clipboardEvent)
addAll(drawCommands)
addAll(windowSetChangedEvent)
addAll(markdownEvents)
windowColorsEvent?.let { add(it); windowColorsEvent = null }
addAll(caretInfoEvents.map(::toFilterableEvent))
addAll(newImagesCopy.map(::toFilterableEvent))
addAll(clipboardEvent.map(::toFilterableEvent))
addAll(drawCommands.map(::toFilterableEvent))
addAll(windowSetChangedEvent.map(::toFilterableEvent))
addAll(markdownEvents.map(::toFilterableEvent))
addAll(speculativeEvents)
windowColorsEvent?.let { add(toFilterableEvent(it)); windowColorsEvent = null }
}

ProjectorImageCacher.collectGarbage()
Expand Down Expand Up @@ -484,6 +499,46 @@ class ProjectorServer private constructor(
is ClientWindowCloseEvent -> SwingUtilities.invokeLater { PWindow.getWindow(message.windowId)?.close() }

is ClientWindowInterestEvent -> SwingUtilities.invokeLater { clientSettings.interestManager.processClientEvent(message) }

is ClientSpeculativeKeyPressEvent -> {

val editor = EditorFactory.getInstance().allEditors.find {
System.identityHashCode(it) == message.editorId
}

if (editor == null) {
processMessage(clientSettings, message.originalEvent) // fallback
} else {

invokeAndWaitIfNeeded {
runWriteAction {
executeCommand {
val insertedString = message.originalEvent.char.toString()

val selectionInfo = message.selectionInfo

editor.document.apply {
if (selectionInfo != null) {
replaceString(selectionInfo.startOffset, selectionInfo.endOffset, insertedString)
}
else {
insertString(message.offset, insertedString)
}
}

val newOffset = (selectionInfo?.startOffset ?: message.offset) + insertedString.length

editor.caretModel.primaryCaret.apply {
removeSelection()
moveToOffset(newOffset)
}
}
}
}
}

speculativeQueue.add(SpeculativeEvent.SpeculativeStringDrawnEvent(message.requestId) to clientSettings.address!!)
}
}
}

Expand Down Expand Up @@ -628,14 +683,19 @@ class ProjectorServer private constructor(
clientEventHandler.updateClientsCount()
}

private fun sendPictures(dataToSend: List<ServerEvent>) {
private fun sendPictures(dataToSend: List<FilterableEvent<*>>) {
transports.forEach { transport ->
transport.forEachOpenedConnection { client ->
val readyClientSettings = client.settings as? ReadyClientSettings ?: return@forEachOpenedConnection

val compressed = with(readyClientSettings.setUpClientData) {
val requestedData = extractData(readyClientSettings.requestedData)
val message = readyClientSettings.interestManager.filterEvents(requestedData.asSequence() + dataToSend.asSequence()).toList()
val message = readyClientSettings.interestManager.filterEvents(requestedData.asSequence() + dataToSend.mapNotNull {
when (it.isValidForClient(readyClientSettings)) {
true -> it.originalEvent
false -> null
}
}.asSequence()).toList()

if (message.isEmpty()) {
return@forEachOpenedConnection
Expand Down Expand Up @@ -896,4 +956,8 @@ class ProjectorServer private constructor(

fun getEnvPort() = (getProperty(PORT_PROPERTY_NAME) ?: getProperty(PORT_PROPERTY_NAME_OLD))?.toIntOrNull() ?: DEFAULT_PORT
}

class FilterableEvent<T: ServerEvent>(val originalEvent: T, private val filter: (T, ReadyClientSettings) -> Boolean) {
fun isValidForClient(clientSettings: ReadyClientSettings) = filter(originalEvent, clientSettings)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ package org.jetbrains.projector.server.idea
import com.intellij.ide.DataManager
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.application.invokeAndWaitIfNeeded
import com.intellij.openapi.editor.colors.EditorColors
import com.intellij.openapi.editor.colors.EditorFontType
import com.intellij.openapi.editor.ex.EditorEx
import com.intellij.openapi.editor.impl.EditorImpl
Expand All @@ -38,6 +39,7 @@ import org.jetbrains.projector.common.protocol.data.CommonRectangle
import org.jetbrains.projector.common.protocol.data.Point
import org.jetbrains.projector.common.protocol.toClient.ServerCaretInfoChangedEvent
import org.jetbrains.projector.common.protocol.toClient.data.idea.CaretInfo
import org.jetbrains.projector.common.protocol.toClient.data.idea.SelectionInfo
import org.jetbrains.projector.server.core.ij.invokeWhenIdeaIsInitialized
import org.jetbrains.projector.server.platform.getTextAttributesCompat
import org.jetbrains.projector.server.platform.readAction
Expand Down Expand Up @@ -122,19 +124,49 @@ class CaretInfoUpdater(private val onCaretInfoChanged: (ServerCaretInfoChangedEv
val points = focusedEditor.caretModel.allCarets.map {
val caretLocationInEditor = invokeAndWaitIfNeeded { it.editor.visualPositionToXY(it.visualPosition) }

val caretOffset = readAction { it.offset }
val selectionStart = readAction { it.selectionStart }
val selectionEnd = readAction { it.selectionEnd }

val selectionInfo = if (selectionStart == selectionEnd) {
null
} else {
val selectionStartPointVisual = invokeAndWaitIfNeeded { it.editor.visualPositionToXY(it.selectionStartPosition) }

val selectionStartPoint = Point(
x = (editorLocationInWindowX + selectionStartPointVisual.x).toDouble(),
y = (editorLocationInWindowY + selectionStartPointVisual.y).toDouble(),
)

val selectionEndPointVisual = invokeAndWaitIfNeeded { it.editor.visualPositionToXY(it.selectionEndPosition) }

val selectionEndPoint = Point(
x = (editorLocationInWindowX + selectionEndPointVisual.x).toDouble(),
y = (editorLocationInWindowY + selectionEndPointVisual.y).toDouble(),
)

SelectionInfo(
selectionStartPoint,
selectionStart,
selectionEndPoint,
selectionEnd,
)
}

val point = Point(
x = (editorLocationInWindowX + caretLocationInEditor.x).toDouble(),
y = (editorLocationInWindowY + caretLocationInEditor.y).toDouble(),
)

CaretInfo(point)
CaretInfo(point, caretOffset, selectionInfo)
}

val isVerticalScrollBarVisible = visibleEditorRect.height < focusedEditorComponent.height
val verticalScrollBarWidth = if (isVerticalScrollBarVisible) scrollPane.verticalScrollBar?.width ?: 0 else 0

val textColor = getTextColorBeforeCaret(focusedEditor)
val editorFont = getFontBeforeCaret(focusedEditor)
val backgroundColor = getBackgroundBeforeCaret(focusedEditor)

ServerCaretInfoChangedEvent.CaretInfoChange.Carets(
points,
Expand All @@ -151,6 +183,9 @@ class CaretInfoUpdater(private val onCaretInfoChanged: (ServerCaretInfoChangedEv
lineAscent = lineAscent,
verticalScrollBarWidth = verticalScrollBarWidth,
textColor = textColor,
backgroundColor = backgroundColor,
editorScrolled = Point(visibleEditorRect.x.toDouble(), visibleEditorRect.y.toDouble()),
editorId = System.identityHashCode(focusedEditor),
)
}
}
Expand All @@ -175,7 +210,23 @@ class CaretInfoUpdater(private val onCaretInfoChanged: (ServerCaretInfoChangedEv
return editor.colorsScheme.getFont(editorFontType)
}

private fun getTextAttributesBeforeCaret(editor: EditorEx, filter: (TextAttributes) -> Boolean): TextAttributes? {
private fun getBackgroundBeforeCaret(editor: EditorEx): Int {
val attrs = getTextAttributesBeforeCaret(editor, {
if (it.priority >= 0) it.attrs else null
}) { it.backgroundColor != null }

val color = attrs?.backgroundColor
?: editor.colorsScheme.getColor(EditorColors.CARET_ROW_COLOR)
?: editor.colorsScheme.defaultBackground

return color.rgb
}

private fun getTextAttributesBeforeCaret(
editor: EditorEx,
mapper: (ExtendedTextAttributes) -> TextAttributes? = { it.attrs },
filter: (TextAttributes) -> Boolean
): TextAttributes? {

val caretOffset = readAction { editor.caretModel.offset }

Expand All @@ -194,7 +245,7 @@ class CaretInfoUpdater(private val onCaretInfoChanged: (ServerCaretInfoChangedEv
it(editor, caretOffset, compareAndUpdate)
}

return bestFitAttributes?.attrs
return bestFitAttributes?.let(mapper)
}

private fun getAttrsFromRangeHighlighters(
Expand All @@ -203,7 +254,9 @@ class CaretInfoUpdater(private val onCaretInfoChanged: (ServerCaretInfoChangedEv
compareAndUpdate: (ExtendedTextAttributes) -> Unit,
) {

val rangeHighlighters = invokeAndWaitIfNeeded { editor.filteredDocumentMarkupModel.allHighlighters }
val rangeHighlighters = invokeAndWaitIfNeeded {
editor.filteredDocumentMarkupModel.allHighlighters + editor.markupModel.allHighlighters
}

val startPos = caretOffset - 1

Expand Down