Документация
ОС Аврора 5.2.1

Управление ориентациями контента приложения и интерфейса ОС

Содержание:

Экран заставки (SplashScreen)

Когда приложение работает в какой-либо исключительной ориентации (только в альбомной или только в портретной), можно заранее подготовить Домашний экран пользователя, повернув интерфейс в нужную сторону до запуска приложения. Поворот интерфейса Домашнего экрана произойдёт при нажатии на иконку приложения в момент появления экрана заставки приложения. Это также позволяет отобразить экранную заставку в правильной ориентации, а затем осуществить плавный переход в окно приложения без лишних поворотов интерфейса.

Такое поведение определяется группой полей в секции X-Aurora-Application:

  • SmallScreenOrientation - для устройств с категорией Silica.Screen.sizeCategory == Silica.Screen.Small.
  • MediumScreenOrientation - для устройств с категорией Silica.Screen.sizeCategory == Silica.Screen.Medium.
  • LargeScreenOrientation - для устройств с категорией Silica.Screen.sizeCategory == Silica.Screen.Large.
  • ExtraLargeScreenOrientation - для устройств с категорией Silica.Screen.sizeCategory == Silica.Screen.ExtraLarge.
  • Orientation - для устройств любой категории, но может быть переопределено другим полем из списка выше.

Значения, принимаемые в данных полях: Portrait, Landscape, PortraitInverted, LandscapeInverted, PortraitMask, LandscapeMask, All.

Каждое поле может принимать либо одну конкретную ориентацию из предложенного списка, либо список возможных значений, задаваемый через символ ; (точка с запятой).

Пример для приложения, которое может работать во всех ориентациях, но на устройствах с маленьким дисплеем - только в портрете:

[X-Aurora-Application]
Orientation=All
SmallScreenOrientation=Portrait

Пример для приложения, которое может работать только в неинвертированных ориентациях:

[X-Aurora-Application]
Orientation=Portrait;Landscape

Выбор ориентации осуществляется по следующему алгоритму:

  1. Сначала перебираются все возможные варианты ориентации из поля Orientation, каждое значение сравнивается с текущей ориентацией Домашнего экрана. В случае совпадения двух значений выбирается текущая ориентация Домашнего экрана. Если не совпало ни одно из значений, то выбирается первая ориентация из списка. Например, Домашний экран находится в инвертированной ландшафтной ориентации, в таком случае для списка: Orientation=Portrait;Landscape будет выбрана ориентация Portrait.
  2. Затем перебираются все возможные варианты ориентации из поля, соответствующего категории устройства, каждое значение сравнивается с выбранной ориентацией на первом шаге. В случае совпадения двух значений сохраняется ранее выбранная ориентация. В случае несовпадения ни одного из значений выбирается первая ориентация из списка.
  3. Если итоговая ориентация совпадает с текущей ориентацией Домашнего экрана, то поворота интерфейса не произойдёт, в противном случае интерфейс будет повёрнут в выбранную ориентацию.

Управление ориентацией приложения

В ОС Аврора поддерживаются несколько способов управления ориентацией контента приложения.

Способ управления ориентацией задаётся в файле .desktop посредством поля OrientationBehavior в секции [X-Aurora-Capabilities]. Это поле определяет способ взаимодействия приложения с композитором для управления ориентацией содержимого.

Принимаемые значения OrientationBehavior:

  • Default - Стандартный. Используется по умолчанию при отсутствии поля.
  • OnDemand - Принудительный или "По требованию".
  • Lazy - "Ленивый" режим.

Выбор режима влияет на то, кто выполняет поворот контента (приложение или композитор), на размер окна и на обязательность указания допустимых ориентаций в файле .desktop.

На низком уровне выбранный режим поворота определяет значения, передаваемые композитором в событии configure используемого shell-интерфейса.

Режим Default подразумевает, что приложение самостоятельно выполняет поворот контента относительно базовой ориентации, определяемой физическими размерами экрана. В связи с этим для полноэкранного окна композитор всегда отправляет событие configure, соответствующее нативной геометрии экрана.

Режимы OnDemand и Lazy предполагают, что приложение не выполняет самостоятельный поворот контента, а лишь размещает его в доступной области отображения. В данных режимах композитор отправляет событие configure, соответствующее заявленной приложением поддерживаемой ориентации.

В режиме Lazy необходимо обязательно заполнить поля *Orientation (либо общее поле Orientation) в секции [X-Aurora-Application].

Режим Default - Стандартный (Wayland API)

[X-Aurora-Capabilities]
OrientationBehavior=Default

Режим Default соответствует требованиям спецификации Wayland: приложение самостоятельно поворачивает контент и уведомляет композитор о применённой трансформации. Режим основан на взаимодействии клиента с композитором через следующие события и запросы:

  • wl_output::transform - событие композитора, уведомляющее клиентское приложение о текущей пространственной трансформации (повороте) выходного устройства (дисплея или монитора) относительно его «базовой» («родной») ориентации.

Базовая ориентация - это физическая, аппаратно-заданная ориентация выходного устройства, относительно которой измеряются все повороты. Для большинства дисплеев базовой считается ориентация, при которой изображение отображается «правильно» без поворота (например, когда верх экрана совпадает с физическим верхом устройства). Однако на мобильных устройствах базовая ориентация может определяться производителем (часто это портретная ориентация для смартфонов).

Событие передаёт клиенту абсолютное значение трансформации, т.е. текущий поворот вывода в координатах выходного пространства и информирует клиента о том, как композитор ожидает видеть отображаемый контент, чтобы он соответствовал физической ориентации экрана. Однако сам клиент не обязан применять эту трансформацию к своему контенту - это его выбор. Но если клиент хочет корректно отображать свой интерфейс без искажений, он должен учитывать эту трансформацию при рендеринге.

  • wl_surface::preferred_buffer_transform - событие композитора, указывающее рекомендуемую трансформацию, которую клиент должен применить к контенту, чтобы оптимизировать производительность или качество (например, чтобы избежать дополнительного поворота на стороне композитора). Это событие учитывает текущую трансформацию вывода и внутренние возможности композитора. Клиент может, но не обязан, следовать этой рекомендации; если он применит именно её, композитор сможет вывести полученный контент без дополнительных преобразований.

  • wl_surface::set_buffer_transform - запрос от клиента к композитору, сообщающий композитору, что содержимое буфера (контент), который клиент прикрепляет к своей поверхности (wl_surface), уже повёрнуто клиентом.

В большинстве случаев низкоуровневое взаимодействие инкапсулировано в API используемого фреймворка или библиотеки (Silica, Qt), поэтому разработчику приложения нет необходимости обращаться к указанным вызовам напрямую.

Поведение приложения

  • Приложение самостоятельно выполняет поворот буфера (контента) относительно начальной (базовой) ориентации экрана.

  • После поворота буфера приложение отправляет композитору запрос wl_surface::set_buffer_transform с указанием применённой трансформации.

Поведение композитора

  • Устанавливает размер окна, соответствующий полноэкранному режиму в нативной ориентации (т.е. ориентации, заданной аппаратно).

  • При необходимости поворачивает собственный интерфейс (например: статусбар, панель управления громкостью) в соответствии с запрошенной трансформацией.

Поля X-Aurora-Application/Orientation

Поля X-Aurora-Application/*Orientation необязательны, но настоятельно рекомендуются. Указанные значения используются для отображения экрана-заставки (splashscreen) в той же ориентации, в которой приложение создаст свой контент после запуска. Это позволяет избежать видимого поворота в момент старта.

Подробнее о данных полях можно узнать на странице.

Библиотека компонентов Silica

Управление ориентациями контента приложения и интерфейса ОС реализуется через свойства компонентов ApplicationWindow и Page. Применение необходимых трансформаций к отображаемому контенту выполняется автоматически на уровне библиотеки, что избавляет разработчика от необходимости выполнять явный поворот элементов пользовательского интерфейса вручную.

  1. Свойство allowedOrientations

Доступно как у ApplicationWindow, так и у Page. Оно определяет, какие ориентации разрешены для данного окна или страницы.

На уровне ApplicationWindow: Задаёт допустимые ориентации для всего приложения.

На уровне Page: Позволяет гибко управлять ориентацией для каждой отдельной страницы. Например, страница просмотра видео может разрешать альбомную ориентацию, а страница ввода текста - только портретную.

  1. Свойство orientation

Доступно только для чтения у ApplicationWindow и содержит ориентацию интерфейса текущей активной страницы Page.

Доступно как для чтения (в случае использования allowedOrientations), так и для записи у Page и определяет текущую ориентацию страницы Page.

Пример для Silica

# ru.auroraos.example.desktop

[X-Aurora-Capabilities]
OrientationBehavior=Default

[X-Aurora-Application]
# Подсказка композитору об ориентации стартовой страницы 
# для корректного отображения сплешскрина
Orientation=Portrait
// ru.auroraos.example.qml

import QtQuick 2.6
import Sailfish.Silica 1.0

ApplicationWindow {
    initialPage: Component {
        id: portraitPageComponent

        Page {
            allowedOrientations: Orientation.Portrait
            Button {
                anchors.centerIn: parent
                text: "В ландашфт"
                onClicked: pageStack.push(landscapePageComponent)
            }
        }
    }

    Component {
        id: landscapePageComponent

        Page {
            allowedOrientations: Orientation.Landscape
            Button {
                anchors.centerIn: parent
                text: "Назад в портрет"
                onClicked: pageStack.pop()
            }
        }
    }
}

Фреймворк Qt

Управление ориентациями контента приложения и интерфейса ОС реализуется через свойство contentOrientation компонента Window (при использовании базового модуля Qt Quick) либо через аналогичное свойство компонента ApplicationWindow, наследующего Window (при использовании модуля Qt Quick Controls).

Применение необходимых трансформаций к отображаемому контенту выполняется вручную, например, посредством свойства rotation, доступного в компоненте Item.

Доступ к текущей и базовой ориентациям экрана обеспечивается через свойства orientation и primaryOrientation прикрепляемого объекта Screen соответственно. При этом свойство Screen.orientation обновляется только при условии, что для Screen.orientationUpdateMask установлено значение, отличное от нуля. Screen.orientationUpdateMask имеет тип Qt::ScreenOrientations и содержит маску ориентаций, для которых разрешено обновление свойства Screen.orientation. Событие изменения Screen.orientation инициируется только для тех ориентаций экрана, которые соответствуют данной маске.

Пример для Qt

# ru.auroraos.example.desktop

[X-Aurora-Capabilities]
OrientationBehavior=Default

[X-Aurora-Application]
# Подсказка композитору о поддерживаемых приложением ориентациях 
# для корректного отображения сплешскрина
Orientation=Portrait;Landscape
// ru.auroraos.example.qml 

import QtQuick 2.6
import QtQuick.Window 2.3

Window {
    id: window

    // Разрешает приложению работать только в неинвертированных ориентациях:
    // ландшафтной и портретной.
    Screen.orientationUpdateMask: Qt.LandscapeOrientation | Qt.PortraitOrientation

    // Сообщает композитору о текущей ориентации приложения.
    contentOrientation: Screen.orientation

    Text {
        anchors.horizontalCenter: parent.horizontalCenter
        text: "Нативный верх"
    }

    Item {
        // Поворачивает контент приложения.
        anchors.centerIn: parent
        rotation: Screen.angleBetween(window.contentOrientation, Screen.primaryOrientation)
        width: rotation % 180 === 0 ? parent.width : parent.height
        height: rotation % 180 === 0 ? parent.height : parent.width

        // Полезный контент приложения.
        Rectangle {
            anchors.fill: parent
            anchors.margins: Screen.pixelDensity * 5
            border.color: "green"
            color: "transparent"

            Text {
                anchors.horizontalCenter: parent.horizontalCenter
                text: "Контентный верх"
            }

            Column {
                anchors.centerIn: parent
                Text {
                    anchors.horizontalCenter: parent.horizontalCenter
                    text: "Текущая ориентация:"
                }
                Text {
                    anchors.horizontalCenter: parent.horizontalCenter
                    text: {
                        switch (window.contentOrientation) {
                        case Qt.LandscapeOrientation: return "Ландшафт"
                        case Qt.PortraitOrientation: return "Портрет"
                        default: return "Неизвестно"
                        }
                    }
                }
            }
        }
    }
}

OnDemand - Принудительный режим или "По требованию"

[X-Aurora-Capabilities]
OrientationBehavior=OnDemand

Упрощённый режим, при котором приложение не выполняет фактического поворота контента, а лишь сообщает композитору желаемую трансформацию. Композитор самостоятельно применяет эту трансформацию к содержимому окна.

Данный подход целесообразен в ситуациях, когда разработчик лишён возможности выполнять поворот контента собственными средствами, но располагает высокоуровневыми абстракциями для вызова wl_surface::set_buffer_transform.

Поведение приложения

  • Приложение отправляет композитору запрос wl_surface::set_buffer_transform с указанием желаемой трансформации контента, но само приложние не выполняет никаких дополнительных преобразований (например, через rotation).

Поведение композитора

  • Применяет запрошенную трансформацию к выводимому контенту и изменяет размер окна в соответствии применённым поворотом экрана.

  • При необходимости поворачивает собственный интерфейс (например: статусбар, панель управления громкостью) в соответствии с запрошенной трансформацией.

Поля X-Aurora-Application/Orientation

Поля X-Aurora-Application/*Orientation необязательны, но рекомендуются для корректного отображения экрана-заставки в требуемой ориентации до момента запуска приложения.

Пример для Qt Widgets

Приложение на Qt Widgets с ландшафтной ориентацией.

# ru.auroraos.example.desktop

[X-Aurora-Capabilities]
OrientationBehavior=OnDemand

[X-Aurora-Application]
# Подсказка композитору о том, что приложение работает только в ландшафтном режиме.
# Рекомендуется использовать для корректного отображения сплешскрина.
Orientation=Landscape
// main.cpp

#include <QApplication>
#include <QLabel>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QWindow>

class LandscapeWindow : public QMainWindow
{
public:
    explicit LandscapeWindow(QWidget *parent = nullptr) 
        : QMainWindow(parent)
    {
        setCentralWidget(new QWidget(this));

        QLabel *label = new QLabel("Привет, мир!!!", centralWidget());
        label->setAlignment(Qt::AlignCenter);

        QVBoxLayout *layout = new QVBoxLayout(centralWidget());
        layout->addStretch();
        layout->addWidget(label, 0, Qt::AlignCenter);
        layout->addStretch();
    }

protected:
    bool event(QEvent *event) override
    {
        if (event->type() == QEvent::WinIdChange) {
            if (QWindow *window = windowHandle()) {
                // Информирование композитора о желаемой трансформации контента
                // в момент появления QWindow у QWidget.
                window->reportContentOrientationChange(Qt::LandscapeOrientation);
            }
        }
        return QMainWindow::event(event);
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    LandscapeWindow window;
    window.show();

    return app.exec();
}

Lazy - "Ленивый" режим

[X-Aurora-Capabilities]
OrientationBehavior=Lazy

[X-Aurora-Application]
# Обязательное поле. 
# Задаёт допустимые ориентации приложения для композитора.
# При изменении ориентации устройства композитор выбирает подходящую ориентацию 
# из указанного списка.
Orientation=*Перечисление допустимых ориентаций через точку с запятой*

Данный режим предполагает, что приложение не использует API wl_surface::set_buffer_transform для управления ориентацией контента, соответствующие преобразования выполняются композитором.

Указание допустимых ориентаций в этом случае осуществляется исключительно в файле .desktop.

Такой подход существенно упрощает разработку, так как освобождает разработчика от необходимости реализации поворота контента в приложении или взаимодействия с Wayland API.

Поведение приложения

  • Приложение не использует wl_surface::set_buffer_transform и не выполняет поворота содержимого. Все необходимые трансформации делегируются композитору.

Поведение композитора

  • Выбирает и применяет трансформацию к содержимому окна на основе информации, указанной в полях X-Aurora-Application/*Orientation файла .desktop.

  • Размер окна устанавливается в соответствии с доступной областью рисования, которая определяется выбранной ориентацией.

  • При необходимости поворачивает собственный интерфейс (например: статусбар, панель управления громкостью) в соответствии с запрошенной трансформацией.

Поля X-Aurora-Application/Orientation

Поля X-Aurora-Application/*Orientation обязательны к указанию. Эти поля определяют допустимые ориентации, в которых композитор будет отображать приложение. Если значения не заданы, композитор выберет ориентацию автоматически на основе текущего окружения, что может привести к непредсказуемому поведению или несоответствию ожиданиям разработчика.

Пример для SDL2

Приложение на SDL2 с ландшафтной ориентацией.

# ru.auroraos.example.desktop

[X-Aurora-Capabilities]
OrientationBehavior=Lazy

[X-Aurora-Application]
# Подсказка композитору о том, что приложение работает только в ландшафтном режиме.
# Обязательно использовать для корректного отображения окна приложения.
Orientation=Landscape
// main.c

#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
    SDL_Init(SDL_INIT_VIDEO);
    TTF_Init();

    // Создаём окно с возможностью изменения размера установкой флага SDL_WINDOW_RESIZABLE
    SDL_Window *window = SDL_CreateWindow(
        "Landskape SDL2",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        100, 100,
        SDL_WINDOW_RESIZABLE | SDL_WINDOW_SHOWN
    );


    SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

    TTF_Font *font = TTF_OpenFont("/usr/share/fonts/dejavu/DejaVuSans.ttf", 32);
    if (!font) {
        printf("Ошибка загрузки шрифта: %s\n", TTF_GetError());
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
        TTF_Quit();
        SDL_Quit();
        return 1;
    }

    SDL_Color textColor = { 255, 255, 255, 255 };
    SDL_Surface *textSurface = TTF_RenderUTF8_Blended(font, "Пример, мир!", textColor);
    SDL_Texture *textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);

    int textWidth = textSurface->w;
    int textHeight = textSurface->h;

    SDL_FreeSurface(textSurface);

    SDL_Event event;
    int running = 1;

    while (running) {
        while (SDL_PollEvent(&event)) {
            switch (event.type) {
            case SDL_QUIT:
                running = 0;
                break;
            }
        }

        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);

        int winWidth, winHeight;
        SDL_GetWindowSize(window, &winWidth, &winHeight);

        SDL_Rect fontRect = {
            (winWidth - textWidth) / 2,
            (winHeight - textHeight) / 2,
            textWidth,
            textHeight
        };

        SDL_RenderCopy(renderer, textTexture, NULL, &fontRect);
        SDL_RenderPresent(renderer);
        SDL_Delay(100);
    }

    SDL_DestroyTexture(textTexture);
    TTF_CloseFont(font);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    TTF_Quit();
    SDL_Quit();

    return 0;
}

Мы используем cookies для персонализации сайта и его более удобного использования. Вы можете запретить cookies в настройках браузера.

Пожалуйста ознакомьтесь с политикой использования файлов cookies.