mirror of
https://github.com/etlegacy/Update-Installer.git
synced 2025-02-02 12:21:23 +00:00
Add a basic GTK update installation dialog and a stub function in UpdateInstaller to restart the main app after the update is complete.
* Add optional GTK mode to the updater build. This pulls in a large number of extra dependencies, but dependencies which should be fairly ubiquitous on Linux systems. If these dependencies prove to be a problem we could look at providing an alternative, more basic UI and loading the appropriate UI dynamically. * Implement update progress dialog for GTK. The dialog needs visual polish but is functional.
This commit is contained in:
parent
f1367671b6
commit
85c4c58dc9
7 changed files with 252 additions and 22 deletions
|
@ -3,6 +3,17 @@ add_subdirectory(tests)
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
|
include(UsePkgConfig)
|
||||||
|
pkgconfig(gtk+-2.0 GTK2_INCLUDE_DIR GTK2_LINK_DIR GTK2_LINK_FLAGS GTK2_CFLAGS)
|
||||||
|
|
||||||
|
option(ENABLE_GTK ON)
|
||||||
|
|
||||||
|
if (ENABLE_GTK)
|
||||||
|
include_directories(${GTK2_INCLUDE_DIR})
|
||||||
|
add_definitions(${GTK2_CFLAGS})
|
||||||
|
add_definitions(-DENABLE_GTK)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_definitions(-DTIXML_USE_STL)
|
add_definitions(-DTIXML_USE_STL)
|
||||||
|
|
||||||
set (SOURCES
|
set (SOURCES
|
||||||
|
@ -15,6 +26,10 @@ set (SOURCES
|
||||||
UpdaterOptions.cpp
|
UpdaterOptions.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (ENABLE_GTK)
|
||||||
|
set(SOURCES ${SOURCES} UpdateDialogGtk.cpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
set (HEADERS
|
set (HEADERS
|
||||||
Dir.h
|
Dir.h
|
||||||
FileOps.h
|
FileOps.h
|
||||||
|
@ -25,6 +40,10 @@ set (HEADERS
|
||||||
UpdaterOptions.h
|
UpdaterOptions.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (ENABLE_GTK)
|
||||||
|
set(HEADERS ${HEADERS} UpdateDialogGtk.h)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(updatershared
|
add_library(updatershared
|
||||||
${SOURCES}
|
${SOURCES}
|
||||||
${HEADERS}
|
${HEADERS}
|
||||||
|
@ -35,8 +54,14 @@ 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()
|
||||||
|
@ -52,7 +77,6 @@ if(APPLE)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
target_link_libraries(updater
|
target_link_libraries(updater
|
||||||
updatershared
|
updatershared
|
||||||
)
|
)
|
||||||
|
|
118
src/UpdateDialogGtk.cpp
Normal file
118
src/UpdateDialogGtk.cpp
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
#include "UpdateDialogGtk.h"
|
||||||
|
|
||||||
|
#include "Log.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
UpdateDialogGtk::UpdateDialogGtk()
|
||||||
|
: m_restartApp(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdateDialogGtk::restartApp() const
|
||||||
|
{
|
||||||
|
return m_restartApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDialogGtk::init(int argc, char** argv)
|
||||||
|
{
|
||||||
|
gtk_init(&argc,&argv);
|
||||||
|
|
||||||
|
m_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||||
|
gtk_window_set_title(GTK_WINDOW(m_window),"Mendeley Updater");
|
||||||
|
|
||||||
|
m_progressLabel = gtk_label_new("Installing Updates");
|
||||||
|
GtkWidget* windowLayout = gtk_vbox_new(FALSE,3);
|
||||||
|
GtkWidget* buttonLayout = gtk_hbox_new(FALSE,3);
|
||||||
|
|
||||||
|
m_finishButton = gtk_button_new_with_label("Finish");
|
||||||
|
gtk_widget_set_sensitive(m_finishButton,false);
|
||||||
|
|
||||||
|
m_progressBar = gtk_progress_bar_new();
|
||||||
|
|
||||||
|
gtk_signal_connect(GTK_OBJECT(m_finishButton),"clicked",
|
||||||
|
GTK_SIGNAL_FUNC(UpdateDialogGtk::finish),this);
|
||||||
|
|
||||||
|
gtk_container_add(GTK_CONTAINER(m_window),windowLayout);
|
||||||
|
gtk_container_set_border_width(GTK_CONTAINER(m_window),8);
|
||||||
|
gtk_container_add(GTK_CONTAINER(windowLayout),m_progressLabel);
|
||||||
|
gtk_container_add(GTK_CONTAINER(windowLayout),m_progressBar);
|
||||||
|
gtk_container_add(GTK_CONTAINER(windowLayout),buttonLayout);
|
||||||
|
|
||||||
|
gtk_box_pack_start(GTK_BOX(buttonLayout),m_finishButton,true,false,0);
|
||||||
|
|
||||||
|
gtk_widget_show(m_progressLabel);
|
||||||
|
gtk_widget_show(windowLayout);
|
||||||
|
gtk_widget_show(buttonLayout);
|
||||||
|
gtk_widget_show(m_finishButton);
|
||||||
|
gtk_widget_show(m_progressBar);
|
||||||
|
|
||||||
|
gtk_widget_show(m_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDialogGtk::exec()
|
||||||
|
{
|
||||||
|
gtk_main();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDialogGtk::finish(void* _dialog)
|
||||||
|
{
|
||||||
|
UpdateDialogGtk* dialog = static_cast<UpdateDialogGtk*>(_dialog);
|
||||||
|
dialog->m_restartApp = true;
|
||||||
|
gtk_main_quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean UpdateDialogGtk::notify(void* _message)
|
||||||
|
{
|
||||||
|
Message* message = static_cast<Message*>(_message);
|
||||||
|
switch (message->type)
|
||||||
|
{
|
||||||
|
case Message::UpdateProgress:
|
||||||
|
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(message->dialog->m_progressBar),message->progress/100.0);
|
||||||
|
break;
|
||||||
|
case Message::UpdateFailed:
|
||||||
|
gtk_label_set_text(GTK_LABEL(message->dialog->m_progressLabel),
|
||||||
|
("There was a problem installing the update: " + message->message).c_str());;
|
||||||
|
gtk_widget_set_sensitive(message->dialog->m_finishButton,true);
|
||||||
|
break;
|
||||||
|
case Message::UpdateFinished:
|
||||||
|
gtk_label_set_text(GTK_LABEL(message->dialog->m_progressLabel),
|
||||||
|
"Update installed. Click 'Finish' to restart the application.");
|
||||||
|
gtk_widget_set_sensitive(message->dialog->m_finishButton,true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
delete message;
|
||||||
|
|
||||||
|
// do not invoke this function again
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// callbacks during update installation
|
||||||
|
void UpdateDialogGtk::updateError(const std::string& errorMessage)
|
||||||
|
{
|
||||||
|
Message* message = new Message(this,Message::UpdateFailed);
|
||||||
|
message->message = errorMessage;
|
||||||
|
g_idle_add(&UpdateDialogGtk::notify,message);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdateDialogGtk::updateRetryCancel(const std::string& message)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDialogGtk::updateProgress(int percentage)
|
||||||
|
{
|
||||||
|
Message* message = new Message(this,Message::UpdateProgress);
|
||||||
|
message->progress = percentage;
|
||||||
|
g_idle_add(&UpdateDialogGtk::notify,message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDialogGtk::updateFinished()
|
||||||
|
{
|
||||||
|
Message* message = new Message(this,Message::UpdateFinished);
|
||||||
|
g_idle_add(&UpdateDialogGtk::notify,message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,55 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// TODO - UI for update dialog under Gtk
|
#include "UpdateObserver.h"
|
||||||
class UpdateDialogGtk
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
class UpdateDialogGtk : public UpdateObserver
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
UpdateDialogGtk();
|
||||||
|
|
||||||
|
bool restartApp() const;
|
||||||
|
|
||||||
|
void init(int argc, char** argv);
|
||||||
|
void exec();
|
||||||
|
|
||||||
|
// observer callbacks - these may be called
|
||||||
|
// from a background thread
|
||||||
|
virtual void updateError(const std::string& errorMessage);
|
||||||
|
virtual bool updateRetryCancel(const std::string& message);
|
||||||
|
virtual void updateProgress(int percentage);
|
||||||
|
virtual void updateFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Message
|
||||||
|
{
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
UpdateFailed,
|
||||||
|
UpdateProgress,
|
||||||
|
UpdateFinished
|
||||||
|
};
|
||||||
|
|
||||||
|
Message(UpdateDialogGtk* _dialog, Type _type)
|
||||||
|
: dialog(_dialog)
|
||||||
|
, type(_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateDialogGtk* dialog;
|
||||||
|
Type type;
|
||||||
|
std::string message;
|
||||||
|
int progress;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void finish(void* dialog);
|
||||||
|
static gboolean notify(void* message);
|
||||||
|
|
||||||
|
GtkWidget* m_window;
|
||||||
|
GtkWidget* m_progressLabel;
|
||||||
|
GtkWidget* m_finishButton;
|
||||||
|
GtkWidget* m_progressBar;
|
||||||
|
bool m_restartApp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -302,3 +302,13 @@ bool UpdateInstaller::checkAccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateInstaller::setObserver(UpdateObserver* observer)
|
||||||
|
{
|
||||||
|
m_observer = observer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateInstaller::restartMainApp()
|
||||||
|
{
|
||||||
|
LOG(Warn,"Restarting main app not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@ class UpdateInstaller
|
||||||
|
|
||||||
void run() throw ();
|
void run() throw ();
|
||||||
|
|
||||||
|
void restartMainApp();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void cleanup();
|
void cleanup();
|
||||||
void revert();
|
void revert();
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
class UpdateObserver
|
class UpdateObserver
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
64
src/main.cpp
64
src/main.cpp
|
@ -6,17 +6,13 @@
|
||||||
|
|
||||||
#include "tinythread.h"
|
#include "tinythread.h"
|
||||||
|
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_LINUX) and defined(ENABLE_GTK)
|
||||||
#include "UpdateDialogWin32.h"
|
|
||||||
#elif defined(PLATFORM_MAC)
|
|
||||||
#include "UpdateDialogCocoa.h"
|
|
||||||
#elif defined(PLATFORM_LINUX)
|
|
||||||
#include "UpdateDialogGtk.h"
|
#include "UpdateDialogGtk.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
void setupUi(UpdateInstaller* installer);
|
void runWithUi(int argc, char** argv, UpdateInstaller* installer);
|
||||||
|
|
||||||
void runUpdaterThread(void* arg)
|
void runUpdaterThread(void* arg)
|
||||||
{
|
{
|
||||||
|
@ -44,11 +40,6 @@ int main(int argc, char** argv)
|
||||||
script.parse(options.script);
|
script.parse(options.script);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.mode == UpdateInstaller::Main)
|
|
||||||
{
|
|
||||||
setupUi(&installer);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(Info,"started updater. install-dir: " + options.installDir
|
LOG(Info,"started updater. install-dir: " + options.installDir
|
||||||
+ ", package-dir: " + options.packageDir
|
+ ", package-dir: " + options.packageDir
|
||||||
+ ", wait-pid: " + intToStr(options.waitPid)
|
+ ", wait-pid: " + intToStr(options.waitPid)
|
||||||
|
@ -61,20 +52,55 @@ int main(int argc, char** argv)
|
||||||
installer.setScript(&script);
|
installer.setScript(&script);
|
||||||
installer.setWaitPid(options.waitPid);
|
installer.setWaitPid(options.waitPid);
|
||||||
|
|
||||||
tthread::thread updaterThread(runUpdaterThread,&installer);
|
if (options.mode == UpdateInstaller::Main)
|
||||||
updaterThread.join();
|
{
|
||||||
|
runWithUi(argc,argv,&installer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
installer.run();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupUi(UpdateInstaller* installer)
|
#ifdef PLATFORM_LINUX
|
||||||
|
void runWithUi(int argc, char** argv, UpdateInstaller* installer)
|
||||||
{
|
{
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#ifdef ENABLE_GTK
|
||||||
UpdateDialogWin32 dialog;
|
LOG(Info,"setting up GTK UI");
|
||||||
#elif defined(PLATFORM_MAC)
|
|
||||||
UpdateDialogCocoa dialog;
|
|
||||||
#elif defined(PLATFORM_LINUX)
|
|
||||||
UpdateDialogGtk dialog;
|
UpdateDialogGtk dialog;
|
||||||
|
installer->setObserver(&dialog);
|
||||||
|
dialog.init(argc,argv);
|
||||||
|
tthread::thread updaterThread(runUpdaterThread,installer);
|
||||||
|
dialog.exec();
|
||||||
|
updaterThread.join();
|
||||||
|
|
||||||
|
if (dialog.restartApp())
|
||||||
|
{
|
||||||
|
LOG(Info,"Restarting app after install");
|
||||||
|
installer->restartMainApp();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// no UI available - do a silent install
|
||||||
|
installer->run();
|
||||||
|
installer->restartMainApp();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PLATFORM_MAC
|
||||||
|
void runWithUi(int argc, char** argv, UpdateInstaller* installer)
|
||||||
|
{
|
||||||
|
// TODO - Cocoa UI
|
||||||
|
installer->run();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
void runWithUi(int argc, char** argv, UpdateInstaller* installer)
|
||||||
|
{
|
||||||
|
// TODO - Windows UI
|
||||||
|
installer->run();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue