diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ff47577..20bbdca 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,8 +82,8 @@ if (LINUX) generate_cpp_resource_file(resource_updatergtk ${CMAKE_CURRENT_BINARY_DIR} ${GTK_UPDATER_LIB} ${GTK_BIN_CPP_FILE}) add_dependencies(resource_updatergtk updatergtk) - set(SOURCES ${SOURCES} UpdateDialogGtkWrapper.cpp ${GTK_BIN_CPP_FILE}) - set(HEADERS ${HEADERS} UpdateDialogGtkWrapper.h) + set(SOURCES ${SOURCES} UpdateDialogGtkFactory.cpp ${GTK_BIN_CPP_FILE}) + set(HEADERS ${HEADERS} UpdateDialogGtkFactory.h) endif() if (APPLE) diff --git a/src/UpdateDialog.h b/src/UpdateDialog.h new file mode 100644 index 0000000..501c2c8 --- /dev/null +++ b/src/UpdateDialog.h @@ -0,0 +1,14 @@ +#pragma once + +#include "UpdateObserver.h" + +class UpdateDialog : public UpdateObserver +{ + public: + virtual ~UpdateDialog() {}; + + virtual void init(int argc, char** argv) = 0; + virtual void exec() = 0; + virtual void quit() = 0; +}; + diff --git a/src/UpdateDialogAscii.cpp b/src/UpdateDialogAscii.cpp index 2c8e846..33de123 100644 --- a/src/UpdateDialogAscii.cpp +++ b/src/UpdateDialogAscii.cpp @@ -14,7 +14,7 @@ const char* introMessage = "You can fix this by installing the GTK 2 libraries.\n\n" "Installing Updates...\n"; -void UpdateDialogAscii::init() +void UpdateDialogAscii::init(int /* argc */, char** /* argv */) { const char* path = "/tmp/update-progress"; m_output.open(path); @@ -58,4 +58,11 @@ void UpdateDialogAscii::updateFinished() m_mutex.unlock(); } +void UpdateDialogAscii::quit() +{ +} + +void UpdateDialogAscii::exec() +{ +} diff --git a/src/UpdateDialogAscii.h b/src/UpdateDialogAscii.h index 715e7fc..19fdd6e 100644 --- a/src/UpdateDialogAscii.h +++ b/src/UpdateDialogAscii.h @@ -1,6 +1,6 @@ #pragma once -#include "UpdateObserver.h" +#include "UpdateDialog.h" #include #include "tinythread.h" @@ -11,11 +11,15 @@ * The 'dialog' consists of an xterm tailing the contents * of a file, into which progress messages are written. */ -class UpdateDialogAscii : public UpdateObserver +class UpdateDialogAscii : public UpdateDialog { public: - void init(); + // implements UpdateDialog + virtual void init(int argc, char** argv); + virtual void exec(); + virtual void quit(); + // implements UpdateObserver virtual void updateError(const std::string& errorMessage); virtual void updateProgress(int percentage); virtual void updateFinished(); diff --git a/src/UpdateDialogCocoa.h b/src/UpdateDialogCocoa.h index a1881d7..586fdc8 100644 --- a/src/UpdateDialogCocoa.h +++ b/src/UpdateDialogCocoa.h @@ -1,17 +1,20 @@ #pragma once +#include "UpdateDialog.h" #include "UpdateObserver.h" class UpdateDialogPrivate; -class UpdateDialogCocoa : public UpdateObserver +class UpdateDialogCocoa : public UpdateDialog { public: UpdateDialogCocoa(); ~UpdateDialogCocoa(); - void init(); - void exec(); + // implements UpdateDialog + virtual void init(int argc, char** argv); + virtual void exec(); + virtual void quit(); // implements UpdateObserver virtual void updateError(const std::string& errorMessage); diff --git a/src/UpdateDialogCocoa.mm b/src/UpdateDialogCocoa.mm index 3a42c45..9893acc 100644 --- a/src/UpdateDialogCocoa.mm +++ b/src/UpdateDialogCocoa.mm @@ -98,7 +98,7 @@ void UpdateDialogCocoa::enableDockIcon() TransformProcessType(&psn,kProcessTransformToForegroundApplication); } -void UpdateDialogCocoa::init() +void UpdateDialogCocoa::init(int /* argc */, char** /* argv */) { enableDockIcon(); @@ -185,4 +185,9 @@ void UpdateDialogCocoa::releaseAutoreleasePool(void* arg) [(id)arg release]; } +void UpdateDialogCocoa::quit() +{ + [NSApp stop:nil]; +} + diff --git a/src/UpdateDialogGtk.cpp b/src/UpdateDialogGtk.cpp index 6ad2589..dafa89d 100644 --- a/src/UpdateDialogGtk.cpp +++ b/src/UpdateDialogGtk.cpp @@ -6,31 +6,9 @@ #include #include -UpdateDialogGtk* update_dialog_gtk_new(int argc, char** argv) +UpdateDialogGtk* update_dialog_gtk_new() { - UpdateDialogGtk* dialog = new UpdateDialogGtk; - dialog->init(argc,argv); - return dialog; -} - -void update_dialog_gtk_exec(UpdateDialogGtk* dialog) -{ - dialog->exec(); -} - -void update_dialog_gtk_handle_error(UpdateDialogGtk* dialog, const std::string& errorMessage) -{ - dialog->updateError(errorMessage); -} - -void update_dialog_gtk_handle_progress(UpdateDialogGtk* dialog, int percentage) -{ - dialog->updateProgress(percentage); -} - -void update_dialog_gtk_handle_finished(UpdateDialogGtk* dialog) -{ - dialog->updateFinished(); + return new UpdateDialogGtk(); } UpdateDialogGtk::UpdateDialogGtk() @@ -95,6 +73,12 @@ void UpdateDialogGtk::exec() } void UpdateDialogGtk::finish(GtkWidget* widget, gpointer _dialog) +{ + UpdateDialogGtk* dialog = static_cast(_dialog); + dialog->quit(); +} + +void UpdateDialogGtk::quit() { gtk_main_quit(); } diff --git a/src/UpdateDialogGtk.h b/src/UpdateDialogGtk.h index 05f8d43..70e29c7 100644 --- a/src/UpdateDialogGtk.h +++ b/src/UpdateDialogGtk.h @@ -1,17 +1,20 @@ #pragma once +#include "UpdateDialog.h" #include "UpdateMessage.h" #include "UpdateObserver.h" #include -class UpdateDialogGtk : public UpdateObserver +class UpdateDialogGtk : public UpdateDialog { public: UpdateDialogGtk(); - void init(int argc, char** argv); - void exec(); + // implements UpdateDialog + virtual void init(int argc, char** argv); + virtual void exec(); + virtual void quit(); // observer callbacks - these may be called // from a background thread @@ -33,11 +36,7 @@ class UpdateDialogGtk : public UpdateObserver // helper functions which allow the GTK dialog to be loaded dynamically // at runtime and used only if the GTK libraries are actually present extern "C" { - UpdateDialogGtk* update_dialog_gtk_new(int argc, char** argv); - void update_dialog_gtk_exec(UpdateDialogGtk* dialog); - void update_dialog_gtk_handle_error(UpdateDialogGtk* dialog, const std::string& errorMessage); - void update_dialog_gtk_handle_progress(UpdateDialogGtk* dialog, int percentage); - void update_dialog_gtk_handle_finished(UpdateDialogGtk* dialog); + UpdateDialogGtk* update_dialog_gtk_new(); } diff --git a/src/UpdateDialogGtkFactory.cpp b/src/UpdateDialogGtkFactory.cpp new file mode 100644 index 0000000..b1da8b5 --- /dev/null +++ b/src/UpdateDialogGtkFactory.cpp @@ -0,0 +1,63 @@ +#include "UpdateDialogGtkFactory.h" + +#include "Log.h" +#include "UpdateDialog.h" +#include "StringUtils.h" + +#include +#include +#include +#include +#include +#include + +class UpdateDialogGtk; + +// GTK updater UI library embedded into +// the updater binary +extern unsigned char libupdatergtk_so[]; +extern unsigned int libupdatergtk_so_len; + +// pointers to helper functions in the GTK updater UI library +UpdateDialogGtk* (*update_dialog_gtk_new)() = 0; + +#define BIND_FUNCTION(library,function) \ + function = reinterpret_cast(dlsym(library,#function)); + +bool extractFileFromBinary(const char* path, const void* buffer, size_t length) +{ + int fd = open(path,O_CREAT | O_WRONLY | O_TRUNC,0755); + size_t count = write(fd,buffer,length); + if (fd < 0 || count < length) + { + if (fd >= 0) + { + close(fd); + } + return false; + } + close(fd); + return true; +} + +UpdateDialog* UpdateDialogGtkFactory::createDialog() +{ + const char* libPath = "/tmp/libupdatergtk.so"; + + if (!extractFileFromBinary(libPath,libupdatergtk_so,libupdatergtk_so_len)) + { + LOG(Warn,"Failed to load the GTK UI library - " + std::string(strerror(errno))); + return 0; + } + + void* gtkLib = dlopen(libPath,RTLD_LAZY); + if (!gtkLib) + { + LOG(Warn,"Failed to load the GTK UI - " + std::string(dlerror())); + return 0; + } + + BIND_FUNCTION(gtkLib,update_dialog_gtk_new); + return reinterpret_cast(update_dialog_gtk_new()); +} + diff --git a/src/UpdateDialogGtkFactory.h b/src/UpdateDialogGtkFactory.h new file mode 100644 index 0000000..1806c25 --- /dev/null +++ b/src/UpdateDialogGtkFactory.h @@ -0,0 +1,13 @@ +#pragma once + +class UpdateDialog; + +/** Factory for loading the GTK version of the update dialog + * dynamically at runtime if the GTK libraries are available. + */ +class UpdateDialogGtkFactory +{ + public: + static UpdateDialog* createDialog(); +}; + diff --git a/src/UpdateDialogGtkWrapper.cpp b/src/UpdateDialogGtkWrapper.cpp deleted file mode 100644 index e430d69..0000000 --- a/src/UpdateDialogGtkWrapper.cpp +++ /dev/null @@ -1,95 +0,0 @@ -#include "UpdateDialogGtkWrapper.h" - -#include "Log.h" -#include "StringUtils.h" - -#include -#include -#include -#include -#include -#include - -// GTK updater UI library embedded into -// the updater binary -extern unsigned char libupdatergtk_so[]; -extern unsigned int libupdatergtk_so_len; - -// pointers to helper functions in the GTK updater UI library -UpdateDialogGtk* (*update_dialog_gtk_new)(int,char**) = 0; -void (*update_dialog_gtk_exec)(UpdateDialogGtk* dialog) = 0; -void (*update_dialog_gtk_handle_error)(UpdateDialogGtk* dialog, const std::string& errorMessage) = 0; -void (*update_dialog_gtk_handle_progress)(UpdateDialogGtk* dialog, int percentage) = 0; -void (*update_dialog_gtk_handle_finished)(UpdateDialogGtk* dialog) = 0; - -#define BIND_FUNCTION(library,function) \ - function = reinterpret_cast(dlsym(library,#function)); - -bool extractFileFromBinary(const char* path, const void* buffer, size_t length) -{ - int fd = open(path,O_CREAT | O_WRONLY | O_TRUNC,0755); - size_t count = write(fd,buffer,length); - if (fd < 0 || count < length) - { - if (fd >= 0) - { - close(fd); - } - return false; - } - close(fd); - return true; -} - -UpdateDialogGtkWrapper::UpdateDialogGtkWrapper() -: m_dialog(0) -{ -} - -bool UpdateDialogGtkWrapper::init(int argc, char** argv) -{ - const char* libPath = "/tmp/libupdatergtk.so"; - - if (!extractFileFromBinary(libPath,libupdatergtk_so,libupdatergtk_so_len)) - { - LOG(Warn,"Failed to load the GTK UI library - " + std::string(strerror(errno))); - } - - void* gtkLib = dlopen(libPath,RTLD_LAZY); - if (!gtkLib) - { - LOG(Warn,"Failed to load the GTK UI - " + std::string(dlerror())); - return false; - } - - BIND_FUNCTION(gtkLib,update_dialog_gtk_new); - BIND_FUNCTION(gtkLib,update_dialog_gtk_exec); - BIND_FUNCTION(gtkLib,update_dialog_gtk_handle_error); - BIND_FUNCTION(gtkLib,update_dialog_gtk_handle_progress); - BIND_FUNCTION(gtkLib,update_dialog_gtk_handle_finished); - - m_dialog = update_dialog_gtk_new(argc,argv); - - return true; -} - -void UpdateDialogGtkWrapper::exec() -{ - update_dialog_gtk_exec(m_dialog); -} - -void UpdateDialogGtkWrapper::updateError(const std::string& errorMessage) -{ - update_dialog_gtk_handle_error(m_dialog,errorMessage); -} - -void UpdateDialogGtkWrapper::updateProgress(int percentage) -{ - update_dialog_gtk_handle_progress(m_dialog,percentage); -} - -void UpdateDialogGtkWrapper::updateFinished() -{ - update_dialog_gtk_handle_finished(m_dialog); -} - diff --git a/src/UpdateDialogGtkWrapper.h b/src/UpdateDialogGtkWrapper.h deleted file mode 100644 index e103b46..0000000 --- a/src/UpdateDialogGtkWrapper.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include "UpdateObserver.h" - -class UpdateDialogGtk; - -/** A wrapper around UpdateDialogGtk which allows the GTK UI to - * be loaded dynamically at runtime if the GTK libraries are - * available. - */ -class UpdateDialogGtkWrapper : public UpdateObserver -{ - public: - UpdateDialogGtkWrapper(); - - /** Attempt to load and initialize the GTK updater UI. - * If this function returns false, other calls in UpdateDialogGtkWrapper - * may not be used. - */ - bool init(int argc, char** argv); - void exec(); - - virtual void updateError(const std::string& errorMessage); - virtual void updateProgress(int percentage); - virtual void updateFinished(); - - private: - UpdateDialogGtk* m_dialog; -}; - diff --git a/src/UpdateDialogWin32.cpp b/src/UpdateDialogWin32.cpp index 0b98240..54aa3bc 100644 --- a/src/UpdateDialogWin32.cpp +++ b/src/UpdateDialogWin32.cpp @@ -83,7 +83,7 @@ UpdateDialogWin32::~UpdateDialogWin32() } } -void UpdateDialogWin32::init() +void UpdateDialogWin32::init(int /* argc */, char** /* argv */) { int width = 300; int height = 130; @@ -143,6 +143,11 @@ void UpdateDialogWin32::updateFinished() SendNotifyMessage(m_window.GetHwnd(),WM_USER,reinterpret_cast(message),0); } +void UpdateDialogWin32::quit() +{ + PostQuitMessage(0); +} + LRESULT WINAPI UpdateDialogWin32::windowProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) @@ -157,7 +162,7 @@ LRESULT WINAPI UpdateDialogWin32::windowProc(HWND window, UINT message, WPARAM w { if (reinterpret_cast(lParam) == m_finishButton.GetHwnd()) { - PostQuitMessage(0); + quit(); } } break; diff --git a/src/UpdateDialogWin32.h b/src/UpdateDialogWin32.h index 1070a1a..035c46a 100644 --- a/src/UpdateDialogWin32.h +++ b/src/UpdateDialogWin32.h @@ -8,14 +8,16 @@ #include "controls.h" #include "stdcontrols.h" -class UpdateDialogWin32 : public UpdateObserver +class UpdateDialogWin32 : public UpdateDialog { public: UpdateDialogWin32(); ~UpdateDialogWin32(); - void init(); - void exec(); + // implements UpdateDialog + virtual void init(int argc, char** argv); + virtual void exec(); + virtual void quit(); // implements UpdateObserver virtual void updateError(const std::string& errorMessage); diff --git a/src/UpdateInstaller.cpp b/src/UpdateInstaller.cpp index eb840d1..8798a2c 100644 --- a/src/UpdateInstaller.cpp +++ b/src/UpdateInstaller.cpp @@ -12,6 +12,7 @@ UpdateInstaller::UpdateInstaller() , m_script(0) , m_observer(0) , m_forceElevated(false) +, m_autoClose(false) { } @@ -445,3 +446,8 @@ void UpdateInstaller::postInstallUpdate() #endif } +void UpdateInstaller::setAutoClose(bool autoClose) +{ + m_autoClose = autoClose; +} + diff --git a/src/UpdateInstaller.h b/src/UpdateInstaller.h index 971479f..5dfa263 100644 --- a/src/UpdateInstaller.h +++ b/src/UpdateInstaller.h @@ -32,6 +32,7 @@ class UpdateInstaller void setScript(UpdateScript* script); void setWaitPid(PLATFORM_PID pid); void setForceElevated(bool elevated); + void setAutoClose(bool autoClose); void setObserver(UpdateObserver* observer); @@ -64,5 +65,6 @@ class UpdateInstaller UpdateObserver* m_observer; std::map m_backups; bool m_forceElevated; + bool m_autoClose; }; diff --git a/src/UpdaterOptions.cpp b/src/UpdaterOptions.cpp index 15504cc..1ea820d 100644 --- a/src/UpdaterOptions.cpp +++ b/src/UpdaterOptions.cpp @@ -21,6 +21,7 @@ UpdaterOptions::UpdaterOptions() , waitPid(0) , showVersion(false) , forceElevated(false) +, autoClose(false) { } @@ -115,6 +116,7 @@ void UpdaterOptions::parse(int argc, char** argv) parser.setOption("mode"); parser.setFlag("version"); parser.setFlag("force-elevated"); + parser.setFlag("auto-close"); parser.processCommandArgs(argc,argv); @@ -141,6 +143,7 @@ void UpdaterOptions::parse(int argc, char** argv) showVersion = parser.getFlag("version"); forceElevated = parser.getFlag("force-elevated"); + autoClose = parser.getFlag("auto-close"); if (installDir.empty()) { diff --git a/src/UpdaterOptions.h b/src/UpdaterOptions.h index 6757421..a8496d9 100644 --- a/src/UpdaterOptions.h +++ b/src/UpdaterOptions.h @@ -18,6 +18,7 @@ class UpdaterOptions std::string logFile; bool showVersion; bool forceElevated; + bool autoClose; private: void parseOldFormatArgs(int argc, char** argv); diff --git a/src/main.cpp b/src/main.cpp index ba5224a..848a34f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,7 +10,7 @@ #include "tinythread.h" #if defined(PLATFORM_LINUX) - #include "UpdateDialogGtkWrapper.h" + #include "UpdateDialogGtkFactory.h" #include "UpdateDialogAscii.h" #endif @@ -24,8 +24,9 @@ #endif #include +#include -#define UPDATER_VERSION "0.15" +#define UPDATER_VERSION "0.16" void runWithUi(int argc, char** argv, UpdateInstaller* installer); @@ -144,6 +145,7 @@ int main(int argc, char** argv) installer.setScript(&script); installer.setWaitPid(options.waitPid); installer.setForceElevated(options.forceElevated); + installer.setAutoClose(options.autoClose); if (options.mode == UpdateInstaller::Main) { @@ -161,41 +163,31 @@ int main(int argc, char** argv) return 0; } -#ifdef PLATFORM_LINUX -void runWithUi(int argc, char** argv, UpdateInstaller* installer) +UpdateDialog* createUpdateDialog() { - UpdateDialogAscii asciiDialog; - UpdateDialogGtkWrapper dialog; - bool useGtk = dialog.init(argc,argv); - if (useGtk) +#if defined(PLATFORM_WINDOWS) + return new UpdateDialogWin32(); +#elif defined(PLATFORM_MAC) + return new UpdateDialogCocoa(); +#elif defined(PLATFORM_LINUX) + UpdateDialog* dialog = UpdateDialogGtkFactory::createDialog(); + if (!dialog) { - installer->setObserver(&dialog); + dialog = new UpdateDialogAscii(); } - else - { - asciiDialog.init(); - installer->setObserver(&asciiDialog); - } - tthread::thread updaterThread(runUpdaterThread,installer); - if (useGtk) - { - dialog.exec(); - } - updaterThread.join(); -} + return dialog; #endif +} -#ifdef PLATFORM_MAC void runWithUi(int argc, char** argv, UpdateInstaller* installer) { - UpdateDialogCocoa dialog; - installer->setObserver(&dialog); - dialog.init(); - tthread::thread updaterThread(runUpdaterThread,installer); - dialog.exec(); + std::auto_ptr dialog(createUpdateDialog()); + dialog->init(argc, argv); + installer->setObserver(dialog.get()); + tthread::thread updaterThread(runUpdaterThread, installer); + dialog->exec(); updaterThread.join(); } -#endif #ifdef PLATFORM_WINDOWS // application entry point under Windows @@ -209,14 +201,4 @@ int CALLBACK WinMain(HINSTANCE hInstance, ProcessUtils::convertWindowsCommandLine(GetCommandLineW(),argc,argv); return main(argc,argv); } - -void runWithUi(int argc, char** argv, UpdateInstaller* installer) -{ - UpdateDialogWin32 dialog; - installer->setObserver(&dialog); - dialog.init(); - tthread::thread updaterThread(runUpdaterThread,installer); - dialog.exec(); - updaterThread.join(); -} #endif