Development/VCL/minvcl

    From The Document Foundation Wiki

    LibreOffice uses an internal GUI toolkit, named VCL (Visual Class Library). It creates the GUI widgets for LibreOffice, but it is not generally available for other applications. But there are ways that you can create standalone applications with VCL, at least to learn it better.

    If you take a look into the vcl/workben, you will see several workbenches that are actually built during the build process. Here, we discuss the code of the simplest example: minvcl.

    Minimal VCL Application

    It basically creates a simple application with a single window, and that's all! But even doing that needs several steps. Let's discuss the code itself.

    Header Includes

    First come the includes. The include sal/config.h should come with each and every file in LibreOffice, and also VCL. Then, we have several includes from framework, cpppuhelper, comphelper, com/sun/star/lang and com/sun/star/uno, and then language classes from i18nlangtag.

    #include <sal/config.h>
    #include <framework/desktop.hxx>
    #include <cppuhelper/bootstrap.hxx>
    #include <comphelper/processfactory.hxx>
    #include <com/sun/star/lang/XMultiServiceFactory.hpp>
    #include <com/sun/star/uno/XComponentContext.hpp>
    #include <i18nlangtag/languagetag.hxx>
    #include <i18nlangtag/mslangid.hxx>

    After that, come the includes from VCL. We only use two: the one for a VCL application, and another for a VCL window:

    #include <vcl/svapp.hxx>
    #include <vcl/wrkwin.hxx>

    And at last, the include file for the main function of the VCL application. Every VCL application is supposed to have SAL_IMPLEMENT_MAIN() instead of main(), which is declared in this file.

    #include <sal/main.h>
    #include <iostream>

    Makefiles

    Keep in mind that you have to provide the link libraries via the make file. In this case, the make file is vcl/Executable_minvcl.mk:

    ...
    $(eval $(call gb_Executable_use_libraries,minvcl,\
        tl \
        sal \
        vcl \
        cppu \
        cppuhelper \
        comphelper \
        i18nlangtag \
        fwk \
    ))
    ...

    Application-inherited Class

    The class TheApplication should fall into an anonymous namespace. This class inherits the VCL application class with the name of Application. As you can see, we keep a VclPtr to a vcl::Window named mpWin that keeps a pointer to our window.

    namespace
    {
    class TheApplication : public Application
    {
    public:
        virtual int Main();
    
    private:
        VclPtr<vcl::Window> mpWin;
    };
    }

    In the main file, we use a method named Create() to create a window. Then, we set the title using SetText(), and then invoke show() to make the window visible on the screen. This is the main file of the VCL application. It is the entry point for the application.

    int TheApplication::Main()
    {
        mpWin = VclPtr<WorkWindow>::Create(nullptr, WB_APP | WB_STDWORK);
        mpWin->SetText(u"Minimum VCL application with a window");
        mpWin->Show();
        Execute();
        mpWin.disposeAndClear();
        return 0;
    }

    Main Function

    We use LibreOffice APIs to create a component context and a service manager. The setProcessServiceFactory() function is used to set the service manager for the process. To understand the service manager, you can refer to the DevGuide:

    The LanguageTag::setConfiguredSystemLanguage() function sets the language of the application to the system language. Finally, the framework::getDesktop() function terminates the framework and the DeInitVCL() function frees VCL resources.

    SAL_IMPLEMENT_MAIN()
    {
        try
        {
            TheApplication aApp;
    
            auto xContext = cppu::defaultBootstrap_InitialComponentContext();
            css::uno::Reference<css::lang::XMultiServiceFactory> xServiceManager(
            xContext->getServiceManager(), css::uno::UNO_QUERY);
            comphelper::setProcessServiceFactory(xServiceManager);
            LanguageTag::setConfiguredSystemLanguage(MsLangId::getSystemLanguage());
            InitVCL();
    
            aApp.Main();
    
            framework::getDesktop(::comphelper::getProcessComponentContext())->terminate();
            DeInitVCL();
            comphelper::setProcessServiceFactory(nullptr);
        }
        catch (...)
        {
            std::cout << "Exception has occurred\n";
            return 1;
        }
    
        return 0;
    }

    We should handle the exception in the main function. Here, we just print a simple text to make the user aware that some bad thing has happened.

    Running Application

    That's all! The application is complete now. You can run it via:

    ./bin/run minvcl

    Keep in mind that you have to compile LibreOffice first.