glom r2008 - in trunk: . glom glom/bakery



Author: murrayc
Date: Fri Mar 20 00:31:11 2009
New Revision: 2008
URL: http://svn.gnome.org/viewvc/glom?rev=2008&view=rev

Log:
2009-03-20  Murray Cumming  <murrayc murrayc com>

* configure.ac: Depend on libunique-1.0
* glom/bakery/App_WithDoc_Gtk.[h|cc]: Added set_unique_app(), to make 
the app handle UniqueApp messages, to start new instances or open files.
* glom/main.cc: Use set_unique_app() and send messages to the existing 
instance instead of starting a new instance, if one is already running.

Modified:
   trunk/ChangeLog
   trunk/configure.ac
   trunk/glom/bakery/App_WithDoc_Gtk.cc
   trunk/glom/bakery/App_WithDoc_Gtk.h
   trunk/glom/main.cc

Modified: trunk/configure.ac
==============================================================================
--- trunk/configure.ac	(original)
+++ trunk/configure.ac	Fri Mar 20 00:31:11 2009
@@ -106,7 +106,7 @@
 
 
 # Do not require, goocanvas and gtksourceviewmm in client only mode
-REQUIRED_LIBS="gtkmm-2.4 >= 2.14 gthread-2.0 gconfmm-2.6 libxml++-2.6 libxslt >= 1.1.10 pygda-4.0 >= 2.25.3 pygtk-2.0 >= 2.6.0 libgdamm-4.0 >= 3.99.14 libgda-4.0 >= 4.0.0 libgda-postgres-4.0 goocanvasmm-1.0 >= 0.13.0"
+REQUIRED_LIBS="gtkmm-2.4 >= 2.14 gthread-2.0 gconfmm-2.6 libxml++-2.6 libxslt >= 1.1.10 pygda-4.0 >= 2.25.3 pygtk-2.0 >= 2.6.0 libgdamm-4.0 >= 3.99.14 libgda-4.0 >= 4.0.0 libgda-postgres-4.0 goocanvasmm-1.0 >= 0.13.0 unique-1.0"
 if test $enable_client_only != yes; then
 	REQUIRED_LIBS="$REQUIRED_LIBS gtksourceviewmm-2.0"
 fi

Modified: trunk/glom/bakery/App_WithDoc_Gtk.cc
==============================================================================
--- trunk/glom/bakery/App_WithDoc_Gtk.cc	(original)
+++ trunk/glom/bakery/App_WithDoc_Gtk.cc	Fri Mar 20 00:31:11 2009
@@ -315,4 +315,76 @@
     document_history_remove(uri);
 }
 
+void App_WithDoc_Gtk::set_unique_app(UniqueApp* unique_app)
+{
+  if(!unique_app)
+    return;
+
+  m_unique_app = unique_app;
+  g_object_ref(m_unique_app); //Keep it alive. unrefed in the destructor.
+
+  // The UniqueApp instance must "watch" all the top-level windows the application
+  // creates, so that it can terminate the startup notification sequence for us
+  unique_app_watch_window (unique_app, GTK_WINDOW(gobj()));
+
+  // Handle messages from other instances that try to start:
+  g_signal_connect (unique_app, "message-received", G_CALLBACK(&App_WithDoc_Gtk::on_unique_app_message_received), this /* user_data */);
+
+}
+
+// This handles messages from other UniqueApp instances,
+// to our single instance,
+// sent to the signal instance before the extra instances quit, 
+// soon after they start.
+UniqueResponse App_WithDoc_Gtk::on_unique_app_message_received(UniqueApp* app,
+  UniqueCommand command,
+  UniqueMessageData* message,
+  guint time_,
+  gpointer user_data)
+{
+  App_WithDoc_Gtk* pApp = static_cast<App_WithDoc_Gtk*>(user_data);
+  if(!pApp)
+    return UNIQUE_RESPONSE_FAIL;
+
+  switch(command)
+  {
+    case UNIQUE_ACTIVATE:
+    {
+      Glib::RefPtr<Gdk::Screen> screen = Glib::wrap(unique_message_data_get_screen(message), true);
+      pApp->set_screen(screen);
+      pApp->present();
+      
+      return UNIQUE_RESPONSE_OK;
+    }
+
+    case UNIQUE_NEW:
+    {
+      pApp->on_menu_file_new();
+
+      return UNIQUE_RESPONSE_OK;
+      break;
+    }
+
+    case UNIQUE_OPEN:
+    {
+      char* uri = unique_message_data_get_text(message);
+      std::cout << "DEBUG: uri=" << uri << std::endl;
+      
+      pApp->open_document(uri);
+      pApp->present();
+
+      g_free(uri);
+
+      return UNIQUE_RESPONSE_OK;
+      break;
+    }
+
+    default:
+    {
+      std::cerr << "Unexpected UniqueApp command: " << command << std::endl;
+      return UNIQUE_RESPONSE_FAIL;
+    }
+  }
+}
+
 } //namespace

Modified: trunk/glom/bakery/App_WithDoc_Gtk.h
==============================================================================
--- trunk/glom/bakery/App_WithDoc_Gtk.h	(original)
+++ trunk/glom/bakery/App_WithDoc_Gtk.h	Fri Mar 20 00:31:11 2009
@@ -25,6 +25,7 @@
 #include <gtkmm/toolbutton.h>
 #include <gtkmm/recentmanager.h>
 #include <gtkmm/recentchooser.h>
+#include <unique/unique.h>
 
 namespace GlomBakery
 {
@@ -52,6 +53,12 @@
 
   virtual void init(); //Unique final overrider.
 
+  /** Connect a signal handler for UniqueApp messages,
+   * which handles the default commands, for instance to open new instances 
+   * an to open files.
+   */
+  virtual void set_unique_app(UniqueApp* unique_app);
+
 protected:
   virtual void init_menus_file(); //overridden to add open/save/save as.
   virtual void init_menus_file_recentfiles(const Glib::ustring& path); // call this in init_menus_file()
@@ -70,8 +77,14 @@
 
   void on_recent_files_activate(Gtk::RecentChooser& recent_chooser);
 
+  static UniqueResponse on_unique_app_message_received(UniqueApp* app, UniqueCommand command, UniqueMessageData* message, guint time_, gpointer user_data);
+
   //Menu stuff:
   Glib::RefPtr<Gtk::Action> m_action_save, m_action_saveas;
+
+  //We keep this around just so we can keep a ref on it.
+  //This will only be non-null for the first instance.
+  UniqueApp* m_unique_app;
 };
 
 } //namespace

Modified: trunk/glom/main.cc
==============================================================================
--- trunk/glom/main.cc	(original)
+++ trunk/glom/main.cc	Fri Mar 20 00:31:11 2009
@@ -112,15 +112,17 @@
   //to help valgrind to detect memory leaks:
   atexit(__libc_freeres);
 #else
+  //Allow use of the Windows Sockets API:
   WSADATA data;
-  int errcode = WSAStartup(MAKEWORD(2, 0), &data);
+  const int errcode = WSAStartup(MAKEWORD(2, 0), &data);
   if(errcode != 0)
   {
     std::cerr << "Failed to initialize WinSock: " << errcode << std::endl;
     return -1;
   }
 
-  gchar* installation_dir_c = g_win32_get_package_installation_directory_of_module(NULL);
+  //Get the installation directory for use in other MS Windows initialization later:
+  gchar* installation_dir_c = g_win32_get_package_installation_directory_of_module(0);
   const std::string installation_dir(installation_dir_c);
   g_free(installation_dir_c);
 #endif
@@ -129,7 +131,7 @@
   // correctly according to getenv(), but python still does not look in it.
   // For now, the installer installs all the python stuff directly into the 
   // application directory, although I would like to move this to a python/
-  // subdirectory.
+  // subdirectory. Armin.
 #if 0
 #ifdef G_OS_WIN32
   // Set PYTHONPATH to point to python/ because that's where the installer
@@ -150,16 +152,20 @@
   Glib::setenv("PATH", Glib::getenv("PATH") + ";" + Glib::build_filename(installation_dir, "bin"));
 #endif
 
+
+  // Make this application use the current locale for _() translation:
 #ifdef G_OS_WIN32
-  // Load translations relative to glom.exe on Windows
+  // Load translations relative to glom.exe on Windows:
   bindtextdomain(GETTEXT_PACKAGE, Glib::build_filename(installation_dir, "share/locale").c_str());
 #else
-  //Make this application use the current locale for _() translation:
   bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);  //LOCALEDIR is defined in the Makefile.am
 #endif
   bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
   textdomain(GETTEXT_PACKAGE);
 
+
+  //Initialize gtkmm, Python, etc:
+
   g_thread_init(NULL); //So we can use GMutex.
 
   Gnome::Gda::init();
@@ -167,31 +173,35 @@
   Hildon::init();
 #endif
 
-  Glib::OptionContext context;
-
-  Glom::OptionGroup group;
-  context.set_main_group(group);
   //We use python for calculated-fields:
   Py_Initialize();
   PySys_SetArgv(argc, argv);
-  Gtk::Main mainInstance(argc, argv, context);
+
+
+  //Parse command-line arguments:
+  Glib::OptionContext context;
+  Glom::OptionGroup group;
+  context.set_main_group(group);
+  Gtk::Main mainInstance(argc, argv, context); //Parses standard GTK+ command-line arguments.
 
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
   try
+  {
 #else
   std::auto_ptr<Glib::Error> error;
 #endif // GLIBMM_EXCEPTIONS_ENABLED
-  {
+
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
     context.parse(argc, argv);
 #else
     context.parse(argc, argv, error);
 #endif // GLIBMM_EXCEPTIONS_ENABLED
-  }
+
 #ifdef GLIBMM_EXCEPTIONS_ENABLED
+  }
   catch(const Glib::OptionError& ex)
 #else
-  if(error.get() != NULL)
+  if(error.get())
 #endif
   {
 #ifndef GLIBMM_EXCEPTIONS_ENABLED
@@ -215,7 +225,12 @@
     return 0;
   }
 
+#ifndef GLOM_ENABLE_CLIENT_ONLY
+    gtksourceview::init();
+    Goocanvas::init(PACKAGE, VERSION, argc, argv ) ;
+#endif //!GLOM_ENABLE_CLIENT_ONLY
 
+  //Show the application version:
   if(group.m_arg_version)
   {
     std::cout << VERSION << std::endl;
@@ -226,11 +241,6 @@
   try
 #endif
   {
-#ifndef GLOM_ENABLE_CLIENT_ONLY
-    gtksourceview::init();
-    Goocanvas::init(PACKAGE, VERSION, argc, argv ) ;
-#endif //!GLOM_ENABLE_CLIENT_ONLY
-
     //Get command-line parameters, if any:
     Glib::ustring input_uri = group.m_arg_filename;
 
@@ -255,6 +265,42 @@
     //debugging:
     //input_uri = "file:///home/murrayc/cvs/gnome212/glom/examples/example_smallbusiness.glom";
 
+
+    //Ensure that only one instance of Glom is ever started,
+    //so that the file menu's new/open/quit menu items can be aware of other open files/windows:
+    //
+    //If an instance is already running then ask that instance to do something instead,
+    //and close this instance.
+    UniqueApp* unique_app = unique_app_new("org.glom", NULL /* startup_id */);
+    if( unique_app_is_running(unique_app) )
+    {
+      //There is an existing instance:
+
+      UniqueResponse response = UNIQUE_RESPONSE_OK;
+
+      if(!input_uri.empty())
+      {
+        //Tell the existing instance to do a File/Open:
+        UniqueMessageData *message = unique_message_data_new();
+        unique_message_data_set_text(message, input_uri.c_str(), -1); //TODO: Use set_uris().
+        response = unique_app_send_message(unique_app, UNIQUE_OPEN, message);
+        unique_message_data_free(message);
+      }
+      else
+      {
+        //Tell the existing instance to do a File/New:
+        response = unique_app_send_message(unique_app, UNIQUE_NEW, 0);
+      }
+
+      g_object_unref(unique_app);
+      unique_app = 0;
+      if(response != UNIQUE_RESPONSE_OK)
+        std::cerr << "unique_app_send_message() failed." << std::endl;
+
+      return 0;
+    }
+    //Else this is the first instance:
+
 #ifdef GLOM_ENABLE_POSTGRESQL
     bool install_complete = false;
 #ifndef GLOM_ENABLE_CLIENT_ONLY
@@ -300,18 +346,20 @@
     }
 #endif
 
-
+    //Create the main window (the application):
     Glom::App_Glom* pApp_Glom = 0;
     refXml->get_widget_derived("window_main", pApp_Glom);
 
+    pApp_Glom->set_unique_app(unique_app);
+    g_object_unref(unique_app);
+    unique_app = 0;
+
     pApp_Glom->set_command_line_args(argc, argv);
     pApp_Glom->set_show_sql_debug(group.m_arg_debug_sql);
 
-    bool test = pApp_Glom->init(input_uri); //Sets it up and shows it.
+    const bool test = pApp_Glom->init(input_uri); //Sets it up and shows it.
     if(test) //The user could cancel the offer of a new or existing database.
-    {
       Gtk::Main::run();
-    }
     else
       delete pApp_Glom;
   }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]