系统用户界面

系统用户界面是设备上任何应用程序启动和停止的部分。它负责管理应用程序窗口并用特定的方式组合它们。例如,用于全屏显示应用程序或允许同时显示来自不同应用程序的多个窗口。

在桌面系统中,系统用户界面类似于 Microsoft Windows 的 Shell 或 KDE 的 Plasmashell 加上 KWin 合成器。

系统用户界面有以下任务

任务描述
合成管理多个应用程序的表面,称为窗口。
根据所需设计,在一个或多个物理屏幕上排列这些窗口。
处理窗口装饰、转换效果以及其他系统级用户体验。
通信接口作为交换应用程序及其自身信息(如切换语言)的通道。
输入处理根据用户的当前焦点在输入事件之间切换焦点。
提供系统输入服务,例如,为基于触摸的系统启动虚拟键盘。
管理系统级应用程序和服务通过在用户交互时启动应用程序和在关键时刻(如内存不足)停止它们来管理应用程序生命周期。
通过显示如帧率、当前使用的 CPU 数量以及内存资源等的统计信息,提供集中式 UI 以监视 UI 性能和所有已启动的应用程序。
管理空闲时间和显示主屏幕启动后向用户显示默认视图。
显示基本数据,例如,当前时间。
显示由几个选定应用程序组成的视图。

实现系统用户界面

系统用户界面的主要特性是其管理多个应用程序和窗口的能力。因此,基于 Linux 的系统是推荐的开发环境,其中包括启用多进程模式。在其他操作系统上,您可以使用单进程模式。有关单进程和双进程之间差异的更多信息,请参阅单进程与双进程模式Wayland 和 Qt

窗口管理

系统用户界面的核心作用是处理应用程序窗口。在客户端,您需要使用 ApplicationManagerWindow。在系统用户界面方面,您需要实现 WindowManager::windowAdded 的处理程序。每当客户端窗口可见时,就会发出 WindowManager::windowAdded 信号。该信号有一个参数,即 WindowObject,它是客户端 ApplicationManagerWindow 的系统用户界面表示。

为了区分客户端窗口,您应使用窗口属性。例如,您可以将 type 属性附加到客户端窗口,以便告诉系统用户界面,它是一个顶级窗口、一个弹出窗口还是其他内容。客户端和服务器端窗口表示都可以访问这些属性。通常,它们始终同步;但是底层 Wayland 协议是完全异步的。

要将WindowObject包含在系统 UI 的渲染树中,将WindowObject设为WindowItemwindow属性。该WindowItem充当WindowObjects的容器Item。因此,该WindowItem决定了客户端窗口在系统 UI 中的位置、可见性等。

简单系统 UI 的一个示例是针对"Hello World!"系统 UI 示例编写的。

Item {
    width: 800
    height: 600

    // Show application names and icons
    Column {
        spacing: 20
        Repeater {
            model: ApplicationManager
            Column {
                Image {
                    source: model.icon
                    MouseArea {
                        anchors.fill: parent
                        onClicked: model.isRunning ? application.stop() : application.start()
                    }
                }
                Text {
                    font.pixelSize: 20
                    text: model.name
                }
            }
        }
    }

    // Show windows
    Column {
        anchors.right: parent.right
        Repeater {
            model: WindowManager
            WindowItem {
                width: 600
                height: 200
                window: model.window
            }
        }
    }
}

通知

在需要显示通知或弹出窗口的情况下,应用程序或客户端可以使用ApplicationInterface::createNotification()来创建这些。然后通过NotificationManager在系统 UI 上提供这些通知。

下面的代码片段是桌面系统 UI 示例的一部分,展示了如何显示弹出窗口。

    // System UI for a notification
    Text {
        z: 9999
        font.pixelSize: 46
        anchors.centerIn: parent
        text: NotificationManager.count > 0 ? NotificationManager.get(0).summary : ""
    }

意图

系统 UI 和其他应用程序可以通过IntentObjectIntentServer QML类型发送和接收意图。意图代表系统 UI 上的单个意图定义;该IntentServer是系统 UI 侧表示意图子系统的单例。

有关实现对意图支持的更多详细信息,请参见意图系统 UI 和应用程序示例

生命周期

ApplicationManager提供了启动和停止应用程序的API。然而,建议使用ApplicationObject::start()和ApplicationObject::stop()。可选的,你还可以在start()函数中传递documentUrl。然后,当你多次调用start()时,每次使用不同的documentUrl(),你不会重新启动应用程序;只是触发应用程序或客户端侧的ApplicationInterface::openDocument()。调用ApplicationObject::stop()会在应用程序侧触发ApplicationInterface::quit()。应用程序应该完成所有必要的清理,然后确认它可以被终止,可以通过ApplicationInterface::acknowledgeQuit()完成。

你可以实现其他生命周期管理功能,这些功能针对特定的IPC机制的要求进行定制,如窗口属性、ApplicationInterfaceExtension或专有IPC。

有关更多信息,请参见桌面系统 UI 示例

监控

要监控你的应用程序,你可以使用MonitorModel从各种来源以一定的时间间隔获取数据,并存储这些值的记录。你可以使用这些数据进行分析,如绘制历史值随时间的变化图表。更多信息,请参见显示应用程序进程信息的示例

应用程序安装程序

ApplicationManager提供ApplicationModel中所有可用应用列表。除了与系统UI捆绑的应用和系统应用外,ApplicationManager还提供了一种在运行时安装新应用的方法。这些应用由ApplicationInstaller单例维护。

要开始安装,请使用ApplicationInstaller::startPackageInstallation。一旦提取了应用包的所有元数据,就会发出ApplicationInstaller::taskRequestingInstallationAcknowledge信号。可以使用该信号获取有关包的更多信息,例如名称、大小或权限。此安装需要使用ApplicationInstaller::acknowledgePackageInstallation来确认。安装完成后,您可以像在生命周期中描述的那样启动新应用。要删除已安装的应用,请使用ApplicationInstaller::removePackage

有关更多信息,请参阅应用安装程序

编写系统UI时的最佳实践

以下是在您编写系统UI时应考虑的一些关键实践

  • 始终尽早在目标设备上测试您的系统UI及其应用。 这非常有用,因为您的目标硬件与异步Wayland协议的组合可能会对系统的一些部分产生一些时间限制。例如,在应用启动后,窗口属性何时可供系统UI使用。这些限制最好尽早确定。为了让UI流畅运行,系统UI以及应用(或Wayland客户端)都需要硬件加速。这种流畅性是通过硬件特定的纹理共享机制实现的。现在,这些机制是针对硬件特定的,可能与您的开发机器相比,在目标平台上使用不同的机制。尽早在目标硬件上进行测试可以帮助识别共享机制中的任何问题或其他图形密集型元素(如着色效果或3D引擎集成)的副作用。
  • 允许系统UI停止占用过多内存或CPU的应用。 设计系统时,使其能够在必要时停止应用,特别是在内存或CPU等硬件资源较低的情况下。这可以提供更好的扩展性。
  • 始终使用两个不同的插件文件夹。 一个用于特定于系统UI或受保护的应用。另一个文件夹用于包含基元素的其他应用,例如您的UI样式或不同窗口类型的项目。

关于根元素

  • 如果系统UI的根元素是Item,应用程序管理器将为此创建一个QQuickWindow并将其作为其根Item设置。
  • 如果系统UI的根元素是Window—或一个被Window包裹的Item—无论其可见属性值如何,窗口将首先显示。

©2019 Luxoft Sweden AB。本文件中包含的文档贡献均为各自所有者的版权归属。本文件中提供的文档遵循由自由软件基金会发布的GNU自由文档许可的第1.3版条款。Qt及其相关标志是芬兰Qt Company Ltd.及其在世界范围内的商标。所有其他商标均为各自所有者的财产。