Mir

Merge lp:~alan-griffiths/mir/move-miral-to-mir into lp:mir

Proposed by Alan Griffiths on 2017-08-23
Status: Merged
Approved by: Gerry Boland on 2017-08-30
Approved revision: 4250
Merged at revision: 4235
Proposed branch: lp:~alan-griffiths/mir/move-miral-to-mir
Merge into: lp:mir
Diff against target: 18088 lines (+17392/-3)
127 files modified
CMakeLists.txt (+0/-2)
cmake/FindPIL.cmake (+8/-0)
debian/changelog (+4/-1)
debian/control (+51/-0)
debian/libmiral-dev.install (+3/-0)
debian/libmiral2.install (+1/-0)
debian/libmiral2.symbols (+399/-0)
debian/libmirclientcpp-dev.install (+2/-0)
debian/miral-examples.install (+9/-0)
examples/CMakeLists.txt (+3/-0)
examples/miral-kiosk/CMakeLists.txt (+12/-0)
examples/miral-kiosk/kiosk_main.cpp (+94/-0)
examples/miral-kiosk/kiosk_window_manager.cpp (+148/-0)
examples/miral-kiosk/kiosk_window_manager.h (+52/-0)
examples/miral-kiosk/sw_splash.cpp (+173/-0)
examples/miral-kiosk/sw_splash.h (+44/-0)
examples/miral-shell/CMakeLists.txt (+65/-0)
examples/miral-shell/decoration_provider.cpp (+666/-0)
examples/miral-shell/decoration_provider.h (+119/-0)
examples/miral-shell/desktop/CMakeLists.txt (+12/-0)
examples/miral-shell/desktop/miral-shell.desktop.in (+18/-0)
examples/miral-shell/desktop/ubuntu-logo.svg (+27/-0)
examples/miral-shell/floating_window_manager.cpp (+801/-0)
examples/miral-shell/floating_window_manager.h (+146/-0)
examples/miral-shell/miral-app.sh (+51/-0)
examples/miral-shell/miral-desktop.sh (+45/-0)
examples/miral-shell/miral-run.sh (+17/-0)
examples/miral-shell/miral-screencast.sh (+48/-0)
examples/miral-shell/miral-xrun.sh (+45/-0)
examples/miral-shell/shell_main.cpp (+98/-0)
examples/miral-shell/spinner/CMakeLists.txt (+67/-0)
examples/miral-shell/spinner/eglapp.cpp (+83/-0)
examples/miral-shell/spinner/eglapp.h (+33/-0)
examples/miral-shell/spinner/eglspinner.cpp (+372/-0)
examples/miral-shell/spinner/miregl.cpp (+239/-0)
examples/miral-shell/spinner/miregl.h (+67/-0)
examples/miral-shell/spinner/png2header.py (+87/-0)
examples/miral-shell/spinner/splash.h (+45/-0)
examples/miral-shell/tiling_window_manager.cpp (+688/-0)
examples/miral-shell/tiling_window_manager.h (+140/-0)
examples/miral-shell/titlebar_config.cpp (+38/-0)
examples/miral-shell/titlebar_config.h (+30/-0)
include/miral/mir/client/blob.h (+50/-0)
include/miral/mir/client/connection.h (+54/-0)
include/miral/mir/client/cookie.h (+50/-0)
include/miral/mir/client/display_config.h (+78/-0)
include/miral/mir/client/surface.h (+50/-0)
include/miral/mir/client/window.h (+53/-0)
include/miral/mir/client/window_id.h (+48/-0)
include/miral/mir/client/window_spec.h (+253/-0)
include/miral/miral/active_outputs.h (+74/-0)
include/miral/miral/add_init_callback.h (+47/-0)
include/miral/miral/append_event_filter.h (+44/-0)
include/miral/miral/application.h (+42/-0)
include/miral/miral/application_authorizer.h (+103/-0)
include/miral/miral/application_info.h (+55/-0)
include/miral/miral/canonical_window_manager.h (+59/-0)
include/miral/miral/command_line_option.h (+109/-0)
include/miral/miral/cursor_theme.h (+44/-0)
include/miral/miral/debug_extension.h (+47/-0)
include/miral/miral/display_configuration_option.h (+30/-0)
include/miral/miral/internal_client.h (+88/-0)
include/miral/miral/keymap.h (+58/-0)
include/miral/miral/output.h (+113/-0)
include/miral/miral/runner.h (+74/-0)
include/miral/miral/set_command_line_handler.h (+50/-0)
include/miral/miral/set_terminator.h (+47/-0)
include/miral/miral/set_window_management_policy.h (+55/-0)
include/miral/miral/version.h (+67/-0)
include/miral/miral/window.h (+82/-0)
include/miral/miral/window_info.h (+130/-0)
include/miral/miral/window_management_options.h (+65/-0)
include/miral/miral/window_management_policy.h (+194/-0)
include/miral/miral/window_management_policy_addendum2.h (+70/-0)
include/miral/miral/window_management_policy_addendum3.h (+68/-0)
include/miral/miral/window_manager_tools.h (+254/-0)
include/miral/miral/window_specification.h (+134/-0)
include/miral/miral/workspace_policy.h (+88/-0)
src/CMakeLists.txt (+1/-0)
src/miral/CMakeLists.txt (+140/-0)
src/miral/active_outputs.cpp (+65/-0)
src/miral/add_init_callback.cpp (+33/-0)
src/miral/append_event_filter.cpp (+48/-0)
src/miral/application.cpp (+51/-0)
src/miral/application_authorizer.cpp (+129/-0)
src/miral/application_info.cpp (+99/-0)
src/miral/basic_window_manager.cpp (+2234/-0)
src/miral/basic_window_manager.h (+272/-0)
src/miral/both_versions.h (+33/-0)
src/miral/canonical_window_manager.cpp (+77/-0)
src/miral/command_line_option.cpp (+210/-0)
src/miral/coordinate_translator.cpp (+51/-0)
src/miral/coordinate_translator.h (+52/-0)
src/miral/cursor_theme.cpp (+62/-0)
src/miral/debug_extension.cpp (+51/-0)
src/miral/display_configuration_listeners.cpp (+120/-0)
src/miral/display_configuration_listeners.h (+67/-0)
src/miral/display_configuration_option.cpp (+115/-0)
src/miral/internal_client.cpp (+215/-0)
src/miral/join_client_threads.h (+24/-0)
src/miral/keymap.cpp (+173/-0)
src/miral/miral.pc.in (+9/-0)
src/miral/mirclientcpp.pc.in (+7/-0)
src/miral/mru_window_list.cpp (+65/-0)
src/miral/mru_window_list.h (+46/-0)
src/miral/output.cpp (+117/-0)
src/miral/runner.cpp (+278/-0)
src/miral/set_command_line_handler.cpp (+33/-0)
src/miral/set_terminator.cpp (+33/-0)
src/miral/set_window_management_policy.cpp (+91/-0)
src/miral/symbols.map (+438/-0)
src/miral/version.h.in (+67/-0)
src/miral/window.cpp (+127/-0)
src/miral/window_info.cpp (+594/-0)
src/miral/window_management_options.cpp (+99/-0)
src/miral/window_management_policy.cpp (+37/-0)
src/miral/window_management_trace.cpp (+798/-0)
src/miral/window_management_trace.h (+146/-0)
src/miral/window_manager_tools.cpp (+141/-0)
src/miral/window_manager_tools_implementation.h (+108/-0)
src/miral/window_specification.cpp (+587/-0)
src/miral/workspace_policy.cpp (+29/-0)
src/miral/xcursor.c (+899/-0)
src/miral/xcursor.h (+62/-0)
src/miral/xcursor_loader.cpp (+215/-0)
src/miral/xcursor_loader.h (+66/-0)
tools/update_package_abis.sh (+1/-0)
To merge this branch: bzr merge lp:~alan-griffiths/mir/move-miral-to-mir
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration 2017-08-23 Approve on 2017-08-30
Gerry Boland Approve on 2017-08-29
Brandon Schaefer (community) 2017-08-23 Approve on 2017-08-24
Review via email: mp+329455@code.launchpad.net

Commit message

Incorporate miral project into mir source tree - part 1

Description of the change

Incorporate miral project into mir source tree

***
Let me call out that this introduces an epoch to the package version. The need for this is that miral has already reached version 1.4, so it using 1.0 would causes upgrade problems. The alternative to an epoch would be to use a version >> 1.4 (e.g. 1.5).
***

This is a first-cut:

1. It lacks miral-test
2. The utility script for generating the libmiral symbols file hasn't been ported
3. There's no attempt to remove code obsoleted by MirAL

To post a comment you must log in.
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:4248
https://mir-jenkins.ubuntu.com/job/mir-ci/3575/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4898
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5120
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5109
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5109
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5109
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4937
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4937/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4937
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4937/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4937
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4937/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4937
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4937/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4937
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4937/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4937
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4937/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4937
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4937/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4937
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4937/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3575/rebuild

review: Approve (continuous-integration)
Brandon Schaefer (brandontschaefer) wrote :

seems to be working for me, and i do see anything wrong with the debian bits. LGTM

review: Approve
Brandon Schaefer (brandontschaefer) wrote :

dont*

Gerry Boland (gerboland) wrote :

I'm worried about the miral dpkg version numbers. From the old repo, miral is at 1.4.0+stuff. But miral generated from this will be at 1.0.0+stuff here. That will prevent the 'newer' package being installed.

TBH I'm unsure what can be done, we'd need a Debian package expert.

review: Needs Fixing
Gerry Boland (gerboland) wrote :

In miral.pc, the Version: string is missing.

Gerry Boland (gerboland) wrote :

In miral.pc, I think the include dir is also wrong (missing /miral)

Gerry Boland (gerboland) wrote :

Should copyright years be updated?

4249. By Alan Griffiths on 2017-08-29

Add an epoch so that miral packaged with 1.0 will install

Alan Griffiths (alan-griffiths) wrote :

> Should copyright years be updated?

Surely that's only when the text is updated, not when it is copied.

Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4249
https://mir-jenkins.ubuntu.com/job/mir-ci/3595/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4919/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5144
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5133/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5133/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5133/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4958/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4958/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4958/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4958/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4958/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4958/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4958/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4958/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3595/rebuild

review: Needs Fixing (continuous-integration)
4250. By Alan Griffiths on 2017-08-29

Fix miral and mirclientcpp package configs

Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4250
https://mir-jenkins.ubuntu.com/job/mir-ci/3596/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4920/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5145
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5134/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5134/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5134/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4959/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4959/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4959/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4959/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4959/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4959/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4959/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4959/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3596/rebuild

review: Needs Fixing (continuous-integration)
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4250
https://mir-jenkins.ubuntu.com/job/mir-ci/3597/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4921/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5146
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5135/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5135/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5135/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4960/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4960/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4960/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4960/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4960/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4960/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4960/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4960/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3597/rebuild

review: Needs Fixing (continuous-integration)
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4250
https://mir-jenkins.ubuntu.com/job/mir-ci/3598/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4922/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5147
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5137/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5137/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5137/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4961/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4961/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4961/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4961/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4961/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4961/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4961/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4961/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3598/rebuild

review: Needs Fixing (continuous-integration)
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:4250
https://mir-jenkins.ubuntu.com/job/mir-ci/3599/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4923
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5148
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5138
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5138
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5138
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4962
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4962/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4962
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4962/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4962
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4962/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4962
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4962/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4962
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4962/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4962
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4962/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4962
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4962/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4962
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4962/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/3599/rebuild

review: Approve (continuous-integration)
Gerry Boland (gerboland) wrote :

dpkg --compare-versions 1:1.0.0 gt 1.3.0 && echo "yes"
> yes
I'm ok with it, as long as a packaging expert is too.

Alan Griffiths (alan-griffiths) wrote :

> dpkg --compare-versions 1:1.0.0 gt 1.3.0 && echo "yes"
> > yes
> I'm ok with it, as long as a packaging expert is too.

Well, the suggestion to use an "epoch" came from Chris.

Gerry Boland (gerboland) wrote :

The pkgconfig files are fixed too. I think it looks ok.

review: Approve
Mir CI Bot (mir-ci-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2017-08-10 10:25:55 +0000
3+++ CMakeLists.txt 2017-08-29 09:17:20 +0000
4@@ -81,8 +81,6 @@
5 endif()
6
7 # Link time optimization allows leaner, cleaner libraries
8-message(STATUS "CMAKE_C_COMPILER: " ${CMAKE_C_COMPILER})
9-
10 option(MIR_LINK_TIME_OPTIMIZATION "Enables the linker to optimize binaries." OFF)
11 if(MIR_LINK_TIME_OPTIMIZATION)
12 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto -ffat-lto-objects")
13
14=== added file 'cmake/FindPIL.cmake'
15--- cmake/FindPIL.cmake 1970-01-01 00:00:00 +0000
16+++ cmake/FindPIL.cmake 2017-08-29 09:17:20 +0000
17@@ -0,0 +1,8 @@
18+execute_process(
19+ COMMAND python3 -c "from PIL import Image"
20+ RESULT_VARIABLE HAVE_PIL
21+)
22+
23+if (NOT ${HAVE_PIL} EQUAL 0)
24+ message(FATAL_ERROR "Python Imaging Library (PIL) not found")
25+endif()
26
27=== modified file 'debian/changelog'
28--- debian/changelog 2017-08-16 13:52:52 +0000
29+++ debian/changelog 2017-08-29 09:17:20 +0000
30@@ -1,8 +1,9 @@
31-mir (1.0.0-0ubuntu1) UNRELEASED; urgency=medium
32+mir (1:1.0.0-0ubuntu1) UNRELEASED; urgency=medium
33
34 * New upstream release 1.0.0(https://launchpad.net/mir/+milestone/1.0.0)
35 - ABI summary:
36 . mirclient ABI unchanged at 9
37+ . miral ABI introduced at 2
38 . mirserver ABI bumped to 45
39 . mircommon ABI unchanged at 7
40 . mirplatform ABI unchanged at 61
41@@ -15,6 +16,8 @@
42 . Update licences to (L)GPL3 or (L)GPL2.
43 . [mir_demo_client_display_config] add orientation changing
44 . RPC: Don't require the server ACK client's buffer-release requests.
45+ . Added libmirclientcpp to Mir source package
46+ . Added libmiral to Mir source package
47 - Bugs fixed:
48 . Fix handling of invalid display configuration. (LP: #1643446)
49 . Move full responsibility for buffer IPC into frontend. (LP: #1395421)
50
51=== modified file 'debian/control'
52--- debian/control 2017-08-02 13:18:44 +0000
53+++ debian/control 2017-08-29 09:17:20 +0000
54@@ -45,6 +45,7 @@
55 libcapnp-dev,
56 capnproto,
57 libepoxy-dev,
58+ python3-pil:native,
59 Standards-Version: 3.9.4
60 Homepage: https://launchpad.net/mir
61 # If you aren't a member of ~mir-team but need to upload packaging changes,
62@@ -477,3 +478,53 @@
63 .
64 Contains header files that define the interfaces through which platforms and
65 renderers access the functionality needed to render with GL.
66+
67+Package: libmiral2
68+Section: libs
69+Architecture: linux-any
70+Multi-Arch: same
71+Pre-Depends: ${misc:Pre-Depends}
72+Depends: ${misc:Depends},
73+ ${shlibs:Depends},
74+Description: Display server for Ubuntu - ABI preserving abstraction layer
75+ MirAL provides an ABI-stable abstraction layer for Mir based shells,
76+ insulating them from mirserver ABI breaks.
77+ .
78+ Contains the shared library containing MirAL abstraction layer.
79+
80+Package: libmiral-dev
81+Section: libdevel
82+Architecture: linux-any
83+Multi-Arch: same
84+Pre-Depends: ${misc:Pre-Depends}
85+Depends: libmiral2 (= ${binary:Version}),
86+ libmirclientcpp-dev (= ${binary:Version}),
87+ ${misc:Depends},
88+Description: Developer files for the Mir ABI-stable abstraction layer
89+ MirAL provides an ABI-stable abstraction layer for Mir based shells,
90+ insulating them from mirserver ABI breaks.
91+ .
92+ Contains header files required for development using the MirAL abstraction
93+ layer.
94+
95+Package: libmirclientcpp-dev
96+Section: libdevel
97+Architecture: linux-any
98+Multi-Arch: same
99+Pre-Depends: ${misc:Pre-Depends}
100+Depends: libmirclient-dev,
101+Description: A C++ wrapper for libmirclient-dev
102+ Provides RAII (and other facilities) for Mir client library types.
103+ .
104+ Contains header files useful for C++ development against Mir.
105+
106+Package: miral-examples
107+Architecture: linux-any
108+Depends: ${misc:Depends},
109+ ${shlibs:Depends},
110+Recommends: dmz-cursor-theme,
111+Description: Display server for Ubuntu - demonstration programs
112+ MirAL provides an ABI-stable abstraction layer for Mir based shells,
113+ insulating them from mirserver ABI breaks.
114+ .
115+ Contains demo applications that use the MirAL abstraction layer
116
117=== added file 'debian/libmiral-dev.install'
118--- debian/libmiral-dev.install 1970-01-01 00:00:00 +0000
119+++ debian/libmiral-dev.install 2017-08-29 09:17:20 +0000
120@@ -0,0 +1,3 @@
121+usr/include/miral/miral/*
122+usr/lib/*/pkgconfig/miral.pc
123+usr/lib/*/libmiral.so
124
125=== added file 'debian/libmiral2.install'
126--- debian/libmiral2.install 1970-01-01 00:00:00 +0000
127+++ debian/libmiral2.install 2017-08-29 09:17:20 +0000
128@@ -0,0 +1,1 @@
129+usr/lib/*/libmiral.so.2
130
131=== added file 'debian/libmiral2.symbols'
132--- debian/libmiral2.symbols 1970-01-01 00:00:00 +0000
133+++ debian/libmiral2.symbols 2017-08-29 09:17:20 +0000
134@@ -0,0 +1,399 @@
135+libmiral.so.2 libmiral2 #MINVER#
136+ MIRAL_1.0@MIRAL_1.0 1.0.0
137+ (c++)"miral::WindowInfo::height_inc(mir::geometry::detail::IntWrapper<mir::geometry::DeltaYTag>)@MIRAL_1.0" 1.0.0
138+ (c++)"miral::WindowInfo::max_aspect(miral::WindowSpecification::AspectRatio)@MIRAL_1.0" 1.0.0
139+ (c++)"miral::WindowInfo::max_height(mir::geometry::detail::IntWrapper<mir::geometry::HeightTag>)@MIRAL_1.0" 1.0.0
140+ (c++)"miral::WindowInfo::min_aspect(miral::WindowSpecification::AspectRatio)@MIRAL_1.0" 1.0.0
141+ (c++)"miral::WindowInfo::min_height(mir::geometry::detail::IntWrapper<mir::geometry::HeightTag>)@MIRAL_1.0" 1.0.0
142+ (c++)"miral::WindowInfo::remove_child(miral::Window const&)@MIRAL_1.0" 1.0.0
143+ (c++)"miral::WindowInfo::restore_rect(mir::geometry::Rectangle const&)@MIRAL_1.0" 1.0.0
144+ (c++)"miral::WindowInfo::needs_titlebar(MirSurfaceType)@MIRAL_1.0" 1.0.0
145+ (c++)"miral::WindowInfo::confine_pointer(MirPointerConfinementState)@MIRAL_1.0" 1.0.0
146+ (c++)"miral::WindowInfo::preferred_orientation(MirOrientationMode)@MIRAL_1.0" 1.0.0
147+ (c++)"miral::WindowInfo::name(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
148+ (c++)"miral::WindowInfo::type(MirSurfaceType)@MIRAL_1.0" 1.0.0
149+ (c++)"miral::WindowInfo::state(MirSurfaceState)@MIRAL_1.0" 1.0.0
150+ (c++)"miral::WindowInfo::parent(miral::Window const&)@MIRAL_1.0" 1.0.0
151+ (c++)"miral::WindowInfo::userdata(std::shared_ptr<void>)@MIRAL_1.0" 1.0.0
152+ (c++)"miral::WindowInfo::add_child(miral::Window const&)@MIRAL_1.0" 1.0.0
153+ (c++)"miral::WindowInfo::max_width(mir::geometry::detail::IntWrapper<mir::geometry::WidthTag>)@MIRAL_1.0" 1.0.0
154+ (c++)"miral::WindowInfo::min_width(mir::geometry::detail::IntWrapper<mir::geometry::WidthTag>)@MIRAL_1.0" 1.0.0
155+ (c++)"miral::WindowInfo::output_id(mir::optional_value<int>)@MIRAL_1.0" 1.0.0
156+ (c++)"miral::WindowInfo::width_inc(mir::geometry::detail::IntWrapper<mir::geometry::DeltaXTag>)@MIRAL_1.0" 1.0.0
157+ (c++)"miral::WindowInfo::WindowInfo(miral::Window const&, miral::WindowSpecification const&)@MIRAL_1.0" 1.0.0
158+ (c++)"miral::WindowInfo::WindowInfo(miral::WindowInfo const&)@MIRAL_1.0" 1.0.0
159+ (c++)"miral::WindowInfo::WindowInfo()@MIRAL_1.0" 1.0.0
160+ (c++)"miral::WindowInfo::WindowInfo(miral::Window const&, miral::WindowSpecification const&)@MIRAL_1.0" 1.0.0
161+ (c++)"miral::WindowInfo::WindowInfo(miral::WindowInfo const&)@MIRAL_1.0" 1.0.0
162+ (c++)"miral::WindowInfo::WindowInfo()@MIRAL_1.0" 1.0.0
163+ (c++)"miral::WindowInfo::~WindowInfo()@MIRAL_1.0" 1.0.0
164+ (c++)"miral::WindowInfo::~WindowInfo()@MIRAL_1.0" 1.0.0
165+ (c++)"miral::WindowInfo::operator=(miral::WindowInfo const&)@MIRAL_1.0" 1.0.0
166+ (c++)"miral::CursorTheme::CursorTheme(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
167+ (c++)"miral::CursorTheme::CursorTheme(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
168+ (c++)"miral::CursorTheme::~CursorTheme()@MIRAL_1.0" 1.0.0
169+ (c++)"miral::CursorTheme::~CursorTheme()@MIRAL_1.0" 1.0.0
170+ (c++)"miral::SetTerminator::SetTerminator(std::function<void (int)> const&)@MIRAL_1.0" 1.0.0
171+ (c++)"miral::SetTerminator::SetTerminator(std::function<void (int)> const&)@MIRAL_1.0" 1.0.0
172+ (c++)"miral::SetTerminator::~SetTerminator()@MIRAL_1.0" 1.0.0
173+ (c++)"miral::SetTerminator::~SetTerminator()@MIRAL_1.0" 1.0.0
174+ (c++)"miral::DebugExtension::enable()@MIRAL_1.0" 1.0.0
175+ (c++)"miral::DebugExtension::disable()@MIRAL_1.0" 1.0.0
176+ (c++)"miral::DebugExtension::DebugExtension(miral::DebugExtension const&)@MIRAL_1.0" 1.0.0
177+ (c++)"miral::DebugExtension::DebugExtension()@MIRAL_1.0" 1.0.0
178+ (c++)"miral::DebugExtension::DebugExtension(miral::DebugExtension const&)@MIRAL_1.0" 1.0.0
179+ (c++)"miral::DebugExtension::DebugExtension()@MIRAL_1.0" 1.0.0
180+ (c++)"miral::DebugExtension::operator=(miral::DebugExtension const&)@MIRAL_1.0" 1.0.0
181+ (c++)"miral::AddInitCallback::AddInitCallback(std::function<void ()> const&)@MIRAL_1.0" 1.0.0
182+ (c++)"miral::AddInitCallback::AddInitCallback(std::function<void ()> const&)@MIRAL_1.0" 1.0.0
183+ (c++)"miral::AddInitCallback::~AddInitCallback()@MIRAL_1.0" 1.0.0
184+ (c++)"miral::AddInitCallback::~AddInitCallback()@MIRAL_1.0" 1.0.0
185+ (c++)"miral::ApplicationInfo::add_window(miral::Window const&)@MIRAL_1.0" 1.0.0
186+ (c++)"miral::ApplicationInfo::remove_window(miral::Window const&)@MIRAL_1.0" 1.0.0
187+ (c++)"miral::ApplicationInfo::userdata(std::shared_ptr<void>)@MIRAL_1.0" 1.0.0
188+ (c++)"miral::ApplicationInfo::ApplicationInfo(miral::ApplicationInfo const&)@MIRAL_1.0" 1.0.0
189+ (c++)"miral::ApplicationInfo::ApplicationInfo(std::shared_ptr<mir::scene::Session> const&)@MIRAL_1.0" 1.0.0
190+ (c++)"miral::ApplicationInfo::ApplicationInfo()@MIRAL_1.0" 1.0.0
191+ (c++)"miral::ApplicationInfo::ApplicationInfo(miral::ApplicationInfo const&)@MIRAL_1.0" 1.0.0
192+ (c++)"miral::ApplicationInfo::ApplicationInfo(std::shared_ptr<mir::scene::Session> const&)@MIRAL_1.0" 1.0.0
193+ (c++)"miral::ApplicationInfo::ApplicationInfo()@MIRAL_1.0" 1.0.0
194+ (c++)"miral::ApplicationInfo::~ApplicationInfo()@MIRAL_1.0" 1.0.0
195+ (c++)"miral::ApplicationInfo::~ApplicationInfo()@MIRAL_1.0" 1.0.0
196+ (c++)"miral::ApplicationInfo::operator=(miral::ApplicationInfo const&)@MIRAL_1.0" 1.0.0
197+ (c++)"miral::AppendEventFilter::AppendEventFilter(std::function<int (MirEvent const*)> const&)@MIRAL_1.0" 1.0.0
198+ (c++)"miral::AppendEventFilter::AppendEventFilter(std::function<int (MirEvent const*)> const&)@MIRAL_1.0" 1.0.0
199+ (c++)"miral::AppendEventFilter::operator()(mir::Server&)@MIRAL_1.0" 1.0.0
200+ (c++)"miral::CommandLineOption::CommandLineOption(miral::CommandLineOption const&)@MIRAL_1.0" 1.0.0
201+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (mir::optional_value<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
202+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (mir::optional_value<bool> const&)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
203+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (mir::optional_value<int> const&)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
204+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*)@MIRAL_1.0" 1.0.0
205+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
206+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (bool)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
207+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (bool)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)@MIRAL_1.0" 1.0.0
208+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (double)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, double)@MIRAL_1.0" 1.0.0
209+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (int)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)@MIRAL_1.0" 1.0.0
210+ (c++)"miral::CommandLineOption::CommandLineOption(miral::CommandLineOption const&)@MIRAL_1.0" 1.0.0
211+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (mir::optional_value<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
212+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (mir::optional_value<bool> const&)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
213+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (mir::optional_value<int> const&)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
214+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char const*)@MIRAL_1.0" 1.0.0
215+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
216+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (bool)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
217+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (bool)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)@MIRAL_1.0" 1.0.0
218+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (double)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, double)@MIRAL_1.0" 1.0.0
219+ (c++)"miral::CommandLineOption::CommandLineOption(std::function<void (int)>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)@MIRAL_1.0" 1.0.0
220+ (c++)"miral::CommandLineOption::~CommandLineOption()@MIRAL_1.0" 1.0.0
221+ (c++)"miral::CommandLineOption::~CommandLineOption()@MIRAL_1.0" 1.0.0
222+ (c++)"miral::CommandLineOption::operator=(miral::CommandLineOption const&)@MIRAL_1.0" 1.0.0
223+ (c++)"miral::WindowManagerTools::raise_tree(miral::Window const&)@MIRAL_1.0" 1.0.0
224+ (c++)"miral::WindowManagerTools::force_close(miral::Window const&)@MIRAL_1.0" 1.0.0
225+ (c++)"miral::WindowManagerTools::modify_window(miral::Window const&, miral::WindowSpecification const&)@MIRAL_1.0" 1.0.0
226+ (c++)"miral::WindowManagerTools::modify_window(miral::WindowInfo&, miral::WindowSpecification const&)@MIRAL_1.0" 1.0.0
227+ (c++)"miral::WindowManagerTools::active_display()@MIRAL_1.0" 1.0.0
228+ (c++)"miral::WindowManagerTools::find_application(std::function<bool (miral::ApplicationInfo const&)> const&)@MIRAL_1.0" 1.0.0
229+ (c++)"miral::WindowManagerTools::invoke_under_lock(std::function<void ()> const&)@MIRAL_1.0" 1.0.0
230+ (c++)"miral::WindowManagerTools::drag_active_window(mir::geometry::Displacement)@MIRAL_1.0" 1.0.0
231+ (c++)"miral::WindowManagerTools::ask_client_to_close(miral::Window const&)@MIRAL_1.0" 1.0.0
232+ (c++)"miral::WindowManagerTools::for_each_application(std::function<void (miral::ApplicationInfo&)> const&)@MIRAL_1.0" 1.0.0
233+ (c++)"miral::WindowManagerTools::select_active_window(miral::Window const&)@MIRAL_1.0" 1.0.0
234+ (c++)"miral::WindowManagerTools::focus_next_application()@MIRAL_1.0" 1.0.0
235+ (c++)"miral::WindowManagerTools::focus_next_within_application()@MIRAL_1.0" 1.0.0
236+ (c++)"miral::WindowManagerTools::WindowManagerTools(miral::WindowManagerToolsImplementation*)@MIRAL_1.0" 1.0.0
237+ (c++)"miral::WindowManagerTools::WindowManagerTools(miral::WindowManagerTools const&)@MIRAL_1.0" 1.0.0
238+ (c++)"miral::WindowManagerTools::WindowManagerTools(miral::WindowManagerToolsImplementation*)@MIRAL_1.0" 1.0.0
239+ (c++)"miral::WindowManagerTools::WindowManagerTools(miral::WindowManagerTools const&)@MIRAL_1.0" 1.0.0
240+ (c++)"miral::WindowManagerTools::~WindowManagerTools()@MIRAL_1.0" 1.0.0
241+ (c++)"miral::WindowManagerTools::~WindowManagerTools()@MIRAL_1.0" 1.0.0
242+ (c++)"miral::WindowManagerTools::operator=(miral::WindowManagerTools const&)@MIRAL_1.0" 1.0.0
243+ (c++)"miral::WindowSpecification::height_inc()@MIRAL_1.0" 1.0.0
244+ (c++)"miral::WindowSpecification::input_mode()@MIRAL_1.0" 1.0.0
245+ (c++)"miral::WindowSpecification::max_aspect()@MIRAL_1.0" 1.0.0
246+ (c++)"miral::WindowSpecification::max_height()@MIRAL_1.0" 1.0.0
247+ (c++)"miral::WindowSpecification::min_aspect()@MIRAL_1.0" 1.0.0
248+ (c++)"miral::WindowSpecification::min_height()@MIRAL_1.0" 1.0.0
249+ (c++)"miral::WindowSpecification::input_shape()@MIRAL_1.0" 1.0.0
250+ (c++)"miral::WindowSpecification::shell_chrome()@MIRAL_1.0" 1.0.0
251+ (c++)"miral::WindowSpecification::confine_pointer()@MIRAL_1.0" 1.0.0
252+ (c++)"miral::WindowSpecification::placement_hints()@MIRAL_1.0" 1.0.0
253+ (c++)"miral::WindowSpecification::preferred_orientation()@MIRAL_1.0" 1.0.0
254+ (c++)"miral::WindowSpecification::window_placement_gravity()@MIRAL_1.0" 1.0.0
255+ (c++)"miral::WindowSpecification::aux_rect_placement_offset()@MIRAL_1.0" 1.0.0
256+ (c++)"miral::WindowSpecification::aux_rect_placement_gravity()@MIRAL_1.0" 1.0.0
257+ (c++)"miral::WindowSpecification::name[abi:cxx11]()@MIRAL_1.0" 1.0.0
258+ (c++)"miral::WindowSpecification::size()@MIRAL_1.0" 1.0.0
259+ (c++)"miral::WindowSpecification::type()@MIRAL_1.0" 1.0.0
260+ (c++)"miral::WindowSpecification::state()@MIRAL_1.0" 1.0.0
261+ (c++)"miral::WindowSpecification::parent()@MIRAL_1.0" 1.0.0
262+ (c++)"miral::WindowSpecification::aux_rect()@MIRAL_1.0" 1.0.0
263+ (c++)"miral::WindowSpecification::top_left()@MIRAL_1.0" 1.0.0
264+ (c++)"miral::WindowSpecification::userdata()@MIRAL_1.0" 1.0.0
265+ (c++)"miral::WindowSpecification::max_width()@MIRAL_1.0" 1.0.0
266+ (c++)"miral::WindowSpecification::min_width()@MIRAL_1.0" 1.0.0
267+ (c++)"miral::WindowSpecification::output_id()@MIRAL_1.0" 1.0.0
268+ (c++)"miral::WindowSpecification::width_inc()@MIRAL_1.0" 1.0.0
269+ (c++)"miral::WindowSpecification::WindowSpecification(mir::scene::SurfaceCreationParameters const&)@MIRAL_1.0" 1.0.0
270+ (c++)"miral::WindowSpecification::WindowSpecification(mir::shell::SurfaceSpecification const&)@MIRAL_1.0" 1.0.0
271+ (c++)"miral::WindowSpecification::WindowSpecification(miral::WindowSpecification const&)@MIRAL_1.0" 1.0.0
272+ (c++)"miral::WindowSpecification::WindowSpecification()@MIRAL_1.0" 1.0.0
273+ (c++)"miral::WindowSpecification::WindowSpecification(mir::scene::SurfaceCreationParameters const&)@MIRAL_1.0" 1.0.0
274+ (c++)"miral::WindowSpecification::WindowSpecification(mir::shell::SurfaceSpecification const&)@MIRAL_1.0" 1.0.0
275+ (c++)"miral::WindowSpecification::WindowSpecification(miral::WindowSpecification const&)@MIRAL_1.0" 1.0.0
276+ (c++)"miral::WindowSpecification::WindowSpecification()@MIRAL_1.0" 1.0.0
277+ (c++)"miral::WindowSpecification::~WindowSpecification()@MIRAL_1.0" 1.0.0
278+ (c++)"miral::WindowSpecification::~WindowSpecification()@MIRAL_1.0" 1.0.0
279+ (c++)"miral::WindowSpecification::operator=(miral::WindowSpecification const&)@MIRAL_1.0" 1.0.0
280+ (c++)"miral::ActiveOutputsMonitor::add_listener(miral::ActiveOutputsListener*)@MIRAL_1.0" 1.0.0
281+ (c++)"miral::ActiveOutputsMonitor::delete_listener(miral::ActiveOutputsListener*)@MIRAL_1.0" 1.0.0
282+ (c++)"miral::ActiveOutputsMonitor::ActiveOutputsMonitor(miral::ActiveOutputsMonitor const&)@MIRAL_1.0" 1.0.0
283+ (c++)"miral::ActiveOutputsMonitor::ActiveOutputsMonitor()@MIRAL_1.0" 1.0.0
284+ (c++)"miral::ActiveOutputsMonitor::ActiveOutputsMonitor(miral::ActiveOutputsMonitor const&)@MIRAL_1.0" 1.0.0
285+ (c++)"miral::ActiveOutputsMonitor::ActiveOutputsMonitor()@MIRAL_1.0" 1.0.0
286+ (c++)"miral::ActiveOutputsMonitor::~ActiveOutputsMonitor()@MIRAL_1.0" 1.0.0
287+ (c++)"miral::ActiveOutputsMonitor::~ActiveOutputsMonitor()@MIRAL_1.0" 1.0.0
288+ (c++)"miral::ActiveOutputsMonitor::operator=(miral::ActiveOutputsMonitor const&)@MIRAL_1.0" 1.0.0
289+ (c++)"miral::ActiveOutputsMonitor::operator()(mir::Server&)@MIRAL_1.0" 1.0.0
290+ (c++)"miral::ActiveOutputsListener::advise_output_end()@MIRAL_1.0" 1.0.0
291+ (c++)"miral::ActiveOutputsListener::advise_output_begin()@MIRAL_1.0" 1.0.0
292+ (c++)"miral::ActiveOutputsListener::advise_output_create(miral::Output const&)@MIRAL_1.0" 1.0.0
293+ (c++)"miral::ActiveOutputsListener::advise_output_delete(miral::Output const&)@MIRAL_1.0" 1.0.0
294+ (c++)"miral::ActiveOutputsListener::advise_output_update(miral::Output const&, miral::Output const&)@MIRAL_1.0" 1.0.0
295+ (c++)"miral::SetCommandLineHandler::SetCommandLineHandler(std::function<void (int, char const* const*)> const&)@MIRAL_1.0" 1.0.0
296+ (c++)"miral::SetCommandLineHandler::SetCommandLineHandler(std::function<void (int, char const* const*)> const&)@MIRAL_1.0" 1.0.0
297+ (c++)"miral::SetCommandLineHandler::~SetCommandLineHandler()@MIRAL_1.0" 1.0.0
298+ (c++)"miral::SetCommandLineHandler::~SetCommandLineHandler()@MIRAL_1.0" 1.0.0
299+ (c++)"miral::StartupInternalClient::StartupInternalClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::function<void (miral::toolkit::Connection)>, std::function<void (std::weak_ptr<mir::scene::Session>)>)@MIRAL_1.0" 1.0.0
300+ (c++)"miral::StartupInternalClient::StartupInternalClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::function<void (miral::toolkit::Connection)>, std::function<void (std::weak_ptr<mir::scene::Session>)>)@MIRAL_1.0" 1.0.0
301+ (c++)"miral::StartupInternalClient::~StartupInternalClient()@MIRAL_1.0" 1.0.0
302+ (c++)"miral::StartupInternalClient::~StartupInternalClient()@MIRAL_1.0" 1.0.0
303+ (c++)"miral::StartupInternalClient::operator()(mir::Server&)@MIRAL_1.0" 1.0.0
304+ (c++)"miral::ApplicationCredentials::ApplicationCredentials(mir::frontend::SessionCredentials const&)@MIRAL_1.0" 1.0.0
305+ (c++)"miral::ApplicationCredentials::ApplicationCredentials(mir::frontend::SessionCredentials const&)@MIRAL_1.0" 1.0.0
306+ (c++)"miral::InternalClientLauncher::InternalClientLauncher()@MIRAL_1.0" 1.0.0
307+ (c++)"miral::InternalClientLauncher::InternalClientLauncher()@MIRAL_1.0" 1.0.0
308+ (c++)"miral::InternalClientLauncher::~InternalClientLauncher()@MIRAL_1.0" 1.0.0
309+ (c++)"miral::InternalClientLauncher::~InternalClientLauncher()@MIRAL_1.0" 1.0.0
310+ (c++)"miral::InternalClientLauncher::operator()(mir::Server&)@MIRAL_1.0" 1.0.0
311+ (c++)"miral::WindowManagementPolicy::advise_end()@MIRAL_1.0" 1.0.0
312+ (c++)"miral::WindowManagementPolicy::advise_begin()@MIRAL_1.0" 1.0.0
313+ (c++)"miral::WindowManagementPolicy::advise_raise(std::vector<miral::Window, std::allocator<miral::Window> > const&)@MIRAL_1.0" 1.0.0
314+ (c++)"miral::WindowManagementPolicy::advise_resize(miral::WindowInfo const&, mir::geometry::Size const&)@MIRAL_1.0" 1.0.0
315+ (c++)"miral::WindowManagementPolicy::advise_move_to(miral::WindowInfo const&, mir::geometry::Point)@MIRAL_1.0" 1.0.0
316+ (c++)"miral::WindowManagementPolicy::advise_new_app(miral::ApplicationInfo&)@MIRAL_1.0" 1.0.0
317+ (c++)"miral::WindowManagementPolicy::advise_delete_app(miral::ApplicationInfo const&)@MIRAL_1.0" 1.0.0
318+ (c++)"miral::WindowManagementPolicy::advise_focus_lost(miral::WindowInfo const&)@MIRAL_1.0" 1.0.0
319+ (c++)"miral::WindowManagementPolicy::advise_new_window(miral::WindowInfo const&)@MIRAL_1.0" 1.0.0
320+ (c++)"miral::WindowManagementPolicy::advise_focus_gained(miral::WindowInfo const&)@MIRAL_1.0" 1.0.0
321+ (c++)"miral::WindowManagementPolicy::advise_state_change(miral::WindowInfo const&, MirSurfaceState)@MIRAL_1.0" 1.0.0
322+ (c++)"miral::WindowManagementPolicy::advise_delete_window(miral::WindowInfo const&)@MIRAL_1.0" 1.0.0
323+ (c++)"miral::equivalent_display_area(miral::Output const&, miral::Output const&)@MIRAL_1.0" 1.0.0
324+ (c++)"miral::SetWindowManagmentPolicy::SetWindowManagmentPolicy(std::function<std::unique_ptr<miral::WindowManagementPolicy, std::default_delete<miral::WindowManagementPolicy> > (miral::WindowManagerTools const&)> const&)@MIRAL_1.0" 1.0.0
325+ (c++)"miral::SetWindowManagmentPolicy::SetWindowManagmentPolicy(std::function<std::unique_ptr<miral::WindowManagementPolicy, std::default_delete<miral::WindowManagementPolicy> > (miral::WindowManagerTools const&)> const&)@MIRAL_1.0" 1.0.0
326+ (c++)"miral::SetWindowManagmentPolicy::~SetWindowManagmentPolicy()@MIRAL_1.0" 1.0.0
327+ (c++)"miral::SetWindowManagmentPolicy::~SetWindowManagmentPolicy()@MIRAL_1.0" 1.0.0
328+ (c++)"miral::apply_lifecycle_state_to(std::shared_ptr<mir::scene::Session> const&, MirLifecycleState)@MIRAL_1.0" 1.0.0
329+ (c++)"miral::CanonicalWindowManagerPolicy::place_new_surface(miral::ApplicationInfo const&, miral::WindowSpecification const&)@MIRAL_1.0" 1.0.0
330+ (c++)"miral::CanonicalWindowManagerPolicy::advise_focus_gained(miral::WindowInfo const&)@MIRAL_1.0" 1.0.0
331+ (c++)"miral::CanonicalWindowManagerPolicy::handle_raise_window(miral::WindowInfo&)@MIRAL_1.0" 1.0.0
332+ (c++)"miral::CanonicalWindowManagerPolicy::handle_window_ready(miral::WindowInfo&)@MIRAL_1.0" 1.0.0
333+ (c++)"miral::CanonicalWindowManagerPolicy::handle_modify_window(miral::WindowInfo&, miral::WindowSpecification const&)@MIRAL_1.0" 1.0.0
334+ (c++)"miral::CanonicalWindowManagerPolicy::confirm_inherited_move(miral::WindowInfo const&, mir::geometry::Displacement)@MIRAL_1.0" 1.0.0
335+ (c++)"miral::CanonicalWindowManagerPolicy::CanonicalWindowManagerPolicy(miral::WindowManagerTools const&)@MIRAL_1.0" 1.0.0
336+ (c++)"miral::CanonicalWindowManagerPolicy::CanonicalWindowManagerPolicy(miral::WindowManagerTools const&)@MIRAL_1.0" 1.0.0
337+ (c++)"miral::BasicSetApplicationAuthorizer::BasicSetApplicationAuthorizer(std::function<std::shared_ptr<miral::ApplicationAuthorizer> ()> const&)@MIRAL_1.0" 1.0.0
338+ (c++)"miral::BasicSetApplicationAuthorizer::BasicSetApplicationAuthorizer(std::function<std::shared_ptr<miral::ApplicationAuthorizer> ()> const&)@MIRAL_1.0" 1.0.0
339+ (c++)"miral::BasicSetApplicationAuthorizer::~BasicSetApplicationAuthorizer()@MIRAL_1.0" 1.0.0
340+ (c++)"miral::BasicSetApplicationAuthorizer::~BasicSetApplicationAuthorizer()@MIRAL_1.0" 1.0.0
341+ (c++)"miral::BasicSetApplicationAuthorizer::operator()(mir::Server&)@MIRAL_1.0" 1.0.0
342+ (c++)"miral::display_configuration_options(mir::Server&)@MIRAL_1.0" 1.0.0
343+ (c++)"miral::kill(std::shared_ptr<mir::scene::Session> const&, int)@MIRAL_1.0" 1.0.0
344+ (c++)"miral::Keymap::set_keymap(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
345+ (c++)"miral::Keymap::Keymap(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
346+ (c++)"miral::Keymap::Keymap(miral::Keymap const&)@MIRAL_1.0" 1.0.0
347+ (c++)"miral::Keymap::Keymap()@MIRAL_1.0" 1.0.0
348+ (c++)"miral::Keymap::Keymap(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@MIRAL_1.0" 1.0.0
349+ (c++)"miral::Keymap::Keymap(miral::Keymap const&)@MIRAL_1.0" 1.0.0
350+ (c++)"miral::Keymap::Keymap()@MIRAL_1.0" 1.0.0
351+ (c++)"miral::Keymap::~Keymap()@MIRAL_1.0" 1.0.0
352+ (c++)"miral::Keymap::~Keymap()@MIRAL_1.0" 1.0.0
353+ (c++)"miral::Keymap::operator=(miral::Keymap const&)@MIRAL_1.0" 1.0.0
354+ (c++)"miral::Output::Output(mir::graphics::DisplayConfigurationOutput const&)@MIRAL_1.0" 1.0.0
355+ (c++)"miral::Output::Output(miral::Output const&)@MIRAL_1.0" 1.0.0
356+ (c++)"miral::Output::Output(mir::graphics::DisplayConfigurationOutput const&)@MIRAL_1.0" 1.0.0
357+ (c++)"miral::Output::Output(miral::Output const&)@MIRAL_1.0" 1.0.0
358+ (c++)"miral::Output::~Output()@MIRAL_1.0" 1.0.0
359+ (c++)"miral::Output::~Output()@MIRAL_1.0" 1.0.0
360+ (c++)"miral::Output::operator=(miral::Output const&)@MIRAL_1.0" 1.0.0
361+ (c++)"miral::Window::resize(mir::geometry::Size const&)@MIRAL_1.0" 1.0.0
362+ (c++)"miral::Window::move_to(mir::geometry::Point)@MIRAL_1.0" 1.0.0
363+ (c++)"miral::Window::Window(std::shared_ptr<mir::scene::Session> const&, std::shared_ptr<mir::scene::Surface> const&)@MIRAL_1.0" 1.0.0
364+ (c++)"miral::Window::Window()@MIRAL_1.0" 1.0.0
365+ (c++)"miral::Window::Window(std::shared_ptr<mir::scene::Session> const&, std::shared_ptr<mir::scene::Surface> const&)@MIRAL_1.0" 1.0.0
366+ (c++)"miral::Window::Window()@MIRAL_1.0" 1.0.0
367+ (c++)"miral::Window::~Window()@MIRAL_1.0" 1.0.0
368+ (c++)"miral::Window::~Window()@MIRAL_1.0" 1.0.0
369+ (c++)"miral::pid_of(std::shared_ptr<mir::scene::Session> const&)@MIRAL_1.0" 1.0.0
370+ (c++)"miral::name_of[abi:cxx11](std::shared_ptr<mir::scene::Session> const&)@MIRAL_1.0" 1.0.0
371+ (c++)"miral::MirRunner::add_stop_callback(std::function<void ()> const&)@MIRAL_1.0" 1.0.0
372+ (c++)"miral::MirRunner::add_start_callback(std::function<void ()> const&)@MIRAL_1.0" 1.0.0
373+ (c++)"miral::MirRunner::set_exception_handler(std::function<void ()> const&)@MIRAL_1.0" 1.0.0
374+ (c++)"miral::MirRunner::stop()@MIRAL_1.0" 1.0.0
375+ (c++)"miral::MirRunner::run_with(std::initializer_list<std::function<void (mir::Server&)> >)@MIRAL_1.0" 1.0.0
376+ (c++)"miral::MirRunner::MirRunner(int, char const**)@MIRAL_1.0" 1.0.0
377+ (c++)"miral::MirRunner::MirRunner(int, char const**, char const*)@MIRAL_1.0" 1.0.0
378+ (c++)"miral::MirRunner::MirRunner(int, char const**)@MIRAL_1.0" 1.0.0
379+ (c++)"miral::MirRunner::MirRunner(int, char const**, char const*)@MIRAL_1.0" 1.0.0
380+ (c++)"miral::MirRunner::~MirRunner()@MIRAL_1.0" 1.0.0
381+ (c++)"miral::MirRunner::~MirRunner()@MIRAL_1.0" 1.0.0
382+ (c++)"miral::operator==(miral::Output::PhysicalSizeMM const&, miral::Output::PhysicalSizeMM const&)@MIRAL_1.0" 1.0.0
383+ (c++)"miral::operator==(miral::Window const&, std::shared_ptr<mir::scene::Surface> const&)@MIRAL_1.0" 1.0.0
384+ (c++)"miral::operator==(miral::Window const&, miral::Window const&)@MIRAL_1.0" 1.0.0
385+ (c++)"miral::operator==(std::shared_ptr<mir::scene::Surface> const&, miral::Window const&)@MIRAL_1.0" 1.0.0
386+ (c++)"miral::WindowInfo::height_inc() const@MIRAL_1.0" 1.0.0
387+ (c++)"miral::WindowInfo::is_visible() const@MIRAL_1.0" 1.0.0
388+ (c++)"miral::WindowInfo::max_aspect() const@MIRAL_1.0" 1.0.0
389+ (c++)"miral::WindowInfo::max_height() const@MIRAL_1.0" 1.0.0
390+ (c++)"miral::WindowInfo::min_aspect() const@MIRAL_1.0" 1.0.0
391+ (c++)"miral::WindowInfo::min_height() const@MIRAL_1.0" 1.0.0
392+ (c++)"miral::WindowInfo::can_morph_to(MirSurfaceType) const@MIRAL_1.0" 1.0.0
393+ (c++)"miral::WindowInfo::restore_rect() const@MIRAL_1.0" 1.0.0
394+ (c++)"miral::WindowInfo::can_be_active() const@MIRAL_1.0" 1.0.0
395+ (c++)"miral::WindowInfo::has_output_id() const@MIRAL_1.0" 1.0.0
396+ (c++)"miral::WindowInfo::confine_pointer() const@MIRAL_1.0" 1.0.0
397+ (c++)"miral::WindowInfo::constrain_resize(mir::geometry::Point&, mir::geometry::Size&) const@MIRAL_1.0" 1.0.0
398+ (c++)"miral::WindowInfo::must_have_parent() const@MIRAL_1.0" 1.0.0
399+ (c++)"miral::WindowInfo::must_not_have_parent() const@MIRAL_1.0" 1.0.0
400+ (c++)"miral::WindowInfo::preferred_orientation() const@MIRAL_1.0" 1.0.0
401+ (c++)"miral::WindowInfo::name[abi:cxx11]() const@MIRAL_1.0" 1.0.0
402+ (c++)"miral::WindowInfo::type() const@MIRAL_1.0" 1.0.0
403+ (c++)"miral::WindowInfo::state() const@MIRAL_1.0" 1.0.0
404+ (c++)"miral::WindowInfo::parent() const@MIRAL_1.0" 1.0.0
405+ (c++)"miral::WindowInfo::window() const@MIRAL_1.0" 1.0.0
406+ (c++)"miral::WindowInfo::children() const@MIRAL_1.0" 1.0.0
407+ (c++)"miral::WindowInfo::userdata() const@MIRAL_1.0" 1.0.0
408+ (c++)"miral::WindowInfo::max_width() const@MIRAL_1.0" 1.0.0
409+ (c++)"miral::WindowInfo::min_width() const@MIRAL_1.0" 1.0.0
410+ (c++)"miral::WindowInfo::output_id() const@MIRAL_1.0" 1.0.0
411+ (c++)"miral::WindowInfo::width_inc() const@MIRAL_1.0" 1.0.0
412+ (c++)"miral::CursorTheme::operator()(mir::Server&) const@MIRAL_1.0" 1.0.0
413+ (c++)"miral::SetTerminator::operator()(mir::Server&) const@MIRAL_1.0" 1.0.0
414+ (c++)"miral::DebugExtension::operator()(mir::Server&) const@MIRAL_1.0" 1.0.0
415+ (c++)"miral::AddInitCallback::operator()(mir::Server&) const@MIRAL_1.0" 1.0.0
416+ (c++)"miral::ApplicationInfo::application() const@MIRAL_1.0" 1.0.0
417+ (c++)"miral::ApplicationInfo::name[abi:cxx11]() const@MIRAL_1.0" 1.0.0
418+ (c++)"miral::ApplicationInfo::windows() const@MIRAL_1.0" 1.0.0
419+ (c++)"miral::ApplicationInfo::userdata() const@MIRAL_1.0" 1.0.0
420+ (c++)"miral::CommandLineOption::operator()(mir::Server&) const@MIRAL_1.0" 1.0.0
421+ (c++)"miral::WindowManagerTools::active_window() const@MIRAL_1.0" 1.0.0
422+ (c++)"miral::WindowManagerTools::id_for_window[abi:cxx11](miral::Window const&) const@MIRAL_1.0" 1.0.0
423+ (c++)"miral::WindowManagerTools::count_applications() const@MIRAL_1.0" 1.0.0
424+ (c++)"miral::WindowManagerTools::info_for_window_id(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const@MIRAL_1.0" 1.0.0
425+ (c++)"miral::WindowManagerTools::place_and_size_for_state(miral::WindowSpecification&, miral::WindowInfo const&) const@MIRAL_1.0" 1.0.0
426+ (c++)"miral::WindowManagerTools::info_for(miral::Window const&) const@MIRAL_1.0" 1.0.0
427+ (c++)"miral::WindowManagerTools::info_for(std::weak_ptr<mir::scene::Session> const&) const@MIRAL_1.0" 1.0.0
428+ (c++)"miral::WindowManagerTools::info_for(std::weak_ptr<mir::scene::Surface> const&) const@MIRAL_1.0" 1.0.0
429+ (c++)"miral::WindowManagerTools::window_at(mir::geometry::Point) const@MIRAL_1.0" 1.0.0
430+ (c++)"miral::WindowSpecification::height_inc() const@MIRAL_1.0" 1.0.0
431+ (c++)"miral::WindowSpecification::input_mode() const@MIRAL_1.0" 1.0.0
432+ (c++)"miral::WindowSpecification::max_aspect() const@MIRAL_1.0" 1.0.0
433+ (c++)"miral::WindowSpecification::max_height() const@MIRAL_1.0" 1.0.0
434+ (c++)"miral::WindowSpecification::min_aspect() const@MIRAL_1.0" 1.0.0
435+ (c++)"miral::WindowSpecification::min_height() const@MIRAL_1.0" 1.0.0
436+ (c++)"miral::WindowSpecification::input_shape() const@MIRAL_1.0" 1.0.0
437+ (c++)"miral::WindowSpecification::shell_chrome() const@MIRAL_1.0" 1.0.0
438+ (c++)"miral::WindowSpecification::confine_pointer() const@MIRAL_1.0" 1.0.0
439+ (c++)"miral::WindowSpecification::placement_hints() const@MIRAL_1.0" 1.0.0
440+ (c++)"miral::WindowSpecification::preferred_orientation() const@MIRAL_1.0" 1.0.0
441+ (c++)"miral::WindowSpecification::window_placement_gravity() const@MIRAL_1.0" 1.0.0
442+ (c++)"miral::WindowSpecification::aux_rect_placement_offset() const@MIRAL_1.0" 1.0.0
443+ (c++)"miral::WindowSpecification::aux_rect_placement_gravity() const@MIRAL_1.0" 1.0.0
444+ (c++)"miral::WindowSpecification::name[abi:cxx11]() const@MIRAL_1.0" 1.0.0
445+ (c++)"miral::WindowSpecification::size() const@MIRAL_1.0" 1.0.0
446+ (c++)"miral::WindowSpecification::type() const@MIRAL_1.0" 1.0.0
447+ (c++)"miral::WindowSpecification::state() const@MIRAL_1.0" 1.0.0
448+ (c++)"miral::WindowSpecification::parent() const@MIRAL_1.0" 1.0.0
449+ (c++)"miral::WindowSpecification::update(mir::scene::SurfaceCreationParameters&) const@MIRAL_1.0" 1.0.0
450+ (c++)"miral::WindowSpecification::aux_rect() const@MIRAL_1.0" 1.0.0
451+ (c++)"miral::WindowSpecification::top_left() const@MIRAL_1.0" 1.0.0
452+ (c++)"miral::WindowSpecification::userdata() const@MIRAL_1.0" 1.0.0
453+ (c++)"miral::WindowSpecification::max_width() const@MIRAL_1.0" 1.0.0
454+ (c++)"miral::WindowSpecification::min_width() const@MIRAL_1.0" 1.0.0
455+ (c++)"miral::WindowSpecification::output_id() const@MIRAL_1.0" 1.0.0
456+ (c++)"miral::WindowSpecification::width_inc() const@MIRAL_1.0" 1.0.0
457+ (c++)"miral::ActiveOutputsMonitor::process_outputs(std::function<void (std::vector<miral::Output, std::allocator<miral::Output> > const&)> const&) const@MIRAL_1.0" 1.0.0
458+ (c++)"miral::WindowManagerOptions::operator()(mir::Server&) const@MIRAL_1.0" 1.0.0
459+ (c++)"miral::SetCommandLineHandler::operator()(mir::Server&) const@MIRAL_1.0" 1.0.0
460+ (c++)"miral::ApplicationCredentials::gid() const@MIRAL_1.0" 1.0.0
461+ (c++)"miral::ApplicationCredentials::pid() const@MIRAL_1.0" 1.0.0
462+ (c++)"miral::ApplicationCredentials::uid() const@MIRAL_1.0" 1.0.0
463+ (c++)"miral::InternalClientLauncher::launch(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::function<void (miral::toolkit::Connection)> const&, std::function<void (std::weak_ptr<mir::scene::Session>)> const&) const@MIRAL_1.0" 1.0.0
464+ (c++)"miral::SetWindowManagmentPolicy::operator()(mir::Server&) const@MIRAL_1.0" 1.0.0
465+ (c++)"miral::BasicSetApplicationAuthorizer::the_application_authorizer() const@MIRAL_1.0" 1.0.0
466+ (c++)"miral::Keymap::operator()(mir::Server&) const@MIRAL_1.0" 1.0.0
467+ (c++)"miral::Output::power_mode() const@MIRAL_1.0" 1.0.0
468+ (c++)"miral::Output::form_factor() const@MIRAL_1.0" 1.0.0
469+ (c++)"miral::Output::orientation() const@MIRAL_1.0" 1.0.0
470+ (c++)"miral::Output::pixel_format() const@MIRAL_1.0" 1.0.0
471+ (c++)"miral::Output::refresh_rate() const@MIRAL_1.0" 1.0.0
472+ (c++)"miral::Output::is_same_output(miral::Output const&) const@MIRAL_1.0" 1.0.0
473+ (c++)"miral::Output::physical_size_mm() const@MIRAL_1.0" 1.0.0
474+ (c++)"miral::Output::type() const@MIRAL_1.0" 1.0.0
475+ (c++)"miral::Output::used() const@MIRAL_1.0" 1.0.0
476+ (c++)"miral::Output::scale() const@MIRAL_1.0" 1.0.0
477+ (c++)"miral::Output::valid() const@MIRAL_1.0" 1.0.0
478+ (c++)"miral::Output::extents() const@MIRAL_1.0" 1.0.0
479+ (c++)"miral::Output::connected() const@MIRAL_1.0" 1.0.0
480+ (c++)"miral::Window::application() const@MIRAL_1.0" 1.0.0
481+ (c++)"miral::Window::size() const@MIRAL_1.0" 1.0.0
482+ (c++)"miral::Window::top_left() const@MIRAL_1.0" 1.0.0
483+ (c++)"miral::Window::operator std::shared_ptr<mir::scene::Surface>() const@MIRAL_1.0" 1.0.0
484+ (c++)"miral::Window::operator std::weak_ptr<mir::scene::Surface>() const@MIRAL_1.0" 1.0.0
485+ (c++)"miral::Window::operator bool() const@MIRAL_1.0" 1.0.0
486+ (c++)"typeinfo for miral::ActiveOutputsListener@MIRAL_1.0" 1.0.0
487+ (c++)"typeinfo for miral::WindowManagementPolicy@MIRAL_1.0" 1.0.0
488+ (c++)"typeinfo for miral::CanonicalWindowManagerPolicy@MIRAL_1.0" 1.0.0
489+ (c++)"vtable for miral::ActiveOutputsListener@MIRAL_1.0" 1.0.0
490+ (c++)"vtable for miral::WindowManagementPolicy@MIRAL_1.0" 1.0.0
491+ (c++)"vtable for miral::CanonicalWindowManagerPolicy@MIRAL_1.0" 1.0.0
492+ MIRAL_1.1@MIRAL_1.1 1.0.0
493+ (c++)"miral::WindowInfo::needs_titlebar(MirWindowType)@MIRAL_1.1" 1.0.0
494+ (c++)"miral::WindowInfo::type(MirWindowType)@MIRAL_1.1" 1.0.0
495+ (c++)"miral::WindowInfo::state(MirWindowState)@MIRAL_1.1" 1.0.0
496+ (c++)"miral::WindowManagementPolicy::advise_state_change(miral::WindowInfo const&, MirWindowState)@MIRAL_1.1" 1.0.0
497+ (c++)"miral::WindowInfo::can_morph_to(MirWindowType) const@MIRAL_1.1" 1.0.0
498+ (c++)"miral::CanonicalWindowManagerPolicy::place_new_window(miral::ApplicationInfo const&, miral::WindowSpecification const&)@MIRAL_1.1" 1.0.0
499+ MIRAL_1.2@MIRAL_1.2 1.0.0
500+ (c++)"miral::StartupInternalClient::StartupInternalClient(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::function<void (mir::client::Connection)>, std::function<void (std::weak_ptr<mir::scene::Session>)>)@MIRAL_1.2" 1.0.0
501+ (c++)"miral::InternalClientLauncher::launch(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::function<void (mir::client::Connection)> const&, std::function<void (std::weak_ptr<mir::scene::Session>)> const&) const@MIRAL_1.2" 1.0.0
502+ (c++)"miral::WindowInfo::shell_chrome(MirShellChrome)@MIRAL_1.2" 1.0.0
503+ (c++)"miral::WindowInfo::shell_chrome() const@MIRAL_1.2" 1.0.0
504+ (c++)"miral::WindowManagerTools::drag_window(miral::Window const&, mir::geometry::Displacement)@MIRAL_1.2" 1.0.0
505+ (c++)"typeinfo for miral::ApplicationAuthorizer@MIRAL_1.0" 1.0.0
506+ (c++)"typeinfo for miral::ApplicationAuthorizer1@MIRAL_1.2" 1.0.0
507+ MIRAL_1.3@MIRAL_1.3 1.0.0
508+ (c++)"miral::operator<(miral::Window const&, miral::Window const&)@MIRAL_1.0" 1.0.0
509+ (c++)"miral::WindowManagerTools::create_workspace()@MIRAL_1.3" 1.0.0
510+ (c++)"miral::WindowManagerTools::add_tree_to_workspace(miral::Window const&, std::shared_ptr<miral::Workspace> const&)@MIRAL_1.3" 1.0.0
511+ (c++)"miral::WindowManagerTools::focus_prev_within_application()@MIRAL_1.3" 1.0.0
512+ (c++)"miral::WindowManagerTools::remove_tree_from_workspace(miral::Window const&, std::shared_ptr<miral::Workspace> const&)@MIRAL_1.3" 1.0.0
513+ (c++)"miral::WindowManagerTools::move_workspace_content_to_workspace(std::shared_ptr<miral::Workspace> const&, std::shared_ptr<miral::Workspace> const&)@MIRAL_1.3" 1.0.0
514+ (c++)"miral::WorkspacePolicy::advise_adding_to_workspace(std::shared_ptr<miral::Workspace> const&, std::vector<miral::Window, std::allocator<miral::Window> > const&)@MIRAL_1.3" 1.0.0
515+ (c++)"miral::WorkspacePolicy::advise_removing_from_workspace(std::shared_ptr<miral::Workspace> const&, std::vector<miral::Window, std::allocator<miral::Window> > const&)@MIRAL_1.3" 1.0.0
516+ (c++)"miral::WindowManagerTools::for_each_window_in_workspace(std::shared_ptr<miral::Workspace> const&, std::function<void (miral::Window const&)> const&)@MIRAL_1.3" 1.0.0
517+ (c++)"miral::WindowManagerTools::for_each_workspace_containing(miral::Window const&, std::function<void (std::shared_ptr<miral::Workspace> const&)> const&)@MIRAL_1.3" 1.0.0
518+ (c++)"typeinfo for miral::WorkspacePolicy@MIRAL_1.3" 1.0.0
519+ (c++)"vtable for miral::WorkspacePolicy@MIRAL_1.3" 1.0.0
520+ MIRAL_1.3.1@MIRAL_1.3.1 1.0.0
521+ (c++)"miral::SetWindowManagementPolicy::SetWindowManagementPolicy(std::function<std::unique_ptr<miral::WindowManagementPolicy, std::default_delete<miral::WindowManagementPolicy> > (miral::WindowManagerTools const&)> const&)@MIRAL_1.3.1" 1.0.0
522+ (c++)"miral::SetWindowManagementPolicy::SetWindowManagementPolicy(std::function<std::unique_ptr<miral::WindowManagementPolicy, std::default_delete<miral::WindowManagementPolicy> > (miral::WindowManagerTools const&)> const&)@MIRAL_1.3.1" 1.0.0
523+ (c++)"miral::SetWindowManagementPolicy::~SetWindowManagementPolicy()@MIRAL_1.3.1" 1.0.0
524+ (c++)"miral::SetWindowManagementPolicy::~SetWindowManagementPolicy()@MIRAL_1.3.1" 1.0.0
525+ (c++)"miral::SetWindowManagementPolicy::operator()(mir::Server&) const@MIRAL_1.3.1" 1.0.0
526+ MIRAL_1.4.0@MIRAL_1.4.0 1.0.0
527+ (c++)"miral::WindowManagerTools::end_drag_and_drop()@MIRAL_1.4.0" 1.0.0
528+ (c++)"miral::WindowManagerTools::start_drag_and_drop(miral::WindowInfo&, std::vector<unsigned char, std::allocator<unsigned char> > const&)@MIRAL_1.4.0" 1.0.0
529+ (c++)"typeinfo for miral::WindowManagementPolicyAddendum2@MIRAL_1.4.0" 1.0.0
530+ MIRAL_1.5.0@MIRAL_1.5.0 1.0.0
531+ (c++)"miral::pre_init(miral::CommandLineOption const&)@MIRAL_1.5.0" 1.0.0
532+ (c++)"typeinfo for miral::WindowManagementPolicyAddendum3@MIRAL_1.5.0" 1.0.0
533+ (c++)"miral::WindowManagerTools::active_output()@MIRAL_1.5.0" 1.0.0
534\ No newline at end of file
535
536=== added file 'debian/libmirclientcpp-dev.install'
537--- debian/libmirclientcpp-dev.install 1970-01-01 00:00:00 +0000
538+++ debian/libmirclientcpp-dev.install 2017-08-29 09:17:20 +0000
539@@ -0,0 +1,2 @@
540+usr/include/miral/mir/*/*
541+usr/lib/*/pkgconfig/mirclientcpp.pc
542
543=== added file 'debian/miral-examples.install'
544--- debian/miral-examples.install 1970-01-01 00:00:00 +0000
545+++ debian/miral-examples.install 2017-08-29 09:17:20 +0000
546@@ -0,0 +1,9 @@
547+usr/bin/miral-shell
548+usr/bin/miral-run
549+usr/bin/miral-kiosk
550+usr/bin/miral-xrun
551+usr/bin/miral-screencast
552+usr/bin/miral-desktop
553+usr/bin/miral-app
554+usr/share/applications/miral-shell.desktop
555+usr/share/icons/hicolor/scalable/apps/ubuntu-logo.svg
556
557=== modified file 'examples/CMakeLists.txt'
558--- examples/CMakeLists.txt 2017-07-14 11:29:56 +0000
559+++ examples/CMakeLists.txt 2017-08-29 09:17:20 +0000
560@@ -1,3 +1,6 @@
561+add_subdirectory(miral-kiosk)
562+add_subdirectory(miral-shell)
563+
564 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -fno-strict-aliasing -Wextra")
565
566 add_library(eglapp STATIC
567
568=== added directory 'examples/miral-kiosk'
569=== added file 'examples/miral-kiosk/CMakeLists.txt'
570--- examples/miral-kiosk/CMakeLists.txt 1970-01-01 00:00:00 +0000
571+++ examples/miral-kiosk/CMakeLists.txt 2017-08-29 09:17:20 +0000
572@@ -0,0 +1,12 @@
573+include_directories(
574+ ${PROJECT_SOURCE_DIR}/include/miral
575+ ${PROJECT_SOURCE_DIR}/include/client
576+)
577+
578+mir_add_wrapped_executable(miral-kiosk
579+ kiosk_main.cpp
580+ kiosk_window_manager.cpp kiosk_window_manager.h
581+ sw_splash.cpp sw_splash.h
582+)
583+
584+target_link_libraries(miral-kiosk miral)
585
586=== added file 'examples/miral-kiosk/kiosk_main.cpp'
587--- examples/miral-kiosk/kiosk_main.cpp 1970-01-01 00:00:00 +0000
588+++ examples/miral-kiosk/kiosk_main.cpp 2017-08-29 09:17:20 +0000
589@@ -0,0 +1,94 @@
590+/*
591+ * Copyright © 2016 Canonical Ltd.
592+ *
593+ * This program is free software: you can redistribute it and/or modify
594+ * under the terms of the GNU General Public License version 2 or 3 as as
595+ * published by the Free Software Foundation.
596+ *
597+ * This program is distributed in the hope that it will be useful,
598+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
599+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
600+ * GNU General Public License for more details.
601+ *
602+ * You should have received a copy of the GNU General Public License
603+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
604+ *
605+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
606+ */
607+
608+#include "kiosk_window_manager.h"
609+
610+#include <miral/runner.h>
611+#include <miral/application_authorizer.h>
612+#include <miral/command_line_option.h>
613+#include <miral/keymap.h>
614+#include <miral/set_window_management_policy.h>
615+#include <miral/internal_client.h>
616+
617+#include <unistd.h>
618+#include <atomic>
619+
620+namespace
621+{
622+struct KioskAuthorizer : miral::ApplicationAuthorizer
623+{
624+ KioskAuthorizer(SwSplash const& splash) : splash{splash}{}
625+
626+ virtual bool connection_is_allowed(miral::ApplicationCredentials const& creds) override
627+ {
628+ // Allow internal applications and (optionally) only ones that start "immediately"
629+ // (For the sake of an example "immediately" means while the spash is running)
630+ return getpid() == creds.pid() || !startup_only || splash.session().lock();
631+ }
632+
633+ virtual bool configure_display_is_allowed(miral::ApplicationCredentials const& /*creds*/) override
634+ {
635+ return false;
636+ }
637+
638+ virtual bool set_base_display_configuration_is_allowed(miral::ApplicationCredentials const& /*creds*/) override
639+ {
640+ return false;
641+ }
642+
643+ virtual bool screencast_is_allowed(miral::ApplicationCredentials const& /*creds*/) override
644+ {
645+ return true;
646+ }
647+
648+ virtual bool prompt_session_is_allowed(miral::ApplicationCredentials const& /*creds*/) override
649+ {
650+ return false;
651+ }
652+
653+ static std::atomic<bool> startup_only;
654+
655+ SwSplash splash;
656+};
657+
658+std::atomic<bool> KioskAuthorizer::startup_only{false};
659+}
660+
661+int main(int argc, char const* argv[])
662+{
663+ using namespace miral;
664+
665+ SwSplash splash;
666+
667+ CommandLineOption startup_only{
668+ [&](bool startup_only) {KioskAuthorizer::startup_only = startup_only; },
669+ "kiosk-startup-apps-only",
670+ "Only allow applications to connect during startup",
671+ KioskAuthorizer::startup_only};
672+
673+ return MirRunner{argc, argv}.run_with(
674+ {
675+ CommandLineOption{[&](std::string const& ) { },
676+ "desktop_file_hint", "Ignored for Unity8 compatability", "miral-shell.desktop"},
677+ set_window_management_policy<KioskWindowManagerPolicy>(splash),
678+ SetApplicationAuthorizer<KioskAuthorizer>{splash},
679+ Keymap{},
680+ startup_only,
681+ StartupInternalClient{"Intro", splash}
682+ });
683+}
684
685=== added file 'examples/miral-kiosk/kiosk_window_manager.cpp'
686--- examples/miral-kiosk/kiosk_window_manager.cpp 1970-01-01 00:00:00 +0000
687+++ examples/miral-kiosk/kiosk_window_manager.cpp 2017-08-29 09:17:20 +0000
688@@ -0,0 +1,148 @@
689+/*
690+ * Copyright © 2016 Canonical Ltd.
691+ *
692+ * This program is free software: you can redistribute it and/or modify it
693+ * under the terms of the GNU General Public License version 2 or 3 as
694+ * published by the Free Software Foundation.
695+ *
696+ * This program is distributed in the hope that it will be useful,
697+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
698+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
699+ * GNU General Public License for more details.
700+ *
701+ * You should have received a copy of the GNU General Public License
702+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
703+ *
704+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
705+ */
706+
707+#include "kiosk_window_manager.h"
708+
709+#include <miral/application_info.h>
710+#include <miral/window_info.h>
711+#include <miral/window_manager_tools.h>
712+
713+#include <linux/input.h>
714+
715+namespace ms = mir::scene;
716+using namespace miral;
717+
718+KioskWindowManagerPolicy::KioskWindowManagerPolicy(WindowManagerTools const& tools, SwSplash const& splash) :
719+ CanonicalWindowManagerPolicy{tools},
720+ splash{splash}
721+{
722+}
723+
724+bool KioskWindowManagerPolicy::handle_keyboard_event(MirKeyboardEvent const* event)
725+{
726+ auto const action = mir_keyboard_event_action(event);
727+ auto const scan_code = mir_keyboard_event_scan_code(event);
728+ auto const modifiers = mir_keyboard_event_modifiers(event) & modifier_mask;
729+
730+ if (action == mir_keyboard_action_down &&
731+ modifiers == mir_input_event_modifier_alt &&
732+ scan_code == KEY_TAB)
733+ {
734+ tools.focus_next_application();
735+
736+ return true;
737+ }
738+ else if (action == mir_keyboard_action_down &&
739+ modifiers == mir_input_event_modifier_alt &&
740+ scan_code == KEY_GRAVE)
741+ {
742+ tools.focus_next_within_application();
743+
744+ return true;
745+ }
746+ else if (action == mir_keyboard_action_down &&
747+ modifiers == (mir_input_event_modifier_alt | mir_input_event_modifier_shift) &&
748+ scan_code == KEY_GRAVE)
749+ {
750+ tools.focus_prev_within_application();
751+
752+ return true;
753+ }
754+ else if (action == mir_keyboard_action_down && scan_code == KEY_F4)
755+ {
756+ switch (modifiers & modifier_mask)
757+ {
758+ case mir_input_event_modifier_alt:
759+ tools.ask_client_to_close(tools.active_window());;
760+ return true;
761+
762+ default:
763+ break;
764+ }
765+ }
766+
767+ return false;
768+}
769+
770+bool KioskWindowManagerPolicy::handle_touch_event(MirTouchEvent const* event)
771+{
772+ auto const count = mir_touch_event_point_count(event);
773+
774+ long total_x = 0;
775+ long total_y = 0;
776+
777+ for (auto i = 0U; i != count; ++i)
778+ {
779+ total_x += mir_touch_event_axis_value(event, i, mir_touch_axis_x);
780+ total_y += mir_touch_event_axis_value(event, i, mir_touch_axis_y);
781+ }
782+
783+ Point const cursor{total_x/count, total_y/count};
784+
785+ tools.select_active_window(tools.window_at(cursor));
786+
787+ return false;
788+}
789+
790+bool KioskWindowManagerPolicy::handle_pointer_event(MirPointerEvent const* event)
791+{
792+ auto const action = mir_pointer_event_action(event);
793+
794+ Point const cursor{
795+ mir_pointer_event_axis_value(event, mir_pointer_axis_x),
796+ mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
797+
798+ if (action == mir_pointer_action_button_down)
799+ {
800+ tools.select_active_window(tools.window_at(cursor));
801+ }
802+
803+ return false;
804+}
805+
806+void KioskWindowManagerPolicy::advise_focus_gained(WindowInfo const& info)
807+{
808+ CanonicalWindowManagerPolicy::advise_focus_gained(info);
809+
810+ if (auto session = splash.session().lock())
811+ {
812+ auto const& app_info = tools.info_for(session);
813+
814+ for (auto const& s : app_info.windows())
815+ tools.raise_tree(s);
816+ }
817+}
818+
819+void KioskWindowManagerPolicy::advise_new_window(WindowInfo const& window_info)
820+{
821+ // We do this here, not in place_new_window() so that clients get a resize event.
822+ // This shouldn't be necessary, but works better with the gtk-mir backend.
823+ if (window_info.type() == mir_window_type_normal &&
824+ !window_info.parent() &&
825+ window_info.state() == mir_window_state_restored)
826+ {
827+ WindowSpecification specification;
828+
829+ specification.state() = mir_window_state_maximized;
830+
831+ tools.place_and_size_for_state(specification, window_info);
832+ tools.modify_window(window_info.window(), specification);
833+ }
834+
835+ CanonicalWindowManagerPolicy::advise_new_window(window_info);
836+}
837
838=== added file 'examples/miral-kiosk/kiosk_window_manager.h'
839--- examples/miral-kiosk/kiosk_window_manager.h 1970-01-01 00:00:00 +0000
840+++ examples/miral-kiosk/kiosk_window_manager.h 2017-08-29 09:17:20 +0000
841@@ -0,0 +1,52 @@
842+/*
843+ * Copyright © 2016 Canonical Ltd.
844+ *
845+ * This program is free software: you can redistribute it and/or modify it
846+ * under the terms of the GNU General Public License version 2 or 3 as
847+ * published by the Free Software Foundation.
848+ *
849+ * This program is distributed in the hope that it will be useful,
850+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
851+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
852+ * GNU General Public License for more details.
853+ *
854+ * You should have received a copy of the GNU General Public License
855+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
856+ *
857+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
858+ */
859+
860+#ifndef MIRAL_KIOSK_WINDOW_MANAGER_H
861+#define MIRAL_KIOSK_WINDOW_MANAGER_H
862+
863+#include "sw_splash.h"
864+
865+#include <miral/canonical_window_manager.h>
866+
867+using namespace mir::geometry;
868+
869+class KioskWindowManagerPolicy : public miral::CanonicalWindowManagerPolicy
870+{
871+public:
872+ KioskWindowManagerPolicy(miral::WindowManagerTools const& tools, SwSplash const&);
873+
874+ void advise_focus_gained(miral::WindowInfo const& info) override;
875+
876+ virtual void advise_new_window(miral::WindowInfo const& window_info) override;
877+
878+ bool handle_keyboard_event(MirKeyboardEvent const* event) override;
879+ bool handle_touch_event(MirTouchEvent const* event) override;
880+ bool handle_pointer_event(MirPointerEvent const* event) override;
881+
882+private:
883+ static const int modifier_mask =
884+ mir_input_event_modifier_alt |
885+ mir_input_event_modifier_shift |
886+ mir_input_event_modifier_sym |
887+ mir_input_event_modifier_ctrl |
888+ mir_input_event_modifier_meta;
889+
890+ SwSplash const splash;
891+};
892+
893+#endif /* MIRAL_KIOSK_WINDOW_MANAGER_H */
894
895=== added file 'examples/miral-kiosk/sw_splash.cpp'
896--- examples/miral-kiosk/sw_splash.cpp 1970-01-01 00:00:00 +0000
897+++ examples/miral-kiosk/sw_splash.cpp 2017-08-29 09:17:20 +0000
898@@ -0,0 +1,173 @@
899+/*
900+ * Copyright © 2016 Canonical Ltd.
901+ *
902+ * This program is free software: you can redistribute it and/or modify it
903+ * under the terms of the GNU General Public License version 2 or 3 as
904+ * published by the Free Software Foundation.
905+ *
906+ * This program is distributed in the hope that it will be useful,
907+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
908+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
909+ * GNU General Public License for more details.
910+ *
911+ * You should have received a copy of the GNU General Public License
912+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
913+ *
914+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
915+ */
916+
917+#include "sw_splash.h"
918+
919+#include <mir/client/display_config.h>
920+#include <mir/client/surface.h>
921+#include <mir/client/window.h>
922+#include <mir/client/window_spec.h>
923+
924+#include <mir_toolkit/mir_buffer_stream.h>
925+
926+#include <chrono>
927+#include <cstring>
928+#include <thread>
929+#include <mutex>
930+
931+namespace
932+{
933+MirPixelFormat find_8888_format(MirConnection* connection)
934+{
935+ unsigned int const num_formats = 32;
936+ MirPixelFormat pixel_formats[num_formats];
937+ unsigned int valid_formats;
938+ mir_connection_get_available_surface_formats(connection, pixel_formats, num_formats, &valid_formats);
939+
940+ for (unsigned int i = 0; i < num_formats; ++i)
941+ {
942+ MirPixelFormat cur_pf = pixel_formats[i];
943+ if (cur_pf == mir_pixel_format_abgr_8888 ||
944+ cur_pf == mir_pixel_format_argb_8888)
945+ {
946+ return cur_pf;
947+ }
948+ }
949+
950+ for (unsigned int i = 0; i < num_formats; ++i)
951+ {
952+ MirPixelFormat cur_pf = pixel_formats[i];
953+ if (cur_pf == mir_pixel_format_xbgr_8888 ||
954+ cur_pf == mir_pixel_format_xrgb_8888)
955+ {
956+ return cur_pf;
957+ }
958+ }
959+
960+ return *pixel_formats;
961+}
962+
963+auto create_window(MirConnection* connection, mir::client::Surface const& surface) -> mir::client::Window
964+{
965+ int id = 0;
966+ int width = 0;
967+ int height = 0;
968+
969+ mir::client::DisplayConfig{connection}.for_each_output([&](MirOutput const* output)
970+ {
971+ if (mir_output_get_connection_state(output) == mir_output_connection_state_connected &&
972+ mir_output_is_enabled(output))
973+ {
974+ id = mir_output_get_id(output);
975+
976+ MirOutputMode const* mode = mir_output_get_current_mode(output);
977+ width = mir_output_mode_get_width(mode);
978+ height = mir_output_mode_get_height(mode);
979+ }
980+ });
981+
982+ return mir::client::WindowSpec::for_normal_window(connection, width, height)
983+ .set_name("splash")
984+ .set_fullscreen_on_output(id)
985+ .add_surface(surface, width, height, 0, 0)
986+ .create_window();
987+}
988+
989+void render_pattern(MirGraphicsRegion *region, uint8_t pattern[])
990+{
991+ char *row = region->vaddr;
992+
993+ for (int j = 0; j < region->height; j++)
994+ {
995+ uint32_t *pixel = (uint32_t*)row;
996+
997+ for (int i = 0; i < region->width; i++)
998+ memcpy(pixel+i, pattern, sizeof pixel[i]);
999+
1000+ row += region->stride;
1001+ }
1002+}
1003+}
1004+
1005+struct SwSplash::Self
1006+{
1007+ std::mutex mutex;
1008+ std::weak_ptr<mir::scene::Session> session;
1009+};
1010+
1011+SwSplash::SwSplash() : self{std::make_shared<Self>()} {}
1012+
1013+SwSplash::~SwSplash() = default;
1014+
1015+void SwSplash::operator()(std::weak_ptr<mir::scene::Session> const& session)
1016+{
1017+ std::lock_guard<decltype(self->mutex)> lock{self->mutex};
1018+ self->session = session;
1019+}
1020+
1021+auto SwSplash::session() const -> std::weak_ptr<mir::scene::Session>
1022+{
1023+ std::lock_guard<decltype(self->mutex)> lock{self->mutex};
1024+ return self->session;
1025+}
1026+
1027+void SwSplash::operator()(MirConnection* connection)
1028+{
1029+ MirPixelFormat pixel_format = find_8888_format(connection);
1030+
1031+ uint8_t pattern[4] = { 0x14, 0x48, 0xDD, 0xFF };
1032+
1033+ switch(pixel_format)
1034+ {
1035+ case mir_pixel_format_abgr_8888:
1036+ case mir_pixel_format_xbgr_8888:
1037+ std::swap(pattern[2],pattern[0]);
1038+ break;
1039+
1040+ case mir_pixel_format_argb_8888:
1041+ case mir_pixel_format_xrgb_8888:
1042+ break;
1043+
1044+ default:
1045+ return;
1046+ };
1047+
1048+
1049+ mir::client::Surface surface{mir_connection_create_render_surface_sync(connection, 42, 42)};
1050+ MirBufferStream* buffer_stream = mir_render_surface_get_buffer_stream(surface, 42, 42, pixel_format);
1051+
1052+ auto const window = create_window(connection, surface);
1053+
1054+ MirGraphicsRegion graphics_region;
1055+
1056+ auto const time_limit = std::chrono::steady_clock::now() + std::chrono::seconds(2);
1057+
1058+ do
1059+ {
1060+ mir_buffer_stream_get_graphics_region(buffer_stream, &graphics_region);
1061+
1062+ render_pattern(&graphics_region, pattern);
1063+ mir_buffer_stream_swap_buffers_sync(buffer_stream);
1064+
1065+ for (auto& x : pattern)
1066+ x = 3*x/4;
1067+
1068+ std::this_thread::sleep_for(std::chrono::milliseconds(200));
1069+ }
1070+ while (std::chrono::steady_clock::now() < time_limit);
1071+}
1072
1073=== added file 'examples/miral-kiosk/sw_splash.h'
1074--- examples/miral-kiosk/sw_splash.h 1970-01-01 00:00:00 +0000
1075+++ examples/miral-kiosk/sw_splash.h 2017-08-29 09:17:20 +0000
1076@@ -0,0 +1,44 @@
1077+/*
1078+ * Copyright © 2016 Canonical Ltd.
1079+ *
1080+ * This program is free software: you can redistribute it and/or modify it
1081+ * under the terms of the GNU General Public License version 2 or 3 as
1082+ * published by the Free Software Foundation.
1083+ *
1084+ * This program is distributed in the hope that it will be useful,
1085+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1086+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1087+ * GNU General Public License for more details.
1088+ *
1089+ * You should have received a copy of the GNU General Public License
1090+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1091+ *
1092+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
1093+ */
1094+
1095+#ifndef MIRAL_SHELL_SW_SPLASH_H
1096+#define MIRAL_SHELL_SW_SPLASH_H
1097+
1098+#include <mir_toolkit/client_types.h>
1099+
1100+#include <memory>
1101+
1102+namespace mir { class Server; namespace scene { class Session; }}
1103+
1104+// A very simple s/w rendered splash animation
1105+class SwSplash
1106+{
1107+public:
1108+ SwSplash();
1109+ ~SwSplash();
1110+
1111+ void operator()(MirConnection* connection);
1112+ void operator()(std::weak_ptr<mir::scene::Session> const& session);
1113+ auto session() const -> std::weak_ptr<mir::scene::Session>;
1114+
1115+private:
1116+ struct Self;
1117+ std::shared_ptr<Self> const self;
1118+};
1119+
1120+#endif //MIRAL_SHELL_SW_SPLASH_H
1121
1122=== added directory 'examples/miral-shell'
1123=== added file 'examples/miral-shell/CMakeLists.txt'
1124--- examples/miral-shell/CMakeLists.txt 1970-01-01 00:00:00 +0000
1125+++ examples/miral-shell/CMakeLists.txt 2017-08-29 09:17:20 +0000
1126@@ -0,0 +1,65 @@
1127+include_directories(
1128+ ${PROJECT_SOURCE_DIR}/include/miral
1129+ ${PROJECT_SOURCE_DIR}/include/client
1130+)
1131+
1132+add_subdirectory(spinner)
1133+add_subdirectory(desktop)
1134+
1135+add_custom_target(miral-run ALL
1136+ cp ${CMAKE_CURRENT_SOURCE_DIR}/miral-run.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/miral-run
1137+)
1138+
1139+install(PROGRAMS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/miral-run
1140+ DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
1141+)
1142+
1143+add_custom_target(miral-xrun ALL
1144+ cp ${CMAKE_CURRENT_SOURCE_DIR}/miral-xrun.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/miral-xrun
1145+)
1146+
1147+install(PROGRAMS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/miral-xrun
1148+ DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
1149+)
1150+
1151+add_custom_target(miral-screencast ALL
1152+ cp ${CMAKE_CURRENT_SOURCE_DIR}/miral-screencast.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/miral-screencast
1153+)
1154+
1155+install(PROGRAMS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/miral-screencast
1156+ DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
1157+)
1158+
1159+add_custom_target(miral-desktop ALL
1160+ cp ${CMAKE_CURRENT_SOURCE_DIR}/miral-desktop.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/miral-desktop
1161+)
1162+
1163+install(PROGRAMS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/miral-desktop
1164+ DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
1165+)
1166+
1167+add_custom_target(miral-app ALL
1168+ cp ${CMAKE_CURRENT_SOURCE_DIR}/miral-app.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/miral-app
1169+)
1170+
1171+install(PROGRAMS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/miral-app
1172+ DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
1173+)
1174+
1175+mir_add_wrapped_executable(miral-shell
1176+ shell_main.cpp
1177+ tiling_window_manager.cpp tiling_window_manager.h
1178+ floating_window_manager.cpp floating_window_manager.h
1179+ decoration_provider.cpp decoration_provider.h
1180+ titlebar_config.cpp titlebar_config.h
1181+)
1182+
1183+pkg_check_modules(FREETYPE freetype2 REQUIRED)
1184+target_include_directories(miral-shell PRIVATE ${FREETYPE_INCLUDE_DIRS})
1185+target_compile_definitions(miral-shell PRIVATE -DTYPO_SUPPORTS_FREETYPE)
1186+target_link_libraries(miral-shell
1187+ miral-spinner
1188+ miral
1189+ ${FREETYPE_LIBRARIES}
1190+)
1191+
1192
1193=== added file 'examples/miral-shell/decoration_provider.cpp'
1194--- examples/miral-shell/decoration_provider.cpp 1970-01-01 00:00:00 +0000
1195+++ examples/miral-shell/decoration_provider.cpp 2017-08-29 09:17:20 +0000
1196@@ -0,0 +1,666 @@
1197+/*
1198+ * Copyright © 2016-2017 Canonical Ltd.
1199+ *
1200+ * This program is free software: you can redistribute it and/or modify it
1201+ * under the terms of the GNU General Public License version 2 or 3 as
1202+ * published by the Free Software Foundation.
1203+ *
1204+ * This program is distributed in the hope that it will be useful,
1205+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1206+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1207+ * GNU General Public License for more details.
1208+ *
1209+ * You should have received a copy of the GNU General Public License
1210+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1211+ *
1212+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
1213+ */
1214+
1215+#include "decoration_provider.h"
1216+#include "titlebar_config.h"
1217+
1218+#include <mir/client/display_config.h>
1219+#include <mir/client/window_spec.h>
1220+
1221+#include <mir_toolkit/mir_buffer_stream.h>
1222+
1223+#include <ft2build.h>
1224+#include FT_FREETYPE_H
1225+
1226+#include <locale>
1227+#include <codecvt>
1228+#include <string>
1229+#include <cstring>
1230+#include <sstream>
1231+
1232+#include <iostream>
1233+
1234+namespace
1235+{
1236+int const title_bar_height = 12;
1237+char const* const wallpaper_name = "wallpaper";
1238+
1239+void null_window_callback(MirWindow*, void*) {}
1240+
1241+struct preferred_codecvt : std::codecvt_byname<wchar_t, char, std::mbstate_t>
1242+{
1243+ preferred_codecvt() : std::codecvt_byname<wchar_t, char, std::mbstate_t>("") {}
1244+ ~preferred_codecvt() = default;
1245+};
1246+
1247+struct Printer
1248+{
1249+ Printer();
1250+ ~Printer();
1251+ Printer(Printer const&) = delete;
1252+ Printer& operator=(Printer const&) = delete;
1253+
1254+ void print(MirGraphicsRegion const& region, std::string const& title, int const intensity);
1255+ void printhelp(MirGraphicsRegion const& region);
1256+
1257+private:
1258+ std::wstring_convert<preferred_codecvt> converter;
1259+
1260+ bool working = false;
1261+ FT_Library lib;
1262+ FT_Face face;
1263+};
1264+
1265+void paint_surface(MirBufferStream* buffer_stream, std::string const& title, int const intensity)
1266+{
1267+ // TODO sometimes buffer_stream is nullptr - find out why (and fix).
1268+ // (Only observed when creating a lot of clients at once)
1269+ if (!buffer_stream)
1270+ return;
1271+
1272+ MirGraphicsRegion region;
1273+ mir_buffer_stream_get_graphics_region(buffer_stream, &region);
1274+
1275+ char* row = region.vaddr;
1276+
1277+ for (int j = 0; j != region.height; ++j)
1278+ {
1279+ memset(row, intensity, 4*region.width);
1280+ row += region.stride;
1281+ }
1282+
1283+ static Printer printer;
1284+ printer.print(region, title, intensity);
1285+
1286+ mir_buffer_stream_swap_buffers_sync(buffer_stream);
1287+}
1288+
1289+Printer::Printer()
1290+{
1291+ if (FT_Init_FreeType(&lib))
1292+ return;
1293+
1294+ if (FT_New_Face(lib, titlebar::font_file().c_str(), 0, &face))
1295+ {
1296+ std::cerr << "WARNING: failed to load titlebar font: \"" << titlebar::font_file() << "\"\n";
1297+ FT_Done_FreeType(lib);
1298+ return;
1299+ }
1300+
1301+ FT_Set_Pixel_Sizes(face, 0, 10);
1302+ working = true;
1303+}
1304+
1305+Printer::~Printer()
1306+{
1307+ if (working)
1308+ {
1309+ FT_Done_Face(face);
1310+ FT_Done_FreeType(lib);
1311+ }
1312+}
1313+
1314+void Printer::print(MirGraphicsRegion const& region, std::string const& title_, int const intensity)
1315+try
1316+{
1317+ if (!working)
1318+ return;
1319+
1320+ auto title = converter.from_bytes(title_);
1321+
1322+ int base_x = 2;
1323+ int base_y = region.height-2;
1324+
1325+ for (auto const& ch : title)
1326+ {
1327+ FT_Load_Glyph(face, FT_Get_Char_Index(face, ch), FT_LOAD_DEFAULT);
1328+ auto const glyph = face->glyph;
1329+ FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL);
1330+
1331+ auto const& bitmap = glyph->bitmap;
1332+ auto const x = base_x + glyph->bitmap_left;
1333+
1334+ if (static_cast<int>(x + bitmap.width) <= region.width)
1335+ {
1336+ unsigned char* src = bitmap.buffer;
1337+
1338+ auto const y = base_y - glyph->bitmap_top;
1339+ char* dest = region.vaddr + y*region.stride + 4*x;
1340+
1341+ for (auto row = 0u; row != std::min(bitmap.rows, glyph->bitmap_top+2u); ++row)
1342+ {
1343+ for (auto col = 0u; col != bitmap.width; ++col)
1344+ memset(dest+ 4*col, (intensity*(0xff^src[col]))/0xff, 4);
1345+
1346+ src += bitmap.pitch;
1347+ dest += region.stride;
1348+ }
1349+ }
1350+
1351+ base_x += glyph->advance.x >> 6;
1352+ base_y += glyph->advance.y >> 6;
1353+ }
1354+}
1355+catch (...)
1356+{
1357+ std::cerr << "WARNING: failed render title: \"" << title_ << "\"\n";
1358+}
1359+
1360+void Printer::printhelp(MirGraphicsRegion const& region)
1361+{
1362+ if (!working)
1363+ return;
1364+
1365+ static char const* const helptext[] =
1366+ {
1367+ "Welcome to miral-shell",
1368+ "",
1369+ "Keyboard shortcuts:",
1370+ "",
1371+ " o Switch apps: Alt-Tab, tap or click on the corresponding window",
1372+ " o Next (previous) app window: Alt-` (Alt-Shift-`)",
1373+ "",
1374+ " o Move window: Alt-leftmousebutton drag (three finger drag)",
1375+ " o Resize window: Alt-middle_button drag (three finger pinch)",
1376+ "",
1377+ " o Maximize/restore current window (to display size). : Alt-F11",
1378+ " o Maximize/restore current window (to display height): Shift-F11",
1379+ " o Maximize/restore current window (to display width) : Ctrl-F11",
1380+ "",
1381+ " o Switch workspace: Meta-Alt-[F1|F2|F3|F4]",
1382+ " o Switch workspace taking active window: Meta-Ctrl-[F1|F2|F3|F4]",
1383+ "",
1384+ " o To exit: Ctrl-Alt-BkSp",
1385+ };
1386+
1387+ int help_width = 0;
1388+ unsigned int help_height = 0;
1389+ unsigned int line_height = 0;
1390+
1391+ for (auto const* rawline : helptext)
1392+ {
1393+ int line_width = 0;
1394+
1395+ auto const line = converter.from_bytes(rawline);
1396+
1397+ auto const fwidth = std::min(region.width / 60, 20);
1398+
1399+ FT_Set_Pixel_Sizes(face, fwidth, 0);
1400+
1401+ for (auto const& ch : line)
1402+ {
1403+ FT_Load_Glyph(face, FT_Get_Char_Index(face, ch), FT_LOAD_DEFAULT);
1404+ auto const glyph = face->glyph;
1405+ FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL);
1406+
1407+ line_width += glyph->advance.x >> 6;
1408+ line_height = std::max(line_height, glyph->bitmap.rows + glyph->bitmap.rows/2);
1409+ }
1410+
1411+ if (help_width < line_width) help_width = line_width;
1412+ help_height += line_height;
1413+ }
1414+
1415+ int base_y = (region.height - help_height)/2;
1416+
1417+ for (auto const* rawline : helptext)
1418+ {
1419+ int base_x = (region.width - help_width)/2;
1420+
1421+ auto const line = converter.from_bytes(rawline);
1422+
1423+ for (auto const& ch : line)
1424+ {
1425+ FT_Load_Glyph(face, FT_Get_Char_Index(face, ch), FT_LOAD_DEFAULT);
1426+ auto const glyph = face->glyph;
1427+ FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL);
1428+
1429+ auto const& bitmap = glyph->bitmap;
1430+ auto const x = base_x + glyph->bitmap_left;
1431+
1432+ if (static_cast<int>(x + bitmap.width) <= region.width)
1433+ {
1434+ unsigned char* src = bitmap.buffer;
1435+
1436+ auto const y = base_y - glyph->bitmap_top;
1437+ char* dest = region.vaddr + y * region.stride + 4 * x;
1438+
1439+ for (auto row = 0u; row != bitmap.rows; ++row)
1440+ {
1441+ for (auto col = 0u; col != 4 * bitmap.width; ++col)
1442+ dest[col] |= src[col / 4]/2;
1443+
1444+ src += bitmap.pitch;
1445+ dest += region.stride;
1446+
1447+ if (dest > region.vaddr + region.height * region.stride)
1448+ break;
1449+ }
1450+ }
1451+
1452+ base_x += glyph->advance.x >> 6;
1453+ }
1454+ base_y += line_height;
1455+ }
1456+}
1457+
1458+void render_background(MirBufferStream* buffer_stream, MirGraphicsRegion& graphics_region)
1459+{
1460+ static uint8_t const pattern[4] = {0x00, 0x00, 0x00, 0x00 };
1461+
1462+ char* row = (&graphics_region)->vaddr;
1463+
1464+ for (int j = 0; j < (&graphics_region)->height; j++)
1465+ {
1466+ uint32_t* pixel = (uint32_t*)row;
1467+
1468+ for (int i = 0; i < (&graphics_region)->width; i++)
1469+ memcpy(pixel + i, pattern, sizeof pixel[i]);
1470+
1471+ row += (&graphics_region)->stride;
1472+ }
1473+
1474+ static Printer printer;
1475+ printer.printhelp(*&graphics_region);
1476+
1477+ mir_buffer_stream_swap_buffers_sync(buffer_stream);
1478+}
1479+}
1480+
1481+using namespace mir::client;
1482+using namespace mir::geometry;
1483+
1484+DecorationProvider::DecorationProvider(miral::WindowManagerTools const& tools) : tools{tools}
1485+{
1486+
1487+}
1488+
1489+DecorationProvider::~DecorationProvider()
1490+{
1491+}
1492+
1493+void DecorationProvider::stop()
1494+{
1495+ enqueue_work([this]
1496+ {
1497+ std::lock_guard<decltype(mutex)> lock{mutex};
1498+ window_to_titlebar.clear();
1499+ });
1500+
1501+ enqueue_work([this]
1502+ {
1503+ if (connection)
1504+ {
1505+ wallpaper.erase(begin(wallpaper), end(wallpaper));
1506+ }
1507+ connection.reset();
1508+ });
1509+ stop_work();
1510+}
1511+
1512+void DecorationProvider::operator()(Connection connection)
1513+{
1514+ this->connection = connection;
1515+
1516+ DisplayConfig const display_conf{this->connection};
1517+
1518+ display_conf.for_each_output([this](MirOutput const* output)
1519+ {
1520+ if (!mir_output_is_enabled(output))
1521+ return;
1522+
1523+ auto const mode = mir_output_get_current_mode(output);
1524+ auto const output_id = mir_output_get_id(output);
1525+ auto const width = mir_output_mode_get_width(mode);
1526+ auto const height = mir_output_mode_get_height(mode);
1527+
1528+ Surface surface{mir_connection_create_render_surface_sync(DecorationProvider::connection, width, height)};
1529+
1530+ auto const buffer_stream =
1531+ mir_render_surface_get_buffer_stream(surface, width, height, mir_pixel_format_xrgb_8888);
1532+
1533+ auto window = WindowSpec::for_gloss(DecorationProvider::connection, width, height)
1534+ .set_fullscreen_on_output(output_id)
1535+ .set_event_handler(&handle_event_for_background, this)
1536+ .add_surface(surface, width, height, 0, 0)
1537+ .set_name(wallpaper_name).create_window();
1538+
1539+ wallpaper.push_back(Wallpaper{surface, window, buffer_stream});
1540+
1541+ MirGraphicsRegion graphics_region;
1542+ mir_buffer_stream_get_graphics_region(buffer_stream, &graphics_region);
1543+ render_background(buffer_stream, graphics_region);
1544+ });
1545+
1546+ start_work();
1547+}
1548+
1549+void DecorationProvider::operator()(std::weak_ptr<mir::scene::Session> const& session)
1550+{
1551+ std::lock_guard<decltype(mutex)> lock{mutex};
1552+ this->weak_session = session;
1553+}
1554+
1555+auto DecorationProvider::session() const -> std::shared_ptr<mir::scene::Session>
1556+{
1557+ std::lock_guard<decltype(mutex)> lock{mutex};
1558+ return weak_session.lock();
1559+}
1560+
1561+void DecorationProvider::handle_event(MirWindow* window, MirEvent const* ev, void* context_)
1562+{
1563+ auto* const context = (Data*)context_;
1564+
1565+ switch (mir_event_get_type(ev))
1566+ {
1567+ case mir_event_type_resize:
1568+ {
1569+ MirResizeEvent const* resize = mir_event_get_resize_event(ev);
1570+ int const new_width = mir_resize_event_get_width(resize);
1571+ int const new_height = mir_resize_event_get_height(resize);
1572+ mir_render_surface_set_size(context->surface, new_width, new_height);
1573+ WindowSpec::for_changes(context->connection)
1574+ .add_surface(context->surface, new_width, new_height, 0, 0)
1575+ .apply_to(window);
1576+ break;
1577+ }
1578+
1579+ default:
1580+ break;
1581+ }
1582+}
1583+
1584+void DecorationProvider::create_titlebar_for(miral::Window const& window)
1585+{
1586+ if (is_decoration(window)) return;
1587+
1588+ enqueue_work([this, window]
1589+ {
1590+ auto const width = window.size().width.as_int();
1591+ std::ostringstream buffer;
1592+ buffer << std::shared_ptr<mir::scene::Surface>(window).get();
1593+
1594+ Surface surface{mir_connection_create_render_surface_sync(this->connection, width, title_bar_height)};
1595+
1596+ std::lock_guard<decltype(mutex)> lock{mutex};
1597+
1598+ auto const data = &window_to_titlebar[window];
1599+ data->connection = connection;
1600+ data->surface = surface;
1601+ data->stream = mir_render_surface_get_buffer_stream(surface, width, title_bar_height, mir_pixel_format_xrgb_8888);
1602+ windows_awaiting_titlebar[buffer.str()] = window;
1603+
1604+ WindowSpec::for_gloss(connection, width, title_bar_height)
1605+ .add_surface(surface, width, title_bar_height, 0, 0)
1606+ .set_name(buffer.str().c_str())
1607+ .set_event_handler(&handle_event, data)
1608+ .create_window(insert, data);
1609+ });
1610+}
1611+
1612+void DecorationProvider::paint_titlebar_for(miral::WindowInfo const& info, int intensity)
1613+{
1614+ if (auto data = find_titlebar_data(info.window()))
1615+ {
1616+ data->intensity = intensity;
1617+
1618+ auto const title = info.name();
1619+
1620+ enqueue_work([this, stream=data->stream, title, intensity]{ paint_surface(stream, title, intensity); });
1621+ }
1622+}
1623+
1624+void DecorationProvider::destroy_titlebar_for(miral::Window const& window)
1625+{
1626+ if (auto data = find_titlebar_data(window))
1627+ {
1628+ if (auto surface = data->titlebar.exchange(nullptr))
1629+ {
1630+ enqueue_work([surface]
1631+ {
1632+ mir_window_release(surface, &null_window_callback, nullptr);
1633+ });
1634+ }
1635+
1636+ if (data->titlebar.load())
1637+ {
1638+ enqueue_work([this, window]
1639+ {
1640+ std::lock_guard<decltype(mutex)> lock{mutex};
1641+ window_to_titlebar.erase(window);
1642+ });
1643+ }
1644+ else
1645+ {
1646+ data->on_create = [this, window](MirWindow*)
1647+ {
1648+ enqueue_work([this, window]
1649+ {
1650+ std::lock_guard<decltype(mutex)> lock{mutex};
1651+ window_to_titlebar.erase(window);
1652+ });
1653+ };
1654+ }
1655+ }
1656+}
1657+
1658+void DecorationProvider::resize_titlebar_for(miral::WindowInfo const& window_info, Size const& size)
1659+{
1660+ auto const window = window_info.window();
1661+
1662+ if (window.size().width == size.width)
1663+ return;
1664+
1665+ if (auto titlebar_window = find_titlebar_window(window))
1666+ {
1667+ titlebar_window.resize({size.width, title_bar_height});
1668+
1669+ repaint_titlebar_for(window_info);
1670+ }
1671+}
1672+
1673+void DecorationProvider::place_new_decoration(miral::WindowSpecification& window_spec)
1674+{
1675+ auto const name = window_spec.name().value();
1676+ if (name == wallpaper_name) return;
1677+
1678+ std::lock_guard<decltype(mutex)> lock{mutex};
1679+
1680+ auto const scene_surface = windows_awaiting_titlebar[name].lock();
1681+ windows_awaiting_titlebar.erase(name);
1682+
1683+ auto& parent_info = tools.info_for(scene_surface);
1684+ auto const parent_window = parent_info.window();
1685+
1686+ window_spec.parent() = scene_surface;
1687+ window_spec.size() = Size{parent_window.size().width, Height{title_bar_height}};
1688+ window_spec.top_left() = parent_window.top_left() - Displacement{0, title_bar_height};
1689+}
1690+
1691+void DecorationProvider::advise_new_titlebar(miral::WindowInfo const& window_info)
1692+{
1693+ if (window_info.name() == wallpaper_name) return;
1694+
1695+ {
1696+ std::lock_guard<decltype(mutex)> lock{mutex};
1697+
1698+ window_to_titlebar[window_info.parent()].window = window_info.window();
1699+ }
1700+
1701+ tools.raise_tree(window_info.parent());
1702+}
1703+
1704+void DecorationProvider::advise_state_change(miral::WindowInfo const& window_info, MirWindowState state)
1705+{
1706+ if (auto titlebar = find_titlebar_window(window_info.window()))
1707+ {
1708+ miral::WindowSpecification modifications;
1709+ switch (state)
1710+ {
1711+ case mir_window_state_hidden:
1712+ case mir_window_state_minimized:
1713+ case mir_window_state_fullscreen:
1714+ modifications.state() = mir_window_state_hidden;
1715+ break;
1716+
1717+ default:
1718+ modifications.state() = mir_window_state_restored;
1719+ break;
1720+ }
1721+
1722+ tools.modify_window(titlebar, modifications);
1723+ repaint_titlebar_for(window_info);
1724+ }
1725+}
1726+
1727+void DecorationProvider::repaint_titlebar_for(miral::WindowInfo const& window_info)
1728+{
1729+ if (auto data = find_titlebar_data(window_info.window()))
1730+ {
1731+ auto const title = window_info.name();
1732+
1733+ enqueue_work([this, stream=data->stream, title, intensity=data->intensity.load()]
1734+ { paint_surface(stream, title, intensity); });
1735+ }
1736+}
1737+
1738+DecorationProvider::Data::~Data()
1739+{
1740+ if (auto surface = titlebar.exchange(nullptr))
1741+ mir_window_release(surface, &null_window_callback, nullptr);
1742+}
1743+
1744+void DecorationProvider::insert(MirWindow* surface, Data* data)
1745+{
1746+ data->on_create(surface);
1747+ data->titlebar = surface;
1748+}
1749+
1750+DecorationProvider::Data* DecorationProvider::find_titlebar_data(miral::Window const& window)
1751+{
1752+ std::lock_guard<decltype(mutex)> lock{mutex};
1753+
1754+ auto const find = window_to_titlebar.find(window);
1755+
1756+ return (find != window_to_titlebar.end()) ? &find->second : nullptr;
1757+}
1758+
1759+miral::Window DecorationProvider::find_titlebar_window(miral::Window const& window) const
1760+{
1761+ std::lock_guard<decltype(mutex)> lock{mutex};
1762+
1763+ auto const find = window_to_titlebar.find(window);
1764+
1765+ return (find != window_to_titlebar.end()) ? find->second.window : miral::Window{};
1766+}
1767+
1768+bool DecorationProvider::is_decoration(miral::Window const& window) const
1769+{
1770+ return window.application() == session();
1771+}
1772+
1773+bool DecorationProvider::is_titlebar(miral::WindowInfo const& window_info) const
1774+{
1775+ return window_info.window().application() == session() && window_info.name() != wallpaper_name;
1776+}
1777+
1778+void DecorationProvider::handle_event_for_background(MirWindow* window, MirEvent const* event, void* context)
1779+{
1780+ static_cast<DecorationProvider*>(context)->handle_event_for_background(window, event);
1781+}
1782+
1783+void DecorationProvider::handle_event_for_background(MirWindow* window, MirEvent const* ev)
1784+{
1785+ switch (mir_event_get_type(ev))
1786+ {
1787+ case mir_event_type_resize:
1788+ {
1789+ MirResizeEvent const* resize = mir_event_get_resize_event(ev);
1790+ int const new_width = mir_resize_event_get_width(resize);
1791+ int const new_height = mir_resize_event_get_height(resize);
1792+
1793+ enqueue_work([window, new_width, new_height, this]()
1794+ {
1795+ auto found = find_if(begin(wallpaper), end(wallpaper), [&](Wallpaper const& w) { return w.window == window;});
1796+ if (found == end(wallpaper)) return;
1797+
1798+ mir_buffer_stream_set_size(found->stream, new_width, new_height);
1799+ mir_render_surface_set_size(found->surface, new_width, new_height);
1800+
1801+ WindowSpec::for_changes(connection)
1802+ .add_surface(found->surface, new_width, new_height, 0, 0)
1803+ .apply_to(window);
1804+
1805+ MirGraphicsRegion graphics_region;
1806+
1807+ // We expect a buffer of the right size so we shouldn't need to limit repaints
1808+ // but we also to avoid an infinite loop.
1809+ int repaint_limit = 3;
1810+
1811+ do
1812+ {
1813+ mir_buffer_stream_get_graphics_region(found->stream, &graphics_region);
1814+ render_background(found->stream, graphics_region);
1815+ }
1816+ while ((new_width != graphics_region.width || new_height != graphics_region.height)
1817+ && --repaint_limit != 0);
1818+ });
1819+ break;
1820+ }
1821+
1822+ default:
1823+ break;
1824+ }
1825+}
1826+
1827+Worker::~Worker()
1828+{
1829+}
1830+
1831+void Worker::do_work()
1832+{
1833+ while (!work_done)
1834+ {
1835+ WorkQueue::value_type work;
1836+ {
1837+ std::unique_lock<decltype(work_mutex)> lock{work_mutex};
1838+ work_cv.wait(lock, [this] { return !work_queue.empty(); });
1839+ work = work_queue.front();
1840+ work_queue.pop();
1841+ }
1842+
1843+ work();
1844+ }
1845+}
1846+
1847+void Worker::enqueue_work(std::function<void()> const& functor)
1848+{
1849+ std::lock_guard<decltype(work_mutex)> lock{work_mutex};
1850+ work_queue.push(functor);
1851+ work_cv.notify_one();
1852+}
1853+
1854+void Worker::start_work()
1855+{
1856+ do_work();
1857+}
1858+
1859+void Worker::stop_work()
1860+{
1861+ enqueue_work([this] { work_done = true; });
1862+}
1863
1864=== added file 'examples/miral-shell/decoration_provider.h'
1865--- examples/miral-shell/decoration_provider.h 1970-01-01 00:00:00 +0000
1866+++ examples/miral-shell/decoration_provider.h 2017-08-29 09:17:20 +0000
1867@@ -0,0 +1,119 @@
1868+/*
1869+ * Copyright © 2016-2017 Canonical Ltd.
1870+ *
1871+ * This program is free software: you can redistribute it and/or modify it
1872+ * under the terms of the GNU General Public License version 2 or 3 as
1873+ * published by the Free Software Foundation.
1874+ *
1875+ * This program is distributed in the hope that it will be useful,
1876+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1877+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1878+ * GNU General Public License for more details.
1879+ *
1880+ * You should have received a copy of the GNU General Public License
1881+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1882+ *
1883+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
1884+ */
1885+
1886+#ifndef MIRAL_SHELL_DECORATION_PROVIDER_H
1887+#define MIRAL_SHELL_DECORATION_PROVIDER_H
1888+
1889+
1890+#include <miral/window_manager_tools.h>
1891+
1892+#include <mir/client/connection.h>
1893+#include <mir/client/surface.h>
1894+#include <mir/client/window.h>
1895+
1896+#include <mir/geometry/rectangle.h>
1897+#include <mir_toolkit/client_types.h>
1898+
1899+#include <atomic>
1900+#include <map>
1901+#include <mutex>
1902+#include <condition_variable>
1903+#include <queue>
1904+
1905+class Worker
1906+{
1907+public:
1908+ ~Worker();
1909+
1910+ void start_work();
1911+ void enqueue_work(std::function<void()> const& functor);
1912+ void stop_work();
1913+
1914+private:
1915+ using WorkQueue = std::queue<std::function<void()>>;
1916+
1917+ std::mutex mutable work_mutex;
1918+ std::condition_variable work_cv;
1919+ WorkQueue work_queue;
1920+ bool work_done = false;
1921+
1922+ void do_work();
1923+};
1924+
1925+class DecorationProvider : Worker
1926+{
1927+public:
1928+ DecorationProvider(miral::WindowManagerTools const& tools);
1929+ ~DecorationProvider();
1930+
1931+ void operator()(mir::client::Connection connection);
1932+ void operator()(std::weak_ptr<mir::scene::Session> const& session);
1933+
1934+ auto session() const -> std::shared_ptr<mir::scene::Session>;
1935+
1936+ void create_titlebar_for(miral::Window const& window);
1937+ void place_new_decoration(miral::WindowSpecification& window_spec);
1938+ void paint_titlebar_for(miral::WindowInfo const& window, int intensity);
1939+ void destroy_titlebar_for(miral::Window const& window);
1940+ void resize_titlebar_for(miral::WindowInfo const& window_info, mir::geometry::Size const& size);
1941+ void advise_new_titlebar(miral::WindowInfo const& window_info);
1942+ void advise_state_change(miral::WindowInfo const& window_info, MirWindowState state);
1943+
1944+ void stop();
1945+
1946+ bool is_decoration(miral::Window const& window) const;
1947+ bool is_titlebar(miral::WindowInfo const& window_info) const;
1948+
1949+private:
1950+ struct Data
1951+ {
1952+ MirConnection* connection{nullptr};
1953+ mir::client::Surface surface;
1954+ MirBufferStream* stream{nullptr};
1955+ std::atomic<MirWindow*> titlebar{nullptr};
1956+ std::atomic<int> intensity{0xff};
1957+ std::function<void(MirWindow* surface)> on_create{[](MirWindow*){}};
1958+ miral::Window window;
1959+
1960+ ~Data();
1961+ };
1962+
1963+ using SurfaceMap = std::map<std::weak_ptr<mir::scene::Surface>, Data, std::owner_less<std::weak_ptr<mir::scene::Surface>>>;
1964+ using TitleMap = std::map<std::string, std::weak_ptr<mir::scene::Surface>>;
1965+
1966+ miral::WindowManagerTools tools;
1967+ std::mutex mutable mutex;
1968+ mir::client::Connection connection;
1969+ struct Wallpaper { mir::client::Surface surface; mir::client::Window window; MirBufferStream* stream; };
1970+ std::vector<Wallpaper> wallpaper;
1971+ std::weak_ptr<mir::scene::Session> weak_session;
1972+
1973+ SurfaceMap window_to_titlebar;
1974+ TitleMap windows_awaiting_titlebar;
1975+
1976+ static void insert(MirWindow* surface, Data* data);
1977+ Data* find_titlebar_data(miral::Window const& window);
1978+ miral::Window find_titlebar_window(miral::Window const& window) const;
1979+ void repaint_titlebar_for(miral::WindowInfo const& window_info);
1980+ static void handle_event(MirWindow* window, MirEvent const* ev, void* context_);
1981+ static void handle_event_for_background(MirWindow* window, MirEvent const* event, void* context_);
1982+ void handle_event_for_background(MirWindow* window, MirEvent const* ev);
1983+};
1984+
1985+
1986+#endif //MIRAL_SHELL_DECORATION_PROVIDER_H
1987
1988=== added directory 'examples/miral-shell/desktop'
1989=== added file 'examples/miral-shell/desktop/CMakeLists.txt'
1990--- examples/miral-shell/desktop/CMakeLists.txt 1970-01-01 00:00:00 +0000
1991+++ examples/miral-shell/desktop/CMakeLists.txt 2017-08-29 09:17:20 +0000
1992@@ -0,0 +1,12 @@
1993+set(ICON_NAME ubuntu-logo)
1994+set(PROGRAM_NAME miral-app)
1995+
1996+configure_file(miral-shell.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/miral-shell.desktop @ONLY)
1997+
1998+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/miral-shell.desktop
1999+ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications
2000+)
2001+
2002+install(FILES ${ICON_NAME}.svg
2003+ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps
2004+)
2005
2006=== added file 'examples/miral-shell/desktop/miral-shell.desktop.in'
2007--- examples/miral-shell/desktop/miral-shell.desktop.in 1970-01-01 00:00:00 +0000
2008+++ examples/miral-shell/desktop/miral-shell.desktop.in 2017-08-29 09:17:20 +0000
2009@@ -0,0 +1,18 @@
2010+[Desktop Entry]
2011+Version=1.0
2012+Name=Miral Shell
2013+GenericName=Mir Shell
2014+Comment=A Mir Shell
2015+Keywords=Mir;Server;Shell
2016+Type=Application
2017+Icon=@ICON_NAME@
2018+Exec=@PROGRAM_NAME@
2019+Terminal=false
2020+Categories=Utility
2021+#MimeType=
2022+X-Ubuntu-Touch=true
2023+X-Ubuntu-Gettext-Domain=miral-shell
2024+X-Ubuntu-Single-Instance=true
2025+X-Ubuntu-Default-Department-ID=miral-shell
2026+#X-Screenshot=
2027+X-Ubuntu-Splash-Color=#FFFFFF
2028
2029=== added file 'examples/miral-shell/desktop/ubuntu-logo.svg'
2030--- examples/miral-shell/desktop/ubuntu-logo.svg 1970-01-01 00:00:00 +0000
2031+++ examples/miral-shell/desktop/ubuntu-logo.svg 2017-08-29 09:17:20 +0000
2032@@ -0,0 +1,27 @@
2033+<?xml version="1.0" encoding="utf-8"?>
2034+<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In -->
2035+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
2036+ <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
2037+]>
2038+<svg version="1.1"
2039+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
2040+ x="0px" y="0px" width="285px" height="285px" viewBox="-0.866 -0.866 285 285" enable-background="new -0.866 -0.866 285 285"
2041+ xml:space="preserve">
2042+<defs>
2043+</defs>
2044+<path fill="#DD4814" d="M283.465,141.734c0,78.273-63.457,141.73-141.734,141.73S0,220.008,0,141.734C0,63.455,63.453,0,141.73,0
2045+ S283.465,63.455,283.465,141.734z"/>
2046+<path fill="#FFFFFF" d="M45.356,122.812c-10.453,0-18.923,8.47-18.923,18.923c0,10.449,8.47,18.92,18.923,18.92
2047+ c10.449,0,18.92-8.471,18.92-18.92C64.276,131.281,55.806,122.812,45.356,122.812z M180.463,208.814
2048+ c-9.051,5.225-12.149,16.793-6.926,25.84c5.226,9.051,16.793,12.151,25.844,6.926c9.048-5.224,12.148-16.792,6.923-25.842
2049+ C201.08,206.691,189.511,203.59,180.463,208.814z M86.458,141.732c0-18.701,9.293-35.219,23.504-45.221L96.128,73.338
2050+ c-16.56,11.064-28.878,27.978-33.995,47.788c5.977,4.872,9.796,12.291,9.796,20.608c0,8.315-3.819,15.734-9.797,20.605
2051+ c5.116,19.812,17.435,36.726,33.995,47.789l13.835-23.175C95.751,176.953,86.458,160.436,86.458,141.732z M141.733,86.457
2052+ c28.877,0,52.564,22.141,55.047,50.373l26.968-0.394c-1.327-20.844-10.432-39.562-24.425-53.319
2053+ c-7.194,2.718-15.505,2.306-22.688-1.842c-7.192-4.152-11.705-11.156-12.941-18.757c-6.992-1.935-14.351-2.99-21.96-2.99
2054+ c-13.086,0-25.449,3.072-36.431,8.512l13.146,23.56C125.526,88.307,133.412,86.457,141.733,86.457z M141.733,197.008
2055+ c-8.322,0-16.207-1.85-23.285-5.143L105.3,215.427c10.983,5.438,23.347,8.511,36.433,8.511c7.609,0,14.968-1.055,21.961-2.99
2056+ c1.236-7.601,5.75-14.605,12.943-18.76c7.183-4.146,15.494-4.558,22.688-1.839c13.992-13.758,23.097-32.476,24.422-53.32
2057+ l-26.968-0.394C194.298,174.871,170.61,197.008,141.733,197.008z M180.46,74.649c9.05,5.227,20.619,2.126,25.842-6.921
2058+ c5.226-9.051,2.128-20.619-6.923-25.845c-9.049-5.224-20.617-2.124-25.843,6.927C168.312,57.857,171.412,69.426,180.46,74.649z"/>
2059+</svg>
2060
2061=== added file 'examples/miral-shell/floating_window_manager.cpp'
2062--- examples/miral-shell/floating_window_manager.cpp 1970-01-01 00:00:00 +0000
2063+++ examples/miral-shell/floating_window_manager.cpp 2017-08-29 09:17:20 +0000
2064@@ -0,0 +1,801 @@
2065+/*
2066+ * Copyright © 2016-2017 Canonical Ltd.
2067+ *
2068+ * This program is free software: you can redistribute it and/or modify it
2069+ * under the terms of the GNU General Public License version 2 or 3 as
2070+ * published by the Free Software Foundation.
2071+ *
2072+ * This program is distributed in the hope that it will be useful,
2073+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2074+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2075+ * GNU General Public License for more details.
2076+ *
2077+ * You should have received a copy of the GNU General Public License
2078+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2079+ *
2080+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
2081+ */
2082+
2083+#include "floating_window_manager.h"
2084+#include "decoration_provider.h"
2085+
2086+#include <miral/application_info.h>
2087+#include <miral/internal_client.h>
2088+#include <miral/window_info.h>
2089+#include <miral/window_manager_tools.h>
2090+
2091+#include <linux/input.h>
2092+#include <csignal>
2093+
2094+using namespace miral;
2095+
2096+namespace
2097+{
2098+DeltaY const title_bar_height{12};
2099+
2100+struct PolicyData
2101+{
2102+ bool in_hidden_workspace{false};
2103+
2104+ MirWindowState old_state;
2105+};
2106+
2107+inline PolicyData& policy_data_for(WindowInfo const& info)
2108+{
2109+ return *std::static_pointer_cast<PolicyData>(info.userdata());
2110+}
2111+}
2112+
2113+FloatingWindowManagerPolicy::FloatingWindowManagerPolicy(
2114+ WindowManagerTools const& tools,
2115+ SpinnerSplash const& spinner,
2116+ miral::InternalClientLauncher const& launcher,
2117+ std::function<void()>& shutdown_hook) :
2118+ CanonicalWindowManagerPolicy(tools),
2119+ spinner{spinner},
2120+ decoration_provider{std::make_unique<DecorationProvider>(tools)}
2121+{
2122+ launcher.launch("decorations", *decoration_provider);
2123+ shutdown_hook = [this] { decoration_provider->stop(); };
2124+
2125+ for (auto key : {KEY_F1, KEY_F2, KEY_F3, KEY_F4})
2126+ key_to_workspace[key] = this->tools.create_workspace();
2127+
2128+ active_workspace = key_to_workspace[KEY_F1];
2129+}
2130+
2131+FloatingWindowManagerPolicy::~FloatingWindowManagerPolicy() = default;
2132+
2133+bool FloatingWindowManagerPolicy::handle_pointer_event(MirPointerEvent const* event)
2134+{
2135+ auto const action = mir_pointer_event_action(event);
2136+ auto const modifiers = mir_pointer_event_modifiers(event) & modifier_mask;
2137+ Point const cursor{
2138+ mir_pointer_event_axis_value(event, mir_pointer_axis_x),
2139+ mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
2140+
2141+ bool consumes_event = false;
2142+ bool is_resize_event = false;
2143+
2144+ if (action == mir_pointer_action_button_down)
2145+ {
2146+ if (auto const window = tools.window_at(cursor))
2147+ tools.select_active_window(window);
2148+ }
2149+ else if (action == mir_pointer_action_motion &&
2150+ modifiers == mir_input_event_modifier_alt)
2151+ {
2152+ if (mir_pointer_event_button_state(event, mir_pointer_button_primary))
2153+ {
2154+ if (auto const target = tools.window_at(old_cursor))
2155+ {
2156+ if (tools.select_active_window(target) == target)
2157+ tools.drag_active_window(cursor - old_cursor);
2158+ }
2159+ consumes_event = true;
2160+ }
2161+
2162+ if (mir_pointer_event_button_state(event, mir_pointer_button_tertiary))
2163+ {
2164+ { // Workaround for lp:1627697
2165+ auto now = std::chrono::steady_clock::now();
2166+ if (resizing && now < last_resize+std::chrono::milliseconds(20))
2167+ return true;
2168+
2169+ last_resize = now;
2170+ }
2171+
2172+ if (!resizing)
2173+ tools.select_active_window(tools.window_at(old_cursor));
2174+ is_resize_event = resize(tools.active_window(), cursor, old_cursor);
2175+ consumes_event = true;
2176+ }
2177+ }
2178+
2179+ if (!consumes_event && action == mir_pointer_action_motion && !modifiers)
2180+ {
2181+ if (mir_pointer_event_button_state(event, mir_pointer_button_primary))
2182+ {
2183+ if (auto const possible_titlebar = tools.window_at(old_cursor))
2184+ {
2185+ auto const& info = tools.info_for(possible_titlebar);
2186+ if (decoration_provider->is_titlebar(info))
2187+ {
2188+ if (tools.select_active_window(info.parent()) == info.parent())
2189+ tools.drag_active_window(cursor - old_cursor);
2190+ consumes_event = true;
2191+ }
2192+ }
2193+ }
2194+ }
2195+
2196+ if (resizing && !is_resize_event)
2197+ end_resize();
2198+
2199+ resizing = is_resize_event;
2200+ old_cursor = cursor;
2201+ return consumes_event;
2202+}
2203+
2204+void FloatingWindowManagerPolicy::end_resize()
2205+{
2206+ if (!resizing && !pinching)
2207+ return;
2208+
2209+ if (auto window = tools.active_window())
2210+ {
2211+ auto& window_info = tools.info_for(window);
2212+
2213+ auto new_size = window.size();
2214+ auto new_pos = window.top_left();
2215+ window_info.constrain_resize(new_pos, new_size);
2216+
2217+ WindowSpecification modifications;
2218+ modifications.top_left() = new_pos;
2219+ modifications.size() = new_size;
2220+ tools.modify_window(window_info, modifications);
2221+ }
2222+
2223+ resizing = false;
2224+ pinching = false;
2225+}
2226+
2227+bool FloatingWindowManagerPolicy::handle_touch_event(MirTouchEvent const* event)
2228+{
2229+ auto const count = mir_touch_event_point_count(event);
2230+
2231+ long total_x = 0;
2232+ long total_y = 0;
2233+
2234+ for (auto i = 0U; i != count; ++i)
2235+ {
2236+ total_x += mir_touch_event_axis_value(event, i, mir_touch_axis_x);
2237+ total_y += mir_touch_event_axis_value(event, i, mir_touch_axis_y);
2238+ }
2239+
2240+ Point cursor{total_x/count, total_y/count};
2241+
2242+ bool is_drag = true;
2243+ for (auto i = 0U; i != count; ++i)
2244+ {
2245+ switch (mir_touch_event_action(event, i))
2246+ {
2247+ case mir_touch_action_up:
2248+ return false;
2249+
2250+ case mir_touch_action_down:
2251+ is_drag = false;
2252+ continue;
2253+
2254+ default:
2255+ continue;
2256+ }
2257+ }
2258+
2259+ int touch_pinch_top = std::numeric_limits<int>::max();
2260+ int touch_pinch_left = std::numeric_limits<int>::max();
2261+ int touch_pinch_width = 0;
2262+ int touch_pinch_height = 0;
2263+
2264+ for (auto i = 0U; i != count; ++i)
2265+ {
2266+ for (auto j = 0U; j != i; ++j)
2267+ {
2268+ int dx = mir_touch_event_axis_value(event, i, mir_touch_axis_x) -
2269+ mir_touch_event_axis_value(event, j, mir_touch_axis_x);
2270+
2271+ int dy = mir_touch_event_axis_value(event, i, mir_touch_axis_y) -
2272+ mir_touch_event_axis_value(event, j, mir_touch_axis_y);
2273+
2274+ if (touch_pinch_width < dx)
2275+ touch_pinch_width = dx;
2276+
2277+ if (touch_pinch_height < dy)
2278+ touch_pinch_height = dy;
2279+ }
2280+
2281+ int const x = mir_touch_event_axis_value(event, i, mir_touch_axis_x);
2282+
2283+ int const y = mir_touch_event_axis_value(event, i, mir_touch_axis_y);
2284+
2285+ if (touch_pinch_top > y)
2286+ touch_pinch_top = y;
2287+
2288+ if (touch_pinch_left > x)
2289+ touch_pinch_left = x;
2290+ }
2291+
2292+ bool consumes_event = false;
2293+ if (is_drag)
2294+ {
2295+ if (count == 3)
2296+ {
2297+ if (auto window = tools.active_window())
2298+ {
2299+ auto const old_size = window.size();
2300+ auto const delta_width = DeltaX{touch_pinch_width - old_touch_pinch_width};
2301+ auto const delta_height = DeltaY{touch_pinch_height - old_touch_pinch_height};
2302+
2303+ auto new_width = std::max(old_size.width + delta_width, Width{5});
2304+ auto new_height = std::max(old_size.height + delta_height, Height{5});
2305+ Displacement movement{
2306+ DeltaX{touch_pinch_left - old_touch_pinch_left},
2307+ DeltaY{touch_pinch_top - old_touch_pinch_top}};
2308+
2309+ auto& window_info = tools.info_for(window);
2310+ keep_window_within_constraints(window_info, movement, new_width, new_height);
2311+
2312+ auto new_pos = window.top_left() + movement;
2313+ Size new_size{new_width, new_height};
2314+
2315+ { // Workaround for lp:1627697
2316+ auto now = std::chrono::steady_clock::now();
2317+ if (pinching && now < last_resize+std::chrono::milliseconds(20))
2318+ return true;
2319+
2320+ last_resize = now;
2321+ }
2322+
2323+ WindowSpecification modifications;
2324+ modifications.top_left() = new_pos;
2325+ modifications.size() = new_size;
2326+ tools.modify_window(window_info, modifications);
2327+ pinching = true;
2328+ }
2329+ consumes_event = true;
2330+ }
2331+ }
2332+ else
2333+ {
2334+ if (auto const& window = tools.window_at(cursor))
2335+ tools.select_active_window(window);
2336+ }
2337+
2338+ if (!consumes_event && pinching)
2339+ end_resize();
2340+
2341+ old_cursor = cursor;
2342+ old_touch_pinch_top = touch_pinch_top;
2343+ old_touch_pinch_left = touch_pinch_left;
2344+ old_touch_pinch_width = touch_pinch_width;
2345+ old_touch_pinch_height = touch_pinch_height;
2346+ return consumes_event;
2347+}
2348+
2349+void FloatingWindowManagerPolicy::advise_new_window(WindowInfo const& window_info)
2350+{
2351+ CanonicalWindowManagerPolicy::advise_new_window(window_info);
2352+
2353+ auto const parent = window_info.parent();
2354+
2355+ if (decoration_provider->is_titlebar(window_info))
2356+ {
2357+ decoration_provider->advise_new_titlebar(window_info);
2358+
2359+ if (tools.active_window() == parent)
2360+ decoration_provider->paint_titlebar_for(tools.info_for(parent), 0xFF);
2361+ else
2362+ decoration_provider->paint_titlebar_for(tools.info_for(parent), 0x3F);
2363+ }
2364+
2365+ if (!parent)
2366+ tools.add_tree_to_workspace(window_info.window(), active_workspace);
2367+ else
2368+ {
2369+ if (policy_data_for(tools.info_for(parent)).in_hidden_workspace)
2370+ apply_workspace_hidden_to(window_info.window());
2371+ }
2372+}
2373+
2374+void FloatingWindowManagerPolicy::handle_window_ready(WindowInfo& window_info)
2375+{
2376+ if (window_info.window().application() != spinner.session() && window_info.needs_titlebar(window_info.type()))
2377+ decoration_provider->create_titlebar_for(window_info.window());
2378+
2379+ CanonicalWindowManagerPolicy::handle_window_ready(window_info);
2380+ keep_spinner_on_top();
2381+}
2382+
2383+void FloatingWindowManagerPolicy::advise_focus_lost(WindowInfo const& info)
2384+{
2385+ CanonicalWindowManagerPolicy::advise_focus_lost(info);
2386+
2387+ decoration_provider->paint_titlebar_for(info, 0x3F);
2388+}
2389+
2390+void FloatingWindowManagerPolicy::advise_focus_gained(WindowInfo const& info)
2391+{
2392+ CanonicalWindowManagerPolicy::advise_focus_gained(info);
2393+
2394+ decoration_provider->paint_titlebar_for(info, 0xFF);
2395+ keep_spinner_on_top();
2396+}
2397+
2398+void FloatingWindowManagerPolicy::keep_spinner_on_top()
2399+{
2400+ // Frig to force the spinner to the top
2401+ if (auto const spinner_session = spinner.session())
2402+ {
2403+ auto const& spinner_info = tools.info_for(spinner_session);
2404+
2405+ for (auto const& window : spinner_info.windows())
2406+ tools.raise_tree(window);
2407+ }
2408+}
2409+
2410+void FloatingWindowManagerPolicy::advise_state_change(WindowInfo const& window_info, MirWindowState state)
2411+{
2412+ CanonicalWindowManagerPolicy::advise_state_change(window_info, state);
2413+
2414+ decoration_provider->advise_state_change(window_info, state);
2415+}
2416+
2417+void FloatingWindowManagerPolicy::advise_resize(WindowInfo const& window_info, Size const& new_size)
2418+{
2419+ CanonicalWindowManagerPolicy::advise_resize(window_info, new_size);
2420+
2421+ decoration_provider->resize_titlebar_for(window_info, new_size);
2422+}
2423+
2424+void FloatingWindowManagerPolicy::advise_delete_window(WindowInfo const& window_info)
2425+{
2426+ CanonicalWindowManagerPolicy::advise_delete_window(window_info);
2427+
2428+ decoration_provider->destroy_titlebar_for(window_info.window());
2429+}
2430+
2431+bool FloatingWindowManagerPolicy::handle_keyboard_event(MirKeyboardEvent const* event)
2432+{
2433+ auto const action = mir_keyboard_event_action(event);
2434+ auto const scan_code = mir_keyboard_event_scan_code(event);
2435+ auto const modifiers = mir_keyboard_event_modifiers(event) & modifier_mask;
2436+
2437+ // Switch workspaces
2438+ if (action == mir_keyboard_action_down &&
2439+ modifiers == (mir_input_event_modifier_alt | mir_input_event_modifier_meta))
2440+ {
2441+ auto const found = key_to_workspace.find(scan_code);
2442+
2443+ if (found != key_to_workspace.end())
2444+ {
2445+ switch_workspace_to(found->second);
2446+ return true;
2447+ }
2448+ }
2449+
2450+ // Switch workspace taking the active window
2451+ if (action == mir_keyboard_action_down &&
2452+ modifiers == (mir_input_event_modifier_ctrl | mir_input_event_modifier_meta))
2453+ {
2454+ auto const found = key_to_workspace.find(scan_code);
2455+
2456+ if (found != key_to_workspace.end())
2457+ {
2458+ switch_workspace_to(found->second, tools.active_window());
2459+ return true;
2460+ }
2461+ }
2462+
2463+ if (action != mir_keyboard_action_repeat)
2464+ end_resize();
2465+
2466+ if (action == mir_keyboard_action_down && scan_code == KEY_F11)
2467+ {
2468+ switch (modifiers)
2469+ {
2470+ case mir_input_event_modifier_alt:
2471+ toggle(mir_window_state_maximized);
2472+ return true;
2473+
2474+ case mir_input_event_modifier_shift:
2475+ toggle(mir_window_state_vertmaximized);
2476+ return true;
2477+
2478+ case mir_input_event_modifier_ctrl:
2479+ toggle(mir_window_state_horizmaximized);
2480+ return true;
2481+
2482+ case mir_input_event_modifier_meta:
2483+ toggle(mir_window_state_fullscreen);
2484+ return true;
2485+
2486+ default:
2487+ break;
2488+ }
2489+ }
2490+ else if (action == mir_keyboard_action_down && scan_code == KEY_F4)
2491+ {
2492+ switch (modifiers)
2493+ {
2494+ case mir_input_event_modifier_alt|mir_input_event_modifier_shift:
2495+ if (auto const& window = tools.active_window())
2496+ kill(window.application(), SIGTERM);
2497+ return true;
2498+
2499+ case mir_input_event_modifier_alt:
2500+ tools.ask_client_to_close(tools.active_window());;
2501+ return true;
2502+
2503+ default:
2504+ break;
2505+ }
2506+ }
2507+ else if (action == mir_keyboard_action_down &&
2508+ modifiers == mir_input_event_modifier_alt &&
2509+ scan_code == KEY_TAB)
2510+ {
2511+ tools.focus_next_application();
2512+
2513+ return true;
2514+ }
2515+ else if (action == mir_keyboard_action_down &&
2516+ modifiers == mir_input_event_modifier_alt &&
2517+ scan_code == KEY_GRAVE)
2518+ {
2519+ tools.focus_next_within_application();
2520+
2521+ return true;
2522+ }
2523+ else if (action == mir_keyboard_action_down &&
2524+ modifiers == (mir_input_event_modifier_alt | mir_input_event_modifier_shift) &&
2525+ scan_code == KEY_GRAVE)
2526+ {
2527+ tools.focus_prev_within_application();
2528+
2529+ return true;
2530+ }
2531+ else if (action == mir_keyboard_action_down &&
2532+ modifiers == (mir_input_event_modifier_ctrl|mir_input_event_modifier_meta))
2533+ {
2534+ if (auto active_window = tools.active_window())
2535+ {
2536+ auto active_output = tools.active_output();
2537+ auto& window_info = tools.info_for(active_window);
2538+ WindowSpecification modifications;
2539+
2540+ switch (scan_code)
2541+ {
2542+ case KEY_LEFT:
2543+ modifications.state() = mir_window_state_vertmaximized;
2544+ tools.place_and_size_for_state(modifications, window_info);
2545+ modifications.top_left() = active_output.top_left + title_bar_height;
2546+ break;
2547+
2548+ case KEY_RIGHT:
2549+ modifications.state() = mir_window_state_vertmaximized;
2550+ tools.place_and_size_for_state(modifications, window_info);
2551+ modifications.top_left() = active_output.top_right() -
2552+ as_displacement({active_window.size().width, 0}) + title_bar_height;
2553+ break;
2554+
2555+ case KEY_UP:
2556+ modifications.state() = mir_window_state_horizmaximized;
2557+ tools.place_and_size_for_state(modifications, window_info);
2558+
2559+ modifications.top_left() = active_output.top_left + title_bar_height;
2560+ break;
2561+
2562+ case KEY_DOWN:
2563+ modifications.state() = mir_window_state_horizmaximized;
2564+ tools.place_and_size_for_state(modifications, window_info);
2565+
2566+ modifications.top_left() = active_output.bottom_right() - as_displacement(
2567+ modifications.size().is_set() ? modifications.size().value() : active_window.size());
2568+ break;
2569+
2570+ default:
2571+ return false;
2572+ }
2573+
2574+ tools.modify_window(window_info, modifications);
2575+ return true;
2576+ }
2577+ }
2578+
2579+ return false;
2580+}
2581+
2582+void FloatingWindowManagerPolicy::toggle(MirWindowState state)
2583+{
2584+ if (auto const window = tools.active_window())
2585+ {
2586+ auto& info = tools.info_for(window);
2587+
2588+ WindowSpecification modifications;
2589+
2590+ modifications.state() = (info.state() == state) ? mir_window_state_restored : state;
2591+ tools.place_and_size_for_state(modifications, info);
2592+ tools.modify_window(info, modifications);
2593+ }
2594+}
2595+
2596+bool FloatingWindowManagerPolicy::resize(Window const& window, Point cursor, Point old_cursor)
2597+{
2598+ if (!window)
2599+ return false;
2600+
2601+ auto& window_info = tools.info_for(window);
2602+
2603+ auto const top_left = window.top_left();
2604+ Rectangle const old_pos{top_left, window.size()};
2605+
2606+ if (!resizing)
2607+ {
2608+ auto anchor = old_pos.bottom_right();
2609+
2610+ for (auto const& corner : {
2611+ old_pos.top_right(),
2612+ old_pos.bottom_left(),
2613+ top_left})
2614+ {
2615+ if ((old_cursor - anchor).length_squared() <
2616+ (old_cursor - corner).length_squared())
2617+ {
2618+ anchor = corner;
2619+ }
2620+ }
2621+
2622+ left_resize = anchor.x != top_left.x;
2623+ top_resize = anchor.y != top_left.y;
2624+ }
2625+
2626+ int const x_sign = left_resize? -1 : 1;
2627+ int const y_sign = top_resize? -1 : 1;
2628+
2629+ auto movement = cursor-old_cursor;
2630+
2631+ auto new_width = old_pos.size.width + x_sign * movement.dx;
2632+ auto new_height = old_pos.size.height + y_sign * movement.dy;
2633+
2634+ keep_window_within_constraints(window_info, movement, new_width, new_height);
2635+
2636+ Size new_size{new_width, new_height};
2637+ Point new_pos = top_left + left_resize*movement.dx + top_resize*movement.dy;
2638+
2639+ WindowSpecification modifications;
2640+ modifications.top_left() = new_pos;
2641+ modifications.size() = new_size;
2642+ tools.modify_window(window, modifications);
2643+
2644+ return true;
2645+}
2646+
2647+void FloatingWindowManagerPolicy::keep_window_within_constraints(
2648+ WindowInfo const& window_info, Displacement& movement, Width& new_width, Height& new_height) const
2649+{
2650+ switch (window_info.state())
2651+ {
2652+ case mir_window_state_maximized:
2653+ case mir_window_state_fullscreen:
2654+ new_width = window_info.window().size().width;
2655+ new_height = window_info.window().size().height;
2656+ movement = {0, 0};
2657+ break;
2658+
2659+ case mir_window_state_vertmaximized:
2660+ new_height = window_info.window().size().height;
2661+ movement.dy = DeltaY{0};
2662+ break;
2663+
2664+ case mir_window_state_horizmaximized:
2665+ new_width = window_info.window().size().width;
2666+ movement.dx - DeltaX{0};
2667+ break;
2668+
2669+ default:;
2670+ }
2671+
2672+ auto const min_width = std::max(window_info.min_width(), Width{5});
2673+ auto const min_height = std::max(window_info.min_height(), Height{5});
2674+
2675+ if (new_width < min_width)
2676+ {
2677+ new_width = min_width;
2678+ if (movement.dx > DeltaX{0})
2679+ movement.dx = DeltaX{0};
2680+ }
2681+
2682+ if (new_height < min_height)
2683+ {
2684+ new_height = min_height;
2685+ if (movement.dy > DeltaY{0})
2686+ movement.dy = DeltaY{0};
2687+ }
2688+
2689+ auto const max_width = window_info.max_width();
2690+ auto const max_height = window_info.max_height();
2691+
2692+ if (new_width > max_width)
2693+ {
2694+ new_width = max_width;
2695+ if (movement.dx < DeltaX{0})
2696+ movement.dx = DeltaX{0};
2697+ }
2698+
2699+ if (new_height > max_height)
2700+ {
2701+ new_height = max_height;
2702+ if (movement.dy < DeltaY{0})
2703+ movement.dy = DeltaY{0};
2704+ }
2705+}
2706+
2707+WindowSpecification FloatingWindowManagerPolicy::place_new_window(
2708+ ApplicationInfo const& app_info, WindowSpecification const& request_parameters)
2709+{
2710+ auto parameters = CanonicalWindowManagerPolicy::place_new_window(app_info, request_parameters);
2711+
2712+ bool const needs_titlebar = WindowInfo::needs_titlebar(parameters.type().value());
2713+
2714+ if (parameters.state().value() != mir_window_state_fullscreen && needs_titlebar)
2715+ parameters.top_left() = Point{parameters.top_left().value().x, parameters.top_left().value().y + title_bar_height};
2716+
2717+ if (app_info.application() == decoration_provider->session())
2718+ decoration_provider->place_new_decoration(parameters);
2719+
2720+ parameters.userdata() = std::make_shared<PolicyData>();
2721+ return parameters;
2722+}
2723+
2724+void FloatingWindowManagerPolicy::advise_adding_to_workspace(
2725+ std::shared_ptr<Workspace> const& workspace, std::vector<Window> const& windows)
2726+{
2727+ if (windows.empty())
2728+ return;
2729+
2730+ for (auto const& window : windows)
2731+ {
2732+ if (workspace == active_workspace)
2733+ {
2734+ apply_workspace_visible_to(window);
2735+ }
2736+ else
2737+ {
2738+ apply_workspace_hidden_to(window);
2739+ }
2740+ }
2741+}
2742+
2743+auto FloatingWindowManagerPolicy::confirm_placement_on_display(
2744+ miral::WindowInfo const& /*window_info*/, MirWindowState new_state, Rectangle const& new_placement) -> Rectangle
2745+{
2746+ switch (new_state)
2747+ {
2748+ default:
2749+ return new_placement;
2750+
2751+ case mir_window_state_maximized:
2752+ case mir_window_state_vertmaximized:
2753+ auto result = new_placement;
2754+
2755+ result.top_left.y = result.top_left.y + title_bar_height;
2756+ result.size.height = result.size.height - title_bar_height;
2757+ return result;
2758+ }
2759+}
2760+
2761+void FloatingWindowManagerPolicy::switch_workspace_to(
2762+ std::shared_ptr<Workspace> const& workspace,
2763+ Window const& window)
2764+{
2765+ if (workspace == active_workspace)
2766+ return;
2767+
2768+ auto const old_active = active_workspace;
2769+ active_workspace = workspace;
2770+
2771+ auto const old_active_window = tools.active_window();
2772+
2773+ if (!old_active_window)
2774+ {
2775+ // If there's no active window, the first shown grabs focus: get the right one
2776+ if (auto const ww = workspace_to_active[workspace])
2777+ {
2778+ tools.for_each_workspace_containing(ww, [&](std::shared_ptr<miral::Workspace> const& ws)
2779+ {
2780+ if (ws == workspace)
2781+ {
2782+ apply_workspace_visible_to(ww);
2783+ }
2784+ });
2785+ }
2786+ }
2787+
2788+ tools.remove_tree_from_workspace(window, old_active);
2789+ tools.add_tree_to_workspace(window, active_workspace);
2790+
2791+ tools.for_each_window_in_workspace(active_workspace, [&](Window const& window)
2792+ {
2793+ if (decoration_provider->is_decoration(window))
2794+ return; // decorations are taken care of automatically
2795+
2796+ apply_workspace_visible_to(window);
2797+ });
2798+
2799+ bool hide_old_active = false;
2800+ tools.for_each_window_in_workspace(old_active, [&](Window const& window)
2801+ {
2802+ if (decoration_provider->is_decoration(window))
2803+ return; // decorations are taken care of automatically
2804+
2805+ if (window == old_active_window)
2806+ {
2807+ // If we hide the active window focus will shift: do that last
2808+ hide_old_active = true;
2809+ return;
2810+ }
2811+
2812+ apply_workspace_hidden_to(window);
2813+ });
2814+
2815+ if (hide_old_active)
2816+ {
2817+ apply_workspace_hidden_to(old_active_window);
2818+
2819+ // Remember the old active_window when we switch away
2820+ workspace_to_active[old_active] = old_active_window;
2821+ }
2822+}
2823+
2824+void FloatingWindowManagerPolicy::apply_workspace_hidden_to(Window const& window)
2825+{
2826+ auto const& window_info = tools.info_for(window);
2827+ auto& pdata = policy_data_for(window_info);
2828+ if (!pdata.in_hidden_workspace)
2829+ {
2830+ pdata.in_hidden_workspace = true;
2831+ pdata.old_state = window_info.state();
2832+
2833+ WindowSpecification modifications;
2834+ modifications.state() = mir_window_state_hidden;
2835+ tools.place_and_size_for_state(modifications, window_info);
2836+ tools.modify_window(window_info.window(), modifications);
2837+ }
2838+}
2839+
2840+void FloatingWindowManagerPolicy::apply_workspace_visible_to(Window const& window)
2841+{
2842+ auto const& window_info = tools.info_for(window);
2843+ auto& pdata = policy_data_for(window_info);
2844+ if (pdata.in_hidden_workspace)
2845+ {
2846+ pdata.in_hidden_workspace = false;
2847+ WindowSpecification modifications;
2848+ modifications.state() = pdata.old_state;
2849+ tools.place_and_size_for_state(modifications, window_info);
2850+ tools.modify_window(window_info.window(), modifications);
2851+ }
2852+}
2853+
2854+void FloatingWindowManagerPolicy::handle_modify_window(WindowInfo& window_info, WindowSpecification const& modifications)
2855+{
2856+ auto mods = modifications;
2857+
2858+ auto& pdata = policy_data_for(window_info);
2859+
2860+ if (pdata.in_hidden_workspace && mods.state().is_set())
2861+ pdata.old_state = mods.state().consume();
2862+
2863+ CanonicalWindowManagerPolicy::handle_modify_window(window_info, mods);
2864+}
2865+
2866
2867=== added file 'examples/miral-shell/floating_window_manager.h'
2868--- examples/miral-shell/floating_window_manager.h 1970-01-01 00:00:00 +0000
2869+++ examples/miral-shell/floating_window_manager.h 2017-08-29 09:17:20 +0000
2870@@ -0,0 +1,146 @@
2871+/*
2872+ * Copyright © 2016-2017 Canonical Ltd.
2873+ *
2874+ * This program is free software: you can redistribute it and/or modify it
2875+ * under the terms of the GNU General Public License version 2 or 3 as
2876+ * published by the Free Software Foundation.
2877+ *
2878+ * This program is distributed in the hope that it will be useful,
2879+ * but WITHOUT ANY WARRANTY; without even the implied warranty ofb
2880+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2881+ * GNU General Public License for more details.
2882+ *
2883+ * You should have received a copy of the GNU General Public License
2884+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2885+ *
2886+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
2887+ */
2888+
2889+#ifndef MIRAL_SHELL_FLOATING_WINDOW_MANAGER_H
2890+#define MIRAL_SHELL_FLOATING_WINDOW_MANAGER_H
2891+
2892+#include <miral/canonical_window_manager.h>
2893+#include <miral/window_management_policy_addendum3.h>
2894+#include <miral/workspace_policy.h>
2895+
2896+
2897+#include "spinner/splash.h"
2898+
2899+#include <chrono>
2900+#include <map>
2901+
2902+namespace miral { class InternalClientLauncher; }
2903+
2904+using namespace mir::geometry;
2905+
2906+class DecorationProvider;
2907+
2908+class FloatingWindowManagerPolicy : public miral::CanonicalWindowManagerPolicy,
2909+ public miral::WorkspacePolicy, public miral::WindowManagementPolicyAddendum3
2910+{
2911+public:
2912+ FloatingWindowManagerPolicy(
2913+ miral::WindowManagerTools const& tools,
2914+ SpinnerSplash const& spinner,
2915+ miral::InternalClientLauncher const& launcher,
2916+ std::function<void()>& shutdown_hook);
2917+ ~FloatingWindowManagerPolicy();
2918+
2919+ virtual miral::WindowSpecification place_new_window(
2920+ miral::ApplicationInfo const& app_info, miral::WindowSpecification const& request_parameters) override;
2921+
2922+ /** @name example event handling:
2923+ * o Switch apps: Alt+Tab, tap or click on the corresponding window
2924+ * o Switch window: Alt+`, tap or click on the corresponding window
2925+ * o Move window: Alt-leftmousebutton drag (three finger drag)
2926+ * o Resize window: Alt-middle_button drag (three finger pinch)
2927+ * o Maximize/restore current window (to display size): Alt-F11
2928+ * o Maximize/restore current window (to display height): Shift-F11
2929+ * o Maximize/restore current window (to display width): Ctrl-F11
2930+ * o Switch workspace . . . . . . . . . . : Meta-Alt-[F1|F2|F3|F4]
2931+ * o Switch workspace taking active window: Meta-Ctrl-[F1|F2|F3|F4]
2932+ * @{ */
2933+ bool handle_pointer_event(MirPointerEvent const* event) override;
2934+ bool handle_touch_event(MirTouchEvent const* event) override;
2935+ bool handle_keyboard_event(MirKeyboardEvent const* event) override;
2936+ /** @} */
2937+
2938+ /** @name track events that affect titlebar
2939+ * @{ */
2940+ void advise_new_window(miral::WindowInfo const& window_info) override;
2941+ void handle_window_ready(miral::WindowInfo& window_info) override;
2942+ void advise_focus_lost(miral::WindowInfo const& info) override;
2943+ void advise_focus_gained(miral::WindowInfo const& info) override;
2944+ void advise_state_change(miral::WindowInfo const& window_info, MirWindowState state) override;
2945+ void advise_resize(miral::WindowInfo const& window_info, Size const& new_size) override;
2946+ void advise_delete_window(miral::WindowInfo const& window_info) override;
2947+
2948+ void handle_modify_window(miral::WindowInfo& window_info, miral::WindowSpecification const& modifications) override;
2949+ /** @} */
2950+
2951+protected:
2952+ static const int modifier_mask =
2953+ mir_input_event_modifier_alt |
2954+ mir_input_event_modifier_shift |
2955+ mir_input_event_modifier_sym |
2956+ mir_input_event_modifier_ctrl |
2957+ mir_input_event_modifier_meta;
2958+
2959+private:
2960+ void toggle(MirWindowState state);
2961+
2962+ bool resize(miral::Window const& window, Point cursor, Point old_cursor);
2963+
2964+ Point old_cursor{};
2965+
2966+ bool resizing = false;
2967+ bool left_resize = false;
2968+ bool top_resize = false;
2969+
2970+ int old_touch_pinch_top = 0;
2971+ int old_touch_pinch_left = 0;
2972+ int old_touch_pinch_width = 0;
2973+ int old_touch_pinch_height = 0;
2974+ bool pinching = false;
2975+
2976+ SpinnerSplash const spinner;
2977+
2978+ std::unique_ptr<DecorationProvider> const decoration_provider;
2979+
2980+ void end_resize();
2981+
2982+ void keep_window_within_constraints(
2983+ miral::WindowInfo const& window_info,
2984+ Displacement& movement,
2985+ Width& new_width,
2986+ Height& new_height) const;
2987+
2988+ // Workaround for lp:1627697
2989+ std::chrono::steady_clock::time_point last_resize;
2990+
2991+ void advise_adding_to_workspace(
2992+ std::shared_ptr<miral::Workspace> const& workspace,
2993+ std::vector<miral::Window> const& windows) override;
2994+
2995+ auto confirm_placement_on_display(
2996+ miral::WindowInfo const& window_info,
2997+ MirWindowState new_state,
2998+ Rectangle const& new_placement) -> Rectangle override;
2999+
3000+ // Switch workspace, taking window (if not null)
3001+ void switch_workspace_to(
3002+ std::shared_ptr<miral::Workspace> const& workspace,
3003+ miral::Window const& window = miral::Window{});
3004+
3005+ std::shared_ptr<miral::Workspace> active_workspace;
3006+ std::map<int, std::shared_ptr<miral::Workspace>> key_to_workspace;
3007+ std::map<std::shared_ptr<miral::Workspace>, miral::Window> workspace_to_active;
3008+
3009+ void apply_workspace_visible_to(miral::Window const& window);
3010+
3011+ void apply_workspace_hidden_to(miral::Window const& window);
3012+
3013+ void keep_spinner_on_top();
3014+};
3015+
3016+#endif //MIRAL_SHELL_FLOATING_WINDOW_MANAGER_H
3017
3018=== added file 'examples/miral-shell/miral-app.sh'
3019--- examples/miral-shell/miral-app.sh 1970-01-01 00:00:00 +0000
3020+++ examples/miral-shell/miral-app.sh 2017-08-29 09:17:20 +0000
3021@@ -0,0 +1,51 @@
3022+#! /bin/bash
3023+
3024+miral_server=miral-shell
3025+launcher='gnome-terminal --app-id com.canonical.miral.Terminal'
3026+hostsocket=
3027+bindir=$(dirname $0)
3028+
3029+if [ -n "${MIR_SOCKET}" ]
3030+then
3031+ if [ ! -e "${MIR_SOCKET}" ]
3032+ then
3033+ echo "Error: Host endpoint '${MIR_SOCKET}' does not exists"; exit 1
3034+ fi
3035+ hostsocket='--host-socket ${MIR_SOCKET}'
3036+fi
3037+
3038+socket=${XDG_RUNTIME_DIR}/miral_socket
3039+
3040+while [ $# -gt 0 ]
3041+do
3042+ if [ "$1" == "--help" -o "$1" == "-h" ]
3043+ then
3044+ echo "$(basename $0) - Handy launch script for a hosted miral \"desktop session\""
3045+ echo "Usage: $(basename $0) [options] [shell options]"
3046+ echo "Options are:"
3047+ echo " -kiosk use miral-kiosk instead of ${miral_server}"
3048+ echo " -launcher <launcher> use <launcher> instead of '${launcher}'"
3049+ echo " -socket <socket> set the mir socket [${socket}]"
3050+ echo " -bindir <bindir> path to the miral executable [${bindir}]"
3051+ exit 0
3052+ elif [ "$1" == "-kiosk" ]; then miral_server=miral-kiosk
3053+ elif [ "$1" == "-launcher" ]; then shift; launcher=$1
3054+ elif [ "$1" == "-socket" ]; then shift; socket=$1
3055+ elif [ "$1" == "-bindir" ]; then shift; bindir=$1
3056+ elif [ "${1:0:2}" == "--" ]; then break
3057+ fi
3058+ shift
3059+done
3060+
3061+if [ "${bindir}" != "" ]; then bindir="${bindir}/"; fi
3062+
3063+if [ -e "${socket}" ]; then echo "Error: session endpoint '${socket}' already exists"; exit 1 ;fi
3064+
3065+sh -c "${bindir}${miral_server} $* ${hostsocket} --file ${socket} --desktop_file_hint=miral-shell.desktop"&
3066+
3067+while [ ! -e "${socket}" ]; do echo "waiting for ${socket}"; sleep 1 ;done
3068+
3069+unset QT_QPA_PLATFORMTHEME
3070+MIR_SOCKET=${socket} XDG_SESSION_TYPE=mir GDK_BACKEND=mir QT_QPA_PLATFORM=ubuntumirclient SDL_VIDEODRIVER=mir dbus-run-session -- ${launcher}
3071+killall ${bindir}${miral_server}
3072+
3073
3074=== added file 'examples/miral-shell/miral-desktop.sh'
3075--- examples/miral-shell/miral-desktop.sh 1970-01-01 00:00:00 +0000
3076+++ examples/miral-shell/miral-desktop.sh 2017-08-29 09:17:20 +0000
3077@@ -0,0 +1,45 @@
3078+#! /bin/bash
3079+
3080+socket=${XDG_RUNTIME_DIR}/miral_socket
3081+miral_server=miral-shell
3082+launcher='gnome-terminal --app-id com.canonical.miral.Terminal'
3083+bindir=$(dirname $0)
3084+vt=4
3085+
3086+while [ $# -gt 0 ]
3087+do
3088+ if [ "$1" == "--help" -o "$1" == "-h" ]
3089+ then
3090+ echo "$(basename $0) - Handy launch script for a miral \"desktop session\""
3091+ echo "Usage: $(basename $0) [options] [shell options]"
3092+ echo "Options are:"
3093+ echo " -kiosk use miral-kiosk instead of ${miral_server}"
3094+ echo " -launcher <launcher> use <launcher> instead of '${launcher}'"
3095+ echo " -vt <termid> set the virtual terminal [${vt}]"
3096+ echo " -socket <socket> set the mir socket [${socket}]"
3097+ echo " -bindir <bindir> path to the miral executable [${bindir}]"
3098+ exit 0
3099+ elif [ "$1" == "-kiosk" ]; then miral_server=miral-kiosk
3100+ elif [ "$1" == "-launcher" ]; then shift; launcher=$1
3101+ elif [ "$1" == "-vt" ]; then shift; vt=$1
3102+ elif [ "$1" == "-socket" ]; then shift; socket=$1
3103+ elif [ "$1" == "-bindir" ]; then shift; bindir=$1/
3104+ elif [ "${1:0:2}" == "--" ]; then break
3105+ fi
3106+ shift
3107+done
3108+
3109+if [ "${bindir}" != "" ]; then bindir="${bindir}/"; fi
3110+
3111+if [ -e "${socket}" ]; then echo "Error: '${socket}' already exists"; exit 1 ;fi
3112+
3113+sudo ls >> /dev/null
3114+oldvt=$(sudo fgconsole)
3115+sudo sh -c "LD_LIBRARY_PATH=${LD_LIBRARY_PATH} ${bindir}${miral_server} --vt ${vt} --arw-file --file ${socket} $*; chvt ${oldvt}"&
3116+
3117+while [ ! -e "${socket}" ]; do echo "waiting for ${socket}"; sleep 1 ;done
3118+
3119+unset QT_QPA_PLATFORMTHEME
3120+MIR_SOCKET=${socket} XDG_SESSION_TYPE=mir GDK_BACKEND=mir QT_QPA_PLATFORM=ubuntumirclient SDL_VIDEODRIVER=mir dbus-run-session -- ${launcher}
3121+sudo killall ${bindir}${miral_server}
3122+
3123
3124=== added file 'examples/miral-shell/miral-run.sh'
3125--- examples/miral-shell/miral-run.sh 1970-01-01 00:00:00 +0000
3126+++ examples/miral-shell/miral-run.sh 2017-08-29 09:17:20 +0000
3127@@ -0,0 +1,17 @@
3128+#!/bin/sh
3129+
3130+if [ -e "${XDG_RUNTIME_DIR}/miral_socket" ];
3131+then
3132+ socket=${XDG_RUNTIME_DIR}/miral_socket
3133+elif [ -e "${XDG_RUNTIME_DIR}/mir_socket" ];
3134+then
3135+ socket=${XDG_RUNTIME_DIR}/mir_socket
3136+else
3137+ echo "Error: Cannot detect Mir endpoint"; exit 1
3138+fi
3139+
3140+if [ "$1" = "gnome-terminal" ]
3141+then extras='--app-id com.canonical.miral.Terminal'
3142+fi
3143+unset QT_QPA_PLATFORMTHEME
3144+MIR_SOCKET=${socket} XDG_SESSION_TYPE=mir GDK_BACKEND=mir QT_QPA_PLATFORM=ubuntumirclient SDL_VIDEODRIVER=mir "$@" ${extras}&
3145
3146=== added file 'examples/miral-shell/miral-screencast.sh'
3147--- examples/miral-shell/miral-screencast.sh 1970-01-01 00:00:00 +0000
3148+++ examples/miral-shell/miral-screencast.sh 2017-08-29 09:17:20 +0000
3149@@ -0,0 +1,48 @@
3150+#!/bin/bash
3151+width=1920
3152+height=1080
3153+output=screencast.mp4
3154+socket=${XDG_RUNTIME_DIR}/miral_socket
3155+if [ -v MIR_SERVER ]; then socket=${MIR_SERVER}; fi
3156+
3157+while [ $# -gt 0 ]
3158+do
3159+ if [ "$1" == "--help" -o "$1" == "-h" ]
3160+ then
3161+ echo "$(basename $0) - screencast capture script for use with Mir servers"
3162+ echo "Usage: $0 [options]"
3163+ echo "Options are:"
3164+ echo " --width set the capture width [${width}]"
3165+ echo " --height set the capture height [${height}]"
3166+ echo " --output set the output filename [${output}]"
3167+ echo " --socket set the mir socket [${socket}]"
3168+ echo " --tmpfile specify the temporary work file"
3169+ exit 0
3170+ elif [ "$1" == "--socket" ]; then shift; socket=$1
3171+ elif [ "$1" == "--output" ]; then shift; output=$1
3172+ elif [ "$1" == "--width" ]; then shift; width=$1
3173+ elif [ "$1" == "--height" ]; then shift; height=$1
3174+ elif [ "$1" == "--tmpfile" ]; then shift; tempfile=$1
3175+ fi
3176+ shift
3177+done
3178+
3179+echo width = ${width}
3180+echo height = ${height}
3181+echo output = ${output}
3182+echo socket = ${socket}
3183+
3184+if ! which mirscreencast >> /dev/null ; then echo "Need mirscreencast - run \"sudo apt install mir-utils\""; exit 1 ;fi
3185+if ! which mencoder >> /dev/null ; then echo "Need mencoder - run \"sudo apt install mencoder\""; exit 1 ;fi
3186+
3187+if [ -e ${output} ]; then echo "Output exists, moving to ${output}~"; mv ${output} ${output}~ ;fi
3188+while [ ! -e "${socket}" ]; do echo "waiting for ${socket}"; sleep 1 ;done
3189+
3190+if [ ! -v tempfile ]; then tempfile=$(mktemp); fi
3191+mirscreencast --size ${width} ${height} -m ${socket} -f ${tempfile}& mirscreencast_pid=$!
3192+trap 'kill ${mirscreencast_pid}; rm -f -- "${tempfile}"; exit 0' INT TERM HUP EXIT
3193+
3194+sleep 1; # don't lose the next message in the spew from mirscreencast
3195+read -rsp $'\n\nPress enter when recording complete...'
3196+
3197+mencoder -demuxer rawvideo -rawvideo fps=60:w=${width}:h=${height}:format=bgra -ovc x264 -o ${output} ${tempfile}
3198
3199=== added file 'examples/miral-shell/miral-xrun.sh'
3200--- examples/miral-shell/miral-xrun.sh 1970-01-01 00:00:00 +0000
3201+++ examples/miral-shell/miral-xrun.sh 2017-08-29 09:17:20 +0000
3202@@ -0,0 +1,45 @@
3203+#!/bin/bash
3204+port=0
3205+
3206+while [ -e "/tmp/.X11-unix/X${port}" ]; do
3207+ let port+=1
3208+done
3209+
3210+unset QT_QPA_PLATFORMTHEME
3211+unset GDK_BACKEND
3212+unset QT_QPA_PLATFORM
3213+unset SDL_VIDEODRIVER
3214+
3215+if [ -e "${XDG_RUNTIME_DIR}/miral_socket" ];
3216+then
3217+ socket=${XDG_RUNTIME_DIR}/miral_socket
3218+elif [ -e "${XDG_RUNTIME_DIR}/mir_socket" ];
3219+then
3220+ socket=${XDG_RUNTIME_DIR}/mir_socket
3221+else
3222+ echo "Error: Cannot detect Mir endpoint"; exit 1
3223+fi
3224+
3225+while [ $# -gt 0 ]
3226+do
3227+ if [ "$1" == "--help" -o "$1" == "-h" ]
3228+ then
3229+ echo "$(basename $0) - Handy launch script for providing an Xmir X11 server"
3230+ echo "Usage: $(basename $0) [options] command"
3231+ echo "Options are:"
3232+ echo " -force set toolkit environment variables to force X11 use"
3233+ exit 0
3234+ elif [ "$1" == "-force" ];
3235+ then
3236+ export XDG_SESSION_TYPE=x11
3237+ export GDK_BACKEND=x11
3238+ export QT_QPA_PLATFORM=xcb
3239+ export SDL_VIDEODRIVER=x11
3240+ else break
3241+ fi
3242+ shift
3243+done
3244+
3245+MIR_SOCKET=${socket} Xmir -rootless :${port} & pid=$!
3246+DISPLAY=:${port} "$@"
3247+kill ${pid}
3248
3249=== added file 'examples/miral-shell/shell_main.cpp'
3250--- examples/miral-shell/shell_main.cpp 1970-01-01 00:00:00 +0000
3251+++ examples/miral-shell/shell_main.cpp 2017-08-29 09:17:20 +0000
3252@@ -0,0 +1,98 @@
3253+/*
3254+ * Copyright © 2016-2017 Canonical Ltd.
3255+ *
3256+ * This program is free software: you can redistribute it and/or modify
3257+ * under the terms of the GNU General Public License version 2 or 3 as as
3258+ * published by the Free Software Foundation.
3259+ *
3260+ * This program is distributed in the hope that it will be useful,
3261+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3262+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3263+ * GNU General Public License for more details.
3264+ *
3265+ * You should have received a copy of the GNU General Public License
3266+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3267+ *
3268+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
3269+ */
3270+
3271+#include "tiling_window_manager.h"
3272+#include "floating_window_manager.h"
3273+#include "titlebar_config.h"
3274+#include "spinner/splash.h"
3275+
3276+#include <miral/display_configuration_option.h>
3277+#include <miral/runner.h>
3278+#include <miral/window_management_options.h>
3279+#include <miral/append_event_filter.h>
3280+#include <miral/debug_extension.h>
3281+#include <miral/internal_client.h>
3282+#include <miral/command_line_option.h>
3283+#include <miral/cursor_theme.h>
3284+#include <miral/keymap.h>
3285+
3286+#include <linux/input.h>
3287+
3288+int main(int argc, char const* argv[])
3289+{
3290+ using namespace miral;
3291+
3292+ std::function<void()> shutdown_hook{[]{}};
3293+
3294+ SpinnerSplash spinner;
3295+ InternalClientLauncher launcher;
3296+ ActiveOutputsMonitor outputs_monitor;
3297+ WindowManagerOptions window_managers
3298+ {
3299+ add_window_manager_policy<FloatingWindowManagerPolicy>("floating", spinner, launcher, shutdown_hook),
3300+ add_window_manager_policy<TilingWindowManagerPolicy>("tiling", spinner, launcher, outputs_monitor),
3301+ };
3302+
3303+ MirRunner runner{argc, argv};
3304+
3305+ runner.add_stop_callback([&] { shutdown_hook(); });
3306+
3307+ auto const quit_on_ctrl_alt_bksp = [&](MirEvent const* event)
3308+ {
3309+ if (mir_event_get_type(event) != mir_event_type_input)
3310+ return false;
3311+
3312+ MirInputEvent const* input_event = mir_event_get_input_event(event);
3313+ if (mir_input_event_get_type(input_event) != mir_input_event_type_key)
3314+ return false;
3315+
3316+ MirKeyboardEvent const* kev = mir_input_event_get_keyboard_event(input_event);
3317+ if (mir_keyboard_event_action(kev) != mir_keyboard_action_down)
3318+ return false;
3319+
3320+ MirInputEventModifiers mods = mir_keyboard_event_modifiers(kev);
3321+ if (!(mods & mir_input_event_modifier_alt) || !(mods & mir_input_event_modifier_ctrl))
3322+ return false;
3323+
3324+ if (mir_keyboard_event_scan_code(kev) != KEY_BACKSPACE)
3325+ return false;
3326+
3327+ runner.stop();
3328+ return true;
3329+ };
3330+
3331+ Keymap config_keymap;
3332+ DebugExtension debug_extensions;
3333+
3334+ return runner.run_with(
3335+ {
3336+ CommandLineOption{[&](std::string const& ) { },
3337+ "desktop_file_hint", "Ignored for Unity8 compatibility", "miral-shell.desktop"},
3338+ CursorTheme{"DMZ-White"},
3339+ window_managers,
3340+ display_configuration_options,
3341+ launcher,
3342+ outputs_monitor,
3343+ config_keymap,
3344+ debug_extensions,
3345+ AppendEventFilter{quit_on_ctrl_alt_bksp},
3346+ StartupInternalClient{"Intro", spinner},
3347+ pre_init(CommandLineOption{[&](std::string const& typeface) { ::titlebar::font_file(typeface); },
3348+ "shell-titlebar-font", "font file to use for titlebars", ::titlebar::font_file()})
3349+ });
3350+}
3351
3352=== added directory 'examples/miral-shell/spinner'
3353=== added file 'examples/miral-shell/spinner/CMakeLists.txt'
3354--- examples/miral-shell/spinner/CMakeLists.txt 1970-01-01 00:00:00 +0000
3355+++ examples/miral-shell/spinner/CMakeLists.txt 2017-08-29 09:17:20 +0000
3356@@ -0,0 +1,67 @@
3357+# -*- Mode: CMake; indent-tabs-mode: nil; tab-width: 2 -*-
3358+#
3359+# Copyright © 2014 Canonical Ltd.
3360+#
3361+# This program is free software: you can redistribute it and/or modify
3362+# it under the terms of the GNU General Public License version 3 as
3363+# published by the Free Software Foundation.
3364+#
3365+# This program is distributed in the hope that it will be useful,
3366+# but WITHOUT ANY WARRANTY; without even the implied warranty of
3367+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3368+# GNU General Public License for more details.
3369+#
3370+# You should have received a copy of the GNU General Public License
3371+# along with this program. If not, see <http://www.gnu.org/licenses/>.
3372+
3373+pkg_check_modules(GLIB REQUIRED glib-2.0)
3374+find_package(GLESv2 REQUIRED)
3375+find_package(PIL REQUIRED)
3376+
3377+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-overlength-strings")
3378+
3379+
3380+function(png2header png header varname)
3381+ add_custom_command(
3382+ OUTPUT ${header}
3383+ COMMAND python3 ${CMAKE_CURRENT_SOURCE_DIR}/png2header.py ${png} ${varname} > ${header}
3384+ DEPENDS ${png} ${CMAKE_CURRENT_SOURCE_DIR}/png2header.py
3385+ )
3386+endfunction()
3387+
3388+png2header(
3389+ ${CMAKE_CURRENT_SOURCE_DIR}/spinner-glow.png
3390+ ${CMAKE_CURRENT_BINARY_DIR}/spinner_glow.h
3391+ spinner_glow
3392+)
3393+
3394+png2header(
3395+ ${CMAKE_CURRENT_SOURCE_DIR}/spinner-logo.png
3396+ ${CMAKE_CURRENT_BINARY_DIR}/spinner_logo.h
3397+ spinner_logo
3398+)
3399+
3400+include_directories(
3401+ ${GLIB_INCLUDE_DIRS}
3402+ ${GLESv2_INCLUDE_DIRS}
3403+ ${CMAKE_CURRENT_BINARY_DIR}
3404+)
3405+
3406+add_library(miral-spinner STATIC
3407+ eglapp.cpp
3408+ eglapp.h
3409+ eglspinner.cpp
3410+ miregl.h
3411+ miregl.cpp
3412+ splash.h
3413+ ${CMAKE_CURRENT_BINARY_DIR}/spinner_logo.h
3414+ ${CMAKE_CURRENT_BINARY_DIR}/spinner_glow.h
3415+)
3416+
3417+target_link_libraries(miral-spinner
3418+ mirclientcpp
3419+ EGL
3420+ ${GLIB_LDFLAGS}
3421+ ${GLESv2_LIBRARIES}
3422+ ${MIRCLIENT_LDFLAGS}
3423+)
3424
3425=== added file 'examples/miral-shell/spinner/eglapp.cpp'
3426--- examples/miral-shell/spinner/eglapp.cpp 1970-01-01 00:00:00 +0000
3427+++ examples/miral-shell/spinner/eglapp.cpp 2017-08-29 09:17:20 +0000
3428@@ -0,0 +1,83 @@
3429+/*
3430+ * Copyright © 2013, 2015 Canonical Ltd.
3431+ *
3432+ * This program is free software: you can redistribute it and/or modify
3433+ * under the terms of the GNU General Public License version 2 or 3 as as
3434+ * published by the Free Software Foundation.
3435+ *
3436+ * This program is distributed in the hope that it will be useful,
3437+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3438+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3439+ * GNU General Public License for more details.
3440+ *
3441+ * You should have received a copy of the GNU General Public License
3442+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3443+ */
3444+
3445+#include "eglapp.h"
3446+
3447+#include <mir/client/display_config.h>
3448+
3449+#include "miregl.h"
3450+
3451+
3452+float mir_eglapp_background_opacity = 1.0f;
3453+
3454+
3455+namespace
3456+{
3457+MirPixelFormat select_pixel_format(MirConnection* connection)
3458+{
3459+ unsigned int format[mir_pixel_formats];
3460+ unsigned int nformats;
3461+
3462+ mir_connection_get_available_surface_formats(
3463+ connection,
3464+ (MirPixelFormat*) format,
3465+ mir_pixel_formats,
3466+ &nformats);
3467+
3468+ auto const pixel_format = (MirPixelFormat) format[0];
3469+
3470+ printf("Server supports %d of %d surface pixel formats. Using format: %d\n",
3471+ nformats, mir_pixel_formats, pixel_format);
3472+
3473+ return pixel_format;
3474+}
3475+}
3476+
3477+std::vector<std::shared_ptr<MirEglSurface>> mir_eglapp_init(MirConnection* const connection)
3478+{
3479+ char const * const name = "eglappsurface";
3480+
3481+ if (!mir_connection_is_valid(connection))
3482+ throw std::runtime_error("Can't get connection");
3483+
3484+ auto const pixel_format = select_pixel_format(connection);
3485+
3486+ auto const mir_egl_app = make_mir_eglapp(connection, pixel_format);
3487+
3488+ std::vector<std::shared_ptr<MirEglSurface>> result;
3489+
3490+ mir::client::DisplayConfig{connection}.for_each_output([&](MirOutput const* output)
3491+ {
3492+ if (mir_output_get_connection_state(output) == mir_output_connection_state_connected &&
3493+ mir_output_is_enabled(output))
3494+ {
3495+ auto const mode = mir_output_get_current_mode(output);
3496+ auto const output_id = mir_output_get_id(output);
3497+
3498+ printf("Active output [%u] at (%d, %d) is %dx%d\n",
3499+ output_id,
3500+ mir_output_get_position_x(output), mir_output_get_position_y(output),
3501+ mir_output_mode_get_width(mode), mir_output_mode_get_height(mode));
3502+
3503+ result.push_back(std::make_shared<MirEglSurface>(mir_egl_app, name, output));
3504+ }
3505+ });
3506+
3507+ if (result.empty())
3508+ throw std::runtime_error("No active outputs found.");
3509+
3510+ return result;
3511+}
3512
3513=== added file 'examples/miral-shell/spinner/eglapp.h'
3514--- examples/miral-shell/spinner/eglapp.h 1970-01-01 00:00:00 +0000
3515+++ examples/miral-shell/spinner/eglapp.h 2017-08-29 09:17:20 +0000
3516@@ -0,0 +1,33 @@
3517+/*
3518+ * Copyright © 2013 Canonical Ltd.
3519+ *
3520+ * This program is free software: you can redistribute it and/or modify
3521+ * under the terms of the GNU General Public License version 2 or 3 as as
3522+ * published by the Free Software Foundation.
3523+ *
3524+ * This program is distributed in the hope that it will be useful,
3525+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3526+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3527+ * GNU General Public License for more details.
3528+ *
3529+ * You should have received a copy of the GNU General Public License
3530+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3531+ *
3532+ * Author: Daniel van Vugt <daniel.van.vugt@canonical.com>
3533+ */
3534+
3535+#ifndef __EGLAPP_H__
3536+#define __EGLAPP_H__
3537+
3538+#include <mir_toolkit/client_types.h>
3539+
3540+#include <memory>
3541+#include <vector>
3542+
3543+class MirEglSurface;
3544+
3545+extern float mir_eglapp_background_opacity;
3546+
3547+std::vector<std::shared_ptr<MirEglSurface>> mir_eglapp_init(MirConnection* const connection);
3548+
3549+#endif
3550
3551=== added file 'examples/miral-shell/spinner/eglspinner.cpp'
3552--- examples/miral-shell/spinner/eglspinner.cpp 1970-01-01 00:00:00 +0000
3553+++ examples/miral-shell/spinner/eglspinner.cpp 2017-08-29 09:17:20 +0000
3554@@ -0,0 +1,372 @@
3555+/*
3556+ * Copyright © 2013-2015 Canonical Ltd.
3557+ *
3558+ * This program is free software: you can redistribute it and/or modify
3559+ * under the terms of the GNU General Public License version 2 or 3 as as
3560+ * published by the Free Software Foundation.
3561+ *
3562+ * This program is distributed in the hope that it will be useful,
3563+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3564+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3565+ * GNU General Public License for more details.
3566+ *
3567+ * You should have received a copy of the GNU General Public License
3568+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3569+ *
3570+ * Authors: Daniel van Vugt <daniel.van.vugt@canonical.com>
3571+ * Mirco Müller <mirco.mueller@canonical.com>
3572+ * Alan Griffiths <alan@octopull.co.uk>
3573+ * Kevin DuBois <kevin.dubois@canonical.com>
3574+ */
3575+
3576+#include "splash.h"
3577+
3578+#include <chrono>
3579+
3580+#include "eglapp.h"
3581+#include "miregl.h"
3582+#include <assert.h>
3583+#include <glib.h>
3584+#include <string.h>
3585+#include <GLES2/gl2.h>
3586+#include <sys/stat.h>
3587+#include <signal.h>
3588+#include <atomic>
3589+#include <mutex>
3590+
3591+#include <mir_toolkit/mir_client_library.h>
3592+
3593+#include "spinner_glow.h"
3594+#include "spinner_logo.h"
3595+
3596+static GLuint load_shader(const char *src, GLenum type)
3597+{
3598+ GLuint shader = glCreateShader(type);
3599+ if (shader)
3600+ {
3601+ GLint compiled;
3602+ glShaderSource(shader, 1, &src, NULL);
3603+ glCompileShader(shader);
3604+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
3605+ if (!compiled)
3606+ {
3607+ GLchar log[1024];
3608+ glGetShaderInfoLog(shader, sizeof log - 1, NULL, log);
3609+ log[sizeof log - 1] = '\0';
3610+ printf("load_shader compile failed: %s\n", log);
3611+ glDeleteShader(shader);
3612+ shader = 0;
3613+ }
3614+ }
3615+ return shader;
3616+}
3617+
3618+// Colours from http://design.ubuntu.com/brand/colour-palette
3619+//#define MID_AUBERGINE 0.368627451f, 0.152941176f, 0.31372549f
3620+//#define ORANGE 0.866666667f, 0.282352941f, 0.141414141f
3621+//#define WARM_GREY 0.682352941f, 0.654901961f, 0.623529412f
3622+//#define COOL_GREY 0.2f, 0.2f, 0.2f
3623+#define LIGHT_AUBERGINE 0.466666667f, 0.297297297f, 0.435294118f
3624+//#define DARK_AUBERGINE 0.17254902f, 0.0f, 0.117647059f
3625+//#define BLACK 0.0f, 0.0f, 0.0f
3626+//#define WHITE 1.0f, 1.0f, 1.0f
3627+
3628+template <typename Image>
3629+void uploadTexture (GLuint id, Image& image)
3630+{
3631+ glBindTexture(GL_TEXTURE_2D, id);
3632+
3633+ glTexImage2D(GL_TEXTURE_2D,
3634+ 0,
3635+ GL_RGBA,
3636+ image.width,
3637+ image.height,
3638+ 0,
3639+ GL_RGBA,
3640+ GL_UNSIGNED_BYTE,
3641+ image.pixel_data);
3642+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
3643+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
3644+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
3645+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
3646+ glBindTexture(GL_TEXTURE_2D, 0);
3647+}
3648+
3649+GLuint createShaderProgram(const char* vertexShaderSrc, const char* fragmentShaderSrc)
3650+{
3651+ if (!vertexShaderSrc || !fragmentShaderSrc)
3652+ return 0;
3653+
3654+ GLuint vShaderId = 0;
3655+ vShaderId = load_shader(vertexShaderSrc, GL_VERTEX_SHADER);
3656+ assert(vShaderId);
3657+
3658+ GLuint fShaderId = 0;
3659+ fShaderId = load_shader(fragmentShaderSrc, GL_FRAGMENT_SHADER);
3660+ assert(fShaderId);
3661+
3662+ GLuint progId = 0;
3663+ progId = glCreateProgram();
3664+ assert(progId);
3665+ glAttachShader(progId, vShaderId);
3666+ glAttachShader(progId, fShaderId);
3667+ glLinkProgram(progId);
3668+
3669+ GLint linked = 0;
3670+ glGetProgramiv(progId, GL_LINK_STATUS, &linked);
3671+ if (!linked)
3672+ {
3673+ GLchar log[1024];
3674+ glGetProgramInfoLog(progId, sizeof log - 1, NULL, log);
3675+ log[sizeof log - 1] = '\0';
3676+ printf("Link failed: %s\n", log);
3677+ return 0;
3678+ }
3679+
3680+ return progId;
3681+}
3682+
3683+typedef struct _AnimationValues
3684+{
3685+ double lastTimeStamp;
3686+ GLfloat angle;
3687+ GLfloat fadeBackground;
3688+ GLfloat fadeLogo;
3689+ GLfloat fadeGlow;
3690+} AnimationValues;
3691+
3692+bool updateAnimation (GTimer* timer, AnimationValues* anim)
3693+{
3694+ if (!timer || !anim)
3695+ return false;
3696+
3697+ //1.) 0.0 - 0.6: logo fades in fully
3698+ //2.) 0.0 - 6.0: logo does one full spin 360°
3699+ //3.) 6.0 - 6.833: glow fades in fully, black-background fades out to 50%
3700+ //4.) 6.833 - 7.666: glow fades out fully, black-background fades out to 0%
3701+ //5.) 7.666 - 8.266: logo fades out fully
3702+ //8.266..: now spinner can be closed as all its elements are faded out
3703+
3704+ // Hacked to run three times as fast
3705+ double elapsed = 3*g_timer_elapsed (timer, NULL);
3706+ double dt = elapsed - anim->lastTimeStamp;
3707+ anim->lastTimeStamp = elapsed;
3708+
3709+ // step 1.)
3710+ if (elapsed < 0.6f)
3711+ anim->fadeLogo += 1.6f * dt;
3712+
3713+ // step 2.)
3714+ anim->angle -= (0.017453292519943f * 360.0f / 18.0f) * dt;
3715+
3716+ // step 3.) glow
3717+ if (elapsed > 6.0f && elapsed < 6.833f)
3718+ anim->fadeGlow += 1.2f * dt;
3719+
3720+ // step 3.) background
3721+ if (elapsed > 0.6f && elapsed < 6.833f)
3722+ { if (anim->fadeBackground > 0) anim->fadeBackground -= 0.15f * dt; else anim->fadeBackground = 0; }
3723+
3724+ // step 4.) glow
3725+ if (elapsed > 7.0f)
3726+ anim->fadeGlow -= 0.6f * dt;
3727+
3728+ // step 5.)
3729+ if (elapsed > 6.833f)
3730+ anim->fadeLogo -= 1.6f * dt;
3731+
3732+ return elapsed < 8.266f;
3733+}
3734+
3735+namespace
3736+{
3737+const char vShaderSrcSpinner[] =
3738+ "attribute vec4 vPosition; \n"
3739+ "attribute vec2 aTexCoords; \n"
3740+ "uniform float theta; \n"
3741+ "varying vec2 vTexCoords; \n"
3742+ "void main() \n"
3743+ "{ \n"
3744+ " float c = cos(theta); \n"
3745+ " float s = sin(theta); \n"
3746+ " mat2 m; \n"
3747+ " m[0] = vec2(c, s); \n"
3748+ " m[1] = vec2(-s, c); \n"
3749+ " vTexCoords = m * aTexCoords + vec2 (0.5, 0.5); \n"
3750+ " gl_Position = vec4(vPosition.xy, -1.0, 1.0); \n"
3751+ "} \n";
3752+
3753+const char fShaderSrcGlow[] =
3754+ "precision mediump float; \n"
3755+ "varying vec2 vTexCoords; \n"
3756+ "uniform sampler2D uSampler; \n"
3757+ "uniform float uFadeGlow; \n"
3758+ "void main() \n"
3759+ "{ \n"
3760+ " vec4 col = texture2D(uSampler, vTexCoords); \n"
3761+ " col = col * uFadeGlow; \n"
3762+ " gl_FragColor = col; \n"
3763+ "} \n";
3764+
3765+const char fShaderSrcLogo[] =
3766+ "precision mediump float; \n"
3767+ "varying vec2 vTexCoords; \n"
3768+ "uniform sampler2D uSampler; \n"
3769+ "uniform float uFadeLogo; \n"
3770+ "void main() \n"
3771+ "{ \n"
3772+ " vec4 col = texture2D(uSampler, vTexCoords); \n"
3773+ " col = col * uFadeLogo; \n"
3774+ " gl_FragColor = col; \n"
3775+ "} \n";
3776+
3777+std::atomic<bool> dying{false};
3778+void lifecycle_event_callback(MirConnection* /*connection*/, MirLifecycleState state, void* context)
3779+{
3780+ if (state == mir_lifecycle_connection_lost)
3781+ static_cast<decltype(dying)*>(context)->store(true);
3782+}
3783+}
3784+
3785+struct SpinnerSplash::Self
3786+{
3787+ std::mutex mutex;
3788+ std::weak_ptr<mir::scene::Session> session;
3789+};
3790+
3791+SpinnerSplash::SpinnerSplash() : self{std::make_shared<Self>()} {}
3792+
3793+SpinnerSplash::~SpinnerSplash() = default;
3794+
3795+void SpinnerSplash::operator()(std::weak_ptr<mir::scene::Session> const& session)
3796+{
3797+ std::lock_guard<decltype(self->mutex)> lock{self->mutex};
3798+ self->session = session;
3799+}
3800+
3801+auto SpinnerSplash::session() const
3802+-> std::shared_ptr<mir::scene::Session>
3803+{
3804+ std::lock_guard<decltype(self->mutex)> lock{self->mutex};
3805+ return self->session.lock();
3806+}
3807+
3808+void SpinnerSplash::operator()(MirConnection* const connection)
3809+try
3810+{
3811+ GLuint prog[2];
3812+ GLuint texture[2];
3813+ GLint vpos[2];
3814+ GLint theta;
3815+ GLint fadeGlow;
3816+ GLint fadeLogo;
3817+ GLint aTexCoords[2];
3818+ GLint sampler[2];
3819+
3820+ mir_connection_set_lifecycle_event_callback(connection, &lifecycle_event_callback, &dying);
3821+ auto const windows = mir_eglapp_init(connection);
3822+
3823+ if (!windows.size()) return;
3824+
3825+ double pixelSize = 10 * 11.18;
3826+ const GLfloat texCoordsSpinner[] =
3827+ {
3828+ -0.5f, 0.5f,
3829+ -0.5f, -0.5f,
3830+ 0.5f, 0.5f,
3831+ 0.5f, -0.5f,
3832+ };
3833+
3834+ prog[0] = createShaderProgram(vShaderSrcSpinner, fShaderSrcGlow);
3835+ prog[1] = createShaderProgram(vShaderSrcSpinner, fShaderSrcLogo);
3836+
3837+ // setup proper GL-blending
3838+ glEnable(GL_BLEND);
3839+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
3840+ glBlendEquation(GL_FUNC_ADD);
3841+
3842+ // get locations of shader-attributes/uniforms
3843+ vpos[0] = glGetAttribLocation(prog[0], "vPosition");
3844+ aTexCoords[0] = glGetAttribLocation(prog[0], "aTexCoords");
3845+ theta = glGetUniformLocation(prog[0], "theta");
3846+ sampler[0] = glGetUniformLocation(prog[0], "uSampler");
3847+ fadeGlow = glGetUniformLocation(prog[0], "uFadeGlow");
3848+ vpos[1] = glGetAttribLocation(prog[1], "vPosition");
3849+ aTexCoords[1] = glGetAttribLocation(prog[1], "aTexCoords");
3850+ sampler[1] = glGetUniformLocation(prog[1], "uSampler");
3851+ fadeLogo = glGetUniformLocation(prog[1], "uFadeLogo");
3852+
3853+ // create and upload spinner-artwork
3854+ // note that the embedded image data has pre-multiplied alpha
3855+ glGenTextures(2, texture);
3856+ uploadTexture(texture[0], spinner_glow);
3857+ uploadTexture(texture[1], spinner_logo);
3858+
3859+ // bunch of shader-attributes to enable
3860+ glVertexAttribPointer(aTexCoords[0], 2, GL_FLOAT, GL_FALSE, 0, texCoordsSpinner);
3861+ glVertexAttribPointer(aTexCoords[1], 2, GL_FLOAT, GL_FALSE, 0, texCoordsSpinner);
3862+ glEnableVertexAttribArray(vpos[0]);
3863+ glEnableVertexAttribArray(vpos[1]);
3864+ glEnableVertexAttribArray(aTexCoords[0]);
3865+ glEnableVertexAttribArray(aTexCoords[1]);
3866+ glActiveTexture(GL_TEXTURE0);
3867+
3868+ AnimationValues anim = {0.0, 0.0, 1.0, 0.0, 0.0};
3869+ GTimer* timer = g_timer_new();
3870+
3871+ do
3872+ {
3873+ for (auto const& surface : windows)
3874+ surface->paint([&](unsigned int width, unsigned int height)
3875+ {
3876+ GLfloat halfRealWidth = ((2.0 / width) * pixelSize) / 2.0;
3877+ GLfloat halfRealHeight = ((2.0 / height) * pixelSize) / 2.0;
3878+
3879+ const GLfloat vertices[] =
3880+ {
3881+ halfRealWidth, halfRealHeight,
3882+ halfRealWidth, -halfRealHeight,
3883+ -halfRealWidth, halfRealHeight,
3884+ -halfRealWidth,-halfRealHeight,
3885+ };
3886+
3887+ glVertexAttribPointer(vpos[0], 2, GL_FLOAT, GL_FALSE, 0, vertices);
3888+ glVertexAttribPointer(vpos[1], 2, GL_FLOAT, GL_FALSE, 0, vertices);
3889+
3890+ glViewport(0, 0, width, height);
3891+
3892+ GLfloat color[] = {LIGHT_AUBERGINE};
3893+ for (auto& c : color) { c*= anim.fadeBackground; }
3894+
3895+ glClearColor(color[0], color[1], color[2], anim.fadeBackground);
3896+ glClear(GL_COLOR_BUFFER_BIT);
3897+
3898+ // draw glow
3899+ glUseProgram(prog[0]);
3900+ glBindTexture(GL_TEXTURE_2D, texture[0]);
3901+ glUniform1i(sampler[0], 0);
3902+ glUniform1f(theta, anim.angle);
3903+ glUniform1f(fadeGlow, anim.fadeGlow);
3904+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3905+
3906+ // draw logo
3907+ glUseProgram(prog[1]);
3908+ glBindTexture(GL_TEXTURE_2D, texture[1]);
3909+ glUniform1i(sampler[1], 0);
3910+ glUniform1f(theta, anim.angle);
3911+ glUniform1f(fadeLogo, anim.fadeLogo);
3912+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
3913+ });
3914+
3915+ if (dying.load())
3916+ throw std::runtime_error("Server disconnected");
3917+ }
3918+ while (updateAnimation(timer, &anim));
3919+
3920+ glDeleteTextures(2, texture);
3921+ g_timer_destroy (timer);
3922+}
3923+catch (std::exception const& x)
3924+{
3925+ printf("%s\n", x.what());
3926+}
3927
3928=== added file 'examples/miral-shell/spinner/miregl.cpp'
3929--- examples/miral-shell/spinner/miregl.cpp 1970-01-01 00:00:00 +0000
3930+++ examples/miral-shell/spinner/miregl.cpp 2017-08-29 09:17:20 +0000
3931@@ -0,0 +1,239 @@
3932+/*
3933+ * Copyright © 2015 Canonical Ltd.
3934+ *
3935+ * This program is free software: you can redistribute it and/or modify
3936+ * under the terms of the GNU General Public License version 2 or 3 as as
3937+ * published by the Free Software Foundation.
3938+ *
3939+ * This program is distributed in the hope that it will be useful,
3940+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3941+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3942+ * GNU General Public License for more details.
3943+ *
3944+ * You should have received a copy of the GNU General Public License
3945+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3946+ */
3947+
3948+#include "miregl.h"
3949+#include <miral/window_specification.h>
3950+#include <mir/client/window_spec.h>
3951+#include <mir_toolkit/mir_client_library.h>
3952+
3953+#include <cstring>
3954+
3955+#include <GLES2/gl2.h>
3956+
3957+using namespace mir::client;
3958+
3959+class MirEglApp
3960+{
3961+public:
3962+ MirEglApp(MirConnection* const connection, MirPixelFormat pixel_format);
3963+
3964+ EGLSurface create_surface(MirRenderSurface* surface);
3965+
3966+ void make_current(EGLSurface eglsurface) const;
3967+
3968+ void swap_buffers(EGLSurface eglsurface) const;
3969+
3970+ void destroy_surface(EGLSurface eglsurface) const;
3971+
3972+ void get_surface_size(EGLSurface eglsurface, int* width, int* height) const;
3973+
3974+ void set_swap_interval(EGLSurface eglsurface, int interval) const;
3975+
3976+ bool supports_surfaceless_context();
3977+
3978+ ~MirEglApp();
3979+
3980+ MirConnection* const connection;
3981+private:
3982+ EGLDisplay egldisplay;
3983+ EGLContext eglctx;
3984+ EGLConfig eglconfig;
3985+ EGLint neglconfigs;
3986+ EGLSurface dummy_surface;
3987+};
3988+
3989+std::shared_ptr<MirEglApp> make_mir_eglapp(
3990+ MirConnection* const connection, MirPixelFormat const& pixel_format)
3991+{
3992+ return std::make_shared<MirEglApp>(connection, pixel_format);
3993+}
3994+
3995+MirEglSurface::MirEglSurface(
3996+ std::shared_ptr<MirEglApp> const& mir_egl_app,
3997+ char const* name,
3998+ MirOutput const* output)
3999+:
4000+ mir_egl_app{mir_egl_app}
4001+{
4002+ auto const mode = mir_output_get_current_mode(output);
4003+ auto const output_id = mir_output_get_id(output);
4004+ auto const width = mir_output_mode_get_width(mode);
4005+ auto const height = mir_output_mode_get_height(mode);
4006+
4007+ surface = Surface{mir_connection_create_render_surface_sync(mir_egl_app->connection, width, height)};
4008+
4009+ eglsurface = mir_egl_app->create_surface(surface);
4010+
4011+ window = WindowSpec::for_normal_window(mir_egl_app->connection, width, height)
4012+ .add_surface(surface, width, height, 0, 0)
4013+ .set_name(name)
4014+ .set_fullscreen_on_output(output_id)
4015+ .create_window();
4016+
4017+ if (!mir_window_is_valid(window))
4018+ throw std::runtime_error(std::string("Can't create a window ") + mir_window_get_error_message(window));
4019+
4020+ mir_egl_app->set_swap_interval(eglsurface, -1);
4021+}
4022+
4023+MirEglSurface::~MirEglSurface()
4024+{
4025+ mir_egl_app->destroy_surface(eglsurface);
4026+}
4027+
4028+void MirEglSurface::egl_make_current()
4029+{
4030+ mir_egl_app->get_surface_size(eglsurface, &width_, &height_);
4031+ mir_egl_app->make_current(eglsurface);
4032+}
4033+
4034+void MirEglSurface::swap_buffers()
4035+{
4036+ mir_egl_app->swap_buffers(eglsurface);
4037+}
4038+
4039+unsigned int MirEglSurface::width() const
4040+{
4041+ return width_;
4042+}
4043+
4044+unsigned int MirEglSurface::height() const
4045+{
4046+ return height_;
4047+}
4048+
4049+MirEglApp::MirEglApp(MirConnection* const connection, MirPixelFormat pixel_format) :
4050+ connection{connection},
4051+ dummy_surface{EGL_NO_SURFACE}
4052+{
4053+ unsigned int bpp = 8*MIR_BYTES_PER_PIXEL(pixel_format);
4054+
4055+ EGLint attribs[] =
4056+ {
4057+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
4058+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
4059+ EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
4060+ EGL_BUFFER_SIZE, (EGLint) bpp,
4061+ EGL_NONE
4062+ };
4063+
4064+ egldisplay = eglGetDisplay((EGLNativeDisplayType)(connection));
4065+ if (egldisplay == EGL_NO_DISPLAY)
4066+ throw std::runtime_error("Can't eglGetDisplay");
4067+
4068+ EGLint major;
4069+ EGLint minor;
4070+ if (!eglInitialize(egldisplay, &major, &minor))
4071+ throw std::runtime_error("Can't eglInitialize");
4072+
4073+ if (major != 1 || minor != 4)
4074+ throw std::runtime_error("EGL version is not 1.4");
4075+
4076+ if (!eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs))
4077+ throw std::runtime_error("Could not eglChooseConfig");
4078+
4079+ if (neglconfigs == 0)
4080+ throw std::runtime_error("No EGL config available");
4081+
4082+ EGLint ctxattribs[] =
4083+ {
4084+ EGL_CONTEXT_CLIENT_VERSION, 2,
4085+ EGL_NONE
4086+ };
4087+
4088+ eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, ctxattribs);
4089+ if (eglctx == EGL_NO_CONTEXT)
4090+ throw std::runtime_error("eglCreateContext failed");
4091+
4092+ if (!supports_surfaceless_context())
4093+ {
4094+ static EGLint const dummy_pbuffer_attribs[] =
4095+ {
4096+ EGL_WIDTH, 1,
4097+ EGL_HEIGHT, 1,
4098+ EGL_NONE
4099+ };
4100+
4101+ dummy_surface = eglCreatePbufferSurface(egldisplay, eglconfig, dummy_pbuffer_attribs);
4102+ if (dummy_surface == EGL_NO_SURFACE)
4103+ throw std::runtime_error("eglCreatePbufferSurface failed");
4104+ }
4105+
4106+ make_current(dummy_surface);
4107+}
4108+
4109+EGLSurface MirEglApp::create_surface(MirRenderSurface* surface)
4110+{
4111+ auto const eglsurface = eglCreateWindowSurface(
4112+ egldisplay,
4113+ eglconfig,
4114+ (EGLNativeWindowType)surface, NULL);
4115+
4116+ if (eglsurface == EGL_NO_SURFACE)
4117+ throw std::runtime_error("eglCreateWindowSurface failed");
4118+
4119+ return eglsurface;
4120+}
4121+
4122+void MirEglApp::make_current(EGLSurface eglsurface) const
4123+{
4124+ if (!eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx))
4125+ throw std::runtime_error("Can't eglMakeCurrent");
4126+}
4127+
4128+void MirEglApp::swap_buffers(EGLSurface eglsurface) const
4129+{
4130+ eglSwapBuffers(egldisplay, eglsurface);
4131+}
4132+
4133+void MirEglApp::destroy_surface(EGLSurface eglsurface) const
4134+{
4135+ eglDestroySurface(egldisplay, eglsurface);
4136+}
4137+
4138+void MirEglApp::get_surface_size(EGLSurface eglsurface, int* width, int* height) const
4139+{
4140+ eglQuerySurface(egldisplay, eglsurface, EGL_WIDTH, width);
4141+ eglQuerySurface(egldisplay, eglsurface, EGL_HEIGHT, height);
4142+}
4143+
4144+void MirEglApp::set_swap_interval(EGLSurface eglsurface, int interval) const
4145+{
4146+ auto const previous_surface = eglGetCurrentSurface(EGL_DRAW);
4147+
4148+ make_current(eglsurface);
4149+ eglSwapInterval(egldisplay, interval);
4150+
4151+ if (previous_surface != EGL_NO_SURFACE)
4152+ make_current(previous_surface);
4153+}
4154+
4155+bool MirEglApp::supports_surfaceless_context()
4156+{
4157+ auto const extensions = eglQueryString(egldisplay, EGL_EXTENSIONS);
4158+ if (!extensions)
4159+ return false;
4160+ return std::strstr(extensions, "EGL_KHR_surfaceless_context") != nullptr;
4161+}
4162+
4163+MirEglApp::~MirEglApp()
4164+{
4165+ eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
4166+ if (dummy_surface != EGL_NO_SURFACE)
4167+ destroy_surface(dummy_surface);
4168+ eglDestroyContext(egldisplay, eglctx);
4169+ eglTerminate(egldisplay);
4170+}
4171
4172=== added file 'examples/miral-shell/spinner/miregl.h'
4173--- examples/miral-shell/spinner/miregl.h 1970-01-01 00:00:00 +0000
4174+++ examples/miral-shell/spinner/miregl.h 2017-08-29 09:17:20 +0000
4175@@ -0,0 +1,67 @@
4176+/*
4177+ * Copyright © 2015 Canonical Ltd.
4178+ *
4179+ * This program is free software: you can redistribute it and/or modify
4180+ * under the terms of the GNU General Public License version 2 or 3 as as
4181+ * published by the Free Software Foundation.
4182+ *
4183+ * This program is distributed in the hope that it will be useful,
4184+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4185+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4186+ * GNU General Public License for more details.
4187+ *
4188+ * You should have received a copy of the GNU General Public License
4189+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4190+ */
4191+
4192+#ifndef UNITYSYSTEMCOMPOSITOR_MIREGL_H
4193+#define UNITYSYSTEMCOMPOSITOR_MIREGL_H
4194+
4195+#include <mir/client/surface.h>
4196+#include <mir/client/window.h>
4197+
4198+#include <EGL/egl.h>
4199+
4200+#include <memory>
4201+
4202+class MirEglApp;
4203+class MirEglSurface;
4204+
4205+std::shared_ptr<MirEglApp> make_mir_eglapp(
4206+ MirConnection* const connection,
4207+ MirPixelFormat const& pixel_format);
4208+
4209+class MirEglSurface
4210+{
4211+public:
4212+ MirEglSurface(
4213+ std::shared_ptr<MirEglApp> const& mir_egl_app,
4214+ char const* name,
4215+ MirOutput const* output);
4216+
4217+ ~MirEglSurface();
4218+
4219+ template<typename Painter>
4220+ void paint(Painter const& functor)
4221+ {
4222+ egl_make_current();
4223+ functor(width(), height());
4224+ swap_buffers();
4225+ }
4226+
4227+private:
4228+ void egl_make_current();
4229+
4230+ void swap_buffers();
4231+ unsigned int width() const;
4232+ unsigned int height() const;
4233+
4234+ std::shared_ptr<MirEglApp> const mir_egl_app;
4235+ mir::client::Surface surface;
4236+ mir::client::Window window;
4237+ EGLSurface eglsurface;
4238+ int width_;
4239+ int height_;
4240+};
4241+
4242+#endif //UNITYSYSTEMCOMPOSITOR_MIREGL_H
4243
4244=== added file 'examples/miral-shell/spinner/png2header.py'
4245--- examples/miral-shell/spinner/png2header.py 1970-01-01 00:00:00 +0000
4246+++ examples/miral-shell/spinner/png2header.py 2017-08-29 09:17:20 +0000
4247@@ -0,0 +1,87 @@
4248+#!/usr/bin/env python
4249+# coding: utf-8
4250+
4251+# Copyright © 2015 Canonical Ltd.
4252+#
4253+# This program is free software: you can redistribute it and/or modify
4254+# it under the terms of the GNU General Public License version 2 or 3
4255+# as published by the Free Software Foundation.
4256+#
4257+# This program is distributed in the hope that it will be useful,
4258+# but WITHOUT ANY WARRANTY; without even the implied warranty of
4259+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4260+# GNU General Public License for more details.
4261+#
4262+# You should have received a copy of the GNU General Public License
4263+# along with this program. If not, see <http://www.gnu.org/licenses/>.
4264+#
4265+# Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
4266+
4267+import sys
4268+from PIL import Image
4269+
4270+def premultiply(image):
4271+ pixels = image.load()
4272+ for i in range(image.size[0]):
4273+ for j in range(image.size[1]):
4274+ orig = pixels[i,j]
4275+ m = orig[3] / 255.0
4276+ pixels[i,j] = (int(orig[0] * m) , int(orig[1] * m), int(orig[2] * m), orig[3])
4277+
4278+def tocstring(data):
4279+ result = ''
4280+ line_chars = 0
4281+ line_limit = 80
4282+
4283+ for c in data:
4284+ if line_chars == 0:
4285+ result += ' "'
4286+
4287+ s = '\\%o' % c
4288+ result += s
4289+ line_chars += len(s)
4290+
4291+ if line_chars >= line_limit:
4292+ result += '"\n'
4293+ line_chars = 0
4294+
4295+ if line_chars != 0:
4296+ result += '"'
4297+
4298+ return result
4299+
4300+def bytes_per_pixel(image):
4301+ if image.mode == 'RGBA':
4302+ return 4
4303+ elif image.mode == 'RGB':
4304+ return 3
4305+ else:
4306+ raise "Unsupported image mode %s" % image.mode
4307+
4308+def export(image, variable_name):
4309+ image_info = (image.size[0], image.size[1], bytes_per_pixel(image))
4310+ print("static const struct {")
4311+ print(" unsigned int width;")
4312+ print(" unsigned int height;")
4313+ print(" unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */")
4314+ print(" unsigned char pixel_data[%d * %d * %d + 1];" % image_info)
4315+ print("} %s = {" % variable_name)
4316+ print(" %d, %d, %d," % image_info)
4317+ print(tocstring(image.tobytes()))
4318+ print("};")
4319+
4320+def show_usage():
4321+ print("Usage: ./png2header.py PNGFILE VARNAME > HEADER_FILE", file=sys.stderr)
4322+ print("Convert a PNG image to an embeddable C/C++ header file", file=sys.stderr)
4323+
4324+if len(sys.argv) < 3:
4325+ show_usage()
4326+ sys.exit(1)
4327+
4328+image_filename = sys.argv[1]
4329+variable_name = sys.argv[2]
4330+
4331+image = Image.open(image_filename)
4332+if image.mode == 'RGBA':
4333+ premultiply(image)
4334+export(image, variable_name)
4335
4336=== added file 'examples/miral-shell/spinner/spinner-glow.png'
4337Binary files examples/miral-shell/spinner/spinner-glow.png 1970-01-01 00:00:00 +0000 and examples/miral-shell/spinner/spinner-glow.png 2017-08-29 09:17:20 +0000 differ
4338=== added file 'examples/miral-shell/spinner/spinner-logo.png'
4339Binary files examples/miral-shell/spinner/spinner-logo.png 1970-01-01 00:00:00 +0000 and examples/miral-shell/spinner/spinner-logo.png 2017-08-29 09:17:20 +0000 differ
4340=== added file 'examples/miral-shell/spinner/splash.h'
4341--- examples/miral-shell/spinner/splash.h 1970-01-01 00:00:00 +0000
4342+++ examples/miral-shell/spinner/splash.h 2017-08-29 09:17:20 +0000
4343@@ -0,0 +1,45 @@
4344+/*
4345+ * Copyright © 2016 Canonical Ltd.
4346+ *
4347+ * This program is free software: you can redistribute it and/or modify it
4348+ * under the terms of the GNU General Public License version 2 or 3 as
4349+ * published by the Free Software Foundation.
4350+ *
4351+ * This program is distributed in the hope that it will be useful,
4352+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4353+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4354+ * GNU General Public License for more details.
4355+ *
4356+ * You should have received a copy of the GNU General Public License
4357+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4358+ *
4359+ * Authored by: Alan Griffiths <alan@octopull.co.uk>
4360+ */
4361+
4362+#ifndef MIRAL_SHELL_SPINNER_SPLASH_H
4363+#define MIRAL_SHELL_SPINNER_SPLASH_H
4364+
4365+#include <mir_toolkit/client_types.h>
4366+
4367+#include <memory>
4368+
4369+namespace mir { namespace scene { class Session; }}
4370+
4371+namespace mir { class Server; namespace scene { class Session; }}
4372+
4373+class SpinnerSplash
4374+{
4375+public:
4376+ SpinnerSplash();
4377+ ~SpinnerSplash();
4378+
4379+ void operator()(MirConnection* connection);
4380+ void operator()(std::weak_ptr<mir::scene::Session> const& session);
4381+ auto session() const -> std::shared_ptr<mir::scene::Session>;
4382+
4383+private:
4384+ struct Self;
4385+ std::shared_ptr<Self> const self;
4386+};
4387+
4388+#endif //MIRAL_SHELL_SPINNER_SPLASH_H
4389
4390=== added file 'examples/miral-shell/tiling_window_manager.cpp'
4391--- examples/miral-shell/tiling_window_manager.cpp 1970-01-01 00:00:00 +0000
4392+++ examples/miral-shell/tiling_window_manager.cpp 2017-08-29 09:17:20 +0000
4393@@ -0,0 +1,688 @@
4394+/*
4395+ * Copyright © 2015-2016 Canonical Ltd.
4396+ *
4397+ * This program is free software: you can redistribute it and/or modify it
4398+ * under the terms of the GNU General Public License version 2 or 3 as
4399+ * published by the Free Software Foundation.
4400+ *
4401+ * This program is distributed in the hope that it will be useful,
4402+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4403+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4404+ * GNU General Public License for more details.
4405+ *
4406+ * You should have received a copy of the GNU General Public License
4407+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4408+ *
4409+ * Authored By: Alan Griffiths <alan@octopull.co.uk>
4410+ */
4411+
4412+#include "tiling_window_manager.h"
4413+
4414+#include <miral/application_info.h>
4415+#include <miral/window_info.h>
4416+#include <miral/window_manager_tools.h>
4417+#include <miral/output.h>
4418+
4419+#include <linux/input.h>
4420+#include <algorithm>
4421+#include <csignal>
4422+
4423+namespace ms = mir::scene;
4424+using namespace miral;
4425+
4426+namespace
4427+{
4428+struct TilingWindowManagerPolicyData
4429+{
4430+ Rectangle tile;
4431+ Rectangle old_tile;
4432+};
4433+
4434+template<class Info>
4435+inline Rectangle& tile_for(Info& info)
4436+{
4437+ return std::static_pointer_cast<TilingWindowManagerPolicyData>(info.userdata())->tile;
4438+}
4439+
4440+template<class Info>
4441+inline Rectangle const& tile_for(Info const& info)
4442+{
4443+ return std::static_pointer_cast<TilingWindowManagerPolicyData>(info.userdata())->tile;
4444+}
4445+}
4446+
4447+void TilingWindowManagerPolicy::MRUTileList::push(std::shared_ptr<void> const& tile)
4448+{
4449+ tiles.erase(remove(begin(tiles), end(tiles), tile), end(tiles));
4450+ tiles.push_back(tile);
4451+}
4452+
4453+void TilingWindowManagerPolicy::MRUTileList::erase(std::shared_ptr<void> const& tile)
4454+{
4455+ tiles.erase(remove(begin(tiles), end(tiles), tile), end(tiles));
4456+}
4457+
4458+void TilingWindowManagerPolicy::MRUTileList::enumerate(Enumerator const& enumerator) const
4459+{
4460+ for (auto i = tiles.rbegin(); i != tiles.rend(); ++i)
4461+ enumerator(const_cast<std::shared_ptr<void> const&>(*i));
4462+}
4463+
4464+// Demonstrate implementing a simple tiling algorithm
4465+
4466+TilingWindowManagerPolicy::TilingWindowManagerPolicy(
4467+ WindowManagerTools const& tools,
4468+ SpinnerSplash const& spinner,
4469+ miral::InternalClientLauncher const& launcher,
4470+ miral::ActiveOutputsMonitor& outputs_monitor) :
4471+ tools{tools},
4472+ spinner{spinner},
4473+ launcher{launcher},
4474+ outputs_monitor{outputs_monitor}
4475+{
4476+ outputs_monitor.add_listener(this);
4477+}
4478+
4479+TilingWindowManagerPolicy::~TilingWindowManagerPolicy()
4480+{
4481+ outputs_monitor.delete_listener(this);
4482+}
4483+
4484+void TilingWindowManagerPolicy::click(Point cursor)
4485+{
4486+ auto const window = tools.window_at(cursor);
4487+ tools.select_active_window(window);
4488+}
4489+
4490+void TilingWindowManagerPolicy::resize(Point cursor)
4491+{
4492+ if (auto const application = application_under(cursor))
4493+ {
4494+ if (application == application_under(old_cursor))
4495+ {
4496+ if (auto const window = tools.select_active_window(tools.window_at(old_cursor)))
4497+ {
4498+ resize(window, cursor, old_cursor, tile_for(tools.info_for(application)));
4499+ }
4500+ }
4501+ }
4502+}
4503+
4504+auto TilingWindowManagerPolicy::place_new_window(
4505+ ApplicationInfo const& app_info,
4506+ WindowSpecification const& request_parameters)
4507+ -> WindowSpecification
4508+{
4509+ auto parameters = request_parameters;
4510+
4511+ parameters.userdata() = app_info.userdata();
4512+ parameters.state() = parameters.state().is_set() ?
4513+ transform_set_state(parameters.state().value()) : mir_window_state_restored;
4514+
4515+ if (app_info.application() != spinner.session())
4516+ {
4517+ Rectangle const& tile = tile_for(app_info);
4518+
4519+ if (!parameters.parent().is_set() || !parameters.parent().value().lock())
4520+ {
4521+ if (app_info.windows().empty())
4522+ {
4523+ parameters.top_left() = tile.top_left;
4524+ parameters.size() = tile.size;
4525+ }
4526+ else
4527+ {
4528+ auto top_level_windows = count_if(begin(app_info.windows()), end(app_info.windows()), [this]
4529+ (Window const& window){ return !tools.info_for(window).parent(); });
4530+
4531+ parameters.top_left() = tile.top_left + top_level_windows*Displacement{15, 15};
4532+ }
4533+ }
4534+
4535+ clip_to_tile(parameters, tile);
4536+ }
4537+
4538+ return parameters;
4539+}
4540+
4541+void TilingWindowManagerPolicy::advise_new_window(WindowInfo const& window_info)
4542+{
4543+ if (window_info.type() == mir_window_type_normal &&
4544+ !window_info.parent() &&
4545+ window_info.state() == mir_window_state_restored)
4546+ {
4547+ WindowSpecification specification;
4548+
4549+ specification.state() = mir_window_state_maximized;
4550+
4551+ tools.place_and_size_for_state(specification, window_info);
4552+ constrain_size_and_place(specification, window_info.window(), tile_for(window_info));
4553+ tools.modify_window(window_info.window(), specification);
4554+ }
4555+}
4556+
4557+void TilingWindowManagerPolicy::handle_window_ready(WindowInfo& window_info)
4558+{
4559+ if (window_info.can_be_active())
4560+ tools.select_active_window(window_info.window());
4561+
4562+ if (spinner.session() != window_info.window().application())
4563+ {
4564+ tiles.push(window_info.userdata());
4565+ dirty_tiles = true;
4566+ }
4567+}
4568+
4569+namespace
4570+{
4571+template<typename ValueType>
4572+void reset(mir::optional_value<ValueType>& option)
4573+{
4574+ if (option.is_set()) option.consume();
4575+}
4576+}
4577+
4578+void TilingWindowManagerPolicy::handle_modify_window(
4579+ miral::WindowInfo& window_info,
4580+ miral::WindowSpecification const& modifications)
4581+{
4582+ auto const window = window_info.window();
4583+ auto const tile = tile_for(window_info);
4584+ auto mods = modifications;
4585+
4586+ constrain_size_and_place(mods, window, tile);
4587+
4588+ reset(mods.output_id());
4589+
4590+ tools.modify_window(window_info, mods);
4591+}
4592+
4593+void TilingWindowManagerPolicy::constrain_size_and_place(
4594+ WindowSpecification& mods, Window const& window, Rectangle const& tile) const
4595+{
4596+ if (mods.size().is_set())
4597+ {
4598+ auto width = std::min(tile.size.width, mods.size().value().width);
4599+ auto height = std::min(tile.size.height, mods.size().value().height);
4600+
4601+ mods.size() = Size{width, height};
4602+ }
4603+
4604+ if (mods.top_left().is_set())
4605+ {
4606+ auto x = std::max(tile.top_left.x, mods.top_left().value().x);
4607+ auto y = std::max(tile.top_left.y, mods.top_left().value().y);
4608+
4609+ mods.top_left() = Point{x, y};
4610+ }
4611+
4612+ auto top_left = mods.top_left().is_set() ? mods.top_left().value() : window.top_left();
4613+ auto bottom_right = top_left + as_displacement(mods.size().is_set() ? mods.size().value() : window.size());
4614+ auto overhang = bottom_right - tile.bottom_right();
4615+
4616+ if (overhang.dx > DeltaX{0}) top_left = top_left - overhang.dx;
4617+ if (overhang.dy > DeltaY{0}) top_left = top_left - overhang.dy;
4618+
4619+ if (top_left != window.top_left())
4620+ mods.top_left() = top_left;
4621+ else
4622+ reset(mods.top_left());
4623+}
4624+
4625+auto TilingWindowManagerPolicy::transform_set_state(MirWindowState value)
4626+-> MirWindowState
4627+{
4628+ switch (value)
4629+ {
4630+ default:
4631+ return mir_window_state_restored;
4632+
4633+ case mir_window_state_hidden:
4634+ case mir_window_state_minimized:
4635+ return mir_window_state_hidden;
4636+ }
4637+}
4638+
4639+void TilingWindowManagerPolicy::drag(Point cursor)
4640+{
4641+ if (auto const application = application_under(cursor))
4642+ {
4643+ if (application == application_under(old_cursor))
4644+ {
4645+ if (auto const window = tools.select_active_window(tools.window_at(old_cursor)))
4646+ {
4647+
4648+ auto const tile = tile_for(tools.info_for(application));
4649+ WindowSpecification mods;
4650+ mods.top_left() = window.top_left() + (cursor-old_cursor);
4651+ constrain_size_and_place(mods, window, tile);
4652+ tools.modify_window(window, mods);
4653+ }
4654+ }
4655+ }
4656+}
4657+
4658+void TilingWindowManagerPolicy::handle_raise_window(WindowInfo& window_info)
4659+{
4660+ tools.select_active_window(window_info.window());
4661+}
4662+
4663+bool TilingWindowManagerPolicy::handle_keyboard_event(MirKeyboardEvent const* event)
4664+{
4665+ auto const action = mir_keyboard_event_action(event);
4666+ auto const scan_code = mir_keyboard_event_scan_code(event);
4667+ auto const modifiers = mir_keyboard_event_modifiers(event) & modifier_mask;
4668+
4669+ if (action == mir_keyboard_action_down && scan_code == KEY_F12 &&
4670+ (modifiers & modifier_mask) == mir_input_event_modifier_alt)
4671+ {
4672+ launcher.launch("Spinner", spinner);
4673+ return true;
4674+ }
4675+
4676+ if (action == mir_keyboard_action_down && scan_code == KEY_F11)
4677+ {
4678+ switch (modifiers & modifier_mask)
4679+ {
4680+ case mir_input_event_modifier_alt:
4681+ toggle(mir_window_state_maximized);
4682+ return true;
4683+
4684+ case mir_input_event_modifier_shift:
4685+ toggle(mir_window_state_vertmaximized);
4686+ return true;
4687+
4688+ case mir_input_event_modifier_ctrl:
4689+ toggle(mir_window_state_horizmaximized);
4690+ return true;
4691+
4692+ default:
4693+ break;
4694+ }
4695+ }
4696+ else if (action == mir_keyboard_action_down && scan_code == KEY_F4)
4697+ {
4698+ switch (modifiers & modifier_mask)
4699+ {
4700+ case mir_input_event_modifier_alt|mir_input_event_modifier_shift:
4701+ if (auto const& window = tools.active_window())
4702+ kill(window.application(), SIGTERM);
4703+ return true;
4704+
4705+ case mir_input_event_modifier_alt:
4706+ tools.ask_client_to_close(tools.active_window());;
4707+ return true;
4708+
4709+ default:
4710+ break;
4711+ }
4712+ }
4713+ else if (action == mir_keyboard_action_down &&
4714+ modifiers == mir_input_event_modifier_alt &&
4715+ scan_code == KEY_TAB)
4716+ {
4717+ tools.focus_next_application();
4718+
4719+ return true;
4720+ }
4721+ else if (action == mir_keyboard_action_down &&
4722+ modifiers == mir_input_event_modifier_alt &&
4723+ scan_code == KEY_GRAVE)
4724+ {
4725+ tools.focus_next_within_application();
4726+
4727+ return true;
4728+ }
4729+ else if (action == mir_keyboard_action_down &&
4730+ modifiers == (mir_input_event_modifier_alt | mir_input_event_modifier_shift) &&
4731+ scan_code == KEY_GRAVE)
4732+ {
4733+ tools.focus_prev_within_application();
4734+
4735+ return true;
4736+ }
4737+
4738+ return false;
4739+}
4740+
4741+bool TilingWindowManagerPolicy::handle_touch_event(MirTouchEvent const* event)
4742+{
4743+ auto const count = mir_touch_event_point_count(event);
4744+
4745+ long total_x = 0;
4746+ long total_y = 0;
4747+
4748+ for (auto i = 0U; i != count; ++i)
4749+ {
4750+ total_x += mir_touch_event_axis_value(event, i, mir_touch_axis_x);
4751+ total_y += mir_touch_event_axis_value(event, i, mir_touch_axis_y);
4752+ }
4753+
4754+ Point const cursor{total_x/count, total_y/count};
4755+
4756+ bool is_drag = true;
4757+ for (auto i = 0U; i != count; ++i)
4758+ {
4759+ switch (mir_touch_event_action(event, i))
4760+ {
4761+ case mir_touch_action_up:
4762+ return false;
4763+
4764+ case mir_touch_action_down:
4765+ is_drag = false;
4766+ continue;
4767+
4768+ default:
4769+ continue;
4770+ }
4771+ }
4772+
4773+ bool consumes_event = false;
4774+ if (is_drag)
4775+ {
4776+ switch (count)
4777+ {
4778+ case 4:
4779+ resize(cursor);
4780+ consumes_event = true;
4781+ break;
4782+
4783+ case 3:
4784+ drag(cursor);
4785+ consumes_event = true;
4786+ break;
4787+ }
4788+ }
4789+ else
4790+ {
4791+ if (auto const& window = tools.window_at(cursor))
4792+ tools.select_active_window(window);
4793+ }
4794+
4795+ old_cursor = cursor;
4796+ return consumes_event;
4797+}
4798+
4799+bool TilingWindowManagerPolicy::handle_pointer_event(MirPointerEvent const* event)
4800+{
4801+ auto const action = mir_pointer_event_action(event);
4802+ auto const modifiers = mir_pointer_event_modifiers(event) & modifier_mask;
4803+ Point const cursor{
4804+ mir_pointer_event_axis_value(event, mir_pointer_axis_x),
4805+ mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
4806+
4807+ bool consumes_event = false;
4808+
4809+ if (action == mir_pointer_action_button_down)
4810+ {
4811+ click(cursor);
4812+ }
4813+ else if (action == mir_pointer_action_motion &&
4814+ modifiers == mir_input_event_modifier_alt)
4815+ {
4816+ if (mir_pointer_event_button_state(event, mir_pointer_button_primary))
4817+ {
4818+ drag(cursor);
4819+ consumes_event = true;
4820+ }
4821+ else if (mir_pointer_event_button_state(event, mir_pointer_button_tertiary))
4822+ {
4823+ resize(cursor);
4824+ consumes_event = true;
4825+ }
4826+ }
4827+
4828+ old_cursor = cursor;
4829+ return consumes_event;
4830+}
4831+
4832+void TilingWindowManagerPolicy::toggle(MirWindowState state)
4833+{
4834+ if (auto window = tools.active_window())
4835+ {
4836+ auto& window_info = tools.info_for(window);
4837+
4838+ if (window_info.state() == state)
4839+ state = mir_window_state_restored;
4840+
4841+ WindowSpecification mods;
4842+ mods.state() = transform_set_state(state);
4843+ tools.modify_window(window_info, mods);
4844+ }
4845+}
4846+
4847+auto TilingWindowManagerPolicy::application_under(Point position)
4848+-> Application
4849+{
4850+ return tools.find_application([&, this](ApplicationInfo const& info)
4851+ { return spinner.session() != info.application() && tile_for(info).contains(position);});
4852+}
4853+
4854+void TilingWindowManagerPolicy::update_tiles(Rectangles const& outputs)
4855+{
4856+ auto const tile_count = tiles.count();
4857+
4858+ if (tile_count < 1 || outputs.size() < 1) return;
4859+
4860+ auto const bounding_rect = outputs.bounding_rectangle();
4861+
4862+ auto const total_width = bounding_rect.size.width.as_int();
4863+ auto const total_height = bounding_rect.size.height.as_int();
4864+
4865+ auto index = 0;
4866+
4867+ if (tile_count < 3)
4868+ {
4869+ tiles.enumerate([&](std::shared_ptr<void> const& userdata)
4870+ {
4871+ auto const tile_data = std::static_pointer_cast<TilingWindowManagerPolicyData>(userdata);
4872+ tile_data->old_tile = tile_data->tile;
4873+
4874+ auto const x = (total_width * index) / tile_count;
4875+ ++index;
4876+ auto const dx = (total_width * index) / tile_count - x;
4877+
4878+ tile_data->tile = Rectangle{{x, 0}, {dx, total_height}};
4879+ });
4880+ }
4881+ else
4882+ {
4883+ tiles.enumerate([&](std::shared_ptr<void> const& userdata)
4884+ {
4885+ auto const tile_data = std::static_pointer_cast<TilingWindowManagerPolicyData>(userdata);
4886+ tile_data->old_tile = tile_data->tile;
4887+
4888+ auto const dx = total_width/2;
4889+ if (!index)
4890+ {
4891+ tile_data->tile = Rectangle{{0, 0}, {dx, total_height}};
4892+ }
4893+ else
4894+ {
4895+ auto const x = dx;
4896+ auto const y = total_height*(index-1) / (tile_count-1);
4897+ auto const dy = total_height / (tile_count-1);
4898+ tile_data->tile = Rectangle{{x, y}, {dx, dy}};
4899+ }
4900+
4901+ ++index;
4902+ });
4903+ }
4904+
4905+ tools.for_each_application([&](ApplicationInfo& info)
4906+ {
4907+ if (spinner.session() == info.application())
4908+ return;
4909+
4910+ auto const tile_data = std::static_pointer_cast<TilingWindowManagerPolicyData>(info.userdata());
4911+ update_surfaces(info, tile_data->old_tile, tile_data->tile);
4912+ });
4913+}
4914+
4915+void TilingWindowManagerPolicy::update_surfaces(ApplicationInfo& info, Rectangle const& old_tile, Rectangle const& new_tile)
4916+{
4917+ for (auto const& window : info.windows())
4918+ {
4919+ if (window)
4920+ {
4921+ auto& window_info = tools.info_for(window);
4922+
4923+ if (!window_info.parent())
4924+ {
4925+ auto const new_pos = window.top_left() + (new_tile.top_left - old_tile.top_left);
4926+ auto const offset = new_pos - new_tile.top_left;
4927+
4928+ // For now just scale if was filling width/height of tile
4929+ auto const old_size = window.size();
4930+ auto const scaled_width = old_size.width == old_tile.size.width ? new_tile.size.width : old_size.width;
4931+ auto const scaled_height = old_size.height == old_tile.size.height ? new_tile.size.height : old_size.height;
4932+
4933+ auto width = std::min(new_tile.size.width.as_int() - offset.dx.as_int(), scaled_width.as_int());
4934+ auto height = std::min(new_tile.size.height.as_int() - offset.dy.as_int(), scaled_height.as_int());
4935+
4936+ WindowSpecification modifications;
4937+ modifications.top_left() = new_pos;
4938+ modifications.size() = {width, height};
4939+ tools.modify_window(window_info, modifications);
4940+ }
4941+ }
4942+ }
4943+}
4944+
4945+void TilingWindowManagerPolicy::clip_to_tile(miral::WindowSpecification& parameters, Rectangle const& tile)
4946+{
4947+ auto const displacement = parameters.top_left().value() - tile.top_left;
4948+
4949+ auto width = std::min(tile.size.width.as_int()-displacement.dx.as_int(), parameters.size().value().width.as_int());
4950+ auto height = std::min(tile.size.height.as_int()-displacement.dy.as_int(), parameters.size().value().height.as_int());
4951+
4952+ parameters.size() = Size{width, height};
4953+}
4954+
4955+void TilingWindowManagerPolicy::resize(Window window, Point cursor, Point old_cursor, Rectangle bounds)
4956+{
4957+ auto const top_left = window.top_left();
4958+
4959+ auto const old_displacement = old_cursor - top_left;
4960+ auto const new_displacement = cursor - top_left;
4961+
4962+ auto const scale_x = float(new_displacement.dx.as_int())/std::max(1.0f, float(old_displacement.dx.as_int()));
4963+ auto const scale_y = float(new_displacement.dy.as_int())/std::max(1.0f, float(old_displacement.dy.as_int()));
4964+
4965+ if (scale_x <= 0.0f || scale_y <= 0.0f) return;
4966+
4967+ auto const old_size = window.size();
4968+ Size new_size{scale_x*old_size.width, scale_y*old_size.height};
4969+
4970+ auto const size_limits = as_size(bounds.bottom_right() - top_left);
4971+
4972+ if (new_size.width > size_limits.width)
4973+ new_size.width = size_limits.width;
4974+
4975+ if (new_size.height > size_limits.height)
4976+ new_size.height = size_limits.height;
4977+
4978+ window.resize(new_size);
4979+}
4980+
4981+void TilingWindowManagerPolicy::advise_focus_gained(WindowInfo const& info)
4982+{
4983+ tools.raise_tree(info.window());
4984+
4985+ if (auto const spinner_session = spinner.session())
4986+ {
4987+ auto const& spinner_info = tools.info_for(spinner_session);
4988+
4989+ if (spinner_info.windows().size() > 0)
4990+ tools.raise_tree(spinner_info.windows()[0]);
4991+ }
4992+ else
4993+ {
4994+ tiles.push(info.userdata());
4995+ dirty_tiles = true;
4996+ }
4997+}
4998+
4999+void TilingWindowManagerPolicy::advise_new_app(miral::ApplicationInfo& application)
5000+{
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches