Merge lp:~ci-train-bot/unity8/unity8-ubuntu-xenial-landing-022 into lp:unity8
- unity8-ubuntu-xenial-landing-022
- Merge into trunk
| Status: | Merged |
|---|---|
| Merged at revision: | 2096 |
| Proposed branch: | lp:~ci-train-bot/unity8/unity8-ubuntu-xenial-landing-022 |
| Merge into: | lp:unity8 |
| Diff against target: |
5795 lines (+3025/-1212) 103 files modified
CMakeLists.txt (+4/-1) data/unity8.conf (+10/-0) debian/changelog (+36/-0) debian/control (+9/-7) debian/copyright (+21/-0) debian/unity8-private.install (+1/-0) debian/unity8.install (+1/-0) plugins/CMakeLists.txt (+1/-0) plugins/Cursor/3rd_party/CMakeLists.txt (+1/-0) plugins/Cursor/3rd_party/xcursor/CMakeLists.txt (+15/-0) plugins/Cursor/3rd_party/xcursor/xcursor.c (+968/-0) plugins/Cursor/3rd_party/xcursor/xcursor.h (+65/-0) plugins/Cursor/CMakeLists.txt (+28/-0) plugins/Cursor/Cursor.qml (+12/-0) plugins/Cursor/CursorImageProvider.cpp (+191/-0) plugins/Cursor/CursorImageProvider.h (+76/-0) plugins/Cursor/MousePointer.cpp (+125/-0) plugins/Cursor/MousePointer.h (+59/-0) plugins/Cursor/plugin.cpp (+39/-0) plugins/Cursor/plugin.h (+33/-0) plugins/Cursor/qmldir (+3/-0) plugins/IntegratedLightDM/UsersModel.cpp (+7/-6) plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp (+2/-1) plugins/ScreenGrabber/screengrabber.cpp (+2/-2) plugins/ScreenGrabber/screengrabber.h (+1/-1) plugins/Unity/CMakeLists.txt (+1/-0) plugins/Unity/Launcher/desktopfilehandler.cpp (+3/-2) plugins/Unity/Platform/CMakeLists.txt (+9/-0) plugins/Unity/Platform/platform.cpp (+43/-0) plugins/Unity/Platform/platform.h (+58/-0) plugins/Unity/Platform/plugin.cpp (+27/-0) plugins/Unity/Platform/plugin.h (+32/-0) plugins/Unity/Platform/qmldir (+2/-0) plugins/Unity/Session/dbusunitysessionservice.cpp (+2/-1) plugins/Utils/CMakeLists.txt (+0/-2) plugins/Utils/plugin.cpp (+0/-5) plugins/Utils/relativetimeformatter.cpp (+0/-260) plugins/Utils/relativetimeformatter.h (+0/-34) plugins/Utils/timeformatter.cpp (+0/-206) plugins/Utils/timeformatter.h (+0/-68) plugins/Utils/timezoneFormatter.cpp (+1/-1) qml/Components/Dialogs.qml (+3/-2) qml/Components/ScreenGrabber.qml (+4/-1) qml/Components/WallpaperResolver.qml (+63/-0) qml/DeviceConfiguration.qml (+1/-0) qml/DisabledScreenNotice.qml (+49/-0) qml/Greeter/Greeter.qml (+1/-1) qml/Launcher/Launcher.qml (+1/-0) qml/Notifications/Notification.qml (+2/-0) qml/Notifications/NotificationMenuItemFactory.qml (+2/-1) qml/Notifications/Notifications.qml (+2/-0) qml/OrientedShell.qml (+10/-1) qml/Panel/Indicators/MenuItemFactory.qml (+19/-15) qml/Panel/Indicators/MessageMenuItemFactory.qml (+35/-26) qml/Panel/Panel.qml (+1/-0) qml/Rotation/RotationStates.qml (+2/-2) qml/Shell.qml (+24/-40) qml/Stages/ApplicationWindow.qml (+2/-0) qml/Stages/DecoratedWindow.qml (+7/-4) qml/Stages/DesktopStage.qml (+5/-8) qml/Stages/SurfaceContainer.qml (+1/-0) qml/Stages/WindowDecoration.qml (+32/-4) qml/Stages/WindowResizeArea.qml (+135/-62) src/ApplicationArguments.h (+10/-2) src/CMakeLists.txt (+3/-0) src/SecondaryWindow.cpp (+31/-0) src/SecondaryWindow.h (+30/-0) src/ShellApplication.cpp (+197/-0) src/ShellApplication.h (+55/-0) src/ShellView.cpp (+59/-0) src/ShellView.h (+34/-0) src/main.cpp (+4/-101) tests/autopilot/unity8/fixture_setup.py (+1/-1) tests/autopilot/unity8/greeter/tests/__init__.py (+1/-1) tests/autopilot/unity8/launcher.py (+1/-1) tests/autopilot/unity8/settings_wizard/__init__.py (+7/-2) tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py (+10/-5) tests/autopilot/unity8/shell/__init__.py (+1/-1) tests/autopilot/unity8/shell/tests/__init__.py (+1/-1) tests/mocks/CMakeLists.txt (+1/-0) tests/mocks/Cursor/CMakeLists.txt (+1/-0) tests/mocks/Cursor/Cursor.qml (+20/-0) tests/mocks/Cursor/qmldir (+2/-0) tests/mocks/Unity/Launcher/MockQuickListModel.cpp (+1/-1) tests/mocks/Unity/fake_resultsmodel.cpp (+1/-1) tests/mocks/Unity/fake_scopesoverview.cpp (+1/-1) tests/mocks/Utils/CMakeLists.txt (+0/-2) tests/mocks/Utils/Utils.qmltypes (+31/-28) tests/mocks/Utils/plugin.cpp (+0/-13) tests/plugins/ScreenGrabber/ScreenGrabberTest.cpp (+11/-0) tests/plugins/ScreenGrabber/grabber.qml (+1/-1) tests/plugins/Unity/Indicators/UnityMenuModelStackTest.cpp (+2/-9) tests/plugins/Utils/CMakeLists.txt (+0/-1) tests/plugins/Utils/TimeFormatterTest.cpp (+0/-155) tests/plugins/Wizard/tst_pagelist.cpp (+5/-5) tests/qmltests/CMakeLists.txt (+3/-1) tests/qmltests/Components/tst_WallpaperResolver.qml (+89/-0) tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml (+6/-16) tests/qmltests/Panel/Indicators/tst_MessageMenuItemFactory.qml (+6/-13) tests/qmltests/Stages/tst_WindowResizeArea.qml (+18/-61) tests/qmltests/tst_DisabledScreenNotice.qml (+37/-0) tests/qmltests/tst_OrientedShell.qml (+55/-1) tests/qmltests/tst_Shell.qml (+0/-24) |
| To merge this branch: | bzr merge lp:~ci-train-bot/unity8/unity8-ubuntu-xenial-landing-022 |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Unity Team | 2015-10-26 | Pending | |
|
Review via email:
|
|||
Commit Message
Description of the Change
Only use this to base new silos on this one.
- 2018. By CI Train Bot Account on 2015-10-26
-
Resync trunk.
- 2019. By Michał Sawicz on 2015-10-26
-
Add missing copyright to Cursor.qml
Approved by: Albert Astals Cid
- 2020. By Launchpad Translations on behalf of unity-team on 2015-10-28
-
Launchpad automatic translations update.
- 2021. By Launchpad Translations on behalf of unity-team on 2015-10-30
-
Launchpad automatic translations update.
- 2022. By Daniel d'Andrada on 2015-11-04
-
Use SDK 1.3 across all files Fixes: #1449628, #1503498, #1508363
Approved by: PS Jenkins bot - 2023. By Andrea Cimitan on 2015-11-04
-
Updated all 1.3 UbuntuShape to use new APIs where possible
Approved by: Albert Astals Cid - 2024. By Andrea Cimitan on 2015-11-04
-
Make zoomable and video playback widgets edge to edge
Approved by: Albert Astals Cid - 2025. By Andrea Cimitan on 2015-11-04
-
Add sharing widget to zoomable image and video playback
Approved by: Albert Astals Cid, Pawel Stolowski - 2026. By Albert Astals Cid on 2015-11-04
-
Make the scope settings list scroll to text visible area
Fixes: #1499084
Approved by: Michael Terry - 2027. By Albert Astals Cid on 2015-11-04
-
Move to importing QtQuick 2.4 & friends
This means we obviously require Qt 5.4 or greater, we had for a while
but make it official now
Approved by: Michael Terry - 2028. By Albert Astals Cid on 2015-11-04
-
Add an Item that proxies for old and new audio roles Fixes: #1493851
- 2029. By Michael Zanetti on 2015-11-04
-
Fixes for the panel buttons
* Hide panel buttons when switching to staged mode
* properly save/restore window states, not just geometry Fixes: #1431566, #1443319, #1504269, #1510360
Approved by: Lukáš Tinkl - 2030. By Michał Sawicz on 2015-11-04
-
Enable support for overriding application orientations based on device type Fixes: #1478637
- 2031. By Michael Terry on 2015-11-04
-
Handle lifecycle policy exceptions ourselves, instead of letting qtmir do it for us and allow non-Touch apps to opt-out of the Touch lifecycle.
This requires using the new isTouchApp unity-api property to ApplicationInfo
Interface. Now that qtmir won't decide policy for suspending exemptions anymore, we take over the interpretation of the lifecycleException GSettings key. Since the GSettings key for that was registered under the qtmir namespace (and there's no technical reason to migrate settings), I left the schema in qtmir itself. We merely consume it.
- 2032. By Michał Sawicz on 2015-11-04
-
Support server->client visibility change to stop rendering (lp:#1475678) Fixes: #1475678
Approved by: Daniel d'Andrada - 2033. By Christopher Lee on 2015-11-04
-
Quick spelling fix in process control output.
Approved by: Albert Astals Cid - 2034. By Albert Astals Cid on 2015-11-04
-
CroppedImageMin
imumSourceSize: Fix 'Binding loop detected for property "imageAspectRatio"' Approved by: Gerry Boland, Michał Sawicz
- 2035. By Michael Terry on 2015-11-04
-
Avoid showing the shutdown dialog when turning on the screen if your device is under heavy load.
Specifically, we actually watch the timestamp of input events as they come in to determine how long it's been. This means that if for whatever reason, processing of events get delayed, we don't misinterpret user input.
To test this, try running the following command and then turning the screen on and off again:
sudo cpulimit -l 1 -c 1 -p `ps ax | grep dbus-daemon | head -n 1 | awk '{print $1;}'`Without this branch, you'll notice that at some point, you see the shutdown dialog in error. Because unity8 couldn't keep up with events and thought 2s passed between power-pressed and power-released events.
But if we watch the timestamps, we can avoid that particular fate. Fixes: #1508563
Approved by: Albert Astals Cid, Michael Zanetti - 2036. By CI Train Bot Account on 2015-11-04
-
Releasing 8.11+16.
04.20151104- 0ubuntu1 - 2037. By Launchpad Translations on behalf of unity-team on 2015-11-07
-
Launchpad automatic translations update.
- 2038. By Launchpad Translations on behalf of unity-team on 2015-11-08
-
Launchpad automatic translations update.
- 2039. By Launchpad Translations on behalf of unity-team on 2015-11-11
-
Launchpad automatic translations update.
- 2040. By Michael Terry on 2015-11-12
-
Make a few DBus calls asynchronous, for a smoother UX.
The calls I've changed here are neither hugely important nor frequent calls. But every little bit helps.
- Made a few sync calls async.
- Made a few sync calls more obviously sync. We had several instances of asyncCall()'s return value -- a QDBusPendingReply -- being assigned to a QDBusReply variable, which makes it wait for the call to finish. In cases where it didn't make sense to rewrite logic to be async, I've merely changed the method to be call() instead of asyncCall() for clarity.
- I removed the API in our AccountsService plugin for even making sync calls. This won't stop future developers from from writing sync code, but might give them pause.
- I removed some test mocks for our AccountsService plugin interface and changed those tests to use our actual AS plugin against a mock AS server. In truth, this change was because I had a devil of a time crafting a fake reply that included a custom complex type. But it's a good change anyway. Exercises more of our code in tests and reduces duplicated interfaces.
Approved by: Albert Astals Cid - 2041. By Daniel d'Andrada on 2015-11-12
-
Cursor: properly initialize hotspot position Fixes: #1510407
Approved by: Gerry Boland - 2042. By Albert Astals Cid on 2015-11-12
-
Warn we're using only the cache when not connected to the interwebs
Approved by: Michael Terry
- 2043. By Michael Zanetti on 2015-11-12
-
added icon for the dash Fixes: #1488146
Approved by: Albert Astals Cid, Lukáš Tinkl - 2044. By Daniel d'Andrada on 2015-11-12
-
Update GSettings mock in tst_OrientedShell
Gets rid of the following warning:
OrientedShell.qml:76: Error: Cannot assign to non-existent property "disableHeight"
Approved by: Albert Astals Cid - 2045. By Andrea Cimitan on 2015-11-12
-
Add sharing widget to zoomable image and video playback
Approved by: Albert Astals Cid, Pawel Stolowski - 2046. By Lukáš Tinkl on 2015-11-12
-
Restore windows when activating from the spread, maintain a focus stack
Stop displaying the "grabbing" icon when we merely click to focus the app's decoration.
Provide keyboard shortcuts for common window operations
Approved by: Michael Zanetti - 2047. By Michael Zanetti on 2015-11-12
-
prevent windows to be moved under the panel
If they happen to have a saved state which is under the panel
(might happen on alt+drag later), they will be moved below the panel
on close and reopen. This is how unity7 behaves in this regard. Fixes: #1438465
Approved by: Lukáš Tinkl - 2048. By Michael Zanetti on 2015-11-12
-
use UbuntuNumberAni
mations instead of linear ones for window state transitions Fixes: #1497097
Approved by: Lukáš Tinkl - 2049. By Albert Astals Cid on 2015-11-12
-
Make cardWidth and cardHeight real
If they are var the properties depending on them get reevaluated even if they don't change
Approved by: Michael Zanetti - 2050. By Michael Zanetti on 2015-11-12
-
update inputinfo api to the latest upstream snapshot
* Import latest update of api from gerrit.
* drop all the old mock code
* instead of mocking the whole api, add mocks for the backend only. This should simplify future updates and moving to upstream implementation a lot.
* update tests to use new mocking system
Approved by: Lukáš Tinkl - 2051. By Michael Zanetti on 2015-11-12
-
Add a warning dialog when disconnecting the external monitor.
In case there are still legacy apps running, the dialog forces the user to reconnect the external monitor, or close all the legacy apps.
Approved by: Daniel d'Andrada - 2052. By Albert Astals Cid on 2015-11-12
-
Reset instead of qFatal when removing things from the middle
This can be optimized but let's see how this behaves, at least we won't qFatal anymore :D Fixes: #1238979
Approved by: Andrea Cimitan - 2053. By CI Train Bot Account on 2015-11-12
-
Releasing 8.11+16.
04.20151112. 1-0ubuntu1 - 2054. By CI Train Bot Account on 2015-11-20
-
Resync trunk.
- 2055. By Launchpad Translations on behalf of unity-team on 2015-11-21
-
Launchpad automatic translations update.
- 2056. By Launchpad Translations on behalf of unity-team on 2015-11-23
-
Launchpad automatic translations update.
- 2057. By Josh Arenson on 2015-11-26
-
Don't let IntegratedLightDM muck with the username Fixes: #1497081
Approved by: Lukáš Tinkl - 2058. By Michael Zanetti on 2015-11-26
-
move screenshots out of the Dash dir
This was consuming 2.5 megs of installed size while they really are
only used for testing.
Approved by: Albert Astals Cid - 2059. By Daniel d'Andrada on 2015-11-26
-
Don't stretch application surfaces when resizing Fixes: #1497083
Approved by: Michael Zanetti - 2060. By Lukáš Tinkl on 2015-11-26
-
Implement new visuals for panel and window decorations Fixes: #1493066, #1497095, #1511020
Approved by: Daniel d'Andrada - 2061. By Daniel d'Andrada on 2015-11-26
-
Mouse has to push against edges to show launcher or apps spread
edge-barrier-
sensitivity is the property that should show up in the System Settings GUI. edge-barrier-
min-push and edge-barrier- max-push are exposed in GSettings merely as a convenience so you can tweak those values without having to restart unity8. But they should NOT show up in system settings. Fixes: #1510969
Approved by: Michael Zanetti - 2062. By Daniel d'Andrada on 2015-11-26
-
DesktopStage: swiping from right edge shows window spread
Approved by: Lukáš Tinkl - 2063. By Daniel d'Andrada on 2015-11-26
-
Cursor: Add more fallback names, a blank and custom cursor support
Approved by: Lukáš Tinkl - 2064. By Albert Astals Cid on 2015-11-26
-
clazy improvements
Pass small (<=16 bytes) and trivially-
copyable[ 1] and trivially- destructible [2] type by value [3]
Don't call QList::operator[]() on temporary
Fix QString(const char*) being called
Use qEnvironmentVariableIsEmpty( ) instead of qgetenv().isEmpty()
Use the multiarg arg()
use Q_FOREACH for non const qt containers
delete copy constructor and assignment operator for non copyable class
remove assignment operator that does the same as the default one[1] http://
en.cppreference .com/w/ cpp/concept/ TriviallyCopyab le
[2] http://www.cplusplus. com/reference/ type_traits/ is_trivially_ destructible/
[3] http://www.macieira. org/blog/ 2012/02/ the-value- of-passing- by-value/ - 2065. By Lukáš Tinkl on 2015-11-26
-
Make saving screenshots really async
Approved by: Michael Zanetti - 2066. By Albert Astals Cid on 2015-11-26
-
Initialize the image to be transparent
Otherwise since we're not painting all the pixels we get noise Fixes: #1517128
Approved by: Daniel d'Andrada - 2067. By Daniel d'Andrada on 2015-11-26
-
Cursor plugin: add scroll wheel handling Fixes: #1497091
Approved by: Lukáš Tinkl - 2068. By Albert Astals Cid on 2015-11-26
-
Update pot file
Approved by: Lukáš Tinkl, Michael Terry
- 2069. By Michael Zanetti on 2015-11-26
-
detect touchpads too, not only mice Fixes: #1518395
Approved by: Lukáš Tinkl, Daniel d'Andrada - 2070. By Lukáš Tinkl on 2015-11-26
-
Let systemd/logind handle the lid-close action
Approved by: Michael Zanetti - 2071. By Andrea Cimitan on 2015-11-26
-
Shadows in launcher and dash using UbuntuShapeIcon
Approved by: Michael Zanetti, Albert Astals Cid - 2072. By CI Train Bot Account on 2015-11-26
-
Releasing 8.11+16.
04.20151126- 0ubuntu1 - 2073. By CI Train Bot Account on 2015-11-29
-
Resync trunk.
- 2074. By Launchpad Translations on behalf of unity-team on 2015-11-30
-
Launchpad automatic translations update.
- 2075. By Launchpad Translations on behalf of unity-team on 2015-12-01
-
Launchpad automatic translations update.
- 2076. By Timo Jyrinki on 2015-12-01
-
Rebuild against Qt 5.5.1.
- 2077. By Launchpad Translations on behalf of unity-team on 2015-12-02
-
Launchpad automatic translations update.
- 2078. By Launchpad Translations on behalf of unity-team on 2015-12-05
-
Launchpad automatic translations update.
- 2079. By Launchpad Translations on behalf of unity-team on 2015-12-07
-
Launchpad automatic translations update.
- 2080. By Daniel d'Andrada on 2015-12-08
-
MirSurfaceItem got a new property: fillMode
And put it to use in SurfaceContainer. That's the final piece to finally get rid of stretched windows Fixes: #1497083
- 2081. By Daniel d'Andrada on 2015-12-08
-
Session can have multiple surfaces now
As a first step, we just display the latest surface for each application.
- 2082. By Michael Terry on 2015-12-08
-
Let qtmir know which apps are exempt from the lifecycle management.
This way, it can manage its own wakelocks better (and stop preventing the system from deep sleeping). - 2083. By Albert Astals Cid on 2015-12-08
-
Make sure that unfavoriting a scope gives us the next one
This is currently broken due to a regression in the Qt Quick ListView
Approved by: Michael Zanetti - 2084. By Albert Astals Cid on 2015-12-08
-
Create ratings on demand instead of all at the same time
Fixes: #1492214, #1519898
Approved by: Michael Zanetti - 2085. By Andrea Cimitan on 2015-12-08
-
Add shadows to ubuntu store icon
Approved by: Albert Astals Cid - 2086. By Albert Astals Cid on 2015-12-08
-
Move images only used in tests to tests folder
Approved by: Michael Zanetti - 2087. By Lukáš Tinkl on 2015-12-08
-
Indicators convergence: use the "phone" profile everywhere Fixes: #1520492
Approved by: Albert Astals Cid - 2088. By Albert Astals Cid on 2015-12-08
-
LVWPH: Process correctly section changes Fixes: #1519893
Approved by: Michael Zanetti - 2089. By Daniel d'Andrada on 2015-12-08
-
plugins/Cursor: Do not force loading a specific cursor size Fixes: #1517878
Approved by: Lukáš Tinkl - 2090. By Michael Zanetti on 2015-12-08
-
drop the ignoredMice hack again
the new inputinfo backend seems to be clever enough to not
wrongly detect the hardware in there as real a real mouse Fixes: #1521580
Approved by: Daniel d'Andrada - 2091. By Michael Zanetti on 2015-12-08
-
add some debug prints to the uinput backend
this should make debugging bug reports easier
Approved by: Michael Terry - 2092. By Michał Sawicz on 2015-12-08
-
Update .pot file in debian/clean when in train
Approved by: Didier Roche, Robert Bruce Park - 2093. By Albert Astals Cid on 2015-12-08
-
Allow dragging launcher items with the quicklist open
Fixes: #1250861
Approved by: Michael Zanetti - 2094. By Michael Zanetti on 2015-12-08
-
Use proper z ordering instead of app index for occlusion detection
Approved by: Nick Dedekind - 2095. By CI Train Bot Account on 2015-12-08
-
Releasing 8.11+16.
04.20151208. 1-0ubuntu1 - 2096. By CI Train Bot Account on 2015-12-08
-
Update translation template
Preview Diff
| 1 | === modified file 'CMakeLists.txt' |
| 2 | --- CMakeLists.txt 2015-09-30 16:49:52 +0000 |
| 3 | +++ CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 4 | @@ -57,7 +57,7 @@ |
| 5 | find_package(Qt5Concurrent 5.2 REQUIRED) |
| 6 | find_package(Qt5Sql 5.2 REQUIRED) |
| 7 | |
| 8 | -pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application>=8) |
| 9 | +pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=9) |
| 10 | |
| 11 | # Standard install paths |
| 12 | include(GNUInstallDirs) |
| 13 | @@ -101,6 +101,9 @@ |
| 14 | # Save a few container detach and conversions |
| 15 | add_definitions(-DQT_STRICT_ITERATORS) |
| 16 | |
| 17 | +# Use the fast string builder |
| 18 | +add_definitions(-DQT_USE_QSTRINGBUILDER) |
| 19 | + |
| 20 | # Autopilot tests |
| 21 | include(autopilot) |
| 22 | declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/) |
| 23 | |
| 24 | === modified file 'data/unity8.conf' |
| 25 | --- data/unity8.conf 2015-09-01 12:41:57 +0000 |
| 26 | +++ data/unity8.conf 2015-10-26 09:06:21 +0000 |
| 27 | @@ -46,6 +46,16 @@ |
| 28 | initctl set-env --global MIR_SERVER_PROMPT_FILE=1 |
| 29 | |
| 30 | initctl emit --no-wait indicator-services-start |
| 31 | + |
| 32 | + # Disable Qt's stuttering 'touch compression' to fix scrolling smoothness |
| 33 | + # issues (LP: #1486341). As a bonus, this eliminates most of the |
| 34 | + # lag seen in the indicator panel pull-down (LP: #1488327) and also |
| 35 | + # reduces lag seen in apps: |
| 36 | + initctl set-env --global QML_NO_TOUCH_COMPRESSION=1 |
| 37 | + |
| 38 | + # For twice the fun and half the latency, try this (Warning: not all |
| 39 | + # devices are fast enough to keep up smoothly yet)... |
| 40 | + # initctl set-env MIR_SERVER_NBUFFERS=2 |
| 41 | end script |
| 42 | |
| 43 | exec ${BINARY:-unity8} $ARGS |
| 44 | |
| 45 | === modified file 'debian/changelog' |
| 46 | --- debian/changelog 2015-10-09 09:13:03 +0000 |
| 47 | +++ debian/changelog 2015-10-26 09:06:21 +0000 |
| 48 | @@ -1,3 +1,39 @@ |
| 49 | +unity8 (8.11+15.10.20151021-0ubuntu1) wily; urgency=medium |
| 50 | + |
| 51 | + [ Albert Astals Cid ] |
| 52 | + * Clazy fixes |
| 53 | + * Enable Efficient String Construction by default |
| 54 | + |
| 55 | + [ CI Train Bot ] |
| 56 | + * New rebuild forced. |
| 57 | + |
| 58 | + [ Daniel d'Andrada ] |
| 59 | + * Have unity8 drawing its own cursor (LP: #1488417) |
| 60 | + * Initial multi-monitor support |
| 61 | + |
| 62 | + [ Daniel van Vugt ] |
| 63 | + * Disable Qt's stuttering 'touch compression' to fix scrolling |
| 64 | + smoothness (LP: #1486341, #1488327) |
| 65 | + |
| 66 | + [ Lukáš Tinkl ] |
| 67 | + * Fix autopilot wizard test skipping the reporting page |
| 68 | + * Implement Unity.Platform plugin wrapping org.freedesktop.hostname1 |
| 69 | + (LP: #1504318) |
| 70 | + * React to window title (aka surface name) changes (LP: #1497092) |
| 71 | + * Rotate the screenshots according to the actual orientation |
| 72 | + |
| 73 | + [ Michał Sawicz ] |
| 74 | + * Fix application API dependency |
| 75 | + * Have unity8 drawing its own cursor (LP: #1488417) |
| 76 | + * Initial multi-monitor support |
| 77 | + * Rotate the screenshots according to the actual orientation |
| 78 | + |
| 79 | + [ Nick Dedekind ] |
| 80 | + * Fixed leak in UnityMenuModelStackTest |
| 81 | + * Moved time translation to SDK (LP: #1372061) |
| 82 | + |
| 83 | + -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 21 Oct 2015 11:51:53 +0000 |
| 84 | + |
| 85 | unity8 (8.11+15.10.20151009-0ubuntu1) wily; urgency=medium |
| 86 | |
| 87 | [ CI Train Bot ] |
| 88 | |
| 89 | === modified file 'debian/control' |
| 90 | --- debian/control 2015-09-23 18:15:40 +0000 |
| 91 | +++ debian/control 2015-10-26 09:06:21 +0000 |
| 92 | @@ -25,10 +25,11 @@ |
| 93 | libpay2-dev, |
| 94 | libpulse-dev, |
| 95 | libqmenumodel-dev (>= 0.2.9), |
| 96 | + libqt5svg5-dev, |
| 97 | libqt5xmlpatterns5-dev, |
| 98 | libsystemsettings-dev, |
| 99 | libudev-dev, |
| 100 | - libunity-api-dev (>= 7.100), |
| 101 | + libunity-api-dev (>= 7.101), |
| 102 | libusermetricsoutput1-dev, |
| 103 | libxcb1-dev, |
| 104 | pkg-config, |
| 105 | @@ -49,7 +50,7 @@ |
| 106 | qtdeclarative5-private-dev (>= 5.2.1), |
| 107 | qtdeclarative5-qtmultimedia-plugin, |
| 108 | qtdeclarative5-ubuntu-settings-components (>= 0.6), |
| 109 | - qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239), |
| 110 | + qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1627) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1627), |
| 111 | qtdeclarative5-ubuntu-web-plugin, |
| 112 | ttf-ubuntu-font-family, |
| 113 | Standards-Version: 3.9.4 |
| 114 | @@ -64,7 +65,7 @@ |
| 115 | Package: indicators-client |
| 116 | Architecture: amd64 armhf i386 |
| 117 | Depends: qmenumodel-qml (>= 0.2.9), |
| 118 | - qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239), |
| 119 | + qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1627) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1627), |
| 120 | unity8 (= ${binary:Version}), |
| 121 | ${misc:Depends}, |
| 122 | ${shlibs:Depends}, |
| 123 | @@ -87,7 +88,8 @@ |
| 124 | Package: unity8 |
| 125 | Architecture: any |
| 126 | Provides: indicator-renderer, |
| 127 | -Depends: gsettings-desktop-schemas, |
| 128 | +Depends: dmz-cursor-theme, |
| 129 | + gsettings-desktop-schemas, |
| 130 | libcap2-bin, |
| 131 | libglib2.0-bin, |
| 132 | qmenumodel-qml (>= 0.2.9), |
| 133 | @@ -122,10 +124,10 @@ |
| 134 | Depends: qml-module-qtquick-layouts, |
| 135 | qtdeclarative5-ubuntu-settings-components (>= 0.6), |
| 136 | qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl, |
| 137 | - qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239), |
| 138 | + qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1627) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1627), |
| 139 | qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl, |
| 140 | ubuntu-thumbnailer-impl-0, |
| 141 | - unity-application-impl-8, |
| 142 | + unity-application-impl-9, |
| 143 | unity-notifications-impl-3, |
| 144 | unity-plugin-scopes | unity-scopes-impl, |
| 145 | unity-scopes-impl-7, |
| 146 | @@ -171,7 +173,7 @@ |
| 147 | Depends: ${misc:Depends}, |
| 148 | ${shlibs:Depends}, |
| 149 | Provides: unity-application-impl, |
| 150 | - unity-application-impl-8, |
| 151 | + unity-application-impl-9, |
| 152 | Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1) |
| 153 | Description: Fake environment for running Unity 8 shell |
| 154 | Provides fake implementations of some QML modules used by Unity 8 shell |
| 155 | |
| 156 | === modified file 'debian/copyright' |
| 157 | --- debian/copyright 2014-06-11 15:36:51 +0000 |
| 158 | +++ debian/copyright 2015-10-26 09:06:21 +0000 |
| 159 | @@ -60,3 +60,24 @@ |
| 160 | packaging of this file. Please review the following information to |
| 161 | ensure the GNU General Public License version 3.0 requirements will be |
| 162 | met: http://www.gnu.org/copyleft/gpl.html. |
| 163 | + |
| 164 | +Files: plugins/Cursor/3rd_party/xcursor/xcursor.* |
| 165 | +Copyright: 2002 Keith Packard |
| 166 | +License: Keith Packard |
| 167 | + Permission to use, copy, modify, distribute, and sell this software and its |
| 168 | + documentation for any purpose is hereby granted without fee, provided that |
| 169 | + the above copyright notice appear in all copies and that both that |
| 170 | + copyright notice and this permission notice appear in supporting |
| 171 | + documentation, and that the name of Keith Packard not be used in |
| 172 | + advertising or publicity pertaining to distribution of the software without |
| 173 | + specific, written prior permission. Keith Packard makes no |
| 174 | + representations about the suitability of this software for any purpose. It |
| 175 | + is provided "as is" without express or implied warranty. |
| 176 | + . |
| 177 | + KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
| 178 | + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
| 179 | + EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
| 180 | + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| 181 | + DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| 182 | + TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| 183 | + PERFORMANCE OF THIS SOFTWARE. |
| 184 | |
| 185 | === modified file 'debian/unity8-private.install' |
| 186 | --- debian/unity8-private.install 2015-09-02 09:30:32 +0000 |
| 187 | +++ debian/unity8-private.install 2015-10-26 09:06:21 +0000 |
| 188 | @@ -1,6 +1,7 @@ |
| 189 | usr/lib/*/libunity8-private.* |
| 190 | usr/lib/*/unity8/libUbuntuGestures* |
| 191 | usr/lib/*/unity8/qml/AccountsService |
| 192 | +usr/lib/*/unity8/qml/Cursor |
| 193 | usr/lib/*/unity8/qml/Dash |
| 194 | usr/lib/*/unity8/qml/GlobalShortcut |
| 195 | usr/lib/*/unity8/qml/Greeter |
| 196 | |
| 197 | === modified file 'debian/unity8.install' |
| 198 | --- debian/unity8.install 2015-10-01 13:10:32 +0000 |
| 199 | +++ debian/unity8.install 2015-10-26 09:06:21 +0000 |
| 200 | @@ -12,6 +12,7 @@ |
| 201 | usr/share/unity8/Rotation |
| 202 | usr/share/unity8/DeviceConfiguration.qml |
| 203 | usr/share/unity8/OrientedShell.qml |
| 204 | +usr/share/unity8/DisabledScreenNotice.qml |
| 205 | usr/share/unity8/Shell.qml |
| 206 | usr/share/unity8/Stages |
| 207 | usr/share/unity8/Tutorial |
| 208 | |
| 209 | === modified file 'plugins/CMakeLists.txt' |
| 210 | --- plugins/CMakeLists.txt 2015-09-02 09:30:32 +0000 |
| 211 | +++ plugins/CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 212 | @@ -12,6 +12,7 @@ |
| 213 | endmacro() |
| 214 | |
| 215 | add_subdirectory(AccountsService) |
| 216 | +add_subdirectory(Cursor) |
| 217 | add_subdirectory(GlobalShortcut) |
| 218 | add_subdirectory(Greeter) |
| 219 | add_subdirectory(IntegratedLightDM) |
| 220 | |
| 221 | === added directory 'plugins/Cursor' |
| 222 | === added directory 'plugins/Cursor/3rd_party' |
| 223 | === added file 'plugins/Cursor/3rd_party/CMakeLists.txt' |
| 224 | --- plugins/Cursor/3rd_party/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
| 225 | +++ plugins/Cursor/3rd_party/CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 226 | @@ -0,0 +1,1 @@ |
| 227 | +add_subdirectory(xcursor) |
| 228 | |
| 229 | === added directory 'plugins/Cursor/3rd_party/xcursor' |
| 230 | === added file 'plugins/Cursor/3rd_party/xcursor/CMakeLists.txt' |
| 231 | --- plugins/Cursor/3rd_party/xcursor/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
| 232 | +++ plugins/Cursor/3rd_party/xcursor/CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 233 | @@ -0,0 +1,15 @@ |
| 234 | +add_definitions(-D_DEFAULT_SOURCE=1) |
| 235 | + |
| 236 | +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") |
| 237 | + |
| 238 | +set( |
| 239 | + XCURSOR_SOURCES |
| 240 | + |
| 241 | + xcursor.c |
| 242 | +) |
| 243 | + |
| 244 | +add_library( |
| 245 | + xcursorloader-static STATIC |
| 246 | + |
| 247 | + ${XCURSOR_SOURCES} |
| 248 | +) |
| 249 | |
| 250 | === added file 'plugins/Cursor/3rd_party/xcursor/xcursor.c' |
| 251 | --- plugins/Cursor/3rd_party/xcursor/xcursor.c 1970-01-01 00:00:00 +0000 |
| 252 | +++ plugins/Cursor/3rd_party/xcursor/xcursor.c 2015-10-26 09:06:21 +0000 |
| 253 | @@ -0,0 +1,968 @@ |
| 254 | +/* |
| 255 | + * Copyright © 2002 Keith Packard |
| 256 | + * |
| 257 | + * Permission to use, copy, modify, distribute, and sell this software and its |
| 258 | + * documentation for any purpose is hereby granted without fee, provided that |
| 259 | + * the above copyright notice appear in all copies and that both that |
| 260 | + * copyright notice and this permission notice appear in supporting |
| 261 | + * documentation, and that the name of Keith Packard not be used in |
| 262 | + * advertising or publicity pertaining to distribution of the software without |
| 263 | + * specific, written prior permission. Keith Packard makes no |
| 264 | + * representations about the suitability of this software for any purpose. It |
| 265 | + * is provided "as is" without express or implied warranty. |
| 266 | + * |
| 267 | + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
| 268 | + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
| 269 | + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
| 270 | + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| 271 | + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| 272 | + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| 273 | + * PERFORMANCE OF THIS SOFTWARE. |
| 274 | + */ |
| 275 | + |
| 276 | +#include "xcursor.h" |
| 277 | +#include <stdio.h> |
| 278 | +#include <stdlib.h> |
| 279 | +#include <string.h> |
| 280 | +#include <dirent.h> |
| 281 | + |
| 282 | +/* |
| 283 | + * From libXcursor/include/X11/extensions/Xcursor.h |
| 284 | + */ |
| 285 | + |
| 286 | +#define XcursorTrue 1 |
| 287 | +#define XcursorFalse 0 |
| 288 | + |
| 289 | +/* |
| 290 | + * Cursor files start with a header. The header |
| 291 | + * contains a magic number, a version number and a |
| 292 | + * table of contents which has type and offset information |
| 293 | + * for the remaining tables in the file. |
| 294 | + * |
| 295 | + * File minor versions increment for compatible changes |
| 296 | + * File major versions increment for incompatible changes (never, we hope) |
| 297 | + * |
| 298 | + * Chunks of the same type are always upward compatible. Incompatible |
| 299 | + * changes are made with new chunk types; the old data can remain under |
| 300 | + * the old type. Upward compatible changes can add header data as the |
| 301 | + * header lengths are specified in the file. |
| 302 | + * |
| 303 | + * File: |
| 304 | + * FileHeader |
| 305 | + * LISTofChunk |
| 306 | + * |
| 307 | + * FileHeader: |
| 308 | + * CARD32 magic magic number |
| 309 | + * CARD32 header bytes in file header |
| 310 | + * CARD32 version file version |
| 311 | + * CARD32 ntoc number of toc entries |
| 312 | + * LISTofFileToc toc table of contents |
| 313 | + * |
| 314 | + * FileToc: |
| 315 | + * CARD32 type entry type |
| 316 | + * CARD32 subtype entry subtype (size for images) |
| 317 | + * CARD32 position absolute file position |
| 318 | + */ |
| 319 | + |
| 320 | +#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */ |
| 321 | + |
| 322 | +/* |
| 323 | + * Current Xcursor version number. Will be substituted by configure |
| 324 | + * from the version in the libXcursor configure.ac file. |
| 325 | + */ |
| 326 | + |
| 327 | +#define XCURSOR_LIB_MAJOR 1 |
| 328 | +#define XCURSOR_LIB_MINOR 1 |
| 329 | +#define XCURSOR_LIB_REVISION 13 |
| 330 | +#define XCURSOR_LIB_VERSION ((XCURSOR_LIB_MAJOR * 10000) + \ |
| 331 | + (XCURSOR_LIB_MINOR * 100) + \ |
| 332 | + (XCURSOR_LIB_REVISION)) |
| 333 | + |
| 334 | +/* |
| 335 | + * This version number is stored in cursor files; changes to the |
| 336 | + * file format require updating this version number |
| 337 | + */ |
| 338 | +#define XCURSOR_FILE_MAJOR 1 |
| 339 | +#define XCURSOR_FILE_MINOR 0 |
| 340 | +#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR)) |
| 341 | +#define XCURSOR_FILE_HEADER_LEN (4 * 4) |
| 342 | +#define XCURSOR_FILE_TOC_LEN (3 * 4) |
| 343 | + |
| 344 | +typedef struct _XcursorFileToc { |
| 345 | + XcursorUInt type; /* chunk type */ |
| 346 | + XcursorUInt subtype; /* subtype (size for images) */ |
| 347 | + XcursorUInt position; /* absolute position in file */ |
| 348 | +} XcursorFileToc; |
| 349 | + |
| 350 | +typedef struct _XcursorFileHeader { |
| 351 | + XcursorUInt magic; /* magic number */ |
| 352 | + XcursorUInt header; /* byte length of header */ |
| 353 | + XcursorUInt version; /* file version number */ |
| 354 | + XcursorUInt ntoc; /* number of toc entries */ |
| 355 | + XcursorFileToc *tocs; /* table of contents */ |
| 356 | +} XcursorFileHeader; |
| 357 | + |
| 358 | +/* |
| 359 | + * The rest of the file is a list of chunks, each tagged by type |
| 360 | + * and version. |
| 361 | + * |
| 362 | + * Chunk: |
| 363 | + * ChunkHeader |
| 364 | + * <extra type-specific header fields> |
| 365 | + * <type-specific data> |
| 366 | + * |
| 367 | + * ChunkHeader: |
| 368 | + * CARD32 header bytes in chunk header + type header |
| 369 | + * CARD32 type chunk type |
| 370 | + * CARD32 subtype chunk subtype |
| 371 | + * CARD32 version chunk type version |
| 372 | + */ |
| 373 | + |
| 374 | +#define XCURSOR_CHUNK_HEADER_LEN (4 * 4) |
| 375 | + |
| 376 | +typedef struct _XcursorChunkHeader { |
| 377 | + XcursorUInt header; /* bytes in chunk header */ |
| 378 | + XcursorUInt type; /* chunk type */ |
| 379 | + XcursorUInt subtype; /* chunk subtype (size for images) */ |
| 380 | + XcursorUInt version; /* version of this type */ |
| 381 | +} XcursorChunkHeader; |
| 382 | + |
| 383 | +/* |
| 384 | + * Here's a list of the known chunk types |
| 385 | + */ |
| 386 | + |
| 387 | +/* |
| 388 | + * Comments consist of a 4-byte length field followed by |
| 389 | + * UTF-8 encoded text |
| 390 | + * |
| 391 | + * Comment: |
| 392 | + * ChunkHeader header chunk header |
| 393 | + * CARD32 length bytes in text |
| 394 | + * LISTofCARD8 text UTF-8 encoded text |
| 395 | + */ |
| 396 | + |
| 397 | +#define XCURSOR_COMMENT_TYPE 0xfffe0001 |
| 398 | +#define XCURSOR_COMMENT_VERSION 1 |
| 399 | +#define XCURSOR_COMMENT_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (1 *4)) |
| 400 | +#define XCURSOR_COMMENT_COPYRIGHT 1 |
| 401 | +#define XCURSOR_COMMENT_LICENSE 2 |
| 402 | +#define XCURSOR_COMMENT_OTHER 3 |
| 403 | +#define XCURSOR_COMMENT_MAX_LEN 0x100000 |
| 404 | + |
| 405 | +typedef struct _XcursorComment { |
| 406 | + XcursorUInt version; |
| 407 | + XcursorUInt comment_type; |
| 408 | + char *comment; |
| 409 | +} XcursorComment; |
| 410 | + |
| 411 | +/* |
| 412 | + * Each cursor image occupies a separate image chunk. |
| 413 | + * The length of the image header follows the chunk header |
| 414 | + * so that future versions can extend the header without |
| 415 | + * breaking older applications |
| 416 | + * |
| 417 | + * Image: |
| 418 | + * ChunkHeader header chunk header |
| 419 | + * CARD32 width actual width |
| 420 | + * CARD32 height actual height |
| 421 | + * CARD32 xhot hot spot x |
| 422 | + * CARD32 yhot hot spot y |
| 423 | + * CARD32 delay animation delay |
| 424 | + * LISTofCARD32 pixels ARGB pixels |
| 425 | + */ |
| 426 | + |
| 427 | +#define XCURSOR_IMAGE_TYPE 0xfffd0002 |
| 428 | +#define XCURSOR_IMAGE_VERSION 1 |
| 429 | +#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4)) |
| 430 | +#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */ |
| 431 | + |
| 432 | +typedef struct _XcursorFile XcursorFile; |
| 433 | + |
| 434 | +struct _XcursorFile { |
| 435 | + void *closure; |
| 436 | + int (*read) (XcursorFile *file, unsigned char *buf, int len); |
| 437 | + int (*write) (XcursorFile *file, unsigned char *buf, int len); |
| 438 | + int (*seek) (XcursorFile *file, long offset, int whence); |
| 439 | +}; |
| 440 | + |
| 441 | +typedef struct _XcursorComments { |
| 442 | + int ncomment; /* number of comments */ |
| 443 | + XcursorComment **comments; /* array of XcursorComment pointers */ |
| 444 | +} XcursorComments; |
| 445 | + |
| 446 | +/* |
| 447 | + * From libXcursor/src/file.c |
| 448 | + */ |
| 449 | + |
| 450 | +static XcursorImage * |
| 451 | +XcursorImageCreate (int width, int height) |
| 452 | +{ |
| 453 | + XcursorImage *image; |
| 454 | + |
| 455 | + image = malloc (sizeof (XcursorImage) + |
| 456 | + width * height * sizeof (XcursorPixel)); |
| 457 | + if (!image) |
| 458 | + return NULL; |
| 459 | + image->version = XCURSOR_IMAGE_VERSION; |
| 460 | + image->pixels = (XcursorPixel *) (image + 1); |
| 461 | + image->size = width > height ? width : height; |
| 462 | + image->width = width; |
| 463 | + image->height = height; |
| 464 | + image->delay = 0; |
| 465 | + return image; |
| 466 | +} |
| 467 | + |
| 468 | +static void |
| 469 | +XcursorImageDestroy (XcursorImage *image) |
| 470 | +{ |
| 471 | + free (image); |
| 472 | +} |
| 473 | + |
| 474 | +static XcursorImages * |
| 475 | +XcursorImagesCreate (int size) |
| 476 | +{ |
| 477 | + XcursorImages *images; |
| 478 | + |
| 479 | + images = malloc (sizeof (XcursorImages) + |
| 480 | + size * sizeof (XcursorImage *)); |
| 481 | + if (!images) |
| 482 | + return NULL; |
| 483 | + images->nimage = 0; |
| 484 | + images->images = (XcursorImage **) (images + 1); |
| 485 | + images->name = NULL; |
| 486 | + return images; |
| 487 | +} |
| 488 | + |
| 489 | +void |
| 490 | +XcursorImagesDestroy (XcursorImages *images) |
| 491 | +{ |
| 492 | + int n; |
| 493 | + |
| 494 | + if (!images) |
| 495 | + return; |
| 496 | + |
| 497 | + for (n = 0; n < images->nimage; n++) |
| 498 | + XcursorImageDestroy (images->images[n]); |
| 499 | + if (images->name) |
| 500 | + free (images->name); |
| 501 | + free (images); |
| 502 | +} |
| 503 | + |
| 504 | +static void |
| 505 | +XcursorImagesSetName (XcursorImages *images, const char *name) |
| 506 | +{ |
| 507 | + char *new; |
| 508 | + |
| 509 | + if (!images || !name) |
| 510 | + return; |
| 511 | + |
| 512 | + new = malloc (strlen (name) + 1); |
| 513 | + |
| 514 | + if (!new) |
| 515 | + return; |
| 516 | + |
| 517 | + strcpy (new, name); |
| 518 | + if (images->name) |
| 519 | + free (images->name); |
| 520 | + images->name = new; |
| 521 | +} |
| 522 | + |
| 523 | +static XcursorBool |
| 524 | +_XcursorReadUInt (XcursorFile *file, XcursorUInt *u) |
| 525 | +{ |
| 526 | + unsigned char bytes[4]; |
| 527 | + |
| 528 | + if (!file || !u) |
| 529 | + return XcursorFalse; |
| 530 | + |
| 531 | + if ((*file->read) (file, bytes, 4) != 4) |
| 532 | + return XcursorFalse; |
| 533 | + *u = ((bytes[0] << 0) | |
| 534 | + (bytes[1] << 8) | |
| 535 | + (bytes[2] << 16) | |
| 536 | + (bytes[3] << 24)); |
| 537 | + return XcursorTrue; |
| 538 | +} |
| 539 | + |
| 540 | +static void |
| 541 | +_XcursorFileHeaderDestroy (XcursorFileHeader *fileHeader) |
| 542 | +{ |
| 543 | + free (fileHeader); |
| 544 | +} |
| 545 | + |
| 546 | +static XcursorFileHeader * |
| 547 | +_XcursorFileHeaderCreate (int ntoc) |
| 548 | +{ |
| 549 | + XcursorFileHeader *fileHeader; |
| 550 | + |
| 551 | + if (ntoc > 0x10000) |
| 552 | + return NULL; |
| 553 | + fileHeader = malloc (sizeof (XcursorFileHeader) + |
| 554 | + ntoc * sizeof (XcursorFileToc)); |
| 555 | + if (!fileHeader) |
| 556 | + return NULL; |
| 557 | + fileHeader->magic = XCURSOR_MAGIC; |
| 558 | + fileHeader->header = XCURSOR_FILE_HEADER_LEN; |
| 559 | + fileHeader->version = XCURSOR_FILE_VERSION; |
| 560 | + fileHeader->ntoc = ntoc; |
| 561 | + fileHeader->tocs = (XcursorFileToc *) (fileHeader + 1); |
| 562 | + return fileHeader; |
| 563 | +} |
| 564 | + |
| 565 | +static XcursorFileHeader * |
| 566 | +_XcursorReadFileHeader (XcursorFile *file) |
| 567 | +{ |
| 568 | + XcursorFileHeader head, *fileHeader; |
| 569 | + XcursorUInt skip; |
| 570 | + unsigned int n; |
| 571 | + |
| 572 | + if (!file) |
| 573 | + return NULL; |
| 574 | + |
| 575 | + if (!_XcursorReadUInt (file, &head.magic)) |
| 576 | + return NULL; |
| 577 | + if (head.magic != XCURSOR_MAGIC) |
| 578 | + return NULL; |
| 579 | + if (!_XcursorReadUInt (file, &head.header)) |
| 580 | + return NULL; |
| 581 | + if (!_XcursorReadUInt (file, &head.version)) |
| 582 | + return NULL; |
| 583 | + if (!_XcursorReadUInt (file, &head.ntoc)) |
| 584 | + return NULL; |
| 585 | + skip = head.header - XCURSOR_FILE_HEADER_LEN; |
| 586 | + if (skip) |
| 587 | + if ((*file->seek) (file, skip, SEEK_CUR) == EOF) |
| 588 | + return NULL; |
| 589 | + fileHeader = _XcursorFileHeaderCreate (head.ntoc); |
| 590 | + if (!fileHeader) |
| 591 | + return NULL; |
| 592 | + fileHeader->magic = head.magic; |
| 593 | + fileHeader->header = head.header; |
| 594 | + fileHeader->version = head.version; |
| 595 | + fileHeader->ntoc = head.ntoc; |
| 596 | + for (n = 0; n < fileHeader->ntoc; n++) |
| 597 | + { |
| 598 | + if (!_XcursorReadUInt (file, &fileHeader->tocs[n].type)) |
| 599 | + break; |
| 600 | + if (!_XcursorReadUInt (file, &fileHeader->tocs[n].subtype)) |
| 601 | + break; |
| 602 | + if (!_XcursorReadUInt (file, &fileHeader->tocs[n].position)) |
| 603 | + break; |
| 604 | + } |
| 605 | + if (n != fileHeader->ntoc) |
| 606 | + { |
| 607 | + _XcursorFileHeaderDestroy (fileHeader); |
| 608 | + return NULL; |
| 609 | + } |
| 610 | + return fileHeader; |
| 611 | +} |
| 612 | + |
| 613 | +static XcursorBool |
| 614 | +_XcursorSeekToToc (XcursorFile *file, |
| 615 | + XcursorFileHeader *fileHeader, |
| 616 | + int toc) |
| 617 | +{ |
| 618 | + if (!file || !fileHeader || \ |
| 619 | + (*file->seek) (file, fileHeader->tocs[toc].position, SEEK_SET) == EOF) |
| 620 | + return XcursorFalse; |
| 621 | + return XcursorTrue; |
| 622 | +} |
| 623 | + |
| 624 | +static XcursorBool |
| 625 | +_XcursorFileReadChunkHeader (XcursorFile *file, |
| 626 | + XcursorFileHeader *fileHeader, |
| 627 | + int toc, |
| 628 | + XcursorChunkHeader *chunkHeader) |
| 629 | +{ |
| 630 | + if (!file || !fileHeader || !chunkHeader) |
| 631 | + return XcursorFalse; |
| 632 | + if (!_XcursorSeekToToc (file, fileHeader, toc)) |
| 633 | + return XcursorFalse; |
| 634 | + if (!_XcursorReadUInt (file, &chunkHeader->header)) |
| 635 | + return XcursorFalse; |
| 636 | + if (!_XcursorReadUInt (file, &chunkHeader->type)) |
| 637 | + return XcursorFalse; |
| 638 | + if (!_XcursorReadUInt (file, &chunkHeader->subtype)) |
| 639 | + return XcursorFalse; |
| 640 | + if (!_XcursorReadUInt (file, &chunkHeader->version)) |
| 641 | + return XcursorFalse; |
| 642 | + /* sanity check */ |
| 643 | + if (chunkHeader->type != fileHeader->tocs[toc].type || |
| 644 | + chunkHeader->subtype != fileHeader->tocs[toc].subtype) |
| 645 | + return XcursorFalse; |
| 646 | + return XcursorTrue; |
| 647 | +} |
| 648 | + |
| 649 | +#define dist(a,b) ((a) > (b) ? (a) - (b) : (b) - (a)) |
| 650 | + |
| 651 | +static XcursorDim |
| 652 | +_XcursorFindBestSize (XcursorFileHeader *fileHeader, |
| 653 | + XcursorDim size, |
| 654 | + int *nsizesp) |
| 655 | +{ |
| 656 | + unsigned int n; |
| 657 | + int nsizes = 0; |
| 658 | + XcursorDim bestSize = 0; |
| 659 | + XcursorDim thisSize; |
| 660 | + |
| 661 | + if (!fileHeader || !nsizesp) |
| 662 | + return 0; |
| 663 | + |
| 664 | + for (n = 0; n < fileHeader->ntoc; n++) |
| 665 | + { |
| 666 | + if (fileHeader->tocs[n].type != XCURSOR_IMAGE_TYPE) |
| 667 | + continue; |
| 668 | + thisSize = fileHeader->tocs[n].subtype; |
| 669 | + if (!bestSize || dist (thisSize, size) < dist (bestSize, size)) |
| 670 | + { |
| 671 | + bestSize = thisSize; |
| 672 | + nsizes = 1; |
| 673 | + } |
| 674 | + else if (thisSize == bestSize) |
| 675 | + nsizes++; |
| 676 | + } |
| 677 | + *nsizesp = nsizes; |
| 678 | + return bestSize; |
| 679 | +} |
| 680 | + |
| 681 | +static int |
| 682 | +_XcursorFindImageToc (XcursorFileHeader *fileHeader, |
| 683 | + XcursorDim size, |
| 684 | + int count) |
| 685 | +{ |
| 686 | + unsigned int toc; |
| 687 | + XcursorDim thisSize; |
| 688 | + |
| 689 | + if (!fileHeader) |
| 690 | + return 0; |
| 691 | + |
| 692 | + for (toc = 0; toc < fileHeader->ntoc; toc++) |
| 693 | + { |
| 694 | + if (fileHeader->tocs[toc].type != XCURSOR_IMAGE_TYPE) |
| 695 | + continue; |
| 696 | + thisSize = fileHeader->tocs[toc].subtype; |
| 697 | + if (thisSize != size) |
| 698 | + continue; |
| 699 | + if (!count) |
| 700 | + break; |
| 701 | + count--; |
| 702 | + } |
| 703 | + if (toc == fileHeader->ntoc) |
| 704 | + return -1; |
| 705 | + return toc; |
| 706 | +} |
| 707 | + |
| 708 | +static XcursorImage * |
| 709 | +_XcursorReadImage (XcursorFile *file, |
| 710 | + XcursorFileHeader *fileHeader, |
| 711 | + int toc) |
| 712 | +{ |
| 713 | + XcursorChunkHeader chunkHeader; |
| 714 | + XcursorImage head; |
| 715 | + XcursorImage *image; |
| 716 | + int n; |
| 717 | + XcursorPixel *p; |
| 718 | + |
| 719 | + if (!file || !fileHeader) |
| 720 | + return NULL; |
| 721 | + |
| 722 | + if (!_XcursorFileReadChunkHeader (file, fileHeader, toc, &chunkHeader)) |
| 723 | + return NULL; |
| 724 | + if (!_XcursorReadUInt (file, &head.width)) |
| 725 | + return NULL; |
| 726 | + if (!_XcursorReadUInt (file, &head.height)) |
| 727 | + return NULL; |
| 728 | + if (!_XcursorReadUInt (file, &head.xhot)) |
| 729 | + return NULL; |
| 730 | + if (!_XcursorReadUInt (file, &head.yhot)) |
| 731 | + return NULL; |
| 732 | + if (!_XcursorReadUInt (file, &head.delay)) |
| 733 | + return NULL; |
| 734 | + /* sanity check data */ |
| 735 | + if (head.width >= 0x10000 || head.height > 0x10000) |
| 736 | + return NULL; |
| 737 | + if (head.width == 0 || head.height == 0) |
| 738 | + return NULL; |
| 739 | + if (head.xhot > head.width || head.yhot > head.height) |
| 740 | + return NULL; |
| 741 | + |
| 742 | + /* Create the image and initialize it */ |
| 743 | + image = XcursorImageCreate (head.width, head.height); |
| 744 | + if (image == NULL) |
| 745 | + return NULL; |
| 746 | + if (chunkHeader.version < image->version) |
| 747 | + image->version = chunkHeader.version; |
| 748 | + image->size = chunkHeader.subtype; |
| 749 | + image->xhot = head.xhot; |
| 750 | + image->yhot = head.yhot; |
| 751 | + image->delay = head.delay; |
| 752 | + n = image->width * image->height; |
| 753 | + p = image->pixels; |
| 754 | + while (n--) |
| 755 | + { |
| 756 | + if (!_XcursorReadUInt (file, p)) |
| 757 | + { |
| 758 | + XcursorImageDestroy (image); |
| 759 | + return NULL; |
| 760 | + } |
| 761 | + p++; |
| 762 | + } |
| 763 | + return image; |
| 764 | +} |
| 765 | + |
| 766 | +static XcursorImages * |
| 767 | +XcursorXcFileLoadImages (XcursorFile *file, int size) |
| 768 | +{ |
| 769 | + XcursorFileHeader *fileHeader; |
| 770 | + XcursorDim bestSize; |
| 771 | + int nsize; |
| 772 | + XcursorImages *images; |
| 773 | + int n; |
| 774 | + int toc; |
| 775 | + |
| 776 | + if (!file || size < 0) |
| 777 | + return NULL; |
| 778 | + fileHeader = _XcursorReadFileHeader (file); |
| 779 | + if (!fileHeader) |
| 780 | + return NULL; |
| 781 | + bestSize = _XcursorFindBestSize (fileHeader, (XcursorDim) size, &nsize); |
| 782 | + if (!bestSize) |
| 783 | + { |
| 784 | + _XcursorFileHeaderDestroy (fileHeader); |
| 785 | + return NULL; |
| 786 | + } |
| 787 | + images = XcursorImagesCreate (nsize); |
| 788 | + if (!images) |
| 789 | + { |
| 790 | + _XcursorFileHeaderDestroy (fileHeader); |
| 791 | + return NULL; |
| 792 | + } |
| 793 | + for (n = 0; n < nsize; n++) |
| 794 | + { |
| 795 | + toc = _XcursorFindImageToc (fileHeader, bestSize, n); |
| 796 | + if (toc < 0) |
| 797 | + break; |
| 798 | + images->images[images->nimage] = _XcursorReadImage (file, fileHeader, |
| 799 | + toc); |
| 800 | + if (!images->images[images->nimage]) |
| 801 | + break; |
| 802 | + images->nimage++; |
| 803 | + } |
| 804 | + _XcursorFileHeaderDestroy (fileHeader); |
| 805 | + if (images->nimage != nsize) |
| 806 | + { |
| 807 | + XcursorImagesDestroy (images); |
| 808 | + images = NULL; |
| 809 | + } |
| 810 | + return images; |
| 811 | +} |
| 812 | + |
| 813 | +static int |
| 814 | +_XcursorStdioFileRead (XcursorFile *file, unsigned char *buf, int len) |
| 815 | +{ |
| 816 | + FILE *f = file->closure; |
| 817 | + return fread (buf, 1, len, f); |
| 818 | +} |
| 819 | + |
| 820 | +static int |
| 821 | +_XcursorStdioFileWrite (XcursorFile *file, unsigned char *buf, int len) |
| 822 | +{ |
| 823 | + FILE *f = file->closure; |
| 824 | + return fwrite (buf, 1, len, f); |
| 825 | +} |
| 826 | + |
| 827 | +static int |
| 828 | +_XcursorStdioFileSeek (XcursorFile *file, long offset, int whence) |
| 829 | +{ |
| 830 | + FILE *f = file->closure; |
| 831 | + return fseek (f, offset, whence); |
| 832 | +} |
| 833 | + |
| 834 | +static void |
| 835 | +_XcursorStdioFileInitialize (FILE *stdfile, XcursorFile *file) |
| 836 | +{ |
| 837 | + file->closure = stdfile; |
| 838 | + file->read = _XcursorStdioFileRead; |
| 839 | + file->write = _XcursorStdioFileWrite; |
| 840 | + file->seek = _XcursorStdioFileSeek; |
| 841 | +} |
| 842 | + |
| 843 | +static XcursorImages * |
| 844 | +XcursorFileLoadImages (FILE *file, int size) |
| 845 | +{ |
| 846 | + XcursorFile f; |
| 847 | + |
| 848 | + if (!file) |
| 849 | + return NULL; |
| 850 | + |
| 851 | + _XcursorStdioFileInitialize (file, &f); |
| 852 | + return XcursorXcFileLoadImages (&f, size); |
| 853 | +} |
| 854 | + |
| 855 | +/* |
| 856 | + * From libXcursor/src/library.c |
| 857 | + */ |
| 858 | + |
| 859 | +#ifndef ICONDIR |
| 860 | +#define ICONDIR "/usr/X11R6/lib/X11/icons" |
| 861 | +#endif |
| 862 | + |
| 863 | +#ifndef XCURSORPATH |
| 864 | +#define XCURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:~/.cursors:/usr/share/cursors/xorg-x11:"ICONDIR |
| 865 | +#endif |
| 866 | + |
| 867 | +static const char * |
| 868 | +XcursorLibraryPath (void) |
| 869 | +{ |
| 870 | + static const char *path; |
| 871 | + |
| 872 | + if (!path) |
| 873 | + { |
| 874 | + path = getenv ("XCURSOR_PATH"); |
| 875 | + if (!path) |
| 876 | + path = XCURSORPATH; |
| 877 | + } |
| 878 | + return path; |
| 879 | +} |
| 880 | + |
| 881 | +static void |
| 882 | +_XcursorAddPathElt (char *path, const char *elt, int len) |
| 883 | +{ |
| 884 | + int pathlen = strlen (path); |
| 885 | + |
| 886 | + /* append / if the path doesn't currently have one */ |
| 887 | + if (path[0] == '\0' || path[pathlen - 1] != '/') |
| 888 | + { |
| 889 | + strcat (path, "/"); |
| 890 | + pathlen++; |
| 891 | + } |
| 892 | + if (len == -1) |
| 893 | + len = strlen (elt); |
| 894 | + /* strip leading slashes */ |
| 895 | + while (len && elt[0] == '/') |
| 896 | + { |
| 897 | + elt++; |
| 898 | + len--; |
| 899 | + } |
| 900 | + strncpy (path + pathlen, elt, len); |
| 901 | + path[pathlen + len] = '\0'; |
| 902 | +} |
| 903 | + |
| 904 | +static char * |
| 905 | +_XcursorBuildThemeDir (const char *dir, const char *theme) |
| 906 | +{ |
| 907 | + const char *colon; |
| 908 | + const char *tcolon; |
| 909 | + char *full; |
| 910 | + char *home; |
| 911 | + int dirlen; |
| 912 | + int homelen; |
| 913 | + int themelen; |
| 914 | + int len; |
| 915 | + |
| 916 | + if (!dir || !theme) |
| 917 | + return NULL; |
| 918 | + |
| 919 | + colon = strchr (dir, ':'); |
| 920 | + if (!colon) |
| 921 | + colon = dir + strlen (dir); |
| 922 | + |
| 923 | + dirlen = colon - dir; |
| 924 | + |
| 925 | + tcolon = strchr (theme, ':'); |
| 926 | + if (!tcolon) |
| 927 | + tcolon = theme + strlen (theme); |
| 928 | + |
| 929 | + themelen = tcolon - theme; |
| 930 | + |
| 931 | + home = NULL; |
| 932 | + homelen = 0; |
| 933 | + if (*dir == '~') |
| 934 | + { |
| 935 | + home = getenv ("HOME"); |
| 936 | + if (!home) |
| 937 | + return NULL; |
| 938 | + homelen = strlen (home); |
| 939 | + dir++; |
| 940 | + dirlen--; |
| 941 | + } |
| 942 | + |
| 943 | + /* |
| 944 | + * add space for any needed directory separators, one per component, |
| 945 | + * and one for the trailing null |
| 946 | + */ |
| 947 | + len = 1 + homelen + 1 + dirlen + 1 + themelen + 1; |
| 948 | + |
| 949 | + full = malloc (len); |
| 950 | + if (!full) |
| 951 | + return NULL; |
| 952 | + full[0] = '\0'; |
| 953 | + |
| 954 | + if (home) |
| 955 | + _XcursorAddPathElt (full, home, -1); |
| 956 | + _XcursorAddPathElt (full, dir, dirlen); |
| 957 | + _XcursorAddPathElt (full, theme, themelen); |
| 958 | + return full; |
| 959 | +} |
| 960 | + |
| 961 | +static char * |
| 962 | +_XcursorBuildFullname (const char *dir, const char *subdir, const char *file) |
| 963 | +{ |
| 964 | + char *full; |
| 965 | + |
| 966 | + if (!dir || !subdir || !file) |
| 967 | + return NULL; |
| 968 | + |
| 969 | + full = malloc (strlen (dir) + 1 + strlen (subdir) + 1 + strlen (file) + 1); |
| 970 | + if (!full) |
| 971 | + return NULL; |
| 972 | + full[0] = '\0'; |
| 973 | + _XcursorAddPathElt (full, dir, -1); |
| 974 | + _XcursorAddPathElt (full, subdir, -1); |
| 975 | + _XcursorAddPathElt (full, file, -1); |
| 976 | + return full; |
| 977 | +} |
| 978 | + |
| 979 | +static const char * |
| 980 | +_XcursorNextPath (const char *path) |
| 981 | +{ |
| 982 | + char *colon = strchr (path, ':'); |
| 983 | + |
| 984 | + if (!colon) |
| 985 | + return NULL; |
| 986 | + return colon + 1; |
| 987 | +} |
| 988 | + |
| 989 | +#define XcursorWhite(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') |
| 990 | +#define XcursorSep(c) ((c) == ';' || (c) == ',') |
| 991 | + |
| 992 | +static char * |
| 993 | +_XcursorThemeInherits (const char *full) |
| 994 | +{ |
| 995 | + char line[8192]; |
| 996 | + char *result = NULL; |
| 997 | + FILE *f; |
| 998 | + |
| 999 | + if (!full) |
| 1000 | + return NULL; |
| 1001 | + |
| 1002 | + f = fopen (full, "r"); |
| 1003 | + if (f) |
| 1004 | + { |
| 1005 | + while (fgets (line, sizeof (line), f)) |
| 1006 | + { |
| 1007 | + if (!strncmp (line, "Inherits", 8)) |
| 1008 | + { |
| 1009 | + char *l = line + 8; |
| 1010 | + char *r; |
| 1011 | + while (*l == ' ') l++; |
| 1012 | + if (*l != '=') continue; |
| 1013 | + l++; |
| 1014 | + while (*l == ' ') l++; |
| 1015 | + result = malloc (strlen (l) + 1); |
| 1016 | + if (result) |
| 1017 | + { |
| 1018 | + r = result; |
| 1019 | + while (*l) |
| 1020 | + { |
| 1021 | + while (XcursorSep(*l) || XcursorWhite (*l)) l++; |
| 1022 | + if (!*l) |
| 1023 | + break; |
| 1024 | + if (r != result) |
| 1025 | + *r++ = ':'; |
| 1026 | + while (*l && !XcursorWhite(*l) && |
| 1027 | + !XcursorSep(*l)) |
| 1028 | + *r++ = *l++; |
| 1029 | + } |
| 1030 | + *r++ = '\0'; |
| 1031 | + } |
| 1032 | + break; |
| 1033 | + } |
| 1034 | + } |
| 1035 | + fclose (f); |
| 1036 | + } |
| 1037 | + return result; |
| 1038 | +} |
| 1039 | + |
| 1040 | +static FILE * |
| 1041 | +XcursorScanTheme (const char *theme, const char *name) |
| 1042 | +{ |
| 1043 | + FILE *f = NULL; |
| 1044 | + char *full; |
| 1045 | + char *dir; |
| 1046 | + const char *path; |
| 1047 | + char *inherits = NULL; |
| 1048 | + const char *i; |
| 1049 | + |
| 1050 | + if (!theme || !name) |
| 1051 | + return NULL; |
| 1052 | + |
| 1053 | + /* |
| 1054 | + * Scan this theme |
| 1055 | + */ |
| 1056 | + for (path = XcursorLibraryPath (); |
| 1057 | + path && f == NULL; |
| 1058 | + path = _XcursorNextPath (path)) |
| 1059 | + { |
| 1060 | + dir = _XcursorBuildThemeDir (path, theme); |
| 1061 | + if (dir) |
| 1062 | + { |
| 1063 | + full = _XcursorBuildFullname (dir, "cursors", name); |
| 1064 | + if (full) |
| 1065 | + { |
| 1066 | + f = fopen (full, "r"); |
| 1067 | + free (full); |
| 1068 | + } |
| 1069 | + if (!f && !inherits) |
| 1070 | + { |
| 1071 | + full = _XcursorBuildFullname (dir, "", "index.theme"); |
| 1072 | + if (full) |
| 1073 | + { |
| 1074 | + inherits = _XcursorThemeInherits (full); |
| 1075 | + free (full); |
| 1076 | + } |
| 1077 | + } |
| 1078 | + free (dir); |
| 1079 | + } |
| 1080 | + } |
| 1081 | + /* |
| 1082 | + * Recurse to scan inherited themes |
| 1083 | + */ |
| 1084 | + for (i = inherits; i && f == NULL; i = _XcursorNextPath (i)) |
| 1085 | + f = XcursorScanTheme (i, name); |
| 1086 | + if (inherits != NULL) |
| 1087 | + free (inherits); |
| 1088 | + return f; |
| 1089 | +} |
| 1090 | + |
| 1091 | +XcursorImages * |
| 1092 | +XcursorLibraryLoadImages (const char *file, const char *theme, int size) |
| 1093 | +{ |
| 1094 | + FILE *f = NULL; |
| 1095 | + XcursorImages *images = NULL; |
| 1096 | + |
| 1097 | + if (!file) |
| 1098 | + return NULL; |
| 1099 | + |
| 1100 | + if (theme) |
| 1101 | + f = XcursorScanTheme (theme, file); |
| 1102 | + if (!f) |
| 1103 | + f = XcursorScanTheme ("default", file); |
| 1104 | + if (f) |
| 1105 | + { |
| 1106 | + images = XcursorFileLoadImages (f, size); |
| 1107 | + if (images) |
| 1108 | + XcursorImagesSetName (images, file); |
| 1109 | + fclose (f); |
| 1110 | + } |
| 1111 | + return images; |
| 1112 | +} |
| 1113 | + |
| 1114 | +static void |
| 1115 | +load_all_cursors_from_dir(const char *path, int size, |
| 1116 | + void (*load_callback)(XcursorImages *, void *), |
| 1117 | + void *user_data) |
| 1118 | +{ |
| 1119 | + FILE *f; |
| 1120 | + DIR *dir = opendir(path); |
| 1121 | + struct dirent *ent; |
| 1122 | + char *full; |
| 1123 | + XcursorImages *images; |
| 1124 | + |
| 1125 | + if (!dir) |
| 1126 | + return; |
| 1127 | + |
| 1128 | + for(ent = readdir(dir); ent; ent = readdir(dir)) { |
| 1129 | +#ifdef _DIRENT_HAVE_D_TYPE |
| 1130 | + if (ent->d_type != DT_UNKNOWN && |
| 1131 | + (ent->d_type != DT_REG && ent->d_type != DT_LNK)) |
| 1132 | + continue; |
| 1133 | +#endif |
| 1134 | + |
| 1135 | + full = _XcursorBuildFullname(path, "", ent->d_name); |
| 1136 | + if (!full) |
| 1137 | + continue; |
| 1138 | + |
| 1139 | + f = fopen(full, "r"); |
| 1140 | + if (!f) { |
| 1141 | + free(full); |
| 1142 | + continue; |
| 1143 | + } |
| 1144 | + |
| 1145 | + images = XcursorFileLoadImages(f, size); |
| 1146 | + |
| 1147 | + if (images) { |
| 1148 | + XcursorImagesSetName(images, ent->d_name); |
| 1149 | + load_callback(images, user_data); |
| 1150 | + } |
| 1151 | + |
| 1152 | + fclose (f); |
| 1153 | + free(full); |
| 1154 | + } |
| 1155 | + |
| 1156 | + closedir(dir); |
| 1157 | +} |
| 1158 | + |
| 1159 | +/** Load all the cursor of a theme |
| 1160 | + * |
| 1161 | + * This function loads all the cursor images of a given theme and its |
| 1162 | + * inherited themes. Each cursor is loaded into an XcursorImages object |
| 1163 | + * which is passed to the caller's load callback. If a cursor appears |
| 1164 | + * more than once across all the inherited themes, the load callback |
| 1165 | + * will be called multiple times, with possibly different XcursorImages |
| 1166 | + * object which have the same name. The user is expected to destroy the |
| 1167 | + * XcursorImages objects passed to the callback with |
| 1168 | + * XcursorImagesDestroy(). |
| 1169 | + * |
| 1170 | + * \param theme The name of theme that should be loaded |
| 1171 | + * \param size The desired size of the cursor images |
| 1172 | + * \param load_callback A callback function that will be called |
| 1173 | + * for each cursor loaded. The first parameter is the XcursorImages |
| 1174 | + * object representing the loaded cursor and the second is a pointer |
| 1175 | + * to data provided by the user. |
| 1176 | + * \param user_data The data that should be passed to the load callback |
| 1177 | + */ |
| 1178 | +void |
| 1179 | +xcursor_load_theme(const char *theme, int size, |
| 1180 | + void (*load_callback)(XcursorImages *, void *), |
| 1181 | + void *user_data) |
| 1182 | +{ |
| 1183 | + char *full, *dir; |
| 1184 | + char *inherits = NULL; |
| 1185 | + const char *path, *i; |
| 1186 | + |
| 1187 | + if (!theme) |
| 1188 | + theme = "default"; |
| 1189 | + |
| 1190 | + for (path = XcursorLibraryPath(); |
| 1191 | + path; |
| 1192 | + path = _XcursorNextPath(path)) { |
| 1193 | + dir = _XcursorBuildThemeDir(path, theme); |
| 1194 | + if (!dir) |
| 1195 | + continue; |
| 1196 | + |
| 1197 | + full = _XcursorBuildFullname(dir, "cursors", ""); |
| 1198 | + |
| 1199 | + if (full) { |
| 1200 | + load_all_cursors_from_dir(full, size, load_callback, |
| 1201 | + user_data); |
| 1202 | + free(full); |
| 1203 | + } |
| 1204 | + |
| 1205 | + if (!inherits) { |
| 1206 | + full = _XcursorBuildFullname(dir, "", "index.theme"); |
| 1207 | + if (full) { |
| 1208 | + inherits = _XcursorThemeInherits(full); |
| 1209 | + free(full); |
| 1210 | + } |
| 1211 | + } |
| 1212 | + |
| 1213 | + free(dir); |
| 1214 | + } |
| 1215 | + |
| 1216 | + for (i = inherits; i; i = _XcursorNextPath(i)) |
| 1217 | + xcursor_load_theme(i, size, load_callback, user_data); |
| 1218 | + |
| 1219 | + if (inherits) |
| 1220 | + free(inherits); |
| 1221 | +} |
| 1222 | |
| 1223 | === added file 'plugins/Cursor/3rd_party/xcursor/xcursor.h' |
| 1224 | --- plugins/Cursor/3rd_party/xcursor/xcursor.h 1970-01-01 00:00:00 +0000 |
| 1225 | +++ plugins/Cursor/3rd_party/xcursor/xcursor.h 2015-10-26 09:06:21 +0000 |
| 1226 | @@ -0,0 +1,65 @@ |
| 1227 | +/* |
| 1228 | + * Copyright © 2002 Keith Packard |
| 1229 | + * |
| 1230 | + * Permission to use, copy, modify, distribute, and sell this software and its |
| 1231 | + * documentation for any purpose is hereby granted without fee, provided that |
| 1232 | + * the above copyright notice appear in all copies and that both that |
| 1233 | + * copyright notice and this permission notice appear in supporting |
| 1234 | + * documentation, and that the name of Keith Packard not be used in |
| 1235 | + * advertising or publicity pertaining to distribution of the software without |
| 1236 | + * specific, written prior permission. Keith Packard makes no |
| 1237 | + * representations about the suitability of this software for any purpose. It |
| 1238 | + * is provided "as is" without express or implied warranty. |
| 1239 | + * |
| 1240 | + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
| 1241 | + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
| 1242 | + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
| 1243 | + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| 1244 | + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| 1245 | + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| 1246 | + * PERFORMANCE OF THIS SOFTWARE. |
| 1247 | + */ |
| 1248 | + |
| 1249 | +#ifndef XCURSOR_H |
| 1250 | +#define XCURSOR_H |
| 1251 | + |
| 1252 | +#include <stdint.h> |
| 1253 | + |
| 1254 | + |
| 1255 | +typedef int XcursorBool; |
| 1256 | +typedef uint32_t XcursorUInt; |
| 1257 | + |
| 1258 | +typedef XcursorUInt XcursorDim; |
| 1259 | +typedef XcursorUInt XcursorPixel; |
| 1260 | + |
| 1261 | +typedef struct _XcursorImage { |
| 1262 | + XcursorUInt version; /* version of the image data */ |
| 1263 | + XcursorDim size; /* nominal size for matching */ |
| 1264 | + XcursorDim width; /* actual width */ |
| 1265 | + XcursorDim height; /* actual height */ |
| 1266 | + XcursorDim xhot; /* hot spot x (must be inside image) */ |
| 1267 | + XcursorDim yhot; /* hot spot y (must be inside image) */ |
| 1268 | + XcursorUInt delay; /* animation delay to next frame (ms) */ |
| 1269 | + XcursorPixel *pixels; /* pointer to pixels */ |
| 1270 | +} XcursorImage; |
| 1271 | + |
| 1272 | +/* |
| 1273 | + * Other data structures exposed by the library API |
| 1274 | + */ |
| 1275 | +typedef struct _XcursorImages { |
| 1276 | + int nimage; /* number of images */ |
| 1277 | + XcursorImage **images; /* array of XcursorImage pointers */ |
| 1278 | + char *name; /* name used to load images */ |
| 1279 | +} XcursorImages; |
| 1280 | + |
| 1281 | +XcursorImages * |
| 1282 | +XcursorLibraryLoadImages (const char *file, const char *theme, int size); |
| 1283 | + |
| 1284 | +void |
| 1285 | +XcursorImagesDestroy (XcursorImages *images); |
| 1286 | + |
| 1287 | +void |
| 1288 | +xcursor_load_theme(const char *theme, int size, |
| 1289 | + void (*load_callback)(XcursorImages *, void *), |
| 1290 | + void *user_data); |
| 1291 | +#endif |
| 1292 | |
| 1293 | === added file 'plugins/Cursor/CMakeLists.txt' |
| 1294 | --- plugins/Cursor/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
| 1295 | +++ plugins/Cursor/CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 1296 | @@ -0,0 +1,28 @@ |
| 1297 | +add_subdirectory(3rd_party) |
| 1298 | + |
| 1299 | +include_directories( |
| 1300 | + ${CMAKE_CURRENT_SOURCE_DIR} |
| 1301 | + ${CMAKE_CURRENT_SOURCE_DIR}/3rd_party/xcursor |
| 1302 | + ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
| 1303 | +) |
| 1304 | + |
| 1305 | +set(QMLPLUGIN_SRC |
| 1306 | + plugin.cpp |
| 1307 | + MousePointer.cpp |
| 1308 | + CursorImageProvider.cpp |
| 1309 | + # We need to run moc on this header |
| 1310 | + ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirMousePointerInterface.h |
| 1311 | + ) |
| 1312 | + |
| 1313 | +add_library(Cursor-qml SHARED |
| 1314 | + ${QMLPLUGIN_SRC} |
| 1315 | + ) |
| 1316 | + |
| 1317 | +target_link_libraries(Cursor-qml |
| 1318 | + xcursorloader-static |
| 1319 | + ${QT5PLATFORM_SUPPORT_LDFLAGS} |
| 1320 | +) |
| 1321 | + |
| 1322 | +qt5_use_modules(Cursor-qml Qml Quick DBus Network Gui Sql Concurrent Svg) |
| 1323 | + |
| 1324 | +add_unity8_plugin(Cursor 1.0 Cursor TARGETS Cursor-qml) |
| 1325 | |
| 1326 | === added file 'plugins/Cursor/Cursor.qml' |
| 1327 | --- plugins/Cursor/Cursor.qml 1970-01-01 00:00:00 +0000 |
| 1328 | +++ plugins/Cursor/Cursor.qml 2015-10-26 09:06:21 +0000 |
| 1329 | @@ -0,0 +1,12 @@ |
| 1330 | +import QtQuick 2.4 |
| 1331 | +import Cursor 1.0 // For MousePointer |
| 1332 | + |
| 1333 | +MousePointer { |
| 1334 | + id: mousePointer |
| 1335 | + |
| 1336 | + Image { |
| 1337 | + x: -mousePointer.hotspotX |
| 1338 | + y: -mousePointer.hotspotY |
| 1339 | + source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName |
| 1340 | + } |
| 1341 | +} |
| 1342 | |
| 1343 | === added file 'plugins/Cursor/CursorImageProvider.cpp' |
| 1344 | --- plugins/Cursor/CursorImageProvider.cpp 1970-01-01 00:00:00 +0000 |
| 1345 | +++ plugins/Cursor/CursorImageProvider.cpp 2015-10-26 09:06:21 +0000 |
| 1346 | @@ -0,0 +1,191 @@ |
| 1347 | +/* |
| 1348 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1349 | + * |
| 1350 | + * This program is free software: you can redistribute it and/or modify it under |
| 1351 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 1352 | + * the Free Software Foundation. |
| 1353 | + * |
| 1354 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 1355 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 1356 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 1357 | + * Lesser General Public License for more details. |
| 1358 | + * |
| 1359 | + * You should have received a copy of the GNU Lesser General Public License |
| 1360 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1361 | + */ |
| 1362 | + |
| 1363 | +#include "CursorImageProvider.h" |
| 1364 | + |
| 1365 | +#include <QDebug> |
| 1366 | +#include <QFile> |
| 1367 | +#include <QPainter> |
| 1368 | +#include <QSvgRenderer> |
| 1369 | + |
| 1370 | +CursorImageProvider *CursorImageProvider::m_instance = nullptr; |
| 1371 | + |
| 1372 | +///// |
| 1373 | +// BuiltInCursorImage |
| 1374 | + |
| 1375 | +BuiltInCursorImage::BuiltInCursorImage() |
| 1376 | +{ |
| 1377 | + const char *svgString = |
| 1378 | + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" |
| 1379 | + "<svg" |
| 1380 | + " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"" |
| 1381 | + " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"" |
| 1382 | + " xmlns:svg=\"http://www.w3.org/2000/svg\"" |
| 1383 | + " xmlns=\"http://www.w3.org/2000/svg\"" |
| 1384 | + " version=\"1.1\">" |
| 1385 | + " <path" |
| 1386 | + " style=\"fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:40;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1\"" |
| 1387 | + " d=\"M 20.504,50.94931 460.42533,518.14486 266.47603,515.61948 366.48114,719.16522 274.05218,770.68296 172.53185,559.56112 20.504,716.13476 Z\" />" |
| 1388 | + "</svg>"; |
| 1389 | + |
| 1390 | + qimage = QImage(20, 32, QImage::Format_ARGB32); |
| 1391 | + QPainter imagePainter(&qimage); |
| 1392 | + |
| 1393 | + QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString)); |
| 1394 | + svgRenderer->render(&imagePainter); |
| 1395 | + delete svgRenderer; |
| 1396 | +} |
| 1397 | + |
| 1398 | +///// |
| 1399 | +// XCursorImage |
| 1400 | + |
| 1401 | +XCursorImage::XCursorImage(const QString &theme, const QString &file) |
| 1402 | + : xcursorImages(nullptr) |
| 1403 | +{ |
| 1404 | + xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme), 32); |
| 1405 | + if (!xcursorImages) { |
| 1406 | + return; |
| 1407 | + } |
| 1408 | + |
| 1409 | + bool loaded = false; |
| 1410 | + for (int i = 0; i < xcursorImages->nimage && !loaded; ++i) { |
| 1411 | + XcursorImage *xcursorImage = xcursorImages->images[i]; |
| 1412 | + if (xcursorImage->size == 32) { |
| 1413 | + |
| 1414 | + qimage = QImage((uchar*)xcursorImage->pixels, |
| 1415 | + xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32); |
| 1416 | + |
| 1417 | + hotspot.setX(xcursorImage->xhot); |
| 1418 | + hotspot.setY(xcursorImage->yhot); |
| 1419 | + |
| 1420 | + loaded = true; |
| 1421 | + } |
| 1422 | + } |
| 1423 | +} |
| 1424 | + |
| 1425 | +XCursorImage::~XCursorImage() |
| 1426 | +{ |
| 1427 | + XcursorImagesDestroy(xcursorImages); |
| 1428 | +} |
| 1429 | + |
| 1430 | +///// |
| 1431 | +// CursorImageProvider |
| 1432 | + |
| 1433 | +CursorImageProvider::CursorImageProvider() |
| 1434 | + : QQuickImageProvider(QQuickImageProvider::Image) |
| 1435 | +{ |
| 1436 | + if (m_instance) { |
| 1437 | + qFatal("Cannot have multiple CursorImageProvider instances"); |
| 1438 | + } |
| 1439 | + m_instance = this; |
| 1440 | +} |
| 1441 | + |
| 1442 | +CursorImageProvider::~CursorImageProvider() |
| 1443 | +{ |
| 1444 | + { |
| 1445 | + QList< QMap<QString, CursorImage*> > cursorList = m_cursors.values(); |
| 1446 | + |
| 1447 | + for (int i = 0; i < cursorList.count(); ++i) { |
| 1448 | + QList<CursorImage*> cursorImageList = cursorList[i].values(); |
| 1449 | + for (int j = 0; j < cursorImageList.count(); ++j) { |
| 1450 | + delete cursorImageList[j]; |
| 1451 | + } |
| 1452 | + } |
| 1453 | + } |
| 1454 | + |
| 1455 | + m_cursors.clear(); |
| 1456 | + m_instance = nullptr; |
| 1457 | +} |
| 1458 | + |
| 1459 | +QImage CursorImageProvider::requestImage(const QString &cursorThemeAndName, QSize *size, const QSize & /*requestedSize*/) |
| 1460 | +{ |
| 1461 | + CursorImage *cursorImage = fetchCursor(cursorThemeAndName); |
| 1462 | + size->setWidth(cursorImage->qimage.width()); |
| 1463 | + size->setHeight(cursorImage->qimage.height()); |
| 1464 | + |
| 1465 | + return cursorImage->qimage; |
| 1466 | +} |
| 1467 | + |
| 1468 | +QPoint CursorImageProvider::hotspot(const QString &themeName, const QString &cursorName) |
| 1469 | +{ |
| 1470 | + CursorImage *cursorImage = fetchCursor(themeName, cursorName); |
| 1471 | + if (cursorImage) { |
| 1472 | + return cursorImage->hotspot; |
| 1473 | + } else { |
| 1474 | + return QPoint(0,0); |
| 1475 | + } |
| 1476 | +} |
| 1477 | + |
| 1478 | +CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName) |
| 1479 | +{ |
| 1480 | + QString themeName; |
| 1481 | + QString cursorName; |
| 1482 | + { |
| 1483 | + QStringList themeAndNameList = cursorThemeAndName.split("/"); |
| 1484 | + if (themeAndNameList.size() != 2) { |
| 1485 | + return nullptr; |
| 1486 | + } |
| 1487 | + themeName = themeAndNameList[0]; |
| 1488 | + cursorName = themeAndNameList[1]; |
| 1489 | + } |
| 1490 | + |
| 1491 | + return fetchCursor(themeName, cursorName); |
| 1492 | +} |
| 1493 | + |
| 1494 | +CursorImage *CursorImageProvider::fetchCursor(const QString &themeName, const QString &cursorName) |
| 1495 | +{ |
| 1496 | + CursorImage *cursorImage = fetchCursorHelper(themeName, cursorName); |
| 1497 | + |
| 1498 | + // Try some fallbacks |
| 1499 | + if (cursorImage->qimage.isNull()) { |
| 1500 | + if (cursorName == "ibeam") { |
| 1501 | + qDebug() << "CursorImageProvider: \"ibeam\" not found, falling back to \"xterm\""; |
| 1502 | + cursorImage = fetchCursorHelper(themeName, "xterm"); |
| 1503 | + } else if (cursorName == "xterm") { |
| 1504 | + qDebug() << "CursorImageProvider: \"xterm\" not found, falling back to \"ibeam\""; |
| 1505 | + cursorImage = fetchCursorHelper(themeName, "ibeam"); |
| 1506 | + } |
| 1507 | + } |
| 1508 | + |
| 1509 | + // if it all fails, there must be at least a left_ptr |
| 1510 | + if (cursorImage->qimage.isNull() && cursorName != "left_ptr") { |
| 1511 | + qDebug() << "CursorImageProvider:" << cursorName |
| 1512 | + << "not found (nor its fallbacks, if any). Going for \"left_ptr\" as a last resort."; |
| 1513 | + cursorImage = fetchCursorHelper(themeName, "left_ptr"); |
| 1514 | + } |
| 1515 | + |
| 1516 | + if (cursorImage->qimage.isNull()) { |
| 1517 | + // finally, go for the built-in cursor |
| 1518 | + qWarning() << "CursorImageProvider: couldn't find any cursors. Using the built-in one"; |
| 1519 | + if (!m_builtInCursorImage) { |
| 1520 | + m_builtInCursorImage.reset(new BuiltInCursorImage); |
| 1521 | + } |
| 1522 | + cursorImage = m_builtInCursorImage.data(); |
| 1523 | + } |
| 1524 | + |
| 1525 | + return cursorImage; |
| 1526 | +} |
| 1527 | + |
| 1528 | +CursorImage *CursorImageProvider::fetchCursorHelper(const QString &themeName, const QString &cursorName) |
| 1529 | +{ |
| 1530 | + QMap<QString, CursorImage*> &themeCursors = m_cursors[themeName]; |
| 1531 | + |
| 1532 | + if (!themeCursors.contains(cursorName)) { |
| 1533 | + themeCursors[cursorName] = new XCursorImage(themeName, cursorName); |
| 1534 | + } |
| 1535 | + |
| 1536 | + return themeCursors[cursorName]; |
| 1537 | +} |
| 1538 | |
| 1539 | === added file 'plugins/Cursor/CursorImageProvider.h' |
| 1540 | --- plugins/Cursor/CursorImageProvider.h 1970-01-01 00:00:00 +0000 |
| 1541 | +++ plugins/Cursor/CursorImageProvider.h 2015-10-26 09:06:21 +0000 |
| 1542 | @@ -0,0 +1,76 @@ |
| 1543 | +/* |
| 1544 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1545 | + * |
| 1546 | + * This program is free software: you can redistribute it and/or modify it under |
| 1547 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 1548 | + * the Free Software Foundation. |
| 1549 | + * |
| 1550 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 1551 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 1552 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 1553 | + * Lesser General Public License for more details. |
| 1554 | + * |
| 1555 | + * You should have received a copy of the GNU Lesser General Public License |
| 1556 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1557 | + */ |
| 1558 | + |
| 1559 | +#ifndef CURSORIMAGEPROVIDER_H |
| 1560 | +#define CURSORIMAGEPROVIDER_H |
| 1561 | + |
| 1562 | +#include <QQuickImageProvider> |
| 1563 | +#include <QScopedPointer> |
| 1564 | + |
| 1565 | +// xcursor static lib |
| 1566 | +extern "C" |
| 1567 | +{ |
| 1568 | +#include <xcursor.h> |
| 1569 | +} |
| 1570 | + |
| 1571 | +class CursorImage { |
| 1572 | +public: |
| 1573 | + virtual ~CursorImage() {} |
| 1574 | + |
| 1575 | + QImage qimage; |
| 1576 | + QPoint hotspot; |
| 1577 | +}; |
| 1578 | + |
| 1579 | +class XCursorImage : public CursorImage { |
| 1580 | +public: |
| 1581 | + XCursorImage(const QString &theme, const QString &file); |
| 1582 | + virtual ~XCursorImage(); |
| 1583 | + |
| 1584 | + XcursorImages *xcursorImages; |
| 1585 | +}; |
| 1586 | + |
| 1587 | +class BuiltInCursorImage : public CursorImage { |
| 1588 | +public: |
| 1589 | + BuiltInCursorImage(); |
| 1590 | +}; |
| 1591 | + |
| 1592 | +class CursorImageProvider : public QQuickImageProvider |
| 1593 | +{ |
| 1594 | +public: |
| 1595 | + CursorImageProvider(); |
| 1596 | + virtual ~CursorImageProvider(); |
| 1597 | + |
| 1598 | + static CursorImageProvider *instance() { return m_instance; } |
| 1599 | + |
| 1600 | + |
| 1601 | + QImage requestImage(const QString &cursorName, QSize *size, const QSize &requestedSize) override; |
| 1602 | + |
| 1603 | + QPoint hotspot(const QString &themeName, const QString &cursorName); |
| 1604 | + |
| 1605 | +private: |
| 1606 | + CursorImage *fetchCursor(const QString &cursorThemeAndName); |
| 1607 | + CursorImage *fetchCursor(const QString &themeName, const QString &cursorName); |
| 1608 | + CursorImage *fetchCursorHelper(const QString &themeName, const QString &cursorName); |
| 1609 | + |
| 1610 | + // themeName -> (cursorName -> cursorImage) |
| 1611 | + QMap<QString, QMap<QString, CursorImage*> > m_cursors; |
| 1612 | + |
| 1613 | + QScopedPointer<CursorImage> m_builtInCursorImage; |
| 1614 | + |
| 1615 | + static CursorImageProvider *m_instance; |
| 1616 | +}; |
| 1617 | + |
| 1618 | +#endif // CURSORIMAGEPROVIDER_H |
| 1619 | |
| 1620 | === added file 'plugins/Cursor/MousePointer.cpp' |
| 1621 | --- plugins/Cursor/MousePointer.cpp 1970-01-01 00:00:00 +0000 |
| 1622 | +++ plugins/Cursor/MousePointer.cpp 2015-10-26 09:06:21 +0000 |
| 1623 | @@ -0,0 +1,125 @@ |
| 1624 | +/* |
| 1625 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1626 | + * |
| 1627 | + * This program is free software: you can redistribute it and/or modify it under |
| 1628 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 1629 | + * the Free Software Foundation. |
| 1630 | + * |
| 1631 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 1632 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 1633 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 1634 | + * Lesser General Public License for more details. |
| 1635 | + * |
| 1636 | + * You should have received a copy of the GNU Lesser General Public License |
| 1637 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1638 | + */ |
| 1639 | + |
| 1640 | +#include "MousePointer.h" |
| 1641 | +#include "CursorImageProvider.h" |
| 1642 | + |
| 1643 | +// Unity API |
| 1644 | +#include <unity/shell/application/MirPlatformCursor.h> |
| 1645 | + |
| 1646 | +#include <QQuickWindow> |
| 1647 | +#include <QGuiApplication> |
| 1648 | + |
| 1649 | +#include <qpa/qwindowsysteminterface.h> |
| 1650 | + |
| 1651 | +MousePointer::MousePointer(QQuickItem *parent) |
| 1652 | + : MirMousePointerInterface(parent) |
| 1653 | + , m_cursorName("left_ptr") |
| 1654 | + , m_themeName("default") |
| 1655 | + , m_hotspotX(0) |
| 1656 | + , m_hotspotY(0) |
| 1657 | +{ |
| 1658 | +} |
| 1659 | + |
| 1660 | +void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons, |
| 1661 | + Qt::KeyboardModifiers modifiers) |
| 1662 | +{ |
| 1663 | + if (!parentItem()) { |
| 1664 | + return; |
| 1665 | + } |
| 1666 | + |
| 1667 | + qreal newX = x() + movement.x(); |
| 1668 | + if (newX < 0) { |
| 1669 | + newX = 0; |
| 1670 | + } else if (newX > parentItem()->width()) { |
| 1671 | + newX = parentItem()->width(); |
| 1672 | + } |
| 1673 | + setX(newX); |
| 1674 | + |
| 1675 | + qreal newY = y() + movement.y(); |
| 1676 | + if (newY < 0) { |
| 1677 | + newY = 0; |
| 1678 | + } else if (newY > parentItem()->height()) { |
| 1679 | + newY = parentItem()->height(); |
| 1680 | + } |
| 1681 | + setY(newY); |
| 1682 | + |
| 1683 | + QPointF scenePosition = mapToItem(nullptr, QPointF(0, 0)); |
| 1684 | + QWindowSystemInterface::handleMouseEvent(window(), timestamp, scenePosition /*local*/, scenePosition /*global*/, |
| 1685 | + buttons, modifiers); |
| 1686 | +} |
| 1687 | + |
| 1688 | +void MousePointer::itemChange(ItemChange change, const ItemChangeData &value) |
| 1689 | +{ |
| 1690 | + if (change == ItemSceneChange) { |
| 1691 | + registerWindow(value.window); |
| 1692 | + } |
| 1693 | +} |
| 1694 | + |
| 1695 | +void MousePointer::registerWindow(QWindow *window) |
| 1696 | +{ |
| 1697 | + if (m_registeredWindow && window != m_registeredWindow) { |
| 1698 | + auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredWindow->screen()->handle()->cursor()); |
| 1699 | + if (previousCursor) { |
| 1700 | + previousCursor->setMousePointer(nullptr); |
| 1701 | + } else { |
| 1702 | + qCritical("QPlatformCursor is not a MirPlatformCursor! Cursor module only works in a Mir server."); |
| 1703 | + } |
| 1704 | + } |
| 1705 | + |
| 1706 | + m_registeredWindow = window; |
| 1707 | + |
| 1708 | + if (m_registeredWindow) { |
| 1709 | + auto cursor = dynamic_cast<MirPlatformCursor*>(window->screen()->handle()->cursor()); |
| 1710 | + if (cursor) { |
| 1711 | + cursor->setMousePointer(this); |
| 1712 | + } else { |
| 1713 | + qCritical("QPlaformCursor is not a MirPlatformCursor! Cursor module only works in Mir."); |
| 1714 | + } |
| 1715 | + } |
| 1716 | +} |
| 1717 | + |
| 1718 | +void MousePointer::setCursorName(const QString &cursorName) |
| 1719 | +{ |
| 1720 | + if (cursorName != m_cursorName) { |
| 1721 | + m_cursorName = cursorName; |
| 1722 | + Q_EMIT cursorNameChanged(m_cursorName); |
| 1723 | + updateHotspot(); |
| 1724 | + } |
| 1725 | +} |
| 1726 | + |
| 1727 | +void MousePointer::updateHotspot() |
| 1728 | +{ |
| 1729 | + QPoint newHotspot = CursorImageProvider::instance()->hotspot(m_themeName, m_cursorName); |
| 1730 | + |
| 1731 | + if (m_hotspotX != newHotspot.x()) { |
| 1732 | + m_hotspotX = newHotspot.x(); |
| 1733 | + Q_EMIT hotspotXChanged(m_hotspotX); |
| 1734 | + } |
| 1735 | + |
| 1736 | + if (m_hotspotY != newHotspot.y()) { |
| 1737 | + m_hotspotY = newHotspot.y(); |
| 1738 | + Q_EMIT hotspotYChanged(m_hotspotY); |
| 1739 | + } |
| 1740 | +} |
| 1741 | + |
| 1742 | +void MousePointer::setThemeName(const QString &themeName) |
| 1743 | +{ |
| 1744 | + if (m_themeName != themeName) { |
| 1745 | + m_themeName = themeName; |
| 1746 | + Q_EMIT themeNameChanged(m_themeName); |
| 1747 | + } |
| 1748 | +} |
| 1749 | |
| 1750 | === added file 'plugins/Cursor/MousePointer.h' |
| 1751 | --- plugins/Cursor/MousePointer.h 1970-01-01 00:00:00 +0000 |
| 1752 | +++ plugins/Cursor/MousePointer.h 2015-10-26 09:06:21 +0000 |
| 1753 | @@ -0,0 +1,59 @@ |
| 1754 | +/* |
| 1755 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1756 | + * |
| 1757 | + * This program is free software: you can redistribute it and/or modify it under |
| 1758 | + * the terms of the GNU Lesser General Public License version 3, as published by |
| 1759 | + * the Free Software Foundation. |
| 1760 | + * |
| 1761 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
| 1762 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
| 1763 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 1764 | + * Lesser General Public License for more details. |
| 1765 | + * |
| 1766 | + * You should have received a copy of the GNU Lesser General Public License |
| 1767 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1768 | + */ |
| 1769 | + |
| 1770 | +#ifndef MOUSEPOINTER_H |
| 1771 | +#define MOUSEPOINTER_H |
| 1772 | + |
| 1773 | +// Qt |
| 1774 | +#include <QPointer> |
| 1775 | +#include <QWindow> |
| 1776 | + |
| 1777 | +// Unity API |
| 1778 | +#include <unity/shell/application/MirMousePointerInterface.h> |
| 1779 | + |
| 1780 | +class MousePointer : public MirMousePointerInterface { |
| 1781 | + Q_OBJECT |
| 1782 | +public: |
| 1783 | + MousePointer(QQuickItem *parent = nullptr); |
| 1784 | + |
| 1785 | + void setCursorName(const QString &qtCursorName) override; |
| 1786 | + QString cursorName() const override { return m_cursorName; } |
| 1787 | + |
| 1788 | + void setThemeName(const QString &themeName) override; |
| 1789 | + QString themeName() const override { return m_themeName; } |
| 1790 | + |
| 1791 | + qreal hotspotX() const override { return m_hotspotX; } |
| 1792 | + qreal hotspotY() const override { return m_hotspotY; } |
| 1793 | + |
| 1794 | +public Q_SLOTS: |
| 1795 | + void handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons, |
| 1796 | + Qt::KeyboardModifiers modifiers) override; |
| 1797 | + |
| 1798 | +protected: |
| 1799 | + void itemChange(ItemChange change, const ItemChangeData &value) override; |
| 1800 | + |
| 1801 | +private: |
| 1802 | + void registerWindow(QWindow *window); |
| 1803 | + void updateHotspot(); |
| 1804 | + |
| 1805 | + QPointer<QWindow> m_registeredWindow; |
| 1806 | + QString m_cursorName; |
| 1807 | + QString m_themeName; |
| 1808 | + int m_hotspotX; |
| 1809 | + int m_hotspotY; |
| 1810 | +}; |
| 1811 | + |
| 1812 | +#endif // MOUSEPOINTER_H |
| 1813 | |
| 1814 | === added file 'plugins/Cursor/plugin.cpp' |
| 1815 | --- plugins/Cursor/plugin.cpp 1970-01-01 00:00:00 +0000 |
| 1816 | +++ plugins/Cursor/plugin.cpp 2015-10-26 09:06:21 +0000 |
| 1817 | @@ -0,0 +1,39 @@ |
| 1818 | +/* |
| 1819 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1820 | + * |
| 1821 | + * This program is free software; you can redistribute it and/or modify |
| 1822 | + * it under the terms of the GNU General Public License as published by |
| 1823 | + * the Free Software Foundation; version 3. |
| 1824 | + * |
| 1825 | + * This program is distributed in the hope that it will be useful, |
| 1826 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 1827 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 1828 | + * GNU General Public License for more details. |
| 1829 | + * |
| 1830 | + * You should have received a copy of the GNU General Public License |
| 1831 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1832 | + */ |
| 1833 | + |
| 1834 | +// Qt |
| 1835 | +#include <QtQml/qqml.h> |
| 1836 | +#include <QQmlContext> |
| 1837 | + |
| 1838 | +// self |
| 1839 | +#include "plugin.h" |
| 1840 | + |
| 1841 | +// local |
| 1842 | +#include "CursorImageProvider.h" |
| 1843 | +#include "MousePointer.h" |
| 1844 | + |
| 1845 | +void CursorPlugin::registerTypes(const char *uri) |
| 1846 | +{ |
| 1847 | + Q_ASSERT(uri == QLatin1String("Cursor")); |
| 1848 | + qmlRegisterType<MousePointer>(uri, 1, 0, "MousePointer"); |
| 1849 | +} |
| 1850 | + |
| 1851 | +void CursorPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
| 1852 | +{ |
| 1853 | + QQmlExtensionPlugin::initializeEngine(engine, uri); |
| 1854 | + |
| 1855 | + engine->addImageProvider(QLatin1String("cursor"), new CursorImageProvider()); |
| 1856 | +} |
| 1857 | |
| 1858 | === added file 'plugins/Cursor/plugin.h' |
| 1859 | --- plugins/Cursor/plugin.h 1970-01-01 00:00:00 +0000 |
| 1860 | +++ plugins/Cursor/plugin.h 2015-10-26 09:06:21 +0000 |
| 1861 | @@ -0,0 +1,33 @@ |
| 1862 | +/* |
| 1863 | + * Copyright (C) 2015 Canonical, Ltd. |
| 1864 | + * |
| 1865 | + * This program is free software; you can redistribute it and/or modify |
| 1866 | + * it under the terms of the GNU General Public License as published by |
| 1867 | + * the Free Software Foundation; version 3. |
| 1868 | + * |
| 1869 | + * This program is distributed in the hope that it will be useful, |
| 1870 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 1871 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 1872 | + * GNU General Public License for more details. |
| 1873 | + * |
| 1874 | + * You should have received a copy of the GNU General Public License |
| 1875 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 1876 | + */ |
| 1877 | + |
| 1878 | +#ifndef CURSOR_PLUGIN_H |
| 1879 | +#define CURSOR_PLUGIN_H |
| 1880 | + |
| 1881 | +#include <QtQml/QQmlEngine> |
| 1882 | +#include <QtQml/QQmlExtensionPlugin> |
| 1883 | + |
| 1884 | +class CursorPlugin : public QQmlExtensionPlugin |
| 1885 | +{ |
| 1886 | + Q_OBJECT |
| 1887 | + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") |
| 1888 | + |
| 1889 | +public: |
| 1890 | + void registerTypes(const char *uri) override; |
| 1891 | + void initializeEngine(QQmlEngine *engine, const char *uri) override; |
| 1892 | +}; |
| 1893 | + |
| 1894 | +#endif // CURSOR_PLUGIN_H |
| 1895 | |
| 1896 | === added file 'plugins/Cursor/qmldir' |
| 1897 | --- plugins/Cursor/qmldir 1970-01-01 00:00:00 +0000 |
| 1898 | +++ plugins/Cursor/qmldir 2015-10-26 09:06:21 +0000 |
| 1899 | @@ -0,0 +1,3 @@ |
| 1900 | +module Cursor |
| 1901 | +plugin Cursor-qml |
| 1902 | +Cursor 1.0 Cursor.qml |
| 1903 | |
| 1904 | === modified file 'plugins/IntegratedLightDM/UsersModel.cpp' |
| 1905 | --- plugins/IntegratedLightDM/UsersModel.cpp 2015-04-30 09:31:51 +0000 |
| 1906 | +++ plugins/IntegratedLightDM/UsersModel.cpp 2015-10-26 09:06:21 +0000 |
| 1907 | @@ -43,16 +43,17 @@ |
| 1908 | |
| 1909 | QVariant MangleModel::data(const QModelIndex &index, int role) const |
| 1910 | { |
| 1911 | - QVariant data = QSortFilterProxyModel::data(index, role); |
| 1912 | + QVariant variantData = QSortFilterProxyModel::data(index, role); |
| 1913 | |
| 1914 | // If user's real name is empty, switch to unix name |
| 1915 | - if (role == QLightDM::UsersModel::RealNameRole && data.toString().isEmpty()) { |
| 1916 | - data = QSortFilterProxyModel::data(index, QLightDM::UsersModel::NameRole); |
| 1917 | - } else if (role == QLightDM::UsersModel::BackgroundPathRole && data.toString().startsWith('#')) { |
| 1918 | - data = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + data.toString() + "'/></svg>"; |
| 1919 | + if (role == QLightDM::UsersModel::RealNameRole && variantData.toString().isEmpty()) { |
| 1920 | + variantData = QSortFilterProxyModel::data(index, QLightDM::UsersModel::NameRole); |
| 1921 | + } else if (role == QLightDM::UsersModel::BackgroundPathRole && variantData.toString().startsWith('#')) { |
| 1922 | + const QString stringData = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + variantData.toString() + "'/></svg>"; |
| 1923 | + variantData = stringData; |
| 1924 | } |
| 1925 | |
| 1926 | - return data; |
| 1927 | + return variantData; |
| 1928 | } |
| 1929 | |
| 1930 | // **** Now we continue with actual UsersModel class **** |
| 1931 | |
| 1932 | === modified file 'plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp' |
| 1933 | --- plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp 2015-09-14 09:11:08 +0000 |
| 1934 | +++ plugins/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp 2015-10-26 09:06:21 +0000 |
| 1935 | @@ -34,7 +34,8 @@ |
| 1936 | entries.reserve(users.count()); |
| 1937 | Q_FOREACH(const QString &user, users) |
| 1938 | { |
| 1939 | - QString name = settings.value(user + "/name", user[0].toUpper() + user.mid(1)).toString(); |
| 1940 | + QVariant defaultValue = QString(user[0].toUpper() + user.mid(1)); |
| 1941 | + QString name = settings.value(user + "/name", defaultValue).toString(); |
| 1942 | entries.append({user, name, 0, 0, false, false, 0, 0}); |
| 1943 | } |
| 1944 | } |
| 1945 | |
| 1946 | === modified file 'plugins/ScreenGrabber/screengrabber.cpp' |
| 1947 | --- plugins/ScreenGrabber/screengrabber.cpp 2015-09-23 15:14:01 +0000 |
| 1948 | +++ plugins/ScreenGrabber/screengrabber.cpp 2015-10-26 09:06:21 +0000 |
| 1949 | @@ -60,7 +60,7 @@ |
| 1950 | } |
| 1951 | } |
| 1952 | |
| 1953 | -void ScreenGrabber::captureAndSave() |
| 1954 | +void ScreenGrabber::captureAndSave(int angle) |
| 1955 | { |
| 1956 | if (fileNamePrefix.isEmpty()) |
| 1957 | { |
| 1958 | @@ -82,7 +82,7 @@ |
| 1959 | return; |
| 1960 | } |
| 1961 | |
| 1962 | - const QImage screenshot = main_window->grabWindow(); |
| 1963 | + const QImage screenshot = main_window->grabWindow().transformed(QTransform().rotate(angle)); |
| 1964 | const QString filename = makeFileName(); |
| 1965 | qDebug() << "Saving screenshot to" << filename; |
| 1966 | auto saveOp = QtConcurrent::run(saveScreenshot, screenshot, filename, getFormat(), screenshotQuality); |
| 1967 | |
| 1968 | === modified file 'plugins/ScreenGrabber/screengrabber.h' |
| 1969 | --- plugins/ScreenGrabber/screengrabber.h 2015-07-17 19:59:31 +0000 |
| 1970 | +++ plugins/ScreenGrabber/screengrabber.h 2015-10-26 09:06:21 +0000 |
| 1971 | @@ -29,7 +29,7 @@ |
| 1972 | ~ScreenGrabber() = default; |
| 1973 | |
| 1974 | public Q_SLOTS: |
| 1975 | - void captureAndSave(); |
| 1976 | + void captureAndSave(int angle = 0); |
| 1977 | |
| 1978 | Q_SIGNALS: |
| 1979 | void screenshotSaved(const QString &filename); |
| 1980 | |
| 1981 | === modified file 'plugins/Unity/CMakeLists.txt' |
| 1982 | --- plugins/Unity/CMakeLists.txt 2015-05-05 11:19:15 +0000 |
| 1983 | +++ plugins/Unity/CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 1984 | @@ -4,3 +4,4 @@ |
| 1985 | add_subdirectory(Session) |
| 1986 | add_subdirectory(DashCommunicator) |
| 1987 | add_subdirectory(InputInfo) |
| 1988 | +add_subdirectory(Platform) |
| 1989 | |
| 1990 | === modified file 'plugins/Unity/Launcher/desktopfilehandler.cpp' |
| 1991 | --- plugins/Unity/Launcher/desktopfilehandler.cpp 2015-09-14 09:41:55 +0000 |
| 1992 | +++ plugins/Unity/Launcher/desktopfilehandler.cpp 2015-10-26 09:06:21 +0000 |
| 1993 | @@ -111,8 +111,9 @@ |
| 1994 | settings.beginGroup(QStringLiteral("Desktop Entry")); |
| 1995 | |
| 1996 | // First try to find Name[xx_YY] and Name[xx] in .desktop file |
| 1997 | - QString locale = QLocale().name(); |
| 1998 | - QString shortLocale = locale.split('_').first(); |
| 1999 | + const QString locale = QLocale().name(); |
| 2000 | + const QStringList splitLocale = locale.split(QLatin1Char('_')); |
| 2001 | + const QString shortLocale = splitLocale.first(); |
| 2002 | |
| 2003 | if (locale != shortLocale && settings.contains(QStringLiteral("Name[%1]").arg(locale))) { |
| 2004 | return settings.value(QStringLiteral("Name[%1]").arg(locale)).toString(); |
| 2005 | |
| 2006 | === added directory 'plugins/Unity/Platform' |
| 2007 | === added file 'plugins/Unity/Platform/CMakeLists.txt' |
| 2008 | --- plugins/Unity/Platform/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
| 2009 | +++ plugins/Unity/Platform/CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 2010 | @@ -0,0 +1,9 @@ |
| 2011 | +set(platformplugin_SRCS |
| 2012 | + platform.cpp |
| 2013 | + plugin.cpp) |
| 2014 | + |
| 2015 | +add_library(Platform-qml SHARED ${platformplugin_SRCS}) |
| 2016 | + |
| 2017 | +qt5_use_modules(Platform-qml DBus Qml) |
| 2018 | + |
| 2019 | +add_unity8_plugin(Unity.Platform 1.0 Unity/Platform TARGETS Platform-qml) |
| 2020 | |
| 2021 | === added file 'plugins/Unity/Platform/platform.cpp' |
| 2022 | --- plugins/Unity/Platform/platform.cpp 1970-01-01 00:00:00 +0000 |
| 2023 | +++ plugins/Unity/Platform/platform.cpp 2015-10-26 09:06:21 +0000 |
| 2024 | @@ -0,0 +1,43 @@ |
| 2025 | +/* |
| 2026 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2027 | + * |
| 2028 | + * This program is free software; you can redistribute it and/or modify |
| 2029 | + * it under the terms of the GNU General Public License as published by |
| 2030 | + * the Free Software Foundation; version 3. |
| 2031 | + * |
| 2032 | + * This program is distributed in the hope that it will be useful, |
| 2033 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2034 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2035 | + * GNU General Public License for more details. |
| 2036 | + * |
| 2037 | + * You should have received a copy of the GNU General Public License |
| 2038 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2039 | + */ |
| 2040 | + |
| 2041 | +#include "platform.h" |
| 2042 | + |
| 2043 | +#include <QDBusConnection> |
| 2044 | + |
| 2045 | +Platform::Platform(QObject *parent) |
| 2046 | + : QObject(parent) |
| 2047 | + , m_iface("org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.hostname1", |
| 2048 | + QDBusConnection::systemBus(), this) |
| 2049 | +{ |
| 2050 | + QMetaObject::invokeMethod(this, "init"); |
| 2051 | +} |
| 2052 | + |
| 2053 | +void Platform::init() |
| 2054 | +{ |
| 2055 | + m_chassis = m_iface.property("Chassis").toString(); |
| 2056 | + m_isPC = (m_chassis == "desktop" || m_chassis == "laptop" || m_chassis == "server"); |
| 2057 | +} |
| 2058 | + |
| 2059 | +QString Platform::chassis() const |
| 2060 | +{ |
| 2061 | + return m_chassis; |
| 2062 | +} |
| 2063 | + |
| 2064 | +bool Platform::isPC() const |
| 2065 | +{ |
| 2066 | + return m_isPC; |
| 2067 | +} |
| 2068 | |
| 2069 | === added file 'plugins/Unity/Platform/platform.h' |
| 2070 | --- plugins/Unity/Platform/platform.h 1970-01-01 00:00:00 +0000 |
| 2071 | +++ plugins/Unity/Platform/platform.h 2015-10-26 09:06:21 +0000 |
| 2072 | @@ -0,0 +1,58 @@ |
| 2073 | +/* |
| 2074 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2075 | + * |
| 2076 | + * This program is free software; you can redistribute it and/or modify |
| 2077 | + * it under the terms of the GNU General Public License as published by |
| 2078 | + * the Free Software Foundation; version 3. |
| 2079 | + * |
| 2080 | + * This program is distributed in the hope that it will be useful, |
| 2081 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2082 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2083 | + * GNU General Public License for more details. |
| 2084 | + * |
| 2085 | + * You should have received a copy of the GNU General Public License |
| 2086 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2087 | + */ |
| 2088 | + |
| 2089 | +#ifndef PLATFORM_H |
| 2090 | +#define PLATFORM_H |
| 2091 | + |
| 2092 | +#include <QDBusInterface> |
| 2093 | + |
| 2094 | +/** |
| 2095 | + * @brief The Platform class |
| 2096 | + * |
| 2097 | + * Wrapper around platform detection support (org.freedesktop.hostname1) |
| 2098 | + */ |
| 2099 | +class Platform: public QObject |
| 2100 | +{ |
| 2101 | + Q_OBJECT |
| 2102 | + /** |
| 2103 | + * The chassis property |
| 2104 | + * |
| 2105 | + * Supported values include: "laptop", "computer", "handset" or "tablet" |
| 2106 | + * For full list see: http://www.freedesktop.org/wiki/Software/systemd/hostnamed/ |
| 2107 | + */ |
| 2108 | + Q_PROPERTY(QString chassis READ chassis CONSTANT) |
| 2109 | + /** |
| 2110 | + * Whether the machine is an ordinary PC (desktop, laptop or server) |
| 2111 | + */ |
| 2112 | + Q_PROPERTY(bool isPC READ isPC CONSTANT) |
| 2113 | + |
| 2114 | +public: |
| 2115 | + Platform(QObject *parent = nullptr); |
| 2116 | + ~Platform() = default; |
| 2117 | + |
| 2118 | + QString chassis() const; |
| 2119 | + bool isPC() const; |
| 2120 | + |
| 2121 | +private Q_SLOTS: |
| 2122 | + void init(); |
| 2123 | + |
| 2124 | +private: |
| 2125 | + QDBusInterface m_iface; |
| 2126 | + QString m_chassis; |
| 2127 | + bool m_isPC; |
| 2128 | +}; |
| 2129 | + |
| 2130 | +#endif // PLATFORM_H |
| 2131 | |
| 2132 | === added file 'plugins/Unity/Platform/plugin.cpp' |
| 2133 | --- plugins/Unity/Platform/plugin.cpp 1970-01-01 00:00:00 +0000 |
| 2134 | +++ plugins/Unity/Platform/plugin.cpp 2015-10-26 09:06:21 +0000 |
| 2135 | @@ -0,0 +1,27 @@ |
| 2136 | +/* |
| 2137 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2138 | + * |
| 2139 | + * This program is free software; you can redistribute it and/or modify |
| 2140 | + * it under the terms of the GNU General Public License as published by |
| 2141 | + * the Free Software Foundation; version 3. |
| 2142 | + * |
| 2143 | + * This program is distributed in the hope that it will be useful, |
| 2144 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2145 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2146 | + * GNU General Public License for more details. |
| 2147 | + * |
| 2148 | + * You should have received a copy of the GNU General Public License |
| 2149 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2150 | + */ |
| 2151 | + |
| 2152 | +#include "plugin.h" |
| 2153 | +#include "platform.h" |
| 2154 | + |
| 2155 | +#include <QtQml> |
| 2156 | + |
| 2157 | +void GlobalShortcutPlugin::registerTypes(const char *uri) |
| 2158 | +{ |
| 2159 | + Q_ASSERT(uri == QLatin1String("Unity.Platform")); |
| 2160 | + |
| 2161 | + qmlRegisterSingletonType<Platform>(uri, 1, 0, "Platform", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Platform; }); |
| 2162 | +} |
| 2163 | |
| 2164 | === added file 'plugins/Unity/Platform/plugin.h' |
| 2165 | --- plugins/Unity/Platform/plugin.h 1970-01-01 00:00:00 +0000 |
| 2166 | +++ plugins/Unity/Platform/plugin.h 2015-10-26 09:06:21 +0000 |
| 2167 | @@ -0,0 +1,32 @@ |
| 2168 | +/* |
| 2169 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2170 | + * |
| 2171 | + * This program is free software; you can redistribute it and/or modify |
| 2172 | + * it under the terms of the GNU General Public License as published by |
| 2173 | + * the Free Software Foundation; version 3. |
| 2174 | + * |
| 2175 | + * This program is distributed in the hope that it will be useful, |
| 2176 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2177 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2178 | + * GNU General Public License for more details. |
| 2179 | + * |
| 2180 | + * You should have received a copy of the GNU General Public License |
| 2181 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2182 | + */ |
| 2183 | + |
| 2184 | +#ifndef PLATFORMPLUGIN_H |
| 2185 | +#define PLATFORMPLUGIN_H |
| 2186 | + |
| 2187 | +#include <QQmlExtensionPlugin> |
| 2188 | + |
| 2189 | +class GlobalShortcutPlugin: public QQmlExtensionPlugin |
| 2190 | +{ |
| 2191 | + Q_OBJECT |
| 2192 | + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) |
| 2193 | + |
| 2194 | +public: |
| 2195 | + void registerTypes(const char *uri) override; |
| 2196 | +}; |
| 2197 | + |
| 2198 | + |
| 2199 | +#endif // PLATFORMPLUGIN_H |
| 2200 | |
| 2201 | === added file 'plugins/Unity/Platform/qmldir' |
| 2202 | --- plugins/Unity/Platform/qmldir 1970-01-01 00:00:00 +0000 |
| 2203 | +++ plugins/Unity/Platform/qmldir 2015-10-26 09:06:21 +0000 |
| 2204 | @@ -0,0 +1,2 @@ |
| 2205 | +module Unity.Platform |
| 2206 | +plugin Platform-qml |
| 2207 | |
| 2208 | === modified file 'plugins/Unity/Session/dbusunitysessionservice.cpp' |
| 2209 | --- plugins/Unity/Session/dbusunitysessionservice.cpp 2015-09-14 09:11:08 +0000 |
| 2210 | +++ plugins/Unity/Session/dbusunitysessionservice.cpp 2015-10-26 09:06:21 +0000 |
| 2211 | @@ -292,7 +292,8 @@ |
| 2212 | if (p) { |
| 2213 | const QString gecos = QString::fromLocal8Bit(p->pw_gecos); |
| 2214 | if (!gecos.isEmpty()) { |
| 2215 | - return gecos.split(QLatin1Char(',')).first(); |
| 2216 | + const QStringList splitGecos = gecos.split(QLatin1Char(',')); |
| 2217 | + return splitGecos.first(); |
| 2218 | } |
| 2219 | } |
| 2220 | |
| 2221 | |
| 2222 | === modified file 'plugins/Utils/CMakeLists.txt' |
| 2223 | --- plugins/Utils/CMakeLists.txt 2015-09-25 12:13:13 +0000 |
| 2224 | +++ plugins/Utils/CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 2225 | @@ -15,8 +15,6 @@ |
| 2226 | inputwatcher.cpp |
| 2227 | qlimitproxymodelqml.cpp |
| 2228 | unitysortfilterproxymodelqml.cpp |
| 2229 | - relativetimeformatter.cpp |
| 2230 | - timeformatter.cpp |
| 2231 | Timer.cpp |
| 2232 | unitymenumodelpaths.cpp |
| 2233 | windowkeysfilter.cpp |
| 2234 | |
| 2235 | === modified file 'plugins/Utils/plugin.cpp' |
| 2236 | --- plugins/Utils/plugin.cpp 2015-09-25 12:13:13 +0000 |
| 2237 | +++ plugins/Utils/plugin.cpp 2015-10-26 09:06:21 +0000 |
| 2238 | @@ -29,8 +29,6 @@ |
| 2239 | #include "inputwatcher.h" |
| 2240 | #include "qlimitproxymodelqml.h" |
| 2241 | #include "unitysortfilterproxymodelqml.h" |
| 2242 | -#include "relativetimeformatter.h" |
| 2243 | -#include "timeformatter.h" |
| 2244 | #include "unitymenumodelpaths.h" |
| 2245 | #include "windowkeysfilter.h" |
| 2246 | #include "windowscreenshotprovider.h" |
| 2247 | @@ -60,11 +58,8 @@ |
| 2248 | qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel"); |
| 2249 | qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel"); |
| 2250 | qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths"); |
| 2251 | - qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter"); |
| 2252 | qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter"); |
| 2253 | - qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter"); |
| 2254 | qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve"); |
| 2255 | - qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter"); |
| 2256 | qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage); |
| 2257 | qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher"); |
| 2258 | qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants); |
| 2259 | |
| 2260 | === removed file 'plugins/Utils/relativetimeformatter.cpp' |
| 2261 | --- plugins/Utils/relativetimeformatter.cpp 2015-09-21 13:17:30 +0000 |
| 2262 | +++ plugins/Utils/relativetimeformatter.cpp 1970-01-01 00:00:00 +0000 |
| 2263 | @@ -1,260 +0,0 @@ |
| 2264 | -/* |
| 2265 | - * Copyright 2014 Canonical Ltd. |
| 2266 | - * |
| 2267 | - * This program is free software; you can redistribute it and/or modify |
| 2268 | - * it under the terms of the GNU General Public License as published by |
| 2269 | - * the Free Software Foundation; version 3. |
| 2270 | - * |
| 2271 | - * This program is distributed in the hope that it will be useful, |
| 2272 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2273 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2274 | - * GNU General Public License for more details. |
| 2275 | - * |
| 2276 | - * You should have received a copy of the GNU General Public License |
| 2277 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2278 | - * |
| 2279 | - */ |
| 2280 | - |
| 2281 | -// Local |
| 2282 | -#include "relativetimeformatter.h" |
| 2283 | - |
| 2284 | -// Qt |
| 2285 | -#include <QDateTime> |
| 2286 | - |
| 2287 | -// Other |
| 2288 | -#include <glib.h> |
| 2289 | -#include <glib/gi18n.h> |
| 2290 | -#include <locale.h> |
| 2291 | -#include <langinfo.h> |
| 2292 | -#include <string.h> |
| 2293 | - |
| 2294 | -RelativeTimeFormatter::RelativeTimeFormatter(QObject *parent) |
| 2295 | - : GDateTimeFormatter(parent) |
| 2296 | -{ |
| 2297 | -} |
| 2298 | - |
| 2299 | - /* Check the system locale setting to see if the format is 24-hour |
| 2300 | - time or 12-hour time */ |
| 2301 | -gboolean |
| 2302 | -is_locale_12h(void) |
| 2303 | -{ |
| 2304 | - int i; |
| 2305 | - static const char *formats_24h[] = {"%H", "%R", "%T", "%OH", "%k", nullptr}; |
| 2306 | - const char* t_fmt = nl_langinfo(T_FMT); |
| 2307 | - |
| 2308 | - for (i=0; formats_24h[i]!=nullptr; i++) |
| 2309 | - if (strstr(t_fmt, formats_24h[i]) != nullptr) |
| 2310 | - return FALSE; |
| 2311 | - |
| 2312 | - return TRUE; |
| 2313 | -} |
| 2314 | - |
| 2315 | -typedef enum |
| 2316 | -{ |
| 2317 | - DATE_PROXIMITY_YESTERDAY, |
| 2318 | - DATE_PROXIMITY_TODAY, |
| 2319 | - DATE_PROXIMITY_TOMORROW, |
| 2320 | - DATE_PROXIMITY_LAST_WEEK, |
| 2321 | - DATE_PROXIMITY_NEXT_WEEK, |
| 2322 | - DATE_PROXIMITY_FAR |
| 2323 | -} date_proximity_t; |
| 2324 | - |
| 2325 | -static date_proximity_t |
| 2326 | -getDateProximity(GDateTime* now, GDateTime* time) |
| 2327 | -{ |
| 2328 | - date_proximity_t prox = DATE_PROXIMITY_FAR; |
| 2329 | - gint now_year, now_month, now_day; |
| 2330 | - gint time_year, time_month, time_day; |
| 2331 | - |
| 2332 | - // does it happen today? |
| 2333 | - g_date_time_get_ymd(now, &now_year, &now_month, &now_day); |
| 2334 | - g_date_time_get_ymd(time, &time_year, &time_month, &time_day); |
| 2335 | - if ((now_year == time_year) && (now_month == time_month) && (now_day == time_day)) { |
| 2336 | - return DATE_PROXIMITY_TODAY; |
| 2337 | - } |
| 2338 | - |
| 2339 | - // did it happen yesterday? |
| 2340 | - GDateTime* yesterday = g_date_time_add_days(now, -1); |
| 2341 | - gint tom_year, tom_month, tom_day; |
| 2342 | - g_date_time_get_ymd(yesterday, &tom_year, &tom_month, &tom_day); |
| 2343 | - g_date_time_unref(yesterday); |
| 2344 | - if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) { |
| 2345 | - return DATE_PROXIMITY_YESTERDAY; |
| 2346 | - } |
| 2347 | - |
| 2348 | - // does it happen tomorrow? |
| 2349 | - GDateTime* tomorrow = g_date_time_add_days(now, 1); |
| 2350 | - g_date_time_get_ymd(tomorrow, &tom_year, &tom_month, &tom_day); |
| 2351 | - g_date_time_unref(tomorrow); |
| 2352 | - if ((tom_year == time_year) && (tom_month == time_month) && (tom_day == time_day)) { |
| 2353 | - return DATE_PROXIMITY_TOMORROW; |
| 2354 | - } |
| 2355 | - |
| 2356 | - // does it happen this week? |
| 2357 | - if (g_date_time_compare(time, now) < 0) { |
| 2358 | - GDateTime* last_week = g_date_time_add_days(now, -6); |
| 2359 | - GDateTime* last_week_bound = g_date_time_new_local(g_date_time_get_year(last_week), |
| 2360 | - g_date_time_get_month(last_week), |
| 2361 | - g_date_time_get_day_of_month(last_week), |
| 2362 | - 0, 0, 0); |
| 2363 | - if (g_date_time_compare(time, last_week_bound) >= 0) |
| 2364 | - prox = DATE_PROXIMITY_LAST_WEEK; |
| 2365 | - |
| 2366 | - g_date_time_unref(last_week); |
| 2367 | - g_date_time_unref(last_week_bound); |
| 2368 | - } else { |
| 2369 | - GDateTime* next_week = g_date_time_add_days(now, 6); |
| 2370 | - GDateTime* next_week_bound = g_date_time_new_local(g_date_time_get_year(next_week), |
| 2371 | - g_date_time_get_month(next_week), |
| 2372 | - g_date_time_get_day_of_month(next_week), |
| 2373 | - 23, 59, 59.9); |
| 2374 | - if (g_date_time_compare(time, next_week_bound) <= 0) |
| 2375 | - prox = DATE_PROXIMITY_NEXT_WEEK; |
| 2376 | - |
| 2377 | - g_date_time_unref(next_week); |
| 2378 | - g_date_time_unref(next_week_bound); |
| 2379 | - } |
| 2380 | - |
| 2381 | - return prox; |
| 2382 | -} |
| 2383 | - |
| 2384 | -const char* |
| 2385 | -dgettext_datetime(const char *text) |
| 2386 | -{ |
| 2387 | - return dgettext("unity8", text); |
| 2388 | -} |
| 2389 | - |
| 2390 | -/** |
| 2391 | - * _ a time yesterday should be shown as (e.g. “Yesterday 3:55 PM”) |
| 2392 | - * _ a time today should be shown as just the time (e.g. “3:55 PM”) |
| 2393 | - * _ a time tomorrow should be shown as(e.g. “Tomorrow 3:55 PM”) |
| 2394 | - * _ a time any other day this week should be shown as the short version of the |
| 2395 | - * day and time (e.g. “Wed 3:55 PM”) |
| 2396 | - * weekday (e.g. “Friday”) |
| 2397 | - * _ a time after this week should be shown as the short version of the day, |
| 2398 | - * date, and time (e.g. “Wed 21 Apr 3:55 PM”) |
| 2399 | - * _ in addition, when presenting the times of upcoming events, the time should |
| 2400 | - * be followed by the timezone if it is different from the one the computer |
| 2401 | - * is currently set to. For example, “Wed 3:55 PM UTC−5”. |
| 2402 | - * |
| 2403 | - * TODO - keep inline with indicator-datetime |
| 2404 | - */ |
| 2405 | -char* generate_full_format_string_at_time (GDateTime* now, |
| 2406 | - GDateTime* then) |
| 2407 | -{ |
| 2408 | - GString* ret = g_string_new (nullptr); |
| 2409 | - |
| 2410 | - if (then != nullptr) { |
| 2411 | - const date_proximity_t prox = getDateProximity(now, then); |
| 2412 | - |
| 2413 | - if (is_locale_12h()) { |
| 2414 | - switch (prox) { |
| 2415 | - case DATE_PROXIMITY_YESTERDAY: |
| 2416 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
| 2417 | - This format string is used for showing, on a 12-hour clock, times that happen yesterday. |
| 2418 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
| 2419 | - en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 1:00 PM" */ |
| 2420 | - g_string_assign (ret, dgettext_datetime("Yesterday\u2003%l:%M %p")); |
| 2421 | - break; |
| 2422 | - |
| 2423 | - case DATE_PROXIMITY_TODAY: |
| 2424 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
| 2425 | - This format string is used for showing, on a 12-hour clock, times that happened today. |
| 2426 | - en_US example: "%l:%M %p" --> "1:00 PM" */ |
| 2427 | - g_string_assign (ret, dgettext_datetime("%l:%M %p")); |
| 2428 | - break; |
| 2429 | - |
| 2430 | - case DATE_PROXIMITY_TOMORROW: |
| 2431 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
| 2432 | - This format string is used for showing, on a 12-hour clock, events/appointments that happen tomorrow. |
| 2433 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
| 2434 | - en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 1:00 PM" */ |
| 2435 | - g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%l:%M %p")); |
| 2436 | - break; |
| 2437 | - |
| 2438 | - case DATE_PROXIMITY_LAST_WEEK: |
| 2439 | - case DATE_PROXIMITY_NEXT_WEEK: |
| 2440 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
| 2441 | - This format string is used for showing, on a 12-hour clock, times that happened in the last week. |
| 2442 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
| 2443 | - en_US example: "%a\u2003%l:%M %p" --> "Fri 1:00 PM" */ |
| 2444 | - g_string_assign (ret, dgettext_datetime("%a\u2003%l:%M %p")); |
| 2445 | - break; |
| 2446 | - |
| 2447 | - case DATE_PROXIMITY_FAR: |
| 2448 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
| 2449 | - This format string is used for showing, on a 12-hour clock, times that happened before a week from now. |
| 2450 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
| 2451 | - en_US example: "%a %b %d\u2003%l:%M %p" --> "Fri Oct 31 1:00 PM" |
| 2452 | - en_GB example: "%a %d %b\u2003%l:%M %p" --> "Fri 31 Oct 1:00 PM" */ |
| 2453 | - g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%l:%M %p")); |
| 2454 | - break; |
| 2455 | - } |
| 2456 | - } else { |
| 2457 | - switch (prox) { |
| 2458 | - |
| 2459 | - case DATE_PROXIMITY_YESTERDAY: |
| 2460 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
| 2461 | - This format string is used for showing, on a 24-hour clock, times that happen yesterday. |
| 2462 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
| 2463 | - en_US example: "Yesterday\u2003%l:%M %p" --> "Yesterday 13:00" */ |
| 2464 | - g_string_assign (ret, dgettext_datetime("Yesterday\u2003%H:%M")); |
| 2465 | - break; |
| 2466 | - |
| 2467 | - case DATE_PROXIMITY_TODAY: |
| 2468 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
| 2469 | - This format string is used for showing, on a 24-hour clock, times that happened today. |
| 2470 | - en_US example: "%H:%M" --> "13:00" */ |
| 2471 | - g_string_assign (ret, dgettext_datetime("%H:%M")); |
| 2472 | - break; |
| 2473 | - |
| 2474 | - case DATE_PROXIMITY_TOMORROW: |
| 2475 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
| 2476 | - This format string is used for showing, on a 24-hour clock, events/appointments that happen tomorrow. |
| 2477 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
| 2478 | - en_US example: "Tomorrow\u2003%l:%M %p" --> "Tomorrow 13:00" */ |
| 2479 | - g_string_assign (ret, dgettext_datetime("Tomorrow\u2003%H:%M")); |
| 2480 | - break; |
| 2481 | - |
| 2482 | - case DATE_PROXIMITY_LAST_WEEK: |
| 2483 | - case DATE_PROXIMITY_NEXT_WEEK: |
| 2484 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
| 2485 | - This format string is used for showing, on a 24-hour clock, times that happened in the last week. |
| 2486 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
| 2487 | - en_US example: "%a\u2003%H:%M" --> "Fri 13:00" */ |
| 2488 | - g_string_assign (ret, dgettext_datetime("%a\u2003%H:%M")); |
| 2489 | - break; |
| 2490 | - |
| 2491 | - case DATE_PROXIMITY_FAR: |
| 2492 | - /* Translators, please edit/rearrange these strftime(3) tokens to suit your locale! |
| 2493 | - This format string is used for showing, on a 24-hour clock, times that happened before a week from now. |
| 2494 | - (\u2003 is a unicode em space which is slightly wider than a normal space.) |
| 2495 | - en_US example: "%a %b %d\u2003%H:%M" --> "Fri Oct 31 13:00" |
| 2496 | - en_GB example: "%a %d %b\u2003%H:%M" --> "Fri 31 Oct 13:00" */ |
| 2497 | - g_string_assign (ret, dgettext_datetime("%a %d %b\u2003%H:%M")); |
| 2498 | - break; |
| 2499 | - } |
| 2500 | - } |
| 2501 | - } |
| 2502 | - |
| 2503 | - return g_string_free (ret, FALSE); |
| 2504 | -} |
| 2505 | - |
| 2506 | -QString RelativeTimeFormatter::format() const |
| 2507 | -{ |
| 2508 | - GDateTime* now = g_date_time_new_now_local(); |
| 2509 | - if (!now) { return QString(); } |
| 2510 | - |
| 2511 | - GDateTime* then = g_date_time_new_from_unix_local(time()); |
| 2512 | - if (!then) { return QString(); } |
| 2513 | - |
| 2514 | - char* time_format = generate_full_format_string_at_time(now, then); |
| 2515 | - |
| 2516 | - QString str(QString::fromUtf8(time_format)); |
| 2517 | - g_free(time_format); |
| 2518 | - |
| 2519 | - g_date_time_unref(now); |
| 2520 | - g_date_time_unref(then); |
| 2521 | - |
| 2522 | - return str; |
| 2523 | -} |
| 2524 | |
| 2525 | === removed file 'plugins/Utils/relativetimeformatter.h' |
| 2526 | --- plugins/Utils/relativetimeformatter.h 2014-09-19 14:46:53 +0000 |
| 2527 | +++ plugins/Utils/relativetimeformatter.h 1970-01-01 00:00:00 +0000 |
| 2528 | @@ -1,34 +0,0 @@ |
| 2529 | -/* |
| 2530 | - * Copyright 2014 Canonical Ltd. |
| 2531 | - * |
| 2532 | - * This program is free software; you can redistribute it and/or modify |
| 2533 | - * it under the terms of the GNU General Public License as published by |
| 2534 | - * the Free Software Foundation; version 3. |
| 2535 | - * |
| 2536 | - * This program is distributed in the hope that it will be useful, |
| 2537 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2538 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2539 | - * GNU General Public License for more details. |
| 2540 | - * |
| 2541 | - * You should have received a copy of the GNU General Public License |
| 2542 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2543 | - * |
| 2544 | - */ |
| 2545 | - |
| 2546 | -#ifndef RELATIVETIMEFORMATTER_H |
| 2547 | -#define RELATIVETIMEFORMATTER_H |
| 2548 | - |
| 2549 | -#include "timeformatter.h" |
| 2550 | - |
| 2551 | -// TODO - move this to the sdk |
| 2552 | -// https://blueprints.launchpad.net/ubuntu-ui-toolkit/+spec/time-formatter |
| 2553 | -class RelativeTimeFormatter : public GDateTimeFormatter |
| 2554 | -{ |
| 2555 | - Q_OBJECT |
| 2556 | -public: |
| 2557 | - RelativeTimeFormatter(QObject *parent = 0); |
| 2558 | - |
| 2559 | - QString format() const override; |
| 2560 | -}; |
| 2561 | - |
| 2562 | -#endif // RELATIVETIMEFORMATTER_H |
| 2563 | |
| 2564 | === removed file 'plugins/Utils/timeformatter.cpp' |
| 2565 | --- plugins/Utils/timeformatter.cpp 2015-09-24 14:02:25 +0000 |
| 2566 | +++ plugins/Utils/timeformatter.cpp 1970-01-01 00:00:00 +0000 |
| 2567 | @@ -1,206 +0,0 @@ |
| 2568 | -/* |
| 2569 | - * Copyright 2013 Canonical Ltd. |
| 2570 | - * |
| 2571 | - * This program is free software; you can redistribute it and/or modify |
| 2572 | - * it under the terms of the GNU General Public License as published by |
| 2573 | - * the Free Software Foundation; version 3. |
| 2574 | - * |
| 2575 | - * This program is distributed in the hope that it will be useful, |
| 2576 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2577 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2578 | - * GNU General Public License for more details. |
| 2579 | - * |
| 2580 | - * You should have received a copy of the GNU General Public License |
| 2581 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2582 | - * |
| 2583 | - * Author: Lars Uebernickel <lars.uebernickel@canonical.com> |
| 2584 | - */ |
| 2585 | - |
| 2586 | -#include "timeformatter.h" |
| 2587 | - |
| 2588 | -#include <gio/gio.h> |
| 2589 | -#include <QDateTime> |
| 2590 | - |
| 2591 | -struct TimeFormatterPrivate |
| 2592 | -{ |
| 2593 | - TimeFormatter *formatter; |
| 2594 | - |
| 2595 | - QString format; |
| 2596 | - QString timeString; |
| 2597 | - qint64 time; |
| 2598 | - |
| 2599 | - GDBusConnection *system_bus; |
| 2600 | - guint subscription_id; |
| 2601 | - GCancellable *cancellable; |
| 2602 | -}; |
| 2603 | - |
| 2604 | -static void |
| 2605 | -timedate1_properties_changed (GDBusConnection *connection, |
| 2606 | - const gchar *sender_name, |
| 2607 | - const gchar *object_path, |
| 2608 | - const gchar *interface_name, |
| 2609 | - const gchar *signal_name, |
| 2610 | - GVariant *parameters, |
| 2611 | - gpointer user_data) |
| 2612 | -{ |
| 2613 | - Q_UNUSED(connection); |
| 2614 | - Q_UNUSED(sender_name); |
| 2615 | - Q_UNUSED(object_path); |
| 2616 | - Q_UNUSED(interface_name); |
| 2617 | - Q_UNUSED(signal_name); |
| 2618 | - |
| 2619 | - TimeFormatterPrivate *priv = (TimeFormatterPrivate *)user_data; |
| 2620 | - GVariant *changed; |
| 2621 | - GVariantIter *iter; |
| 2622 | - const gchar *name; |
| 2623 | - |
| 2624 | - if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)"))) |
| 2625 | - return; |
| 2626 | - |
| 2627 | - g_variant_get (parameters, "(s@a{sv}as)", nullptr, &changed, &iter); |
| 2628 | - |
| 2629 | - if (g_variant_lookup (changed, "Timezone", "s", nullptr)) { |
| 2630 | - priv->formatter->update(); |
| 2631 | - } |
| 2632 | - else { |
| 2633 | - while (g_variant_iter_next (iter, "&s", &name)) { |
| 2634 | - if (g_str_equal (name, "Timezone")) { |
| 2635 | - priv->formatter->update(); |
| 2636 | - break; |
| 2637 | - } |
| 2638 | - } |
| 2639 | - } |
| 2640 | - |
| 2641 | - g_variant_unref (changed); |
| 2642 | - g_variant_iter_free (iter); |
| 2643 | -} |
| 2644 | - |
| 2645 | -static void |
| 2646 | -got_bus(GObject *object, GAsyncResult *result, gpointer user_data) |
| 2647 | -{ |
| 2648 | - Q_UNUSED(object); |
| 2649 | - |
| 2650 | - TimeFormatterPrivate *priv = (TimeFormatterPrivate *)user_data; |
| 2651 | - GError *error = nullptr; |
| 2652 | - |
| 2653 | - priv->system_bus = g_bus_get_finish (result, &error); |
| 2654 | - if (priv->system_bus == nullptr) { |
| 2655 | - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) |
| 2656 | - qWarning("TimeFormatter: cannot connect to the system bus: %s", error->message); |
| 2657 | - g_error_free (error); |
| 2658 | - return; |
| 2659 | - } |
| 2660 | - |
| 2661 | - /* Listen to the PropertiesChanged on the org.freedesktop.timedate1 |
| 2662 | - * interface from any sender. In practice, this signal will only be sent |
| 2663 | - * from timedated (we can trust other processes on the system bus to behave |
| 2664 | - * nicely). That way, we don't have to watch timedated's well-known name |
| 2665 | - * and keep the process alive. |
| 2666 | - */ |
| 2667 | - priv->subscription_id = g_dbus_connection_signal_subscribe (priv->system_bus, |
| 2668 | - nullptr, /* sender */ |
| 2669 | - "org.freedesktop.DBus.Properties", |
| 2670 | - "PropertiesChanged", |
| 2671 | - nullptr, |
| 2672 | - "org.freedesktop.timedate1", |
| 2673 | - G_DBUS_SIGNAL_FLAGS_NONE, |
| 2674 | - timedate1_properties_changed, |
| 2675 | - priv, nullptr); |
| 2676 | -} |
| 2677 | - |
| 2678 | -TimeFormatter::TimeFormatter(QObject *parent): QObject(parent) |
| 2679 | -{ |
| 2680 | - priv = new TimeFormatterPrivate; |
| 2681 | - priv->formatter = this; |
| 2682 | - priv->time = 0; |
| 2683 | - priv->format = QStringLiteral("yyyy-MM-dd hh:mm"); |
| 2684 | - priv->system_bus = nullptr; |
| 2685 | - priv->subscription_id = 0; |
| 2686 | - priv->cancellable = g_cancellable_new (); |
| 2687 | - |
| 2688 | - g_bus_get (G_BUS_TYPE_SYSTEM, priv->cancellable, got_bus, priv); |
| 2689 | -} |
| 2690 | - |
| 2691 | -TimeFormatter::TimeFormatter(const QString &initialFormat, QObject *parent): TimeFormatter(parent) |
| 2692 | -{ |
| 2693 | - priv->format = initialFormat; |
| 2694 | -} |
| 2695 | - |
| 2696 | -TimeFormatter::~TimeFormatter() |
| 2697 | -{ |
| 2698 | - if (priv->system_bus) { |
| 2699 | - g_dbus_connection_signal_unsubscribe (priv->system_bus, priv->subscription_id); |
| 2700 | - g_object_unref (priv->system_bus); |
| 2701 | - } |
| 2702 | - |
| 2703 | - g_cancellable_cancel (priv->cancellable); |
| 2704 | - g_object_unref (priv->cancellable); |
| 2705 | -} |
| 2706 | - |
| 2707 | -QString TimeFormatter::format() const |
| 2708 | -{ |
| 2709 | - return priv->format; |
| 2710 | -} |
| 2711 | - |
| 2712 | -QString TimeFormatter::timeString() const |
| 2713 | -{ |
| 2714 | - return priv->timeString; |
| 2715 | -} |
| 2716 | - |
| 2717 | -qint64 TimeFormatter::time() const |
| 2718 | -{ |
| 2719 | - return priv->time; |
| 2720 | -} |
| 2721 | - |
| 2722 | -void TimeFormatter::setFormat(const QString &format) |
| 2723 | -{ |
| 2724 | - if (priv->format != format) { |
| 2725 | - priv->format = format; |
| 2726 | - Q_EMIT formatChanged(priv->format); |
| 2727 | - update(); |
| 2728 | - } |
| 2729 | -} |
| 2730 | - |
| 2731 | -void TimeFormatter::setTime(qint64 time) |
| 2732 | -{ |
| 2733 | - if (priv->time != time) { |
| 2734 | - priv->time = time; |
| 2735 | - Q_EMIT timeChanged(priv->time); |
| 2736 | - update(); |
| 2737 | - } |
| 2738 | -} |
| 2739 | - |
| 2740 | -void TimeFormatter::update() |
| 2741 | -{ |
| 2742 | - priv->timeString = formatTime(); |
| 2743 | - Q_EMIT timeStringChanged(priv->timeString); |
| 2744 | -} |
| 2745 | - |
| 2746 | -QString TimeFormatter::formatTime() const |
| 2747 | -{ |
| 2748 | - return QDateTime::fromMSecsSinceEpoch(time() / 1000).toString(format()); |
| 2749 | -} |
| 2750 | - |
| 2751 | -GDateTimeFormatter::GDateTimeFormatter(QObject* parent) |
| 2752 | -: TimeFormatter(QStringLiteral("%d-%m-%Y %I:%M%p"), parent) |
| 2753 | -{ |
| 2754 | -} |
| 2755 | - |
| 2756 | -QString GDateTimeFormatter::formatTime() const |
| 2757 | -{ |
| 2758 | - gchar* time_string; |
| 2759 | - GDateTime* datetime; |
| 2760 | - QByteArray formatBytes = format().toUtf8(); |
| 2761 | - |
| 2762 | - datetime = g_date_time_new_from_unix_local(time()); |
| 2763 | - if (!datetime) { |
| 2764 | - return QLatin1String(""); |
| 2765 | - } |
| 2766 | - |
| 2767 | - time_string = g_date_time_format(datetime, formatBytes.constData()); |
| 2768 | - QString formattedTime(QString::fromUtf8(time_string)); |
| 2769 | - |
| 2770 | - g_free(time_string); |
| 2771 | - g_date_time_unref(datetime); |
| 2772 | - return formattedTime; |
| 2773 | -} |
| 2774 | |
| 2775 | === removed file 'plugins/Utils/timeformatter.h' |
| 2776 | --- plugins/Utils/timeformatter.h 2015-09-17 13:42:15 +0000 |
| 2777 | +++ plugins/Utils/timeformatter.h 1970-01-01 00:00:00 +0000 |
| 2778 | @@ -1,68 +0,0 @@ |
| 2779 | -/* |
| 2780 | - * Copyright 2013 Canonical Ltd. |
| 2781 | - * |
| 2782 | - * This program is free software; you can redistribute it and/or modify |
| 2783 | - * it under the terms of the GNU General Public License as published by |
| 2784 | - * the Free Software Foundation; version 3. |
| 2785 | - * |
| 2786 | - * This program is distributed in the hope that it will be useful, |
| 2787 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2788 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2789 | - * GNU General Public License for more details. |
| 2790 | - * |
| 2791 | - * You should have received a copy of the GNU General Public License |
| 2792 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2793 | - * |
| 2794 | - * Author: Lars Uebernickel <lars.uebernickel@canonical.com> |
| 2795 | - */ |
| 2796 | - |
| 2797 | -#ifndef TIME_FORMATTER_H |
| 2798 | -#define TIME_FORMATTER_H |
| 2799 | - |
| 2800 | -#include <QObject> |
| 2801 | - |
| 2802 | -// TODO - bug #1260728 |
| 2803 | -class TimeFormatter : public QObject |
| 2804 | -{ |
| 2805 | - Q_OBJECT |
| 2806 | - Q_PROPERTY(QString format READ format WRITE setFormat NOTIFY formatChanged) |
| 2807 | - Q_PROPERTY(QString timeString READ timeString NOTIFY timeStringChanged) |
| 2808 | - Q_PROPERTY(qint64 time READ time WRITE setTime NOTIFY timeChanged) |
| 2809 | - |
| 2810 | -public: |
| 2811 | - TimeFormatter(QObject *parent = 0); |
| 2812 | - virtual ~TimeFormatter(); |
| 2813 | - |
| 2814 | - virtual QString format() const; |
| 2815 | - QString timeString() const; |
| 2816 | - qint64 time() const; |
| 2817 | - |
| 2818 | - void setFormat(const QString &format); |
| 2819 | - void setTime(qint64 time); |
| 2820 | - |
| 2821 | - void update(); |
| 2822 | - |
| 2823 | -Q_SIGNALS: |
| 2824 | - void formatChanged(const QString &format); |
| 2825 | - void timeStringChanged(const QString &timeString); |
| 2826 | - void timeChanged(qint64 time); |
| 2827 | - |
| 2828 | -protected: |
| 2829 | - TimeFormatter(const QString &initialFormat, QObject *parent = 0); |
| 2830 | - |
| 2831 | - virtual QString formatTime() const; |
| 2832 | - |
| 2833 | -private: |
| 2834 | - struct TimeFormatterPrivate *priv; |
| 2835 | -}; |
| 2836 | - |
| 2837 | -class GDateTimeFormatter : public TimeFormatter |
| 2838 | -{ |
| 2839 | -public: |
| 2840 | - GDateTimeFormatter(QObject *parent = 0); |
| 2841 | - |
| 2842 | -protected: |
| 2843 | - QString formatTime() const override; |
| 2844 | -}; |
| 2845 | - |
| 2846 | -#endif |
| 2847 | |
| 2848 | === modified file 'plugins/Utils/timezoneFormatter.cpp' |
| 2849 | --- plugins/Utils/timezoneFormatter.cpp 2015-09-17 13:42:15 +0000 |
| 2850 | +++ plugins/Utils/timezoneFormatter.cpp 2015-10-26 09:06:21 +0000 |
| 2851 | @@ -29,7 +29,7 @@ |
| 2852 | if (tz.isValid()) { |
| 2853 | const QDateTime now = QDateTime::currentDateTime().toTimeZone(tz); |
| 2854 | // return locale-aware string in the form "day, hh:mm", e.g. "Mon 14:30" or "Mon 1:30 pm" |
| 2855 | - return QStringLiteral("%1 %2").arg(now.toString("ddd")).arg(now.time().toString(Qt::DefaultLocaleShortDate)); |
| 2856 | + return QStringLiteral("%1 %2").arg(now.toString(QStringLiteral("ddd"))).arg(now.time().toString(Qt::DefaultLocaleShortDate)); |
| 2857 | } |
| 2858 | return QString(); |
| 2859 | } |
| 2860 | |
| 2861 | === modified file 'qml/Components/Dialogs.qml' |
| 2862 | --- qml/Components/Dialogs.qml 2015-09-02 09:30:32 +0000 |
| 2863 | +++ qml/Components/Dialogs.qml 2015-10-26 09:06:21 +0000 |
| 2864 | @@ -20,6 +20,7 @@ |
| 2865 | import Unity.Session 0.1 |
| 2866 | import Ubuntu.Components 1.1 |
| 2867 | import GlobalShortcut 1.0 |
| 2868 | +import Unity.Platform 1.0 |
| 2869 | import "../Greeter" |
| 2870 | |
| 2871 | Item { |
| 2872 | @@ -46,13 +47,13 @@ |
| 2873 | |
| 2874 | GlobalShortcut { // reboot/shutdown dialog |
| 2875 | shortcut: Qt.Key_PowerDown |
| 2876 | - active: root.usageScenario === "desktop" |
| 2877 | + active: Platform.isPC |
| 2878 | onTriggered: root.unitySessionService.RequestShutdown() |
| 2879 | } |
| 2880 | |
| 2881 | GlobalShortcut { // reboot/shutdown dialog |
| 2882 | shortcut: Qt.Key_PowerOff |
| 2883 | - active: root.usageScenario === "desktop" |
| 2884 | + active: Platform.isPC |
| 2885 | onTriggered: root.unitySessionService.RequestShutdown() |
| 2886 | } |
| 2887 | |
| 2888 | |
| 2889 | === modified file 'qml/Components/ScreenGrabber.qml' |
| 2890 | --- qml/Components/ScreenGrabber.qml 2015-08-24 15:39:53 +0000 |
| 2891 | +++ qml/Components/ScreenGrabber.qml 2015-10-26 09:06:21 +0000 |
| 2892 | @@ -26,6 +26,9 @@ |
| 2893 | anchors.fill: parent |
| 2894 | opacity: 0.0 |
| 2895 | |
| 2896 | + // to be set from outside |
| 2897 | + property int rotationAngle: 0 |
| 2898 | + |
| 2899 | ScreenGrabber { |
| 2900 | id: screenGrabber |
| 2901 | objectName: "screenGrabber" |
| 2902 | @@ -67,7 +70,7 @@ |
| 2903 | to: 0.0 |
| 2904 | onStopped: { |
| 2905 | if (visible) { |
| 2906 | - screenGrabber.captureAndSave(); |
| 2907 | + screenGrabber.captureAndSave(root.rotationAngle); |
| 2908 | visible = false; |
| 2909 | } |
| 2910 | } |
| 2911 | |
| 2912 | === added file 'qml/Components/WallpaperResolver.qml' |
| 2913 | --- qml/Components/WallpaperResolver.qml 1970-01-01 00:00:00 +0000 |
| 2914 | +++ qml/Components/WallpaperResolver.qml 2015-10-26 09:06:21 +0000 |
| 2915 | @@ -0,0 +1,63 @@ |
| 2916 | +/* |
| 2917 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2918 | + * |
| 2919 | + * This program is free software; you can redistribute it and/or modify |
| 2920 | + * it under the terms of the GNU General Public License as published by |
| 2921 | + * the Free Software Foundation; version 3. |
| 2922 | + * |
| 2923 | + * This program is distributed in the hope that it will be useful, |
| 2924 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 2925 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 2926 | + * GNU General Public License for more details. |
| 2927 | + * |
| 2928 | + * You should have received a copy of the GNU General Public License |
| 2929 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 2930 | + */ |
| 2931 | + |
| 2932 | +import QtQuick 2.4 |
| 2933 | +import AccountsService 0.1 |
| 2934 | +import GSettings 1.0 |
| 2935 | +import Ubuntu.Components 1.3 |
| 2936 | + |
| 2937 | +/* |
| 2938 | + Defines the background URL based on several factors, such as: |
| 2939 | + - default, fallback, background |
| 2940 | + - Background set in AccountSettings, if any |
| 2941 | + - Background set in GSettings, if any |
| 2942 | + */ |
| 2943 | +QtObject { |
| 2944 | + // Users should set their UI width here. |
| 2945 | + property real width |
| 2946 | + |
| 2947 | + property url defaultBackground: Qt.resolvedUrl(width >= units.gu(60) ? "../graphics/tablet_background.jpg" |
| 2948 | + : "../graphics/phone_background.jpg") |
| 2949 | + |
| 2950 | + // That's the property users of this component are going to consume. |
| 2951 | + readonly property url background: asImageTester.status == Image.Ready ? asImageTester.source |
| 2952 | + : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground |
| 2953 | + |
| 2954 | + // This is a dummy image to detect if the custom AS set wallpaper loads successfully. |
| 2955 | + property var _asImageTester: Image { |
| 2956 | + id: asImageTester |
| 2957 | + source: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : "" |
| 2958 | + height: 0 |
| 2959 | + width: 0 |
| 2960 | + sourceSize.height: 0 |
| 2961 | + sourceSize.width: 0 |
| 2962 | + } |
| 2963 | + |
| 2964 | + // This is a dummy image to detect if the custom GSettings set wallpaper loads successfully. |
| 2965 | + property var _gsImageTester: Image { |
| 2966 | + id: gsImageTester |
| 2967 | + source: backgroundSettings.pictureUri && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : "" |
| 2968 | + height: 0 |
| 2969 | + width: 0 |
| 2970 | + sourceSize.height: 0 |
| 2971 | + sourceSize.width: 0 |
| 2972 | + } |
| 2973 | + |
| 2974 | + property var _gsettings: GSettings { |
| 2975 | + id: backgroundSettings |
| 2976 | + schema.id: "org.gnome.desktop.background" |
| 2977 | + } |
| 2978 | +} |
| 2979 | |
| 2980 | === modified file 'qml/DeviceConfiguration.qml' |
| 2981 | --- qml/DeviceConfiguration.qml 2015-07-01 17:52:34 +0000 |
| 2982 | +++ qml/DeviceConfiguration.qml 2015-10-26 09:06:21 +0000 |
| 2983 | @@ -86,6 +86,7 @@ |
| 2984 | PropertyChanges { |
| 2985 | target: root |
| 2986 | category: "desktop" |
| 2987 | + supportedOrientations: root.useNativeOrientation |
| 2988 | } |
| 2989 | } |
| 2990 | ] |
| 2991 | |
| 2992 | === added file 'qml/DisabledScreenNotice.qml' |
| 2993 | --- qml/DisabledScreenNotice.qml 1970-01-01 00:00:00 +0000 |
| 2994 | +++ qml/DisabledScreenNotice.qml 2015-10-26 09:06:21 +0000 |
| 2995 | @@ -0,0 +1,49 @@ |
| 2996 | +/* |
| 2997 | + * Copyright (C) 2015 Canonical, Ltd. |
| 2998 | + * |
| 2999 | + * This program is free software; you can redistribute it and/or modify |
| 3000 | + * it under the terms of the GNU General Public License as published by |
| 3001 | + * the Free Software Foundation; version 3. |
| 3002 | + * |
| 3003 | + * This program is distributed in the hope that it will be useful, |
| 3004 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 3005 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 3006 | + * GNU General Public License for more details. |
| 3007 | + * |
| 3008 | + * You should have received a copy of the GNU General Public License |
| 3009 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3010 | + */ |
| 3011 | + |
| 3012 | +import QtQuick 2.4 |
| 3013 | +import Ubuntu.Components 1.3 |
| 3014 | +import "Components" |
| 3015 | + |
| 3016 | +Image { |
| 3017 | + id: root |
| 3018 | + |
| 3019 | + WallpaperResolver { |
| 3020 | + width: root.width |
| 3021 | + id: wallpaperResolver |
| 3022 | + } |
| 3023 | + |
| 3024 | + source: wallpaperResolver.background |
| 3025 | + |
| 3026 | + UbuntuShape { |
| 3027 | + anchors.fill: text |
| 3028 | + anchors.margins: -units.gu(2) |
| 3029 | + backgroundColor: "black" |
| 3030 | + opacity: 0.4 |
| 3031 | + } |
| 3032 | + |
| 3033 | + Label { |
| 3034 | + id: text |
| 3035 | + anchors.centerIn: parent |
| 3036 | + width: parent.width / 2 |
| 3037 | + text: i18n.tr("Your device is now connected to an external display.") |
| 3038 | + color: "white" |
| 3039 | + horizontalAlignment: Text.AlignHCenter |
| 3040 | + verticalAlignment: Text.AlignVCenter |
| 3041 | + fontSize: "x-large" |
| 3042 | + wrapMode: Text.Wrap |
| 3043 | + } |
| 3044 | +} |
| 3045 | |
| 3046 | === modified file 'qml/Greeter/Greeter.qml' |
| 3047 | --- qml/Greeter/Greeter.qml 2015-09-02 13:06:56 +0000 |
| 3048 | +++ qml/Greeter/Greeter.qml 2015-10-26 09:06:21 +0000 |
| 3049 | @@ -251,7 +251,7 @@ |
| 3050 | |
| 3051 | // event eater |
| 3052 | // Nothing should leak to items behind the greeter |
| 3053 | - MouseArea { anchors.fill: parent } |
| 3054 | + MouseArea { anchors.fill: parent; hoverEnabled: true } |
| 3055 | |
| 3056 | Loader { |
| 3057 | id: loader |
| 3058 | |
| 3059 | === modified file 'qml/Launcher/Launcher.qml' |
| 3060 | --- qml/Launcher/Launcher.qml 2015-09-02 14:18:40 +0000 |
| 3061 | +++ qml/Launcher/Launcher.qml 2015-10-26 09:06:21 +0000 |
| 3062 | @@ -188,6 +188,7 @@ |
| 3063 | bottom: parent.bottom |
| 3064 | } |
| 3065 | enabled: root.shadeBackground && root.state == "visible" |
| 3066 | + visible: enabled // otherwise it will get in the way of cursor selection for some reason |
| 3067 | onPressed: { |
| 3068 | root.state = "" |
| 3069 | } |
| 3070 | |
| 3071 | === modified file 'qml/Notifications/Notification.qml' |
| 3072 | --- qml/Notifications/Notification.qml 2015-10-08 19:30:59 +0000 |
| 3073 | +++ qml/Notifications/Notification.qml 2015-10-26 09:06:21 +0000 |
| 3074 | @@ -50,6 +50,7 @@ |
| 3075 | readonly property real contentSpacing: units.gu(2) |
| 3076 | readonly property bool canBeClosed: type === Notification.Ephemeral |
| 3077 | property bool hasMouse |
| 3078 | + property url background: "" |
| 3079 | |
| 3080 | objectName: "background" |
| 3081 | implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : outterColumn.height - shapedBack.anchors.topMargin + contentSpacing * 2) : 0 |
| 3082 | @@ -401,6 +402,7 @@ |
| 3083 | menuData: model |
| 3084 | menuIndex: index |
| 3085 | maxHeight: notification.maxHeight |
| 3086 | + background: notification.background |
| 3087 | |
| 3088 | onLoaded: { |
| 3089 | notification.fullscreen = Qt.binding(function() { return fullscreen; }); |
| 3090 | |
| 3091 | === modified file 'qml/Notifications/NotificationMenuItemFactory.qml' |
| 3092 | --- qml/Notifications/NotificationMenuItemFactory.qml 2014-11-17 13:46:56 +0000 |
| 3093 | +++ qml/Notifications/NotificationMenuItemFactory.qml 2015-10-26 09:06:21 +0000 |
| 3094 | @@ -30,6 +30,7 @@ |
| 3095 | property int menuIndex : -1 |
| 3096 | property int maxHeight |
| 3097 | readonly property bool fullscreen: menuData.type === "com.canonical.snapdecision.pinlock" |
| 3098 | + property url background: "" |
| 3099 | |
| 3100 | signal accepted() |
| 3101 | |
| 3102 | @@ -149,7 +150,7 @@ |
| 3103 | infoText: notification.summary |
| 3104 | errorText: errorAction.valid ? errorAction.state : "" |
| 3105 | retryText: notification.body |
| 3106 | - background: shell.background |
| 3107 | + background: menuFactory.background |
| 3108 | darkenBackground: 0.4 |
| 3109 | |
| 3110 | onEntered: { |
| 3111 | |
| 3112 | === modified file 'qml/Notifications/Notifications.qml' |
| 3113 | --- qml/Notifications/Notifications.qml 2015-09-22 14:23:44 +0000 |
| 3114 | +++ qml/Notifications/Notifications.qml 2015-10-26 09:06:21 +0000 |
| 3115 | @@ -29,6 +29,7 @@ |
| 3116 | property real margin |
| 3117 | property bool useModal: snapDecisionProxyModel.count > 0 |
| 3118 | property bool hasMouse |
| 3119 | + property url background: "" |
| 3120 | |
| 3121 | UnitySortFilterProxyModel { |
| 3122 | id: snapDecisionProxyModel |
| 3123 | @@ -60,6 +61,7 @@ |
| 3124 | maxHeight: notificationList.height |
| 3125 | margins: notificationList.margin |
| 3126 | hasMouse: notificationList.hasMouse |
| 3127 | + background: notificationList.background |
| 3128 | |
| 3129 | // make sure there's no opacity-difference between the several |
| 3130 | // elements in a notification |
| 3131 | |
| 3132 | === modified file 'qml/OrientedShell.qml' |
| 3133 | --- qml/OrientedShell.qml 2015-09-22 14:23:44 +0000 |
| 3134 | +++ qml/OrientedShell.qml 2015-10-26 09:06:21 +0000 |
| 3135 | @@ -76,6 +76,12 @@ |
| 3136 | oskSettings.disableHeight = shell.usageScenario == "desktop" |
| 3137 | } |
| 3138 | |
| 3139 | + // we must rotate to a supported orientation regardless of shell's preference |
| 3140 | + property bool orientationChangesEnabled: |
| 3141 | + (orientation & supportedOrientations) === 0 ? true |
| 3142 | + : shell.orientationChangesEnabled |
| 3143 | + |
| 3144 | + |
| 3145 | Binding { |
| 3146 | target: oskSettings |
| 3147 | property: "stayHidden" |
| 3148 | @@ -89,7 +95,10 @@ |
| 3149 | } |
| 3150 | |
| 3151 | readonly property int supportedOrientations: shell.supportedOrientations |
| 3152 | - & deviceConfiguration.supportedOrientations |
| 3153 | + & (deviceConfiguration.supportedOrientations == deviceConfiguration.useNativeOrientation |
| 3154 | + ? nativeOrientation |
| 3155 | + : deviceConfiguration.supportedOrientations) |
| 3156 | + |
| 3157 | property int acceptedOrientationAngle: { |
| 3158 | if (orientation & supportedOrientations) { |
| 3159 | return Screen.angleBetween(nativeOrientation, orientation); |
| 3160 | |
| 3161 | === modified file 'qml/Panel/Indicators/MenuItemFactory.qml' |
| 3162 | --- qml/Panel/Indicators/MenuItemFactory.qml 2015-09-17 18:02:22 +0000 |
| 3163 | +++ qml/Panel/Indicators/MenuItemFactory.qml 2015-10-26 09:06:21 +0000 |
| 3164 | @@ -20,7 +20,7 @@ |
| 3165 | import QMenuModel 0.1 |
| 3166 | import Utils 0.1 as Utils |
| 3167 | import Ubuntu.Components.ListItems 0.1 as ListItems |
| 3168 | -import Ubuntu.Components 1.2 |
| 3169 | +import Ubuntu.Components 1.3 |
| 3170 | import Unity.Session 0.1 |
| 3171 | |
| 3172 | Item { |
| 3173 | @@ -350,20 +350,23 @@ |
| 3174 | id: alarmMenu; |
| 3175 | |
| 3176 | Menus.EventMenu { |
| 3177 | + id: alarmItem |
| 3178 | objectName: "alarmMenu" |
| 3179 | property QtObject menuData: null |
| 3180 | property var menuModel: menuFactory.menuModel |
| 3181 | property int menuIndex: -1 |
| 3182 | property var extendedData: menuData && menuData.ext || undefined |
| 3183 | - // TODO - bug #1260728 |
| 3184 | - property var timeFormatter: Utils.GDateTimeFormatter { |
| 3185 | - time: getExtendedProperty(extendedData, "xCanonicalTime", 0) |
| 3186 | - format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "") |
| 3187 | + |
| 3188 | + property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000) |
| 3189 | + LiveTimer { |
| 3190 | + frequency: LiveTimer.Relative |
| 3191 | + relativeTime: alarmItem.serverTime |
| 3192 | + onTrigger: alarmItem.serverTime = new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000) |
| 3193 | } |
| 3194 | |
| 3195 | text: menuData && menuData.label || "" |
| 3196 | iconSource: menuData && menuData.icon || "image://theme/alarm-clock" |
| 3197 | - time: timeFormatter.timeString |
| 3198 | + time: i18n.relativeDateTime(serverTime) |
| 3199 | enabled: menuData && menuData.sensitive || false |
| 3200 | highlightWhenPressed: false |
| 3201 | |
| 3202 | @@ -379,8 +382,7 @@ |
| 3203 | |
| 3204 | function loadAttributes() { |
| 3205 | if (!menuModel || menuIndex == -1) return; |
| 3206 | - menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64', |
| 3207 | - 'x-canonical-time-format': 'string'}); |
| 3208 | + menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64'}); |
| 3209 | } |
| 3210 | } |
| 3211 | } |
| 3212 | @@ -389,20 +391,23 @@ |
| 3213 | id: appointmentMenu; |
| 3214 | |
| 3215 | Menus.EventMenu { |
| 3216 | + id: appointmentItem |
| 3217 | objectName: "appointmentMenu" |
| 3218 | property QtObject menuData: null |
| 3219 | property var menuModel: menuFactory.menuModel |
| 3220 | property int menuIndex: -1 |
| 3221 | property var extendedData: menuData && menuData.ext || undefined |
| 3222 | - // TODO - bug #1260728 |
| 3223 | - property var timeFormatter: Utils.GDateTimeFormatter { |
| 3224 | - time: getExtendedProperty(extendedData, "xCanonicalTime", 0) |
| 3225 | - format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "") |
| 3226 | + |
| 3227 | + property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000) |
| 3228 | + LiveTimer { |
| 3229 | + frequency: LiveTimer.Relative |
| 3230 | + relativeTime: appointmentItem.serverTime |
| 3231 | + onTrigger: appointmentItem.serverTime = new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000) |
| 3232 | } |
| 3233 | |
| 3234 | text: menuData && menuData.label || "" |
| 3235 | iconSource: menuData && menuData.icon || "image://theme/calendar" |
| 3236 | - time: timeFormatter.timeString |
| 3237 | + time: i18n.relativeDateTime(serverTime) |
| 3238 | eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0)) |
| 3239 | enabled: menuData && menuData.sensitive || false |
| 3240 | highlightWhenPressed: false |
| 3241 | @@ -420,8 +425,7 @@ |
| 3242 | function loadAttributes() { |
| 3243 | if (!menuModel || menuIndex == -1) return; |
| 3244 | menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-color': 'string', |
| 3245 | - 'x-canonical-time': 'int64', |
| 3246 | - 'x-canonical-time-format': 'string'}); |
| 3247 | + 'x-canonical-time': 'int64'}); |
| 3248 | } |
| 3249 | } |
| 3250 | } |
| 3251 | |
| 3252 | === modified file 'qml/Panel/Indicators/MessageMenuItemFactory.qml' |
| 3253 | --- qml/Panel/Indicators/MessageMenuItemFactory.qml 2015-09-15 22:50:16 +0000 |
| 3254 | +++ qml/Panel/Indicators/MessageMenuItemFactory.qml 2015-10-26 09:06:21 +0000 |
| 3255 | @@ -19,7 +19,7 @@ |
| 3256 | */ |
| 3257 | |
| 3258 | import QtQuick 2.0 |
| 3259 | -import Ubuntu.Components 0.1 |
| 3260 | +import Ubuntu.Components 1.3 |
| 3261 | import Ubuntu.Settings.Menus 0.1 as Menus |
| 3262 | import QMenuModel 0.1 as QMenuModel |
| 3263 | import Utils 0.1 as Utils |
| 3264 | @@ -35,12 +35,17 @@ |
| 3265 | signal menuSelected |
| 3266 | signal menuDeselected |
| 3267 | |
| 3268 | - property var extendedData: menuData && menuData.ext || undefined |
| 3269 | - property var actionsDescription: getExtendedProperty(extendedData, "xCanonicalMessageActions", undefined) |
| 3270 | - |
| 3271 | - // TODO - bug #1260728 |
| 3272 | - property var timeFormatter: Utils.RelativeTimeFormatter { |
| 3273 | - time: getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000000 |
| 3274 | + QtObject { |
| 3275 | + id: priv |
| 3276 | + property var extendedData: menuData && menuData.ext || undefined |
| 3277 | + property var actionsDescription: getExtendedProperty(extendedData, "xCanonicalMessageActions", undefined) |
| 3278 | + property date time: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) / 1000) |
| 3279 | + property string timeString: i18n.relativeDateTime(time) |
| 3280 | + } |
| 3281 | + LiveTimer { |
| 3282 | + frequency: LiveTimer.Relative |
| 3283 | + relativeTime: priv.time |
| 3284 | + onTrigger: priv.timeString = Qt.binding(function() { return i18n.relativeDateTime(priv.time); }) |
| 3285 | } |
| 3286 | |
| 3287 | onMenuModelChanged: { |
| 3288 | @@ -50,7 +55,7 @@ |
| 3289 | loadAttributes(); |
| 3290 | } |
| 3291 | |
| 3292 | - sourceComponent: loadMessage(actionsDescription) |
| 3293 | + sourceComponent: loadMessage(priv.actionsDescription) |
| 3294 | |
| 3295 | function loadMessage(actions) |
| 3296 | { |
| 3297 | @@ -100,11 +105,11 @@ |
| 3298 | objectName: "simpleTextMessage" |
| 3299 | // text |
| 3300 | title: menuData && menuData.label || "" |
| 3301 | - time: timeFormatter.timeString |
| 3302 | - body: getExtendedProperty(extendedData, "xCanonicalText", "") |
| 3303 | + time: priv.timeString |
| 3304 | + body: getExtendedProperty(priv.extendedData, "xCanonicalText", "") |
| 3305 | // icons |
| 3306 | - avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact") |
| 3307 | - icon: getExtendedProperty(extendedData, "xCanonicalAppIcon", "image://theme/message") |
| 3308 | + avatar: getExtendedProperty(priv.extendedData, "icon", "image://theme/contact") |
| 3309 | + icon: getExtendedProperty(priv.extendedData, "xCanonicalAppIcon", "image://theme/message") |
| 3310 | // actions |
| 3311 | enabled: menuData && menuData.sensitive || false |
| 3312 | removable: !selected |
| 3313 | @@ -133,7 +138,9 @@ |
| 3314 | Menus.TextMessageMenu { |
| 3315 | id: message |
| 3316 | objectName: "textMessage" |
| 3317 | - property var replyActionDescription: actionsDescription && actionsDescription.length > 0 ? actionsDescription[0] : undefined |
| 3318 | + property var replyActionDescription: priv.actionsDescription && priv.actionsDescription.length > 0 ? |
| 3319 | + priv.actionsDescription[0] : |
| 3320 | + undefined |
| 3321 | |
| 3322 | property var replyAction: QMenuModel.UnityMenuAction { |
| 3323 | model: menuModel |
| 3324 | @@ -143,13 +150,13 @@ |
| 3325 | |
| 3326 | // text |
| 3327 | title: menuData && menuData.label || "" |
| 3328 | - time: timeFormatter.timeString |
| 3329 | - body: getExtendedProperty(extendedData, "xCanonicalText", "") |
| 3330 | - replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.tr("Send")) |
| 3331 | + time: priv.timeString |
| 3332 | + body: getExtendedProperty(priv.extendedData, "xCanonicalText", "") |
| 3333 | + replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.ctr("Button: Send a reply message", "Send")) |
| 3334 | replyHintText: i18n.ctr("Label: Hint in message indicator line edit", "Reply") |
| 3335 | // icons |
| 3336 | - avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact") |
| 3337 | - icon: getExtendedProperty(extendedData, "xCanonicalAppIcon", "image://theme/message") |
| 3338 | + avatar: getExtendedProperty(priv.extendedData, "icon", "image://theme/contact") |
| 3339 | + icon: getExtendedProperty(priv.extendedData, "xCanonicalAppIcon", "image://theme/message") |
| 3340 | // actions |
| 3341 | replyEnabled: replyAction.valid && replyAction.enabled |
| 3342 | enabled: menuData && menuData.sensitive || false |
| 3343 | @@ -183,8 +190,10 @@ |
| 3344 | Menus.SnapDecisionMenu { |
| 3345 | id: message |
| 3346 | objectName: "snapDecision" |
| 3347 | - property var activateActionDescription: actionsDescription && actionsDescription.length > 0 ? actionsDescription[0] : undefined |
| 3348 | - property var replyActionDescription: actionsDescription && actionsDescription.length > 1 ? actionsDescription[1] : undefined |
| 3349 | + property var activateActionDescription: priv.actionsDescription && priv.actionsDescription.length > 0 ? |
| 3350 | + priv.actionsDescription[0] : undefined |
| 3351 | + property var replyActionDescription: priv.actionsDescription && priv.actionsDescription.length > 1 ? |
| 3352 | + priv.actionsDescription[1] : undefined |
| 3353 | |
| 3354 | property var activateAction: QMenuModel.UnityMenuAction { |
| 3355 | model: menuModel |
| 3356 | @@ -199,13 +208,13 @@ |
| 3357 | |
| 3358 | // text |
| 3359 | title: menuData && menuData.label || "" |
| 3360 | - time: timeFormatter.timeString |
| 3361 | - body: getExtendedProperty(extendedData, "xCanonicalText", "") |
| 3362 | - actionButtonText: getExtendedProperty(activateActionDescription, "label", i18n.tr("Call back")) |
| 3363 | - replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.tr("Send")) |
| 3364 | + time: priv.timeString |
| 3365 | + body: getExtendedProperty(priv.extendedData, "xCanonicalText", "") |
| 3366 | + actionButtonText: getExtendedProperty(activateActionDescription, "label", i18n.ctr("Button: Call back on phone", "Call back")) |
| 3367 | + replyButtonText: getExtendedProperty(replyActionDescription, "label", i18n.ctr("Button: Send a reply message", "Send")) |
| 3368 | // icons |
| 3369 | - avatar: getExtendedProperty(extendedData, "icon", "image://theme/contact") |
| 3370 | - icon: getExtendedProperty(extendedData, "xCanonicalAppIcon", "image://theme/missed-call") |
| 3371 | + avatar: getExtendedProperty(priv.extendedData, "icon", "image://theme/contact") |
| 3372 | + icon: getExtendedProperty(priv.extendedData, "xCanonicalAppIcon", "image://theme/missed-call") |
| 3373 | // actions |
| 3374 | actionEnabled: activateAction.valid && activateAction.enabled |
| 3375 | replyEnabled: replyAction.valid && replyAction.enabled |
| 3376 | |
| 3377 | === modified file 'qml/Panel/Panel.qml' |
| 3378 | --- qml/Panel/Panel.qml 2015-06-29 03:58:22 +0000 |
| 3379 | +++ qml/Panel/Panel.qml 2015-10-26 09:06:21 +0000 |
| 3380 | @@ -48,6 +48,7 @@ |
| 3381 | MouseArea { |
| 3382 | anchors.fill: parent |
| 3383 | onClicked: if (indicators.fullyOpened) indicators.hide(); |
| 3384 | + hoverEnabled: true // should also eat hover events, otherwise they will pass through |
| 3385 | } |
| 3386 | } |
| 3387 | |
| 3388 | |
| 3389 | === modified file 'qml/Rotation/RotationStates.qml' |
| 3390 | --- qml/Rotation/RotationStates.qml 2015-05-11 14:36:03 +0000 |
| 3391 | +++ qml/Rotation/RotationStates.qml 2015-10-26 09:06:21 +0000 |
| 3392 | @@ -83,7 +83,7 @@ |
| 3393 | } |
| 3394 | |
| 3395 | function tryUpdateState() { |
| 3396 | - if (d.transitioning || (!d.startingUp && !root.shell.orientationChangesEnabled)) { |
| 3397 | + if (d.transitioning || (!d.startingUp && !root.orientedShell.orientationChangesEnabled)) { |
| 3398 | return; |
| 3399 | } |
| 3400 | |
| 3401 | @@ -95,7 +95,7 @@ |
| 3402 | } |
| 3403 | |
| 3404 | property Connections shellConnections: Connections { |
| 3405 | - target: root.shell |
| 3406 | + target: root.orientedShell |
| 3407 | onOrientationChangesEnabledChanged: { |
| 3408 | d.tryUpdateState(); |
| 3409 | } |
| 3410 | |
| 3411 | === modified file 'qml/Shell.qml' |
| 3412 | --- qml/Shell.qml 2015-09-22 14:23:44 +0000 |
| 3413 | +++ qml/Shell.qml 2015-10-26 09:06:21 +0000 |
| 3414 | @@ -17,7 +17,6 @@ |
| 3415 | import QtQuick 2.0 |
| 3416 | import QtQuick.Window 2.0 |
| 3417 | import AccountsService 0.1 |
| 3418 | -import GSettings 1.0 |
| 3419 | import Unity.Application 0.1 |
| 3420 | import Ubuntu.Components 0.1 |
| 3421 | import Ubuntu.Components.Popups 1.0 |
| 3422 | @@ -41,6 +40,7 @@ |
| 3423 | import Unity.Session 0.1 |
| 3424 | import Unity.DashCommunicator 0.1 |
| 3425 | import Unity.Indicators 0.1 as Indicators |
| 3426 | +import Cursor 1.0 |
| 3427 | |
| 3428 | |
| 3429 | Item { |
| 3430 | @@ -63,7 +63,7 @@ |
| 3431 | function updateFocusedAppOrientationAnimated() { |
| 3432 | applicationsDisplayLoader.item.updateFocusedAppOrientationAnimated(); |
| 3433 | } |
| 3434 | - property bool hasMouse |
| 3435 | + property bool hasMouse: false |
| 3436 | |
| 3437 | // to be read from outside |
| 3438 | readonly property int mainAppWindowOrientationAngle: |
| 3439 | @@ -107,9 +107,11 @@ |
| 3440 | enabled: greeter && !greeter.waiting |
| 3441 | |
| 3442 | property real edgeSize: units.gu(2) |
| 3443 | - property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg") |
| 3444 | - property url background: asImageTester.status == Image.Ready ? asImageTester.source |
| 3445 | - : gsImageTester.status == Image.Ready ? gsImageTester.source : defaultBackground |
| 3446 | + |
| 3447 | + WallpaperResolver { |
| 3448 | + id: wallpaperResolver |
| 3449 | + width: shell.width |
| 3450 | + } |
| 3451 | |
| 3452 | readonly property alias greeter: greeterLoader.item |
| 3453 | |
| 3454 | @@ -130,31 +132,6 @@ |
| 3455 | shell.activateApplication(app); |
| 3456 | } |
| 3457 | |
| 3458 | - // This is a dummy image to detect if the custom AS set wallpaper loads successfully. |
| 3459 | - Image { |
| 3460 | - id: asImageTester |
| 3461 | - source: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : "" |
| 3462 | - height: 0 |
| 3463 | - width: 0 |
| 3464 | - sourceSize.height: 0 |
| 3465 | - sourceSize.width: 0 |
| 3466 | - } |
| 3467 | - |
| 3468 | - GSettings { |
| 3469 | - id: backgroundSettings |
| 3470 | - schema.id: "org.gnome.desktop.background" |
| 3471 | - } |
| 3472 | - |
| 3473 | - // This is a dummy image to detect if the custom GSettings set wallpaper loads successfully. |
| 3474 | - Image { |
| 3475 | - id: gsImageTester |
| 3476 | - source: backgroundSettings.pictureUri && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : "" |
| 3477 | - height: 0 |
| 3478 | - width: 0 |
| 3479 | - sourceSize.height: 0 |
| 3480 | - sourceSize.width: 0 |
| 3481 | - } |
| 3482 | - |
| 3483 | Binding { |
| 3484 | target: LauncherModel |
| 3485 | property: "applicationManager" |
| 3486 | @@ -190,11 +167,6 @@ |
| 3487 | onScreenshotTriggered: screenGrabber.capture(); |
| 3488 | } |
| 3489 | |
| 3490 | - ScreenGrabber { |
| 3491 | - id: screenGrabber |
| 3492 | - z: dialogs.z + 10 |
| 3493 | - } |
| 3494 | - |
| 3495 | GlobalShortcut { |
| 3496 | // dummy shortcut to force creation of GlobalShortcutRegistry before WindowKeyFilter |
| 3497 | } |
| 3498 | @@ -327,7 +299,7 @@ |
| 3499 | Binding { |
| 3500 | target: applicationsDisplayLoader.item |
| 3501 | property: "background" |
| 3502 | - value: shell.background |
| 3503 | + value: wallpaperResolver.background |
| 3504 | } |
| 3505 | Binding { |
| 3506 | target: applicationsDisplayLoader.item |
| 3507 | @@ -432,7 +404,7 @@ |
| 3508 | tabletMode: shell.usageScenario != "phone" |
| 3509 | launcherOffset: launcher.progress |
| 3510 | forcedUnlock: tutorial.running |
| 3511 | - background: shell.background |
| 3512 | + background: wallpaperResolver.background |
| 3513 | |
| 3514 | // avoid overlapping with Launcher's edge drag area |
| 3515 | // FIXME: Fix TouchRegistry & friends and remove this workaround |
| 3516 | @@ -607,7 +579,7 @@ |
| 3517 | id: wizard |
| 3518 | objectName: "wizard" |
| 3519 | anchors.fill: parent |
| 3520 | - background: shell.background |
| 3521 | + background: wallpaperResolver.background |
| 3522 | |
| 3523 | function unlockWhenDoneWithWizard() { |
| 3524 | if (!active) { |
| 3525 | @@ -638,6 +610,7 @@ |
| 3526 | model: NotificationBackend.Model |
| 3527 | margin: units.gu(1) |
| 3528 | hasMouse: shell.hasMouse |
| 3529 | + background: wallpaperResolver.background |
| 3530 | |
| 3531 | y: topmostIsFullscreen ? 0 : panel.panelHeight |
| 3532 | height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight) |
| 3533 | @@ -684,9 +657,21 @@ |
| 3534 | onShowHome: showHome() |
| 3535 | } |
| 3536 | |
| 3537 | + ScreenGrabber { |
| 3538 | + id: screenGrabber |
| 3539 | + rotationAngle: -shell.orientationAngle |
| 3540 | + z: dialogs.z + 10 |
| 3541 | + } |
| 3542 | + |
| 3543 | + Cursor { |
| 3544 | + id: cursor |
| 3545 | + visible: shell.hasMouse |
| 3546 | + z: screenGrabber.z + 1 |
| 3547 | + } |
| 3548 | + |
| 3549 | Rectangle { |
| 3550 | id: shutdownFadeOutRectangle |
| 3551 | - z: screenGrabber.z + 10 |
| 3552 | + z: cursor.z + 1 |
| 3553 | enabled: false |
| 3554 | visible: false |
| 3555 | color: "black" |
| 3556 | @@ -703,5 +688,4 @@ |
| 3557 | } |
| 3558 | } |
| 3559 | } |
| 3560 | - |
| 3561 | } |
| 3562 | |
| 3563 | === modified file 'qml/Stages/ApplicationWindow.qml' |
| 3564 | --- qml/Stages/ApplicationWindow.qml 2015-09-17 12:25:29 +0000 |
| 3565 | +++ qml/Stages/ApplicationWindow.qml 2015-10-26 09:06:21 +0000 |
| 3566 | @@ -27,6 +27,8 @@ |
| 3567 | readonly property bool fullscreen: application ? application.fullscreen : false |
| 3568 | property alias interactive: sessionContainer.interactive |
| 3569 | property bool orientationChangesEnabled: d.supportsSurfaceResize ? d.surfaceOldEnoughToBeResized : true |
| 3570 | + readonly property string title: sessionContainer.surface && sessionContainer.surface.name !== "" ? |
| 3571 | + sessionContainer.surface.name : d.name |
| 3572 | |
| 3573 | // to be set from outside |
| 3574 | property QtObject application |
| 3575 | |
| 3576 | === modified file 'qml/Stages/DecoratedWindow.qml' |
| 3577 | --- qml/Stages/DecoratedWindow.qml 2015-09-08 10:32:28 +0000 |
| 3578 | +++ qml/Stages/DecoratedWindow.qml 2015-10-26 09:06:21 +0000 |
| 3579 | @@ -31,9 +31,10 @@ |
| 3580 | property bool highlightShown: false |
| 3581 | property real shadowOpacity: 1 |
| 3582 | |
| 3583 | - signal close(); |
| 3584 | - signal maximize(); |
| 3585 | - signal minimize(); |
| 3586 | + signal close() |
| 3587 | + signal maximize() |
| 3588 | + signal minimize() |
| 3589 | + signal decorationPressed() |
| 3590 | |
| 3591 | BorderImage { |
| 3592 | anchors { |
| 3593 | @@ -61,13 +62,15 @@ |
| 3594 | |
| 3595 | WindowDecoration { |
| 3596 | id: decoration |
| 3597 | + target: root.parent |
| 3598 | objectName: application ? "appWindowDecoration_" + application.appId : "appWindowDecoration_null" |
| 3599 | anchors { left: parent.left; top: parent.top; right: parent.right } |
| 3600 | height: units.gu(3) |
| 3601 | - title: model.name |
| 3602 | + title: window.title !== "" ? window.title : model.name |
| 3603 | onClose: root.close(); |
| 3604 | onMaximize: root.maximize(); |
| 3605 | onMinimize: root.minimize(); |
| 3606 | + onPressed: root.decorationPressed(); |
| 3607 | visible: decorationShown |
| 3608 | } |
| 3609 | |
| 3610 | |
| 3611 | === modified file 'qml/Stages/DesktopStage.qml' |
| 3612 | --- qml/Stages/DesktopStage.qml 2015-09-18 15:28:07 +0000 |
| 3613 | +++ qml/Stages/DesktopStage.qml 2015-10-26 09:06:21 +0000 |
| 3614 | @@ -138,9 +138,6 @@ |
| 3615 | height: units.gu(50) |
| 3616 | focus: model.appId === priv.focusedAppId |
| 3617 | |
| 3618 | - readonly property int minWidth: units.gu(10) |
| 3619 | - readonly property int minHeight: units.gu(10) |
| 3620 | - |
| 3621 | property bool maximized: false |
| 3622 | property bool minimized: false |
| 3623 | |
| 3624 | @@ -215,12 +212,11 @@ |
| 3625 | when: index == spread.highlightedIndex && blurLayer.ready |
| 3626 | } |
| 3627 | |
| 3628 | - WindowMoveResizeArea { |
| 3629 | - id: windowMoveResizeArea |
| 3630 | + WindowResizeArea { |
| 3631 | target: appDelegate |
| 3632 | - minWidth: appDelegate.minWidth |
| 3633 | - minHeight: appDelegate.minHeight |
| 3634 | - resizeHandleWidth: units.gu(2) |
| 3635 | + minWidth: units.gu(10) |
| 3636 | + minHeight: units.gu(10) |
| 3637 | + borderThickness: units.gu(2) |
| 3638 | windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing |
| 3639 | |
| 3640 | onPressed: { ApplicationManager.focusApplication(model.appId) } |
| 3641 | @@ -240,6 +236,7 @@ |
| 3642 | onClose: ApplicationManager.stopApplication(model.appId) |
| 3643 | onMaximize: appDelegate.maximize() |
| 3644 | onMinimize: appDelegate.minimize() |
| 3645 | + onDecorationPressed: { ApplicationManager.focusApplication(model.appId) } |
| 3646 | } |
| 3647 | } |
| 3648 | } |
| 3649 | |
| 3650 | === modified file 'qml/Stages/SurfaceContainer.qml' |
| 3651 | --- qml/Stages/SurfaceContainer.qml 2015-09-09 13:44:12 +0000 |
| 3652 | +++ qml/Stages/SurfaceContainer.qml 2015-10-26 09:06:21 +0000 |
| 3653 | @@ -28,6 +28,7 @@ |
| 3654 | property bool hadSurface: false |
| 3655 | property bool interactive |
| 3656 | property int surfaceOrientationAngle: 0 |
| 3657 | + property string name: surface ? surface.name : "" |
| 3658 | property bool resizeSurface: true |
| 3659 | |
| 3660 | onSurfaceChanged: { |
| 3661 | |
| 3662 | === modified file 'qml/Stages/WindowDecoration.qml' |
| 3663 | --- qml/Stages/WindowDecoration.qml 2015-03-13 19:18:35 +0000 |
| 3664 | +++ qml/Stages/WindowDecoration.qml 2015-10-26 09:06:21 +0000 |
| 3665 | @@ -1,5 +1,5 @@ |
| 3666 | /* |
| 3667 | - * Copyright (C) 2014 Canonical, Ltd. |
| 3668 | + * Copyright (C) 2014-2015 Canonical, Ltd. |
| 3669 | * |
| 3670 | * This program is free software; you can redistribute it and/or modify |
| 3671 | * it under the terms of the GNU General Public License as published by |
| 3672 | @@ -12,25 +12,53 @@ |
| 3673 | * |
| 3674 | * You should have received a copy of the GNU General Public License |
| 3675 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3676 | - * |
| 3677 | - * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
| 3678 | */ |
| 3679 | |
| 3680 | import QtQuick 2.3 |
| 3681 | +import Unity.Application 0.1 // For Mir singleton |
| 3682 | import Ubuntu.Components 1.1 |
| 3683 | import "../Components" |
| 3684 | |
| 3685 | -Item { |
| 3686 | +MouseArea { |
| 3687 | id: root |
| 3688 | clip: true |
| 3689 | |
| 3690 | + property Item target |
| 3691 | property alias title: titleLabel.text |
| 3692 | property bool active: false |
| 3693 | + hoverEnabled: true |
| 3694 | |
| 3695 | signal close() |
| 3696 | signal minimize() |
| 3697 | signal maximize() |
| 3698 | |
| 3699 | + QtObject { |
| 3700 | + id: priv |
| 3701 | + property real distanceX |
| 3702 | + property real distanceY |
| 3703 | + property bool dragging |
| 3704 | + } |
| 3705 | + |
| 3706 | + onPressedChanged: { |
| 3707 | + if (pressed) { |
| 3708 | + var pos = mapToItem(root.target, mouseX, mouseY); |
| 3709 | + priv.distanceX = pos.x; |
| 3710 | + priv.distanceY = pos.y; |
| 3711 | + priv.dragging = true; |
| 3712 | + Mir.cursorName = "grabbing"; |
| 3713 | + } else { |
| 3714 | + priv.dragging = false; |
| 3715 | + Mir.cursorName = ""; |
| 3716 | + } |
| 3717 | + } |
| 3718 | + onPositionChanged: { |
| 3719 | + if (priv.dragging) { |
| 3720 | + var pos = mapToItem(root.target.parent, mouseX, mouseY); |
| 3721 | + root.target.x = pos.x - priv.distanceX; |
| 3722 | + root.target.y = pos.y - priv.distanceY; |
| 3723 | + } |
| 3724 | + } |
| 3725 | + |
| 3726 | Rectangle { |
| 3727 | anchors.fill: parent |
| 3728 | anchors.bottomMargin: -radius |
| 3729 | |
| 3730 | === renamed file 'qml/Stages/WindowMoveResizeArea.qml' => 'qml/Stages/WindowResizeArea.qml' |
| 3731 | --- qml/Stages/WindowMoveResizeArea.qml 2015-09-08 10:32:28 +0000 |
| 3732 | +++ qml/Stages/WindowResizeArea.qml 2015-10-26 09:06:21 +0000 |
| 3733 | @@ -12,18 +12,19 @@ |
| 3734 | * |
| 3735 | * You should have received a copy of the GNU General Public License |
| 3736 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 3737 | - * |
| 3738 | - * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
| 3739 | */ |
| 3740 | |
| 3741 | import QtQuick 2.3 |
| 3742 | import Ubuntu.Components 1.1 |
| 3743 | import Utils 0.1 |
| 3744 | +import Unity.Application 0.1 // for Mir.cursorName |
| 3745 | |
| 3746 | MouseArea { |
| 3747 | id: root |
| 3748 | anchors.fill: target |
| 3749 | - anchors.margins: -resizeHandleWidth |
| 3750 | + anchors.margins: -borderThickness |
| 3751 | + |
| 3752 | + hoverEnabled: true |
| 3753 | |
| 3754 | property var windowStateStorage: WindowStateStorage |
| 3755 | |
| 3756 | @@ -31,24 +32,10 @@ |
| 3757 | // The area will anchor to it and manage move and resize events |
| 3758 | property Item target: null |
| 3759 | property string windowId: "" |
| 3760 | - property int resizeHandleWidth: 0 |
| 3761 | + property int borderThickness: 0 |
| 3762 | property int minWidth: 0 |
| 3763 | property int minHeight: 0 |
| 3764 | |
| 3765 | - QtObject { |
| 3766 | - id: priv |
| 3767 | - readonly property int windowWidth: root.width - root.resizeHandleWidth * 2 |
| 3768 | - readonly property int windowHeight: root.height - resizeHandleWidth * 2 |
| 3769 | - |
| 3770 | - property var startPoint |
| 3771 | - |
| 3772 | - property bool resizeTop: false |
| 3773 | - property bool resizeBottom: false |
| 3774 | - property bool resizeLeft: false |
| 3775 | - property bool resizeRight: false |
| 3776 | - |
| 3777 | - } |
| 3778 | - |
| 3779 | Component.onCompleted: { |
| 3780 | var windowState = windowStateStorage.getGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height)) |
| 3781 | if (windowState !== undefined) { |
| 3782 | @@ -59,51 +46,137 @@ |
| 3783 | } |
| 3784 | } |
| 3785 | |
| 3786 | - onPressed: { |
| 3787 | - priv.startPoint = Qt.point(mouse.x, mouse.y); |
| 3788 | - priv.resizeTop = mouseY < root.resizeHandleWidth; |
| 3789 | - priv.resizeBottom = mouseY > (root.height - root.resizeHandleWidth); |
| 3790 | - priv.resizeLeft = mouseX < root.resizeHandleWidth; |
| 3791 | - priv.resizeRight = mouseX > (root.width - root.resizeHandleWidth); |
| 3792 | - } |
| 3793 | - |
| 3794 | - onPositionChanged: { |
| 3795 | - var currentPoint = Qt.point(mouse.x, mouse.y); |
| 3796 | - var mouseDiff = Qt.point(currentPoint.x - priv.startPoint.x, currentPoint.y - priv.startPoint.y); |
| 3797 | - var moveDiff = Qt.point(0, 0); |
| 3798 | - var sizeDiff = Qt.point(0, 0); |
| 3799 | - var maxSizeDiff = Qt.point(root.minWidth - root.target.width, root.minHeight - root.target.height) |
| 3800 | - |
| 3801 | - if (priv.resizeTop || priv.resizeBottom || priv.resizeLeft || priv.resizeRight) { |
| 3802 | - if (priv.resizeTop) { |
| 3803 | - sizeDiff.y = Math.max(maxSizeDiff.y, -currentPoint.y + priv.startPoint.y) |
| 3804 | - moveDiff.y = -sizeDiff.y |
| 3805 | - } |
| 3806 | - if (priv.resizeBottom) { |
| 3807 | - sizeDiff.y = Math.max(maxSizeDiff.y, currentPoint.y - priv.startPoint.y) |
| 3808 | - priv.startPoint.y += sizeDiff.y |
| 3809 | - } |
| 3810 | - if (priv.resizeLeft) { |
| 3811 | - sizeDiff.x = Math.max(maxSizeDiff.x, -currentPoint.x + priv.startPoint.x) |
| 3812 | - moveDiff.x = -sizeDiff.x |
| 3813 | - } |
| 3814 | - if (priv.resizeRight) { |
| 3815 | - sizeDiff.x = Math.max(maxSizeDiff.x, currentPoint.x - priv.startPoint.x) |
| 3816 | - priv.startPoint.x += sizeDiff.x |
| 3817 | - } |
| 3818 | - |
| 3819 | - target.x += moveDiff.x; |
| 3820 | - target.y += moveDiff.y; |
| 3821 | - target.width += sizeDiff.x; |
| 3822 | - target.height += sizeDiff.y; |
| 3823 | - } else { |
| 3824 | - target.x += mouseDiff.x; |
| 3825 | - target.y += mouseDiff.y; |
| 3826 | - } |
| 3827 | - |
| 3828 | - } |
| 3829 | - |
| 3830 | Component.onDestruction: { |
| 3831 | windowStateStorage.saveGeometry(root.windowId, Qt.rect(target.x, target.y, target.width, target.height)) |
| 3832 | } |
| 3833 | + |
| 3834 | + QtObject { |
| 3835 | + id: d |
| 3836 | + property bool leftBorder: false |
| 3837 | + property bool rightBorder: false |
| 3838 | + property bool topBorder: false |
| 3839 | + property bool bottomBorder: false |
| 3840 | + |
| 3841 | + property bool dragging: false |
| 3842 | + property real startMousePosX |
| 3843 | + property real startMousePosY |
| 3844 | + property real startX |
| 3845 | + property real startY |
| 3846 | + property real startWidth |
| 3847 | + property real startHeight |
| 3848 | + |
| 3849 | + property string cursorName: { |
| 3850 | + if (root.containsMouse || root.pressed) { |
| 3851 | + if (leftBorder && !topBorder && !bottomBorder) { |
| 3852 | + return "left_side"; |
| 3853 | + } else if (rightBorder && !topBorder && !bottomBorder) { |
| 3854 | + return "right_side"; |
| 3855 | + } else if (topBorder && !leftBorder && !rightBorder) { |
| 3856 | + return "top_side"; |
| 3857 | + } else if (bottomBorder && !leftBorder && !rightBorder) { |
| 3858 | + return "bottom_side"; |
| 3859 | + } else if (leftBorder && topBorder) { |
| 3860 | + return "top_left_corner"; |
| 3861 | + } else if (leftBorder && bottomBorder) { |
| 3862 | + return "bottom_left_corner"; |
| 3863 | + } else if (rightBorder && topBorder) { |
| 3864 | + return "top_right_corner"; |
| 3865 | + } else if (rightBorder && bottomBorder) { |
| 3866 | + return "bottom_right_corner"; |
| 3867 | + } else { |
| 3868 | + return ""; |
| 3869 | + } |
| 3870 | + } else { |
| 3871 | + return ""; |
| 3872 | + } |
| 3873 | + } |
| 3874 | + onCursorNameChanged: { |
| 3875 | + Mir.cursorName = cursorName; |
| 3876 | + } |
| 3877 | + |
| 3878 | + function updateBorders() { |
| 3879 | + leftBorder = mouseX <= borderThickness; |
| 3880 | + rightBorder = mouseX >= width - borderThickness; |
| 3881 | + topBorder = mouseY <= borderThickness; |
| 3882 | + bottomBorder = mouseY >= height - borderThickness; |
| 3883 | + } |
| 3884 | + } |
| 3885 | + |
| 3886 | + onPressedChanged: { |
| 3887 | + var pos = mapToItem(target.parent, mouseX, mouseY); |
| 3888 | + |
| 3889 | + if (pressed) { |
| 3890 | + d.updateBorders(); |
| 3891 | + var pos = mapToItem(root.target.parent, mouseX, mouseY); |
| 3892 | + d.startMousePosX = pos.x; |
| 3893 | + d.startMousePosY = pos.y; |
| 3894 | + d.startX = target.x; |
| 3895 | + d.startY = target.y; |
| 3896 | + d.startWidth = target.width; |
| 3897 | + d.startHeight = target.height; |
| 3898 | + d.dragging = true; |
| 3899 | + } else { |
| 3900 | + d.dragging = false; |
| 3901 | + if (containsMouse) { |
| 3902 | + d.updateBorders(); |
| 3903 | + } |
| 3904 | + } |
| 3905 | + } |
| 3906 | + |
| 3907 | + onEntered: { |
| 3908 | + if (!pressed) { |
| 3909 | + d.updateBorders(); |
| 3910 | + } |
| 3911 | + } |
| 3912 | + |
| 3913 | + onPositionChanged: { |
| 3914 | + if (!pressed) { |
| 3915 | + d.updateBorders(); |
| 3916 | + } |
| 3917 | + |
| 3918 | + if (!d.dragging) { |
| 3919 | + return; |
| 3920 | + } |
| 3921 | + |
| 3922 | + var pos = mapToItem(target.parent, mouse.x, mouse.y); |
| 3923 | + |
| 3924 | + var deltaX = pos.x - d.startMousePosX; |
| 3925 | + var deltaY = pos.y - d.startMousePosY; |
| 3926 | + |
| 3927 | + if (d.leftBorder) { |
| 3928 | + var newTargetX = d.startX + deltaX; |
| 3929 | + if (target.x + target.width > newTargetX + minWidth) { |
| 3930 | + target.width = target.x + target.width - newTargetX; |
| 3931 | + target.x = newTargetX; |
| 3932 | + } else { |
| 3933 | + target.x = target.x + target.width - minWidth; |
| 3934 | + target.width = minWidth; |
| 3935 | + } |
| 3936 | + |
| 3937 | + } else if (d.rightBorder) { |
| 3938 | + if (d.startWidth + deltaX >= minWidth) { |
| 3939 | + target.width = d.startWidth + deltaX; |
| 3940 | + } else { |
| 3941 | + target.width = minWidth; |
| 3942 | + } |
| 3943 | + } |
| 3944 | + |
| 3945 | + if (d.topBorder) { |
| 3946 | + var newTargetY = d.startY + deltaY; |
| 3947 | + if (target.y + target.height > newTargetY + minHeight) { |
| 3948 | + target.height = target.y + target.height - newTargetY; |
| 3949 | + target.y = newTargetY; |
| 3950 | + } else { |
| 3951 | + target.y = target.y + target.height - minHeight; |
| 3952 | + target.height = minHeight; |
| 3953 | + } |
| 3954 | + |
| 3955 | + } else if (d.bottomBorder) { |
| 3956 | + if (d.startHeight + deltaY >= minHeight) { |
| 3957 | + target.height = d.startHeight + deltaY; |
| 3958 | + } else { |
| 3959 | + target.height = minHeight; |
| 3960 | + } |
| 3961 | + } |
| 3962 | + } |
| 3963 | } |
| 3964 | |
| 3965 | === modified file 'src/ApplicationArguments.h' |
| 3966 | --- src/ApplicationArguments.h 2015-09-14 09:11:08 +0000 |
| 3967 | +++ src/ApplicationArguments.h 2015-10-26 09:06:21 +0000 |
| 3968 | @@ -26,17 +26,25 @@ |
| 3969 | class ApplicationArguments : public QObject |
| 3970 | { |
| 3971 | Q_OBJECT |
| 3972 | - Q_PROPERTY(QString deviceName READ deviceName CONSTANT) |
| 3973 | + Q_PROPERTY(QString deviceName READ deviceName NOTIFY deviceNameChanged) |
| 3974 | Q_PROPERTY(QString mode READ mode CONSTANT) |
| 3975 | public: |
| 3976 | ApplicationArguments(QObject *parent = nullptr); |
| 3977 | |
| 3978 | - void setDeviceName(const QString &deviceName) { m_deviceName = deviceName; } |
| 3979 | + void setDeviceName(const QString &deviceName) { |
| 3980 | + if (deviceName != m_deviceName) { |
| 3981 | + m_deviceName = deviceName; |
| 3982 | + Q_EMIT deviceNameChanged(m_deviceName); |
| 3983 | + } |
| 3984 | + } |
| 3985 | QString deviceName() const { return m_deviceName; } |
| 3986 | |
| 3987 | void setMode(const QString &mode) { m_mode = mode; } |
| 3988 | QString mode() const { return m_mode; } |
| 3989 | |
| 3990 | +Q_SIGNALS: |
| 3991 | + void deviceNameChanged(const QString&); |
| 3992 | + |
| 3993 | private: |
| 3994 | QString m_deviceName; |
| 3995 | QString m_mode; |
| 3996 | |
| 3997 | === modified file 'src/CMakeLists.txt' |
| 3998 | --- src/CMakeLists.txt 2015-06-24 11:41:09 +0000 |
| 3999 | +++ src/CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 4000 | @@ -21,6 +21,9 @@ |
| 4001 | main.cpp |
| 4002 | MouseTouchAdaptor.cpp |
| 4003 | CachingNetworkManagerFactory.cpp |
| 4004 | + SecondaryWindow.cpp |
| 4005 | + ShellApplication.cpp |
| 4006 | + ShellView.cpp |
| 4007 | UnityCommandLineParser.cpp |
| 4008 | ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree |
| 4009 | ) |
| 4010 | |
| 4011 | === added file 'src/SecondaryWindow.cpp' |
| 4012 | --- src/SecondaryWindow.cpp 1970-01-01 00:00:00 +0000 |
| 4013 | +++ src/SecondaryWindow.cpp 2015-10-26 09:06:21 +0000 |
| 4014 | @@ -0,0 +1,31 @@ |
| 4015 | +/* |
| 4016 | + * Copyright (C) 2015 Canonical, Ltd. |
| 4017 | + * |
| 4018 | + * This program is free software; you can redistribute it and/or modify |
| 4019 | + * it under the terms of the GNU General Public License as published by |
| 4020 | + * the Free Software Foundation; version 3. |
| 4021 | + * |
| 4022 | + * This program is distributed in the hope that it will be useful, |
| 4023 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 4024 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 4025 | + * GNU General Public License for more details. |
| 4026 | + * |
| 4027 | + * You should have received a copy of the GNU General Public License |
| 4028 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 4029 | + */ |
| 4030 | + |
| 4031 | +#include "SecondaryWindow.h" |
| 4032 | + |
| 4033 | +// local |
| 4034 | +#include <paths.h> |
| 4035 | + |
| 4036 | +SecondaryWindow::SecondaryWindow(QQmlEngine *engine) |
| 4037 | + : QQuickView(engine, nullptr) |
| 4038 | +{ |
| 4039 | + setResizeMode(QQuickView::SizeRootObjectToView); |
| 4040 | + setColor("black"); |
| 4041 | + setTitle(QStringLiteral("Unity8 Shell - Secondary Screen")); |
| 4042 | + |
| 4043 | + QUrl source(::qmlDirectory() + "/DisabledScreenNotice.qml"); |
| 4044 | + setSource(source); |
| 4045 | +} |
| 4046 | |
| 4047 | === added file 'src/SecondaryWindow.h' |
| 4048 | --- src/SecondaryWindow.h 1970-01-01 00:00:00 +0000 |
| 4049 | +++ src/SecondaryWindow.h 2015-10-26 09:06:21 +0000 |
| 4050 | @@ -0,0 +1,30 @@ |
| 4051 | +/* |
| 4052 | + * Copyright (C) 2015 Canonical, Ltd. |
| 4053 | + * |
| 4054 | + * This program is free software; you can redistribute it and/or modify |
| 4055 | + * it under the terms of the GNU General Public License as published by |
| 4056 | + * the Free Software Foundation; version 3. |
| 4057 | + * |
| 4058 | + * This program is distributed in the hope that it will be useful, |
| 4059 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 4060 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 4061 | + * GNU General Public License for more details. |
| 4062 | + * |
| 4063 | + * You should have received a copy of the GNU General Public License |
| 4064 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 4065 | + */ |
| 4066 | + |
| 4067 | +#ifndef UNITY_SECONDARY_WINDOW_H |
| 4068 | +#define UNITY_SECONDARY_WINDOW_H |
| 4069 | + |
| 4070 | +#include <QQuickView> |
| 4071 | + |
| 4072 | +class SecondaryWindow : public QQuickView |
| 4073 | +{ |
| 4074 | + Q_OBJECT |
| 4075 | + |
| 4076 | +public: |
| 4077 | + SecondaryWindow(QQmlEngine *engine); |
| 4078 | +}; |
| 4079 | + |
| 4080 | +#endif // UNITY_SECONDARY_WINDOW_H |
| 4081 | |
| 4082 | === added file 'src/ShellApplication.cpp' |
| 4083 | --- src/ShellApplication.cpp 1970-01-01 00:00:00 +0000 |
| 4084 | +++ src/ShellApplication.cpp 2015-10-26 09:06:21 +0000 |
| 4085 | @@ -0,0 +1,197 @@ |
| 4086 | +/* |
| 4087 | + * Copyright (C) 2015 Canonical, Ltd. |
| 4088 | + * |
| 4089 | + * This program is free software; you can redistribute it and/or modify |
| 4090 | + * it under the terms of the GNU General Public License as published by |
| 4091 | + * the Free Software Foundation; version 3. |
| 4092 | + * |
| 4093 | + * This program is distributed in the hope that it will be useful, |
| 4094 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 4095 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 4096 | + * GNU General Public License for more details. |
| 4097 | + * |
| 4098 | + * You should have received a copy of the GNU General Public License |
| 4099 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 4100 | + */ |
| 4101 | + |
| 4102 | +#include "ShellApplication.h" |
| 4103 | + |
| 4104 | +// Qt |
| 4105 | +#include <QLibrary> |
| 4106 | +#include <QScreen> |
| 4107 | + |
| 4108 | +#include <libintl.h> |
| 4109 | + |
| 4110 | +// libandroid-properties |
| 4111 | +#include <hybris/properties/properties.h> |
| 4112 | + |
| 4113 | +// local |
| 4114 | +#include <paths.h> |
| 4115 | +#include "CachingNetworkManagerFactory.h" |
| 4116 | +#include "MouseTouchAdaptor.h" |
| 4117 | +#include "UnityCommandLineParser.h" |
| 4118 | + |
| 4119 | +ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer) |
| 4120 | + : QGuiApplication(argc, argv) |
| 4121 | + , m_shellView(nullptr) |
| 4122 | + , m_secondaryWindow(nullptr) |
| 4123 | + , m_mouseTouchAdaptor(nullptr) |
| 4124 | + , m_qmlEngine(nullptr) |
| 4125 | +{ |
| 4126 | + |
| 4127 | + setApplicationName(QStringLiteral("unity8")); |
| 4128 | + |
| 4129 | + connect(this, &QGuiApplication::screenAdded, this, &ShellApplication::onScreenAdded); |
| 4130 | + |
| 4131 | + setupQmlEngine(isMirServer); |
| 4132 | + |
| 4133 | + UnityCommandLineParser parser(*this); |
| 4134 | + |
| 4135 | + if (!parser.deviceName().isEmpty()) { |
| 4136 | + m_deviceName = parser.deviceName(); |
| 4137 | + } else { |
| 4138 | + char buffer[200]; |
| 4139 | + property_get("ro.product.device", buffer /* value */, "desktop" /* default_value*/); |
| 4140 | + m_deviceName = QString(buffer); |
| 4141 | + } |
| 4142 | + m_qmlArgs.setDeviceName(m_deviceName); |
| 4143 | + |
| 4144 | + m_qmlArgs.setMode(parser.mode()); |
| 4145 | + |
| 4146 | + // The testability driver is only loaded by QApplication but not by QGuiApplication. |
| 4147 | + // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own. |
| 4148 | + if (parser.hasTestability() || getenv("QT_LOAD_TESTABILITY")) { |
| 4149 | + QLibrary testLib(QStringLiteral("qttestability")); |
| 4150 | + if (testLib.load()) { |
| 4151 | + typedef void (*TasInitialize)(void); |
| 4152 | + TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init"); |
| 4153 | + if (initFunction) { |
| 4154 | + initFunction(); |
| 4155 | + } else { |
| 4156 | + qCritical("Library qttestability resolve failed!"); |
| 4157 | + } |
| 4158 | + } else { |
| 4159 | + qCritical("Library qttestability load failed!"); |
| 4160 | + } |
| 4161 | + } |
| 4162 | + |
| 4163 | + bindtextdomain("unity8", translationDirectory().toUtf8().data()); |
| 4164 | + textdomain("unity8"); |
| 4165 | + |
| 4166 | + m_shellView = new ShellView(m_qmlEngine, &m_qmlArgs); |
| 4167 | + |
| 4168 | + if (parser.windowGeometry().isValid()) { |
| 4169 | + m_shellView->setWidth(parser.windowGeometry().width()); |
| 4170 | + m_shellView->setHeight(parser.windowGeometry().height()); |
| 4171 | + } |
| 4172 | + |
| 4173 | + if (parser.hasFrameless()) { |
| 4174 | + m_shellView->setFlags(Qt::FramelessWindowHint); |
| 4175 | + } |
| 4176 | + |
| 4177 | + // You will need this if you want to interact with touch-only components using a mouse |
| 4178 | + // Needed only when manually testing on a desktop. |
| 4179 | + if (parser.hasMouseToTouch()) { |
| 4180 | + m_mouseTouchAdaptor = MouseTouchAdaptor::instance(); |
| 4181 | + } |
| 4182 | + |
| 4183 | + |
| 4184 | + // Some hard-coded policy for now. |
| 4185 | + // NB: We don't support more than two screens at the moment |
| 4186 | + // |
| 4187 | + // TODO: Support an arbitrary number of screens and different policies |
| 4188 | + // (eg cloned desktop, several desktops, etc) |
| 4189 | + if (isMirServer && screens().count() == 2) { |
| 4190 | + m_shellView->setScreen(screens().at(1)); |
| 4191 | + m_qmlArgs.setDeviceName("desktop"); |
| 4192 | + |
| 4193 | + m_secondaryWindow = new SecondaryWindow(m_qmlEngine); |
| 4194 | + m_secondaryWindow->setScreen(screens().at(0)); |
| 4195 | + // QWindow::showFullScreen() also calls QWindow::requestActivate() and we don't want that! |
| 4196 | + m_secondaryWindow->setWindowState(Qt::WindowFullScreen); |
| 4197 | + m_secondaryWindow->setVisible(true); |
| 4198 | + } |
| 4199 | + |
| 4200 | + if (isMirServer || parser.hasFullscreen()) { |
| 4201 | + m_shellView->showFullScreen(); |
| 4202 | + } else { |
| 4203 | + m_shellView->show(); |
| 4204 | + } |
| 4205 | +} |
| 4206 | + |
| 4207 | +ShellApplication::~ShellApplication() |
| 4208 | +{ |
| 4209 | + destroyResources(); |
| 4210 | +} |
| 4211 | + |
| 4212 | +void ShellApplication::destroyResources() |
| 4213 | +{ |
| 4214 | + // Deletion order is important. Don't use QScopedPointers and the like |
| 4215 | + // Otherwise the process will hang on shutdown (bug somewhere I guess). |
| 4216 | + delete m_shellView; |
| 4217 | + m_shellView = nullptr; |
| 4218 | + |
| 4219 | + delete m_secondaryWindow; |
| 4220 | + m_secondaryWindow = nullptr; |
| 4221 | + |
| 4222 | + delete m_mouseTouchAdaptor; |
| 4223 | + m_mouseTouchAdaptor = nullptr; |
| 4224 | + |
| 4225 | + delete m_qmlEngine; |
| 4226 | + m_qmlEngine = nullptr; |
| 4227 | +} |
| 4228 | + |
| 4229 | +void ShellApplication::setupQmlEngine(bool isMirServer) |
| 4230 | +{ |
| 4231 | + m_qmlEngine = new QQmlEngine(this); |
| 4232 | + |
| 4233 | + m_qmlEngine->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory())); |
| 4234 | + |
| 4235 | + prependImportPaths(m_qmlEngine, ::overrideImportPaths()); |
| 4236 | + if (!isMirServer) { |
| 4237 | + prependImportPaths(m_qmlEngine, ::nonMirImportPaths()); |
| 4238 | + } |
| 4239 | + appendImportPaths(m_qmlEngine, ::fallbackImportPaths()); |
| 4240 | + |
| 4241 | + m_qmlEngine->setNetworkAccessManagerFactory(new CachingNetworkManagerFactory); |
| 4242 | + |
| 4243 | + QObject::connect(m_qmlEngine, &QQmlEngine::quit, this, &QGuiApplication::quit); |
| 4244 | +} |
| 4245 | + |
| 4246 | +void ShellApplication::onScreenAdded(QScreen * /*screen*/) |
| 4247 | +{ |
| 4248 | + // TODO: Support an arbitrary number of screens and different policies |
| 4249 | + // (eg cloned desktop, several desktops, etc) |
| 4250 | + if (screens().count() == 2) { |
| 4251 | + m_shellView->setScreen(screens().at(1)); |
| 4252 | + m_qmlArgs.setDeviceName("desktop"); |
| 4253 | + // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having |
| 4254 | + // its backing QPlatformWindow recreated). So lets refocus it. |
| 4255 | + m_shellView->requestActivate(); |
| 4256 | + |
| 4257 | + m_secondaryWindow = new SecondaryWindow(m_qmlEngine); |
| 4258 | + m_secondaryWindow->setScreen(screens().at(0)); |
| 4259 | + |
| 4260 | + // QWindow::showFullScreen() also calls QWindow::requestActivate() and we don't want that! |
| 4261 | + m_secondaryWindow->setWindowState(Qt::WindowFullScreen); |
| 4262 | + m_secondaryWindow->setVisible(true); |
| 4263 | + } |
| 4264 | +} |
| 4265 | + |
| 4266 | +void ShellApplication::onScreenAboutToBeRemoved(QScreen *screen) |
| 4267 | +{ |
| 4268 | + // TODO: Support an arbitrary number of screens and different policies |
| 4269 | + // (eg cloned desktop, several desktops, etc) |
| 4270 | + if (screen == m_shellView->screen()) { |
| 4271 | + Q_ASSERT(screens().count() > 1); |
| 4272 | + Q_ASSERT(screens().at(0) != screen); |
| 4273 | + Q_ASSERT(m_secondaryWindow); |
| 4274 | + delete m_secondaryWindow; |
| 4275 | + m_secondaryWindow = nullptr; |
| 4276 | + m_shellView->setScreen(screens().first()); |
| 4277 | + m_qmlArgs.setDeviceName(m_deviceName); |
| 4278 | + // Changing the QScreen where a QWindow is drawn makes it also lose focus (besides having |
| 4279 | + // its backing QPlatformWindow recreated). So lets refocus it. |
| 4280 | + m_shellView->requestActivate(); |
| 4281 | + } |
| 4282 | +} |
| 4283 | |
| 4284 | === added file 'src/ShellApplication.h' |
| 4285 | --- src/ShellApplication.h 1970-01-01 00:00:00 +0000 |
| 4286 | +++ src/ShellApplication.h 2015-10-26 09:06:21 +0000 |
| 4287 | @@ -0,0 +1,55 @@ |
| 4288 | +/* |
| 4289 | + * Copyright (C) 2015 Canonical, Ltd. |
| 4290 | + * |
| 4291 | + * This program is free software; you can redistribute it and/or modify |
| 4292 | + * it under the terms of the GNU General Public License as published by |
| 4293 | + * the Free Software Foundation; version 3. |
| 4294 | + * |
| 4295 | + * This program is distributed in the hope that it will be useful, |
| 4296 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 4297 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 4298 | + * GNU General Public License for more details. |
| 4299 | + * |
| 4300 | + * You should have received a copy of the GNU General Public License |
| 4301 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 4302 | + */ |
| 4303 | + |
| 4304 | +#ifndef SHELLAPPLICATION_H |
| 4305 | +#define SHELLAPPLICATION_H |
| 4306 | + |
| 4307 | +#include <QGuiApplication> |
| 4308 | +#include <QQmlEngine> |
| 4309 | +#include <QQuickView> |
| 4310 | +#include <QScopedPointer> |
| 4311 | + |
| 4312 | +#include "ApplicationArguments.h" |
| 4313 | +#include "MouseTouchAdaptor.h" |
| 4314 | +#include "SecondaryWindow.h" |
| 4315 | +#include "ShellView.h" |
| 4316 | + |
| 4317 | +class ShellApplication : public QGuiApplication |
| 4318 | +{ |
| 4319 | + Q_OBJECT |
| 4320 | +public: |
| 4321 | + ShellApplication(int & argc, char ** argv, bool isMirServer); |
| 4322 | + virtual ~ShellApplication(); |
| 4323 | + |
| 4324 | + void destroyResources(); |
| 4325 | +public Q_SLOTS: |
| 4326 | + // called by qtmir |
| 4327 | + void onScreenAboutToBeRemoved(QScreen *screen); |
| 4328 | + |
| 4329 | +private Q_SLOTS: |
| 4330 | + void onScreenAdded(QScreen*); |
| 4331 | + |
| 4332 | +private: |
| 4333 | + void setupQmlEngine(bool isMirServer); |
| 4334 | + QString m_deviceName; |
| 4335 | + ApplicationArguments m_qmlArgs; |
| 4336 | + ShellView *m_shellView; |
| 4337 | + SecondaryWindow *m_secondaryWindow; |
| 4338 | + MouseTouchAdaptor *m_mouseTouchAdaptor; |
| 4339 | + QQmlEngine *m_qmlEngine; |
| 4340 | +}; |
| 4341 | + |
| 4342 | +#endif // SHELLAPPLICATION_H |
| 4343 | |
| 4344 | === added file 'src/ShellView.cpp' |
| 4345 | --- src/ShellView.cpp 1970-01-01 00:00:00 +0000 |
| 4346 | +++ src/ShellView.cpp 2015-10-26 09:06:21 +0000 |
| 4347 | @@ -0,0 +1,59 @@ |
| 4348 | +/* |
| 4349 | + * Copyright (C) 2015 Canonical, Ltd. |
| 4350 | + * |
| 4351 | + * This program is free software; you can redistribute it and/or modify |
| 4352 | + * it under the terms of the GNU General Public License as published by |
| 4353 | + * the Free Software Foundation; version 3. |
| 4354 | + * |
| 4355 | + * This program is distributed in the hope that it will be useful, |
| 4356 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 4357 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 4358 | + * GNU General Public License for more details. |
| 4359 | + * |
| 4360 | + * You should have received a copy of the GNU General Public License |
| 4361 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 4362 | + */ |
| 4363 | + |
| 4364 | +#include "ShellView.h" |
| 4365 | + |
| 4366 | +// Qt |
| 4367 | +#include <QQmlContext> |
| 4368 | +#include <QQuickItem> |
| 4369 | + |
| 4370 | +// local |
| 4371 | +#include <paths.h> |
| 4372 | + |
| 4373 | +ShellView::ShellView(QQmlEngine *engine, QObject *qmlArgs) |
| 4374 | + : QQuickView(engine, nullptr) |
| 4375 | +{ |
| 4376 | + setResizeMode(QQuickView::SizeRootObjectToView); |
| 4377 | + setColor("black"); |
| 4378 | + setTitle(QStringLiteral("Unity8")); |
| 4379 | + |
| 4380 | + rootContext()->setContextProperty(QStringLiteral("applicationArguments"), qmlArgs); |
| 4381 | + |
| 4382 | + QUrl source(::qmlDirectory() + "/OrientedShell.qml"); |
| 4383 | + setSource(source); |
| 4384 | + |
| 4385 | + connect(this, &QWindow::widthChanged, this, &ShellView::onWidthChanged); |
| 4386 | + connect(this, &QWindow::heightChanged, this, &ShellView::onHeightChanged); |
| 4387 | +} |
| 4388 | + |
| 4389 | +void ShellView::onWidthChanged(int w) |
| 4390 | +{ |
| 4391 | + // For good measure in case SizeRootObjectToView doesn't fulfill its promise. |
| 4392 | + // |
| 4393 | + // There's at least one situation that's know to leave the root object with an outdated size. |
| 4394 | + // (really looks like Qt bug) |
| 4395 | + // Happens when starting unity8 with an external monitor already connected. |
| 4396 | + // The QResizeEvent we get still has the size of the first screen and since the resize move is triggered |
| 4397 | + // from the resize event handler, the root item doesn't get resized. |
| 4398 | + // TODO: Confirm the Qt bug and submit a patch upstream |
| 4399 | + rootObject()->setWidth(w); |
| 4400 | +} |
| 4401 | + |
| 4402 | +void ShellView::onHeightChanged(int h) |
| 4403 | +{ |
| 4404 | + // See comment in ShellView::onWidthChanged() |
| 4405 | + rootObject()->setHeight(h); |
| 4406 | +} |
| 4407 | |
| 4408 | === added file 'src/ShellView.h' |
| 4409 | --- src/ShellView.h 1970-01-01 00:00:00 +0000 |
| 4410 | +++ src/ShellView.h 2015-10-26 09:06:21 +0000 |
| 4411 | @@ -0,0 +1,34 @@ |
| 4412 | +/* |
| 4413 | + * Copyright (C) 2015 Canonical, Ltd. |
| 4414 | + * |
| 4415 | + * This program is free software; you can redistribute it and/or modify |
| 4416 | + * it under the terms of the GNU General Public License as published by |
| 4417 | + * the Free Software Foundation; version 3. |
| 4418 | + * |
| 4419 | + * This program is distributed in the hope that it will be useful, |
| 4420 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 4421 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 4422 | + * GNU General Public License for more details. |
| 4423 | + * |
| 4424 | + * You should have received a copy of the GNU General Public License |
| 4425 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 4426 | + */ |
| 4427 | + |
| 4428 | +#ifndef UNITY_SHELL_VIEW_H |
| 4429 | +#define UNITY_SHELL_VIEW_H |
| 4430 | + |
| 4431 | +#include <QQuickView> |
| 4432 | + |
| 4433 | +class ShellView : public QQuickView |
| 4434 | +{ |
| 4435 | + Q_OBJECT |
| 4436 | + |
| 4437 | +public: |
| 4438 | + ShellView(QQmlEngine *engine, QObject *qmlArgs); |
| 4439 | + |
| 4440 | +private Q_SLOTS: |
| 4441 | + void onWidthChanged(int); |
| 4442 | + void onHeightChanged(int); |
| 4443 | +}; |
| 4444 | + |
| 4445 | +#endif // UNITY_SHELL_VIEW_H |
| 4446 | |
| 4447 | === modified file 'src/main.cpp' |
| 4448 | --- src/main.cpp 2015-09-23 15:14:01 +0000 |
| 4449 | +++ src/main.cpp 2015-10-26 09:06:21 +0000 |
| 4450 | @@ -14,26 +14,8 @@ |
| 4451 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 4452 | */ |
| 4453 | |
| 4454 | -// Qt |
| 4455 | -#include <QCommandLineParser> |
| 4456 | -#include <QtQuick/QQuickView> |
| 4457 | -#include <QtGui/QGuiApplication> |
| 4458 | -#include <QtQml/QQmlEngine> |
| 4459 | -#include <QtQml/QQmlContext> |
| 4460 | -#include <QLibrary> |
| 4461 | -#include <QDebug> |
| 4462 | -#include <csignal> |
| 4463 | -#include <libintl.h> |
| 4464 | - |
| 4465 | -// libandroid-properties |
| 4466 | -#include <hybris/properties/properties.h> |
| 4467 | - |
| 4468 | // local |
| 4469 | -#include <paths.h> |
| 4470 | -#include "MouseTouchAdaptor.h" |
| 4471 | -#include "ApplicationArguments.h" |
| 4472 | -#include "CachingNetworkManagerFactory.h" |
| 4473 | -#include "UnityCommandLineParser.h" |
| 4474 | +#include "ShellApplication.h" |
| 4475 | |
| 4476 | int main(int argc, const char *argv[]) |
| 4477 | { |
| 4478 | @@ -43,91 +25,12 @@ |
| 4479 | isMirServer = true; |
| 4480 | } |
| 4481 | |
| 4482 | - QGuiApplication::setApplicationName(QStringLiteral("unity8")); |
| 4483 | - QGuiApplication *application; |
| 4484 | - |
| 4485 | - application = new QGuiApplication(argc, (char**)argv); |
| 4486 | - |
| 4487 | - UnityCommandLineParser parser(*application); |
| 4488 | - |
| 4489 | - ApplicationArguments qmlArgs; |
| 4490 | - |
| 4491 | - if (!parser.deviceName().isEmpty()) { |
| 4492 | - qmlArgs.setDeviceName(parser.deviceName()); |
| 4493 | - } else { |
| 4494 | - char buffer[200]; |
| 4495 | - property_get("ro.product.device", buffer /* value */, "desktop" /* default_value*/); |
| 4496 | - qmlArgs.setDeviceName(QString(buffer)); |
| 4497 | - } |
| 4498 | - |
| 4499 | - qmlArgs.setMode(parser.mode()); |
| 4500 | - |
| 4501 | - // The testability driver is only loaded by QApplication but not by QGuiApplication. |
| 4502 | - // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own. |
| 4503 | - if (parser.hasTestability() || getenv("QT_LOAD_TESTABILITY")) { |
| 4504 | - QLibrary testLib(QStringLiteral("qttestability")); |
| 4505 | - if (testLib.load()) { |
| 4506 | - typedef void (*TasInitialize)(void); |
| 4507 | - TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init"); |
| 4508 | - if (initFunction) { |
| 4509 | - initFunction(); |
| 4510 | - } else { |
| 4511 | - qCritical("Library qttestability resolve failed!"); |
| 4512 | - } |
| 4513 | - } else { |
| 4514 | - qCritical("Library qttestability load failed!"); |
| 4515 | - } |
| 4516 | - } |
| 4517 | - |
| 4518 | - bindtextdomain("unity8", translationDirectory().toUtf8().data()); |
| 4519 | - textdomain("unity8"); |
| 4520 | - |
| 4521 | - QQuickView* view = new QQuickView(); |
| 4522 | - view->setResizeMode(QQuickView::SizeRootObjectToView); |
| 4523 | - view->setColor("black"); |
| 4524 | - view->setTitle(QStringLiteral("Unity8 Shell")); |
| 4525 | - |
| 4526 | - if (parser.windowGeometry().isValid()) { |
| 4527 | - view->setWidth(parser.windowGeometry().width()); |
| 4528 | - view->setHeight(parser.windowGeometry().height()); |
| 4529 | - } |
| 4530 | - |
| 4531 | - view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory())); |
| 4532 | - view->rootContext()->setContextProperty(QStringLiteral("applicationArguments"), &qmlArgs); |
| 4533 | - if (parser.hasFrameless()) { |
| 4534 | - view->setFlags(Qt::FramelessWindowHint); |
| 4535 | - } |
| 4536 | - |
| 4537 | - // You will need this if you want to interact with touch-only components using a mouse |
| 4538 | - // Needed only when manually testing on a desktop. |
| 4539 | - MouseTouchAdaptor *mouseTouchAdaptor = 0; |
| 4540 | - if (parser.hasMouseToTouch()) { |
| 4541 | - mouseTouchAdaptor = MouseTouchAdaptor::instance(); |
| 4542 | - } |
| 4543 | - |
| 4544 | - QUrl source(::qmlDirectory() + "/OrientedShell.qml"); |
| 4545 | - prependImportPaths(view->engine(), ::overrideImportPaths()); |
| 4546 | - if (!isMirServer) { |
| 4547 | - prependImportPaths(view->engine(), ::nonMirImportPaths()); |
| 4548 | - } |
| 4549 | - appendImportPaths(view->engine(), ::fallbackImportPaths()); |
| 4550 | - |
| 4551 | - CachingNetworkManagerFactory *managerFactory = new CachingNetworkManagerFactory(); |
| 4552 | - view->engine()->setNetworkAccessManagerFactory(managerFactory); |
| 4553 | - |
| 4554 | - view->setSource(source); |
| 4555 | - QObject::connect(view->engine(), &QQmlEngine::quit, application, &QGuiApplication::quit); |
| 4556 | - |
| 4557 | - if (isMirServer || parser.hasFullscreen()) { |
| 4558 | - view->showFullScreen(); |
| 4559 | - } else { |
| 4560 | - view->show(); |
| 4561 | - } |
| 4562 | + ShellApplication *application = new ShellApplication(argc, (char**)argv, isMirServer); |
| 4563 | |
| 4564 | int result = application->exec(); |
| 4565 | |
| 4566 | - delete view; |
| 4567 | - delete mouseTouchAdaptor; |
| 4568 | + application->destroyResources(); |
| 4569 | + |
| 4570 | delete application; |
| 4571 | |
| 4572 | return result; |
| 4573 | |
| 4574 | === modified file 'tests/autopilot/unity8/fixture_setup.py' |
| 4575 | --- tests/autopilot/unity8/fixture_setup.py 2015-09-21 12:50:10 +0000 |
| 4576 | +++ tests/autopilot/unity8/fixture_setup.py 2015-10-26 09:06:21 +0000 |
| 4577 | @@ -133,7 +133,7 @@ |
| 4578 | args = [binary_arg] + env_args |
| 4579 | self.unity_proxy = process_helpers.restart_unity_with_testability( |
| 4580 | *args) |
| 4581 | - self.main_win = self.unity_proxy.select_single(shell.QQuickView) |
| 4582 | + self.main_win = self.unity_proxy.select_single(shell.ShellView) |
| 4583 | |
| 4584 | def _create_sensors(self): |
| 4585 | # Wait for unity to start running. |
| 4586 | |
| 4587 | === modified file 'tests/autopilot/unity8/greeter/tests/__init__.py' |
| 4588 | --- tests/autopilot/unity8/greeter/tests/__init__.py 2015-04-29 19:21:18 +0000 |
| 4589 | +++ tests/autopilot/unity8/greeter/tests/__init__.py 2015-10-26 09:06:21 +0000 |
| 4590 | @@ -24,5 +24,5 @@ |
| 4591 | class GreeterTestCase(UnityTestCase): |
| 4592 | def get_shell(self, unity_proxy): |
| 4593 | main_window = ( |
| 4594 | - unity_proxy.select_single(shell.QQuickView)) |
| 4595 | + unity_proxy.select_single(shell.ShellView)) |
| 4596 | return main_window.select_single('Shell') |
| 4597 | |
| 4598 | === modified file 'tests/autopilot/unity8/launcher.py' |
| 4599 | --- tests/autopilot/unity8/launcher.py 2015-04-29 19:21:18 +0000 |
| 4600 | +++ tests/autopilot/unity8/launcher.py 2015-10-26 09:06:21 +0000 |
| 4601 | @@ -42,7 +42,7 @@ |
| 4602 | logger.debug('The launcher is already opened.') |
| 4603 | |
| 4604 | def _swipe_to_show_launcher(self): |
| 4605 | - view = self.get_root_instance().select_single('QQuickView') |
| 4606 | + view = self.get_root_instance().select_single('ShellView') |
| 4607 | start_y = stop_y = view.y + view.height // 2 |
| 4608 | |
| 4609 | start_x = view.x + 1 |
| 4610 | |
| 4611 | === modified file 'tests/autopilot/unity8/settings_wizard/__init__.py' |
| 4612 | --- tests/autopilot/unity8/settings_wizard/__init__.py 2015-05-21 16:52:05 +0000 |
| 4613 | +++ tests/autopilot/unity8/settings_wizard/__init__.py 2015-10-26 09:06:21 +0000 |
| 4614 | @@ -375,12 +375,17 @@ |
| 4615 | wizard = get_wizard(self) |
| 4616 | next_page = wizard.get_current_page() |
| 4617 | locationPageEnabled = True |
| 4618 | + reportingPageEnabled = True |
| 4619 | if next_page.objectName == 'locationPage': |
| 4620 | next_page = wizard.get_location_page() |
| 4621 | else: |
| 4622 | locationPageEnabled = False |
| 4623 | - next_page = wizard.get_reporting_page() |
| 4624 | - return locationPageEnabled, next_page |
| 4625 | + if next_page.objectName == 'reportingPage': |
| 4626 | + next_page = wizard.get_reporting_page() |
| 4627 | + else: |
| 4628 | + reportingPageEnabled = False |
| 4629 | + next_page = wizard.get_finished_page() |
| 4630 | + return locationPageEnabled, reportingPageEnabled, next_page |
| 4631 | |
| 4632 | def _get_notification(self, unity): |
| 4633 | logger.info('Waiting longer for notification object') |
| 4634 | |
| 4635 | === modified file 'tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py' |
| 4636 | --- tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py 2015-05-21 16:37:36 +0000 |
| 4637 | +++ tests/autopilot/unity8/settings_wizard/tests/test_settings_wizard.py 2015-10-26 09:06:21 +0000 |
| 4638 | @@ -80,14 +80,19 @@ |
| 4639 | password_page = next_page |
| 4640 | wifi_connect_page = self._test_password_page(password_page) |
| 4641 | |
| 4642 | - locationPageEnabled, next_page = self._test_wifi_connect_page( |
| 4643 | - wifi_connect_page) |
| 4644 | + reporting_page = None |
| 4645 | + locationPageEnabled, reportingPageEnabled, next_page = self._test_wifi_connect_page(wifi_connect_page) |
| 4646 | if locationPageEnabled: |
| 4647 | location_page = next_page |
| 4648 | - reporting_page = self._test_location_page(location_page) |
| 4649 | + if reportingPageEnabled: |
| 4650 | + reporting_page = self._test_location_page(location_page) |
| 4651 | + else: |
| 4652 | + finish_page = next_page |
| 4653 | + |
| 4654 | + if reporting_page is not None: |
| 4655 | + finish_page = self._test_reporting_page(reporting_page) |
| 4656 | else: |
| 4657 | - reporting_page = next_page |
| 4658 | - finish_page = self._test_reporting_page(reporting_page) |
| 4659 | + finish_page = next_page |
| 4660 | |
| 4661 | finish_page.finish() |
| 4662 | self.assertFalse( |
| 4663 | |
| 4664 | === modified file 'tests/autopilot/unity8/shell/__init__.py' |
| 4665 | --- tests/autopilot/unity8/shell/__init__.py 2015-06-22 15:47:34 +0000 |
| 4666 | +++ tests/autopilot/unity8/shell/__init__.py 2015-10-26 09:06:21 +0000 |
| 4667 | @@ -93,7 +93,7 @@ |
| 4668 | return _urgency_enums.get(urgency.upper()) |
| 4669 | |
| 4670 | |
| 4671 | -class QQuickView(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
| 4672 | +class ShellView(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
| 4673 | """An helper class that makes it easy to interact with the shell""" |
| 4674 | |
| 4675 | def get_greeter(self): |
| 4676 | |
| 4677 | === modified file 'tests/autopilot/unity8/shell/tests/__init__.py' |
| 4678 | --- tests/autopilot/unity8/shell/tests/__init__.py 2015-09-21 12:50:10 +0000 |
| 4679 | +++ tests/autopilot/unity8/shell/tests/__init__.py 2015-10-26 09:06:21 +0000 |
| 4680 | @@ -297,7 +297,7 @@ |
| 4681 | |
| 4682 | @property |
| 4683 | def main_window(self): |
| 4684 | - return self._proxy.select_single(shell.QQuickView) |
| 4685 | + return self._proxy.select_single(shell.ShellView) |
| 4686 | |
| 4687 | |
| 4688 | class DashBaseTestCase(AutopilotTestCase): |
| 4689 | |
| 4690 | === modified file 'tests/mocks/CMakeLists.txt' |
| 4691 | --- tests/mocks/CMakeLists.txt 2015-08-06 22:45:56 +0000 |
| 4692 | +++ tests/mocks/CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 4693 | @@ -29,6 +29,7 @@ |
| 4694 | endmacro() |
| 4695 | |
| 4696 | add_subdirectory(AccountsService) |
| 4697 | +add_subdirectory(Cursor) |
| 4698 | add_subdirectory(GSettings.1.0) |
| 4699 | add_subdirectory(indicator-service) |
| 4700 | add_subdirectory(libusermetrics) |
| 4701 | |
| 4702 | === added directory 'tests/mocks/Cursor' |
| 4703 | === added file 'tests/mocks/Cursor/CMakeLists.txt' |
| 4704 | --- tests/mocks/Cursor/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
| 4705 | +++ tests/mocks/Cursor/CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 4706 | @@ -0,0 +1,1 @@ |
| 4707 | +add_unity8_mock(Cursor 1.0 Cursor PREFIX mocks) |
| 4708 | |
| 4709 | === added file 'tests/mocks/Cursor/Cursor.qml' |
| 4710 | --- tests/mocks/Cursor/Cursor.qml 1970-01-01 00:00:00 +0000 |
| 4711 | +++ tests/mocks/Cursor/Cursor.qml 2015-10-26 09:06:21 +0000 |
| 4712 | @@ -0,0 +1,20 @@ |
| 4713 | +/* |
| 4714 | + * Copyright (C) 2015 Canonical, Ltd. |
| 4715 | + * |
| 4716 | + * This program is free software; you can redistribute it and/or modify |
| 4717 | + * it under the terms of the GNU General Public License as published by |
| 4718 | + * the Free Software Foundation; version 3. |
| 4719 | + * |
| 4720 | + * This program is distributed in the hope that it will be useful, |
| 4721 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 4722 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 4723 | + * GNU General Public License for more details. |
| 4724 | + * |
| 4725 | + * You should have received a copy of the GNU General Public License |
| 4726 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 4727 | + */ |
| 4728 | + |
| 4729 | +import QtQuick 2.4 |
| 4730 | + |
| 4731 | +Item { |
| 4732 | +} |
| 4733 | |
| 4734 | === added file 'tests/mocks/Cursor/qmldir' |
| 4735 | --- tests/mocks/Cursor/qmldir 1970-01-01 00:00:00 +0000 |
| 4736 | +++ tests/mocks/Cursor/qmldir 2015-10-26 09:06:21 +0000 |
| 4737 | @@ -0,0 +1,2 @@ |
| 4738 | +module Cursor |
| 4739 | +Cursor 1.0 Cursor.qml |
| 4740 | |
| 4741 | === modified file 'tests/mocks/Unity/Launcher/MockQuickListModel.cpp' |
| 4742 | --- tests/mocks/Unity/Launcher/MockQuickListModel.cpp 2013-08-19 15:10:58 +0000 |
| 4743 | +++ tests/mocks/Unity/Launcher/MockQuickListModel.cpp 2015-10-26 09:06:21 +0000 |
| 4744 | @@ -32,7 +32,7 @@ |
| 4745 | switch (role) |
| 4746 | { |
| 4747 | case RoleLabel: |
| 4748 | - return QLatin1String("test menu entry ") + QString::number(index.row()); |
| 4749 | + return QString(QLatin1String("test menu entry ") + QString::number(index.row())); |
| 4750 | case RoleIcon: |
| 4751 | return QLatin1String("copy.png"); |
| 4752 | case RoleClickable: |
| 4753 | |
| 4754 | === modified file 'tests/mocks/Unity/fake_resultsmodel.cpp' |
| 4755 | --- tests/mocks/Unity/fake_resultsmodel.cpp 2015-09-22 10:44:21 +0000 |
| 4756 | +++ tests/mocks/Unity/fake_resultsmodel.cpp 2015-10-26 09:06:21 +0000 |
| 4757 | @@ -78,7 +78,7 @@ |
| 4758 | case RoleTitle: |
| 4759 | return QString("Title.%1.%2").arg(m_categoryId).arg(index.row()); |
| 4760 | case RoleArt: |
| 4761 | - return qmlDirectory() + "/graphics/applicationIcons/dash.png"; |
| 4762 | + return QString(qmlDirectory() + "/graphics/applicationIcons/dash.png"); |
| 4763 | case RoleSubtitle: |
| 4764 | return QString("Subtitle.%1.%2").arg(m_categoryId).arg(index.row()); |
| 4765 | case RoleMascot: |
| 4766 | |
| 4767 | === modified file 'tests/mocks/Unity/fake_scopesoverview.cpp' |
| 4768 | --- tests/mocks/Unity/fake_scopesoverview.cpp 2015-09-22 10:44:21 +0000 |
| 4769 | +++ tests/mocks/Unity/fake_scopesoverview.cpp 2015-10-26 09:06:21 +0000 |
| 4770 | @@ -308,7 +308,7 @@ |
| 4771 | case RoleSubtitle: |
| 4772 | return scope && scope->name() == "Videos this is long ab cd ef gh ij kl" ? "tube, movies, cinema, pictures, art, moving images, magic in a box" : QString(); |
| 4773 | case RoleArt: |
| 4774 | - return qmlDirectory() + "/graphics/applicationIcons/dash.png"; |
| 4775 | + return QString(qmlDirectory() + "/graphics/applicationIcons/dash.png"); |
| 4776 | case RoleMascot: |
| 4777 | case RoleEmblem: |
| 4778 | case RoleSummary: |
| 4779 | |
| 4780 | === modified file 'tests/mocks/Utils/CMakeLists.txt' |
| 4781 | --- tests/mocks/Utils/CMakeLists.txt 2015-09-17 12:25:29 +0000 |
| 4782 | +++ tests/mocks/Utils/CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 4783 | @@ -13,8 +13,6 @@ |
| 4784 | ${CMAKE_SOURCE_DIR}/plugins/Utils/activefocuslogger.cpp |
| 4785 | ${CMAKE_SOURCE_DIR}/plugins/Utils/qlimitproxymodelqml.cpp |
| 4786 | ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp |
| 4787 | - ${CMAKE_SOURCE_DIR}/plugins/Utils/relativetimeformatter.cpp |
| 4788 | - ${CMAKE_SOURCE_DIR}/plugins/Utils/timeformatter.cpp |
| 4789 | ${CMAKE_SOURCE_DIR}/plugins/Utils/unitymenumodelpaths.cpp |
| 4790 | ${CMAKE_SOURCE_DIR}/plugins/Utils/windowkeysfilter.cpp |
| 4791 | ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp |
| 4792 | |
| 4793 | === modified file 'tests/mocks/Utils/Utils.qmltypes' |
| 4794 | --- tests/mocks/Utils/Utils.qmltypes 2015-03-04 13:04:58 +0000 |
| 4795 | +++ tests/mocks/Utils/Utils.qmltypes 2015-10-26 09:06:21 +0000 |
| 4796 | @@ -4,10 +4,19 @@ |
| 4797 | // It is used for QML tooling purposes only. |
| 4798 | // |
| 4799 | // This file was auto-generated by: |
| 4800 | -// 'qmlplugindump -notrelocatable Utils 0.1 plugins' |
| 4801 | +// 'qmlplugindump -notrelocatable Utils 0.1 tests/mocks' |
| 4802 | |
| 4803 | Module { |
| 4804 | Component { |
| 4805 | + name: "Constants" |
| 4806 | + prototype: "QObject" |
| 4807 | + exports: ["Utils/Constants 0.1"] |
| 4808 | + isCreatable: false |
| 4809 | + isSingleton: true |
| 4810 | + exportMetaObjectRevisions: [0] |
| 4811 | + Property { name: "indicatorValueTimeout"; type: "int"; isReadonly: true } |
| 4812 | + } |
| 4813 | + Component { |
| 4814 | name: "EasingCurve" |
| 4815 | prototype: "QObject" |
| 4816 | exports: ["Utils/EasingCurve 0.1"] |
| 4817 | @@ -18,6 +27,22 @@ |
| 4818 | Property { name: "value"; type: "double"; isReadonly: true } |
| 4819 | } |
| 4820 | Component { |
| 4821 | + name: "InputWatcher" |
| 4822 | + prototype: "QObject" |
| 4823 | + exports: ["Utils/InputWatcher 0.1"] |
| 4824 | + exportMetaObjectRevisions: [0] |
| 4825 | + Property { name: "target"; type: "QObject"; isPointer: true } |
| 4826 | + Property { name: "targetPressed"; type: "bool"; isReadonly: true } |
| 4827 | + Signal { |
| 4828 | + name: "targetChanged" |
| 4829 | + Parameter { name: "value"; type: "QObject"; isPointer: true } |
| 4830 | + } |
| 4831 | + Signal { |
| 4832 | + name: "targetPressedChanged" |
| 4833 | + Parameter { name: "value"; type: "bool" } |
| 4834 | + } |
| 4835 | + } |
| 4836 | + Component { |
| 4837 | name: "QAbstractProxyModel" |
| 4838 | prototype: "QAbstractItemModel" |
| 4839 | Property { name: "sourceModel"; type: "QAbstractItemModel"; isPointer: true } |
| 4840 | @@ -60,33 +85,6 @@ |
| 4841 | Method { name: "invalidate" } |
| 4842 | } |
| 4843 | Component { |
| 4844 | - name: "RelativeTimeFormatter" |
| 4845 | - prototype: "TimeFormatter" |
| 4846 | - exports: ["Utils/RelativeTimeFormatter 0.1"] |
| 4847 | - exportMetaObjectRevisions: [0] |
| 4848 | - } |
| 4849 | - Component { |
| 4850 | - name: "TimeFormatter" |
| 4851 | - prototype: "QObject" |
| 4852 | - exports: ["Utils/GDateTimeFormatter 0.1", "Utils/TimeFormatter 0.1"] |
| 4853 | - exportMetaObjectRevisions: [0, 0] |
| 4854 | - Property { name: "format"; type: "string" } |
| 4855 | - Property { name: "timeString"; type: "string"; isReadonly: true } |
| 4856 | - Property { name: "time"; type: "qlonglong" } |
| 4857 | - Signal { |
| 4858 | - name: "formatChanged" |
| 4859 | - Parameter { name: "format"; type: "string" } |
| 4860 | - } |
| 4861 | - Signal { |
| 4862 | - name: "timeStringChanged" |
| 4863 | - Parameter { name: "timeString"; type: "string" } |
| 4864 | - } |
| 4865 | - Signal { |
| 4866 | - name: "timeChanged" |
| 4867 | - Parameter { name: "time"; type: "qlonglong" } |
| 4868 | - } |
| 4869 | - } |
| 4870 | - Component { |
| 4871 | name: "UnityMenuModelPaths" |
| 4872 | prototype: "QObject" |
| 4873 | exports: ["Utils/UnityMenuModelPaths 0.1"] |
| 4874 | @@ -160,6 +158,11 @@ |
| 4875 | isCreatable: false |
| 4876 | isSingleton: true |
| 4877 | exportMetaObjectRevisions: [0] |
| 4878 | + Property { name: "geometry"; type: "QVariantMap" } |
| 4879 | + Signal { |
| 4880 | + name: "geometryChanged" |
| 4881 | + Parameter { name: "geometry"; type: "QVariantMap" } |
| 4882 | + } |
| 4883 | Method { |
| 4884 | name: "saveGeometry" |
| 4885 | Parameter { name: "windowId"; type: "string" } |
| 4886 | |
| 4887 | === modified file 'tests/mocks/Utils/plugin.cpp' |
| 4888 | --- tests/mocks/Utils/plugin.cpp 2015-09-17 12:25:29 +0000 |
| 4889 | +++ tests/mocks/Utils/plugin.cpp 2015-10-26 09:06:21 +0000 |
| 4890 | @@ -23,14 +23,6 @@ |
| 4891 | |
| 4892 | // local |
| 4893 | #include "plugin.h" |
| 4894 | -#include "inputwatcher.h" |
| 4895 | -#include "qlimitproxymodelqml.h" |
| 4896 | -#include "unitysortfilterproxymodelqml.h" |
| 4897 | -#include "relativetimeformatter.h" |
| 4898 | -#include "timeformatter.h" |
| 4899 | -#include "unitymenumodelpaths.h" |
| 4900 | -#include "windowkeysfilter.h" |
| 4901 | -#include "easingcurve.h" |
| 4902 | #include "windowstatestorage.h" |
| 4903 | #include "constants.h" |
| 4904 | |
| 4905 | @@ -39,8 +31,6 @@ |
| 4906 | #include <inputwatcher.h> |
| 4907 | #include <qlimitproxymodelqml.h> |
| 4908 | #include <unitysortfilterproxymodelqml.h> |
| 4909 | -#include <relativetimeformatter.h> |
| 4910 | -#include <timeformatter.h> |
| 4911 | #include <unitymenumodelpaths.h> |
| 4912 | #include <windowkeysfilter.h> |
| 4913 | #include <windowscreenshotprovider.h> |
| 4914 | @@ -67,11 +57,8 @@ |
| 4915 | qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel"); |
| 4916 | qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel"); |
| 4917 | qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths"); |
| 4918 | - qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter"); |
| 4919 | qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter"); |
| 4920 | - qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter"); |
| 4921 | qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve"); |
| 4922 | - qmlRegisterType<RelativeTimeFormatter>(uri, 0, 1, "RelativeTimeFormatter"); |
| 4923 | qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage); |
| 4924 | qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher"); |
| 4925 | qmlRegisterSingletonType<Constants>(uri, 0, 1, "Constants", createConstants); |
| 4926 | |
| 4927 | === modified file 'tests/plugins/ScreenGrabber/ScreenGrabberTest.cpp' |
| 4928 | --- tests/plugins/ScreenGrabber/ScreenGrabberTest.cpp 2015-07-20 15:06:46 +0000 |
| 4929 | +++ tests/plugins/ScreenGrabber/ScreenGrabberTest.cpp 2015-10-26 09:06:21 +0000 |
| 4930 | @@ -55,6 +55,17 @@ |
| 4931 | QVERIFY(!args.first().toString().isEmpty()); |
| 4932 | } |
| 4933 | |
| 4934 | + void testRotatedScreenshot() |
| 4935 | + { |
| 4936 | + QSignalSpy grabberSpy(m_grabber, &ScreenGrabber::screenshotSaved); |
| 4937 | + m_grabber->captureAndSave(90); // rotate by 90° |
| 4938 | + const QVariantList args = grabberSpy.takeFirst(); |
| 4939 | + const QString filename = args.first().toString(); |
| 4940 | + QVERIFY(!filename.isEmpty()); |
| 4941 | + QImage img(filename); |
| 4942 | + QVERIFY(img.height() > img.width()); // verify that the image got rotated by 90° (height > width) |
| 4943 | + } |
| 4944 | + |
| 4945 | private: |
| 4946 | QQuickView *m_view; |
| 4947 | ScreenGrabber *m_grabber = nullptr; |
| 4948 | |
| 4949 | === modified file 'tests/plugins/ScreenGrabber/grabber.qml' |
| 4950 | --- tests/plugins/ScreenGrabber/grabber.qml 2015-07-17 19:59:31 +0000 |
| 4951 | +++ tests/plugins/ScreenGrabber/grabber.qml 2015-10-26 09:06:21 +0000 |
| 4952 | @@ -20,7 +20,7 @@ |
| 4953 | Rectangle { |
| 4954 | property var grabber: screenGrabber |
| 4955 | |
| 4956 | - width: 100 |
| 4957 | + width: 101 // width intentionally bigger than height to test rotation |
| 4958 | height: 100 |
| 4959 | color: "green" |
| 4960 | |
| 4961 | |
| 4962 | === modified file 'tests/plugins/Unity/Indicators/UnityMenuModelStackTest.cpp' |
| 4963 | --- tests/plugins/Unity/Indicators/UnityMenuModelStackTest.cpp 2015-08-19 13:56:21 +0000 |
| 4964 | +++ tests/plugins/Unity/Indicators/UnityMenuModelStackTest.cpp 2015-10-26 09:06:21 +0000 |
| 4965 | @@ -43,6 +43,8 @@ |
| 4966 | { |
| 4967 | delete m_model; |
| 4968 | m_model = nullptr; |
| 4969 | + // send deleteLaters to avoid leaks. |
| 4970 | + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); |
| 4971 | } |
| 4972 | |
| 4973 | void testHeadOnSetHead() |
| 4974 | @@ -146,19 +148,10 @@ |
| 4975 | |
| 4976 | m_model->removeRow(removeIndex); |
| 4977 | |
| 4978 | - waitFor([&stack, resultCount]() { return stack.count() == resultCount; }, 1000); |
| 4979 | QCOMPARE(stack.count(), resultCount); |
| 4980 | } |
| 4981 | |
| 4982 | private: |
| 4983 | - bool waitFor(std::function<bool()> functor, int ms) { |
| 4984 | - |
| 4985 | - QElapsedTimer timer; |
| 4986 | - timer.start(); |
| 4987 | - while(!functor() && timer.elapsed() < ms) { QTest::qWait(10); } |
| 4988 | - return functor(); |
| 4989 | - } |
| 4990 | - |
| 4991 | QVariant recuseAddMenu(int subMenuCount, int depth_remaining) |
| 4992 | { |
| 4993 | QVariantList rows; |
| 4994 | |
| 4995 | === modified file 'tests/plugins/Utils/CMakeLists.txt' |
| 4996 | --- tests/plugins/Utils/CMakeLists.txt 2015-04-30 07:56:43 +0000 |
| 4997 | +++ tests/plugins/Utils/CMakeLists.txt 2015-10-26 09:06:21 +0000 |
| 4998 | @@ -7,7 +7,6 @@ |
| 4999 | foreach(util_test |
| 5000 | QLimitProxyModel |
