From f8c21cb846115ae7afecd24f9368d1a914e4843c Mon Sep 17 00:00:00 2001 From: "Zane U. Ji" Date: Fri, 20 Dec 2013 20:39:04 +0800 Subject: [PATCH] Bring the window of an existing instance to front --- Makefile.in | 2 + configure | 95 ++++++++++++++++++++++++- configure.ac | 15 +++- src/Makefile.am | 4 +- src/Makefile.in | 10 +-- src/myipc.cpp | 160 +++++++++++++++++++++++++++++++++++++----- src/myipc.h | 48 +++++++++---- src/xmlcopyeditor.cpp | 56 ++++----------- src/xmlcopyeditor.h | 3 +- 9 files changed, 306 insertions(+), 87 deletions(-) diff --git a/Makefile.in b/Makefile.in index a9435e8..20988a8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -222,6 +222,8 @@ ENCHANT_LIBS = @ENCHANT_LIBS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_LIBS = @GTK_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ diff --git a/configure b/configure index 7e5352a..9bf5ca2 100755 --- a/configure +++ b/configure @@ -633,6 +633,8 @@ ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS +GTK_LIBS +GTK_CFLAGS ASPELL_LIBS ENCHANT_LIBS ENCHANT_CFLAGS @@ -791,7 +793,9 @@ PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR ENCHANT_CFLAGS -ENCHANT_LIBS' +ENCHANT_LIBS +GTK_CFLAGS +GTK_LIBS' # Initialize some variables set by options. @@ -1455,6 +1459,8 @@ Some influential environment variables: C compiler flags for ENCHANT, overriding pkg-config ENCHANT_LIBS linker flags for ENCHANT, overriding pkg-config + GTK_CFLAGS C compiler flags for GTK, overriding pkg-config + GTK_LIBS linker flags for GTK, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -15561,6 +15567,86 @@ fi +# Check gtk +# This has to match the one wxWidgets linked with +# It is needed to make single-instance-check work + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK" >&5 +$as_echo_n "checking for GTK... " >&6; } + +if test -n "$GTK_CFLAGS"; then + pkg_cv_GTK_CFLAGS="$GTK_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gtk+-2.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GTK_CFLAGS=`$PKG_CONFIG --cflags "gtk+-2.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$GTK_LIBS"; then + pkg_cv_GTK_LIBS="$GTK_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0\""; } >&5 + ($PKG_CONFIG --exists --print-errors "gtk+-2.0") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_GTK_LIBS=`$PKG_CONFIG --libs "gtk+-2.0" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + GTK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gtk+-2.0" 2>&1` + else + GTK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gtk+-2.0" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$GTK_PKG_ERRORS" >&5 + + CXXFLAGS="$CXXFLAGS -D__NO_GTK__" + #[PKG_CHECK_MODULES(GTK, [gtk+-3.0], [AC_MSG_RESULT([gtk+-3.0])])] + +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + CXXFLAGS="$CXXFLAGS -D__NO_GTK__" + #[PKG_CHECK_MODULES(GTK, [gtk+-3.0], [AC_MSG_RESULT([gtk+-3.0])])] + +else + GTK_CFLAGS=$pkg_cv_GTK_CFLAGS + GTK_LIBS=$pkg_cv_GTK_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk+-2.0" >&5 +$as_echo "gtk+-2.0" >&6; } +fi + ac_config_files="$ac_config_files Makefile src/Makefile" cat >confcache <<\_ACEOF @@ -18050,8 +18136,11 @@ echo "***************************************" echo if [ "$debugbuild" = "y" ]; then -echo "Debug Enabled" +echo "Debug Enabled" else -echo "Debug Disabled" +echo "Debug Disabled" +fi +if [ "$GTK_LIBS" = "" ]; then +echo "GTK No. There will be problems when single instance is enabled." fi diff --git a/configure.ac b/configure.ac index bf745fd..b156490 100644 --- a/configure.ac +++ b/configure.ac @@ -138,6 +138,14 @@ PKG_CHECK_MODULES(ENCHANT, [enchant], [CXXFLAGS="$CXXFLAGS -DUSE_ENCHANT"], AC_SUBST(ASPELL_LIBS) +# Check gtk +# This has to match the one wxWidgets linked with +# It is needed to make single-instance-check work +PKG_CHECK_MODULES(GTK, [gtk+-2.0], [AC_MSG_RESULT([gtk+-2.0])], + [CXXFLAGS="$CXXFLAGS -D__NO_GTK__"] + #[PKG_CHECK_MODULES(GTK, [gtk+-3.0], [AC_MSG_RESULT([gtk+-3.0])])] +) + AC_OUTPUT(Makefile src/Makefile) dnl Summarized output @@ -146,8 +154,11 @@ echo "***************************************" echo if [[ "$debugbuild" = "y" ]]; then -echo "Debug Enabled" +echo "Debug Enabled" else -echo "Debug Disabled" +echo "Debug Disabled" +fi +if [[ "$GTK_LIBS" = "" ]]; then +echo "GTK No. There will be problems when single instance is enabled." fi diff --git a/src/Makefile.am b/src/Makefile.am index 42d527d..16dc638 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -33,7 +33,7 @@ xmlcopyeditor_SOURCES = xmlcopyeditor.cpp associatedialog.cpp casehandler.cpp \ xmlcopyeditor.desktop xmlcopyeditor_LDFLAGS = $(WX_LIBS) \ - -lexpat -lxslt -lxml2 -lpcre -lxerces-c $(ASPELL_LIBS) $(ENCHANT_LIBS) + -lexpat -lxslt -lxml2 -lpcre -lxerces-c $(ASPELL_LIBS) $(ENCHANT_LIBS) $(GTK_LIBS) nobase_dist_xmlcopyeditor_DATA = $(srcdir)/catalog/catalog \ $(srcdir)/copying/*.txt \ @@ -82,5 +82,5 @@ pixmap_DATA = xmlcopyeditor.png applications_DATA = xmlcopyeditor.desktop -AM_CPPFLAGS = -I/usr/include/libxml2 $(ENCHANT_CFLAGS) +AM_CPPFLAGS = -I/usr/include/libxml2 $(ENCHANT_CFLAGS) $(GTK_CFLAGS) diff --git a/src/Makefile.in b/src/Makefile.in index 964a9d2..78e5a30 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -258,6 +258,8 @@ ENCHANT_LIBS = @ENCHANT_LIBS@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GREP = @GREP@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_LIBS = @GTK_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ @@ -379,7 +381,7 @@ xmlcopyeditor_SOURCES = xmlcopyeditor.cpp associatedialog.cpp casehandler.cpp \ xmlcopyeditor.desktop xmlcopyeditor_LDFLAGS = $(WX_LIBS) \ - -lexpat -lxslt -lxml2 -lpcre -lxerces-c $(ASPELL_LIBS) $(ENCHANT_LIBS) + -lexpat -lxslt -lxml2 -lpcre -lxerces-c $(ASPELL_LIBS) $(ENCHANT_LIBS) $(GTK_LIBS) nobase_dist_xmlcopyeditor_DATA = $(srcdir)/catalog/catalog \ $(srcdir)/copying/*.txt \ @@ -426,7 +428,7 @@ nobase_dist_xmlcopyeditor_DATA = $(srcdir)/catalog/catalog \ pixmap_DATA = xmlcopyeditor.png applications_DATA = xmlcopyeditor.desktop -AM_CPPFLAGS = -I/usr/include/libxml2 $(ENCHANT_CFLAGS) +AM_CPPFLAGS = -I/usr/include/libxml2 $(ENCHANT_CFLAGS) $(GTK_CFLAGS) all: all-am .SUFFIXES: @@ -440,9 +442,9 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/Makefile + $(AUTOMAKE) --foreign src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff --git a/src/myipc.cpp b/src/myipc.cpp index 1901019..fb8b629 100644 --- a/src/myipc.cpp +++ b/src/myipc.cpp @@ -19,6 +19,17 @@ #include "myipc.h" #include "xmlcopyeditor.h" +#include "pathresolver.h" +#if defined ( __WXGTK__ ) && !defined ( __NO_GTK__ ) +#include + +guint32 XTimeNow() +{ + struct timespec ts; + clock_gettime ( CLOCK_MONOTONIC, &ts ); + return ts.tv_sec * 1000 + ts.tv_nsec / 1000000; +} +#endif // __WXGTK__ MyServerConnection *server_connection = 0; MyClientConnection *client_connection = 0; @@ -32,7 +43,9 @@ wxConnectionBase *MyServer::OnAcceptConnection ( const wxString& topic ) return NULL; } -MyServerConnection::MyServerConnection() : wxConnection() +MyServerConnection::MyServerConnection() + : wxConnection() + , mFrameWnd ( ( wxIntPtr ) NULL ) { server_connection = this; } @@ -48,13 +61,8 @@ MyServerConnection::~MyServerConnection() bool MyServerConnection::OnPoke ( const wxString& WXUNUSED ( topic ) , const wxString& item -#if wxCHECK_VERSION(2,9,0) - , const void *data - , size_t size -#else - , wxChar *data - , int size -#endif + , IPCData *data + , IPCSize_t size , wxIPCFormat WXUNUSED ( format ) ) { @@ -78,10 +86,63 @@ bool MyServerConnection::OnPoke ( frame->openFile ( ( wxString& ) item ); //frame->addToFileQueue ( ( wxString& ) item ); // prevent event loop problems } +#ifndef __WXMSW__ +#if defined ( __WXGTK__ ) && !defined ( __NO_GTK__ ) + // Processes mostly cannot raise theire own windows. + // http://osdir.com/ml/gnome.gaim.devel/2004-12/msg00077.html + GtkWidget *widget = frame->GetHandle(); + GdkWindow *window = gtk_widget_get_window ( widget ); + gdk_x11_window_set_user_time ( window, + //XTimeNow() ); // This works too. + gdk_x11_get_server_time ( window ) ); + //gdk_window_show ( window ); + //gdk_window_raise ( window ); + //gtk_window_present ( GTK_WINDOW ( widget ) ); +#endif // __WXGTK__ && !__NO_GTK__ + frame->Show(); frame->Raise(); +#endif // __WXMSW__ return true; } +IPCData *MyServerConnection::OnRequest + ( const wxString& WXUNUSED ( topic ) + , const wxString& item + , IPCSize_t *size + , wxIPCFormat WXUNUSED ( format ) /*= wxIPC_PRIVATE */ + ) +{ + if ( size == NULL ) + return NULL; + + if ( item == IPC_FRAME_WND ) + { + if ( !mFrameWnd ) + { + wxWindow *window = wxTheApp->GetTopWindow(); + if ( window ) + { +#if defined ( __WXGTK__ ) && !defined ( __NO_GTK__ ) + GtkWidget *wnd = window->GetHandle(); + if ( wnd ) + { + GdkWindow *gwnd = gtk_widget_get_window ( wnd ); + if ( gwnd ) + mFrameWnd = GDK_WINDOW_XID ( gwnd ); + } +#else + mFrameWnd = window->GetHandle(); +#endif + } + } + *size = sizeof mFrameWnd; + return ( IPCData * ) &mFrameWnd; + } + + *size = 0; + return NULL; +} + bool MyServerConnection::OnStartAdvise ( const wxString& WXUNUSED ( topic ), const wxString& WXUNUSED ( item ) ) { @@ -89,7 +150,8 @@ bool MyServerConnection::OnStartAdvise ( const wxString& WXUNUSED ( topic ), } MyClientConnection::MyClientConnection() -{} +{ +} wxConnectionBase *MyClient::OnMakeConnection() { @@ -99,13 +161,8 @@ wxConnectionBase *MyClient::OnMakeConnection() bool MyClientConnection::OnAdvise ( const wxString& WXUNUSED ( topic ) , const wxString& WXUNUSED ( item ) -#if wxCHECK_VERSION(2,9,0) - , const void * WXUNUSED ( data ) - , size_t WXUNUSED ( size ) -#else - , wxChar * WXUNUSED ( data ) - , int WXUNUSED ( size ) -#endif + , IPCData * WXUNUSED ( data ) + , IPCSize_t WXUNUSED ( size ) , wxIPCFormat WXUNUSED ( format ) ) { @@ -119,7 +176,74 @@ bool MyClientConnection::OnDisconnect() } MyServer::MyServer() -{ } +{ +} MyClient::MyClient() -{ } +{ +} + +bool MyClient::talkToServer ( int argc, const wxChar * const *argv ) +{ + MyClientConnection *connection = ( MyClientConnection * ) + MakeConnection ( _T ( "localhost" ), IPC_SERVICE, IPC_TOPIC ); + if ( !connection || !connection->StartAdvise ( IPC_ADVISE_NAME ) ) + return false; + + wxString argument; + // wxConnectionBase::Poke expects something other than NULL in debug + // version +#ifdef __WXDEBUG__ + static wxChar whatBuffer[] = _T ( "Data" ); +#else + static wxChar whatBuffer[0]; +#endif + if ( argc <= 1 ) + { + connection->Poke ( IPC_NO_FILE, whatBuffer ); + } + else for ( int i = 1; i < argc; i++ ) + { + argument = argv[i]; + argument = PathResolver::run ( argument ); + if ( ! connection->Poke ( argument, whatBuffer ) ) + break; + } + + // Bring the window to front + IPCSize_t size; + const void *data = connection->Request ( IPC_FRAME_WND, &size ); + if ( !data ) + return false; +#ifdef __WXMSW__ + if ( size == sizeof ( HWND ) ) + { + HWND hwnd = * ( const HWND * )data; + if ( ::IsIconic ( hwnd ) ) + ::ShowWindow ( hwnd, SW_RESTORE ); + else + ::SetForegroundWindow ( hwnd ); + } +#elif defined ( __WXGTK__x ) // It doesn't work + if ( size == sizeof ( GdkNativeWindow ) ) + { + GdkNativeWindow xWnd = * ( GdkNativeWindow * ) data; + GdkWindow *window = gdk_window_foreign_new ( xWnd ); + if ( window ) + { + gdk_x11_window_set_user_time ( window, + XTimeNow() ); + //gdk_x11_get_server_time ( window ) ); + gdk_window_show ( window ); + gdk_window_raise ( window ); + gdk_window_unref ( window ); + //GtkWidget *widget; + //gdk_window_get_user_data(window, (void**)&widget); + //printf ("widget: %p\n",widget); + //gtk_window_present ( GTK_WINDOW ( widget ) ); + } + } +#endif // __WXMSW__ + + return true; +} diff --git a/src/myipc.h b/src/myipc.h index 201689e..cf0d638 100644 --- a/src/myipc.h +++ b/src/myipc.h @@ -25,11 +25,30 @@ #include #include +#if defined ( __WXGTK__ ) && !defined ( __NO_GTK__ ) +#if wxCHECK_VERSION(2,9,0) // GSocket is defined in wxWidgets 2.8 +#include +#else // wxCHECK_VERSION(2,9,0) +#define GSocket GlibGSocket +#include +#undef GSocket +#endif // wxCHECK_VERSION(2,9,0) +#endif // __WXGTK__ && !__NO_GTK__ + #define IPC_SERVICE _T("4242") #define IPC_TOPIC _T("IPC TEST") #define IPC_ADVISE_NAME _T("Item") +#define IPC_FRAME_WND _T("FrameWnd") #define IPC_NO_FILE _T("[nofile]") +#if wxCHECK_VERSION(2,9,0) +typedef const void IPCData; +typedef size_t IPCSize_t; +#else +typedef wxChar IPCData; +typedef int IPCSize_t; +#endif + class MyServerConnection; class MyClientConnection; extern MyServerConnection *server_connection; @@ -42,16 +61,20 @@ class MyServerConnection : public wxConnection ~MyServerConnection(); bool OnPoke ( const wxString& topic , const wxString& item -#if wxCHECK_VERSION(2,9,0) - , const void *data - , size_t size -#else - , wxChar *data - , int size -#endif + , IPCData *data + , IPCSize_t size , wxIPCFormat format ); bool OnStartAdvise ( const wxString& topic, const wxString& item ); + IPCData *OnRequest(const wxString& topic, const wxString& item, + IPCSize_t *size, wxIPCFormat format = wxIPC_PRIVATE ); + + protected: +#if defined ( __WXGTK__ ) && !defined ( __NO_GTK__ ) + GdkNativeWindow mFrameWnd; +#else + WXWidget mFrameWnd; +#endif }; class MyClientConnection: public wxConnection @@ -60,13 +83,8 @@ class MyClientConnection: public wxConnection MyClientConnection(); bool OnAdvise ( const wxString& topic , const wxString& item -#if wxCHECK_VERSION(2,9,0) - , const void *data - , size_t size -#else - , wxChar *data - , int size -#endif + , IPCData *data + , IPCSize_t size , wxIPCFormat format ); bool OnDisconnect(); }; @@ -76,6 +94,7 @@ class MyClient: public wxClient public: MyClient(); wxConnectionBase *OnMakeConnection(); + bool talkToServer ( int argc, const wxChar * const *argv ); }; class MyServer: public wxServer @@ -86,3 +105,4 @@ class MyServer: public wxServer }; #endif + diff --git a/src/xmlcopyeditor.cpp b/src/xmlcopyeditor.cpp index 561417a..c249271 100644 --- a/src/xmlcopyeditor.cpp +++ b/src/xmlcopyeditor.cpp @@ -64,6 +64,7 @@ #include "threadreaper.h" #include #include "dtd2schema.h" +#include "myipc.h" #define ngettext wxGetTranslation @@ -304,68 +305,37 @@ bool MyApp::OnInit() break; } +#ifdef __WXMSW__ + singleInstanceCheck = true; +#else + singleInstanceCheck = false; +#endif if ( config.get() ) { -#ifdef __WXMSW__ - singleInstanceCheck = config->Read ( _T ( "singleInstanceCheck" ), true ); -#else - long longFalse = 0; - singleInstanceCheck = config->Read ( _T ( "singleInstanceCheck" ), longFalse ); -#endif + singleInstanceCheck = config->Read ( _T ( "singleInstanceCheck" ), + singleInstanceCheck ); lang = config->Read ( _T ( "lang" ), systemLocale ); } else { lang = systemLocale; -#ifdef __WXMSW__ - singleInstanceCheck = true; -#else - singleInstanceCheck = false; -#endif } - wxString name, service, hostName; - name.Printf ( _T ( "xmlcopyeditor-%s" ), wxGetUserId().c_str() ); - service = IPC_SERVICE; - hostName = _T ( "localhost" ); - if ( singleInstanceCheck ) { + wxString name; + name.Printf ( _T ( "xmlcopyeditor-%s" ), wxGetUserId().c_str() ); checker = new wxSingleInstanceChecker ( name ); - while ( checker->IsAnotherRunning() ) + if ( checker->IsAnotherRunning() ) { - // attempt calling server MyClient client; - MyClientConnection *connection = ( MyClientConnection * ) - client.MakeConnection ( hostName, service, IPC_TOPIC ); - if ( !connection || !connection->StartAdvise ( IPC_ADVISE_NAME ) ) - break; - else - { - wxString argument; - wxChar whatBuffer[] = _T ( "Data" ); - if ( this->argc > 1 ) - { - for ( int i = 1; i < this->argc; i++ ) - { - argument = ( wxString ) this->argv[i]; - argument = PathResolver::run ( argument ); - if ( ! connection->Poke ( argument, whatBuffer ) ) - break; - } - } - else - { - argument = ( wxString ) IPC_NO_FILE; - connection->Poke ( argument, whatBuffer ); - } + if ( client.talkToServer ( argc, argv ) ) return false; - } } } server = new MyServer; - server->Create ( service ); + server->Create ( IPC_SERVICE ); myLocale.Init ( lang, wxLOCALE_LOAD_DEFAULT ); diff --git a/src/xmlcopyeditor.h b/src/xmlcopyeditor.h index b0fdb67..938a1e1 100644 --- a/src/xmlcopyeditor.h +++ b/src/xmlcopyeditor.h @@ -52,7 +52,6 @@ #include "xmldoc.h" #include "myhtmlpane.h" #include "xmlencodinghandler.h" -#include "myipc.h" #include enum @@ -167,6 +166,8 @@ enum CONST_QUESTION }; +class MyServer; + class MyApp : public wxApp { public: