1
0
mirror of git://projects.qi-hardware.com/gmenu2x.git synced 2024-11-22 13:29:42 +02:00

Created separate subclasses for output and off-screen surfaces

There are a few exclusive operations for each type. Also we no longer
need the freeWhenDone flag since the class now determines whether the
surface should be freed or not.
This commit is contained in:
Maarten ter Huurne 2014-08-10 13:25:54 +02:00
parent b3719d1331
commit 4bd1c799bd
17 changed files with 195 additions and 161 deletions

View File

@ -46,14 +46,14 @@ static unsigned short getBatteryLevel()
return 0;
}
Battery::Battery(SurfaceCollection &sc_)
Battery::Battery(SurfaceCollection& sc_)
: sc(sc_)
{
lastUpdate = SDL_GetTicks();
update();
}
const Surface &Battery::getIcon()
OffscreenSurface const& Battery::getIcon()
{
// Check battery status every 60 seconds.
unsigned int now = SDL_GetTicks();

View File

@ -3,7 +3,7 @@
#include <string>
class Surface;
class OffscreenSurface;
class SurfaceCollection;
@ -12,17 +12,17 @@ class SurfaceCollection;
*/
class Battery {
public:
Battery(SurfaceCollection &sc);
Battery(SurfaceCollection& sc);
/**
* Gets the icon that reflects the current battery status.
*/
const Surface &getIcon();
OffscreenSurface const& getIcon();
private:
void update();
SurfaceCollection &sc;
SurfaceCollection& sc;
std::string iconPath;
unsigned int lastUpdate;
};

View File

@ -224,13 +224,13 @@ void BrowseDialog::quit()
void BrowseDialog::paint()
{
Surface& s = *gmenu2x->s;
OutputSurface& s = *gmenu2x->s;
unsigned int i, iY;
unsigned int firstElement, lastElement;
unsigned int offsetY;
Surface bg(gmenu2x->bg);
OffscreenSurface bg(gmenu2x->bg);
drawTitleIcon(bg, "icons/explorer.png", true);
writeTitle(bg, title);
writeSubTitle(bg, subtitle);

View File

@ -259,7 +259,7 @@ GMenu2X::GMenu2X()
exit(EXIT_FAILURE);
}
s = Surface::openOutputSurface(resX, resY, confInt["videoBpp"]);
s = OutputSurface::open(resX, resY, confInt["videoBpp"]);
if (!fileExists(confStr["wallpaper"])) {
DEBUG("No wallpaper defined; we will take the default one.\n");
@ -305,7 +305,6 @@ GMenu2X::~GMenu2X() {
fflush(NULL);
sc.clear();
delete s;
#ifdef ENABLE_INOTIFY
delete monitor;
@ -317,17 +316,17 @@ void GMenu2X::initBG() {
// Load wallpaper.
delete bg;
bg = Surface::loadImage(confStr["wallpaper"]);
bg = OffscreenSurface::loadImage(confStr["wallpaper"]);
if (!bg) {
bg = Surface::emptySurface(resX, resY);
bg = OffscreenSurface::emptySurface(resX, resY);
}
drawTopBar(*bg);
drawBottomBar(*bg);
Surface *bgmain = sc.add(bg, "bgmain");
OffscreenSurface *bgmain = sc.add(*bg, "bgmain");
Surface *sd = Surface::loadImage("imgs/sd.png", confStr["skin"]);
Surface *sd = OffscreenSurface::loadImage("imgs/sd.png", confStr["skin"]);
if (sd) sd->blit(*bgmain, 3, bottomBarIconY);
string df = getDiskFree(getHome().c_str());
@ -336,7 +335,7 @@ void GMenu2X::initBG() {
cpuX = font->getTextWidth(df)+32;
#ifdef ENABLE_CPUFREQ
Surface *cpu = Surface::loadImage("imgs/cpu.png", confStr["skin"]);
Surface *cpu = OffscreenSurface::loadImage("imgs/cpu.png", confStr["skin"]);
if (cpu) cpu->blit(bgmain, cpuX, bottomBarIconY);
cpuX += 19;
manualX = cpuX+font->getTextWidth("300MHz")+5;
@ -348,21 +347,21 @@ void GMenu2X::initBG() {
int serviceX = resX-38;
if (usbnet) {
if (web) {
Surface *webserver = Surface::loadImage(
Surface *webserver = OffscreenSurface::loadImage(
"imgs/webserver.png", confStr["skin"]);
if (webserver) webserver->blit(*bgmain, serviceX, bottomBarIconY);
serviceX -= 19;
delete webserver;
}
if (samba) {
Surface *sambaS = Surface::loadImage(
Surface *sambaS = OffscreenSurface::loadImage(
"imgs/samba.png", confStr["skin"]);
if (sambaS) sambaS->blit(*bgmain, serviceX, bottomBarIconY);
serviceX -= 19;
delete sambaS;
}
if (inet) {
Surface *inetS = Surface::loadImage("imgs/inet.png", confStr["skin"]);
Surface *inetS = OffscreenSurface::loadImage("imgs/inet.png", confStr["skin"]);
if (inetS) inetS->blit(*bgmain, serviceX, bottomBarIconY);
serviceX -= 19;
delete inetS;

View File

@ -42,6 +42,7 @@ class Launcher;
class Layer;
class MediaMonitor;
class Menu;
class OutputSurface;
class Surface;
#ifndef GMENU2X_SYSTEM_DIR
@ -158,7 +159,8 @@ public:
SurfaceCollection sc;
Translator tr;
Surface *s, *bg;
std::unique_ptr<OutputSurface> s;
Surface *bg;
std::unique_ptr<Font> font;
//Status functions

View File

@ -149,7 +149,7 @@ bool InputDialog::exec() {
Uint32 caretTick = 0, curTick;
bool caretOn = true;
Surface bg(gmenu2x->bg);
OffscreenSurface bg(gmenu2x->bg);
drawTitleIcon(bg, icon, false);
writeTitle(bg, title);
writeSubTitle(bg, text);
@ -159,7 +159,7 @@ bool InputDialog::exec() {
close = false;
ok = true;
while (!close) {
Surface& s = *gmenu2x->s;
OutputSurface& s = *gmenu2x->s;
bg.blit(s, 0, 0);

View File

@ -433,13 +433,13 @@ void LinkApp::showManual() {
gmenu2x->setSafeMaxClock();
#endif
Surface *pngman = Surface::loadImage(manual);
OffscreenSurface *pngman = OffscreenSurface::loadImage(manual);
if (!pngman) {
return;
}
Surface *bg = Surface::loadImage(gmenu2x->confStr["wallpaper"]);
OffscreenSurface *bg = OffscreenSurface::loadImage(gmenu2x->confStr["wallpaper"]);
if (!bg) {
bg = Surface::emptySurface(gmenu2x->s->width(), gmenu2x->s->height());
bg = OffscreenSurface::emptySurface(gmenu2x->s->width(), gmenu2x->s->height());
}
bg->convertToDisplayFormat();
@ -459,7 +459,7 @@ void LinkApp::showManual() {
#endif
while (!close) {
Surface& s = *gmenu2x->s;
OutputSurface& s = *gmenu2x->s;
if (repaint) {
bg->blit(s, 0, 0);

View File

@ -62,8 +62,8 @@ void MessageBox::setButton(InputManager::Button button, const string &label) {
}
int MessageBox::exec() {
Surface& s = *gmenu2x->s;
Surface bg(s);
OutputSurface& s = *gmenu2x->s;
OffscreenSurface bg(s);
//Darken background
bg.box(0, 0, gmenu2x->resX, gmenu2x->resY, 0,0,0,200);

View File

@ -59,7 +59,7 @@ int Selector::exec(int startSelection) {
fl.setFilter(link->getSelectorFilter());
fl.browse();
Surface bg(gmenu2x->bg);
OffscreenSurface bg(gmenu2x->bg);
drawTitleIcon(bg, link->getIconPath(), true);
writeTitle(bg, link->getTitle());
writeSubTitle(bg, link->getDescription());
@ -95,7 +95,7 @@ int Selector::exec(int startSelection) {
gmenu2x->sc.addSkinRes("imgs/folder.png");
gmenu2x->sc.defaultAlpha = false;
while (!close) {
Surface& s = *gmenu2x->s;
OutputSurface& s = *gmenu2x->s;
bg.blit(s, 0, 0);

View File

@ -50,7 +50,7 @@ SettingsDialog::~SettingsDialog() {
}
bool SettingsDialog::exec() {
Surface bg(gmenu2x->bg);
OffscreenSurface bg(gmenu2x->bg);
bg.convertToDisplayFormat();
bool close = false, ts_pressed = false;
@ -78,7 +78,7 @@ bool SettingsDialog::exec() {
}
while (!close) {
Surface& s = *gmenu2x->s;
OutputSurface& s = *gmenu2x->s;
if (ts.available()) ts.poll();

View File

@ -32,6 +32,9 @@
using namespace std;
// RGBAColor:
RGBAColor RGBAColor::fromString(const string &strColor) {
return {
uint8_t(constrain(strtol(strColor.substr(0, 2).c_str(), nullptr, 16),
@ -58,46 +61,11 @@ ostream& operator<<(ostream& os, RGBAColor const& color) {
return os;
}
Surface *Surface::openOutputSurface(int width, int height, int bitsperpixel) {
SDL_ShowCursor(SDL_DISABLE);
SDL_Surface *raw = SDL_SetVideoMode(
width, height, bitsperpixel, SDL_HWSURFACE | SDL_DOUBLEBUF);
return raw ? new Surface(raw, false) : NULL;
}
Surface *Surface::emptySurface(int width, int height) {
SDL_Surface *raw = SDL_CreateRGBSurface(
SDL_SWSURFACE, width, height, 32, 0, 0, 0, 0);
if (!raw) return NULL;
SDL_FillRect(raw, NULL, SDL_MapRGB(raw->format, 0, 0, 0));
return new Surface(raw, true);
}
Surface *Surface::loadImage(const string &img, const string &skin, bool loadAlpha) {
string skinpath;
if (!skin.empty() && !img.empty() && img[0]!='/')
skinpath = SurfaceCollection::getSkinFilePath(skin, img);
else
skinpath = img;
SDL_Surface *raw = loadPNG(skinpath, loadAlpha);
if (!raw) {
ERROR("Couldn't load surface '%s'\n", img.c_str());
return NULL;
}
return new Surface(raw, true);
}
Surface::Surface(SDL_Surface *raw_, bool freeWhenDone_)
: raw(raw_)
, freeWhenDone(freeWhenDone_)
{
}
// Surface:
Surface::Surface(Surface const& other)
: Surface(SDL_ConvertSurface(
other.raw, other.raw->format, SDL_SWSURFACE), true)
: Surface(SDL_ConvertSurface(other.raw, other.raw->format, SDL_SWSURFACE))
{
// Note: A bug in SDL_ConvertSurface() leaves the per-surface alpha
// undefined when converting from RGBA to RGBA. This can cause
@ -106,48 +74,6 @@ Surface::Surface(Surface const& other)
raw->format->alpha = other.raw->format->alpha;
}
Surface::Surface(Surface&& other)
: raw(other.raw)
, freeWhenDone(other.freeWhenDone)
{
other.raw = nullptr;
other.freeWhenDone = false;
}
Surface::~Surface()
{
if (freeWhenDone) {
SDL_FreeSurface(raw);
}
}
Surface& Surface::operator=(Surface other)
{
swap(other);
return *this;
}
void Surface::swap(Surface& other)
{
std::swap(raw, other.raw);
std::swap(freeWhenDone, other.freeWhenDone);
}
void Surface::convertToDisplayFormat() {
SDL_Surface *newSurface = SDL_DisplayFormat(raw);
if (newSurface) {
if (freeWhenDone) {
SDL_FreeSurface(raw);
}
raw = newSurface;
freeWhenDone = true;
}
}
void Surface::flip() {
SDL_Flip(raw);
}
void Surface::blit(SDL_Surface *destination, int x, int y, int w, int h, int a) const {
if (destination == NULL || a==0) return;
@ -351,3 +277,79 @@ void Surface::fillRectAlpha(SDL_Rect rect, RGBAColor c) {
SDL_UnlockSurface(raw);
}
}
// OffscreenSurface:
OffscreenSurface *OffscreenSurface::emptySurface(int width, int height)
{
SDL_Surface *raw = SDL_CreateRGBSurface(
SDL_SWSURFACE, width, height, 32, 0, 0, 0, 0);
if (!raw) return nullptr;
SDL_FillRect(raw, nullptr, SDL_MapRGB(raw->format, 0, 0, 0));
return new OffscreenSurface(raw);
}
OffscreenSurface *OffscreenSurface::loadImage(
const string &img, const string &skin, bool loadAlpha)
{
string skinpath;
if (!skin.empty() && !img.empty() && img[0]!='/')
skinpath = SurfaceCollection::getSkinFilePath(skin, img);
else
skinpath = img;
SDL_Surface *raw = loadPNG(skinpath, loadAlpha);
if (!raw) {
ERROR("Couldn't load surface '%s'\n", img.c_str());
return nullptr;
}
return new OffscreenSurface(raw);
}
OffscreenSurface::OffscreenSurface(OffscreenSurface&& other)
: Surface(other.raw)
{
other.raw = nullptr;
}
OffscreenSurface::~OffscreenSurface()
{
SDL_FreeSurface(raw);
}
OffscreenSurface& OffscreenSurface::operator=(OffscreenSurface other)
{
swap(other);
return *this;
}
void OffscreenSurface::swap(OffscreenSurface& other)
{
std::swap(raw, other.raw);
}
void OffscreenSurface::convertToDisplayFormat() {
SDL_Surface *newSurface = SDL_DisplayFormat(raw);
if (newSurface) {
SDL_FreeSurface(raw);
raw = newSurface;
}
}
// OutputSurface:
unique_ptr<OutputSurface> OutputSurface::open(
int width, int height, int bitsPerPixel)
{
SDL_ShowCursor(SDL_DISABLE);
SDL_Surface *raw = SDL_SetVideoMode(
width, height, bitsPerPixel, SDL_HWSURFACE | SDL_DOUBLEBUF);
return unique_ptr<OutputSurface>(raw ? new OutputSurface(raw) : nullptr);
}
void OutputSurface::flip() {
SDL_Flip(raw);
}

View File

@ -1,6 +1,7 @@
/***************************************************************************
* Copyright (C) 2006 by Massimiliano Torromeo *
* massimiliano.torromeo@gmail.com *
* massimiliano.torromeo@gmail.com *
* Copyright (C) 2010-2014 by various authors; see Git log *
* *
* 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 *
@ -26,6 +27,7 @@
#include <SDL.h>
#include <cstdint>
#include <memory>
#include <ostream>
#include <string>
@ -42,36 +44,15 @@ struct RGBAColor {
std::ostream& operator<<(std::ostream& os, RGBAColor const& color);
/**
Wrapper around SDL_Surface
@author Massimiliano Torromeo <massimiliano.torromeo@gmail.com>
*/
* Abstract base class for surfaces; wraps SDL_Surface.
*/
class Surface {
public:
static Surface *openOutputSurface(int width, int height, int bitsperpixel);
static Surface *emptySurface(int width, int height);
static Surface *loadImage(const std::string &img,
const std::string &skin="", bool loadAlpha=true);
// TODO: Remove this once naked Surface pointers are no longer in use.
Surface(Surface *other) : Surface(*other) {}
Surface(Surface const& other);
Surface(Surface&& other);
~Surface();
Surface& operator=(Surface other);
void swap(Surface& other);
/** Converts the underlying surface to the same pixel format as the frame
* buffer, for faster blitting. This removes the alpha channel if the
* image has done.
*/
void convertToDisplayFormat();
Surface& operator=(Surface const& other) = delete;
int width() const { return raw->w; }
int height() const { return raw->h; }
void flip();
void clearClipRect();
void setClipRect(int x, int y, int w, int h);
void setClipRect(SDL_Rect rect);
@ -96,8 +77,16 @@ public:
rectangle((SDL_Rect){ x, y, w, h }, RGBAColor(r, g, b, a));
}
protected:
Surface(SDL_Surface *raw) : raw(raw) {}
Surface(Surface const& other);
SDL_Surface *raw;
// For direct access to "raw".
friend class Font;
private:
Surface(SDL_Surface *raw, bool freeWhenDone);
void blit(SDL_Surface *destination, int x, int y, int w=0, int h=0, int a=-1) const;
void blitCenter(SDL_Surface *destination, int x, int y, int w=0, int h=0, int a=-1) const;
void blitRight(SDL_Surface *destination, int x, int y, int w=0, int h=0, int a=-1) const;
@ -111,12 +100,53 @@ private:
* rectangle.
*/
void applyClipRect(SDL_Rect& rect);
};
SDL_Surface *raw;
bool freeWhenDone;
/**
* A surface that is off-screen: not visible.
*/
class OffscreenSurface: public Surface {
public:
static OffscreenSurface *emptySurface(int width, int height);
static OffscreenSurface *loadImage(const std::string &img,
const std::string &skin="", bool loadAlpha=true);
// For direct access to "raw".
friend class Font;
// TODO: Remove this once naked Surface pointers are no longer in use.
OffscreenSurface(Surface *other) : Surface(*other) {}
OffscreenSurface(Surface const& other) : Surface(other) {}
OffscreenSurface(OffscreenSurface&& other);
~OffscreenSurface();
OffscreenSurface& operator=(OffscreenSurface other);
void swap(OffscreenSurface& other);
/**
* Converts the underlying surface to the same pixel format as the frame
* buffer, for faster blitting. This removes the alpha channel if the
* image has one.
*/
void convertToDisplayFormat();
private:
OffscreenSurface(SDL_Surface *raw) : Surface(raw) {}
};
/**
* A surface that is used for writing to a video output device.
*/
class OutputSurface: public Surface {
public:
static std::unique_ptr<OutputSurface> open(
int width, int height, int bitsPerPixel);
/**
* Offers the current buffer to the video system to be presented and
* acquires a new buffer to draw into.
*/
void flip();
private:
OutputSurface(SDL_Surface *raw) : Surface(raw) {}
};
#endif

View File

@ -98,14 +98,14 @@ bool SurfaceCollection::exists(const string &path) {
return surfaces.find(path) != surfaces.end();
}
Surface *SurfaceCollection::add(Surface const& s, std::string const& path) {
OffscreenSurface *SurfaceCollection::add(Surface const& s, std::string const& path) {
if (exists(path)) del(path);
Surface *copy = new Surface(s);
auto copy = new OffscreenSurface(s);
surfaces[path] = copy;
return copy;
}
Surface *SurfaceCollection::add(const string &path) {
OffscreenSurface *SurfaceCollection::add(const string &path) {
if (path.empty()) return NULL;
if (exists(path)) del(path);
string filePath = path;
@ -120,14 +120,14 @@ Surface *SurfaceCollection::add(const string &path) {
}
DEBUG("Adding surface: '%s'\n", path.c_str());
Surface *s = Surface::loadImage(filePath, "", defaultAlpha);
if (s != NULL) {
auto s = OffscreenSurface::loadImage(filePath, "", defaultAlpha);
if (s) {
surfaces[path] = s;
}
return s;
}
Surface *SurfaceCollection::addSkinRes(const string &path, bool useDefault) {
OffscreenSurface *SurfaceCollection::addSkinRes(const string &path, bool useDefault) {
if (path.empty()) return NULL;
if (exists(path)) del(path);
@ -136,8 +136,8 @@ Surface *SurfaceCollection::addSkinRes(const string &path, bool useDefault) {
return NULL;
DEBUG("Adding skin surface: '%s'\n", path.c_str());
Surface *s = Surface::loadImage(skinpath);
if (s != NULL) {
auto s = OffscreenSurface::loadImage(skinpath);
if (s) {
surfaces[path] = s;
}
return s;
@ -163,7 +163,7 @@ void SurfaceCollection::move(const string &from, const string &to) {
surfaces.erase(from);
}
Surface *SurfaceCollection::operator[](const string &key) {
OffscreenSurface *SurfaceCollection::operator[](const string &key) {
SurfaceHash::iterator i = surfaces.find(key);
if (i == surfaces.end())
return add(key);
@ -171,7 +171,7 @@ Surface *SurfaceCollection::operator[](const string &key) {
return i->second;
}
Surface *SurfaceCollection::skinRes(const string &key, bool useDefault) {
OffscreenSurface *SurfaceCollection::skinRes(const string &key, bool useDefault) {
if (key.empty()) return NULL;
SurfaceHash::iterator i = surfaces.find(key);

View File

@ -23,9 +23,10 @@
#include <string>
#include <unordered_map>
class OffscreenSurface;
class Surface;
typedef std::unordered_map<std::string, Surface *> SurfaceHash;
typedef std::unordered_map<std::string, OffscreenSurface *> SurfaceHash;
/**
Hash Map of surfaces that loads surfaces not already loaded and reuses already loaded ones.
@ -49,17 +50,17 @@ public:
* Adds a copy of the given surface to this collection under the given
* path. Returns the copy.
*/
Surface *add(Surface const& s, std::string const& path);
OffscreenSurface *add(Surface const& s, std::string const& path);
Surface *add(const std::string &path);
Surface *addSkinRes(const std::string &path, bool useDefault = true);
OffscreenSurface *add(const std::string &path);
OffscreenSurface *addSkinRes(const std::string &path, bool useDefault = true);
void del(const std::string &path);
void clear();
void move(const std::string &from, const std::string &to);
bool exists(const std::string &path);
Surface *operator[](const std::string &);
Surface *skinRes(const std::string &key, bool useDefault = true);
OffscreenSurface *operator[](const std::string &);
OffscreenSurface *skinRes(const std::string &key, bool useDefault = true);
private:
SurfaceHash surfaces;

View File

@ -60,7 +60,7 @@ void TextDialog::drawText(const vector<string> &text, unsigned int y,
void TextDialog::exec() {
bool close = false;
Surface bg(gmenu2x->bg);
OffscreenSurface bg(gmenu2x->bg);
//link icon
if (!fileExists(icon))
@ -87,7 +87,7 @@ void TextDialog::exec() {
unsigned firstRow = 0;
while (!close) {
Surface& s = *gmenu2x->s;
OutputSurface& s = *gmenu2x->s;
bg.blit(s, 0, 0);
drawText(text, contentY, firstRow, rowsPerPage);

View File

@ -68,7 +68,7 @@ TextManualDialog::TextManualDialog(GMenu2X *gmenu2x, const string &title, const
}
void TextManualDialog::exec() {
Surface bg(gmenu2x->bg);
OffscreenSurface bg(gmenu2x->bg);
//link icon
if (!fileExists(icon))
@ -102,7 +102,7 @@ void TextManualDialog::exec() {
bool close = false;
while (!close) {
Surface& s = *gmenu2x->s;
OutputSurface& s = *gmenu2x->s;
bg.blit(s,0,0);
writeSubTitle(s, pages[page].title);

View File

@ -88,7 +88,7 @@ bool WallpaperDialog::exec()
unsigned int nb_elements = height / fontheight;
while (!close) {
Surface& s = *gmenu2x->s;
OutputSurface& s = *gmenu2x->s;
if (selected > firstElement + nb_elements - 1)
firstElement = selected - nb_elements + 1;