A quick plugin, to restart Krita and reopen documents
Provided “provided as is” , no file to download, you have to create plugin files by yourself
Code is under GPL v3 license 
Installation
In krita/pykrita
directory
Step 1)
Create file restart.desktop
with following content
Code
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=restart
X-Python-2-Compatible=false
X-Krita-Manual=Manual.html
Name=Restart
Comment=Restart plugin
Step 2)
Create sub-directory restart
Step 3)
In sub-directory restart
, create file __init__.py
with following content
Code
from .restart import Restart
# And add the extension to Krita's list of extensions:
app = Krita.instance()
# Instantiate your class:
extension = Restart(parent=app)
app.addExtension(extension)
Step 4)
In sub-directory restart
, create file restart.py
with following content
Code
from PyQt5.Qt import *
from krita import *
import re
import os
import sys
import random
import subprocess
EXTENSION_ID = 'pykrita_restart'
MENU_ENTRY = 'Restart Krita'
class Restart(Extension):
ACTION_CANCEL=0
ACTION_SAVE_DOC=1
ACTION_IGNORE_DOC=2
__FILE_AFTER_RESTART="filesAfterRestart.txt"
def __init__(self, parent):
"""Initialise plugin"""
super().__init__(parent)
# determinate path where to save temp files
# prefer a local applicaion directory rather than a /tmp directory
paths=QStandardPaths.standardLocations(QStandardPaths.AppDataLocation)
if len(paths):
self.__tempPath=paths[0]
else:
self.__tempPath=QStandardPaths.standardLocations(QStandardPaths.HomeLocation)[0]
self.__fileAfterRestart=os.path.join(self.__tempPath, Restart.__FILE_AFTER_RESTART)
# openeded documents dictionnary
self.__docs={}
def setup(self):
"""Executed at Krita startup, beofre main window is created"""
# define a trigger, to let plugin reopen document as soon as window is created
Krita.instance().notifier().windowCreated.connect(self.onWindowCreated)
@pyqtSlot()
def onWindowCreated(self):
"""Slot executed when Krita window is created"""
if os.path.isfile(self.__fileAfterRestart):
# if a file with list of document exists, process it to open documents
Krita.instance().activeWindow().qwindow().setCursor(Qt.WaitCursor)
with open(self.__fileAfterRestart, 'r') as file:
fileContent=file.read()
# there's one file per line
files=fileContent.split("\n")
for fileName in files:
# just be sure to avoid empty lines..
if fileName!='':
# open document and attach it to current window
doc=Krita.instance().openDocument(fileName)
Krita.instance().activeWindow().addView(doc)
if re.search(r"\\tempDocToDelete_\d{4}_\d{6}\.kra$", fileName):
# this is a temp file, delete it
os.remove(fileName)
# remove name (as it was when Krita has been restarted)
# -- works on Windows, not on Linux...
# -- need to find a way to fix this in Linux
doc.setFileName("")
# remove file with list of document (be sure to not reopened it on next "normal" Krita close/start)
os.remove(self.__fileAfterRestart)
Krita.instance().activeWindow().qwindow().unsetCursor()
def createActions(self, window):
"""Add menu entry for plugin"""
action = window.createAction(EXTENSION_ID, MENU_ENTRY, "tools/scripts")
action.triggered.connect(self.actionRestart)
def actionRestart(self):
"""Execute restart action"""
# check if documents are opened, and ask for user confirmation
action=self.__checkOpenedDocuments()
if action==Restart.ACTION_CANCEL:
# do not restart...
return
elif action==Restart.ACTION_SAVE_DOC:
# user asked for an automatic save of documents
self.__saveDocuments()
# close documents before restart (and define file with list of document to reopen)
self.__closeDocuments()
# -- restart --
if sys.platform=='win32':
# running on Windows
readyToRestart=self.__restartOsWindow()
elif sys.platform=='linux':
readyToRestart=self.__restartOsLinux()
else:
# need to implement restart process for Linux, MacOS
readyToRestart=False
if readyToRestart:
# ok, possible to restart
QApplication.quit()
else:
QMessageBox.warning(None, "Restart Krita", "Unable to initialise restart process\nAction cancelled")
def __restartOsLinux(self):
"""Linux specific process to restart Krita
Might be OK on *nix environment...
"""
kritaPid=os.getpid()
pidCheckCmd=f"ps -p {kritaPid} -o cmd --no-headers"
kritaPath=os.popen(pidCheckCmd).read().replace("\n","")
shCmd=f"sh -c 'while [ $({pidCheckCmd}) ]; do sleep 0.5; done; {kritaPath}&'&"
os.system(shCmd)
return True
def __restartOsWindow(self):
"""Windows 10 specific process to restart Krita
Might be OK on Windows 11, maybe Ok on Windows 7...
"""
kritaPid=os.getpid()
kritaPath=sys.executable
# note:
# following "EncodedCommand":
# cABhAHIAYQBtACAAKAANAAoAIAAgAFsAUABhAHIAYQBtAGUAdABlAHIAKABNAGEAbgBkAGEAdABvAHIAeQA9ACQAdAByAHUAZQApAF0AWwBpAG4AdABdACQAawByAGkAdABhAFAAaQBkACwADQAKACAAIABbAFAAYQByAGEAbQBlAHQAZQByACgATQBhAG4AZABhAHQAbwByAHkAPQAkAHQAcgB1AGUAKQBdAFsAcwB0AHIAaQBuAGcAXQAkAGsAcgBpAHQAYQBQAGEAdABoAA0ACgApAA0ACgANAAoAWwBiAG8AbwBsAF0AJABsAG8AbwBwAD0AJABUAHIAdQBlAA0ACgB3AGgAaQBsAGUAKAAkAGwAbwBvAHAAKQAgAHsADQAKACAAIAAgACAAdAByAHkAIAB7AA0ACgAgACAAIAAgACAAIAAgACAAJABwAD0ARwBlAHQALQBQAHIAbwBjAGUAcwBzACAALQBpAGQAIAAkAGsAcgBpAHQAYQBQAGkAZAAgAC0ARQByAHIAbwByAEEAYwB0AGkAbwBuACAAJwBTAHQAbwBwACcADQAKACAAIAAgACAAIAAgACAAIABTAHQAYQByAHQALQBTAGwAZQBlAHAAIAAtAE0AaQBsAGwAaQBzAGUAYwBvAG4AZABzACAANQAwADAADQAKACAAIAAgACAAfQANAAoAIAAgACAAIABjAGEAdABjAGgAIAB7AA0ACgAgACAAIAAgACAAIAAgACAAIwAgAG4AbwB0ACAAZgBvAHUAbgBkAA0ACgAgACAAIAAgACAAIAAgACAAIwAgAGUAeABpAHQAIABsAG8AbwBwAA0ACgAgACAAIAAgACAAIAAgACAAJABsAG8AbwBwAD0AJABGAGEAbABzAGUADQAKACAAIAAgACAAfQANAAoAfQANAAoADQAKAEkAbgB2AG8AawBlAC0ARQB4AHAAcgBlAHMAcwBpAG8AbgAgACQAawByAGkAdABhAFAAYQB0AGgA
# is a base64 encoded powershell script
# """
# param (
# [Parameter(Mandatory=$true)][int]$kritaPid,
# [Parameter(Mandatory=$true)][string]$kritaPath
# )
#
# [bool]$loop=$True
# while($loop) {
# try {
# $p=Get-Process -id $kritaPid -ErrorAction 'Stop'
# Start-Sleep -Milliseconds 500
# }
# catch {
# # not found
# # exit loop
# $loop=$False
# }
# }
#
# Invoke-Expression $kritaPath
# """
#
# ==> recommended: decode Base64 string by yourself to be sure of its content :-P
#
cmdParameters=f"/c powershell -noprofile -ExecutionPolicy bypass -command '{kritaPid}', '{kritaPath}' | powershell -noprofile -ExecutionPolicy bypass -EncodedCommand cABhAHIAYQBtACAAKAANAAoAIAAgAFsAUABhAHIAYQBtAGUAdABlAHIAKABNAGEAbgBkAGEAdABvAHIAeQA9ACQAdAByAHUAZQApAF0AWwBpAG4AdABdACQAawByAGkAdABhAFAAaQBkACwADQAKACAAIABbAFAAYQByAGEAbQBlAHQAZQByACgATQBhAG4AZABhAHQAbwByAHkAPQAkAHQAcgB1AGUAKQBdAFsAcwB0AHIAaQBuAGcAXQAkAGsAcgBpAHQAYQBQAGEAdABoAA0ACgApAA0ACgANAAoAWwBiAG8AbwBsAF0AJABsAG8AbwBwAD0AJABUAHIAdQBlAA0ACgB3AGgAaQBsAGUAKAAkAGwAbwBvAHAAKQAgAHsADQAKACAAIAAgACAAdAByAHkAIAB7AA0ACgAgACAAIAAgACAAIAAgACAAJABwAD0ARwBlAHQALQBQAHIAbwBjAGUAcwBzACAALQBpAGQAIAAkAGsAcgBpAHQAYQBQAGkAZAAgAC0ARQByAHIAbwByAEEAYwB0AGkAbwBuACAAJwBTAHQAbwBwACcADQAKACAAIAAgACAAIAAgACAAIABTAHQAYQByAHQALQBTAGwAZQBlAHAAIAAtAE0AaQBsAGwAaQBzAGUAYwBvAG4AZABzACAANQAwADAADQAKACAAIAAgACAAfQANAAoAIAAgACAAIABjAGEAdABjAGgAIAB7AA0ACgAgACAAIAAgACAAIAAgACAAIwAgAG4AbwB0ACAAZgBvAHUAbgBkAA0ACgAgACAAIAAgACAAIAAgACAAIwAgAGUAeABpAHQAIABsAG8AbwBwAA0ACgAgACAAIAAgACAAIAAgACAAJABsAG8AbwBwAD0AJABGAGEAbABzAGUADQAKACAAIAAgACAAfQANAAoAfQANAAoADQAKAEkAbgB2AG8AawBlAC0ARQB4AHAAcgBlAHMAcwBpAG8AbgAgACQAawByAGkAdABhAFAAYQB0AGgA"
return QProcess.startDetached("cmd", [cmdParameters])
def __checkOpenedDocuments(self):
"""Check if there's documents opened and ask user for confirmation
Build a dictionnary of documents name <> document instance
"""
self.__docs={}
numTempDoc=1
numModified=0
for doc in Krita.instance().documents():
if doc.fileName()=='':
# doc not yet saved, produce a tmp filename
fileName=os.path.join(self.__tempPath, f"tempDocToDelete_{numTempDoc:04}_{random.randint(1,999999):06}.kra")
self.__docs[fileName]=doc
else:
self.__docs[doc.fileName()]=doc
if doc.modified():
numModified+=1
if numModified==0:
userAnswer=QMessageBox.question(None, "Restart Krita", "Do you really want to restart Krita?", QMessageBox.Yes|QMessageBox.No)
if userAnswer==QMessageBox.No:
return Restart.ACTION_CANCEL
else:
# no documents modified, ignore
return Restart.ACTION_IGNORE_DOC
else:
userAnswer=QMessageBox.question(None, "Restart Krita", "There's some unsaved documents\nSave documents before restarting Krita?", QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel)
if userAnswer==QMessageBox.Cancel:
return Restart.ACTION_CANCEL
elif userAnswer==QMessageBox.Yes:
return Restart.ACTION_SAVE_DOC
else:
return Restart.ACTION_IGNORE_DOC
def __closeDocuments(self):
"""Close all documents from dictionnary
Save document list in temporary text file
"""
docList=[]
for docName in self.__docs:
if doc:=self.__docs[docName]:
if doc.fileName()!='':
docList.append(doc.fileName())
doc.close()
if len(docList)>0:
with open(self.__fileAfterRestart, 'w') as file:
file.write('\n'.join(docList))
def __saveDocuments(self):
"""Save opened document that are in modified status"""
for docName in self.__docs:
if doc:=self.__docs[docName]:
if doc.modified():
if doc.fileName()=='':
doc.setFileName(docName)
doc.save()
Step 5)
Start Krita, go in Settings > Configure Krita, then Python Plugin Manager and activate Restart plugin
Restart Krita
Plugin is now active; go in Tools > Script > Restart Krita to restart Krita
Plugin is practically complete
Maybe some bugs to fix, or some stuff to improve, especially concerning “not saved” document
But you now have a complete basis to build your own plugin
Works on Windows 10 & Linux
Not tested on OSX
Grum999