mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-02-19 06:26:55 +00:00
moved Interfaces to types.h, tooltip hiding fixed
This commit is contained in:
parent
0ede06700a
commit
47ead03925
@ -315,15 +315,16 @@ namespace Sandbox {
|
||||
t_assert_full(SandboxData != 0, "_data is null in Global::" #Name, __FILE__, __LINE__); \
|
||||
return SandboxData->Name; \
|
||||
}
|
||||
#define DefineSandbox(Type, Name) DefineSandboxReadOnly(Type, Name) \
|
||||
void Set##Name(const Type &Name) { \
|
||||
t_assert_full(SandboxData != 0, "_data is null in Global::Set" #Name, __FILE__, __LINE__); \
|
||||
SandboxData->Name = Name; \
|
||||
} \
|
||||
#define DefineSandboxRef(Type, Name) DefineSandboxReadOnly(Type, Name) \
|
||||
Type &Ref##Name() { \
|
||||
t_assert_full(SandboxData != 0, "_data is null in Global::Ref" #Name, __FILE__, __LINE__); \
|
||||
return SandboxData->Name; \
|
||||
}
|
||||
#define DefineSandbox(Type, Name) DefineSandboxRef(Type, Name) \
|
||||
void Set##Name(const Type &Name) { \
|
||||
t_assert_full(SandboxData != 0, "_data is null in Global::Set" #Name, __FILE__, __LINE__); \
|
||||
SandboxData->Name = Name; \
|
||||
}
|
||||
|
||||
DefineSandboxReadOnly(uint64, LaunchId);
|
||||
|
||||
|
@ -123,9 +123,10 @@ namespace Sandbox {
|
||||
void finish();
|
||||
|
||||
#define DeclareSandboxReadOnly(Type, Name) const Type &Name();
|
||||
#define DeclareSandbox(Type, Name) DeclareSandboxReadOnly(Type, Name) \
|
||||
void Set##Name(const Type &Name); \
|
||||
#define DeclareSandboxRef(Type, Name) DeclareSandboxReadOnly(Type, Name) \
|
||||
Type &Ref##Name();
|
||||
#define DeclareSandbox(Type, Name) DeclareSandboxRef(Type, Name) \
|
||||
void Set##Name(const Type &Name);
|
||||
|
||||
DeclareSandboxReadOnly(uint64, LaunchId);
|
||||
|
||||
|
@ -523,22 +523,33 @@ PopupMenu::~PopupMenu() {
|
||||
|
||||
PopupTooltip *PopupTooltipInstance = 0;
|
||||
|
||||
PopupTooltip::PopupTooltip(const QPoint &p, const QString &text, const style::Tooltip &st) : TWidget(0)
|
||||
, _st(0) {
|
||||
if (PopupTooltip *instance = PopupTooltipInstance) {
|
||||
hide();
|
||||
deleteLater();
|
||||
} else {
|
||||
PopupTooltipInstance = this;
|
||||
Sandboxer::installEventFilter(this);
|
||||
_hideByLeaveTimer.setSingleShot(true);
|
||||
connect(&_hideByLeaveTimer, SIGNAL(timeout()), this, SLOT(onHideByLeave()));
|
||||
AbstractTooltipShower::~AbstractTooltipShower() {
|
||||
if (PopupTooltipInstance && PopupTooltipInstance->_shower == this) {
|
||||
PopupTooltipInstance->_shower = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PopupTooltip::PopupTooltip() : TWidget(0)
|
||||
, _shower(0)
|
||||
, _st(0) {
|
||||
PopupTooltipInstance = this;
|
||||
|
||||
setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::ToolTip | Qt::NoDropShadowWindowHint);
|
||||
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||
|
||||
PopupTooltipInstance->popup(p, text, &st);
|
||||
_showTimer.setSingleShot(true);
|
||||
connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShow()));
|
||||
}
|
||||
|
||||
void PopupTooltip::onShow() {
|
||||
if (_shower) {
|
||||
QString text = _shower->tooltipText();
|
||||
if (text.isEmpty()) {
|
||||
Hide();
|
||||
} else {
|
||||
PopupTooltipInstance->popup(_shower->tooltipPos(), text, _shower->tooltipSt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PopupTooltip::eventFilter(QObject *o, QEvent *e) {
|
||||
@ -565,6 +576,13 @@ PopupTooltip::~PopupTooltip() {
|
||||
}
|
||||
|
||||
void PopupTooltip::popup(const QPoint &m, const QString &text, const style::Tooltip *st) {
|
||||
if (!_hideByLeaveTimer.isSingleShot()) {
|
||||
_hideByLeaveTimer.setSingleShot(true);
|
||||
connect(&_hideByLeaveTimer, SIGNAL(timeout()), this, SLOT(onHideByLeave()));
|
||||
|
||||
Sandboxer::installEventFilter(this);
|
||||
}
|
||||
|
||||
_point = m;
|
||||
_st = st;
|
||||
_text = Text(_st->textFont, text, _textPlainOptions, _st->widthMax, true);
|
||||
@ -631,14 +649,27 @@ void PopupTooltip::paintEvent(QPaintEvent *e) {
|
||||
|
||||
void PopupTooltip::hideEvent(QHideEvent *e) {
|
||||
if (PopupTooltipInstance == this) {
|
||||
PopupTooltipInstance = 0;
|
||||
deleteLater();
|
||||
Hide();
|
||||
}
|
||||
}
|
||||
|
||||
void PopupTooltip::Show(int32 delay, const AbstractTooltipShower *shower) {
|
||||
if (!PopupTooltipInstance) {
|
||||
new PopupTooltip();
|
||||
}
|
||||
PopupTooltipInstance->_shower = shower;
|
||||
if (delay >= 0) {
|
||||
PopupTooltipInstance->_showTimer.start(delay);
|
||||
} else {
|
||||
PopupTooltipInstance->onShow();
|
||||
}
|
||||
}
|
||||
|
||||
void PopupTooltip::Hide() {
|
||||
if (PopupTooltip *instance = PopupTooltipInstance) {
|
||||
PopupTooltipInstance = 0;
|
||||
instance->_showTimer.stop();
|
||||
instance->_hideByLeaveTimer.stop();
|
||||
instance->hide();
|
||||
instance->deleteLater();
|
||||
}
|
||||
|
@ -108,21 +108,31 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class AbstractTooltipShower {
|
||||
public:
|
||||
virtual QString tooltipText() const = 0;
|
||||
virtual QPoint tooltipPos() const = 0;
|
||||
virtual const style::Tooltip *tooltipSt() const {
|
||||
return &st::defaultTooltip;
|
||||
}
|
||||
virtual ~AbstractTooltipShower();
|
||||
};
|
||||
|
||||
class PopupTooltip : public TWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
PopupTooltip(const QPoint &p, const QString &text, const style::Tooltip &st = st::defaultTooltip);
|
||||
|
||||
bool eventFilter(QObject *o, QEvent *e);
|
||||
|
||||
static void Show(int32 delay, const AbstractTooltipShower *shower);
|
||||
static void Hide();
|
||||
|
||||
~PopupTooltip();
|
||||
|
||||
public slots:
|
||||
|
||||
void onShow();
|
||||
void onHideByLeave();
|
||||
|
||||
protected:
|
||||
@ -132,8 +142,14 @@ protected:
|
||||
|
||||
private:
|
||||
|
||||
PopupTooltip();
|
||||
|
||||
void popup(const QPoint &p, const QString &text, const style::Tooltip *st);
|
||||
|
||||
friend class AbstractTooltipShower;
|
||||
const AbstractTooltipShower *_shower;
|
||||
QTimer _showTimer;
|
||||
|
||||
Text _text;
|
||||
QPoint _point;
|
||||
|
||||
|
@ -75,8 +75,6 @@ HistoryInner::HistoryInner(HistoryWidget *historyWidget, ScrollArea *scroll, His
|
||||
, _menu(0) {
|
||||
connect(App::wnd(), SIGNAL(imageLoaded()), this, SLOT(update()));
|
||||
|
||||
_tooltipTimer.setSingleShot(true);
|
||||
connect(&_tooltipTimer, SIGNAL(timeout()), this, SLOT(showLinkTip()));
|
||||
_touchSelectTimer.setSingleShot(true);
|
||||
connect(&_touchSelectTimer, SIGNAL(timeout()), this, SLOT(onTouchSelect()));
|
||||
|
||||
@ -1628,12 +1626,12 @@ void HistoryInner::onUpdateSelected() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lnk || cursorState == HistoryInDateCursorState) {
|
||||
_tooltipTimer.start(1000);
|
||||
}
|
||||
if (_dragCursorState == HistoryInDateCursorState && cursorState != HistoryInDateCursorState) {
|
||||
PopupTooltip::Hide();
|
||||
}
|
||||
if (lnk || cursorState == HistoryInDateCursorState) {
|
||||
PopupTooltip::Show(1000, this);
|
||||
}
|
||||
|
||||
if (_dragAction == NoDrag) {
|
||||
_dragCursorState = cursorState;
|
||||
@ -1869,15 +1867,20 @@ void HistoryInner::applyDragSelection(SelectedItems *toItems) const {
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryInner::showLinkTip() {
|
||||
QString HistoryInner::tooltipText() const {
|
||||
TextLinkPtr lnk = textlnkOver();
|
||||
if (lnk && !lnk->fullDisplayed()) {
|
||||
new PopupTooltip(_dragPos, lnk->readable());
|
||||
return lnk->readable();
|
||||
} else if (_dragCursorState == HistoryInDateCursorState && _dragAction == NoDrag) {
|
||||
if (App::hoveredItem()) {
|
||||
new PopupTooltip(_dragPos, App::hoveredItem()->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)));
|
||||
return App::hoveredItem()->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat));
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
QPoint HistoryInner::tooltipPos() const {
|
||||
return _dragPos;
|
||||
}
|
||||
|
||||
void HistoryInner::onParentGeometryChanged() {
|
||||
@ -2017,9 +2020,6 @@ BotKeyboard::BotKeyboard() : TWidget()
|
||||
setGeometry(0, 0, _st->margin, _st->margin);
|
||||
_height = _st->margin;
|
||||
setMouseTracking(true);
|
||||
|
||||
_cmdTipTimer.setSingleShot(true);
|
||||
connect(&_cmdTipTimer, SIGNAL(timeout()), this, SLOT(showCommandTip()));
|
||||
}
|
||||
|
||||
void BotKeyboard::paintEvent(QPaintEvent *e) {
|
||||
@ -2259,17 +2259,22 @@ void BotKeyboard::clearSelection() {
|
||||
}
|
||||
}
|
||||
|
||||
void BotKeyboard::showCommandTip() {
|
||||
QPoint BotKeyboard::tooltipPos() const {
|
||||
return _lastMousePos;
|
||||
}
|
||||
|
||||
QString BotKeyboard::tooltipText() const {
|
||||
if (_sel >= 0) {
|
||||
int row = (_sel / MatrixRowShift), col = _sel % MatrixRowShift;
|
||||
if (!_btns.at(row).at(col).full) {
|
||||
new PopupTooltip(_lastMousePos, _btns.at(row).at(col).cmd);
|
||||
return _btns.at(row).at(col).cmd;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void BotKeyboard::updateSelected() {
|
||||
_cmdTipTimer.start(1000);
|
||||
PopupTooltip::Show(1000, this);
|
||||
|
||||
if (_down >= 0) return;
|
||||
|
||||
|
@ -33,7 +33,7 @@ enum DragState {
|
||||
};
|
||||
|
||||
class HistoryWidget;
|
||||
class HistoryInner : public TWidget {
|
||||
class HistoryInner : public TWidget, public AbstractTooltipShower {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@ -97,6 +97,10 @@ public:
|
||||
void notifyIsBotChanged();
|
||||
void notifyMigrateUpdated();
|
||||
|
||||
// AbstractTooltipShower
|
||||
virtual QString tooltipText() const;
|
||||
virtual QPoint tooltipPos() const;
|
||||
|
||||
~HistoryInner();
|
||||
|
||||
public slots:
|
||||
@ -104,8 +108,6 @@ public slots:
|
||||
void onUpdateSelected();
|
||||
void onParentGeometryChanged();
|
||||
|
||||
void showLinkTip();
|
||||
|
||||
void openContextUrl();
|
||||
void copyContextUrl();
|
||||
void saveContextImage();
|
||||
@ -150,8 +152,6 @@ private:
|
||||
|
||||
bool _firstLoading;
|
||||
|
||||
QTimer _tooltipTimer;
|
||||
|
||||
Qt::CursorShape _cursor;
|
||||
typedef QMap<HistoryItem*, uint32> SelectedItems;
|
||||
SelectedItems _selected;
|
||||
@ -249,7 +249,7 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class BotKeyboard : public TWidget {
|
||||
class BotKeyboard : public TWidget, public AbstractTooltipShower {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@ -277,9 +277,12 @@ public:
|
||||
return _wasForMsgId;
|
||||
}
|
||||
|
||||
// AbstractTooltipShower
|
||||
virtual QString tooltipText() const;
|
||||
virtual QPoint tooltipPos() const;
|
||||
|
||||
public slots:
|
||||
|
||||
void showCommandTip();
|
||||
void updateSelected();
|
||||
|
||||
private:
|
||||
@ -290,7 +293,6 @@ private:
|
||||
FullMsgId _wasForMsgId;
|
||||
int32 _height, _maxOuterHeight;
|
||||
bool _maximizeSize, _singleUse, _forceReply;
|
||||
QTimer _cmdTipTimer;
|
||||
|
||||
QPoint _lastMousePos;
|
||||
struct Button {
|
||||
|
@ -91,8 +91,6 @@ OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, PeerD
|
||||
|
||||
App::contextItem(0);
|
||||
|
||||
_linkTipTimer.setSingleShot(true);
|
||||
connect(&_linkTipTimer, SIGNAL(timeout()), this, SLOT(showLinkTip()));
|
||||
_touchSelectTimer.setSingleShot(true);
|
||||
connect(&_touchSelectTimer, SIGNAL(timeout()), this, SLOT(onTouchSelect()));
|
||||
|
||||
@ -1024,7 +1022,7 @@ void OverviewInner::onUpdateSelected() {
|
||||
_cursorState = cursorState;
|
||||
}
|
||||
if (lnk || cursorState == HistoryInDateCursorState) {
|
||||
_linkTipTimer.start(1000);
|
||||
PopupTooltip::Show(1000, this);
|
||||
}
|
||||
|
||||
fixItemIndex(_dragItemIndex, _dragItem);
|
||||
@ -1139,16 +1137,20 @@ void OverviewInner::onUpdateSelected() {
|
||||
}
|
||||
}
|
||||
|
||||
QPoint OverviewInner::tooltipPos() const {
|
||||
return _dragPos;
|
||||
}
|
||||
|
||||
void OverviewInner::showLinkTip() {
|
||||
QString OverviewInner::tooltipText() const {
|
||||
TextLinkPtr lnk = textlnkOver();
|
||||
if (lnk && !lnk->fullDisplayed()) {
|
||||
new PopupTooltip(_dragPos, lnk->readable());
|
||||
return lnk->readable();
|
||||
} else if (_cursorState == HistoryInDateCursorState && _dragAction == NoDrag && _mousedItem) {
|
||||
if (HistoryItem *item = App::histItemById(itemChannel(_mousedItem), itemMsgId(_mousedItem))) {
|
||||
new PopupTooltip(_dragPos, item->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat)));
|
||||
return item->date.toString(QLocale::system().dateTimeFormat(QLocale::LongFormat));
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
void OverviewInner::updateDragSelection(MsgId dragSelFrom, int32 dragSelFromIndex, MsgId dragSelTo, int32 dragSelToIndex, bool dragSelecting) {
|
||||
|
@ -21,7 +21,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
||||
#pragma once
|
||||
|
||||
class OverviewWidget;
|
||||
class OverviewInner : public QWidget, public RPCSender {
|
||||
class OverviewInner : public QWidget, public AbstractTooltipShower, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@ -76,12 +76,15 @@ public:
|
||||
void clearSelectedItems(bool onlyTextSelection = false);
|
||||
void fillSelectedItems(SelectedItemSet &sel, bool forDelete = true);
|
||||
|
||||
// AbstractTooltipShower
|
||||
virtual QString tooltipText() const;
|
||||
virtual QPoint tooltipPos() const;
|
||||
|
||||
~OverviewInner();
|
||||
|
||||
public slots:
|
||||
|
||||
void onUpdateSelected();
|
||||
void showLinkTip();
|
||||
|
||||
void openContextUrl();
|
||||
void copyContextUrl();
|
||||
|
@ -34,37 +34,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
||||
#include "audio.h"
|
||||
#include "localstorage.h"
|
||||
|
||||
class InterfacesMetadatasMap : public QMap<uint64, InterfacesMetadata*> {
|
||||
public:
|
||||
~InterfacesMetadatasMap() {
|
||||
for (const_iterator i = cbegin(), e = cend(); i != e; ++i) {
|
||||
delete i.value();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const InterfacesMetadata *GetInterfacesMetadata(uint64 mask) {
|
||||
typedef QMap<uint64, InterfacesMetadata*> InterfacesMetadatasMap;
|
||||
static InterfacesMetadatasMap InterfacesMetadatas;
|
||||
static QMutex InterfacesMetadatasMutex;
|
||||
|
||||
QMutexLocker lock(&InterfacesMetadatasMutex);
|
||||
InterfacesMetadatasMap::const_iterator i = InterfacesMetadatas.constFind(mask);
|
||||
if (i == InterfacesMetadatas.cend()) {
|
||||
InterfacesMetadata *meta = new InterfacesMetadata(mask);
|
||||
if (!meta) { // terminate if we can't allocate memory
|
||||
throw "Can't allocate memory!";
|
||||
}
|
||||
|
||||
i = InterfacesMetadatas.insert(mask, meta);
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
InterfaceWrapStruct InterfaceWraps[64];
|
||||
|
||||
QAtomicInt InterfaceIndexLast(0);
|
||||
|
||||
namespace {
|
||||
int32 peerColorIndex(const PeerId &peer) {
|
||||
int32 myId(MTP::authedId()), peerId(peerToBareInt(peer));
|
||||
|
@ -20,174 +20,6 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class Interfaces;
|
||||
typedef void(*InterfaceConstruct)(void *location, Interfaces *interfaces);
|
||||
typedef void(*InterfaceDestruct)(void *location);
|
||||
|
||||
struct InterfaceWrapStruct {
|
||||
InterfaceWrapStruct() : Size(0), Construct(0), Destruct(0) {
|
||||
}
|
||||
InterfaceWrapStruct(int size, InterfaceConstruct construct, InterfaceDestruct destruct)
|
||||
: Size(size)
|
||||
, Construct(construct)
|
||||
, Destruct(destruct) {
|
||||
}
|
||||
int Size;
|
||||
InterfaceConstruct Construct;
|
||||
InterfaceDestruct Destruct;
|
||||
};
|
||||
|
||||
template <int Value, int Denominator>
|
||||
struct CeilDivideMinimumOne {
|
||||
static const int Result = ((Value / Denominator) + ((!Value || (Value % Denominator)) ? 1 : 0));
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
struct InterfaceWrapTemplate {
|
||||
static const int Size = CeilDivideMinimumOne<sizeof(Type), sizeof(uint64)>::Result * sizeof(uint64);
|
||||
static void Construct(void *location, Interfaces *interfaces) {
|
||||
new (location) Type(interfaces);
|
||||
}
|
||||
static void Destruct(void *location) {
|
||||
((Type*)location)->~Type();
|
||||
}
|
||||
};
|
||||
|
||||
extern InterfaceWrapStruct InterfaceWraps[64];
|
||||
extern QAtomicInt InterfaceIndexLast;
|
||||
|
||||
template <typename Type>
|
||||
class BasicInterface {
|
||||
public:
|
||||
static int Index() {
|
||||
static QAtomicInt _index(0);
|
||||
if (int index = _index.loadAcquire()) {
|
||||
return index - 1;
|
||||
}
|
||||
while (true) {
|
||||
int last = InterfaceIndexLast.loadAcquire();
|
||||
if (InterfaceIndexLast.testAndSetOrdered(last, last + 1)) {
|
||||
t_assert(last < 64);
|
||||
if (_index.testAndSetOrdered(0, last + 1)) {
|
||||
InterfaceWraps[last] = InterfaceWrapStruct(InterfaceWrapTemplate<Type>::Size, InterfaceWrapTemplate<Type>::Construct, InterfaceWrapTemplate<Type>::Destruct);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return _index.loadAcquire() - 1;
|
||||
}
|
||||
static uint64 Bit() {
|
||||
return (1 << Index());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
class BasicInterfaceWithPointer : public BasicInterface<Type> {
|
||||
public:
|
||||
BasicInterfaceWithPointer(Interfaces *interfaces) : interfaces(interfaces) {
|
||||
}
|
||||
Interfaces *interfaces = 0;
|
||||
};
|
||||
|
||||
class InterfacesMetadata {
|
||||
public:
|
||||
|
||||
InterfacesMetadata(uint64 mask) : size(0), last(64), _mask(mask) {
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
uint64 m = (1 << i);
|
||||
if (_mask & m) {
|
||||
int s = InterfaceWraps[i].Size;
|
||||
if (s) {
|
||||
offsets[i] = size;
|
||||
size += s;
|
||||
} else {
|
||||
offsets[i] = -1;
|
||||
}
|
||||
} else if (_mask < m) {
|
||||
last = i;
|
||||
for (; i < 64; ++i) {
|
||||
offsets[i] = -1;
|
||||
}
|
||||
} else {
|
||||
offsets[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int size, last;
|
||||
int offsets[64];
|
||||
|
||||
private:
|
||||
uint64 _mask;
|
||||
|
||||
};
|
||||
|
||||
const InterfacesMetadata *GetInterfacesMetadata(uint64 mask);
|
||||
|
||||
class Interfaces {
|
||||
public:
|
||||
|
||||
Interfaces(uint64 mask = 0) : _meta(GetInterfacesMetadata(mask)), _data(0) {
|
||||
if (_meta->size) {
|
||||
_data = malloc(_meta->size);
|
||||
if (!_data) { // terminate if we can't allocate memory
|
||||
throw "Can't allocate memory!";
|
||||
}
|
||||
|
||||
for (int i = 0; i < _meta->last; ++i) {
|
||||
int offset = _meta->offsets[i];
|
||||
if (offset >= 0) {
|
||||
try {
|
||||
InterfaceWraps[i].Construct(_dataptrunsafe(offset), this);
|
||||
} catch (...) {
|
||||
while (i > 0) {
|
||||
--i;
|
||||
offset = _meta->offsets[--i];
|
||||
if (offset >= 0) {
|
||||
InterfaceWraps[i].Destruct(_dataptrunsafe(offset));
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
~Interfaces() {
|
||||
if (_data) {
|
||||
for (int i = 0; i < _meta->last; ++i) {
|
||||
int offset = _meta->offsets[i];
|
||||
if (offset >= 0) {
|
||||
InterfaceWraps[i].Destruct(_dataptrunsafe(offset));
|
||||
}
|
||||
}
|
||||
free(_data);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type *Get() {
|
||||
return (Type*)_dataptr(_meta->offsets[Type::Index()]);
|
||||
}
|
||||
template <typename Type>
|
||||
const Type *Get() const {
|
||||
return (const Type*)_dataptr(_meta->offsets[Type::Index()]);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void *_dataptrunsafe(int skip) const {
|
||||
return (char*)_data + skip;
|
||||
}
|
||||
void *_dataptr(int skip) const {
|
||||
return (skip >= 0) ? _dataptrunsafe(skip) : 0;
|
||||
}
|
||||
const InterfacesMetadata *_meta;
|
||||
void *_data;
|
||||
|
||||
};
|
||||
|
||||
typedef int32 ChannelId;
|
||||
static const ChannelId NoChannel = 0;
|
||||
|
||||
|
@ -1016,3 +1016,34 @@ MimeType mimeTypeForData(const QByteArray &data) {
|
||||
}
|
||||
return MimeType(QMimeDatabase().mimeTypeForData(data));
|
||||
}
|
||||
|
||||
class InterfacesMetadatasMap : public QMap<uint64, InterfacesMetadata*> {
|
||||
public:
|
||||
~InterfacesMetadatasMap() {
|
||||
for (const_iterator i = cbegin(), e = cend(); i != e; ++i) {
|
||||
delete i.value();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const InterfacesMetadata *GetInterfacesMetadata(uint64 mask) {
|
||||
typedef QMap<uint64, InterfacesMetadata*> InterfacesMetadatasMap;
|
||||
static InterfacesMetadatasMap InterfacesMetadatas;
|
||||
static QMutex InterfacesMetadatasMutex;
|
||||
|
||||
QMutexLocker lock(&InterfacesMetadatasMutex);
|
||||
InterfacesMetadatasMap::const_iterator i = InterfacesMetadatas.constFind(mask);
|
||||
if (i == InterfacesMetadatas.cend()) {
|
||||
InterfacesMetadata *meta = new InterfacesMetadata(mask);
|
||||
if (!meta) { // terminate if we can't allocate memory
|
||||
throw "Can't allocate memory!";
|
||||
}
|
||||
|
||||
i = InterfacesMetadatas.insert(mask, meta);
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
InterfaceWrapStruct InterfaceWraps[64];
|
||||
|
||||
QAtomicInt InterfaceIndexLast(0);
|
||||
|
@ -529,6 +529,174 @@ inline void destroyImplementation(I *&ptr) {
|
||||
deleteAndMark(ptr);
|
||||
}
|
||||
|
||||
class Interfaces;
|
||||
typedef void(*InterfaceConstruct)(void *location, Interfaces *interfaces);
|
||||
typedef void(*InterfaceDestruct)(void *location);
|
||||
|
||||
struct InterfaceWrapStruct {
|
||||
InterfaceWrapStruct() : Size(0), Construct(0), Destruct(0) {
|
||||
}
|
||||
InterfaceWrapStruct(int size, InterfaceConstruct construct, InterfaceDestruct destruct)
|
||||
: Size(size)
|
||||
, Construct(construct)
|
||||
, Destruct(destruct) {
|
||||
}
|
||||
int Size;
|
||||
InterfaceConstruct Construct;
|
||||
InterfaceDestruct Destruct;
|
||||
};
|
||||
|
||||
template <int Value, int Denominator>
|
||||
struct CeilDivideMinimumOne {
|
||||
static const int Result = ((Value / Denominator) + ((!Value || (Value % Denominator)) ? 1 : 0));
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
struct InterfaceWrapTemplate {
|
||||
static const int Size = CeilDivideMinimumOne<sizeof(Type), sizeof(uint64)>::Result * sizeof(uint64);
|
||||
static void Construct(void *location, Interfaces *interfaces) {
|
||||
new (location) Type(interfaces);
|
||||
}
|
||||
static void Destruct(void *location) {
|
||||
((Type*)location)->~Type();
|
||||
}
|
||||
};
|
||||
|
||||
extern InterfaceWrapStruct InterfaceWraps[64];
|
||||
extern QAtomicInt InterfaceIndexLast;
|
||||
|
||||
template <typename Type>
|
||||
class BasicInterface {
|
||||
public:
|
||||
static int Index() {
|
||||
static QAtomicInt _index(0);
|
||||
if (int index = _index.loadAcquire()) {
|
||||
return index - 1;
|
||||
}
|
||||
while (true) {
|
||||
int last = InterfaceIndexLast.loadAcquire();
|
||||
if (InterfaceIndexLast.testAndSetOrdered(last, last + 1)) {
|
||||
t_assert(last < 64);
|
||||
if (_index.testAndSetOrdered(0, last + 1)) {
|
||||
InterfaceWraps[last] = InterfaceWrapStruct(InterfaceWrapTemplate<Type>::Size, InterfaceWrapTemplate<Type>::Construct, InterfaceWrapTemplate<Type>::Destruct);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return _index.loadAcquire() - 1;
|
||||
}
|
||||
static uint64 Bit() {
|
||||
return (1 << Index());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
class BasicInterfaceWithPointer : public BasicInterface<Type> {
|
||||
public:
|
||||
BasicInterfaceWithPointer(Interfaces *interfaces) : interfaces(interfaces) {
|
||||
}
|
||||
Interfaces *interfaces = 0;
|
||||
};
|
||||
|
||||
class InterfacesMetadata {
|
||||
public:
|
||||
|
||||
InterfacesMetadata(uint64 mask) : size(0), last(64), _mask(mask) {
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
uint64 m = (1 << i);
|
||||
if (_mask & m) {
|
||||
int s = InterfaceWraps[i].Size;
|
||||
if (s) {
|
||||
offsets[i] = size;
|
||||
size += s;
|
||||
} else {
|
||||
offsets[i] = -1;
|
||||
}
|
||||
} else if (_mask < m) {
|
||||
last = i;
|
||||
for (; i < 64; ++i) {
|
||||
offsets[i] = -1;
|
||||
}
|
||||
} else {
|
||||
offsets[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int size, last;
|
||||
int offsets[64];
|
||||
|
||||
private:
|
||||
uint64 _mask;
|
||||
|
||||
};
|
||||
|
||||
const InterfacesMetadata *GetInterfacesMetadata(uint64 mask);
|
||||
|
||||
class Interfaces {
|
||||
public:
|
||||
|
||||
Interfaces(uint64 mask = 0) : _meta(GetInterfacesMetadata(mask)), _data(0) {
|
||||
if (_meta->size) {
|
||||
_data = malloc(_meta->size);
|
||||
if (!_data) { // terminate if we can't allocate memory
|
||||
throw "Can't allocate memory!";
|
||||
}
|
||||
|
||||
for (int i = 0; i < _meta->last; ++i) {
|
||||
int offset = _meta->offsets[i];
|
||||
if (offset >= 0) {
|
||||
try {
|
||||
InterfaceWraps[i].Construct(_dataptrunsafe(offset), this);
|
||||
} catch (...) {
|
||||
while (i > 0) {
|
||||
--i;
|
||||
offset = _meta->offsets[--i];
|
||||
if (offset >= 0) {
|
||||
InterfaceWraps[i].Destruct(_dataptrunsafe(offset));
|
||||
}
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
~Interfaces() {
|
||||
if (_data) {
|
||||
for (int i = 0; i < _meta->last; ++i) {
|
||||
int offset = _meta->offsets[i];
|
||||
if (offset >= 0) {
|
||||
InterfaceWraps[i].Destruct(_dataptrunsafe(offset));
|
||||
}
|
||||
}
|
||||
free(_data);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type *Get() {
|
||||
return (Type*)_dataptr(_meta->offsets[Type::Index()]);
|
||||
}
|
||||
template <typename Type>
|
||||
const Type *Get() const {
|
||||
return (const Type*)_dataptr(_meta->offsets[Type::Index()]);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void *_dataptrunsafe(int skip) const {
|
||||
return (char*)_data + skip;
|
||||
}
|
||||
void *_dataptr(int skip) const {
|
||||
return (skip >= 0) ? _dataptrunsafe(skip) : 0;
|
||||
}
|
||||
const InterfacesMetadata *_meta;
|
||||
void *_data;
|
||||
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
class FunctionImplementation {
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user