mirror of
https://github.com/etlegacy/Update-Installer.git
synced 2024-11-10 06:31:49 +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)
|
||||
|
||||
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)
|
||||
|
||||
set (SOURCES
|
||||
|
@ -15,6 +26,10 @@ set (SOURCES
|
|||
UpdaterOptions.cpp
|
||||
)
|
||||
|
||||
if (ENABLE_GTK)
|
||||
set(SOURCES ${SOURCES} UpdateDialogGtk.cpp)
|
||||
endif()
|
||||
|
||||
set (HEADERS
|
||||
Dir.h
|
||||
FileOps.h
|
||||
|
@ -25,6 +40,10 @@ set (HEADERS
|
|||
UpdaterOptions.h
|
||||
)
|
||||
|
||||
if (ENABLE_GTK)
|
||||
set(HEADERS ${HEADERS} UpdateDialogGtk.h)
|
||||
endif()
|
||||
|
||||
add_library(updatershared
|
||||
${SOURCES}
|
||||
${HEADERS}
|
||||
|
@ -35,8 +54,14 @@ target_link_libraries(updatershared
|
|||
tinyxml
|
||||
minizip
|
||||
tinythread
|
||||
${GTK2_LINK_FLAGS}
|
||||
)
|
||||
|
||||
if (ENABLE_GTK)
|
||||
target_link_libraries(updatershared
|
||||
${GTK2_LINK_FLAGS})
|
||||
endif()
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(updatershared pthread)
|
||||
endif()
|
||||
|
@ -52,7 +77,6 @@ if(APPLE)
|
|||
)
|
||||
endif()
|
||||
|
||||
|
||||
target_link_libraries(updater
|
||||
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
|
||||
|
||||
// TODO - UI for update dialog under Gtk
|
||||
class UpdateDialogGtk
|
||||
#include "UpdateObserver.h"
|
||||
|
||||
#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 restartMainApp();
|
||||
|
||||
private:
|
||||
void cleanup();
|
||||
void revert();
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class UpdateObserver
|
||||
{
|
||||
public:
|
||||
|
|
64
src/main.cpp
64
src/main.cpp
|
@ -6,17 +6,13 @@
|
|||
|
||||
#include "tinythread.h"
|
||||
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
#include "UpdateDialogWin32.h"
|
||||
#elif defined(PLATFORM_MAC)
|
||||
#include "UpdateDialogCocoa.h"
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
#if defined(PLATFORM_LINUX) and defined(ENABLE_GTK)
|
||||
#include "UpdateDialogGtk.h"
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void setupUi(UpdateInstaller* installer);
|
||||
void runWithUi(int argc, char** argv, UpdateInstaller* installer);
|
||||
|
||||
void runUpdaterThread(void* arg)
|
||||
{
|
||||
|
@ -44,11 +40,6 @@ int main(int argc, char** argv)
|
|||
script.parse(options.script);
|
||||
}
|
||||
|
||||
if (options.mode == UpdateInstaller::Main)
|
||||
{
|
||||
setupUi(&installer);
|
||||
}
|
||||
|
||||
LOG(Info,"started updater. install-dir: " + options.installDir
|
||||
+ ", package-dir: " + options.packageDir
|
||||
+ ", wait-pid: " + intToStr(options.waitPid)
|
||||
|
@ -61,20 +52,55 @@ int main(int argc, char** argv)
|
|||
installer.setScript(&script);
|
||||
installer.setWaitPid(options.waitPid);
|
||||
|
||||
tthread::thread updaterThread(runUpdaterThread,&installer);
|
||||
updaterThread.join();
|
||||
if (options.mode == UpdateInstaller::Main)
|
||||
{
|
||||
runWithUi(argc,argv,&installer);
|
||||
}
|
||||
else
|
||||
{
|
||||
installer.run();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setupUi(UpdateInstaller* installer)
|
||||
#ifdef PLATFORM_LINUX
|
||||
void runWithUi(int argc, char** argv, UpdateInstaller* installer)
|
||||
{
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
UpdateDialogWin32 dialog;
|
||||
#elif defined(PLATFORM_MAC)
|
||||
UpdateDialogCocoa dialog;
|
||||
#elif defined(PLATFORM_LINUX)
|
||||
#ifdef ENABLE_GTK
|
||||
LOG(Info,"setting up GTK UI");
|
||||
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
|
||||
|
||||
#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