How do you close LibreOffice Calc from a macro?

I am writing a shell script that runs a macro on a specified document in LibreOffice Calc. After the macro is ran, I would like Libre to automatically close. However, if I try to kill Libre from the script, it just crashes and freezes up instead of closing, so I was wondering if it might be possible to just run some command at the end of the macro that would close LibreOffice.

I also tried running it in both headless and invisible mode, but I must’ve had a misunderstanding of what they do, because all they did was prevent any dialogue boxes from popping up instead of actually preventing Libre from pooping up. If it helps any here is the line from the shell that starts Libre, opens the file, and runs the macro:

  soffice "macro:///Standard.SaveCSV.Main" $1

All help is appreciated!

The particular systems that this script will go on will not have the wmctrl tool, so that’s out. I need another way to gracefully shut down office. When I tried using killall to bring it down, the next time I’d start it up, it would want to do recovery mode, and I can’t have that. Also, we don’t need to worry about document saving because that is the point of this macro (sorry for not mentioning that earlier). This would be so much easier if there were some kind of close command in Basic.

Hi @Goody, Adding a close command to LibreBasic sounds like a fine idea. Please file an enhancement bug and provide as much information as possible. The QA team will be happy to help you triage your feature request in the bugtracker. Thanks!

You didn’t mention your operating system, but I’ve done something on linux that may be adaptable. I kill all instances of openoffice (never tried on libreoffice) with a cron script and the wmctrl tool. You might start a bash script from your macro that does the same. You may need to detach it from the initiating process. It will kill all instances of openoffice.

export DISPLAY=:0  # may not be needed except with cron
until [ -z "$(pgrep soffice.bin)" ] #for all openoffice instances
do
/usr/bin/wmctrl -c openoffice 2> /dev/null #close all openoffice instances
done
/usr/bin/killall soffice.bin  #this line forces closed all docs left in an unclosed state, otherwise they pop up a save dialog.

My OS is Red Hat Enterprises Linux 6. I will have to try to see if I can’t get the above code to work. Thanks.

(note to self: you can’t use comments to resolve q’s! :slight_smile:

If you’ve found a function that works for you, please describe it in an Answer to this question. If not, please file an enhancement bug and provide as much information as possible. The QA team will be happy to help you triage your feature request in the bugtracker.

If you do file an enhancement bug, please post a link to it in a comment below using the format “fdo#123456”.

Thanks for the input – this sounds like it would be a really good enhancement for LO!

In python, I do it like this. First, I run a bash script that launches a libreoffice instance that I can connect to:

#/bin/bash
# First we check if any other libreoffice instances are already running
# of course, if an instance is opened meanwhile, it will be closed.    
ps cax | grep soffice.bin > /dev/null
if [ $? -eq 0 ]; then # libreoffice is running, so just close the window we opened
    arg="--close-window"
 else # it was not running, kill it all
    arg="--close-office"
 fi
libreoffice "--accept=pipe,name=some_name;urp;StarOffice.Servicemanager" ~/test.ods &
sleep 3 # we need time to connect    
~/.config/libreoffice/4/user/Scripts/python/vytvor_fakturu.py $arg

Credit for checking if the process is running goes here.
my_script.py is then (largely based on this) like this:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""In Libreoffice 4, python3 is default, so this script needs to be python3 too
Unicode is just good practise.
I guess this line is different on Windows."""

import uno
from pythonscript import ScriptContext
import sys

def connect_to_office():
     """We connect to libreoffice only when run externally.
     If that is the case, XSCRIPTCONTEXT is not in global scope."""
    if not 'XSCRIPTCONTEXT' in globals():
        localContext = uno.getComponentContext()
        resolver = localContext.ServiceManager.createInstanceWithContext(
                         'com.sun.star.bridge.UnoUrlResolver', localContext )
        client = resolver.resolve("uno:pipe,"
                        "name=some_name;" 
                        "urp;"
                        "StarOffice.ComponentContext")
        global XSCRIPTCONTEXT
        XSCRIPTCONTEXT = ScriptContext(client, None, None)

"""this is the macro that would be run firectly from libreoffice"""
def run_all():
    connect_to_office()
    oDoc = XSCRIPTCONTEXT.getDocument()
    """I assume a calc file here, this prints Hello world to cell A1"""
    oSheet = oDoc.CurrentController.ActiveSheet
    oCell = oSheet.getCellRangeByName("A1")
    oCell.String = 'Hello world!'
    if cmd_argument == '--close-office':
        oDoc.close(0) # if we do not close the document first, libreoffice will ask if we want to save changes
        d = XSCRIPTCONTEXT.getDesktop()
        d.terminate() # this closes all instances, I think
    elif cmd_argument == '--close-window':
        oDoc.close(0) # this just closes the document we connected to but soffice.bin will continue to run

    """Libreoffice allows to run functions as macros, but in a script
executed from a shell, any function needs to be run, but we must
make sure it is not run twice in case it is run directly
from libreoffice."""
if __name__ == "__main__":
     if len(sys.argv) > 1: # do not throw exceptions when the script is run without arguments
        run_all(sys.argv[1])
"""Make only this macro visible to libreoffice UI.
I.e., it hides connecto_to_office macro.
The comma at the end is important."""
g_exportedScripts = run_all,

Oh what a mess :wink:
from now on every Pipe to LO will have the Name abraxas.
I should rename my own to something other :wink:

Oh, I have not realized that actually meant something. It is easy to change:-).

Doc.close(true)

oDocument.close(true)

ThisComponent.CurrentController.Frame.Close(False)

probaly this could help