Prevent ''Waiting for image operation to complete' dialog box from stealing attention? (KDE plasma)

Hi,

I’m working on a multi-layer interchange exporter for Krita.
I’m testing this on a real animation project in krita with animated cell sequence key frames and nested transform masks. The addon prepares it so it can go to other apps like blender.

When the exporting, it’s firing procedural on all layers, processing and exporting them individually. For each layer there is this ‘waiting for image operation to complete’ message that pulls the user back into loading process from what ever application they were in; stealing focus and preventing multi-tasking.

I would like for the user to be able to use their computers to do other things while they wait for an export to run. The way it pulls attention back means the user can’t user their pc for the duration of this process that can take as long as 15 minutes on heavy 8k scenes. This is a massive problem for batch exporting, as technical artists are busy and need all the time they can spare.

How would I handle this so that Krita only pulls attention at MAX; once when complete?

I’m on the fedora like distro; Nobara 43, and I’m using KDE plasma 6.5.4.

-S

Not sure if this is the thing you are looking for: Document::batchMode()
From the docs here Krita - Document Class Reference

I’ve got something somewhere that I use sometimes to save a bunch of documents, looks like this:

def saveDoc(doc):
    bm = doc.batchmode()
    doc.setBatchmode(True)
    fname = doc.fileName()
    if not fname:
        with tempfile.NamedTemporaryFile(
            delete=False
        ) as tf:
            doc.saveAs(tf.name + ".kra")
    else:
        doc.saveAs(fname)
    doc.setBatchmode(bm)
    

# example if you do all docs
for doc in app.documents():
    saveDoc(doc)


Hi @vurentjie,

Thanks for taking a look.

Clarifications:

• Export runs with Document.setBatchmode(True)
• The plugin does not show any modal dialogs
• The focus-stealing dialog appears to be Krita’s internal
“Waiting for image operation to complete”

The exporter does:

  • Repeated node.save(...)
  • Frequent setCurrentTime() frame switching
  • Per-layer export across animated frames

This intermittently triggers the dialog and it steals desktop focus.

Two observations:

  1. Document.saveAs() in batchmode does NOT trigger this.
  2. The issue correlates with repeated Node.save(...) inside a tight loop.

I can reproduce similar behaviour with a minimal script that:

  • switches frame
  • calls node.save(...)
  • repeats in a loop
    with batchmode enabled.

So the core question is:

Is there a supported way to prevent Krita’s internal “Waiting for image operation” modal from appearing during scripted batch operations that repeatedly call Node.save()?

Or alternatively, is there an API-supported way to explicitly drain or await the image operation queue (e.g. waitForDone()) to prevent the modal from being raised?

Thanks.

Ok not sure then really.

Maybe it is Krita.instance().setBatchmode(True) and not Document.setBatchmode.

But I tried in a rough way to do what you said about switching frames, but couldn’t repro what you are experiencing:

ki = Krita.instance()
doc = ki.activeDocument()

ki.setBatchmode(True) 
for i in range(1,100):
    ki.action('next_frame').trigger()
    doc.activeNode().save(f"/home/vurentjie/Downloads/test{i}.jpeg", 100.0, 100.0, InfoObject())
ki.setBatchmode(False)      

Hi @vurentjie

Thanks for trying that, really helpful.

A couple of differences that might explain why it does not reproduce on your side:

  • The issue seems load-sensitive. It happens on an 8K animation document with many layers and repeated saves, not on small docs.
  • Using action('next_frame').trigger() might drive the UI path, not the same as setting time directly. My exporter uses direct time changes and then saves.
  • The exporter calls node.save(...) many times across different nodes, not just activeNode().

However, at this point it may be easier if you test the actual exporter branch directly, since the behaviour seems load- and document-sensitive.

Here is the OCA branch I’m testing:

Reproduction steps:

  1. Open the attached test document (8K animation, multiple layers).
  2. Start export.
  3. Switch focus to another application while export runs.
  4. The “Waiting for image operation to complete” dialog intermittently steals focus back to Krita.

It does not occur (as much) on small test documents, and I have not been able to isolate it down to a minimal snippet yet.

Try testing this on a heavy document with many layers, preferably with clone layers and transform layers.

-S

Will take a look when I can. Didn’t see any attached test doc. If you can share a link it would be helpful too.

I guess there is some small time gap when frames switch and transforms re-apply that the image is in an indeterminate state where saving would break. And it’s more noticable on complex scenes.

So there is definitely no api call to check for this. The dialog is called KisDelayedSaveDialog, you can browse Krita’s source to get an idea of it’s usage. This dialog checks a image.isIdle method that is not available in pykrita.

Below snippet can turn off the blocking feature of the dialog so the rest of the ui is accessible.
But not sure how safe this is, and also not sure how well it works if multiple dialogs are spawned or if the user interacts with the document. It’s a bit of a hack.

from PyQt5.QtCore import QObject, QEvent, Qt
from PyQt5.QtWidgets import QApplication, QDialog

class DelayedSaveDialogWatcher(QObject):
    def eventFilter(self, obj, event):
        if event.type() == QEvent.Show and isinstance(obj, QDialog):
            cls = obj.metaObject().className()
            if cls == 'KisDelayedSaveDialog':
                obj.setWindowModality(Qt.NonModal)
                obj.setAttribute(Qt.WA_ShowWithoutActivating, True)
        return False

# demo usage, make sure to attach the watcher 
# to some other object so it's not garbage collected
ki = Krita.instance()
ki.watcher = DelayedSaveDialogWatcher()
QApplication.instance().installEventFilter(ki.watcher)

Any way, good luck, hope you figure something out.

(One more thing, if you don’t mind alternative workflows, maybe you can try moving the document to a second Krita window, and exporting it there. Let the user continue in the first window. )

Thanks, I think that might be the kind of pointer I needed.

Knowing this is KisDelayedSaveDialog and that it’s gating on image.isIdle() (not exposed to PyKrita) explains a lot. The “indeterminate state” during frame switching/transforms also matches what I’m seeing: it’s much more noticeable on complex scenes.

Your eventFilter approach is interesting. Even if it’s a hack, it may be the only practical way in Python to stop the dialog from stealing focus during long batch exports.

A couple of clarifications so I can try to implement it as safely as possible:

  1. Is KisDelayedSaveDialog the only dialog class I should be filtering for this, or are there other internal “delayed save / image operation” dialogs that can also steal focus during Node.save() loops?

  2. Do you know if making it NonModal + WA_ShowWithoutActivating is the least-bad approach, or is there a better attribute/flag combination that avoids breaking the protection logic?

My preference is for long-running scripted exports to not repeatedly pull focus back from other applications. Users often need to keep working outside Krita during a 10-15 minute export.

I might try this watcher approach and report back if it behaves consistently or if multiple dialogs create edge cases.

Thanks again for digging into it.

-S

Most dialogs in Krita will block focus, e.g Scale Image, Configure Krita, any of the filter dialogs.

But this is the only one that is going to do that in your case.

There are 3 variations of this dialog with the same className,

  • one with Save/Cancel/Close buttons, (appears when you try save while the image is still processing)
  • one with just a single cancel button that can be dismissed, (appears for a few other cases, maybe when trying to switch or manipulate layers),
  • and one without any close buttons (cannot be dismissed) (checked whenever the image data is accessed)

I think the one problematic scenario is this:

  • the dialog appears
  • the script removes the blocking
  • the user interacts with the busy document while the dialog is still visible (maybe even just gives it focus by clicking on it or on the tab)

I am not entirely sure what Krita will do in this case, maybe it will just respawn a second dialog (perhaps one of the other variations mentioned above), maybe it will freeze.

I think you will have to experiment to figure out how and if it works in your case.

(Maybe you could also try closing/hiding the dialog automatically as soon as it appears. So that if the user interacts with the document again, it doesn’t spawn multiple dialogs. But not sure if that is possible or breaks anything. I didn’t try it.)