Merge lp:~dandrader/unity8/miral into lp:unity8

Proposed by Daniel d'Andrada
Status: Merged
Approved by: Lukáš Tinkl
Approved revision: no longer in the source branch.
Merged at revision: 2744
Proposed branch: lp:~dandrader/unity8/miral
Merge into: lp:unity8
Prerequisite: lp:~dandrader/unity8/fixMakeTryApplicationWindow
Diff against target: 11323 lines (+5093/-2297)
127 files modified
CMakeLists.txt (+14/-1)
data/com.canonical.Unity8.gschema.xml (+2/-2)
debian/changelog (+33/-0)
debian/control (+5/-3)
plugins/Greeter/Unity/Launcher/CMakeLists.txt (+1/-1)
plugins/Greeter/Unity/Launcher/launcheritem.cpp (+13/-0)
plugins/Greeter/Unity/Launcher/launcheritem.h (+3/-0)
plugins/LightDM/FullLightDM/CMakeLists.txt (+5/-1)
plugins/Unity/Indicators/CMakeLists.txt (+3/-0)
plugins/Unity/Launcher/CMakeLists.txt (+4/-1)
plugins/Unity/Launcher/appdrawermodel.cpp (+62/-0)
plugins/Unity/Launcher/appdrawermodel.h (+33/-0)
plugins/Unity/Launcher/launcheritem.cpp (+13/-0)
plugins/Unity/Launcher/launcheritem.h (+4/-0)
plugins/Unity/Launcher/launchermodel.cpp (+6/-37)
plugins/Unity/Launcher/launchermodel.h (+0/-14)
plugins/Unity/Launcher/plugin.cpp (+2/-1)
plugins/Unity/Launcher/ualwrapper.cpp (+73/-0)
plugins/Unity/Launcher/ualwrapper.h (+35/-0)
plugins/Utils/CMakeLists.txt (+4/-0)
plugins/Utils/ElapsedTimer.h (+1/-1)
plugins/Utils/Timer.cpp (+5/-2)
plugins/Utils/Timer.h (+5/-6)
plugins/Utils/appdrawerproxymodel.cpp (+189/-0)
plugins/Utils/appdrawerproxymodel.h (+87/-0)
plugins/Utils/globalfunctions.cpp (+5/-0)
plugins/Utils/globalfunctions.h (+2/-0)
plugins/Utils/plugin.cpp (+2/-0)
plugins/Utils/windowstatestorage.cpp (+23/-0)
plugins/Utils/windowstatestorage.h (+5/-0)
plugins/WindowManager/CMakeLists.txt (+3/-1)
plugins/WindowManager/TopLevelSurfaceList.cpp (+0/-481)
plugins/WindowManager/TopLevelSurfaceList.h (+0/-223)
plugins/WindowManager/TopLevelWindowModel.cpp (+668/-0)
plugins/WindowManager/TopLevelWindowModel.h (+260/-0)
plugins/WindowManager/Window.cpp (+237/-0)
plugins/WindowManager/Window.h (+161/-0)
plugins/WindowManager/WindowManagerPlugin.cpp (+5/-2)
po/unity8.pot (+80/-43)
qml/Components/InputMethod.qml (+5/-4)
qml/Components/KeyboardShortcutsOverlay.qml (+13/-0)
qml/Components/KeymapSwitcher.qml (+4/-1)
qml/Components/VirtualTouchPad.qml (+269/-1)
qml/Dash/Previews/PreviewAudioPlayback.qml (+1/-0)
qml/DisabledScreenNotice.qml (+6/-58)
qml/Greeter/Greeter.qml (+1/-5)
qml/Greeter/LoginList.qml (+1/-1)
qml/Greeter/WideView.qml (+7/-2)
qml/Launcher/BackgroundBlur.qml (+81/-0)
qml/Launcher/Drawer.qml (+306/-0)
qml/Launcher/DrawerGridView.qml (+47/-0)
qml/Launcher/DrawerListView.qml (+32/-0)
qml/Launcher/Launcher.qml (+182/-34)
qml/Launcher/MoreAppsHeader.qml (+46/-0)
qml/Panel/Indicators/MenuItemFactory.qml (+22/-1)
qml/Shell.qml (+25/-41)
qml/Stage/FakeMaximizeDelegate.qml (+7/-7)
qml/Stage/MoveHandler.qml (+3/-3)
qml/Stage/Spread/WindowedRightEdgeMaths.qml (+19/-4)
qml/Stage/Stage.qml (+196/-186)
qml/Stage/StageMaths.qml (+2/-7)
qml/Stage/StagedFullscreenPolicy.qml (+4/-4)
qml/Stage/TopLevelSurfaceRepeater.qml (+0/-67)
qml/Stage/WindowControlsOverlay.qml (+1/-1)
qml/Stage/WindowResizeArea.qml (+2/-70)
qml/Stage/WindowStateSaver.qml (+63/-0)
qml/Stage/WindowedFullscreenPolicy.qml (+1/-1)
qml/Tutorial/TutorialLeftLong.qml (+1/-1)
src/ShellApplication.cpp (+1/-0)
tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpp (+1/-1)
tests/mocks/LightDM/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp (+23/-23)
tests/mocks/QtMultimedia/videooutput.h (+1/-1)
tests/mocks/Unity/Application/ApplicationInfo.cpp (+48/-24)
tests/mocks/Unity/Application/ApplicationInfo.h (+2/-2)
tests/mocks/Unity/Application/ApplicationManager.cpp (+92/-63)
tests/mocks/Unity/Application/ApplicationManager.h (+31/-4)
tests/mocks/Unity/Application/CMakeLists.txt (+1/-1)
tests/mocks/Unity/Application/MirSurface.cpp (+86/-99)
tests/mocks/Unity/Application/MirSurface.h (+29/-27)
tests/mocks/Unity/Application/MirSurfaceItem.cpp (+4/-4)
tests/mocks/Unity/Application/MirSurfaceItem.h (+1/-2)
tests/mocks/Unity/Application/MirSurfaceListModel.cpp (+12/-34)
tests/mocks/Unity/Application/MirSurfaceListModel.h (+2/-7)
tests/mocks/Unity/Application/SurfaceManager.cpp (+172/-26)
tests/mocks/Unity/Application/SurfaceManager.h (+28/-10)
tests/mocks/Unity/Application/plugin.cpp (+4/-34)
tests/mocks/Unity/Launcher/CMakeLists.txt (+5/-1)
tests/mocks/Unity/Launcher/MockAppDrawerModel.cpp (+75/-0)
tests/mocks/Unity/Launcher/MockAppDrawerModel.h (+32/-0)
tests/mocks/Unity/Launcher/MockLauncherItem.cpp (+13/-0)
tests/mocks/Unity/Launcher/MockLauncherItem.h (+6/-0)
tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+3/-0)
tests/mocks/Unity/Launcher/plugin.cpp (+4/-0)
tests/mocks/Utils/CMakeLists.txt (+4/-0)
tests/mocks/Utils/plugin.cpp (+2/-0)
tests/mocks/Utils/windowstatestorage.cpp (+23/-0)
tests/mocks/Utils/windowstatestorage.h (+5/-0)
tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt (+1/-1)
tests/plugins/Unity/Launcher/CMakeLists.txt (+2/-1)
tests/plugins/Unity/Launcher/launchermodeltest.cpp (+6/-0)
tests/plugins/Utils/WindowInputMonitorTest.cpp (+76/-9)
tests/qmltests/CMakeLists.txt (+1/-0)
tests/qmltests/Components/tst_VirtualTouchPad.qml (+55/-1)
tests/qmltests/Dash/Previews/tst_Preview.qml (+63/-0)
tests/qmltests/Dash/tst_Dash.qml (+4/-3)
tests/qmltests/Dash/tst_DashShell.qml (+0/-29)
tests/qmltests/Launcher/tst_Drawer.qml (+264/-0)
tests/qmltests/Launcher/tst_Launcher.qml (+4/-4)
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml (+6/-1)
tests/qmltests/Panel/tst_ActiveCallHint.qml (+16/-2)
tests/qmltests/Panel/tst_Panel.qml (+8/-1)
tests/qmltests/Stage/ApplicationCheckBox.qml (+1/-1)
tests/qmltests/Stage/tst_ApplicationWindow.qml (+10/-10)
tests/qmltests/Stage/tst_DesktopStage.qml (+124/-80)
tests/qmltests/Stage/tst_PhoneStage.qml (+18/-38)
tests/qmltests/Stage/tst_SurfaceContainer.qml (+4/-0)
tests/qmltests/Stage/tst_TabletStage.qml (+16/-10)
tests/qmltests/Stage/tst_WindowResizeArea.qml (+1/-66)
tests/qmltests/Tutorial/tst_Tutorial.qml (+30/-8)
tests/qmltests/tst_DisabledScreenNotice.qml (+23/-9)
tests/qmltests/tst_OrientedShell.qml (+6/-13)
tests/qmltests/tst_Shell.qml (+143/-242)
tests/qmltests/tst_ShellWithPin.qml (+18/-75)
tests/uqmlscene/CMakeLists.txt (+5/-1)
tests/utils/modules/Unity/Test/StageTestCase.qml (+68/-0)
tests/utils/modules/Unity/Test/UnityTestCase.qml (+8/-9)
tests/utils/modules/Unity/Test/qmldir (+2/-1)
To merge this branch: bzr merge lp:~dandrader/unity8/miral
Reviewer Review Type Date Requested Status
Unity8 CI Bot continuous-integration Needs Fixing
Lukáš Tinkl (community) Approve
Emanuele Antonio Faraone (community) Approve
Michael Zanetti Pending
Review via email: mp+312194@code.launchpad.net

This proposal supersedes a proposal from 2016-11-23.

Commit message

Let the model deal with some window management decisions

eg: which window to focus, whether to change surface state

unity8 requests and reacts to changes in the model instead of applying them

Description of the change

Prereq-archive: ppa:ci-train-ppa-service/2160

For the upcoming, miral-powered, qtmir.

One notable introduction is the Window object, which is a sligthly higher level abstraction of a MirSurface (and a drop-in replacement for it) to be used by Stage.qml. Window always exists in a TopLevelWindowModel entry so that QML code no longer has to if(){}else{} for the existence of a MirSurface (because of the splash screen case)

* Are there any related MPs required for this MP to build/function as expected? Please list.

https://code.launchpad.net/~unity-team/unity-api/miral/+merge/309938
https://code.launchpad.net/~unity-team/qtmir/miral-qt-integration/+merge/312244

It's all in this silo: https://bileto.ubuntu.com/#/ticket/2160

* Did you perform an exploratory manual test run of your code change and any related functionality?

Yes.

* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
Not applicable

* If you changed the UI, has there been a design review?
Not applicable

To post a comment you must log in.
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2697
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2487/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/3279/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3307
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3161/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3161
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3161/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3161
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3161/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3161/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3161
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3161/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3161
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3161/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3161/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3161
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3161/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3161
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3161/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2487/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

* See a bunch of inline comments

* I think we should not give up on the differntiation between claimFocus() and requestFocus(). One of them says the stage wants to actually focus something *now* while the other indicates that the app requested focus on its own (or perhaps u-a-l did). IMO claimFocus() should not be dropped and still do the raisId() call on the model. requestfocus() instead should end up in the shell, and if the shell is ok with doing so, it should call claimFocus() itself.

* IMO you're exaggerating with the debug messages. unity8.toplevelsurfacelist was already very annoying and this seems to have even more prints. Sure, you can argue that I could turn them off with the debug filter, which is what I do, but then I get none any more while the most important ones like raise() added() and removed() would still make sense.

This has been a code review for the code up until the mocks. Still needs review for tests/mocks and especially in depth testing.

review: Needs Fixing
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

Not yet sure if just an issue in the mocks or not, but this breaks:

- open an app
- click the minimize button in the window decoration
- click the app again in the launcher to restore it
- now click the minimize button again
=> button doesn't work any more

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
> * IMO you're exaggerating with the debug messages. unity8.toplevelsurfacelist was already very annoying and this seems to have even more prints. Sure, you can argue that I could turn them off with the debug filter, which is what I do, but then I get none any more while the most important ones like raise() added() and removed() would still make sense.

Reduced the logging output. Should be the way you prefer now.

Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

- have 3 apps (a, b and c), make them overlap a bit for better visibility
- focus a by clicking it
- focus b by clicking it
- focus c by clicking it
- minimize c
=> a will be focused

expected: after minimizing c, b should be focused

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
> * I think we should not give up on the differntiation between claimFocus() and requestFocus(). One of them says the stage wants to actually focus something*now* while the other indicates that the app requested focus on its own (or perhaps u-a-l did). IMO claimFocus() should not be dropped and still do the raisId() call on the model. requestfocus() instead should end up in the shell, and if the shell is ok with doing so, it should call claimFocus() itself.

What you are explaining effectively is that: leave things as they are
currently with regards to focus. Which means focus lives in unity8 and
miral has no say over it.

The whole point of this miral effort is exactly to move such window
management decisions down to Mir, as dictated by our high-profile
stakeholder.

On the bright side, focus requests made by unity8 should naturally
always be sensible (since it knows the situation pretty well) and
therefore miral should always swiftly comply. So in terms of end
results, those requests will work just like imperative assignments.

Focus is a central piece of window management and if miral is to do
anything useful it has to have a say in it. And we cannot have two
entities making decisions on focus (unity8 and miral) as it will
inevitably be racy and conflictive.

As for the origin of the focus change request (shell vs. application),
it doesn't matter from miral's standpoint. It will comply to either as
long the change is valid and makes sense. Eg.: it should never allow a
window blocked by a child modal dialog to be focused. So it's mostly
sanity checking. I don't see miral ignoring requests on a whim. :)

Besides, having two separate code paths would make unity8 code more
complex. Eg: Having both code that sets surface state and code that
responds to surface state changes. "If surface state change was done in
response my your own set(), do nothing, else, ponder and respond."

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2698
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2512/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/3317/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3345
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3197/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3197
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3197/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3197
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3197/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3197/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3197
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3197/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3197
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3197/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3197/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3197
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3197/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3197
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3197/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2512/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
>> +int TopLevelWindowModel::nextFreeId(int candidateId)
>> >+{
>> >+ if (candidateId > m_maxId) {
>> >+ return nextFreeId(1);
>> >+ } else {
>> >+ if (indexForId(candidateId) == -1) {
>> >+ // it's indeed free
>> >+ return candidateId;
>> >+ } else {
>> >+ return nextFreeId(candidateId + 1);
>> >+ }
>> >+ }
>> >+}
> In the very unlikely event that we'd run out of free ids, this would crash with a stack overflow. Think it makes sense to write this in a non-recursive manner and perhaps add some way to actually handle failures?
>
If we run out of free ids it's because there's already a bug somewhere.
There's no way there's a valid situation where we would have literally a
million windows lying around.

But a non-recursive version is indeed lighter-weight on resources if it
ever has to traverse a long stretch of taken ids. Done.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2699
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2513/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/3318/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3346
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3198/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3198
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3198/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3198
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3198/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3198/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3198
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3198/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3198
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3198/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3198/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3198
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3198/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3198
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3198/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2513/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
>> +QString TopLevelWindowModel::toString()
>> >+{
>> >+ QString str;
>> >+ for (int i = 0; i < m_windowModel.count(); ++i) {
>> >+ auto item = m_windowModel.at(i);
>> >+
>> >+ QString itemStr = QString("(index=%1,appId=%2,surface=0x%3,id=%4)")
>> >+ .arg(i)
>> >+ .arg(item.application->appId())
>> >+ .arg((qintptr)item.window->surface(), 0, 16)
>> >+ .arg(item.window->id());
> it would be slightly more performant if you'd use QString::arg(QString, QString, QSttring, QString) instead as it has to walk the string only once with that...
>
Done.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
>> +public Q_SLOTS:
>> >+ /**
>> >+ * @brief Returns the surface at the given index
>> >+ *
>> >+ * It will be a nullptr if the application is still starting up and thus hasn't yet created
>> >+ * and drawn into a surface.
>> >+ *
>> >+ * Same as windowAt(index).surface()
>> >+ */
>> >+ unity::shell::application::MirSurfaceInterface *surfaceAt(int index) const;
>> >+
>> >+ /**
>> >+ * @brief Returns the window at the given index
>> >+ *
>> >+ * Will always be valid
>> >+ */
>> >+ Window *windowAt(int index) const;
>> >+
>> >+ /**
>> >+ * @brief Returns the application at the given index
>> >+ */
>> >+ unity::shell::application::ApplicationInfoInterface *applicationAt(int index) const;
>> >+
>> >+ /**
>> >+ * @brief Returns the unique id of the element at the given index
>> >+ */
>> >+ int idAt(int index) const;
>> >+
>> >+ /**
>> >+ * @brief Returns the index where the row with the given id is located
>> >+ *
>> >+ * Returns -1 if there's no row with the given id.
>> >+ */
>> >+ int indexForId(int id) const;
> slots with return value are weird. All the above should be public Q_INVOKABLE instead IMO.

Which uglifies the header file. Not great either.

Done.

>
>> >+
>> >+ /**
>> >+ * @brief Raises the row with the given id to the top of the window stack (index == count-1)
>> >+ */
>> >+ void raiseId(int id);
> this makes sense as slot indeed
>
But it's only a slot so it can be called from QML. Made it a Q_INVOKABLE
as well to match the others.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
>> +Window::Window(int id)
>> >+ : QObject(nullptr)
>> >+ , m_id(id)
>> >+{
>> >+ DEBUG_MSG << "()";
>> >+ QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
> is there a reason why you can't use QObject's parent instead?

Laziness. Done.

>
> Would make sense in any case to parent the Window objects properly IMO
>
Yes, that's a nice safety net.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
>> +QString Window::toString() const
>> >+{
>> >+ if (surface()) {
>> >+ return QString("Window[0x%1, id=%2, MirSurface[0x%3,\"%4\"]]")
>> >+ .arg((quintptr)this, 0, 16)
>> >+ .arg(id())
>> >+ .arg((quintptr)surface(), 0, 16)
>> >+ .arg(surface()->name());
> same here... if this is only ever executed in certain debug modes, ok with me, but if this is executed in production code too, please use the single .arg(..., ..., ...) call for better performance.
>
Done.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
>> + Q_PROPERTY(unity::shell::application::MirSurfaceInterface* surface READ surface NOTIFY surfaceChanged)
> gah I despise this overly excessive namespacing...

Me too! Nested namespaces are an eyesore.

> IMO you could just do "using namespace unity::shell::application;" and be done with this, really... It's not like we'd ever have a conflicting MirSurfaceInterface class somewhere else...
>
Not in a header file though. I think that's bad form. A .cpp file
#including this header would inadvertently get the
unity::shell::application namespace included in their main one.

I'm also scared of doing namespace manipulations in Qt macros. That
might go wrong.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
>> + qRegisterMetaType<Window*>("Window*");
> think it would make sense to qmlRegisterUncreatableType<Window>(...) too? Seems it would be useful API to be able to access Window from QML
>

Not sure. qmlRegisterUncreatableType() documentation says: "This is
useful where the type is only intended for providing attached properties
or enum values."
Not the case here.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
>> - onMinimizeClicked: root.minimizeClicked();
>> >+ onMinimizeClicked: {
>> >+ if (applicationWindow.surface) {
>> >+ applicationWindow.surface.requestState(Mir.MinimizedState);
>> >+ }
>> >+ }
> this seems odd... why would you refactor DecoratedWindow to not directly operate on the data any more but instead pass everything outside with signals in a earlier branch, but now start introducing this somewhat messy behavior here again? IMO this should also be passed to outside to the Stage, and only the stage being in charge to actually execute things on the surfaces.
>
That's some old change that pre-dates that branch you mentioned.
Reverted.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
>> - function focusNext() {
> same as I mentioned earlier. I'm still a bit scared of dropping control over this from the qml part, but lets see how it works... At least now that the model is part of unity8 again, it seems easier to change that back or modify in yet another way if we need to.
>
This is a perfect case where it makes sense to delegate to the C++
model. Choosing the next window do be focused when the current one is
minimized is a bunch of imperative code (and WM policy) that fits better
in C++ and not mixed with animation code in QML.

Particularly now that the model knows everything (who's focused and the
position and state of all surfaces).

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2700
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2514/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/3319/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3347
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3199/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3199
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3199/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3199
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3199/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3199/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3199
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3199/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3199
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3199/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3199/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3199
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3199/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3199
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3199/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2514/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
>> if (!shown && priv.mainStageDelegate && !root.spreadShown) {
>> >- priv.mainStageDelegate.claimFocus();
>> >+ priv.mainStageDelegate.requestFocus();
> ok... given that requestFocus() effectively does claimFocus() now, this change totally makes sense... but we're losing the distinction between "the stage wants to focus something" and "an app requests focus by itsel (or something else than the stage)".
>
> Can you think of a way to keep that separation perhaps?
>
Heh, I actually think it is a good thing to handle them the same way (as
I said in some other comment).

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
>> + function updateQmlFocusFromMirSurfaceFocus() {
>> >+ if (model.window.focused) {
>> > claimFocus();
>> >+ priv.focusedAppDelegate = appDelegate;
>> >+ //} else if (priv.focusedAppDelegate === appDelegate && root.state != "spread") {
>> >+ // priv.focusedAppDelegate = null;
> leftover?
>
Yes, removed.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 12:29, Michael Zanetti wrote:
>> + onMaximizeHorizontallyClicked: {
>> >+ if (appDelegate.maximizedHorizontally)
>> >+ appDelegate.requestRestore();
>> >+ else
>> >+ appDelegate.requestMaximizeHorizontally();
>> >+ }
> {} missing
>
>> >+ onMaximizeVerticallyClicked: {
>> >+ if (appDelegate.maximizedVertically)
>> >+ appDelegate.requestRestore();
>> >+ else
>> >+ appDelegate.requestMaximizeVertically();
>> >+ }
> {} missing
>

Not sure if that's in our coding style but ok, added.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 14:16, Michael Zanetti wrote:
> Review: Needs Fixing
>
> Not yet sure if just an issue in the mocks or not, but this breaks:
>
> - open an app
> - click the minimize button in the window decoration
> - click the app again in the launcher to restore it
> - now click the minimize button again
> => button doesn't work any more

Bug in the mock. Works with qtmir.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2705
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2515/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/3320/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3348
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3200/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3200
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3200/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3200
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3200/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3200/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3200
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3200/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3200
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3200/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3200/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3200
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3200/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3200
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3200/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2515/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2706
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2516/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/3321/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3349
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3201/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3201
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3201/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3201
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3201/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3201/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3201
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3201/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3201
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3201/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3201/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3201
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3201/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3201
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3201/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2516/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal

>>>> - priv.mainStageDelegate.claimFocus();
>>>> >> >+ priv.mainStageDelegate.requestFocus();
>> > ok... given that requestFocus() effectively does claimFocus() now, this change totally makes sense... but we're losing the distinction between "the stage wants to focus something" and "an app requests focus by itsel (or something else than the stage)".
>> >
>> > Can you think of a way to keep that separation perhaps?
>> >
> Heh, I actually think it is a good thing to handle them the same way (as
> I said in some other comment).

How does focus stealing prevention come into play here? I believe the
plan was to only grant focus to apps that send along a ~MirCookie based
on a timestamp. I believe it's described here:

https://docs.google.com/document/d/1L85DdfDd3lDbvchYbgQ45C_lJ1IeTMG4uc7Nuq_XdAE/edit#heading=h.nlenkblnkaqq

Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

On 18.11.2016 21:09, Daniel d'Andrada wrote:
> On 18/11/2016 12:29, Michael Zanetti wrote:
>>> + qRegisterMetaType<Window*>("Window*");
>> think it would make sense to qmlRegisterUncreatableType<Window>(...) too? Seems it would be useful API to be able to access Window from QML
>>
>
> Not sure. qmlRegisterUncreatableType() documentation says: "This is
> useful where the type is only intended for providing attached properties
> or enum values."
> Not the case here.

I'm more thinking about being able to access the Window type in QML
altogether. Not really about providing attached properties etc, but it
could make sense to do pass the Window object to somewhere in QML and
access its property there without having access to the model.

Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

> On 18/11/2016 12:29, Michael Zanetti wrote:
> > * I think we should not give up on the differntiation between claimFocus()
> and requestFocus(). One of them says the stage wants to actually focus
> something*now* while the other indicates that the app requested focus on its
> own (or perhaps u-a-l did). IMO claimFocus() should not be dropped and still
> do the raisId() call on the model. requestfocus() instead should end up in the
> shell, and if the shell is ok with doing so, it should call claimFocus()
> itself.
>
> What you are explaining effectively is that: leave things as they are
> currently with regards to focus. Which means focus lives in unity8 and
> miral has no say over it.
>
> The whole point of this miral effort is exactly to move such window
> management decisions down to Mir, as dictated by our high-profile
> stakeholder.

There's a bunch of other stakeholders though that want to have it pixel perfect when it comes to animations and transitions. I am not saying miral should not have any say, but miral should send a requestFocus() to the shell and the shell will do it.
What I'm saying is that miral can tell unity to change the focus, and unity will follow that (unless it's in the middle of a transition or something). What you're proposing is that miral has all the say on when to change focus, and unity8 cannot do any course correction if the moment is bad.

> Focus is a central piece of window management and if miral is to do
> anything useful it has to have a say in it. And we cannot have two
> entities making decisions on focus (unity8 and miral) as it will
> inevitably be racy and conflictive.

which is exactly what we have now... unity8 thinks it is in charge, but miral can just jump in and trash it. I'm really just trying to avoid that.

>
> As for the origin of the focus change request (shell vs. application),
> it doesn't matter from miral's standpoint. It will comply to either as
> long the change is valid and makes sense. Eg.: it should never allow a
> window blocked by a child modal dialog to be focused. So it's mostly
> sanity checking. I don't see miral ignoring requests on a whim. :)
>
> Besides, having two separate code paths would make unity8 code more
> complex. Eg: Having both code that sets surface state and code that
> responds to surface state changes. "If surface state change was done in
> response my your own set(), do nothing, else, ponder and respond."

And I'm also not talking about 2 separate code paths. I'm saying the one code path should go through unity8 and not just manipulate the model at random.

Therefore I think only unity8 should manipulate the model, taking miral as consultant on how to manipulate it. This current approach is really the one that creates multiple entities fighting over the state of the model.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 18/11/2016 14:21, Michael Zanetti wrote:
> Review: Needs Fixing
>
> - have 3 apps (a, b and c), make them overlap a bit for better visibility
> - focus a by clicking it
> - focus b by clicking it
> - focus c by clicking it
> - minimize c
> => a will be focused
>
> expected: after minimizing c, b should be focused

Can't reproduce in "make tryDesktopStage". Need more specific steps
(like exact test and apps launched).

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 21/11/2016 07:27, Michael Zanetti wrote:
>
> On 18.11.2016 21:09, Daniel d'Andrada wrote:
>> On 18/11/2016 12:29, Michael Zanetti wrote:
>>>> + qRegisterMetaType<Window*>("Window*");
>>> think it would make sense to qmlRegisterUncreatableType<Window>(...) too? Seems it would be useful API to be able to access Window from QML
>>>
>> Not sure. qmlRegisterUncreatableType() documentation says: "This is
>> useful where the type is only intended for providing attached properties
>> or enum values."
>> Not the case here.
> I'm more thinking about being able to access the Window type in QML
> altogether. Not really about providing attached properties etc, but it
> could make sense to do pass the Window object to somewhere in QML and
> access its property there without having access to the model.
>
>
This already happens in Stage.qml:

"""
x: model.window.position.x - decoratedWindow.contentX
y: model.window.position.y - decoratedWindow.contentY
"""

Looks like qmlRegisterUncreatableType() is not needed for that. If think
you only need it for Window.foo type of constructs.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 21/11/2016 06:48, Michał Sawicz wrote:
>>>>> - priv.mainStageDelegate.claimFocus();
>>>>>>>> + priv.mainStageDelegate.requestFocus();
>>>> ok... given that requestFocus() effectively does claimFocus() now, this change totally makes sense... but we're losing the distinction between "the stage wants to focus something" and "an app requests focus by itsel (or something else than the stage)".
>>>>
>>>> Can you think of a way to keep that separation perhaps?
>>>>
>> Heh, I actually think it is a good thing to handle them the same way (as
>> I said in some other comment).
> How does focus stealing prevention come into play here? I believe the
> plan was to only grant focus to apps that send along a ~MirCookie based
> on a timestamp. I believe it's described here:
>
> https://docs.google.com/document/d/1L85DdfDd3lDbvchYbgQ45C_lJ1IeTMG4uc7Nuq_XdAE/edit#heading=h.nlenkblnkaqq
>
>
This happens at a level lower than unity8. All unity8 knows and cares
about is that some surface in the model got focus.

Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

On 21.11.2016 12:09, Daniel d'Andrada wrote:
> On 21/11/2016 07:27, Michael Zanetti wrote:
>>
>> On 18.11.2016 21:09, Daniel d'Andrada wrote:
>>> On 18/11/2016 12:29, Michael Zanetti wrote:
>>>>> + qRegisterMetaType<Window*>("Window*");
>>>> think it would make sense to qmlRegisterUncreatableType<Window>(...) too? Seems it would be useful API to be able to access Window from QML
>>>>
>>> Not sure. qmlRegisterUncreatableType() documentation says: "This is
>>> useful where the type is only intended for providing attached properties
>>> or enum values."
>>> Not the case here.
>> I'm more thinking about being able to access the Window type in QML
>> altogether. Not really about providing attached properties etc, but it
>> could make sense to do pass the Window object to somewhere in QML and
>> access its property there without having access to the model.
>>
>>
> This already happens in Stage.qml:
>
> """
> x: model.window.position.x - decoratedWindow.contentX
> y: model.window.position.y - decoratedWindow.contentY
> """
>
> Looks like qmlRegisterUncreatableType() is not needed for that. If think
> you only need it for Window.foo type of constructs.

Hmm, ok... fine then.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2707
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2517/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/3322/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3350
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3202/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3202
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3202/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3202
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3202/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3202/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3202
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3202/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3202
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3202/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3202/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3202
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3202/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3202
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3202/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2517/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

> On 18/11/2016 14:21, Michael Zanetti wrote:
> > Review: Needs Fixing
> >
> > - have 3 apps (a, b and c), make them overlap a bit for better visibility
> > - focus a by clicking it
> > - focus b by clicking it
> > - focus c by clicking it
> > - minimize c
> > => a will be focused
> >
> > expected: after minimizing c, b should be focused
>
>
> Can't reproduce in "make tryDesktopStage". Need more specific steps
> (like exact test and apps launched).

Hmm... I can't reproduce it any more either after your latest changes.

Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

> On 18/11/2016 14:16, Michael Zanetti wrote:
> > Review: Needs Fixing
> >
> > Not yet sure if just an issue in the mocks or not, but this breaks:
> >
> > - open an app
> > - click the minimize button in the window decoration
> > - click the app again in the launcher to restore it
> > - now click the minimize button again
> > => button doesn't work any more
>
> Bug in the mock. Works with qtmir.

This is really why I think we need to move all those models to unity8, put unity8 in control of them and mock things at a lower level. All our tests regarding window management are just useless right now... they can perfectly pass while the real thing can be broken really badly.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 21/11/2016 10:08, Michael Zanetti wrote:
>> On 18/11/2016 14:16, Michael Zanetti wrote:
>>> Review: Needs Fixing
>>>
>>> Not yet sure if just an issue in the mocks or not, but this breaks:
>>>
>>> - open an app
>>> - click the minimize button in the window decoration
>>> - click the app again in the launcher to restore it
>>> - now click the minimize button again
>>> => button doesn't work any more
>> Bug in the mock. Works with qtmir.
> This is really why I think we need to move all those models to unity8, put unity8 in control of them and mock things at a lower level. All our tests regarding window management are just useless right now... they can perfectly pass while the real thing can be broken really badly.

Window management policy things like "if currently focused window gets
minimized, focus the most recently focused window that is not hidden or
minimized" will now belong to a lower level (miral) and as such they get
mock implementations in our tests.

Thus qml tests that strictly check window management policy will indeed
get redundant. Test of this nature now belong to miral's own test suite.

Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

> On 21/11/2016 10:08, Michael Zanetti wrote:
> >> On 18/11/2016 14:16, Michael Zanetti wrote:
> >>> Review: Needs Fixing
> >>>
> >>> Not yet sure if just an issue in the mocks or not, but this breaks:
> >>>
> >>> - open an app
> >>> - click the minimize button in the window decoration
> >>> - click the app again in the launcher to restore it
> >>> - now click the minimize button again
> >>> => button doesn't work any more
> >> Bug in the mock. Works with qtmir.
> > This is really why I think we need to move all those models to unity8, put
> unity8 in control of them and mock things at a lower level. All our tests
> regarding window management are just useless right now... they can perfectly
> pass while the real thing can be broken really badly.
>
>
> Window management policy things like "if currently focused window gets
> minimized, focus the most recently focused window that is not hidden or
> minimized" will now belong to a lower level (miral) and as such they get
> mock implementations in our tests.
>
> Thus qml tests that strictly check window management policy will indeed
> get redundant. Test of this nature now belong to miral's own test suite.

Right, but we would still need tests that make sure that the QML part works together with the model as we expect it. And right now we don't have such tests... Anyhow, this is a different discussion than this particular merge proposal. It just once again popped up here. Also this isn't a new problem, we already had this since forever, but as long as we only had the one ApplicationManager model which would not even do much except moving things when unity8 said so, it was still easy enough to keep the mock close enough to the real thing. Now this seems to grow out of a manageable size.

Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal
Download full text (3.3 KiB)

> > On 18/11/2016 12:29, Michael Zanetti wrote:
> > > * I think we should not give up on the differntiation between claimFocus()
> > and requestFocus(). One of them says the stage wants to actually focus
> > something*now* while the other indicates that the app requested focus on
> its
> > own (or perhaps u-a-l did). IMO claimFocus() should not be dropped and still
> > do the raisId() call on the model. requestfocus() instead should end up in
> the
> > shell, and if the shell is ok with doing so, it should call claimFocus()
> > itself.
> >
> > What you are explaining effectively is that: leave things as they are
> > currently with regards to focus. Which means focus lives in unity8 and
> > miral has no say over it.
> >
> > The whole point of this miral effort is exactly to move such window
> > management decisions down to Mir, as dictated by our high-profile
> > stakeholder.
>
> There's a bunch of other stakeholders though that want to have it pixel
> perfect when it comes to animations and transitions. I am not saying miral
> should not have any say, but miral should send a requestFocus() to the shell
> and the shell will do it.
> What I'm saying is that miral can tell unity to change the focus, and unity
> will follow that (unless it's in the middle of a transition or something).
> What you're proposing is that miral has all the say on when to change focus,
> and unity8 cannot do any course correction if the moment is bad.
>
> > Focus is a central piece of window management and if miral is to do
> > anything useful it has to have a say in it. And we cannot have two
> > entities making decisions on focus (unity8 and miral) as it will
> > inevitably be racy and conflictive.
>
> which is exactly what we have now... unity8 thinks it is in charge, but miral
> can just jump in and trash it. I'm really just trying to avoid that.
>
> >
> > As for the origin of the focus change request (shell vs. application),
> > it doesn't matter from miral's standpoint. It will comply to either as
> > long the change is valid and makes sense. Eg.: it should never allow a
> > window blocked by a child modal dialog to be focused. So it's mostly
> > sanity checking. I don't see miral ignoring requests on a whim. :)
> >
> > Besides, having two separate code paths would make unity8 code more
> > complex. Eg: Having both code that sets surface state and code that
> > responds to surface state changes. "If surface state change was done in
> > response my your own set(), do nothing, else, ponder and respond."
>
> And I'm also not talking about 2 separate code paths. I'm saying the one code
> path should go through unity8 and not just manipulate the model at random.
>
> Therefore I think only unity8 should manipulate the model, taking miral as
> consultant on how to manipulate it. This current approach is really the one
> that creates multiple entities fighting over the state of the model.

This is a valid concern. The model must only have one owner. I think it safest that Unity8 has total ownership of the model and uses MirAL's recommendations only when it can.

MirAL has no concept of intermediary-states (like transitions/animations cause), so cannot advise Unit...

Read more...

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

Thanks a lot for the activate() thing. Makes me feel much more comfy with the whole thing.

One minor thing (see inline comments) which I missed last time.

I'll give it another test with the latest changes, but it looks like we're getting close to an approval now.

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 23/11/2016 09:24, Michael Zanetti wrote:
>> readonly property Item clientAreaItem: applicationWindow
>> >
>> >+ readonly property real contentX: applicationWindow.x
>> >+ readonly property real contentY: applicationWindow.y
> afaict, you're only using that for knowing how much to add/remove for the decoration height. There is already a property "decorationHeight" you can use so this would be not needed, esp as applicationWindow.y will always be 0 at this point too.
>
Actually I can just use the existing clientAreaItem property right above
them. Fixed.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 23/11/2016 09:24, Michael Zanetti wrote:
> Qt.point(appDelegate.requestedX + decoratedWindow.decorationHeight, appDelegate.requestedY)
>
> should be enough

I would rather not assume that decorations only affect the Y coordinate.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2715
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2558/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/3369/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3397
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3248/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3248/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3248/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3248/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3248
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3248/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3248
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3248/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3248/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3248/console
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3248/console

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2558/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

New instances of the same app do not cascade:

0. make tryShell
1. Launch dialer
2. Click the "+" button to launch a second instance
3. The new window doesn't cascade

review: Needs Fixing
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

If you add a trust prompt to a window and launch a second instance of the same app, the newly created window is not focused

review: Needs Fixing
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

Windows are not restored properly:

1. Maximize dash
2. Minimize it
3. Click the bfb icon
4. The dash window is restored to "normal" size, not to the maximized from step 1.

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 29/11/2016 15:35, Lukáš Tinkl wrote:
> Review: Needs Fixing
>
> New instances of the same app do not cascade:
>
> 0. make tryShell
> 1. Launch dialer
> 2. Click the "+" button to launch a second instance
> 3. The new window doesn't cascade

Same happens in trunk

Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

Double click to maximize breaks:

1. Double click the dash decoration to maximize the window
2. Drag it down from the panel to restore it
3. Double click again to maximize -> no longer works

review: Needs Fixing
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

In tablet mode, if you put a fullscreen app into side stage (like camera), the main app (dash usually) has its decoration cut at the top.

review: Needs Fixing
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

> In tablet mode, if you put a fullscreen app into side stage (like camera), the
> main app (dash usually) has its decoration cut at the top.

This happens in trunk too

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 29/11/2016 15:37, Lukáš Tinkl wrote:
> Review: Needs Fixing
>
> If you add a trust prompt to a window and launch a second instance of the same app, the newly created window is not focused

Fixed. Bug in the Unity.Application mock.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 29/11/2016 15:39, Lukáš Tinkl wrote:
> Review: Needs Fixing
>
> Windows are not restored properly:
>
> 1. Maximize dash
> 2. Minimize it
> 3. Click the bfb icon
> 4. The dash window is restored to "normal" size, not to the maximized from step 1.

That's due to the simplicity of the Unity.Application mock. It doesn't
have a full blown implementation of the window management bits/policy
that have been now moved to a lower level, behind
Unity.Application/qtmir API. This use case works with the real
Unity.Application/qtmir.

Unfortunately this means that right now we can no longer test everything
window management related in our qmltests. For some things untiy8 just
sits back and expects to get the correct changes to the model for free,
which it will then respond to by updating the qml items and animating
the qml scene (the view).

To be more specific, in response to the click on step 3 unity8 just
calls MirSurface->activate(). qtmir/miral will take care of noticing
that this surface is minimized and will restore it to its previous state
before finally focusing and raising it.

Revision history for this message
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal

On 29/11/2016 15:50, Lukáš Tinkl wrote:
> Review: Needs Fixing
>
> Double click to maximize breaks:
>
> 1. Double click the dash decoration to maximize the window
> 2. Drag it down from the panel to restore it
> 3. Double click again to maximize -> no longer works

Fixed.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

Doesn't compile any more (or run), need this patch: https://pastebin.kde.org/pipwxeqjp

review: Needs Fixing
lp:~dandrader/unity8/miral updated
2726. By Launchpad Translations on behalf of unity-team

Launchpad automatic translations update.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 30/11/2016 18:55, Lukáš Tinkl wrote:
> Review: Needs Fixing
>
> Doesn't compile any more (or run), need this patch: https://pastebin.kde.org/pipwxeqjp

Ooops! Fixed, thanks.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2729
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2625/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3457
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1981
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1981
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3485
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3332
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3332/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3332
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3332/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3332
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3332/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3332
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3332/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3332
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3332/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3332
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3332/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2625/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2730
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2626/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3458
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1982
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1982
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3486
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3333
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3333/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3333
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3333/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3333
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3333/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3333
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3333/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3333
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3333/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3333
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3333/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2626/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2733
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2634/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3466
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1989
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1989
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3494
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3341
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3341/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3341
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3341/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3341
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3341/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3341
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3341/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3341
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3341/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3341
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3341/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2634/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2734
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2637/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3469
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1991
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1991
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3497
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3344
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3344/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3344
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3344/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3344
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3344/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3344
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3344/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3344
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3344/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3344
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3344/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2637/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2736
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2638/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3470
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1992
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1992
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3498
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3345
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3345/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3345
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3345/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3345
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3345/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3345
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3345/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3345
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3345/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3345
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3345/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2638/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Emanuele Antonio Faraone (emanueleant03) :
review: Approve
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2737
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2641/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3473
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1995
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1995
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3501
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3348
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3348/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3348
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3348/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3348
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3348/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3348
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3348/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3348
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3348/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3348
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3348/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2641/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2738
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2643/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3475
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1997
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1997
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3503
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3350/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3350
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3350/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2643/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2742
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2646/
Executed test runs:

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2646/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2742
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2645/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3477
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1999
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1999
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3505
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3352
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3352/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3352
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3352/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3352
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3352/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3352
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3352/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3352
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3352/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3352
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3352/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2645/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2743
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2648/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3481
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/2001
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/2001
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3509
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3356
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3356/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3356
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3356/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3356
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3356/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3356
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3356/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3356
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3356/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3356
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3356/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2648/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2744
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2651/
Executed test runs:

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2651/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:2744
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2650/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3483
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/2003
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/2003
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3511
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3358
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3358/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3358
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3358/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3358
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3358/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3358
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3358/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3358
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3358/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3358
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3358/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2650/rebuild

review: Approve (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

Looking good except this hard to track focus related issue:

https://imgur.com/a/ZcR0A

It can happen when an application is taking a long time to start up, and you close it before it does. At that point, the focus chain is broken and the user is left with no app/window focused at all (as can be seen from the empty window title in the top panel)

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> Looking good except this hard to track focus related issue:
>
> https://imgur.com/a/ZcR0A
>
> It can happen when an application is taking a long time to start up, and you
> close it before it does. At that point, the focus chain is broken and the user
> is left with no app/window focused at all (as can be seen from the empty
> window title in the top panel)

Fixed, thanks.

Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

In QString Window::toString() const:

I think what you're really after is this: http://doc.qt.io/qt-5/qdebug.html#writing-custom-types-to-a-stream

review: Needs Information
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 06/12/2016 12:57, Lukáš Tinkl wrote:
> Review: Needs Information
>
> In QString Window::toString() const:
>
> I think what you're really after is this: http://doc.qt.io/qt-5/qdebug.html#writing-custom-types-to-a-stream

Already have it. It uses toString() in its implementation.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2746
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2659/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3493
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/2010
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/2010
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3521
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3368
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3368/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3368
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3368/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3368
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3368/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3368
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3368/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3368
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3368/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3368
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3368/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2659/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:2746
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2663/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/3497/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3525
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3372
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3372/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3372
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3372/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3372
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3372/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3372
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3372/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3372
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3372/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3372/console

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2663/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:2746
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2665/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3499
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/2015
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/2015
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3527
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3374
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3374/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3374
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3374/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3374
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3374/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3374
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3374/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3374
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3374/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3374
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3374/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2665/rebuild

review: Approve (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

* Did you perform an exploratory manual test run of the code change and any related functionality?

Yes

* Did CI run pass? If not, please explain why.

Yes (they will again once the silo gets rebuilt)

review: Approve
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
lp:~dandrader/unity8/miral updated
2727. By Lukáš Tinkl

Fix the Super key not invoking the dash scope home (LP: #1607427)

Approved by: Daniel d'Andrada, Unity8 CI Bot

2728. By Albert Astals Cid

Add the Wsuggest-override flag to gcc

While at it mark system includes as such so we don't get warnings we can not fix

Approved by: Michael Zanetti, Unity8 CI Bot

2729. By Albert Astals Cid

Add support for compiler sanitizers via ECM

2730. By Albert Astals Cid

Use timeStep as delay time

Passing iterations / speed didn't make much sense since that parameter is a delay in milliseconds and the default parameters would give a value of 5 / units.gu(10) that is smaller than 1 millisecond.

Qt 5.7 calculation for velocity was very unhappy if we moved things so fast in less than 1ms and ignored the movements, so this also makes tests pass on Qt 5.7 (LP: #1642919)

Approved by: Josh Arenson, Unity8 CI Bot

2731. By Michael Zanetti

Add the ApplicationDrawer

Approved by: Lukáš Tinkl, Unity8 CI Bot

2732. By Michael Zanetti

tune right edge push

make it less intrusive when accidentally hitting the edge with the mouse
tweak visuals for the mouse case (LP: #1646094)

Approved by: Unity8 CI Bot

2733. By Michael Zanetti

improve close button visiblity when hovering with the mouse

Approved by: Albert Astals Cid, Unity8 CI Bot

2734. By Albert Astals Cid

Bring back fix for 1517830

Now with autotest \o/ (LP: #1517830)

Approved by: Andrea Cimitan, Unity8 CI Bot

2735. By Daniel d'Andrada

Fix "make tryApplicationWindow"

No surface was showing up on the screen
Also remove outdated button (feature is no longer there)

Approved by: Albert Astals Cid, Unity8 CI Bot

2736. By Albert Astals Cid

Fix compile warnings in mocks

Approved by: Daniel d'Andrada, Unity8 CI Bot

2737. By Josh Arenson

Enable the greeter to remember which session the user last logged into

This also fixes a small issue with how the default session was handled. (LP: #1631365)

Approved by: Albert Astals Cid, Unity8 CI Bot

2738. By Daniel d'Andrada

Take save/restore functions out of WindowResizeArea

They've no relationship with resizing whatsoever.

Approved by: Lukáš Tinkl, Unity8 CI Bot

2739. By Michael Zanetti

Update virtual touchpad visuals and add a tutorial. (LP: #1585220)

Approved by: Lukáš Tinkl, Unity8 CI Bot

2740. By Albert Astals Cid

Do not hide panel when launching an application if the mouse is on the panel

Need Functions.itemUnderMouse because MouseArea.containsMouse returns true when tapping (i.e. no mouse used) on it.

Unfortunately the QML testlib do not set the proper value when issueing a mouseMove so i can't add a test that proofs it works, i'll try to propose something upstream and then add the test at a later MR (LP: #1591311)

Approved by: Lukáš Tinkl, Unity8 CI Bot

2741. By Pete Woods

MenuItemFactory: Add subtitle support to SwitchItem widget

Approved by: Marco Trevisan (Treviño), Michał Sawicz, Unity8 CI Bot

2742. By CI Train Bot Account

Releasing 8.15+17.04.20161207.1-0ubuntu1

2743. By Daniel d'Andrada

Let the model deal with some window management decisions

eg: which window to focus, whether to change surface state

unit8 requests and reacts to changes in the model instead of applying them

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2016-10-24 11:34:08 +0000
+++ CMakeLists.txt 2016-12-12 16:49:02 +0000
@@ -40,6 +40,19 @@
40 ENABLE_COVERAGE_REPORT(TARGETS ${SHELL_APP} FILTER /usr/include ${CMAKE_SOURCE_DIR}/tests/* ${CMAKE_BINARY_DIR}/*)40 ENABLE_COVERAGE_REPORT(TARGETS ${SHELL_APP} FILTER /usr/include ${CMAKE_SOURCE_DIR}/tests/* ${CMAKE_BINARY_DIR}/*)
41endif()41endif()
4242
43find_package (ECM 1.7.0 QUIET NO_MODULE)
44if (ECM_FOUND)
45 # Provides us with -DECM_ENABLE_SANITIZERS='X'
46 # Where X can be address, thread, memory, leak, undefined
47 include("${ECM_MODULE_DIR}/ECMEnableSanitizers.cmake")
48endif()
49
50if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
51 if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0.0")
52 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override" )
53 endif()
54endif()
55
43# Make sure we have all the needed symbols56# Make sure we have all the needed symbols
44set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,defs")57set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,defs")
45set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,defs")58set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,defs")
@@ -57,7 +70,7 @@
57find_package(Qt5Concurrent 5.4 REQUIRED)70find_package(Qt5Concurrent 5.4 REQUIRED)
58find_package(Qt5Sql 5.4 REQUIRED)71find_package(Qt5Sql 5.4 REQUIRED)
5972
60pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=22)73pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=23)
61pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)74pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
62pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)75pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
63pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)76pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
6477
=== modified file 'data/com.canonical.Unity8.gschema.xml'
--- data/com.canonical.Unity8.gschema.xml 2016-11-16 05:54:50 +0000
+++ data/com.canonical.Unity8.gschema.xml 2016-12-12 16:49:02 +0000
@@ -12,7 +12,7 @@
12 <description>The usage mode chosen will affect the Window Management behaviour.</description>12 <description>The usage mode chosen will affect the Window Management behaviour.</description>
13 </key>13 </key>
14 <key type="y" name="edge-barrier-sensitivity">14 <key type="y" name="edge-barrier-sensitivity">
15 <default>35</default>15 <default>50</default>
16 <range min="1" max="100"/>16 <range min="1" max="100"/>
17 <summary>Sensitivity of screen edge barriers for the mouse pointer.</summary>17 <summary>Sensitivity of screen edge barriers for the mouse pointer.</summary>
18 <description>Some UI actions like revealing the launcher or the applications spread are triggered by pushing the mouse pointer against a screen edge. This key defines how much you have to push in order to trigger the associated action.</description>18 <description>Some UI actions like revealing the launcher or the applications spread are triggered by pushing the mouse pointer against a screen edge. This key defines how much you have to push in order to trigger the associated action.</description>
@@ -23,7 +23,7 @@
23 <description>How much you have to push (in grid units)the mouse against an edge barrier when sensibility is 100.</description>23 <description>How much you have to push (in grid units)the mouse against an edge barrier when sensibility is 100.</description>
24 </key>24 </key>
25 <key type="u" name="edge-barrier-max-push">25 <key type="u" name="edge-barrier-max-push">
26 <default>60</default>26 <default>120</default>
27 <summary>Maximum push needed to overcome edge barrier</summary>27 <summary>Maximum push needed to overcome edge barrier</summary>
28 <description>How much you have to push (in grid units) the mouse against an edge barrier when sensibility is 1.</description>28 <description>How much you have to push (in grid units) the mouse against an edge barrier when sensibility is 1.</description>
29 </key>29 </key>
3030
=== modified file 'debian/changelog'
--- debian/changelog 2016-11-29 09:43:33 +0000
+++ debian/changelog 2016-12-12 16:49:02 +0000
@@ -1,3 +1,36 @@
1unity8 (8.15+17.04.20161207.1-0ubuntu1) zesty; urgency=medium
2
3 [ Albert Astals Cid ]
4 * Add the Wsuggest-override flag to gcc
5 * Add support for compiler sanitizers via ECM
6 * Use timeStep as delay time (LP: #1642919)
7 * Bring back fix for 1517830 (LP: #1517830)
8 * Fix compile warnings in mocks
9 * Do not hide panel when launching an application if the mouse is on
10 the panel (LP: #1591311)
11
12 [ Daniel d'Andrada ]
13 * Fix "make tryApplicationWindow"
14 * Take save/restore functions out of WindowResizeArea
15
16 [ Josh Arenson ]
17 * Enable the greeter to remember which session the user last logged
18 into (LP: #1631365)
19
20 [ Lukáš Tinkl ]
21 * Fix the Super key not invoking the dash scope home (LP: #1607427)
22
23 [ Michael Zanetti ]
24 * Add the ApplicationDrawer
25 * tune right edge push (LP: #1646094)
26 * improve close button visiblity when hovering with the mouse
27 * Update virtual touchpad visuals and add a tutorial. (LP: #1585220)
28
29 [ Pete Woods ]
30 * MenuItemFactory: Add subtitle support to SwitchItem widget
31
32 -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 07 Dec 2016 13:49:24 +0000
33
1unity8 (8.15+17.04.20161129-0ubuntu1) zesty; urgency=medium34unity8 (8.15+17.04.20161129-0ubuntu1) zesty; urgency=medium
235
3 [ Albert Astals Cid ]36 [ Albert Astals Cid ]
437
=== modified file 'debian/control'
--- debian/control 2016-11-29 09:40:16 +0000
+++ debian/control 2016-12-12 16:49:02 +0000
@@ -38,7 +38,7 @@
38 libubuntugestures5-private-dev (>= 1.3.2030),38 libubuntugestures5-private-dev (>= 1.3.2030),
39 libudev-dev,39 libudev-dev,
40 libudm-common-dev,40 libudm-common-dev,
41 libunity-api-dev (>= 7.120),41 libunity-api-dev (>= 8.0),
42 libusermetricsoutput1-dev,42 libusermetricsoutput1-dev,
43# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop43# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
44 libx11-dev[!arm64 !armhf],44 libx11-dev[!arm64 !armhf],
@@ -49,6 +49,7 @@
49 python3-all:any,49 python3-all:any,
50 python3-setuptools,50 python3-setuptools,
51 qml-module-qt-labs-folderlistmodel,51 qml-module-qt-labs-folderlistmodel,
52 qml-module-qt-labs-settings,
52 qml-module-qtqml-statemachine,53 qml-module-qtqml-statemachine,
53 qml-module-qtmultimedia (>= 5.4.1-1ubuntu19~overlay2),54 qml-module-qtmultimedia (>= 5.4.1-1ubuntu19~overlay2),
54 qml-module-qtquick-layouts,55 qml-module-qtquick-layouts,
@@ -122,6 +123,7 @@
122 qmenumodel-qml (>= 0.2.10),123 qmenumodel-qml (>= 0.2.10),
123 qml-module-biometryd,124 qml-module-biometryd,
124 qml-module-qt-labs-folderlistmodel,125 qml-module-qt-labs-folderlistmodel,
126 qml-module-qt-labs-settings,
125 qml-module-qtqml-statemachine,127 qml-module-qtqml-statemachine,
126 qml-module-qtquick-xmllistmodel,128 qml-module-qtquick-xmllistmodel,
127 qml-module-qtsysteminfo,129 qml-module-qtsysteminfo,
@@ -160,7 +162,7 @@
160 qttranslations5-l10n,162 qttranslations5-l10n,
161 ubuntu-thumbnailer-impl-0,163 ubuntu-thumbnailer-impl-0,
162 ubuntu-wallpapers,164 ubuntu-wallpapers,
163 unity-application-impl-22,165 unity-application-impl-23,
164 unity-notifications-impl-3,166 unity-notifications-impl-3,
165 unity-plugin-scopes | unity-scopes-impl,167 unity-plugin-scopes | unity-scopes-impl,
166 unity-scopes-impl-12,168 unity-scopes-impl-12,
@@ -206,7 +208,7 @@
206Depends: ${misc:Depends},208Depends: ${misc:Depends},
207 ${shlibs:Depends},209 ${shlibs:Depends},
208Provides: unity-application-impl,210Provides: unity-application-impl,
209 unity-application-impl-22,211 unity-application-impl-23,
210Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)212Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
211Description: Fake environment for running Unity 8 shell213Description: Fake environment for running Unity 8 shell
212 Provides fake implementations of some QML modules used by Unity 8 shell214 Provides fake implementations of some QML modules used by Unity 8 shell
213215
=== modified file 'plugins/Greeter/Unity/Launcher/CMakeLists.txt'
--- plugins/Greeter/Unity/Launcher/CMakeLists.txt 2016-10-28 12:08:59 +0000
+++ plugins/Greeter/Unity/Launcher/CMakeLists.txt 2016-12-12 16:49:02 +0000
@@ -1,4 +1,4 @@
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=10)1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
33
4add_definitions(-DSM_BUSNAME=systemBus)4add_definitions(-DSM_BUSNAME=systemBus)
55
=== modified file 'plugins/Greeter/Unity/Launcher/launcheritem.cpp'
--- plugins/Greeter/Unity/Launcher/launcheritem.cpp 2016-05-10 16:23:34 +0000
+++ plugins/Greeter/Unity/Launcher/launcheritem.cpp 2016-12-12 16:49:02 +0000
@@ -76,6 +76,19 @@
76 }76 }
77}77}
7878
79QStringList LauncherItem::keywords() const
80{
81 return m_keywords;
82}
83
84void LauncherItem::setKeywords(const QStringList &keywords)
85{
86 if (m_keywords != keywords) {
87 m_keywords = keywords;
88 Q_EMIT keywordsChanged(keywords);
89 }
90}
91
79bool LauncherItem::pinned() const92bool LauncherItem::pinned() const
80{93{
81 return m_pinned;94 return m_pinned;
8295
=== modified file 'plugins/Greeter/Unity/Launcher/launcheritem.h'
--- plugins/Greeter/Unity/Launcher/launcheritem.h 2016-05-10 15:51:00 +0000
+++ plugins/Greeter/Unity/Launcher/launcheritem.h 2016-12-12 16:49:02 +0000
@@ -34,6 +34,7 @@
34 QString appId() const override;34 QString appId() const override;
35 QString name() const override;35 QString name() const override;
36 QString icon() const override;36 QString icon() const override;
37 QStringList keywords() const override;
37 bool pinned() const override;38 bool pinned() const override;
38 bool running() const override;39 bool running() const override;
39 bool recent() const override;40 bool recent() const override;
@@ -49,6 +50,7 @@
49private:50private:
50 void setName(const QString &name);51 void setName(const QString &name);
51 void setIcon(const QString &icon);52 void setIcon(const QString &icon);
53 void setKeywords(const QStringList &keywords);
52 void setPinned(bool pinned);54 void setPinned(bool pinned);
53 void setRunning(bool running);55 void setRunning(bool running);
54 void setRecent(bool recent);56 void setRecent(bool recent);
@@ -63,6 +65,7 @@
63 QString m_appId;65 QString m_appId;
64 QString m_name;66 QString m_name;
65 QString m_icon;67 QString m_icon;
68 QStringList m_keywords;
66 bool m_pinned;69 bool m_pinned;
67 bool m_running;70 bool m_running;
68 bool m_recent;71 bool m_recent;
6972
=== modified file 'plugins/LightDM/FullLightDM/CMakeLists.txt'
--- plugins/LightDM/FullLightDM/CMakeLists.txt 2016-07-08 15:44:53 +0000
+++ plugins/LightDM/FullLightDM/CMakeLists.txt 2016-12-12 16:49:02 +0000
@@ -6,8 +6,12 @@
66
7include_directories(7include_directories(
8 ../8 ../
9 ${CMAKE_CURRENT_BINARY_DIR}
10 )
11
12include_directories(
13 SYSTEM
9 ${LIBLIGHTDM_INCLUDE_DIRS}14 ${LIBLIGHTDM_INCLUDE_DIRS}
10 ${CMAKE_CURRENT_BINARY_DIR}
11 )15 )
1216
13foreach(source_file ${QMLPLUGIN_SRC})17foreach(source_file ${QMLPLUGIN_SRC})
1418
=== modified file 'plugins/Unity/Indicators/CMakeLists.txt'
--- plugins/Unity/Indicators/CMakeLists.txt 2016-06-02 09:32:33 +0000
+++ plugins/Unity/Indicators/CMakeLists.txt 2016-12-12 16:49:02 +0000
@@ -11,6 +11,9 @@
11include_directories(11include_directories(
12 SYSTEM12 SYSTEM
13 ${GLIB_INCLUDE_DIRS}13 ${GLIB_INCLUDE_DIRS}
14)
15include_directories(
16 SYSTEM
14 ${GIO_INCLUDE_DIRS}17 ${GIO_INCLUDE_DIRS}
15 ${QMENUMODEL_INCLUDE_DIRS}18 ${QMENUMODEL_INCLUDE_DIRS}
16)19)
1720
=== modified file 'plugins/Unity/Launcher/CMakeLists.txt'
--- plugins/Unity/Launcher/CMakeLists.txt 2016-10-28 12:08:59 +0000
+++ plugins/Unity/Launcher/CMakeLists.txt 2016-12-12 16:49:02 +0000
@@ -1,4 +1,4 @@
1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=10)1pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)2pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
33
4add_definitions(-DSM_BUSNAME=systemBus)4add_definitions(-DSM_BUSNAME=systemBus)
@@ -25,6 +25,8 @@
25 dbusinterface.cpp25 dbusinterface.cpp
26 gsettings.cpp26 gsettings.cpp
27 asadapter.cpp27 asadapter.cpp
28 appdrawermodel.cpp
29 ualwrapper.cpp
28 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp30 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
29 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h31 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
30 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h32 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
@@ -32,6 +34,7 @@
32 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h34 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
33 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h35 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
34 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h36 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
37 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/AppDrawerModelInterface.h
35 )38 )
3639
37add_library(UnityLauncher-qml MODULE40add_library(UnityLauncher-qml MODULE
3841
=== added file 'plugins/Unity/Launcher/appdrawermodel.cpp'
--- plugins/Unity/Launcher/appdrawermodel.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Unity/Launcher/appdrawermodel.cpp 2016-12-12 16:49:02 +0000
@@ -0,0 +1,62 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "appdrawermodel.h"
18#include "ualwrapper.h"
19
20#include <QDebug>
21#include <QDateTime>
22
23AppDrawerModel::AppDrawerModel(QObject *parent):
24 AppDrawerModelInterface(parent)
25{
26 Q_FOREACH (const QString &appId, UalWrapper::installedApps()) {
27 UalWrapper::AppInfo info = UalWrapper::getApplicationInfo(appId);
28 if (!info.valid) {
29 qWarning() << "Failed to get app info for app" << appId;
30 continue;
31 }
32 m_list.append(new LauncherItem(appId, info.name, info.icon, this));
33 m_list.last()->setKeywords(info.keywords);
34 }
35 qsrand(QDateTime::currentMSecsSinceEpoch() / 100);
36}
37
38int AppDrawerModel::rowCount(const QModelIndex &parent) const
39{
40 Q_UNUSED(parent)
41 return m_list.count();
42}
43
44QVariant AppDrawerModel::data(const QModelIndex &index, int role) const
45{
46 switch (role) {
47 case RoleAppId:
48 return m_list.at(index.row())->appId();
49 case RoleName:
50 return m_list.at(index.row())->name();
51 case RoleIcon:
52 return m_list.at(index.row())->icon();
53 case RoleKeywords:
54 return m_list.at(index.row())->keywords();
55 case RoleUsage:
56 // FIXME: u-a-l needs to provide API for usage stats.
57 // don't forget to drop the qsrand() call in the ctor when dropping this.
58 return qrand();
59 }
60
61 return QVariant();
62}
063
=== added file 'plugins/Unity/Launcher/appdrawermodel.h'
--- plugins/Unity/Launcher/appdrawermodel.h 1970-01-01 00:00:00 +0000
+++ plugins/Unity/Launcher/appdrawermodel.h 2016-12-12 16:49:02 +0000
@@ -0,0 +1,33 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17
18#include <unity/shell/launcher/AppDrawerModelInterface.h>
19
20#include "launcheritem.h"
21
22class AppDrawerModel: public AppDrawerModelInterface
23{
24 Q_OBJECT
25public:
26 AppDrawerModel(QObject* parent = nullptr);
27
28 int rowCount(const QModelIndex &parent) const override;
29 QVariant data(const QModelIndex &index, int role) const override;
30
31private:
32 QList<LauncherItem*> m_list;
33};
034
=== modified file 'plugins/Unity/Launcher/launcheritem.cpp'
--- plugins/Unity/Launcher/launcheritem.cpp 2016-10-28 11:54:16 +0000
+++ plugins/Unity/Launcher/launcheritem.cpp 2016-12-12 16:49:02 +0000
@@ -90,6 +90,19 @@
90 }90 }
91}91}
9292
93QStringList LauncherItem::keywords() const
94{
95 return m_keywords;
96}
97
98void LauncherItem::setKeywords(const QStringList &keywords)
99{
100 if (m_keywords != keywords) {
101 m_keywords = keywords;
102 Q_EMIT keywordsChanged(keywords);
103 }
104}
105
93bool LauncherItem::pinned() const106bool LauncherItem::pinned() const
94{107{
95 return m_pinned;108 return m_pinned;
96109
=== modified file 'plugins/Unity/Launcher/launcheritem.h'
--- plugins/Unity/Launcher/launcheritem.h 2016-05-10 15:51:00 +0000
+++ plugins/Unity/Launcher/launcheritem.h 2016-12-12 16:49:02 +0000
@@ -37,6 +37,7 @@
37 QString appId() const override;37 QString appId() const override;
38 QString name() const override;38 QString name() const override;
39 QString icon() const override;39 QString icon() const override;
40 QStringList keywords() const override;
40 bool pinned() const override;41 bool pinned() const override;
41 bool running() const override;42 bool running() const override;
42 bool recent() const override;43 bool recent() const override;
@@ -52,6 +53,7 @@
52private:53private:
53 void setName(const QString &name);54 void setName(const QString &name);
54 void setIcon(const QString &icon);55 void setIcon(const QString &icon);
56 void setKeywords(const QStringList &keywords);
55 void setPinned(bool pinned);57 void setPinned(bool pinned);
56 void setRunning(bool running);58 void setRunning(bool running);
57 void setRecent(bool recent);59 void setRecent(bool recent);
@@ -66,6 +68,7 @@
66 QString m_appId;68 QString m_appId;
67 QString m_name;69 QString m_name;
68 QString m_icon;70 QString m_icon;
71 QStringList m_keywords;
69 bool m_pinned;72 bool m_pinned;
70 bool m_running;73 bool m_running;
71 bool m_recent;74 bool m_recent;
@@ -79,6 +82,7 @@
79 QuickListEntry m_quitAction;82 QuickListEntry m_quitAction;
8083
81 friend class LauncherModel;84 friend class LauncherModel;
85 friend class AppDrawerModel;
82};86};
8387
84#endif // LAUNCHERITEM_H88#endif // LAUNCHERITEM_H
8589
=== modified file 'plugins/Unity/Launcher/launchermodel.cpp'
--- plugins/Unity/Launcher/launchermodel.cpp 2016-09-23 15:10:26 +0000
+++ plugins/Unity/Launcher/launchermodel.cpp 2016-12-12 16:49:02 +0000
@@ -19,18 +19,14 @@
19#include "gsettings.h"19#include "gsettings.h"
20#include "dbusinterface.h"20#include "dbusinterface.h"
21#include "asadapter.h"21#include "asadapter.h"
22#include "ualwrapper.h"
2223
23#include <ubuntu-app-launch/appid.h>
24#include <ubuntu-app-launch/application.h>
25#include <ubuntu-app-launch/registry.h>
26#include <unity/shell/application/ApplicationInfoInterface.h>24#include <unity/shell/application/ApplicationInfoInterface.h>
27#include <unity/shell/application/MirSurfaceListInterface.h>25#include <unity/shell/application/MirSurfaceListInterface.h>
2826
29#include <QDesktopServices>27#include <QDesktopServices>
30#include <QDebug>28#include <QDebug>
3129
32namespace ual = ubuntu::app_launch;
33
34using namespace unity::shell::application;30using namespace unity::shell::application;
3531
36LauncherModel::LauncherModel(QObject *parent):32LauncherModel::LauncherModel(QObject *parent):
@@ -38,8 +34,7 @@
38 m_settings(new GSettings(this)),34 m_settings(new GSettings(this)),
39 m_dbusIface(new DBusInterface(this)),35 m_dbusIface(new DBusInterface(this)),
40 m_asAdapter(new ASAdapter()),36 m_asAdapter(new ASAdapter()),
41 m_appManager(nullptr),37 m_appManager(nullptr)
42 m_ualRegistry(std::make_shared<ual::Registry>())
43{38{
44 connect(m_dbusIface, &DBusInterface::countChanged, this, &LauncherModel::countChanged);39 connect(m_dbusIface, &DBusInterface::countChanged, this, &LauncherModel::countChanged);
45 connect(m_dbusIface, &DBusInterface::countVisibleChanged, this, &LauncherModel::countVisibleChanged);40 connect(m_dbusIface, &DBusInterface::countVisibleChanged, this, &LauncherModel::countVisibleChanged);
@@ -159,7 +154,7 @@
159 index = m_list.count();154 index = m_list.count();
160 }155 }
161156
162 auto appInfo = getApplicationInfo(appId);157 UalWrapper::AppInfo appInfo = UalWrapper::getApplicationInfo(appId);
163 if (!appInfo.valid) {158 if (!appInfo.valid) {
164 qWarning() << "Can't pin application, appId not found:" << appId;159 qWarning() << "Can't pin application, appId not found:" << appId;
165 return;160 return;
@@ -335,32 +330,6 @@
335 return -1;330 return -1;
336}331}
337332
338LauncherModel::AppInfo LauncherModel::getApplicationInfo(const QString &appId)
339{
340 AppInfo info;
341
342 ual::AppID ualAppId = ual::AppID::find(m_ualRegistry, appId.toStdString());
343 if (ualAppId.empty()) {
344 return info;
345 }
346
347 std::shared_ptr<ual::Application> ualApp;
348 try
349 {
350 ualApp = ual::Application::create(ualAppId, m_ualRegistry);
351 }
352 catch (std::runtime_error &e)
353 {
354 qWarning() << "Couldn't find application info for" << appId << "-" << e.what();
355 return info;
356 }
357
358 info.valid = true;
359 info.name = QString::fromStdString(ualApp->info()->name());
360 info.icon = QString::fromStdString(ualApp->info()->iconPath());
361 return info;
362}
363
364void LauncherModel::progressChanged(const QString &appId, int progress)333void LauncherModel::progressChanged(const QString &appId, int progress)
365{334{
366 const int idx = findApplication(appId);335 const int idx = findApplication(appId);
@@ -408,7 +377,7 @@
408 }377 }
409 } else {378 } else {
410 // Need to create a new LauncherItem and show the highlight379 // Need to create a new LauncherItem and show the highlight
411 auto appInfo = getApplicationInfo(appId);380 UalWrapper::AppInfo appInfo = UalWrapper::getApplicationInfo(appId);
412 if (countVisible && appInfo.valid) {381 if (countVisible && appInfo.valid) {
413 LauncherItem *item = new LauncherItem(appId,382 LauncherItem *item = new LauncherItem(appId,
414 appInfo.name,383 appInfo.name,
@@ -428,7 +397,7 @@
428 // First walk through all the existing items and see if we need to remove something397 // First walk through all the existing items and see if we need to remove something
429 QList<LauncherItem*> toBeRemoved;398 QList<LauncherItem*> toBeRemoved;
430 Q_FOREACH (LauncherItem* item, m_list) {399 Q_FOREACH (LauncherItem* item, m_list) {
431 auto appInfo = getApplicationInfo(item->appId());400 UalWrapper::AppInfo appInfo = UalWrapper::getApplicationInfo(item->appId());
432 if (!appInfo.valid) {401 if (!appInfo.valid) {
433 // Application no longer available => drop it!402 // Application no longer available => drop it!
434 toBeRemoved << item;403 toBeRemoved << item;
@@ -480,7 +449,7 @@
480 if (itemIndex == -1) {449 if (itemIndex == -1) {
481 // Need to add it. Just add it into the addedIndex to keep same ordering as the list450 // Need to add it. Just add it into the addedIndex to keep same ordering as the list
482 // in the settings.451 // in the settings.
483 auto appInfo = getApplicationInfo(entry);452 UalWrapper::AppInfo appInfo = UalWrapper::getApplicationInfo(entry);
484 if (!appInfo.valid) {453 if (!appInfo.valid) {
485 continue;454 continue;
486 }455 }
487456
=== modified file 'plugins/Unity/Launcher/launchermodel.h'
--- plugins/Unity/Launcher/launchermodel.h 2016-09-23 14:44:26 +0000
+++ plugins/Unity/Launcher/launchermodel.h 2016-12-12 16:49:02 +0000
@@ -27,12 +27,6 @@
27class DBusInterface;27class DBusInterface;
28class ASAdapter;28class ASAdapter;
2929
30namespace ubuntu {
31 namespace app_launch {
32 class Registry;
33 }
34}
35
36using namespace unity::shell::launcher;30using namespace unity::shell::launcher;
37using namespace unity::shell::application;31using namespace unity::shell::application;
3832
@@ -73,13 +67,6 @@
7367
74 void unpin(const QString &appId);68 void unpin(const QString &appId);
7569
76 struct AppInfo {
77 bool valid = false;
78 QString name;
79 QString icon;
80 };
81 AppInfo getApplicationInfo(const QString &appId);
82
83private Q_SLOTS:70private Q_SLOTS:
84 void countChanged(const QString &appId, int count);71 void countChanged(const QString &appId, int count);
85 void countVisibleChanged(const QString &appId, bool count);72 void countVisibleChanged(const QString &appId, bool count);
@@ -98,7 +85,6 @@
98 ASAdapter *m_asAdapter;85 ASAdapter *m_asAdapter;
9986
100 ApplicationManagerInterface *m_appManager;87 ApplicationManagerInterface *m_appManager;
101 std::shared_ptr<ubuntu::app_launch::Registry> m_ualRegistry;
10288
103 friend class LauncherModelTest;89 friend class LauncherModelTest;
104};90};
10591
=== modified file 'plugins/Unity/Launcher/plugin.cpp'
--- plugins/Unity/Launcher/plugin.cpp 2015-09-14 09:11:08 +0000
+++ plugins/Unity/Launcher/plugin.cpp 2016-12-12 16:49:02 +0000
@@ -26,7 +26,7 @@
26// local26// local
27#include "launchermodel.h"27#include "launchermodel.h"
28#include "launcheritem.h"28#include "launcheritem.h"
2929#include "appdrawermodel.h"
3030
31using namespace unity::shell::launcher;31using namespace unity::shell::launcher;
3232
@@ -46,4 +46,5 @@
46 qmlRegisterSingletonType<LauncherModel>(uri, 0, 1, "LauncherModel", modelProvider);46 qmlRegisterSingletonType<LauncherModel>(uri, 0, 1, "LauncherModel", modelProvider);
47 qmlRegisterUncreatableType<LauncherItem>(uri, 0, 1, "LauncherItem", QStringLiteral("Can't create new Launcher Items in QML. Get them from the LauncherModel."));47 qmlRegisterUncreatableType<LauncherItem>(uri, 0, 1, "LauncherItem", QStringLiteral("Can't create new Launcher Items in QML. Get them from the LauncherModel."));
48 qmlRegisterUncreatableType<QuickListModel>(uri, 0, 1, "QuickListModel", QStringLiteral("Can't create a QuickListModel in QML. Get them from the LauncherItems."));48 qmlRegisterUncreatableType<QuickListModel>(uri, 0, 1, "QuickListModel", QStringLiteral("Can't create a QuickListModel in QML. Get them from the LauncherItems."));
49 qmlRegisterType<AppDrawerModel>(uri, 0, 1, "AppDrawerModel");
49}50}
5051
=== added file 'plugins/Unity/Launcher/ualwrapper.cpp'
--- plugins/Unity/Launcher/ualwrapper.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Unity/Launcher/ualwrapper.cpp 2016-12-12 16:49:02 +0000
@@ -0,0 +1,73 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <QDebug>
18
19#include "ualwrapper.h"
20
21#include <ubuntu-app-launch/registry.h>
22using namespace ubuntu::app_launch;
23
24UalWrapper::UalWrapper(QObject *parent):
25 QObject(parent)
26{
27
28}
29
30QStringList UalWrapper::installedApps()
31{
32 QStringList appIds;
33 try {
34 for (const std::shared_ptr<Application> &app : Registry::installedApps()) {
35 if (!app->appId().package.value().empty()) {
36 appIds << QString::fromStdString(app->appId().package.value() + "_" + app->appId().appname.value());
37 } else {
38 appIds << QString::fromStdString(app->appId().appname);
39 }
40 }
41 } catch (const std::runtime_error &e) {
42 qWarning() << "ubuntu-all-launch threw an exception listing apps:" << e.what();
43 }
44
45 return appIds;
46}
47
48UalWrapper::AppInfo UalWrapper::getApplicationInfo(const QString &appId)
49{
50 AppInfo info;
51
52 try {
53 AppID ualAppId = AppID::find(appId.toStdString());
54 if (ualAppId.empty()) {
55 qWarning() << "Empty ualAppId result for" << appId;
56 return info;
57 }
58
59 std::shared_ptr<Application> ualApp;
60 ualApp = Application::create(ualAppId, Registry::getDefault());
61
62 info.name = QString::fromStdString(ualApp->info()->name());
63 info.icon = QString::fromStdString(ualApp->info()->iconPath());
64 for (const std::string &keyword : ualApp->info()->keywords().value()) {
65 info.keywords << QString::fromStdString(keyword);
66 }
67 info.valid = true;
68 } catch (const std::runtime_error &e) {
69 qWarning() << "ubuntu-app-launch threw an exception getting app info for appId:" << appId << ":" << e.what();
70 }
71
72 return info;
73}
074
=== added file 'plugins/Unity/Launcher/ualwrapper.h'
--- plugins/Unity/Launcher/ualwrapper.h 1970-01-01 00:00:00 +0000
+++ plugins/Unity/Launcher/ualwrapper.h 2016-12-12 16:49:02 +0000
@@ -0,0 +1,35 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <QObject>
18
19class UalWrapper: public QObject
20{
21 Q_OBJECT
22public:
23 struct AppInfo {
24 bool valid = false;
25 QString name;
26 QString icon;
27 QStringList keywords;
28 };
29
30 UalWrapper(QObject* parent = nullptr);
31
32 static QStringList installedApps();
33 static AppInfo getApplicationInfo(const QString &appId);
34
35};
036
=== modified file 'plugins/Utils/CMakeLists.txt'
--- plugins/Utils/CMakeLists.txt 2016-06-29 18:05:44 +0000
+++ plugins/Utils/CMakeLists.txt 2016-12-12 16:49:02 +0000
@@ -15,6 +15,10 @@
15 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h15 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
16 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h16 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
17 applicationsfiltermodel.cpp17 applicationsfiltermodel.cpp
18 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/AppDrawerModelInterface.h
19 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
20 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
21 appdrawerproxymodel.cpp
18 constants.cpp22 constants.cpp
19 WindowInputMonitor.cpp23 WindowInputMonitor.cpp
20 inputwatcher.cpp24 inputwatcher.cpp
2125
=== modified file 'plugins/Utils/ElapsedTimer.h'
--- plugins/Utils/ElapsedTimer.h 2015-04-22 10:40:54 +0000
+++ plugins/Utils/ElapsedTimer.h 2016-12-12 16:49:02 +0000
@@ -41,7 +41,7 @@
41public:41public:
42 void start() override { m_timer.start(); }42 void start() override { m_timer.start(); }
43 qint64 msecsSinceReference() const override { return m_timer.msecsSinceReference(); }43 qint64 msecsSinceReference() const override { return m_timer.msecsSinceReference(); }
44 qint64 elapsed() const override { return m_timer.elapsed(); }44 qint64 elapsed() const override { return m_timer.isValid() ? m_timer.elapsed() : 0; }
45private:45private:
46 QElapsedTimer m_timer;46 QElapsedTimer m_timer;
47};47};
4848
=== modified file 'plugins/Utils/Timer.cpp'
--- plugins/Utils/Timer.cpp 2015-04-22 10:40:54 +0000
+++ plugins/Utils/Timer.cpp 2016-12-12 16:49:02 +0000
@@ -37,13 +37,16 @@
37void Timer::start()37void Timer::start()
38{38{
39 m_timer.start();39 m_timer.start();
40 AbstractTimer::start();
41}40}
4241
43void Timer::stop()42void Timer::stop()
44{43{
45 m_timer.stop();44 m_timer.stop();
46 AbstractTimer::stop();45}
46
47bool Timer::isRunning() const
48{
49 return m_timer.isActive();
47}50}
4851
49bool Timer::isSingleShot() const52bool Timer::isSingleShot() const
5053
=== modified file 'plugins/Utils/Timer.h'
--- plugins/Utils/Timer.h 2015-04-22 10:40:54 +0000
+++ plugins/Utils/Timer.h 2016-12-12 16:49:02 +0000
@@ -30,18 +30,16 @@
30{30{
31 Q_OBJECT31 Q_OBJECT
32public:32public:
33 AbstractTimer(QObject *parent) : QObject(parent), m_isRunning(false) {}33 AbstractTimer(QObject *parent) : QObject(parent) {}
34 virtual int interval() const = 0;34 virtual int interval() const = 0;
35 virtual void setInterval(int msecs) = 0;35 virtual void setInterval(int msecs) = 0;
36 virtual void start() { m_isRunning = true; }36 virtual void start() = 0;
37 virtual void stop() { m_isRunning = false; }37 virtual void stop() = 0;
38 bool isRunning() const { return m_isRunning; }38 virtual bool isRunning() const = 0;
39 virtual bool isSingleShot() const = 0;39 virtual bool isSingleShot() const = 0;
40 virtual void setSingleShot(bool value) = 0;40 virtual void setSingleShot(bool value) = 0;
41Q_SIGNALS:41Q_SIGNALS:
42 void timeout();42 void timeout();
43private:
44 bool m_isRunning;
45};43};
4644
47/** A QTimer wrapper */45/** A QTimer wrapper */
@@ -55,6 +53,7 @@
55 void setInterval(int msecs) override;53 void setInterval(int msecs) override;
56 void start() override;54 void start() override;
57 void stop() override;55 void stop() override;
56 bool isRunning() const override;
58 bool isSingleShot() const override;57 bool isSingleShot() const override;
59 void setSingleShot(bool value) override;58 void setSingleShot(bool value) override;
60private:59private:
6160
=== added file 'plugins/Utils/appdrawerproxymodel.cpp'
--- plugins/Utils/appdrawerproxymodel.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Utils/appdrawerproxymodel.cpp 2016-12-12 16:49:02 +0000
@@ -0,0 +1,189 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "appdrawerproxymodel.h"
18
19#include <unity/shell/launcher/LauncherItemInterface.h>
20
21#include <QDebug>
22
23AppDrawerProxyModel::AppDrawerProxyModel(QObject *parent):
24 QSortFilterProxyModel(parent)
25{
26 setSortRole(AppDrawerModelInterface::RoleName);
27 setSortLocaleAware(true);
28 sort(0);
29
30 connect(this, &QAbstractListModel::rowsInserted, this, &AppDrawerProxyModel::countChanged);
31 connect(this, &QAbstractListModel::rowsRemoved, this, &AppDrawerProxyModel::countChanged);
32 connect(this, &QAbstractListModel::layoutChanged, this, &AppDrawerProxyModel::countChanged);
33}
34
35QAbstractItemModel *AppDrawerProxyModel::source() const
36{
37 return m_source;
38}
39
40void AppDrawerProxyModel::setSource(QAbstractItemModel *source)
41{
42 if (m_source != source) {
43 m_source = source;
44 setSourceModel(m_source);
45 setSortRole(m_sortBy == SortByAToZ ? AppDrawerModelInterface::RoleName : AppDrawerModelInterface::RoleUsage);
46 connect(m_source, &QAbstractItemModel::rowsRemoved, this, &AppDrawerProxyModel::invalidateFilter);
47 connect(m_source, &QAbstractItemModel::rowsInserted, this, &AppDrawerProxyModel::invalidateFilter);
48 Q_EMIT sourceChanged();
49 }
50}
51
52AppDrawerProxyModel::GroupBy AppDrawerProxyModel::group() const
53{
54 return m_group;
55}
56
57void AppDrawerProxyModel::setGroup(AppDrawerProxyModel::GroupBy group)
58{
59 if (m_group != group) {
60 m_group = group;
61 Q_EMIT groupChanged();
62 invalidateFilter();
63 }
64}
65
66QString AppDrawerProxyModel::filterLetter() const
67{
68 return m_filterLetter;
69}
70
71void AppDrawerProxyModel::setFilterLetter(const QString &filterLetter)
72{
73 if (m_filterLetter != filterLetter) {
74 m_filterLetter = filterLetter;
75 Q_EMIT filterLetterChanged();
76 invalidateFilter();
77 }
78}
79
80QString AppDrawerProxyModel::filterString() const
81{
82 return m_filterString;
83}
84
85void AppDrawerProxyModel::setFilterString(const QString &filterString)
86{
87 if (m_filterString != filterString) {
88 m_filterString = filterString;
89 Q_EMIT filterStringChanged();
90 invalidateFilter();
91 }
92}
93
94AppDrawerProxyModel::SortBy AppDrawerProxyModel::sortBy() const
95{
96 return m_sortBy;
97}
98
99void AppDrawerProxyModel::setSortBy(AppDrawerProxyModel::SortBy sortBy)
100{
101 if (m_sortBy != sortBy) {
102 m_sortBy = sortBy;
103 Q_EMIT sortByChanged();
104 setSortRole(m_sortBy == SortByAToZ ? AppDrawerModelInterface::RoleName : AppDrawerModelInterface::RoleUsage);
105 sort(0);
106 }
107}
108
109int AppDrawerProxyModel::count() const
110{
111 return rowCount();
112}
113
114QVariant AppDrawerProxyModel::data(const QModelIndex &index, int role) const
115{
116 QModelIndex idx = mapToSource(index);
117 if (role == Qt::UserRole) {
118 QString name = m_source->data(idx, AppDrawerModelInterface::RoleName).toString();
119 return name.length() > 0 ? QString(name.at(0)).toUpper() : QChar();
120 }
121 return m_source->data(idx, role);
122}
123
124QHash<int, QByteArray> AppDrawerProxyModel::roleNames() const
125{
126 if (m_source) {
127 QHash<int, QByteArray> roles = m_source->roleNames();
128 roles.insert(Qt::UserRole, "letter");
129 return roles;
130 }
131 return QHash<int, QByteArray>();
132}
133
134bool AppDrawerProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
135{
136 Q_UNUSED(source_parent)
137
138 if (m_group == GroupByAToZ && source_row > 0) {
139 QString currentName = m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleName).toString();
140 QChar currentLetter = currentName.length() > 0 ? currentName.at(0) : QChar();
141 QString previousName = m_source->data(m_source->index(source_row - 1,0 ), AppDrawerModelInterface::RoleName).toString();
142 QChar previousLetter = previousName.length() > 0 ? previousName.at(0) : QChar();
143 if (currentLetter.toLower() == previousLetter.toLower()) {
144 return false;
145 }
146 } else if(m_group == GroupByAll && source_row > 0) {
147 return false;
148 }
149 if (!m_filterLetter.isEmpty()) {
150 QString currentName = m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleName).toString();
151 QString currentLetter = currentName.length() > 0 ? QString(currentName.at(0)) : QString();
152 if (currentLetter.toLower() != m_filterLetter.toLower()) {
153 return false;
154 }
155 }
156 if (!m_filterString.isEmpty()) {
157 QStringList allWords = m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleKeywords).toStringList();
158 allWords.prepend(m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleName).toString());
159 bool found = false;
160 Q_FOREACH (const QString currentWord, allWords) {
161 if (currentWord.toLower().startsWith(m_filterString.toLower())) {
162 found = true;
163 break;
164 }
165 }
166 if (!found) {
167 return false;
168 }
169 }
170 return true;
171}
172
173QString AppDrawerProxyModel::appId(int index) const
174{
175 if (index >= 0 && index < rowCount()) {
176 QModelIndex sourceIndex = mapToSource(this->index(index, 0));
177
178 AppDrawerModelInterface* adm = dynamic_cast<AppDrawerModelInterface*>(m_source);
179 if (adm) {
180 return adm->data(sourceIndex, AppDrawerModelInterface::RoleAppId).toString();
181 }
182
183 AppDrawerProxyModel* adpm = qobject_cast<AppDrawerProxyModel*>(m_source);
184 if (adpm) {
185 return adpm->appId(sourceIndex.row());
186 }
187 }
188 return nullptr;
189}
0190
=== added file 'plugins/Utils/appdrawerproxymodel.h'
--- plugins/Utils/appdrawerproxymodel.h 1970-01-01 00:00:00 +0000
+++ plugins/Utils/appdrawerproxymodel.h 2016-12-12 16:49:02 +0000
@@ -0,0 +1,87 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <QSortFilterProxyModel>
18
19#include <unity/shell/launcher/AppDrawerModelInterface.h>
20
21using namespace unity::shell::launcher;
22
23class AppDrawerProxyModel: public QSortFilterProxyModel
24{
25 Q_OBJECT
26 Q_ENUMS(GroupBy)
27 Q_ENUMS(SortBy)
28 Q_PROPERTY(QAbstractItemModel* source READ source WRITE setSource NOTIFY sourceChanged)
29 Q_PROPERTY(GroupBy group READ group WRITE setGroup NOTIFY groupChanged)
30 Q_PROPERTY(QString filterLetter READ filterLetter WRITE setFilterLetter NOTIFY filterLetterChanged)
31 Q_PROPERTY(QString filterString READ filterString WRITE setFilterString NOTIFY filterStringChanged)
32 Q_PROPERTY(SortBy sortBy READ sortBy WRITE setSortBy NOTIFY sortByChanged)
33 Q_PROPERTY(int count READ count NOTIFY countChanged)
34
35public:
36 enum GroupBy {
37 GroupByNone,
38 GroupByAll,
39 GroupByAToZ
40 };
41 enum SortBy {
42 SortByAToZ,
43 SortByUsage
44 };
45
46 AppDrawerProxyModel(QObject* parent = nullptr);
47
48 QAbstractItemModel* source() const;
49 void setSource(QAbstractItemModel* source);
50
51 GroupBy group() const;
52 void setGroup(GroupBy group);
53
54 QString filterLetter() const;
55 void setFilterLetter(const QString &filterLetter);
56
57 QString filterString() const;
58 void setFilterString(const QString &filterString);
59
60 SortBy sortBy() const;
61 void setSortBy(SortBy sortBy);
62
63 int count() const;
64
65 QVariant data(const QModelIndex &index, int role) const override;
66 QHash<int, QByteArray> roleNames() const override;
67
68 Q_INVOKABLE QString appId(int index) const;
69
70protected:
71 bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
72
73Q_SIGNALS:
74 void sourceChanged();
75 void groupChanged();
76 void filterLetterChanged();
77 void filterStringChanged();
78 void sortByChanged();
79 void countChanged();
80
81private:
82 QAbstractItemModel* m_source = nullptr;
83 GroupBy m_group = GroupByNone;
84 QString m_filterLetter;
85 QString m_filterString;
86 SortBy m_sortBy = SortByAToZ;
87};
088
=== modified file 'plugins/Utils/globalfunctions.cpp'
--- plugins/Utils/globalfunctions.cpp 2016-06-02 09:32:33 +0000
+++ plugins/Utils/globalfunctions.cpp 2016-12-12 16:49:02 +0000
@@ -51,3 +51,8 @@
51 }51 }
52 return nullptr;52 return nullptr;
53}53}
54
55bool GlobalFunctions::itemUnderMouse(QQuickItem* item)
56{
57 return item && item->isUnderMouse();
58}
5459
=== modified file 'plugins/Utils/globalfunctions.h'
--- plugins/Utils/globalfunctions.h 2016-03-11 20:18:12 +0000
+++ plugins/Utils/globalfunctions.h 2016-12-12 16:49:02 +0000
@@ -37,6 +37,8 @@
37 int x,37 int x,
38 int y,38 int y,
39 QJSValue matcher);39 QJSValue matcher);
40
41 static Q_INVOKABLE bool itemUnderMouse(QQuickItem* item);
40};42};
4143
42#endif // GLOBALFUNCTIONS_H44#endif // GLOBALFUNCTIONS_H
4345
=== modified file 'plugins/Utils/plugin.cpp'
--- plugins/Utils/plugin.cpp 2016-06-28 20:38:00 +0000
+++ plugins/Utils/plugin.cpp 2016-12-12 16:49:02 +0000
@@ -39,6 +39,7 @@
39#include "deviceconfigparser.h"39#include "deviceconfigparser.h"
40#include "globalfunctions.h"40#include "globalfunctions.h"
41#include "URLDispatcher.h"41#include "URLDispatcher.h"
42#include "appdrawerproxymodel.h"
4243
43static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)44static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
44{45{
@@ -82,4 +83,5 @@
82 qmlRegisterType<DeviceConfigParser>(uri, 0, 1, "DeviceConfigParser");83 qmlRegisterType<DeviceConfigParser>(uri, 0, 1, "DeviceConfigParser");
83 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);84 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
84 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");85 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
86 qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
85}87}
8688
=== modified file 'plugins/Utils/windowstatestorage.cpp'
--- plugins/Utils/windowstatestorage.cpp 2016-08-23 13:53:07 +0000
+++ plugins/Utils/windowstatestorage.cpp 2016-12-12 16:49:02 +0000
@@ -189,3 +189,26 @@
189 }189 }
190 return query;190 return query;
191}191}
192
193Mir::State WindowStateStorage::toMirState(WindowState state) const
194{
195 // assumes a single state (not an OR of several)
196 switch (state) {
197 case WindowStateMaximized: return Mir::MaximizedState;
198 case WindowStateMinimized: return Mir::MinimizedState;
199 case WindowStateFullscreen: return Mir::FullscreenState;
200 case WindowStateMaximizedLeft: return Mir::MaximizedLeftState;
201 case WindowStateMaximizedRight: return Mir::MaximizedRightState;
202 case WindowStateMaximizedHorizontally: return Mir::HorizMaximizedState;
203 case WindowStateMaximizedVertically: return Mir::VertMaximizedState;
204 case WindowStateMaximizedTopLeft: return Mir::MaximizedTopLeftState;
205 case WindowStateMaximizedTopRight: return Mir::MaximizedTopRightState;
206 case WindowStateMaximizedBottomLeft: return Mir::MaximizedBottomLeftState;
207 case WindowStateMaximizedBottomRight: return Mir::MaximizedBottomRightState;
208
209 case WindowStateNormal:
210 case WindowStateRestored:
211 default:
212 return Mir::RestoredState;
213 }
214}
192215
=== modified file 'plugins/Utils/windowstatestorage.h'
--- plugins/Utils/windowstatestorage.h 2016-08-23 13:53:07 +0000
+++ plugins/Utils/windowstatestorage.h 2016-12-12 16:49:02 +0000
@@ -19,6 +19,9 @@
19#include <QMutex>19#include <QMutex>
20#include <QFuture>20#include <QFuture>
2121
22// unity-api
23#include <unity/shell/application/Mir.h>
24
22class WindowStateStorage: public QObject25class WindowStateStorage: public QObject
23{26{
24 Q_OBJECT27 Q_OBJECT
@@ -56,6 +59,8 @@
56 Q_INVOKABLE void saveStage(const QString &appId, int stage);59 Q_INVOKABLE void saveStage(const QString &appId, int stage);
57 Q_INVOKABLE int getStage(const QString &appId, int defaultValue) const;60 Q_INVOKABLE int getStage(const QString &appId, int defaultValue) const;
5861
62 Q_INVOKABLE Mir::State toMirState(WindowState state) const;
63
59private:64private:
60 void initdb();65 void initdb();
6166
6267
=== modified file 'plugins/WindowManager/CMakeLists.txt'
--- plugins/WindowManager/CMakeLists.txt 2016-06-20 09:43:38 +0000
+++ plugins/WindowManager/CMakeLists.txt 2016-12-12 16:49:02 +0000
@@ -1,10 +1,12 @@
1set(WINDOWMANAGER_SRC1set(WINDOWMANAGER_SRC
2 TopLevelSurfaceList.cpp2 TopLevelWindowModel.cpp
3 Window.cpp
3 WindowManagerPlugin.cpp4 WindowManagerPlugin.cpp
4 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h5 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
5 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h6 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
6 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h7 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
7 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceListInterface.h8 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceListInterface.h
9 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/SurfaceManagerInterface.h
8 )10 )
911
10add_library(windowmanager-qml SHARED ${WINDOWMANAGER_SRC})12add_library(windowmanager-qml SHARED ${WINDOWMANAGER_SRC})
1113
=== removed file 'plugins/WindowManager/TopLevelSurfaceList.cpp'
--- plugins/WindowManager/TopLevelSurfaceList.cpp 2016-09-14 15:02:01 +0000
+++ plugins/WindowManager/TopLevelSurfaceList.cpp 1970-01-01 00:00:00 +0000
@@ -1,481 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "TopLevelSurfaceList.h"
18
19// unity-api
20#include <unity/shell/application/ApplicationInfoInterface.h>
21#include <unity/shell/application/MirSurfaceInterface.h>
22#include <unity/shell/application/MirSurfaceListInterface.h>
23
24#include <QMetaObject>
25
26Q_LOGGING_CATEGORY(UNITY_TOPSURFACELIST, "unity.topsurfacelist", QtDebugMsg)
27
28#define DEBUG_MSG qCDebug(UNITY_TOPSURFACELIST).nospace().noquote() << __func__
29
30using namespace unity::shell::application;
31
32TopLevelSurfaceList::TopLevelSurfaceList(QObject *parent) :
33 QAbstractListModel(parent)
34{
35 DEBUG_MSG << "()";
36}
37
38TopLevelSurfaceList::~TopLevelSurfaceList()
39{
40 DEBUG_MSG << "()";
41}
42
43int TopLevelSurfaceList::rowCount(const QModelIndex &parent) const
44{
45 return !parent.isValid() ? m_surfaceList.size() : 0;
46}
47
48QVariant TopLevelSurfaceList::data(const QModelIndex& index, int role) const
49{
50 if (index.row() < 0 || index.row() >= m_surfaceList.size())
51 return QVariant();
52
53 if (role == SurfaceRole) {
54 MirSurfaceInterface *surface = m_surfaceList.at(index.row()).surface;
55 return QVariant::fromValue(surface);
56 } else if (role == ApplicationRole) {
57 return QVariant::fromValue(m_surfaceList.at(index.row()).application);
58 } else if (role == IdRole) {
59 return QVariant::fromValue(m_surfaceList.at(index.row()).id);
60 } else {
61 return QVariant();
62 }
63}
64
65void TopLevelSurfaceList::raise(MirSurfaceInterface *surface)
66{
67 if (!surface)
68 return;
69
70 DEBUG_MSG << "(MirSurface[" << (void*)surface << "])";
71
72 int i = indexOf(surface);
73 if (i != -1) {
74 raiseId(m_surfaceList.at(i).id);
75 }
76}
77
78void TopLevelSurfaceList::appendPlaceholder(ApplicationInfoInterface *application)
79{
80 DEBUG_MSG << "(" << application->appId() << ")";
81
82 appendSurfaceHelper(nullptr, application);
83}
84
85void TopLevelSurfaceList::appendSurface(MirSurfaceInterface *surface, ApplicationInfoInterface *application)
86{
87 Q_ASSERT(surface != nullptr);
88
89 bool filledPlaceholder = false;
90 for (int i = 0; i < m_surfaceList.count() && !filledPlaceholder; ++i) {
91 ModelEntry &entry = m_surfaceList[i];
92 if (entry.application == application && entry.surface == nullptr) {
93 entry.surface = surface;
94 connectSurface(surface);
95 DEBUG_MSG << " appId=" << application->appId() << " surface=" << surface
96 << ", filling out placeholder. after: " << toString();
97 Q_EMIT dataChanged(index(i) /* topLeft */, index(i) /* bottomRight */, QVector<int>() << SurfaceRole);
98 filledPlaceholder = true;
99 }
100 }
101
102 if (!filledPlaceholder) {
103 DEBUG_MSG << " appId=" << application->appId() << " surface=" << surface << ", adding new row";
104 appendSurfaceHelper(surface, application);
105 }
106}
107
108void TopLevelSurfaceList::appendSurfaceHelper(MirSurfaceInterface *surface, ApplicationInfoInterface *application)
109{
110 if (m_modelState == IdleState) {
111 m_modelState = InsertingState;
112 beginInsertRows(QModelIndex(), m_surfaceList.size() /*first*/, m_surfaceList.size() /*last*/);
113 } else {
114 Q_ASSERT(m_modelState == ResettingState);
115 // No point in signaling anything if we're resetting the whole model
116 }
117
118 int id = generateId();
119 m_surfaceList.append(ModelEntry(surface, application, id));
120 if (surface) {
121 connectSurface(surface);
122 }
123
124 if (m_modelState == InsertingState) {
125 endInsertRows();
126 Q_EMIT countChanged();
127 Q_EMIT listChanged();
128 m_modelState = IdleState;
129 }
130
131 DEBUG_MSG << " after " << toString();
132}
133
134void TopLevelSurfaceList::connectSurface(MirSurfaceInterface *surface)
135{
136 connect(surface, &MirSurfaceInterface::liveChanged, this, [this, surface](bool live){
137 if (!live) {
138 onSurfaceDied(surface);
139 }
140 });
141 connect(surface, &QObject::destroyed, this, [this, surface](){ this->onSurfaceDestroyed(surface); });
142}
143
144void TopLevelSurfaceList::onSurfaceDied(MirSurfaceInterface *surface)
145{
146 int i = indexOf(surface);
147 if (i == -1) {
148 return;
149 }
150
151 auto application = m_surfaceList[i].application;
152
153 // can't be starting if it already has a surface
154 Q_ASSERT(application->state() != ApplicationInfoInterface::Starting);
155
156 if (application->state() == ApplicationInfoInterface::Running) {
157 m_surfaceList[i].removeOnceSurfaceDestroyed = true;
158 } else {
159 // assume it got killed by the out-of-memory daemon.
160 //
161 // So leave entry in the model and only remove its surface, so shell can display a screenshot
162 // in its place.
163 m_surfaceList[i].removeOnceSurfaceDestroyed = false;
164 }
165}
166
167void TopLevelSurfaceList::onSurfaceDestroyed(MirSurfaceInterface *surface)
168{
169 int i = indexOf(surface);
170 if (i == -1) {
171 return;
172 }
173
174 if (m_surfaceList[i].removeOnceSurfaceDestroyed) {
175 removeAt(i);
176 } else {
177 m_surfaceList[i].surface = nullptr;
178 Q_EMIT dataChanged(index(i) /* topLeft */, index(i) /* bottomRight */, QVector<int>() << SurfaceRole);
179 DEBUG_MSG << " Removed surface from entry. After: " << toString();
180 }
181}
182
183void TopLevelSurfaceList::removeAt(int index)
184{
185 if (m_modelState == IdleState) {
186 beginRemoveRows(QModelIndex(), index, index);
187 m_modelState = RemovingState;
188 } else {
189 Q_ASSERT(m_modelState == ResettingState);
190 // No point in signaling anything if we're resetting the whole model
191 }
192
193 m_surfaceList.removeAt(index);
194
195 if (m_modelState == RemovingState) {
196 endRemoveRows();
197 Q_EMIT countChanged();
198 Q_EMIT listChanged();
199 m_modelState = IdleState;
200 }
201
202 DEBUG_MSG << " after " << toString();
203}
204
205int TopLevelSurfaceList::indexOf(MirSurfaceInterface *surface)
206{
207 for (int i = 0; i < m_surfaceList.count(); ++i) {
208 if (m_surfaceList.at(i).surface == surface) {
209 return i;
210 }
211 }
212 return -1;
213}
214
215void TopLevelSurfaceList::move(int from, int to)
216{
217 if (from == to) return;
218 DEBUG_MSG << " from=" << from << " to=" << to;
219
220 if (from >= 0 && from < m_surfaceList.size() && to >= 0 && to < m_surfaceList.size()) {
221 QModelIndex parent;
222 /* When moving an item down, the destination index needs to be incremented
223 by one, as explained in the documentation:
224 http://qt-project.org/doc/qt-5.0/qtcore/qabstractitemmodel.html#beginMoveRows */
225
226 Q_ASSERT(m_modelState == IdleState);
227 m_modelState = MovingState;
228
229 beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
230 m_surfaceList.move(from, to);
231 endMoveRows();
232 Q_EMIT listChanged();
233
234 m_modelState = IdleState;
235
236 DEBUG_MSG << " after " << toString();
237 }
238}
239
240MirSurfaceInterface *TopLevelSurfaceList::surfaceAt(int index) const
241{
242 if (index >=0 && index < m_surfaceList.count()) {
243 return m_surfaceList[index].surface;
244 } else {
245 return nullptr;
246 }
247}
248
249ApplicationInfoInterface *TopLevelSurfaceList::applicationAt(int index) const
250{
251 if (index >=0 && index < m_surfaceList.count()) {
252 return m_surfaceList[index].application;
253 } else {
254 return nullptr;
255 }
256}
257
258int TopLevelSurfaceList::idAt(int index) const
259{
260 if (index >=0 && index < m_surfaceList.count()) {
261 return m_surfaceList[index].id;
262 } else {
263 return 0;
264 }
265}
266
267int TopLevelSurfaceList::indexForId(int id) const
268{
269 for (int i = 0; i < m_surfaceList.count(); ++i) {
270 if (m_surfaceList[i].id == id) {
271 return i;
272 }
273 }
274 return -1;
275}
276
277void TopLevelSurfaceList::doRaiseId(int id)
278{
279 int fromIndex = indexForId(id);
280 if (fromIndex != -1) {
281 move(fromIndex, 0 /* toIndex */);
282 }
283}
284
285void TopLevelSurfaceList::raiseId(int id)
286{
287 if (m_modelState == IdleState) {
288 DEBUG_MSG << "(id=" << id << ") - do it now.";
289 doRaiseId(id);
290 } else {
291 DEBUG_MSG << "(id=" << id << ") - Model busy (modelState=" << m_modelState << "). Try again in the next event loop.";
292 // The model has just signalled some change. If we have a Repeater responding to this update, it will get nuts
293 // if we perform yet another model change straight away.
294 //
295 // A bad sympton of this problem is a Repeater.itemAt(index) call returning null event though Repeater.count says
296 // the index is definitely within bounds.
297 QMetaObject::invokeMethod(this, "raiseId", Qt::QueuedConnection, Q_ARG(int, id));
298 }
299}
300
301int TopLevelSurfaceList::generateId()
302{
303 int id = m_nextId;
304 m_nextId = nextFreeId(m_nextId + 1);
305 Q_EMIT nextIdChanged();
306 return id;
307}
308
309int TopLevelSurfaceList::nextFreeId(int candidateId)
310{
311 if (candidateId > m_maxId) {
312 return nextFreeId(1);
313 } else {
314 if (indexForId(candidateId) == -1) {
315 // it's indeed free
316 return candidateId;
317 } else {
318 return nextFreeId(candidateId + 1);
319 }
320 }
321}
322
323QString TopLevelSurfaceList::toString()
324{
325 QString str;
326 for (int i = 0; i < m_surfaceList.count(); ++i) {
327 auto item = m_surfaceList.at(i);
328
329 QString itemStr = QString("(index=%1,appId=%2,surface=0x%3,id=%4)")
330 .arg(i)
331 .arg(item.application->appId())
332 .arg((qintptr)item.surface, 0, 16)
333 .arg(item.id);
334
335 if (i > 0) {
336 str.append(",");
337 }
338 str.append(itemStr);
339 }
340 return str;
341}
342
343void TopLevelSurfaceList::addApplication(ApplicationInfoInterface *application)
344{
345 DEBUG_MSG << "(" << application->appId() << ")";
346 Q_ASSERT(!m_applications.contains(application));
347 m_applications.append(application);
348
349 MirSurfaceListInterface *surfaceList = application->surfaceList();
350
351 if (application->state() != ApplicationInfoInterface::Stopped) {
352 if (surfaceList->count() == 0) {
353 appendPlaceholder(application);
354 } else {
355 for (int i = 0; i < surfaceList->count(); ++i) {
356 appendSurface(surfaceList->get(i), application);
357 }
358 }
359 }
360
361 connect(surfaceList, &QAbstractItemModel::rowsInserted, this,
362 [this, application, surfaceList](const QModelIndex & /*parent*/, int first, int last)
363 {
364 for (int i = last; i >= first; --i) {
365 this->appendSurface(surfaceList->get(i), application);
366 }
367 });
368}
369
370void TopLevelSurfaceList::removeApplication(ApplicationInfoInterface *application)
371{
372 DEBUG_MSG << "(" << application->appId() << ")";
373 Q_ASSERT(m_applications.contains(application));
374
375 MirSurfaceListInterface *surfaceList = application->surfaceList();
376
377 disconnect(surfaceList, 0, this, 0);
378
379 Q_ASSERT(m_modelState == IdleState);
380 m_modelState = RemovingState;
381
382 int i = 0;
383 while (i < m_surfaceList.count()) {
384 if (m_surfaceList.at(i).application == application) {
385 beginRemoveRows(QModelIndex(), i, i);
386 m_surfaceList.removeAt(i);
387 endRemoveRows();
388 Q_EMIT countChanged();
389 Q_EMIT listChanged();
390 } else {
391 ++i;
392 }
393 }
394
395 m_modelState = IdleState;
396
397 DEBUG_MSG << " after " << toString();
398
399 m_applications.removeAll(application);
400}
401
402QAbstractListModel *TopLevelSurfaceList::applicationsModel() const
403{
404 return m_applicationsModel;
405}
406
407void TopLevelSurfaceList::setApplicationsModel(QAbstractListModel* value)
408{
409 if (m_applicationsModel == value) {
410 return;
411 }
412
413 DEBUG_MSG << "(" << value << ")";
414
415 Q_ASSERT(m_modelState == IdleState);
416 m_modelState = ResettingState;
417
418 beginResetModel();
419
420 if (m_applicationsModel) {
421 m_surfaceList.clear();
422 m_applications.clear();
423 disconnect(m_applicationsModel, 0, this, 0);
424 }
425
426 m_applicationsModel = value;
427
428 if (m_applicationsModel) {
429 findApplicationRole();
430
431 connect(m_applicationsModel, &QAbstractItemModel::rowsInserted,
432 this, [this](const QModelIndex &/*parent*/, int first, int last) {
433 for (int i = first; i <= last; ++i) {
434 auto application = getApplicationFromModelAt(i);
435 addApplication(application);
436 }
437 });
438
439 connect(m_applicationsModel, &QAbstractItemModel::rowsAboutToBeRemoved,
440 this, [this](const QModelIndex &/*parent*/, int first, int last) {
441 for (int i = first; i <= last; ++i) {
442 auto application = getApplicationFromModelAt(i);
443 removeApplication(application);
444 }
445 });
446
447 for (int i = 0; i < m_applicationsModel->rowCount(); ++i) {
448 auto application = getApplicationFromModelAt(i);
449 addApplication(application);
450 }
451 }
452
453 endResetModel();
454 m_modelState = IdleState;
455}
456
457ApplicationInfoInterface *TopLevelSurfaceList::getApplicationFromModelAt(int index)
458{
459 QModelIndex modelIndex = m_applicationsModel->index(index);
460
461 QVariant variant = m_applicationsModel->data(modelIndex, m_applicationRole);
462
463 // variant.value<ApplicationInfoInterface*>() returns null for some reason.
464 return static_cast<ApplicationInfoInterface*>(variant.value<QObject*>());
465}
466
467void TopLevelSurfaceList::findApplicationRole()
468{
469 QHash<int, QByteArray> namesHash = m_applicationsModel->roleNames();
470
471 m_applicationRole = -1;
472 for (auto i = namesHash.begin(); i != namesHash.end() && m_applicationRole == -1; ++i) {
473 if (i.value() == "application") {
474 m_applicationRole = i.key();
475 }
476 }
477
478 if (m_applicationRole == -1) {
479 qFatal("TopLevelSurfaceList: applicationsModel must have a \"application\" role.");
480 }
481}
4820
=== removed file 'plugins/WindowManager/TopLevelSurfaceList.h'
--- plugins/WindowManager/TopLevelSurfaceList.h 2016-04-04 13:39:44 +0000
+++ plugins/WindowManager/TopLevelSurfaceList.h 1970-01-01 00:00:00 +0000
@@ -1,223 +0,0 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef TOPLEVELSURFACELIST_H
18#define TOPLEVELSURFACELIST_H
19
20#include <QAbstractListModel>
21#include <QList>
22#include <QLoggingCategory>
23
24Q_DECLARE_LOGGING_CATEGORY(UNITY_TOPSURFACELIST)
25
26namespace unity {
27 namespace shell {
28 namespace application {
29 class ApplicationInfoInterface;
30 class MirSurfaceInterface;
31 }
32 }
33}
34
35/**
36 * @brief A model of top-level surfaces
37 *
38 * It's an abstraction of top-level application windows.
39 *
40 * When an entry first appears, it normaly doesn't have a surface yet, meaning that the application is
41 * still starting up. A shell should then display a splash screen or saved screenshot of the application
42 * until its surface comes up.
43 *
44 * As applications can have multiple surfaces and you can also have entries without surfaces at all,
45 * the only way to unambiguously refer to an entry in this model is through its id.
46 */
47class TopLevelSurfaceList : public QAbstractListModel
48{
49
50 Q_OBJECT
51
52 /**
53 * @brief A list model of applications.
54 *
55 * It's expected to have a role called "application" which returns a ApplicationInfoInterface
56 */
57 Q_PROPERTY(QAbstractListModel* applicationsModel READ applicationsModel
58 WRITE setApplicationsModel
59 NOTIFY applicationsModelChanged)
60
61 /**
62 * @brief Number of top-level surfaces in this model
63 *
64 * This is the same as rowCount, added in order to keep compatibility with QML ListModels.
65 */
66 Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
67
68 /**
69 The id to be used on the next entry created
70 Useful for tests
71 */
72 Q_PROPERTY(int nextId READ nextId NOTIFY nextIdChanged)
73public:
74
75 /**
76 * @brief The Roles supported by the model
77 *
78 * SurfaceRole - A MirSurfaceInterface. It will be null if the application is still starting up
79 * ApplicationRole - An ApplicationInfoInterface
80 * IdRole - A unique identifier for this entry. Useful to unambiguosly track elements as they move around in the list
81 */
82 enum Roles {
83 SurfaceRole = Qt::UserRole,
84 ApplicationRole = Qt::UserRole + 1,
85 IdRole = Qt::UserRole + 2,
86 };
87
88 explicit TopLevelSurfaceList(QObject *parent = nullptr);
89 virtual ~TopLevelSurfaceList();
90
91 // QAbstractItemModel methods
92 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
93 QVariant data(const QModelIndex& index, int role) const override;
94 QHash<int, QByteArray> roleNames() const override {
95 QHash<int, QByteArray> roleNames { {SurfaceRole, "surface"},
96 {ApplicationRole, "application"},
97 {IdRole, "id"} };
98 return roleNames;
99 }
100
101 int nextId() const { return m_nextId; }
102
103 QAbstractListModel *applicationsModel() const;
104 void setApplicationsModel(QAbstractListModel*);
105
106public Q_SLOTS:
107 /**
108 * @brief Returns the surface at the given index
109 *
110 * It will be a nullptr if the application is still starting up and thus hasn't yet created
111 * and drawn into a surface.
112 */
113 unity::shell::application::MirSurfaceInterface *surfaceAt(int index) const;
114
115 /**
116 * @brief Returns the application at the given index
117 */
118 unity::shell::application::ApplicationInfoInterface *applicationAt(int index) const;
119
120 /**
121 * @brief Returns the unique id of the element at the given index
122 */
123 int idAt(int index) const;
124
125 /**
126 * @brief Returns the index where the row with the given id is located
127 *
128 * Returns -1 if there's no row with the given id.
129 */
130 int indexForId(int id) const;
131
132 /**
133 * @brief Raises the row with the given id to index 0
134 */
135 void raiseId(int id);
136
137 void doRaiseId(int id);
138
139Q_SIGNALS:
140 void countChanged();
141
142 /**
143 * @brief Emitted when the list changes
144 *
145 * Emitted when model gains an element, loses an element or when elements exchange positions.
146 */
147 void listChanged();
148
149 void nextIdChanged();
150
151 void applicationsModelChanged();
152
153private:
154 void addApplication(unity::shell::application::ApplicationInfoInterface *application);
155 void removeApplication(unity::shell::application::ApplicationInfoInterface *application);
156
157 int indexOf(unity::shell::application::MirSurfaceInterface *surface);
158 void raise(unity::shell::application::MirSurfaceInterface *surface);
159 void move(int from, int to);
160 void appendSurfaceHelper(unity::shell::application::MirSurfaceInterface *surface,
161 unity::shell::application::ApplicationInfoInterface *application);
162 void connectSurface(unity::shell::application::MirSurfaceInterface *surface);
163 int generateId();
164 int nextFreeId(int candidateId);
165 QString toString();
166 void onSurfaceDestroyed(unity::shell::application::MirSurfaceInterface *surface);
167 void onSurfaceDied(unity::shell::application::MirSurfaceInterface *surface);
168 void removeAt(int index);
169 void findApplicationRole();
170
171 unity::shell::application::ApplicationInfoInterface *getApplicationFromModelAt(int index);
172
173 /*
174 Placeholder for a future surface from a starting or running application.
175 Enables shell to give immediate feedback to the user by showing, eg,
176 a splash screen.
177
178 It's a model row containing a null surface and the given application.
179 */
180 void appendPlaceholder(unity::shell::application::ApplicationInfoInterface *application);
181
182 /*
183 Adds a model row with the given surface and application
184
185 Alternatively, if a placeholder exists for the given application it's
186 filled with the given surface instead.
187 */
188 void appendSurface(unity::shell::application::MirSurfaceInterface *surface,
189 unity::shell::application::ApplicationInfoInterface *application);
190
191 struct ModelEntry {
192 ModelEntry(unity::shell::application::MirSurfaceInterface *surface, unity::shell::application::ApplicationInfoInterface *application, int id)
193 : surface(surface), application(application), id(id) {}
194 unity::shell::application::MirSurfaceInterface *surface;
195 unity::shell::application::ApplicationInfoInterface *application;
196 int id;
197 bool removeOnceSurfaceDestroyed{false};
198 };
199
200 QList<ModelEntry> m_surfaceList;
201 int m_nextId{1};
202 static const int m_maxId{1000000};
203
204 // applications that are being monitored
205 QList<unity::shell::application::ApplicationInfoInterface *> m_applications;
206
207 QAbstractListModel* m_applicationsModel{nullptr};
208 int m_applicationRole{-1};
209
210 enum ModelState {
211 IdleState,
212 InsertingState,
213 RemovingState,
214 MovingState,
215 ResettingState
216 };
217 ModelState m_modelState{IdleState};
218};
219
220Q_DECLARE_METATYPE(TopLevelSurfaceList*)
221Q_DECLARE_METATYPE(QAbstractListModel*)
222
223#endif // TOPLEVELSURFACELIST_H
2240
=== added file 'plugins/WindowManager/TopLevelWindowModel.cpp'
--- plugins/WindowManager/TopLevelWindowModel.cpp 1970-01-01 00:00:00 +0000
+++ plugins/WindowManager/TopLevelWindowModel.cpp 2016-12-12 16:49:02 +0000
@@ -0,0 +1,668 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "TopLevelWindowModel.h"
18
19// unity-api
20#include <unity/shell/application/ApplicationInfoInterface.h>
21#include <unity/shell/application/ApplicationManagerInterface.h>
22#include <unity/shell/application/MirSurfaceInterface.h>
23#include <unity/shell/application/MirSurfaceListInterface.h>
24#include <unity/shell/application/SurfaceManagerInterface.h>
25
26// Qt
27#include <QGuiApplication>
28#include <QDebug>
29
30// local
31#include "Window.h"
32
33Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
34
35#define DEBUG_MSG qCDebug(TOPLEVELWINDOWMODEL).nospace().noquote() << __func__
36#define INFO_MSG qCInfo(TOPLEVELWINDOWMODEL).nospace().noquote() << __func__
37
38namespace unityapi = unity::shell::application;
39
40TopLevelWindowModel::TopLevelWindowModel()
41{
42}
43
44void TopLevelWindowModel::setApplicationManager(unityapi::ApplicationManagerInterface* value)
45{
46 if (m_applicationManager == value) {
47 return;
48 }
49
50 DEBUG_MSG << "(" << value << ")";
51
52 Q_ASSERT(m_modelState == IdleState);
53 m_modelState = ResettingState;
54
55 beginResetModel();
56
57 if (m_applicationManager) {
58 m_windowModel.clear();
59 disconnect(m_applicationManager, 0, this, 0);
60 }
61
62 m_applicationManager = value;
63
64 if (m_applicationManager) {
65 connect(m_applicationManager, &QAbstractItemModel::rowsInserted,
66 this, [this](const QModelIndex &/*parent*/, int first, int last) {
67 for (int i = first; i <= last; ++i) {
68 auto application = m_applicationManager->get(i);
69 addApplication(application);
70 }
71 });
72
73 connect(m_applicationManager, &QAbstractItemModel::rowsAboutToBeRemoved,
74 this, [this](const QModelIndex &/*parent*/, int first, int last) {
75 for (int i = first; i <= last; ++i) {
76 auto application = m_applicationManager->get(i);
77 removeApplication(application);
78 }
79 });
80
81 for (int i = 0; i < m_applicationManager->rowCount(); ++i) {
82 auto application = m_applicationManager->get(i);
83 addApplication(application);
84 }
85 }
86
87 endResetModel();
88 m_modelState = IdleState;
89}
90
91void TopLevelWindowModel::setSurfaceManager(unityapi::SurfaceManagerInterface *surfaceManager)
92{
93 if (surfaceManager == m_surfaceManager) {
94 return;
95 }
96
97 DEBUG_MSG << "(" << surfaceManager << ")";
98
99 if (m_surfaceManager) {
100 disconnect(m_surfaceManager, 0, this, 0);
101 }
102
103 m_surfaceManager = surfaceManager;
104
105 if (m_surfaceManager) {
106 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfaceCreated, this, &TopLevelWindowModel::onSurfaceCreated);
107 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::surfacesRaised, this, &TopLevelWindowModel::onSurfacesRaised);
108 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsStarted, this, &TopLevelWindowModel::onModificationsStarted);
109 connect(m_surfaceManager, &unityapi::SurfaceManagerInterface::modificationsEnded, this, &TopLevelWindowModel::onModificationsEnded);
110 }
111
112 Q_EMIT surfaceManagerChanged(m_surfaceManager);
113}
114
115void TopLevelWindowModel::addApplication(unityapi::ApplicationInfoInterface *application)
116{
117 DEBUG_MSG << "(" << application->appId() << ")";
118
119 if (application->state() != unityapi::ApplicationInfoInterface::Stopped && application->surfaceList()->count() == 0) {
120 prependPlaceholder(application);
121 }
122}
123
124void TopLevelWindowModel::removeApplication(unityapi::ApplicationInfoInterface *application)
125{
126 DEBUG_MSG << "(" << application->appId() << ")";
127
128 Q_ASSERT(m_modelState == IdleState);
129
130 int i = 0;
131 while (i < m_windowModel.count()) {
132 if (m_windowModel.at(i).application == application) {
133 removeAt(i);
134 } else {
135 ++i;
136 }
137 }
138}
139
140void TopLevelWindowModel::prependPlaceholder(unityapi::ApplicationInfoInterface *application)
141{
142 INFO_MSG << "(" << application->appId() << ")";
143
144 prependSurfaceHelper(nullptr, application);
145}
146
147void TopLevelWindowModel::prependSurface(unityapi::MirSurfaceInterface *surface, unityapi::ApplicationInfoInterface *application)
148{
149 Q_ASSERT(surface != nullptr);
150
151 bool filledPlaceholder = false;
152 for (int i = 0; i < m_windowModel.count() && !filledPlaceholder; ++i) {
153 ModelEntry &entry = m_windowModel[i];
154 if (entry.application == application && entry.window->surface() == nullptr) {
155 entry.window->setSurface(surface);
156 connectSurface(surface);
157 INFO_MSG << " appId=" << application->appId() << " surface=" << surface
158 << ", filling out placeholder. after: " << toString();
159 filledPlaceholder = true;
160 }
161 }
162
163 if (!filledPlaceholder) {
164 INFO_MSG << " appId=" << application->appId() << " surface=" << surface << ", adding new row";
165 prependSurfaceHelper(surface, application);
166 }
167}
168
169void TopLevelWindowModel::prependSurfaceHelper(unityapi::MirSurfaceInterface *surface, unityapi::ApplicationInfoInterface *application)
170{
171 if (m_modelState == IdleState) {
172 m_modelState = InsertingState;
173 beginInsertRows(QModelIndex(), 0 /*first*/, 0 /*last*/);
174 } else {
175 Q_ASSERT(m_modelState == ResettingState);
176 // No point in signaling anything if we're resetting the whole model
177 }
178
179 int id = generateId();
180 Window *window = new Window(id, this);
181 if (surface) {
182 window->setSurface(surface);
183 }
184 m_windowModel.prepend(ModelEntry(window, application));
185 if (surface) {
186 connectSurface(surface);
187 }
188
189 connectWindow(window);
190
191 if (m_modelState == InsertingState) {
192 endInsertRows();
193 Q_EMIT countChanged();
194 Q_EMIT listChanged();
195 m_modelState = IdleState;
196 }
197
198 if (!surface) {
199 activateEmptyWindow(window);
200 }
201
202 INFO_MSG << " after " << toString();
203}
204
205void TopLevelWindowModel::connectWindow(Window *window)
206{
207 connect(window, &Window::focusRequested, this, [this, window]() {
208 if (!window->surface()) {
209 activateEmptyWindow(window);
210 }
211 });
212
213 connect(window, &Window::focusedChanged, this, [this, window](bool focused) {
214 if (window->surface()) {
215 // Condense changes to the focused window
216 // eg: Do focusedWindow=A to focusedWindow=B instead of
217 // focusedWindow=A to focusedWindow=null to focusedWindow=B
218 if (focused) {
219 Q_ASSERT(m_newlyFocusedWindow == nullptr);
220 m_focusedWindowChanged = true;
221 m_newlyFocusedWindow = window;
222 } else if (m_focusedWindow == window) {
223 m_focusedWindowChanged = true;
224 } else {
225 // don't clear the focused window if you were not there in the first place
226 // happens when a filled window gets replaced with an empty one (no surface) as the focused window.
227 }
228 }
229 });
230
231 connect(window, &Window::closeRequested, this, [this, window]() {
232 if (!window->surface()) {
233 // do things ourselves as miral doesn't know about this window
234 int id = window->id();
235 int index = indexForId(id);
236 bool focusOther = false;
237 Q_ASSERT(index >= 0);
238 if (window->focused()) {
239 focusOther = true;
240 }
241 m_windowModel[index].application->close();
242 if (focusOther) {
243 activateTopMostWindowWithoutId(id);
244 }
245 }
246 });
247
248 connect(window, &Window::emptyWindowActivated, this, [this, window]() {
249 activateEmptyWindow(window);
250 });
251}
252
253void TopLevelWindowModel::activateEmptyWindow(Window *window)
254{
255 Q_ASSERT(!window->surface());
256 DEBUG_MSG << "(" << window << ")";
257
258 // miral doesn't know about empty windows (ie, windows that are not backed up by MirSurfaces)
259 // So we have to activate them ourselves (instead of asking SurfaceManager to do it for us).
260
261 window->setFocused(true);
262 raiseId(window->id());
263 Window *previousWindow = m_focusedWindow;
264 setFocusedWindow(window);
265 if (previousWindow && previousWindow->surface() && previousWindow->surface()->focused()) {
266 m_surfaceManager->activate(nullptr);
267 }
268}
269
270void TopLevelWindowModel::connectSurface(unityapi::MirSurfaceInterface *surface)
271{
272 connect(surface, &unityapi::MirSurfaceInterface::liveChanged, this, [this, surface](bool live){
273 if (!live) {
274 onSurfaceDied(surface);
275 }
276 });
277 connect(surface, &QObject::destroyed, this, [this, surface](){ this->onSurfaceDestroyed(surface); });
278}
279
280void TopLevelWindowModel::onSurfaceDied(unityapi::MirSurfaceInterface *surface)
281{
282 if (surface->type() == Mir::InputMethodType) {
283 removeInputMethodWindow();
284 return;
285 }
286
287 int i = indexOf(surface);
288 if (i == -1) {
289 return;
290 }
291
292 auto application = m_windowModel[i].application;
293
294 // can't be starting if it already has a surface
295 Q_ASSERT(application->state() != unityapi::ApplicationInfoInterface::Starting);
296
297 if (application->state() == unityapi::ApplicationInfoInterface::Running) {
298 m_windowModel[i].removeOnceSurfaceDestroyed = true;
299 } else {
300 // assume it got killed by the out-of-memory daemon.
301 //
302 // So leave entry in the model and only remove its surface, so shell can display a screenshot
303 // in its place.
304 m_windowModel[i].removeOnceSurfaceDestroyed = false;
305 }
306}
307
308void TopLevelWindowModel::onSurfaceDestroyed(unityapi::MirSurfaceInterface *surface)
309{
310 int i = indexOf(surface);
311 if (i == -1) {
312 return;
313 }
314
315 if (m_windowModel[i].removeOnceSurfaceDestroyed) {
316 removeAt(i);
317 } else {
318 auto window = m_windowModel[i].window;
319 window->setSurface(nullptr);
320 window->setFocused(false);
321 INFO_MSG << " Removed surface from entry. After: " << toString();
322 }
323}
324
325void TopLevelWindowModel::onSurfaceCreated(unityapi::MirSurfaceInterface *surface)
326{
327 DEBUG_MSG << "(" << surface << ")";
328 if (surface->type() == Mir::InputMethodType) {
329 int id = generateId();
330 Window *qmlWindow = new Window(id, this);
331 connectWindow(qmlWindow);
332 qmlWindow->setSurface(surface);
333 setInputMethodWindow(qmlWindow);
334 } else {
335 auto application = m_applicationManager->findApplicationWithSurface(surface);
336 if (application) {
337 prependSurface(surface, application);
338 } else {
339 // Must be a prompt session. No need to do add it as a prompt surface is not top-level.
340 // It will show up in the ApplicationInfoInterface::promptSurfaceList of some application.
341 // Still wrap it in a Window though, so that we keep focusedWindow() up to date.
342 int id = generateId();
343 Window *promptWindow = new Window(id, this);
344 connectWindow(promptWindow);
345 promptWindow->setSurface(surface);
346 connect(surface, &QObject::destroyed, promptWindow, [=](){
347 promptWindow->setSurface(nullptr);
348 promptWindow->deleteLater();
349 });
350 }
351 }
352 // TODO: handle surfaces that are neither top-level windows nor input method. eg: child dialogs, popups, menus
353}
354
355void TopLevelWindowModel::removeAt(int index)
356{
357 if (m_modelState == IdleState) {
358 beginRemoveRows(QModelIndex(), index, index);
359 m_modelState = RemovingState;
360 } else {
361 Q_ASSERT(m_modelState == ResettingState);
362 // No point in signaling anything if we're resetting the whole model
363 }
364
365 auto window = m_windowModel[index].window;
366
367 window->setSurface(nullptr);
368 window->setFocused(false);
369
370 m_windowModel.removeAt(index);
371
372 if (m_modelState == RemovingState) {
373 endRemoveRows();
374 Q_EMIT countChanged();
375 Q_EMIT listChanged();
376 m_modelState = IdleState;
377 }
378
379 disconnect(window, 0, this, 0);
380 if (m_focusedWindow == window) {
381 setFocusedWindow(nullptr);
382 }
383 delete window;
384
385 INFO_MSG << " after " << toString();
386}
387
388void TopLevelWindowModel::setInputMethodWindow(Window *window)
389{
390 if (m_inputMethodWindow) {
391 qWarning("Multiple Input Method Surfaces created, removing the old one!");
392 delete m_inputMethodWindow;
393 }
394 m_inputMethodWindow = window;
395 Q_EMIT inputMethodSurfaceChanged(m_inputMethodWindow->surface());
396}
397
398void TopLevelWindowModel::removeInputMethodWindow()
399{
400 if (m_inputMethodWindow) {
401 delete m_inputMethodWindow;
402 m_inputMethodWindow = nullptr;
403 Q_EMIT inputMethodSurfaceChanged(nullptr);
404 }
405}
406
407void TopLevelWindowModel::onSurfacesRaised(const QVector<unityapi::MirSurfaceInterface*> &surfaces)
408{
409 DEBUG_MSG << "(" << surfaces << ")";
410 const int raiseCount = surfaces.size();
411 for (int i = 0; i < raiseCount; i++) {
412 int fromIndex = findIndexOf(surfaces[i]);
413 if (fromIndex != -1) {
414 move(fromIndex, 0);
415 }
416 }
417}
418
419int TopLevelWindowModel::rowCount(const QModelIndex &/*parent*/) const
420{
421 return m_windowModel.count();
422}
423
424QVariant TopLevelWindowModel::data(const QModelIndex& index, int role) const
425{
426 if (index.row() < 0 || index.row() >= m_windowModel.size())
427 return QVariant();
428
429 if (role == WindowRole) {
430 Window *window = m_windowModel.at(index.row()).window;
431 return QVariant::fromValue(window);
432 } else if (role == ApplicationRole) {
433 return QVariant::fromValue(m_windowModel.at(index.row()).application);
434 } else {
435 return QVariant();
436 }
437}
438
439int TopLevelWindowModel::findIndexOf(const unityapi::MirSurfaceInterface *surface) const
440{
441 for (int i=0; i<m_windowModel.count(); i++) {
442 if (m_windowModel[i].window->surface() == surface) {
443 return i;
444 }
445 }
446 return -1;
447}
448
449int TopLevelWindowModel::generateId()
450{
451 int id = m_nextId;
452 m_nextId = nextFreeId(nextId(id), id);
453 return id;
454}
455
456int TopLevelWindowModel::nextId(int id) const
457{
458 if (id == m_maxId) {
459 return id = 1;
460 } else {
461 return id + 1;
462 }
463}
464
465int TopLevelWindowModel::nextFreeId(int candidateId, const int latestId)
466{
467 int firstCandidateId = candidateId;
468
469 while (indexForId(candidateId) != -1 || candidateId == latestId) {
470 candidateId = nextId(candidateId);
471
472 if (candidateId == firstCandidateId) {
473 qFatal("TopLevelWindowModel: run out of window ids.");
474 }
475 }
476
477 return candidateId;
478}
479
480QString TopLevelWindowModel::toString()
481{
482 QString str;
483 for (int i = 0; i < m_windowModel.count(); ++i) {
484 auto item = m_windowModel.at(i);
485
486 QString itemStr = QString("(index=%1,appId=%2,surface=0x%3,id=%4)")
487 .arg(QString::number(i),
488 item.application->appId(),
489 QString::number((qintptr)item.window->surface(), 16),
490 QString::number(item.window->id()));
491
492 if (i > 0) {
493 str.append(",");
494 }
495 str.append(itemStr);
496 }
497 return str;
498}
499
500int TopLevelWindowModel::indexOf(unityapi::MirSurfaceInterface *surface)
501{
502 for (int i = 0; i < m_windowModel.count(); ++i) {
503 if (m_windowModel.at(i).window->surface() == surface) {
504 return i;
505 }
506 }
507 return -1;
508}
509
510int TopLevelWindowModel::indexForId(int id) const
511{
512 for (int i = 0; i < m_windowModel.count(); ++i) {
513 if (m_windowModel[i].window->id() == id) {
514 return i;
515 }
516 }
517 return -1;
518}
519
520Window *TopLevelWindowModel::windowAt(int index) const
521{
522 if (index >=0 && index < m_windowModel.count()) {
523 return m_windowModel[index].window;
524 } else {
525 return nullptr;
526 }
527}
528
529unityapi::MirSurfaceInterface *TopLevelWindowModel::surfaceAt(int index) const
530{
531 if (index >=0 && index < m_windowModel.count()) {
532 return m_windowModel[index].window->surface();
533 } else {
534 return nullptr;
535 }
536}
537
538unityapi::ApplicationInfoInterface *TopLevelWindowModel::applicationAt(int index) const
539{
540 if (index >=0 && index < m_windowModel.count()) {
541 return m_windowModel[index].application;
542 } else {
543 return nullptr;
544 }
545}
546
547int TopLevelWindowModel::idAt(int index) const
548{
549 if (index >=0 && index < m_windowModel.count()) {
550 return m_windowModel[index].window->id();
551 } else {
552 return 0;
553 }
554}
555
556void TopLevelWindowModel::raiseId(int id)
557{
558 if (m_modelState == IdleState) {
559 DEBUG_MSG << "(id=" << id << ") - do it now.";
560 doRaiseId(id);
561 } else {
562 DEBUG_MSG << "(id=" << id << ") - Model busy (modelState=" << m_modelState << "). Try again in the next event loop.";
563 // The model has just signalled some change. If we have a Repeater responding to this update, it will get nuts
564 // if we perform yet another model change straight away.
565 //
566 // A bad sympton of this problem is a Repeater.itemAt(index) call returning null event though Repeater.count says
567 // the index is definitely within bounds.
568 QMetaObject::invokeMethod(this, "raiseId", Qt::QueuedConnection, Q_ARG(int, id));
569 }
570}
571
572void TopLevelWindowModel::doRaiseId(int id)
573{
574 int fromIndex = indexForId(id);
575 // can't raise something that doesn't exist or that it's already on top
576 if (fromIndex != -1 && fromIndex != 0) {
577 auto surface = m_windowModel[fromIndex].window->surface();
578 if (surface) {
579 m_surfaceManager->raise(surface);
580 } else {
581 // move it ourselves. Since there's no mir::scene::Surface/miral::Window, there's nothing
582 // miral can do about it.
583 move(fromIndex, 0);
584 }
585 }
586}
587
588void TopLevelWindowModel::setFocusedWindow(Window *window)
589{
590 if (window != m_focusedWindow) {
591 INFO_MSG << "(" << window << ")";
592
593 Window* previousWindow = m_focusedWindow;
594
595 m_focusedWindow = window;
596 Q_EMIT focusedWindowChanged(m_focusedWindow);
597
598 if (previousWindow && previousWindow->focused() && !previousWindow->surface()) {
599 // do it ourselves. miral doesn't know about this window
600 previousWindow->setFocused(false);
601 }
602 }
603}
604
605unityapi::MirSurfaceInterface* TopLevelWindowModel::inputMethodSurface() const
606{
607 return m_inputMethodWindow ? m_inputMethodWindow->surface() : nullptr;
608}
609
610Window* TopLevelWindowModel::focusedWindow() const
611{
612 return m_focusedWindow;
613}
614
615void TopLevelWindowModel::move(int from, int to)
616{
617 if (from == to) return;
618 DEBUG_MSG << " from=" << from << " to=" << to;
619
620 if (from >= 0 && from < m_windowModel.size() && to >= 0 && to < m_windowModel.size()) {
621 QModelIndex parent;
622 /* When moving an item down, the destination index needs to be incremented
623 by one, as explained in the documentation:
624 http://qt-project.org/doc/qt-5.0/qtcore/qabstractitemmodel.html#beginMoveRows */
625
626 Q_ASSERT(m_modelState == IdleState);
627 m_modelState = MovingState;
628
629 beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
630#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
631 const auto &window = m_windowModel.takeAt(from);
632 m_windowModel.insert(to, window);
633#else
634 m_windowModel.move(from, to);
635#endif
636 endMoveRows();
637
638 Q_EMIT listChanged();
639 m_modelState = IdleState;
640
641 INFO_MSG << " after " << toString();
642 }
643}
644void TopLevelWindowModel::onModificationsStarted()
645{
646}
647
648void TopLevelWindowModel::onModificationsEnded()
649{
650 if (m_focusedWindowChanged) {
651 setFocusedWindow(m_newlyFocusedWindow);
652 }
653 // reset
654 m_focusedWindowChanged = false;
655 m_newlyFocusedWindow = nullptr;
656}
657
658void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
659{
660 DEBUG_MSG << "(" << forbiddenId << ")";
661
662 for (int i = 0; i < m_windowModel.count(); ++i) {
663 Window *window = m_windowModel[i].window;
664 if (window->id() != forbiddenId) {
665 window->activate();
666 }
667 }
668}
0669
=== added file 'plugins/WindowManager/TopLevelWindowModel.h'
--- plugins/WindowManager/TopLevelWindowModel.h 1970-01-01 00:00:00 +0000
+++ plugins/WindowManager/TopLevelWindowModel.h 2016-12-12 16:49:02 +0000
@@ -0,0 +1,260 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License version 3, as published by
6 * the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef TOPLEVELWINDOWMODEL_H
18#define TOPLEVELWINDOWMODEL_H
19
20#include <QAbstractListModel>
21#include <QLoggingCategory>
22
23Q_DECLARE_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL)
24
25class Window;
26
27namespace unity {
28 namespace shell {
29 namespace application {
30 class ApplicationInfoInterface;
31 class ApplicationManagerInterface;
32 class MirSurfaceInterface;
33 class SurfaceManagerInterface;
34 }
35 }
36}
37
38/**
39 * @brief A model of top-level surfaces
40 *
41 * It's an abstraction of top-level application windows.
42 *
43 * When an entry first appears, it normaly doesn't have a surface yet, meaning that the application is
44 * still starting up. A shell should then display a splash screen or saved screenshot of the application
45 * until its surface comes up.
46 *
47 * As applications can have multiple surfaces and you can also have entries without surfaces at all,
48 * the only way to unambiguously refer to an entry in this model is through its id.
49 */
50class TopLevelWindowModel : public QAbstractListModel
51{
52 Q_OBJECT
53
54 /**
55 * @brief Number of top-level surfaces in this model
56 *
57 * This is the same as rowCount, added in order to keep compatibility with QML ListModels.
58 */
59 Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
60
61 /**
62 * @brief The input method surface, if any
63 *
64 * The surface of a onscreen keyboard (akak "virtual keyboard") would be kept here and not in the model itself.
65 */
66 Q_PROPERTY(unity::shell::application::MirSurfaceInterface* inputMethodSurface READ inputMethodSurface NOTIFY inputMethodSurfaceChanged)
67
68 /**
69 * @brief The currently focused window, if any
70 */
71 Q_PROPERTY(Window* focusedWindow READ focusedWindow NOTIFY focusedWindowChanged)
72
73 Q_PROPERTY(unity::shell::application::SurfaceManagerInterface* surfaceManager
74 READ surfaceManager
75 WRITE setSurfaceManager
76 NOTIFY surfaceManagerChanged)
77
78 Q_PROPERTY(unity::shell::application::ApplicationManagerInterface* applicationManager
79 READ applicationManager
80 WRITE setApplicationManager
81 NOTIFY applicationManagerChanged)
82
83 /**
84 The id to be used on the next entry created
85 Useful for tests
86 */
87 Q_PROPERTY(int nextId READ nextId NOTIFY nextIdChanged)
88
89public:
90 /**
91 * @brief The Roles supported by the model
92 *
93 * WindowRole - A Window.
94 * ApplicationRole - An ApplicationInfoInterface
95 */
96 enum Roles {
97 WindowRole = Qt::UserRole,
98 ApplicationRole = Qt::UserRole + 1,
99 };
100
101 TopLevelWindowModel();
102
103 // From QAbstractItemModel
104 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
105 QVariant data(const QModelIndex& index, int role) const override;
106 QHash<int, QByteArray> roleNames() const override {
107 QHash<int, QByteArray> roleNames { {WindowRole, "window"},
108 {ApplicationRole, "application"} };
109 return roleNames;
110 }
111
112 // Own API
113
114 unity::shell::application::MirSurfaceInterface* inputMethodSurface() const;
115 Window* focusedWindow() const;
116
117 unity::shell::application::ApplicationManagerInterface *applicationManager() const { return m_applicationManager; }
118 void setApplicationManager(unity::shell::application::ApplicationManagerInterface*);
119
120 unity::shell::application::SurfaceManagerInterface *surfaceManager() const { return m_surfaceManager; }
121 void setSurfaceManager(unity::shell::application::SurfaceManagerInterface*);
122
123 int nextId() const { return m_nextId; }
124
125public:
126 /**
127 * @brief Returns the surface at the given index
128 *
129 * It will be a nullptr if the application is still starting up and thus hasn't yet created
130 * and drawn into a surface.
131 *
132 * Same as windowAt(index).surface()
133 */
134 Q_INVOKABLE unity::shell::application::MirSurfaceInterface *surfaceAt(int index) const;
135
136 /**
137 * @brief Returns the window at the given index
138 *
139 * Will always be valid
140 */
141 Q_INVOKABLE Window *windowAt(int index) const;
142
143 /**
144 * @brief Returns the application at the given index
145 */
146 Q_INVOKABLE unity::shell::application::ApplicationInfoInterface *applicationAt(int index) const;
147
148 /**
149 * @brief Returns the unique id of the element at the given index
150 */
151 Q_INVOKABLE int idAt(int index) const;
152
153 /**
154 * @brief Returns the index where the row with the given id is located
155 *
156 * Returns -1 if there's no row with the given id.
157 */
158 Q_INVOKABLE int indexForId(int id) const;
159
160 /**
161 * @brief Raises the row with the given id to the top of the window stack (index == count-1)
162 */
163 Q_INVOKABLE void raiseId(int id);
164
165Q_SIGNALS:
166 void countChanged();
167 void inputMethodSurfaceChanged(unity::shell::application::MirSurfaceInterface* inputMethodSurface);
168 void focusedWindowChanged(Window *focusedWindow);
169 void applicationManagerChanged(unity::shell::application::ApplicationManagerInterface*);
170 void surfaceManagerChanged(unity::shell::application::SurfaceManagerInterface*);
171
172 /**
173 * @brief Emitted when the list changes
174 *
175 * Emitted when model gains an element, loses an element or when elements exchange positions.
176 */
177 void listChanged();
178
179 void nextIdChanged();
180
181private Q_SLOTS:
182 void onSurfaceCreated(unity::shell::application::MirSurfaceInterface *surface);
183 void onSurfacesRaised(const QVector<unity::shell::application::MirSurfaceInterface*> &surfaces);
184
185 void onModificationsStarted();
186 void onModificationsEnded();
187
188private:
189 void doRaiseId(int id);
190 int generateId();
191 int nextFreeId(int candidateId, const int latestId);
192 int nextId(int id) const;
193 QString toString();
194 int indexOf(unity::shell::application::MirSurfaceInterface *surface);
195
196 void setInputMethodWindow(Window *window);
197 void setFocusedWindow(Window *window);
198 void removeInputMethodWindow();
199 int findIndexOf(const unity::shell::application::MirSurfaceInterface *surface) const;
200 void removeAt(int index);
201
202 void addApplication(unity::shell::application::ApplicationInfoInterface *application);
203 void removeApplication(unity::shell::application::ApplicationInfoInterface *application);
204
205 void prependPlaceholder(unity::shell::application::ApplicationInfoInterface *application);
206 void prependSurface(unity::shell::application::MirSurfaceInterface *surface,
207 unity::shell::application::ApplicationInfoInterface *application);
208 void prependSurfaceHelper(unity::shell::application::MirSurfaceInterface *surface,
209 unity::shell::application::ApplicationInfoInterface *application);
210
211 void connectWindow(Window *window);
212 void connectSurface(unity::shell::application::MirSurfaceInterface *surface);
213
214 void onSurfaceDied(unity::shell::application::MirSurfaceInterface *surface);
215 void onSurfaceDestroyed(unity::shell::application::MirSurfaceInterface *surface);
216
217 void move(int from, int to);
218
219 void activateEmptyWindow(Window *window);
220
221 void activateTopMostWindowWithoutId(int forbiddenId);
222
223 struct ModelEntry {
224 ModelEntry() {}
225 ModelEntry(Window *window,
226 unity::shell::application::ApplicationInfoInterface *application)
227 : window(window), application(application) {}
228 Window *window{nullptr};
229 unity::shell::application::ApplicationInfoInterface *application{nullptr};
230 bool removeOnceSurfaceDestroyed{false};
231 };
232
233 QVector<ModelEntry> m_windowModel;
234 Window* m_inputMethodWindow{nullptr};
235 Window* m_focusedWindow{nullptr};
236
237 int m_nextId{1};
238 // Just something big enough that we don't risk running out of unused id numbers.
239 // Not sure if QML int type supports something close to std::numeric_limits<int>::max() and
240 // there's no reason to try out its limits.
241 static const int m_maxId{1000000};
242
243 unity::shell::application::ApplicationManagerInterface* m_applicationManager{nullptr};
244 unity::shell::application::SurfaceManagerInterface *m_surfaceManager{nullptr};
245
246 enum ModelState {
247 IdleState,
248 InsertingState,
249 RemovingState,
250 MovingState,
251 ResettingState
252 };
253 ModelState m_modelState{IdleState};
254
255 // Valid between modificationsStarted and modificationsEnded
256 bool m_focusedWindowChanged{false};
257 Window *m_newlyFocusedWindow{nullptr};
258};
259
260#endif // TOPLEVELWINDOWMODEL_H
0261
=== added file 'plugins/WindowManager/Window.cpp'
--- plugins/WindowManager/Window.cpp 1970-01-01 00:00:00 +0000
+++ plugins/WindowManager/Window.cpp 2016-12-12 16:49:02 +0000
@@ -0,0 +1,237 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "Window.h"
18
19// unity-api
20#include <unity/shell/application/MirSurfaceInterface.h>
21
22#include <QQmlEngine>
23#include <QTextStream>
24
25namespace unityapi = unity::shell::application;
26
27Q_LOGGING_CATEGORY(UNITY_WINDOW, "unity.window", QtWarningMsg)
28
29#define DEBUG_MSG qCDebug(UNITY_WINDOW).nospace() << qPrintable(toString()) << "::" << __func__
30
31Window::Window(int id, QObject *parent)
32 : QObject(parent)
33 , m_id(id)
34{
35 DEBUG_MSG << "()";
36 QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
37}
38
39Window::~Window()
40{
41 DEBUG_MSG << "()";
42}
43
44QPoint Window::position() const
45{
46 return m_position;
47}
48
49QPoint Window::requestedPosition() const
50{
51 return m_requestedPosition;
52}
53
54void Window::setRequestedPosition(const QPoint &value)
55{
56 m_positionRequested = true;
57 if (value != m_requestedPosition) {
58 m_requestedPosition = value;
59 Q_EMIT requestedPositionChanged(m_requestedPosition);
60 if (m_surface) {
61 m_surface->setRequestedPosition(value);
62 } else {
63 // fake-miral: always comply
64 m_position = m_requestedPosition;
65 Q_EMIT positionChanged(m_position);
66 }
67 }
68}
69
70Mir::State Window::state() const
71{
72 return m_state;
73}
74
75bool Window::focused() const
76{
77 return m_focused;
78}
79
80bool Window::confinesMousePointer() const
81{
82 if (m_surface) {
83 return m_surface->confinesMousePointer();
84 } else {
85 return false;
86 }
87}
88
89int Window::id() const
90{
91 return m_id;
92}
93
94unityapi::MirSurfaceInterface* Window::surface() const
95{
96 return m_surface;
97}
98
99void Window::requestState(Mir::State state)
100{
101 m_stateRequested = true;
102 if (m_surface) {
103 m_surface->requestState(state);
104 } else if (m_state != state) {
105 m_state = state;
106 Q_EMIT stateChanged(m_state);
107 }
108}
109
110void Window::close()
111{
112 if (m_surface) {
113 m_surface->close();
114 } else {
115 Q_EMIT closeRequested();
116 }
117}
118
119void Window::activate()
120{
121 DEBUG_MSG << "()";
122 if (m_surface) {
123 m_surface->activate();
124 } else {
125 Q_EMIT emptyWindowActivated();
126 }
127}
128
129void Window::setSurface(unityapi::MirSurfaceInterface *surface)
130{
131 DEBUG_MSG << "(" << surface << ")";
132 if (m_surface) {
133 disconnect(m_surface, 0, this, 0);
134 }
135
136 m_surface = surface;
137
138 if (m_surface) {
139 connect(surface, &unityapi::MirSurfaceInterface::focusRequested, this, [this]() {
140 Q_EMIT focusRequested();
141 });
142
143 connect(surface, &unityapi::MirSurfaceInterface::closeRequested, this, &Window::closeRequested);
144
145 connect(surface, &unityapi::MirSurfaceInterface::positionChanged, this, [this]() {
146 updatePosition();
147 });
148
149 connect(surface, &unityapi::MirSurfaceInterface::stateChanged, this, [this]() {
150 updateState();
151 });
152
153 connect(surface, &unityapi::MirSurfaceInterface::focusedChanged, this, [this]() {
154 updateFocused();
155 });
156
157 // bring it up to speed
158 if (m_positionRequested) {
159 m_surface->setRequestedPosition(m_requestedPosition);
160 }
161 if (m_stateRequested && m_surface->state() == Mir::RestoredState) {
162 m_surface->requestState(m_state);
163 }
164
165 // and sync with surface
166 updatePosition();
167 updateState();
168 updateFocused();
169 }
170
171 Q_EMIT surfaceChanged(surface);
172}
173
174void Window::updatePosition()
175{
176 if (m_surface->position() != m_position) {
177 m_position = m_surface->position();
178 Q_EMIT positionChanged(m_position);
179 }
180}
181
182void Window::updateState()
183{
184 if (m_surface->state() != m_state) {
185 m_state = m_surface->state();
186 Q_EMIT stateChanged(m_state);
187 }
188}
189
190void Window::updateFocused()
191{
192 if (m_surface->focused() != m_focused) {
193 m_focused = m_surface->focused();
194 Q_EMIT focusedChanged(m_focused);
195 }
196}
197
198void Window::setFocused(bool value)
199{
200 if (value != m_focused) {
201 DEBUG_MSG << "(" << value << ")";
202 m_focused = value;
203 Q_EMIT focusedChanged(m_focused);
204 // when we have a surface we get focus changes from updateFocused() instead
205 Q_ASSERT(!m_surface);
206 }
207}
208
209QString Window::toString() const
210{
211 QString result;
212 {
213 QTextStream stream(&result);
214 stream << "Window["<<(void*)this<<", id="<<id()<<", ";
215 if (surface()) {
216 stream << "MirSurface["<<(void*)surface()<<",\""<<surface()->name()<<"\"]";
217 } else {
218 stream << "null";
219 }
220 stream << "]";
221 }
222 return result;
223}
224
225QDebug operator<<(QDebug dbg, const Window *window)
226{
227 QDebugStateSaver saver(dbg);
228 dbg.nospace();
229
230 if (window) {
231 dbg << qPrintable(window->toString());
232 } else {
233 dbg << (void*)(window);
234 }
235
236 return dbg;
237}
0238
=== added file 'plugins/WindowManager/Window.h'
--- plugins/WindowManager/Window.h 1970-01-01 00:00:00 +0000
+++ plugins/WindowManager/Window.h 2016-12-12 16:49:02 +0000
@@ -0,0 +1,161 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#ifndef UNITY_WINDOW_H
18#define UNITY_WINDOW_H
19
20#include <QLoggingCategory>
21#include <QObject>
22#include <QPoint>
23
24// Unity API
25#include <unity/shell/application/Mir.h>
26
27namespace unity {
28 namespace shell {
29 namespace application {
30 class MirSurfaceInterface;
31 }
32 }
33}
34
35
36Q_DECLARE_LOGGING_CATEGORY(UNITY_WINDOW)
37
38/**
39 @brief A slightly higher concept than MirSurface
40
41 A Window exists before its MirSurface gets created (for splashscreen purposes)
42 and might also hang around after the backing surface is gone (In case the application
43 was killed to free up memory, as it should still remain in the window list since the user
44 did not explicitly close it).
45 */
46class Window : public QObject
47{
48 Q_OBJECT
49
50 /**
51 * @brief Position of the current surface buffer, in pixels.
52 */
53 Q_PROPERTY(QPoint position READ position NOTIFY positionChanged)
54
55 /**
56 * @brief Requested position of the current surface buffer, in pixels.
57 */
58 Q_PROPERTY(QPoint requestedPosition READ requestedPosition WRITE setRequestedPosition NOTIFY requestedPositionChanged)
59
60 /**
61 * @brief State of the surface
62 */
63 Q_PROPERTY(Mir::State state READ state NOTIFY stateChanged)
64
65 /**
66 * @brief Whether the surface is focused
67 *
68 * It will be true if this surface is MirFocusControllerInterface::focusedSurface
69 */
70 Q_PROPERTY(bool focused READ focused NOTIFY focusedChanged)
71
72 /**
73 * @brief Whether the surface wants to confine the mouse pointer within its boundaries
74 *
75 * If true, the surface doesn't want the mouse pointer to leave its boundaries while it's focused.
76 */
77 Q_PROPERTY(bool confinesMousePointer READ confinesMousePointer NOTIFY confinesMousePointerChanged)
78
79 /**
80 * @brief A unique identifier for this window.
81 * Useful for telling windows apart in a list model as they get moved around
82 */
83 Q_PROPERTY(int id READ id CONSTANT)
84
85 /**
86 * @brief Surface backing up this window
87 * It might be null if a surface hasn't been created yet (application is starting up) or if
88 * the corresponding application has been killed (but can still get restarted to continue from
89 * where it left)
90 */
91 Q_PROPERTY(unity::shell::application::MirSurfaceInterface* surface READ surface NOTIFY surfaceChanged)
92
93public:
94 Window(int id, QObject *parent = nullptr);
95 virtual ~Window();
96 QPoint position() const;
97 QPoint requestedPosition() const;
98 void setRequestedPosition(const QPoint &);
99 Mir::State state() const;
100 bool focused() const;
101 bool confinesMousePointer() const;
102 int id() const;
103 unity::shell::application::MirSurfaceInterface* surface() const;
104
105 void setSurface(unity::shell::application::MirSurfaceInterface *surface);
106 void setFocused(bool value);
107
108 QString toString() const;
109
110public Q_SLOTS:
111 /**
112 * @brief Requests a change to the specified state
113 */
114 void requestState(Mir::State state);
115
116 /**
117 * @brief Sends a close request
118 *
119 */
120 void close();
121
122 /**
123 * @brief Focuses and raises the window
124 */
125 void activate();
126
127Q_SIGNALS:
128 void closeRequested();
129 void emptyWindowActivated();
130
131 void positionChanged(QPoint position);
132 void requestedPositionChanged(QPoint position);
133 void stateChanged(Mir::State value);
134 void focusedChanged(bool value);
135 void confinesMousePointerChanged(bool value);
136 void surfaceChanged(unity::shell::application::MirSurfaceInterface *surface);
137
138 /**
139 * @brief Emitted when focus for this window is requested by an external party
140 */
141 void focusRequested();
142
143private:
144 void updatePosition();
145 void updateState();
146 void updateFocused();
147
148 QPoint m_position;
149 QPoint m_requestedPosition;
150 bool m_positionRequested{false};
151 bool m_focused{false};
152 int m_id;
153 Mir::State m_state{Mir::RestoredState};
154 bool m_stateRequested{false};
155 unity::shell::application::MirSurfaceInterface *m_surface{nullptr};
156};
157
158QDebug operator<<(QDebug dbg, const Window *window);
159
160Q_DECLARE_METATYPE(Window*)
161#endif // UNITY_WINDOW_H
0162
=== modified file 'plugins/WindowManager/WindowManagerPlugin.cpp'
--- plugins/WindowManager/WindowManagerPlugin.cpp 2016-04-04 13:37:49 +0000
+++ plugins/WindowManager/WindowManagerPlugin.cpp 2016-12-12 16:49:02 +0000
@@ -16,13 +16,16 @@
1616
17#include "WindowManagerPlugin.h"17#include "WindowManagerPlugin.h"
1818
19#include "TopLevelSurfaceList.h"19#include "TopLevelWindowModel.h"
20#include "Window.h"
2021
21#include <QtQml>22#include <QtQml>
2223
23void WindowManagerPlugin::registerTypes(const char *uri)24void WindowManagerPlugin::registerTypes(const char *uri)
24{25{
25 qmlRegisterType<TopLevelSurfaceList>(uri, 0, 1, "TopLevelSurfaceList");26 qmlRegisterType<TopLevelWindowModel>(uri, 1, 0, "TopLevelWindowModel");
27
28 qRegisterMetaType<Window*>("Window*");
2629
27 qRegisterMetaType<QAbstractListModel*>("QAbstractListModel*");30 qRegisterMetaType<QAbstractListModel*>("QAbstractListModel*");
28}31}
2932
=== modified file 'po/unity8.pot'
--- po/unity8.pot 2016-11-29 09:43:33 +0000
+++ po/unity8.pot 2016-12-12 16:49:02 +0000
@@ -8,7 +8,7 @@
8msgstr ""8msgstr ""
9"Project-Id-Version: unity8\n"9"Project-Id-Version: unity8\n"
10"Report-Msgid-Bugs-To: \n"10"Report-Msgid-Bugs-To: \n"
11"POT-Creation-Date: 2016-11-29 09:43+0000\n"11"POT-Creation-Date: 2016-12-07 13:49+0000\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -23,7 +23,7 @@
23msgstr ""23msgstr ""
2424
25#: plugins/Unity/Launcher/launcheritem.cpp:5025#: plugins/Unity/Launcher/launcheritem.cpp:50
26#: plugins/Unity/Launcher/launcheritem.cpp:10926#: plugins/Unity/Launcher/launcheritem.cpp:122
27msgid "Pin shortcut"27msgid "Pin shortcut"
28msgstr ""28msgstr ""
2929
@@ -31,7 +31,7 @@
31msgid "Quit"31msgid "Quit"
32msgstr ""32msgstr ""
3333
34#: plugins/Unity/Launcher/launcheritem.cpp:10934#: plugins/Unity/Launcher/launcheritem.cpp:122
35msgid "Unpin shortcut"35msgid "Unpin shortcut"
36msgstr ""36msgstr ""
3737
@@ -175,87 +175,95 @@
175msgid "Same as clicking on a launcher icon."175msgid "Same as clicking on a launcher icon."
176msgstr ""176msgstr ""
177177
178#: qml/Components/KeyboardShortcutsOverlay.qml:181178#: qml/Components/KeyboardShortcutsOverlay.qml:177
179msgid "Super + A"
180msgstr ""
181
182#: qml/Components/KeyboardShortcutsOverlay.qml:182
183msgid "Opens the Application Drawer."
184msgstr ""
185
186#: qml/Components/KeyboardShortcutsOverlay.qml:194
179msgid "Scopes"187msgid "Scopes"
180msgstr ""188msgstr ""
181189
182#: qml/Components/KeyboardShortcutsOverlay.qml:188190#: qml/Components/KeyboardShortcutsOverlay.qml:201
183msgid "Super (Tap)"191msgid "Super (Tap)"
184msgstr ""192msgstr ""
185193
186#: qml/Components/KeyboardShortcutsOverlay.qml:193194#: qml/Components/KeyboardShortcutsOverlay.qml:206
187msgid "Opens the Scopes home."195msgid "Opens the Scopes home."
188msgstr ""196msgstr ""
189197
190#: qml/Components/KeyboardShortcutsOverlay.qml:209198#: qml/Components/KeyboardShortcutsOverlay.qml:222
191msgid "Switching"199msgid "Switching"
192msgstr ""200msgstr ""
193201
194#: qml/Components/KeyboardShortcutsOverlay.qml:216202#: qml/Components/KeyboardShortcutsOverlay.qml:229
195msgid "Alt + Tab"203msgid "Alt + Tab"
196msgstr ""204msgstr ""
197205
198#: qml/Components/KeyboardShortcutsOverlay.qml:221206#: qml/Components/KeyboardShortcutsOverlay.qml:234
199msgid "Switches between applications."207msgid "Switches between applications."
200msgstr ""208msgstr ""
201209
202#: qml/Components/KeyboardShortcutsOverlay.qml:229210#: qml/Components/KeyboardShortcutsOverlay.qml:242
203msgid "Super + W"211msgid "Super + W"
204msgstr ""212msgstr ""
205213
206#: qml/Components/KeyboardShortcutsOverlay.qml:234214#: qml/Components/KeyboardShortcutsOverlay.qml:247
207msgid "Opens the desktop spread."215msgid "Opens the desktop spread."
208msgstr ""216msgstr ""
209217
210#: qml/Components/KeyboardShortcutsOverlay.qml:242218#: qml/Components/KeyboardShortcutsOverlay.qml:255
211msgid "Cursor Left or Right"219msgid "Cursor Left or Right"
212msgstr ""220msgstr ""
213221
214#: qml/Components/KeyboardShortcutsOverlay.qml:247222#: qml/Components/KeyboardShortcutsOverlay.qml:260
215msgid "Moves the focus."223msgid "Moves the focus."
216msgstr ""224msgstr ""
217225
218#: qml/Components/KeyboardShortcutsOverlay.qml:259226#: qml/Components/KeyboardShortcutsOverlay.qml:272
219msgid "Windows"227msgid "Windows"
220msgstr ""228msgstr ""
221229
222#: qml/Components/KeyboardShortcutsOverlay.qml:266230#: qml/Components/KeyboardShortcutsOverlay.qml:279
223msgid "Ctrl + Super + D"231msgid "Ctrl + Super + D"
224msgstr ""232msgstr ""
225233
226#: qml/Components/KeyboardShortcutsOverlay.qml:271234#: qml/Components/KeyboardShortcutsOverlay.qml:284
227msgid "Minimizes all windows."235msgid "Minimizes all windows."
228msgstr ""236msgstr ""
229237
230#: qml/Components/KeyboardShortcutsOverlay.qml:279238#: qml/Components/KeyboardShortcutsOverlay.qml:292
231msgid "Ctrl + Super + Up"239msgid "Ctrl + Super + Up"
232msgstr ""240msgstr ""
233241
234#: qml/Components/KeyboardShortcutsOverlay.qml:284242#: qml/Components/KeyboardShortcutsOverlay.qml:297
235msgid "Maximizes the current window."243msgid "Maximizes the current window."
236msgstr ""244msgstr ""
237245
238#: qml/Components/KeyboardShortcutsOverlay.qml:292246#: qml/Components/KeyboardShortcutsOverlay.qml:305
239msgid "Ctrl + Super + Down"247msgid "Ctrl + Super + Down"
240msgstr ""248msgstr ""
241249
242#: qml/Components/KeyboardShortcutsOverlay.qml:297250#: qml/Components/KeyboardShortcutsOverlay.qml:310
243msgid "Minimizes or restores the current window."251msgid "Minimizes or restores the current window."
244msgstr ""252msgstr ""
245253
246#: qml/Components/KeyboardShortcutsOverlay.qml:305254#: qml/Components/KeyboardShortcutsOverlay.qml:318
247msgid "Ctrl + Super + Left or Right"255msgid "Ctrl + Super + Left or Right"
248msgstr ""256msgstr ""
249257
250#: qml/Components/KeyboardShortcutsOverlay.qml:310258#: qml/Components/KeyboardShortcutsOverlay.qml:323
251msgid "Semi-maximizes the current window."259msgid "Semi-maximizes the current window."
252msgstr ""260msgstr ""
253261
254#: qml/Components/KeyboardShortcutsOverlay.qml:318262#: qml/Components/KeyboardShortcutsOverlay.qml:331
255msgid "Alt + F4"263msgid "Alt + F4"
256msgstr ""264msgstr ""
257265
258#: qml/Components/KeyboardShortcutsOverlay.qml:323266#: qml/Components/KeyboardShortcutsOverlay.qml:336
259msgid "Closes the current window."267msgid "Closes the current window."
260msgstr ""268msgstr ""
261269
@@ -311,6 +319,28 @@
311msgid "Preview Share Item"319msgid "Preview Share Item"
312msgstr ""320msgstr ""
313321
322#: qml/Components/VirtualTouchPad.qml:317
323msgid ""
324"Your device is now connected to an external display. Use this screen as a "
325"touch pad to interact with the pointer."
326msgstr ""
327
328#: qml/Components/VirtualTouchPad.qml:327
329msgid "Tap left button to click."
330msgstr ""
331
332#: qml/Components/VirtualTouchPad.qml:339
333msgid "Tap right button to right click."
334msgstr ""
335
336#: qml/Components/VirtualTouchPad.qml:351
337msgid "Swipe with two fingers to scroll."
338msgstr ""
339
340#: qml/Components/VirtualTouchPad.qml:396
341msgid "Find more settings in the system settings."
342msgstr ""
343
314#: qml/Dash/DashPageHeader.qml:361344#: qml/Dash/DashPageHeader.qml:361
315msgctxt "Button: Open the Ubuntu Store"345msgctxt "Button: Open the Ubuntu Store"
316msgid "Store"346msgid "Store"
@@ -408,12 +438,6 @@
408msgid "Also installed"438msgid "Also installed"
409msgstr ""439msgstr ""
410440
411#: qml/DisabledScreenNotice.qml:109
412msgid ""
413"Your device is now connected to an external display. Use this screen as a "
414"touch pad to interact with the pointer."
415msgstr ""
416
417#: qml/Greeter/CoverPage.qml:127441#: qml/Greeter/CoverPage.qml:127
418msgid "Unlock"442msgid "Unlock"
419msgstr ""443msgstr ""
@@ -437,7 +461,7 @@
437msgstr[0] ""461msgstr[0] ""
438msgstr[1] ""462msgstr[1] ""
439463
440#: qml/Greeter/Greeter.qml:596464#: qml/Greeter/Greeter.qml:592
441msgid "Try again"465msgid "Try again"
442msgstr ""466msgstr ""
443467
@@ -465,6 +489,19 @@
465msgid "Select desktop environment"489msgid "Select desktop environment"
466msgstr ""490msgstr ""
467491
492#: qml/Launcher/Drawer.qml:80
493msgid "Search…"
494msgstr ""
495
496#: qml/Launcher/Drawer.qml:101
497msgctxt "Apps sorted alphabetically"
498msgid "A-Z"
499msgstr ""
500
501#: qml/Launcher/MoreAppsHeader.qml:32
502msgid "More apps in the store"
503msgstr ""
504
468#: qml/Notifications/NotificationMenuItemFactory.qml:124505#: qml/Notifications/NotificationMenuItemFactory.qml:124
469msgid "Show password"506msgid "Show password"
470msgstr ""507msgstr ""
@@ -477,62 +514,62 @@
477msgid "Conference"514msgid "Conference"
478msgstr ""515msgstr ""
479516
480#: qml/Panel/Indicators/MenuItemFactory.qml:847517#: qml/Panel/Indicators/MenuItemFactory.qml:868
481msgid "Nothing is playing"518msgid "Nothing is playing"
482msgstr ""519msgstr ""
483520
484#: qml/Panel/Indicators/MenuItemFactory.qml:975521#: qml/Panel/Indicators/MenuItemFactory.qml:996
485#, qt-format522#, qt-format
486msgid "%1 hour"523msgid "%1 hour"
487msgid_plural "%1 hours"524msgid_plural "%1 hours"
488msgstr[0] ""525msgstr[0] ""
489msgstr[1] ""526msgstr[1] ""
490527
491#: qml/Panel/Indicators/MenuItemFactory.qml:979528#: qml/Panel/Indicators/MenuItemFactory.qml:1000
492#, qt-format529#, qt-format
493msgid "%1 minute"530msgid "%1 minute"
494msgid_plural "%1 minutes"531msgid_plural "%1 minutes"
495msgstr[0] ""532msgstr[0] ""
496msgstr[1] ""533msgstr[1] ""
497534
498#: qml/Panel/Indicators/MenuItemFactory.qml:984535#: qml/Panel/Indicators/MenuItemFactory.qml:1005
499#, qt-format536#, qt-format
500msgid "%1 second"537msgid "%1 second"
501msgid_plural "%1 seconds"538msgid_plural "%1 seconds"
502msgstr[0] ""539msgstr[0] ""
503msgstr[1] ""540msgstr[1] ""
504541
505#: qml/Panel/Indicators/MenuItemFactory.qml:987542#: qml/Panel/Indicators/MenuItemFactory.qml:1008
506msgid "0 seconds"543msgid "0 seconds"
507msgstr ""544msgstr ""
508545
509#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"546#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
510#: qml/Panel/Indicators/MenuItemFactory.qml:989547#: qml/Panel/Indicators/MenuItemFactory.qml:1010
511#, qt-format548#, qt-format
512msgid "%1 remaining"549msgid "%1 remaining"
513msgstr ""550msgstr ""
514551
515#: qml/Panel/Indicators/MenuItemFactory.qml:995552#: qml/Panel/Indicators/MenuItemFactory.qml:1016
516msgid "In queue…"553msgid "In queue…"
517msgstr ""554msgstr ""
518555
519#: qml/Panel/Indicators/MenuItemFactory.qml:999556#: qml/Panel/Indicators/MenuItemFactory.qml:1020
520msgid "Downloading"557msgid "Downloading"
521msgstr ""558msgstr ""
522559
523#: qml/Panel/Indicators/MenuItemFactory.qml:1001560#: qml/Panel/Indicators/MenuItemFactory.qml:1022
524msgid "Paused, tap to resume"561msgid "Paused, tap to resume"
525msgstr ""562msgstr ""
526563
527#: qml/Panel/Indicators/MenuItemFactory.qml:1003564#: qml/Panel/Indicators/MenuItemFactory.qml:1024
528msgid "Canceled"565msgid "Canceled"
529msgstr ""566msgstr ""
530567
531#: qml/Panel/Indicators/MenuItemFactory.qml:1005568#: qml/Panel/Indicators/MenuItemFactory.qml:1026
532msgid "Finished"569msgid "Finished"
533msgstr ""570msgstr ""
534571
535#: qml/Panel/Indicators/MenuItemFactory.qml:1007572#: qml/Panel/Indicators/MenuItemFactory.qml:1028
536msgid "Failed, tap to retry"573msgid "Failed, tap to retry"
537msgstr ""574msgstr ""
538575
539576
=== modified file 'qml/Components/InputMethod.qml'
--- qml/Components/InputMethod.qml 2016-10-06 13:06:31 +0000
+++ qml/Components/InputMethod.qml 2016-12-12 16:49:02 +0000
@@ -23,6 +23,8 @@
2323
24 readonly property rect visibleRect: surfaceItem.surface && visible ? surfaceItem.surface.inputBounds : Qt.rect(0, 0, 0, 0)24 readonly property rect visibleRect: surfaceItem.surface && visible ? surfaceItem.surface.inputBounds : Qt.rect(0, 0, 0, 0)
2525
26 property var surface
27
26 MirSurfaceItem {28 MirSurfaceItem {
27 id: surfaceItem29 id: surfaceItem
28 anchors.fill: parent30 anchors.fill: parent
@@ -31,7 +33,7 @@
3133
32 surfaceWidth: root.enabled ? width : -134 surfaceWidth: root.enabled ? width : -1
33 surfaceHeight: root.enabled ? height : -135 surfaceHeight: root.enabled ? height : -1
34 surface: SurfaceManager.inputMethodSurface36 surface: root.surface
3537
36 onLiveChanged: {38 onLiveChanged: {
37 if (surface !== null && !live) {39 if (surface !== null && !live) {
@@ -50,7 +52,6 @@
50 }52 }
5153
52 visible: surfaceItem.surface &&54 visible: surfaceItem.surface &&
53 surfaceItem.surfaceState != Mir.HiddenState &&55 surfaceItem.surface.visible &&
54 surfaceItem.surfaceState != Mir.MinimizedState &&56 root.enabled
55 root.enabled
56}57}
5758
=== modified file 'qml/Components/KeyboardShortcutsOverlay.qml'
--- qml/Components/KeyboardShortcutsOverlay.qml 2016-05-11 11:09:42 +0000
+++ qml/Components/KeyboardShortcutsOverlay.qml 2016-12-12 16:49:02 +0000
@@ -173,6 +173,19 @@
173 Layout.maximumWidth: maxTextSize173 Layout.maximumWidth: maxTextSize
174 }174 }
175175
176 Label {
177 text: i18n.tr("Super + A")
178 fontSize: "small"
179 font.weight: Font.Medium
180 }
181 Label {
182 text: i18n.tr("Opens the Application Drawer.")
183 fontSize: "small"
184 font.weight: Font.Light
185 wrapMode: Text.Wrap
186 Layout.maximumWidth: maxTextSize
187 }
188
176189
177 // Scopes section190 // Scopes section
178 Item { Layout.columnSpan: 2; height: units.gu(2) }191 Item { Layout.columnSpan: 2; height: units.gu(2) }
179192
=== modified file 'qml/Components/KeymapSwitcher.qml'
--- qml/Components/KeymapSwitcher.qml 2016-07-11 14:40:56 +0000
+++ qml/Components/KeymapSwitcher.qml 2016-12-12 16:49:02 +0000
@@ -23,6 +23,9 @@
23QtObject {23QtObject {
24 id: root24 id: root
2525
26 // to be set from outside
27 property var focusedSurface: null
28
26 property GlobalShortcut shortcutNext: GlobalShortcut {29 property GlobalShortcut shortcutNext: GlobalShortcut {
27 shortcut: Qt.MetaModifier|Qt.Key_Space30 shortcut: Qt.MetaModifier|Qt.Key_Space
28 onTriggered: root.nextKeymap()31 onTriggered: root.nextKeymap()
@@ -60,7 +63,7 @@
60 }63 }
6164
62 property Binding surfaceKeymapBinding: Binding {65 property Binding surfaceKeymapBinding: Binding {
63 target: MirFocusController.focusedSurface66 target: root.focusedSurface
64 property: "keymap"67 property: "keymap"
65 value: root.currentKeymap68 value: root.currentKeymap
66 }69 }
6770
=== modified file 'qml/Components/VirtualTouchPad.qml'
--- qml/Components/VirtualTouchPad.qml 2016-02-18 17:21:40 +0000
+++ qml/Components/VirtualTouchPad.qml 2016-12-12 16:49:02 +0000
@@ -15,20 +15,58 @@
15 */15 */
1616
17import QtQuick 2.417import QtQuick 2.4
18import QtQuick.Layouts 1.1
18import Ubuntu.Components 1.319import Ubuntu.Components 1.3
20import Qt.labs.settings 1.0
21import Unity.Screens 0.1
19import UInput 0.122import UInput 0.1
23import "../Components"
2024
21Item {25Item {
26 id: root
22 property var uinput: UInput {27 property var uinput: UInput {
23 Component.onCompleted: createMouse();28 Component.onCompleted: createMouse();
24 Component.onDestruction: removeMouse();29 Component.onDestruction: removeMouse();
25 }30 }
2631
27 readonly property bool pressed: point1.pressed || point2.pressed32 Component.onCompleted: {
33 if (!settings.touchpadTutorialHasRun) {
34 root.runTutorial()
35 }
36 }
37
38 function runTutorial() {
39 // If the tutorial animation is started too early, e.g. in Component.onCompleted,
40 // root width & height might be reported as 0x0 still. As animations read their
41 // values at startup and won't update them, lets make sure to only start once
42 // we have some actual size.
43 if (root.width > 0 && root.height > 0) {
44 tutorial.start();
45 } else {
46 tutorialTimer.start();
47 }
48 }
49
50 Timer {
51 id: tutorialTimer
52 interval: 50
53 repeat: false
54 running: false
55 onTriggered: root.runTutorial();
56 }
57
58 readonly property bool pressed: point1.pressed || point2.pressed || leftButton.pressed || rightButton.pressed
59
60 property var settings: Settings {
61 objectName: "virtualTouchPadSettings"
62 property bool touchpadTutorialHasRun: false
63 property bool oskEnabled: true
64 }
2865
29 MultiPointTouchArea {66 MultiPointTouchArea {
30 objectName: "touchPadArea"67 objectName: "touchPadArea"
31 anchors.fill: parent68 anchors.fill: parent
69 enabled: !tutorial.running || tutorial.paused
3270
33 // FIXME: Once we have Qt DPR support, this should be Qt.styleHints.startDragDistance71 // FIXME: Once we have Qt DPR support, this should be Qt.styleHints.startDragDistance
34 readonly property int clickThreshold: internalGu * 1.572 readonly property int clickThreshold: internalGu * 1.5
@@ -37,6 +75,11 @@
37 property bool isDrag: false75 property bool isDrag: false
3876
39 onPressed: {77 onPressed: {
78 if (tutorial.paused) {
79 tutorial.resume();
80 return;
81 }
82
40 // If double-tapping *really* fast, it could happen that we end up having only point2 pressed83 // If double-tapping *really* fast, it could happen that we end up having only point2 pressed
41 // Make sure we check for both combos, only point1 or only point284 // Make sure we check for both combos, only point1 or only point2
42 if (((point1.pressed && !point2.pressed) || (!point1.pressed && point2.pressed))85 if (((point1.pressed && !point2.pressed) || (!point1.pressed && point2.pressed))
@@ -135,4 +178,229 @@
135 }178 }
136 ]179 ]
137 }180 }
181
182 RowLayout {
183 anchors { left: parent.left; right: parent.right; bottom: parent.bottom; margins: -internalGu * 1 }
184 height: internalGu * 10
185 spacing: internalGu * 1
186
187 MouseArea {
188 id: leftButton
189 objectName: "leftButton"
190 Layout.fillWidth: true
191 Layout.fillHeight: true
192 onPressed: uinput.pressMouse(UInput.ButtonLeft);
193 onReleased: uinput.releaseMouse(UInput.ButtonLeft);
194 property bool highlight: false
195 UbuntuShape {
196 anchors.fill: parent
197 backgroundColor: leftButton.highlight || leftButton.pressed ? UbuntuColors.ash : UbuntuColors.inkstone
198 Behavior on backgroundColor { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
199 }
200 }
201
202 MouseArea {
203 id: rightButton
204 objectName: "rightButton"
205 Layout.fillWidth: true
206 Layout.fillHeight: true
207 onPressed: uinput.pressMouse(UInput.ButtonRight);
208 onReleased: uinput.releaseMouse(UInput.ButtonRight);
209 property bool highlight: false
210 UbuntuShape {
211 anchors.fill: parent
212 backgroundColor: rightButton.highlight || rightButton.pressed ? UbuntuColors.ash : UbuntuColors.inkstone
213 Behavior on backgroundColor { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
214 }
215 }
216 }
217
218 AbstractButton {
219 id: oskButton
220 objectName: "oskButton"
221 anchors { right: parent.right; top: parent.top; margins: internalGu * 2 }
222 height: internalGu * 6
223 width: height
224
225 onClicked: {
226 settings.oskEnabled = !settings.oskEnabled
227 }
228
229 Rectangle {
230 anchors.fill: parent
231 radius: width / 2
232 color: UbuntuColors.inkstone
233 }
234
235 Icon {
236 anchors.fill: parent
237 anchors.margins: internalGu * 1.5
238 name: "input-keyboard-symbolic"
239 }
240 }
241
242 Screens {
243 id: screens
244 }
245
246 InputMethod {
247 id: inputMethod
248 // Don't resize when there is only one screen to avoid resize clashing with the InputMethod in the Shell.
249 enabled: screens.count > 1 && settings.oskEnabled && !tutorial.running
250 objectName: "inputMethod"
251 anchors.fill: parent
252 }
253
254 Label {
255 id: tutorialLabel
256 objectName: "tutorialLabel"
257 anchors { left: parent.left; top: parent.top; right: parent.right; margins: internalGu * 4; topMargin: internalGu * 10 }
258 opacity: 0
259 visible: opacity > 0
260 font.pixelSize: 2 * internalGu
261 color: "white"
262 wrapMode: Text.WordWrap
263 }
264
265 Icon {
266 id: tutorialImage
267 objectName: "tutorialImage"
268 height: internalGu * 8
269 width: height
270 name: "input-touchpad-symbolic"
271 color: "white"
272 opacity: 0
273 visible: opacity > 0
274 anchors { top: tutorialLabel.bottom; horizontalCenter: parent.horizontalCenter; margins: internalGu * 2 }
275 }
276
277 Item {
278 id: tutorialFinger1
279 objectName: "tutorialFinger1"
280 width: internalGu * 5
281 height: width
282 property real scale: 1
283 opacity: 0
284 visible: opacity > 0
285 Rectangle {
286 width: parent.width * parent.scale
287 height: width
288 anchors.centerIn: parent
289 radius: width / 2
290 color: UbuntuColors.inkstone
291 }
292 }
293
294 Item {
295 id: tutorialFinger2
296 objectName: "tutorialFinger2"
297 width: internalGu * 5
298 height: width
299 property real scale: 1
300 opacity: 0
301 visible: opacity > 0
302 Rectangle {
303 width: parent.width * parent.scale
304 height: width
305 anchors.centerIn: parent
306 radius: width / 2
307 color: UbuntuColors.inkstone
308 }
309 }
310
311 SequentialAnimation {
312 id: tutorial
313 objectName: "tutorialAnimation"
314
315 PropertyAction { targets: [leftButton, rightButton, oskButton]; property: "enabled"; value: false }
316 PropertyAction { targets: [leftButton, rightButton, oskButton]; property: "opacity"; value: 0 }
317 PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Your device is now connected to an external display. Use this screen as a touch pad to interact with the pointer.") }
318 UbuntuNumberAnimation { targets: [tutorialLabel, tutorialImage]; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
319 PropertyAction { target: tutorial; property: "paused"; value: true }
320 PauseAnimation { duration: 500 } // it takes a bit until pausing actually takes effect
321 UbuntuNumberAnimation { targets: [tutorialLabel, tutorialImage]; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
322
323 UbuntuNumberAnimation { target: leftButton; property: "opacity"; to: 1 }
324 UbuntuNumberAnimation { target: rightButton; property: "opacity"; to: 1 }
325
326 PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
327 PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Tap left button to click.") }
328 UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
329 SequentialAnimation {
330 loops: 2
331 PropertyAction { target: leftButton; property: "highlight"; value: true }
332 PauseAnimation { duration: UbuntuAnimation.FastDuration }
333 PropertyAction { target: leftButton; property: "highlight"; value: false }
334 PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
335 }
336 UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
337
338 PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
339 PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Tap right button to right click.") }
340 UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
341 SequentialAnimation {
342 loops: 2
343 PropertyAction { target: rightButton; property: "highlight"; value: true }
344 PauseAnimation { duration: UbuntuAnimation.FastDuration }
345 PropertyAction { target: rightButton; property: "highlight"; value: false }
346 PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
347 }
348 UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
349
350 PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
351 PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Swipe with two fingers to scroll.") }
352 UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
353 PropertyAction { target: tutorialFinger1; property: "x"; value: root.width / 2 - tutorialFinger1.width - internalGu * 1 }
354 PropertyAction { target: tutorialFinger2; property: "x"; value: root.width / 2 + tutorialFinger1.width + internalGu * 1 - tutorialFinger2.width }
355 PropertyAction { target: tutorialFinger1; property: "y"; value: root.height / 2 - internalGu * 10 }
356 PropertyAction { target: tutorialFinger2; property: "y"; value: root.height / 2 - internalGu * 10 }
357 SequentialAnimation {
358 ParallelAnimation {
359 UbuntuNumberAnimation { target: tutorialFinger1; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
360 UbuntuNumberAnimation { target: tutorialFinger2; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
361 UbuntuNumberAnimation { target: tutorialFinger1; property: "scale"; from: 0; to: 1; duration: UbuntuAnimation.FastDuration }
362 UbuntuNumberAnimation { target: tutorialFinger2; property: "scale"; from: 0; to: 1; duration: UbuntuAnimation.FastDuration }
363 }
364 ParallelAnimation {
365 UbuntuNumberAnimation { target: tutorialFinger1; property: "y"; to: root.height / 2 + internalGu * 10; duration: UbuntuAnimation.SleepyDuration }
366 UbuntuNumberAnimation { target: tutorialFinger2; property: "y"; to: root.height / 2 + internalGu * 10; duration: UbuntuAnimation.SleepyDuration }
367 }
368 ParallelAnimation {
369 UbuntuNumberAnimation { target: tutorialFinger1; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
370 UbuntuNumberAnimation { target: tutorialFinger2; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
371 UbuntuNumberAnimation { target: tutorialFinger1; property: "scale"; from: 1; to: 0; duration: UbuntuAnimation.FastDuration }
372 UbuntuNumberAnimation { target: tutorialFinger2; property: "scale"; from: 1; to: 0; duration: UbuntuAnimation.FastDuration }
373 }
374 PauseAnimation { duration: UbuntuAnimation.SlowDuration }
375 ParallelAnimation {
376 UbuntuNumberAnimation { target: tutorialFinger1; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
377 UbuntuNumberAnimation { target: tutorialFinger2; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
378 UbuntuNumberAnimation { target: tutorialFinger1; property: "scale"; from: 0; to: 1; duration: UbuntuAnimation.FastDuration }
379 UbuntuNumberAnimation { target: tutorialFinger2; property: "scale"; from: 0; to: 1; duration: UbuntuAnimation.FastDuration }
380 }
381 ParallelAnimation {
382 UbuntuNumberAnimation { target: tutorialFinger1; property: "y"; to: root.height / 2 - internalGu * 10; duration: UbuntuAnimation.SleepyDuration }
383 UbuntuNumberAnimation { target: tutorialFinger2; property: "y"; to: root.height / 2 - internalGu * 10; duration: UbuntuAnimation.SleepyDuration }
384 }
385 ParallelAnimation {
386 UbuntuNumberAnimation { target: tutorialFinger1; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
387 UbuntuNumberAnimation { target: tutorialFinger2; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
388 UbuntuNumberAnimation { target: tutorialFinger1; property: "scale"; from: 1; to: 0; duration: UbuntuAnimation.FastDuration }
389 UbuntuNumberAnimation { target: tutorialFinger2; property: "scale"; from: 1; to: 0; duration: UbuntuAnimation.FastDuration }
390 }
391 PauseAnimation { duration: UbuntuAnimation.SlowDuration }
392 }
393 UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
394
395 PauseAnimation { duration: UbuntuAnimation.SleepyDuration }
396 PropertyAction { target: tutorialLabel; property: "text"; value: i18n.tr("Find more settings in the system settings.") }
397 UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 1; duration: UbuntuAnimation.FastDuration }
398 PauseAnimation { duration: 2000 }
399 UbuntuNumberAnimation { target: tutorialLabel; property: "opacity"; to: 0; duration: UbuntuAnimation.FastDuration }
400
401 UbuntuNumberAnimation { target: oskButton; property: "opacity"; to: 1 }
402 PropertyAction { targets: [leftButton, rightButton, oskButton]; property: "enabled"; value: true }
403
404 PropertyAction { target: settings; property: "touchpadTutorialHasRun"; value: true }
405 }
138}406}
139407
=== modified file 'qml/Dash/Previews/PreviewAudioPlayback.qml'
--- qml/Dash/Previews/PreviewAudioPlayback.qml 2016-11-03 12:06:32 +0000
+++ qml/Dash/Previews/PreviewAudioPlayback.qml 2016-12-12 16:49:02 +0000
@@ -70,6 +70,7 @@
70 objectName: "playButton"70 objectName: "playButton"
71 width: trackRow.column1Width71 width: trackRow.column1Width
72 height: width72 height: width
73 activeFocusOnPress: false
7374
74 onClicked: {75 onClicked: {
75 if (trackItem.isPlayingItem) {76 if (trackItem.isPlayingItem) {
7677
=== modified file 'qml/DisabledScreenNotice.qml'
--- qml/DisabledScreenNotice.qml 2016-05-06 14:29:25 +0000
+++ qml/DisabledScreenNotice.qml 2016-12-12 16:49:02 +0000
@@ -18,15 +18,12 @@
18import QtQuick.Layouts 1.118import QtQuick.Layouts 1.1
19import Ubuntu.Components 1.319import Ubuntu.Components 1.3
20import Unity.Session 0.120import Unity.Session 0.1
21import Unity.Screens 0.1
22import QtQuick.Window 2.221import QtQuick.Window 2.2
23import "Components"22import "Components"
2423
25Item {24Item {
26 id: root25 id: root
2726
28 property bool infoNoteDisplayed: true
29
30 // For testing27 // For testing
31 property var screen: Screen28 property var screen: Screen
32 property var orientationLock: OrientationLock29 property var orientationLock: OrientationLock
@@ -36,10 +33,6 @@
36 name: applicationArguments.deviceName33 name: applicationArguments.deviceName
37 }34 }
3835
39 Screens {
40 id: screens
41 }
42
43 Item {36 Item {
44 id: contentContainer37 id: contentContainer
45 objectName: "contentContainer"38 objectName: "contentContainer"
@@ -75,58 +68,13 @@
75 }68 }
76 transformOrigin: Item.Center69 transformOrigin: Item.Center
7770
71 Rectangle {
72 anchors.fill: parent
73 color: UbuntuColors.jet
74 }
75
78 VirtualTouchPad {76 VirtualTouchPad {
79 anchors.fill: parent77 objectName: "virtualTouchPad"
80
81 onPressedChanged: {
82 if (pressed && infoNoteDisplayed) {
83 infoNoteDisplayed = false;
84 }
85 }
86 }
87
88 Rectangle {
89 anchors.fill: parent
90 color: "#3b3b3b"
91 }
92
93 Item {
94 objectName: "infoNoticeArea"
95 anchors.fill: parent
96 opacity: infoNoteDisplayed ? 1 : 0
97 visible: opacity > 0
98 Behavior on opacity {
99 UbuntuNumberAnimation { }
100 }
101
102 Column {
103 anchors.centerIn: parent
104 width: parent.width - (internalGu * 8)
105 spacing: internalGu * 4
106
107 Label {
108 id: text
109 text: i18n.tr("Your device is now connected to an external display. Use this screen as a touch pad to interact with the pointer.")
110 color: "white"
111 width: parent.width
112 font.pixelSize: 2.5 * internalGu
113 wrapMode: Text.Wrap
114 }
115 Icon {
116 height: internalGu * 8
117 width: height
118 name: "input-touchpad-symbolic"
119 color: "white"
120 anchors.horizontalCenter: parent.horizontalCenter
121 }
122 }
123 }
124
125 InputMethod {
126 id: inputMethod
127 // Don't resize when there is only one screen to avoid resize clashing with the InputMethod in the Shell.
128 enabled: screens.count > 1
129 objectName: "inputMethod"
130 anchors.fill: parent78 anchors.fill: parent
131 }79 }
132 }80 }
13381
=== modified file 'qml/Greeter/Greeter.qml'
--- qml/Greeter/Greeter.qml 2016-09-22 10:33:39 +0000
+++ qml/Greeter/Greeter.qml 2016-12-12 16:49:02 +0000
@@ -145,11 +145,7 @@
145 }145 }
146 }146 }
147147
148 if (loader.item.sessionToStart === LightDMService.greeter.defaultSession) {148 return LightDMService.greeter.defaultSession;
149 return LightDMService.greeter.defaultSession;
150 } else {
151 return "ubuntu"; // The default / fallback
152 }
153 }149 }
154150
155 QtObject {151 QtObject {
156152
=== modified file 'qml/Greeter/LoginList.qml'
--- qml/Greeter/LoginList.qml 2016-09-22 10:33:39 +0000
+++ qml/Greeter/LoginList.qml 2016-12-12 16:49:02 +0000
@@ -165,7 +165,7 @@
165 }165 }
166166
167 delegate: Item {167 delegate: Item {
168 width: parent.width168 width: userList.width
169 height: root.cellHeight169 height: root.cellHeight
170170
171 readonly property bool belowHighlight: (userList.currentIndex < 0 && index > 0) || (userList.currentIndex >= 0 && index > userList.currentIndex)171 readonly property bool belowHighlight: (userList.currentIndex < 0 && index > 0) || (userList.currentIndex >= 0 && index > userList.currentIndex)
172172
=== modified file 'qml/Greeter/WideView.qml'
--- qml/Greeter/WideView.qml 2016-09-07 17:13:38 +0000
+++ qml/Greeter/WideView.qml 2016-12-12 16:49:02 +0000
@@ -125,6 +125,8 @@
125 id: loginList125 id: loginList
126 objectName: "loginList"126 objectName: "loginList"
127127
128 property int selectedUserIndex: 0
129
128 width: units.gu(40)130 width: units.gu(40)
129 anchors {131 anchors {
130 left: parent.left132 left: parent.left
@@ -139,9 +141,12 @@
139 Behavior on boxVerticalOffset { UbuntuNumberAnimation {} }141 Behavior on boxVerticalOffset { UbuntuNumberAnimation {} }
140142
141 model: root.userModel143 model: root.userModel
142 currentSession: LightDMService.greeter.defaultSession144 currentSession: LightDMService.users.data(selectedUserIndex, LightDMService.userRoles.SessionRole);
143 onResponded: root.responded(response)145 onResponded: root.responded(response)
144 onSelected: root.selected(index)146 onSelected: {
147 root.selected(index)
148 loginList.selectedUserIndex = index;
149 }
145 onSessionChooserButtonClicked: parent.state = "SessionsList"150 onSessionChooserButtonClicked: parent.state = "SessionsList"
146151
147 Keys.forwardTo: [sessionChooserLoader.item]152 Keys.forwardTo: [sessionChooserLoader.item]
148153
=== added file 'qml/Launcher/BackgroundBlur.qml'
--- qml/Launcher/BackgroundBlur.qml 1970-01-01 00:00:00 +0000
+++ qml/Launcher/BackgroundBlur.qml 2016-12-12 16:49:02 +0000
@@ -0,0 +1,81 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19import QtGraphicalEffects 1.0
20
21Item {
22 id: root
23
24 property int blurAmount: 32
25 property Item sourceItem
26 property rect blurRect: Qt.rect(0,0,0,0)
27 property alias cached: fastBlur.cached
28
29 Rectangle {
30 id: blurMask
31 color: "yellow"
32 x: blurRect.x
33 y: blurRect.y
34 width: blurRect.width
35 height: blurRect.height
36 }
37
38 ShaderEffect {
39 id: maskedBlurEffect
40 x: blurRect.x
41 y: blurRect.y
42 width: blurRect.width
43 height: blurRect.height
44
45 property variant source: ShaderEffectSource {
46 id: shaderEffectSource
47 sourceItem: root.sourceItem
48 hideSource: false
49 sourceRect: root.blurRect
50 }
51
52 property var mask: ShaderEffectSource {
53 sourceItem: blurMask
54 hideSource: true
55 }
56
57 fragmentShader: "
58 varying highp vec2 qt_TexCoord0;
59 uniform sampler2D source;
60 uniform sampler2D mask;
61 void main(void)
62 {
63 highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
64 highp vec4 maskColor = texture2D(mask, qt_TexCoord0);
65
66 sourceColor *= maskColor.a;
67
68 gl_FragColor = sourceColor;
69 }"
70 }
71
72 FastBlur {
73 id: fastBlur
74 x: blurRect.x
75 y: blurRect.y
76 width: blurRect.width
77 height: blurRect.height
78 source: maskedBlurEffect
79 radius: Math.min(blurAmount, 128)
80 }
81 }
082
=== added file 'qml/Launcher/Drawer.qml'
--- qml/Launcher/Drawer.qml 1970-01-01 00:00:00 +0000
+++ qml/Launcher/Drawer.qml 2016-12-12 16:49:02 +0000
@@ -0,0 +1,306 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19import Unity.Launcher 0.1
20import Utils 0.1
21import "../Components"
22import Qt.labs.settings 1.0
23
24FocusScope {
25 id: root
26
27 property int panelWidth: 0
28 readonly property bool moving: listLoader.item && listLoader.item.moving
29
30 signal applicationSelected(string appId)
31
32 property bool draggingHorizontally: false
33 property int dragDistance: 0
34
35 onFocusChanged: {
36 if (focus) {
37 searchField.selectAll();
38 }
39 }
40
41 function focusInput() {
42 searchField.selectAll();
43 searchField.focus = true;
44 }
45
46 Settings {
47 property alias selectedTab: sections.selectedIndex
48 }
49
50 MouseArea {
51 anchors.fill: parent
52 hoverEnabled: true
53 acceptedButtons: Qt.AllButtons
54 onWheel: wheel.accepted = true
55 }
56
57 Rectangle {
58 anchors.fill: parent
59 color: "#BF000000"
60
61 AppDrawerModel {
62 id: appDrawerModel
63 }
64
65 AppDrawerProxyModel {
66 id: sortProxyModel
67 source: appDrawerModel
68 filterString: searchField.displayText
69 sortBy: AppDrawerProxyModel.SortByAToZ
70 }
71
72 Item {
73 id: contentContainer
74 anchors.fill: parent
75 anchors.leftMargin: root.panelWidth
76
77 TextField {
78 id: searchField
79 anchors { left: parent.left; top: parent.top; right: parent.right; margins: units.gu(1) }
80 placeholderText: i18n.tr("Search…")
81 focus: true
82 onAccepted: {
83 if (searchField.displayText != "" && listLoader.item && listLoader.item.currentItem) {
84 root.applicationSelected(listLoader.item.getFirstAppId());
85 }
86 }
87 }
88
89 Item {
90 id: sectionsContainer
91 anchors { left: parent.left; top: searchField.bottom; right: parent.right; }
92 height: sections.height
93 clip: true
94 z: 2
95
96 Sections {
97 id: sections
98 width: parent.width
99 actions: [
100 Action {
101 text: i18n.ctr("Apps sorted alphabetically", "A-Z")
102 // TODO: Disabling this for now as we don't get the right input from u-a-l yet.
103// },
104// Action {
105// text: i18n.ctr("Most used apps", "Most used")
106 }
107 ]
108
109 Rectangle {
110 anchors.bottom: parent.bottom
111 height: units.dp(1)
112 color: 'gray'
113 width: contentContainer.width
114 }
115 }
116 }
117
118 Loader {
119 id: listLoader
120 anchors { left: parent.left; top: sectionsContainer.bottom; right: parent.right; bottom: parent.bottom; leftMargin: units.gu(1); rightMargin: units.gu(1) }
121 sourceComponent: {
122 switch (sections.selectedIndex) {
123 case 0: return aToZComponent;
124 case 1: return mostUsedComponent;
125 }
126 }
127 Binding {
128 target: listLoader.item || null
129 property: "objectName"
130 value: "drawerItemList"
131 }
132 }
133
134 MouseArea {
135 parent: listLoader.item ? listLoader.item : null
136 anchors.fill: parent
137 propagateComposedEvents: true
138 property int oldX: 0
139 onPressed: {
140 oldX = mouseX;
141 }
142 onMouseXChanged: {
143 var diff = oldX - mouseX;
144 root.draggingHorizontally |= diff > units.gu(2);
145 if (!root.draggingHorizontally) {
146 return;
147 }
148 propagateComposedEvents = false;
149 parent.interactive = false;
150 root.dragDistance += diff;
151 oldX = mouseX
152 }
153 onReleased: {
154 if (root.draggingHorizontally) {
155 root.draggingHorizontally = false;
156 parent.interactive = true;
157 }
158 reactivateTimer.start();
159 }
160 Timer {
161 id: reactivateTimer
162 interval: 0
163 onTriggered: parent.propagateComposedEvents = true;
164 }
165 }
166
167 Component {
168 id: mostUsedComponent
169 DrawerListView {
170
171 header: MoreAppsHeader {
172 width: parent.width
173 height: units.gu(6)
174 }
175
176 model: AppDrawerProxyModel {
177 source: sortProxyModel
178 group: AppDrawerProxyModel.GroupByAll
179 sortBy: AppDrawerProxyModel.SortByUsage
180 }
181
182 delegate: UbuntuShape {
183 width: parent.width
184 color: "#20ffffff"
185 aspect: UbuntuShape.Flat
186 // NOTE: Cannot use gridView.rows here as it would evaluate to 0 at first and only update later,
187 // which messes up the ListView.
188 height: (Math.ceil(mostUsedGridView.model.count / mostUsedGridView.columns) * mostUsedGridView.delegateHeight) + units.gu(2)
189
190 readonly property string appId: model.appId
191
192 DrawerGridView {
193 id: mostUsedGridView
194 anchors.fill: parent
195 topMargin: units.gu(1)
196 bottomMargin: units.gu(1)
197 clip: true
198
199 model: sortProxyModel
200
201 delegateWidth: units.gu(8)
202 delegateHeight: units.gu(10)
203 delegate: drawerDelegateComponent
204 }
205 }
206 }
207 }
208
209 Component {
210 id: aToZComponent
211 DrawerListView {
212
213 header: MoreAppsHeader {
214 width: parent.width
215 height: units.gu(6)
216 }
217
218 model: AppDrawerProxyModel {
219 source: sortProxyModel
220 sortBy: AppDrawerProxyModel.SortByAToZ
221 group: AppDrawerProxyModel.GroupByAToZ
222 }
223
224 delegate: UbuntuShape {
225 width: parent.width
226 color: "#20ffffff"
227 aspect: UbuntuShape.Flat
228
229 readonly property string appId: model.appId
230
231 // NOTE: Cannot use gridView.rows here as it would evaluate to 0 at first and only update later,
232 // which messes up the ListView.
233 height: (Math.ceil(gridView.model.count / gridView.columns) * gridView.delegateHeight) +
234 categoryNameLabel.implicitHeight + units.gu(2)
235
236 Label {
237 id: categoryNameLabel
238 anchors { left: parent.left; top: parent.top; right: parent.right; margins: units.gu(1) }
239 text: model.letter
240 }
241
242 DrawerGridView {
243 id: gridView
244 anchors { left: parent.left; top: categoryNameLabel.bottom; right: parent.right; topMargin: units.gu(1) }
245 height: rows * delegateHeight
246
247 interactive: false
248
249 model: AppDrawerProxyModel {
250 id: categoryModel
251 source: sortProxyModel
252 filterLetter: model.letter
253 }
254 delegateWidth: units.gu(8)
255 delegateHeight: units.gu(10)
256 delegate: drawerDelegateComponent
257 }
258 }
259 }
260 }
261 }
262
263 Component {
264 id: drawerDelegateComponent
265 AbstractButton {
266 width: GridView.view.cellWidth
267 height: units.gu(10)
268 objectName: "drawerItem_" + model.appId
269
270 onClicked: root.applicationSelected(model.appId)
271
272 Column {
273 width: units.gu(8)
274 anchors.horizontalCenter: parent.horizontalCenter
275 height: childrenRect.height
276 spacing: units.gu(1)
277
278 UbuntuShape {
279 id: appIcon
280 width: units.gu(6)
281 height: 7.5 / 8 * width
282 anchors.horizontalCenter: parent.horizontalCenter
283 backgroundMode: UbuntuShape.SolidColor
284 backgroundColor: UbuntuColors.lightGrey
285 radius: "medium"
286 borderSource: 'undefined'
287 source: Image {
288 id: sourceImage
289 sourceSize.width: appIcon.width
290 source: model.icon
291 }
292 sourceFillMode: UbuntuShape.PreserveAspectCrop
293 }
294
295 Label {
296 text: model.name
297 width: parent.width
298 horizontalAlignment: Text.AlignHCenter
299 fontSize: "small"
300 elide: Text.ElideRight
301 }
302 }
303 }
304 }
305 }
306}
0307
=== added file 'qml/Launcher/DrawerGridView.qml'
--- qml/Launcher/DrawerGridView.qml 1970-01-01 00:00:00 +0000
+++ qml/Launcher/DrawerGridView.qml 2016-12-12 16:49:02 +0000
@@ -0,0 +1,47 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import "../Components"
19
20Item {
21 id: root
22
23 property int delegateWidth: units.gu(10)
24 property int delegateHeight: units.gu(10)
25 property alias delegate: gridView.delegate
26 property alias model: gridView.model
27 property alias interactive: gridView.interactive
28
29 property alias header: gridView.header
30 property alias topMargin: gridView.topMargin
31 property alias bottomMargin: gridView.bottomMargin
32
33 readonly property int columns: width / delegateWidth
34 readonly property int rows: Math.ceil(gridView.model.count / root.columns)
35
36 GridView {
37 id: gridView
38 anchors.fill: parent
39 leftMargin: spacing
40
41 readonly property int overflow: width - (root.columns * root.delegateWidth)
42 readonly property real spacing: overflow / (root.columns)
43
44 cellWidth: root.delegateWidth + spacing
45 cellHeight: root.delegateHeight
46 }
47}
048
=== added file 'qml/Launcher/DrawerListView.qml'
--- qml/Launcher/DrawerListView.qml 1970-01-01 00:00:00 +0000
+++ qml/Launcher/DrawerListView.qml 2016-12-12 16:49:02 +0000
@@ -0,0 +1,32 @@
1/*
2 * Copyright (C) 2016 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.4
18import Ubuntu.Components 1.3
19import "../Components"
20
21ListView {
22 id: root
23 anchors.fill: parent
24 topMargin: units.gu(1)
25 bottomMargin: units.gu(1)
26 spacing: units.gu(1)
27 clip: true
28
29 function getFirstAppId() {
30 return model.appId(0);
31 }
32}
033
=== modified file 'qml/Launcher/Launcher.qml'
--- qml/Launcher/Launcher.qml 2016-09-22 10:14:18 +0000
+++ qml/Launcher/Launcher.qml 2016-12-12 16:49:02 +0000
@@ -19,18 +19,23 @@
19import Ubuntu.Components 1.319import Ubuntu.Components 1.3
20import Ubuntu.Gestures 0.120import Ubuntu.Gestures 0.1
21import Unity.Launcher 0.121import Unity.Launcher 0.1
22import Utils 0.1 as Utils
2223
23FocusScope {24FocusScope {
24 id: root25 id: root
2526
27 readonly property int ignoreHideIfMouseOverLauncher: 1
28
26 property bool autohideEnabled: false29 property bool autohideEnabled: false
27 property bool lockedVisible: false30 property bool lockedVisible: false
28 property bool available: true // can be used to disable all interactions31 property bool available: true // can be used to disable all interactions
29 property alias inverted: panel.inverted32 property alias inverted: panel.inverted
33 property Item blurSource: null
34 property int topPanelHeight: 0
35 property bool drawerEnabled: true
3036
31 property int panelWidth: units.gu(10)37 property int panelWidth: units.gu(10)
32 property int dragAreaWidth: units.gu(1)38 property int dragAreaWidth: units.gu(1)
33 property int minimizeDistance: units.gu(26)
34 property real progress: dragArea.dragging && dragArea.touchPosition.x > panelWidth ?39 property real progress: dragArea.dragging && dragArea.touchPosition.x > panelWidth ?
35 (width * (dragArea.touchPosition.x-panelWidth) / (width - panelWidth)) : 040 (width * (dragArea.touchPosition.x-panelWidth) / (width - panelWidth)) : 0
3641
@@ -43,13 +48,11 @@
43 readonly property alias shortcutHintsShown: panel.shortcutHintsShown48 readonly property alias shortcutHintsShown: panel.shortcutHintsShown
4449
45 readonly property bool shown: panel.x > -panel.width50 readonly property bool shown: panel.x > -panel.width
51 readonly property bool drawerShown: drawer.x == 0
4652
47 // emitted when an application is selected53 // emitted when an application is selected
48 signal launcherApplicationSelected(string appId)54 signal launcherApplicationSelected(string appId)
4955
50 // emitted when the apps dash should be shown because of a swipe gesture
51 signal dash()
52
53 // emitted when the dash icon in the launcher has been tapped56 // emitted when the dash icon in the launcher has been tapped
54 signal showDashHome()57 signal showDashHome()
5558
@@ -62,6 +65,9 @@
62 }65 }
6366
64 onSuperPressedChanged: {67 onSuperPressedChanged: {
68 if (state == "drawer")
69 return;
70
65 if (superPressed) {71 if (superPressed) {
66 superPressTimer.start();72 superPressTimer.start();
67 superLongPressTimer.start();73 superLongPressTimer.start();
@@ -102,7 +108,10 @@
102 }108 }
103 }109 }
104110
105 function hide() {111 function hide(flags) {
112 if ((flags & ignoreHideIfMouseOverLauncher) && Utils.Functions.itemUnderMouse(panel)) {
113 return;
114 }
106 switchToNextState("")115 switchToNextState("")
107 }116 }
108117
@@ -132,7 +141,7 @@
132 }141 }
133142
134 function pushEdge(amount) {143 function pushEdge(amount) {
135 if (root.state === "") {144 if (root.state === "" || root.state == "visible" || root.state == "visibleTemporary") {
136 edgeBarrier.push(amount);145 edgeBarrier.push(amount);
137 }146 }
138 }147 }
@@ -143,6 +152,22 @@
143 switchToNextState("visible")152 switchToNextState("visible")
144 }153 }
145154
155 function openDrawer(focusInputField) {
156 if (!drawerEnabled) {
157 return;
158 }
159
160 panel.shortcutHintsShown = false;
161 superPressTimer.stop();
162 superLongPressTimer.stop();
163 root.focus = true;
164 drawer.focus = true;
165 if (focusInputField) {
166 drawer.focusInput();
167 }
168 switchToNextState("drawer")
169 }
170
146 Keys.onPressed: {171 Keys.onPressed: {
147 switch (event.key) {172 switch (event.key) {
148 case Qt.Key_Backtab:173 case Qt.Key_Backtab:
@@ -278,7 +303,7 @@
278 InverseMouseArea {303 InverseMouseArea {
279 id: closeMouseArea304 id: closeMouseArea
280 anchors.fill: panel305 anchors.fill: panel
281 enabled: root.state == "visible" && (!root.lockedVisible || panel.highlightIndex >= -1)306 enabled: root.state == "visible" || root.state == "drawer"
282 visible: enabled307 visible: enabled
283 onPressed: {308 onPressed: {
284 mouse.accepted = false;309 mouse.accepted = false;
@@ -307,23 +332,61 @@
307 }332 }
308 }333 }
309334
310 EdgeBarrier {335 BackgroundBlur {
311 id: edgeBarrier336 id: backgroundBlur
312 edge: Qt.LeftEdge337 anchors.fill: parent
313 target: parent338 anchors.topMargin: root.inverted ? 0 : -root.topPanelHeight
314 enabled: root.available339 visible: root.blurSource && drawer.x > -drawer.width
315 onPassed: { root.switchToNextState("visibleTemporary"); }340 blurAmount: units.gu(6)
316 material: Component {341 sourceItem: root.blurSource
317 Item {342 blurRect: Qt.rect(panel.width,
318 Rectangle {343 root.topPanelHeight,
319 width: parent.height344 drawer.width + drawer.x - panel.width,
320 height: parent.width345 height - root.topPanelHeight)
321 rotation: -90346 cached: drawer.moving
322 anchors.centerIn: parent347 }
323 gradient: Gradient {348
324 GradientStop { position: 0.0; color: Qt.rgba(panel.color.r, panel.color.g, panel.color.b, .5)}349 Drawer {
325 GradientStop { position: 1.0; color: Qt.rgba(panel.color.r,panel.color.g,panel.color.b,0)}350 id: drawer
326 }351 objectName: "drawer"
352 anchors {
353 top: parent.top
354 topMargin: root.inverted ? root.topPanelHeight : 0
355 bottom: parent.bottom
356 right: parent.left
357 }
358 width: Math.min(root.width, units.gu(90)) * .9
359 panelWidth: panel.width
360 visible: x > -width
361
362 Behavior on anchors.rightMargin {
363 enabled: !dragArea.dragging && !launcherDragArea.drag.active && panel.animate && !drawer.draggingHorizontally
364 NumberAnimation {
365 duration: 300
366 easing.type: Easing.OutCubic
367 }
368 }
369
370 onApplicationSelected: {
371 root.hide();
372 root.launcherApplicationSelected(appId)
373 root.focus = false;
374 }
375
376 Keys.onEscapePressed: {
377 switchToNextState("");
378 root.focus = false;
379 }
380
381 onDragDistanceChanged: {
382 anchors.rightMargin = Math.max(-drawer.width, anchors.rightMargin + dragDistance);
383 }
384 onDraggingHorizontallyChanged: {
385 if (!draggingHorizontally) {
386 if (drawer.x < -units.gu(10)) {
387 root.hide();
388 } else {
389 root.openDrawer();
327 }390 }
328 }391 }
329 }392 }
@@ -332,7 +395,7 @@
332 LauncherPanel {395 LauncherPanel {
333 id: panel396 id: panel
334 objectName: "launcherPanel"397 objectName: "launcherPanel"
335 enabled: root.available && root.state == "visible" || root.state == "visibleTemporary"398 enabled: root.available && (root.state == "visible" || root.state == "visibleTemporary" || root.state == "drawer")
336 width: root.panelWidth399 width: root.panelWidth
337 anchors {400 anchors {
338 top: parent.top401 top: parent.top
@@ -359,11 +422,11 @@
359 property bool animate: true422 property bool animate: true
360423
361 onApplicationSelected: {424 onApplicationSelected: {
362 root.hide();425 root.hide(ignoreHideIfMouseOverLauncher);
363 launcherApplicationSelected(appId)426 launcherApplicationSelected(appId)
364 }427 }
365 onShowDashHome: {428 onShowDashHome: {
366 root.hide();429 root.hide(ignoreHideIfMouseOverLauncher);
367 root.showDashHome();430 root.showDashHome();
368 }431 }
369432
@@ -394,6 +457,38 @@
394 }457 }
395 }458 }
396459
460 EdgeBarrier {
461 id: edgeBarrier
462 edge: Qt.LeftEdge
463 target: parent
464 enabled: root.available
465 onProgressChanged: {
466 if (progress > .5 && root.state != "visibleTemporary" && root.state != "drawer" && root.state != "visible") {
467 root.switchToNextState("visibleTemporary");
468 }
469 }
470 onPassed: {
471 if (root.drawerEnabled) {
472 root.switchToNextState("drawer");
473 }
474 }
475
476 material: Component {
477 Item {
478 Rectangle {
479 width: parent.height
480 height: parent.width
481 rotation: -90
482 anchors.centerIn: parent
483 gradient: Gradient {
484 GradientStop { position: 0.0; color: Qt.rgba(panel.color.r, panel.color.g, panel.color.b, .5)}
485 GradientStop { position: 1.0; color: Qt.rgba(panel.color.r,panel.color.g,panel.color.b,0)}
486 }
487 }
488 }
489 }
490 }
491
397 SwipeArea {492 SwipeArea {
398 id: dragArea493 id: dragArea
399 objectName: "launcherDragArea"494 objectName: "launcherDragArea"
@@ -405,25 +500,62 @@
405 width: root.dragAreaWidth500 width: root.dragAreaWidth
406 height: root.height501 height: root.height
407502
503 function easeInOutCubic(t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 }
504
505 property var lastDragPoints: []
506
507 function dragDirection() {
508 if (lastDragPoints.length < 5) {
509 return "unknown";
510 }
511
512 var toRight = true;
513 var toLeft = true;
514 for (var i = lastDragPoints.length - 5; i < lastDragPoints.length; i++) {
515 if (toRight && lastDragPoints[i] < lastDragPoints[i-1]) {
516 toRight = false;
517 }
518 if (toLeft && lastDragPoints[i] > lastDragPoints[i-1]) {
519 toLeft = false;
520 }
521 }
522 return toRight ? "right" : toLeft ? "left" : "unknown";
523 }
524
408 onDistanceChanged: {525 onDistanceChanged: {
409 if (!dragging || launcher.state == "visible")526 if (dragging && launcher.state != "visible" && launcher.state != "drawer") {
410 return;527 panel.x = -panel.width + Math.min(Math.max(0, distance), panel.width);
528 }
411529
412 panel.x = -panel.width + Math.min(Math.max(0, distance), panel.width);530 if (root.drawerEnabled && dragging && launcher.state != "drawer") {
531 lastDragPoints.push(distance)
532 var drawerHintDistance = panel.width + units.gu(1)
533 if (distance < drawerHintDistance) {
534 drawer.anchors.rightMargin = -Math.min(Math.max(0, distance), drawer.width);
535 } else {
536 var linearDrawerX = Math.min(Math.max(0, distance - drawerHintDistance), drawer.width);
537 var linearDrawerProgress = linearDrawerX / (drawer.width)
538 var easedDrawerProgress = easeInOutCubic(linearDrawerProgress);
539 drawer.anchors.rightMargin = -(drawerHintDistance + easedDrawerProgress * (drawer.width - drawerHintDistance));
540 }
541 }
413 }542 }
414543
415 onDraggingChanged: {544 onDraggingChanged: {
416 if (!dragging) {545 if (!dragging) {
417 if (distance > panel.width / 2) {546 if (distance > panel.width / 2) {
418 root.switchToNextState("visible")547 if (root.drawerEnabled && distance > panel.width * 3 && dragDirection() !== "left") {
419 if (distance > minimizeDistance) {548 root.switchToNextState("drawer");
420 root.dash();549 root.focus = true;
550 } else {
551 root.switchToNextState("visible");
421 }552 }
422 } else if (root.state === "") {553 } else if (root.state === "") {
423 // didn't drag far enough. rollback554 // didn't drag far enough. rollback
424 root.switchToNextState("")555 root.switchToNextState("");
425 }556 }
426 }557 }
558 lastDragPoints = [];
427 }559 }
428 }560 }
429561
@@ -434,6 +566,10 @@
434 target: panel566 target: panel
435 x: -root.panelWidth567 x: -root.panelWidth
436 }568 }
569 PropertyChanges {
570 target: drawer
571 anchors.rightMargin: 0
572 }
437 },573 },
438 State {574 State {
439 name: "visible"575 name: "visible"
@@ -441,6 +577,18 @@
441 target: panel577 target: panel
442 x: -root.x // so we never go past panelWidth, even when teased by tutorial578 x: -root.x // so we never go past panelWidth, even when teased by tutorial
443 }579 }
580 PropertyChanges {
581 target: drawer
582 anchors.rightMargin: 0
583 }
584 },
585 State {
586 name: "drawer"
587 extend: "visible"
588 PropertyChanges {
589 target: drawer
590 anchors.rightMargin: -drawer.width + root.x // so we never go past panelWidth, even when teased by tutorial
591 }
444 },592 },
445 State {593 State {
446 name: "visibleTemporary"594 name: "visibleTemporary"
447595
=== added file 'qml/Launcher/MoreAppsHeader.qml'
--- qml/Launcher/MoreAppsHeader.qml 1970-01-01 00:00:00 +0000
+++ qml/Launcher/MoreAppsHeader.qml 2016-12-12 16:49:02 +0000
@@ -0,0 +1,46 @@
1import QtQuick 2.4
2import Ubuntu.Components 1.3
3
4AbstractButton {
5 id: root
6
7 onClicked: {
8 // TODO: Make this point to the snappy store as soon as we stop landing to vivid
9 Qt.openUrlExternally("scope://com.canonical.scopes.clickstore")
10 }
11
12 UbuntuShape {
13 width: parent.width
14 height: parent.height - units.gu(1)
15 color: "#20ffffff"
16 aspect: UbuntuShape.Flat
17
18 Row {
19 anchors.fill: parent
20 anchors.margins: units.gu(1)
21 spacing: units.gu(1)
22
23 Icon {
24 height: units.gu(2.2)
25 width: height
26 name: "stock_application"
27 anchors.verticalCenter: parent.verticalCenter
28 color: "white"
29 }
30
31 Label {
32 text: i18n.tr("More apps in the store")
33 anchors.verticalCenter: parent.verticalCenter
34 fontSize: "small"
35 }
36
37 Icon {
38 height: units.gu(2.5)
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches