litan / kojo

The Kojo Learning Environment
http://www.kogics.net/kojo
Other
69 stars 22 forks source link

Kojo gets stuck in fullscreen in MacOS #21

Open bulent2k2 opened 3 years ago

bulent2k2 commented 3 years ago

Had to reboot the macbook. No key or key combo worked. Esc, Cmd-Tab, Cmd-Ctr-F.

The code that's the culprit is rather simple (see below).

It worked fine until I switched to full screen and then back, turned on the axes (not sure that's relevant, but just to capture the sequence of events. I will write again after root-causing this), turned the axes off again and the keys (defined below) stopped working. I then switch it to full screen using the context menu (stupid thing to do, but, that's hindsight for you :-) and got stuck. Now that I captured this so far, let me try to reproduce it. Wish me luck.

onKeyPress {
    case 90 => { // pressed z
        removeLastPoint()
        println(points.size + " points now")
    }
    case 67 => { // pressed c
        if (emptyStack()) { println("stack empty now") }
        else {
            val oldPoint = popFromStack()
            points.append(oldPoint)
            println(s"${points.size}")
            if (points.size > 2) {
                drawTriangles()
            }
        }
    }
    case 88 => { // pressed x
        while (!emptyStack) removedPoints.pop
        println("empty")
    }
    case a => println(s"$a")
}
bulent2k2 commented 3 years ago

Ok, thanks to my son playing with Kojo, and his sharper observational skills (there is nothing like being 10! :-), we now suspect it is the "Clear" command in the context menu of the canvas that caused this. Once we click on it, the onKeyPress stops working.

litan commented 3 years ago

Once you do a clear, all event handlers are gone. So that part seems to be working as expected. Can you reproduce the hang?

btw, the code fragment above is missing stuff. It does not compile...

bulent2k2 commented 3 years ago

The full code below. I will have to get back to reproducing it.. (I wasn't too eager as I need to reboot the mac again to get out of it if I can successfully reproduce it :-)

// üçgen desenle kaplama (delaunay triangulation)
// her tıklama yeni bir nokta ekler
// noktaları üçgenlerle bağlıyoruz
// son noktayı silmek için sola bakan ok (yani geri gitme tuşuna) 
// ya da z tuşuna bas. z'ye bastıkça silmeye devam eder
// silinen son noktayı geri koymak için sağa bakan oka (yani ileri gitme tuşuna)
// ya da c'ye bas. c'ye bastıkça geri koymaya devam eder
// silinen noktaları tamamen unutmak için x'e bas.

cleari()
clearOutput()
setBackground(white)
disablePanAndZoom()
val cb = canvasBounds
val points = ArrayBuffer(Point(-100, -50), Point(100, -50), Point(-100, 50))

onMouseClick { (x, y) =>
    points.append(Point(x, y))
    println(s"Şimdi ${points.size} nokta var. Yeni nokta: ($x, $y)")
    if (points.size > 2) {
        drawTriangles()
    }
}

import collection.mutable.Stack
val removedPoints = Stack.empty[Point]
def pushToStack(p: Point) = removedPoints.push(p)
def popFromStack() = removedPoints.pop
def emptyStack() = removedPoints.size == 0

onKeyPress { key =>
    {
        def back = {
            removeLastPoint()
            println(points.size + " nokta kaldı")
        }
        def fwd = if (emptyStack())
            println("Başka silinmiş nokta kalmadı")
        else {
            val oldPoint = popFromStack()
            points.append(oldPoint)
            println(s"${points.size} noktaya çıktı")
            if (points.size > 2) {
                drawTriangles()
            }
        }
        key match {
            case 37 => back // arrow left
            case 90 => back // z
            case 39 => fwd // arrow right
            case 67 => fwd // c
            case 88 => { // pressed x
                while (!emptyStack) removedPoints.pop
                println("Çöpü boşalttık")
            }
            case a => println(s"$a nolu tuşa bastın")
        }
    }
}
def removeLastPoint() {
    if (points.size > 0) {
        pushToStack(points(points.size - 1))
        points.remove(points.size - 1)
    }
    if (points.size > 2)
        drawTriangles()
    else
        erasePictures()
}
def drawTriangles() {
    erasePictures()
    val trs = triangulate(points)
    println(s"${trs.size} üçgen var")
    trs.foreach { t =>
        val pic = Picture {
            val lg = cm.linearGradient(t.a.x, t.a.y, black, t.b.x, t.b.y, blue)
            setFillColor(lg)
            setPenColor(gray)
            setPosition(t.a.x, t.a.y)
            lineTo(t.b.x, t.b.y)
            lineTo(t.c.x, t.c.y)
        }
        draw(pic)
    }
}

val message1 = penColor(black) -> Picture.text("Tıklayınca başlar", 40)
val message2 = penColor(black) -> Picture.text("Tıkladıkça devam eder", 30)

val msg = picColCentered(message2, Picture.vgap(20), message1)
drawCentered(msg)
bulent2k2 commented 3 years ago

Played with it quite a bit, but, couldn't reproduce it :-( Upon second thought, I don't think it is the "Clear" command in the context menu of the canvas. I distinctly remember seeing the triangles during the full-screen that got stuck. I suspect that it is one of the other commands in the context menu, as I think I remember that the event loop froze first and then I switched to full-screen. But, I can't be sure. When the event loop didn't respond to any keyboard event during the freeze, it didn't respond to mouse click events either. The triangulation didn't change despite many mouse clicks and keyboard events... But, I was also changing the Kojo script, especially the onKeyPress part..

litan commented 3 years ago

Ok, let me know if you run into this again (I am also unable to reproduce the problem). One thing to note is that - whatever Kojo does should never freeze the OS. If it does, there's a bug somewhere in the OS (triggered in this case by the JVM)!

bulent2k2 commented 3 years ago

I will! Bug in OS is very likely as this happened soon after the OS was upgraded to BigSur. Bunch of other stuff had some crashes (e.g., tkdiff/tcl/wish) and even the kojo exec script in the package (from makezip.sh) had issues.

bulent2k2 commented 3 years ago

I had another encounter with this issue. This time, there was an infinite loop nested within onMouseClick { ... }. The escape key becomes inactive, I believe. No other key (Cmd/Ctrl etc.) in MacOS had any effect and I had to reboot the machine again. Just try it with while(true) {} within onMouseClick { ... } and click on the button. If it doesn't reproduce for you, I will re-produce on my end and submit the code/stack trace. Please let me know.

litan commented 3 years ago

Just try it with while(true) {} within onMouseClick { ... }

If you put an infinite loop in a GUI thread callback, the Kojo GUI will freeze. That is the expected behavior. But that should not freeze the OS!

On Linux, after freezing Kojo via the above method, I can go (for example) to the terminal and kill the frozen Kojo process.

bulent2k2 commented 3 years ago

I agree 100%. The issue is a problem only in fullscreen mode in MacOS where none of the keys like Esc or Cmd-Tab work to switch to another window like terminal or even bring up the Force-Stop program. So, yes, there is no freezing, but, there doesn't seem to be any way to get out of fullscreen. I suspect this won't happen in Windows due to Ctrl-Alt-Delete interrupt to fullscreen which brings up the task manager... Or in Linux where a similar interrupt (maybe Ctrl-C or Ctrl-D) is likely to work..

litan commented 3 years ago

Yes. On Linux (in fullscreen mode), you can just Alt-Tab to switch away or run a keyboard shortcut to open a terminal.

bulent2k2 commented 3 years ago

Here is what I just confirmed in MacOS (Version 11.1, Big Sur): 1) Run Kojo 2) Switch to full-screen mode using the "Full-Screen Canvas" command in the context menu of the Canvas. 3) Cmd-Tab to switch away doesn't work. Note: No need to run a script. Cmd-Tab works in non-full screen mode.

Is it Kojo that disables Cmd-Tab functionality in full-screen mode? I checked some other apps and even in full-screen Cmd-Tab works.

It is also interesting and may provide a hint that Cmd-Shift-3 (screen capture) does work in full-screen, but the related Cmd-Shift-4 (screen capture with interactive bounding box) does not. Just to note, they both work in non-full screen mode as expected even when the focus is in the canvas.

Finally, please also note that when all of Kojo is switched to full-screen (using the green dot on the upper left of every macOs window), Cmd-Tab works. Only when we get into Full-Screen Canvas mode, Cmd-Tab is disabled.

litan commented 3 years ago

Is it Kojo that disables Cmd-Tab functionality in full-screen mode?

Nope. Alt-Tab works fine to switch away on Linux. Must be some JVM/MacOS thing.

bulent2k2 commented 3 years ago

It might be helpful to know that Cmd-Option-Esc combo forcibly quits Kojo when Kojo is in fullscreen mode. This saves a reboot for me when JVM is stuck. That's at least the case in MacOS v11.4 (Big Sur).

In non-fullscreen, the same combo brings up the "Force Quit Applications" window.