mirror of
https://github.com/etlegacy/Update-Installer.git
synced 2025-01-22 07:21:13 +00:00
Make the GTK dependency optional at runtime on Linux
Build the GTK dialog as a separate shared library which is embedded into the main updater binary. At runtime the updater extracts the shared library and attempts to load it. If this succeeds, the GTK UI is used, otherwise the updater will fall back to something else - currently a silent install.
This commit is contained in:
parent
93f58e77da
commit
630d64e859
6 changed files with 189 additions and 16 deletions
|
@ -16,6 +16,8 @@ if (ENABLE_GTK)
|
||||||
include_directories(${GTK2_INCLUDE_DIR})
|
include_directories(${GTK2_INCLUDE_DIR})
|
||||||
add_definitions(${GTK2_CFLAGS})
|
add_definitions(${GTK2_CFLAGS})
|
||||||
add_definitions(-DENABLE_GTK)
|
add_definitions(-DENABLE_GTK)
|
||||||
|
add_library(updatergtk SHARED UpdateDialogGtk.cpp UpdateDialogGtk.h)
|
||||||
|
target_link_libraries(updatergtk ${GTK2_LINK_FLAGS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_definitions(-DTIXML_USE_STL)
|
add_definitions(-DTIXML_USE_STL)
|
||||||
|
@ -30,9 +32,6 @@ set (SOURCES
|
||||||
UpdaterOptions.cpp
|
UpdaterOptions.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (ENABLE_GTK)
|
|
||||||
set(SOURCES ${SOURCES} UpdateDialogGtk.cpp)
|
|
||||||
endif()
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(SOURCES ${SOURCES} UpdateDialogCocoa.mm)
|
set(SOURCES ${SOURCES} UpdateDialogCocoa.mm)
|
||||||
endif()
|
endif()
|
||||||
|
@ -51,8 +50,19 @@ set (HEADERS
|
||||||
)
|
)
|
||||||
|
|
||||||
if (ENABLE_GTK)
|
if (ENABLE_GTK)
|
||||||
set(HEADERS ${HEADERS} UpdateDialogGtk.h)
|
# embed the GTK helper library into the updater binary.
|
||||||
|
# At runtime it will be extracted and loaded if the
|
||||||
|
# GTK libraries are available
|
||||||
|
|
||||||
|
set(GTK_UPDATER_LIB libupdatergtk.so)
|
||||||
|
set(GTK_BIN_FILE ${CMAKE_CURRENT_BINARY_DIR}/libupdatergtk.cpp)
|
||||||
|
add_custom_command(OUTPUT ${GTK_BIN_FILE}
|
||||||
|
COMMAND xxd -i ${GTK_UPDATER_LIB} ${GTK_BIN_FILE}
|
||||||
|
DEPENDS updatergtk)
|
||||||
|
set(SOURCES ${SOURCES} UpdateDialogGtkWrapper.cpp ${GTK_BIN_FILE})
|
||||||
|
set(HEADERS ${HEADERS} UpdateDialogGtkWrapper.h)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(HEADERS ${HEADERS} UpdateDialogCocoa.h)
|
set(HEADERS ${HEADERS} UpdateDialogCocoa.h)
|
||||||
endif()
|
endif()
|
||||||
|
@ -70,14 +80,8 @@ target_link_libraries(updatershared
|
||||||
tinyxml
|
tinyxml
|
||||||
minizip
|
minizip
|
||||||
tinythread
|
tinythread
|
||||||
${GTK2_LINK_FLAGS}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (ENABLE_GTK)
|
|
||||||
target_link_libraries(updatershared
|
|
||||||
${GTK2_LINK_FLAGS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (UNIX)
|
if (UNIX)
|
||||||
target_link_libraries(updatershared pthread)
|
target_link_libraries(updatershared pthread)
|
||||||
endif()
|
endif()
|
||||||
|
@ -97,6 +101,7 @@ endif()
|
||||||
|
|
||||||
target_link_libraries(updater
|
target_link_libraries(updater
|
||||||
updatershared
|
updatershared
|
||||||
|
dl
|
||||||
)
|
)
|
||||||
|
|
||||||
install(TARGETS updater RUNTIME DESTINATION bin)
|
install(TARGETS updater RUNTIME DESTINATION bin)
|
||||||
|
|
|
@ -1,11 +1,37 @@
|
||||||
#include "UpdateDialogGtk.h"
|
#include "UpdateDialogGtk.h"
|
||||||
|
|
||||||
#include "Log.h"
|
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
UpdateDialogGtk* update_dialog_gtk_new(int argc, char** argv)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
UpdateDialogGtk::UpdateDialogGtk()
|
UpdateDialogGtk::UpdateDialogGtk()
|
||||||
: m_hadError(false)
|
: m_hadError(false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,3 +30,14 @@ class UpdateDialogGtk : public UpdateObserver
|
||||||
bool m_hadError;
|
bool m_hadError;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
95
src/UpdateDialogGtkWrapper.cpp
Normal file
95
src/UpdateDialogGtkWrapper.cpp
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#include "UpdateDialogGtkWrapper.h"
|
||||||
|
|
||||||
|
#include "Log.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// 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<typeof(function)>(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);
|
||||||
|
}
|
||||||
|
|
30
src/UpdateDialogGtkWrapper.h
Normal file
30
src/UpdateDialogGtkWrapper.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
12
src/main.cpp
12
src/main.cpp
|
@ -8,7 +8,7 @@
|
||||||
#include "tinythread.h"
|
#include "tinythread.h"
|
||||||
|
|
||||||
#if defined(PLATFORM_LINUX) and defined(ENABLE_GTK)
|
#if defined(PLATFORM_LINUX) and defined(ENABLE_GTK)
|
||||||
#include "UpdateDialogGtk.h"
|
#include "UpdateDialogGtkWrapper.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(PLATFORM_MAC)
|
#if defined(PLATFORM_MAC)
|
||||||
|
@ -88,11 +88,17 @@ int main(int argc, char** argv)
|
||||||
void runWithUi(int argc, char** argv, UpdateInstaller* installer)
|
void runWithUi(int argc, char** argv, UpdateInstaller* installer)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_GTK
|
#ifdef ENABLE_GTK
|
||||||
UpdateDialogGtk dialog;
|
UpdateDialogGtkWrapper dialog;
|
||||||
|
bool useGtk = dialog.init(argc,argv);
|
||||||
|
if (useGtk)
|
||||||
|
{
|
||||||
installer->setObserver(&dialog);
|
installer->setObserver(&dialog);
|
||||||
dialog.init(argc,argv);
|
}
|
||||||
tthread::thread updaterThread(runUpdaterThread,installer);
|
tthread::thread updaterThread(runUpdaterThread,installer);
|
||||||
|
if (useGtk)
|
||||||
|
{
|
||||||
dialog.exec();
|
dialog.exec();
|
||||||
|
}
|
||||||
updaterThread.join();
|
updaterThread.join();
|
||||||
#else
|
#else
|
||||||
// no UI available - do a silent install
|
// no UI available - do a silent install
|
||||||
|
|
Loading…
Reference in a new issue