/* Copyright (C) 2009 and 2011 Chris Vine

The library comprised in this file or of which this file is part is
distributed by Chris Vine under the GNU Lesser General Public
License as follows:

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   as published by the Free Software Foundation; either version 2.1 of
   the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License, version 2.1, for more details.

   You should have received a copy of the GNU Lesser General Public
   License, version 2.1, along with this library (see the file LGPL.TXT
   which came with this source code package in the c++-gtk-utils
   sub-directory); if not, write to the Free Software Foundation, Inc.,
   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

*/

#ifndef CGU_PROG_PRESENT_H
#define CGU_PROG_PRESENT_H

#include <glib.h>

#include <c++-gtk-utils/cgu_config.h>

namespace Cgu {

/**
 * @defgroup prog_present prog_present
 * @anchor prog_presenterAnchor
 *
 * \#include <c++-gtk-utils/prog_present.h>
 *
 * The c++-gtk-utils library provides functions to make a single
 * instance program.  The functionality for a single instance is
 * provided by gio (if glib >= 2.26 is installed) or dbus-glib, but
 * the interface in this file comprises only two functions,
 * register_prog() and present_instance().  register_prog() returns
 * 'true' if it is the first program instance to run in a particular
 * user session, otherwise 'false'.  If false is returned,
 * present_instance() is then called to bring up the program instance
 * already running.  register_prog() is passed a function to carry out
 * the program presentation.
 *
 * Typical usage would be, for example:
 *
 * @code
 * GtkWidget* window;
 * gboolean present_func(void* data, const char** args) {
 *   gdk_x11_window_move_to_current_desktop(gtk_widget_get_window(window));
 *   gtk_window_present(GTK_WINDOW(window));
 *   return TRUE;
 * }
 *
 * using namespace Cgu;
 *
 * int main(int argc, char* argv[]) {
 *   gtk_init(&argc, &argv);
 *   if (register_prog("my_prog", present_func)) {
 *     window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 *     ... go through normal business of creating GTK+ program interface ...
 *     gtk_main();
 *   }
 *   else {
 *     if (!present_instance()) gdk_notify_startup_complete();
 *     else {
 *       ... carry out a dbus failure strategy, which may mean starting
 *       ... the program anyway with appropriate warnings to the user
 *       ... that there may be multiple instances running, or may mean
 *       ... displaying a GtkMessageDialog object to the user suggesting
 *       ... that the user should check that the session message bus
 *       ... daemon is running, and then terminating
 *     }
 *   }
 *   return 0;
 * }
 * @endcode
 *
 * @b NOTE
 *
 * These functions are only compiled into the library if either
 * dbus-glib >= 0.70, or glib >= 2.26 (for gio's dbus implementation),
 * is installed.  If both are installed, gio's dbus implementation is
 * used.
 */



/**
 * Function pointer type that present_instance() will execute via dbus
 * and intended to cause eg the program window to show itself. It must
 * return TRUE if successful, FALSE if not.  Returning FALSE will
 * cause present_instance() to return 2.  However, generally any
 * GDK/GTK+ errors encountered by the function represented by this
 * function pointer are best reported by that function bringing up a
 * dialog diagnostic rather than by returning FALSE (in other words,
 * in most cases you will want to return TRUE, even if there has been
 * a problem).  It should not throw, as the dbus and dbus-glib
 * implementation has C linkage and cannot handle exceptions.
 * @param object_data NULL or persistent data, as determined by the
 * call to register_prog().  By default it is NULL.
 * @param instance_args NULL or a NULL terminated array of strings to
 * be passed to the PresentFunc function on a particular invocation,
 * as determined by present_instance().  By default it is NULL.
 * @return TRUE if successful, FALSE if not and it is important to
 * notify the caller of the problem.
 * @ingroup prog_present
 */
typedef gboolean(*PresentFunc)(void* object_data, const char** instance_args);

/**
 * register_prog() returns 'true' if this is the first instance of the
 * program to register itself, otherwise 'false'.  false will also be
 * returned, and an error logged, if a dbus connection cannot be
 * obtained in order to carry out program registration (in which case
 * the subsequent call to present_instance() will return 1,
 * representing failure).  The first argument (prog_name) can be
 * anything that contains valid xml name characters (provided that for
 * any one program it is always the same for that program), but it is
 * best to pass the name of the program to be invoked.  The object
 * data argument is persistent data passed to each invocation of
 * PresentFunc for that program while it is running, so the data
 * passed needs to exist throughout program execution (eg, allocate it
 * on the heap or have it in the same scope as that in which main()
 * returns).  By default a NULL value is passed.  It does not throw.
 * @param prog_name An identifier name comprising valid xml
 * characters.
 * @param func A function pointer representing the function to be
 * executed by present_instance() if the program is already running.
 * @param object_data NULL or persistent data to be passed to each
 * invocation of func.  By default it is NULL.
 * @return 'true' if this is the first instance of the program to
 * register itself, otherwise 'false'.  false will also be returned,
 * and an error logged, if a dbus connection cannot be obtained in
 * order to carry out program registration (in which case the
 * subsequent call to present_instance() will return 1, representing
 * failure).
 * @ingroup prog_present
 */
bool register_prog(const char* prog_name, PresentFunc func, void* object_data = 0);

/**
 * present_instance() is to be called if register_prog() returns
 * false.  Returns 0 on success, 1 if there has been a dbus error or 2
 * if the PresentFunc callback registered by register_prog() has
 * returned FALSE.  The instance_args argument is passed to
 * PresentFunc on this invocation, and is either NULL (the default
 * argument), or a NULL terminated array of strings, and in most cases
 * you won't need it so NULL is appropriate.  It is a blocking call
 * (it will wait for the PresentFunc function to complete).  It does
 * not throw.
 * @param instance_args NULL or a NULL terminated array of strings to
 * be passed to the PresentFunc function on this invocation.  By
 * default it is NULL.
 * @return 0 on success, 1 on failure (say, because a dbus connection
 * could not be obtained in order to carry out program registration)
 * or 2 if the PresentFunc callback registered by register_prog()
 * returns FALSE.
 * @ingroup prog_present
 */
int present_instance(const char** instance_args = 0);

} // namespace Cgu

#endif
