mirror of
https://github.com/aseprite/aseprite.git
synced 2024-09-02 13:09:27 +00:00
Add automatic check for updates with app::CheckUpdateThreadLauncher
and show notifications in StatusBar. + Added updater library. + Removed "Check for New Version" command.
This commit is contained in:
parent
c7cf74228b
commit
cf9a296e5d
@ -325,7 +325,6 @@
|
||||
<item command="QuickReference" text="Quick &Reference" />
|
||||
<separator />
|
||||
<item command="Donate" text="&Donate" />
|
||||
<item command="CheckUpdates" text="&Check for New Version" />
|
||||
<separator />
|
||||
<item command="About" text="&About" />
|
||||
</menu>
|
||||
|
@ -51,7 +51,7 @@ if (CMAKE_USE_PTHREADS_INIT)
|
||||
endif()
|
||||
|
||||
# All libraries for .exe files
|
||||
set(all_libs aseprite-library undo-lib filters-lib gui-lib gfx-lib net-lib base-lib
|
||||
set(all_libs aseprite-library undo-lib updater-lib filters-lib gui-lib gfx-lib net-lib base-lib
|
||||
${libs3rdparty} allegro ${sys_libs})
|
||||
|
||||
# Directories where .h files can be found
|
||||
@ -76,6 +76,7 @@ add_subdirectory(gfx)
|
||||
add_subdirectory(gui)
|
||||
add_subdirectory(net)
|
||||
add_subdirectory(undo)
|
||||
add_subdirectory(updater)
|
||||
|
||||
######################################################################
|
||||
# aseprite library
|
||||
@ -100,6 +101,7 @@ add_library(aseprite-library
|
||||
undo_transaction.cpp
|
||||
xml_exception.cpp
|
||||
xml_widgets.cpp
|
||||
app/check_update.cpp
|
||||
app/color.cpp
|
||||
app/color_utils.cpp
|
||||
commands/cmd_about.cpp
|
||||
@ -110,7 +112,6 @@ add_library(aseprite-library
|
||||
commands/cmd_change_color.cpp
|
||||
commands/cmd_change_image_type.cpp
|
||||
commands/cmd_change_pen.cpp
|
||||
commands/cmd_check_updates.cpp
|
||||
commands/cmd_clear.cpp
|
||||
commands/cmd_close_file.cpp
|
||||
commands/cmd_configure_tools.cpp
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "app.h"
|
||||
|
||||
#include "app/check_update.h"
|
||||
#include "app/color_utils.h"
|
||||
#include "base/exception.h"
|
||||
#include "base/unique_ptr.h"
|
||||
@ -157,8 +158,12 @@ App::App(int argc, char* argv[])
|
||||
set_current_palette(NULL, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int App::run()
|
||||
{
|
||||
app::CheckUpdateThreadLauncher checkUpdate;
|
||||
|
||||
// Initialize GUI interface
|
||||
if (isGui()) {
|
||||
View* view;
|
||||
@ -282,6 +287,10 @@ int App::run()
|
||||
// Support to drop files from Windows explorer
|
||||
install_drop_files();
|
||||
|
||||
// Launch the thread to check for updates.
|
||||
checkUpdate.launch();
|
||||
|
||||
// Run the GUI main message loop
|
||||
gui_run();
|
||||
|
||||
uninstall_drop_files();
|
||||
|
184
src/app/check_update.cpp
Normal file
184
src/app/check_update.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "app/check_update.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "base/bind.h"
|
||||
#include "core/cfg.h"
|
||||
#include "modules/gui.h"
|
||||
#include "widgets/statebar.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace app {
|
||||
|
||||
class CheckUpdateBackgroundJob : public updater::CheckUpdateDelegate
|
||||
{
|
||||
public:
|
||||
CheckUpdateBackgroundJob()
|
||||
: m_canceled(false)
|
||||
, m_received(false) { }
|
||||
|
||||
virtual ~CheckUpdateBackgroundJob() { }
|
||||
|
||||
void cancel()
|
||||
{
|
||||
m_canceled = true;
|
||||
}
|
||||
|
||||
bool isCanceled() const
|
||||
{
|
||||
return m_canceled;
|
||||
}
|
||||
|
||||
bool isReceived() const
|
||||
{
|
||||
return m_received;
|
||||
}
|
||||
|
||||
void sendRequest(const updater::Uuid& uuid, const std::string& extraParams)
|
||||
{
|
||||
m_checker.checkNewVersion(uuid, extraParams, this);
|
||||
}
|
||||
|
||||
const updater::CheckUpdateResponse& getResponse() const
|
||||
{
|
||||
return m_response;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// CheckUpdateDelegate implementation
|
||||
virtual void onResponse(updater::CheckUpdateResponse& data)
|
||||
{
|
||||
m_response = data;
|
||||
m_received = true;
|
||||
}
|
||||
|
||||
bool m_canceled;
|
||||
bool m_received;
|
||||
updater::CheckUpdate m_checker;
|
||||
updater::CheckUpdateResponse m_response;
|
||||
};
|
||||
|
||||
CheckUpdateThreadLauncher::CheckUpdateThreadLauncher()
|
||||
: m_received(false)
|
||||
, m_guiMonitor(NULL)
|
||||
, m_inits(get_config_int("Updater", "Inits", 0))
|
||||
, m_exits(get_config_int("Updater", "Exits", 0))
|
||||
{
|
||||
// Minimal stats: number of initializations
|
||||
set_config_int("Updater", "Inits", get_config_int("Updater", "Inits", 0)+1);
|
||||
flush_config_file();
|
||||
}
|
||||
|
||||
CheckUpdateThreadLauncher::~CheckUpdateThreadLauncher()
|
||||
{
|
||||
if (m_guiMonitor) {
|
||||
remove_gui_monitor(m_guiMonitor);
|
||||
m_guiMonitor = NULL;
|
||||
}
|
||||
|
||||
if (m_thread) {
|
||||
if (m_bgJob)
|
||||
m_bgJob->cancel();
|
||||
|
||||
m_thread->join();
|
||||
}
|
||||
|
||||
// Minimal stats: number of exits
|
||||
set_config_int("Updater", "Exits", get_config_int("Updater", "Exits", 0)+1);
|
||||
flush_config_file();
|
||||
}
|
||||
|
||||
void CheckUpdateThreadLauncher::launch()
|
||||
{
|
||||
if (m_uuid.empty())
|
||||
m_uuid = get_config_string("Updater", "Uuid", "");
|
||||
|
||||
m_bgJob.reset(new CheckUpdateBackgroundJob);
|
||||
m_thread.reset(new base::thread(Bind<void>(&CheckUpdateThreadLauncher::checkForUpdates, this)));
|
||||
|
||||
// Start a timer to monitor the progress of the background job
|
||||
// executed in "m_thread". The "monitorProxy" method will be called
|
||||
// periodically by the GUI main thread.
|
||||
m_guiMonitor = add_gui_monitor(CheckUpdateThreadLauncher::monitorProxy, NULL, (void*)this);
|
||||
}
|
||||
|
||||
bool CheckUpdateThreadLauncher::isReceived() const
|
||||
{
|
||||
return m_received;
|
||||
}
|
||||
|
||||
void CheckUpdateThreadLauncher::monitorActivity()
|
||||
{
|
||||
// If we do not receive a response yet...
|
||||
if (!m_received)
|
||||
return; // Skip and wait the next call.
|
||||
|
||||
// Depending on the type of update received
|
||||
switch (m_response.getUpdateType()) {
|
||||
|
||||
case updater::CheckUpdateResponse::NoUpdate:
|
||||
// Nothing to do, we are up-to-date
|
||||
break;
|
||||
|
||||
case updater::CheckUpdateResponse::Critical:
|
||||
case updater::CheckUpdateResponse::Major:
|
||||
app_get_statusbar()->showNotification("New Version!", m_response.getUrl().c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
// Save the new UUID
|
||||
if (!m_response.getUuid().empty()) {
|
||||
m_uuid = m_response.getUuid();
|
||||
set_config_string("Updater", "Uuid", m_uuid.c_str());
|
||||
flush_config_file();
|
||||
}
|
||||
|
||||
// Remove the monitor
|
||||
remove_gui_monitor(m_guiMonitor);
|
||||
m_guiMonitor = NULL;
|
||||
}
|
||||
|
||||
void CheckUpdateThreadLauncher::monitorProxy(void* data)
|
||||
{
|
||||
((CheckUpdateThreadLauncher*)data)->monitorActivity();
|
||||
}
|
||||
|
||||
// This method is executed in a special thread to send the HTTP request.
|
||||
void CheckUpdateThreadLauncher::checkForUpdates()
|
||||
{
|
||||
// Add mini-stats in the request
|
||||
std::stringstream extraParams;
|
||||
extraParams << "inits=" << m_inits
|
||||
<< "&exits=" << m_exits;
|
||||
|
||||
// Send the HTTP request to check for updates.
|
||||
m_bgJob->sendRequest(m_uuid, extraParams.str());
|
||||
|
||||
if (m_bgJob->isReceived()) {
|
||||
m_received = true;
|
||||
m_response = m_bgJob->getResponse();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
68
src/app/check_update.h
Normal file
68
src/app/check_update.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef APP_CHECK_UPDATE_H_INCLUDED
|
||||
#define APP_CHECK_UPDATE_H_INCLUDED
|
||||
|
||||
#include "base/thread.h"
|
||||
#include "base/unique_ptr.h"
|
||||
#include "updater/check_update.h"
|
||||
|
||||
struct Monitor;
|
||||
|
||||
namespace app {
|
||||
|
||||
class CheckUpdateBackgroundJob;
|
||||
|
||||
class CheckUpdateThreadLauncher
|
||||
{
|
||||
public:
|
||||
CheckUpdateThreadLauncher();
|
||||
~CheckUpdateThreadLauncher();
|
||||
|
||||
void launch();
|
||||
|
||||
bool isReceived() const;
|
||||
|
||||
const updater::CheckUpdateResponse& getResponse() const
|
||||
{
|
||||
return m_response;
|
||||
}
|
||||
|
||||
private:
|
||||
void monitorActivity();
|
||||
static void monitorProxy(void* data);
|
||||
|
||||
void checkForUpdates();
|
||||
|
||||
updater::Uuid m_uuid;
|
||||
UniquePtr<base::thread> m_thread;
|
||||
UniquePtr<CheckUpdateBackgroundJob> m_bgJob;
|
||||
bool m_received;
|
||||
updater::CheckUpdateResponse m_response;
|
||||
Monitor* m_guiMonitor;
|
||||
|
||||
// Mini-stats
|
||||
int m_inits;
|
||||
int m_exits;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,107 +0,0 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <allegro.h>
|
||||
|
||||
#include "base/convert_to.h"
|
||||
#include "base/string.h"
|
||||
#include "commands/command.h"
|
||||
#include "launcher.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// about
|
||||
|
||||
class CheckUpdatesCommand : public Command
|
||||
{
|
||||
public:
|
||||
CheckUpdatesCommand();
|
||||
Command* clone() const { return new CheckUpdatesCommand(*this); }
|
||||
|
||||
protected:
|
||||
void onExecute(Context* context);
|
||||
};
|
||||
|
||||
CheckUpdatesCommand::CheckUpdatesCommand()
|
||||
: Command("CheckUpdates",
|
||||
"Check for New Version",
|
||||
CmdUIOnlyFlag)
|
||||
{
|
||||
}
|
||||
|
||||
void CheckUpdatesCommand::onExecute(Context* context)
|
||||
{
|
||||
std::string url;
|
||||
url += WEBSITE;
|
||||
url += "update/?v=";
|
||||
url += VERSION; // ASE version
|
||||
|
||||
// Operating system
|
||||
std::string os;
|
||||
switch (os_type) {
|
||||
case OSTYPE_WIN3: os = "win3"; break;
|
||||
case OSTYPE_WIN95: os = "win95"; break;
|
||||
case OSTYPE_WIN98: os = "win98"; break;
|
||||
case OSTYPE_WINME: os = "winme"; break;
|
||||
case OSTYPE_WINNT: os = "winnt"; break;
|
||||
case OSTYPE_WIN2000: os = "win2000"; break;
|
||||
case OSTYPE_WINXP: os = "winxp"; break;
|
||||
case OSTYPE_WIN2003: os = "win2003"; break;
|
||||
case OSTYPE_WINVISTA: os = "winvista"; break;
|
||||
case OSTYPE_OS2: os = "os2"; break;
|
||||
case OSTYPE_WARP: os = "warp"; break;
|
||||
case OSTYPE_DOSEMU: os = "dosemu"; break;
|
||||
case OSTYPE_OPENDOS: os = "opendos"; break;
|
||||
case OSTYPE_LINUX: os = "linux"; break;
|
||||
case OSTYPE_SUNOS: os = "sunos"; break;
|
||||
case OSTYPE_FREEBSD: os = "freebsd"; break;
|
||||
case OSTYPE_NETBSD: os = "netbsd"; break;
|
||||
case OSTYPE_IRIX: os = "irix"; break;
|
||||
case OSTYPE_DARWIN: os = "darwin"; break;
|
||||
case OSTYPE_QNX: os = "qnx"; break;
|
||||
case OSTYPE_UNIX: os = "unix"; break;
|
||||
case OSTYPE_BEOS: os = "beos"; break;
|
||||
case OSTYPE_MACOS: os = "macos"; break;
|
||||
case OSTYPE_MACOSX: os = "macosx"; break;
|
||||
default:
|
||||
os = "unknown";
|
||||
break;
|
||||
}
|
||||
url += "&os=" + os;
|
||||
|
||||
// Version of the operating system
|
||||
if (os_version >= 0) {
|
||||
url += "&osver=";
|
||||
url += base::convert_to<base::string>(os_version);
|
||||
}
|
||||
if (os_revision >= 0) {
|
||||
url += "&osrev=";
|
||||
url += base::convert_to<base::string>(os_revision);
|
||||
}
|
||||
|
||||
Launcher::openUrl(url);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// CommandFactory
|
||||
|
||||
Command* CommandFactory::createCheckUpdatesCommand()
|
||||
{
|
||||
return new CheckUpdatesCommand;
|
||||
}
|
@ -25,7 +25,6 @@ FOR_EACH_COMMAND(CelProperties)
|
||||
FOR_EACH_COMMAND(ChangeColor)
|
||||
FOR_EACH_COMMAND(ChangeImageType)
|
||||
FOR_EACH_COMMAND(ChangePen)
|
||||
FOR_EACH_COMMAND(CheckUpdates)
|
||||
FOR_EACH_COMMAND(Clear)
|
||||
FOR_EACH_COMMAND(CloseAllFiles)
|
||||
FOR_EACH_COMMAND(CloseEditor)
|
||||
|
16
src/updater/CMakeLists.txt
Normal file
16
src/updater/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
# ASE - Allegro Sprite Editor
|
||||
# Copyright (C) 2001-2011 David Capello
|
||||
|
||||
set(UPDATER_LIB_SOURCES
|
||||
check_update.cpp
|
||||
user_agent.cpp)
|
||||
|
||||
if(WIN32)
|
||||
set(UPDATER_LIB_SOURCES ${UPDATER_LIB_SOURCES} user_agent_win.c)
|
||||
else()
|
||||
if(APPLE)
|
||||
set(UPDATER_LIB_SOURCES ${UPDATER_LIB_SOURCES} user_agent_mac.m)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(updater-lib ${UPDATER_LIB_SOURCES})
|
150
src/updater/check_update.cpp
Normal file
150
src/updater/check_update.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "updater/check_update.h"
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/convert_to.h"
|
||||
#include "net/http_headers.h"
|
||||
#include "net/http_request.h"
|
||||
#include "net/http_response.h"
|
||||
#include "tinyxml.h"
|
||||
#include "updater/user_agent.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#define UPDATE_URL WEBSITE "update/?xml=1"
|
||||
|
||||
namespace updater {
|
||||
|
||||
CheckUpdateResponse::CheckUpdateResponse()
|
||||
: m_type(Unknown)
|
||||
{
|
||||
}
|
||||
|
||||
CheckUpdateResponse::CheckUpdateResponse(const CheckUpdateResponse& other)
|
||||
: m_type(other.m_type)
|
||||
, m_version(other.m_version)
|
||||
, m_url(other.m_url)
|
||||
{
|
||||
}
|
||||
|
||||
CheckUpdateResponse::CheckUpdateResponse(const std::string& responseBody)
|
||||
: m_type(Unknown)
|
||||
{
|
||||
TiXmlDocument doc;
|
||||
doc.Parse(responseBody.c_str());
|
||||
|
||||
TiXmlHandle handle(&doc);
|
||||
TiXmlElement* xmlUpdate = handle.FirstChild("update").ToElement();
|
||||
if (!xmlUpdate) {
|
||||
// TODO show error?
|
||||
return;
|
||||
}
|
||||
|
||||
const char* latest_attr = xmlUpdate->Attribute("latest");
|
||||
const char* version_attr = xmlUpdate->Attribute("version");
|
||||
const char* type_attr = xmlUpdate->Attribute("type");
|
||||
const char* url_attr = xmlUpdate->Attribute("url");
|
||||
const char* uuid_attr = xmlUpdate->Attribute("uuid");
|
||||
|
||||
if (latest_attr && strcmp(latest_attr, "1") == 0)
|
||||
m_type = NoUpdate;
|
||||
|
||||
if (type_attr) {
|
||||
if (strcmp(type_attr, "critical") == 0)
|
||||
m_type = Critical;
|
||||
else if (strcmp(type_attr, "major") == 0)
|
||||
m_type = Major;
|
||||
}
|
||||
|
||||
if (version_attr)
|
||||
m_version = base::convert_to<base::Version>(std::string(version_attr));
|
||||
|
||||
if (url_attr)
|
||||
m_url = url_attr;
|
||||
|
||||
if (uuid_attr)
|
||||
m_uuid = uuid_attr;
|
||||
}
|
||||
|
||||
class CheckUpdate::CheckUpdateImpl
|
||||
{
|
||||
public:
|
||||
CheckUpdateImpl() { }
|
||||
~CheckUpdateImpl() { }
|
||||
|
||||
void abort()
|
||||
{
|
||||
// TODO impl
|
||||
}
|
||||
|
||||
void checkNewVersion(const Uuid& uuid, const std::string& extraParams, CheckUpdateDelegate* delegate)
|
||||
{
|
||||
using namespace base;
|
||||
using namespace net;
|
||||
|
||||
std::string url = UPDATE_URL;
|
||||
if (!uuid.empty()) {
|
||||
url += "&uuid=";
|
||||
url += uuid;
|
||||
}
|
||||
if (!extraParams.empty()) {
|
||||
url += "&";
|
||||
url += extraParams;
|
||||
}
|
||||
|
||||
HttpRequest request(url);
|
||||
HttpHeaders headers;
|
||||
headers.setHeader("User-Agent", getUserAgent());
|
||||
request.setHeaders(headers);
|
||||
|
||||
std::stringstream body;
|
||||
HttpResponse response(&body);
|
||||
request.send(response);
|
||||
|
||||
CheckUpdateResponse data(body.str());
|
||||
delegate->onResponse(data);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
CheckUpdate::CheckUpdate()
|
||||
: m_impl(new CheckUpdateImpl)
|
||||
{
|
||||
}
|
||||
|
||||
CheckUpdate::~CheckUpdate()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
void CheckUpdate::abort()
|
||||
{
|
||||
m_impl->abort();
|
||||
}
|
||||
|
||||
void CheckUpdate::checkNewVersion(const Uuid& uuid, const std::string& extraParams, CheckUpdateDelegate* delegate)
|
||||
{
|
||||
m_impl->checkNewVersion(uuid, extraParams, delegate);
|
||||
}
|
||||
|
||||
}
|
105
src/updater/check_update.h
Normal file
105
src/updater/check_update.h
Normal file
@ -0,0 +1,105 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef UPDATER_CHECK_UPDATE_H_INCLUDED
|
||||
#define UPDATER_CHECK_UPDATE_H_INCLUDED
|
||||
|
||||
#include "base/disable_copying.h"
|
||||
#include "base/version.h"
|
||||
|
||||
namespace updater {
|
||||
|
||||
typedef std::string Uuid;
|
||||
|
||||
// Data received by a "check new version" request.
|
||||
class CheckUpdateResponse
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
Unknown,
|
||||
NoUpdate, // No update available. You've the latest version.
|
||||
Critical, // There are critical bugs fixed.
|
||||
Major // New major version.
|
||||
};
|
||||
|
||||
CheckUpdateResponse();
|
||||
CheckUpdateResponse(const CheckUpdateResponse& other);
|
||||
CheckUpdateResponse(const std::string& responseBody);
|
||||
|
||||
// Returns the type of the available update.
|
||||
Type getUpdateType() const { return m_type; }
|
||||
|
||||
// Returns the latest version available to be downloaded.
|
||||
base::Version getLatestVersion() const { return m_version; }
|
||||
|
||||
// Returns the URL to download the new version.
|
||||
std::string getUrl() const { return m_url; }
|
||||
|
||||
// Returns a UUID to be assigned to this user. This parameter is
|
||||
// returned only when the request is done without an existent
|
||||
// UUID.
|
||||
Uuid getUuid() const { return m_uuid; }
|
||||
|
||||
private:
|
||||
Type m_type;
|
||||
base::Version m_version;
|
||||
std::string m_url;
|
||||
Uuid m_uuid;
|
||||
};
|
||||
|
||||
// Delegate called by CheckUpdate when the request to the server is
|
||||
// done. It must be implemented by the client of CheckUpdate.
|
||||
class CheckUpdateDelegate
|
||||
{
|
||||
public:
|
||||
virtual ~CheckUpdateDelegate() { }
|
||||
|
||||
// Returns true when the user is quitting the application so he does
|
||||
// not want to continue checking for updates.
|
||||
// virtual bool abortRequest() = 0;
|
||||
|
||||
// Called by CheckUpdate::checkNewVersion() when the response from
|
||||
// the "updates server" is received.
|
||||
virtual void onResponse(CheckUpdateResponse& data) = 0;
|
||||
};
|
||||
|
||||
// Checks for new versions.
|
||||
class CheckUpdate
|
||||
{
|
||||
public:
|
||||
CheckUpdate();
|
||||
~CheckUpdate();
|
||||
|
||||
// Cancels any operation in progress. It is called automatically in
|
||||
// the destructor.
|
||||
void abort();
|
||||
|
||||
// Sends a request to the "updates server" and calls the delegate
|
||||
// when the response is received.
|
||||
void checkNewVersion(const Uuid& uuid, const std::string& extraParams, CheckUpdateDelegate* delegate);
|
||||
|
||||
private:
|
||||
class CheckUpdateImpl;
|
||||
CheckUpdateImpl* m_impl;
|
||||
|
||||
DISABLE_COPYING(CheckUpdate);
|
||||
};
|
||||
|
||||
} // namespace updater
|
||||
|
||||
#endif
|
101
src/updater/user_agent.cpp
Normal file
101
src/updater/user_agent.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#if _WIN32 // Windows
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
extern "C" BOOL IsWow64();
|
||||
|
||||
#elif __APPLE__ // Mac OS X
|
||||
|
||||
extern "C" void getMacOSXVersion(int* major, int* minor, int* bugFix);
|
||||
|
||||
#else // Unix-like system
|
||||
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace updater {
|
||||
|
||||
std::string getUserAgent()
|
||||
{
|
||||
std::stringstream userAgent;
|
||||
|
||||
// ASEPRITE name and version
|
||||
|
||||
userAgent << PACKAGE << "/" << VERSION << " (";
|
||||
|
||||
#if _WIN32
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Windows
|
||||
|
||||
OSVERSIONINFOEX osv;
|
||||
osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||||
::GetVersionEx((OSVERSIONINFO*)&osv);
|
||||
|
||||
userAgent << "Windows";
|
||||
switch (osv.wProductType) {
|
||||
case VER_NT_DOMAIN_CONTROLLER:
|
||||
case VER_NT_SERVER:
|
||||
userAgent << " Server";
|
||||
break;
|
||||
case VER_NT_WORKSTATION:
|
||||
userAgent << " NT";
|
||||
break;
|
||||
}
|
||||
userAgent << " " << osv.dwMajorVersion << "." << osv.dwMinorVersion;
|
||||
|
||||
if (osv.wServicePackMajor > 0)
|
||||
userAgent << " SP" << osv.wServicePackMajor;
|
||||
|
||||
if (IsWow64())
|
||||
userAgent << "; WOW64";
|
||||
|
||||
#elif __APPLE__
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Mac OS X
|
||||
|
||||
int major, minor, bugFix;
|
||||
getMacOSXVersion(&major, &minor, &bugFix);
|
||||
userAgent << "Mac OS X " << major << "." << minor << "." << bugFix;
|
||||
|
||||
#else
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Unix like
|
||||
|
||||
struct utsname utsn;
|
||||
uname(&utsn);
|
||||
userAgent << utsn.sysname << " " utsn.release;
|
||||
|
||||
#endif
|
||||
|
||||
userAgent << ")";
|
||||
return userAgent.str();
|
||||
}
|
||||
|
||||
} // namespace updater
|
32
src/updater/user_agent.h
Normal file
32
src/updater/user_agent.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef UPDATER_USER_AGENT_H_INCLUDED
|
||||
#define UPDATER_USER_AGENT_H_INCLUDED
|
||||
|
||||
#include "base/disable_copying.h"
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
namespace updater {
|
||||
|
||||
std::string getUserAgent();
|
||||
|
||||
} // namespace updater
|
||||
|
||||
#endif // UPDATER_USER_AGENT_H_INCLUDED
|
47
src/updater/user_agent_mac.m
Normal file
47
src/updater/user_agent_mac.m
Normal file
@ -0,0 +1,47 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
void getMacOSXVersion(int* major, int* minor, int* bugFix)
|
||||
{
|
||||
OSErr err;
|
||||
SInt32 systemVersion, versionMajor, versionMinor, versionBugFix;
|
||||
if (Gestalt(gestaltSystemVersion, &systemVersion) != noErr) goto fail;
|
||||
if (systemVersion < 0x1040) {
|
||||
if (major) *major = ((systemVersion & 0xF000) >> 12) * 10 + ((systemVersion & 0x0F00) >> 8);
|
||||
if (minor) *minor = (systemVersion & 0x00F0) >> 4;
|
||||
if (bugFix) *bugFix = (systemVersion & 0x000F);
|
||||
}
|
||||
else {
|
||||
if ((err = Gestalt(gestaltSystemVersionMajor, &versionMajor)) != noErr) goto fail;
|
||||
if ((err = Gestalt(gestaltSystemVersionMinor, &versionMinor)) != noErr) goto fail;
|
||||
if ((err = Gestalt(gestaltSystemVersionBugFix, &versionBugFix)) != noErr) goto fail;
|
||||
if (major) *major = versionMajor;
|
||||
if (minor) *minor = versionMinor;
|
||||
if (bugFix) *bugFix = versionBugFix;
|
||||
}
|
||||
return;
|
||||
|
||||
fail:
|
||||
if (major) *major = 10;
|
||||
if (minor) *minor = 0;
|
||||
if (bugFix) *bugFix = 0;
|
||||
}
|
37
src/updater/user_agent_win.c
Normal file
37
src/updater/user_agent_win.c
Normal file
@ -0,0 +1,37 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
|
||||
|
||||
static LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
|
||||
|
||||
BOOL IsWow64()
|
||||
{
|
||||
BOOL isWow64 = FALSE;
|
||||
|
||||
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle("kernel32"),
|
||||
"IsWow64Process");
|
||||
if (fnIsWow64Process != NULL)
|
||||
fnIsWow64Process(GetCurrentProcess(), &isWow64);
|
||||
|
||||
return isWow64;
|
||||
}
|
@ -137,6 +137,22 @@ StatusBar::StatusBar()
|
||||
m_commandsBox = box1;
|
||||
}
|
||||
|
||||
// Create the box to show notifications.
|
||||
{
|
||||
Box* box1 = new Box(JI_HORIZONTAL);
|
||||
Box* box2 = new Box(JI_VERTICAL);
|
||||
|
||||
jwidget_set_border(box1, 2*jguiscale(), 1*jguiscale(), 2*jguiscale(), 2*jguiscale());
|
||||
jwidget_noborders(box2);
|
||||
jwidget_expansive(box2, true);
|
||||
|
||||
m_linkLabel = new LinkLabel((std::string(WEBSITE) + "donate/").c_str(), "Support This Project");
|
||||
|
||||
box1->addChild(box2);
|
||||
box1->addChild(m_linkLabel);
|
||||
m_notificationsBox = box1;
|
||||
}
|
||||
|
||||
// Construct move-pixels box
|
||||
{
|
||||
Box* filler = new Box(JI_HORIZONTAL);
|
||||
@ -153,6 +169,8 @@ StatusBar::StatusBar()
|
||||
m_transparentColor->Change.connect(Bind<void>(&StatusBar::onTransparentColorChange, this));
|
||||
}
|
||||
|
||||
addChild(m_notificationsBox);
|
||||
|
||||
App::instance()->CurrentToolChange.connect(&StatusBar::onCurrentToolChange, this);
|
||||
}
|
||||
|
||||
@ -162,6 +180,9 @@ StatusBar::~StatusBar()
|
||||
delete *it;
|
||||
|
||||
delete m_tipwindow; // widget
|
||||
delete m_movePixelsBox;
|
||||
delete m_commandsBox;
|
||||
delete m_notificationsBox;
|
||||
}
|
||||
|
||||
void StatusBar::addListener(StatusBarListener* listener)
|
||||
@ -209,8 +230,8 @@ bool StatusBar::setStatusText(int msecs, const char *format, ...)
|
||||
m_timeout = ji_clock + msecs;
|
||||
m_state = SHOW_TEXT;
|
||||
|
||||
this->setText(buf);
|
||||
this->invalidate();
|
||||
setText(buf);
|
||||
invalidate();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -254,8 +275,8 @@ void StatusBar::showTip(int msecs, const char *format, ...)
|
||||
|
||||
// Set the text in status-bar (with inmediate timeout)
|
||||
m_timeout = ji_clock;
|
||||
this->setText(buf);
|
||||
this->invalidate();
|
||||
setText(buf);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void StatusBar::showColor(int msecs, const char* text, const Color& color, int alpha)
|
||||
@ -312,6 +333,14 @@ Color StatusBar::getTransparentColor()
|
||||
return m_transparentColor->getColor();
|
||||
}
|
||||
|
||||
void StatusBar::showNotification(const char* text, const char* link)
|
||||
{
|
||||
m_linkLabel->setText(text);
|
||||
m_linkLabel->setUrl(link);
|
||||
layout();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Progress bars stuff
|
||||
|
||||
@ -377,6 +406,12 @@ bool StatusBar::onProcessMessage(Message* msg)
|
||||
|
||||
case JM_SETPOS:
|
||||
jrect_copy(this->rc, &msg->setpos.rect);
|
||||
{
|
||||
JRect rc = jrect_new_copy(this->rc);
|
||||
rc->x1 = rc->x2 - m_notificationsBox->getPreferredSize().w;
|
||||
jwidget_set_rect(m_notificationsBox, rc);
|
||||
jrect_free(rc);
|
||||
}
|
||||
{
|
||||
JRect rc = jrect_new_copy(this->rc);
|
||||
rc->x2 -= jrect_w(rc)/4 + 4*jguiscale();
|
||||
@ -393,17 +428,6 @@ bool StatusBar::onProcessMessage(Message* msg)
|
||||
}
|
||||
return true;
|
||||
|
||||
case JM_CLOSE:
|
||||
if (!hasChild(m_commandsBox)) {
|
||||
// Append the "m_commandsBox" so it is destroyed in StatusBar dtor.
|
||||
addChild(m_commandsBox);
|
||||
}
|
||||
if (!hasChild(m_movePixelsBox)) {
|
||||
// Append the "m_movePixelsBox" so it is destroyed in StatusBar dtor.
|
||||
addChild(m_movePixelsBox);
|
||||
}
|
||||
break;
|
||||
|
||||
case JM_DRAW: {
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(this->getTheme());
|
||||
int text_color = ji_color_foreground();
|
||||
@ -506,7 +530,7 @@ bool StatusBar::onProcessMessage(Message* msg)
|
||||
}
|
||||
}
|
||||
// Show layers only when we are not moving pixels
|
||||
else if (!this->hasChild(m_movePixelsBox)) {
|
||||
else if (!hasChild(m_movePixelsBox)) {
|
||||
// Available width for layers buttons
|
||||
int width = jrect_w(rc)/4;
|
||||
|
||||
@ -517,6 +541,11 @@ bool StatusBar::onProcessMessage(Message* msg)
|
||||
const ActiveDocumentReader document(UIContext::instance());
|
||||
const Sprite* sprite(document ? document->getSprite(): NULL);
|
||||
if (sprite) {
|
||||
if (hasChild(m_notificationsBox)) {
|
||||
removeChild(m_notificationsBox);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
const LayerFolder* folder = sprite->getFolder();
|
||||
LayerConstIterator it = folder->get_layer_begin();
|
||||
LayerConstIterator end = folder->get_layer_end();
|
||||
@ -554,22 +583,10 @@ bool StatusBar::onProcessMessage(Message* msg)
|
||||
}
|
||||
}
|
||||
else {
|
||||
int x1 = rc->x2-width;
|
||||
int x2 = rc->x2;
|
||||
bool hot = (0 == m_hot_layer);
|
||||
|
||||
theme->draw_bounds_nw(doublebuffer,
|
||||
x1, rc->y1, x2, rc->y2,
|
||||
hot ? PART_TOOLBUTTON_HOT_NW:
|
||||
PART_TOOLBUTTON_NORMAL_NW,
|
||||
hot ? theme->get_button_hot_face_color():
|
||||
theme->get_button_normal_face_color());
|
||||
|
||||
textout_centre_ex(doublebuffer, this->getFont(), "Donate",
|
||||
(x1+x2)/2,
|
||||
(rc->y1+rc->y2)/2-text_height(this->getFont())/2,
|
||||
hot ? theme->get_button_hot_text_color():
|
||||
theme->get_button_normal_text_color(), -1);
|
||||
if (!hasChild(m_notificationsBox)) {
|
||||
addChild(m_notificationsBox);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (LockedDocumentException&) {
|
||||
@ -591,8 +608,8 @@ bool StatusBar::onProcessMessage(Message* msg)
|
||||
case JM_MOUSEENTER: {
|
||||
bool state = (UIContext::instance()->getActiveDocument() != NULL);
|
||||
|
||||
if (!this->hasChild(m_movePixelsBox)) {
|
||||
if (!this->hasChild(m_commandsBox) && state) {
|
||||
if (!hasChild(m_movePixelsBox)) {
|
||||
if (state && !hasChild(m_commandsBox)) {
|
||||
m_b_first->setEnabled(state);
|
||||
m_b_prev->setEnabled(state);
|
||||
m_b_play->setEnabled(state);
|
||||
@ -601,12 +618,15 @@ bool StatusBar::onProcessMessage(Message* msg)
|
||||
|
||||
updateFromLayer();
|
||||
|
||||
if (hasChild(m_notificationsBox))
|
||||
removeChild(m_notificationsBox);
|
||||
|
||||
addChild(m_commandsBox);
|
||||
invalidate();
|
||||
}
|
||||
else {
|
||||
// Status text for donations
|
||||
setStatusText(0, "Click the \"Donate\" button to support ASE development");
|
||||
else if (!state && !hasChild(m_notificationsBox)) {
|
||||
addChild(m_notificationsBox);
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -696,14 +716,6 @@ bool StatusBar::onProcessMessage(Message* msg)
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Call "Donate" command
|
||||
Command* donate = CommandsModule::instance()
|
||||
->getCommandByName(CommandId::Donate);
|
||||
|
||||
Params params;
|
||||
UIContext::instance()->executeCommand(donate, ¶ms);
|
||||
}
|
||||
}
|
||||
catch (LockedDocumentException&) {
|
||||
// Do nothing...
|
||||
@ -712,7 +724,7 @@ bool StatusBar::onProcessMessage(Message* msg)
|
||||
break;
|
||||
|
||||
case JM_MOUSELEAVE:
|
||||
if (this->hasChild(m_commandsBox)) {
|
||||
if (hasChild(m_commandsBox)) {
|
||||
// If we want restore the state-bar and the slider doesn't have
|
||||
// the capture...
|
||||
if (jmanager_get_capture() != m_slider) {
|
||||
@ -818,3 +830,4 @@ void StatusBar::updateFromLayer()
|
||||
m_slider->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,10 +20,12 @@
|
||||
#define WIDGETS_STATEBAR_H_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "app/color.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "gui/base.h"
|
||||
#include "gui/link_label.h"
|
||||
#include "gui/widget.h"
|
||||
#include "listeners.h"
|
||||
|
||||
@ -87,6 +89,9 @@ public:
|
||||
Progress* addProgress();
|
||||
void removeProgress(Progress* progress);
|
||||
|
||||
// Method to show notifications (each notification can contain a link).
|
||||
void showNotification(const char* text, const char* link);
|
||||
|
||||
protected:
|
||||
bool onProcessMessage(Message* msg) OVERRIDE;
|
||||
|
||||
@ -121,6 +126,10 @@ private:
|
||||
Button* m_b_next; // Go to next frame
|
||||
Button* m_b_last; // Go to last frame
|
||||
|
||||
// Box of notifications.
|
||||
Widget* m_notificationsBox;
|
||||
LinkLabel* m_linkLabel;
|
||||
|
||||
// Box with move-pixels commands (when the user drag-and-drop selected pixels using the editor)
|
||||
Box* m_movePixelsBox;
|
||||
Widget* m_transparentLabel;
|
||||
|
Loading…
Reference in New Issue
Block a user