QtShell 컴포저
QtShell Compositor는 QtShell 셸 확장을 사용하는 방법을 보여줍니다.
QtShell 컴포저는 QtShell 이라는 특수 셸 확장 프로토콜을 사용하는 완전한 Qt Wayland Compositor 을 구현하는 데스크톱 스타일의 웨이랜드 컴포저 예제입니다.
컴포저는 Qt Quick 및 QML로 구현됩니다.
연결하기
이 예시에서는 WaylandCompositor 객체에 대한 유일한 확장으로 QtShell 을 나열합니다. 즉, 서버에 연결하는 모든 클라이언트는 이 확장도 지원해야 하므로 컴포지터와 동일한 버전의 Qt로 실행되는 Qt 응용 프로그램이어야 합니다.
QtShell { onQtShellSurfaceCreated: (qtShellSurface) => screen.handleShellSurface(qtShellSurface) }
클라이언트가 QtShell 인터페이스에 연결하면 QtShellSurface 을 생성하고 컴포저는 qtShellSurfaceCreated 신호의 방출을 통해 이를 알립니다. 그런 다음 이 예제에서는 나중에 쉽게 액세스할 수 있도록 ListModel 에 셸 표면을 추가합니다.
property ListModel shellSurfaces: ListModel {} function handleShellSurface(shellSurface) { shellSurfaces.append({shellSurface: shellSurface}); }
ListModel 은 화면에 클라이언트 콘텐츠를 표시하는 데 필요한 Qt Quick 항목을 생성하는 Repeater 의 모델로 사용됩니다.
Repeater { id: chromeRepeater model: output.shellSurfaces // Chrome displays a shell surface on the screen (See Chrome.qml) Chrome { shellSurface: modelData onClientDestroyed: { output.shellSurfaces.remove(index) } } }
창 상태와 장식을 처리하는 로컬 Chrome
유형을 사용합니다.
Chrome
Chrome
유형은 클라이언트 콘텐츠를 표시하고 창 상태, 위치, 크기 등을 처리하는 유형입니다. 기본으로 제공되는 QtShellChrome 유형은 창 상태(최대화, 최소화, 전체 화면) 및 창 활성화(한 번에 하나의 창만 활성화되도록 함)를 자동으로 처리하는 기본값을 사용합니다.
이 동작은 어느 정도 사용자 정의할 수 있지만, 기본 Item 유형 대신 처음부터 Chrome
기능을 작성할 수도 있습니다. QtShellChrome 는 일반적인 컴포저 동작을 제공하는 편의 클래스이며, 예제에서 이 로직을 구현하는 시간을 절약할 수 있습니다.
Chrome
을 작성하더라도 클라이언트 콘텐츠를 보관할 ShellSurfaceItem 이 있어야 합니다.
ShellSurfaceItem { id: shellSurfaceItemId anchors.top: titleBar.bottom anchors.bottom: bottomResizeHandle.top anchors.left: leftResizeHandle.right anchors.right: rightResizeHandle.left moveItem: chrome staysOnBottom: shellSurface.windowFlags & Qt.WindowStaysOnBottomHint staysOnTop: !staysOnBottom && shellSurface.windowFlags & Qt.WindowStaysOnTopHint } shellSurfaceItem: shellSurfaceItemId
ShellSurfaceItem 은 Qt Quick 장면에서 클라이언트 콘텐츠의 시각적 표현입니다. 일반적으로 클라이언트 버퍼의 크기와 일치해야 하며, 그렇지 않으면 늘어나거나 눌려 보일 수 있습니다. QtShellChrome 의 크기는 자동으로 클라이언트 버퍼의 크기와 프레임 여백의 크기인 QtShellSurface 의 windowGeometry 로 조정됩니다. 프레임 여백은 Chrome
의 측면에 있는 예약된 영역으로 창 장식을 포함하는 데 사용할 수 있습니다.
따라서 ShellSurfaceItem 은 클라이언트 버퍼를 위해 예약된 영역을 채우기 위해 창 장식에 고정됩니다.
창 장식
창 장식은 일반적으로 클라이언트 콘텐츠 주위에 정보(예: 창 제목)와 사용자 상호 작용 가능성(예: 창 크기 조정, 닫기, 이동 등)을 추가하는 프레임입니다.
QtShell 를 사용하면 창 장식은 항상 클라이언트가 아닌 컴포저에 의해 그려집니다. 크기와 위치가 올바르게 전달되려면 QtShell 에서도 이러한 장식을 위해 창이 얼마나 예약되어 있는지 알아야 합니다. 이는 QtShellChrome 에서 자동으로 처리하거나 frameMarginLeft, frameMarginRight, frameMarginTop 및 frameMarginBottom 를 설정하여 수동으로 처리할 수 있습니다.
창 주위에 크기 조정 핸들이 있고 상단에 제목 표시줄이 있는 일반적인 경우에는 기본 프레임 여백을 사용하는 것이 더 편리합니다. QtShell 컴포저 예시가 이를 보여줍니다.
먼저 창 장식의 여러 부분을 나타내는 Qt Quick 항목을 만듭니다. 예를 들어 왼쪽에는 사용자가 창 크기를 조정하기 위해 잡고 드래그할 수 있는 크기 조정 핸들이 있어야 합니다.
Rectangle { id: leftResizeHandle color: "gray" width: visible ? 5 : 0 anchors.topMargin: 5 anchors.bottomMargin: 5 anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom }
예제에서는 이 핸들을 5픽셀 너비의 직사각형으로 만들어 Chrome
의 상단, 하단 및 왼쪽에 고정했습니다.
마찬가지로 오른쪽, 위, 아래, 왼쪽 위, 오른쪽 위, 왼쪽 아래 및 오른쪽 아래 크기 조정 핸들을 나타내는 Qt Quick 항목을 추가합니다. 제목 표시줄도 추가합니다. 장식이 만들어지고 Chrome
의 측면에 올바르게 고정되면 QtShellChrome 에서 해당 속성을 설정합니다.
leftResizeHandle: leftResizeHandle rightResizeHandle: rightResizeHandle topResizeHandle: topResizeHandle bottomResizeHandle: bottomResizeHandle bottomLeftResizeHandle: bottomLeftResizeHandle bottomRightResizeHandle: bottomRightResizeHandle topLeftResizeHandle: topLeftResizeHandle topRightResizeHandle: topRightResizeHandle titleBar: titleBar
장식 속성이 설정되면 기본 크기 조정 및 위치 변경 동작이 자동으로 추가됩니다. 사용자는 크기 조정 핸들과 상호 작용하여 창 크기를 조정하고 제목 표시줄을 드래그하여 위치를 변경할 수 있습니다. QtShellSurface 의 프레임 여백도 장식의 크기를 고려하여 자동으로 설정됩니다(프레임 여백 속성을 명시적으로 설정하지 않은 경우).
장식의 가시성은 QtShellSurface 의 창 플래그에 따라 QtShellChrome 에 의해 자동으로 처리됩니다.
창 관리
장식의 일부로 창 상태와 수명을 관리하는 도구 버튼이 있는 것이 일반적입니다. 이 예에서는 이러한 버튼이 제목 표시줄에 추가되었습니다.
RowLayout { id: rowLayout anchors.right: parent.right anchors.rightMargin: 5 ToolButton { text: "-" Layout.margins: 5 visible: (chrome.windowFlags & Qt.WindowMinimizeButtonHint) != 0 onClicked: { chrome.toggleMinimized() } } ToolButton { text: "+" Layout.margins: 5 visible: (chrome.windowFlags & Qt.WindowMaximizeButtonHint) != 0 onClicked: { chrome.toggleMaximized() } } ToolButton { id: xButton text: "X" Layout.margins: 5 visible: (chrome.windowFlags & Qt.WindowCloseButtonHint) != 0 onClicked: shellSurface.sendClose() } }
각 버튼의 표시 여부는 해당 버튼의 창 플래그에 따라 조건부로 결정되며, 각 버튼을 클릭하면 QtShellChrome 에서 해당 메서드를 호출하기만 하면 됩니다. 예외는 "닫기" 버튼으로, QtShellSurface 에서 sendClose() 메서드를 호출합니다. 이렇게 하면 클라이언트가 스스로 닫히도록 지시하고 애플리케이션이 정상적으로 종료됩니다.
Row { id: taskbar height: 40 anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom Repeater { anchors.fill: parent model: output.shellSurfaces ToolButton { anchors.verticalCenter: parent.verticalCenter text: modelData.windowTitle onClicked: { var item = chromeRepeater.itemAt(index) if ((item.windowState & Qt.WindowMinimized) != 0) item.toggleMinimized() chromeRepeater.itemAt(index).activate() } } } }
추가 창 관리 도구로 이 예시에는 "작업 표시줄"이 있습니다. 이것은 창 제목과 함께 하단에 있는 도구 버튼의 행입니다. 이 버튼을 클릭하면 애플리케이션을 최소화하고 다른 창에 가려진 경우 애플리케이션을 전면으로 가져올 수 있습니다. Chrome
과 유사하게 Repeater 을 사용하여 도구 버튼을 만들고 셸 표면 목록을 모델로 사용합니다. 단순화를 위해 이 예제에서는 오버플로(작업 표시줄에 너무 많은 애플리케이션이 있는 경우) 처리를 하지 않았지만, 적절한 컴포저에서는 이 또한 고려해야 할 사항입니다.
마지막으로, 작업 표시줄의 영역을 채우기 위해 최대화된 애플리케이션이 확장되는 것을 방지하기 위해 클라이언트 창에서 사용할 수 있는 WaylandOutput 부동산의 일부를 관리하는 특수 항목을 만듭니다.
Item { id: usableArea anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right anchors.bottom: taskbar.top }
이 항목은 WaylandOutput 의 측면에 고정되어 있지만 하단 앵커는 작업 표시줄 상단에 있습니다.
Chrome
에서는 이 영역을 사용하여 창의 maximizedRect 을 정의합니다.
maximizedRect: Qt.rect(usableArea.x, usableArea.y, usableArea.width, usableArea.height)
기본적으로 이 속성은 전체 WaylandOutput 와 일치합니다. 그러나 우리의 경우에는 사용 가능한 영역에 작업 표시줄을 포함하고 싶지 않으므로 기본값을 재정의합니다.
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.