Warning, file /office/calligra/gemini/lib/GeminiMainWindow.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 * Copyright (C) 2015 Dan Leinir Turthra Jensen <admin@leinir.dk> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Library General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Library General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Library General Public License 0015 * along with this library; see the file COPYING.LIB. If not, write to 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 0020 #include "GeminiMainWindow.h" 0021 #include "GeminiModeSwitchEvent.h" 0022 0023 #include <QApplication> 0024 #include <QMap> 0025 #include <QQuickView> 0026 #include <QTimer> 0027 #include <QVBoxLayout> 0028 0029 #ifdef Q_OS_WIN 0030 // Slate mode/docked detection stuff 0031 #include <Shellapi.h> 0032 #define SM_CONVERTIBLESLATEMODE 0x2003 0033 #define SM_SYSTEMDOCKED 0x2004 0034 #endif 0035 0036 struct View { 0037 View() : quickView(0), widget(0) {} 0038 QQuickView* quickView; 0039 QWidget* widget; 0040 QWidget* getWidget(QWidget* parent = 0) { 0041 QWidget* view; 0042 if(widget) { 0043 view = widget; 0044 } 0045 else { 0046 QWidget* container = QWidget::createWindowContainer(quickView); 0047 view = new QWidget(parent); 0048 view->setLayout(new QVBoxLayout()); 0049 view->layout()->setContentsMargins(0,0,0,0); 0050 view->layout()->setSpacing(0); 0051 view->layout()->addWidget(container); 0052 } 0053 return view; 0054 } 0055 }; 0056 0057 class GeminiMainWindow::Private { 0058 public: 0059 Private(GeminiMainWindow* qq) 0060 : q(qq) 0061 , fullScreenThrottle(new QTimer(qq)) 0062 , currentState(UnknownState) 0063 , stateLocked(false) 0064 { 0065 fullScreenThrottle->setInterval(500); 0066 fullScreenThrottle->setSingleShot(true); 0067 0068 // Initialise the event receiver map to empty 0069 eventReceivers.insert(CreateState, 0); 0070 eventReceivers.insert(EditState, 0); 0071 eventReceivers.insert(ViewState, 0); 0072 0073 // Initialise the view map to empty 0074 views.insert(CreateState, 0); 0075 views.insert(EditState, 0); 0076 views.insert(ViewState, 0); 0077 } 0078 GeminiMainWindow* q; 0079 QTimer* fullScreenThrottle; 0080 0081 GeminiState previousState; 0082 GeminiState currentState; 0083 bool stateLocked; 0084 0085 QMap<GeminiState, View*> views; 0086 QMap<GeminiState, QObject*> eventReceivers; 0087 0088 GeminiModeSynchronisationObject* syncObject; 0089 }; 0090 0091 GeminiMainWindow::GeminiMainWindow(QWidget* parent, Qt::WindowFlags flags) 0092 : QMainWindow(parent, flags) 0093 , d(new Private(this)) 0094 { 0095 } 0096 0097 GeminiMainWindow::~GeminiMainWindow() 0098 { 0099 delete d; 0100 } 0101 0102 GeminiMainWindow::GeminiState GeminiMainWindow::currentState() const 0103 { 0104 return d->currentState; 0105 } 0106 0107 bool GeminiMainWindow::fullScreen() const 0108 { 0109 return (windowState() & Qt::WindowFullScreen) == Qt::WindowFullScreen; 0110 } 0111 0112 void GeminiMainWindow::setFullScreen(bool newState) 0113 { 0114 if(newState) { 0115 if(d->fullScreenThrottle->isActive()) { 0116 // not a good thing... you need to avoid this happening. This exists to avoid a death-loop, 0117 // such as what might happen if readermode is enabled when the window is not maximised 0118 // as this causes a resize loop which makes readermode switch between enabled and disabled, 0119 // which in turn makes fullScreen be set and reset all the time... very bad, so let's try 0120 // and avoid that. 0121 } 0122 else { 0123 setWindowState(windowState() | Qt::WindowFullScreen); 0124 } 0125 } 0126 else { 0127 // this is really unpleasant... however, fullscreen is very twitchy, and exiting it as below 0128 // will cause an inconsistent state, so we simply assume exiting fullscreen leaves you maximised. 0129 // It isn't optimal, but it is the best state for now, this has taken too long to work out. 0130 // setWindowState(windowState() & ~Qt::WindowFullScreen); 0131 // should really do it, but... it doesn't. So, we end up with what we have next: 0132 showMaximized(); 0133 } 0134 d->fullScreenThrottle->start(); 0135 emit fullScreenChanged(); 0136 } 0137 0138 0139 void GeminiMainWindow::changeState(GeminiMainWindow::GeminiState newState, bool lockNewState) 0140 { 0141 d->syncObject = new GeminiModeSynchronisationObject; 0142 0143 if(centralWidget()) { 0144 //Notify the view we are switching away from that we are about to switch away from it 0145 //giving it the possibility to set up the synchronisation object. 0146 GeminiModeSwitchEvent aboutToSwitchEvent(GeminiModeSwitchEvent::AboutToSwitchViewModeEvent, d->eventReceivers[d->currentState], d->eventReceivers[newState], d->syncObject); 0147 QApplication::sendEvent(d->eventReceivers[d->currentState], &aboutToSwitchEvent); 0148 0149 centralWidget()->setParent(0); 0150 } 0151 0152 View* view = d->views[newState]; 0153 setCentralWidget(view->getWidget()); 0154 qApp->processEvents(); 0155 if(view->quickView) 0156 view->quickView->setVisible(true); 0157 resize(size()); 0158 0159 d->previousState = d->currentState; 0160 d->currentState = newState; 0161 emit currentStateChanged(); 0162 0163 QTimer::singleShot(50, this, SLOT(stateChanging())); 0164 } 0165 0166 void GeminiMainWindow::stateChanging() 0167 { 0168 qApp->processEvents(); 0169 //Notify the new view that we just switched to it, passing our synchronisation object 0170 //so it can use those values to sync with the old view. 0171 GeminiModeSwitchEvent switchedEvent(GeminiModeSwitchEvent::SwitchedToThisModeEvent, d->eventReceivers[d->previousState], d->eventReceivers[d->currentState], d->syncObject); 0172 QApplication::sendEvent(d->eventReceivers[d->currentState], &switchedEvent); 0173 d->syncObject = 0; 0174 qApp->processEvents(); 0175 } 0176 0177 bool GeminiMainWindow::stateLocked() const 0178 { 0179 return d->stateLocked; 0180 } 0181 0182 void GeminiMainWindow::setStateLocked(bool locked) 0183 { 0184 d->stateLocked = locked; 0185 emit stateLockedChanged(); 0186 } 0187 0188 void GeminiMainWindow::setViewForState(QWidget* widget, GeminiMainWindow::GeminiState state) 0189 { 0190 View* view = d->views[state]; 0191 view->quickView = 0; 0192 view->widget = widget; 0193 } 0194 0195 void GeminiMainWindow::setViewForState(QQuickView* quickView, GeminiMainWindow::GeminiState state) 0196 { 0197 View* view = d->views[state]; 0198 view->quickView = quickView; 0199 view->widget = 0; 0200 } 0201 0202 void GeminiMainWindow::setEventReceiverForState(QObject* receiver, GeminiMainWindow::GeminiState state) 0203 { 0204 d->eventReceivers[state] = receiver; 0205 } 0206 0207 #ifdef Q_OS_WIN 0208 bool GeminiMainWindow::winEvent( MSG * message, long * result ) 0209 { 0210 if (message && message->message == WM_SETTINGCHANGE && message->lParam && !d->stateLocked) 0211 { 0212 if (wcscmp(TEXT("ConvertibleSlateMode"), (TCHAR *) message->lParam) == 0 || wcscmp(TEXT("SystemDockMode"), (TCHAR *) message->lParam) == 0) { 0213 bool slateMode = (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0); 0214 bool undocked = !(GetSystemMetrics(SM_SYSTEMDOCKED) != 0); 0215 if(slateMode || undocked) { 0216 // find out if we are entirely without sensible input devices, or portrait 0217 // if we are, change to ViewState. EditState will do for now as an autoswitch... 0218 changeState(EditState); 0219 } 0220 else { 0221 // If we are neither slate nor undocked, then we're in clamshell or we are docked, which is the same thing. 0222 changeState(CreateState); 0223 } 0224 *result = 0; 0225 return true; 0226 } 0227 } 0228 return false; 0229 } 0230 #endif