Official:Plugin Development

From Scribus Wiki
Revision as of 21:37, 21 December 2010 by Malex (talk | contribs)
Jump to navigation Jump to search


How to write a Scribus Plugin

Preface

This article shows you how to write plugins for Scribus. Plugins are libraries that are loaded into the main application at run-time. Plugins can extend and to an extent modify the behavior of the application without having to edit and recompile the core application. They are useful for adding extra tools, extra import and export functions, and for various more advanced uses.

This document assumes some basic knowledge of C++. You're assumed to know what a header file is, how include files work, know about classes an inheritance, and have some general familiarity with the language. Some familiarity with Qt - mainly QString and QObject - will also help. Issues like virtual and pure virtual functions, "extern C" declarations, the details of memory management, etc are glossed over and avoided in this document. You don't have to know about them, but it'll help you follow what's going on better if you do.

We're not going to try to explain the details of how the Scribus plugin system works here. This is just about how to write a plugin. The documentation in the scplugin.h and pluginmanager.h help explain how the system works.

For any reasonable plugin idea, you will receive encouragement and assistance from the Scribus Team. As rule, we do not do a lot of planning or development discussion by e-mail, but by IRC. Probably 99% of the planning and project discussions take place there. You will find #scribus usually lively during parts of each day. The team is mostly resident in Europe, so Central European Time evenings is when it is busiest.

Where do I find Scribus Plugins?

Scribus ships with a number of standard plug-ins. These will be installed along with the Scribus program and its other files. On UNIX, plug-ins will be installed in the same prefix as the main app. In Mac OS X they're included in the .app bundle. If you want to know what these plug-ins do, the easiest way to find out is to to fire up Scribus and go into Edit->Preferences and click on the "plugins" icon. From there you will see a list of what plug-ins are installed, what type of plug-in they are, and where the files are.

In addition to the plug-ins shipped as standard with Scribus, it is possible to build and install plug-ins you obtain from elsewhere, or to write and add your own.

Before you start coding

Let's suppose you've got a great idea to improve Scribus and you cannot wait to start writing some excellent C++ code. Hold on for just a few minutes and read this section; you might save yourself some time and trouble.

Important

Maybe you are at the edge of "reinventing the wheel" - that is, writing something you don't have to because someone else has already done it. You should probably join the mailing-list and post about your idea, or join the #scribus channel on irc.freenode.net. Your topic will be discussed and you will probably get some help and ideas from the developers and from other users. As Scribus is freely licensed, you're welcome to work on your own, but at least an introductory chat on IRC, or a mail to the mailing list may save hours of work and head banging. We want to make writing plug-ins as painless as possible for those who're interested.

Compatability

Scribus does not have a fixed C++ API for plugins to use. Releases are not binary compatible, and unstable versions frequently break source compatibility. Source compatibility is not currently guaranteed even across stable releases if changes are required to fix a problem. We hope to improve this so we can provide a stable C++ API for external code in the future. For now, if possible you should try to bundle the core of your plugin's functionality into a separate module that knows as little about the innards of Scribus as possible.

This document covers implementing a plugin for Scribus 1.3.x. It is dramatically different to what was required for the 1.2.x series. Future changes should be smaller.

Quick Start

It's not too hard to jump in and start writing a plugin. The documentation below describes the implementation of a plugin in some detail, with references to places where you can find out more if you need it. A "plugin template" is provided for your use, so if you like you can get started by making a copy of that and getting hacking. Some basic instructions are included in the file, and if you get confused you can refer back to this document.

We'll build the plugin as a part of Scribus. That's the easiest way to get started, though you'll probably want to start distributing it separately later on (see later). To start work on an Action plugin:

We use CMake, as support for autotools has been deprecated and moving forward it will be the only one used in 1.3.5+

  • Copy scribus/plugins/myplugin to scribus/plugins/pluginname (where "pluginname" is what you want to call your plugin). pluginname must be a valid C identifier - I suggest sticking to nothing but lower case characters.
  • Edit scribus/plugins/CmakeLists.txt and add "pluginname" to it by adding the subdirectory to the others. This tells Scribus's build system to compile your plugin.
  • rename all the files in scribus/plugins/pluginname/ from myplugin to pluginname, eg myplugin.h to pluginname.h.
  • rename myplugin wherever it appears in the files to pluginname, e.g. myplugin_getPluginAPIVersion() to pluginname_getPluginAPIVersion(). Do the same for MyPlugin and MYPLUGIN. On UNIX, you can use this command:
    sed -i -e "s/myplugin/pluginname/g" -e "s/MyPlugin/PluginName/g" -e "s/MYPLUGIN/PLUGINNAME/g" myplugin*
    (all on one line, run from scribus/plugins/pluginname/).

You're now ready to start work on your plug-in. First, you need to fill out some information about your plug-in in pluginname.cpp:

  • In PluginName::languageChange():
    • Change m_actionInfo.text to the text of the menu item you want to trigger your plugin.
    • Change m_actionInfo.menu to the name of the menu you want the menu item to go in. See FIXME where???? FIXME for a list of menu names.
    • If you want your plugin to have a keyboard shortcut, uncomment m_actionInfo.keySequence and set it to your preferred shortcut. The example there should show you how that works.
  • Change the name in PluginName::fullTrName() to the name of your plugin as you want it to appear in the Help->About Plugins dialog box and in the Plugin Manager pane in the preferences.
  • If you want your plugin to have information such as author info and a description when the user looks at it in Help->About Plugins, fill out as much as you want of the about info by assigning members of about. You can see what information can be provided by looking at the definition of AboutData in scplugin.h.

You've finished setting up the plugin, and can now start programming. Your code should go in pluginnameimpl.cpp and pluginnameimpl.h. The existing code should display a message dialog box.

To compile the plugin, you can simply re-run cmake with your usual options. , and make in the top-level Scribus directory. You may need to remove CmakeCache.txt, but this is becoming a rarer necessity in newer versions of CMake. When the compile completes, run make install and fire up Scribus. Your plugin should now appear in the plugin manager (in the preferences), and should have a menu item. If you press the menu item, a dialog box should appear.

Building plugins outside the Scribus tree

Quick and dirty using QMake

Warning

  • Beware - a qmake project easy to use but isn't necessarily the most standard way to distribute software on the Linux platform. Scribus runs natively on Linux/Unix, MacOSX, OS/2 and Windows. This process is an example only for development. When you create your bug-free functional package then make time to prepare a full featured distributon as described in the next section.
  • Let's compile it, but it isn't so easy as typing in gcc myplugin.cpp ;). One easy way to build it - Qt qmake (because some people really really hate autoconf and automake in their complexity. We've been know to call it worse things more than once. ). Note: you will need to create an empty config.h file before running these steps
  • On Linux or OSX systems where Qt3 and Qt4 are installed parallel, you may need to provide the full path: e.g. /usr/lib/Qt4/qmake
$qmake -project

Now the project file is created and we'll make just a few changes into it.



 ######################################################################
 # Automatically generated by qmake (1.06c) Sun Dec 14 13:32:11 2003
 ######################################################################
 
 #change TEMPLATE = app. We aren't working on application just plugin
 TEMPLATE = lib
 INCLUDEPATH += .
 #As working with Scribus, we need Scribus includes too.
 INCLUDEPATH += /home/subzero/devel/Scribus/include/Scribus/
 #And Scribus have to use freetype2.
 #So we should link it too. Use paths returned from
 ##freetype-config --cflags and --libs
 INCLUDEPATH += /usr/include/freetype2
 LIBS += -lfreetype -lz
 
 # Input
 #create empty config.h file
 HEADERS += myplugin.h config.h
 SOURCES += myplugin.cpp

 

After these changes you're ready to compile

$qmake
$make

Running Qmake creates the Makefile and by running make you compile your plugin.Then just copy *so* files into Scribus plugin directory and run Scribus. You'll see "Do Nothing Plugin" in the Extras menu.

It is clear that you have to use some other way to distribute your source code to others - some use autogenerated qmake pro files, other use the autoconf/automake combination.

Distribute it! (a.k.a. Compile it! 2nd edition)

Qmake is user frendly and useful for rapid development, but traditionally there has been one standard way to compile/distribute software for Linux, *BSD etc. - autoconf and automake. Lets call these two programs by the automagic acronym in the following text.To use automagic successfully you'll need chalk drawn to the north oriented pentagram on the floor (Carrefour, 2€), red-black daemonic dress (Hugo Boss, 2000€) and a sacrificed penguin on the home altar (one hour of fear in your local zoo). Err, only joking.. dont harm any nice little penguins, you wont need to. We strongly prefer the simpler and easier to use CMake build system.Download the donothingplugin-1.0.tar.gz example from http://docs.scribus.net, unpack it and browse it.===Learning More===To go on from here, you should probably read scplugin.h and ensure you understand that. There is an explanation of the way the plugin system works in more detail here. Above all else, though, you'll learn how to get things done by reading the other plugins and the core Scribus code.

Storing your plugin's preferences:

Scribus provides a preferences api for plugin writers to store data between Scribus launches. There are two types of storage formats available: key-value pairs and tables.First you will need to get the PrefsContext object for your plugin. Then you can query PrefsContext to get the value for a specific key or you can ask for a PrefsTable by it's name. Here is a short example using key-value pairs.

 
 #include <prefsfile.h>
 #include <prefscontext.h>
 
 extern PrefsFile* prefsFile;
 
 PrefsContext *myPluginPrefs = prefsFile->getPluginContext("MyPlugin");
 
 // default value -1 will be used if "i" doesn't already exist
 int i = myPluginPrefs->getInt("i");
 
 // default value "dog" will be used if "s" doesn't already exist
 QString s = myPluginPrefs->get("s", "dog");
 
 myPluginPrefs->set("i", 221);
 myPluginPrefs->set("s", "cat");
 

Scribus Object Model

Scribus's source code is lightly documented. There is a significant effort to correct this, but given the size of the codebase it's taking quite some time. Please do try to follow what's going on based on the header files and the code. If you're unable to sort it out, feel free to drop in on IRC or ask on the mailing list, and someone may well be able to help you. Try to be patient - we're not always on IRC or available, and it can take time to answer a message if everybody's busy.If you feel like improving the documentation or fixing the doxygen api docs generation, the praise will be endless.One important thing to understand is that the core Scribus application can be accessed via the static global pointer ScApp, declared in scribus.h. Confusingly, this is a QMainWindow subclass. You can also get to the QApplication subclass used as ScQApp from scribusapp.h.Some major subsystems are singleton classes that are accessible via ClassName::instance() . Examples include PluginManager, ScPaths, and growing numbers of others. The advantage of this is that you can interact with these classes without having to delve into the guts of ScApp.

Plugin related links

Qt documentation from Trolltech
QMake documentation from Trolltech