VCL application in its minimal form

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. Previously, we discussed some of them in this post.

Now, I want to discuss the code of the simplest example: minvcl.

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.

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, comes 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>

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 \
))...

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>

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;
}

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.

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. 🙂

minvcl

The minvcl window

Final Notes

There are many complex things that you can do with VCL, but this was the simplest example that you can possibly create! I will discuss creating more complex applications that create user interfaces with things like buttons, text and many other UI things. The nice thing about VCL is that you can even create UI from the widgets created from the .ui files designed with Glade. This makes creating GUIs much easier.

I will discuss more complex examples in the next blog posts.