Unity 8
 All Classes Functions Properties
Shell.qml
1 /*
2  * Copyright (C) 2013 Canonical, Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 import QtQuick 2.0
18 import AccountsService 0.1
19 import GSettings 1.0
20 import Unity.Application 0.1
21 import Ubuntu.Components 0.1
22 import Ubuntu.Components.Popups 0.1
23 import Ubuntu.Gestures 0.1
24 import Unity.Launcher 0.1
25 import LightDM 0.1 as LightDM
26 import Powerd 0.1
27 import SessionBroadcast 0.1
28 import "Dash"
29 import "Greeter"
30 import "Launcher"
31 import "Panel"
32 import "Components"
33 import "Notifications"
34 import Unity.Notifications 1.0 as NotificationBackend
35 import Unity.Session 0.1
36 
37 FocusScope {
38  id: shell
39 
40  // this is only here to select the width / height of the window if not running fullscreen
41  property bool tablet: false
42  width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
43  height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
44 
45  property real edgeSize: units.gu(2)
46  property url defaultBackground: Qt.resolvedUrl(shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg")
47  property url background
48  readonly property real panelHeight: panel.panelHeight
49 
50  property bool dashShown: dash.shown
51 
52  property bool sideStageEnabled: shell.width >= units.gu(100)
53  readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId
54 
55  function activateApplication(appId) {
56  if (ApplicationManager.findApplication(appId)) {
57  ApplicationManager.requestFocusApplication(appId);
58  stages.show(true);
59  if (stages.locked && ApplicationManager.focusedApplicationId == appId) {
60  applicationsDisplayLoader.item.select(appId);
61  }
62  } else {
63  var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
64  ApplicationManager.startApplication(appId, execFlags);
65  stages.show(false);
66  }
67  }
68 
69  Binding {
70  target: LauncherModel
71  property: "applicationManager"
72  value: ApplicationManager
73  }
74 
75  Component.onCompleted: {
76  Theme.name = "Ubuntu.Components.Themes.SuruGradient"
77  }
78 
79  GSettings {
80  id: backgroundSettings
81  schema.id: "org.gnome.desktop.background"
82  }
83  property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
84  onGSettingsPictureChanged: {
85  shell.background = gSettingsPicture
86  }
87 
88  VolumeControl {
89  id: volumeControl
90  }
91 
92  Keys.onVolumeUpPressed: volumeControl.volumeUp()
93  Keys.onVolumeDownPressed: volumeControl.volumeDown()
94 
95  Item {
96  id: underlayClipper
97  anchors.fill: parent
98  anchors.rightMargin: stages.overlayWidth
99  clip: stages.overlayMode && !stages.painting
100 
101  InputFilterArea {
102  anchors.fill: parent
103  blockInput: parent.clip
104  }
105 
106  Item {
107  id: underlay
108  objectName: "underlay"
109  anchors.fill: parent
110  anchors.rightMargin: -parent.anchors.rightMargin
111 
112  // Whether the underlay is fully covered by opaque UI elements.
113  property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicators.width
114 
115  // Whether the user should see the topmost application surface (if there's one at all).
116  readonly property bool applicationSurfaceShouldBeSeen: stages.shown && !stages.painting && !stages.overlayMode
117 
118  // NB! Application surfaces are stacked behind the shell one. So they can only be seen by the user
119  // through the translucent parts of the shell surface.
120  visible: !fullyCovered && !applicationSurfaceShouldBeSeen
121 
122  Rectangle {
123  anchors.fill: parent
124  color: "black"
125  opacity: dash.disappearingAnimationProgress
126  }
127 
128  Image {
129  anchors.fill: dash
130  source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
131  fillMode: Image.PreserveAspectCrop
132  horizontalAlignment: Image.AlignRight
133  verticalAlignment: Image.AlignTop
134  }
135 
136  Dash {
137  id: dash
138  objectName: "dash"
139 
140  available: !LightDM.Greeter.active
141  hides: [stages, launcher, panel.indicators]
142  shown: disappearingAnimationProgress !== 1.0 && greeterWrapper.showProgress !== 1.0
143  enabled: disappearingAnimationProgress === 0.0 && greeterWrapper.showProgress === 0.0 && edgeDemo.dashEnabled
144 
145  anchors {
146  fill: parent
147  topMargin: panel.panelHeight
148  }
149 
150  contentScale: 1.0 - 0.2 * disappearingAnimationProgress
151  opacity: 1.0 - disappearingAnimationProgress
152  property real disappearingAnimationProgress: {
153  if (stages.overlayMode) {
154  return 0;
155  } else {
156  return stages.showProgress
157  }
158  }
159 
160  // FIXME: only necessary because stages.showProgress is not animated
161  Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
162  }
163  }
164  }
165 
166  EdgeDragArea {
167  id: stagesDragHandle
168  direction: Direction.Leftwards
169 
170  anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
171  width: shell.edgeSize
172 
173  property real progress: stages.width
174 
175  onTouchXChanged: {
176  if (status == DirectionalDragArea.Recognized) {
177  if (ApplicationManager.count == 0) {
178  progress = Math.max(stages.width - stagesDragHandle.width + touchX, stages.width * .3)
179  } else {
180  progress = stages.width - stagesDragHandle.width + touchX
181  }
182  }
183  }
184 
185  onDraggingChanged: {
186  if (!dragging) {
187  if (ApplicationManager.count > 0 && progress < stages.width - units.gu(10)) {
188  stages.show(true)
189  }
190  stagesDragHandle.progress = stages.width;
191  }
192  }
193  }
194 
195  Item {
196  id: stages
197  objectName: "stages"
198  width: parent.width
199  height: parent.height
200 
201  x: {
202  if (shown) {
203  if (overlayMode || locked || greeter.fakeActiveForApp !== "") {
204  return 0;
205  }
206  return launcher.progress
207  } else {
208  return stagesDragHandle.progress
209  }
210  }
211 
212  Behavior on x { SmoothedAnimation { velocity: 600; duration: UbuntuAnimation.FastDuration } }
213 
214  property bool shown: false
215 
216  property real showProgress: overlayMode ? 0 : MathUtils.clamp(1 - x / shell.width, 0, 1)
217 
218  property bool fullyShown: x == 0
219  property bool fullyHidden: x == width
220 
221  property bool painting: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.painting : false
222  property bool fullscreen: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.fullscreen : false
223  property bool overlayMode: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.overlayMode : false
224  property int overlayWidth: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.overlayWidth : false
225  property bool locked: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.locked : false
226 
227  function show(focusApp) {
228  shown = true;
229  panel.indicators.hide();
230  edgeDemo.stopDemo();
231  greeter.hide();
232  if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0 && focusApp) {
233  ApplicationManager.focusApplication(ApplicationManager.get(0).appId);
234  }
235  }
236 
237  function hide() {
238  shown = false;
239  if (ApplicationManager.focusedApplicationId) {
240  ApplicationManager.unfocusCurrentApplication();
241  }
242  }
243 
244  Connections {
245  target: ApplicationManager
246 
247  onFocusRequested: {
248  if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== appId) {
249  lockscreen.show();
250  }
251  greeter.hide();
252  stages.show(true);
253  }
254 
255  onFocusedApplicationIdChanged: {
256  if (greeter.fakeActiveForApp !== "" && greeter.fakeActiveForApp !== ApplicationManager.focusedApplicationId) {
257  lockscreen.show();
258  }
259  if (ApplicationManager.focusedApplicationId.length > 0) {
260  stages.show(false);
261  } else {
262  if (!stages.overlayMode) {
263  stages.hide();
264  }
265  }
266  }
267 
268  onApplicationAdded: {
269  stages.show(false);
270  }
271 
272  onApplicationRemoved: {
273  if (ApplicationManager.focusedApplicationId.length == 0) {
274  stages.hide();
275  }
276  }
277  }
278 
279  property bool dialogShown: false
280 
281  Component {
282  id: logoutDialog
283  Dialog {
284  id: dialogueLogout
285  title: "Logout"
286  text: "Are you sure that you want to logout?"
287  Button {
288  text: "Cancel"
289  onClicked: {
290  PopupUtils.close(dialogueLogout);
291  stages.dialogShown = false;
292  }
293  }
294  Button {
295  text: "Yes"
296  onClicked: {
298  PopupUtils.close(dialogueLogout);
299  stages.dialogShown = false;
300  }
301  }
302  }
303  }
304 
305  Component {
306  id: shutdownDialog
307  Dialog {
308  id: dialogueShutdown
309  title: "Shutdown"
310  text: "Are you sure that you want to shutdown?"
311  Button {
312  text: "Cancel"
313  onClicked: {
314  PopupUtils.close(dialogueShutdown);
315  stages.dialogShown = false;
316  }
317  }
318  Button {
319  text: "Yes"
320  onClicked: {
321  dBusUnitySessionServiceConnection.closeAllApps();
323  PopupUtils.close(dialogueShutdown);
324  stages.dialogShown = false;
325  }
326  }
327  }
328  }
329 
330  Component {
331  id: rebootDialog
332  Dialog {
333  id: dialogueReboot
334  title: "Reboot"
335  text: "Are you sure that you want to reboot?"
336  Button {
337  text: "Cancel"
338  onClicked: {
339  PopupUtils.close(dialogueReboot)
340  stages.dialogShown = false;
341  }
342  }
343  Button {
344  text: "Yes"
345  onClicked: {
346  dBusUnitySessionServiceConnection.closeAllApps();
348  PopupUtils.close(dialogueReboot);
349  stages.dialogShown = false;
350  }
351  }
352  }
353  }
354 
355  Component {
356  id: powerDialog
357  Dialog {
358  id: dialoguePower
359  title: "Power"
360  text: i18n.tr("Are you sure you would like to turn power off?")
361  Button {
362  text: i18n.tr("Power off")
363  onClicked: {
364  dBusUnitySessionServiceConnection.closeAllApps();
365  PopupUtils.close(dialoguePower);
366  stages.dialogShown = false;
367  shutdownFadeOutRectangle.enabled = true;
368  shutdownFadeOutRectangle.visible = true;
369  shutdownFadeOut.start();
370  }
371  }
372  Button {
373  text: i18n.tr("Restart")
374  onClicked: {
375  dBusUnitySessionServiceConnection.closeAllApps();
377  PopupUtils.close(dialoguePower);
378  stages.dialogShown = false;
379  }
380  }
381  Button {
382  text: i18n.tr("Cancel")
383  onClicked: {
384  PopupUtils.close(dialoguePower);
385  stages.dialogShown = false;
386  }
387  }
388  }
389  }
390 
391  function showPowerDialog() {
392  if (!stages.dialogShown) {
393  stages.dialogShown = true;
394  PopupUtils.open(powerDialog);
395  }
396  }
397 
398  Connections {
399  id: dBusUnitySessionServiceConnection
400  objectName: "dBusUnitySessionServiceConnection"
402 
403  function closeAllApps() {
404  while (true) {
405  var app = ApplicationManager.get(0);
406  if (app === null) {
407  break;
408  }
409  ApplicationManager.stopApplication(app.appId);
410  }
411  }
412 
413  onLogoutRequested: {
414  // Display a dialog to ask the user to confirm.
415  if (!stages.dialogShown) {
416  stages.dialogShown = true;
417  PopupUtils.open(logoutDialog);
418  }
419  }
420 
421  onShutdownRequested: {
422  // Display a dialog to ask the user to confirm.
423  if (!stages.dialogShown) {
424  stages.dialogShown = true;
425  PopupUtils.open(shutdownDialog);
426  }
427  }
428 
429  onRebootRequested: {
430  // Display a dialog to ask the user to confirm.
431  if (!stages.dialogShown) {
432  stages.dialogShown = true;
433  PopupUtils.open(rebootDialog);
434  }
435  }
436 
437  onLogoutReady: {
438  closeAllApps();
439  Qt.quit();
440  }
441  }
442 
443  Loader {
444  id: applicationsDisplayLoader
445  anchors.fill: parent
446 
447  source: shell.sideStageEnabled ? "Stages/StageWithSideStage.qml" : "Stages/PhoneStage.qml"
448 
449  Binding {
450  target: applicationsDisplayLoader.item
451  property: "objectName"
452  value: "stage"
453  }
454  Binding {
455  target: applicationsDisplayLoader.item
456  property: "moving"
457  value: !stages.fullyShown
458  }
459  Binding {
460  target: applicationsDisplayLoader.item
461  property: "shown"
462  value: stages.shown
463  }
464  Binding {
465  target: applicationsDisplayLoader.item
466  property: "dragAreaWidth"
467  value: shell.edgeSize
468  }
469  Binding {
470  target: applicationsDisplayLoader.item
471  property: "spreadEnabled"
472  value: greeter.fakeActiveForApp === "" // to support emergency dialer hack
473  }
474  }
475  }
476 
477  Lockscreen {
478  id: lockscreen
479  objectName: "lockscreen"
480 
481  readonly property int backgroundTopMargin: -panel.panelHeight
482 
483  hides: [launcher, panel.indicators]
484  shown: false
485  enabled: true
486  showAnimation: StandardAnimation { property: "opacity"; to: 1 }
487  hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
488  y: panel.panelHeight
489  x: required ? 0 : - width
490  width: parent.width
491  height: parent.height - panel.panelHeight
492  background: shell.background
493  minPinLength: 4
494  maxPinLength: 4
495 
496  onEntered: LightDM.Greeter.respond(passphrase);
497  onCancel: greeter.show()
498  onEmergencyCall: {
499  greeter.fakeActiveForApp = "dialer-app"
500  shell.activateApplication("dialer-app")
501  lockscreen.hide()
502  }
503 
504  onShownChanged: if (shown) greeter.fakeActiveForApp = ""
505 
506  Component.onCompleted: {
507  if (LightDM.Users.count == 1) {
508  LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
509  }
510  }
511  }
512 
513  Connections {
514  target: LightDM.Greeter
515 
516  onShowGreeter: greeter.show()
517 
518  onShowPrompt: {
519  if (LightDM.Users.count == 1) {
520  // TODO: There's no better way for now to determine if its a PIN or a passphrase.
521  if (text == "PIN") {
522  lockscreen.alphaNumeric = false
523  } else {
524  lockscreen.alphaNumeric = true
525  }
526  lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
527  lockscreen.show();
528  }
529  }
530 
531  onAuthenticationComplete: {
532  if (LightDM.Greeter.promptless) {
533  return;
534  }
535  if (LightDM.Greeter.authenticated) {
536  lockscreen.hide();
537  greeter.login();
538  } else {
539  lockscreen.clear(true);
540  }
541  }
542  }
543 
544  Binding {
545  target: LightDM.Greeter
546  property: "active"
547  value: greeter.shown || lockscreen.shown || greeter.fakeActiveForApp != ""
548  }
549 
550  Rectangle {
551  anchors.fill: parent
552  color: "black"
553  opacity: greeterWrapper.showProgress * 0.8
554  }
555 
556  Item {
557  // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
558  id: greeterWrapper
559  x: launcher.progress
560  y: panel.panelHeight
561  width: parent.width
562  height: parent.height - panel.panelHeight
563 
564  Behavior on x {
565  enabled: !launcher.dashSwipe
566  StandardAnimation {}
567  }
568 
569  readonly property real showProgress: MathUtils.clamp((1 - x/width) + greeter.showProgress - 1, 0, 1)
570  onShowProgressChanged: if (LightDM.Greeter.promptless && showProgress === 0) greeter.login()
571 
572  Greeter {
573  id: greeter
574  objectName: "greeter"
575 
576  signal sessionStarted() // helpful for tests
577 
578  property string fakeActiveForApp: ""
579 
580  available: true
581  hides: [launcher, panel.indicators]
582  shown: true
583 
584  defaultBackground: shell.background
585 
586  width: parent.width
587  height: parent.height
588 
589  dragHandleWidth: shell.edgeSize
590 
591  function login() {
592  enabled = false;
593  LightDM.Greeter.startSessionSync();
594  sessionStarted();
595  greeter.hide();
596  lockscreen.hide();
597  launcher.hide();
598  enabled = true;
599  }
600 
601  onShownChanged: {
602  if (shown) {
603  lockscreen.reset();
604  if (!LightDM.Greeter.promptless) {
605  lockscreen.show();
606  }
607  // If there is only one user, we start authenticating with that one here.
608  // If there are more users, the Greeter will handle that
609  if (LightDM.Users.count == 1) {
610  LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
611  }
612  greeter.fakeActiveForApp = "";
613  greeter.forceActiveFocus();
614  }
615  }
616 
617  onUnlocked: greeter.hide()
618  onSelected: {
619  // Update launcher items for new user
620  var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
621  AccountsService.user = user;
622  LauncherModel.setUser(user);
623  }
624 
625  onTease: launcher.tease()
626 
627  Binding {
628  target: ApplicationManager
629  property: "suspended"
630  value: greeter.shown && greeterWrapper.showProgress == 1
631  }
632  }
633  }
634 
635  InputFilterArea {
636  anchors.fill: parent
637  blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown
638  || panel.indicators.shown
639  }
640 
641  Connections {
642  id: powerConnection
643  target: Powerd
644 
645  onDisplayPowerStateChange: {
646  // We ignore any display-off signals when the proximity sensor
647  // is active. This usually indicates something like a phone call.
648  if (status == Powerd.Off && reason != Powerd.Proximity) {
649  greeter.showNow();
650  }
651 
652  // No reason to chew demo CPU when user isn't watching
653  if (status == Powerd.Off) {
654  edgeDemo.paused = true;
655  } else if (status == Powerd.On) {
656  edgeDemo.paused = false;
657  }
658  }
659  }
660 
661  function showHome() {
662  if (edgeDemo.running) {
663  return
664  }
665 
666  if (LightDM.Greeter.active) {
667  if (!LightDM.Greeter.promptless) {
668  lockscreen.show()
669  }
670  greeter.hide()
671  }
672 
673  var animate = !LightDM.Greeter.active && !stages.shown
674  dash.setCurrentScope("clickscope", animate, false)
675  stages.hide()
676  }
677 
678  function showDash() {
679  if (LightDM.Greeter.active && !LightDM.Greeter.promptless) {
680  return;
681  }
682 
683  if (stages.shown && !stages.overlayMode && !stages.locked) {
684  stages.hide();
685  launcher.fadeOut();
686  } else {
687  launcher.switchToNextState("visible");
688  }
689 
690  if (greeter.shown) {
691  greeter.hideRight();
692  launcher.fadeOut();
693  }
694  }
695 
696  Item {
697  id: overlay
698 
699  anchors.fill: parent
700 
701  Panel {
702  id: panel
703  objectName: "panel"
704  anchors.fill: parent //because this draws indicator menus
705  indicators {
706  hides: [launcher]
707  available: edgeDemo.panelEnabled && greeter.fakeActiveForApp === ""
708  contentEnabled: edgeDemo.panelContentEnabled
709  width: parent.width > units.gu(60) ? units.gu(40) : parent.width
710  panelHeight: units.gu(3)
711  }
712  property string focusedAppId: ApplicationManager.focusedApplicationId
713  property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
714  fullscreenMode: (focusedApplication && stages.fullscreen && !LightDM.Greeter.active) || greeter.fakeActiveForApp !== ""
715 
716  InputFilterArea {
717  anchors {
718  top: parent.top
719  left: parent.left
720  right: parent.right
721  }
722  height: (panel.fullscreenMode) ? shell.edgeSize : panel.panelHeight
723  blockInput: true
724  }
725  }
726 
727  InputFilterArea {
728  blockInput: launcher.shown
729  anchors {
730  top: parent.top
731  bottom: parent.bottom
732  left: parent.left
733  }
734  width: launcher.width
735  }
736 
737  Launcher {
738  id: launcher
739  objectName: "launcher"
740 
741  readonly property bool dashSwipe: progress > 0
742 
743  anchors.top: parent.top
744  anchors.bottom: parent.bottom
745  width: parent.width
746  dragAreaWidth: shell.edgeSize
747  available: edgeDemo.launcherEnabled && greeter.fakeActiveForApp === ""
748 
749  onShowDashHome: showHome()
750  onDash: showDash()
751  onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
752  onLauncherApplicationSelected: {
753  if (greeter.fakeActiveForApp !== "") {
754  lockscreen.show()
755  }
756  if (!edgeDemo.running)
757  shell.activateApplication(appId)
758  }
759  onShownChanged: {
760  if (shown) {
761  panel.indicators.hide()
762  }
763  }
764  }
765 
766  Rectangle {
767  id: modalNotificationBackground
768 
769  visible: notifications.useModal && !greeter.shown && (notifications.state == "narrow")
770  color: "#000000"
771  anchors.fill: parent
772  opacity: 0.5
773 
774  MouseArea {
775  anchors.fill: parent
776  }
777 
778  InputFilterArea {
779  anchors.fill: parent
780  blockInput: modalNotificationBackground.visible
781  }
782  }
783 
784  Notifications {
785  id: notifications
786 
787  model: NotificationBackend.Model
788  margin: units.gu(1)
789 
790  y: panel.panelHeight
791  width: parent.width
792  height: parent.height - panel.panelHeight
793 
794  states: [
795  State {
796  name: "narrow"
797  when: overlay.width <= units.gu(60)
798  AnchorChanges { target: notifications; anchors.left: parent.left }
799  },
800  State {
801  name: "wide"
802  when: overlay.width > units.gu(60)
803  AnchorChanges { target: notifications; anchors.left: undefined }
804  PropertyChanges { target: notifications; width: units.gu(38) }
805  }
806  ]
807 
808  InputFilterArea {
809  anchors { left: parent.left; right: parent.right }
810  height: parent.contentHeight
811  blockInput: height > 0
812  }
813  }
814  }
815 
816  focus: true
817  onFocusChanged: if (!focus) forceActiveFocus();
818 
819  InputFilterArea {
820  anchors {
821  top: parent.top
822  bottom: parent.bottom
823  left: parent.left
824  }
825  width: shell.edgeSize
826  blockInput: true
827  }
828 
829  InputFilterArea {
830  anchors {
831  top: parent.top
832  bottom: parent.bottom
833  right: parent.right
834  }
835  width: shell.edgeSize
836  blockInput: true
837  }
838 
839  Binding {
840  target: i18n
841  property: "domain"
842  value: "unity8"
843  }
844 
845  OSKController {
846  anchors.topMargin: panel.panelHeight
847  anchors.fill: parent // as needs to know the geometry of the shell
848  }
849 
850  //FIXME: This should be handled in the input stack, keyboard shouldnt propagate
851  MouseArea {
852  anchors.bottom: parent.bottom
853  anchors.left: parent.left
854  anchors.right: parent.right
855  height: ApplicationManager.keyboardVisible ? ApplicationManager.keyboardHeight : 0
856 
857  enabled: ApplicationManager.keyboardVisible
858  }
859 
860  Label {
861  anchors.centerIn: parent
862  visible: ApplicationManager.fake ? ApplicationManager.fake : false
863  text: "EARLY ALPHA\nNOT READY FOR USE"
864  color: "lightgrey"
865  opacity: 0.2
866  font.weight: Font.Black
867  horizontalAlignment: Text.AlignHCenter
868  verticalAlignment: Text.AlignVCenter
869  fontSizeMode: Text.Fit
870  rotation: -45
871  scale: Math.min(parent.width, parent.height) / width
872  }
873 
874  EdgeDemo {
875  id: edgeDemo
876  greeter: greeter
877  launcher: launcher
878  dash: dash
879  indicators: panel.indicators
880  underlay: underlay
881  }
882 
883  Connections {
884  target: SessionBroadcast
885  onShowHome: showHome()
886  }
887 
888  Keys.onPressed: {
889  if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
890  if (!powerKeyTimer.running) {
891  powerKeyTimer.start();
892  }
893  event.accepted = true;
894  }
895  }
896 
897  Keys.onReleased: {
898  if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
899  powerKeyTimer.stop();
900  event.accepted = true;
901  }
902  }
903 
904  Timer {
905  id: powerKeyTimer
906  interval: 2000
907  repeat: false
908  triggeredOnStart: false
909 
910  onTriggered: {
911  stages.showPowerDialog();
912  }
913  }
914 
915  Rectangle {
916  id: shutdownFadeOutRectangle
917  enabled: false
918  visible: false
919  color: "black"
920  anchors.fill: parent
921  opacity: 0.0
922  NumberAnimation on opacity {
923  id: shutdownFadeOut
924  from: 0.0
925  to: 1.0
926  onStopped: {
927  if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
929  }
930  }
931  }
932  }
933 }