diff --git a/Telegram/SourceFiles/base/object_ptr.h b/Telegram/SourceFiles/base/object_ptr.h new file mode 100644 index 000000000..bb3b55e23 --- /dev/null +++ b/Telegram/SourceFiles/base/object_ptr.h @@ -0,0 +1,126 @@ +/* +This file is part of Kepka - The Unofficial Telegram Desktop client, +see https://github.com/procxx/kepka + +Kepka 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 3 of the License, or +(at your option) any later version. + +It 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. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/procxx/kepka/blob/master/LICENSE +Copyright (c) 2018 pro.cxx Community +*/ +#pragma once + +#include +#include + +// Smart pointer for QObject*, has move semantics, destroys object if it doesn't have a parent. +template +class object_ptr { +public: + object_ptr(std::nullptr_t) { + } + + // No default constructor, but constructors with at least + // one argument are simply make functions. + template + explicit object_ptr(Parent &&parent, Args&&... args) : _object(new Object(std::forward(parent), std::forward(args)...)) { + } + + object_ptr(const object_ptr &other) = delete; + object_ptr &operator=(const object_ptr &other) = delete; + object_ptr(object_ptr &&other) : _object(base::take(other._object)) { + } + object_ptr &operator=(object_ptr &&other) { + auto temp = std::move(other); + destroy(); + std::swap(_object, temp._object); + return *this; + } + + template ::value>> + object_ptr(object_ptr &&other) : _object(base::take(other._object)) { + } + + template ::value>> + object_ptr &operator=(object_ptr &&other) { + _object = base::take(other._object); + return *this; + } + + object_ptr &operator=(std::nullptr_t) { + _object = nullptr; + return *this; + } + + // So we can pass this pointer to methods like connect(). + Object *data() const { + return static_cast(_object.data()); + } + operator Object*() const { + return data(); + } + + explicit operator bool() const { + return _object != nullptr; + } + + Object *operator->() const { + return data(); + } + Object &operator*() const { + return *data(); + } + + // Use that instead "= new Object(parent, ...)" + template + void create(Parent &&parent, Args&&... args) { + destroy(); + _object = new Object(std::forward(parent), std::forward(args)...); + } + void destroy() { + delete base::take(_object); + } + void destroyDelayed() { + if (_object) { + if (auto widget = base::up_cast(data())) { + widget->hide(); + } + base::take(_object)->deleteLater(); + } + } + + ~object_ptr() { + if (auto pointer = _object) { + if (!pointer->parent()) { + destroy(); + } + } + } + + template + friend object_ptr static_object_cast(object_ptr source); + +private: + template + friend class object_ptr; + + QPointer _object; + +}; + +template +inline object_ptr static_object_cast(object_ptr source) { + auto result = object_ptr(nullptr); + result._object = static_cast(base::take(source._object).data()); + return std::move(result); +} \ No newline at end of file diff --git a/Telegram/SourceFiles/ui/twidget.h b/Telegram/SourceFiles/ui/twidget.h index 13791bced..d086c5f71 100644 --- a/Telegram/SourceFiles/ui/twidget.h +++ b/Telegram/SourceFiles/ui/twidget.h @@ -28,6 +28,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include #include "base/lambda.h" #include "base/flags.h" +#include "base/object_ptr.h" #include "ui/style/style_core.h" #include "styles/palette.h" #include "styles/style_basic.h" @@ -426,108 +427,6 @@ private: }; -// Smart pointer for QObject*, has move semantics, destroys object if it doesn't have a parent. -template -class object_ptr { -public: - object_ptr(std::nullptr_t) { - } - - // No default constructor, but constructors with at least - // one argument are simply make functions. - template - explicit object_ptr(Parent &&parent, Args&&... args) : _object(new Object(std::forward(parent), std::forward(args)...)) { - } - - object_ptr(const object_ptr &other) = delete; - object_ptr &operator=(const object_ptr &other) = delete; - object_ptr(object_ptr &&other) : _object(base::take(other._object)) { - } - object_ptr &operator=(object_ptr &&other) { - auto temp = std::move(other); - destroy(); - std::swap(_object, temp._object); - return *this; - } - - template ::value>> - object_ptr(object_ptr &&other) : _object(base::take(other._object)) { - } - - template ::value>> - object_ptr &operator=(object_ptr &&other) { - _object = base::take(other._object); - return *this; - } - - object_ptr &operator=(std::nullptr_t) { - _object = nullptr; - return *this; - } - - // So we can pass this pointer to methods like connect(). - Object *data() const { - return static_cast(_object.data()); - } - operator Object*() const { - return data(); - } - - explicit operator bool() const { - return _object != nullptr; - } - - Object *operator->() const { - return data(); - } - Object &operator*() const { - return *data(); - } - - // Use that instead "= new Object(parent, ...)" - template - void create(Parent &&parent, Args&&... args) { - destroy(); - _object = new Object(std::forward(parent), std::forward(args)...); - } - void destroy() { - delete base::take(_object); - } - void destroyDelayed() { - if (_object) { - if (auto widget = base::up_cast(data())) { - widget->hide(); - } - base::take(_object)->deleteLater(); - } - } - - ~object_ptr() { - if (auto pointer = _object) { - if (!pointer->parent()) { - destroy(); - } - } - } - - template - friend object_ptr static_object_cast(object_ptr source); - -private: - template - friend class object_ptr; - - QPointer _object; - -}; - -template -inline object_ptr static_object_cast(object_ptr source) { - auto result = object_ptr(nullptr); - result._object = static_cast(base::take(source._object).data()); - return std::move(result); -} - void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button, const QPoint &globalPoint); inline void sendSynteticMouseEvent(QWidget *widget, QEvent::Type type, Qt::MouseButton button) {