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:
David Capello 2011-07-26 23:25:02 -03:00
parent c7cf74228b
commit cf9a296e5d
16 changed files with 820 additions and 157 deletions

View File

@ -325,7 +325,6 @@
<item command="QuickReference" text="Quick &amp;Reference" />
<separator />
<item command="Donate" text="&amp;Donate" />
<item command="CheckUpdates" text="&amp;Check for New Version" />
<separator />
<item command="About" text="&amp;About" />
</menu>

View File

@ -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

View File

@ -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
View 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
View 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

View File

@ -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;
}

View File

@ -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)

View 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})

View 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
View 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
View 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
View 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

View 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;
}

View 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;
}

View File

@ -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, &params);
}
}
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);
}
}

View File

@ -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;