./0000755000004100000410000000000013115234677011254 5ustar www-datawww-data./CMakeLists.txt0000644000004100000410000003101413115234664014007 0ustar www-datawww-data# Copyright © 2012 Canonical Ltd. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 3 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Authored by: Thomas Voss , # Alan Griffiths set(CMAKE_GCOV gcov) project(Mir) cmake_minimum_required(VERSION 2.8) cmake_policy(SET CMP0015 NEW) cmake_policy(SET CMP0022 NEW) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(MIR_VERSION_MAJOR 0) set(MIR_VERSION_MINOR 26) set(MIR_VERSION_PATCH 3) add_definitions(-DMIR_VERSION_MAJOR=${MIR_VERSION_MAJOR}) add_definitions(-DMIR_VERSION_MINOR=${MIR_VERSION_MINOR}) add_definitions(-DMIR_VERSION_MICRO=${MIR_VERSION_PATCH}) add_definitions(-D_GNU_SOURCE) add_definitions(-D_FILE_OFFSET_BITS=64) set(MIR_VERSION ${MIR_VERSION_MAJOR}.${MIR_VERSION_MINOR}.${MIR_VERSION_PATCH}) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) execute_process( COMMAND ${CMAKE_CXX_COMPILER} -dumpmachine OUTPUT_VARIABLE TARGET_ARCH OUTPUT_STRIP_TRAILING_WHITESPACE ) option(use_debflags "Use build flags from dpkg-buildflags." OFF) if(use_debflags) include (cmake/Debian.cmake) endif() include (cmake/EnableCoverageReport.cmake) include (cmake/MirCommon.cmake) include (GNUInstallDirs) set(build_types "None;Debug;Release;RelWithDebInfo;MinSizeRel;Coverage;AddressSanitizer;ThreadSanitizer;UBSanitizer") # Change informational string for CMAKE_BUILD_TYPE set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "${build_types}" FORCE) # Enable cmake-gui to display a drop down list for CMAKE_BUILD_TYPE set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${build_types}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -g -Werror -Wall -pedantic -Wextra -fPIC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -g -std=c++14 -Werror -Wall -fno-strict-aliasing -pedantic -Wnon-virtual-dtor -Wextra -fPIC") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--as-needed") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") include(CheckCXXCompilerFlag) check_cxx_compiler_flag(-Wmismatched-tags HAS_W_MISMATCHED_TAGS) if(HAS_W_MISMATCHED_TAGS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-mismatched-tags") endif() option(MIR_USE_LD_GOLD "Enables the \"gold\" linker." OFF) if(MIR_USE_LD_GOLD) set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=gold") set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fuse-ld=gold") set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold") endif() # Link time optimization allows leaner, cleaner libraries message(STATUS "CMAKE_C_COMPILER: " ${CMAKE_C_COMPILER}) option(MIR_LINK_TIME_OPTIMIZATION "Enables the linker to optimize binaries." OFF) if(MIR_LINK_TIME_OPTIMIZATION) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto -ffat-lto-objects") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -ffat-lto-objects") if(${CMAKE_COMPILER_IS_GNUCXX}) set(CMAKE_NM "gcc-nm") set(CMAKE_AR "gcc-ar") set(CMAKE_RANLIB "gcc-ranlib") endif() endif() string(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type_lower) ##################################################################### # Enable code coverage calculation with gcov/gcovr/lcov # Usage: # * Switch build type to coverage (use ccmake or cmake-gui) # * Invoke make, make test, make coverage # * Find html report in subdir coveragereport # * Find xml report feasible for jenkins in coverage.xml ##################################################################### if(cmake_build_type_lower MATCHES "coverage") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage -fprofile-arcs") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -ftest-coverage -fprofile-arcs") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -ftest-coverage -fprofile-arcs") endif() if(cmake_build_type_lower MATCHES "addresssanitizer") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=address") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address") elseif(cmake_build_type_lower MATCHES "threadsanitizer") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -fno-omit-frame-pointer") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -fno-omit-frame-pointer") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=thread") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=thread") link_libraries(tsan) # Workaround for LP:1413474 elseif(cmake_build_type_lower MATCHES "ubsanitizer") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-omit-frame-pointer") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-omit-frame-pointer") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fsanitize=undefined") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=undefined") # "Symbol already defined" errors occur with pre-compiled headers SET(MIR_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "Use precompiled headers" FORCE) else() # AddressSanitizer builds fail if we disallow undefined symbols set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--no-undefined") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-undefined") endif() # Define LOG_NDEBUG=1 to ensure Android ALOGV calls are not compiled in to # consume CPU time... add_definitions(-DLOG_NDEBUG=1) enable_testing() include_directories(include/core) include_directories(include/common) include_directories(include/cookie) # Check for boost find_package(Boost 1.48.0 COMPONENTS date_time system program_options filesystem REQUIRED) include_directories (SYSTEM ${Boost_INCLUDE_DIRS} ) option( MIR_DISABLE_EPOLL_REACTOR "Disable boost::asio's epoll implementation and switch to a select-based reactor to account for ancient kernels on ppa builders." OFF ) if(MIR_DISABLE_EPOLL_REACTOR) add_definitions( -DBOOST_ASIO_DISABLE_EPOLL -DBOOST_ASIO_DISABLE_KQUEUE -DBOOST_ASIO_DISABLE_DEV_POLL ) endif(MIR_DISABLE_EPOLL_REACTOR) add_definitions(-DMESA_EGL_NO_X11_HEADERS) # Default to KMS backend, but build all of them set( MIR_PLATFORM mesa-kms;android;mesa-x11;eglstream-kms CACHE STRING "a list of graphics backends to build (options are 'mesa-kms', 'android', 'mesa-x11', or 'eglstream-kms')" ) list(GET MIR_PLATFORM 0 MIR_TEST_PLATFORM) option(MIR_ENABLE_TESTS "Build tests" ON) foreach(platform IN LISTS MIR_PLATFORM) if (platform STREQUAL "mesa-kms") set(MIR_BUILD_PLATFORM_MESA_KMS TRUE) endif() if (platform STREQUAL "android") set(MIR_BUILD_PLATFORM_ANDROID TRUE) endif() if (platform STREQUAL "mesa-x11") set(MIR_BUILD_PLATFORM_MESA_X11 TRUE) endif() if (platform STREQUAL "eglstream-kms") set(MIR_BUILD_PLATFORM_EGLSTREAM_KMS TRUE) endif() endforeach(platform) find_package(EGL REQUIRED) find_package(GLESv2 REQUIRED) find_package(GLM REQUIRED) find_package(Protobuf REQUIRED ) find_package(CapnProto REQUIRED) find_package(GLog REQUIRED) find_package(GFlags REQUIRED) find_package(LTTngUST REQUIRED) pkg_check_modules(UDEV REQUIRED libudev) pkg_check_modules(GLIB REQUIRED glib-2.0) include_directories (SYSTEM ${GLESv2_INCLUDE_DIRS}) include_directories (SYSTEM ${EGL_INCLUDE_DIRS}) include_directories (SYSTEM ${GLM_INCLUDE_DIRS}) # # Full OpenGL support is possibly complete but not yet perfect. So is # presently disabled by default due to: # 1. Black windows bug: https://bugs.freedesktop.org/show_bug.cgi?id=92265 # 2. Use of glEGLImageTargetTexture2DOES in: # src/platform/graphics/egl_extensions.cpp # possibly shouldn't work even though it does. Or should it? # #if (TARGET_ARCH STREQUAL "x86_64-linux-gnu" OR # TARGET_ARCH STREQUAL "i386-linux-gnu") # set(DEFAULT_LIBGL "libGL") #else() set(DEFAULT_LIBGL "libGLESv2") #endif() set(MIR_SERVER_LIBGL ${DEFAULT_LIBGL} CACHE STRING "OpenGL library to use in Mir servers {libGL,libGLESv2}") if (MIR_SERVER_LIBGL STREQUAL "libGL") pkg_check_modules(GL REQUIRED gl) add_definitions( -DGL_GLEXT_PROTOTYPES -DMIR_SERVER_GL_H= -DMIR_SERVER_GLEXT_H= -DMIR_SERVER_EGL_OPENGL_BIT=EGL_OPENGL_BIT -DMIR_SERVER_EGL_OPENGL_API=EGL_OPENGL_API ) elseif (MIR_SERVER_LIBGL STREQUAL "libGLESv2") pkg_check_modules(GL REQUIRED glesv2) add_definitions( -DMIR_SERVER_GL_H= -DMIR_SERVER_GLEXT_H= -DMIR_SERVER_EGL_OPENGL_BIT=EGL_OPENGL_ES2_BIT -DMIR_SERVER_EGL_OPENGL_API=EGL_OPENGL_ES_API ) else() message(FATAL_ERROR "Invalid MIR_SERVER_LIBGL value ${MIR_SERVER_LIBGL}") endif() if (MIR_BUILD_PLATFORM_ANDROID) find_package(AndroidProperties REQUIRED) find_package(LibHardware REQUIRED) endif() if (MIR_BUILD_PLATFORM_MESA_KMS OR MIR_BUILD_PLATFORM_MESA_X11) find_package( PkgConfig ) pkg_check_modules( GBM REQUIRED gbm>=9.0.0) pkg_check_modules( DRM REQUIRED libdrm ) endif() if (MIR_BUILD_PLATFORM_EGLSTREAM_KMS) pkg_check_modules(EPOXY REQUIRED epoxy) endif() set(MIR_ANDROID_INCLUDE_DIRECTORIES) # to be filled by android-input set(MIR_ANDROID_INPUT_COMPILE_FLAGS) # to be filled by android-input set(MIR_3RD_PARTY_INCLUDE_DIRECTORIES) add_subdirectory(3rd_party/) set(MIR_TRACEPOINT_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/mir/tools) set(MIR_GENERATED_INCLUDE_DIRECTORIES) macro(uses_android_input _target_name) set_property(TARGET ${_target_name} APPEND_STRING PROPERTY COMPILE_FLAGS "${MIR_ANDROID_INPUT_COMPILE_FLAGS}") endmacro() add_subdirectory(src/) include_directories(${MIR_GENERATED_INCLUDE_DIRECTORIES}) # This copy is used by users of mirplatforminputevdev if ("${LIBINPUT_VERSION}" VERSION_LESS "1.1") add_definitions(-DMIR_LIBINPUT_HAS_ACCEL_PROFILE=0) else () add_definitions(-DMIR_LIBINPUT_HAS_ACCEL_PROFILE=1) endif () add_subdirectory(benchmarks/) add_subdirectory(examples/) add_subdirectory(playground/) add_subdirectory(guides/) add_subdirectory(cmake/) if (MIR_ENABLE_TESTS) find_package(GtestGmock REQUIRED) pkg_check_modules(LIBEVDEV REQUIRED libevdev) include_directories(${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR}) add_subdirectory(tests/) # There's no nice way to format this. Thanks CMake. mir_add_test(NAME LGPL-required COMMAND /bin/sh -c "! grep -rl 'GNU General' ${PROJECT_SOURCE_DIR}/src/client ${PROJECT_SOURCE_DIR}/include/client ${PROJECT_SOURCE_DIR}/src/common ${PROJECT_SOURCE_DIR}/include/common ${PROJECT_SOURCE_DIR}/src/include/common ${PROJECT_SOURCE_DIR}/src/platform ${PROJECT_SOURCE_DIR}/include/platform ${PROJECT_SOURCE_DIR}/src/include/platform ${PROJECT_SOURCE_DIR}/src/capnproto" ) mir_add_test(NAME GPL-required COMMAND /bin/sh -c "! grep -rl 'GNU Lesser' ${PROJECT_SOURCE_DIR}/src/server ${PROJECT_SOURCE_DIR}/include/server ${PROJECT_SOURCE_DIR}/src/include/server ${PROJECT_SOURCE_DIR}/tests ${PROJECT_SOURCE_DIR}/examples" ) mir_add_test(NAME package-abis COMMAND /bin/sh -c "cd ${PROJECT_SOURCE_DIR} && tools/update_package_abis.sh --check --verbose") endif () enable_coverage_report(mirserver) include (cmake/Doxygen.cmake) include (cmake/ABICheck.cmake) add_custom_target(ptest COMMAND "${CMAKE_SOURCE_DIR}/tools/run_ctests.sh" "--cost-file" "${CMAKE_BINARY_DIR}/ptest_ctest_cost_data.txt" "sh ${CMAKE_BINARY_DIR}/discover_all_tests.sh" "--" "$$ARGS" ) add_custom_target(release-checks) mir_check_no_unreleased_symbols(mirclient release-checks) mir_check_no_unreleased_symbols(mircommon release-checks) mir_check_no_unreleased_symbols(mircookie release-checks) mir_check_no_unreleased_symbols(mirplatform release-checks) mir_check_no_unreleased_symbols(mirprotobuf release-checks) mir_check_no_unreleased_symbols(mirserver release-checks) if (TARGET doc) add_custom_target(doc-show xdg-open ${CMAKE_BINARY_DIR}/doc/html/index.html DEPENDS doc) endif() ./playground/0000755000004100000410000000000013115234677013440 5ustar www-datawww-data./playground/render_surface.cpp0000644000004100000410000001523013115234664017130 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author: Christopher James Halse Rogers * Cemil Azizoglu */ #include #include #include #include #include #include #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/rs/mir_render_surface.h" #include "client_helpers.h" namespace me = mir::examples; class Pixel { public: Pixel(void* addr, MirPixelFormat format) : addr{addr}, format{format} { } void write(int r, int g, int b, int a) { switch (format) { case mir_pixel_format_abgr_8888: *((uint32_t*) addr) = (uint32_t) a << 24 | (uint32_t) b << 16 | (uint32_t) g << 8 | (uint32_t) r; break; case mir_pixel_format_xbgr_8888: *((uint32_t*) addr) = /* Not filling in the X byte is correct but buggy (LP: #1423462) */ (uint32_t) b << 16 | (uint32_t) g << 8 | (uint32_t) r; break; case mir_pixel_format_argb_8888: *((uint32_t*) addr) = (uint32_t) a << 24 | (uint32_t) r << 16 | (uint32_t) g << 8 | (uint32_t) b; break; case mir_pixel_format_xrgb_8888: *((uint32_t*) addr) = /* Not filling in the X byte is correct but buggy (LP: #1423462) */ (uint32_t) r << 16 | (uint32_t) g << 8 | (uint32_t) b; break; case mir_pixel_format_rgb_888: *((uint8_t*) addr) = r; *((uint8_t*) addr + 1) = g; *((uint8_t*) addr + 2) = b; break; case mir_pixel_format_bgr_888: *((uint8_t*) addr) = b; *((uint8_t*) addr + 1) = g; *((uint8_t*) addr + 2) = r; break; default: throw std::runtime_error{"Pixel format unsupported by Pixel::write!"}; } } public: void* const addr; MirPixelFormat const format; }; class pixel_iterator : std::iterator { public: pixel_iterator(MirGraphicsRegion const& region, int x, int y) : x{x}, y{y}, buffer(region) { } pixel_iterator(MirGraphicsRegion const& region) : pixel_iterator(region, 0, 0) { } pixel_iterator& operator++() { x++; if (x == buffer.width) { x = 0; y++; } return *this; } pixel_iterator operator++(int) { auto old = *this; ++(*this); return old; } Pixel operator*() const { return Pixel{ buffer.vaddr + (x * MIR_BYTES_PER_PIXEL(buffer.pixel_format)) + (y * buffer.stride), buffer.pixel_format}; } bool operator==(pixel_iterator const& rhs) { return rhs.buffer.vaddr == buffer.vaddr && rhs.x == x && rhs.y == y; } bool operator!=(pixel_iterator const& rhs) { return !(*this == rhs); } private: int x, y; MirGraphicsRegion const buffer; }; pixel_iterator begin(MirGraphicsRegion const& region) { return pixel_iterator(region); } pixel_iterator end(MirGraphicsRegion const& region) { return pixel_iterator{region, 0, region.height}; } void fill_stream_with(MirBufferStream* stream, int r, int g, int b, int a) { MirGraphicsRegion buffer; mir_buffer_stream_get_graphics_region(stream, &buffer); for (auto pixel : buffer) { pixel.write(r, g, b, a); } } void bounce_position(int& position, int& delta, int min, int max) { if (position <= min || position >= max) { delta = -delta; } position += delta; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" int main(int /*argc*/, char* /*argv*/[]) { char const* socket = nullptr; int const width = 200; int const height = 200; int baseColour = 255, dbase = 1; unsigned int nformats{0}; MirPixelFormat pixel_format; me::Connection connection{socket, "MirRenderSurface example"}; auto render_surface = mir_connection_create_render_surface_sync(connection, width, height); if (!mir_render_surface_is_valid(render_surface)) throw std::runtime_error( std::string(mir_render_surface_get_error_message(render_surface))); auto spec = mir_create_normal_window_spec(connection, width, height); mir_window_spec_set_name(spec, "Stream"); mir_window_spec_add_render_surface(spec, render_surface, width, height, 0, 0); mir_connection_get_available_surface_formats(connection, &pixel_format, 1, &nformats); if (nformats == 0) throw std::runtime_error("no pixel formats for buffer stream"); printf("Software Driver selected pixel format %d\n", pixel_format); auto buffer_stream = mir_render_surface_get_buffer_stream( render_surface, width, height, pixel_format); auto window = mir_create_window_sync(spec); mir_window_spec_release(spec); fill_stream_with(buffer_stream, 255, 0, 0, 128); mir_buffer_stream_swap_buffers_sync(buffer_stream); sigset_t halt_signals; sigemptyset(&halt_signals); sigaddset(&halt_signals, SIGTERM); sigaddset(&halt_signals, SIGQUIT); sigaddset(&halt_signals, SIGINT); sigprocmask(SIG_BLOCK, &halt_signals, nullptr); int const signal_watch{signalfd(-1, &halt_signals, SFD_CLOEXEC)}; pollfd signal_poll{ signal_watch, POLLIN | POLLERR, 0 }; while (poll(&signal_poll, 1, 0) <= 0) { bounce_position(baseColour, dbase, 128, 255); fill_stream_with(buffer_stream, baseColour, 0, 0, 128); mir_buffer_stream_swap_buffers_sync(buffer_stream); } mir_render_surface_release(render_surface); mir_window_release_sync(window); close(signal_watch); return 0; } #pragma GCC diagnostic pop ./playground/demo-shell/0000755000004100000410000000000013115234677015471 5ustar www-datawww-data./playground/demo-shell/CMakeLists.txt0000644000004100000410000000052413115234664020226 0ustar www-datawww-dataadd_library(demo-shell STATIC demo_compositor.cpp demo_renderer.cpp window_manager.cpp ) add_subdirectory(typo) target_link_libraries(demo-shell typo) mir_add_wrapped_executable(mir_proving_server demo_shell.cpp ) target_link_libraries(mir_proving_server demo-shell mirserver playgroundserverconfig exampleserverconfig ) ./playground/demo-shell/demo_renderer.cpp0000644000004100000410000003424713115234664021015 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #define MIR_LOG_COMPONENT "DemoRenderer" #include "typo_stub_renderer.h" #ifdef TYPO_SUPPORTS_FREETYPE #include "typo_freetype_renderer.h" #endif #include "demo_renderer.h" #include #include #include using namespace mir; using namespace mir::examples; using namespace mir::geometry; using namespace mir::compositor; using namespace mir::renderer; namespace { struct Color { GLubyte r, g, b, a; }; float penumbra_curve(float x) { return 1.0f - std::sin(x * M_PI / 2.0f); } GLuint generate_shadow_corner_texture(float opacity) { struct Texel { GLubyte luminance; GLubyte alpha; }; int const width = 256; Texel image[width][width]; int const max = width - 1; for (int y = 0; y < width; ++y) { float curve_y = opacity * 255.0f * penumbra_curve(static_cast(y) / max); for (int x = 0; x < width; ++x) { Texel *t = &image[y][x]; t->luminance = 0; t->alpha = curve_y * penumbra_curve(static_cast(x) / max); } } GLuint corner; glGenTextures(1, &corner); glBindTexture(GL_TEXTURE_2D, corner); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width, width, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, image); return corner; } GLuint generate_frame_corner_texture(float corner_radius, Color const& color, GLubyte highlight) { int const height = 256; /* * GCC 4.9 with optimizations enabled will generate armhf NEON/VFP instructions * here that are not understood/implemented by Valgrind (but are by hardware), * causing Valgrind to crash: * eebe 0acc vcvt.s32.f32 s0, s0, #8 * So this clumsy expression below tricks the compiler into not using those * optimized ARM instructions that Valgrind doesn't support yet: */ int const width = height / (1.0f / corner_radius); Color image[height * height]; // Worst case still much faster than the heap int const cx = width; int const cy = cx; int const radius_sqr = cx * cy; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { Color col = color; // Set gradient if (y < cy) { float brighten = (1.0f - (static_cast(y) / cy)) * std::sin(x * M_PI / (2 * (width - 1))); col.r += (highlight - col.r) * brighten; col.g += (highlight - col.g) * brighten; col.b += (highlight - col.b) * brighten; } // Cut out the corner in a circular shape. if (x < cx && y < cy) { int dx = cx - x; int dy = cy - y; if (dx * dx + dy * dy >= radius_sqr) col = {0, 0, 0, 0}; } image[y * width + x] = col; } } GLuint corner; glGenTextures(1, &corner); glBindTexture(GL_TEXTURE_2D, corner); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); glGenerateMipmap(GL_TEXTURE_2D); // Antialiasing please return corner; } static const GLchar inverse_fshader[] = { "#ifdef GL_ES\n" "precision mediump float;\n" "#endif\n" "uniform sampler2D tex;\n" "uniform float alpha;\n" "varying vec2 v_texcoord;\n" "void main() {\n" " vec4 f = texture2D(tex, v_texcoord);\n" " vec3 inverted = (vec3(1.0) - (f.rgb / f.a)) * f.a;\n" " gl_FragColor = alpha*vec4(inverted, f.a);\n" "}\n" }; static const GLchar contrast_fshader[] = { "#ifdef GL_ES\n" "precision mediump float;\n" "#endif\n" "uniform sampler2D tex;\n" "uniform float alpha;\n" "varying vec2 v_texcoord;\n" "void main() {\n" " vec4 raw = texture2D(tex, v_texcoord);\n" " vec3 bent = (1.0 - cos(raw.rgb * 3.141592654)) / 2.0;\n" " gl_FragColor = alpha * vec4(bent, raw.a);\n" "}\n" }; } // namespace DemoRenderer::DemoRenderer( graphics::DisplayBuffer& display_buffer, float const titlebar_height, float const shadow_radius) : renderer::gl::Renderer(display_buffer), titlebar_height{titlebar_height}, shadow_radius{shadow_radius}, corner_radius{0.5f}, colour_effect{none}, inverse_program(family.add_program(vshader, inverse_fshader)), contrast_program(family.add_program(vshader, contrast_fshader)), title_cache(std::make_shared()) { shadow_corner_tex = generate_shadow_corner_texture(0.4f); titlebar_corner_tex = generate_frame_corner_texture(corner_radius, {128,128,128,255}, 255); clear_color[0] = clear_color[1] = clear_color[2] = 0.2f; clear_color[3] = 1.0f; #ifdef TYPO_SUPPORTS_FREETYPE const char title_font_path[] = "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf"; auto ftrenderer = std::make_shared(); if (ftrenderer->load(title_font_path, 128)) title_cache.change_renderer(ftrenderer); else mir::log_error("Failed to load titlebar font: %s", title_font_path); #endif } DemoRenderer::~DemoRenderer() { glDeleteTextures(1, &shadow_corner_tex); glDeleteTextures(1, &titlebar_corner_tex); } void DemoRenderer::begin(DecorMap&& d) const { decor_map = std::move(d); title_cache.drop_unused(); title_cache.mark_all_unused(); } void DemoRenderer::tessellate(std::vector& primitives, graphics::Renderable const& renderable) const { renderer::gl::Renderer::tessellate(primitives, renderable); auto d = decor_map.find(renderable.id()); if (d != decor_map.end()) { auto& decor = d->second; if (decor->type != Decoration::Type::none) { tessellate_shadow(primitives, renderable, shadow_radius); tessellate_frame(primitives, renderable, titlebar_height, decor->name.c_str()); } } } void DemoRenderer::tessellate_shadow(std::vector& primitives, graphics::Renderable const& renderable, float radius) const { auto const& rect = renderable.screen_position(); GLfloat left = rect.top_left.x.as_int(); GLfloat right = left + rect.size.width.as_int(); GLfloat top = rect.top_left.y.as_int(); GLfloat bottom = top + rect.size.height.as_int(); auto n = primitives.size(); primitives.resize(n + 8); GLfloat rightr = right + radius; GLfloat leftr = left - radius; GLfloat topr = top - radius; GLfloat bottomr = bottom + radius; auto& right_shadow = primitives[n++]; right_shadow.tex_id = shadow_corner_tex; right_shadow.vertices[0] = {{right, top, 0.0f}, {0.0f, 0.0f}}; right_shadow.vertices[1] = {{rightr, top, 0.0f}, {1.0f, 0.0f}}; right_shadow.vertices[2] = {{rightr, bottom, 0.0f}, {1.0f, 0.0f}}; right_shadow.vertices[3] = {{right, bottom, 0.0f}, {0.0f, 0.0f}}; auto& left_shadow = primitives[n++]; left_shadow.tex_id = shadow_corner_tex; left_shadow.vertices[0] = {{leftr, top, 0.0f}, {1.0f, 0.0f}}; left_shadow.vertices[1] = {{left, top, 0.0f}, {0.0f, 0.0f}}; left_shadow.vertices[2] = {{left, bottom, 0.0f}, {0.0f, 0.0f}}; left_shadow.vertices[3] = {{leftr, bottom, 0.0f}, {1.0f, 0.0f}}; auto& top_shadow = primitives[n++]; top_shadow.tex_id = shadow_corner_tex; top_shadow.vertices[0] = {{left, topr, 0.0f}, {1.0f, 0.0f}}; top_shadow.vertices[1] = {{right, topr, 0.0f}, {1.0f, 0.0f}}; top_shadow.vertices[2] = {{right, top, 0.0f}, {0.0f, 0.0f}}; top_shadow.vertices[3] = {{left, top, 0.0f}, {0.0f, 0.0f}}; auto& bottom_shadow = primitives[n++]; bottom_shadow.tex_id = shadow_corner_tex; bottom_shadow.vertices[0] = {{left, bottom, 0.0f}, {0.0f, 0.0f}}; bottom_shadow.vertices[1] = {{right, bottom, 0.0f}, {0.0f, 0.0f}}; bottom_shadow.vertices[2] = {{right, bottomr, 0.0f}, {1.0f, 0.0f}}; bottom_shadow.vertices[3] = {{left, bottomr, 0.0f}, {1.0f, 0.0f}}; auto& tr_shadow = primitives[n++]; tr_shadow.tex_id = shadow_corner_tex; tr_shadow.vertices[0] = {{right, top, 0.0f}, {0.0f, 0.0f}}; tr_shadow.vertices[1] = {{right, topr, 0.0f}, {1.0f, 0.0f}}; tr_shadow.vertices[2] = {{rightr, topr, 0.0f}, {1.0f, 1.0f}}; tr_shadow.vertices[3] = {{rightr, top, 0.0f}, {0.0f, 1.0f}}; auto& br_shadow = primitives[n++]; br_shadow.tex_id = shadow_corner_tex; br_shadow.vertices[0] = {{right, bottom, 0.0f}, {0.0f, 0.0f}}; br_shadow.vertices[1] = {{rightr, bottom, 0.0f}, {1.0f, 0.0f}}; br_shadow.vertices[2] = {{rightr, bottomr, 0.0f}, {1.0f, 1.0f}}; br_shadow.vertices[3] = {{right, bottomr, 0.0f}, {0.0f, 1.0f}}; auto& bl_shadow = primitives[n++]; bl_shadow.tex_id = shadow_corner_tex; bl_shadow.vertices[0] = {{left, bottom, 0.0f}, {0.0f, 0.0f}}; bl_shadow.vertices[1] = {{left, bottomr, 0.0f}, {1.0f, 0.0f}}; bl_shadow.vertices[2] = {{leftr, bottomr, 0.0f}, {1.0f, 1.0f}}; bl_shadow.vertices[3] = {{leftr, bottom, 0.0f}, {0.0f, 1.0f}}; auto& tl_shadow = primitives[n++]; tl_shadow.tex_id = shadow_corner_tex; tl_shadow.vertices[0] = {{left, top, 0.0f}, {0.0f, 0.0f}}; tl_shadow.vertices[1] = {{leftr, top, 0.0f}, {1.0f, 0.0f}}; tl_shadow.vertices[2] = {{leftr, topr, 0.0f}, {1.0f, 1.0f}}; tl_shadow.vertices[3] = {{left, topr, 0.0f}, {0.0f, 1.0f}}; } void DemoRenderer::tessellate_frame(std::vector& primitives, graphics::Renderable const& renderable, float titlebar_height, char const* name) const { auto const& rect = renderable.screen_position(); GLfloat left = rect.top_left.x.as_int(); GLfloat right = left + rect.size.width.as_int(); GLfloat top = rect.top_left.y.as_int(); auto n = primitives.size(); primitives.resize(n + 4); GLfloat htop = top - titlebar_height; GLfloat in = titlebar_height * corner_radius; GLfloat inleft = left + in; GLfloat inright = right - in; GLfloat mid = (left + right) / 2.0f; if (inleft > mid) inleft = mid; if (inright < mid) inright = mid; auto& top_left_corner = primitives[n++]; top_left_corner.tex_id = titlebar_corner_tex; top_left_corner.vertices[0] = {{left, htop, 0.0f}, {0.0f, 0.0f}}; top_left_corner.vertices[1] = {{inleft, htop, 0.0f}, {1.0f, 0.0f}}; top_left_corner.vertices[2] = {{inleft, top, 0.0f}, {1.0f, 1.0f}}; top_left_corner.vertices[3] = {{left, top, 0.0f}, {0.0f, 1.0f}}; auto& top_right_corner = primitives[n++]; top_right_corner.tex_id = titlebar_corner_tex; top_right_corner.vertices[0] = {{inright, htop, 0.0f}, {1.0f, 0.0f}}; top_right_corner.vertices[1] = {{right, htop, 0.0f}, {0.0f, 0.0f}}; top_right_corner.vertices[2] = {{right, top, 0.0f}, {0.0f, 1.0f}}; top_right_corner.vertices[3] = {{inright, top, 0.0f}, {1.0f, 1.0f}}; auto& titlebar = primitives[n++]; titlebar.tex_id = titlebar_corner_tex; titlebar.vertices[0] = {{inleft, htop, 0.0f}, {1.0f, 0.0f}}; titlebar.vertices[1] = {{inright, htop, 0.0f}, {1.0f, 0.0f}}; titlebar.vertices[2] = {{inright, top, 0.0f}, {1.0f, 1.0f}}; titlebar.vertices[3] = {{inleft, top, 0.0f}, {1.0f, 1.0f}}; auto str = title_cache.get(name); GLfloat text_vin = titlebar_height / 5; GLfloat text_top = htop + text_vin; GLfloat text_bot = top - text_vin; GLfloat text_height = text_bot - text_top; GLfloat text_scale = text_height / str.height; GLfloat text_left = inleft; GLfloat text_right = text_left + text_scale * str.width; GLfloat text_u = 1.0f; if (text_right > inright) // Title too long for window { text_u = (inright - text_left) / (text_right - text_left); text_right = inright; } auto& text_prim = primitives[n++]; text_prim.tex_id = str.tex; text_prim.vertices[0] = {{text_left, text_top, 0.0f}, {0.0f, 0.0f}}; text_prim.vertices[1] = {{text_right, text_top, 0.0f}, {text_u, 0.0f}}; text_prim.vertices[2] = {{text_right, text_bot, 0.0f}, {text_u, 1.0f}}; text_prim.vertices[3] = {{text_left, text_bot, 0.0f}, {0.0f, 1.0f}}; } void DemoRenderer::set_colour_effect(ColourEffect e) { colour_effect = e; } void DemoRenderer::draw(graphics::Renderable const& renderable, renderer::gl::Renderer::Program const& current_program) const { const renderer::gl::Renderer::Program* const programs[ColourEffect::neffects] = { ¤t_program, &inverse_program, &contrast_program }; renderer::gl::Renderer::draw(renderable, *programs[colour_effect]); } ./playground/demo-shell/demo_compositor.cpp0000644000004100000410000001517613115234664021405 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/graphics/display_buffer.h" #include "mir/compositor/compositor_report.h" #include "mir/compositor/scene_element.h" #include "demo_compositor.h" namespace me = mir::examples; namespace mg = mir::graphics; namespace mc = mir::compositor; namespace geom = mir::geometry; std::mutex me::DemoCompositor::instances_mutex; std::unordered_set me::DemoCompositor::instances; me::DemoCompositor::DemoCompositor( mg::DisplayBuffer& display_buffer, std::shared_ptr const& report) : display_buffer(display_buffer), report(report), viewport(display_buffer.view_area()), zoom_mag{1.0f}, renderer( display_buffer, 30.0f, //titlebar_height 80.0f) //shadow_radius { std::lock_guard lock(instances_mutex); instances.insert(this); } me::DemoCompositor::~DemoCompositor() { std::lock_guard lock(instances_mutex); instances.erase(this); } void me::DemoCompositor::for_each(std::function f) { std::lock_guard lock(instances_mutex); for (auto& i : instances) f(*i); } void me::DemoCompositor::composite(mc::SceneElementSequence&& elements) { report->began_frame(this); //a simple filtering out of renderables that shouldn't be drawn //the elements should be notified if they are rendered or not bool nonrenderlist_elements{false}; mg::RenderableList renderable_list; DecorMap decorated; for(auto const& it : elements) { auto const& renderable = it->renderable(); bool embellished = false; if (auto decor = it->decoration()) { embellished = decor->type != mc::Decoration::Type::none; decorated[renderable->id()] = std::move(decor); } if (embellished || viewport.overlaps(renderable->screen_position())) { renderable_list.push_back(renderable); /* * TODO: This logic could be replaced more cleanly in future by * the surface stack logic setting decoration status more * accurately for fullscreen surfaces. */ // Fullscreen and opaque? Definitely no embellishment if (renderable->screen_position() == viewport && renderable->alpha() == 1.0f && !renderable->shaped() && renderable->transformation() == glm::mat4()) { embellished = false; nonrenderlist_elements = false; // Don't care what's underneath } it->rendered(); } else { it->occluded(); } nonrenderlist_elements |= embellished; } /* * Note: Buffer lifetimes are ensured by the two objects holding * references to them; elements and renderable_list. * So no buffer is going to be released back to the client till * both of those containers get destroyed (end of the function). * Actually, there's a third reference held by the texture cache * in GLRenderer, but that gets released earlier in render(). */ elements.clear(); // Release those that didn't make it to renderable_list if (!nonrenderlist_elements && viewport == display_buffer.view_area() && // no bypass while zoomed display_buffer.overlay(renderable_list)) { report->renderables_in_frame(this, renderable_list); renderer.suspend(); } else { renderer.set_output_transform(display_buffer.orientation(), display_buffer.mirror_mode()); renderer.set_viewport(viewport); renderer.begin(std::move(decorated)); renderer.render(renderable_list); report->renderables_in_frame(this, renderable_list); report->rendered_frame(this); // Release buffers back to the clients now that the swap has returned. // It's important to do this before starting on the potentially slow // flip() ... // FIXME: This clear() call is blocking a little (LP: #1395421) renderable_list.clear(); } report->finished_frame(this); } void me::DemoCompositor::on_cursor_movement( geometry::Point const& p) { cursor_pos = p; if (zoom_mag != 1.0f) update_viewport(); } void me::DemoCompositor::zoom(float mag) { zoom_mag = mag; update_viewport(); } void me::DemoCompositor::set_colour_effect(me::ColourEffect e) { renderer.set_colour_effect(e); } void me::DemoCompositor::update_viewport() { auto const& view_area = display_buffer.view_area(); if (zoom_mag == 1.0f) { // The below calculations should yield the same result as this, but // just in case there are any floating point precision errors, // set it precisely: viewport = view_area; } else { int db_width = view_area.size.width.as_int(); int db_height = view_area.size.height.as_int(); int db_x = view_area.top_left.x.as_int(); int db_y = view_area.top_left.y.as_int(); float zoom_width = db_width / zoom_mag; float zoom_height = db_height / zoom_mag; // Note the 0.5f. This is because cursors (and all input in general) // measures coordinates at the centre of a pixel. But GL measures to // the top-left corner of a pixel. float screen_x = cursor_pos.x.as_int() + 0.5f - db_x; float screen_y = cursor_pos.y.as_int() + 0.5f - db_y; float normal_x = screen_x / db_width; float normal_y = screen_y / db_height; // Position the viewport so the cursor location matches up. // This assumes the hardware cursor still traverses the physical // screen and isn't being warped. int zoom_x = db_x + (db_width - zoom_width) * normal_x; int zoom_y = db_y + (db_height - zoom_height) * normal_y; viewport = {{zoom_x, zoom_y}, {zoom_width, zoom_height}}; } } ./playground/demo-shell/demo_compositor.h0000644000004100000410000000405213115234416021034 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_EXAMPLES_DEMO_COMPOSITOR_H_ #define MIR_EXAMPLES_DEMO_COMPOSITOR_H_ #include "mir/compositor/display_buffer_compositor.h" #include "mir/compositor/scene.h" #include "mir/geometry/rectangle.h" #include "mir/graphics/renderable.h" #include "demo_renderer.h" #include #include namespace mir { namespace compositor { class Scene; class CompositorReport; } namespace graphics { class DisplayBuffer; } namespace examples { class DemoCompositor : public compositor::DisplayBufferCompositor { public: DemoCompositor( graphics::DisplayBuffer& display_buffer, std::shared_ptr const& report); ~DemoCompositor(); void composite(compositor::SceneElementSequence&& elements) override; void zoom(float mag); void on_cursor_movement(geometry::Point const& p); void set_colour_effect(ColourEffect); static void for_each(std::function f); private: void update_viewport(); graphics::DisplayBuffer& display_buffer; std::shared_ptr const report; geometry::Rectangle viewport; geometry::Point cursor_pos; float zoom_mag; DemoRenderer renderer; static std::mutex instances_mutex; static std::unordered_set instances; }; } // namespace examples } // namespace mir #endif // MIR_EXAMPLES_DEMO_COMPOSITOR_H_ ./playground/demo-shell/demo_renderer.h0000644000004100000410000000462013115234416020445 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_EXAMPLES_DEMO_RENDERER_H_ #define MIR_EXAMPLES_DEMO_RENDERER_H_ #include "gl/renderer.h" #include "mir/compositor/decoration.h" #include "typo_glcache.h" #include namespace mir { namespace examples { enum ColourEffect { none, inverse, contrast, neffects }; typedef std::unordered_map> DecorMap; class DemoRenderer : public renderer::gl::Renderer { public: DemoRenderer( graphics::DisplayBuffer& display_buffer, float const titlebar_height, float const shadow_radius); ~DemoRenderer(); void begin(DecorMap&&) const; void set_colour_effect(ColourEffect); protected: void tessellate(std::vector& primitives, graphics::Renderable const& renderable) const override; void draw(graphics::Renderable const& renderable, Renderer::Program const& prog) const override; private: void tessellate_shadow( std::vector& primitives, graphics::Renderable const& renderable, float radius) const; void tessellate_frame( std::vector& primitives, graphics::Renderable const& renderable, float titlebar_height, char const* name) const; float const titlebar_height; float const shadow_radius; float const corner_radius; GLuint shadow_corner_tex; GLuint titlebar_corner_tex; ColourEffect colour_effect; Program inverse_program, contrast_program; mutable DecorMap decor_map; mutable typo::GLCache title_cache; }; } // namespace examples } // namespace mir #endif // MIR_EXAMPLES_DEMO_RENDERER_H_ ./playground/demo-shell/typo/0000755000004100000410000000000013115234677016464 5ustar www-datawww-data./playground/demo-shell/typo/CMakeLists.txt0000644000004100000410000000110413115234664021214 0ustar www-datawww-datafind_package(PkgConfig) pkg_search_module(FREETYPE freetype2) if (FREETYPE_FOUND) set(OPTIONAL_SRCS typo_freetype_renderer.cpp) endif () add_library(typo STATIC typo_renderer.cpp typo_stub_renderer.cpp typo_glcache.cpp ${OPTIONAL_SRCS} ) target_link_libraries(typo ${GL_LIBRARIES}) target_include_directories(typo PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) if (FREETYPE_FOUND) target_compile_definitions(typo PUBLIC -DTYPO_SUPPORTS_FREETYPE) target_link_libraries(typo ${FREETYPE_LIBRARIES}) target_include_directories(typo PUBLIC ${FREETYPE_INCLUDE_DIRS}) endif () ./playground/demo-shell/typo/typo_renderer.cpp0000644000004100000410000000277313115234664022056 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #include "typo_renderer.h" #include using namespace mir::typo; Renderer::Image::Image() : buf(nullptr), width_(0), stride_(0), height_(0), align_(4), format_(alpha8) { } Renderer::Image::~Image() { delete[] buf; } void Renderer::Image::reserve(int w, int h, Format f) { width_ = w; height_ = h; format_ = f; int const bpp = 1; // format is always alpha8 stride_ = (((width_ * bpp) + align_ - 1) / align_) * align_; delete[] buf; auto size = stride_ * height_; buf = new unsigned char[size]; memset(buf, 0, size); } Renderer::~Renderer() { } unsigned long Renderer::unicode_from_utf8(char const** utf8) { int char_len = 1; // TODO: Add support for non-ASCII UTF-8 unsigned long unicode = **utf8; if (unicode) *utf8 += char_len; return unicode; } ./playground/demo-shell/typo/typo_stub_renderer.cpp0000644000004100000410000000272113115234664023104 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #include "typo_stub_renderer.h" #include using namespace mir::typo; void StubRenderer::render(char const* str, Image& img) { int const char_width = 8; int const char_height = 16; int const char_space = 2; int const tex_height = 20; int const len = strlen(str); int const top = (tex_height - char_height) / 2; img.reserve(len*(char_width+char_space) - char_space, tex_height, Image::alpha8); char const* s = str; for (int n = 0; unicode_from_utf8(&s); ++n) { unsigned char* row = img.data() + top*img.stride() + n*(char_width+char_space); for (int y = 0; y < char_height; ++y) { memset(row, 255, char_width); row += img.stride(); } } } ./playground/demo-shell/typo/typo_freetype_renderer.h0000644000004100000410000000232313115234664023415 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_TYPO_FREETYPE_RENDERER_H_ #define MIR_TYPO_FREETYPE_RENDERER_H_ #include "typo_renderer.h" #include #include FT_FREETYPE_H namespace mir { namespace typo { class FreetypeRenderer : public Renderer { public: FreetypeRenderer(); ~FreetypeRenderer(); bool load(char const* font_path, int pref_height); void render(char const* str, Image& img) override; private: FT_Library lib; FT_Face face; int preferred_height; }; } } // namespace mir::typo #endif // MIR_TYPO_FREETYPE_RENDERER_H_ ./playground/demo-shell/typo/typo_stub_renderer.h0000644000004100000410000000174413115234664022555 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_TYPO_STUB_RENDERER_H_ #define MIR_TYPO_STUB_RENDERER_H_ #include "typo_renderer.h" namespace mir { namespace typo { class StubRenderer : public Renderer { public: void render(char const* str, Image& img) override; }; } } // namespace mir::typo #endif // MIR_TYPO_STUB_RENDERER_H_ ./playground/demo-shell/typo/typo_freetype_renderer.cpp0000644000004100000410000000710313115234664023751 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #include "typo_freetype_renderer.h" #include #include using namespace mir::typo; FreetypeRenderer::FreetypeRenderer() : lib(nullptr), face(nullptr), preferred_height(16) { if (FT_Init_FreeType(&lib)) throw std::runtime_error("FreeType init failed"); } FreetypeRenderer::~FreetypeRenderer() { if (face) FT_Done_Face(face); if (lib) FT_Done_FreeType(lib); } bool FreetypeRenderer::load(char const* font_path, int pref_height) { preferred_height = pref_height; if (face) { FT_Done_Face(face); face = nullptr; } if (FT_New_Face(lib, font_path, 0, &face)) return false; FT_Set_Pixel_Sizes(face, 0, preferred_height); return true; } void FreetypeRenderer::render(char const* str, Image& img) { int minx = 0, maxx = 0, miny = 0, maxy = 0; int penx = 0, peny = 0; FT_GlyphSlot slot = face->glyph; char const* s = str; while (unsigned long u = unicode_from_utf8(&s)) { auto glyph = FT_Get_Char_Index(face, u); FT_Load_Glyph(face, glyph, FT_LOAD_DEFAULT); FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); int left = penx + slot->bitmap_left; if (left < minx) minx = left; int right = left + slot->bitmap.width; if (right > maxx) maxx = right; int top = peny - slot->bitmap_top; if (top < miny) miny = top; int bottom = top + slot->bitmap.rows; if (bottom > maxy) maxy = bottom; penx += slot->advance.x >> 6; peny += slot->advance.y >> 6; } int const padding = preferred_height / 8; // Allow mipmapping to smear int width = maxx - minx + 1 + 2*padding; int height = maxy - miny + 1; if (height < preferred_height) // e.g. str has no descenders, but make height = preferred_height; // room so we get a consistent height height += 2*padding; penx = -minx + padding; peny = -miny + padding; img.reserve(width, height, Image::alpha8); s = str; while (unsigned long u = unicode_from_utf8(&s)) { auto glyph = FT_Get_Char_Index(face, u); FT_Load_Glyph(face, glyph, FT_LOAD_DEFAULT); FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL); auto& bitmap = slot->bitmap; int x = penx + slot->bitmap_left; int y = peny - slot->bitmap_top; int right = x + bitmap.width; int bottom = y + bitmap.rows; if (x >= 0 && right <= width && y >= 0 && bottom <= height) { unsigned char* src = bitmap.buffer; unsigned char* dest = img.data() + y*img.stride() + x; int ylimit = y + bitmap.rows; for (; y < ylimit; ++y) { memcpy(dest, src, bitmap.width); src += bitmap.pitch; dest += img.stride(); } } penx += slot->advance.x >> 6; peny += slot->advance.y >> 6; } } ./playground/demo-shell/typo/typo_renderer.h0000644000004100000410000000327613115234664021522 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_TYPO_RENDERER_H_ #define MIR_TYPO_RENDERER_H_ namespace mir { namespace typo { class Renderer { public: class Image { public: Image(); Image(Image const&) = delete; Image(Image const&&) = delete; Image& operator=(Image const&) = delete; ~Image(); typedef enum {alpha8} Format; void reserve(int w, int h, Format f); unsigned char* data() const { return buf; }; int width() const { return width_; } int height() const { return height_; } int stride() const { return stride_; } int alignment() const { return align_; } Format format() const { return format_; } private: unsigned char* buf; int width_, stride_, height_, align_; Format format_; }; virtual ~Renderer(); virtual void render(char const* str, Image& img) = 0; protected: static unsigned long unicode_from_utf8(char const** utf8); }; } } // namespace mir::typo #endif // MIR_TYPO_RENDERER_H_ ./playground/demo-shell/typo/typo_glcache.cpp0000644000004100000410000000514513115234664021632 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #include "typo_glcache.h" #include MIR_SERVER_GL_H using namespace mir::typo; GLCache::GLCache(std::shared_ptr const& r) : renderer(r) { } GLCache::~GLCache() { clear(); } void GLCache::change_renderer(std::shared_ptr const& r) { clear(); renderer = r; } void GLCache::clear() { for (auto& e : map) glDeleteTextures(1, &e.second.tex); map.clear(); } void GLCache::mark_all_unused() { for (auto& e : map) e.second.used = false; } void GLCache::drop_unused() { for (auto e = map.begin(); e != map.end();) { if (!e->second.used) { glDeleteTextures(1, &e->second.tex); e = map.erase(e); } else e++; } } bool GLCache::Entry::valid() const { return width > 0 && height > 0; } GLCache::Entry const& GLCache::get(char const* str) { Entry& entry = map[str]; if (!entry.valid()) { Renderer::Image img; renderer->render(str, img); if (img.data()) { entry.width = img.width(); entry.height = img.height(); glGenTextures(1, &entry.tex); glBindTexture(GL_TEXTURE_2D, entry.tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glPixelStorei(GL_UNPACK_ALIGNMENT, img.alignment()); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, img.width(), img.height(), 0, GL_ALPHA, GL_UNSIGNED_BYTE, img.data()); glGenerateMipmap(GL_TEXTURE_2D); // Antialiasing shrinkage please } } entry.used = true; return entry; } ./playground/demo-shell/typo/typo_glcache.h0000644000004100000410000000270013115234664021271 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_TYPO_GLCACHE_H_ #define MIR_TYPO_GLCACHE_H_ #include "typo_renderer.h" #include #include #include namespace mir { namespace typo { class GLCache { public: struct Entry { bool valid() const; unsigned int tex = 0; int width = 0, height = 0; bool used = false; }; explicit GLCache(std::shared_ptr const&); ~GLCache(); void change_renderer(std::shared_ptr const&); Entry const& get(char const* str); void clear(); void mark_all_unused(); void drop_unused(); private: typedef std::unordered_map Map; Map map; std::shared_ptr renderer; }; } } // namespace mir::typo #endif // MIR_TYPO_GLCACHE_H_ ./playground/demo-shell/demo_shell.cpp0000644000004100000410000000674113115234664020314 0ustar www-datawww-data/* * Copyright © 2013-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ /// \example demo_shell.cpp A simple mir shell #include "demo_compositor.h" #include "window_manager.h" #include "../server_configuration.h" #include "mir/run_mir.h" #include "mir/report_exception.h" #include "mir/graphics/display.h" #include "mir/input/composite_event_filter.h" #include "mir/compositor/display_buffer_compositor_factory.h" #include "mir/renderer/renderer_factory.h" #include "mir/options/option.h" #include "server_example_host_lifecycle_event_listener.h" #include namespace me = mir::examples; namespace ms = mir::scene; namespace mg = mir::graphics; namespace mf = mir::frontend; namespace mi = mir::input; namespace mc = mir::compositor; namespace msh = mir::shell; namespace mir { namespace examples { class DisplayBufferCompositorFactory : public mc::DisplayBufferCompositorFactory { public: DisplayBufferCompositorFactory( std::shared_ptr const& report) : report(report) { } std::unique_ptr create_compositor_for( mg::DisplayBuffer& display_buffer) override { return std::unique_ptr( new me::DemoCompositor{display_buffer, report}); } private: std::shared_ptr const report; }; class DemoServerConfiguration : public mir::examples::ServerConfiguration { public: using mir::examples::ServerConfiguration::ServerConfiguration; std::shared_ptr the_display_buffer_compositor_factory() override { return display_buffer_compositor_factory( [this]() { return std::make_shared( the_compositor_report()); }); } std::shared_ptr the_host_lifecycle_event_listener() override { return host_lifecycle_event_listener( [this]() { return std::make_shared(the_logger()); }); } }; } } int main(int argc, char const* argv[]) try { me::DemoServerConfiguration config(argc, argv); auto wm = std::make_shared(); mir::run_mir(config, [&config, &wm](mir::DisplayServer&) { // We use this strange two stage initialization to avoid a circular dependency between the EventFilters // and the SessionStore wm->set_focus_controller(config.the_focus_controller()); wm->set_display(config.the_display()); wm->set_compositor(config.the_compositor()); wm->set_input_scene(config.the_input_scene()); config.the_composite_event_filter()->prepend(wm); }); return 0; } catch (...) { mir::report_exception(std::cerr); return 1; } ./playground/demo-shell/window_manager.h0000644000004100000410000000542513115234664020645 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_EXAMPLES_WINDOW_MANAGER_H_ #define MIR_EXAMPLES_WINDOW_MANAGER_H_ #include "mir/input/event_filter.h" #include "mir/input/scene.h" #include "mir/geometry/displacement.h" #include "mir/geometry/size.h" #include "demo_renderer.h" #include namespace mir { namespace shell { class FocusController; } namespace graphics { class Display; } namespace compositor { class Compositor; } namespace scene { class Surface; } namespace examples { class WindowManager : public input::EventFilter { public: WindowManager(); ~WindowManager() = default; void set_focus_controller(std::shared_ptr const& focus_controller); void set_display(std::shared_ptr const& display); void set_compositor(std::shared_ptr const& compositor); void set_input_scene(std::shared_ptr const& scene); void force_redraw(); bool handle(MirEvent const& event) override; protected: WindowManager(const WindowManager&) = delete; WindowManager& operator=(const WindowManager&) = delete; private: std::shared_ptr focus_controller; std::shared_ptr display; std::shared_ptr compositor; std::shared_ptr input_scene; geometry::Point click; geometry::Point old_pos; geometry::Point old_cursor; geometry::Size old_size; float old_pinch_diam; int max_fingers; // Maximum number of fingers touched during gesture float zoom_exponent = 0.0f; ColourEffect colour_effect = none; void toggle(ColourEffect); enum {left_edge, hmiddle, right_edge} xedge = hmiddle; enum {top_edge, vmiddle, bottom_edge} yedge = vmiddle; void save_edges(scene::Surface& surf, geometry::Point const& p); void resize(scene::Surface& surf, geometry::Point const& cursor) const; bool handle_key_event(MirKeyboardEvent const* event); bool handle_touch_event(MirTouchEvent const* event); bool handle_pointer_event(MirPointerEvent const* event); }; } } // namespace mir #endif // MIR_EXAMPLES_WINDOW_MANAGER_H_ ./playground/demo-shell/window_manager.cpp0000644000004100000410000004413113115234664021175 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr * Daniel van Vugt */ #include "window_manager.h" #include "demo_compositor.h" #include "mir/shell/focus_controller.h" #include "mir/scene/session.h" #include "mir/scene/surface.h" #include "mir/graphics/display.h" #include "mir/graphics/display_configuration.h" #include "mir/compositor/compositor.h" #include #include #include #include namespace me = mir::examples; namespace msh = mir::shell; namespace mg = mir::graphics; namespace mc = mir::compositor; namespace mi = mir::input; namespace { const int min_swipe_distance = 100; // How long must a swipe be to act on? } me::WindowManager::WindowManager() : old_pinch_diam(0.0f), max_fingers(0) { } void me::WindowManager::set_focus_controller(std::shared_ptr const& controller) { focus_controller = controller; } void me::WindowManager::set_display(std::shared_ptr const& dpy) { display = dpy; } void me::WindowManager::set_compositor(std::shared_ptr const& cptor) { compositor = cptor; } void me::WindowManager::set_input_scene(std::shared_ptr const& s) { input_scene = s; } void me::WindowManager::force_redraw() { // This is clumsy, but the only option our architecture allows us for now // Same hack as used in TouchspotController... input_scene->emit_scene_changed(); } namespace { mir::geometry::Point average_pointer(MirTouchEvent const* tev) { using namespace mir; using namespace geometry; int x = 0, y = 0; int count = mir_touch_event_point_count(tev); for (int i = 0; i < count; i++) { x += mir_touch_event_axis_value(tev, i, mir_touch_axis_x); y += mir_touch_event_axis_value(tev, i, mir_touch_axis_y); } x /= count; y /= count; return Point{x, y}; } float measure_pinch(MirTouchEvent const* tev, mir::geometry::Displacement& dir) { int count = mir_touch_event_point_count(tev); int max = 0; for (int i = 0; i < count; i++) { for (int j = 0; j < i; j++) { int dx = mir_touch_event_axis_value(tev, i, mir_touch_axis_x) - mir_touch_event_axis_value(tev, j, mir_touch_axis_x); int dy = mir_touch_event_axis_value(tev, i, mir_touch_axis_y) - mir_touch_event_axis_value(tev, j, mir_touch_axis_y); int sqr = dx*dx + dy*dy; if (sqr > max) { max = sqr; dir = mir::geometry::Displacement{dx, dy}; } } } return sqrtf(max); // return pinch diameter } } // namespace void me::WindowManager::toggle(ColourEffect which) { colour_effect = (colour_effect == which) ? none : which; me::DemoCompositor::for_each([this](me::DemoCompositor& c) { c.set_colour_effect(colour_effect); }); force_redraw(); } void me::WindowManager::save_edges(scene::Surface& surf, geometry::Point const& p) { int width = surf.size().width.as_int(); int height = surf.size().height.as_int(); int left = surf.top_left().x.as_int(); int right = left + width; int top = surf.top_left().y.as_int(); int bottom = top + height; int leftish = left + width/3; int rightish = right - width/3; int topish = top + height/3; int bottomish = bottom - height/3; int click_x = p.x.as_int(); xedge = (click_x <= leftish) ? left_edge : (click_x >= rightish) ? right_edge : hmiddle; int click_y = p.y.as_int(); yedge = (click_y <= topish) ? top_edge : (click_y >= bottomish) ? bottom_edge : vmiddle; } void me::WindowManager::resize(scene::Surface& surf, geometry::Point const& cursor) const { int width = surf.size().width.as_int(); int height = surf.size().height.as_int(); int left = surf.top_left().x.as_int(); int right = left + width; int top = surf.top_left().y.as_int(); int bottom = top + height; geometry::Displacement drag = cursor - old_cursor; int dx = drag.dx.as_int(); int dy = drag.dy.as_int(); if (xedge == left_edge && dx < width) left = old_pos.x.as_int() + dx; else if (xedge == right_edge) right = old_pos.x.as_int() + old_size.width.as_int() + dx; if (yedge == top_edge && dy < height) top = old_pos.y.as_int() + dy; else if (yedge == bottom_edge) bottom = old_pos.y.as_int() + old_size.height.as_int() + dy; surf.move_to({left, top}); surf.resize({right-left, bottom-top}); } bool me::WindowManager::handle_key_event(MirKeyboardEvent const* kev) { // TODO: Fix android configuration and remove static hack ~racarr static bool display_off = false; if (mir_keyboard_event_action(kev) != mir_keyboard_action_down) return false; auto modifiers = mir_keyboard_event_modifiers(kev); auto scan_code = mir_keyboard_event_scan_code(kev); if (modifiers & mir_input_event_modifier_alt && scan_code == KEY_TAB) // TODO: Use keycode once we support keymapping on the server side { focus_controller->focus_next_session(); if (auto const surface = focus_controller->focused_surface()) focus_controller->raise({surface}); return true; } else if (modifiers & mir_input_event_modifier_alt && scan_code == KEY_GRAVE) { if (auto const prev = focus_controller->focused_surface()) { auto const app = focus_controller->focused_session(); auto const next = app->surface_after(prev); focus_controller->set_focus_to(app, next); focus_controller->raise({next}); } return true; } else if (modifiers & mir_input_event_modifier_alt && scan_code == KEY_F4) { auto const surf = focus_controller->focused_surface(); if (surf) surf->request_client_surface_close(); return true; } else if ((modifiers & mir_input_event_modifier_alt && scan_code == KEY_P) || (scan_code == KEY_POWER)) { compositor->stop(); auto conf = display->configuration(); MirPowerMode new_power_mode = display_off ? mir_power_mode_on : mir_power_mode_off; conf->for_each_output( [&](mg::UserDisplayConfigurationOutput& output) -> void { output.power_mode = new_power_mode; }); display_off = !display_off; display->configure(*conf.get()); if (!display_off) compositor->start(); return true; } else if ((modifiers & mir_input_event_modifier_alt) && (modifiers & mir_input_event_modifier_ctrl) && (scan_code == KEY_ESC)) { std::abort(); return true; } else if ((modifiers & mir_input_event_modifier_alt) && (modifiers & mir_input_event_modifier_ctrl) && (scan_code == KEY_L) && focus_controller) { auto const app = focus_controller->focused_session(); if (app) { app->set_lifecycle_state(mir_lifecycle_state_will_suspend); } } else if ((modifiers & mir_input_event_modifier_alt) && (modifiers & mir_input_event_modifier_ctrl)) { MirOrientation orientation = mir_orientation_normal; bool rotating = true; int mode_change = 0; bool preferred_mode = false; switch (scan_code) { case KEY_UP: orientation = mir_orientation_normal; break; case KEY_DOWN: orientation = mir_orientation_inverted; break; case KEY_LEFT: orientation = mir_orientation_left; break; case KEY_RIGHT: orientation = mir_orientation_right; break; default: rotating = false; break; } switch (scan_code) { case KEY_MINUS: mode_change = -1; break; case KEY_EQUAL: mode_change = +1; break; case KEY_0: preferred_mode = true; break; default: break; } if (rotating || mode_change || preferred_mode) { compositor->stop(); auto conf = display->configuration(); conf->for_each_output( [&](mg::UserDisplayConfigurationOutput& output) -> void { // Only apply changes to the monitor the cursor is on if (!output.extents().contains(old_cursor)) return; if (rotating) output.orientation = orientation; if (preferred_mode) { output.current_mode_index = output.preferred_mode_index; } else if (mode_change) { size_t nmodes = output.modes.size(); if (nmodes) output.current_mode_index = (output.current_mode_index + nmodes + mode_change) % nmodes; } }); display->configure(*conf); compositor->start(); return true; } } else if ((scan_code == KEY_VOLUMEDOWN || scan_code == KEY_VOLUMEUP) && max_fingers == 1) { int delta = (scan_code == KEY_VOLUMEDOWN) ? -1 : +1; static const MirOrientation order[4] = { mir_orientation_normal, mir_orientation_right, mir_orientation_inverted, mir_orientation_left }; compositor->stop(); auto conf = display->configuration(); conf->for_each_output( [&](mg::UserDisplayConfigurationOutput& output) { int i = 0; for (; i < 4; ++i) { if (output.orientation == order[i]) break; } output.orientation = order[(i+4+delta) % 4]; }); display->configure(*conf.get()); compositor->start(); return true; } else if (modifiers & mir_input_event_modifier_meta && scan_code == KEY_N) { toggle(inverse); return true; } else if (modifiers & mir_input_event_modifier_meta && scan_code == KEY_C) { toggle(contrast); return true; } return false; } bool me::WindowManager::handle_pointer_event(MirPointerEvent const* pev) { bool handled = false; geometry::Point cursor{mir_pointer_event_axis_value(pev, mir_pointer_axis_x), mir_pointer_event_axis_value(pev, mir_pointer_axis_y)}; auto action = mir_pointer_event_action(pev); auto modifiers = mir_pointer_event_modifiers(pev); auto vscroll = mir_pointer_event_axis_value(pev, mir_pointer_axis_vscroll); auto primary_button_pressed = mir_pointer_event_button_state(pev, mir_pointer_button_primary); auto tertiary_button_pressed = mir_pointer_event_button_state(pev, mir_pointer_button_tertiary); float new_zoom_mag = 0.0f; // zero means unchanged if (modifiers & mir_input_event_modifier_meta && action == mir_pointer_action_motion && vscroll != 0.0f) { zoom_exponent += vscroll; // Negative exponents do work too, but disable them until // there's a clear edge to the desktop. if (zoom_exponent < 0) zoom_exponent = 0; new_zoom_mag = powf(1.2f, zoom_exponent); handled = true; } me::DemoCompositor::for_each( [new_zoom_mag,&cursor](me::DemoCompositor& c) { if (new_zoom_mag > 0.0f) c.zoom(new_zoom_mag); c.on_cursor_movement(cursor); }); if (zoom_exponent || new_zoom_mag) force_redraw(); auto const surf = focus_controller->focused_surface(); if (surf && (modifiers & mir_input_event_modifier_alt) && (primary_button_pressed || tertiary_button_pressed)) { // Start of a gesture: When the latest finger/button goes down if (action == mir_pointer_action_button_down) { click = cursor; save_edges(*surf, click); handled = true; } else if (action == mir_pointer_action_motion) { geometry::Displacement drag = cursor - old_cursor; if (tertiary_button_pressed) { // Resize by mouse middle button resize(*surf, cursor); } else { surf->move_to(old_pos + drag); } handled = true; } old_pos = surf->top_left(); old_size = surf->size(); } if (surf && (modifiers & mir_input_event_modifier_alt) && action == mir_pointer_action_motion && vscroll) { float alpha = surf->alpha(); alpha += vscroll > 0.0f ? 0.1f : -0.1f; if (alpha < 0.0f) alpha = 0.0f; else if (alpha > 1.0f) alpha = 1.0f; surf->set_alpha(alpha); handled = true; } old_cursor = cursor; return handled; } namespace { bool any_touches_went_down(MirTouchEvent const* tev) { auto count = mir_touch_event_point_count(tev); for (unsigned i = 0; i < count; i++) { if (mir_touch_event_action(tev, i) == mir_touch_action_down) return true; } return false; } bool last_touch_released(MirTouchEvent const* tev) { auto count = mir_touch_event_point_count(tev); if (count > 1) return false; return mir_touch_event_action(tev, 0) == mir_touch_action_up; } } bool me::WindowManager::handle_touch_event(MirTouchEvent const* tev) { bool handled = false; geometry::Point cursor = average_pointer(tev); auto const& modifiers = mir_touch_event_modifiers(tev); int fingers = mir_touch_event_point_count(tev); if (fingers > max_fingers) max_fingers = fingers; auto const surf = focus_controller->focused_surface(); if (surf && (modifiers & mir_input_event_modifier_alt || fingers >= 3)) { geometry::Displacement pinch_dir; auto pinch_diam = measure_pinch(tev, pinch_dir); // Start of a gesture: When the latest finger/button goes down if (any_touches_went_down(tev)) { click = cursor; save_edges(*surf, click); handled = true; } else if(max_fingers <= 3) // Avoid accidental movement { geometry::Displacement drag = cursor - old_cursor; surf->move_to(old_pos + drag); if (fingers == 3) { // Resize by pinch/zoom float diam_delta = pinch_diam - old_pinch_diam; /* * Resize vector (dx,dy) has length=diam_delta and * direction=pinch_dir, so solve for (dx,dy)... */ float lenlen = diam_delta * diam_delta; int x = pinch_dir.dx.as_int(); int y = pinch_dir.dy.as_int(); int xx = x * x; int yy = y * y; int xxyy = xx + yy; int dx = sqrtf(lenlen * xx / xxyy); int dy = sqrtf(lenlen * yy / xxyy); if (diam_delta < 0.0f) { dx = -dx; dy = -dy; } int width = old_size.width.as_int() + dx; int height = old_size.height.as_int() + dy; surf->resize({width, height}); } handled = true; } old_pos = surf->top_left(); old_size = surf->size(); old_pinch_diam = pinch_diam; } auto gesture_ended = last_touch_released(tev); if (max_fingers == 4 && gesture_ended) { // Four fingers released geometry::Displacement dir = cursor - click; if (abs(dir.dx.as_int()) >= min_swipe_distance) { focus_controller->focus_next_session(); if (auto const surface = focus_controller->focused_surface()) focus_controller->raise({surface}); handled = true; } } if (fingers == 1 && gesture_ended) max_fingers = 0; old_cursor = cursor; /* * For now we reserve all 3 or 4 finger gestures for window manipulation. * Make sure clients don't receive spurious events in the process... */ handled |= (max_fingers == 3 || max_fingers == 4); return handled; } bool me::WindowManager::handle(MirEvent const& event) { assert(focus_controller); assert(display); assert(compositor); if (mir_event_get_type(&event) != mir_event_type_input) return false; auto iev = mir_event_get_input_event(&event); auto input_type = mir_input_event_get_type(iev); if (input_type == mir_input_event_type_key) { return handle_key_event(mir_input_event_get_keyboard_event(iev)); } else if (input_type == mir_input_event_type_pointer && focus_controller) { return handle_pointer_event(mir_input_event_get_pointer_event(iev)); } else if (input_type == mir_input_event_type_touch && focus_controller) { return handle_touch_event(mir_input_event_get_touch_event(iev)); } return false; } ./playground/diamond.c0000644000004100000410000001335113115234664015216 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author: Kevin DuBois */ #include "diamond.h" #include "mir_egl_platform_shim.h" #include #include #include int const num_vertices = 4; GLfloat const vertices[] = { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, }; GLfloat const texcoords[] = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, }; static GLuint load_shader(const char *src, GLenum type) { GLuint shader = glCreateShader(type); assert(shader); GLint compiled; glShaderSource(shader, 1, &src, NULL); glCompileShader(shader); glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); if (!compiled) { GLchar log[1024]; glGetShaderInfoLog(shader, sizeof log - 1, NULL, log); log[sizeof log - 1] = '\0'; printf("load_shader compile failed: %s\n", log); glDeleteShader(shader); shader = 0; assert(-1); } return shader; } void render_diamond(Diamond* info, int width, int height) { glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, width, height); glDrawArrays(GL_TRIANGLE_STRIP, 0, info->num_vertices); } Diamond setup_diamond_common() { glClearColor(0.8f, 0.8f, 0.8f, 1.0f); char const vertex_shader_src[] = "attribute vec2 pos; \n" "attribute vec2 texcoord; \n" "varying vec2 v_texcoord; \n" "void main() \n" "{ \n" " gl_Position = vec4(pos.x, pos.y, 0.0, 1.0); \n" " v_texcoord = texcoord; \n" "} \n"; char const fragment_shader_src[] = "precision mediump float; \n" "varying vec2 v_texcoord; \n" "uniform sampler2D tex; \n" "void main() \n" "{ \n" " gl_FragColor = texture2D(tex, v_texcoord); \n" "} \n"; GLint linked = 0; Diamond info; info.vertex_shader = load_shader(vertex_shader_src, GL_VERTEX_SHADER); info.fragment_shader = load_shader(fragment_shader_src, GL_FRAGMENT_SHADER); info.program = glCreateProgram(); assert(info.program); glAttachShader(info.program, info.vertex_shader); glAttachShader(info.program, info.fragment_shader); glLinkProgram(info.program); glGetProgramiv(info.program, GL_LINK_STATUS, &linked); if (!linked) { GLchar log[1024]; glGetProgramInfoLog(info.program, sizeof log - 1, NULL, log); log[sizeof log - 1] = '\0'; printf("Link failed: %s\n", log); assert(-1); } glUseProgram(info.program); info.pos = glGetAttribLocation(info.program, "pos"); info.texuniform = glGetUniformLocation(info.program, "tex"); info.texcoord = glGetAttribLocation(info.program, "texcoord"); info.num_vertices = num_vertices; glUniform1i(info.pos, 0); glUniform1i(info.texuniform, 0); glVertexAttribPointer(info.pos, 2, GL_FLOAT, GL_FALSE, 0, vertices); glVertexAttribPointer(info.texcoord, 2, GL_FLOAT, GL_FALSE, 0, texcoords); glEnableVertexAttribArray(info.pos); glEnableVertexAttribArray(info.texcoord); glActiveTexture(GL_TEXTURE0); glGenTextures(1, &info.texid); glBindTexture(GL_TEXTURE_2D, info.texid); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); return info; } Diamond setup_diamond_import(EGLImageKHR img, int use_shim) { Diamond diamond = setup_diamond_common(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); if (use_shim) { future_driver_glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, img); } else { PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES"); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, img); } return diamond; } Diamond setup_diamond() { Diamond diamond = setup_diamond_common(); static unsigned char data[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); return diamond; } void destroy_diamond(Diamond* info) { glDeleteTextures(1, &info->texid); glDisableVertexAttribArray(info->pos); glDisableVertexAttribArray(info->texcoord); glDeleteShader(info->vertex_shader); glDeleteShader(info->fragment_shader); glDeleteProgram(info->program); } ./playground/CMakeLists.txt0000644000004100000410000000270413115234664016177 0ustar www-datawww-data include_directories( ${PROJECT_SOURCE_DIR}/src/include/server ${PROJECT_SOURCE_DIR}/src/include/platform ${PROJECT_SOURCE_DIR}/src/include/common ${PROJECT_SOURCE_DIR}/src/include/gl ${PROJECT_SOURCE_DIR}/src/include/client ${PROJECT_SOURCE_DIR}/src/renderers ${PROJECT_SOURCE_DIR}/include/client ${PROJECT_SOURCE_DIR}/include/server ${PROJECT_SOURCE_DIR}/include/platform ${PROJECT_SOURCE_DIR}/include/renderer ${PROJECT_SOURCE_DIR}/include/renderers/gl ${PROJECT_SOURCE_DIR}/examples/ ) add_library(playgroundserverconfig STATIC server_configuration.cpp ) add_subdirectory(demo-shell/) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") mir_add_wrapped_executable(mir_demo_client_prerendered_frames mir_demo_client_prerendered_frames.c ) target_link_libraries(mir_demo_client_prerendered_frames mirclient m ) mir_add_wrapped_executable(mir_demo_client_chain_jumping_buffers mir_demo_client_chain_jumping_buffers.c ) target_link_libraries(mir_demo_client_chain_jumping_buffers mirclient ) mir_add_wrapped_executable(mir_demo_client_render_surface render_surface.cpp ) target_link_libraries(mir_demo_client_render_surface mirclient eglapp ) mir_add_wrapped_executable(mir_demo_client_egldiamond_render_surface egldiamond_render_surface.c mir_egl_platform_shim.c diamond.c ) target_link_libraries(mir_demo_client_egldiamond_render_surface mirclient ${EGL_LIBRARIES} ${GLESv2_LIBRARIES} ) ./playground/mir_demo_client_chain_jumping_buffers.c0000644000004100000410000002120713115234664023342 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PALETTE_SIZE 5 void fill_buffer_diagonal_stripes( MirBuffer* buffer, unsigned int fg, unsigned int bg) { MirBufferLayout layout = mir_buffer_layout_unknown; MirGraphicsRegion region; mir_buffer_map(buffer, ®ion, &layout); if ((!region.vaddr) || (region.pixel_format != mir_pixel_format_abgr_8888) || layout != mir_buffer_layout_linear) return; unsigned char* vaddr = (unsigned char*) region.vaddr; int const num_stripes = 10; int const stripes_thickness = region.width / num_stripes; for(int i = 0; i < region.height; i++) { unsigned int* pixel = (unsigned int*) vaddr; for(int j = 0; j < region.width ; j++) { if ((((i + j) / stripes_thickness) % stripes_thickness) % 2) pixel[j] = bg; else pixel[j] = fg; } vaddr += region.stride; } mir_buffer_unmap(buffer); } typedef struct SubmissionInfo { int available; MirBuffer* buffer; pthread_mutex_t lock; pthread_cond_t cv; } SubmissionInfo; static void available_callback(MirBuffer* buffer, void* client_context) { SubmissionInfo* info = (SubmissionInfo*) client_context; pthread_mutex_lock(&info->lock); info->available = 1; info->buffer = buffer; pthread_cond_broadcast(&info->cv); pthread_mutex_unlock(&info->lock); } volatile sig_atomic_t rendering = 1; static void shutdown(int signum) { if ((signum == SIGTERM) || (signum == SIGINT)) rendering = 0; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" int main(int argc, char** argv) { static char const *socket_file = NULL; int arg = -1; int width = 400; int height = 400; while ((arg = getopt (argc, argv, "m:s:h:")) != -1) { switch (arg) { case 'm': socket_file = optarg; break; case 's': { unsigned int w, h; if (sscanf(optarg, "%ux%u", &w, &h) == 2) { width = w; height = h; } else { printf("Invalid size: %s, using default size\n", optarg); } break; } case 'h': case '?': default: puts(argv[0]); printf("Usage:\n"); printf(" -m \n"); printf(" -s WIDTHxHEIGHT of window\n"); printf(" -h help dialog\n"); return -1; } } int const chain_width = width / 2; int const chain_height = height / 2; sigset_t signal_set; sigemptyset(&signal_set); sigaddset(&signal_set, SIGALRM); sigprocmask(SIG_BLOCK, &signal_set, NULL); struct sigaction action; action.sa_handler = shutdown; sigemptyset(&action.sa_mask); action.sa_flags = 0; sigaction(SIGINT, &action, NULL); sigaction(SIGTERM, &action, NULL); int displacement_x = 0; int displacement_y = 0; MirPixelFormat format = mir_pixel_format_abgr_8888; MirConnection* connection = mir_connect_sync(socket_file, "prerendered_frames"); if (!mir_connection_is_valid(connection)) { printf("could not connect to server file at: %s\n", socket_file); return -1; } unsigned int const num_chains = 4; unsigned int const num_buffers = num_chains + 1; unsigned int const fg[PALETTE_SIZE] = { 0xFF14BEA0, 0xFF000000, 0xFF1111FF, 0xFFAAAAAA, 0xFFB00076 }; unsigned int const bg[PALETTE_SIZE] = { 0xFFDF2111, 0xFFFFFFFF, 0xFF11DDDD, 0xFF404040, 0xFFFFFF00 }; unsigned int spare_buffer = 0; MirPresentationChain* chain[num_chains]; MirRenderSurface* render_surface[num_chains]; for(unsigned int i = 0u; i < num_chains; i++) { render_surface[i] = mir_connection_create_render_surface_sync(connection, chain_width, chain_height); if (!mir_render_surface_is_valid(render_surface[i])) { printf("could not create render surface\n"); return -1; } chain[i] = mir_render_surface_get_presentation_chain(render_surface[i]); if (!mir_presentation_chain_is_valid(chain[i])) { printf("could not create MirPresentationChain\n"); // TODO this is a frig to pass smoke tests until we support NBS by default #if (MIR_CLIENT_VERSION <= MIR_VERSION_NUMBER(3, 3, 0)) printf("This is currently an unreleased API - likely server support is switched off\n"); return 0; #else return -1; #endif } } //Arrange a 2x2 grid of chains within window MirWindowSpec* spec = mir_create_normal_window_spec(connection, width, height); mir_window_spec_set_pixel_format(spec, format); mir_window_spec_add_render_surface( spec, render_surface[0], chain_width, chain_height, displacement_x, displacement_y); mir_window_spec_add_render_surface( spec, render_surface[1], chain_width, chain_height, chain_width, displacement_y); mir_window_spec_add_render_surface( spec, render_surface[2], chain_width, chain_height, displacement_x, chain_height); mir_window_spec_add_render_surface( spec, render_surface[3], chain_width, chain_height, chain_width, chain_height); MirWindow* window = mir_create_window_sync(spec); mir_window_spec_release(spec); SubmissionInfo buffer_available[num_buffers]; //prerender the frames for (unsigned int i = 0u; i < num_buffers; i++) { pthread_cond_init(&buffer_available[i].cv, NULL); pthread_mutex_init(&buffer_available[i].lock, NULL); buffer_available[i].available = 0; buffer_available[i].buffer = NULL; mir_connection_allocate_buffer( connection, width, height, format, available_callback, &buffer_available[i]); pthread_mutex_lock(&buffer_available[i].lock); while(!buffer_available[i].buffer) pthread_cond_wait(&buffer_available[i].cv, &buffer_available[i].lock); fill_buffer_diagonal_stripes(buffer_available[i].buffer, fg[i % PALETTE_SIZE], bg[i % PALETTE_SIZE]); pthread_mutex_unlock(&buffer_available[i].lock); } while (rendering) { for(unsigned int i = 0u; i < num_chains; i++) { MirBuffer* b; pthread_mutex_lock(&buffer_available[spare_buffer].lock); while(!buffer_available[spare_buffer].available) pthread_cond_wait(&buffer_available[spare_buffer].cv, &buffer_available[spare_buffer].lock); buffer_available[spare_buffer].available = 0; b = buffer_available[spare_buffer].buffer; pthread_mutex_unlock(&buffer_available[spare_buffer].lock); mir_presentation_chain_submit_buffer( chain[i], b, available_callback, &buffer_available[spare_buffer]); //just looks like a blur if we don't slow things down ualarm(500000, 0); int sig; sigwait(&signal_set, &sig); if (!rendering) break; if (++spare_buffer > num_chains) spare_buffer = 0; } } for (unsigned int i = 0u; i < num_buffers; i++) mir_buffer_release(buffer_available[i].buffer); for (unsigned int i = 0u; i < num_chains; i++) mir_render_surface_release(render_surface[i]); mir_window_release_sync(window); mir_connection_release(connection); return 0; } #pragma GCC diagnostic pop ./playground/README0000644000004100000410000000032113115234664014310 0ustar www-datawww-dataThe Playground These are mir demos that exercise private, in-flux mir functionality. As such functionality matures, related headers become public and the relevant playground code may be moved to 'examples/'. ./playground/diamond.h0000644000004100000410000000251113115234664015217 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author: Kevin DuBois */ #ifndef PLAYGROUND_DIAMOND_H_ #define PLAYGROUND_DIAMOND_H_ #include #include #include #include #include "mir_toolkit/mir_buffer.h" typedef struct { GLuint vertex_shader; GLuint fragment_shader; GLuint program; GLuint pos; GLuint texuniform; GLuint texcoord; GLuint texid; GLfloat const* vertices; GLfloat const* colors; int num_vertices; } Diamond; Diamond setup_diamond(); Diamond setup_diamond_import(EGLImageKHR img, int use_shim); void destroy_diamond(Diamond* info); void render_diamond(Diamond* info, int width, int height); #endif /* PLAYGROUND_DIAMOND_H_ */ ./playground/server_configuration.h0000644000004100000410000000271513115234664020047 0ustar www-datawww-data/* * Copyright © 2013-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_EXAMPLES_SERVER_CONFIGURATION_H_ #define MIR_EXAMPLES_SERVER_CONFIGURATION_H_ #include "mir/default_server_configuration.h" namespace mir { namespace options { class DefaultConfiguration; } namespace examples { class ServerConfiguration : public DefaultServerConfiguration { public: ServerConfiguration(int argc, char const** argv); explicit ServerConfiguration(std::shared_ptr const& configuration_options); std::shared_ptr the_display_configuration_policy() override; std::shared_ptr the_composite_event_filter() override; private: std::shared_ptr quit_filter; }; } } #endif /* MIR_EXAMPLES_SERVER_CONFIGURATION_H_ */ ./playground/mir_egl_platform_shim.h0000644000004100000410000000352513115234664020154 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author: Kevin DuBois */ #ifndef MIR_PLAYGROUND_MIR_EGL_PLATFORM_SHIM_H_ #define MIR_PLAYGROUND_MIR_EGL_PLATFORM_SHIM_H_ #include #include #include #include #include "mir_toolkit/rs/mir_render_surface.h" //Note that these have the same signatures as the proper EGL functions, //and use our intended EGLNativeDisplayType and EGLNativeWindowType. EGLDisplay future_driver_eglGetDisplay(MirConnection*); EGLBoolean future_driver_eglTerminate(EGLDisplay); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" EGLSurface future_driver_eglCreateWindowSurface( EGLDisplay display, EGLConfig config, MirRenderSurface* surface, const EGLint *); #pragma GCC diagnostic pop EGLBoolean future_driver_eglSwapBuffers(EGLDisplay display, EGLSurface surface); EGLImageKHR future_driver_eglCreateImageKHR( EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); EGLBoolean future_driver_eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image); void future_driver_glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image); #endif /* MIR_PLAYGROUND_MIR_EGL_PLATFORM_SHIM_H_*/ ./playground/mir_demo_client_prerendered_frames.c0000644000004100000410000001671713115234664022661 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include float distance(int x0, int y0, int x1, int y1) { float dx = x1 - x0; float dy = y1 - y0; return sqrt((dx * dx + dy * dy)); } void fill_buffer_with_centered_circle_abgr( MirBuffer* buffer, float radius, unsigned int fg, unsigned int bg) { MirBufferLayout layout = mir_buffer_layout_unknown; MirGraphicsRegion region; mir_buffer_map(buffer, ®ion, &layout); if ((!region.vaddr) || (region.pixel_format != mir_pixel_format_abgr_8888) || layout != mir_buffer_layout_linear) return; int const center_x = region.width / 2; int const center_y = region.height / 2; unsigned char* vaddr = (unsigned char*) region.vaddr; for(int i = 0; i < region.height; i++) { unsigned int* pixel = (unsigned int*) vaddr; for(int j = 0; j < region.width ; j++) { int const centered_i = i - center_y; int const centered_j = j - center_x; if (distance(0,0, centered_i, centered_j) > radius) pixel[j] = bg; else pixel[j] = fg; } vaddr += region.stride; } mir_buffer_unmap(buffer); } typedef struct SubmissionInfo { int available; MirBuffer* buffer; pthread_mutex_t lock; pthread_cond_t cv; } SubmissionInfo; static void available_callback(MirBuffer* buffer, void* client_context) { SubmissionInfo* info = (SubmissionInfo*) client_context; pthread_mutex_lock(&info->lock); info->available = 1; info->buffer = buffer; pthread_cond_broadcast(&info->cv); pthread_mutex_unlock(&info->lock); } volatile int rendering = 1; static void shutdown(int signum) { if ((signum == SIGTERM) || (signum == SIGINT)) rendering = 0; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" int main(int argc, char** argv) { static char const *socket_file = NULL; int arg = -1; int width = 400; int height = 400; while ((arg = getopt (argc, argv, "m:s:h:")) != -1) { switch (arg) { case 'm': socket_file = optarg; break; case 's': { unsigned int w, h; if (sscanf(optarg, "%ux%u", &w, &h) == 2) { width = w; height = h; } else { printf("Invalid size: %s, using default size\n", optarg); } break; } case 'h': case '?': default: puts(argv[0]); printf("Usage:\n"); printf(" -m \n"); printf(" -s WIDTHxHEIGHT of window\n"); printf(" -h help dialog\n"); return -1; } } signal(SIGTERM, shutdown); signal(SIGINT, shutdown); int displacement_x = 0; int displacement_y = 0; unsigned int fg = 0xFF1448DD; unsigned int bg = 0xFF6F2177; MirPixelFormat format = mir_pixel_format_abgr_8888; MirConnection* connection = mir_connect_sync(socket_file, "prerendered_frames"); if (!mir_connection_is_valid(connection)) { printf("could not connect to server file at: %s\n", socket_file); return -1; } MirRenderSurface* render_surface = mir_connection_create_render_surface_sync(connection, width, height); if (!mir_render_surface_is_valid(render_surface)) { printf("could not create a render surface\n"); return -1; } MirPresentationChain* chain = mir_render_surface_get_presentation_chain(render_surface); if (!mir_presentation_chain_is_valid(chain)) { printf("could not create MirPresentationChain\n"); // TODO this is a frig to pass smoke tests until we support NBS by default #if (MIR_CLIENT_VERSION <= MIR_VERSION_NUMBER(3, 3, 0)) printf("This is currently an unreleased API - likely server support is switched off\n"); return 0; #else return -1; #endif } MirWindowSpec* spec = mir_create_normal_window_spec(connection, width, height); mir_window_spec_set_pixel_format(spec, format); mir_window_spec_add_render_surface( spec, render_surface, width, height, displacement_x, displacement_y); MirWindow* window = mir_create_window_sync(spec); if (!mir_window_is_valid(window)) { printf("could not create a window\n"); return -1; } mir_window_spec_release(spec); int num_prerendered_frames = 20; SubmissionInfo buffer_available[num_prerendered_frames]; for (int i = 0u; i < num_prerendered_frames; i++) { pthread_cond_init(&buffer_available[i].cv, NULL); pthread_mutex_init(&buffer_available[i].lock, NULL); buffer_available[i].available = 0; buffer_available[i].buffer = NULL; mir_connection_allocate_buffer( connection, width, height, format, available_callback, &buffer_available[i]); pthread_mutex_lock(&buffer_available[i].lock); while(!buffer_available[i].buffer) pthread_cond_wait(&buffer_available[i].cv, &buffer_available[i].lock); if (!mir_buffer_is_valid(buffer_available[i].buffer)) { printf("could not create MirBuffer\n"); return -1; } float max_radius = distance(0, 0, width, height) / 2.0f; float radius_i = ((float) i + 1) / num_prerendered_frames * max_radius; fill_buffer_with_centered_circle_abgr(buffer_available[i].buffer, radius_i, fg, bg); pthread_mutex_unlock(&buffer_available[i].lock); } int i = 0; int inc = -1; while (rendering) { MirBuffer* b; pthread_mutex_lock(&buffer_available[i].lock); while(!buffer_available[i].available) pthread_cond_wait(&buffer_available[i].cv, &buffer_available[i].lock); buffer_available[i].available = 0; b = buffer_available[i].buffer; pthread_mutex_unlock(&buffer_available[i].lock); mir_presentation_chain_submit_buffer(chain, b, available_callback, &buffer_available[i]); if ((i == num_prerendered_frames - 1) || (i == 0)) inc *= -1; i = i + inc; } for (i = 0u; i < num_prerendered_frames; i++) mir_buffer_release(buffer_available[i].buffer); mir_render_surface_release(render_surface); mir_window_release_sync(window); mir_connection_release(connection); return 0; } #pragma GCC diagnostic pop ./playground/mir_egl_platform_shim.c0000644000004100000410000001462213115234664020147 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author: Kevin DuBois */ #include "mir_egl_platform_shim.h" #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/mir_extension_core.h" #include "mir_toolkit/extensions/android_egl.h" #include "mir_toolkit/extensions/hardware_buffer_stream.h" #include #include #include #include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" //Information the driver will have to maintain typedef struct { MirConnection* connection; //EGLNativeDisplayType MirRenderSurface* surface; //EGLNativeWindowType MirBufferStream* stream; //the internal semantics a driver might want to use... //could be MirPresentationChain as well int current_physical_width; //The driver is in charge of the physical width int current_physical_height; //The driver is in charge of the physical height MirExtensionAndroidEGLV1 const* ext; PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; } DriverInfo; static DriverInfo* info = NULL; typedef struct { struct ANativeWindowBuffer *buffer; EGLImageKHR img; } ShimEGLImageKHR; EGLSurface future_driver_eglCreateWindowSurface( EGLDisplay display, EGLConfig config, MirRenderSurface* surface, const EGLint* attr) { MirExtensionHardwareBufferStreamV1 const * ext = mir_extension_hardware_buffer_stream_v1(info->connection); if (info->surface || !ext) { printf("shim only supports one surface at the moment"); return EGL_NO_SURFACE; } info->surface = surface; mir_render_surface_get_size(surface, &info->current_physical_width, &info->current_physical_height); //TODO: the driver needs to be selecting a pixel format that's acceptable based on // the EGLConfig. mir_connection_get_egl_pixel_format // needs to be deprecated once the drivers support the Mir EGL platform. MirPixelFormat pixel_format = mir_connection_get_egl_pixel_format(info->connection, display, config); //this particular [silly] driver has chosen the buffer stream as the way it wants to post //its hardware content. I'd think most drivers would want MirPresentationChain for flexibility info->stream = ext->get_hardware_buffer_stream(surface, info->current_physical_width, info->current_physical_height, pixel_format); printf("The driver chose pixel format %d.\n", pixel_format); return eglCreateWindowSurface(display, config, (EGLNativeWindowType) surface, attr); } EGLBoolean future_driver_eglSwapBuffers(EGLDisplay display, EGLSurface surface) { int width = -1; int height = -1; mir_render_surface_get_size(info->surface, &width, &height); if (width != info->current_physical_width || height != info->current_physical_height) { //note that this affects the next buffer that we get after swapbuffers. mir_buffer_stream_set_size(info->stream, width, height); info->current_physical_width = width; info->current_physical_height = height; } return eglSwapBuffers(display, surface); } #pragma GCC diagnostic pop EGLDisplay future_driver_eglGetDisplay(MirConnection* connection) { if (info) { printf("shim only supports one display connection at the moment"); return EGL_NO_DISPLAY; } info = malloc(sizeof(DriverInfo)); memset(info, 0, sizeof(*info)); info->connection = connection; info->ext = mir_extension_android_egl_v1(info->connection); info->eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR"); info->eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR"); info->glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES"); return eglGetDisplay(mir_connection_get_egl_native_display(connection)); } EGLBoolean future_driver_eglTerminate(EGLDisplay display) { if (info) free(info); return eglTerminate(display); } EGLImageKHR future_driver_eglCreateImageKHR( EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) { //bit pedantic, but we should validate the parameters we require from the extension if ( (target != EGL_NATIVE_PIXMAP_KHR) || (ctx != EGL_NO_CONTEXT) || !info || !info->ext ) return EGL_NO_IMAGE_KHR; //check we have subloaded extension available. if(!strstr(eglQueryString(dpy, EGL_EXTENSIONS), "EGL_ANDROID_image_native_buffer")) return EGL_NO_IMAGE_KHR; static EGLint const expected_attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; int i = 0; while ( (attrib_list[i] != EGL_NONE) && (expected_attrs[i] != EGL_NONE) ) { if (attrib_list[i] != expected_attrs[i]) return EGL_NO_IMAGE_KHR; i++; } ShimEGLImageKHR* img = (ShimEGLImageKHR*) malloc(sizeof(ShimEGLImageKHR)); img->buffer = info->ext->create_buffer(buffer); img->img = info->eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, img->buffer, attrib_list); return (EGLImageKHR) img; } EGLBoolean future_driver_eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image) { if (!info) return EGL_FALSE; ShimEGLImageKHR* img = (ShimEGLImageKHR*) image; EGLBoolean rc = info->eglDestroyImageKHR(dpy, image); info->ext->destroy_buffer(img->buffer); free(img); return rc; } void future_driver_glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image) { if (!info) return; ShimEGLImageKHR* img = (ShimEGLImageKHR*) image; info->glEGLImageTargetTexture2DOES(target, img->img); } ./playground/server_configuration.cpp0000644000004100000410000000607313115234664020403 0ustar www-datawww-data/* * Copyright © 2013-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "server_configuration.h" #include "mir/options/default_configuration.h" #include "mir/input/composite_event_filter.h" #include "mir/graphics/default_display_configuration_policy.h" #include "mir/main_loop.h" #include "server_example_display_configuration_policy.h" #include "server_example_input_event_filter.h" namespace me = mir::examples; namespace mg = mir::graphics; namespace { std::shared_ptr const& customize( std::shared_ptr const& opt) { opt->add_options()(me::display_config_opt, boost::program_options::value()-> default_value(me::clone_opt_val), me::display_config_descr); return opt; } } me::ServerConfiguration::ServerConfiguration(std::shared_ptr const& configuration_options) : DefaultServerConfiguration(customize(configuration_options)) { } me::ServerConfiguration::ServerConfiguration(int argc, char const** argv) : ServerConfiguration(std::make_shared(argc, argv)) { } std::shared_ptr me::ServerConfiguration::the_display_configuration_policy() { return display_configuration_policy( [this]() -> std::shared_ptr { auto display_config = the_options()->get(me::display_config_opt); if (display_config == me::sidebyside_opt_val) return std::make_shared(); else if (display_config == me::single_opt_val) return std::make_shared(); else return DefaultServerConfiguration::the_display_configuration_policy(); }); } std::shared_ptr me::ServerConfiguration::the_composite_event_filter() { return composite_event_filter( [this]() -> std::shared_ptr { if (!quit_filter) quit_filter = std::make_shared([this] { the_main_loop()->stop(); }); auto composite_filter = DefaultServerConfiguration::the_composite_event_filter(); composite_filter->append(quit_filter); return composite_filter; }); } ./playground/egldiamond_render_surface.c0000644000004100000410000002407413115234664020761 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author: Daniel van Vugt * Cemil Azizoglu * Kevin DuBois */ #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/rs/mir_render_surface.h" #include "mir_toolkit/mir_buffer.h" #include "mir_toolkit/mir_presentation_chain.h" #include "mir_egl_platform_shim.h" #include "diamond.h" #include #include #include #include #include #include #include #include #include static volatile sig_atomic_t running = 0; static void shutdown(int signum) { if (running) { running = 0; printf("Signal %d received. Good night.\n", signum); } } #define CHECK(_cond, _err) \ if (!(_cond)) \ { \ printf("%s\n", (_err)); \ return -1; \ } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" //The client arranges the scene in the subscene void resize_callback(MirWindow* window, MirEvent const* event, void* context) { (void) window; MirEventType type = mir_event_get_type(event); if (type == mir_event_type_resize) { MirResizeEvent const* resize_event = mir_event_get_resize_event(event); int width = mir_resize_event_get_width(resize_event); int height = mir_resize_event_get_height(resize_event); MirRenderSurface* rs = (MirRenderSurface*) context; mir_render_surface_set_size(rs, width, height); } } typedef struct { pthread_mutex_t* mut; pthread_cond_t* cond; MirBuffer** buffer; } BufferWait; void wait_buffer(MirBuffer* b, void* context) { BufferWait* w = (BufferWait*) context; pthread_mutex_lock(w->mut); *w->buffer = b; pthread_cond_broadcast(w->cond); pthread_mutex_unlock(w->mut); } bool fill_buffer(MirBuffer* buffer) { MirBufferLayout layout = mir_buffer_layout_unknown; MirGraphicsRegion region; bool rc = mir_buffer_map(buffer, ®ion, &layout); if (!rc || layout == mir_buffer_layout_unknown) return false; unsigned int *data = (unsigned int*) region.vaddr; for (int i = 0; i < region.width; i++) { for (int j = 0; j < region.height; j++) { int idx = (i * (region.stride/4)) + j; if (idx % 32 > 16) data[ idx ] = 0xFF00FFFF; else data[ idx ] = 0xFFFF0000; } } mir_buffer_unmap(buffer); return true; } int main(int argc, char *argv[]) { //once full transition to Mir platform has been made, internal shim will be removed, //and the examples/ will use MirConnection/MirRenderSurface/MirBuffer as their egl types. int use_shim = 1; int swapinterval = 1; char* socket = NULL; int c; while ((c = getopt(argc, argv, "ehnm:")) != -1) { switch (c) { case 'm': socket = optarg; break; case 'e': use_shim = 0; break; case 'n': swapinterval = 0; break; case 'h': default: printf( "Usage:\n" "\t-m mir_socket\n" "\t-e use egl library directly, instead of using shim\n" "\t-n use swapinterval 0\n" "\t-h this message\n"); return -1; } } const char* appname = "EGL Render Surface Demo"; int width = 300; int height = 300; EGLDisplay egldisplay; EGLSurface eglsurface; EGLint ctxattribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLContext eglctx; EGLConfig eglconfig; EGLint neglconfigs; EGLBoolean ok; MirConnection* connection = NULL; MirWindow* window = NULL; MirRenderSurface* render_surface = NULL; signal(SIGINT, shutdown); signal(SIGTERM, shutdown); signal(SIGHUP, shutdown); if (use_shim) printf("internal EGL driver shim in use\n"); else printf("using EGL driver directly\n"); connection = mir_connect_sync(socket, appname); CHECK(mir_connection_is_valid(connection), "Can't get connection"); BufferWait w; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; MirBuffer* buffer = NULL; w.mut = &mutex; w.cond = &cond; w.buffer = &buffer; mir_connection_allocate_buffer( connection, 256, 256, mir_pixel_format_abgr_8888, wait_buffer, &w); pthread_mutex_lock(&mutex); while (buffer == NULL) pthread_cond_wait(&cond, &mutex); pthread_mutex_unlock(&mutex); bool const filled = fill_buffer(buffer); if (use_shim) egldisplay = future_driver_eglGetDisplay(connection); else egldisplay = eglGetDisplay(connection); CHECK(egldisplay != EGL_NO_DISPLAY, "Can't eglGetDisplay"); int maj =0; int min = 0; ok = eglInitialize(egldisplay, &maj, &min); CHECK(ok, "Can't eglInitialize"); printf("EGL version %i.%i\n", maj, min); const EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE }; ok = eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs); CHECK(ok, "Could not eglChooseConfig"); CHECK(neglconfigs > 0, "No EGL config available"); render_surface = mir_connection_create_render_surface_sync(connection, width, height); CHECK(mir_render_surface_is_valid(render_surface), "could not create render surface"); CHECK(mir_render_surface_get_error_message(render_surface), ""); if (use_shim) eglsurface = future_driver_eglCreateWindowSurface(egldisplay, eglconfig, render_surface, NULL); else eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, (EGLNativeWindowType) render_surface, NULL); if (eglsurface == EGL_NO_SURFACE) { printf("eglCreateWindowSurface failed. " "This is likely because the egl driver does not support the usage of MirRenderSurface\n"); mir_render_surface_release(render_surface); mir_connection_release(connection); eglTerminate(egldisplay); return 0; } //The format field is only used for default-created streams. //width and height are the logical width the user wants the window to be MirWindowSpec *spec = mir_create_normal_window_spec(connection, width, height); CHECK(spec, "Can't create a window spec"); mir_window_spec_set_name(spec, appname); mir_window_spec_add_render_surface(spec, render_surface, width, height, 0, 0); mir_window_spec_set_event_handler(spec, resize_callback, render_surface); window = mir_create_window_sync(spec); mir_window_spec_release(spec); eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT, ctxattribs); CHECK(eglctx != EGL_NO_CONTEXT, "eglCreateContext failed"); ok = eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx); CHECK(ok, "Can't eglMakeCurrent"); eglSwapInterval(egldisplay, swapinterval); EGLImageKHR image = EGL_NO_IMAGE_KHR; PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = NULL; PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = NULL; char const* extensions = eglQueryString(egldisplay, EGL_EXTENSIONS); printf("EGL extensions %s\n", extensions); if (strstr(extensions, "EGL_KHR_image_pixmap")) { static EGLint const image_attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; if (use_shim) { eglCreateImageKHR = future_driver_eglCreateImageKHR; eglDestroyImageKHR = future_driver_eglDestroyImageKHR; } else { eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR"); eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR"); } if (filled) image = eglCreateImageKHR(egldisplay, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, buffer, image_attrs); } Diamond diamond; if (image == EGL_NO_IMAGE_KHR) { printf("MirBuffer import not supported by driver. Should see red/white checker\n"); diamond = setup_diamond(); } else { printf("MirBuffer import supported by driver. Should see yellow/blue stripes\n"); diamond = setup_diamond_import(image, use_shim); } EGLint viewport_width = -1; EGLint viewport_height = -1; running = 1; while (running) { eglQuerySurface(egldisplay, eglsurface, EGL_WIDTH, &viewport_width); eglQuerySurface(egldisplay, eglsurface, EGL_HEIGHT, &viewport_height); render_diamond(&diamond, viewport_width, viewport_height); if (use_shim) future_driver_eglSwapBuffers(egldisplay, eglsurface); else eglSwapBuffers(egldisplay, eglsurface); } destroy_diamond(&diamond); eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (image) eglDestroyImageKHR(egldisplay, image); if (use_shim) future_driver_eglTerminate(egldisplay); else eglTerminate(egldisplay); mir_render_surface_release(render_surface); mir_window_release_sync(window); mir_connection_release(connection); return 0; } #pragma GCC diagnostic pop ./COPYING.GPL0000644000004100000410000010437413115234416012730 0ustar www-datawww-data GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ./.clang-format0000644000004100000410000000261513115234416013622 0ustar www-datawww-dataLanguage: Cpp AccessModifierOffset: -4 ConstructorInitializerIndentWidth: 4 AlignEscapedNewlinesLeft: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AllowShortFunctionsOnASingleLine: false AlwaysBreakTemplateDeclarations: true AlwaysBreakBeforeMultilineStrings: false BreakBeforeBinaryOperators: false BreakBeforeTernaryOperators: false BreakConstructorInitializersBeforeComma: false BinPackParameters: false ColumnLimit: 120 ConstructorInitializerAllOnOneLineOrOnePerLine: true DerivePointerBinding: true ExperimentalAutoDetectBinPacking: true IndentCaseLabels: false MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCSpaceBeforeProtocolList: false PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 300 PenaltyBreakString: 1000 PenaltyBreakFirstLessLess: 120 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerBindsToType: true SpacesBeforeTrailingComments: 2 Cpp11BracedListStyle: true Standard: Cpp11 IndentWidth: 4 TabWidth: 8 UseTab: Never BreakBeforeBraces: Allman IndentFunctionDeclarationAfterType: true SpacesInParentheses: false SpacesInAngles: false SpaceInEmptyParentheses: false SpacesInCStyleCastParentheses: false SpaceBeforeAssignmentOperators: true ContinuationIndentWidth: 4 SpaceBeforeParens: ControlStatements ./include/0000755000004100000410000000000013115234677012677 5ustar www-datawww-data./include/platform/0000755000004100000410000000000013115234413014507 5ustar www-datawww-data./include/platform/mir/0000755000004100000410000000000013115234417015302 5ustar www-datawww-data./include/platform/mir/abnormal_exit.h0000644000004100000410000000173713115234416020306 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_ABNORMAL_EXIT_H_ #define MIR_ABNORMAL_EXIT_H_ #include namespace mir { class AbnormalExit : public std::runtime_error { public: AbnormalExit(std::string const& what) : std::runtime_error(what) { } }; } #endif /* MIR_ABNORMAL_EXIT_H_ */ ./include/platform/mir/options/0000755000004100000410000000000013115234417016775 5ustar www-datawww-data./include/platform/mir/options/option.h0000644000004100000410000000320513115234416020455 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_OPTIONS_OPTION_H_ #define MIR_OPTIONS_OPTION_H_ #include #include namespace mir { /// System options. Interface for extracting configuration options from wherever /// they may be (e.g. program arguments, config files or environment variables). namespace options { class Option { public: virtual bool is_set(char const* name) const = 0; virtual bool get(char const* name, bool default_) const = 0; virtual std::string get(char const* name, char const* default_) const = 0; virtual int get(char const* name, int default_) const = 0; virtual boost::any const& get(char const* name) const = 0; template Type get(char const* name) const { return boost::any_cast(get(name)); } protected: Option() = default; virtual ~Option() = default; Option(Option const&) = delete; Option& operator=(Option const&) = delete; }; } } #endif /* MIR_OPTIONS_OPTION_H_ */ ./include/platform/mir/module_properties.h0000644000004100000410000000246513115234416021222 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_PLATFORM_MODULE_PROPERTIES_H_ #define MIR_PLATFORM_MODULE_PROPERTIES_H_ namespace mir { /** * Describes a platform module. Mir provides the following graphics platforms: * "mir:mesa-kms", "mir:mesa-x11" and "mir:android". * Mir provides "mir:evdev-input" input platform. * * Third party platforms should be named according to the vendor and platform: * ":" */ struct ModuleProperties { char const* name; int major_version; int minor_version; int micro_version; char const* file; }; } #endif /* MIR_PLATFORM_MODULE_PROPERTIES_H_ */ ./include/platform/mir/graphics/0000755000004100000410000000000013115234677017112 5ustar www-datawww-data./include/platform/mir/graphics/platform_ipc_package.h0000644000004100000410000000250713115234416023410 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_PLATFORM_IPC_PACKAGE_H_ #define MIR_GRAPHICS_PLATFORM_IPC_PACKAGE_H_ #include #include namespace mir { struct ModuleProperties; namespace graphics { /** * Platform data to be sent to the clients over IPC. */ struct PlatformIPCPackage { PlatformIPCPackage() : graphics_module(nullptr) {} explicit PlatformIPCPackage(ModuleProperties const* graphics_module) : graphics_module(graphics_module) {} std::vector ipc_data; std::vector ipc_fds; ModuleProperties const* graphics_module; }; } } #endif /* MIR_GRAPHICS_PLATFORM_IPC_PACKAGE_H_ */ ./include/platform/mir/graphics/platform_operation_message.h0000644000004100000410000000177113115234416024670 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_PLATFORM_OPERATION_MESSAGE_H_ #define MIR_GRAPHICS_PLATFORM_OPERATION_MESSAGE_H_ #include #include namespace mir { namespace graphics { struct PlatformOperationMessage { std::vector data; std::vector fds; }; } } #endif ./include/platform/mir/graphics/platform_ipc_operations.h0000644000004100000410000000633213115234664024205 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_PLATFORM_IPC_OPERATIONS_H_ #define MIR_GRAPHICS_PLATFORM_IPC_OPERATIONS_H_ #include "platform_ipc_package.h" #include namespace mir { namespace graphics { enum class BufferIpcMsgType { full_msg, //pack the full ipc representation of the buffer update_msg //assume the client has a full representation, and pack only updates to the buffer }; class Buffer; class BufferIpcMessage; struct PlatformOperationMessage; class PlatformIpcOperations { public: virtual ~PlatformIpcOperations() = default; /** * Arranges the IPC package for a buffer that is to be sent through * the frontend from server to client. This should be called every * time a buffer is to be sent cross-process. * * Pack the platform specific contents of Buffer into BufferIpcMessage for sending to the client * * \param [in] message the message that will be sent * \param [in] buffer the buffer to be put in the message * \param [in] msg_type what sort of ipc message is needed */ virtual void pack_buffer(BufferIpcMessage& message, Buffer const& buffer, BufferIpcMsgType msg_type) const = 0; /** * Arranges the IPC package for a buffer that was sent over IPC * client to server. This must be called every time a buffer is * received, as some platform specific processing has to be done on * the incoming buffer. * \param [in] message the message that was sent to the server * \param [in] buffer the buffer associated with the message */ virtual void unpack_buffer(BufferIpcMessage& message, Buffer const& buffer) const = 0; /** * Gets the connection package for the platform. * * The IPC package will be sent to clients when they connect. */ virtual std::shared_ptr connection_ipc_package() = 0; /** * Arranges a platform specific operation triggered by an IPC call * \returns the response that will be sent to the client * \param [in] opcode the opcode that indicates the action to be performed * \param [in] message the message that was sent to the server */ virtual PlatformOperationMessage platform_operation( unsigned int const opcode, PlatformOperationMessage const& message) = 0; protected: PlatformIpcOperations() = default; PlatformIpcOperations(PlatformIpcOperations const&) = delete; PlatformIpcOperations& operator=(PlatformIpcOperations const&) = delete; }; } } #endif /* MIR_GRAPHICS_BUFFER_IPC_PACKER_H_ */ ./include/platform/mir/graphics/display_configuration_policy.h0000644000004100000410000000247713115234416025237 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_DISPLAY_CONFIGURATION_POLICY_H_ #define MIR_GRAPHICS_DISPLAY_CONFIGURATION_POLICY_H_ namespace mir { namespace graphics { class DisplayConfiguration; class DisplayConfigurationPolicy { public: virtual ~DisplayConfigurationPolicy() = default; virtual void apply_to(DisplayConfiguration& conf) = 0; protected: DisplayConfigurationPolicy() = default; DisplayConfigurationPolicy(DisplayConfigurationPolicy const& c) = delete; DisplayConfigurationPolicy& operator=(DisplayConfigurationPolicy const& c) = delete; }; } } #endif /* MIR_GRAPHICS_DISPLAY_CONFIGURATION_POLICY_H_ */ ./include/platform/mir/graphics/buffer_properties.h0000644000004100000410000000405613115234416023004 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_BUFFER_PROPERTIES_H_ #define MIR_GRAPHICS_BUFFER_PROPERTIES_H_ #include "mir/geometry/size.h" #include "mir_toolkit/common.h" namespace mir { namespace graphics { /** * How a buffer is going to be used. * * The usage is not just a hint; for example, depending on the platform, a * 'hardware' buffer may not support direct pixel access. */ enum class BufferUsage { undefined, /** rendering using GL */ hardware, /** rendering using direct pixel access */ software }; /** * Buffer creation properties. */ struct BufferProperties { BufferProperties() : size(), format(mir_pixel_format_invalid), usage(BufferUsage::undefined) { } BufferProperties(const geometry::Size& size, const MirPixelFormat& format, BufferUsage usage) : size{size}, format{format}, usage{usage} { } geometry::Size size; MirPixelFormat format; BufferUsage usage; }; inline bool operator==(BufferProperties const& lhs, BufferProperties const& rhs) { return lhs.size == rhs.size && lhs.format == rhs.format && lhs.usage == rhs.usage; } inline bool operator!=(BufferProperties const& lhs, BufferProperties const& rhs) { return !(lhs == rhs); } } } #endif // MIR_GRAPHICS_BUFFER_PROPERTIES_H_ ./include/platform/mir/graphics/cursor_image.h0000644000004100000410000000266313115234416021740 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_GRAPHICS_CURSOR_IMAGE_H_ #define MIR_GRAPHICS_CURSOR_IMAGE_H_ #include "mir/geometry/size.h" #include "mir/geometry/displacement.h" namespace mir { namespace graphics { class CursorImage { public: virtual ~CursorImage() = default; virtual void const* as_argb_8888() const = 0; virtual geometry::Size size() const = 0; // We use "hotspot" to mean the offset within a cursor image // which should be placed at the onscreen // location of the pointer. virtual geometry::Displacement hotspot() const = 0; protected: CursorImage() = default; CursorImage(CursorImage const&) = delete; CursorImage& operator=(CursorImage const&) = delete; }; } } #endif /* MIR_GRAPHICS_CURSOR_IMAGE_H_ */ ./include/platform/mir/graphics/frame.h0000644000004100000410000000301613115234664020351 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_GRAPHICS_FRAME_H_ #define MIR_GRAPHICS_FRAME_H_ #include "mir/time/posix_timestamp.h" #include namespace mir { namespace graphics { /** * Frame is a unique identifier for a frame displayed on an output. * * This MSC/UST terminology is used because that's what the rest of the * industry calls it: * GLX: https://www.opengl.org/registry/specs/OML/glx_sync_control.txt * WGL: https://www.opengl.org/registry/specs/OML/wgl_sync_control.txt * EGL: https://bugs.chromium.org/p/chromium/issues/attachmentText?aid=178027 * Mesa: "get_sync_values" functions */ struct Frame { typedef mir::time::PosixTimestamp Timestamp; int64_t msc = 0; /**< Media Stream Counter */ Timestamp ust; /**< Unadjusted System Time */ }; }} // namespace mir::graphics #endif // MIR_GRAPHICS_FRAME_H_ ./include/platform/mir/graphics/event_handler_register.h0000644000004100000410000000364013115234416023777 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_GRAPHICS_EVENT_HANDLER_REGISTER_H_ #define MIR_GRAPHICS_EVENT_HANDLER_REGISTER_H_ #include #include #include "mir/module_deleter.h" namespace mir { namespace graphics { class EventHandlerRegister { public: virtual void register_signal_handler( std::initializer_list signals, std::function const& handler) = 0; virtual void register_signal_handler( std::initializer_list signals, mir::UniqueModulePtr> handler) = 0; virtual void register_fd_handler( std::initializer_list fds, void const* owner, std::function const& handler) = 0; virtual void register_fd_handler( std::initializer_list fds, void const* owner, mir::UniqueModulePtr> handler) = 0; virtual void unregister_fd_handler(void const* owner) = 0; protected: EventHandlerRegister() = default; virtual ~EventHandlerRegister() = default; EventHandlerRegister(EventHandlerRegister const&) = delete; EventHandlerRegister& operator=(EventHandlerRegister const&) = delete; }; } } #endif /* MIR_GRAPHICS_EVENT_HANDLER_REGISTER_H_ */ ./include/platform/mir/graphics/display_configuration.h0000644000004100000410000001665413115234664023667 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_DISPLAY_CONFIGURATION_H_ #define MIR_GRAPHICS_DISPLAY_CONFIGURATION_H_ #include "mir/int_wrapper.h" #include "mir/geometry/size.h" #include "mir/geometry/rectangle.h" #include "mir/geometry/point.h" #include "mir/graphics/gamma_curves.h" #include "mir_toolkit/common.h" #include #include #include namespace mir { namespace graphics { namespace detail { struct GraphicsConfCardIdTag; struct GraphicsConfOutputIdTag; } typedef IntWrapper DisplayConfigurationCardId; typedef IntWrapper DisplayConfigurationOutputId; /** * Configuration information for a display card. */ struct DisplayConfigurationCard { DisplayConfigurationCardId id; size_t max_simultaneous_outputs; }; /** * The type of a display output. */ enum class DisplayConfigurationOutputType { unknown = mir_output_type_unknown, vga = mir_output_type_vga, dvii = mir_output_type_dvii, dvid = mir_output_type_dvid, dvia = mir_output_type_dvia, composite = mir_output_type_composite, svideo = mir_output_type_svideo, lvds = mir_output_type_lvds, component = mir_output_type_component, ninepindin = mir_output_type_ninepindin, displayport = mir_output_type_displayport, hdmia = mir_output_type_hdmia, hdmib = mir_output_type_hdmib, tv = mir_output_type_tv, edp = mir_output_type_edp, virt = mir_output_type_virtual, dsi = mir_output_type_dsi, dpi = mir_output_type_dpi, }; /** * Configuration information for a display output mode. */ struct DisplayConfigurationMode { geometry::Size size; double vrefresh_hz; }; /** * Configuration information for a display output. */ struct DisplayConfigurationOutput { /** The output's id. */ DisplayConfigurationOutputId id; /** The id of the card the output is connected to. */ DisplayConfigurationCardId card_id; /** The type of the output. */ DisplayConfigurationOutputType type; /** The pixel formats supported by the output */ std::vector pixel_formats; /** The modes supported by the output. */ std::vector modes; /** The index in the 'modes' vector of the preferred output mode. */ uint32_t preferred_mode_index; /** The physical size of the output. */ geometry::Size physical_size_mm; /** Whether the output is connected. */ bool connected; /** Whether the output is used in the configuration. */ bool used; /** The top left point of this output in the virtual coordinate space. */ geometry::Point top_left; /** The index in the 'modes' vector of the current output mode. */ uint32_t current_mode_index; /** The current output pixel format. A matching entry should be found in the 'pixel_formats' vector*/ MirPixelFormat current_format; /** Current power mode **/ MirPowerMode power_mode; MirOrientation orientation; /** Requested scale factor for this output, for HiDPI support */ float scale; /** Form factor of this output; phone display, tablet, monitor, TV, projector... */ MirFormFactor form_factor; /** Subpixel arrangement of this output */ MirSubpixelArrangement subpixel_arrangement; /** The current gamma for the display */ GammaCurves gamma; MirOutputGammaSupported gamma_supported; /** EDID of the display, if non-empty */ std::vector edid; /** The logical rectangle occupied by the output, based on its position, current mode and orientation (rotation) */ geometry::Rectangle extents() const; bool valid() const; }; /** * Mirror of a DisplayConfigurationOutput, with some fields limited to * being read-only, preventing users from changing things they shouldn't. */ struct UserDisplayConfigurationOutput { DisplayConfigurationOutputId const& id; DisplayConfigurationCardId const& card_id; DisplayConfigurationOutputType const& type; std::vector const& pixel_formats; std::vector const& modes; uint32_t const& preferred_mode_index; geometry::Size const& physical_size_mm; bool const& connected; bool& used; geometry::Point& top_left; uint32_t& current_mode_index; MirPixelFormat& current_format; MirPowerMode& power_mode; MirOrientation& orientation; float& scale; MirFormFactor& form_factor; MirSubpixelArrangement& subpixel_arrangement; GammaCurves& gamma; MirOutputGammaSupported const& gamma_supported; std::vector const& edid; UserDisplayConfigurationOutput(DisplayConfigurationOutput& master); geometry::Rectangle extents() const; }; std::ostream& operator<<(std::ostream& out, DisplayConfigurationCard const& val); bool operator==(DisplayConfigurationCard const& val1, DisplayConfigurationCard const& val2); bool operator!=(DisplayConfigurationCard const& val1, DisplayConfigurationCard const& val2); std::ostream& operator<<(std::ostream& out, DisplayConfigurationMode const& val); bool operator==(DisplayConfigurationMode const& val1, DisplayConfigurationMode const& val2); bool operator!=(DisplayConfigurationMode const& val1, DisplayConfigurationMode const& val2); std::ostream& operator<<(std::ostream& out, DisplayConfigurationOutput const& val); bool operator==(DisplayConfigurationOutput const& val1, DisplayConfigurationOutput const& val2); bool operator!=(DisplayConfigurationOutput const& val1, DisplayConfigurationOutput const& val2); /** * Interface to a configuration of display cards and outputs. */ class DisplayConfiguration { public: virtual ~DisplayConfiguration() = default; /** Executes a function object for each card in the configuration. */ virtual void for_each_card(std::function f) const = 0; /** Executes a function object for each output in the configuration. */ virtual void for_each_output(std::function f) const = 0; virtual void for_each_output(std::function f) = 0; virtual std::unique_ptr clone() const = 0; virtual bool valid() const; protected: DisplayConfiguration() = default; DisplayConfiguration(DisplayConfiguration const& c) = delete; DisplayConfiguration& operator=(DisplayConfiguration const& c) = delete; }; bool operator==(DisplayConfiguration const& lhs, DisplayConfiguration const& rhs); bool operator!=(DisplayConfiguration const& lhs, DisplayConfiguration const& rhs); std::ostream& operator<<(std::ostream& out, DisplayConfiguration const& val); } } #endif /* MIR_GRAPHICS_DISPLAY_CONFIGURATION_H_ */ ./include/platform/mir/graphics/gamma_curves.h0000644000004100000410000000272413115234664021735 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Brandon Schaefer */ #ifndef MIR_GRAPHICS_GAMMA_CURVES_H_ #define MIR_GRAPHICS_GAMMA_CURVES_H_ #include #include namespace mir { namespace graphics { typedef std::vector GammaCurve; class GammaCurves { public: GammaCurves() = default; GammaCurves(GammaCurves const& other) = default; GammaCurves(GammaCurves&& other) = default; GammaCurves(GammaCurve const& red, GammaCurve const& green, GammaCurve const& blue); GammaCurves& operator=(GammaCurves const& other) = default; GammaCurves& operator=(GammaCurves&& other) = default; GammaCurve red; GammaCurve green; GammaCurve blue; }; class LinearGammaLUTs : public GammaCurves { public: explicit LinearGammaLUTs(int size); }; } } #endif ./include/platform/mir/graphics/display_buffer.h0000644000004100000410000000743613115234664022267 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_DISPLAY_BUFFER_H_ #define MIR_GRAPHICS_DISPLAY_BUFFER_H_ #include #include #include #include namespace mir { namespace graphics { class Buffer; class NativeDisplayBuffer { protected: NativeDisplayBuffer() = default; virtual ~NativeDisplayBuffer() = default; NativeDisplayBuffer(NativeDisplayBuffer const&) = delete; NativeDisplayBuffer operator=(NativeDisplayBuffer const&) = delete; }; /** * Interface to an output framebuffer. */ class DisplayBuffer { public: virtual ~DisplayBuffer() = default; /** The area the DisplayBuffer occupies in the virtual screen space. */ virtual geometry::Rectangle view_area() const = 0; /** This will render renderlist to the screen and post the result to the * screen if there is a hardware optimization that can be done. * \param [in] renderlist * The renderables that should appear on the screen if the hardware * is capable of optmizing that list somehow. If what you want * displayed on the screen cannot be represented by a RenderableList, * then you should render using a graphics library like OpenGL. * \returns * True if the hardware can (and has) fully composite/overlay the list; * False if the hardware platform cannot composite the list, and the * caller should then render the list another way using a graphics * library such as OpenGL. **/ virtual bool overlay(RenderableList const& renderlist) = 0; /** Returns the orientation of the display buffer relative to how the * user should see it (the orientation of the output). * This tells us how much (if any) rotation the renderer needs to do. * If your DisplayBuffer can do the rotation itself then this will * always return mir_orientation_normal. If the DisplayBuffer does not * implement the rotation itself then this function will return the * amount of rotation the renderer must do to make things "look right". */ virtual MirOrientation orientation() const = 0; /** Returns the mirror mode of the display buffer relative to orientation * * If your DisplayBuffer can do the mirroring itself then this will * always return mir_mirror_mode_none. If the DisplayBuffer does not * implement the mirroring itself then this function will return the * mirror mode the renderer must do after rotation to make things * "look right". * */ virtual MirMirrorMode mirror_mode() const = 0; /** Returns a pointer to the native display buffer object backing this * display buffer. * * The pointer to the native display buffer remains valid as long as the * display buffer object is valid. */ virtual NativeDisplayBuffer* native_display_buffer() = 0; protected: DisplayBuffer() = default; DisplayBuffer(DisplayBuffer const& c) = delete; DisplayBuffer& operator=(DisplayBuffer const& c) = delete; }; } } #endif /* MIR_GRAPHICS_DISPLAY_BUFFER_H_ */ ./include/platform/mir/graphics/cursor.h0000644000004100000410000000243013115234416020566 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_GRAPHICS_CURSOR_H_ #define MIR_GRAPHICS_CURSOR_H_ #include "mir/geometry/size.h" #include "mir/geometry/point.h" #include namespace mir { namespace graphics { class CursorImage; class Cursor { public: virtual void show() = 0; virtual void show(CursorImage const& cursor_image) = 0; virtual void hide() = 0; virtual void move_to(geometry::Point position) = 0; protected: Cursor() = default; virtual ~Cursor() = default; Cursor(Cursor const&) = delete; Cursor& operator=(Cursor const&) = delete; }; } } #endif /* MIR_GRAPHICS_CURSOR_H_ */ ./include/platform/mir/graphics/graphic_buffer_allocator.h0000644000004100000410000000462413115234664024273 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_GRAPHIC_BUFFER_ALLOCATOR_H_ #define MIR_GRAPHICS_GRAPHIC_BUFFER_ALLOCATOR_H_ #include "mir/graphics/buffer.h" #include #include namespace mir { namespace graphics { struct BufferProperties; /** * Interface to graphic buffer allocation. */ class GraphicBufferAllocator { public: virtual ~GraphicBufferAllocator() = default; /** * Allocates a buffer. * \deprecated. use the other alloc_buffer functions * \param [in] buffer_properties the properties the allocated buffer should have */ virtual std::shared_ptr alloc_buffer(BufferProperties const& buffer_properties) = 0; /** * The supported buffer pixel formats. * \note: once the above is deprecated, this is really only (marginally) useful * for the software allocation path. * (and we could probably move software/cpu buffers up to libmirserver) */ virtual std::vector supported_pixel_formats() = 0; /** * allocates a buffer with the native flags and format specified */ virtual std::shared_ptr alloc_buffer( geometry::Size size, uint32_t native_format, uint32_t native_flags) = 0; /** * allocates a 'software' (cpu-accessible) buffer * note: mesa and eglstreams use ShmBuffer, android uses ANW with software usage bits. */ virtual std::shared_ptr alloc_software_buffer(geometry::Size size, MirPixelFormat) = 0; protected: GraphicBufferAllocator() = default; GraphicBufferAllocator(const GraphicBufferAllocator&) = delete; GraphicBufferAllocator& operator=(const GraphicBufferAllocator&) = delete; }; } } #endif // MIR_GRAPHICS_GRAPHIC_BUFFER_ALLOCATOR_H_ ./include/platform/mir/graphics/virtual_output.h0000644000004100000410000000343713115234416022367 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alberto Aguirre */ #ifndef MIR_GRAPHICS_VIRTUAL_OUTPUT_H_ #define MIR_GRAPHICS_VIRTUAL_OUTPUT_H_ namespace mir { namespace graphics { /** * Interface to a virtual output */ class VirtualOutput { public: /** Enables the virtual output. * * This will initiate the same response as when a physical display is * hotplugged into a system. A configuration change notification will be * generated and the DisplayConfiguration will contain one new output. **/ virtual void enable() = 0; /** Disable the virtual output. * * This will initiate the same response as when a physical display is * unplugged from a system. A configuration change notification will be * generated and the DisplayConfiguration will no longer contain an output * associated with the virtual display. **/ virtual void disable() = 0; VirtualOutput() = default; virtual ~VirtualOutput() = default; private: VirtualOutput(VirtualOutput const&) = delete; VirtualOutput& operator=(VirtualOutput const&) = delete; }; } } #endif /* MIR_GRAPHICS_VIRTUAL_OUTPUT_H_ */ ./include/platform/mir/graphics/display.h0000644000004100000410000001666613115234664020743 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_GRAPHICS_DISPLAY_H_ #define MIR_GRAPHICS_DISPLAY_H_ #include "mir/graphics/frame.h" #include #include #include namespace mir { namespace graphics { class DisplayBuffer; class DisplayConfiguration; class Cursor; class CursorImage; class EventHandlerRegister; class VirtualOutput; typedef std::function DisplayPauseHandler; typedef std::function DisplayResumeHandler; typedef std::function DisplayConfigurationChangeHandler; class NativeDisplay { protected: NativeDisplay() = default; virtual ~NativeDisplay() = default; NativeDisplay(NativeDisplay const&) = delete; NativeDisplay operator=(NativeDisplay const&) = delete; }; /** * DisplaySyncGroup represents a group of displays that need to be output * in unison as a single post() call. * This is only appropriate for platforms whose post() calls are non-blocking * and not synchronous with the screen hardware (e.g. virtual machines or * Android). * Using a DisplaySyncGroup with multiple screens on a platform whose post() * blocks for vsync often results in stuttering, and so should be avoided. * Although using DisplaySyncGroup with a single DisplayBuffer remains safe * for any platform. */ class DisplaySyncGroup { public: /** * Executes a functor that allows the DisplayBuffer contents to be updated **/ virtual void for_each_display_buffer(std::function const& f) = 0; /** Post the content of the DisplayBuffers associated with this DisplaySyncGroup. * The content of all the DisplayBuffers in this DisplaySyncGroup are guaranteed to be onscreen * in the near future. On some platforms, this may wait a potentially long time for vsync. **/ virtual void post() = 0; /** * Returns a recommendation to the compositor as to how long it should * wait before sampling the scene for the next frame. Sampling the * scene too early results in up to one whole frame of extra lag if * rendering is fast or skipped altogether (bypass/overlays). But sampling * too late and we might miss the deadline. If unsure just return zero. * * This is equivalent to: * https://www.opengl.org/registry/specs/NV/glx_delay_before_swap.txt */ virtual std::chrono::milliseconds recommended_sleep() const = 0; virtual ~DisplaySyncGroup() = default; protected: DisplaySyncGroup() = default; DisplaySyncGroup(DisplaySyncGroup const&) = delete; DisplaySyncGroup& operator=(DisplaySyncGroup const&) = delete; }; /** * Interface to the display subsystem. */ class Display { public: /** * Executes a functor for each output group. */ virtual void for_each_display_sync_group(std::function const& f) = 0; /** * Gets a copy of the current output configuration. */ virtual std::unique_ptr configuration() const = 0; /** * Applying a display configuration only if it will not invalidate existing DisplayBuffers * * The Display must guarantee that the references to the DisplayBuffer acquired via * DisplaySyncGroup::for_each_display_buffer() remain valid until the Display is destroyed or * Display::configure() is called. * * If this function returns \c true then the new display configuration has been applied. * If this function returns \c false then the new display configuration has not been applied. * * In either case this function guarantees that existing DisplayBuffer references will remain * valid. * * \param conf [in] Configuration to possibly apply. * \return \c true if \p conf has been applied as the new output configuration. */ virtual bool apply_if_configuration_preserves_display_buffers(DisplayConfiguration const& conf) = 0; /** * Sets a new output configuration. */ virtual void configure(DisplayConfiguration const& conf) = 0; /** * Registers a handler for display configuration changes. * * Note that the handler is called only for hardware changes (e.g. monitor * plugged/unplugged), not for changes initiated by software (e.g. modesetting). * * The implementation should use the functionality provided by the MainLoop * to register the handlers in a way appropriate for the platform. */ virtual void register_configuration_change_handler( EventHandlerRegister& handlers, DisplayConfigurationChangeHandler const& conf_change_handler) = 0; /** * Registers handlers for pausing and resuming the display subsystem. * * The implementation should use the functionality provided by the EventHandlerRegister * to register the handlers in a way appropriate for the platform. */ virtual void register_pause_resume_handlers( EventHandlerRegister& handlers, DisplayPauseHandler const& pause_handler, DisplayResumeHandler const& resume_handler) = 0; /** * Pauses the display. * * This method may temporarily (until resumed) release any resources * associated with the display subsystem. */ virtual void pause() = 0; /** * Resumes the display. */ virtual void resume() = 0; /** * Create a hardware cursor object. */ virtual std::shared_ptr create_hardware_cursor(std::shared_ptr const& initial_image) = 0; /** * Creates a virtual output * \returns null if the implementation does not support virtual outputs */ virtual std::unique_ptr create_virtual_output(int width, int height) = 0; /** Returns a pointer to the native display object backing this * display. * * The pointer to the native display remains valid as long as the * display object is valid. */ virtual NativeDisplay* native_display() = 0; /** * Returns timing information for the last frame displayed on a given * output. * * Frame timing will be provided to clients only when they request it. * This is to ensure idle clients never get woken by unwanted events. * It is also distinctly separate from the display configuration as this * timing information changes many times per second and should not interfere * with the more static display configuration. * * Note: Using unsigned here because DisplayConfigurationOutputId is * troublesome (can't be forward declared) and including * display_configuration.h to get it would be an overkill. */ virtual Frame last_frame_on(unsigned output_id) const = 0; Display() = default; virtual ~Display() = default; private: Display(Display const&) = delete; Display& operator=(Display const&) = delete; }; } } #endif /* MIR_GRAPHICS_DISPLAY_H_ */ ./include/platform/mir/graphics/buffer.h0000644000004100000410000000311513115234664020530 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_GRAPHICS_BUFFER_H_ #define MIR_GRAPHICS_BUFFER_H_ #include "mir/graphics/native_buffer.h" #include "mir/graphics/buffer_id.h" #include "mir/geometry/size.h" #include "mir_toolkit/common.h" #include #include namespace mir { namespace graphics { class NativeBufferBase { protected: NativeBufferBase() = default; virtual ~NativeBufferBase() = default; NativeBufferBase(NativeBuffer const&) = delete; NativeBufferBase operator=(NativeBuffer const&) = delete; }; class Buffer { public: virtual ~Buffer() {} virtual std::shared_ptr native_buffer_handle() const = 0; virtual BufferID id() const = 0; virtual geometry::Size size() const = 0; virtual MirPixelFormat pixel_format() const = 0; virtual NativeBufferBase* native_buffer_base() = 0; protected: Buffer() = default; }; } } #endif // MIR_GRAPHICS_BUFFER_H_ ./include/platform/mir/graphics/platform.h0000644000004100000410000001545413115234664021114 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Thomas Guest */ #ifndef MIR_GRAPHICS_PLATFORM_H_ #define MIR_GRAPHICS_PLATFORM_H_ #include #include "mir/module_properties.h" #include "mir/module_deleter.h" namespace mir { class EmergencyCleanupRegistry; namespace logging { class Logger; } namespace frontend { class Surface; } namespace options { class Option; class ProgramOption; } /// Graphics subsystem. Mediates interaction between core system and /// the graphics environment. namespace graphics { class Buffer; class Display; class DisplayReport; class DisplayConfigurationPolicy; class GraphicBufferAllocator; class GLConfig; class PlatformIpcOperations; class NestedContext; /** * \defgroup platform_enablement Mir platform enablement * * Classes and functions that need to be implemented to add support for a graphics platform. */ /** * Interface to platform specific support for graphics operations. * \ingroup platform_enablement */ class Platform { public: Platform() = default; Platform(const Platform& p) = delete; Platform& operator=(const Platform& p) = delete; virtual ~Platform() = default; /** * Creates the buffer allocator subsystem. */ virtual UniqueModulePtr create_buffer_allocator() = 0; /** * Creates the display subsystem. */ virtual UniqueModulePtr create_display( std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config) = 0; /** * Creates an object capable of doing platform specific processing of buffers * before they are sent or after they are recieved accross IPC */ virtual UniqueModulePtr make_ipc_operations() const = 0; }; /** * A measure of how well a platform supports a device * * \note This is compared as an integer; best + 1 is a valid PlatformPriority that * will be used in preference to a module that reports best. * Platform modules distributed with Mir will never use a priority higher * than best. */ enum PlatformPriority : uint32_t { unsupported = 0, /**< Unable to function at all on this device */ dummy = 1, /**< Used only for dummy or stub platforms. */ supported = 128, /**< Capable of providing a functioning Platform on this device, * possibly with degraded performance or features. */ best = 256 /**< Capable of providing a Platform with the best features and * performance this device is capable of. */ }; typedef mir::UniqueModulePtr(*CreateHostPlatform)( std::shared_ptr const& options, std::shared_ptr const& emergency_cleanup_registry, std::shared_ptr const& report, std::shared_ptr const& logger); typedef mir::UniqueModulePtr(*CreateGuestPlatform)( std::shared_ptr const& report, std::shared_ptr const& nested_context); typedef void(*AddPlatformOptions)( boost::program_options::options_description& config); typedef mir::graphics::PlatformPriority(*PlatformProbe)(mir::options::ProgramOption const& options); typedef mir::ModuleProperties const*(*DescribeModule)(); } } extern "C" { #if defined(__clang__) #pragma clang diagnostic push // These functions are given "C" linkage to avoid name-mangling, not for C compatibility. // (We don't want a warning for doing this intentionally.) #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #endif /** * Function prototype used to return a new host graphics platform. The host graphics platform * is the system entity that owns the physical display and is a mir host server. * * \param [in] options options to use for this platform * \param [in] emergency_cleanup_registry object to register emergency shutdown handlers with * \param [in] report the object to use to report interesting events from the display subsystem * * This factory function needs to be implemented by each platform. * * \ingroup platform_enablement */ mir::UniqueModulePtr create_host_platform( std::shared_ptr const& options, std::shared_ptr const& emergency_cleanup_registry, std::shared_ptr const& report, std::shared_ptr const& logger); /** * Function prototype used to return a new guest graphics platform. The guest graphics platform * exists alongside the host platform and do not output or control the physical displays * * \param [in] nested_context the object that contains resources needed from the host platform * \param [in] report the object to use to report interesting events from the display subsystem * * This factory function needs to be implemented by each platform. * * \ingroup platform_enablement */ mir::UniqueModulePtr create_guest_platform( std::shared_ptr const& report, std::shared_ptr const& nested_context); /** * Function prototype used to add platform specific options to the platform-independent server options. * * \param [in] config a boost::program_options that can be appended with new options * * This factory function needs to be implemented by each platform. * * \ingroup platform_enablement */ void add_graphics_platform_options( boost::program_options::options_description& config); // TODO: We actually need to be more granular here; on a device with more // than one graphics system we may need a different platform per GPU, // so we should be associating platforms with graphics devices in some way mir::graphics::PlatformPriority probe_graphics_platform(mir::options::ProgramOption const& options); mir::ModuleProperties const* describe_graphics_module(); #if defined(__clang__) #pragma clang diagnostic pop #endif } #endif // MIR_GRAPHICS_PLATFORM_H_ ./include/platform/mir/graphics/buffer_basic.h0000644000004100000410000000214013115234416021661 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_BUFFER_BASIC_H_ #define MIR_GRAPHICS_BUFFER_BASIC_H_ #include "mir/graphics/buffer.h" #include "mir/graphics/buffer_id.h" namespace mir { namespace graphics { class BufferBasic : public Buffer { public: BufferBasic(); graphics::BufferID id() const { return buffer_id; } private: BufferID const buffer_id; }; } } #endif /* MIR_GRAPHICS_BUFFER_BASIC_H_ */ ./include/platform/mir/graphics/atomic_frame.h0000644000004100000410000000242013115234664021703 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_GRAPHICS_ATOMIC_FRAME_H_ #define MIR_GRAPHICS_ATOMIC_FRAME_H_ #include "mir/graphics/frame.h" #include namespace mir { namespace graphics { class AtomicFrame { public: Frame load() const; // Preferably use this and provide all fields from the driver: void store(Frame const&); // Or if your driver is limited these will suffice: void increment_now(); void increment_with_timestamp(Frame::Timestamp t); private: mutable std::mutex mutex; Frame frame; }; }} // namespace mir::graphics #endif // MIR_GRAPHICS_ATOMIC_FRAME_H_ ./include/platform/mir/graphics/renderable.h0000644000004100000410000000521113115234664021361 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_RENDERABLE_H_ #define MIR_GRAPHICS_RENDERABLE_H_ #include #include #include #include namespace mir { namespace graphics { class Buffer; class Renderable { public: virtual ~Renderable() = default; typedef void const* ID; // Mostly opaque, but zero is reserved as "invalid" /** * Return a unique ID for the renderable, which may or may not be based * on the underlying surface ID. You should not assume they are related. */ virtual ID id() const = 0; /** * Return the buffer that should be composited/rendered. */ virtual std::shared_ptr buffer() const = 0; virtual geometry::Rectangle screen_position() const = 0; // These are from the old CompositingCriteria. There is a little bit // of function overlap with the above functions still. virtual float alpha() const = 0; /** * Transformation returns the transformation matrix that should be applied * to the surface. By default when there are no transformations this will * be the identity matrix. * * \warning As this functionality is presently only used by * mir_demo_standalone_render_surfaces for rotations it may be * deprecated in future. It is expected that real transformations * may become more transient things (e.g. applied by animation * logic externally instead of being a semi-permanent attribute of * the surface itself). */ virtual glm::mat4 transformation() const = 0; virtual bool shaped() const = 0; // meaning the pixel format has alpha virtual unsigned int swap_interval() const = 0; protected: Renderable() = default; Renderable(Renderable const&) = delete; Renderable& operator=(Renderable const&) = delete; }; typedef std::vector> RenderableList; } } #endif /* MIR_GRAPHICS_RENDERABLE_H_ */ ./include/platform/mir/graphics/gl_config.h0000644000004100000410000000260113115234416021200 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_GL_CONFIG_H_ #define MIR_GRAPHICS_GL_CONFIG_H_ namespace mir { namespace graphics { /** * Interface for customizing aspects of the GL config used by the server. */ class GLConfig { public: virtual ~GLConfig() = default; /** * Gets the bits to use for each pixel in the depth buffer. */ virtual int depth_buffer_bits() const = 0; /** * Gets the bits to use for each pixel in the stencil buffer. */ virtual int stencil_buffer_bits() const = 0; protected: GLConfig() = default; GLConfig(GLConfig const&) = delete; GLConfig& operator=(GLConfig const&) = delete; }; } } #endif /* MIR_GRAPHICS_GL_CONFIG_H_ */ ./include/platform/mir/graphics/buffer_id.h0000644000004100000410000000171013115234416021176 0ustar www-datawww-data/* * Copyright © 2012, 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_BUFFER_ID_H_ #define MIR_GRAPHICS_BUFFER_ID_H_ #include "mir/int_wrapper.h" namespace mir { namespace graphics { struct BufferIdTag; typedef IntWrapper BufferID; } } #endif /* MIR_GRAPHICS_BUFFER_ID_H_ */ ./include/platform/mir/input/0000755000004100000410000000000013115234677016451 5ustar www-datawww-data./include/platform/mir/input/input_sink.h0000644000004100000410000000373513115234664021011 0ustar www-datawww-data/* * Copyright © 2014-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_INPUT_SINK_H_ #define MIR_INPUT_INPUT_SINK_H_ #include "mir_toolkit/event.h" #include "mir/geometry/rectangle.h" #include "mir/geometry/displacement.h" #include namespace mir { namespace input { class InputSink { public: InputSink() = default; virtual ~InputSink() = default; virtual void handle_input(MirEvent& event) = 0; /**! * Obtain the bounding rectangle of the destination area for this input sink */ virtual mir::geometry::Rectangle bounding_rectangle() const = 0; /** * \name Device State interface of InputSink * * In scenarios in which the system is not capable of receiving all changes as they occur, * these method should be used to update the input device state as needed * \{ */ /** * Set all pressed scan codes. * \param scan_codes currently pressed */ virtual void key_state(std::vector const& scan_codes) = 0; /** * Set button state of a pointing device. * \param buttons mask of the buttons currently pressed */ virtual void pointer_state(MirPointerButtons buttons) = 0; /** * \} */ private: InputSink(InputSink const&) = delete; InputSink& operator=(InputSink const&) = delete; }; } } #endif ./include/platform/mir/input/touchpad_settings.h0000644000004100000410000000247713115234416022352 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_TOUCH_PAD_SETTINGS_H_ #define MIR_INPUT_TOUCH_PAD_SETTINGS_H_ #include "mir_toolkit/mir_input_device.h" namespace mir { namespace input { int const no_scroll_button = 0; struct TouchpadSettings { TouchpadSettings() {} MirTouchpadClickModes click_mode{mir_touchpad_click_mode_finger_count}; MirTouchpadScrollModes scroll_mode{mir_touchpad_scroll_mode_two_finger_scroll}; int button_down_scroll_button{no_scroll_button}; bool tap_to_click{true}; bool disable_while_typing{false}; bool disable_with_mouse{false}; bool middle_mouse_button_emulation{true}; }; } } #endif ./include/platform/mir/input/pointer_settings.h0000644000004100000410000000317713115234416022221 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_POINTER_SETTINGS_H_ #define MIR_INPUT_POINTER_SETTINGS_H_ #include "mir_toolkit/client_types.h" #include "mir_toolkit/mir_input_device.h" namespace mir { namespace input { struct PointerSettings { PointerSettings() {} /** * Configure left and right handed mode by selecting a primary button */ MirPointerHandedness handedness{mir_pointer_handedness_right}; /** * Bias cursor acceleration. * - [-1, 0): reduced acceleration * - 0: default acceleration * - (0, 1]: increased acceleration */ double cursor_acceleration_bias{0.0}; /** * Acceleration profile */ MirPointerAcceleration acceleration{mir_pointer_acceleration_adaptive}; /** * Scale horizontal scrolling linearly */ double horizontal_scroll_scale{1.0}; /** * Scale vertical scrolling linearly */ double vertical_scroll_scale{1.0}; }; } } #endif ./include/platform/mir/input/platform.h0000644000004100000410000001154413115234664020447 0ustar www-datawww-data/* * Copyright © 2014-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_PLATFORM_H_ #define MIR_INPUT_PLATFORM_H_ #include "mir/module_properties.h" #include #include #include #include namespace mir { class EmergencyCleanupRegistry; namespace dispatch { class Dispatchable; } namespace input { class InputDevice; class InputReport; class InputDeviceRegistry; class InputPlatformPolicy; enum class PlatformPriority : uint32_t { unsupported = 0, dummy = 1, supported = 128, best = 256, }; /** * Input Platform is used to discover and access available input devices. * * A platform implementation is supposed to handle device occurance events by * opening new device and registering them at the server's InputDeviceRegistry. * Likewise the InputDeviceRegistry shall be informed about removed input devices. * * The actual processing of user input is controlled through the mir::input::InputDevice interface. */ class Platform { public: Platform() = default; virtual ~Platform() = default; /*! * The dispatchable of the platform shall be used to monitor for devices. */ virtual std::shared_ptr dispatchable() = 0; /*! * Request the platform to start monitoring for devices. */ virtual void start() = 0; /*! * Request the platform to stop monitoring for devices. */ virtual void stop() = 0; private: Platform(Platform const&) = delete; Platform& operator=(Platform const&) = delete; }; typedef mir::UniqueModulePtr(*CreatePlatform)( options::Option const& options, std::shared_ptr const& emergency_cleanup_registry, std::shared_ptr const& input_device_registry, std::shared_ptr const& report); typedef void(*AddPlatformOptions)( boost::program_options::options_description& config); typedef PlatformPriority(*ProbePlatform)( options::Option const& options); typedef ModuleProperties const*(*DescribeModule)(); } } extern "C" { #if defined(__clang__) #pragma clang diagnostic push // These functions are given "C" linkage to avoid name-mangling, not for C compatibility. // (We don't want a warning for doing this intentionally.) #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" #endif /** * Function used to initialize an input platform. * * \param [in] options options to use for this platform * \param [in] emergency_cleanup_registry object to register emergency shutdown handlers with * \param [in] input_device_registry object to register input devices handled by this platform * \param [in] report the object to use to report interesting events from the input subsystem * * This factory function needs to be implemented by each platform. * * \ingroup platform_enablement */ mir::UniqueModulePtr create_input_platform( mir::options::Option const& options, std::shared_ptr const& emergency_cleanup_registry, std::shared_ptr const& input_device_registry, std::shared_ptr const& report); /** * Function used to add additional configuration options * * \param [in] config program option description that the platform may extend * * This function needs to be implemented by each platform. * * \ingroup platform_enablement */ void add_input_platform_options(boost::program_options::options_description& config); /** * probe_platform should indicate whether the platform is able to work within * the current environment. * * \param [in] options program options of the mir server * * This function needs to be implemented by each platform. * * \ingroup platform_enablement */ mir::input::PlatformPriority probe_input_platform(mir::options::Option const& options); /** * describe_input_module should return a description of the input platform. * * This function needs to be implemented by each platform. * * \ingroup platform_enablement */ mir::ModuleProperties const* describe_input_module(); #if defined(__clang__) #pragma clang diagnostic pop #endif } #endif // MIR_INPUT_PLATFORM_H_ ./include/platform/mir/input/event_builder.h0000644000004100000410000000432213115234664021446 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_EVENT_BUILDER_H_ #define MIR_INPUT_EVENT_BUILDER_H_ #include "mir_toolkit/event.h" #include "mir/events/contact_state.h" #include #include #include namespace mir { using EventUPtr = std::unique_ptr; namespace input { class EventBuilder { public: EventBuilder() = default; virtual ~EventBuilder() = default; using Timestamp = std::chrono::nanoseconds; virtual EventUPtr key_event(Timestamp timestamp, MirKeyboardAction action, xkb_keysym_t key_code, int scan_code) = 0; virtual EventUPtr pointer_event(Timestamp timestamp, MirPointerAction action, MirPointerButtons buttons_pressed, float hscroll_value, float vscroll_value, float relative_x_value, float relative_y_value) = 0; virtual EventUPtr device_state_event(float cursor_x, float cursor_y) = 0; virtual EventUPtr pointer_event(Timestamp timestamp, MirPointerAction action, MirPointerButtons buttons_pressed, float x_position, float y_position, float hscroll_value, float vscroll_value, float relative_x_value, float relative_y_value) = 0; virtual EventUPtr touch_event(Timestamp timestamp, std::vector const& contacts) = 0; protected: EventBuilder(EventBuilder const&) = delete; EventBuilder& operator=(EventBuilder const&) = delete; }; } } #endif ./include/platform/mir/input/input_device_registry.h0000644000004100000410000000245713115234416023227 0ustar www-datawww-data/* * Copyright © 2014-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_INPUT_DEVICE_REGISTRY_H_ #define MIR_INPUT_INPUT_DEVICE_REGISTRY_H_ #include namespace mir { namespace input { class InputDevice; class InputDeviceRegistry { public: InputDeviceRegistry() = default; virtual ~InputDeviceRegistry() = default; virtual void add_device(std::shared_ptr const& device) = 0; virtual void remove_device(std::shared_ptr const& device) = 0; protected: InputDeviceRegistry(InputDeviceRegistry const&) = delete; InputDeviceRegistry& operator=(InputDeviceRegistry const&) = delete; }; } } #endif ./include/platform/mir/input/input_device.h0000644000004100000410000000364513115234416021277 0ustar www-datawww-data/* * Copyright © 2014-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_INPUT_DEVICE_H_ #define MIR_INPUT_INPUT_DEVICE_H_ #include "mir/module_deleter.h" #include "mir/optional_value.h" #include namespace mir { namespace dispatch { class Dispatchable; } namespace input { class InputSink; class InputDeviceInfo; class EventBuilder; class PointerSettings; class TouchpadSettings; /** * Represents an input device. */ class InputDevice { public: InputDevice() = default; virtual ~InputDevice() = default; /*! * Allow the input device to provide its input events to the given InputSink */ virtual void start(InputSink* destination, EventBuilder* builder) = 0; /*! * Stop the input device from sending input events, to the InputSink. */ virtual void stop() = 0; virtual InputDeviceInfo get_device_info() = 0; virtual optional_value get_pointer_settings() const = 0; virtual void apply_settings(PointerSettings const&) = 0; virtual optional_value get_touchpad_settings() const = 0; virtual void apply_settings(TouchpadSettings const&) = 0; protected: InputDevice(InputDevice const&) = delete; InputDevice& operator=(InputDevice const&) = delete; }; } } #endif ./include/platform/mir/input/input_report.h0000644000004100000410000000305213115234416021343 0ustar www-datawww-data/* * Copyright © 2013-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_INPUT_INPUT_REPORT_H_ #define MIR_INPUT_INPUT_REPORT_H_ #include namespace mir { namespace input { class InputReport { public: virtual ~InputReport() = default; virtual void received_event_from_kernel(int64_t when, int type, int code, int value) = 0; virtual void published_key_event(int dest_fd, uint32_t seq_id, int64_t event_time) = 0; virtual void published_motion_event(int dest_fd, uint32_t seq_id, int64_t event_time) = 0; virtual void opened_input_device(char const* device_name, char const* input_platform) = 0; virtual void failed_to_open_input_device(char const* device_name, char const* input_platform) = 0; protected: InputReport() = default; InputReport(InputReport const&) = delete; InputReport& operator=(InputReport const&) = delete; }; } } #endif /* MIR_INPUT_INPUT_REPORT_H_ */ ./include/platform/mir/input/input_device_info.h0000644000004100000410000000202213115234416022276 0ustar www-datawww-data/* * Copyright © 2014-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_INPUT_INPUT_DEVICE_INFO_H_ #define MIR_INPUT_INPUT_DEVICE_INFO_H_ #include "mir/input/device_capability.h" #include #include namespace mir { namespace input { struct InputDeviceInfo { std::string name; std::string unique_id; DeviceCapabilities capabilities; }; } } #endif ./include/platforms/0000755000004100000410000000000013115234413014672 5ustar www-datawww-data./include/platforms/mesa/0000755000004100000410000000000013115234413015617 5ustar www-datawww-data./include/platforms/mesa/mir_toolkit/0000755000004100000410000000000013115234413020153 5ustar www-datawww-data./include/platforms/mesa/mir_toolkit/mesa/0000755000004100000410000000000013115234677021114 5ustar www-datawww-data./include/platforms/mesa/mir_toolkit/mesa/native_display.h0000644000004100000410000000335313115234664024300 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MESA_NATIVE_DISPLAY_H #define MIR_TOOLKIT_MESA_NATIVE_DISPLAY_H #include #define MIR_MESA_TRUE 1 #define MIR_MESA_FALSE 0 #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif typedef struct MirMesaEGLNativeDisplay MirMesaEGLNativeDisplay; typedef struct MirMesaEGLNativeSurface MirMesaEGLNativeSurface; typedef struct MirBufferPackage MirBufferPackage; struct MirMesaEGLNativeDisplay { int (*display_get_platform)(MirMesaEGLNativeDisplay* display, MirPlatformPackage* package); void *context; }; struct MirMesaEGLNativeSurface { int (*surface_set_swapinterval)(MirMesaEGLNativeSurface* surface, int interval); int (*surface_advance_buffer)(MirMesaEGLNativeSurface* surface, MirBufferPackage* buffer_package); int (*surface_get_parameters)(MirMesaEGLNativeSurface* surface, MirWindowParameters* surface_parameters); }; #ifdef __cplusplus } // extern "C" /**@}*/ #endif #endif /* MIR_TOOLKIT_MESA_NATIVE_DISPLAY_H */ ./include/platforms/mesa/mir_toolkit/mesa/platform_operation.h0000644000004100000410000000311113115234416025154 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_TOOLKIT_MESA_PLATFORM_OPERATION_H_ #define MIR_TOOLKIT_MESA_PLATFORM_OPERATION_H_ #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /* * Supported platform operations for the Mesa driver */ enum MirMesaPlatformOperation { auth_magic = 1, auth_fd = 2, set_gbm_device = 3 }; /* * MesaPlatformOperation::auth_magic related structures */ struct MirMesaAuthMagicRequest { unsigned int magic; }; struct MirMesaAuthMagicResponse { int status; /* 0 on success, a positive error number on failure */ }; /* * MesaPlatformOperation::set_gbm_device related structures */ struct gbm_device; struct MirMesaSetGBMDeviceRequest { struct gbm_device* device; }; struct MirMesaSetGBMDeviceResponse { int status; /* 0 on success, a positive error number on failure */ }; #ifdef __cplusplus } /**@}*/ #endif #endif ./include/core/0000755000004100000410000000000013115234665013624 5ustar www-datawww-data./include/core/mir/0000755000004100000410000000000013115234676014415 5ustar www-datawww-data./include/core/mir/optional_value.h0000644000004100000410000000474313115234664017614 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alberto Aguirre */ #ifndef MIR_OPTIONAL_VALUE_H_ #define MIR_OPTIONAL_VALUE_H_ #include "mir/fatal.h" #include namespace mir { template class optional_value { public: optional_value() = default; optional_value(T const& value) : value_(value), is_set_{true} {} optional_value& operator=(T const& value) { value_ = value; is_set_ = true; return *this; } bool is_set() const { return is_set_; } T const& value() const { die_if_unset(); return value_; } T& value() { die_if_unset(); return value_; } T&& consume() { die_if_unset(); is_set_ = false; return std::move(value_); } private: void die_if_unset() const { if (!is_set()) { (*fatal_error)("Accessing value of unset optional"); } } T value_; bool is_set_{false}; }; template inline bool operator == (optional_value const& lhs, optional_value const& rhs) { return lhs.is_set() == rhs.is_set() && (!lhs.is_set() || lhs.value() == rhs.value()); } template inline bool operator != (optional_value const& lhs, optional_value const& rhs) { return !(lhs == rhs); } template inline bool operator == (optional_value const& lhs, T const& rhs) { return lhs.is_set() && (lhs.value() == rhs); } template inline bool operator != (optional_value const& lhs, T const& rhs) { return !(lhs == rhs); } template inline bool operator == (T const& lhs, optional_value const& rhs) { return rhs == lhs; } template inline bool operator != (T const& lhs, optional_value const& rhs) { return rhs != lhs; } } #endif /* MIR_OPTIONAL_VALUE_H_ */ ./include/core/mir/fatal.h0000644000004100000410000000475613115234416015661 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * --- * Fatal error handling - Fatal errors are situations we don't expect to ever * happen and don't have logic to gracefully recover from. The most useful * thing you can do in that situation is abort to get a clean core file and * stack trace to maximize the chances of it being readable. * * Author: Daniel van Vugt * Alan Griffiths */ #ifndef MIR_FATAL_H_ #define MIR_FATAL_H_ namespace mir { /** * fatal_error() is strictly for "this should never happen" situations that * you cannot recover from. By default it points at fatal_error_except(). * Note the reason parameter is a simple char* so its value is clearly visible * in stack trace output. * \param [in] reason A printf-style format string. */ extern void (*fatal_error)(char const* reason, ...); /** * Throws an exception that will typically kill the Mir server and propagate from * mir::run_mir. * \param [in] reason A printf-style format string. */ void fatal_error_except(char const* reason, ...); /** * An alternative to fatal_error_except() that kills the program and dump core * as cleanly as possible. * \param [in] reason A printf-style format string. */ void fatal_error_abort(char const* reason, ...); // Utility class to override & restore existing error handler class FatalErrorStrategy { public: explicit FatalErrorStrategy(void (*fatal_error_handler)(char const* reason, ...)) : old_fatal_error_handler(fatal_error) { fatal_error = fatal_error_handler; } ~FatalErrorStrategy() { fatal_error = old_fatal_error_handler; } private: void (*old_fatal_error_handler)(char const* reason, ...); FatalErrorStrategy(FatalErrorStrategy const&) = delete; FatalErrorStrategy& operator=(FatalErrorStrategy const&) = delete; }; } // namespace mir #endif // MIR_FATAL_H_ ./include/core/mir/int_wrapper.h0000644000004100000410000000506013115234664017116 0ustar www-datawww-data/* * Copyright © 2012, 2013, 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_INT_WRAPPER_H_ #define MIR_INT_WRAPPER_H_ #include namespace mir { template class IntWrapper { public: constexpr IntWrapper() : value(0) {} explicit constexpr IntWrapper(ValueType value) : value(value) {} ValueType constexpr as_value() const { return value; } private: ValueType value; }; template std::ostream& operator<<(std::ostream& out, IntWrapper const& value) { out << value.as_value(); return out; } template inline constexpr bool operator == (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_value() == rhs.as_value(); } template inline constexpr bool operator != (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_value() != rhs.as_value(); } template inline constexpr bool operator <= (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_value() <= rhs.as_value(); } template inline constexpr bool operator >= (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_value() >= rhs.as_value(); } template inline constexpr bool operator < (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_value() < rhs.as_value(); } } #include namespace std { template struct hash< ::mir::IntWrapper > { std::hash self; constexpr std::size_t operator()(::mir::IntWrapper const& id) const { return self(id.as_value()); } }; } #endif // MIR_INT_WRAPPER_H_ ./include/core/mir/geometry/0000755000004100000410000000000013115234677016251 5ustar www-datawww-data./include/core/mir/geometry/size.h0000644000004100000410000000410313115234664017366 0ustar www-datawww-data/* * Copyright © 2012, 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_GEOMETRY_SIZE_H_ #define MIR_GEOMETRY_SIZE_H_ #include "mir/geometry/dimensions.h" #include namespace mir { namespace geometry { struct Size { constexpr Size() {} constexpr Size(Size const&) = default; Size& operator=(Size const&) = default; template constexpr Size(WidthType&& width, HeightType&& height) : width(width), height(height) {} Width width; Height height; }; inline constexpr bool operator == (Size const& lhs, Size const& rhs) { return lhs.width == rhs.width && lhs.height == rhs.height; } inline constexpr bool operator != (Size const& lhs, Size const& rhs) { return lhs.width != rhs.width || lhs.height != rhs.height; } std::ostream& operator<<(std::ostream& out, Size const& value); template inline constexpr Size operator*(Scalar scale, Size const& size) { return Size{scale*size.width, scale*size.height}; } template inline constexpr Size operator*(Size const& size, Scalar scale) { return scale*size; } #ifdef MIR_GEOMETRY_DISPLACEMENT_H_ inline constexpr Displacement as_displacement(Size const& size) { return Displacement{size.width.as_int(), size.height.as_int()}; } inline constexpr Size as_size(Displacement const& disp) { return Size{disp.dx.as_int(), disp.dy.as_int()}; } #endif } } #endif /* MIR_GEOMETRY_SIZE_H_ */ ./include/core/mir/geometry/forward.h0000644000004100000410000000171313115234416020057 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_GEOMETRY_FORWARD_H_ #define MIR_GEOMETRY_FORWARD_H_ namespace mir { namespace geometry { // Declarations of geometric concepts I think we'll need struct Point; struct Size; class Displacement; struct Rectangle; class Region; } } #endif /* FORWARD_H_ */ ./include/core/mir/geometry/rectangles.h0000644000004100000410000000366013115234416020545 0ustar www-datawww-data/* * Copyright © 2013-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GEOMETRY_RECTANGLES_H_ #define MIR_GEOMETRY_RECTANGLES_H_ #include "mir/geometry/point.h" #include "mir/geometry/rectangle.h" #include #include namespace mir { namespace geometry { /// A collection of rectangles (with possible duplicates). class Rectangles { public: Rectangles(); Rectangles(std::initializer_list const& rects); /* We want to keep implicit copy and move methods */ void add(Rectangle const& rect); /// removes at most one matching rectangle void remove(Rectangle const& rect); void clear(); Rectangle bounding_rectangle() const; void confine(Point& point) const; typedef std::vector::const_iterator const_iterator; typedef std::vector::size_type size_type; const_iterator begin() const; const_iterator end() const; size_type size() const; bool operator==(Rectangles const& rect) const; bool operator!=(Rectangles const& rect) const; private: std::vector rectangles; Rectangle bounding_rectangle_; // TODO unused: delete on next ABI break }; std::ostream& operator<<(std::ostream& out, Rectangles const& value); } } #endif /* MIR_GEOMETRY_RECTANGLES_H_ */ ./include/core/mir/geometry/displacement.h0000644000004100000410000000643513115234664021076 0ustar www-datawww-data/* * Copyright © 2012, 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GEOMETRY_DISPLACEMENT_H_ #define MIR_GEOMETRY_DISPLACEMENT_H_ #include "mir/geometry/dimensions.h" #include "mir/geometry/point.h" #include namespace mir { namespace geometry { struct Displacement { constexpr Displacement() {} constexpr Displacement(Displacement const&) = default; Displacement& operator=(Displacement const&) = default; template constexpr Displacement(DeltaXType&& dx, DeltaYType&& dy) : dx{dx}, dy{dy} {} long long length_squared() const { long long x = dx.as_int(), y = dy.as_int(); return x * x + y * y; } DeltaX dx; DeltaY dy; }; inline constexpr bool operator==(Displacement const& lhs, Displacement const& rhs) { return lhs.dx == rhs.dx && lhs.dy == rhs.dy; } inline constexpr bool operator!=(Displacement const& lhs, Displacement const& rhs) { return lhs.dx != rhs.dx || lhs.dy != rhs.dy; } std::ostream& operator<<(std::ostream& out, Displacement const& value); inline constexpr Displacement operator+(Displacement const& lhs, Displacement const& rhs) { return Displacement{lhs.dx + rhs.dx, lhs.dy + rhs.dy}; } inline constexpr Displacement operator-(Displacement const& lhs, Displacement const& rhs) { return Displacement{lhs.dx - rhs.dx, lhs.dy - rhs.dy}; } inline constexpr Point operator+(Point const& lhs, Displacement const& rhs) { return Point{lhs.x + rhs.dx, lhs.y + rhs.dy}; } inline constexpr Point operator+(Displacement const& lhs, Point const& rhs) { return Point{rhs.x + lhs.dx, rhs.y + lhs.dy}; } inline constexpr Point operator-(Point const& lhs, Displacement const& rhs) { return Point{lhs.x - rhs.dx, lhs.y - rhs.dy}; } inline constexpr Displacement operator-(Point const& lhs, Point const& rhs) { return Displacement{lhs.x - rhs.x, lhs.y - rhs.y}; } inline bool operator<(Displacement const& lhs, Displacement const& rhs) { return lhs.length_squared() < rhs.length_squared(); } template inline constexpr Displacement operator*(Scalar scale, Displacement const& disp) { return Displacement{scale*disp.dx, scale*disp.dy}; } template inline constexpr Displacement operator*(Displacement const& disp, Scalar scale) { return scale*disp; } #ifdef MIR_GEOMETRY_SIZE_H_ inline constexpr Displacement as_displacement(Size const& size) { return Displacement{size.width.as_int(), size.height.as_int()}; } inline constexpr Size as_size(Displacement const& disp) { return Size{disp.dx.as_int(), disp.dy.as_int()}; } #endif } } #endif /* MIR_GEOMETRY_DISPLACEMENT_H_ */ ./include/core/mir/geometry/rectangle.h0000644000004100000410000000470613115234664020371 0ustar www-datawww-data/* * Copyright © 2012, 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths * Alexandros Frantzis */ #ifndef MIR_GEOMETRY_RECTANGLE_H_ #define MIR_GEOMETRY_RECTANGLE_H_ #include "mir/geometry/point.h" #include "size.h" #include namespace mir { namespace geometry { struct Rectangle { constexpr Rectangle() = default; constexpr Rectangle(Point const& top_left, Size const& size) : top_left{top_left}, size{size} { } Point top_left; Size size; /** * The bottom right boundary point of the rectangle. * * Note that the returned point is *not* included in the rectangle * area, that is, the rectangle is represented as [top_left,bottom_right). */ Point bottom_right() const; Point top_right() const; Point bottom_left() const; bool contains(Point const& p) const; /** * Test if the rectangle contains another. * * Note that an empty rectangle can still contain other empty rectangles, * which are treated as points or lines of thickness zero. */ bool contains(Rectangle const& r) const; bool overlaps(Rectangle const& r) const; Rectangle intersection_with(Rectangle const& r) const; X left() const { return top_left.x; } X right() const { return bottom_right().x; } Y top() const { return top_left.y; } Y bottom() const { return bottom_right().y; } }; inline constexpr bool operator == (Rectangle const& lhs, Rectangle const& rhs) { return lhs.top_left == rhs.top_left && lhs.size == rhs.size; } inline constexpr bool operator != (Rectangle const& lhs, Rectangle const& rhs) { return lhs.top_left != rhs.top_left || lhs.size != rhs.size; } std::ostream& operator<<(std::ostream& out, Rectangle const& value); } } #endif /* MIR_GEOMETRY_RECTANGLE_H_ */ ./include/core/mir/geometry/length.h0000644000004100000410000000472413115234664017706 0ustar www-datawww-data/* * Copyright © 2014. 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_GEOMETRY_LENGTH_H_ #define MIR_GEOMETRY_LENGTH_H_ namespace mir { namespace geometry { /// Length represents a physical length in the real world. The number of pixels /// this equates to can then be calculated based on a given DPI. class Length { public: enum Units { micrometres = 1, millimetres = 1000, centimetres = 10000, inches = 25400 }; constexpr Length() : magnitude(0) {} constexpr Length(Length const&) = default; constexpr Length(float mag, Units units) : magnitude(mag * units) {} Length& operator=(Length const&) = default; constexpr float as(Units units) const { return static_cast(magnitude) / units; } constexpr float as_pixels(float dpi) const { return as(inches) * dpi; } constexpr bool operator==(Length const& rhs) const { return magnitude == rhs.magnitude; } constexpr bool operator!=(Length const& rhs) const { return magnitude != rhs.magnitude; } private: float magnitude; }; inline constexpr Length operator"" _mm(long double mag) { return Length(mag, Length::millimetres); } inline constexpr Length operator"" _mm(unsigned long long mag) { return Length(mag, Length::millimetres); } inline constexpr Length operator"" _cm(long double mag) { return Length(mag, Length::centimetres); } inline constexpr Length operator"" _cm(unsigned long long mag) { return Length(mag, Length::centimetres); } inline constexpr Length operator"" _in(long double mag) { return Length(mag, Length::inches); } inline constexpr Length operator"" _in(unsigned long long mag) { return Length(mag, Length::inches); } } // namespace geometry } // namespace mir #endif // MIR_GEOMETRY_LENGTH_H_ ./include/core/mir/geometry/dimensions.h0000644000004100000410000001446513115234664020600 0ustar www-datawww-data/* * Copyright © 2012, 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_GEOMETRY_DIMENSIONS_H_ #define MIR_GEOMETRY_DIMENSIONS_H_ #include #include namespace mir { /// Basic geometry types. Types for dimensions, displacements, etc. /// and the operations that they support. namespace geometry { namespace detail { template class IntWrapper { public: typedef int ValueType; constexpr IntWrapper() : value(0) {} constexpr IntWrapper(IntWrapper const& that) = default; IntWrapper& operator=(IntWrapper const& that) = default; template explicit constexpr IntWrapper(AnyInteger value) : value(static_cast(value)) {} constexpr uint32_t as_uint32_t() const // TODO: Deprecate this later { return (uint32_t)value; } constexpr int as_int() const { return value; } private: ValueType value; }; template std::ostream& operator<<(std::ostream& out, IntWrapper const& value) { out << value.as_int(); return out; } template inline constexpr bool operator == (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_int() == rhs.as_int(); } template inline constexpr bool operator != (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_int() != rhs.as_int(); } template inline constexpr bool operator <= (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_int() <= rhs.as_int(); } template inline constexpr bool operator >= (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_int() >= rhs.as_int(); } template inline constexpr bool operator < (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_int() < rhs.as_int(); } template inline constexpr bool operator > (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_int() > rhs.as_int(); } } // namespace detail typedef detail::IntWrapper Width; typedef detail::IntWrapper Height; // Just to be clear, mir::geometry::Stride is the stride of the buffer in bytes typedef detail::IntWrapper Stride; typedef detail::IntWrapper X; typedef detail::IntWrapper Y; typedef detail::IntWrapper DeltaX; typedef detail::IntWrapper DeltaY; // Adding deltas is fine inline constexpr DeltaX operator+(DeltaX lhs, DeltaX rhs) { return DeltaX(lhs.as_int() + rhs.as_int()); } inline constexpr DeltaY operator+(DeltaY lhs, DeltaY rhs) { return DeltaY(lhs.as_int() + rhs.as_int()); } inline constexpr DeltaX operator-(DeltaX lhs, DeltaX rhs) { return DeltaX(lhs.as_int() - rhs.as_int()); } inline constexpr DeltaY operator-(DeltaY lhs, DeltaY rhs) { return DeltaY(lhs.as_int() - rhs.as_int()); } // Adding deltas to co-ordinates is fine inline constexpr X operator+(X lhs, DeltaX rhs) { return X(lhs.as_int() + rhs.as_int()); } inline constexpr Y operator+(Y lhs, DeltaY rhs) { return Y(lhs.as_int() + rhs.as_int()); } inline constexpr X operator-(X lhs, DeltaX rhs) { return X(lhs.as_int() - rhs.as_int()); } inline constexpr Y operator-(Y lhs, DeltaY rhs) { return Y(lhs.as_int() - rhs.as_int()); } inline X& operator+=(X& lhs, DeltaX rhs) { return lhs = X(lhs.as_int() + rhs.as_int()); } inline Y& operator+=(Y& lhs, DeltaY rhs) { return lhs = Y(lhs.as_int() + rhs.as_int()); } inline X& operator-=(X& lhs, DeltaX rhs) { return lhs = X(lhs.as_int() - rhs.as_int()); } inline Y& operator-=(Y& lhs, DeltaY rhs) { return lhs = Y(lhs.as_int() - rhs.as_int()); } // Adding deltas to Width and Height is fine inline constexpr Width operator+(Width lhs, DeltaX rhs) { return Width(lhs.as_int() + rhs.as_int()); } inline constexpr Height operator+(Height lhs, DeltaY rhs) { return Height(lhs.as_int() + rhs.as_int()); } inline constexpr Width operator-(Width lhs, DeltaX rhs) { return Width(lhs.as_int() - rhs.as_int()); } inline constexpr Height operator-(Height lhs, DeltaY rhs) { return Height(lhs.as_int() - rhs.as_int()); } // Subtracting coordinates is fine inline constexpr DeltaX operator-(X lhs, X rhs) { return DeltaX(lhs.as_int() - rhs.as_int()); } inline constexpr DeltaY operator-(Y lhs, Y rhs) { return DeltaY(lhs.as_int() - rhs.as_int()); } //Subtracting Width and Height is fine inline constexpr DeltaX operator-(Width lhs, Width rhs) { return DeltaX(lhs.as_int() - rhs.as_int()); } inline constexpr DeltaY operator-(Height lhs, Height rhs) { return DeltaY(lhs.as_int() - rhs.as_int()); } // Multiplying by a scalar value is fine template inline constexpr Width operator*(Scalar scale, Width const& w) { return Width{scale*w.as_int()}; } template inline constexpr Height operator*(Scalar scale, Height const& h) { return Height{scale*h.as_int()}; } template inline constexpr DeltaX operator*(Scalar scale, DeltaX const& dx) { return DeltaX{scale*dx.as_int()}; } template inline constexpr DeltaY operator*(Scalar scale, DeltaY const& dy) { return DeltaY{scale*dy.as_int()}; } template inline constexpr Width operator*(Width const& w, Scalar scale) { return scale*w; } template inline constexpr Height operator*(Height const& h, Scalar scale) { return scale*h; } template inline constexpr DeltaX operator*(DeltaX const& dx, Scalar scale) { return scale*dx; } template inline constexpr DeltaY operator*(DeltaY const& dy, Scalar scale) { return scale*dy; } template inline constexpr Target dim_cast(Source s) { return Target(s.as_int()); } } } #endif /* MIR_GEOMETRY_DIMENSIONS_H_ */ ./include/core/mir/geometry/point.h0000644000004100000410000000415413115234664017553 0ustar www-datawww-data/* * Copyright © 2012, 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GEOMETRY_POINT_H_ #define MIR_GEOMETRY_POINT_H_ #include "dimensions.h" #include namespace mir { namespace geometry { struct Point { constexpr Point() = default; constexpr Point(Point const&) = default; Point& operator=(Point const&) = default; template constexpr Point(XType&& x, YType&& y) : x(x), y(y) {} X x; Y y; }; inline constexpr bool operator == (Point const& lhs, Point const& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } inline constexpr bool operator != (Point const& lhs, Point const& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } inline constexpr Point operator+(Point lhs, DeltaX rhs) { return{lhs.x + rhs, lhs.y}; } inline constexpr Point operator+(Point lhs, DeltaY rhs) { return{lhs.x, lhs.y + rhs}; } inline constexpr Point operator-(Point lhs, DeltaX rhs) { return{lhs.x - rhs, lhs.y}; } inline constexpr Point operator-(Point lhs, DeltaY rhs) { return{lhs.x, lhs.y - rhs}; } inline Point& operator+=(Point& lhs, DeltaX rhs) { lhs.x += rhs; return lhs; } inline Point& operator+=(Point& lhs, DeltaY rhs) { lhs.y += rhs; return lhs; } inline Point& operator-=(Point& lhs, DeltaX rhs) { lhs.x -= rhs; return lhs; } inline Point& operator-=(Point& lhs, DeltaY rhs) { lhs.y -= rhs; return lhs; } std::ostream& operator<<(std::ostream& out, Point const& value); } } #endif /* MIR_GEOMETRY_POINT_H_ */ ./include/core/mir_toolkit/0000755000004100000410000000000013115234665016160 5ustar www-datawww-data./include/core/mir_toolkit/deprecations.h0000644000004100000410000000240513115234664021011 0ustar www-datawww-data/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef MIR_DEPRECATIONS_H_ #define MIR_DEPRECATIONS_H_ #ifndef MIR_ENABLE_DEPRECATIONS // use g++ version < 6.2 as a proxy for building on Ubunutu 16.04LTS ("Xenial") or 16.10 (Yakkety) #if defined(__clang__) || !defined(__GNUC__) || (__GNUC__ > 6) || ((__GNUC__ == 6) && (__GNUC_MINOR__ >= 2)) #define MIR_ENABLE_DEPRECATIONS 1 #else #define MIR_ENABLE_DEPRECATIONS 0 #endif #endif #if MIR_ENABLE_DEPRECATIONS > 0 #define MIR_FOR_REMOVAL_IN_VERSION_1(message)\ __attribute__((deprecated(message))) #else #define MIR_FOR_REMOVAL_IN_VERSION_1(message) #endif #endif //MIR_DEPRECATIONS_H_ ./include/core/mir_toolkit/mir_native_buffer.h0000644000004100000410000000345613115234664022026 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #ifndef MIR_CLIENT_MIR_NATIVE_BUFFER_H_ #define MIR_CLIENT_MIR_NATIVE_BUFFER_H_ enum { mir_buffer_package_max = 30 }; typedef enum { mir_buffer_flag_can_scanout = 1, mir_buffer_flag_fenced = 1 << 1 } MirBufferFlag; typedef struct MirBufferPackage { int data_items; int fd_items; int data[mir_buffer_package_max]; int width; /* These must come after data[] to keep ABI compatibility */ int height; int fd[mir_buffer_package_max]; int unused0; /* Retain ABI compatibility (avoid rebuilding Mesa) */ unsigned int flags; /* MirBufferFlag's */ int stride; int age; /**< Number of frames submitted by the client since the client has rendered to this buffer. */ /**< This has the same semantics as the EGL_EXT_buffer_age extension */ /**< \see http://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_buffer_age.txt */ } MirBufferPackage; #ifdef ANDROID struct ANativeWindowBuffer; typedef struct ANativeWindowBuffer MirNativeBuffer; #else typedef struct MirBufferPackage MirNativeBuffer; #endif #endif /* MIR_CLIENT_MIR_NATIVE_BUFFER_H_ */ ./include/core/mir_toolkit/mir_input_device_types.h0000644000004100000410000001100413115234664023075 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_INPUT_DEVICE_TYPES_H_ #define MIR_TOOLKIT_MIR_INPUT_DEVICE_TYPES_H_ #include /** * \addtogroup mir_toolkit * @{ */ #ifdef __cplusplus extern "C" { #endif typedef int64_t MirInputDeviceId; typedef enum MirPointerHandedness { mir_pointer_handedness_right = 0, mir_pointer_handedness_left = 1 } MirPointerHandedness; /** * MirPointerAcceleration describes the way pointer movement is filtered: * - mir_pointer_acceleration_none: (acceleration bias + 1.0) is applied as * a factor to the current velocity of the pointer. So a bias of 0 to results * to no change of velocity. * - mir_pointer_acceleration_adaptive: acceleration bias selects an * acceleration function based on the current velocity that usually consists * of two linear inclines separated by a plateau. */ typedef enum MirPointerAcceleration { mir_pointer_acceleration_none = 1, mir_pointer_acceleration_adaptive = 2 } MirPointerAcceleration; /** * MirTouchpadClickMode configures how the touchpad itself should generate * pointer button events. The available click modes may be active * simultaneously. * - mir_touchpad_click_mode_none: no active click mode * - mir_touchpad_click_mode_area_to_click: simulate pointer buttons using * click areas on the touchpad * - mir_touchpad_click_mode_finger_count: simulate pointer buttons using the * number of fingers down */ typedef enum MirTouchpadClickMode { mir_touchpad_click_mode_none = 0, mir_touchpad_click_mode_area_to_click = 1 << 0, mir_touchpad_click_mode_finger_count = 1 << 1 } MirTouchpadClickMode; typedef unsigned int MirTouchpadClickModes; /** * MirTouchpadScrollMode configures how the touchpad should generate scroll * events. * - mir_touchpad_scroll_mode_none: no scroll * - mir_touchpad_scroll_mode_two_finger_scroll: two finger movement generates * generates vertical and horizontal scroll events * - mir_touchpad_scroll_mode_edge_scroll: touch movement at the edge of the * touchpad genertes scroll events * - mir_touchpad_scroll_mode_button_down_scroll: movement on the touchpad * generates scroll events when a button is held down simultaneously */ typedef enum MirTouchpadScrollMode { mir_touchpad_scroll_mode_none = 0, mir_touchpad_scroll_mode_two_finger_scroll = 1 << 0, mir_touchpad_scroll_mode_edge_scroll = 1 << 1, mir_touchpad_scroll_mode_button_down_scroll = 1 << 2 } MirTouchpadScrollMode; typedef unsigned int MirTouchpadScrollModes; enum MirInputDeviceCapability { mir_input_device_capability_none = 0, mir_input_device_capability_pointer = 1<<1, mir_input_device_capability_keyboard = 1<<2, mir_input_device_capability_touchpad = 1<<3, mir_input_device_capability_touchscreen = 1<<4, mir_input_device_capability_gamepad = 1<<5, mir_input_device_capability_joystick = 1<<6, mir_input_device_capability_switch = 1<<7, mir_input_device_capability_multitouch = 1<<8, //! capable to detect multiple contacts mir_input_device_capability_alpha_numeric = 1<<9 //! offers enough keys for text entry }; typedef unsigned int MirInputDeviceCapabilities; /** * Mapping modes for touchscreen devices. The mode defines how coordinates * from the touchscreen frequently referred to as device coordinates are * translated into scene coordinates. * * This configuration mode is relevant for different classes of input devices, * i.e handheld devices with builtin touchscreens or external graphic tablets or * external monitors with touchscreen capabilities. */ enum MirTouchscreenMappingMode { /** * Map the device coordinates onto specific output. */ mir_touchscreen_mapping_mode_to_output, /** * Map the device coordinates onto the whole wall of outputs. */ mir_touchscreen_mapping_mode_to_display_wall }; #ifdef __cplusplus } #endif /**@}*/ #endif ./include/core/mir_toolkit/mir_version_number.h0000644000004100000410000000255513115234664022243 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_VERSION_NUMBER_H_ #define MIR_VERSION_NUMBER_H_ /** * MIR_VERSION_NUMBER * \param major [in] The major version (eg: 3 for version 3.2.33) * \param minor [in] The minor version (eg: 2 for version 3.2.33) * \param micro [in] The micro version (eg: 33 for version 3.2.33) * * Returns the combined version information as a single 32-bit value for * logical comparisons. For example: * \#if MIR_CLIENT_VERSION >= MIR_VERSION_NUMBER(2,3,4) * * This can be useful to conditionally build code depending on new features or * specific bugfixes in the Mir client library. */ #define MIR_VERSION_NUMBER(major,minor,micro) \ (((major) << 22) + ((minor) << 12) + (micro)) #endif /* MIR_VERSION_NUMBER_H_ */ ./include/core/mir_toolkit/common.h0000644000004100000410000004141413115234664017624 0ustar www-datawww-data/* * Simple definitions common to client and server. * * Copyright © 2013-2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Daniel van Vugt */ #ifndef MIR_COMMON_H_ #define MIR_COMMON_H_ #include //for clang #ifndef __has_feature #define __has_feature(x) 0 // Compatibility with non-clang #endif //for clang #ifndef __has_extension #define __has_extension __has_feature // Compatibility with pre-3.0 #endif #if __GNUC__ >= 6 || \ (__has_extension(attribute_deprecated_with_message) && \ __has_extension(enumerator_attributes)) #define MIR_DEPRECATED_ENUM(ENUM, INSTEAD) \ ENUM MIR_FOR_REMOVAL_IN_VERSION_1("Use " #INSTEAD " instead") #else #define MIR_DEPRECATED_ENUM(ENUM, INSTEAD) \ ENUM #endif /** * \addtogroup mir_toolkit * @{ */ /* This is C code. Not C++. */ /** * Attributes of a surface that the client and server/shell may wish to * get or set over the wire. */ typedef enum MirSurfaceAttrib { /* Do not specify values...code relies on 0...N ordering. */ mir_surface_attrib_type, mir_surface_attrib_state, mir_surface_attrib_swapinterval, /**< \deprecated Do not listen for events reporting this attribute. Use the "mir_*_get_swapinterval()" functions instead if you wish query its value */ mir_surface_attrib_focus, mir_surface_attrib_dpi, mir_surface_attrib_visibility, mir_surface_attrib_preferred_orientation, /* Must be last */ mir_surface_attribs } MirSurfaceAttrib MIR_FOR_REMOVAL_IN_VERSION_1("use MirWindowAttrib"); /** * Attributes of a window that the client and server/shell may wish to * get or set over the wire. */ typedef enum MirWindowAttrib { /* Do not specify values...code relies on 0...N ordering. */ mir_window_attrib_type, mir_window_attrib_state, mir_window_attrib_swapinterval, /**< \deprecated Do not listen for events reporting this attribute. Use the "mir_*_get_swapinterval()" functions instead if you wish query its value */ mir_window_attrib_focus, mir_window_attrib_dpi, mir_window_attrib_visibility, mir_window_attrib_preferred_orientation, /* Must be last */ mir_window_attribs } MirWindowAttrib; typedef enum MirSurfaceType { mir_surface_type_normal, /**< AKA "regular" */ mir_surface_type_utility, /**< AKA "floating" */ mir_surface_type_dialog, mir_surface_type_overlay, /**< \deprecated Use "gloss" instead. */ mir_surface_type_gloss = mir_surface_type_overlay, mir_surface_type_freestyle, mir_surface_type_popover, /**< \deprecated Choose "menu" or "tip" */ mir_surface_type_menu = mir_surface_type_popover, mir_surface_type_inputmethod, /**< AKA "OSK" or handwriting etc. */ mir_surface_type_satellite, /**< AKA "toolbox"/"toolbar" */ mir_surface_type_tip, /**< AKA "tooltip" */ mir_surface_types } MirSurfaceType MIR_FOR_REMOVAL_IN_VERSION_1("use MirWindowType"); typedef enum MirWindowType { mir_window_type_normal, /**< AKA "regular" */ mir_window_type_utility, /**< AKA "floating" */ mir_window_type_dialog, mir_window_type_gloss, mir_window_type_freestyle, mir_window_type_menu, mir_window_type_inputmethod, /**< AKA "OSK" or handwriting etc. */ mir_window_type_satellite, /**< AKA "toolbox"/"toolbar" */ mir_window_type_tip, /**< AKA "tooltip" */ mir_window_types } MirWindowType; typedef enum MirSurfaceState { mir_surface_state_unknown, mir_surface_state_restored, mir_surface_state_minimized, mir_surface_state_maximized, mir_surface_state_vertmaximized, /* mir_surface_state_semimaximized, Omitted for now, since it's functionally a subset of vertmaximized and differs only in the X coordinate. */ mir_surface_state_fullscreen, mir_surface_state_horizmaximized, mir_surface_state_hidden, mir_surface_states } MirSurfaceState MIR_FOR_REMOVAL_IN_VERSION_1("use MirWindowState"); typedef enum MirWindowState { mir_window_state_unknown, mir_window_state_restored, mir_window_state_minimized, mir_window_state_maximized, mir_window_state_vertmaximized, /* mir_window_state_semimaximized, Omitted for now, since it's functionally a subset of vertmaximized and differs only in the X coordinate. */ mir_window_state_fullscreen, mir_window_state_horizmaximized, mir_window_state_hidden, mir_window_states } MirWindowState; typedef enum MirSurfaceFocusState { mir_surface_unfocused = 0, mir_surface_focused } MirSurfaceFocusState MIR_FOR_REMOVAL_IN_VERSION_1("use MirWindowFocusState"); typedef enum MirWindowFocusState { mir_window_focus_state_unfocused = 0, mir_window_focus_state_focused } MirWindowFocusState; typedef enum MirSurfaceVisibility { mir_surface_visibility_occluded = 0, mir_surface_visibility_exposed } MirSurfaceVisibility MIR_FOR_REMOVAL_IN_VERSION_1("use MirWindowFocusState"); typedef enum MirWindowVisibility { mir_window_visibility_occluded = 0, mir_window_visibility_exposed } MirWindowVisibility; typedef enum MirLifecycleState { mir_lifecycle_state_will_suspend, mir_lifecycle_state_resumed, mir_lifecycle_connection_lost } MirLifecycleState; typedef enum MirPowerMode { mir_power_mode_on, /* Display in use. */ mir_power_mode_standby, /* Blanked, low power. */ mir_power_mode_suspend, /* Blanked, lowest power. */ mir_power_mode_off /* Powered down. */ } MirPowerMode; typedef enum MirOutputType { mir_output_type_unknown = 0, /* DRM_MODE_CONNECTOR_Unknown */ mir_output_type_vga = 1, /* DRM_MODE_CONNECTOR_VGA */ mir_output_type_dvii = 2, /* DRM_MODE_CONNECTOR_DVII */ mir_output_type_dvid = 3, /* DRM_MODE_CONNECTOR_DVID */ mir_output_type_dvia = 4, /* DRM_MODE_CONNECTOR_DVIA */ mir_output_type_composite = 5, /* DRM_MODE_CONNECTOR_Composite */ mir_output_type_svideo = 6, /* DRM_MODE_CONNECTOR_SVIDEO */ mir_output_type_lvds = 7, /* DRM_MODE_CONNECTOR_LVDS */ mir_output_type_component = 8, /* DRM_MODE_CONNECTOR_Component */ mir_output_type_ninepindin = 9, /* DRM_MODE_CONNECTOR_9PinDIN */ mir_output_type_displayport = 10, /* DRM_MODE_CONNECTOR_DisplayPort */ mir_output_type_hdmia = 11, /* DRM_MODE_CONNECTOR_HDMIA */ mir_output_type_hdmib = 12, /* DRM_MODE_CONNECTOR_HDMIB */ mir_output_type_tv = 13, /* DRM_MODE_CONNECTOR_TV */ mir_output_type_edp = 14, /* DRM_MODE_CONNECTOR_eDP */ mir_output_type_virtual = 15, /* DRM_MODE_CONNECTOR_VIRTUAL */ mir_output_type_dsi = 16, /* DRM_MODE_CONNECTOR_DSI */ mir_output_type_dpi = 17, /* DRM_MODE_CONNECTOR_DPI */ } MirOutputType; typedef enum MirPromptSessionState { mir_prompt_session_state_stopped = 0, mir_prompt_session_state_started, mir_prompt_session_state_suspended } MirPromptSessionState; /** * 32-bit pixel formats (8888): * The order of components in the enum matches the order of the components * as they would be written in an integer representing a pixel value of that * format. For example; abgr_8888 should be coded as 0xAABBGGRR, which will * end up as R,G,B,A in memory on a little endian system, and as A,B,G,R on a * big endian system. * * 24-bit pixel formats (888): * These are in literal byte order, regardless of CPU architecture it's always * the same. Writing these 3-byte pixels is typically slower than other formats * but uses less memory than 32-bit and is endian-independent. * * 16-bit pixel formats (565/5551/4444): * Always interpreted as one 16-bit integer per pixel with components in * high-to-low bit order following the format name. These are the fastest * formats, however colour quality is visibly lower. */ typedef enum MirPixelFormat { mir_pixel_format_invalid = 0, mir_pixel_format_abgr_8888 = 1, mir_pixel_format_xbgr_8888 = 2, mir_pixel_format_argb_8888 = 3, mir_pixel_format_xrgb_8888 = 4, mir_pixel_format_bgr_888 = 5, mir_pixel_format_rgb_888 = 6, mir_pixel_format_rgb_565 = 7, mir_pixel_format_rgba_5551 = 8, mir_pixel_format_rgba_4444 = 9, /* * TODO: Big endian support would require additional formats in order to * composite software surfaces using OpenGL (GL_RGBA/GL_BGRA_EXT): * mir_pixel_format_rgb[ax]_8888 * mir_pixel_format_bgr[ax]_8888 */ mir_pixel_formats /* Note: This is always max format + 1 */ } MirPixelFormat; /* This could be improved... https://bugs.launchpad.net/mir/+bug/1236254 */ #define MIR_BYTES_PER_PIXEL(f) ((f) == mir_pixel_format_bgr_888 ? 3 : \ (f) == mir_pixel_format_rgb_888 ? 3 : \ (f) == mir_pixel_format_rgb_565 ? 2 : \ (f) == mir_pixel_format_rgba_5551 ? 2 : \ (f) == mir_pixel_format_rgba_4444 ? 2 : \ 4) /** Direction relative to the "natural" orientation of the display */ typedef enum MirOrientation { mir_orientation_normal = 0, mir_orientation_left = 90, mir_orientation_inverted = 180, mir_orientation_right = 270 } MirOrientation; /** Mirroring axis relative to the "natural" orientation of the display */ typedef enum MirMirrorMode { mir_mirror_mode_none, mir_mirror_mode_vertical, mir_mirror_mode_horizontal } MirMirrorMode; typedef enum MirOrientationMode { mir_orientation_mode_portrait = 1 << 0, mir_orientation_mode_landscape = 1 << 1, mir_orientation_mode_portrait_inverted = 1 << 2, mir_orientation_mode_landscape_inverted = 1 << 3, mir_orientation_mode_portrait_any = mir_orientation_mode_portrait | mir_orientation_mode_portrait_inverted, mir_orientation_mode_landscape_any = mir_orientation_mode_landscape | mir_orientation_mode_landscape_inverted, mir_orientation_mode_any = mir_orientation_mode_portrait_any | mir_orientation_mode_landscape_any } MirOrientationMode; typedef enum MirEdgeAttachment { mir_edge_attachment_vertical = 1 << 0, mir_edge_attachment_horizontal = 1 << 1, mir_edge_attachment_any = mir_edge_attachment_vertical | mir_edge_attachment_horizontal } MirEdgeAttachment; // Inspired by GdkGravity /** * Reference point for aligning a surface relative to a rectangle. * Each element (surface and rectangle) has a MirPlacementGravity assigned. */ typedef enum MirPlacementGravity { /// the reference point is at the center. mir_placement_gravity_center = 0, /// the reference point is at the middle of the left edge. mir_placement_gravity_west = 1 << 0, /// the reference point is at the middle of the right edge. mir_placement_gravity_east = 1 << 1, /// the reference point is in the middle of the top edge. mir_placement_gravity_north = 1 << 2, /// the reference point is at the middle of the lower edge. mir_placement_gravity_south = 1 << 3, /// the reference point is at the top left corner. mir_placement_gravity_northwest = mir_placement_gravity_north | mir_placement_gravity_west, /// the reference point is at the top right corner. mir_placement_gravity_northeast = mir_placement_gravity_north | mir_placement_gravity_east, /// the reference point is at the lower left corner. mir_placement_gravity_southwest = mir_placement_gravity_south | mir_placement_gravity_west, /// the reference point is at the lower right corner. mir_placement_gravity_southeast = mir_placement_gravity_south | mir_placement_gravity_east } MirPlacementGravity; // Inspired by GdkAnchorHints /** * Positioning hints for aligning a window relative to a rectangle. * * These hints determine how the window should be positioned in the case that * the surface would fall off-screen if placed in its ideal position. * * For example, \p mir_placement_hints_flip_x will invert the x component of * \p aux_rect_placement_offset and replace \p mir_placement_gravity_northwest * with \p mir_placement_gravity_northeast and vice versa if the window extends * beyond the left or right edges of the monitor. * * If \p mir_placement_hints_slide_x is set, the window can be shifted * horizontally to fit on-screen. * * If \p mir_placement_hints_resize_x is set, the window can be shrunken * horizontally to fit. * * If \p mir_placement_hints_antipodes is set then the rect gravity may be * substituted with the opposite corner (e.g. \p mir_placement_gravity_northeast * to \p mir_placement_gravity_southwest) in combination with other options. * * When multiple flags are set, flipping should take precedence over sliding, * which should take precedence over resizing. */ typedef enum MirPlacementHints { /// allow flipping anchors horizontally mir_placement_hints_flip_x = 1 << 0, /// allow flipping anchors vertically mir_placement_hints_flip_y = 1 << 1, /// allow sliding window horizontally mir_placement_hints_slide_x = 1 << 2, /// allow sliding window vertically mir_placement_hints_slide_y = 1 << 3, /// allow resizing window horizontally mir_placement_hints_resize_x = 1 << 4, /// allow resizing window vertically mir_placement_hints_resize_y = 1 << 5, /// allow flipping aux_anchor to opposite corner mir_placement_hints_antipodes= 1 << 6, /// allow flipping anchors on both axes mir_placement_hints_flip_any = mir_placement_hints_flip_x|mir_placement_hints_flip_y, /// allow sliding window on both axes mir_placement_hints_slide_any = mir_placement_hints_slide_x|mir_placement_hints_slide_y, /// allow resizing window on both axes mir_placement_hints_resize_any = mir_placement_hints_resize_x|mir_placement_hints_resize_y, } MirPlacementHints; /** * Form factor associated with a physical output */ typedef enum MirFormFactor { mir_form_factor_unknown, mir_form_factor_phone, mir_form_factor_tablet, mir_form_factor_monitor, mir_form_factor_tv, mir_form_factor_projector, } MirFormFactor; /** * Physical arrangement of subpixels on the physical output * * This is always relative to the “natural” orientation of the display - mir_orientation_normal. */ typedef enum MirSubpixelArrangement { mir_subpixel_arrangement_unknown, /**< Arrangement of subpixels cannot be determined */ mir_subpixel_arrangement_horizontal_rgb, /**< Subpixels are arranged horizontally, R, G, B from left to right */ mir_subpixel_arrangement_horizontal_bgr, /**< Subpixels are arranged horizontally, B, G, R from left to right */ mir_subpixel_arrangement_vertical_rgb, /**< Subpixels are arranged vertically, R, G, B from top to bottom */ mir_subpixel_arrangement_vertical_bgr, /**< Subpixels are arranged vertically, B, G, R from top to bottom */ mir_subpixel_arrangement_none /**< Device does not have regular subpixels */ } MirSubpixelArrangement; /** * Shell chrome */ typedef enum MirShellChrome { mir_shell_chrome_normal, mir_shell_chrome_low, } MirShellChrome; /** * Pointer Confinement */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" typedef enum MirPointerConfinementState { mir_pointer_unconfined, MIR_DEPRECATED_ENUM(mir_pointer_confined_to_surface, "mir_pointer_confined_to_window"), mir_pointer_confined_to_window = mir_pointer_confined_to_surface, } MirPointerConfinementState; #pragma GCC diagnostic pop /** * Supports gamma correction */ typedef enum MirOutputGammaSupported { mir_output_gamma_unsupported, mir_output_gamma_supported } MirOutputGammaSupported; /**@}*/ #endif ./include/cookie/0000755000004100000410000000000013115234413014134 5ustar www-datawww-data./include/cookie/mir/0000755000004100000410000000000013115234413014723 5ustar www-datawww-data./include/cookie/mir/cookie/0000755000004100000410000000000013115234677016210 5ustar www-datawww-data./include/cookie/mir/cookie/authority.h0000644000004100000410000000745713115234664020422 0ustar www-datawww-data/* * Copyright © 2015-2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers * Brandon Schaefer */ #ifndef MIR_COOKIE_AUTHORITY_H_ #define MIR_COOKIE_AUTHORITY_H_ #include #include #include #include "mir/cookie/cookie.h" namespace mir { namespace cookie { using Secret = std::vector; struct SecurityCheckError : std::runtime_error { SecurityCheckError(); }; /** * \brief A source of moderately-difficult-to-spoof cookies. * * The primary motivation for this is to provide event timestamps that clients find it difficult to spoof. * This is useful for focus grant and similar operations where shell behaviour should be dependent on * the timestamp of the client event that caused the request. * * Some spoofing protection is desirable; experience with X clients shows that they will go to some effort * to attempt to bypass focus stealing prevention. * */ class Authority { public: /** * Optimal size for the provided Secret. * * This is the maximum useful size of the secret key. Keys of greater size * will be reduced to this size internally, and keys of smaller size may be * internally extended to this size. */ static size_t optimal_secret_size(); /** * Construction function used to create an Authority. The secret size must be * no less then minimum_secret_size otherwise an exception will be thrown * * \param [in] secret A secret used to set the key for the hash function * \return An Authority */ static std::unique_ptr create_from(Secret const& secret); /** * Construction function used to create an Authority as well as a secret. * * \param [out] save_secret The secret that was created. * \return An Authority */ static std::unique_ptr create_saving(Secret& save_secret); /** * Construction function used to create an Authority and a secret which it keeps internally. * * \return An Authority */ static std::unique_ptr create(); Authority(Authority const& authority) = delete; Authority& operator=(Authority const& authority) = delete; virtual ~Authority() noexcept = default; /** * Creates a cookie from a timestamp. * * \param [in] timestamp A timestamp * \return A cookie instance */ virtual std::unique_ptr make_cookie(uint64_t const& timestamp) = 0; /** * Creates a cookie from a serialized representation * * \param [in] raw_cookie A blob of bytes representing a serialized cookie * \return A cookie instance */ virtual std::unique_ptr make_cookie(std::vector const& raw_cookie) = 0; /** * Absolute minimum size of secret key the Authority will accept. * * Code should be using optimum_secret_size(); this minimum size is provided * as a user convenience to guard against catastrophically bad initialisation. */ static unsigned const minimum_secret_size = 8; protected: Authority() = default; }; } } #endif // MIR_COOKIE_COOKIE_AUTHORITY_H_ ./include/cookie/mir/cookie/cookie.h0000644000004100000410000000254313115234416017625 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Brandon Schaefer */ #ifndef MIR_COOKIE_COOKIE_H_ #define MIR_COOKIE_COOKIE_H_ #include #include namespace mir { namespace cookie { class Cookie { public: Cookie() = default; virtual ~Cookie() = default; Cookie(Cookie const& cookie) = delete; Cookie& operator=(Cookie const& cookie) = delete; /** * Returns the timestamp that the cookie is built with * * \return The timestamp */ virtual uint64_t timestamp() const = 0; /** * Converts the cookie into a stream of bytes. * * \return The stream of bytes formatted */ virtual std::vector serialize() const = 0; }; } } #endif // MIR_COOKIE_COOKIE_H_ ./include/renderers/0000755000004100000410000000000013115234677014670 5ustar www-datawww-data./include/renderers/gl/0000755000004100000410000000000013115234413015256 5ustar www-datawww-data./include/renderers/gl/mir/0000755000004100000410000000000013115234413016045 5ustar www-datawww-data./include/renderers/gl/mir/renderer/0000755000004100000410000000000013115234413017653 5ustar www-datawww-data./include/renderers/gl/mir/renderer/gl/0000755000004100000410000000000013115234677020271 5ustar www-datawww-data./include/renderers/gl/mir/renderer/gl/context_source.h0000644000004100000410000000226213115234664023504 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_RENDERER_GL_CONTEXT_SOURCE_H_ #define MIR_RENDERER_GL_CONTEXT_SOURCE_H_ #include namespace mir { namespace renderer { namespace gl { class Context; class ContextSource { public: virtual ~ContextSource() = default; virtual std::unique_ptr create_gl_context() = 0; protected: ContextSource() = default; ContextSource(ContextSource const&) = delete; ContextSource& operator=(ContextSource const&) = delete; }; } } } #endif ./include/renderers/gl/mir/renderer/gl/texture_source.h0000644000004100000410000000325713115234416023520 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_RENDERER_GL_TEXTURE_SOURCE_H_ #define MIR_RENDERER_GL_TEXTURE_SOURCE_H_ namespace mir { namespace renderer { namespace gl { //FIXME: (kdub) we're not hiding the differences in texture upload approaches between our platforms // very well with this interface. class TextureSource { public: virtual ~TextureSource() = default; // \warning deprecated, provided for convenience and legacy transition. //will call bind() and then secure_for_render() virtual void gl_bind_to_texture() = 0; //Uploads texture. virtual void bind() = 0; //add synchronization points to the command stream to ensure resources //are present during the draw. Will not upload texture. //should be called if an already uploaded texture is reused. virtual void secure_for_render() = 0; protected: TextureSource() = default; TextureSource(TextureSource const&) = delete; TextureSource& operator=(TextureSource const&) = delete; }; } } } #endif ./include/renderers/gl/mir/renderer/gl/context.h0000644000004100000410000000222413115234664022122 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_RENDERER_GL_CONTEXT_H_ #define MIR_RENDERER_GL_CONTEXT_H_ namespace mir { namespace renderer { namespace gl { class Context { public: virtual ~Context() = default; virtual void make_current() const = 0; virtual void release_current() const = 0; protected: Context() = default; Context(Context const&) = delete; Context& operator=(Context const&) = delete; }; } } } #endif /* MIR_RENDERER_GL_CONTEXT_H_ */ ./include/renderers/gl/mir/renderer/gl/render_target.h0000644000004100000410000000316113115234664023264 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_RENDERER_GL_RENDER_TARGET_H_ #define MIR_RENDERER_GL_RENDER_TARGET_H_ namespace mir { namespace renderer { namespace gl { class RenderTarget { public: virtual ~RenderTarget() = default; /** Makes GL render target current to calling thread */ virtual void make_current() = 0; /** Releases the current GL render target. */ virtual void release_current() = 0; /** * Swap buffers for OpenGL rendering. * After this method returns is the earliest time that it is safe to * free GL-related resources such as textures and buffers. */ virtual void swap_buffers() = 0; /** Binds any necessary resources (fbos, textures if any) * in preparation for drawing. */ virtual void bind() = 0; protected: RenderTarget() = default; RenderTarget(RenderTarget const&) = delete; RenderTarget& operator=(RenderTarget const&) = delete; }; } } } #endif ./include/renderers/sw/0000755000004100000410000000000013115234665015316 5ustar www-datawww-data./include/renderers/sw/mir/0000755000004100000410000000000013115234665016105 5ustar www-datawww-data./include/renderers/sw/mir/renderer/0000755000004100000410000000000013115234665017713 5ustar www-datawww-data./include/renderers/sw/mir/renderer/sw/0000755000004100000410000000000013115234665020344 5ustar www-datawww-data./include/renderers/sw/mir/renderer/sw/pixel_source.h0000644000004100000410000000337713115234664023227 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_RENDERER_SW_PIXEL_SOURCE_H_ #define MIR_RENDERER_SW_PIXEL_SOURCE_H_ #include #include #include "mir/geometry/dimensions.h" namespace mir { namespace renderer { namespace software { class PixelSource { public: virtual ~PixelSource() = default; //functions have legacy issues with their signatures. //FIXME: correct write, it requires that the user does too much to use it correctly, // (ie, it forces them to figure out what size is proper, alloc a buffer, fill it, and then // copy the data into the buffer) virtual void write(unsigned char const* pixels, size_t size) = 0; //FIXME: correct read, it doesn't give size or format information about the pixels. virtual void read(std::function const& do_with_pixels) = 0; virtual geometry::Stride stride() const = 0; protected: PixelSource() = default; PixelSource(PixelSource const&) = delete; PixelSource& operator=(PixelSource const&) = delete; }; } } } #endif /* MIR_RENDERER_SW_PIXEL_SOURCE_H_ */ ./include/test/0000755000004100000410000000000013115234413013642 5ustar www-datawww-data./include/test/mir_test_framework/0000755000004100000410000000000013115234677017561 5ustar www-datawww-data./include/test/mir_test_framework/visible_surface.h0000644000004100000410000000314113115234664023072 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Kevin DuBois */ #ifndef MIR_TEST_FRAMEWORK_VISIBLE_SURFACE_H_ #define MIR_TEST_FRAMEWORK_VISIBLE_SURFACE_H_ #include "mir_toolkit/mir_client_library.h" #include #include #include namespace mir_test_framework { class VisibleSurface { public: explicit VisibleSurface(MirWindowSpec* spec); VisibleSurface(VisibleSurface&&); VisibleSurface& operator=(VisibleSurface&&); VisibleSurface(VisibleSurface const&) = delete; VisibleSurface& operator=(VisibleSurface const&) = delete; ~VisibleSurface(); static void event_callback(MirWindow* surf, MirEvent const* ev, void* context); void set_visibility(MirWindow* surf, bool vis); operator MirWindow*() const; private: std::mutex mutex; std::condition_variable cv; MirWindow* window; bool visible; }; std::ostream& operator<<(std::ostream& os, VisibleSurface const& s); } #endif /* MIR_TEST_FRAMEWORK_VISIBLE_SURFACE_H_ */ ./include/test/mir_test_framework/any_surface.h0000644000004100000410000000207413115234664022230 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Robert Carr */ #ifndef MIR_TEST_FRAMEWORK_ANY_SURFACE_H_ #define MIR_TEST_FRAMEWORK_ANY_SURFACE_H_ #include "mir_toolkit/mir_client_library.h" #include "mir/geometry/size.h" namespace mir_test_framework { MirWindow* make_any_surface(MirConnection *connection); MirWindow* make_surface(MirConnection *connection, mir::geometry::Size size, MirPixelFormat format); } #endif // MIR_TEST_FRAMEWORK_ANY_SURFACE_H_ ./include/test/mir_test_framework/fake_input_device.h0000644000004100000410000000416113115234664023374 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_TEST_FRAMEWORK_FAKE_INPUT_DEVICE_H_ #define MIR_TEST_FRAMEWORK_FAKE_INPUT_DEVICE_H_ #include "mir_toolkit/events/event.h" #include "mir/test/event_factory.h" #include #include namespace mir_test_framework { class FakeInputDevice { public: /** * Valid value range of simulated touch coordinates. The simulated coordinates will be remapped to * the coordinates of the given input sink. * \{ */ static const int maximum_touch_axis_value = 0xFFFF; static const int minimum_touch_axis_value = 0; /// \} FakeInputDevice() = default; virtual ~FakeInputDevice() = default; virtual void emit_device_removal() = 0; virtual void emit_runtime_error() = 0; virtual void emit_event(mir::input::synthesis::KeyParameters const& key) = 0; virtual void emit_event(mir::input::synthesis::ButtonParameters const& button) = 0; virtual void emit_event(mir::input::synthesis::MotionParameters const& motion) = 0; virtual void emit_event(mir::input::synthesis::TouchParameters const& touch) = 0; virtual void emit_touch_sequence(std::function const& generate_parameters, int count, std::chrono::duration delay) = 0; FakeInputDevice(FakeInputDevice const&) = delete; FakeInputDevice& operator=(FakeInputDevice const&) = delete; }; } #endif ./include/test/mir_test_framework/temporary_environment_value.h0000644000004100000410000000222513115234416025564 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TEST_FRAMEWORK_ENVIRONMENT_VALUE_H_ #define MIR_TEST_FRAMEWORK_ENVIRONMENT_VALUE_H_ #include namespace mir_test_framework { class TemporaryEnvironmentValue { public: TemporaryEnvironmentValue(char const* name, char const* value); ~TemporaryEnvironmentValue(); private: static int const overwrite = 1; std::string const name; bool const has_old_value; std::string const old_value; }; } #endif /* MIR_TEST_FRAMEWORK_ENVIRONMENT_VALUE_H_ */ ./include/test/mir_test_framework/observant_shell.h0000644000004100000410000000750013115234664023122 0ustar www-datawww-data/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Brandon Schaefer */ #ifndef MIR_TEST_OBSERVANT_SHELL_H_ #define MIR_TEST_OBSERVANT_SHELL_H_ #include "mir/scene/session.h" #include "mir/scene/surface.h" #include "mir/shell/shell.h" namespace mir_test_framework { struct ObservantShell : mir::shell::Shell { ObservantShell( std::shared_ptr const& wrapped, std::shared_ptr const& surface_observer); void add_display(mir::geometry::Rectangle const& area) override; void remove_display(mir::geometry::Rectangle const& area) override; bool handle(MirEvent const& event) override; void focus_next_session() override; auto focused_session() const -> std::shared_ptr override; void set_focus_to( std::shared_ptr const& focus_session, std::shared_ptr const& focus_surface) override; std::shared_ptr focused_surface() const override; auto surface_at(mir::geometry::Point cursor) const -> std::shared_ptr override; void raise(mir::shell::SurfaceSet const& surfaces) override; std::shared_ptr open_session( pid_t client_pid, std::string const& name, std::shared_ptr const& sink) override; void close_session(std::shared_ptr const& session) override; std::shared_ptr start_prompt_session_for( std::shared_ptr const& session, mir::scene::PromptSessionCreationParameters const& params) override; void add_prompt_provider_for( std::shared_ptr const& prompt_session, std::shared_ptr const& session) override; void stop_prompt_session(std::shared_ptr const& prompt_session) override; mir::frontend::SurfaceId create_surface( std::shared_ptr const& session, mir::scene::SurfaceCreationParameters const& params, std::shared_ptr const& sink) override; void modify_surface( std::shared_ptr const& session, std::shared_ptr const& window, mir::shell::SurfaceSpecification const& modifications) override; void destroy_surface(std::shared_ptr const& session, mir::frontend::SurfaceId window) override; int set_surface_attribute( std::shared_ptr const& session, std::shared_ptr const& window, MirWindowAttrib attrib, int value) override; int get_surface_attribute( std::shared_ptr const& window, MirWindowAttrib attrib) override; void raise_surface( std::shared_ptr const& session, std::shared_ptr const& window, uint64_t timestamp) override; private: std::shared_ptr const wrapped; std::shared_ptr const surface_observer; }; } #endif /* MIR_TEST_OBSERVANT_SHELL_H_ */ ./include/test/mir_test_framework/headless_in_process_server.h0000644000004100000410000000207413115234416025326 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TEST_FRAMEWORK_HEADLESS_IN_PROCESS_SERVER_H_ #define MIR_TEST_FRAMEWORK_HEADLESS_IN_PROCESS_SERVER_H_ #include "mir_test_framework/headless_test.h" namespace mir_test_framework { struct HeadlessInProcessServer : HeadlessTest { HeadlessInProcessServer(); void SetUp() override; void TearDown() override; }; } #endif /* MIR_TEST_FRAMEWORK_HEADLESS_IN_PROCESS_SERVER_H_ */ ./include/test/mir_test_framework/detect_server.h0000644000004100000410000000172713115234416022566 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_TEST_FRAMEWORK_DETECT_SERVER_H_ #define MIR_TEST_FRAMEWORK_DETECT_SERVER_H_ #include #include namespace mir_test_framework { bool detect_server(std::string const& name, std::chrono::milliseconds const& timeout); } #endif /* MIR_TEST_FRAMEWORK_DETECT_SERVER_H_ */ ./include/test/mir_test_framework/stub_server_platform_factory.h0000644000004100000410000000310713115234664025725 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_TEST_FRAMEWORK_STUB_SERVER_PLATFORM_FACTORY_ #define MIR_TEST_FRAMEWORK_STUB_SERVER_PLATFORM_FACTORY_ #include "mir/geometry/rectangle.h" #include "mir/graphics/platform.h" #include "mir/module_deleter.h" #include #include #include namespace mir { namespace input { class InputDeviceInfo; } } namespace mir_test_framework { class FakeInputDevice; std::shared_ptr make_stubbed_server_graphics_platform(std::vector const& display_rects); void set_next_display_rects(std::unique_ptr>&& display_rects); void set_next_preset_display(std::shared_ptr const& display); mir::UniqueModulePtr add_fake_input_device(mir::input::InputDeviceInfo const& info); } #endif /* MIR_TEST_FRAMEWORK_STUB_SERVER_PLATFORM_FACTORY_ */ ./include/test/mir_test_framework/interprocess_client_server_test.h0000644000004100000410000000463513115234664026441 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TEST_FRAMEWORK_INTERPROCESS_CLIENT_SERVER_TEST_H_ #define MIR_TEST_FRAMEWORK_INTERPROCESS_CLIENT_SERVER_TEST_H_ #include "mir_test_framework/headless_test.h" #include "mir/test/cross_process_sync.h" namespace mir_test_framework { class Process; class Result; class InterprocessClientServerTest : public HeadlessTest { public: char const* const mir_test_socket = test_socket_file().c_str(); ~InterprocessClientServerTest(); void init_server(std::function const& init_code); void run_in_server(std::function const& exec_code); void run_in_server_and_disable_core_dump( std::function const& exec_code); void run_in_client(std::function const& client_code); auto new_client_process(std::function const& client_code) -> std::shared_ptr; bool is_test_process() const; pid_t client_pid() const { return client_process_id; } void TearDown() override; // Convenient [test|server|client] identifier if adding debug messages auto process_type() const -> char const* { return process_tag; } void expect_server_signalled(int signal); void stop_server(); bool sigkill_server_process(); Result wait_for_shutdown_server_process(); private: pid_t test_process_id{getpid()}; pid_t server_process_id{0}; pid_t client_process_id{0}; std::shared_ptr server_process; std::unique_ptr shutdown_sync{new mir::test::CrossProcessSync()}; char const* process_tag = "test"; std::function server_setup = []{}; bool server_signal_expected{false}; int expected_server_failure_signal{0}; }; } #endif /* MIR_TEST_FRAMEWORK_INTERPROCESS_CLIENT_SERVER_TEST_H_ */ ./include/test/mir_test_framework/stub_platform_extension.h0000644000004100000410000000415513115234664024710 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_TEST_FRAMEWORK_STUB_PLATFORM_EXTENSION_H_ #define MIR_TEST_FRAMEWORK_STUB_PLATFORM_EXTENSION_H_ #include "mir_toolkit/mir_extension_core.h" #ifdef __cplusplus extern "C" { #endif typedef char const* (*mir_extension_favorite_flavor)(); typedef struct MirExtensionFavoriteFlavorV1 { mir_extension_favorite_flavor favorite_flavor; } MirExtensionFavoriteFlavor; typedef MirExtensionFavoriteFlavorV1 MirExtensionFavoriteFlavorV9; typedef char const* (*mir_extension_animal_name)(); typedef struct MirExtensionAnimalNamesV1 { mir_extension_animal_name animal_name; } MirExtensionAnimalNames; static inline MirExtensionFavoriteFlavorV1 const* mir_extension_favorite_flavor_v1( MirConnection* connection) { return (MirExtensionFavoriteFlavorV1 const*) mir_connection_request_extension( connection, "mir_extension_favorite_flavor", 1); } static inline MirExtensionFavoriteFlavorV9 const* mir_extension_favorite_flavor_v9( MirConnection* connection) { return (MirExtensionFavoriteFlavorV9 const*) mir_connection_request_extension( connection, "mir_extension_favorite_flavor", 9); } static inline MirExtensionAnimalNamesV1 const* mir_extension_animal_names_v1( MirConnection* connection) { return (MirExtensionAnimalNamesV1 const*) mir_connection_request_extension( connection, "mir_extension_animal_names", 1); } #ifdef __cplusplus } #endif #endif /* MIR_TEST_FRAMEWORK_STUB_PLATFORM_EXTENSION_H_ */ ./include/test/mir_test_framework/in_process_server.h0000644000004100000410000000313313115234416023453 0ustar www-datawww-data/* * Copyright © 2013-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_TEST_FRAMEWORK_IN_PROCESS_SERVER_H_ #define MIR_TEST_FRAMEWORK_IN_PROCESS_SERVER_H_ #include "mir_test_framework/server_runner.h" #include namespace mir_test_framework { /// Fixture for running Mir server in test process struct InProcessServer : testing::Test, private ServerRunner { /// Starts the server /// \warning don't forget to call this if you override SetUp() void SetUp() override { ServerRunner::start_server(); } /// Stops the server /// \warning don't forget to call this if you override TearDown() void TearDown() override { ServerRunner::stop_server(); } /// \return a connection string for a new client to connect to the server using ServerRunner::new_connection; /// \return a connection string for a new client to connect to the prompt server using ServerRunner::new_prompt_connection; }; } #endif /* MIR_TEST_FRAMEWORK_IN_PROCESS_SERVER_H_ */ ./include/test/mir_test_framework/process.h0000644000004100000410000000557213115234664021415 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Thomas Voss * Thomas Guest */ #ifndef MIR_TEST_FRAMEWORK_PROCESS_H_ #define MIR_TEST_FRAMEWORK_PROCESS_H_ #include #include #include #include #include #include #include namespace mir_test_framework { enum class TerminationReason { unknown, child_terminated_normally, child_terminated_by_signal, child_terminated_with_core_dump, child_stopped_by_signal, child_resumed_by_signal }; // Aggregated results of running a process to completion struct Result { Result(); // Did the process exit without error? bool succeeded() const; // Was the process terminated by a signal? bool signalled() const; // Was the process terminated normally? bool exited_normally() const; TerminationReason reason; int exit_code; int signal; }; // Posix process control class. class Process { public: // Construct a process with the supplied pid Process(pid_t pid); // Destroy the process cleanly, by terminating it and waiting for // the pid. ~Process(); // Wait for the process to terminate, and return the results. Result wait_for_termination(const std::chrono::milliseconds& timeout = std::chrono::milliseconds(60 * 1000)); void kill(); void terminate(); void stop(); void cont(); void detach(); protected: Process() = delete; Process(const Process&) = delete; Process& operator=(const Process&) = delete; private: pid_t pid; bool terminated; bool detached; }; // Stream print helper std::ostream& operator<<(std::ostream& out, const Result& result); // Fork a child process to run the supplied main function, calling // the exit function when done. // Returns the parent process. template std::shared_ptr fork_and_run_in_a_different_process( Callable&& main_fn, std::function exit_fn) { pid_t pid = fork(); if (pid < 0) { throw std::runtime_error("Failed to fork process"); } if (pid == 0) { main_fn(); exit(exit_fn()); } return std::shared_ptr(new Process(pid)); } } #endif // MIR_TEST_FRAMEWORK_PROCESS_H_ ./include/test/mir_test_framework/stub_client_platform_options.h0000644000004100000410000000313313115234664025720 0ustar www-datawww-data/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_TEST_FRAMEWORK_STUB_CLIENT_PLATFORM_OPTIONS_H_ #define MIR_TEST_FRAMEWORK_STUB_CLIENT_PLATFORM_OPTIONS_H_ #include namespace mir_test_framework { /* * TODO: This should be an enum class, but gcc < 6 doesn't implement the * C++14 DR requiring that std::unordered_map works, and using * a raw enum means we can pass std::hash rather than adding an extra * hash implementation. */ enum FailurePoint { create_client_platform, create_egl_native_window, create_buffer_factory }; /** * Add an exception to the client platform created by the \b next call to create_client_platform * * \param [in] where The platform call that will throw an exception * \param [in,out] what The exception to throw */ void add_client_platform_error(FailurePoint where, std::exception_ptr what); } #endif //MIR_TEST_FRAMEWORK_STUB_CLIENT_PLATFORM_OPTIONS_H_ ./include/test/mir_test_framework/headless_test.h0000644000004100000410000000356013115234664022561 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TEST_FRAMEWORK_HEADLESS_TEST_H_ #define MIR_TEST_FRAMEWORK_HEADLESS_TEST_H_ #include "mir_test_framework/async_server_runner.h" #include namespace mir { class SharedLibrary; } namespace mir { namespace graphics { class Display; }} namespace mir { namespace geometry { struct Rectangle; }} namespace mir_test_framework { /** Basic fixture for tests that don't use graphics or input hardware. * This provides a mechanism for temporarily setting environment variables. * It automatically sets "MIR_SERVER_PLATFORM_GRAPHICS_LIB" to "graphics-dummy.so" * and MIR_SERVER_PLATFORM_INPUT_LIB to "input-stub.so" * as the tests do not hit the graphics hardware. */ class HeadlessTest : public ::testing::Test, public AsyncServerRunner { public: HeadlessTest(); ~HeadlessTest() noexcept; void preset_display(std::shared_ptr const& display); /// Override initial display layout void initial_display_layout(std::vector const& display_rects); private: std::unique_ptr server_platform_graphics_lib; }; std::string const& test_socket_file(); } #endif /* MIR_TEST_FRAMEWORK_HEADLESS_TEST_H_ */ ./include/test/mir_test_framework/placement_applying_shell.h0000644000004100000410000000447213115234664024777 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_TEST_FRAMEWORK_PLACEMENT_APPLYING_SHELL_H_ #define MIR_TEST_FRAMEWORK_PLACEMENT_APPLYING_SHELL_H_ #include "mir/shell/shell_wrapper.h" #include "mir/geometry/rectangle.h" #include "mir/scene/session.h" #include "mir/scene/surface.h" #include "mir/scene/surface_creation_parameters.h" #include #include #include #include #include namespace mir_test_framework { using ClientInputRegions = std::map>; using ClientPositions = std::map; struct PlacementApplyingShell : mir::shell::ShellWrapper { PlacementApplyingShell( std::shared_ptr wrapped_coordinator, ClientInputRegions const& client_input_regions, ClientPositions const& client_positions); ~PlacementApplyingShell(); mir::frontend::SurfaceId create_surface( std::shared_ptr const& session, mir::scene::SurfaceCreationParameters const& params, std::shared_ptr const& sink) override; void modify_surface( std::shared_ptr const& session, std::shared_ptr const& surface, mir::shell::SurfaceSpecification const& modifications) override; bool wait_for_modify_surface(std::chrono::seconds timeout); std::weak_ptr latest_surface; private: ClientInputRegions const& client_input_regions; ClientPositions const& client_positions; std::mutex mutex; std::condition_variable cv; bool modified {false}; }; } #endif ./include/test/mir_test_framework/connected_client_headless_server.h0000644000004100000410000000224213115234416026457 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TEST_FRAMEWORK_CONNECTED_CLIENT_HEADLESS_SERVER_H_ #define MIR_TEST_FRAMEWORK_CONNECTED_CLIENT_HEADLESS_SERVER_H_ #include "mir_test_framework/headless_in_process_server.h" #include "mir_toolkit/mir_client_library.h" namespace mir_test_framework { struct ConnectedClientHeadlessServer : HeadlessInProcessServer { MirConnection* connection{nullptr}; void SetUp() override; void TearDown() override; }; } #endif /* MIR_TEST_FRAMEWORK_CONNECTED_CLIENT_HEADLESS_SERVER_H_ */ ./include/test/mir_test_framework/async_server_runner.h0000644000004100000410000000367613115234416024031 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TESTS_INCLUDE_MIR_TEST_FRAMEWORK_ASYNC_SERVER_RUNNER_H_ #define MIR_TESTS_INCLUDE_MIR_TEST_FRAMEWORK_ASYNC_SERVER_RUNNER_H_ #include "mir_test_framework/temporary_environment_value.h" #include "mir/test/auto_unblock_thread.h" #include "mir/server.h" #include #include #include #include namespace mir_test_framework { class AsyncServerRunner { public: AsyncServerRunner(); ~AsyncServerRunner() noexcept; void add_to_environment(char const* key, char const* value); /// Starts the server on a new thread void start_server(); /// Stops the server and joins thread void stop_server(); /// Wait for the server to exit and joins thread void wait_for_server_exit(); /// \return a connection string for a new client to connect to the server auto new_connection() -> std::string; /// \return a connection string for a client to connect to the server auto connection(int fd) -> std::string; mir::Server server; private: std::list env; mir::test::AutoJoinThread server_thread; std::mutex mutex; std::condition_variable started; bool server_running{false}; }; } #endif /* MIR_TESTS_INCLUDE_MIR_TEST_FRAMEWORK_ASYNC_SERVER_RUNNER_H_ */ ./include/test/mir_test_framework/server_runner.h0000644000004100000410000000361713115234416022627 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TEST_FRAMEWORK_SERVER_RUNNER_H_ #define MIR_TEST_FRAMEWORK_SERVER_RUNNER_H_ #include #include #include #include #include namespace mir { class MainLoop; class DefaultServerConfiguration; } namespace mir_test_framework { /// Utility for running Mir server in test process struct ServerRunner { ServerRunner(); virtual ~ServerRunner(); /// Starts the server /// The method is synchronous, i.e., it returns only after the server has started void start_server(); /// Stops the server /// The method is synchronous, i.e., it returns only after the server has stopped void stop_server(); /// \return a connection string for a new client to connect to the server std::string new_connection(); /// \return a connection string for a new client to connect to the prompt server std::string new_prompt_connection(); private: std::shared_ptr start_mir_server(); virtual mir::DefaultServerConfiguration& server_config() = 0; char const* const old_env; std::thread server_thread; std::mutex main_loop_mutex; std::shared_ptr main_loop; }; } #endif /* MIR_TEST_FRAMEWORK_SERVER_RUNNER_H_ */ ./include/test/mir_test_framework/headless_display_buffer_compositor_factory.h0000644000004100000410000000272413115234664030606 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_TEST_FRAMEWORK_HEADLESS_DISPLAY_BUFFER_COMPOSITOR_FACTORY_H_ #define MIR_TEST_FRAMEWORK_HEADLESS_DISPLAY_BUFFER_COMPOSITOR_FACTORY_H_ #include "mir/compositor/display_buffer_compositor_factory.h" namespace mir_test_framework { class PassthroughTracker; struct HeadlessDisplayBufferCompositorFactory : mir::compositor::DisplayBufferCompositorFactory { HeadlessDisplayBufferCompositorFactory(); HeadlessDisplayBufferCompositorFactory(std::shared_ptr const& tracker); std::unique_ptr create_compositor_for( mir::graphics::DisplayBuffer& display_buffer) override; private: std::shared_ptr const tracker; }; } #endif /* MIR_TEST_FRAMEWORK_HEADLESS_DISPLAY_BUFFER_COMPOSITOR_FACTORY_H_ */ ./include/test/mir_test_framework/headless_nested_server_runner.h0000644000004100000410000000262113115234664026040 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Robert Carr */ #ifndef MIR_TEST_FRAMEWORK_HEADLESS_NESTED_SERVER_RUNNER_H_ #define MIR_TEST_FRAMEWORK_HEADLESS_NESTED_SERVER_RUNNER_H_ #include "mir_test_framework/async_server_runner.h" #include namespace mir_test_framework { struct PassthroughTracker { bool wait_for_passthrough_frames(size_t num_frames, std::chrono::milliseconds ms); void note_passthrough(); private: std::mutex mutex; std::condition_variable cv; size_t num_passthrough; }; class HeadlessNestedServerRunner : public AsyncServerRunner { public: HeadlessNestedServerRunner(std::string const& connect_string); std::shared_ptr const passthrough_tracker; }; } #endif /* MIR_TEST_FRAMEWORK_HEADLESS_NESTED_SERVER_RUNNER_H_ */ ./include/test/mir_test_framework/stub_platform_helpers.h0000644000004100000410000000321113115234416024321 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_TEST_FRAMEWORK_STUB_PLATFORM_HELPERS_H_ #define MIR_TEST_FRAMEWORK_STUB_PLATFORM_HELPERS_H_ #include "mir/graphics/platform_ipc_package.h" #include "mir_toolkit/client_types.h" #include namespace mir_test_framework { constexpr int stub_data_size{21}; constexpr int stub_data_guard{0x0eadbeef}; static inline void pack_stub_ipc_package(mir::graphics::PlatformIPCPackage& package) { package.ipc_data = std::vector(stub_data_size, -1); package.ipc_data[0] = stub_data_guard; } static inline void create_stub_platform_package(MirPlatformPackage& package) { ::memset(&package, 0, sizeof(package)); package.data_items = stub_data_size; package.data[0] = stub_data_guard; } MATCHER(IsStubPlatformPackage, "") { return (arg.data_items == stub_data_size) && (arg.data[0] == stub_data_guard) && (arg.fd_items == 0); } } #endif // MIR_TEST_FRAMEWORK_STUB_PLATFORM_HELPERS_H_ ./include/test/mir_test_framework/stub_graphics_platform_operation.h0000644000004100000410000000170613115234416026546 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alexandros Frantzis */ #ifndef MIR_TEST_FRAMEWORK_STUB_GRAPHICS_PLATFORM_OPERATION_H_ #define MIR_TEST_FRAMEWORK_STUB_GRAPHICS_PLATFORM_OPERATION_H_ namespace mir_test_framework { enum class StubGraphicsPlatformOperation : unsigned int { add = 13, echo_fd = 15 }; } #endif ./include/test/mir_test_framework/executable_path.h0000644000004100000410000000223613115234416023061 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #ifndef MIR_TEST_FRAMEWORK_EXECUTABLE_PATH_H_ #define MIR_TEST_FRAMEWORK_EXECUTABLE_PATH_H_ #include namespace mir_test_framework { std::string executable_path(); std::string library_path(); std::string server_platform_path(); std::string test_data_path(); std::string server_platform(std::string const& name); std::string server_input_platform(std::string const& name); std::string client_platform(std::string const& name); } #endif /* MIR_TEST_FRAMEWORK_EXECUTABLE_PATH_H_ */ ./include/test/mir_test_framework/connected_client_with_a_surface.h0000644000004100000410000000231313115234664026270 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TEST_FRAMEWORK_CONNECTED_CLIENT_WITH_A_SURFACE_H_ #define MIR_TEST_FRAMEWORK_CONNECTED_CLIENT_WITH_A_SURFACE_H_ #include "mir_test_framework/connected_client_headless_server.h" #include "mir/geometry/size.h" namespace mir_test_framework { struct ConnectedClientWithASurface : ConnectedClientHeadlessServer { MirWindow* window{nullptr}; void SetUp() override; void TearDown() override; mir::geometry::Size const surface_size {640, 480}; }; } #endif /* MIR_TEST_FRAMEWORK_CONNECTED_CLIENT_WITH_A_SURFACE_H_ */ ./include/test/mir_test_framework/declarative_placement_window_manage_policy.h0000644000004100000410000000403513115234416030514 0ustar www-datawww-data/* * Copyright © 2014-2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TEST_FRAMEWORK_DECLARATIVE_PLACEMENT_WINDOW_MANAGER_POLICY_H_ #define MIR_TEST_FRAMEWORK_DECLARATIVE_PLACEMENT_WINDOW_MANAGER_POLICY_H_ #include "mir/shell/canonical_window_manager.h" #include "mir/geometry/rectangle.h" #include #include #include namespace mir_test_framework { typedef std::map SurfaceGeometries; /// DeclarativePlacementWindowManagerPolicy is a test utility server component for specifying /// a static list of surface geometries and relative depths. Used, for example, /// in input tests where it is necessary to set up scenarios depending on /// multiple surfaces geometry and stacking. class DeclarativePlacementWindowManagerPolicy : public mir::shell::CanonicalWindowManagerPolicy { public: DeclarativePlacementWindowManagerPolicy( mir::shell::WindowManagerTools* const tools, SurfaceGeometries const& positions_by_name, std::shared_ptr const& display_layout); auto handle_place_new_surface( std::shared_ptr const& session, mir::scene::SurfaceCreationParameters const& request_parameters) -> mir::scene::SurfaceCreationParameters; private: SurfaceGeometries const& surface_geometries_by_name; }; } #endif // MIR_TEST_FRAMEWORK_DECLARATIVE_PLACEMENT_WINDOW_MANAGER_POLICY_H_ ./include/test/mir_test_framework/main.h0000644000004100000410000000250213115234416020644 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for moredetails. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_TEST_FRAMEWORK_MAIN_H #define MIR_TEST_FRAMEWORK_MAIN_H namespace mir_test_framework { /** * Initialize and run the mir test framework as follows: * * ::testing::InitGoogleTest(&argc, argv); * set_commandline(argc, argv); * return RUN_ALL_TESTS(); * * \attention If you override main() for your own purposes call this or do * something equivalent to run the tests. */ int main(int argc, char* argv[]); /** * Note the commandline for use in the mir test framework. The parameter list * referenced by argv must remain valid during the tests. */ void set_commandline(int argc, char* argv[]); } #endif //MIR_TEST_FRAMEWORK_MAIN_H ./include/test/mir/0000755000004100000410000000000013115234413014431 5ustar www-datawww-data./include/test/mir/test/0000755000004100000410000000000013115234677015424 5ustar www-datawww-data./include/test/mir/test/pipe.h0000644000004100000410000000210413115234416016516 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_TEST_PIPE_H_ #define MIR_TEST_PIPE_H_ #include "mir/fd.h" namespace mir { namespace test { class Pipe { public: Pipe(); Pipe(int flags); ~Pipe() = default; Fd read_fd() const; Fd write_fd() const; private: Pipe(Pipe const&) = delete; Pipe& operator=(Pipe const&) = delete; Fd reader; Fd writer; }; } } #endif /* MIR_TEST_PIPE_H_ */ ./include/test/mir/test/empty_deleter.h0000644000004100000410000000156713115234416020437 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_TEST_EMPTY_DELETER_H_ #define MIR_TEST_EMPTY_DELETER_H_ namespace mir { struct EmptyDeleter { void operator()(void const* ) { } }; } #endif /* MIR_TEST_EMPTY_DELETER_H_ */ ./include/test/mir/test/doubles/0000755000004100000410000000000013115234677017061 5ustar www-datawww-data./include/test/mir/test/doubles/mock_prompt_session_listener.h0000644000004100000410000000326013115234416025224 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Nick Dedekind */ #ifndef MIR_TEST_DOUBLES_MOCK_PROMPT_SESSION_LISTENER_H_ #define MIR_TEST_DOUBLES_MOCK_PROMPT_SESSION_LISTENER_H_ #include "mir/scene/prompt_session_listener.h" #include namespace mir { namespace test { namespace doubles { struct MockPromptSessionListener : public scene::PromptSessionListener { virtual ~MockPromptSessionListener() noexcept(true) {} MOCK_METHOD1(starting, void(std::shared_ptr const&)); MOCK_METHOD1(stopping, void(std::shared_ptr const&)); MOCK_METHOD1(suspending, void(std::shared_ptr const&)); MOCK_METHOD1(resuming, void(std::shared_ptr const&)); MOCK_METHOD2(prompt_provider_added, void(scene::PromptSession const&, std::shared_ptr const&)); MOCK_METHOD2(prompt_provider_removed, void(scene::PromptSession const&, std::shared_ptr const&)); }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_MOCK_PROMPT_SESSION_LISTENER_H_ ./include/test/mir/test/doubles/stub_session.h0000644000004100000410000000627513115234664021760 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TEST_DOUBLES_STUB_SESSION_H #define MIR_TEST_DOUBLES_STUB_SESSION_H #include namespace mir { namespace test { namespace doubles { struct StubSession : scene::Session, frontend::SessionExtensions { StubSession(pid_t pid = -1); std::shared_ptr get_surface( frontend::SurfaceId surface) const override; std::string name() const override; void drop_outstanding_requests() override; pid_t process_id() const override; void take_snapshot(scene::SnapshotCallback const& snapshot_taken) override; std::shared_ptr default_surface() const override; void set_lifecycle_state(MirLifecycleState state) override; void send_display_config(graphics::DisplayConfiguration const&) override; void send_error(ClientVisibleError const&) override; void hide() override; void show() override; void start_prompt_session() override; void stop_prompt_session() override; void suspend_prompt_session() override; void resume_prompt_session() override; frontend::SurfaceId create_surface( scene::SurfaceCreationParameters const& params, std::shared_ptr const& sink) override; void destroy_surface(frontend::SurfaceId surface) override; std::shared_ptr surface( frontend::SurfaceId surface) const override; std::shared_ptr surface_after( std::shared_ptr const&) const override; std::shared_ptr get_buffer_stream( frontend::BufferStreamId stream) const override; frontend::BufferStreamId create_buffer_stream( graphics::BufferProperties const& props) override; graphics::BufferID create_buffer(geometry::Size, uint32_t, uint32_t) override; graphics::BufferID create_buffer(geometry::Size, MirPixelFormat) override; void destroy_buffer_stream(frontend::BufferStreamId stream) override; void configure_streams( scene::Surface& surface, std::vector const& config) override; void destroy_surface(std::weak_ptr const& surface) override; void send_input_config(MirInputConfig const& config) override; graphics::BufferID create_buffer(graphics::BufferProperties const& properties) override; void destroy_buffer(graphics::BufferID) override; std::shared_ptr get_buffer(graphics::BufferID) override; pid_t pid; }; } } } #endif //MIR_TEST_DOUBLES_STUB_SESSION_H ./include/test/mir/test/doubles/null_display_sync_group.h0000644000004100000410000000502713115234416024174 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_TEST_DOUBLES_NULL_DISPLAY_SYNC_GROUP_H_ #define MIR_TEST_DOUBLES_NULL_DISPLAY_SYNC_GROUP_H_ #include "mir/graphics/display.h" #include "mir/geometry/size.h" #include "mir/test/doubles/null_display_buffer.h" #include "mir/test/doubles/stub_display_buffer.h" #include namespace mir { namespace test { namespace doubles { struct StubDisplaySyncGroup : graphics::DisplaySyncGroup { public: StubDisplaySyncGroup(std::vector const& output_rects) : output_rects{output_rects} { for (auto const& output_rect : output_rects) display_buffers.emplace_back(output_rect); } StubDisplaySyncGroup(geometry::Size sz) : StubDisplaySyncGroup({{{0,0}, sz}}) {} void for_each_display_buffer(std::function const& f) override { for (auto& db : display_buffers) f(db); } void post() override { /* yield() is needed to ensure reasonable runtime under valgrind for some tests */ std::this_thread::yield(); } std::chrono::milliseconds recommended_sleep() const override { return std::chrono::milliseconds::zero(); } private: std::vector const output_rects; std::vector display_buffers; }; struct NullDisplaySyncGroup : graphics::DisplaySyncGroup { void for_each_display_buffer(std::function const& f) override { f(db); } virtual void post() override { /* yield() is needed to ensure reasonable runtime under valgrind for some tests */ std::this_thread::yield(); } std::chrono::milliseconds recommended_sleep() const override { return std::chrono::milliseconds::zero(); } NullDisplayBuffer db; }; } } } #endif /* MIR_TEST_DOUBLES_NULL_DISPLAY_SYNC_GROUP_H_ */ ./include/test/mir/test/doubles/stub_display_buffer.h0000644000004100000410000000251213115234416023254 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_TEST_DOUBLES_STUB_DISPLAY_BUFFER_H_ #define MIR_TEST_DOUBLES_STUB_DISPLAY_BUFFER_H_ #include "mir/test/doubles/null_display_buffer.h" #include "mir/geometry/rectangle.h" namespace mir { namespace test { namespace doubles { class StubDisplayBuffer : public NullDisplayBuffer { public: StubDisplayBuffer(geometry::Rectangle const& view_area_) : view_area_(view_area_) {} StubDisplayBuffer(StubDisplayBuffer const& s) : view_area_(s.view_area_) {} geometry::Rectangle view_area() const override { return view_area_; } private: geometry::Rectangle view_area_; }; } } } #endif /* MIR_TEST_DOUBLES_STUB_DISPLAY_BUFFER_H_ */ ./include/test/mir/test/doubles/null_display_buffer.h0000644000004100000410000000267013115234664023263 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_TEST_DOUBLES_NULL_DISPLAY_BUFFER_H_ #define MIR_TEST_DOUBLES_NULL_DISPLAY_BUFFER_H_ #include "mir/graphics/display_buffer.h" namespace mir { namespace test { namespace doubles { class NullDisplayBuffer : public graphics::DisplayBuffer, public graphics::NativeDisplayBuffer { public: geometry::Rectangle view_area() const override { return geometry::Rectangle(); } bool overlay(graphics::RenderableList const&) override { return false; } MirOrientation orientation() const override { return mir_orientation_normal; } MirMirrorMode mirror_mode() const override { return mir_mirror_mode_none; } NativeDisplayBuffer* native_display_buffer() override { return this; } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_DISPLAY_BUFFER_H_ */ ./include/test/mir/test/doubles/null_display_buffer_compositor_factory.h0000644000004100000410000000344313115234416027262 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_TEST_DOUBLES_NULL_DISPLAY_BUFFER_COMPOSITOR_FACTORY_H_ #define MIR_TEST_DOUBLES_NULL_DISPLAY_BUFFER_COMPOSITOR_FACTORY_H_ #include "mir/compositor/display_buffer_compositor_factory.h" #include "mir/compositor/display_buffer_compositor.h" #include namespace mir { namespace test { namespace doubles { class NullDisplayBufferCompositorFactory : public compositor::DisplayBufferCompositorFactory { public: auto create_compositor_for(graphics::DisplayBuffer&) -> std::unique_ptr override { struct NullDisplayBufferCompositor : compositor::DisplayBufferCompositor { void composite(compositor::SceneElementSequence&&) { // yield() is needed to ensure reasonable runtime under // valgrind for some tests std::this_thread::yield(); } }; auto raw = new NullDisplayBufferCompositor{}; return std::unique_ptr(raw); } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_DISPLAY_BUFFER_COMPOSITOR_FACTORY_H_ */ ./include/test/mir/test/doubles/null_display_configuration.h0000644000004100000410000000277713115234416024664 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_TEST_DOUBLES_NULL_DISPLAY_CONFIGURATION_H_ #define MIR_TEST_DOUBLES_NULL_DISPLAY_CONFIGURATION_H_ #include "mir/graphics/display_configuration.h" namespace mir { namespace test { namespace doubles { class NullDisplayConfiguration : public graphics::DisplayConfiguration { void for_each_card(std::function) const override { } void for_each_output(std::function) const override { } void for_each_output(std::function) override { } std::unique_ptr clone() const override { return std::make_unique(); } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_DISPLAY_CONFIGURATION_H_ */ ./include/test/mir/test/doubles/null_platform.h0000644000004100000410000000332713115234664022111 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_TEST_DOUBLES_NULL_PLATFORM_H_ #define MIR_TEST_DOUBLES_NULL_PLATFORM_H_ #include "mir/graphics/platform.h" #include "mir/graphics/platform_ipc_package.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "mir/test/doubles/null_display.h" #include "mir/test/doubles/null_platform_ipc_operations.h" namespace mir { namespace test { namespace doubles { class NullPlatform : public graphics::Platform { public: mir::UniqueModulePtr create_buffer_allocator() override { return nullptr; } mir::UniqueModulePtr create_display( std::shared_ptr const&, std::shared_ptr const&) override { return mir::make_module_ptr(); } mir::UniqueModulePtr make_ipc_operations() const override { return mir::make_module_ptr(); } }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_NULL_PLATFORM_ ./include/test/mir/test/doubles/mock_seat_report.h0000644000004100000410000000337013115234664022571 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Brandon Schaefer */ #ifndef MIR_TEST_DOUBLES_MOCK_SEAT_REPORT_H_ #define MIR_TEST_DOUBLES_MOCK_SEAT_REPORT_H_ #include "mir/input/seat_observer.h" #include class MirEvent; namespace mir { namespace test { namespace doubles { class MockSeatObserver : public input::SeatObserver { public: MOCK_METHOD1(seat_add_device, void(uint64_t /*id*/)); MOCK_METHOD1(seat_remove_device, void(uint64_t /*id*/)); MOCK_METHOD1(seat_dispatch_event, void(MirEvent const* /*event*/)); MOCK_METHOD2(seat_get_rectangle_for, void(uint64_t /*id*/, geometry::Rectangle const& /*out_rect*/)); MOCK_METHOD2(seat_set_key_state, void(uint64_t /*id*/, std::vector const& /*scan_codes*/)); MOCK_METHOD2(seat_set_pointer_state, void(uint64_t /*id*/, unsigned /*buttons*/)); MOCK_METHOD2(seat_set_cursor_position, void(float /*cursor_x*/, float /*cursor_y*/)); MOCK_METHOD1(seat_set_confinement_region_called, void(geometry::Rectangles const& /*regions*/)); MOCK_METHOD0(seat_reset_confinement_regions, void()); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_SEAT_REPORT_H_ */ ./include/test/mir/test/doubles/stub_cursor_image.h0000644000004100000410000000234413115234416022740 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alberto Aguirre */ #ifndef MIR_TEST_DOUBLES_STUB_CURSOR_IMAGE_H_ #define MIR_TEST_DOUBLES_STUB_CURSOR_IMAGE_H_ #include "mir/graphics/cursor_image.h" namespace mir { namespace test { namespace doubles { struct StubCursorImage : public mir::graphics::CursorImage { void const* as_argb_8888() const override { return nullptr; } geometry::Size size() const override { return geometry::Size{16, 16}; } geometry::Displacement hotspot() const override { return geometry::Displacement{0, 0}; } }; } } } // namespace mir #endif /* MIR_TEST_DOUBLES_STUB_CURSOR_H_ */ ./include/test/mir/test/doubles/stub_display_configuration.h0000644000004100000410000000663213115234664024666 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_TEST_DOUBLES_STUB_DISPLAY_CONFIGURATION_H_ #define MIR_TEST_DOUBLES_STUB_DISPLAY_CONFIGURATION_H_ #include "mir/graphics/display_configuration.h" #include #include namespace mir { namespace test { namespace doubles { struct StubDisplayConfigurationOutput : public graphics::DisplayConfigurationOutput { StubDisplayConfigurationOutput( geometry::Size px_size, geometry::Size mm_size, MirPixelFormat format, double vrefresh, bool connected); StubDisplayConfigurationOutput( geometry::Size px_size, geometry::Size mm_size, MirPixelFormat format, double vrefresh, bool connected, MirSubpixelArrangement subpixel_arrangement); StubDisplayConfigurationOutput(graphics::DisplayConfigurationOutputId id, geometry::Size px_size, geometry::Size mm_size, MirPixelFormat format, double vrefresh, bool connected); StubDisplayConfigurationOutput(graphics::DisplayConfigurationOutputId id, geometry::Size px_size, geometry::Size mm_size, MirPixelFormat format, double vrefresh, bool connected, MirSubpixelArrangement subpixel_arrangement); StubDisplayConfigurationOutput(graphics::DisplayConfigurationOutputId id, std::vector modes, std::vector formats); }; class StubDisplayConfig : public graphics::DisplayConfiguration { public: StubDisplayConfig(); StubDisplayConfig(StubDisplayConfig const& other); StubDisplayConfig(graphics::DisplayConfiguration const& other); StubDisplayConfig(unsigned int num_displays); StubDisplayConfig(std::vector> const& connected_used); StubDisplayConfig(unsigned int num_displays, std::vector const& pfs); StubDisplayConfig(std::vector const& rects); StubDisplayConfig(std::vector const& outputs); StubDisplayConfig( std::vector const& cards, std::vector const& outputs); void for_each_card(std::function f) const override; void for_each_output(std::function f) const override; void for_each_output(std::function f) override; std::unique_ptr clone() const override; std::vector cards; std::vector outputs; }; } } } #endif /* MIR_TEST_DOUBLES_STUB_DISPLAY_CONFIGURATION_H_ */ ./include/test/mir/test/doubles/mock_display_configuration.h0000644000004100000410000000307513115234664024640 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_TEST_DOUBLES_MOCK_DISPLAY_CONFIGURATION_H_ #define MIR_TEST_DOUBLES_MOCK_DISPLAY_CONFIGURATION_H_ #include "mir/graphics/display_configuration.h" namespace mir { namespace test { namespace doubles { struct MockDisplayConfiguration : public graphics::DisplayConfiguration { MOCK_CONST_METHOD1( for_each_card, void(std::function)); MOCK_CONST_METHOD1( for_each_output, void(std::function)); MOCK_METHOD1( for_each_output, void(std::function)); MOCK_CONST_METHOD0(valid, bool()); std::unique_ptr clone() const { throw std::runtime_error("MockDisplayConfiguration::clone is not implemented"); } }; } } } #endif ./include/test/mir/test/doubles/wrap_shell_to_track_latest_surface.h0000644000004100000410000000305113115234416026332 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TEST_WRAP_SHELL_TO_TRACK_LATEST_SURFACE_H #define MIR_TEST_WRAP_SHELL_TO_TRACK_LATEST_SURFACE_H #include "mir/shell/shell_wrapper.h" #include "mir/scene/session.h" namespace mir { namespace test { namespace doubles { struct WrapShellToTrackLatestSurface : mir::shell::ShellWrapper { using mir::shell::ShellWrapper::ShellWrapper; mir::frontend::SurfaceId create_surface( std::shared_ptr const& session, mir::scene::SurfaceCreationParameters const& params, std::shared_ptr const& sink) override { auto const surface = mir::shell::ShellWrapper::create_surface(session, params, sink); latest_surface = session->surface(surface); return surface; } std::weak_ptr latest_surface; }; } } } #endif //MIR_TEST_WRAP_SHELL_TO_TRACK_LATEST_SURFACE_H ./include/test/mir/test/doubles/mock_egl.h0000644000004100000410000001367713115234664021024 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Thomas Voss */ #ifndef MIR_TEST_DOUBLES_MOCK_EGL_H_ #define MIR_TEST_DOUBLES_MOCK_EGL_H_ #include #include #include #include #ifndef GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES #endif #define EGL_EGLEXT_PROTOTYPES #include #include //for GL extensions #include #include namespace mir { namespace test { namespace doubles { MATCHER_P(AttrMatches, val, std::string("matches")) { auto i = 0; while ((val[i] != EGL_NONE) && (arg[i] != EGL_NONE)) { if (val[i] != arg[i]) return false; i++; } if ((val[i] == EGL_NONE) && (arg[i] == EGL_NONE)) { return true; } return false; } MATCHER_P2(EGLConfigContainsAttrib, attrib, value, "") { bool attrib_position = true; bool attrib_found = false; while (!attrib_position || *arg != EGL_NONE) { if (attrib_position && *arg == attrib) { attrib_found = true; } else if (!attrib_position) { if (attrib_found && *arg == value) { return true; } attrib_found = false; } attrib_position = !attrib_position; ++arg; } return false; } class MockEGL { public: MockEGL(); virtual ~MockEGL(); void expect_nested_egl_usage(); void provide_egl_extensions(); // Provide a functional version of eglSwapBuffers on stubbed platforms // When enabled, if an instance of mir::client::EGLNativeSurface is passed to // eglCreateWindowSurface, then the returned EGLSurface can be used with // eglSwapBuffers to invoke EGLNativeSurface::swap_buffers_sync void provide_stub_platform_buffer_swapping(); typedef void (*generic_function_pointer_t)(void); typedef void* AnyNativeType; MOCK_METHOD1(eglGetDisplay, EGLDisplay(AnyNativeType)); MOCK_METHOD3(eglInitialize, EGLBoolean(EGLDisplay,EGLint*,EGLint*)); MOCK_METHOD1(eglTerminate, EGLBoolean(EGLDisplay)); MOCK_METHOD2(eglQueryString,const char*(EGLDisplay, EGLint)); MOCK_METHOD1(eglBindApi, EGLBoolean(EGLenum)); MOCK_METHOD1(eglGetProcAddress,generic_function_pointer_t(const char*)); // Config management MOCK_METHOD4(eglGetConfigs, EGLBoolean(EGLDisplay,EGLConfig*,EGLint,EGLint*)); MOCK_METHOD5(eglChooseConfig, EGLBoolean(EGLDisplay, const EGLint*,EGLConfig*,EGLint,EGLint*)); MOCK_METHOD4(eglGetConfigAttrib, EGLBoolean(EGLDisplay,EGLConfig,EGLint,EGLint*)); // Surface management MOCK_METHOD4(eglCreateWindowSurface, EGLSurface(EGLDisplay,EGLConfig,AnyNativeType,const EGLint*)); MOCK_METHOD4(eglCreatePixmapSurface, EGLSurface(EGLDisplay,EGLConfig,AnyNativeType,const EGLint*)); MOCK_METHOD3(eglCreatePbufferSurface, EGLSurface(EGLDisplay,EGLConfig,const EGLint*)); MOCK_METHOD2(eglDestroySurface, EGLBoolean(EGLDisplay,EGLSurface)); MOCK_METHOD4(eglQuerySurface, EGLBoolean(EGLDisplay,EGLSurface,EGLint,EGLint*)); // EGL 1.1 render-to-texture APIs MOCK_METHOD4(eglSurfaceAttrib, EGLBoolean(EGLDisplay,EGLSurface,EGLint,EGLint)); MOCK_METHOD3(eglBindTexImage, EGLBoolean(EGLDisplay,EGLSurface,EGLint)); MOCK_METHOD3(eglReleaseTexImage, EGLBoolean(EGLDisplay,EGLSurface,EGLint)); // EGL 1.1 swap control API MOCK_METHOD2(eglSwapInterval, EGLBoolean(EGLDisplay,EGLint)); MOCK_METHOD4(eglCreateContext, EGLContext(EGLDisplay,EGLConfig,EGLContext,const EGLint*)); MOCK_METHOD2(eglDestroyContext, EGLBoolean(EGLDisplay,EGLContext)); MOCK_METHOD4(eglMakeCurrent, EGLBoolean(EGLDisplay,EGLSurface,EGLSurface,EGLContext)); MOCK_METHOD0(eglGetCurrentContext,EGLContext()); MOCK_METHOD1(eglGetCurrentSurface,EGLSurface(EGLint)); MOCK_METHOD0(eglGetCurrentDisplay, EGLDisplay()); MOCK_METHOD4(eglQueryContext, EGLBoolean(EGLDisplay,EGLContext,EGLint,EGLint*)); MOCK_METHOD0(eglWaitGL, EGLBoolean()); MOCK_METHOD1(eglWaitNative, EGLBoolean(EGLint)); MOCK_METHOD2(eglSwapBuffers, EGLBoolean(EGLDisplay,EGLSurface)); MOCK_METHOD3(eglCopyBuffers, EGLBoolean(EGLDisplay,EGLSurface,AnyNativeType)); MOCK_METHOD0(eglGetError, EGLint (void)); MOCK_METHOD5(eglCreateImageKHR, EGLImageKHR(EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint*)); MOCK_METHOD2(eglDestroyImageKHR,EGLBoolean(EGLDisplay, EGLImageKHR)); MOCK_METHOD2(glEGLImageTargetTexture2DOES, void(GLenum, GLeglImageOES)); MOCK_METHOD3(eglCreateSyncKHR, EGLSyncKHR(EGLDisplay, EGLenum, EGLint const*)); MOCK_METHOD2(eglDestroySyncKHR, EGLBoolean(EGLDisplay, EGLSyncKHR)); MOCK_METHOD4(eglClientWaitSyncKHR, EGLint(EGLDisplay, EGLSyncKHR, EGLint, EGLTimeKHR)); MOCK_METHOD5(eglGetSyncValuesCHROMIUM, EGLBoolean(EGLDisplay, EGLSurface, int64_t*, int64_t*, int64_t*)); EGLDisplay const fake_egl_display; EGLConfig const* const fake_configs; EGLint const fake_configs_num; EGLSurface const fake_egl_surface; EGLContext const fake_egl_context; EGLImageKHR const fake_egl_image; int const fake_visual_id; std::mutex mutable current_contexts_mutex; std::unordered_map current_contexts; }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_EGL_H_ */ ./include/test/mir/test/doubles/null_platform_ipc_operations.h0000644000004100000410000000330313115234416025174 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_TEST_DOUBLES_NULL_PLATFORM_IPC_OPERATIONS_H_ #define MIR_TEST_DOUBLES_NULL_PLATFORM_IPC_OPERATIONS_H_ #include "mir/graphics/platform_ipc_operations.h" #include "mir/graphics/platform_operation_message.h" namespace mir { namespace test { namespace doubles { class NullPlatformIpcOperations : public graphics::PlatformIpcOperations { public: void pack_buffer(graphics::BufferIpcMessage&, graphics::Buffer const&, graphics::BufferIpcMsgType) const override { } void unpack_buffer(graphics::BufferIpcMessage&, graphics::Buffer const&) const override { } std::shared_ptr connection_ipc_package() override { return std::make_shared(); } graphics::PlatformOperationMessage platform_operation( unsigned int const, graphics::PlatformOperationMessage const&) override { return graphics::PlatformOperationMessage(); } }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_NULL_PLATFORM_IPC_OPERATIONS_H_ ./include/test/mir/test/doubles/nested_mock_egl.h0000644000004100000410000000230113115234416022337 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TEST_DOUBLES_NESTED_MOCK_EGL_H_ #define MIR_TEST_DOUBLES_NESTED_MOCK_EGL_H_ #include "mir/test/doubles/mock_egl.h" namespace mir { namespace test { namespace doubles { /// MockEGL with configuration for operating a nested server. class NestedMockEGL : public ::testing::NiceMock { public: NestedMockEGL(); private: void egl_initialize(EGLint* major, EGLint* minor); void egl_choose_config(EGLConfig* config, EGLint* num_config); }; } } } #endif /* MIR_TEST_DOUBLES_NESTED_MOCK_EGL_H_ */ ./include/test/mir/test/doubles/stub_surface.h0000644000004100000410000000717713115234664021727 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TEST_DOUBLES_STUB_SURFACE_H #define MIR_TEST_DOUBLES_STUB_SURFACE_H #include namespace mir { namespace test { namespace doubles { // scene::Surface is a horribly wide interface to expose from Mir struct StubSurface : scene::Surface { std::string name() const override; void move_to(geometry::Point const& top_left) override; float alpha() const override; geometry::Size size() const override; geometry::Size client_size() const override; std::shared_ptr primary_buffer_stream() const override; void set_streams(std::list const& streams) override; bool supports_input() const override; int client_input_fd() const override; std::shared_ptr input_channel() const override; input::InputReceptionMode reception_mode() const override; void set_reception_mode(input::InputReceptionMode mode) override; void set_input_region(std::vector const& input_rectangles) override; void resize(geometry::Size const& size) override; geometry::Point top_left() const override; geometry::Rectangle input_bounds() const override; bool input_area_contains(geometry::Point const& point) const override; void consume(MirEvent const* event) override; void set_alpha(float alpha) override; void set_orientation(MirOrientation orientation) override; void set_transformation(glm::mat4 const&) override; bool visible() const override; graphics::RenderableList generate_renderables(compositor::CompositorID id) const override; int buffers_ready_for_compositor(void const* compositor_id) const override; MirWindowType type() const override; MirWindowState state() const override; int configure(MirWindowAttrib attrib, int value) override; int query(MirWindowAttrib attrib) const override; void hide() override; void show() override; void set_cursor_image(std::shared_ptr const& image) override; std::shared_ptr cursor_image() const override; void set_cursor_stream(std::shared_ptr const& stream, geometry::Displacement const& hotspot) override; void request_client_surface_close() override; std::shared_ptr parent() const override; void add_observer(std::shared_ptr const& observer) override; void remove_observer(std::weak_ptr const& observer) override; void set_keymap(MirInputDeviceId id, std::string const& model, std::string const& layout, std::string const& variant, std::string const& options) override; void rename(std::string const& title) override; void set_confine_pointer_state(MirPointerConfinementState state) override; MirPointerConfinementState confine_pointer_state() const override; void placed_relative(geometry::Rectangle const& placement) override; }; } } } #endif //MIR_TEST_DOUBLES_STUB_SURFACE_H ./include/test/mir/test/doubles/stub_input_device.h0000644000004100000410000000462213115234664022745 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_TEST_DOUBLES_STUB_INPUT_DEVICE_H_ #define MIR_TEST_DOUBLES_STUB_INPUT_DEVICE_H_ #include "mir/input/device.h" #include "mir/input/device_capability.h" #include "mir/input/mir_pointer_config.h" #include "mir/input/mir_touchpad_config.h" #include "mir/input/mir_keyboard_config.h" #include "mir/optional_value.h" namespace mir { namespace test { namespace doubles { struct StubDevice : input::Device { StubDevice(MirInputDeviceId id, input::DeviceCapabilities caps, std::string const& name, std::string const& unique_id) : device_id(id), device_capabilities(caps), device_name(name), device_unique_id(unique_id) {} MirInputDeviceId id() const override { return device_id; } input::DeviceCapabilities capabilities() const override { return device_capabilities; } std::string name() const override { return device_name; } std::string unique_id() const override { return device_unique_id; } mir::optional_value pointer_configuration() const override { return {}; } void apply_pointer_configuration(MirPointerConfig const&) override { } mir::optional_value touchpad_configuration() const override { return {}; } void apply_touchpad_configuration(MirTouchpadConfig const&) override { } mir::optional_value keyboard_configuration() const override { return {}; } void apply_keyboard_configuration(MirKeyboardConfig const&) override { } MirInputDeviceId device_id; input::DeviceCapabilities device_capabilities; std::string device_name; std::string device_unique_id; }; } } } #endif ./include/test/mir/test/doubles/null_gl_context.h0000644000004100000410000000206313115234664022427 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_TEST_DOUBLES_NULL_GL_CONTEXT_H_ #define MIR_TEST_DOUBLES_NULL_GL_CONTEXT_H_ #include "mir/renderer/gl/context.h" namespace mir { namespace test { namespace doubles { class NullGLContext : public renderer::gl::Context { public: void make_current() const {} void release_current() const {} }; } } } #endif /* MIR_TEST_DOUBLES_NULL_GL_CONTEXT_H_ */ ./include/test/mir/test/doubles/fake_display.h0000644000004100000410000000420213115234664021657 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_TEST_DOUBLES_FAKE_DISPLAY_H_ #define MIR_TEST_DOUBLES_FAKE_DISPLAY_H_ #include "mir/test/doubles/null_display.h" #include "mir/fd.h" #include "mir/geometry/rectangle.h" #include #include #include namespace mir { namespace test { namespace doubles { class StubDisplayConfig; class FakeDisplay : public NullDisplay { public: FakeDisplay(); explicit FakeDisplay(std::vector const& output_rects); void for_each_display_sync_group(std::function const& f) override; std::unique_ptr configuration() const override; void register_configuration_change_handler( mir::graphics::EventHandlerRegister& handlers, mir::graphics::DisplayConfigurationChangeHandler const& handler) override; bool apply_if_configuration_preserves_display_buffers(graphics::DisplayConfiguration const&) override; void configure(mir::graphics::DisplayConfiguration const&) override; void emit_configuration_change_event( std::shared_ptr const& new_config); void wait_for_configuration_change_handler(); private: std::shared_ptr config; std::vector> groups; Fd const wakeup_trigger; std::atomic handler_called; std::mutex mutable configuration_mutex; }; } } } #endif //MIR_TEST_DOUBLES_FAKE_DISPLAY_H_ ./include/test/mir/test/doubles/mock_input_device_hub.h0000644000004100000410000000252413115234664023556 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_TEST_DOUBLES_MOCK_INPUT_DEVICE_HUB_H_ #define MIR_TEST_DOUBLES_MOCK_INPUT_DEVICE_HUB_H_ #include "mir/input/input_device_hub.h" #include namespace mir { namespace test { namespace doubles { struct MockInputDeviceHub : input::InputDeviceHub { MOCK_METHOD1(add_observer, void(std::shared_ptr const&)); MOCK_METHOD1(remove_observer, void(std::weak_ptr const&)); MOCK_METHOD1(for_each_input_device, void(std::function const&)); MOCK_METHOD1(for_each_mutable_input_device, void(std::function const&)); }; } } } #endif ./include/test/mir/test/doubles/null_display.h0000644000004100000410000000575213115234664021736 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_TEST_DOUBLES_NULL_DISPLAY_H_ #define MIR_TEST_DOUBLES_NULL_DISPLAY_H_ #include "mir/graphics/display.h" #include "mir/graphics/virtual_output.h" #include "mir/renderer/gl/context_source.h" #include "mir/test/doubles/null_gl_context.h" #include "mir/test/doubles/null_display_configuration.h" #include "mir/test/doubles/null_display_sync_group.h" namespace mir { namespace test { namespace doubles { class NullDisplay : public graphics::Display, public graphics::NativeDisplay, public renderer::gl::ContextSource { public: void for_each_display_sync_group(std::function const& f) override { f(group); } std::unique_ptr configuration() const override { return std::unique_ptr( new NullDisplayConfiguration ); } bool apply_if_configuration_preserves_display_buffers(graphics::DisplayConfiguration const&) override { return false; } void configure(graphics::DisplayConfiguration const&) override{} void register_configuration_change_handler( graphics::EventHandlerRegister&, graphics::DisplayConfigurationChangeHandler const&) override { } void register_pause_resume_handlers(graphics::EventHandlerRegister&, graphics::DisplayPauseHandler const&, graphics::DisplayResumeHandler const&) override { } void pause() override{} void resume() override {} std::shared_ptr create_hardware_cursor(std::shared_ptr const& /* initial_image */) override { return {}; } std::unique_ptr create_virtual_output(int /*width*/, int /*height*/) override { return nullptr; } graphics::NativeDisplay* native_display() override { return this; } std::unique_ptr create_gl_context() override { return std::unique_ptr{new NullGLContext()}; } graphics::Frame last_frame_on(unsigned) const override { return {}; } NullDisplaySyncGroup group; }; } } } #endif /* MIR_TEST_DOUBLES_NULL_DISPLAY_H_ */ ./include/test/mir/test/doubles/null_logger.h0000644000004100000410000000221413115234416021531 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TEST_DOUBLES_NULL_LOGGER_H_ #define MIR_TEST_DOUBLES_NULL_LOGGER_H_ #include "mir/logging/logger.h" namespace mir { namespace test { namespace doubles { /// Command line option to enable logging_opt extern char const* const logging_opt; extern char const* const logging_descr; class NullLogger : public mir::logging::Logger { void log(mir::logging::Severity, const std::string&, const std::string&) override; }; } } } #endif /* MIR_TEST_DOUBLES_NULL_LOGGER_H_ */ ./include/test/mir/test/doubles/mock_input_dispatcher.h0000644000004100000410000000223313115234416023577 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_TEST_DOUBLES_MOCK_INPUT_DISPATCHER_H_ #define MIR_TEST_DOUBLES_MOCK_INPUT_DISPATCHER_H_ #include "mir/input/input_dispatcher.h" #include namespace mir { namespace test { namespace doubles { struct MockInputDispatcher : public mir::input::InputDispatcher { MOCK_METHOD1(dispatch, bool(MirEvent const&)); MOCK_METHOD0(start, void()); MOCK_METHOD0(stop, void()); }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_MOCK_INPUT_DISPATCHER_H_ ./include/test/mir/test/doubles/stub_session_authorizer.h0000644000004100000410000000316513115234416024222 0ustar www-datawww-data/* * Copyright © 2013-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TEST_DOUBLES_STUB_SESSION_AUTHORIZER_H_ #define MIR_TEST_DOUBLES_STUB_SESSION_AUTHORIZER_H_ #include "mir/frontend/session_authorizer.h" namespace mir { namespace test { namespace doubles { class StubSessionAuthorizer : public frontend::SessionAuthorizer { bool connection_is_allowed(mir::frontend::SessionCredentials const&) override { return true; } bool configure_display_is_allowed(mir::frontend::SessionCredentials const&) override { return true; } bool set_base_display_configuration_is_allowed(mir::frontend::SessionCredentials const&) override { return true; } bool screencast_is_allowed(mir::frontend::SessionCredentials const&) override { return true; } bool prompt_session_is_allowed(mir::frontend::SessionCredentials const&) override { return true; } }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_STUB_SESSION_AUTHORIZER_H_ ./include/test/mir/test/doubles/mock_window_manager.h0000644000004100000410000000601513115234664023242 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TEST_DOUBLES_MOCK_WINDOW_MANAGER_H_ #define MIR_TEST_DOUBLES_MOCK_WINDOW_MANAGER_H_ #include "mir/shell/window_manager.h" #include "mir/shell/surface_specification.h" #include "mir/scene/surface_creation_parameters.h" #include namespace mir { namespace test { namespace doubles { struct MockWindowManager : shell::WindowManager { MockWindowManager() { using namespace ::testing; ON_CALL(*this, add_surface(_,_,_)).WillByDefault(Invoke(add_surface_default)); } MOCK_METHOD1(add_session, void (std::shared_ptr const&)); MOCK_METHOD1(remove_session, void (std::shared_ptr const&)); MOCK_METHOD3(add_surface, frontend::SurfaceId( std::shared_ptr const& session, scene::SurfaceCreationParameters const& params, std::function const& session, scene::SurfaceCreationParameters const& params)> const& build)); MOCK_METHOD3(modify_surface, void(std::shared_ptr const&, std::shared_ptr const&, shell::SurfaceSpecification const&)); MOCK_METHOD2(remove_surface, void(std::shared_ptr const&, std::weak_ptr const&)); MOCK_METHOD1(add_display, void(geometry::Rectangle const&)); MOCK_METHOD1(remove_display, void(geometry::Rectangle const&)); MOCK_METHOD1(handle_keyboard_event, bool(MirKeyboardEvent const*)); MOCK_METHOD1(handle_touch_event, bool(MirTouchEvent const*)); MOCK_METHOD1(handle_pointer_event, bool(MirPointerEvent const*)); MOCK_METHOD3(handle_raise_surface, void(std::shared_ptr const&, std::shared_ptr const&, uint64_t)); MOCK_METHOD4(set_surface_attribute, int(std::shared_ptr const& session, std::shared_ptr const& surface, MirWindowAttrib attrib, int value)); static frontend::SurfaceId add_surface_default( std::shared_ptr const& session, scene::SurfaceCreationParameters const& params, std::function const& session, scene::SurfaceCreationParameters const& params)> const& build) { return build(session, params); } }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_WINDOW_MANAGER_H_ */ ./include/test/mir/test/doubles/mock_input_device_observer.h0000644000004100000410000000243713115234416024625 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_TEST_DOUBLES_MOCK_INPUT_DEVICE_OBSERVER_H_ #define MIR_TEST_DOUBLES_MOCK_INPUT_DEVICE_OBSERVER_H_ #include "mir/input/input_device_observer.h" #include namespace mir { namespace test { namespace doubles { struct MockInputDeviceObserver : input::InputDeviceObserver { MOCK_METHOD1(device_added, void(std::shared_ptr const& device)); MOCK_METHOD1(device_changed, void(std::shared_ptr const& device)); MOCK_METHOD1(device_removed, void(std::shared_ptr const& device)); MOCK_METHOD0(changes_complete, void()); }; } } } #endif ./include/test/mir/test/doubles/stub_cursor.h0000644000004100000410000000215613115234416021577 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TEST_DOUBLES_STUB_CURSOR_H_ #define MIR_TEST_DOUBLES_STUB_CURSOR_H_ #include "mir/graphics/cursor.h" namespace mir { namespace test { namespace doubles { struct StubCursor : public graphics::Cursor { void show() override {} void show(graphics::CursorImage const&) override {} void hide() override {} void move_to(geometry::Point) override {} }; } } } // namespace mir #endif /* MIR_TEST_DOUBLES_STUB_CURSOR_H_ */ ./include/test/mir/test/validity_matchers.h0000644000004100000410000000451613115234664021312 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_TEST_VALIDITY_MATCHERS_H_ #define MIR_TEST_VALIDITY_MATCHERS_H_ #include #include "mir_toolkit/mir_client_library.h" using ::testing::MakePolymorphicMatcher; using ::testing::MatchResultListener; using ::testing::NotNull; using ::testing::PolymorphicMatcher; class IsValidMatcher { public: // To implement a polymorphic matcher, first define a COPYABLE class // that has three members MatchAndExplain(), DescribeTo(), and // DescribeNegationTo(), like the following. // In this example, we want to use NotNull() with any pointer, so // MatchAndExplain() accepts a pointer of any type as its first argument. // In general, you can define MatchAndExplain() as an ordinary method or // a method template, or even overload it. template bool MatchAndExplain(T* p, MatchResultListener* listener) const; // Describes the property of a value matching this matcher. void DescribeTo(::std::ostream* os) const { *os << "is valid"; } // Describes the property of a value NOT matching this matcher. void DescribeNegationTo(::std::ostream* os) const { *os << "is not valid"; } }; template<> bool IsValidMatcher::MatchAndExplain(MirConnection* connection, MatchResultListener* listener) const; template<> bool IsValidMatcher::MatchAndExplain(MirWindow* surface, MatchResultListener* listener) const; // To construct a polymorphic matcher, pass an instance of the class // to MakePolymorphicMatcher(). Note the return type. inline PolymorphicMatcher IsValid() { return MakePolymorphicMatcher(IsValidMatcher{}); } #endif // MIR_TEST_VALIDITY_MATCHERS_H_ ./include/test/mir/test/death.h0000644000004100000410000000246513115234664016665 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_TEST_DEATH_H_ #define MIR_TEST_DEATH_H_ #include #include namespace mir { namespace test { inline void disable_core_dump() { struct rlimit zeroes{0,0}; setrlimit(RLIMIT_CORE, &zeroes); } } } // namespace mir::test #define MIR_EXPECT_DEATH(statement, message) \ EXPECT_DEATH( \ { \ ::mir::test::disable_core_dump(); \ { statement ; } \ }, message); #define MIR_EXPECT_EXIT(statement, how, message) \ EXPECT_EXIT( \ { \ ::mir::test::disable_core_dump(); \ { statement ; } \ }, how, message); #endif /* MIR_TEST_DEATH_H_ */ ./include/test/mir/test/event_matchers.h0000644000004100000410000004255613115234664020614 0ustar www-datawww-data/* * Copyright © 2013-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr * Andreas Pokorny */ #ifndef MIR_TEST_CLIENT_EVENT_MATCHERS_H_ #define MIR_TEST_CLIENT_EVENT_MATCHERS_H_ #include #include "mir_toolkit/event.h" #include #include #include void PrintTo(MirEvent const& event, std::ostream *os); void PrintTo(MirEvent const* event, std::ostream *os); namespace mir { namespace test { /*! * Pointer and reference adaptors for MirEvent inside gmock matchers. * \{ */ inline MirEvent const* to_address(MirEvent const* event) { return event; } inline MirEvent const* to_address(MirEvent const& event) { return &event; } inline MirEvent const& to_ref(MirEvent const* event) { return *event; } inline MirEvent const& to_ref(MirEvent const& event) { return event; } inline MirKeyboardEvent const* maybe_key_event(MirEvent const* event) { if (mir_event_get_type(event) != mir_event_type_input) return nullptr; auto input_event = mir_event_get_input_event(event); if (mir_input_event_get_type(input_event) != mir_input_event_type_key) return nullptr; return mir_input_event_get_keyboard_event(input_event); } inline MirTouchEvent const* maybe_touch_event(MirEvent const* event) { if (mir_event_get_type(event) != mir_event_type_input) return nullptr; auto input_event = mir_event_get_input_event(event); if (mir_input_event_get_type(input_event) != mir_input_event_type_touch) return nullptr; return mir_input_event_get_touch_event(input_event); } inline MirPointerEvent const* maybe_pointer_event(MirEvent const* event) { if (mir_event_get_type(event) != mir_event_type_input) return nullptr; auto input_event = mir_event_get_input_event(event); if (mir_input_event_get_type(input_event) != mir_input_event_type_pointer) return nullptr; return mir_input_event_get_pointer_event(input_event); } /** * \} */ MATCHER(KeyDownEvent, "") { auto kev = maybe_key_event(to_address(arg)); if (kev == nullptr) return false; if (mir_keyboard_event_action(kev) != mir_keyboard_action_down) return false; return true; } MATCHER(KeyRepeatEvent, "") { auto kev = maybe_key_event(to_address(arg)); if (kev == nullptr) return false; if (mir_keyboard_event_action(kev) != mir_keyboard_action_repeat) return false; return true; } MATCHER(KeyUpEvent, "") { auto kev = maybe_key_event(to_address(arg)); if (kev == nullptr) return false; if (mir_keyboard_event_action(kev) != mir_keyboard_action_up) return false; return true; } MATCHER_P(KeyWithModifiers, modifiers, "") { auto kev = maybe_key_event(to_address(arg)); if (kev == nullptr) return false; if(mir_keyboard_event_modifiers(kev) != modifiers) { return false; } return true; } MATCHER_P(KeyOfSymbol, keysym, "") { auto kev = maybe_key_event(to_address(arg)); if (kev == nullptr) return false; if(mir_keyboard_event_key_code(kev) != static_cast(keysym)) return false; return true; } MATCHER_P(KeyOfScanCode, code, "") { auto kev = maybe_key_event(to_address(arg)); if (kev == nullptr) return false; if(mir_keyboard_event_scan_code(kev) != code) return false; return true; } MATCHER_P(MirKeyboardEventMatches, event, "") { auto expected = maybe_key_event(to_address(event)); auto actual = maybe_key_event(to_address(arg)); if (expected == nullptr || actual == nullptr) return false; return mir_keyboard_event_action(expected) == mir_keyboard_event_action(actual) && mir_keyboard_event_key_code(expected) == mir_keyboard_event_key_code(actual) && mir_keyboard_event_scan_code(expected) == mir_keyboard_event_scan_code(actual) && mir_keyboard_event_modifiers(expected) == mir_keyboard_event_modifiers(actual); } MATCHER_P(MirTouchEventMatches, event, "") { auto expected = maybe_touch_event(to_address(event)); auto actual = maybe_touch_event(to_address(arg)); if (expected == nullptr || actual == nullptr) return false; auto tc = mir_touch_event_point_count(actual); if (mir_touch_event_point_count(expected) != tc) return false; for (unsigned i = 0; i != tc; i++) { if (mir_touch_event_id(actual, i) != mir_touch_event_id(expected, i) || mir_touch_event_action(actual, i) != mir_touch_event_action(expected, i) || mir_touch_event_tooltype(actual, i) != mir_touch_event_tooltype(expected, i) || mir_touch_event_axis_value(actual, i, mir_touch_axis_x) != mir_touch_event_axis_value(expected, i, mir_touch_axis_x) || mir_touch_event_axis_value(actual, i, mir_touch_axis_y) != mir_touch_event_axis_value(expected, i, mir_touch_axis_y)) { return false; } } return true; } MATCHER(PointerEnterEvent, "") { auto pev = maybe_pointer_event(to_address(arg)); if (pev == nullptr) return false; if (mir_pointer_event_action(pev) == mir_pointer_action_enter) return true; return false; } MATCHER(PointerLeaveEvent, "") { auto pev = maybe_pointer_event(to_address(arg)); if (pev == nullptr) return false; if (mir_pointer_event_action(pev) == mir_pointer_action_leave) return true; return false; } inline bool button_event_matches(MirPointerEvent const* pev, float x, float y, MirPointerAction action, MirPointerButtons button_state, bool check_action = true, bool check_buttons = true, bool check_axes = true) { if (pev == nullptr) return false; if (check_action && mir_pointer_event_action(pev) != action) return false; if (check_buttons && mir_pointer_event_buttons(pev) != button_state) return false; if (check_axes && mir_pointer_event_axis_value(pev, mir_pointer_axis_x) != x) return false; if (check_axes && mir_pointer_event_axis_value(pev, mir_pointer_axis_y) != y) return false; return true; } MATCHER_P2(ButtonDownEvent, x, y, "") { auto pev = maybe_pointer_event(to_address(arg)); return button_event_matches(pev, x, y, mir_pointer_action_button_down, 0, true, false); } MATCHER_P2(ButtonDownEventWithButton, pos, button, "") { auto pev = maybe_pointer_event(to_address(arg)); if (pev == nullptr) return false; if (mir_pointer_event_action(pev) != mir_pointer_action_button_down) return false; if (mir_pointer_event_button_state(pev, static_cast(button)) == false) return false; if (mir_pointer_event_axis_value(pev, mir_pointer_axis_x) != pos.x.as_int()) return false; if (mir_pointer_event_axis_value(pev, mir_pointer_axis_y) != pos.y.as_int()) return false; return true; } MATCHER_P2(ButtonUpEvent, x, y, "") { auto pev = maybe_pointer_event(to_address(arg)); return button_event_matches(pev, x, y, mir_pointer_action_button_up, 0, true, false); } MATCHER_P3(ButtonsDown, x, y, buttons, "") { auto pev = maybe_pointer_event(to_address(arg)); return button_event_matches(pev, x, y, mir_pointer_action_button_down, buttons, false); } MATCHER_P3(ButtonsUp, x, y, buttons, "") { auto pev = maybe_pointer_event(to_address(arg)); return button_event_matches(pev, x, y, mir_pointer_action_button_up, buttons, false); } MATCHER_P2(ButtonUpEventWithButton, pos, button, "") { auto pev = maybe_pointer_event(to_address(arg)); if (pev == nullptr) return false; if (mir_pointer_event_action(pev) != mir_pointer_action_button_up) return false; if (mir_pointer_event_button_state(pev, button) == true) return false; if (mir_pointer_event_axis_value(pev, mir_pointer_axis_x) != pos.x.as_int()) return false; if (mir_pointer_event_axis_value(pev, mir_pointer_axis_y) != pos.y.as_int()) return false; return true; } MATCHER_P2(PointerAxisChange, scroll_axis, value, "") { auto parg = to_address(arg); auto pev = maybe_pointer_event(parg); if (pev == nullptr) return false; if (mir_pointer_event_action(pev) != mir_pointer_action_motion) return false; if (mir_pointer_event_axis_value(pev, scroll_axis) != value) return false; return true; } MATCHER_P2(TouchEvent, x, y, "") { auto tev = maybe_touch_event(to_address(arg)); if (tev == nullptr) return false; if (mir_touch_event_action(tev, 0) != mir_touch_action_down) return false; if (std::abs(mir_touch_event_axis_value(tev, 0, mir_touch_axis_x) - x) > 0.5f) return false; if (std::abs(mir_touch_event_axis_value(tev, 0, mir_touch_axis_y) - y) > 0.5f) return false; return true; } MATCHER_P4(TouchContact, slot, action, x, y, "") { auto tev = maybe_touch_event(to_address(arg)); if (tev == nullptr) return false; if (mir_touch_event_action(tev, slot) != action) return false; if (std::abs(mir_touch_event_axis_value(tev, slot, mir_touch_axis_x) - x) > 0.5f) return false; if (std::abs(mir_touch_event_axis_value(tev, slot, mir_touch_axis_y) - y) > 0.5f) return false; return true; } MATCHER_P2(TouchUpEvent, x, y, "") { auto tev = maybe_touch_event(to_address(arg)); if (tev == nullptr) return false; if (mir_touch_event_action(tev, 0) != mir_touch_action_up) return false; if (mir_touch_event_axis_value(tev, 0, mir_touch_axis_x) != x) return false; if (mir_touch_event_axis_value(tev, 0, mir_touch_axis_y) != y) return false; return true; } MATCHER_P2(PointerEventWithPosition, x, y, "") { auto pev = maybe_pointer_event(to_address(arg)); if (pev == nullptr) return false; if (mir_pointer_event_action(pev) != mir_pointer_action_motion) return false; if (mir_pointer_event_axis_value(pev, mir_pointer_axis_x) != x) return false; if (mir_pointer_event_axis_value(pev, mir_pointer_axis_y) != y) return false; return true; } MATCHER_P2(PointerEnterEventWithPosition, x, y, "") { auto pev = maybe_pointer_event(to_address(arg)); if (pev == nullptr) return false; if (mir_pointer_event_action(pev) != mir_pointer_action_enter) return false; if (mir_pointer_event_axis_value(pev, mir_pointer_axis_x) != x) return false; if (mir_pointer_event_axis_value(pev, mir_pointer_axis_y) != y) return false; return true; } MATCHER_P(PointerEventWithModifiers, modifiers, "") { auto pev = maybe_pointer_event(to_address(arg)); if (pev && mir_pointer_event_modifiers(pev) == modifiers) return true; return false; } MATCHER_P2(PointerEventWithDiff, expect_dx, expect_dy, "") { auto pev = maybe_pointer_event(to_address(arg)); if (pev == nullptr) return false; if (mir_pointer_event_action(pev) != mir_pointer_action_motion) return false; auto const error = 0.00001f; auto const actual_dx = mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x); if (std::abs(expect_dx - actual_dx) > error) return false; auto const actual_dy = mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y); if (std::abs(expect_dy - actual_dy) > error) return false; return true; } MATCHER_P2(PointerEnterEventWithDiff, expect_dx, expect_dy, "") { auto pev = maybe_pointer_event(to_address(arg)); if (pev == nullptr) return false; if (mir_pointer_event_action(pev) != mir_pointer_action_enter) return false; auto const error = 0.00001f; auto const actual_dx = mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_x); if (std::abs(expect_dx - actual_dx) > error) return false; auto const actual_dy = mir_pointer_event_axis_value(pev, mir_pointer_axis_relative_y); if (std::abs(expect_dy - actual_dy) > error) return false; return true; } MATCHER_P4(TouchEventInDirection, x0, y0, x1, y1, "") { auto tev = maybe_touch_event(to_address(arg)); if (tev == nullptr) return false; if (mir_touch_event_action(tev, 0) != mir_touch_action_change) return false; auto x2 = mir_touch_event_axis_value(tev, 0, mir_touch_axis_x); auto y2 = mir_touch_event_axis_value(tev, 0, mir_touch_axis_y); float dx1 = x1 - x0; float dy1 = y1 - y0; float dx2 = x2 - x0; float dy2 = y2 - y0; float dot_product = dx1 * dx2 + dy1 * dy2; // Return true if both vectors are roughly the same direction (within // 90 degrees). return dot_product > 0.0f; } MATCHER(TouchMovementEvent, "") { auto tev = maybe_touch_event(to_address(arg)); if (tev == nullptr) return false; if (mir_touch_event_action(tev, 0) != mir_touch_action_change) return false; return true; } MATCHER(PointerMovementEvent, "") { auto pev = maybe_pointer_event(to_address(arg)); if (pev == nullptr) return false; if (mir_pointer_event_action(pev) != mir_pointer_action_motion) return false; return true; } MATCHER_P2(WindowEvent, attrib, value, "") { auto as_address = to_address(arg); if (mir_event_get_type(as_address) != mir_event_type_window) return false; auto surface_ev = mir_event_get_window_event(as_address); auto window_attrib = mir_window_event_get_attribute(surface_ev); if (window_attrib != attrib) return false; if (mir_window_event_get_attribute_value(surface_ev) != value) return false; return true; } MATCHER_P(KeymapEventForDevice, device_id, "") { auto as_address = to_address(arg); if (mir_event_get_type(as_address) != mir_event_type_keymap) return false; auto kmev = mir_event_get_keymap_event(as_address); return device_id == mir_keymap_event_get_device_id(kmev); } MATCHER_P(OrientationEvent, direction, "") { auto as_address = to_address(arg); if (mir_event_get_type(as_address) != mir_event_type_orientation) return false; auto oev = mir_event_get_orientation_event(as_address); if (mir_orientation_event_get_direction(oev) != direction) return false; return true; } MATCHER_P(InputDeviceIdMatches, device_id, "") { if (mir_event_get_type(to_address(arg)) != mir_event_type_input) return false; auto input_event = mir_event_get_input_event(to_address(arg)); return mir_input_event_get_device_id(input_event) == device_id; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" MATCHER(InputConfigurationEvent, "") { auto as_address = to_address(arg); if (mir_event_get_type(as_address) != mir_event_type_input_configuration) return true; return false; } #pragma GCC diagnostic pop MATCHER(InputDeviceStateEvent, "") { auto as_address = to_address(arg); if (mir_event_get_type(as_address) == mir_event_type_input_device_state) return true; return false; } MATCHER_P(DeviceStateWithPressedKeys, keys, "") { auto as_address = to_address(arg); if (mir_event_get_type(as_address) != mir_event_type_input_device_state) return false; auto device_state = mir_event_get_input_device_state_event(as_address); for (size_t index = 0, count = mir_input_device_state_event_device_count(device_state); index != count; ++index) { auto key_count = mir_input_device_state_event_device_pressed_keys_count(device_state, index); auto it_keys = begin(keys); auto end_keys = end(keys); decltype(key_count) num_required_keys = distance(it_keys, end_keys); if (num_required_keys != key_count) continue; std::vector pressed_keys; for (uint32_t i = 0; i < key_count; i++) { pressed_keys.push_back( mir_input_device_state_event_device_pressed_keys_for_index(device_state, index, i)); } if (!std::equal(it_keys, end_keys, std::begin(pressed_keys))) continue; return true; } return false; } MATCHER_P2(DeviceStateWithPosition, x, y, "") { auto as_address = to_address(arg); if (mir_event_get_type(as_address) != mir_event_type_input_device_state) return false; auto device_state = mir_event_get_input_device_state_event(as_address); return x == mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_x) && y == mir_input_device_state_event_pointer_axis(device_state, mir_pointer_axis_y); } MATCHER_P(RectanglesMatches, rectangles, "") { return arg == rectangles; } } } #endif ./include/test/mir/test/cross_process_action.h0000644000004100000410000000226613115234416022016 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_TEST_CROSS_PROCESS_ACTION_H_ #define MIR_TEST_CROSS_PROCESS_ACTION_H_ #include "mir/test/cross_process_sync.h" #include #include namespace mir { namespace test { class CrossProcessAction { public: void exec(std::function const& f); void operator()(std::chrono::milliseconds timeout = std::chrono::milliseconds{-1}); private: CrossProcessSync start_sync; CrossProcessSync finish_sync; }; } } #endif /* MIR_TEST_CROSS_PROCESS_ACTION_H_ */ ./include/test/mir/test/popen.h0000644000004100000410000000241313115234416016705 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alberto Aguirre */ #ifndef MIR_TEST_POPEN_H_ #define MIR_TEST_POPEN_H_ #include #include #include namespace mir { namespace test { /** * Popen - A popen c++ wrapper */ class Popen { public: Popen(std::string const& cmd); /** * Read a line from the output of the executed command * returns false if there is nothing more to read */ bool get_line(std::string& line); private: Popen() = delete; Popen(Popen const&) = delete; Popen& operator=(Popen const&) = delete; std::unique_ptr raw_stream; }; } } #endif ./include/test/mir/test/fake_shared.h0000644000004100000410000000172613115234416020026 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_TEST_FAKE_SHARED_H_ #define MIR_TEST_FAKE_SHARED_H_ #include "mir/test/empty_deleter.h" #include namespace mir { namespace test { template std::shared_ptr fake_shared(Type& t) { return {&t, EmptyDeleter()}; } } } #endif /* MIR_TEST_FAKE_SHARED_H_ */ ./include/test/mir/test/spin_wait.h0000644000004100000410000000207113115234416017561 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_TEST_SPIN_WAIT_H_ #define MIR_TEST_SPIN_WAIT_H_ #include #include namespace mir { namespace test { bool spin_wait_for_condition_or_timeout( std::function const& condition, std::chrono::milliseconds timeout, std::chrono::milliseconds spin_period = std::chrono::milliseconds{10}); } } #endif /* MIR_TEST_SPIN_WAIT_H_ */ ./include/test/mir/test/event_factory.h0000644000004100000410000000434713115234416020444 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TEST_EVENT_FACTORY_H #define MIR_TEST_EVENT_FACTORY_H #include "mir/geometry/point.h" namespace mir { namespace input { namespace synthesis { enum class EventAction { Down, Up }; class KeyParameters { public: KeyParameters(); KeyParameters& from_device(int device_id); KeyParameters& of_scancode(int scancode); KeyParameters& with_action(EventAction action); int device_id; int scancode; EventAction action; }; KeyParameters a_key_down_event(); KeyParameters a_key_up_event(); class ButtonParameters { public: ButtonParameters(); ButtonParameters& from_device(int device_id); ButtonParameters& of_button(int scancode); ButtonParameters& with_action(EventAction action); int device_id; int button; EventAction action; }; ButtonParameters a_button_down_event(); ButtonParameters a_button_up_event(); class MotionParameters { public: MotionParameters(); MotionParameters& from_device(int device_id); MotionParameters& with_movement(int rel_x, int rel_y); int device_id; int rel_x; int rel_y; }; MotionParameters a_pointer_event(); class TouchParameters { public: enum class Action { Tap = 0, Move, Release }; TouchParameters(); TouchParameters& from_device(int device_id); TouchParameters& at_position(geometry::Point abs_pos); TouchParameters& with_action(Action touch_action); int device_id; int abs_x; int abs_y; Action action; }; TouchParameters a_touch_event(); } } } #endif /* MIR_TEST_EVENT_FACTORY_H */ ./include/test/mir/test/auto_unblock_thread.h0000644000004100000410000000477513115234416021615 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alberto Aguirre */ /** AutoUnblockThread is a helper thread class that can gracefully shutdown * at destruction time. This is helpul for tests that botch create * threads and use ASSERT macros for example (or any other condition that * makes the test exit early). Using naked std::thread would call std::terminate * under such conditions. */ #ifndef MIR_TEST_AUTO_UNBLOCK_THREAD_H_ #define MIR_TEST_AUTO_UNBLOCK_THREAD_H_ #include #include namespace mir { namespace test { class AutoJoinThread { public: AutoJoinThread() = default; template explicit AutoJoinThread(Callable&& f, Args&&... args) : thread{std::forward(f), std::forward(args)...} {} ~AutoJoinThread() { stop(); } void stop() { if (thread.joinable()) thread.join(); } std::thread::native_handle_type native_handle() { return thread.native_handle(); } AutoJoinThread(AutoJoinThread&& t) = default; AutoJoinThread& operator=(AutoJoinThread&& t) = default; private: std::thread thread; }; class AutoUnblockThread : public AutoJoinThread { public: AutoUnblockThread() = default; template explicit AutoUnblockThread(std::function const& unblock, Callable&& f, Args&&... args) : AutoJoinThread{std::forward(f), std::forward(args)...}, unblock{unblock} {} ~AutoUnblockThread() { stop(); } AutoUnblockThread(AutoUnblockThread&& t) = default; AutoUnblockThread& operator=(AutoUnblockThread&& t) = default; void stop() { if (unblock) unblock(); AutoJoinThread::stop(); } private: std::function unblock; }; } } #endif ./include/test/mir/test/display_config_matchers.h0000644000004100000410000000772413115234664022463 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_TEST_DISPLAY_CONFIG_MATCHERS_H_ #define MIR_TEST_DISPLAY_CONFIG_MATCHERS_H_ #include "mir_toolkit/client_types.h" #include #include //avoid a valgrind complaint by defining printer for this type static void PrintTo(MirDisplayConfiguration const&, ::std::ostream*) __attribute__ ((unused)); void PrintTo(MirDisplayConfiguration const&, ::std::ostream*) { } namespace mir { namespace protobuf { class DisplayConfiguration; class Connection; static void PrintTo(mir::protobuf::DisplayConfiguration const&, ::std::ostream*) __attribute__ ((unused)); void PrintTo(mir::protobuf::DisplayConfiguration const&, ::std::ostream*) {} static void PrintTo(mir::protobuf::Connection const&, ::std::ostream*) __attribute__ ((unused)); void PrintTo(mir::protobuf::Connection const&, ::std::ostream*) { } } namespace graphics { class DisplayConfiguration; } namespace test { bool compare_display_configurations( testing::MatchResultListener* listener, graphics::DisplayConfiguration const& display_config1, graphics::DisplayConfiguration const& display_config2); bool compare_display_configurations( testing::MatchResultListener* listener, MirDisplayConfiguration const& client_config, graphics::DisplayConfiguration const& display_config); bool compare_display_configurations( testing::MatchResultListener* listener, protobuf::DisplayConfiguration const& protobuf_config, graphics::DisplayConfiguration const& display_config); bool compare_display_configurations( testing::MatchResultListener* listener, MirDisplayConfiguration const* client_config1, MirDisplayConfiguration const* client_config2); bool compare_display_configurations( testing::MatchResultListener* listener, MirDisplayConfiguration const& client_config, protobuf::DisplayConfiguration const& protobuf_config); bool compare_display_configurations( testing::MatchResultListener* listener, graphics::DisplayConfiguration const& display_config1, MirDisplayConfiguration const* display_config2); bool compare_display_configurations( testing::MatchResultListener* listener, std::shared_ptr & display_config1, MirDisplayConfiguration const* display_config2); bool compare_display_configurations( testing::MatchResultListener* listener, MirDisplayConfiguration const* display_config2, graphics::DisplayConfiguration const& display_config1); bool compare_display_configurations( testing::MatchResultListener* listener, MirDisplayConfig const* client_config, graphics::DisplayConfiguration const& server_config); bool compare_display_configurations( testing::MatchResultListener* listener, graphics::DisplayConfiguration const& server_config, MirDisplayConfig const* client_config); bool compare_display_configurations( testing::MatchResultListener* listener, MirDisplayConfig const* config1, MirDisplayConfig const* config2); bool compare_display_configurations( testing::MatchResultListener* listener, std::shared_ptr const& config1, MirDisplayConfig const* config2); MATCHER_P(DisplayConfigMatches, config, "") { return compare_display_configurations(result_listener, arg, config); } } } #endif /* MIR_TEST_DISPLAY_CONFIG_MATCHERS_H_ */ ./include/test/mir/test/signal.h0000644000004100000410000000361513115234664017053 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_TEST_SIGNAL_H_ #define MIR_TEST_SIGNAL_H_ #include #include #include #include namespace mir { namespace test { /** * @brief A threadsafe, waitable signal */ class Signal { public: void raise(); bool raised(); void wait(); template bool wait_for(std::chrono::duration delay) { std::unique_lock lock(mutex); return cv.wait_for(lock, delay, [this]() { return signalled; }); } template bool wait_until(std::chrono::time_point const& time) { std::unique_lock lock(mutex); return cv.wait_until(lock, time, [this]() { return signalled; }); } void reset(); private: std::mutex mutex; std::condition_variable cv; bool signalled{false}; }; ACTION_P(ReturnFalseAndWakeUp, signal) { signal->raise(); return false; } ACTION_P(WakeUp, signal) { signal->raise(); } ACTION_P2(WakeUpWhenZero, signal, atomic_int) { if (atomic_int->fetch_sub(1) == 1) { signal->raise(); } } } } #endif // MIR_TEST_SIGNAL_H_ ./include/test/mir/test/cross_process_sync.h0000644000004100000410000000356213115234416021515 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Thomas Voss */ #ifndef MIR_TEST_CROSS_PROCESS_SYNC_H_ #define MIR_TEST_CROSS_PROCESS_SYNC_H_ #include namespace mir { namespace test { // A cross-process synchronization primitive that supports simple // wait-condition-like scenarios. class CrossProcessSync { public: CrossProcessSync(); CrossProcessSync(const CrossProcessSync& rhs); ~CrossProcessSync() noexcept; CrossProcessSync& operator=(const CrossProcessSync& rhs); // Try to signal the other side that we are ready for at most duration milliseconds. // Throws a std::runtime_error if not successful. void try_signal_ready_for(const std::chrono::milliseconds& duration); void try_signal_ready_for(); // Wait for the other sides to signal readiness for at most duration milliseconds. // Returns the number of ready signals that have been collected since creation. // Throws std::runtime_error if not successful. unsigned int wait_for_signal_ready_for(const std::chrono::milliseconds& duration); unsigned int wait_for_signal_ready_for(); void signal_ready(); unsigned int wait_for_signal_ready(); private: int fds[2]; unsigned int counter; }; } } #endif // MIR_TEST_CROSS_PROCESS_SYNC_H_ ./include/renderer/0000755000004100000410000000000013115234665014502 5ustar www-datawww-data./include/renderer/mir/0000755000004100000410000000000013115234665015271 5ustar www-datawww-data./include/renderer/mir/renderer/0000755000004100000410000000000013115234665017077 5ustar www-datawww-data./include/renderer/mir/renderer/renderer_factory.h0000644000004100000410000000243313115234664022606 0ustar www-datawww-data/* * Copyright © 2013-2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_RENDERER_RENDERER_FACTORY_H_ #define MIR_RENDERER_RENDERER_FACTORY_H_ #include namespace mir { namespace graphics { struct DisplayBuffer; } namespace renderer { class Renderer; class RendererFactory { public: virtual ~RendererFactory() = default; virtual std::unique_ptr create_renderer_for(graphics::DisplayBuffer& display_buffer) = 0; protected: RendererFactory() = default; RendererFactory(RendererFactory const&) = delete; RendererFactory& operator=(RendererFactory const&) = delete; }; } } #endif /* MIR_RENDERER_RENDERER_FACTORY_H_ */ ./include/renderer/mir/renderer/renderer.h0000644000004100000410000000271213115234664021057 0ustar www-datawww-data/* * Copyright © 2012-2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Thomas Voss */ #ifndef MIR_RENDERER_RENDERER_H_ #define MIR_RENDERER_RENDERER_H_ #include "mir/geometry/rectangle.h" #include "mir/graphics/renderable.h" #include "mir_toolkit/common.h" namespace mir { namespace renderer { class Renderer { public: virtual ~Renderer() = default; virtual void set_viewport(geometry::Rectangle const& rect) = 0; // Mirroring is to be applied after orientation virtual void set_output_transform(MirOrientation orientation, MirMirrorMode mode) = 0; virtual void render(graphics::RenderableList const&) const = 0; virtual void suspend() = 0; // called when render() is skipped protected: Renderer() = default; Renderer(const Renderer&) = delete; Renderer& operator=(const Renderer&) = delete; }; } } #endif // MIR_RENDERER_RENDERER_H_ ./include/client/0000755000004100000410000000000013115234413014141 5ustar www-datawww-data./include/client/mir/0000755000004100000410000000000013115234677014744 5ustar www-datawww-data./include/client/mir/events/0000755000004100000410000000000013115234677016250 5ustar www-datawww-data./include/client/mir/events/event_builders.h0000644000004100000410000001614113115234664021432 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Robert Carr */ #ifndef MIR_EVENT_BUILDERS_H_ #define MIR_EVENT_BUILDERS_H_ #include "mir_toolkit/event.h" #include "mir/geometry/size.h" #include "mir/geometry/point.h" #include "mir/geometry/rectangle.h" #include "mir/geometry/displacement.h" #include "mir/frontend/surface_id.h" #include "mir/events/input_device_state.h" #include "mir/events/contact_state.h" #include #include #include #include namespace mir { typedef std::unique_ptr EventUPtr; namespace events { // Surface orientation change event EventUPtr make_event(frontend::SurfaceId const& surface_id, MirOrientation orientation); // Prompt session state change event EventUPtr make_event(MirPromptSessionState state); // Surface resize event EventUPtr make_event(frontend::SurfaceId const& surface_id, geometry::Size const& size); // Surface configure event EventUPtr make_event(frontend::SurfaceId const& surface_id, MirSurfaceAttrib attribute, int value) MIR_FOR_REMOVAL_IN_VERSION_1("use make_event with MirWindowAttribute instead"); // Window configure event EventUPtr make_event(frontend::SurfaceId const& surface_id, MirWindowAttrib attribute, int value); // Close surface event EventUPtr make_event(frontend::SurfaceId const& surface_id); // Keymap event EventUPtr make_event(frontend::SurfaceId const& surface_id, MirInputDeviceId id, std::string const& model, std::string const& layout, std::string const& variant, std::string const& options); // Surface output event EventUPtr make_event( frontend::SurfaceId const& surface_id, int dpi, float scale, double refresh_rate, MirFormFactor form_factor, uint32_t id); /// Surface placement event EventUPtr make_event(frontend::SurfaceId const& surface_id, geometry::Rectangle placement); // Key event EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp, std::vector const& cookie, MirKeyboardAction action, xkb_keysym_t key_code, int scan_code, MirInputEventModifiers modifiers); void set_modifier(MirEvent& event, MirInputEventModifiers modifiers); void set_cursor_position(MirEvent& event, mir::geometry::Point const& pos); void set_cursor_position(MirEvent& event, float x, float y); void set_button_state(MirEvent& event, MirPointerButtons button_state); // Deprecated version with uint64_t mac EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp, uint64_t mac, MirKeyboardAction action, xkb_keysym_t key_code, int scan_code, MirInputEventModifiers modifiers) MIR_FOR_REMOVAL_IN_VERSION_1("unused"); // Deprecated version without mac EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp, MirKeyboardAction action, xkb_keysym_t key_code, int scan_code, MirInputEventModifiers modifiers) MIR_FOR_REMOVAL_IN_VERSION_1("unused"); // Touch event EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp, std::vector const& mac, MirInputEventModifiers modifiers); // Deprecated version with uint64_t mac EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp, uint64_t mac, MirInputEventModifiers modifiers) MIR_FOR_REMOVAL_IN_VERSION_1("unused"); // Deprecated version without mac EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp, MirInputEventModifiers modifiers) MIR_FOR_REMOVAL_IN_VERSION_1("unused"); void add_touch(MirEvent &event, MirTouchId touch_id, MirTouchAction action, MirTouchTooltype tooltype, float x_axis_value, float y_axis_value, float pressure_value, float touch_major_value, float touch_minor_value, float size_value); // Pointer event // Deprecated version without relative axis EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp, uint64_t mac, MirInputEventModifiers modifiers, MirPointerAction action, MirPointerButtons buttons_pressed, float x_axis_value, float y_axis_value, float hscroll_value, float vscroll_value) MIR_FOR_REMOVAL_IN_VERSION_1("unused"); // Deprecated version without relative axis and mac EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp, MirInputEventModifiers modifiers, MirPointerAction action, MirPointerButtons buttons_pressed, float x_axis_value, float y_axis_value, float hscroll_value, float vscroll_value) MIR_FOR_REMOVAL_IN_VERSION_1("unused"); EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp, std::vector const& mac, MirInputEventModifiers modifiers, MirPointerAction action, MirPointerButtons buttons_pressed, float x_axis_value, float y_axis_value, float hscroll_value, float vscroll_value, float relative_x_value, float relative_y_value); // Deprecated version with uint64_t mac EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp, uint64_t mac, MirInputEventModifiers modifiers, MirPointerAction action, MirPointerButtons buttons_pressed, float x_axis_value, float y_axis_value, float hscroll_value, float vscroll_value, float relative_x_value, float relative_y_value) MIR_FOR_REMOVAL_IN_VERSION_1("unused"); // Deprecated version without mac EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp, MirInputEventModifiers modifiers, MirPointerAction action, MirPointerButtons buttons_pressed, float x_axis_value, float y_axis_value, float hscroll_value, float vscroll_value, float relative_x_value, float relative_y_value) MIR_FOR_REMOVAL_IN_VERSION_1("unused"); // Input configuration event EventUPtr make_event(MirInputConfigurationAction action, MirInputDeviceId id, std::chrono::nanoseconds time) MIR_FOR_REMOVAL_IN_VERSION_1("unused"); EventUPtr make_event(std::chrono::nanoseconds timestamp, MirPointerButtons pointer_buttons, MirInputEventModifiers modifiers, float x_axis_value, float y_axis_value, std::vector&& device_states); EventUPtr make_event(MirInputDeviceId device_id, std::chrono::nanoseconds timestamp, std::vector const& mac, MirInputEventModifiers modifiers, std::vector const& contacts); EventUPtr clone_event(MirEvent const& event); void transform_positions(MirEvent& event, mir::geometry::Displacement const& movement); } } #endif // MIR_EVENT_BUILDERS_H_ ./include/client/mir/event_printer.h0000644000004100000410000000615313115234664020002 0ustar www-datawww-data/* * Copyright © 2015-2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_EVENT_PRINTER_H_ #define MIR_EVENT_PRINTER_H_ #include "mir_toolkit/event.h" #include namespace mir { std::ostream& operator<<(std::ostream& out, MirInputEventModifier modifier); std::ostream& operator<<(std::ostream& out, MirKeyboardAction action); std::ostream& operator<<(std::ostream& out, MirTouchAction action); std::ostream& operator<<(std::ostream& out, MirTouchTooltype tool); std::ostream& operator<<(std::ostream& out, MirPointerAction action); std::ostream& operator<<(std::ostream& out, MirPromptSessionState state); std::ostream& operator<<(std::ostream& out, MirOrientation orientation); std::ostream& operator<<(std::ostream& out, MirSurfaceAttrib attribute) MIR_FOR_REMOVAL_IN_VERSION_1("use << with MirWindowAttrib instead"); std::ostream& operator<<(std::ostream& out, MirWindowAttrib attribute); std::ostream& operator<<(std::ostream& out, MirSurfaceFocusState state) MIR_FOR_REMOVAL_IN_VERSION_1("use << with MirWindowFocusState instead"); std::ostream& operator<<(std::ostream& out, MirWindowFocusState state); std::ostream& operator<<(std::ostream& out, MirSurfaceVisibility state) MIR_FOR_REMOVAL_IN_VERSION_1("use << with MirWindowVisibility instead"); std::ostream& operator<<(std::ostream& out, MirWindowVisibility state); std::ostream& operator<<(std::ostream& out, MirSurfaceType type) MIR_FOR_REMOVAL_IN_VERSION_1("use << with MirWindowType instead"); std::ostream& operator<<(std::ostream& out, MirWindowType type); std::ostream& operator<<(std::ostream& out, MirSurfaceState state) MIR_FOR_REMOVAL_IN_VERSION_1("use << with MirWindowState instead"); std::ostream& operator<<(std::ostream& out, MirWindowState state); std::ostream& operator<<(std::ostream& out, MirPromptSessionEvent const& event); std::ostream& operator<<(std::ostream& out, MirResizeEvent const& event); std::ostream& operator<<(std::ostream& out, MirOrientationEvent const& event); std::ostream& operator<<(std::ostream& out, MirInputEvent const& event); std::ostream& operator<<(std::ostream& out, MirCloseWindowEvent const& event); std::ostream& operator<<(std::ostream& out, MirKeymapEvent const& event); std::ostream& operator<<(std::ostream& out, MirWindowEvent const& event); std::ostream& operator<<(std::ostream& out, MirInputDeviceStateEvent const& event); std::ostream& operator<<(std::ostream& out, MirWindowPlacementEvent const& event); std::ostream& operator<<(std::ostream& out, MirEvent const& event); } #endif ./include/client/mir_toolkit/0000755000004100000410000000000013115234677016511 5ustar www-datawww-data./include/client/mir_toolkit/mir_input_device.h0000644000004100000410000003266513115234664022217 0ustar www-datawww-data/* * Copyright © 2015-2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_INPUT_DEVICE_H_ #define MIR_TOOLKIT_MIR_INPUT_DEVICE_H_ #include "mir_toolkit/client_types.h" #include "mir_toolkit/mir_input_device_types.h" /** * \addtogroup mir_toolkit * @{ */ #ifdef __cplusplus extern "C" { #endif /** * Retrieve the number of available input devices. * * \param [in] config The input configuration snapshot * * \return Number of input devices */ size_t mir_input_config_device_count(MirInputConfig const* config); /** * Retrieve the input device at given \a index. * * The pointer returned stays valid until mir_input_config_release * is called with \a config. * * \param [in] config The input configuration snapshot * \param [in] index The index of the input device to return. * \return input device */ MirInputDevice const* mir_input_config_get_device( MirInputConfig const* config, size_t index); /** * Retrieve the input device by \a id. * * The MirInputDevice returned stays valid until mir_input_config_release * is called with \a config. If no device with the given \a id is found * NULL will be returned. * * \param [in] config The input configuration snapshot * \param [in] id The input device id to search for * * \return input device */ MirInputDevice const* mir_input_config_get_device_by_id( MirInputConfig const* config, MirInputDeviceId id); /** * Retrieve the input device at given \a index. * * The pointer returned stays valid until mir_input_config_release * is called with \a config. * * \param [in] config The input configuration snapshot * \param [in] index The index of the input device to return. * \return input device */ MirInputDevice* mir_input_config_get_mutable_device( MirInputConfig* config, size_t index); /** * Retrieve the input device by \a id. * * The MirInputDevice returned stays valid until mir_input_config_release * is called with \a config. If no device with the given \a id is found * NULL will be returned. * * \param [in] config The input configuration snapshot * \param [in] id The input device id to search for * * \return input device */ MirInputDevice* mir_input_config_get_mutable_device_by_id( MirInputConfig* config, MirInputDeviceId id); /** * Retrieve the capabilities of the input device at the given index. * * \param [in] device The input device * * \return The capability flags of the input device */ MirInputDeviceCapabilities mir_input_device_get_capabilities( MirInputDevice const* device); /** * Retrieve the device id of the input device. * The device id is a unique integer value, only valid while the device is * attached. The device id matches the device id attached every input event. * * \param [in] device The input device * * \return The device id of the input device */ MirInputDeviceId mir_input_device_get_id(MirInputDevice const* device); /** * Retrieve the name of the input device. * The string pointed to will be valid as long as MirInputDevice is valid. * The name may be empty but never NULL. * * \param [in] device The input device * * \return The name of the input device */ char const* mir_input_device_get_name(MirInputDevice const* device); /** * Retrieve the unique id of the input device. * The string pointed to will be valid as long as \a device is valid. * The value of the unique id of a given device should be valid across mir * connections session and servers of the same version. * * \param [in] device The input device * * \return The unique id of the input device */ char const* mir_input_device_get_unique_id(MirInputDevice const* device); /** * Retrieve a structure containing the pointer related config options * of the input device. * * If the input device does not control the mouse cursor, there will be no * config options, and the function will return a null pointer. * * \param [in] device The input device * * \return The pointer config */ MirPointerConfig const* mir_input_device_get_pointer_config( MirInputDevice const* device); /** * Retrieve the cursor acceleration profile. * * \param [in] conf The pointer config * * \return The acceleration profile */ MirPointerAcceleration mir_pointer_config_get_acceleration( MirPointerConfig const* conf); /** * Retrieve the cursor acceleration bias. * * The value will be in the range of [-1, 1]: * - 0: default acceleration * - [-1, 0): reduced acceleration * - (0, 1]: increased acceleration * * \param [in] conf The pointer config * * \return The acceleration bias */ double mir_pointer_config_get_acceleration_bias( MirPointerConfig const* conf); /** * Retrieve the horizontal scroll scale. * * The value is a signed linear scale of the horizontal scroll axis. A Negative * value indicates 'natural scrolling'. * * \param [in] conf The pointer config * * \return The horizontal scroll scale */ double mir_pointer_config_get_horizontal_scroll_scale( MirPointerConfig const* conf); /** * Retrieve the vertical scroll scale. * * The value is a signed linear scale of the vertical scroll axis. A Negative * value indicates 'natural scrolling'. * * \param [in] conf The pointer config * * \return The vertical scroll scale */ double mir_pointer_config_get_vertical_scroll_scale( MirPointerConfig const* conf); /** * Retrieve whether the pointer device is configured for right or left handed * use. * * \param [in] conf The pointer config * * \return Right or left handed */ MirPointerHandedness mir_pointer_config_get_handedness( MirPointerConfig const* conf); /** * Retrieve a structure containing the pointer related config options * of the input device that can be manipulated. * * If the input device does not control the mouse cursor, there will be no * config options, and the function will return a null pointer. * * \param [in] device The input device * * \return The pointer config */ MirPointerConfig* mir_input_device_get_mutable_pointer_config( MirInputDevice* device); /** * Set the acceleration mode of the pointer device. * * See \ref MirPointerAcceleration for reference. * * \param [in] conf The pointer config * \param [in] acceleration The acceleration mode */ void mir_pointer_config_set_acceleration( MirPointerConfig* conf, MirPointerAcceleration acceleration); /** * Set the acceleration bias of the pointer device. * * The acceleration bias must be in the range of [-1, 1]: * - 0: default acceleration * - [-1, 0): reduced acceleration * - (0, 1]: increased acceleration * * \param [in] conf The pointer config * \param [in] acceleration_bias The acceleration bias */ void mir_pointer_config_set_acceleration_bias( MirPointerConfig* conf, double acceleration_bias); /** * Set the horizontal scroll scale. * * The horizontal scroll scale is a signed linear scale of scroll motion along * the horizontal axis. Negative scales can be used to configure 'natural * scrolling'. * * \param [in] conf The pointer config * \param [in] horizontal_scroll_scale The horizontal scroll scale */ void mir_pointer_config_set_horizontal_scroll_scale( MirPointerConfig* conf, double horizontal_scroll_scale); /** * Set the vertical scroll scale. * * The vertical scroll scale is a signed linear scale of scroll motion along * the vertical axis. Negative scales can be used to configure 'natural * scrolling'. * * \param [in] conf The pointer config * \param [in] vertical_scroll_scale The vertical scroll scale */ void mir_pointer_config_set_vertical_scroll_scale( MirPointerConfig* conf, double vertical_scroll_scale); /** * Configure left and right hand use of the pointer device. * * This configures which buttons will be used as primary and secondary buttons. * * \param [in] conf The pointer config * \param [in] handedness left or right handed use */ void mir_pointer_config_set_handedness( MirPointerConfig* conf, MirPointerHandedness handedness); /** * Retrieve a structure containing the touchpad related config options * of the input device. * * If the input device is not a touchpad this function will return null pointer. * * \param [in] device The input device * * \return The touchpad config */ MirTouchpadConfig const* mir_input_device_get_touchpad_config( MirInputDevice const* device); /** * Retrieve the click modes of the touchpad. * * See \ref MirTouchpadClickMode for reference. * * \param [in] conf The touchpad config * * \return The touchpad click modes */ MirTouchpadClickModes mir_touchpad_config_get_click_modes( MirTouchpadConfig const* conf); /** * Retrieve the scroll modes of the touchpad. * * See \ref MirTouchpadScrollMode for reference. * * \param [in] conf The touchpad config * * \return The touchpad click modes */ MirTouchpadScrollModes mir_touchpad_config_get_scroll_modes( MirTouchpadConfig const* conf); /** * Retrieve the configured button down for button down scroll mode. * * See \ref MirTouchpadScrollMode for reference. * * \param [in] conf The touchpad config * * \return The touchpad click modes */ int mir_touchpad_config_get_button_down_scroll_button( MirTouchpadConfig const* conf); /** * Retrieve whether a tap gesture generates pointer button events. * * \param [in] conf The touchpad config * * \return whether tap to click is enabled */ bool mir_touchpad_config_get_tap_to_click( MirTouchpadConfig const* conf); /** * Retrieve whether middle mouse button should be emulated. * * \param [in] conf The touchpad config * * \return whether middle mouse button emulation is enabled */ bool mir_touchpad_config_get_middle_mouse_button_emulation( MirTouchpadConfig const* conf); /** * Retrieve whether the touchpad should be disabled when an external pointer * device like a mouse is connected. * * \param [in] conf The touchpad config * * \return whether touchpad is disabled with an external mouse */ bool mir_touchpad_config_get_disable_with_mouse( MirTouchpadConfig const* conf); /** * Retrieve whether the touchpad events should be blocked while the user types. * * \param [in] conf The touchpad config * * \return whether touchpad is disabled during typing */ bool mir_touchpad_config_get_disable_while_typing( MirTouchpadConfig const* conf); /** * Retrieve a structure containing the touchpad related config options * of the input device that can be manipulated. * * If the input device is not a touchpad this function will return null pointer. * * \param [in] device The input device * * \return A mutable touchpad config */ MirTouchpadConfig* mir_input_device_get_mutable_touchpad_config( MirInputDevice* device); /** * Configure the enable click modes for the touchpad. * * \param [in] conf The touchpad config * \param [in] modes the enabled click modes */ void mir_touchpad_config_set_click_modes( MirTouchpadConfig* conf, MirTouchpadClickModes modes); /** * Configure the enabled scroll modes for the touchpad. * * \param [in] conf The touchpad config * \param [in] modes the enabled scroll modes */ void mir_touchpad_config_set_scroll_modes( MirTouchpadConfig* conf, MirTouchpadScrollModes modes); /** * Configure the button for button down scroll mode * * \param [in] conf The touchpad config * \param [in] button the button */ void mir_touchpad_config_set_button_down_scroll_button( MirTouchpadConfig* conf, int button); /** * Configure whether tap to click should be enabled * * \param [in] conf The touchpad config * \param [in] tap_to_click */ void mir_touchpad_config_set_tap_to_click( MirTouchpadConfig* conf, bool tap_to_click); /** * Configure whether middle mouse button emulation should be enabled * * \param [in] conf The touchpad config * \param [in] middle_mouse_button_emulation */ void mir_touchpad_config_set_middle_mouse_button_emulation( MirTouchpadConfig* conf, bool middle_emulation); /** * Configure whether the touchpad should be turned off while a mouse is attached. * * \param [in] conf The touchpad config * \param [in] active disable touchpad with mouse */ void mir_touchpad_config_set_disable_with_mouse( MirTouchpadConfig* conf, bool active); /** * Configure whether the touchpad should be turned off while typing * * \param [in] conf The touchpad config * \param [in] active disable touchpad while typing */ void mir_touchpad_config_set_disable_while_typing( MirTouchpadConfig* conf, bool active); #ifdef __cplusplus } #endif /**@}*/ #endif ./include/client/mir_toolkit/mir_blob.h0000644000004100000410000000544313115234664020451 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_BLOB_H_ #define MIR_TOOLKIT_MIR_BLOB_H_ #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Create a blob from a display configuration * * \param [in] configuration The display configuration * \return A blob */ MirBlob* mir_blob_from_display_configuration(MirDisplayConfiguration* configuration) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_blob_from_display_config instead"); /** * Create a blob from a display config * * \param [in] config The display config * \return A blob */ MirBlob* mir_blob_from_display_config(MirDisplayConfig* config); /** * Create a blob from a buffer. * \note this does not copy the data, the buffer is assumed to be available * until the blob is released. * * \param [in] buffer the buffer * \param [in] buffer_size the buffer size * \return A blob */ MirBlob* mir_blob_onto_buffer(void const* buffer, size_t buffer_size); /** * Create a blob from a display configuration * * \warning will abort() if the blob doesn't represent a meaningful display configuration * * \param [in] blob The blob * \return A display configuration */ MirDisplayConfiguration* mir_blob_to_display_configuration(MirBlob* blob) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_blob_to_display_config instead"); /** * Create a blob from a display config * * \warning will abort() if the blob doesn't represent a meaningful display config * * \param [in] blob The blob * \return A display config */ MirDisplayConfig* mir_blob_to_display_config(MirBlob* blob); /** * Get the size of a blob * \param [in] blob The blob * \return the size */ size_t mir_blob_size(MirBlob* blob); /** * Get the data of a blob * \param [in] blob The blob * \return the data */ void const* mir_blob_data(MirBlob* blob); /** * Release a blob object * \param [in] blob The blob */ void mir_blob_release(MirBlob* blob); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_MIR_BLOB_H_ */ ./include/client/mir_toolkit/events/0000755000004100000410000000000013115234677020015 5ustar www-datawww-data./include/client/mir_toolkit/events/prompt_session_event.h0000644000004100000410000000241013115234664024444 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_EVENTS_PROMPT_SESSION_EVENT_H_ #define MIR_TOOLKIT_EVENTS_PROMPT_SESSION_EVENT_H_ #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Retrieve the new prompt session state reported by a given MirPromptSessionEvent * * \param [in] event The prompt session event * \return The new state */ MirPromptSessionState mir_prompt_session_event_get_state(MirPromptSessionEvent const* event); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_PROMPT_SESSION_EVENT_H_ */ ./include/client/mir_toolkit/events/event.h0000644000004100000410000003043713115234664021312 0ustar www-datawww-data/* * Copyright © 2014-2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_EVENT_H_ #define MIR_TOOLKIT_EVENT_H_ #include #include #include "mir_toolkit/common.h" #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" typedef enum { mir_event_type_key, mir_event_type_motion, MIR_DEPRECATED_ENUM(mir_event_type_surface, "mir_event_type_window"), mir_event_type_window = mir_event_type_surface, mir_event_type_resize, mir_event_type_prompt_session_state_change, mir_event_type_orientation, MIR_DEPRECATED_ENUM(mir_event_type_close_surface, "mir_event_type_close_window"), mir_event_type_close_window = mir_event_type_close_surface, /* Type for new style input event will be returned from mir_event_get_type when old style event type was mir_event_type_key or mir_event_type_motion */ mir_event_type_input, mir_event_type_keymap, MIR_DEPRECATED_ENUM(mir_event_type_input_configuration, "mir_connection_set_input_config_change_callback and mir_event_type_input_device_state"), MIR_DEPRECATED_ENUM(mir_event_type_surface_output, "mir_event_type_window_output"), mir_event_type_window_output = mir_event_type_surface_output, mir_event_type_input_device_state, MIR_DEPRECATED_ENUM(mir_event_type_surface_placement, "mir_event_type_window_placement"), mir_event_type_window_placement = mir_event_type_surface_placement, } MirEventType; #pragma GCC diagnostic pop typedef struct MirSurfaceEvent MirSurfaceEvent MIR_FOR_REMOVAL_IN_VERSION_1("use MirWindowEvent instead"); typedef struct MirSurfaceEvent MirWindowEvent; typedef struct MirResizeEvent MirResizeEvent; typedef struct MirPromptSessionEvent MirPromptSessionEvent; typedef struct MirOrientationEvent MirOrientationEvent; typedef struct MirCloseSurfaceEvent MirCloseSurfaceEvent MIR_FOR_REMOVAL_IN_VERSION_1("use MirCloseWindowEvent instead"); typedef struct MirCloseSurfaceEvent MirCloseWindowEvent; typedef struct MirInputEvent MirInputEvent; typedef struct MirKeymapEvent MirKeymapEvent; typedef struct MirInputConfigurationEvent MirInputConfigurationEvent MIR_FOR_REMOVAL_IN_VERSION_1("Use MirInputDeviceStateEvent and the MirInputConfig callback instead"); typedef struct MirSurfaceOutputEvent MirSurfaceOutputEvent MIR_FOR_REMOVAL_IN_VERSION_1("use MirWindowOutputEvent instead"); typedef struct MirSurfaceOutputEvent MirWindowOutputEvent; typedef struct MirInputDeviceStateEvent MirInputDeviceStateEvent; typedef struct MirSurfacePlacementEvent MirSurfacePlacementEvent MIR_FOR_REMOVAL_IN_VERSION_1("use MirWindowPlacementEvent instead"); typedef struct MirSurfacePlacementEvent MirWindowPlacementEvent; typedef struct MirCookie MirCookie; typedef struct MirEvent MirEvent; #ifdef __cplusplus } /**@}*/ #endif #include "mir_toolkit/events/input/input_event.h" #include "mir_toolkit/events/resize_event.h" #include "mir_toolkit/events/surface_event.h" #include "mir_toolkit/events/window_event.h" #include "mir_toolkit/events/orientation_event.h" #include "mir_toolkit/events/prompt_session_event.h" #include "mir_toolkit/events/keymap_event.h" #include "mir_toolkit/events/input_configuration_event.h" #include "mir_toolkit/events/surface_output_event.h" #include "mir_toolkit/events/window_output_event.h" #include "mir_toolkit/events/input_device_state_event.h" #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Retrieves the type of a MirEvent. Now preferred over direct access to ev->type. * In particular ev->type will never be mir_event_type_input and mir_event_get_type * is the only way to ensure mir_event_get_input_event will succeed. * * \param [in] event The event * \return The event type */ MirEventType mir_event_get_type(MirEvent const* event); /** * Retrieve the MirInputEvent associated with a MirEvent of * type mir_event_type_input. See * for accessors. * * \param [in] event The event * \return The associated MirInputEvent */ MirInputEvent const* mir_event_get_input_event(MirEvent const* event); /** * Retrieve the MirSurfaceEvent associated with a MirEvent of * type mir_event_type_surface. See * for accessors. * * \param [in] event The event * \return The associated MirSurfaceEvent */ MirSurfaceEvent const* mir_event_get_surface_event(MirEvent const* event) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_event_get_window_event instead"); /** * Retrieve the MirWindowEvent associated with a MirEvent of * type mir_event_type_window. See * for accessors. * * \param [in] event The event * \return The associated MirWindowEvent */ MirWindowEvent const* mir_event_get_window_event(MirEvent const* event); /** * Retrieve the MirResizeEvent associated with a MirEvent of * type mir_event_type_resize. See * for accessors. * * \param [in] event The event * \return The associated MirResizeEvent */ MirResizeEvent const* mir_event_get_resize_event(MirEvent const* event); /** * Retrieve the MirPromptSessionEvent associated with a MirEvent of * type mir_event_type_prompt_session_state_change. See * for accessors. * * \param [in] event The event * \return The associated MirPromptSessionEvent */ MirPromptSessionEvent const* mir_event_get_prompt_session_event(MirEvent const* event); /** * Retrieve the MirOrientationEvent associated with a MirEvent of * type mir_event_type_orientation. See * for accessors. * * \param [in] event The event * \return The associated MirOrientationEvent */ MirOrientationEvent const* mir_event_get_orientation_event(MirEvent const* event); // Ignore use of deprecate MirCloseSurfaceEvent typedef in deprecated function (for now) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" /** * Retrieve the MirCloseSurfaceEvent associated with a MirEvent of * type mir_event_type_close_surface. The event is a request to close * the surface it is delivered to and has no accessors. * * \deprecated Use of this function is pointless as there is no way to use the * return value. * * \todo This should be removed from the public API at the next API break. * * \param [in] event The event * \return The associated MirCloseSurfaceEvent */ /// @cond MIR_FOR_REMOVAL_IN_VERSION_1("Use of this function is pointless as there is no way to use the return value") /// @endcond MirCloseSurfaceEvent const* mir_event_get_close_surface_event(MirEvent const* event); #pragma GCC diagnostic pop /** * Retrieve the MirKeymapEvent associated with a MirEvent of * type mir_event_type_keymap. The event signifies that the keymap * applied for the relevant surface has changed. * * \param [in] event The event * \return The associated MirKeymapEvent */ MirKeymapEvent const* mir_event_get_keymap_event(MirEvent const* event); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" /** * Retrieve the MirInputConfig associated with a MirEvent of * type mir_event_type_input_configuration. The event signifies that the * input device configuration has changed. * * \deprecated Input devices and changes to the input devices are indicated * via the MirInputConfigCallback * \param [in] event The event * \return The associated MirInputConfigurationEvent */ /// @cond MIR_FOR_REMOVAL_IN_VERSION_1("Input devices and changes to the input devices are indicated via the MirInputConfigCallback") /// @endcond MirInputConfigurationEvent const* mir_event_get_input_configuration_event(MirEvent const* event); #pragma GCC diagnostic pop /** * Retrieve the MirSurfaceOutputEvent associated with a MirEvent of type * mir_event_type_surface_output. The event signifies that the properties * of the output the surface is displayed upon have changed. * * A MirSurfaceOutputEvent is generated either when the properties of the * output the surface is primarily on change (for example: by user configuration * of resolution) or when the output the surface is primarily on changes * (for example: when a user moves the surface from one monitor to another). * * \param [in] event The event * \return The associated MirSurfaceOutputEvent */ MirSurfaceOutputEvent const* mir_event_get_surface_output_event(MirEvent const* event) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_event_get_window_output_event"); /** * Retrieve the MirWindowOutputEvent associated with a MirEvent of type * mir_event_type_window_output. The event signifies that the properties * of the output the window is displayed upon have changed. * * A MirWindowOutputEvent is generated either when the properties of the * output the window is primarily on change (for example: by user configuration * of resolution) or when the output the window is primarily on changes * (for example: when a user moves the window from one monitor to another). * * \param [in] event The event * \return The associated MirWindowOutputEvent */ MirWindowOutputEvent const* mir_event_get_window_output_event(MirEvent const* event); /** * Retrieve the MirInputDeviceStateEvent associated with a MirEvent of * type mir_event_type_input_device_state. The event signifies that the * client has not received the most recent input events, and thus receives * a state update for all attached devices. * * \param [in] event The event * \return The associated MirInputConfigurationEvent */ MirInputDeviceStateEvent const* mir_event_get_input_device_state_event(MirEvent const* event); /** * Retrieve the MirSurfacePlacementEvent associated with a MirEvent of * type mir_event_type_surface_placement. The event signifies that the * the server has fulfilled a request for relative surface placement. * * \param [in] event The event * \return The associated MirSurfacePlacementEvent */ MirSurfacePlacementEvent const* mir_event_get_surface_placement_event(MirEvent const* event) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_event_get_window_placement_event"); /** * Retrieve the MirWindowPlacementEvent associated with a MirEvent of * type mir_event_type_window_placement. The event signifies that the * the server has fulfilled a request for relative window placement. * * \param [in] event The event * \return The associated MirWindowPlacementEvent */ MirWindowPlacementEvent const* mir_event_get_window_placement_event(MirEvent const* event); /* * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * _________________________ *< Don't use mir_event_ref > * ------------------------- * \ ^__^ * \ (oo)\_______ * (__)\ )\/\ * ||----w | * || || * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * NOTICE: mir_event_ref and mir_event_unref are implemented in terms of copy * until such time that direct MirEvent access is deprecated. This means you * must use the return value as your new reference. */ /** * Reference this MirEvent and return a pointer to the * newly referenced instance * * \param[in] event The event to reference * \return The event pointer to now use */ MirEvent const* mir_event_ref(MirEvent const* event) __attribute__((warn_unused_result)); /** * Release a reference to a MirEvent. * * \param[in] event The event to un-reference */ void mir_event_unref(MirEvent const* event); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_EVENT_H_ */ ./include/client/mir_toolkit/events/window_output_event.h0000644000004100000410000000523513115234664024317 0ustar www-datawww-data/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers * Brandon Schaefer */ #ifndef MIR_TOOLKIT_WINDOW_OUTPUT_EVENT_H_ #define MIR_TOOLKIT_WINDOW_OUTPUT_EVENT_H_ #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Retrieve the DPI of the new output configuration of a MirWindowOutputEvent * * \param [in] ev The event * \return The new DPI value for the window is primarily on. */ int mir_window_output_event_get_dpi(MirWindowOutputEvent const* ev); /** * Retrieve the form factor of the new output configuration of a MirWindowOutputEvent * * \param [in] ev The event * \return The new form factor of the output the window is primarily on. */ MirFormFactor mir_window_output_event_get_form_factor(MirWindowOutputEvent const* ev); /** * Retrieve the suggested scaling factor of the new output configuration of a * MirWindowOutputEvent. * * \param [in] ev The event * \return The new scaling factor of the output the window is primarily on. */ float mir_window_output_event_get_scale(MirWindowOutputEvent const* ev); /** * Retrieve the maximum refresh rate of the output(s) associated with a * MirWindowOutputEvent. For variable refresh rate displays this represents * the maximum refresh rate of the display to aim for, rather than a measurement * of recent performance. * * \param [in] ev The event * \return The refresh rate in Hz */ double mir_window_output_event_get_refresh_rate(MirWindowOutputEvent const* ev); /** * Retrieve the ID of the output this window is on from a MirWindowOutputEvent * * \param [in] ev The event * \return The ID of the output the window is currently considered to be on. * (From MirDisplayOutput::output_id) */ uint32_t mir_window_output_event_get_output_id(MirWindowOutputEvent const *ev); #ifdef __cplusplus } /**@}*/ #endif #endif //MIR_TOOLKIT_WINDOW_OUTPUT_EVENT_H_ ./include/client/mir_toolkit/events/surface_output_event.h0000644000004100000410000000637313115234664024444 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_TOOLKIT_SURFACE_OUTPUT_EVENT_H_ #define MIR_TOOLKIT_SURFACE_OUTPUT_EVENT_H_ #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif // Ignore use of deprecate MirSurfaceOutputEvent typedef in deprecated functions (for now) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" /** * Retrieve the DPI of the new output configuration of a MirSurfaceOutputEvent * * \param [in] ev The event * \return The new DPI value for the surface is primarily on. */ int mir_surface_output_event_get_dpi(MirSurfaceOutputEvent const* ev) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_output_event_get_dpi instead"); /** * Retrieve the form factor of the new output configuration of a MirSurfaceOutputEvent * * \param [in] ev The event * \return The new form factor of the output the surface is primarily on. */ MirFormFactor mir_surface_output_event_get_form_factor(MirSurfaceOutputEvent const* ev) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_output_event_get_form_factor instead"); /** * Retrieve the suggested scaling factor of the new output configuration of a * MirSurfaceOutputEvent. * * \param [in] ev The event * \return The new scaling factor of the output the surface is primarily on. */ float mir_surface_output_event_get_scale(MirSurfaceOutputEvent const* ev) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_output_event_get_scale instead"); /** * Retrieve the maximum refresh rate of the output(s) associated with a * MirSurfaceOutputEvent. For variable refresh rate displays this represents * the maximum refresh rate of the display to aim for, rather than a measurement * of recent performance. * * \param [in] ev The event * \return The refresh rate in Hz */ double mir_surface_output_event_get_refresh_rate(MirSurfaceOutputEvent const* ev) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_output_event_get_refresh_rate instead"); /** * Retrieve the ID of the output this surface is on from a MirSurfaceOutputEvent * * \param [in] ev The event * \return The ID of the output the surface is currently considered to be on. * (From MirDisplayOutput::output_id) */ uint32_t mir_surface_output_event_get_output_id(MirSurfaceOutputEvent const *ev) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_output_event_get_output_id instead"); #pragma GCC diagnostic pop #ifdef __cplusplus } /**@}*/ #endif #endif //MIR_TOOLKIT_SURFACE_OUTPUT_EVENT_H_ ./include/client/mir_toolkit/events/window_placement.h0000644000004100000410000000246113115234664023524 0ustar www-datawww-data/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths * Brandon Schaefer */ #ifndef MIR_TOOLKIT_WINDOW_PLACEMENT_H_ #define MIR_TOOLKIT_WINDOW_PLACEMENT_H_ #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Retrieve the relative position from a placement notification * * \param [in] event The placement event * \return The position relative to the parent window */ MirRectangle mir_window_placement_get_relative_position(MirWindowPlacementEvent const* event); #ifdef __cplusplus } /**@}*/ #endif #endif //MIR_TOOLKIT_WINDOW_PLACEMENT_H_ ./include/client/mir_toolkit/events/keymap_event.h0000644000004100000410000000416113115234664022653 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_EVENTS_KEYMAP_EVENT_H_ #define MIR_TOOLKIT_EVENTS_KEYMAP_EVENT_H_ #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Retrieve the new keymap reported by this MirKeymapEvent * * \deprecated keymap credentials are no longer available use * mir_keymap_event_get_keymap_buffer instead. * * \param[in] ev The keymap event * \param[out] rules XKB rules describing the new keymap. */ void mir_keymap_event_get_rules(MirKeymapEvent const* ev, struct xkb_rule_names* rules) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_keymap_event_get_keymap_buffer() instead"); /** * Retrieve the new keymap reported by this MirKeymapEvent * * The keymap buffer is only valid while the MirKeymapEvent is valid. * The buffer can be used via xkb_keymap_new_from_buffer * \param[in] ev The keymap event * \param[out] buffer the xkbcommon keymap * \param[out] length of the buffer */ void mir_keymap_event_get_keymap_buffer(MirKeymapEvent const* ev, char const** buffer, size_t *length); /** * Retrieve the device id the keymap reported by this MirKeymapEvent applies to * * \param[in] ev The keymap event */ MirInputDeviceId mir_keymap_event_get_device_id(MirKeymapEvent const* ev); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_KEYMAP_EVENT_H_ */ ./include/client/mir_toolkit/events/surface_event.h0000644000004100000410000000355513115234664023023 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_EVENTS_SURFACE_EVENT_H_ #define MIR_TOOLKIT_EVENTS_SURFACE_EVENT_H_ #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif // Ignore use of deprecate MirSurfaceEvent typedef in deprecated functions (for now) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" /** * Retrieve the attribute index configured with a given MirSurfaceEvent * * \param [in] event The event * \return The associated attribute */ MirSurfaceAttrib mir_surface_event_get_attribute(MirSurfaceEvent const* event) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_event_get_attribute instead"); /** * Retrieve the new value of the associated attribute for a given MirSurfaceEvent * * \param [in] event The event * \return The associated attribute value */ int mir_surface_event_get_attribute_value(MirSurfaceEvent const* event) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_event_get_attribute_value with MirWindowEvent instead"); #pragma GCC diagnostic pop #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_SURFACE_EVENT_H_ */ ./include/client/mir_toolkit/events/input_configuration_event.h0000644000004100000410000000623213115234664025454 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_EVENTS_INPUT_CONFIGURATION_EVENT_H_ #define MIR_TOOLKIT_EVENTS_INPUT_CONFIGURATION_EVENT_H_ #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /// MirInputConfigurationEvent indicates a configuration change in the input device subsystem. Eventually /// it's usage will be required to properly interpret MirInputEvent, for example: /// If we receive a button down, and then a device reset, we should not expect /// to receive the button up. /// /// Another example, the maximum/minimum axis values for a device may have been reconfigured and /// need to be required. /// /// Of course as things stand there is no client input-device introspection API so these events /// are difficult to use. typedef enum { mir_input_configuration_action_configuration_changed, mir_input_configuration_action_device_reset } MirInputConfigurationAction MIR_FOR_REMOVAL_IN_VERSION_1("Input devices and changes to the input devices are indicated via the MirInputConfigCallback"); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" /** * Retrieve the input configuration action which occurred. * * \param[in] ev The input configuration event * \return The action */ MirInputConfigurationAction mir_input_configuration_event_get_action(MirInputConfigurationEvent const* ev) MIR_FOR_REMOVAL_IN_VERSION_1("Input devices and changes to the input devices are indicated via the MirInputConfigCallback"); /** * Retreive the time associated with a MirInputConfiguration event * \param[in] ev The input configuration event * \return The time in nanoseconds since epoch */ int64_t mir_input_configuration_event_get_time(MirInputConfigurationEvent const* ev) MIR_FOR_REMOVAL_IN_VERSION_1("Input devices and changes to the input devices are indicated via the MirInputConfigCallback"); /** * Retreive the device id associated with a MirInputConfiguration event * \param[in] ev The input configuration event * \return The device id or -1 if not applicable to events of this action */ MirInputDeviceId mir_input_configuration_event_get_device_id(MirInputConfigurationEvent const* ev) MIR_FOR_REMOVAL_IN_VERSION_1("Input devices and changes to the input devices are indicated via the MirInputConfigCallback"); #pragma GCC diagnostic pop #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_INPUT_CONFIGURATION_EVENT_H_ */ ./include/client/mir_toolkit/events/input_device_state_event.h0000644000004100000410000001044713115234664025247 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_TOOLKIT_EVENTS_INPUT_DEVICE_STATE_EVENT_H_ #define MIR_TOOLKIT_EVENTS_INPUT_DEVICE_STATE_EVENT_H_ #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * MirInputDeviceStateEvent informs clients about the current state of the * input devices. This is necessary when the client did not receive the most * recent input events. The event is sent when the server was resumed after * a pause, or when the client just received the input focus. * * The event contains a single pointer button state and the current cursor * position and the pressed modifier keys. Additionally for key and pointer * devices the pressed keys and buttons are supplied individually. */ /** * Retrieve the button state. * * \param[in] ev The input device state event * \return The combined pointer button state */ MirPointerButtons mir_input_device_state_event_pointer_buttons( MirInputDeviceStateEvent const* ev); /** * Retrieve the pointer position * * \param[in] ev The input device state event * \param[in] axis The pointer axis: mir_pointer_axis_x or mir_pointer_axis_y * \return The pointer position */ float mir_input_device_state_event_pointer_axis( MirInputDeviceStateEvent const* ev, MirPointerAxis axis); /** * Retrieve the time associated with a MirInputDeviceStateEvent * * \param[in] ev The input device state event * \return The time in nanoseconds since epoch */ int64_t mir_input_device_state_event_time( MirInputDeviceStateEvent const* ev); /** * Retrieve the modifier keys pressed on all input devices. * * \param[in] ev The input device state event * \return The modifier mask */ MirInputEventModifiers mir_input_device_state_event_modifiers( MirInputDeviceStateEvent const* ev); /** * Retrieve the number of attached input devices. * * \param[in] ev The input device state event * \return The time in nanoseconds since epoch */ uint32_t mir_input_device_state_event_device_count( MirInputDeviceStateEvent const* ev); /** * Retrieve the device id * * \param[in] ev The input device state event * \param[in] index The index of the input device * \return The device id */ MirInputDeviceId mir_input_device_state_event_device_id( MirInputDeviceStateEvent const* ev, uint32_t index); /* * Retrieve a pressed key on the device identified by the \a index. * The key is encoded as a scan code. * * \param[in] ev The input device state event * \param[in] index The index of the input device * \param[in] pressed_index The index of the pressed key * \return The pressed key at index pressed_index */ uint32_t mir_input_device_state_event_device_pressed_keys_for_index( MirInputDeviceStateEvent const* ev, uint32_t index, uint32_t pressed_index); /** * Retrieve the size of scan code array of the device identified by the \a index. * * \param[in] ev The input device state event * \param[in] index The index of the input device * \return Size of the pressed keys array */ uint32_t mir_input_device_state_event_device_pressed_keys_count( MirInputDeviceStateEvent const* ev, uint32_t index); /** * Retrieve the pointer button state of the device identified by the \a index * * \param[in] ev The input device state event * \param[in] index The index of the input device * \return The pointer button state of the device */ MirPointerButtons mir_input_device_state_event_device_pointer_buttons( MirInputDeviceStateEvent const* ev, uint32_t index); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_EVENTS_INPUT_DEVICE_STATE_EVENT_H_ */ ./include/client/mir_toolkit/events/surface_placement.h0000644000004100000410000000266613115234664023654 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_TOOLKIT_SURFACE_PLACEMENT_H_ #define MIR_TOOLKIT_SURFACE_PLACEMENT_H_ #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif typedef struct MirSurfacePlacementEvent MirSurfacePlacementEvent; /** * Retrieve the relative position from a placement notification * * \param [in] event The placement event * \return The position relative to the parent surface */ MirRectangle mir_surface_placement_get_relative_position(MirSurfacePlacementEvent const* event) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_placement_get_relative_position instead"); #ifdef __cplusplus } /**@}*/ #endif #endif //MIR_TOOLKIT_SURFACE_PLACEMENT_H_ ./include/client/mir_toolkit/events/orientation_event.h0000644000004100000410000000234113115234416023711 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_EVENTS_ORIENTATION_EVENT_H_ #define MIR_TOOLKIT_EVENTS_ORIENTATION_EVENT_H_ #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Retrieve the new orientation reported by this MirOrientationEvent * * \param[in] ev The orientation event * \return The new orientation */ MirOrientation mir_orientation_event_get_direction(MirOrientationEvent const* ev); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_ORIENTATION_EVENT_H_ */ ./include/client/mir_toolkit/events/resize_event.h0000644000004100000410000000257113115234416022664 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_EVENTS_RESIZE_EVENT_H_ #define MIR_TOOLKIT_EVENTS_RESIZE_EVENT_H_ #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Retrieve the new width reported by a given MirResizeEvent * * \param[in] ev The resize event * \return The reported width */ int mir_resize_event_get_width(MirResizeEvent const* ev); /** * Retrieve the new height reported by a given MirResizeEvent * * \param[in] ev The resize event * \return The reported height */ int mir_resize_event_get_height(MirResizeEvent const* ev); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_RESIZE_EVENT_H_ */ ./include/client/mir_toolkit/events/input/0000755000004100000410000000000013115234677021154 5ustar www-datawww-data./include/client/mir_toolkit/events/input/pointer_event.h0000644000004100000410000001061713115234664024207 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_POINTER_EVENT_H_ #define MIR_TOOLKIT_POINTER_EVENT_H_ #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * An event type describing a change in pointer device state. */ typedef struct MirPointerEvent MirPointerEvent; /** * Possible pointer actions */ typedef enum { /* A pointer button has come up */ mir_pointer_action_button_up = 0, /* A pointer button has gone down */ mir_pointer_action_button_down = 1, /* The pointer has entered the surface to which this event was delivered */ mir_pointer_action_enter = 2, /* The pointer has left the surface to which this event was delivered */ mir_pointer_action_leave = 3, /* Axis values have changed for the pointer */ mir_pointer_action_motion = 4, mir_pointer_actions } MirPointerAction; /** * Identifiers for pointer axis */ typedef enum { /* Absolute axis containing the x coordinate of the pointer */ mir_pointer_axis_x = 0, /* Absolute axis containing the y coordinate of the pointer */ mir_pointer_axis_y = 1, /* Relative axis containing ticks reported by the vertical scroll wheel */ mir_pointer_axis_vscroll = 2, /* Relative axis containing ticks reported by the horizontal scroll wheel */ mir_pointer_axis_hscroll = 3, /* Relative axis containing the last reported x differential from the pointer */ mir_pointer_axis_relative_x = 4, /* Relative axis containing the last reported y differential from the pointer */ mir_pointer_axis_relative_y = 5, mir_pointer_axes } MirPointerAxis; /* * Identifiers for pointer buttons */ typedef enum { mir_pointer_button_primary = 1 << 0, mir_pointer_button_secondary = 1 << 1, mir_pointer_button_tertiary = 1 << 2, mir_pointer_button_back = 1 << 3, mir_pointer_button_forward = 1 << 4, mir_pointer_button_side = 1 << 5, mir_pointer_button_extra = 1 << 6, mir_pointer_button_task = 1 << 7 } MirPointerButton; typedef unsigned int MirPointerButtons; /** * Retrieve the modifier keys pressed when the pointer action occured. * * \param [in] event The pointer event * \return The modifier mask */ MirInputEventModifiers mir_pointer_event_modifiers(MirPointerEvent const* event); /** * Retrieve the action which occured to generate a given pointer event. * * \param [in] event The pointer event * \return Action performed by the pointer */ MirPointerAction mir_pointer_event_action(MirPointerEvent const* event); /** * Retrieve the state of a given pointer button when the action occurred. * * \param [in] event The pointer event * \param [in] button The button to check * * \return Whether the given button is depressed */ bool mir_pointer_event_button_state(MirPointerEvent const* event, MirPointerButton button); /** * Retreive the pointer button state as a masked set of values. * * \param [in] event The pointer event * * \return The button state */ MirPointerButtons mir_pointer_event_buttons(MirPointerEvent const* event); /** * Retrieve the axis value reported by a given pointer event. * * \param [in] event The pointer event * \param [in] axis The axis to retreive a value from * \return The value of the given axis */ float mir_pointer_event_axis_value(MirPointerEvent const* event, MirPointerAxis axis); /** * Retrieve the corresponding input event. * * \param [in] event The pointer event * \return The input event */ MirInputEvent const* mir_pointer_event_input_event(MirPointerEvent const* event); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_POINTER_EVENT_H_ */ ./include/client/mir_toolkit/events/input/input_event.h0000644000004100000410000001127513115234664023667 0ustar www-datawww-data/* * Copyright © 2014-2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_INPUT_EVENT_H_ #define MIR_TOOLKIT_INPUT_EVENT_H_ #include "mir_toolkit/events/event.h" #include "mir_toolkit/mir_input_device_types.h" #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif typedef enum { mir_input_event_type_key = 0, mir_input_event_type_touch = 1, mir_input_event_type_pointer = 2, mir_input_event_types } MirInputEventType; /** * Description of key modifier state. */ typedef enum { mir_input_event_modifier_none = 1 << 0, mir_input_event_modifier_alt = 1 << 1, mir_input_event_modifier_alt_left = 1 << 2, mir_input_event_modifier_alt_right = 1 << 3, mir_input_event_modifier_shift = 1 << 4, mir_input_event_modifier_shift_left = 1 << 5, mir_input_event_modifier_shift_right = 1 << 6, mir_input_event_modifier_sym = 1 << 7, mir_input_event_modifier_function = 1 << 8, mir_input_event_modifier_ctrl = 1 << 9, mir_input_event_modifier_ctrl_left = 1 << 10, mir_input_event_modifier_ctrl_right = 1 << 11, mir_input_event_modifier_meta = 1 << 12, mir_input_event_modifier_meta_left = 1 << 13, mir_input_event_modifier_meta_right = 1 << 14, mir_input_event_modifier_caps_lock = 1 << 15, mir_input_event_modifier_num_lock = 1 << 16, mir_input_event_modifier_scroll_lock = 1 << 17 } MirInputEventModifier; typedef unsigned int MirInputEventModifiers; #ifdef __cplusplus } /**@}*/ #endif #include "mir_toolkit/events/input/touch_event.h" #include "mir_toolkit/events/input/keyboard_event.h" #include "mir_toolkit/events/input/pointer_event.h" #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Retrieves the device id responsible for generating an input event. * * \param [in] event The input event * \return The id of the generating device */ MirInputDeviceId mir_input_event_get_device_id(MirInputEvent const* event); /** * Retrieve the time at which an input event occurred. * * \param [in] event The input event * \return A timestamp in nanoseconds-since-epoch */ int64_t mir_input_event_get_event_time(MirInputEvent const* event); /** * Retrieve the type of an input event. E.g. key, touch... * * \param [in] event The input event * \return The input event type */ MirInputEventType mir_input_event_get_type(MirInputEvent const* event); /** * Retrieve the MirKeyboardEvent associated with a given input event. * * \param[in] event The input event * \return The MirKeyboardEvent or NULL if event type is not * mir_input_event_type_key */ MirKeyboardEvent const* mir_input_event_get_keyboard_event(MirInputEvent const* event); /** * Retrieve the MirTouchEvent associated with a given input event. * * \param[in] event The input event * \return The MirTouchEvent or NULL if event type is not * mir_input_event_type_touch */ MirTouchEvent const* mir_input_event_get_touch_event(MirInputEvent const* event); /** * Retrieve the MirPointerEvent associated with a given input event. * * \param[in] event The input event * \return The MirPointerEvent or NULL if event type is not * mir_input_event_type_pointer */ MirPointerEvent const* mir_input_event_get_pointer_event(MirInputEvent const* event); /** * Query if an input event contains a cookie * * \param [in] ev The input event * \return True if the input event contains a cookie */ bool mir_input_event_has_cookie(MirInputEvent const* ev); /** * Returns the cookie associated with an input event. * * \pre The input event must have a MirCookie * \param [in] ev An input event * \return The cookie associated with the given input event * The cookie must be released by calling mir_cookie_release */ MirCookie const* mir_input_event_get_cookie(MirInputEvent const* ev); #ifdef __cplusplus } /**@}*/ #endif #endif // MIR_TOOLKIT_INPUT_EVENT_H_ ./include/client/mir_toolkit/events/input/keyboard_event.h0000644000004100000410000000573413115234664024333 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_KEYBOARD_EVENT_H_ #define MIR_TOOLKIT_KEYBOARD_EVENT_H_ #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * An event type describing a change in keyboard state * * Apology #1: Keyboard events almost always come from a keyboard, except they * can also come from system buttons (power, volume, home). This is an issue * we've inherited from the Linux kernel and Android, but could be solved in * future by giving such system switch events their own input group such as * MirSwitchEvent. */ typedef struct MirKeyboardEvent MirKeyboardEvent; /** * Possible actions for changing key state */ typedef enum { /* A key has come up (released) */ mir_keyboard_action_up, /* A key has gone down (pressed) */ mir_keyboard_action_down, /* System policy has triggered a key repeat on a key which was already down */ mir_keyboard_action_repeat, mir_keyboard_actions } MirKeyboardAction; /** * Retrieve the action which triggered a given key event. * * \param [in] event The key event * \return The associated action */ MirKeyboardAction mir_keyboard_event_action(MirKeyboardEvent const* event); /** * Retrieve the xkb mapped keycode associated with the key acted on.. May * be interpreted as per * * \param [in] event The key event * \return The xkb_keysym */ xkb_keysym_t mir_keyboard_event_key_code(MirKeyboardEvent const* event); /** * Retrieve the raw hardware scan code associated with the key acted on. May * be interpreted as per * * \param [in] event The key event * \return The scancode */ int mir_keyboard_event_scan_code(MirKeyboardEvent const* event); /** * Retrieve the modifier keys pressed when the key action occured. * * \param [in] event The key event * \return The modifier mask */ MirInputEventModifiers mir_keyboard_event_modifiers(MirKeyboardEvent const* event); /** * Retrieve the corresponding input event. * * \param [in] event The keyboard event * \return The input event */ MirInputEvent const* mir_keyboard_event_input_event(MirKeyboardEvent const* event); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_KEYBOARD_EVENT_H_ */ ./include/client/mir_toolkit/events/input/touch_event.h0000644000004100000410000001145313115234664023650 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_TOUCH_EVENT_H_ #define MIR_TOOLKIT_TOUCH_EVENT_H_ #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * An event type describing a change in touch device state. */ typedef struct MirTouchEvent MirTouchEvent; /** * An identifier for a touch-point. TouchId's are unique per-gesture. * That is to say, once a touch has gone down at time T, no other touch will * use that touch's ID until all touches at time T have come up. */ typedef int32_t MirTouchId; /** * Possible per touch actions for state changing */ typedef enum { /* This touch point is going up */ mir_touch_action_up = 0, /* This touch point is going down */ mir_touch_action_down = 1, /* Axis values have changed on this touch point */ mir_touch_action_change = 2, mir_touch_actions } MirTouchAction; /** * Identifiers for touch axis */ typedef enum { /* Axis representing the x coordinate for the touch */ mir_touch_axis_x = 0, /* Axis representing the y coordinate for the touch */ mir_touch_axis_y = 1, /* Axis representing pressure of the touch */ mir_touch_axis_pressure = 2, /* Axis representing the length of the major axis of an ellipse centered at the touch point */ mir_touch_axis_touch_major = 3, /* Axis representing the length of the minor axis of an ellipse centered at the touch point */ mir_touch_axis_touch_minor = 4, /* Axis representing the diameter of a circle centered on the touch point */ mir_touch_axis_size = 5, mir_touch_axes } MirTouchAxis; /** * Identifiers for per-touch tool types */ typedef enum { // Tool type could not be determined mir_touch_tooltype_unknown = 0, // Touch is made with a finger mir_touch_tooltype_finger = 1, // Touch is made with a stylus mir_touch_tooltype_stylus = 2, mir_touch_tooltypes } MirTouchTooltype; /** * Retrieve the modifier keys pressed when the touch action occured. * * \param [in] event The key event * \return The modifier mask */ MirInputEventModifiers mir_touch_event_modifiers(MirTouchEvent const* event); /** * Retrieve the number of touches reported for a given touch event. Each touch * is said to be index in the event and may be accessed by index 0, 1, ... , (touch_count - 1) * * \param [in] event The touch event * \return The number of touches */ unsigned int mir_touch_event_point_count(MirTouchEvent const* event); /** * Retrieve the TouchID for a touch at given index. * * \param [in] event The touch event * \param [in] touch_index The touch index. Must be less than (touch_count - 1). * \return ID of the touch at index */ MirTouchId mir_touch_event_id(MirTouchEvent const* event, size_t touch_index); /** * Retrieve the action which occured for a touch at given index. * * \param [in] event The touch event * \param [in] touch_index The touch index. Must be less than (touch_count - 1). * \return Action performed for the touch at index. */ MirTouchAction mir_touch_event_action(MirTouchEvent const* event, size_t touch_index); /** * Retrieve the tooltype for touch at given index. * * \param [in] event The touch event * \param [in] touch_index The touch index. Must be less than (touch_count - 1). * \return Tooltype used for the touch at index */ MirTouchTooltype mir_touch_event_tooltype(MirTouchEvent const* event, size_t touch_index); /** * Retrieve the axis value for a given axis on an indexed touch. * * \param [in] event The touch event * \param [in] touch_index The touch index. Must be less than (touch_count - 1). * \param [in] axis The axis to retreive a value from * \return The value of the given axis */ float mir_touch_event_axis_value(MirTouchEvent const* event, size_t touch_index, MirTouchAxis axis); /** * Retrieve the corresponding input event. * * \param [in] event The touch event * \return The input event */ MirInputEvent const* mir_touch_event_input_event(MirTouchEvent const* event); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_TOUCH_EVENT_H_ */ ./include/client/mir_toolkit/events/window_event.h0000644000004100000410000000272013115234664022673 0ustar www-datawww-data/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Brandon Schaefer */ #ifndef MIR_TOOLKIT_EVENTS_WINDOW_EVENT_H_ #define MIR_TOOLKIT_EVENTS_WINDOW_EVENT_H_ #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Retrieve the attribute index configured with a given MirWindowEvent * * \param [in] event The event * \return The associated attribute */ MirWindowAttrib mir_window_event_get_attribute(MirWindowEvent const* event); /** * Retrieve the new value of the associated attribute for a given MirWindowEvent * * \param [in] event The event * \return The associated attribute value */ int mir_window_event_get_attribute_value(MirWindowEvent const* event); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_WINDOW_EVENT_H_ */ ./include/client/mir_toolkit/mir_wait.h0000644000004100000410000000361213115234664020473 0ustar www-datawww-data/* * Copyright © 2012-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_WAIT_H_ #define MIR_TOOLKIT_MIR_WAIT_H_ #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif struct MirWaitHandle; /** * Wait on the supplied handle until all instances of the associated request * have completed. Returns immediately if zero are pending. * \param [in] wait_handle Handle returned by an asynchronous request */ void mir_wait_for(MirWaitHandle *wait_handle) MIR_FOR_REMOVAL_IN_VERSION_1("No longer supported - use callbacks or wait for state changes"); /** * Wait on the supplied handle until one instance of the associated request * has completed. Use this instead of mir_wait_for in a threaded environment * to ensure that the act of waiting does not clear all results associated * with the wait handle; only one. Unlike mir_wait_for, this function does * not return if zero are pending and instead waits for one. * \param [in] wait_handle Handle returned by an asynchronous request */ void mir_wait_for_one(MirWaitHandle *wait_handle) MIR_FOR_REMOVAL_IN_VERSION_1("No longer supported - use callbacks or wait for state changes"); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_MIR_WAIT_H_ */ ./include/client/mir_toolkit/mir_error.h0000644000004100000410000000272313115234664020662 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_TOOLKIT_MIR_ERROR_H_ #define MIR_TOOLKIT_MIR_ERROR_H_ #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif #include "client_types.h" /** * Get the domain of a MirError. * * The error domain is required to interpret the rest of the error details. * * \param [in] error The MirError to query * \returns The MirErrorDomain that this error belongs to. */ MirErrorDomain mir_error_get_domain(MirError const* error); /** * Get the domain-specific error code of a MirError. * * \param [in] error The MirError to query * \returns The domain-specific error code */ uint32_t mir_error_get_code(MirError const* error); #ifdef __cplusplus } /**@}*/ #endif #endif // MIR_TOOLKIT_MIR_ERROR_H_ ./include/client/mir_toolkit/mir_window.h0000644000004100000410000010225313115234664021037 0ustar www-datawww-data/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_WINDOW_H_ #define MIR_TOOLKIT_MIR_WINDOW_H_ #include #include #include #include #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Create a window specification for a normal window. * * A normal window is suitable for most application windows. It has no special semantics. * On a desktop shell it will typically have a title-bar, be movable, resizeable, etc. * * \param [in] connection Connection the window will be created on * \param [in] width Requested width. The server is not guaranteed to return a window of this width. * \param [in] height Requested height. The server is not guaranteed to return a window of this height. * * \return A handle that can be passed to mir_create_window() to complete construction. */ MirWindowSpec* mir_create_normal_window_spec(MirConnection* connection, int width, int height); /** * Create a window specification for a menu window. * * Positioning of the window is specified with respect to the parent window * via an adjacency rectangle. The server will attempt to choose an edge of the * adjacency rectangle on which to place the window taking in to account * screen-edge proximity or similar constraints. In addition, the server can use * the edge affinity hint to consider only horizontal or only vertical adjacency * edges in the given rectangle. * * \param [in] connection Connection the window will be created on * \param [in] width Requested width. The server is not guaranteed to * return a window of this width. * \param [in] height Requested height. The server is not guaranteed to * return a window of this height. * \param [in] parent A valid parent window for this menu. * \param [in] rect The adjacency rectangle. The server is not * guaranteed to create a window at the requested * location. * \param [in] edge The preferred edge direction to attach to. Use * mir_edge_attachment_any for no preference. * \return A handle that can be passed to mir_create_window() * to complete construction. */ MirWindowSpec* mir_create_menu_window_spec(MirConnection* connection, int width, int height, MirWindow* parent, MirRectangle* rect, MirEdgeAttachment edge); /** * Create a window specification for a tip window. * * Positioning of the window is specified with respect to the parent window * via an adjacency rectangle. The server will attempt to choose an edge of the * adjacency rectangle on which to place the window taking in to account * screen-edge proximity or similar constraints. In addition, the server can use * the edge affinity hint to consider only horizontal or only vertical adjacency * edges in the given rectangle. * * \param [in] connection Connection the window will be created on * \param [in] width Requested width. The server is not guaranteed to * return a window of this width. * \param [in] height Requested height. The server is not guaranteed to * return a window of this height. * \param [in] parent A valid parent window for this tip. * \param [in] rect The adjacency rectangle. The server is not * guaranteed to create a window at the requested * location. * \param [in] edge The preferred edge direction to attach to. Use * mir_edge_attachment_any for no preference. * \return A handle that can be passed to mir_create_window() * to complete construction. */ MirWindowSpec* mir_create_tip_window_spec(MirConnection* connection, int width, int height, MirWindow* parent, MirRectangle* rect, MirEdgeAttachment edge); /** * Create a window specification for a modal dialog window. * * The dialog window will have input focus; the parent can still be moved, * resized or hidden/minimized but no interaction is possible until the dialog * is dismissed. * * A dialog will typically have no close/maximize button decorations. * * During window creation, if the specified parent is another dialog window * the server may choose to close the specified parent in order to show this * new dialog window. * * \param [in] connection Connection the window will be created on * \param [in] width Requested width. The server is not guaranteed to * return a window of this width. * \param [in] height Requested height. The server is not guaranteed to * return a window of this height. * \param [in] parent A valid parent window. * */ MirWindowSpec* mir_create_modal_dialog_window_spec(MirConnection* connection, int width, int height, MirWindow* parent); /** * Create a window specification for a parentless dialog window. * * A parentless dialog window is similar to a normal window, but it cannot * be fullscreen and typically won't have any maximize/close button decorations. * * A parentless dialog is not allowed to have other dialog children. The server * may decide to close the parent and show the child dialog only. * * \param [in] connection Connection the window will be created on * \param [in] width Requested width. The server is not guaranteed to * return a window of this width. * \param [in] height Requested height. The server is not guaranteed to * return a window of this height. */ MirWindowSpec* mir_create_dialog_window_spec(MirConnection* connection, int width, int height); /** * Create a window specification for an input method window. * * Currently this is only appropriate for the Unity On-Screen-Keyboard. * * \param [in] connection Connection the window will be created on * \param [in] width Requested width. The server is not guaranteed to return a window of this width. * \param [in] height Requested height. The server is not guaranteed to return a window of this height. * \return A handle that can be passed to mir_create_window() to complete construction. */ MirWindowSpec* mir_create_input_method_window_spec(MirConnection* connection, int width, int height); /** * Create a window specification. * This can be used with mir_create_window() to create a window or with * mir_window_apply_spec() to change an existing window. * \remark For use with mir_create_window() at least the type, width, height, * format and buffer_usage must be set. (And for types requiring a parent that * too must be set.) * * \param [in] connection a valid mir connection * \return A handle that can ultimately be passed to * mir_create_window() or mir_window_apply_spec() */ MirWindowSpec* mir_create_window_spec(MirConnection* connection); /** * Set the requested parent. * * \param [in] spec Specification to mutate * \param [in] parent A valid parent window. */ void mir_window_spec_set_parent(MirWindowSpec* spec, MirWindow* parent); /** * Update a window specification with a window type. * This can be used with mir_create_window() to create a window or with * mir_window_apply_spec() to change an existing window. * \remark For use with mir_window_apply_spec() the shell need not support * arbitrary changes of type and some target types may require the setting of * properties such as "parent" that are not already present on the window. * The type transformations the server is required to support are:\n * regular => utility, dialog or satellite\n * utility => regular, dialog or satellite\n * dialog => regular, utility or satellite\n * satellite => regular, utility or dialog\n * popup => satellite * * \param [in] spec Specification to mutate * \param [in] type the target type of the window */ void mir_window_spec_set_type(MirWindowSpec* spec, MirWindowType type); /** * Set the requested name. * * The window name helps the user to distinguish between multiple surfaces * from the same application. A typical desktop shell may use it to provide * text in the window titlebar, in an alt-tab switcher, or equivalent. * * \param [in] spec Specification to mutate * \param [in] name Requested name. This must be valid UTF-8. * Copied into spec; clients can free the buffer passed after this call. */ void mir_window_spec_set_name(MirWindowSpec* spec, char const* name); /** * Set the requested width, in pixels * * \param [in] spec Specification to mutate * \param [in] width Requested width. * * \note The requested dimensions are a hint only. The server is not * guaranteed to create a window of any specific width or height. */ void mir_window_spec_set_width(MirWindowSpec* spec, unsigned width); /** * Set the requested height, in pixels * * \param [in] spec Specification to mutate * \param [in] height Requested height. * * \note The requested dimensions are a hint only. The server is not * guaranteed to create a window of any specific width or height. */ void mir_window_spec_set_height(MirWindowSpec* spec, unsigned height); /** * Set the requested width increment, in pixels. * Defines an arithmetic progression of sizes starting with min_width (if set, otherwise 0) * into which the window prefers to be resized. * * \param [in] spec Specification to mutate * \param [in] width_inc Requested width increment. * * \note The requested dimensions are a hint only. The server is not guaranteed to * create a window of any specific width or height. */ void mir_window_spec_set_width_increment(MirWindowSpec* spec, unsigned width_inc); /** * Set the requested height increment, in pixels * Defines an arithmetic progression of sizes starting with min_height (if set, otherwise 0) * into which the window prefers to be resized. * * \param [in] spec Specification to mutate * \param [in] height_inc Requested height increment. * * \note The requested dimensions are a hint only. The server is not guaranteed to * create a window of any specific width or height. */ void mir_window_spec_set_height_increment(MirWindowSpec* spec, unsigned height_inc); /** * Set the minimum width, in pixels * * \param [in] spec Specification to mutate * \param [in] min_width Minimum width. * * \note The requested dimensions are a hint only. The server is not guaranteed to create a * window of any specific width or height. */ void mir_window_spec_set_min_width(MirWindowSpec* spec, unsigned min_width); /** * Set the minimum height, in pixels * * \param [in] spec Specification to mutate * \param [in] min_height Minimum height. * * \note The requested dimensions are a hint only. The server is not guaranteed to create a * window of any specific width or height. */ void mir_window_spec_set_min_height(MirWindowSpec* spec, unsigned min_height); /** * Set the maximum width, in pixels * * \param [in] spec Specification to mutate * \param [in] max_width maximum width. * * \note The requested dimensions are a hint only. The server is not guaranteed to create a * window of any specific width or height. */ void mir_window_spec_set_max_width(MirWindowSpec* spec, unsigned max_width); /** * Set the maximum height, in pixels * * \param [in] spec Specification to mutate * \param [in] max_height maximum height. * * \note The requested dimensions are a hint only. The server is not guaranteed to create a * window of any specific width or height. */ void mir_window_spec_set_max_height(MirWindowSpec* spec, unsigned max_height); /** * Set the minimum aspect ratio. This is the minimum ratio of window width to height. * It is independent of orientation changes and/or preferences. * * \param [in] spec Specification to mutate * \param [in] width numerator * \param [in] height denominator * * \note The requested aspect ratio is a hint only. The server is not guaranteed * to create a window of any specific aspect. */ void mir_window_spec_set_min_aspect_ratio(MirWindowSpec* spec, unsigned width, unsigned height); /** * Set the maximum aspect ratio. This is the maximum ratio of window width to height. * It is independent of orientation changes and/or preferences. * * \param [in] spec Specification to mutate * \param [in] width numerator * \param [in] height denominator * * \note The requested aspect ratio is a hint only. The server is not guaranteed * to create a window of any specific aspect. */ void mir_window_spec_set_max_aspect_ratio(MirWindowSpec* spec, unsigned width, unsigned height); /** * \param [in] spec Specification to mutate * \param [in] output_id ID of output to place window on. From MirDisplayOutput.output_id * * \note If this call returns %true then a valid window returned from mir_create_window() is * guaranteed to be fullscreen on the specified output. An invalid window is returned * if the server unable to, or policy prevents it from, honouring this request. */ void mir_window_spec_set_fullscreen_on_output(MirWindowSpec* spec, uint32_t output_id); /** * Set the requested preferred orientation mode. * \param [in] spec Specification to mutate * \param [in] mode Requested preferred orientation * * \note If the server is unable to create a window with the preferred orientation at * the point mir_create_window() is called it will instead return an invalid window. */ void mir_window_spec_set_preferred_orientation(MirWindowSpec* spec, MirOrientationMode mode); /** * Request that the created window be attached to a window of a different client. * * This is restricted to input methods, which need to attach their suggestion window * to text entry widgets of other processes. * * \param [in] spec Specification to mutate * \param [in] parent A MirWindowId reference to the parent window * \param [in] attachment_rect A rectangle specifying the region (in parent window coordinates) * that the created window should be attached to. * \param [in] edge The preferred edge direction to attach to. Use * mir_edge_attachment_any for no preference. * \return False if the operation is invalid for this window type. * * \note If the parent window becomes invalid before mir_create_window() is processed, * it will return an invalid window. If the parent window is valid at the time * mir_create_window() is called but is later closed, this window will also receive * a close event. */ bool mir_window_spec_attach_to_foreign_parent(MirWindowSpec* spec, MirWindowId* parent, MirRectangle* attachment_rect, MirEdgeAttachment edge); /** * Set the requested state. * \param [in] spec Specification to mutate * \param [in] state Requested state * * \note If the server is unable to create a window with the requested state at * the point mir_create_window() is called it will instead return an invalid window. */ void mir_window_spec_set_state(MirWindowSpec* spec, MirWindowState state); /** * Set a collection of input rectangles associated with the spec. * Rectangles are specified as a list of regions relative to the top left * of the specified window. If the server applies this specification * to a window input which would normally go to the window but is not * contained within any of the input rectangles instead passes * on to the next client. * * \param [in] spec The spec to accumulate the request in. * \param [in] rectangles An array of MirRectangles specifying the input shape. * \param [in] n_rects The number of elements in the rectangles array. */ void mir_window_spec_set_input_shape(MirWindowSpec* spec, MirRectangle const *rectangles, size_t n_rects); /** * Set the event handler to be called when events arrive for a window. * \warning event_handler could be called from another thread. You must do * any locking appropriate to protect your data accessed in the * callback. There is also a chance that different events will be * called back in different threads, for the same window, * simultaneously. * \param [in] spec The spec to accumulate the request in. * \param [in] callback The callback function * \param [in] context Additional argument to be passed to callback */ void mir_window_spec_set_event_handler(MirWindowSpec* spec, MirWindowEventCallback callback, void* context); /** * Ask the shell to customize "chrome" for this window. * For example, on the phone hide indicators when this window is active. * * \param [in] spec The spec to accumulate the request in. * \param [in] style The requested level of "chrome" */ void mir_window_spec_set_shell_chrome(MirWindowSpec* spec, MirShellChrome style); /** * Attempts to set the pointer confinement spec for this window * * This will request the window manager to confine the pointer to the surfaces region. * * \param [in] spec The spec to accumulate the request in. * \param [in] state The state you would like the pointer confinement to be in. */ void mir_window_spec_set_pointer_confinement(MirWindowSpec* spec, MirPointerConfinementState state); /** * Set the window placement on the spec. * * \param [in] spec the spec to update * \param [in] rect the destination rectangle to align with * \param [in] rect_gravity the point on \p rect to align with * \param [in] surface_gravity the point on the window to align with * \param [in] placement_hints positioning hints to use when limited on space * \param [in] offset_dx horizontal offset to shift w.r.t. \p rect * \param [in] offset_dy vertical offset to shift w.r.t. \p rect * * Moves a window to \p rect, aligning their reference points. * * \p rect is relative to the top-left corner of the parent window. * \p rect_gravity and \p surface_gravity determine the points on \p rect and * the window to pin together. \p rect's alignment point can be offset by * \p offset_dx and \p offset_dy, which is equivalent to offsetting the * position of the window. * * \p placement_hints determine how the window should be positioned in the case * that the window would fall off-screen if placed in its ideal position. * See \ref MirPlacementHints for details. */ void mir_window_spec_set_placement(MirWindowSpec* spec, const MirRectangle* rect, MirPlacementGravity rect_gravity, MirPlacementGravity window_gravity, MirPlacementHints placement_hints, int offset_dx, int offset_dy); /** * Set the name for the cursor from the system cursor theme. * \param [in] spec The spec * \param [in] name The name, or "" to reset to default */ void mir_window_spec_set_cursor_name(MirWindowSpec* spec, char const* name); /** * \note To be deprecated soon. Only for enabling other deprecations. * * Set the requested pixel format. * \param [in] spec Specification to mutate * \param [in] format Requested pixel format * * \note If this call returns %true then the server is guaranteed to honour this request. * If the server is unable to create a window with this pixel format at * the point mir_create_window() is called it will instead return an invalid window. */ void mir_window_spec_set_pixel_format(MirWindowSpec* spec, MirPixelFormat format); /** * \note To be deprecated soon. Only for enabling other deprecations. * * Set the requested buffer usage. * \param [in] spec Specification to mutate * \param [in] usage Requested buffer usage * * \note If this call returns %true then the server is guaranteed to honour this request. * If the server is unable to create a window with this buffer usage at * the point mir_create_window() is called it will instead return an invalid window. */ void mir_window_spec_set_buffer_usage(MirWindowSpec* spec, MirBufferUsage usage); /** * \note To be deprecated soon. Waiting for mir_window_spec_set_render_surfaces() to land. * * Set the streams associated with the spec. * streams[0] is the bottom-most stream, and streams[size-1] is the topmost. * On application of the spec, a stream that is present in the window, * but is not in the list will be disassociated from the window. * On application of the spec, a stream that is not present in the window, * but is in the list will be associated with the window. * Streams set a displacement from the top-left corner of the window. * * \warning disassociating streams from the window will not release() them. * \warning It is wiser to arrange the streams within the bounds of the * window the spec is applied to. Shells can define their own * behavior as to what happens to an out-of-bound stream. * * \param [in] spec The spec to accumulate the request in. * \param [in] streams An array of non-null streams info. * \param [in] num_streams The number of elements in the streams array. */ void mir_window_spec_set_streams(MirWindowSpec* spec, MirBufferStreamInfo* streams, unsigned int num_streams); /** * Set the MirWindowSpec to display content contained in a render surface * * \warning: The initial call to mir_window_spec_add_render_surface will set * the bottom-most content, and subsequent calls will stack the * content on top. * * \param spec The window_spec to be updated * \param render_surface The render surface containing the content to be displayed * \param logical_width The width that the content will be displayed at * (Ignored for buffer streams) * \param logical_height The height that the content will be displayed at * (Ignored for buffer streams) * \param displacement_x The x displacement from the top-left corner of the MirWindow * \param displacement_y The y displacement from the top-left corner of the MirWindow */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" void mir_window_spec_add_render_surface(MirWindowSpec* spec, MirRenderSurface* render_surface, int logical_width, int logical_height, int displacement_x, int displacement_y) MIR_FOR_REMOVAL_IN_VERSION_1("This function is slated for rename due to MirRenderSurface-->MirSurface transition"); #pragma GCC diagnostic pop /** * Release the resources held by a MirWindowSpec. * * \param [in] spec Specification to release */ void mir_window_spec_release(MirWindowSpec* spec); /** * Request changes to the specification of a window. The server will decide * whether and how the request can be honoured. * * \param [in] window The window to mutate * \param [in] spec Spec with the requested changes applied */ void mir_window_apply_spec(MirWindow* window, MirWindowSpec* spec); /** * Create a window from a given specification * * * \param [in] requested_specification Specification of the attributes for the created window * \param [in] callback Callback function to be invoked when creation is complete * \param [in, out] context User data passed to callback function. * This callback is guaranteed to be called, and called with a * non-null MirWindow*, but the window may be invalid in * case of an error. */ void mir_create_window(MirWindowSpec* requested_specification, MirWindowCallback callback, void* context); /** * Create a window from a given specification and wait for the result. * \param [in] requested_specification Specification of the attributes for the created window * \return The new window. This is guaranteed non-null, but may be invalid * in the case of error. */ MirWindow* mir_create_window_sync(MirWindowSpec* requested_specification); /** * Release the supplied window and any associated buffer. * * \warning callback could be called from another thread. You must do any * locking appropriate to protect your data accessed in the * callback. * \param [in] window The window * \param [in] callback Callback function to be invoked when the request * completes * \param [in,out] context User data passed to the callback function */ void mir_window_release( MirWindow* window, MirWindowCallback callback, void *context); /** * Release the specified window like in mir_window_release(), but also wait * for the operation to complete. * \param [in] window The window to be released */ void mir_window_release_sync(MirWindow* window); /** * Test for a valid window * \param [in] window The window * \return True if the supplied window is valid, or * false otherwise. */ bool mir_window_is_valid(MirWindow* window); /** * Set the event handler to be called when events arrive for a window. * \warning event_handler could be called from another thread. You must do * any locking appropriate to protect your data accessed in the * callback. There is also a chance that different events will be * called back in different threads, for the same window, * simultaneously. * \param [in] window The window * \param [in] callback The callback function * \param [in] context Additional argument to be passed to callback */ void mir_window_set_event_handler(MirWindow* window, MirWindowEventCallback callback, void* context); /** * Retrieve the primary MirBufferStream associated with a window (to advance buffers, * obtain EGLNativeWindow, etc...) * * \deprecated Users should use mir_window_spec_set_streams() to arrange * the content of a window, instead of relying on a stream * being created by default. * \warning If the window was created with, or modified to have a * MirWindowSpec containing streams added through * mir_window_spec_set_streams(), the default stream will * be removed, and this function will return NULL. * \param[in] window The window */ MirBufferStream* mir_window_get_buffer_stream(MirWindow* window); /** * Retrieve a text description of the error. The returned string is owned by * the library and remains valid until the window or the associated * connection has been released. * \param [in] window The window * \return A text description of any error resulting in an * invalid window, or the empty string "" if the * connection is valid. */ char const* mir_window_get_error_message(MirWindow* window); /** * Get a window's parameters. * \pre The window is valid * \param [in] window The window * \param [out] parameters Structure to be populated */ void mir_window_get_parameters(MirWindow* window, MirWindowParameters* parameters); /** * Get the orientation of a window. * \param [in] window The window to query * \return The orientation of the window */ MirOrientation mir_window_get_orientation(MirWindow* window); /** * Attempts to raise the window to the front. * * \param [in] window The window to raise * \param [in] cookie A cookie instance obtained from an input event. * An invalid cookie will terminate the client connection. */ void mir_window_raise(MirWindow* window, MirCookie const* cookie); /** * Get the type (purpose) of a window. * \param [in] window The window to query * \return The type of the window */ MirWindowType mir_window_get_type(MirWindow* window); /** * Change the state of a window. * \param [in] window The window to operate on * \param [in] state The new state of the window */ void mir_window_set_state(MirWindow* window, MirWindowState state); /** * Get the current state of a window. * \param [in] window The window to query * \return The state of the window */ MirWindowState mir_window_get_state(MirWindow* window); /** * Query the focus state for a window. * \param [in] window The window to operate on * \return The focus state of said window */ MirWindowFocusState mir_window_get_focus_state(MirWindow* window); /** * Query the visibility state for a window. * \param [in] window The window to operate on * \return The visibility state of said window */ MirWindowVisibility mir_window_get_visibility(MirWindow* window); /** * Query the DPI value of the window (dots per inch). This will vary depending * on the physical display configuration and where the window is within it. * \return The DPI of the window, or zero if unknown. */ int mir_window_get_dpi(MirWindow* window); /** * Choose the cursor state for a window: whether a cursor is shown, * and which cursor if so. * \param [in] window The window to operate on * \param [in] parameters The configuration parameters obtained * from mir_cursor* family of functions. * */ void mir_window_configure_cursor(MirWindow* window, MirCursorConfiguration const* parameters); /** * Request to set the preferred orientations of a window. * The request may be rejected by the server; to check wait on the * result and check the applied value using mir_window_get_preferred_orientation * \param [in] window The window to operate on * \param [in] orientation The preferred orientation modes */ void mir_window_set_preferred_orientation(MirWindow* window, MirOrientationMode orientation); /** * Get the preferred orientation modes of a window. * \param [in] window The window to query * \return The preferred orientation modes */ MirOrientationMode mir_window_get_preferred_orientation(MirWindow* window); /** * \brief Request an ID for the window that can be shared cross-process and * across restarts. * * This call acquires a MirWindowId for this MirWindow. This MirWindowId * can be serialized to a string, stored or sent to another process, and then * later deserialized to refer to the same window. * * \param [in] window The window to acquire a persistent reference to. * \param [in] callback Callback to invoke when the request completes. * \param [in,out] context User data passed to completion callback. */ void mir_window_request_persistent_id(MirWindow* window, MirWindowIdCallback callback, void* context) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_window_request_window_id() instead"); void mir_window_request_window_id(MirWindow* window, MirWindowIdCallback callback, void* context); /** * \brief Request a persistent ID for a window and wait for the result * \param [in] window The window to acquire a persistent ID for. * \return A MirWindowId. This MirWindowId is owned by the calling code, and must * be freed with a call to mir_persistent_id_release() */ MirPersistentId* mir_window_request_persistent_id_sync(MirWindow* window) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_window_request_window_id_sync"); MirWindowId* mir_window_request_window_id_sync(MirWindow* window); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_MIR_WINDOW_H_ */ ./include/client/mir_toolkit/event.h0000644000004100000410000000156313115234416017777 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_EVENT_COMPAT_HEADER_H_ #define MIR_TOOLKIT_EVENT_COMPAT_HEADER_H_ #include "mir_toolkit/events/event.h" #endif /* MIR_TOOLKIT_EVENT_COMPAT_HEADER_H_ */ ./include/client/mir_toolkit/mir_presentation_chain.h0000644000004100000410000000534113115234664023405 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_PRESENTATION_CHAIN_H_ #define MIR_TOOLKIT_MIR_PRESENTATION_CHAIN_H_ #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Test for a valid presentation chain * * \param [in] presentation_chain The presentation chain * \return True if the supplied presentation_chain is valid, * or false otherwise. */ bool mir_presentation_chain_is_valid(MirPresentationChain* presentation_chain); /** * Retrieve a text description of the error. The returned string is owned by * the library and remains valid until the chain or the associated * connection has been released. * \param [in] presentation_chain The presentation chain * \return A text description of any error * resulting in an invalid chain, or the * empty string "" if the chain is valid. */ char const *mir_presentation_chain_get_error_message( MirPresentationChain* presentation_chain); /** Submit a buffer to the server so the server can display it. * * The server will notify the client when the buffer is available again via * the callback registered during buffer creation. * * \warning: Once submitted, the buffer cannot be modified or resubmitted * until the server has returned it. There's no guarantee about * how long a server may hold the submitted buffer. * * \param [in] presentation_chain The presentation chain * \param [in] buffer The buffer to be submitted * \param [in] available_callback The callback called when the buffer * is available * \param [in] available_context The context for the available_callback **/ void mir_presentation_chain_submit_buffer( MirPresentationChain* presentation_chain, MirBuffer* buffer, MirBufferCallback available_callback, void* available_context); #ifdef __cplusplus } /**@}*/ #endif #endif // MIR_TOOLKIT_MIR_PRESENTATION_CHAIN_H_ ./include/client/mir_toolkit/mir_buffer_stream.h0000644000004100000410000002512313115234664022354 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_BUFFER_STREAM_H_ #define MIR_TOOLKIT_MIR_BUFFER_STREAM_H_ #include #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Test for a valid buffer stream * * \param [in] buffer_stream The buffer stream * \return True if the supplied buffer_stream is valid, or * false otherwise. */ bool mir_buffer_stream_is_valid(MirBufferStream *buffer_stream); /** * Retrieve a text description of the error. The returned string is owned by * the library and remains valid until the stream or the associated * connection has been released. * \param [in] buffer_stream The buffer stream * \return A text description of any error resulting in an * invalid stream, or the empty string "" if the * connection is valid. */ char const *mir_buffer_stream_get_error_message(MirBufferStream *buffer_stream); /** * Create a new buffer stream. * * For example, the resulting buffer stream may be used * with mir_cursor_configuration_from_buffer_stream, * in order to post images to the system cursor. * * \param [in] connection A valid connection * \param [in] width Requested buffer width * \param [in] height Requested buffer height * \param [in] format Requested pixel format * \param [in] buffer_usage Requested buffer usage, use * mir_buffer_usage_software for cursor image streams * \param [in] callback Callback to be invoked when the request completes * The callback is guaranteed to be called and called with a * non-null MirBufferStream*, but the stream may be invalid in * case of an error. * \param [in] context Userdata to pass to callback function * * \return A handle that can be supplied to mir_wait_for */ MirWaitHandle* mir_connection_create_buffer_stream(MirConnection *connection, int width, int height, MirPixelFormat format, MirBufferUsage buffer_usage, MirBufferStreamCallback callback, void* context); /** * Create a new buffer stream unattached to a surface and wait for the result. * The resulting buffer stream may be used with * mir_cursor_configuration_from_buffer_stream in order to post images * to the system cursor. * * \param [in] connection A valid connection * \param [in] width Requested buffer width * \param [in] height Requested buffer height * \param [in] format Requested pixel format * \param [in] buffer_usage Requested buffer usage, use * mir_buffer_usage_software for cursor image streams * * \return The new buffer stream. This is guaranteed non-null, * but may be invalid in the case of error. */ MirBufferStream* mir_connection_create_buffer_stream_sync(MirConnection *connection, int width, int height, MirPixelFormat format, MirBufferUsage buffer_usage); /** * Release the supplied stream and any associated buffer. The returned wait * handle remains valid until the connection to the server is released. * \warning callback could be called from another thread. You must do any * locking appropriate to protect your data accessed in the * callback. * \param [in] buffer_stream The stream * \param [in] callback Callback function to be invoked when the request * completes * \param [in,out] context User data passed to the callback function * \return A handle that can be passed to mir_wait_for */ MirWaitHandle *mir_buffer_stream_release( MirBufferStream * buffer_stream, MirBufferStreamCallback callback, void *context); /** * Release the specified buffer stream like in mir,_buffer_stream_release(), * but also wait for the operation to complete. * \param [in] buffer_stream The buffer stream to be released */ void mir_buffer_stream_release_sync(MirBufferStream *buffer_stream); /** * Get the underlying platform type so the buffer obtained in "raw" * representation in mir_buffer_stream_get_current_buffer() * may be understood * * \deprecated Use of this function is inherently non-portable in the presence * of plug-in platform modules as these need not correspond to the available * types. To identify the graphics platform use * mir_connection_get_graphics_module(). To safely interpret the * buffer contents use mir_buffer_stream_get_graphics_region(). * * \todo This should be removed from the public API at the next API break. * * \pre The stream is valid * \param [in] stream The stream * \return One of mir_platform_type_android or * mir_platform_type_gbm */ /// @cond MIR_FOR_REMOVAL_IN_VERSION_1("To identify the graphics platform use mir_connection_get_graphics_module(). \n" "To safely interpret the buffer contents use mir_buffer_stream_get_graphics_region()") /// @endcond MirPlatformType mir_buffer_stream_get_platform_type(MirBufferStream *stream); /** * Retrieve the current buffer in "raw" representation. * \pre The buffer stream is valid * \param [in] buffer_stream The buffer stream * \param [out] buffer_package Structure to be populated */ void mir_buffer_stream_get_current_buffer(MirBufferStream *buffer_stream, MirNativeBuffer **buffer_package); /** * Advance a buffer stream's buffer. The returned handle remains valid until the * next call to mir_buffer_stream_swap_buffers, until the buffer stream has been * released or the connection to the server has been released. * \warning callback could be called from another thread. You must do any * locking appropriate to protect your data accessed in the * callback. * \param [in] buffer_stream The buffer stream * \param [in] callback Callback function to be invoked when the request * completes * \param [in,out] context User data passed to the callback function * \return A handle that can be passed to mir_wait_for */ MirWaitHandle *mir_buffer_stream_swap_buffers( MirBufferStream *buffer_stream, MirBufferStreamCallback callback, void *context); /** * Advance a buffer stream's buffer as in mir_buffer stream_swap_buffers(), * but also wait for the operation to complete. * \param [in] buffer_stream The buffer stream whose buffer to advance */ void mir_buffer_stream_swap_buffers_sync(MirBufferStream *buffer_stream); /** * Retrieve a buffer stream's graphics region * \warning Depending on platform, this can map the graphics buffer each * time its called. The region remains mapped until * mir_buffer_stream_swap_buffers(). * \pre The buffer stream is valid * \param [in] buffer_stream The buffer stream * \param [out] graphics_region Structure to be populated * \return True if the region is valid, false otherwise. */ bool mir_buffer_stream_get_graphics_region( MirBufferStream *buffer_stream, MirGraphicsRegion *graphics_region); /** * Retrieve a window type which may be used by EGL. * \param [in] buffer_stream The buffer stream * \return An EGLNativeWindowType that the client can use */ MirEGLNativeWindowType mir_buffer_stream_get_egl_native_window(MirBufferStream *buffer_stream); /** * Set the scale associated with all buffers in the stream * \param [in] buffer_stream The buffer stream * \param [in] scale The scale * \return A handle that can be passed to mir_wait_for */ MirWaitHandle *mir_buffer_stream_set_scale(MirBufferStream* buffer_stream, float scale); /** * Set the scale as in mir_buffer_stream_set_scale(), but also wait for the * operation to complete. * \param [in] buffer_stream The buffer stream * \param [in] scale The scale */ void mir_buffer_stream_set_scale_sync(MirBufferStream* buffer_stream, float scale); /** * Set the swapinterval for the stream. * \warning EGL users should use eglSwapInterval directly. * \param [in] stream The buffer stream * \param [in] interval The number of vblank signals that * mir_buffer_stream_swap_buffers will wait for * \return A wait handle that can be passed to mir_wait_for, * or NULL if the interval could not be supported */ MirWaitHandle* mir_buffer_stream_set_swapinterval(MirBufferStream* stream, int interval); /** * Query the swapinterval that the stream is operating with. * The default interval is 1. * \param [in] stream The buffer stream * \return The swapinterval value that the client is operating with. * Returns -1 if stream is invalid. */ int mir_buffer_stream_get_swapinterval(MirBufferStream* stream); /** * Set the physical size of the buffers provided by the buffer stream. * * \warning: This does not affect the size of the current buffer. * The next buffer after calling mir_buffer_stream_swap_buffers * will have the designated size. * * \param [in] stream The buffer stream * \param [in] width The desired physical width * \param [in] height The desired physical height */ void mir_buffer_stream_set_size(MirBufferStream* stream, int width, int height); /** * Get the physical size of the next buffer that will be provided by the stream. * * \param [in] stream The buffer stream * \param [out] width The physical width of the stream * \param [out] height The physical height of the stream */ void mir_buffer_stream_get_size(MirBufferStream* stream, int* width, int* height); #ifdef __cplusplus } /**@}*/ #endif #endif // MIR_TOOLKIT_MIR_BUFFER_STREAM_H_ ./include/client/mir_toolkit/mir_cursor_configuration.h0000644000004100000410000000514113115234664023772 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_CURSOR_H_ #define MIR_TOOLKIT_MIR_CURSOR_H_ #include #include #include /** * Opaque structure containing cursor parameterization. Create with mir_cursor* family. * Used with mir_window_configure_cursor. */ typedef struct MirCursorConfiguration MirCursorConfiguration; #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Release resources assosciated with cursor parameters * \param [in] parameters The operand */ void mir_cursor_configuration_destroy(MirCursorConfiguration *parameters); /** * Returns a new MirCursorConfiguration representing a named cursor * from the system cursor theme. Symbolic cursor names, such as * mir_default_cursor_name and mir_caret_cursor_name are available * see (mir_toolkit/cursors.h). * as input. * \deprecated Users should use mir_window_spec_set_cursor_name. * \param [in] name The cursor name * \return A cursor parameters object which must be passed * to_mir_cursor_configuration_destroy */ /// @cond MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_cursor_name()") /// @endcond MirCursorConfiguration *mir_cursor_configuration_from_name(char const* name); /** * Returns a new cursor configuration tied to a given buffer stream. * If the configuration is successfully applied buffers from the stream will be used * to fill the system cursor. * \param [in] stream The buffer stream * \param [in] hotspot_x The x-coordinate to use as the cursor's hotspot. * \param [in] hotspot_y The y-coordinate to use as the cursor's hotspot. * \return A cursor parameters object which must be passed * to_mir_cursor_configuration_destroy */ MirCursorConfiguration *mir_cursor_configuration_from_buffer_stream(MirBufferStream const* stream, int hotspot_x, int hotspot_y); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_MIR_CURSOR_H_ */ ./include/client/mir_toolkit/mir_surface.h0000644000004100000410000003414513115234664021164 0ustar www-datawww-data/* * Copyright © 2012-2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_SURFACE_H_ #define MIR_TOOLKIT_MIR_SURFACE_H_ #include #include #include #include #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif // Functions in this pragma section are to be deprecated #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" MirSurfaceSpec* mir_connection_create_spec_for_normal_surface(MirConnection* connection, int width, int height, MirPixelFormat format) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_create_normal_window_spec() instead"); MirSurfaceSpec* mir_connection_create_spec_for_menu(MirConnection* connection, int width, int height, MirPixelFormat format, MirSurface* parent, MirRectangle* rect, MirEdgeAttachment edge) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_specify_menu() instead"); MirSurfaceSpec* mir_connection_create_spec_for_tooltip(MirConnection* connection, int width, int height, MirPixelFormat format, MirSurface* parent, MirRectangle* zone) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_create_tip_window_spec() instead"); MirSurfaceSpec* mir_connection_create_spec_for_tip(MirConnection* connection, int width, int height, MirPixelFormat format, MirSurface* parent, MirRectangle* rect, MirEdgeAttachment edge) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_create_tip_window_spec() instead"); MirSurfaceSpec* mir_connection_create_spec_for_modal_dialog(MirConnection* connection, int width, int height, MirPixelFormat format, MirSurface* parent) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_create_modal_dialog_window_spec() instead"); MirSurfaceSpec* mir_connection_create_spec_for_dialog(MirConnection* connection, int width, int height, MirPixelFormat format) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_create_dialog_window_spec() instead"); MirSurfaceSpec* mir_create_surface_spec(MirConnection* connection) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_create_window_spec() instead"); MirSurfaceSpec* mir_connection_create_spec_for_changes(MirConnection* connection) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_create_window_spec() instead"); void mir_surface_spec_set_parent(MirSurfaceSpec* spec, MirSurface* parent) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_window_spec_set_parent() instead"); /** *\deprecated This will soon be a property of the backing content. * * Query the swapinterval that the surface is operating with. * The default interval is 1. * \param [in] surface The surface to operate on * \return The swapinterval value that the client is operating with. * Returns -1 if surface is invalid, or if the default stream * was removed by use of mir_window_spec_set_streams(). */ int mir_surface_get_swapinterval(MirSurface* surface) MIR_FOR_REMOVAL_IN_VERSION_1("This will soon be a property of the backing content"); void mir_surface_spec_set_type(MirSurfaceSpec* spec, MirSurfaceType type) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_type() instead"); void mir_surface_spec_set_name(MirSurfaceSpec* spec, char const* name) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_name() instead"); void mir_surface_spec_set_width(MirSurfaceSpec* spec, unsigned width) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_width() instead"); void mir_surface_spec_set_height(MirSurfaceSpec* spec, unsigned height) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_height() instead"); void mir_surface_spec_set_width_increment(MirSurfaceSpec* spec, unsigned width_inc) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_width_increment() instead"); void mir_surface_spec_set_height_increment(MirSurfaceSpec* spec, unsigned height_inc) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_height_increment() instead"); void mir_surface_spec_set_min_width(MirSurfaceSpec* spec, unsigned min_width) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_min_width() instead"); void mir_surface_spec_set_min_height(MirSurfaceSpec* spec, unsigned min_height) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_min_height() instead"); void mir_surface_spec_set_max_width(MirSurfaceSpec* spec, unsigned max_width) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_max_width() instead"); void mir_surface_spec_set_max_height(MirSurfaceSpec* spec, unsigned max_height) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_max_height() instead"); void mir_surface_spec_set_min_aspect_ratio(MirSurfaceSpec* spec, unsigned width, unsigned height) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_min_aspect_ratio() instead"); void mir_surface_spec_set_max_aspect_ratio(MirSurfaceSpec* spec, unsigned width, unsigned height) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_max_aspect_ratio() instead"); void mir_surface_spec_set_fullscreen_on_output(MirSurfaceSpec* spec, uint32_t output_id) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_fullscreen_on_output() instead"); void mir_surface_spec_set_preferred_orientation(MirSurfaceSpec* spec, MirOrientationMode mode) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_preferred_orientation() instead"); bool mir_surface_spec_attach_to_foreign_parent(MirSurfaceSpec* spec, MirPersistentId* parent, MirRectangle* attachment_rect, MirEdgeAttachment edge) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_attach_to_foreign_parent() instead"); void mir_surface_spec_set_state(MirSurfaceSpec* spec, MirSurfaceState state) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_state() instead"); void mir_surface_spec_release(MirSurfaceSpec* spec) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_release() instead"); void mir_surface_spec_set_input_shape(MirSurfaceSpec* spec, MirRectangle const *rectangles, size_t n_rects) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_input_shape() instead"); void mir_surface_spec_set_event_handler(MirSurfaceSpec* spec, mir_surface_event_callback callback, void* context) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_event_handler() instead"); void mir_surface_spec_set_shell_chrome(MirSurfaceSpec* spec, MirShellChrome style) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_shell_chrome() instead"); void mir_surface_spec_set_pointer_confinement(MirSurfaceSpec* spec, MirPointerConfinementState state) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_pointer_confinement() instead"); void mir_surface_spec_set_placement(MirSurfaceSpec* spec, const MirRectangle* rect, MirPlacementGravity rect_gravity, MirPlacementGravity window_gravity, MirPlacementHints placement_hints, int offset_dx, int offset_dy) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_placement() instead"); MirSurfaceSpec* mir_connection_create_spec_for_input_method(MirConnection* connection, int width, int height, MirPixelFormat format) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_create_input_method_window_spec() instead"); void mir_surface_spec_set_pixel_format(MirSurfaceSpec* spec, MirPixelFormat format) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_pixel_format() instead"); void mir_surface_spec_set_buffer_usage(MirSurfaceSpec* spec, MirBufferUsage usage) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_buffer_usage() instead"); void mir_surface_spec_set_streams(MirSurfaceSpec* spec, MirBufferStreamInfo* streams, unsigned int num_streams) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_spec_set_streams() instead"); void mir_surface_apply_spec(MirSurface* surface, MirSurfaceSpec* spec) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_apply_spec() instead"); bool mir_surface_is_valid(MirSurface *surface) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_is_valid() instead"); MirWaitHandle* mir_surface_create(MirSurfaceSpec* requested_specification, mir_surface_callback callback, void* context) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_create_window() instead"); MirSurface* mir_surface_create_sync(MirSurfaceSpec* requested_specification) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_create_window_sync() instead"); MirWaitHandle *mir_surface_release( MirSurface *surface, mir_surface_callback callback, void *context) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_release() instead"); void mir_surface_release_sync(MirSurface *surface) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_release_sync() instead"); void mir_surface_set_event_handler(MirSurface *surface, mir_surface_event_callback callback, void* context) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_set_event_handler() instead"); MirBufferStream* mir_surface_get_buffer_stream(MirSurface *surface) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_get_buffer_stream() instead"); char const* mir_surface_get_error_message(MirSurface *surface) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_get_error_message() instead"); void mir_surface_get_parameters(MirSurface *surface, MirSurfaceParameters *parameters) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_get_parameters() instead"); MirSurfaceType mir_surface_get_type(MirSurface* surface) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_get_type() instead"); MirWaitHandle* mir_surface_set_state(MirSurface *surface, MirSurfaceState state) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_set_state() instead"); MirSurfaceState mir_surface_get_state(MirSurface *surface) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_get_state() instead"); /** * Set the swapinterval for the default stream. * \warning EGL users should use eglSwapInterval directly. * \warning If the surface was created with, or modified to have a * MirSurfaceSpec containing streams added through * mir_window_spec_set_streams(), the default stream will * be removed, and this function will return NULL. * \param [in] surface The surface to operate on * \param [in] interval The number of vblank signals that * mir_surface_swap_buffers will wait for * \return A wait handle that can be passed to mir_wait_for, * or NULL if the interval could not be supported */ MirWaitHandle* mir_surface_set_swapinterval(MirSurface* surface, int interval) MIR_FOR_REMOVAL_IN_VERSION_1("Swap interval should be set on the backing content"); int mir_surface_get_dpi(MirSurface* surface) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_get_dpi() instead"); MirSurfaceFocusState mir_surface_get_focus(MirSurface *surface) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_get_focus_state() instead"); MirSurfaceVisibility mir_surface_get_visibility(MirSurface *surface) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_get_visibility() instead"); MirWaitHandle* mir_surface_configure_cursor(MirSurface *surface, MirCursorConfiguration const* parameters) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_configure_cursor() instead"); MirOrientation mir_surface_get_orientation(MirSurface *surface) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_get_orientation() instead"); MirWaitHandle* mir_surface_set_preferred_orientation(MirSurface *surface, MirOrientationMode orientation) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_set_preferred_orientation() instead"); MirOrientationMode mir_surface_get_preferred_orientation(MirSurface *surface) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_get_preferred_orientation() instead"); MirWaitHandle* mir_surface_request_persistent_id(MirSurface* surface, mir_surface_id_callback callback, void* context) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_request_persistent_id() instead"); MirPersistentId* mir_surface_request_persistent_id_sync(MirSurface *surface) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_request_persistent_id_sync() instead"); void mir_surface_raise(MirSurface* surface, MirCookie const* cookie) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_window_raise() instead"); #pragma GCC diagnostic pop #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_MIR_SURFACE_H_ */ ./include/client/mir_toolkit/mir_display_configuration.h0000644000004100000410000005213513115234664024127 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_TOOLKIT_MIR_DISPLAY_CONFIGURATION_H_ #define MIR_TOOLKIT_MIR_DISPLAY_CONFIGURATION_H_ #include "client_types.h" #include #ifdef __cplusplus extern "C" { #endif /** * \addtogroup mir_toolkit * @{ */ /** * A descriptor for a display mode. * * A display mode contains all the information necessary to drive a display. It * includes resolution and refresh rate, but also pixel clock, vsync and hsync * timings, and so on. */ typedef struct MirOutputMode MirOutputMode; /** * Release resources associated with a MirDisplayConfig handle. * * \param [in] config The handle to release */ void mir_display_config_release(MirDisplayConfig* config); /** * Get the maximum possible number of simultaneously active outputs this system * supports. * * \note There may be restrictions on the configuration required to achieve this * many active outputs. Typically the achievable number of simultaneously active * outputs is lower than this number. * * \param [in] config The configuration to query * \returns The maximum number of simultaneously active outputs * supportable at this time. */ int mir_display_config_get_max_simultaneous_outputs( MirDisplayConfig const* config) MIR_FOR_REMOVAL_IN_VERSION_1("Not accurate in Mir 0.26 and later. May be removed in future."); /** * Get the number of outputs available in this display configuration. * * This returns the total number of outputs the system has. This includes both * enabled and disabled output connections, and is typically larger than the * value returned from mir_display_config_get_max_simultaneous_outputs(). * * Typically this will be constant over the lifetime of a client as devices * usually do not gain extra physical ports at runtime. However, hotpluggable * display devices exist and the number of virtual outputs may change at * runtime, so this should always be called to determine the number of outputs * to iterate over. * * \param [in] config The configuration to query * \returns The number of outputs available in this configuration. */ int mir_display_config_get_num_outputs(MirDisplayConfig const* config); /** * Get a read-only handle to the index 'th output of this configuration * * \note The MirOutput handle is only valid while config is valid. * \pre 0 <= index < mir_display_config_get_num_outputs(config) * \param [in] config The configuration to query * \param [in] index The index of the output to get * \returns A read-only handle to a MirOutput within config which is valid * until mir_display_config_release(config) is called. */ MirOutput const* mir_display_config_get_output(MirDisplayConfig const* config, size_t index); /** * Get a modifyable handle to the index 'th output of this configuration * * \note The MirOutput handle is only valid while config is valid. * \pre 0 <= index < mir_display_config_get_num_outputs(config) * \param [in] config The configuration to query * \param [in] index The index of the output to get * \returns A handle to a MirOutput within config which is valid * until mir_display_config_release(config) is called. */ MirOutput* mir_display_config_get_mutable_output(MirDisplayConfig* config, size_t index); /** * Get the number of modes in the supported mode list of this output. * * The list of supported modes is retrieved from the hardware, possibly modified * by any applicable quirk tables, and may not be exhaustive. * * \param [in] output The MirOutput to query * \returns The number of modes in the supported mode list of output. */ int mir_output_get_num_modes(MirOutput const* output); /** * Get a handle for a mode descriptor from the list of supported modes. * * The list of supported modes is retrieved from the hardware, possibly modified * by any applicable quirk tables, and may not be exhaustive. * * \pre 0 <= index < mir_output_get_num_modes(output) * \note The handle remains valid as long as output is valid. * * \param [in] output The MirOutput to query * \param [in] index The index of the mode to retrieve. * \returns A handle for a description of the supported mode. This is valid * for as long as output is valid. The return value is never null. */ MirOutputMode const* mir_output_get_mode(MirOutput const* output, size_t index); /** * Get a handle to the output's preferred mode. * * This is provided by the output itself. For modern displays (LCD, OLED, etc) * it is typically a mode with the native resolution. * * An output may not have a preferred mode, in which case this call will return * NULL. * * \note The handle remains valid as long as output is valid. * * \param [in] output The MirOutput to query * \returns A handle for a description of the supported mode. This is valid * for as long as output is valid. If the output does not have a * preferred mode, it returns NULL. */ MirOutputMode const* mir_output_get_preferred_mode(MirOutput const* output); /** * Get the index of the output's preferred mode. * * This is provided by the output itself. For modern displays (LCD, OLED, etc) * it is typically a mode with the native resolution. * * An output may not have a preferred mode, in which case this call will return * (size_t)-1. * * \param [in] output The MirOutput to query * \returns The index of the output's preferred mode, if it has one, or * (size_t)-1 if output does not have a preferred mode. */ size_t mir_output_get_preferred_mode_index(MirOutput const* output); /** * Get a handle to the output's current mode. * * An output may not have a current mode (for example, if it is disabled), in * which case this call will return NULL. * * \note The handle remains valid as long as output is valid. * * \param [in] output The MirOutput to query * \returns A handle for a description of the supported mode. This is valid * for as long as output is valid. If the output does not have a * current mode, it returns NULL. */ MirOutputMode const* mir_output_get_current_mode(MirOutput const* output); /** * Get the index of to the output's current mode. * * An output may not have a current mode (for example, if it is disabled), in * which case this call will return (size_t)-1. * * \param [in] output The MirOutput to query * \returns The index of the output's current mode, if it has one, or * (size_t)-1 if output does not have a current mode. */ size_t mir_output_get_current_mode_index(MirOutput const* output); /** * Set the current mode of an output. * * \param [in] output The MirOutput to mutate * \param [in] mode The MirOutputMode to set as the current mode. */ void mir_output_set_current_mode(MirOutput* output, MirOutputMode const* mode); /** * Get the number of pixel formats supported by this output * * \param [in] output The MirOutput to query * \returns The number of pixel formats for output. */ int mir_output_get_num_pixel_formats(MirOutput const* output); /** * Get a pixel format from the list of supported formats * * \pre 0 <= index < mir_output_get_num_pixel_formats(output) * * \param [in] output The MirOutput to query * \param [in] index The index of the format to query * \returns The index 'th supported pixel format. */ MirPixelFormat mir_output_get_pixel_format(MirOutput const* output, size_t index); /** * Get the current pixel format. * * \param [in] output The MirOutput to query * \returns The current pixel format. This may be mir_pixel_format_invalid * (for example, if the output is not currently enabled). */ MirPixelFormat mir_output_get_current_pixel_format(MirOutput const* output); /** * Set the output format * * \param [in] output The MirOutput to modify * \param [in] format The MirPixelFormat to set */ void mir_output_set_pixel_format(MirOutput* output, MirPixelFormat format); /** * Get the ID of an output * * This can be used to refer to the output in other parts of the API, such as * mir_window_spec_set_fullscreen_on_output(). * * \param [in] output The MirOutput to query. * \returns The ID of output, which may be used to refer to it in other * parts of the API. */ int mir_output_get_id(MirOutput const* output); /** * Get the physical connection type of an output. * * This is a best-effort determination, and may be incorrect. * * \param [in] output The MirOutput to query * \returns The type of the display connection, or mir_output_type_unknown * if it cannot be determined. */ MirOutputType mir_output_get_type(MirOutput const* output); /** * Get the textual name of an output type. * * \param [in] type The MirDisplayOutputType to describe. * \returns The name of the output type. */ char const* mir_display_output_type_name(MirDisplayOutputType type) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_output_type_name instead"); /** * Get the textual name of an output type. * * \param [in] type The MirOutputType to describe. * \returns The name of the output type. */ char const* mir_output_type_name(MirOutputType type); /** * Get the x coordinate of the top-left point of the output in the virtual * display space. * * Outputs can be thought of as viewports into a virtual display space. They may * freely overlap, coincide, or be disjoint as desired. * * Output orientation changes the orientation of the output rectangle in virtual * display space, but does not change its top-left corner. * * \param [in] output The MirOutput to query * \returns The x coordinate of the top-left point of the output in the * virtual display space. */ int mir_output_get_position_x(MirOutput const* output); /** * Get the y coordinate of the top-left point of the output in the virtual * display space. * * Outputs can be thought of as viewports into a virtual display space. They may * freely overlap, coincide, or be disjoint as desired. * * Output orientation changes the orientation of the output rectangle in virtual * display space, but does not change its top-left corner. * * \param [in] output The MirOutput to query * \returns The y coordinate of the top-left point of the output in the * virtual display space. */ int mir_output_get_position_y(MirOutput const* output); /** * Set the coordinates of the top-left point of the output in the virtual * display space. * * Outputs can be thought of as viewports into a virtual display space. They may * freely overlap, coincide, or be disjoint as desired. * * Output orientation changes the orientation of the output rectangle in virtual * display space, but does not change its top-left corner. * * \param [in] output The MirOutput to mutate * \param [in] x The new x coordinate of the top-left point of the * output in virtual display space. * \param [in] y The new y coordinate of the top-left point of the * output in virtual display space. */ void mir_output_set_position(MirOutput* output, int x, int y); /** * Get whether there is a display physically connected to the output. * * This gives a best-effort determination of whether or not enabling this output * will result in an image being displayed to the user. * * The accuracy of this determination varies with connection type - for example, * for DisplayPort and HDMI connections a return value of * mir_output_connection_state_connected is usually a reliable indicator that * there is a powered-on display connected. * * VGA and DVI connectors can usually determine whether or not there is a * physically connected display, but cannot distinguish between a powered or * unpowered display. * * It is not always possible to determine whether or not there is a display * connected; in such cases mir_output_connection_state_unknown is returned. * * \param [in] output The MirOutput to query * \returns Whether there is a display connected to this output. */ MirOutputConnectionState mir_output_get_connection_state( MirOutput const* output); /** * Get whether this output is enabled in the current configuration. * * \param [in] output the MirOutput to query * \returns Whether the output is enabled. */ bool mir_output_is_enabled(MirOutput const* output); /** * Enable this output * * \param [in] output the MirOutput to enable */ void mir_output_enable(MirOutput* output); /** * Disable this output * * \param [in] output the MirOutput to disable */ void mir_output_disable(MirOutput* output); /** * Get a descriptive manufacturer/model string for the connected display. * The format of this string is arbitrary and driver-specific but should be * human-readable and helpful for someone to identify which physical display * this is. Note this function is not called get_name because that would imply * the returned value is different for each output, whereas it may not be. * * \returns A nul-terminated string or NULL if none available. This string * remains valid for the lifetime of the MirOutput object. */ char const* mir_output_get_model(MirOutput const* output); /** * Get the physical width of the connected display, in millimetres. * * A best-effort report of the physical width of the display connected to this * output. This is retrieved from the display hardware, possibly modified by any * applicable quirk tables. * * Where this information is unavailable or inapplicable (for example, * projectors), 0 is returned. * * \param [in] output the MirOutput to query * \returns Physical width of the connected display, in mm. */ int mir_output_get_physical_width_mm(MirOutput const* output); /** * Get the physical height of the connected display, in millimetres. * * A best-effort report of the physical height of the display connected to this * output. This is retrieved from the display hardware, possibly modified by any * applicable quirk tables. * * Where this information is unavailable or inapplicable (for example, * projectors), 0 is returned. * * \param [in] output the MirOutput to query * \returns Physical height of the connected display, in mm. */ int mir_output_get_physical_height_mm(MirOutput const* output); /** * Get the power state of a connected display. * * It is undefined which power state is returned for an output which is not * connected. * * \param [in] output The MirOutput to query * \returns The power state of the display connected to output. */ MirPowerMode mir_output_get_power_mode(MirOutput const* output); /** * Set the power state of a connected display. * * It is undefined what power state is set if the output is not connected. * * \param [in] output The MirOutput to mutate * \param [in] mode The new MirPowerMode for output */ void mir_output_set_power_mode(MirOutput* output, MirPowerMode mode); /** * Get the orientation of a display. * * \param [in] output The MirOutput to query * \returns The orientation of output */ MirOrientation mir_output_get_orientation(MirOutput const* output); /** * Set the orientation of a display. * * \param [in] output The MirOutput to mutate * \param [in] orientation The new MirOrientation for output */ void mir_output_set_orientation(MirOutput* output, MirOrientation orientation); /** * Get the scale-factor of a display * * The scale-factor specifies the conversion between logical pixels and physical pixels on this output. * * A surface with dimensions 200×100 on an output with scale-factor 2.0 will display 400x200 pixels * on this output, will display 300x150 pixels on an output with scale-factor 1.5, and so on. * * Where this calculation would result in a fractional number of pixels the floor is used, so a surface with * dimensions 101x100 on an output with scale-factor of 1.5 will display 151x150 pixels, not 152x150. * * \param [in] output The MirOutput to query * \returns The scale-factor of this monitor */ float mir_output_get_scale_factor(MirOutput const* output); /** * Get the subpixel arrangement of a display * * \param [in] output The MirOutput to query * \returns The MirSubpixelArrangement corresponding to the physical arrangement of subpixels * on this display, or mir_subpixel_arrangement_unknown if this cannot be determined. */ MirSubpixelArrangement mir_output_get_subpixel_arrangement(MirOutput const* output); /** * Get the form-factor of a connected output. * * This call succeeds even if the output is not connected, but may return nonsense values. * * \param [in] output The MirOutput to query * \returns The form factor of this output */ MirFormFactor mir_output_get_form_factor(MirOutput const* output); /** Gets if the platform supports gamma correction * * \param [in] output The MirOutput to query * \returns true if gamma is supported on the hardware, otherwise not supported */ bool mir_output_is_gamma_supported(MirOutput const* client_output); /** Gets the gamma size * * \param [in] output The MirOutput to query * \returns The size of the gamma ramp LUT * */ uint32_t mir_output_get_gamma_size(MirOutput const* client_output); /** Get the gamma ramp of a display * * Copies the gammas into user created buffers up to the size provided * * \param [in] output The MirOutput to query * \param [out] red The red gamma ramp * \param [out] green The green gamma ramp * \param [out] blue The blue gamma ramp * \param [in] size The size of the gamma ramp */ void mir_output_get_gamma(MirOutput const* client_output, uint16_t* red, uint16_t* green, uint16_t* blue, uint32_t size); /** Set the gamma ramp of a display * * \param [in] output The MirOutput to query * \param [in] red The red gamma ramp * \param [in] green The green gamma ramp * \param [in] blue The blue gamma ramp * \param [in] size The size of the gamma ramp */ void mir_output_set_gamma(MirOutput* client_output, uint16_t const* red, uint16_t const* green, uint16_t const* blue, uint32_t size); /** * Set the scale-factor of a display * * The scale-factor specifies the conversion between logical pixels and physical * pixels on this output. See mir_output_get_scale_factor for further details. * * \param [in] output The MirOutput to modify * \param [in] scale The scale factor */ void mir_output_set_scale_factor(MirOutput* output, float scale); /** * Get the raw EDID data of a display. * * This returns a pointer to the start of the raw, unparsed EDID data. * Some displays or connection types may not provide EDID data. In that case, * this returns NULL. * * An EDID is always at least 128 bytes, but may be longer in the presence of extensions. * * \param [in] output The MirOutput to query * \returns A pointer to the start of the raw EDID data. * This pointer remains valid as long as the MirOutput remains valid. * Returns NULL if there is no EDID available. */ uint8_t const* mir_output_get_edid(MirOutput const* output); /** * Get the size of the EDID of this display. * * If the EDID is unavailable for some reason this returns 0. * * An EDID is always at least 128 bytes, but may be longer in the presence of extensions. * * \param [in] output The MirOutput to query * \returns The size of the data pointed to by mir_output_get_edid(output). */ size_t mir_output_get_edid_size(MirOutput const* output); /** * Get the width, in pixels, of a MirOutputMode * * \note This is unaffected by the orientation of the output * * \param [in] mode The MirOutputMode to query * \returns The width, in pixels, of mode. */ int mir_output_mode_get_width(MirOutputMode const* mode); /** Get the height, in pixels, of a MirOutputMode * * \note This is unaffected by the orientation of the output * * \param [in] mode The MirOutputMode to query * \returns The height, in pixels, of mode. */ int mir_output_mode_get_height(MirOutputMode const* mode); /** Get the refresh rate, in Hz, of a MirOutputMode * * \param [in] mode The MirOutputMode to query * \returns The refresh rate, in Hz, of mode */ double mir_output_mode_get_refresh_rate(MirOutputMode const* mode); /**@}*/ #ifdef __cplusplus } #endif #endif //MIR_TOOLKIT_MIR_DISPLAY_CONFIGURATION_H_ ./include/client/mir_toolkit/extensions/0000755000004100000410000000000013115234665020705 5ustar www-datawww-data./include/client/mir_toolkit/extensions/mesa_drm_auth.h0000644000004100000410000000430613115234664023670 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_CLIENT_EXTENSIONS_MESA_DRM_AUTH_H_ #define MIR_CLIENT_EXTENSIONS_MESA_DRM_AUTH_H_ #include "mir_toolkit/mir_extension_core.h" #ifdef __cplusplus extern "C" { #endif struct MirConnection; typedef void (*MirAuthFdCallback)( int auth_fd, void* context); /* * Request authenticated FD from server. * \param [in] connection The connection * \param [in] cb The callback triggered on server response * \param [in] context The context for the callback */ typedef void (*MirExtensionMesaDrmAuthFd)(MirConnection*, MirAuthFdCallback cb, void* context); typedef void (*MirAuthMagicCallback)( int response, void* context); /* * Request magic cookie from server. * \param [in] connection The connection * \param [in] magic The magic * \param [in] cb The callback triggered on server response * \param [in] context The context for the callback */ typedef void (*MirExtensionMesaDrmAuthMagic)( MirConnection* connection, int magic, MirAuthMagicCallback cb, void* context); typedef struct MirExtensionMesaDRMAuthV1 { MirExtensionMesaDrmAuthFd drm_auth_fd; MirExtensionMesaDrmAuthMagic drm_auth_magic; } MirExtensionMesaDRMAuthV1; static inline MirExtensionMesaDRMAuthV1 const* mir_extension_mesa_drm_auth_v1( MirConnection* connection) { return (MirExtensionMesaDRMAuthV1 const*) mir_connection_request_extension( connection, "mir_extension_mesa_drm_auth", 1); } #ifdef __cplusplus } #endif #endif /* MIR_CLIENT_EXTENSIONS_MESA_DRM_AUTH_H_ */ ./include/client/mir_toolkit/extensions/window_coordinate_translation.h0000644000004100000410000000461513115234664027217 0ustar www-datawww-data/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_CLIENT_EXTENSIONS_WINDOW_COORDINATE_TRANSLATION_H_ #define MIR_CLIENT_EXTENSIONS_WINDOW_COORDINATE_TRANSLATION_H_ #include "mir_toolkit/mir_extension_core.h" #ifdef __cplusplus extern "C" { #endif /* Important note about extension: * There are many cases where such a mapping does not exist or would be expensive * to calculate. Only Mir servers started with the --debug option will ever provide * this extension, and even when --debug is enabled servers are free to * return nothing. */ /** * Get the screen coordinates corresponding to a pair of window coordinates * \pre The window is valid * \param [in] window The window * \param [in] x, y Surface coordinates to map to screen coordinates * \param [out] screen_x, screen_y The screen coordinates corresponding to x, y. * * This call will only be interesting for automated testing, where both the client * and shell state is known and constrained. */ typedef void (*MirExtensionWindowTranslateCoordinates)( MirWindow* window, int x, int y, int* screen_x, int* screen_y); typedef struct MirExtensionWindowCoordinateTranslationV1 { MirExtensionWindowTranslateCoordinates window_translate_coordinates; } MirExtensionWindowCoordinateTranslationV1; static inline MirExtensionWindowCoordinateTranslationV1 const* mir_extension_window_coordinate_translation_v1(MirConnection* connection) { return (MirExtensionWindowCoordinateTranslationV1 const*) mir_connection_request_extension( connection, "mir_extension_window_coordinate_translation", 1); } #ifdef __cplusplus } #endif #endif /* MIR_CLIENT_EXTENSIONS_WINDOW_COORDINATE_TRANSLATION_H_ */ ./include/client/mir_toolkit/extensions/gbm_buffer.h0000644000004100000410000001336313115234664023161 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_CLIENT_EXTENSIONS_GBM_BUFFER_H_ #define MIR_CLIENT_EXTENSIONS_GBM_BUFFER_H_ #include "mir_toolkit/mir_connection.h" #include "mir_toolkit/mir_extension_core.h" #include "mir_toolkit/mir_buffer.h" #ifdef __cplusplus extern "C" { #endif /** Allocate a MirBuffer via gbm * * available in V1 and V2. * * The callback will be called when the buffer is available for use. * It will be called once when created, and once per every * mir_presentation_chain_submit_buffer. * * The buffer can be destroyed via mir_buffer_release(). * * \note Not all formats or flags are available, and allocations may fail. * Be sure to check mir_buffer_is_valid() on the returned buffer. * \param [in] connection The connection * \param [in] width Requested buffer width * \param [in] height Requested buffer height * \param [in] gbm_pixel_format The pixel format, one of the GBM_FORMATs * \param [in] gbm_bo_flags The gbm_bo_flags for the buffer. * \param [in] available_callback The callback called when the buffer * is available * \param [in] available_context The context for the available_callback **/ typedef void (*mir_connection_allocate_buffer_gbm)( MirConnection* connection, int width, int height, unsigned int gbm_pixel_format, unsigned int gbm_bo_flags, MirBufferCallback available_callback, void* available_context); /** v2 version of mir_connection_allocate_buffer_gbm, with more accurate types. */ typedef void (*MirConnectionAllocateBufferGbm)( MirConnection* connection, uint32_t width, uint32_t height, uint32_t gbm_pixel_format, uint32_t gbm_bo_flags, MirBufferCallback available_callback, void* available_context); typedef struct MirExtensionGbmBufferV1 { mir_connection_allocate_buffer_gbm allocate_buffer_gbm; } MirExtensionGbmBufferV1; static inline MirExtensionGbmBufferV1 const* mir_extension_gbm_buffer_v1( MirConnection* connection) { return (MirExtensionGbmBufferV1 const*) mir_connection_request_extension( connection, "mir_extension_gbm_buffer", 1); } /** Allocate a MirBuffer via gbm and wait for the allocation. * available in V2. * The buffer can be destroyed via mir_buffer_release(). * * \param [in] connection The connection * \param [in] width Requested buffer width * \param [in] height Requested buffer height * \param [in] gbm_pixel_format The pixel format, one of the GBM_FORMATs * \param [in] gbm_bo_flags The gbm_bo_flags for the buffer. * \return The buffer **/ typedef MirBuffer* (*MirConnectionAllocateBufferGbmSync)( MirConnection* connection, uint32_t width, uint32_t height, uint32_t gbm_pixel_format, uint32_t gbm_bo_flags); /** Check if a MirBuffer is suitable for import via GBM_BO_IMPORT_FD * * \param [in] buffer The buffer * \return True if suitable, false if unsuitable */ typedef bool (*MirBufferIsGbmImportable)(MirBuffer* buffer); /** Access the fd a MirBuffer suitable for gbm import * \pre The buffer is suitable for GBM_BO_IMPORT_FD * \warning The fd is owned by the buffer. Do not close() it. * \param [in] buffer The buffer * \return The fd */ typedef int (*MirBufferGbmFd)(MirBuffer* buffer); /** Get the stride of a MirBuffer * \pre The buffer is suitable for GBM_BO_IMPORT_FD * \param [in] buffer The buffer * \return The stride of the buffer */ typedef uint32_t (*MirBufferGbmStride)(MirBuffer* buffer); /** Get the GBM_FORMAT of a MirBuffer * \pre The buffer is suitable for GBM_BO_IMPORT_FD * \param [in] buffer The buffer * \return The GBM_FORMAT of the buffer */ typedef uint32_t (*MirBufferGbmFormat)(MirBuffer* buffer); /** Get the gbm_bo_flags of a MirBuffer * \pre The buffer is suitable for GBM_BO_IMPORT_FD * \param [in] buffer The buffer * \return The gbm_bo_flags of the buffer */ typedef uint32_t (*MirBufferGbmFlags)(MirBuffer* buffer); /** Get the age of a MirBuffer * \pre The buffer is suitable for GBM_BO_IMPORT_FD * \param [in] buffer The buffer * \return The age of the buffer */ typedef unsigned int (*MirBufferGbmAge)(MirBuffer* buffer); typedef struct MirExtensionGbmBufferV2 { MirConnectionAllocateBufferGbm allocate_buffer_gbm; MirConnectionAllocateBufferGbmSync allocate_buffer_gbm_sync; MirBufferIsGbmImportable is_gbm_importable; MirBufferGbmFd fd; MirBufferGbmStride stride; MirBufferGbmFormat format; MirBufferGbmFlags flags; MirBufferGbmAge age; } MirExtensionGbmBufferV2; static inline MirExtensionGbmBufferV2 const* mir_extension_gbm_buffer_v2( MirConnection* connection) { return (MirExtensionGbmBufferV2 const*) mir_connection_request_extension( connection, "mir_extension_gbm_buffer", 2); } #ifdef __cplusplus } #endif #endif /* MIR_CLIENT_EXTENSIONS_GBM_BUFFER_H_ */ ./include/client/mir_toolkit/extensions/android_buffer.h0000644000004100000410000000530213115234664024026 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_CLIENT_EXTENSIONS_ANDROID_BUFFER_H_ #define MIR_CLIENT_EXTENSIONS_ANDROID_BUFFER_H_ #include "mir_toolkit/mir_connection.h" #include "mir_toolkit/mir_buffer.h" #include "mir_toolkit/mir_extension_core.h" #ifdef __cplusplus extern "C" { #endif /** Allocate a MirBuffer usable by the android platform. * * The callback will be called when the buffer is available for use. * It will be called once when created, and once per every * mir_presentation_chain_submit_buffer. * * The buffer can be destroyed via mir_buffer_release(). * * \note Not all GRALLOC_USAGE flags or HAL_PIXEL_FORMATs are available. * Be sure to check mir_buffer_is_valid() on the returned buffer. * \param [in] connection The connection * \param [in] width Requested buffer width * \param [in] height Requested buffer height * \param [in] hal_pixel_format The pixel format, one of * Android's HAL_PIXEL_FORMAT*s * \param [in] gralloc_usage_flags The GRALLOC_USAGE* flags for the buffer. * \param [in] available_callback The callback called when the buffer * is available * \param [in] available_context The context for the available_callback **/ typedef void (*mir_connection_allocate_buffer_android)( MirConnection* connection, int width, int height, unsigned int hal_pixel_format, unsigned int gralloc_usage_flags, MirBufferCallback available_callback, void* available_context); typedef struct MirExtensionAndroidBufferV1 { mir_connection_allocate_buffer_android allocate_buffer_android; } MirExtensionAndroidBufferV1; static inline MirExtensionAndroidBufferV1 const* mir_extension_android_buffer_v1( MirConnection* connection) { return (MirExtensionAndroidBufferV1 const*) mir_connection_request_extension( connection, "mir_extension_android_buffer", 1); } #ifdef __cplusplus } #endif #endif /* MIR_CLIENT_EXTENSIONS_ANDROID_BUFFER_H_ */ ./include/client/mir_toolkit/extensions/graphics_module.h0000644000004100000410000000340213115234664024221 0ustar www-datawww-data/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_CLIENT_EXTENSIONS_GRAPHICS_MODULE_H_ #define MIR_CLIENT_EXTENSIONS_GRAPHICS_MODULE_H_ #include "mir_toolkit/mir_extension_core.h" #ifdef __cplusplus extern "C" { #endif /** * Query graphics platform module. * * \note The char pointers in MirModuleProperties are owned by the connection and should not be * freed. They remain valid until the connection is released. * * \param [in] connection The connection * \param [out] properties Structure to be populated */ typedef void (*MirConnectionGetGraphicsModule) (MirConnection *connection, MirModuleProperties *properties); typedef struct MirExtensionGraphicsModuleV1 { MirConnectionGetGraphicsModule graphics_module; } MirExtensionGraphicsModuleV1; static inline MirExtensionGraphicsModuleV1 const* mir_extension_graphics_module_v1( MirConnection* connection) { return (MirExtensionGraphicsModuleV1 const*) mir_connection_request_extension( connection, "mir_extension_graphics_module", 1); } #ifdef __cplusplus } #endif #endif /* MIR_CLIENT_EXTENSIONS_GRAPHICS_MODULE_H_ */ ./include/client/mir_toolkit/extensions/android_egl.h0000644000004100000410000000434413115234664023331 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_CLIENT_EXTENSIONS_ANDROID_EGL_H_ #define MIR_CLIENT_EXTENSIONS_ANDROID_EGL_H_ #include "mir_toolkit/mir_connection.h" #include "mir_toolkit/rs/mir_render_surface.h" #include "mir_toolkit/mir_buffer.h" #include "mir_toolkit/mir_extension_core.h" #ifdef __cplusplus extern "C" { #endif struct ANativeWindow; struct ANativeWindowBuffer; typedef void* (*mir_extension_to_native_display_type)(MirConnection*); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" typedef struct ANativeWindow* (*mir_extension_create_anw)( MirRenderSurface* rs, int width, int height, unsigned int hal_pixel_format, unsigned int gralloc_usage_flags); #pragma GCC diagnostic pop typedef void (*mir_extension_destroy_anw)(struct ANativeWindow*); typedef struct ANativeWindowBuffer* (*mir_extension_create_anwb)(MirBuffer*); typedef void (*mir_extension_destroy_anwb)(struct ANativeWindowBuffer*); typedef struct MirExtensionAndroidEGLV1 { mir_extension_to_native_display_type to_display; mir_extension_create_anw create_window; mir_extension_destroy_anw destroy_window; mir_extension_create_anwb create_buffer; mir_extension_destroy_anwb destroy_buffer; } MirExtensionAndroidEGLV1; static inline MirExtensionAndroidEGLV1 const* mir_extension_android_egl_v1( MirConnection* connection) { return (MirExtensionAndroidEGLV1 const*) mir_connection_request_extension( connection, "mir_extension_android_egl", 1); } #ifdef __cplusplus } #endif #endif /* MIR_CLIENT_EXTENSIONS_ANDROID_EGL_H_ */ ./include/client/mir_toolkit/extensions/set_gbm_device.h0000644000004100000410000000322613115234664024017 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_CLIENT_EXTENSIONS_SET_GBM_DEVICE_H_ #define MIR_CLIENT_EXTENSIONS_SET_GBM_DEVICE_H_ #include "mir_toolkit/mir_extension_core.h" #ifdef __cplusplus extern "C" { #endif struct gbm_device; //Set the gbm device used by the client // \param [in] device The gbm_device. // \param [in] context The context to set the gbm device. typedef void (*MirSetGbmDevice)(struct gbm_device*, void* const context); typedef struct MirExtensionSetGbmDeviceV1 { MirSetGbmDevice set_gbm_device; void* const context; } MirExtensionSetGbmDeviceV1; //legacy compatibility typedef MirExtensionSetGbmDeviceV1 MirExtensionSetGbmDevice; static inline MirExtensionSetGbmDeviceV1 const* mir_extension_set_gbm_device_v1( MirConnection* connection) { return (MirExtensionSetGbmDeviceV1 const*) mir_connection_request_extension( connection, "mir_extension_set_gbm_device", 1); } #ifdef __cplusplus } #endif #endif /* MIR_CLIENT_EXTENSIONS_SET_GBM_DEVICE_H_ */ ./include/client/mir_toolkit/extensions/fenced_buffers.h0000644000004100000410000000762213115234664024024 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_CLIENT_EXTENSIONS_FENCED_BUFFERS_H_ #define MIR_CLIENT_EXTENSIONS_FENCED_BUFFERS_H_ #include "mir_toolkit/mir_extension_core.h" #ifdef __cplusplus extern "C" { #endif typedef enum MirBufferAccess { mir_none, mir_read, mir_read_write, } MirBufferAccess; /** @name Fenced Buffer content access functions. * * These functions will wait until it is safe to access the buffer for the given purpose. * If used with mir_none, the buffer will be given the buffer immediately, and without synchronization. * It is then up to the user to ensure that the buffer contents are not accessed at inapproprate times. * * \note the following functions (mir_buffer_get_native_buffer, mir_buffer_get_graphics_region) * can only be used when the buffer is not submitted to the server. * @{ */ /** * Retrieve the native fence associated with this buffer * * \warning Take care not to close the fd, the Mir client api * retains ownership of the fence fd. * \param [in] buffer The buffer. * \return The fd representing the fence associated with buffer. * **/ typedef int (*mir_buffer_get_fence)(MirBuffer*); /** * Protect the buffer's contents by associating a native fence with it. * * \warning any fence currently associated with buffer will be replaced in favor * of fence without waiting for the replaced fence to clear * \warning The Mir client api assumes ownership of the fence fd. * \param [in] buffer The buffer * \param [in] fence The fence that will be associated with buffer. If negative, * this will remove the fence associated with this buffer. * \param [in] access The ongoing access that is represented by fence. * If mir_none is set, this will remove the fence protecting the buffer content. **/ typedef void (*mir_buffer_associate_fence)( MirBuffer* buffer, int fence, MirBufferAccess access); /** Wait for the fence associated with the buffer to signal. After returning, * it is permissible to access the buffer's content for the designated purpose in access. * * \param [in] buffer The buffer * \param [in] access The access to wait for. * \param [in] timeout The amount of time to wait for the fence in nanoseconds, * or -1 for infinite timeout. * \return zero when fence was cleared successfully, or * a negative number when the timeout was reached before the fence signals **/ typedef int (*mir_buffer_wait_for_access)( MirBuffer* buffer, MirBufferAccess access, int timeout); typedef struct MirExtensionFencedBuffersV1 { mir_buffer_get_fence get_fence; mir_buffer_associate_fence associate_fence; mir_buffer_wait_for_access wait_for_access; } MirExtensionFencedBuffersV1; static inline MirExtensionFencedBuffersV1 const* mir_extension_fenced_buffers_v1( MirConnection* connection) { return (MirExtensionFencedBuffersV1 const*) mir_connection_request_extension( connection, "mir_extension_fenced_buffers", 1); } #ifdef __cplusplus } #endif #endif /* MIR_CLIENT_EXTENSIONS_ANDORID_EGL_H_ */ ./include/client/mir_toolkit/mir_buffer.h0000644000004100000410000001142113115234664020775 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_BUFFER_H_ #define MIR_TOOLKIT_MIR_BUFFER_H_ #include #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** Allocate a MirBuffer and do not wait for the server to return it. * The buffer will be suitable for writing to via the CPU. Buffers that * will be used on a GPU should be allocated via the platform appropriate * extensions. (eg, mir_extension_gbm_buffer or mir_extension_android_buffer) * * The callback will be called when the buffer is created. * * \param [in] connection The connection * \param [in] width Requested buffer width * \param [in] height Requested buffer height * \param [in] buffer_usage Requested buffer usage * \param [in] available_callback The callback called when the buffer * is available * \param [in] available_context The context for the available_callback **/ void mir_connection_allocate_buffer( MirConnection* connection, int width, int height, MirPixelFormat format, MirBufferCallback available_callback, void* available_context); /** Allocate a MirBuffer and wait for the server to return it. * * \param [in] connection The connection * \param [in] width Requested buffer width * \param [in] height Requested buffer height * \param [in] buffer_usage Requested buffer usage * \return The buffer **/ MirBuffer* mir_connection_allocate_buffer_sync( MirConnection* connection, int width, int height, MirPixelFormat format); /** Test for a valid buffer * \param [in] buffer The buffer * \return True if the buffer is valid, or false otherwise. **/ bool mir_buffer_is_valid(MirBuffer* buffer); /** Retrieve a text description an error associated with a MirBuffer. * The returned string is owned by the library and remains valid until the * buffer or the associated connection has been released. * \param [in] buffer The buffer * \return A text description of any error resulting in an * invalid buffer, or the empty string "" if the * connection is valid. **/ char const *mir_buffer_get_error_message(MirBuffer* buffer); /** * Access the MirBufferPackage * * \param [in] buffer The buffer * \return The MirBufferPackage representing buffer */ MirBufferPackage* mir_buffer_get_buffer_package(MirBuffer* buffer); /** Access a CPU-mapped region associated with a given buffer. * * \param [in] buffer The buffer * \param [out] region The mapped region * \param [out] layout The memory layout of the region * \return true if success, false if failure * \warning The buffer should be flushed via mir_buffer_munmap() before * submitting the buffer to the server. **/ bool mir_buffer_map(MirBuffer* buffer, MirGraphicsRegion* region, MirBufferLayout* layout); /** Flush the CPU caches for the buffer. * * \post MirGraphicsRegions that are associated with the buffer will be invalid. * \param [in] buffer The buffer **/ void mir_buffer_unmap(MirBuffer* buffer); /** Retrieve the width of the buffer in pixels. * * \param [in] buffer The buffer * \return The width of the buffer in pixels **/ unsigned int mir_buffer_get_width(MirBuffer* buffer); /** Retrieve the height of the buffer in pixels. * * \param [in] buffer The buffer * \return The height of the buffer in pixels **/ unsigned int mir_buffer_get_height(MirBuffer* buffer); /** Retrieve the pixel format of the buffer. * * \param [in] buffer The buffer * \return The pixel format of the buffer **/ MirPixelFormat mir_buffer_get_pixel_format(MirBuffer* buffer); /** @} */ /** release a MirBuffer * \param [in] buffer The buffer to be released **/ void mir_buffer_release(MirBuffer* buffer); #ifdef __cplusplus } /**@}*/ #endif #endif // MIR_TOOLKIT_MIR_BUFFER_H_ ./include/client/mir_toolkit/mir_extension_core.h0000644000004100000410000000305313115234664022552 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_CLIENT_EXTENSION_CORE_H_ #define MIR_CLIENT_EXTENSION_CORE_H_ #include "mir_toolkit/mir_connection.h" #ifdef __cplusplus extern "C" { #endif /** * Request a Mir extension * \note Extensions should provide an inline function to access * the extension that should be preferred to using this directly. * * \param [in] connection A connection * \param [in] interface The name of the interface. * \param [in] version The version of the interface. * \return A pointer that can be cast to the object * provided by the interface or NULL if the * extension is not supported. */ void const* mir_connection_request_extension( MirConnection* connection, char const* interface, int version); #ifdef __cplusplus } #endif #endif //MIR_CLIENT_EXTENSION_CORE_H_ ./include/client/mir_toolkit/client_types.h0000644000004100000410000004643113115234664021370 0ustar www-datawww-data/* * client_types.h: Type definitions used in client apps and libmirclient. * * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_TOOLKIT_CLIENT_TYPES_H_ #define MIR_TOOLKIT_CLIENT_TYPES_H_ #include #include #include #include #ifdef __cplusplus /** * \defgroup mir_toolkit MIR graphics tools API * @{ */ extern "C" { #endif /* Display server connection API */ typedef void* MirEGLNativeWindowType; typedef void* MirEGLNativeDisplayType; typedef struct MirConnection MirConnection; typedef struct MirSurface MirSurface MIR_FOR_REMOVAL_IN_VERSION_1("Use MirWindow instead"); typedef struct MirSurface MirWindow; typedef struct MirSurfaceSpec MirSurfaceSpec MIR_FOR_REMOVAL_IN_VERSION_1("Use MirWindowSpec instead"); typedef struct MirSurfaceSpec MirWindowSpec; typedef struct MirScreencast MirScreencast; typedef struct MirScreencastSpec MirScreencastSpec; typedef struct MirPromptSession MirPromptSession; typedef struct MirBufferStream MirBufferStream; typedef struct MirPersistentId MirPersistentId MIR_FOR_REMOVAL_IN_VERSION_1("Use MirWindowId instead"); typedef struct MirPersistentId MirWindowId; typedef struct MirBlob MirBlob; typedef struct MirDisplayConfig MirDisplayConfig; typedef struct MirError MirError; typedef struct MirPresentationChain MirPresentationChain; typedef struct MirBuffer MirBuffer; typedef struct MirRenderSurface MirRenderSurface; /** * Descriptor for an output connection. * * Each MirOutput corresponds to a video output. This may be a physical connection on the system, * like HDMI or DisplayPort, or may be a virtual output such as a remote display or screencast display. */ typedef struct MirOutput MirOutput; /** * Returned by asynchronous functions. Must not be free'd by * callers. See the individual function documentation for information * on the lifetime of wait handles. */ typedef struct MirWaitHandle MirWaitHandle; typedef struct MirPlatformMessage MirPlatformMessage; /** * Callback to be passed when issuing a mir_connect request. * \param [in] connection the new connection * \param [in,out] client_context context provided by client in calling * mir_connect */ typedef void (*MirConnectedCallback)( MirConnection *connection, void *client_context); typedef MirConnectedCallback mir_connected_callback MIR_FOR_REMOVAL_IN_VERSION_1("Use MirConnectedCallback instead"); /** * Callback to be passed when calling window functions : * \param [in] window the window being updated * \param [in,out] client_context context provided by client in calling * mir_connect */ typedef void (*MirWindowCallback)(MirWindow *window, void *client_context); /** * Callback to be passed when calling: * - mir_buffer_stream_* functions requiring a callback. * \param [in] stream the buffer stream being updated * \param [in,out] client_context context provided by client in calling * mir_connect */ typedef void (*MirBufferStreamCallback)( MirBufferStream *stream, void *client_context); typedef MirBufferStreamCallback mir_buffer_stream_callback MIR_FOR_REMOVAL_IN_VERSION_1("Use MirBufferStreamCallback instead"); /** * Callback for handling of window events. * \param [in] window The window on which an event has occurred * \param [in] event The event to be handled * \param [in,out] context The context provided by client */ typedef void (*MirWindowEventCallback)( MirWindow* window, MirEvent const* event, void* context); /** * Callback called when a lifecycle event/callback is requested * from the running server. * \param [in] connection The connection associated with the lifecycle event * \param [in] cb The callback requested * \param [in,out] context The context provided by the client */ typedef void (*MirLifecycleEventCallback)( MirConnection* connection, MirLifecycleState state, void* context); typedef MirLifecycleEventCallback mir_lifecycle_event_callback MIR_FOR_REMOVAL_IN_VERSION_1("Use MirLifecycleEventCallback instead"); /** * Callback called when the server pings for responsiveness testing. * \param [in] connection The connection associated with this ping * \param [in] serial Identifier of this ping, to be passed to * mir_connection_pong() * \param [in,out] context The context provided by the client */ typedef void (*MirPingEventCallback)( MirConnection* connection, int32_t serial, void* context); typedef MirPingEventCallback mir_ping_event_callback MIR_FOR_REMOVAL_IN_VERSION_1("Use MirPingEventCallback instead"); /** * Callback called when a display config change has occurred * \param [in] connection The connection associated with the display change * \param [in,out] context The context provided by client */ typedef void (*MirDisplayConfigCallback)( MirConnection* connection, void* context); typedef MirDisplayConfigCallback mir_display_config_callback MIR_FOR_REMOVAL_IN_VERSION_1("Use MirDisplayConfigCallback instead"); /** * Callback called when a request for client file descriptors completes * \param [in] prompt_session The prompt session * \param [in] count The number of FDs allocated * \param [in] fds Array of FDs * \param [in,out] context The context provided by client * * \note Copy the FDs as the array will be invalidated after callback completes */ typedef void (*MirClientFdCallback)( MirPromptSession *prompt_session, size_t count, int const* fds, void* context); typedef MirClientFdCallback mir_client_fd_callback MIR_FOR_REMOVAL_IN_VERSION_1("Use MirClientFdCallback instead"); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" typedef void (*MirWindowIdCallback)( MirWindow* window, MirPersistentId* id, void* context); #pragma GCC diagnostic pop /** * MirBufferUsage specifies how a surface can and will be used. A "hardware" * surface can be used for OpenGL accelerated rendering. A "software" surface * is one that can be addressed in main memory and blitted to directly. */ typedef enum MirBufferUsage { mir_buffer_usage_hardware = 1, mir_buffer_usage_software } MirBufferUsage; /** * MirWindowParameters is the structure of minimum required information that * you must provide to Mir in order to create a window. */ typedef struct MirSurfaceParameters { char const *name; int width; int height; MirPixelFormat pixel_format; MirBufferUsage buffer_usage; /** * The id of the output to place the surface in. * * Use one of the output ids from MirDisplayConfiguration/MirDisplayOutput * to place a surface on that output. Only fullscreen placements are * currently supported. If you don't have special placement requirements, * use the value mir_display_output_id_invalid. */ uint32_t output_id; } MirSurfaceParameters MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_window_get apis or listen for attribute events instead"); enum { mir_platform_package_max = 32 }; /** * The native buffer type for the system the client is connected on * * \deprecated Use of this type is inherently non-portable in the presence * of plug-in platform modules as these need not correspond to the available * types. * \todo This should be removed from the public API at the next API break. */ #ifndef __cplusplus MIR_FOR_REMOVAL_IN_VERSION_1("Use of this type is inherently non-portable") #endif typedef enum MirPlatformType { mir_platform_type_gbm, mir_platform_type_android, mir_platform_type_eglstream, } MirPlatformType; typedef struct MirPlatformPackage { int data_items; int fd_items; int data[mir_platform_package_max]; int fd[mir_platform_package_max]; } MirPlatformPackage; /** * Retrieved information about a loadable module. This allows clients to * identify the underlying platform. E.g. whether the graphics are * "mir:android" or "mir:mesa". * Third party graphics platforms do not currently exist but should be * named according to the vendor and platform. Vis: ":" */ typedef struct MirModuleProperties { char const *name; int major_version; int minor_version; int micro_version; char const *filename; } MirModuleProperties; typedef enum MirBufferLayout { mir_buffer_layout_unknown = 0, mir_buffer_layout_linear = 1, } MirBufferLayout; typedef enum MirPresentMode { mir_present_mode_immediate, //same as VK_PRESENT_MODE_IMMEDIATE_KHR mir_present_mode_mailbox, //same as VK_PRESENT_MODE_MAILBOX_KHR mir_present_mode_fifo, //same as VK_PRESENT_MODE_FIFO_KHR mir_present_mode_fifo_relaxed, //same as VK_PRESENT_MODE_FIFO_RELAXED_KHR mir_present_mode_num_modes } MirPresentMode; /** * Retrieved information about a MirWindow. This is most useful for learning * how and where to write to a 'mir_buffer_usage_software' surface. */ typedef struct MirGraphicsRegion { int width; int height; int stride; MirPixelFormat pixel_format; char *vaddr; } MirGraphicsRegion; /** * DEPRECATED. use MirDisplayConfiguration */ enum { mir_supported_pixel_format_max = 32 }; typedef struct MirDisplayInfo { uint32_t width; uint32_t height; int supported_pixel_format_items; MirPixelFormat supported_pixel_format[mir_supported_pixel_format_max]; } MirDisplayInfo; /** * MirDisplayConfiguration provides details of the graphics environment. */ typedef struct MirDisplayCard { uint32_t card_id; uint32_t max_simultaneous_outputs; } MirDisplayCard; typedef enum MirDisplayOutputType { mir_display_output_type_unknown = mir_output_type_unknown, mir_display_output_type_vga = mir_output_type_vga, mir_display_output_type_dvii = mir_output_type_dvii, mir_display_output_type_dvid = mir_output_type_dvid, mir_display_output_type_dvia = mir_output_type_dvia, mir_display_output_type_composite = mir_output_type_composite, mir_display_output_type_svideo = mir_output_type_svideo, mir_display_output_type_lvds = mir_output_type_lvds, mir_display_output_type_component = mir_output_type_component, mir_display_output_type_ninepindin = mir_output_type_ninepindin, mir_display_output_type_displayport = mir_output_type_displayport, mir_display_output_type_hdmia = mir_output_type_hdmia, mir_display_output_type_hdmib = mir_output_type_hdmib, mir_display_output_type_tv = mir_output_type_tv, mir_display_output_type_edp = mir_output_type_edp, mir_display_output_type_virtual = mir_output_type_virtual, mir_display_output_type_dsi = mir_output_type_dsi, mir_display_output_type_dpi = mir_output_type_dpi, } MirDisplayOutputType; typedef enum MirOutputConnectionState { mir_output_connection_state_disconnected = 0, mir_output_connection_state_connected, mir_output_connection_state_unknown } MirOutputConnectionState; typedef struct MirDisplayMode { uint32_t vertical_resolution; uint32_t horizontal_resolution; double refresh_rate; } MirDisplayMode; enum { mir_display_output_id_invalid = 0 }; typedef struct MirDisplayOutput { uint32_t num_modes; MirDisplayMode* modes; uint32_t preferred_mode; /**< There might be no preferred mode, which is indicated by a value >=num_modes. */ uint32_t current_mode; uint32_t num_output_formats; MirPixelFormat* output_formats; MirPixelFormat current_format; uint32_t card_id; uint32_t output_id; MirDisplayOutputType type; int32_t position_x; int32_t position_y; uint32_t connected; uint32_t used; uint32_t physical_width_mm; uint32_t physical_height_mm; MirPowerMode power_mode; MirOrientation orientation; } MirDisplayOutput; typedef struct MirDisplayConfiguration { uint32_t num_outputs; MirDisplayOutput* outputs; uint32_t num_cards; MirDisplayCard *cards; } MirDisplayConfiguration; /** * The displacement from the top-left corner of the surface. */ typedef struct MirBufferStreamInfo { MirBufferStream* stream; int displacement_x; int displacement_y; } MirBufferStreamInfo; typedef struct MirRectangle { int left; int top; unsigned int width; unsigned int height; } MirRectangle; typedef struct MirInputConfig MirInputConfig; typedef struct MirInputDevice MirInputDevice; typedef struct MirPointerConfig MirPointerConfig; typedef struct MirTouchpadConfig MirTouchpadConfig; /** * MirScreencastParameters is the structure of required information that * you must provide to Mir in order to create a MirScreencast. * The width and height parameters can be used to down-scale the screencast * For no scaling set them to the region width and height. */ typedef struct MirScreencastParameters { /** * The rectangular region of the screen to capture - * The region is specified in virtual screen space hence multiple screens can be captured simultaneously */ MirRectangle region; /** The width of the screencast which can be different than the screen region capture width */ unsigned int width; /** The height of the screencast which can be different than the screen region capture height */ unsigned int height; /** * The pixel format of the screencast. * It must be a supported format obtained from mir_connection_get_available_surface_formats. */ MirPixelFormat pixel_format; } MirScreencastParameters; /** * Callback to be passed when calling MirScreencast functions. * \param [in] screencast the screencast being updated * \param [in,out] client_context context provided by the client */ typedef void (*MirScreencastCallback)( MirScreencast *screencast, void *client_context); typedef MirScreencastCallback mir_screencast_callback MIR_FOR_REMOVAL_IN_VERSION_1("Use MirScreencastCallback instead"); /** * Callback member of MirPromptSession for handling of prompt sessions. * \param [in] prompt_provider The prompt session associated with the callback * \param [in,out] context The context provided by the client */ typedef void (*MirPromptSessionCallback)( MirPromptSession* prompt_provider, void* context); typedef MirPromptSessionCallback mir_prompt_session_callback MIR_FOR_REMOVAL_IN_VERSION_1("Use MirPromptSessionCallback instead"); /** * Callback member of MirPromptSession for handling of prompt sessions events. * \param [in] prompt_provider The prompt session associated with the callback * \param [in] state The state of the prompt session * \param [in,out] context The context provided by the client */ typedef void (*MirPromptSessionStateChangeCallback)( MirPromptSession* prompt_provider, MirPromptSessionState state, void* context); typedef MirPromptSessionStateChangeCallback mir_prompt_session_state_change_callback MIR_FOR_REMOVAL_IN_VERSION_1("Use MirPromptSessionStateChangeCallback instead"); /** * Callback called when a platform operation completes. * * \warning The reply is owned by the callee, who should release it when it's * not needed any more. * * \param [in] connection The connection associated with the platform operation * \param [in] reply The platform operation reply * \param [in,out] context The context provided by the client */ typedef void (*MirPlatformOperationCallback)( MirConnection* connection, MirPlatformMessage* reply, void* context); typedef MirPlatformOperationCallback mir_platform_operation_callback MIR_FOR_REMOVAL_IN_VERSION_1("Use MirPlatformOperationCallback instead"); /** * Callback called when a change of input devices has occurred * \param [in] connection The connection associated with the input device * change * \param [in,out] context The context provided by client */ typedef void (*MirInputConfigCallback)( MirConnection* connection, void* context); typedef MirInputConfigCallback mir_input_config_callback MIR_FOR_REMOVAL_IN_VERSION_1("Use MirInputConfigCallback instead"); typedef void (*MirBufferCallback)(MirBuffer*, void* context); /** * Specifies the origin of an error. * * This is required to interpret the other aspects of a MirError. */ typedef enum MirErrorDomain { /** * Errors relating to display configuration. * * Associated error codes are found in \ref MirDisplayConfigurationError. */ mir_error_domain_display_configuration, /** * Errors relating to input configuration. * * Associated error codes are found in \ref MirInputConfigurationError. */ mir_error_domain_input_configuration, } MirErrorDomain; /** * Errors from the \ref mir_error_domain_display_configuration \ref MirErrorDomain */ typedef enum MirDisplayConfigurationError { /** * Client is not permitted to change global display configuration */ mir_display_configuration_error_unauthorized, /** * A global configuration change request is already pending */ mir_display_configuration_error_in_progress, /** * A cancel request was received, but no global display configuration preview is in progress */ mir_display_configuration_error_no_preview_in_progress, /** * Display configuration was attempted but was rejected by the hardware */ mir_display_configuration_error_rejected_by_hardware } MirDisplayConfigurationError; /** * Errors from the \ref mir_error_domain_input_configuration \ref MirErrorDomain */ typedef enum MirInputConfigurationError { /** * Input configuration was attempted but was rejected by driver */ mir_input_configuration_error_rejected_by_driver } MirInputConfigurationError; typedef void (*MirErrorCallback)( MirConnection* connection, MirError const* error, void* context); typedef MirErrorCallback mir_error_callback MIR_FOR_REMOVAL_IN_VERSION_1("Use MirErrorCallback instead"); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" typedef void (*mir_surface_callback)(MirSurface *surface, void *client_context) MIR_FOR_REMOVAL_IN_VERSION_1("Use MirWindowCallback instead"); typedef void (*mir_surface_event_callback)( MirSurface* surface, MirEvent const* event, void* context) MIR_FOR_REMOVAL_IN_VERSION_1("Use MirWindowEventCallback instead"); typedef void (*mir_surface_id_callback)( MirSurface* surface, MirPersistentId* id, void* context) MIR_FOR_REMOVAL_IN_VERSION_1("Use MirWindowIdCallback instead"); typedef MirSurfaceParameters MirWindowParameters; #pragma GCC diagnostic pop #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_CLIENT_TYPES_H_ */ ./include/client/mir_toolkit/rs/0000755000004100000410000000000013115234665017132 5ustar www-datawww-data./include/client/mir_toolkit/rs/mir_render_surface.h0000644000004100000410000002126513115234664023146 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Cemil Azizoglu */ #ifndef MIR_TOOLKIT_MIR_RENDER_SURFACE_H_ #define MIR_TOOLKIT_MIR_RENDER_SURFACE_H_ #include #include #ifndef MIR_DEPRECATE_RENDERSURFACES #define MIR_DEPRECATE_RENDERSURFACES 0 #endif #if MIR_ENABLE_DEPRECATIONS > 0 && MIR_DEPRECATE_RENDERSURFACES > 0 #define MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME\ __attribute__((deprecated("This function is slated for rename due to MirRenderSurface-->MirSurface transition"))) #else #define MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME #endif #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif typedef void (*MirRenderSurfaceCallback)(MirRenderSurface*, void* context) MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" /** * Create a render surface * * \param [in] connection A valid connection * \param [in] width The width in pixels * \param [in] height The height in pixels * \param [in] MirRenderSurfaceCallback Callback to be invoked when the request completes. * The callback is guaranteed to be called and called * with a non-null MirRenderSurface*, but the render * surface may be invalid in case of error. * \param [in,out] context User data to pass to callback function */ void mir_connection_create_render_surface( MirConnection* connection, int width, int height, MirRenderSurfaceCallback callback, void* context) MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME; /** * Create a render surface and wait for the result * * \param [in] connection A valid connection * \param [in] width The width in pixels * \param [in] height The height in pixels * * \return The new render surface, guaranteed to be * non-null, but may be invalid in case of error */ MirRenderSurface* mir_connection_create_render_surface_sync( MirConnection* connection, int width, int height) MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME; /** * Get the size of the MirRenderSurface * * \param [in] render_surface The render surface * \param [out] width The width in pixels * \param [out] height The height in pixels */ void mir_render_surface_get_size( MirRenderSurface* render_surface, int* width, int* height) MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME; /** * Set the size of the MirRenderSurface * * \param [in] render_surface The render surface * \param [in] width The width in pixels * \param [in] height The height in pixels */ void mir_render_surface_set_size( MirRenderSurface* render_surface, int width, int height) MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME; /** * Test for a valid render surface * * \param [in] render_surface The render surface * * \return True if the supplied render surface is valid, * or false otherwise */ bool mir_render_surface_is_valid( MirRenderSurface* render_surface) MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME; /** * Retrieve a text description of the error. The returned string is owned by * the library and remains valid until the render surface or the associated * connection has been released. * \param [in] redner_surface The render surface * \return A text description of any error resulting in an * invalid render surface, or the empty string "" if the * object is valid. */ char const *mir_render_surface_get_error_message( MirRenderSurface* render_surface) MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME; /** * Release the specified render surface * * \param [in] render_surface The render surface to be released */ void mir_render_surface_release( MirRenderSurface* render_surface) MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME; /** * Obtain the buffer stream backing a given render surface. * The MirBufferStream will contain buffers suitable for writing via the CPU. * * \param [in] render_surface The render surface * \param [in] width Requested width * \param [in] height Requested height * \param [in] format Requested pixel format * * \return The buffer stream contained in the given render surface * or 'nullptr' if it, or * mir_render_surface_get_presentation_chain(), has already * been called once */ MirBufferStream* mir_render_surface_get_buffer_stream( MirRenderSurface* render_surface, int width, int height, MirPixelFormat format) MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME; /** * Obtain the presentation chain backing a given render surface. * The MirPresentationChain is created in mir_present_mode_fifo submission mode. * * \return The chain contained in the given render surface * or 'nullptr' if it, or * mir_render_surface_get_buffer_stream(), has already * been called once */ MirPresentationChain* mir_render_surface_get_presentation_chain( MirRenderSurface* render_surface) MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME; /** Query whether the server supports a given presentation mode. * * \param [in] connection The connection * \param [in] mode The MirPresentMode * \return True if supported, false if not */ bool mir_connection_present_mode_supported( MirConnection* connection, MirPresentMode mode); /** Respecify the submission mode that the MirPresentationChain is operating with. * The buffers currently queued will immediately be requeued according * to the new mode. * * \pre mir_connection_present_mode_supported must indicate that the mode is supported * \param [in] chain The chain * \param [in] mode The mode to change to */ void mir_presentation_chain_set_mode( MirPresentationChain* chain, MirPresentMode mode); /** * Set the MirWindowSpec to contain a specific cursor. * * \param [in] spec The spec * \param [in] render_surface The rendersurface to set, or nullptr to reset to default cursor. * \param [in] hotspot_x The x-coordinate to use as the cursor's hotspot * \param [in] hotspot_y The y-coordinate to use as the cursor's hotspot */ void mir_window_spec_set_cursor_render_surface( MirWindowSpec* spec, MirRenderSurface* render_surface, int hotspot_x, int hotspot_y) MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME; /** * Set the MirWindowSpec to display content contained in a render surface * * \warning: The initial call to mir_window_spec_add_render_surface will set * the bottom-most content, and subsequent calls will stack the * content on top. * * \param spec The window_spec to be updated * \param render_surface The render surface containing the content to be displayed * \param logical_width The width that the content will be displayed at * (Ignored for buffer streams) * \param logical_height The height that the content will be displayed at * (Ignored for buffer streams) * \param displacement_x The x displacement from the top-left corner of the MirWindow * \param displacement_y The y displacement from the top-left corner of the MirWindow */ void mir_window_spec_add_render_surface(MirWindowSpec* spec, MirRenderSurface* render_surface, int logical_width, int logical_height, int displacement_x, int displacement_y) MIR_DEPRECATE_RENDERSURFACES_FOR_RENAME; #pragma GCC diagnostic pop #ifdef __cplusplus } /**@}*/ #endif #endif // MIR_TOOLKIT_MIR_RENDER_SURFACE_H_ ./include/client/mir_toolkit/cursors.h0000644000004100000410000000670313115234664020364 0ustar www-datawww-data/* * Cursor name definitions. * * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Robert Carr */ /* XXX Deprecate this header? Tell people to just use CSS cursor names. */ #ifndef MIR_CURSORS_H_ #define MIR_CURSORS_H_ /** * \addtogroup mir_toolkit * @{ */ /* This is C code. Not C++. */ #ifdef __cplusplus extern "C" { #endif /** * A special cursor name for use with mir_cursor_configuration_from_name * representing the system default cursor. */ extern char const *const mir_default_cursor_name; /** * A special cursor name for use with mir_cursor_configuration_from_name * representing a disabled cursor image. */ extern char const *const mir_disabled_cursor_name; /** * The standard arrow cursor (typically the system default) */ extern char const* const mir_arrow_cursor_name; /** * The "wait" cursor, typically an hourglass or watch used during operations * which prevent the user from interacting. */ extern char const* const mir_busy_cursor_name; /** * The caret or ibeam cursor, indicating acceptance of text input */ extern char const* const mir_caret_cursor_name; /** * The pointing hand cursor, typically used for clickable elements such * as hyperlinks. */ extern char const* const mir_pointing_hand_cursor_name; /** * The open handed cursor, typically used to indicate that the area beneath * the cursor may be clicked and dragged around. */ extern char const* const mir_open_hand_cursor_name; /** * The close handed cursor, typically used to indicate that a drag operation is in process * which involves scrolling. */ extern char const* const mir_closed_hand_cursor_name; /** * The cursor used to indicate a horizontal resize operation. */ extern char const* const mir_horizontal_resize_cursor_name; /** * The cursor used to indicate a vertical resize operation. */ extern char const* const mir_vertical_resize_cursor_name; /** * The cursor used to indicate diagonal resizing a top right corner. */ extern char const* const mir_diagonal_resize_bottom_to_top_cursor_name; /** * The cursor used to indicate diagonal resizing a bottom right corner. */ extern char const* const mir_diagonal_resize_top_to_bottom_cursor_name; /** * The cursor used to indicate resize with no directional constraint. */ extern char const* const mir_omnidirectional_resize_cursor_name; /** * The cursor used for vertical splitters, indicating that a handle may be * dragged to adjust vertical space. */ extern char const* const mir_vsplit_resize_cursor_name; /** * The cursor used for horizontal splitters, indicating that a handle may be * dragged to adjust horizontal space. */ extern char const* const mir_hsplit_resize_cursor_name; /** * The cursor used for crosshair, which may be used for picking colors or * finer precision. */ extern char const* const mir_crosshair_cursor_name; #ifdef __cplusplus } #endif /**@}*/ #endif ./include/client/mir_toolkit/mir_connection.h0000644000004100000410000004376413115234664021702 0ustar www-datawww-data/* * Copyright © 2012-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_CONNECTION_H_ #define MIR_TOOLKIT_MIR_CONNECTION_H_ #include #include #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Request a connection to the Mir server. The supplied callback is called when * the connection is established, or fails. The returned wait handle remains * valid until the connection has been released. * \warning callback could be called from another thread. You must do any * locking appropriate to protect your data accessed in the * callback. * \param [in] server File path of the server socket to connect to, or * NULL to choose the default server (can be set by * the $MIR_SOCKET environment variable) * \param [in] app_name A name referring to the application * \param [in] callback Callback function to be invoked when request * completes * \param [in,out] context User data passed to the callback function * \return A handle that can be passed to mir_wait_for */ MirWaitHandle *mir_connect( char const *server, char const *app_name, MirConnectedCallback callback, void *context); /** * Perform a mir_connect() but also wait for and return the result. * \param [in] server File path of the server socket to connect to, or * NULL to choose the default server * \param [in] app_name A name referring to the application * \return The resulting MirConnection */ MirConnection *mir_connect_sync(char const *server, char const *app_name); /** * Test for a valid connection * \param [in] connection The connection * \return True if the supplied connection is valid, or * false otherwise. */ bool mir_connection_is_valid(MirConnection *connection); /** * Retrieve a text description of the last error. The returned string is owned * by the library and remains valid until the connection has been released. * \param [in] connection The connection * \return A text description of any error resulting in an * invalid connection, or the empty string "" if the * connection is valid. */ char const *mir_connection_get_error_message(MirConnection *connection); /** * Release a connection to the Mir server * \param [in] connection The connection */ void mir_connection_release(MirConnection *connection); /** * Query platform-specific data and/or file descriptors that are required to * initialize GL/EGL features. * \param [in] connection The connection * \param [out] platform_package Structure to be populated */ void mir_connection_get_platform(MirConnection *connection, MirPlatformPackage *platform_package) MIR_FOR_REMOVAL_IN_VERSION_1("use platform extensions instead"); /** * Query graphics platform module. * * \note The char pointers in MirModuleProperties are owned by the connection and should not be * freed. They remain valid until the connection is released. * * \param [in] connection The connection * \param [out] properties Structure to be populated */ void mir_connection_get_graphics_module(MirConnection *connection, MirModuleProperties *properties) MIR_FOR_REMOVAL_IN_VERSION_1("use graphics module extension instead"); /** * Register a callback to be called when a Lifecycle state change occurs. * \param [in] connection The connection * \param [in] callback The function to be called when the state change occurs * \param [in,out] context User data passed to the callback function */ void mir_connection_set_lifecycle_event_callback(MirConnection* connection, MirLifecycleEventCallback callback, void* context); /** * Register a callback for server ping events. * * The server may send ping requests to detect unresponsive applications. Clients should * process this with their regular event handling, and call mir_connection_pong() in response. * * The shell may treat a client which fails to pong in a timely fashion differently; a common * response is to overlay the surface with an unresponsive application message. * * A default implementation that immediately calls pong is provided; toolkits SHOULD override * this default implementation to more accurately reflect the state of their event processing * loop. * * \param [in] connection The connection * \param [in] callback The function to be called on ping events. * \param [in] context User data passed to the callback function */ void mir_connection_set_ping_event_callback(MirConnection* connection, MirPingEventCallback callback, void* context); /** * Respond to a ping event * \param [in] connection The connection * \param [in] serial Serial from the ping event */ void mir_connection_pong(MirConnection* connection, int32_t serial); /** * Query the display * * \deprecated Use mir_connection_create_display_configuration() instead. * * \warning return value must be destroyed via mir_display_config_destroy() * \warning may return null if connection is invalid * \param [in] connection The connection * \return structure that describes the display configuration */ MirDisplayConfiguration* mir_connection_create_display_config(MirConnection *connection) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_connection_create_display_configuration instead"); /** * Query the display * * \pre mir_connection_is_valid(connection) == true * \warning return value must be destroyed via mir_display_config_release() * * \param [in] connection The connection * \return structure that describes the display configuration */ MirDisplayConfig* mir_connection_create_display_configuration(MirConnection* connection); /** * Register a callback to be called when the hardware display configuration changes * * Once a change has occurred, you can use mir_connection_create_display_configuration to see * the new configuration. * * \param [in] connection The connection * \param [in] callback The function to be called when a display change occurs * \param [in,out] context User data passed to the callback function */ void mir_connection_set_display_config_change_callback( MirConnection* connection, MirDisplayConfigCallback callback, void* context); /** * Destroy the DisplayConfiguration resource acquired from mir_connection_create_display_config * \param [in] display_configuration The display_configuration information resource to be destroyed */ void mir_display_config_destroy(MirDisplayConfiguration* display_configuration) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_display_config_release instead"); /** * Apply the display configuration * * The display configuration is applied to this connection only (per-connection * configuration) and is invalidated when a hardware change occurs. Clients should * register a callback with mir_connection_set_display_config_change_callback() * to get notified about hardware changes, so that the can apply a new configuration. * * \warning This request may be denied. Check that the request succeeded with mir_connection_get_error_message. * \param [in] connection The connection * \param [in] display_configuration The display_configuration to apply * \return A handle that can be passed to mir_wait_for */ MirWaitHandle* mir_connection_apply_display_config(MirConnection *connection, MirDisplayConfiguration* display_configuration) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_connection_apply_session_display_config instead"); /** * Apply the display config for the connection * * The display config is applied to this connection only (per-connection * config) and is invalidated when a hardware change occurs. Clients should * register a callback with mir_connection_set_display_config_change_callback() * to get notified about hardware changes, so that they can apply a new config. * * \param [in] connection The connection * \param [in] display_config The display_config to apply */ void mir_connection_apply_session_display_config(MirConnection* connection, MirDisplayConfig const* display_config); /** * Remove the display configuration for the connection * * If a session display config is applied to the connection it is removed, and * the base display config is used. If there was no previous call to * mir_connection_apply_session_display_config this will do nothing. * * \param [in] connection The connection */ void mir_connection_remove_session_display_config(MirConnection* connection); /** * Set the base display configuration * * The base display configuration is the configuration the server applies when * there is no active per-connection configuration. * * When the wait handle returned by this function becomes ready, clients can use * mir_connection_get_error_message() to check if an authorization error occurred. * Only authorization errors are guaranteed to return an error message for this * operation. * * A successful result (i.e. no error) does not guarantee that the base display * configuration has been changed to the desired value. Clients should register * a callback with mir_connection_set_display_config_change_callback() to monitor * actual base display configuration changes. * * \warning This request may be denied. Check that the request succeeded with mir_connection_get_error_message. * \param [in] connection The connection * \param [in] display_configuration The display_configuration to set as base * \return A handle that can be passed to mir_wait_for */ MirWaitHandle* mir_connection_set_base_display_config( MirConnection* connection, MirDisplayConfiguration const* display_configuration) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_connection_preview_base_display_configuration/mir_connection_confirm_base_display_configuration"); /** * Preview a new base display configuration * * The base display configuration is the configuration the server applies when * there is no active per-connection configuration. * * The display configuration will automatically revert to the previous * settings after timeout_seconds unless confirmed by a call to * mir_connection_confirm_base_display_configuration(), or is reverted * immediately after a call to mir_connection_cancel_display_configuration_preview(). * * If this request succeeds a configuration change event is sent to the * client. Clients should register a callback with * mir_connection_set_display_config_change_callback() in order to determine * when this call succeeds. * * If the configuration is not confirmed before timeout_seconds have elapsed * a second configuration change event is sent, with the old config. * * \param [in] connection The connection * \param [in] configuration The MirDisplayConfig to set as base * \param [in] timeout_seconds The time the server should wait, in seconds, * for the change to be confirmed before * reverting to the previous configuration. */ void mir_connection_preview_base_display_configuration( MirConnection* connection, MirDisplayConfig const* configuration, int timeout_seconds); /** * Confirm a base configuration change initiated by mir_connection_preview_base_display_configuration() * * The base display configuration is the configuration the server applies when * there is no active per-connection configuration. * * If this request succeeds a second configuration change event is sent to the * client, identical to the one sent after * mir_connection_preview_base_display_configuration(). Clients should * register a callback with mir_connection_set_display_config_change_callback() * in order to determine when this call succeeds. * * The MirDisplayConfig must be the same as the one passed to * mir_connection_preview_base_display_configuration(). * * \param [in] connection The connection * \param [in] configuration The MirDisplayConfig to confirm as base * configuration. */ void mir_connection_confirm_base_display_configuration( MirConnection* connection, MirDisplayConfig const* configuration); /** * Cancel a pending base display configuration preview. * * If this request succeeds a configuration change event is sent to the client, * with the now-current base display configuration. * * This call will fail if there is no display configuration preview current. * A client can detect this by registering a callback with * mir_connection_set_error_callback() and checking for * mir_display_configuration_error_no_preview_in_progress. * * \param [in] connection The connection */ void mir_connection_cancel_base_display_configuration_preview( MirConnection* connection); /** * Get a display type that can be used for OpenGL ES 2.0 acceleration. * \param [in] connection The connection * \return An EGLNativeDisplayType that the client can use */ MirEGLNativeDisplayType mir_connection_get_egl_native_display(MirConnection *connection); /** * Get the exact MirPixelFormat to use in creating a surface for a chosen * EGLConfig. * \param [in] connection The connection * \param [in] egldisplay The EGLDisplay for the given config * \param [in] eglconfig The EGLConfig you have chosen to use * \return The MirPixelFormat to use in surface creation */ MirPixelFormat mir_connection_get_egl_pixel_format( MirConnection *connection, void *egldisplay, void *eglconfig); /** * Get the list of possible formats that a surface can be created with. * \param [in] connection The connection * \param [out] formats List of valid formats to create surfaces with * \param [in] formats_size size of formats list * \param [out] num_valid_formats number of valid formats returned in formats * * \note Users of EGL should call mir_connection_get_egl_pixel_format instead, * as it will take the guesswork out of choosing between similar pixel * formats. At the moment, this function returns a compatible list of * formats likely to work for either software or hardware rendering. * However it is not the full or accurate list and will be replaced in * future by a function that takes the intended MirBufferUsage into * account. */ void mir_connection_get_available_surface_formats( MirConnection* connection, MirPixelFormat* formats, unsigned const int formats_size, unsigned int *num_valid_formats); /** * Perform a platform specific operation. * * The MirPlatformMessage used for the request needs to remain valid * until this operation finishes. * * \param [in] connection The connection * \param [in] request The message used for this operation * \param [in] callback The callback to call when the operation finishes * \param [in,out] context User data passed to the callback function * \return A handle that can be passed to mir_wait_for */ MirWaitHandle* mir_connection_platform_operation( MirConnection* connection, MirPlatformMessage const* request, MirPlatformOperationCallback callback, void* context) MIR_FOR_REMOVAL_IN_VERSION_1("use platform specific extensions instead"); /** * Create a snapshot of the attached input devices and device configurations. * \warning return value must be destroyed via mir_input_config_release() * \warning may return null if connection is invalid * \param [in] connection The connection * \return structure that describes the input configuration */ MirInputConfig* mir_connection_create_input_config(MirConnection *connection); /** * \deprecated Use mir_input_config_release() instead. * * Release this snapshot of the input configuration. * This invalidates any pointers retrieved from this structure. * * \param [in] config The input configuration */ void mir_input_config_destroy(MirInputConfig const* config) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_input_config_release instead"); /** * Release this snapshot of the input configuration. * This invalidates any pointers retrieved from this structure. * * \param [in] config The input configuration */ void mir_input_config_release(MirInputConfig const* config); /** * Register a callback to be called when the input devices change. * * Once a change has occurred, you can use mir_connection_create_input_config * to get an updated snapshot of the input device configuration. * * \param [in] connection The connection * \param [in] callback The function to be called when a change occurs * \param [in,out] context User data passed to the callback function */ void mir_connection_set_input_config_change_callback( MirConnection* connection, MirInputConfigCallback callback, void* context); /** * Register a callback to be called on non-fatal errors * * \param [in] connection The connection * \param [in] callback The function to be called when an error occurs * \param [in,out] context User data passed to the callback function */ void mir_connection_set_error_callback( MirConnection* connection, MirErrorCallback callback, void* context); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_MIR_CONNECTION_H_ */ ./include/client/mir_toolkit/mir_screencast.h0000644000004100000410000001174013115234664021662 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef MIR_TOOLKIT_MIR_SCREENCAST_H_ #define MIR_TOOLKIT_MIR_SCREENCAST_H_ #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Create a screencast specification. * * \remark For use with mir_screencast_create() at the width, height, * pixel format and capture region must be set. * * \param [in] connection a valid mir connection * \return A handle that can ultimately be passed to * mir_create_window() or mir_window_apply_spec() */ MirScreencastSpec* mir_create_screencast_spec(MirConnection* connection); /** * Set the requested width, in pixels * * \param [in] spec Specification to mutate * \param [in] width Requested width. * */ void mir_screencast_spec_set_width(MirScreencastSpec* spec, unsigned int width); /** * Set the requested height, in pixels * * \param [in] spec Specification to mutate * \param [in] height Requested height. * */ void mir_screencast_spec_set_height(MirScreencastSpec* spec, unsigned int height); /** * Set the requested pixel format. * * \param [in] spec Specification to mutate * \param [in] format Requested pixel format * */ void mir_screencast_spec_set_pixel_format(MirScreencastSpec* spec, MirPixelFormat format); /** * Set the rectangular region to capture. * * \param [in] spec Specification to mutate * \param [in] region The rectangular region of the screen to capture * specified in virtual screen space coordinates * */ void mir_screencast_spec_set_capture_region(MirScreencastSpec* spec, MirRectangle const* region); /** * Set the requested mirror mode. * * \param [in] spec Specification to mutate * \param [in] mode The mirroring mode to apply when screencasting * */ void mir_screencast_spec_set_mirror_mode(MirScreencastSpec* spec, MirMirrorMode mode); /** * Set the requested number of buffers to use. * * \param [in] spec Specification to mutate * \param [in] nbuffers The number of buffers to allocate for screencasting * */ void mir_screencast_spec_set_number_of_buffers(MirScreencastSpec* spec, unsigned int nbuffers); /** * Release the resources held by a MirScreencastSpec. * * \param [in] spec Specification to release */ void mir_screencast_spec_release(MirScreencastSpec* spec); /** * Create a screencast from a given specification * * \param [in] spec Specification of the screencast attributes * \return The resulting screencast */ MirScreencast* mir_screencast_create_sync(MirScreencastSpec* spec); /** * Test for a valid screencast * * \param [in] screencast The screencast to verify * \return True if the supplied screencast is valid, false otherwise. */ bool mir_screencast_is_valid(MirScreencast *screencast); /** * Retrieve a text description of the error. The returned string is owned by * the library and remains valid until the screencast or the associated * connection has been released. * * \param [in] screencast The screencast * \return A text description of any error resulting in an * invalid screencast, or the empty string "" if the * screencast is valid. */ char const *mir_screencast_get_error_message(MirScreencast *screencast); /** * Create a screencast on the supplied connection. * * A screencast allows clients to read the contents of the screen. * * \warning This request may be denied. * \param [in] connection The connection * \param [in] parameters The screencast parameters * \return The resulting screencast */ MirScreencast* mir_connection_create_screencast_sync( MirConnection* connection, MirScreencastParameters* parameters) MIR_FOR_REMOVAL_IN_VERSION_1("use mir_screencast_create_sync instead"); /** * Release the specified screencast. * \param [in] screencast The screencast to be released */ void mir_screencast_release_sync( MirScreencast* screencast); /** * Retrieve the MirBufferStream associated with a screencast * (to advance buffers, obtain EGLNativeWindowType, etc...) * * \param[in] screencast The screencast */ MirBufferStream* mir_screencast_get_buffer_stream(MirScreencast* screencast); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_MIR_SCREENCAST_H_ */ ./include/client/mir_toolkit/mir_platform_message.h0000644000004100000410000001125413115234664023060 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_PLATFORM_MESSAGE_H_ #define MIR_TOOLKIT_MIR_PLATFORM_MESSAGE_H_ #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif struct MirPlatformMessage; typedef struct { void const* const data; size_t const size; } MirPlatformMessageData; typedef struct { int const* const fds; size_t const num_fds; } MirPlatformMessageFds; /** * Create a platform message to use with mir_connection_platform_operation(). * * Each call to mir_platform_message_create() should be matched by * a call to mir_platform_message_release() to avoid memory leaks. * * \param [in] opcode The platform message opcode * \return The created MirPlatformMessage */ MIR_FOR_REMOVAL_IN_VERSION_1("use mir_extension_mesa_drm_auth or mir_extension_set_gbm_device") MirPlatformMessage* mir_platform_message_create(unsigned int opcode); /** * Release a platform message. * * \param [in] message The MirPlatformMessage */ MIR_FOR_REMOVAL_IN_VERSION_1("use mir_extension_mesa_drm_auth or mir_extension_set_gbm_device") void mir_platform_message_release(MirPlatformMessage const* message); /** * Set the data associated with a message. * * The data is copied into the message. * * \param [in] message The MirPlatformMessage * \param [in] data Pointer to the data * \param [in] data_size The size of the data in bytes */ MIR_FOR_REMOVAL_IN_VERSION_1("use mir_extension_mesa_drm_auth or mir_extension_set_gbm_device") void mir_platform_message_set_data(MirPlatformMessage* message, void const* data, size_t data_size); /** * Sets the fds associated with a message. * * The fd array is copied into the message, but the message does not take * ownership of the fds, i.e., the caller is responsible for keeping * the fds open for as long as this message needs to remain valid. * * Note that the fds associated with a message are not closed when the message * is released. The caller is responsible for closing the fds when the message * doesn't need them anymore (see also mir_platform_message_get_fds()). * * \param [in] message The MirPlatformMessage * \param [in] fds Pointer to the array of fds * \param [in] num_fds The number of fds */ MIR_FOR_REMOVAL_IN_VERSION_1("use mir_extension_mesa_drm_auth or mir_extension_set_gbm_device") void mir_platform_message_set_fds(MirPlatformMessage* message, int const* fds, size_t num_fds); /** * Get the opcode of a message. * * \param [in] message The MirPlatformMessage * \return The opcode */ MIR_FOR_REMOVAL_IN_VERSION_1("use mir_extension_mesa_drm_auth or mir_extension_set_gbm_device") unsigned int mir_platform_message_get_opcode(MirPlatformMessage const* message); /** * Get the data associated with a message. * * The memory holding the returned data array is owned by the message and is * valid only as long as the message is valid and mir_platform_set_data() is * not called. You must not change or free the returned data array. * * \param [in] message The MirPlatformMessage * \return The data */ MIR_FOR_REMOVAL_IN_VERSION_1("use mir_extension_mesa_drm_auth or mir_extension_set_gbm_device") MirPlatformMessageData mir_platform_message_get_data(MirPlatformMessage const* message); /** * Gets the fds associated with a message. * * The memory of the returned fd array is owned by the message and is valid * only as long as the message is valid and mir_platform_set_fds() is not * called. You must not change or free the returned fd array. * * Note that the fds associated with a message will not be closed when the * message is released. Users are responsible for getting and closing the * fds to avoid leaks. * * \param [in] message The MirPlatformMessage * \return The fds */ MIR_FOR_REMOVAL_IN_VERSION_1("use mir_extension_mesa_drm_auth or mir_extension_set_gbm_device") MirPlatformMessageFds mir_platform_message_get_fds(MirPlatformMessage const* message); #ifdef __cplusplus } /**@}*/ #endif #endif ./include/client/mir_toolkit/debug/0000755000004100000410000000000013115234677017577 5ustar www-datawww-data./include/client/mir_toolkit/debug/surface.h0000644000004100000410000000651613115234664021404 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_CLIENT_LIBRARY_DEBUG_H #define MIR_CLIENT_LIBRARY_DEBUG_H #include #include /* This header defines debug interfaces that aren't expected to be generally useful * and do not have the same API-stability guarantees that the main API has */ #ifdef __cplusplus extern "C" { #endif /** * Return the ID of a window (only useful for debug output). * \pre The window is valid * \param [in] window The window * \return An internal ID that identifies the window */ int mir_debug_window_id(MirWindow *window); /** * Get the ID of the window's current buffer (only useful for debug purposes) * \pre The window is valid * \param [in] window The window * \return The internal buffer ID of the window's current buffer. * This is the buffer that is currently being drawn to, * and would be returned by mir_window_get_current_buffer. */ uint32_t mir_debug_window_current_buffer_id(MirWindow *window); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" /** * Get the screen coordinates corresponding to a pair of surface coordinates * \pre The surface is valid * \param [in] surface The surface * \param [in] x, y Surface coordinates to map to screen coordinates * \param [out] screen_x, screen_y The screen coordinates corresponding to x, y. * \return True if screen_x and screen_y contain values * \note There are many cases where such a mapping does not exist or would be expensive * to calculate. Only Mir servers started with the --debug option will ever return * values for this call, and even when --debug is enabled servers are free to * return nothing. * * This call will only be interesting for automated testing, where both the client * and shell state is known and constrained. */ bool mir_debug_surface_coords_to_screen(MirSurface *surface, int x, int y, int* screen_x, int* screen_y) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_extension_window_coordinate_translation instead"); int mir_debug_surface_id(MirSurface *surface) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_debug_window_id() instead"); uint32_t mir_debug_surface_current_buffer_id(MirSurface *surface) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_debug_window_current_buffer_id() instead"); #pragma GCC diagnostic pop #ifdef __cplusplus } #endif #endif /* MIR_CLIENT_LIBRARY_DEBUG_H */ ./include/client/mir_toolkit/mir_window_id.h0000644000004100000410000000402613115234664021512 0ustar www-datawww-data/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_WINDOW_ID_H_ #define MIR_TOOLKIT_MIR_WINDOW_ID_H_ #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * \brief Check the validity of a MirWindowId * \param [in] id The MirWindowId * \return True iff the MirWindowId contains a valid ID value. * * \note This does not guarantee that the ID refers to a currently valid object. */ bool mir_window_id_is_valid(MirWindowId* id); /** * \brief Free a MirWindowId * \param [in] id The MirWindowId to free * \note This frees only the client-side representation; it has no effect on the * object referred to by \arg id. */ void mir_window_id_release(MirWindowId* id); /** * \brief Get a string representation of a MirSurfaceId * \param [in] id The ID to serialise * \return A string representation of id. This string is owned by the MirSurfaceId, * and must not be freed by the caller. * * \see mir_surface_id_from_string */ char const* mir_window_id_as_string(MirWindowId* id); /** * \brief Deserialise a string representation of a MirSurfaceId * \param [in] string_representation Serialised representation of the ID * \return The deserialised MirSurfaceId */ MirWindowId* mir_window_id_from_string(char const* string_representation); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_MIR_WINDOW_ID_H_ */ ./include/client/mir_toolkit/mir_client_library.h0000644000004100000410000000262713115234664022536 0ustar www-datawww-data/* * Copyright © 2012-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_CLIENT_LIBRARY_H #define MIR_CLIENT_LIBRARY_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif /* MIR_CLIENT_LIBRARY_H */ ./include/client/mir_toolkit/mir_persistent_id.h0000644000004100000410000000500513115234664022401 0ustar www-datawww-data/* * Copyright © 2017 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifndef MIR_TOOLKIT_MIR_PERSISTENT_ID_H_ #define MIR_TOOLKIT_MIR_PERSISTENT_ID_H_ #include #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" /** * \brief Check the validity of a MirPersistentId * \param [in] id The MirPersistentId * \return True iff the MirPersistentId contains a valid ID value. * * \note This does not guarantee that the ID refers to a currently valid object. */ bool mir_persistent_id_is_valid(MirPersistentId* id) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_window_id_is_valid() instead"); /** * \brief Free a MirPersistentId * \param [in] id The MirPersistentId to free * \note This frees only the client-side representation; it has no effect on the * object referred to by \arg id. */ void mir_persistent_id_release(MirPersistentId* id) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_window_id_release() instead"); /** * \brief Get a string representation of a MirSurfaceId * \param [in] id The ID to serialise * \return A string representation of id. This string is owned by the MirSurfaceId, * and must not be freed by the caller. * * \see mir_surface_id_from_string */ char const* mir_persistent_id_as_string(MirPersistentId* id) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_window_id_as_string() instead"); /** * \brief Deserialise a string representation of a MirSurfaceId * \param [in] string_representation Serialised representation of the ID * \return The deserialised MirSurfaceId */ MirPersistentId* mir_persistent_id_from_string(char const* string_representation) MIR_FOR_REMOVAL_IN_VERSION_1("Use mir_window_id_from_string() instead"); #pragma GCC diagnostic pop #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_MIR_PERSISTENT_ID_H_ */ ./include/client/mir_toolkit/mir_cookie.h0000644000004100000410000000443113115234664021000 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Brandon Schaefer */ #ifndef MIR_TOOLKIT_MIR_COOKIE_H_ #define MIR_TOOLKIT_MIR_COOKIE_H_ #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Queries the size needed to serialize a given cookie * * \param [in] cookie A cookie instance * \return The size of the serialized representation of the given cookie */ size_t mir_cookie_buffer_size(MirCookie const* cookie); /** * Serializes a cookie into the given buffer * * \pre The size must be equal to mir_cookie_size * \param [in] cookie A cookie instance * \param [in] buffer A buffer which is filled with the serialized representation of the given cookie * \param [in] size The size of the given buffer */ void mir_cookie_to_buffer(MirCookie const* cookie, void* buffer, size_t size); /** * Create a cookie from a serialized representation * * \param [in] buffer The buffer containing a serialized cookie. * \param [in] size The size of the buffer. * The buffer may be freed immediately after this call. * \return A MirCookie instance. The instance must be released * with a call to mir_cookie_release. * NULL will be returned if the buffer and size don't describe * the contents of a MirCookie. */ MirCookie const* mir_cookie_from_buffer(void const* buffer, size_t size); /** * Release the MirCookie * * \param [in] cookie The cookie to release */ void mir_cookie_release(MirCookie const* cookie); #ifdef __cplusplus } /**@}*/ #endif #endif // MIR_TOOLKIT_MIR_COOKIE_H_ ./include/client/mir_toolkit/mir_prompt_session.h0000644000004100000410000001016713115234664022616 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef MIR_TOOLKIT_MIR_PROMPT_SESSION_H_ #define MIR_TOOLKIT_MIR_PROMPT_SESSION_H_ #include "mir_toolkit/mir_client_library.h" #include #include #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /** * Create and start a new prompt session * \param [in] connection The connection * \param [in] application_pid The process id of the initiating application * \param [in] state_change_callback The function to be called when a prompt session state change occurs * \param [in,out] context User data passed to the callback functions * \return A handle that can be passed to mir_wait_for */ MirPromptSession *mir_connection_create_prompt_session_sync( MirConnection* connection, pid_t application_pid, MirPromptSessionStateChangeCallback state_change_callback, void *context); /** * Allocate some FDs for prompt providers to connect on * * Prompt helpers need to allocate connection FDs it will pass to * prompt providers to use when connecting to the server. The server can * then associate them with the prompt session. * * \warning This API is tentative until the implementation of prompt sessions is complete * \param [in] prompt_session The prompt session * \param [in] no_of_fds The number of fds to allocate * \param [in] callback Callback invoked when request completes * \param [in,out] context User data passed to the callback function * \return A handle that can be passed to mir_wait_for */ MirWaitHandle* mir_prompt_session_new_fds_for_prompt_providers( MirPromptSession *prompt_session, unsigned int no_of_fds, MirClientFdCallback callback, void * context); /** * Allocate some FDs for prompt providers to connect on * * Prompt helpers need to allocate connection FDs it will pass to * prompt providers to use when connecting to the server. The server can * then associate them with the prompt session. * * \warning This API is tentative until the implementation of prompt sessions is complete * \param [in] prompt_session The prompt session * \param [in] no_of_fds The number of fds to allocate * \param [out] fds An int array of at least size no_of_fds * \return The number of fds actually allocated */ size_t mir_prompt_session_new_fds_for_prompt_providers_sync( MirPromptSession *prompt_session, unsigned int no_of_fds, int* fds); /** * Stop and release the specified prompt session * \param [in] prompt_session The prompt session */ void mir_prompt_session_release_sync(MirPromptSession *prompt_session); /** * Test for a valid prompt session * \param [in] prompt_session The prompt session * \return True if prompt_session is valid, false otherwise */ bool mir_prompt_session_is_valid(MirPromptSession *prompt_session); /** * Retrieve a text description of the last error. The returned string is owned * by the library and remains valid until the prompt session has been released. * \param [in] prompt_session The prompt session * \return A text description of any error resulting in an * invalid connection, or the empty string "" if the * connection is valid. */ char const *mir_prompt_session_error_message(MirPromptSession *prompt_session); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_MIR_PROMPT_SESSION_H_ */ ./include/server/0000755000004100000410000000000013115234413014171 5ustar www-datawww-data./include/server/mir/0000755000004100000410000000000013115234677014774 5ustar www-datawww-data./include/server/mir/scene/0000755000004100000410000000000013115234677016071 5ustar www-datawww-data./include/server/mir/scene/coordinate_translator.h0000644000004100000410000000441413115234664022641 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_SCENE_COORDINATE_TRANSLATOR_H_ #define MIR_SCENE_COORDINATE_TRANSLATOR_H_ #include "mir/geometry/point.h" #include namespace mir { namespace frontend { class Surface; } namespace scene { /** * Support for the debug "surface to screen" coordinate translation interface. * \note For shells which do surface transformations the default implementation * will return incorrect results. */ class CoordinateTranslator { public: virtual ~CoordinateTranslator() = default; /** * \brief Translate a surface coordinate into the screen coordinate space * \param [in] surface A frontend::Surface. This will need to be dynamic_cast into * the scene::Surface relevant for the shell. * \param [in] x, y Coordinates to translate from the surface coordinate space * \return The coordinates in the screen coordinate space. * \throws A std::runtime_error if the translation cannot be performed * for any reason. * * \note It is acceptable for this call to unconditionally throw a std::runtime_error. * It is not required for normal functioning of the server or clients; clients which * use the debug extension will receive an appropriate failure notice. */ virtual geometry::Point surface_to_screen(std::shared_ptr surface, int32_t x, int32_t y) = 0; virtual bool translation_supported() const = 0; }; } } #endif // MIR_SCENE_COORDINATE_TRANSLATOR_H_ ./include/server/mir/scene/prompt_session_creation_parameters.h0000644000004100000410000000175513115234416025434 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Nick Dedekind */ #ifndef MIR_SCENE_PROMPT_SESSION_CREATION_PARAMETERS_H_ #define MIR_SCENE_PROMPT_SESSION_CREATION_PARAMETERS_H_ #include namespace mir { namespace scene { struct PromptSessionCreationParameters { pid_t application_pid = 0; }; } } #endif /* MIR_SCENE_PROMPT_SESSION_CREATION_PARAMETERS_H_ */ ./include/server/mir/scene/session_listener.h0000644000004100000410000000306413115234416021624 0ustar www-datawww-data/* * Copyright © 2012-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_SCENE_SESSION_LISTENER_H_ #define MIR_SCENE_SESSION_LISTENER_H_ #include namespace mir { namespace scene { class Surface; class Session; class SessionListener { public: virtual void starting(std::shared_ptr const& session) = 0; virtual void stopping(std::shared_ptr const& session) = 0; virtual void focused(std::shared_ptr const& session) = 0; virtual void unfocused() = 0; virtual void surface_created(Session& session, std::shared_ptr const& surface) = 0; virtual void destroying_surface(Session& session, std::shared_ptr const& surface) = 0; protected: SessionListener() = default; virtual ~SessionListener() = default; SessionListener(const SessionListener&) = delete; SessionListener& operator=(const SessionListener&) = delete; }; } } #endif // MIR_SCENE_SESSION_LISTENER_H_ ./include/server/mir/scene/surface_creation_parameters.h0000644000004100000410000001057413115234664024004 0ustar www-datawww-data/* * Copyright © 2013-2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_SCENE_SURFACE_CREATION_PARAMETERS_H_ #define MIR_SCENE_SURFACE_CREATION_PARAMETERS_H_ #include "mir_toolkit/common.h" #include "mir/geometry/point.h" #include "mir/geometry/size.h" #include "mir/graphics/buffer_properties.h" #include "mir/graphics/display_configuration.h" #include "mir/frontend/surface_id.h" #include "mir/input/input_reception_mode.h" #include "mir/optional_value.h" #include "mir/shell/surface_specification.h" #include #include namespace mir { namespace scene { class Surface; struct SurfaceCreationParameters { SurfaceCreationParameters(); SurfaceCreationParameters& of_name(std::string const& new_name); SurfaceCreationParameters& of_size(geometry::Size new_size); SurfaceCreationParameters& of_size(geometry::Width::ValueType width, geometry::Height::ValueType height); SurfaceCreationParameters& of_position(geometry::Point const& top_left); SurfaceCreationParameters& of_buffer_usage(graphics::BufferUsage new_buffer_usage); SurfaceCreationParameters& of_pixel_format(MirPixelFormat new_pixel_format); SurfaceCreationParameters& with_input_mode(input::InputReceptionMode const& new_mode); SurfaceCreationParameters& with_output_id(graphics::DisplayConfigurationOutputId const& output_id); SurfaceCreationParameters& of_type(MirWindowType type); SurfaceCreationParameters& with_state(MirWindowState state); SurfaceCreationParameters& with_preferred_orientation(MirOrientationMode mode); SurfaceCreationParameters& with_parent_id(frontend::SurfaceId const& id); SurfaceCreationParameters& with_aux_rect(geometry::Rectangle const& rect); SurfaceCreationParameters& with_edge_attachment(MirEdgeAttachment edge); SurfaceCreationParameters& with_buffer_stream(frontend::BufferStreamId const& id); std::string name; geometry::Size size; geometry::Point top_left; graphics::BufferUsage buffer_usage; MirPixelFormat pixel_format; input::InputReceptionMode input_mode; graphics::DisplayConfigurationOutputId output_id; mir::optional_value state; mir::optional_value type; mir::optional_value preferred_orientation; mir::optional_value parent_id; mir::optional_value content_id; mir::optional_value aux_rect; mir::optional_value edge_attachment; optional_value placement_hints; optional_value surface_placement_gravity; optional_value aux_rect_placement_gravity; optional_value aux_rect_placement_offset_x; optional_value aux_rect_placement_offset_y; std::weak_ptr parent; optional_value min_width; optional_value min_height; optional_value max_width; optional_value max_height; mir::optional_value width_inc; mir::optional_value height_inc; mir::optional_value min_aspect; mir::optional_value max_aspect; mir::optional_value> input_shape; mir::optional_value shell_chrome; mir::optional_value> streams; mir::optional_value confine_pointer; }; bool operator==(const SurfaceCreationParameters& lhs, const SurfaceCreationParameters& rhs); bool operator!=(const SurfaceCreationParameters& lhs, const SurfaceCreationParameters& rhs); SurfaceCreationParameters a_surface(); } } #endif /* MIR_SCENE_SURFACE_CREATION_PARAMETERS_H_ */ ./include/server/mir/scene/application_not_responding_detector.h0000644000004100000410000000414413115234416025540 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Christopher James Halse Rogers */ #ifndef MIR_SCENE_APPLICATION_NOT_RESPONDING_DETECTOR_H_ #define MIR_SCENE_APPLICATION_NOT_RESPONDING_DETECTOR_H_ #include #include namespace mir { namespace frontend { class Session; } namespace scene { class Session; class ApplicationNotRespondingDetector { public: ApplicationNotRespondingDetector() = default; virtual ~ApplicationNotRespondingDetector() = default; /** * Notification object for application-not-responsive signals * * \note These signals will be called without any locks held; it's safe * to call methods on the ApplicationNotRespondingDetector from these * delegates. */ class Observer { public: Observer() = default; virtual ~Observer() = default; virtual void session_unresponsive(Session const* session) = 0; virtual void session_now_responsive(Session const* session) = 0; }; virtual void register_session(frontend::Session const* session, std::function const& pinger) = 0; virtual void unregister_session(frontend::Session const* session) = 0; virtual void pong_received(frontend::Session const* received_for) = 0; virtual void register_observer(std::shared_ptr const& observer) = 0; virtual void unregister_observer(std::shared_ptr const& observer) = 0; }; } } #endif // MIR_SCENE_APPLICATION_NOT_RESPONDING_DETECTOR_H_ ./include/server/mir/scene/prompt_session_listener.h0000644000004100000410000000343013115234416023222 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Nick Dedekind */ #ifndef MIR_SCENE_PROMPT_SESSION_LISTENER_H_ #define MIR_SCENE_PROMPT_SESSION_LISTENER_H_ #include namespace mir { namespace scene { class Session; class PromptSession; class PromptSessionListener { public: virtual void starting(std::shared_ptr const& prompt_session) = 0; virtual void stopping(std::shared_ptr const& prompt_session) = 0; virtual void suspending(std::shared_ptr const& prompt_session) = 0; virtual void resuming(std::shared_ptr const& prompt_session) = 0; virtual void prompt_provider_added(PromptSession const& prompt_session, std::shared_ptr const& prompt_provider) = 0; virtual void prompt_provider_removed(PromptSession const& prompt_session, std::shared_ptr const& prompt_provider) = 0; protected: PromptSessionListener() = default; virtual ~PromptSessionListener() = default; PromptSessionListener(const PromptSessionListener&) = delete; PromptSessionListener& operator=(const PromptSessionListener&) = delete; }; } } #endif // MIR_SCENE_PROMPT_SESSION_LISTENER_H_ ./include/server/mir/scene/null_session_listener.h0000644000004100000410000000307713115234416022662 0ustar www-datawww-data/* * Copyright © 2012-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_SCENE_NULL_SESSION_LISTENER_H_ #define MIR_SCENE_NULL_SESSION_LISTENER_H_ #include "mir/scene/session_listener.h" namespace mir { namespace scene { class NullSessionListener : public SessionListener { public: NullSessionListener() = default; virtual ~NullSessionListener() noexcept(true) = default; void starting(std::shared_ptr const&) override {} void stopping(std::shared_ptr const&) override {} void focused(std::shared_ptr const&) override {} void unfocused() override {} void surface_created(Session&, std::shared_ptr const&) override {} void destroying_surface(Session&, std::shared_ptr const&) override {} protected: NullSessionListener(const NullSessionListener&) = delete; NullSessionListener& operator=(const NullSessionListener&) = delete; }; } } #endif // MIR_SCENE_NULL_SESSION_LISTENER_H_ ./include/server/mir/scene/buffer_stream_factory.h0000644000004100000410000000372213115234664022615 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: * Alan Griffiths * Thomas Voss */ #ifndef MIR_SCENE_BUFFER_STREAM_FACTORY_H_ #define MIR_SCENE_BUFFER_STREAM_FACTORY_H_ #include "mir/frontend/buffer_stream_id.h" #include namespace mir { namespace compositor { class BufferStream; } namespace graphics { struct BufferProperties; } namespace frontend { class ClientBuffers; class BufferSink; } namespace scene { class BufferStreamFactory { public: virtual ~BufferStreamFactory() = default; virtual std::shared_ptr create_buffer_stream( frontend::BufferStreamId, std::shared_ptr const& sink, int nbuffers, graphics::BufferProperties const& buffer_properties) = 0; virtual std::shared_ptr create_buffer_stream( frontend::BufferStreamId, std::shared_ptr const& sink, graphics::BufferProperties const& buffer_properties) = 0; virtual std::shared_ptr create_buffer_map( std::shared_ptr const& sink) = 0; protected: BufferStreamFactory() = default; BufferStreamFactory(const BufferStreamFactory&) = delete; BufferStreamFactory& operator=(const BufferStreamFactory&) = delete; }; } } #endif // MIR_SCENE_BUFFER_STREAM_FACTORY_H_ ./include/server/mir/scene/application_not_responding_detector_wrapper.h0000644000004100000410000000340413115234664027303 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_SCENE_APPLICATION_NOT_RESPONDING_DETECTOR_WRAPPER_H_ #define MIR_SCENE_APPLICATION_NOT_RESPONDING_DETECTOR_WRAPPER_H_ #include "mir/scene/application_not_responding_detector.h" #include namespace mir { namespace scene { class ApplicationNotRespondingDetectorWrapper : public ApplicationNotRespondingDetector { public: ApplicationNotRespondingDetectorWrapper(std::shared_ptr const& wrapped); ~ApplicationNotRespondingDetectorWrapper(); virtual void register_session(frontend::Session const* session, std::function const& pinger) override; virtual void unregister_session(frontend::Session const* session) override; virtual void pong_received(frontend::Session const* received_for) override; virtual void register_observer(std::shared_ptr const& observer) override; virtual void unregister_observer(std::shared_ptr const& observer) override; protected: std::shared_ptr const wrapped; }; } } #endif //MIR_SCENE_APPLICATION_NOT_RESPONDING_DETECTOR_WRAPPER_H_ ./include/server/mir/scene/snapshot.h0000644000004100000410000000211013115234416020062 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alexandros Frantzis */ #ifndef MIR_SCENE_SNAPSHOT_H_ #define MIR_SCENE_SNAPSHOT_H_ #include "mir/geometry/size.h" #include "mir/geometry/dimensions.h" #include namespace mir { namespace scene { struct Snapshot { geometry::Size size; geometry::Stride stride; void const* pixels; }; typedef std::function SnapshotCallback; } } #endif /* MIR_SCENE_SNAPSHOT_H_ */ ./include/server/mir/scene/session_coordinator.h0000644000004100000410000000335213115234664022327 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_SCENE_SESSION_COORDINATOR_H_ #define MIR_SCENE_SESSION_COORDINATOR_H_ #include "mir/frontend/surface_id.h" #include "mir_toolkit/common.h" #include namespace mir { namespace frontend { class EventSink; } namespace scene { class Session; class Surface; struct SurfaceCreationParameters; class SessionCoordinator { public: virtual void set_focus_to(std::shared_ptr const& focus) = 0; virtual void unset_focus() = 0; virtual std::shared_ptr open_session( pid_t client_pid, std::string const& name, std::shared_ptr const& sink) = 0; virtual void close_session(std::shared_ptr const& session) = 0; virtual std::shared_ptr successor_of(std::shared_ptr const&) const = 0; protected: SessionCoordinator() = default; virtual ~SessionCoordinator() = default; SessionCoordinator(SessionCoordinator const&) = delete; SessionCoordinator& operator=(SessionCoordinator const&) = delete; }; } } #endif /* MIR_SCENE_SESSION_COORDINATOR_H_ */ ./include/server/mir/scene/surface_observer.h0000644000004100000410000000463013115234664021600 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_SCENE_SURFACE_OBSERVER_H_ #define MIR_SCENE_SURFACE_OBSERVER_H_ #include "mir_toolkit/common.h" #include "mir_toolkit/events/event.h" #include "mir/input/input_reception_mode.h" #include "mir/geometry/rectangle.h" #include #include namespace mir { namespace geometry { struct Size; struct Point; } namespace graphics { class CursorImage; } namespace scene { class SurfaceObserver { public: virtual void attrib_changed(MirWindowAttrib attrib, int value) = 0; virtual void resized_to(geometry::Size const& size) = 0; virtual void moved_to(geometry::Point const& top_left) = 0; virtual void hidden_set_to(bool hide) = 0; virtual void frame_posted(int frames_available, geometry::Size const& size) = 0; virtual void alpha_set_to(float alpha) = 0; virtual void orientation_set_to(MirOrientation orientation) = 0; virtual void transformation_set_to(glm::mat4 const& t) = 0; virtual void reception_mode_set_to(input::InputReceptionMode mode) = 0; virtual void cursor_image_set_to(graphics::CursorImage const& image) = 0; virtual void client_surface_close_requested() = 0; virtual void keymap_changed(MirInputDeviceId id, std::string const& model, std::string const& layout, std::string const& variant, std::string const& options) = 0; virtual void renamed(char const* name) = 0; virtual void cursor_image_removed() = 0; virtual void placed_relative(geometry::Rectangle const& placement) = 0; protected: SurfaceObserver() = default; virtual ~SurfaceObserver() = default; SurfaceObserver(SurfaceObserver const&) = delete; SurfaceObserver& operator=(SurfaceObserver const&) = delete; }; } } #endif // MIR_SCENE_SURFACE_OBSERVER_H_ ./include/server/mir/scene/session.h0000644000004100000410000000535413115234664017730 0ustar www-datawww-data/* * Copyright © 2012-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Robert Carr */ #ifndef MIR_SCENE_SESSION_H_ #define MIR_SCENE_SESSION_H_ #include "mir/frontend/session.h" #include "mir/scene/snapshot.h" #include #include namespace mir { namespace frontend { class EventSink; } namespace shell { struct StreamSpecification; } namespace scene { class Surface; struct SurfaceCreationParameters; class Session : public frontend::Session { public: virtual void drop_outstanding_requests() = 0; virtual pid_t process_id() const = 0; virtual void take_snapshot(SnapshotCallback const& snapshot_taken) = 0; virtual std::shared_ptr default_surface() const = 0; virtual void set_lifecycle_state(MirLifecycleState state) = 0; virtual void hide() = 0; virtual void show() = 0; virtual void start_prompt_session() = 0; virtual void stop_prompt_session() = 0; virtual void suspend_prompt_session() = 0; virtual void resume_prompt_session() = 0; virtual frontend::SurfaceId create_surface( SurfaceCreationParameters const& params, std::shared_ptr const& sink) = 0; virtual void destroy_surface(frontend::SurfaceId surface) = 0; virtual std::shared_ptr surface(frontend::SurfaceId surface) const = 0; virtual std::shared_ptr surface_after(std::shared_ptr const&) const = 0; virtual std::shared_ptr get_buffer_stream(frontend::BufferStreamId stream) const = 0; virtual frontend::BufferStreamId create_buffer_stream(graphics::BufferProperties const& props) = 0; virtual void destroy_buffer_stream(frontend::BufferStreamId stream) = 0; virtual void configure_streams(Surface& surface, std::vector const& config) = 0; virtual void destroy_surface(std::weak_ptr const& surface) = 0; virtual graphics::BufferID create_buffer(graphics::BufferProperties const& properties) = 0; virtual void destroy_buffer(graphics::BufferID) = 0; virtual std::shared_ptr get_buffer(graphics::BufferID) = 0; }; } } #endif // MIR_SCENE_SESSION_H_ ./include/server/mir/scene/null_surface_observer.h0000644000004100000410000000423513115234664022633 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_SCENE_NULL_SURFACE_OBSERVER_H_ #define MIR_SCENE_NULL_SURFACE_OBSERVER_H_ #include "mir/scene/surface_observer.h" namespace mir { namespace scene { class NullSurfaceObserver : public SurfaceObserver { public: NullSurfaceObserver() = default; virtual ~NullSurfaceObserver() = default; void attrib_changed(MirWindowAttrib attrib, int value) override; void resized_to(geometry::Size const& size) override; void moved_to(geometry::Point const& top_left) override; void hidden_set_to(bool hide) override; void frame_posted(int frames_available, geometry::Size const& size) override; void alpha_set_to(float alpha) override; void orientation_set_to(MirOrientation orientation) override; void transformation_set_to(glm::mat4 const& t) override; void cursor_image_set_to(graphics::CursorImage const& image) override; void reception_mode_set_to(input::InputReceptionMode mode) override; void client_surface_close_requested() override; void keymap_changed(MirInputDeviceId id, std::string const& model, std::string const& layout, std::string const& variant, std::string const& options) override; void renamed(char const* name) override; void cursor_image_removed() override; void placed_relative(geometry::Rectangle const& placement) override; protected: NullSurfaceObserver(NullSurfaceObserver const&) = delete; NullSurfaceObserver& operator=(NullSurfaceObserver const&) = delete; }; } } #endif // MIR_SCENE_NULL_SURFACE_OBSERVER_H_ ./include/server/mir/scene/prompt_session_manager.h0000644000004100000410000000754513115234416023022 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Nick Dedekind */ #ifndef MIR_SCENE_PROMPT_SESSION_MANAGER_H_ #define MIR_SCENE_PROMPT_SESSION_MANAGER_H_ #include #include #include namespace mir { namespace scene { class Session; class PromptSession; struct PromptSessionCreationParameters; class PromptSessionManager { public: virtual ~PromptSessionManager() = default; /** * Start a new prompt session * \param [in] session The prompt helper session * \param [in] params The creation parameters for constructing the prompt session */ virtual std::shared_ptr start_prompt_session_for(std::shared_ptr const& session, PromptSessionCreationParameters const& params) const = 0; /** * Stop a started prompt session * \param [in] prompt_session The prompt session */ virtual void stop_prompt_session(std::shared_ptr const& prompt_session) const = 0; /** * Suspend a prompt session * \param [in] prompt_session The prompt session */ virtual void suspend_prompt_session(std::shared_ptr const& prompt_session) const = 0; /** * Resume a suspended prompt session * \param [in] prompt_session The prompt session */ virtual void resume_prompt_session(std::shared_ptr const& prompt_session) const = 0; /** * Add a prompt provider to an existing prompt session * \param [in] prompt_session The prompt session * \param [in] prompt_provider The prompt provider to add to the prompt session */ virtual void add_prompt_provider(std::shared_ptr const& prompt_session, std::shared_ptr const& prompt_provider) const = 0; /** * Remove a session from all associated prompt sessions * \param [in] session The new session that is to be removed */ virtual void remove_session(std::shared_ptr const& session) const = 0; /** * Retrieve the application session for a prompt session * \param [in] prompt_session The prompt session */ virtual std::shared_ptr application_for(std::shared_ptr const& prompt_session) const = 0; /** * Retrieve the helper session for a prompt session * \param [in] prompt_session The prompt session */ virtual std::shared_ptr helper_for(std::shared_ptr const& prompt_session) const = 0; /** * Iterate over all the prompt providers associated with a prompt session * \param [in] prompt_session The prompt session * \param [in] f The callback function to call for each provider */ virtual void for_each_provider_in(std::shared_ptr const& prompt_session, std::function const& prompt_provider)> const& f) const = 0; protected: PromptSessionManager() = default; PromptSessionManager(const PromptSessionManager&) = delete; PromptSessionManager& operator=(const PromptSessionManager&) = delete; }; } } #endif // MIR_SCENE_PROMPT_SESSION_MANAGER_H_ ./include/server/mir/scene/prompt_session.h0000644000004100000410000000332213115234664021322 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Nick Dedekind */ #ifndef MIR_SCENE_PROMPT_SESSION_H_ #define MIR_SCENE_PROMPT_SESSION_H_ #include "mir/frontend/prompt_session.h" namespace mir { namespace scene { class Session; class PromptSession : public frontend::PromptSession { public: /** * Start a prompt session * \param [in] helper_session The prompt session helper session */ virtual void start(std::shared_ptr const& helper_session) = 0; /** * Stop a prompt session * \param [in] helper_session The prompt session helper session */ virtual void stop(std::shared_ptr const& helper_session) = 0; /** * Suspend a prompt session * \param [in] helper_session The prompt session helper session */ virtual void suspend(std::shared_ptr const& helper_session) = 0; /** * Resume a prompt session * \param [in] helper_session The prompt session helper session */ virtual void resume(std::shared_ptr const& helper_session) = 0; }; } } #endif // MIR_SHELL_PROMPT_SESSION_H_ ./include/server/mir/scene/surface_factory.h0000644000004100000410000000260013115234664021413 0ustar www-datawww-data/* * Copyright © 2013-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_SCENE_SURFACE_FACTORY_H_ #define MIR_SCENE_SURFACE_FACTORY_H_ #include "mir/scene/surface_creation_parameters.h" #include #include namespace mir { namespace compositor { class BufferStream; } namespace scene { class Surface; class StreamInfo; class SurfaceFactory { public: SurfaceFactory() = default; virtual ~SurfaceFactory() = default; virtual std::shared_ptr create_surface( std::list const& streams, SurfaceCreationParameters const& params) = 0; private: SurfaceFactory(const SurfaceFactory&) = delete; SurfaceFactory& operator=(const SurfaceFactory&) = delete; }; } } #endif /* MIR_SCENE_SURFACE_FACTORY_H_ */ ./include/server/mir/scene/observer.h0000644000004100000410000000360113115234416020060 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_SCENE_OBSERVER_H_ #define MIR_SCENE_OBSERVER_H_ #include namespace mir { namespace scene { class Surface; /// An observer for top level notifications of scene changes. In order /// to receive more granular change notifications a user may install /// mir::scene::SurfaceObserver in surface_added. class Observer { public: virtual void surface_added(Surface* surface) = 0; virtual void surface_removed(Surface* surface) = 0; virtual void surfaces_reordered() = 0; // Used to indicate the scene has changed in some way beyond the present surfaces // and will require full recomposition. virtual void scene_changed() = 0; // Called at observer registration to notify of already existing surfaces. virtual void surface_exists(Surface* surface) = 0; // Called when observer is unregistered, for example, to provide a place to // unregister SurfaceObservers which may have been added in surface_added/exists virtual void end_observation() = 0; protected: Observer() = default; virtual ~Observer() = default; Observer(Observer const&) = delete; Observer& operator=(Observer const&) = delete; }; } } // namespace mir #endif // MIR_SCENE_OBSERVER_H_ ./include/server/mir/scene/surface.h0000644000004100000410000001142513115234664017671 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_SCENE_SURFACE_H_ #define MIR_SCENE_SURFACE_H_ #include "mir/graphics/renderable.h" #include "mir/input/surface.h" #include "mir/frontend/surface.h" #include "mir/compositor/compositor_id.h" #include "mir/optional_value.h" #include #include namespace mir { namespace input { class InputChannel; } namespace shell { class InputTargeter; } namespace geometry { struct Rectangle; } namespace graphics { class CursorImage; } namespace compositor { class BufferStream; } namespace scene { struct StreamInfo { std::shared_ptr stream; geometry::Displacement displacement; optional_value size; }; class SurfaceObserver; class Surface : public input::Surface, public frontend::Surface { public: // resolve ambiguous member function names std::string name() const override = 0; geometry::Size client_size() const override = 0; geometry::Rectangle input_bounds() const override = 0; // member functions that don't exist in base classes /// Top-left corner (of the window frame if present) virtual geometry::Point top_left() const = 0; /// Size of the surface including window frame (if any) virtual geometry::Size size() const = 0; virtual graphics::RenderableList generate_renderables(compositor::CompositorID id) const = 0; virtual int buffers_ready_for_compositor(void const* compositor_id) const = 0; virtual float alpha() const = 0; //only used in examples/ virtual MirWindowType type() const = 0; virtual MirWindowState state() const = 0; virtual void hide() = 0; virtual void show() = 0; virtual bool visible() const = 0; virtual void move_to(geometry::Point const& top_left) = 0; /** * Sets the input region for this surface. * * The input region is expressed in coordinates relative to the surface (i.e., * use (0,0) for the top left point of the surface). * * By default the input region is the whole surface. To unset a custom input region * and revert to the default set an empty input region, i.e., set_input_region({}). * To disable input set a non-empty region containing an empty rectangle, i.e., * set_input_region({Rectangle{}}). */ virtual void set_input_region(std::vector const& region) = 0; virtual void resize(geometry::Size const& size) = 0; virtual void set_transformation(glm::mat4 const& t) = 0; virtual void set_alpha(float alpha) = 0; virtual void set_orientation(MirOrientation orientation) = 0; virtual void set_cursor_image(std::shared_ptr const& image) override = 0; virtual std::shared_ptr cursor_image() const override = 0; virtual void add_observer(std::shared_ptr const& observer) = 0; virtual void remove_observer(std::weak_ptr const& observer) = 0; // TODO input_channel() relates to adding and removing the surface // TODO from the scene and is probably not cleanest interface for this. virtual std::shared_ptr input_channel() const override = 0; virtual void set_reception_mode(input::InputReceptionMode mode) = 0; virtual void request_client_surface_close() = 0; virtual std::shared_ptr parent() const = 0; // TODO a legacy of old interactions and needs removing virtual int configure(MirWindowAttrib attrib, int value) = 0; // TODO a legacy of old interactions and needs removing virtual int query(MirWindowAttrib attrib) const = 0; virtual void set_keymap(MirInputDeviceId id, std::string const& model, std::string const& layout, std::string const& variant, std::string const& options) = 0; virtual void rename(std::string const& title) = 0; virtual void set_streams(std::list const& streams) = 0; virtual void set_confine_pointer_state(MirPointerConfinementState state) = 0; virtual MirPointerConfinementState confine_pointer_state() const = 0; virtual void placed_relative(geometry::Rectangle const& placement) = 0; }; } } #endif // MIR_SCENE_SURFACE_H_ ./include/server/mir/frontend/0000755000004100000410000000000013115234677016613 5ustar www-datawww-data./include/server/mir/frontend/buffer_sink.h0000644000004100000410000000317013115234664021256 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_FRONTEND_BUFFER_SINK_H_ #define MIR_FRONTEND_BUFFER_SINK_H_ #include "mir/frontend/buffer_stream_id.h" #include "mir/graphics/platform_ipc_operations.h" #include "mir/graphics/buffer_properties.h" #include namespace mir { namespace graphics { class Buffer; } namespace frontend { class BufferSink { public: virtual ~BufferSink() = default; virtual void send_buffer(frontend::BufferStreamId id, graphics::Buffer& buffer, graphics::BufferIpcMsgType) = 0; virtual void add_buffer(graphics::Buffer&) = 0; virtual void error_buffer(geometry::Size req_size, MirPixelFormat req_format, std::string const& error_msg) = 0; virtual void remove_buffer(graphics::Buffer&) = 0; virtual void update_buffer(graphics::Buffer&) = 0; protected: BufferSink() = default; BufferSink(BufferSink const&) = delete; BufferSink& operator=(BufferSink const&) = delete; }; } } // namespace mir #endif // MIR_FRONTEND_BUFFER_SINK_H_ ./include/server/mir/frontend/buffer_stream.h0000644000004100000410000000436513115234664021614 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_FRONTEND_BUFFER_STREAM_H_ #define MIR_FRONTEND_BUFFER_STREAM_H_ #include #include "mir/graphics/buffer_id.h" #include #include namespace mir { namespace graphics { class Buffer; struct BufferProperties; } namespace scene { class SurfaceObserver; } namespace frontend { class BufferStream { public: virtual ~BufferStream() = default; virtual void submit_buffer(std::shared_ptr const& buffer) = 0; virtual void add_observer(std::shared_ptr const& observer) = 0; virtual void remove_observer(std::weak_ptr const& observer) = 0; virtual void with_most_recent_buffer_do( std::function const& exec) = 0; virtual MirPixelFormat pixel_format() const = 0; //TODO: associate/disassociate_buffer are only used for timeout framedropping policy decisions. // They will be removed once timeout framedropping policy moves to the client side. virtual void associate_buffer(graphics::BufferID) = 0; virtual void disassociate_buffer(graphics::BufferID) = 0; //TODO: framedropping for swapinterval-0 can probably be effectively managed from the client // side once we only support the NBS system. virtual void allow_framedropping(bool) = 0; virtual void set_scale(float scale) = 0; protected: BufferStream() = default; BufferStream(BufferStream const&) = delete; BufferStream& operator=(BufferStream const&) = delete; }; } } #endif /* MIR_FRONTEND_BUFFER_STREAM_H_ */ ./include/server/mir/frontend/session_credentials.h0000644000004100000410000000205413115234416023014 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef MIR_FRONTEND_SESSION_CREDENTIALS_ID_H_ #define MIR_FRONTEND_SESSION_CREDENTIALS_ID_H_ #include namespace mir { namespace frontend { class SessionCredentials { public: SessionCredentials(pid_t pid, uid_t uid, gid_t gid); pid_t pid() const; uid_t uid() const; gid_t gid() const; private: SessionCredentials() = delete; pid_t the_pid; uid_t the_uid; gid_t the_gid; }; } } #endif ./include/server/mir/frontend/client_buffers.h0000644000004100000410000000276013115234664021757 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_FRONTEND_CLIENT_BUFFERS_H_ #define MIR_FRONTEND_CLIENT_BUFFERS_H_ #include "mir/graphics/buffer_id.h" #include namespace mir { namespace graphics { class Buffer; } namespace frontend { class ClientBuffers { public: virtual graphics::BufferID add_buffer(std::shared_ptr const& properties) = 0; virtual void remove_buffer(graphics::BufferID id) = 0; virtual std::shared_ptr& operator[](graphics::BufferID) = 0; virtual void send_buffer(graphics::BufferID id) = 0; virtual void receive_buffer(graphics::BufferID id) = 0; ClientBuffers(ClientBuffers const&) = delete; ClientBuffers& operator=(ClientBuffers const&) = delete; virtual ~ClientBuffers() = default; ClientBuffers() = default; }; } } #endif /* MIR_FRONTEND_CLIENT_BUFFERS_H_ */ ./include/server/mir/frontend/session_authorizer.h0000644000004100000410000000306013115234416022711 0ustar www-datawww-data/* * Copyright © 2013-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Robert Carr */ #ifndef MIR_FRONTEND_SESSION_AUTHORIZER_H_ #define MIR_FRONTEND_SESSION_AUTHORIZER_H_ namespace mir { namespace frontend { class SessionCredentials; class SessionAuthorizer { public: virtual ~SessionAuthorizer() = default; virtual bool connection_is_allowed(SessionCredentials const& creds) = 0; virtual bool configure_display_is_allowed(SessionCredentials const& creds) = 0; virtual bool set_base_display_configuration_is_allowed(SessionCredentials const& creds) = 0; virtual bool screencast_is_allowed(SessionCredentials const& creds) = 0; virtual bool prompt_session_is_allowed(SessionCredentials const& creds) = 0; protected: SessionAuthorizer() = default; SessionAuthorizer(SessionAuthorizer const&) = delete; SessionAuthorizer& operator=(SessionAuthorizer const&) = delete; }; } } // namespace mir #endif // MIR_FRONTEND_SESSION_AUTHORIZER_H_ ./include/server/mir/frontend/session.h0000644000004100000410000000517213115234664020450 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Robert Carr */ #ifndef MIR_FRONTEND_SESSION_H_ #define MIR_FRONTEND_SESSION_H_ #include "mir_toolkit/common.h" #include "mir/frontend/surface_id.h" #include "mir/graphics/buffer_id.h" #include "mir/geometry/size.h" #include "mir/frontend/buffer_stream_id.h" #include #include class MirInputConfig; namespace mir { class ClientVisibleError; namespace graphics { class DisplayConfiguration; struct BufferProperties; class Buffer; } namespace frontend { class Surface; class BufferStream; class Session { public: virtual ~Session() = default; virtual std::shared_ptr get_surface(SurfaceId surface) const = 0; virtual std::shared_ptr get_buffer_stream(BufferStreamId stream) const = 0; virtual BufferStreamId create_buffer_stream(graphics::BufferProperties const& props) = 0; virtual void destroy_buffer_stream(BufferStreamId stream) = 0; virtual graphics::BufferID create_buffer(graphics::BufferProperties const& properties) = 0; virtual void destroy_buffer(graphics::BufferID) = 0; virtual std::shared_ptr get_buffer(graphics::BufferID) = 0; virtual std::string name() const = 0; virtual void send_display_config(graphics::DisplayConfiguration const&) = 0; virtual void send_error(ClientVisibleError const&) = 0; virtual void send_input_config(MirInputConfig const& config) = 0; protected: Session() = default; Session(Session const&) = delete; Session& operator=(Session const&) = delete; }; class SessionExtensions { public: virtual ~SessionExtensions() = default; virtual graphics::BufferID create_buffer(geometry::Size, MirPixelFormat) = 0; virtual graphics::BufferID create_buffer(geometry::Size, uint32_t native_format, uint32_t native_flags) = 0; protected: SessionExtensions() = default; SessionExtensions(SessionExtensions const&) = delete; SessionExtensions& operator=(SessionExtensions const&) = delete; }; } } #endif // MIR_FRONTEND_SESSION_H_ ./include/server/mir/frontend/session_mediator_observer.h0000644000004100000410000000524113115234664024240 0ustar www-datawww-data/* * Copyright © 2012-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_FRONTEND_SESSION_MEDIATOR_OBSERVER_H_ #define MIR_FRONTEND_SESSION_MEDIATOR_OBSERVER_H_ #include #include namespace mir { namespace frontend { // Interface for monitoring application activity class SessionMediatorObserver { public: virtual ~SessionMediatorObserver() = default; virtual void session_connect_called(std::string const& app_name) = 0; virtual void session_create_surface_called(std::string const& app_name) = 0; virtual void session_submit_buffer_called(std::string const& app_name) = 0; virtual void session_allocate_buffers_called(std::string const& app_name) = 0; virtual void session_release_buffers_called(std::string const& app_name) = 0; virtual void session_release_surface_called(std::string const& app_name) = 0; virtual void session_disconnect_called(std::string const& app_name) = 0; virtual void session_configure_surface_called(std::string const& app_name) = 0; virtual void session_configure_surface_cursor_called(std::string const& app_name) = 0; virtual void session_configure_display_called(std::string const& app_name) = 0; virtual void session_set_base_display_configuration_called(std::string const& app_name) = 0; virtual void session_preview_base_display_configuration_called(std::string const& app_name) = 0; virtual void session_confirm_base_display_configuration_called(std::string const& app_name) = 0; virtual void session_start_prompt_session_called(std::string const& app_name, pid_t application_process) = 0; virtual void session_stop_prompt_session_called(std::string const& app_name) = 0; virtual void session_create_buffer_stream_called(std::string const& app_name) = 0; virtual void session_release_buffer_stream_called(std::string const& app_name) = 0; virtual void session_error( std::string const& app_name, char const* method, std::string const& what) = 0; }; } } #endif /* MIR_FRONTEND_SESSION_MEDIATOR_OBSERVER_H_ */ ./include/server/mir/frontend/prompt_session.h0000644000004100000410000000225213115234416022040 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Nick Dedekind */ #ifndef MIR_FRONTEND_PROMPT_SESSION_H_ #define MIR_FRONTEND_PROMPT_SESSION_H_ #include "mir_toolkit/common.h" #include #include #include #include namespace mir { namespace frontend { class PromptSession { public: virtual ~PromptSession() = default; protected: PromptSession() = default; PromptSession(const PromptSession&) = delete; PromptSession& operator=(const PromptSession&) = delete; }; } } #endif // MIR_FRONTEND_PROMPT_SESSION_H_ ./include/server/mir/frontend/surface.h0000644000004100000410000000346413115234416020412 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_FRONTEND_SURFACE_H_ #define MIR_FRONTEND_SURFACE_H_ #include "mir/frontend/buffer_stream.h" #include "mir/geometry/size.h" #include "mir/geometry/displacement.h" #include "mir_toolkit/common.h" #include #include namespace mir { namespace graphics { class Buffer; class CursorImage; } namespace frontend { class ClientBufferTracker; class BufferStream; class Surface { public: virtual ~Surface() = default; /// Size of the client area of the surface (excluding any decorations) virtual geometry::Size client_size() const = 0; virtual std::shared_ptr primary_buffer_stream() const = 0; virtual bool supports_input() const = 0; virtual int client_input_fd() const = 0; virtual void set_cursor_image(std::shared_ptr const& image) = 0; virtual void set_cursor_stream(std::shared_ptr const& image, geometry::Displacement const& hotspot) = 0; protected: Surface() = default; Surface(Surface const&) = delete; Surface& operator=(Surface const&) = delete; }; } } #endif /* MIR_FRONTEND_SURFACE_H_ */ ./include/server/mir/report_exception.h0000644000004100000410000000215613115234416020531 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_REPORT_EXCEPTION_H_ #define MIR_REPORT_EXCEPTION_H_ #include namespace mir { /** * Call this from a catch block (and only from a catch block) * to write error information to an output stream. */ void report_exception(std::ostream& out); /** * Call this from a catch block (and only from a catch block) * to write error information to std:cerr. */ void report_exception(); } #endif /* MIR_REPORT_EXCEPTION_H_ */ ./include/server/mir/main_loop.h0000644000004100000410000000222313115234664017115 0ustar www-datawww-data/* * Copyright © 2013-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_MAIN_LOOP_H_ #define MIR_MAIN_LOOP_H_ #include "mir/graphics/event_handler_register.h" #include "mir/time/alarm_factory.h" #include "mir/server_action_queue.h" #include "mir/executor.h" namespace mir { class MainLoop : public graphics::EventHandlerRegister, public time::AlarmFactory, public ServerActionQueue, public Executor { public: virtual void run() = 0; virtual void stop() = 0; }; } #endif /* MIR_MAIN_LOOP_H_ */ ./include/server/mir/terminate_with_current_exception.h0000644000004100000410000000201413115234416023774 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_TERMINATE_WITH_CURRENT_EXCEPTION_H_ #define MIR_TERMINATE_WITH_CURRENT_EXCEPTION_H_ namespace mir { void terminate_with_current_exception(); /// called by main thread to rethrow any termination exception void check_for_termination_exception(); void clear_termination_exception(); } #endif /* MIR_TERMINATE_WITH_CURRENT_EXCEPTION_H_ */ ./include/server/mir/server_status_listener.h0000644000004100000410000000241613115234664021762 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Ancell */ #ifndef MIR_SERVER_STATUS_LISTENER_H_ #define MIR_SERVER_STATUS_LISTENER_H_ namespace mir { class ServerStatusListener { public: virtual void paused() = 0; virtual void resumed() = 0; virtual void started() = 0; virtual void ready_for_user_input() = 0; virtual void stop_receiving_input() = 0; protected: ServerStatusListener() = default; virtual ~ServerStatusListener() = default; ServerStatusListener(ServerStatusListener const&) = delete; ServerStatusListener& operator=(ServerStatusListener const&) = delete; }; } #endif /* MIR_SERVER_STATUS_LISTENER_H_ */ ./include/server/mir/compositor/0000755000004100000410000000000013115234677017172 5ustar www-datawww-data./include/server/mir/compositor/compositor_report.h0000644000004100000410000000332113115234416023122 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_COMPOSITOR_COMPOSITOR_REPORT_H_ #define MIR_COMPOSITOR_COMPOSITOR_REPORT_H_ #include "mir/graphics/renderable.h" namespace mir { namespace compositor { class CompositorReport { public: typedef const void* SubCompositorId; // e.g. thread/display buffer ID virtual void added_display(int width, int height, int x, int y, SubCompositorId id) = 0; virtual void began_frame(SubCompositorId id) = 0; virtual void renderables_in_frame(SubCompositorId id, graphics::RenderableList const& renderables) = 0; virtual void rendered_frame(SubCompositorId id) = 0; virtual void finished_frame(SubCompositorId id) = 0; virtual void started() = 0; virtual void stopped() = 0; virtual void scheduled() = 0; protected: CompositorReport() = default; virtual ~CompositorReport() = default; CompositorReport(CompositorReport const&) = delete; CompositorReport& operator=(CompositorReport const&) = delete; }; } // namespace compositor } // namespace mir #endif // MIR_COMPOSITOR_COMPOSITOR_REPORT_H_ ./include/server/mir/compositor/display_buffer_compositor.h0000644000004100000410000000253613115234416024614 0ustar www-datawww-data/* * Copyright © 2012-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths * Alexandros Frantzis */ #ifndef MIR_COMPOSITOR_DISPLAY_BUFFER_COMPOSITOR_H_ #define MIR_COMPOSITOR_DISPLAY_BUFFER_COMPOSITOR_H_ #include "mir/compositor/scene.h" namespace mir { namespace compositor { class DisplayBufferCompositor { public: virtual ~DisplayBufferCompositor() = default; virtual void composite(SceneElementSequence&& scene_sequence) = 0; protected: DisplayBufferCompositor() = default; DisplayBufferCompositor& operator=(DisplayBufferCompositor const&) = delete; DisplayBufferCompositor(DisplayBufferCompositor const&) = delete; }; } } #endif /* MIR_COMPOSITOR_DISPLAY_BUFFER_COMPOSITOR_H_ */ ./include/server/mir/compositor/scene_element.h0000644000004100000410000000277313115234416022151 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_COMPOSITOR_SCENE_ELEMENT_H_ #define MIR_COMPOSITOR_SCENE_ELEMENT_H_ #include namespace mir { namespace graphics { class Renderable; } namespace compositor { class Decoration; class SceneElement { public: virtual ~SceneElement() = default; virtual std::shared_ptr renderable() const = 0; virtual void rendered() = 0; virtual void occluded() = 0; //TODO: Decoration is opaque on purpose. It is only used by an internal example, // and this function should be removed from the public API. virtual std::unique_ptr decoration() const = 0; protected: SceneElement() = default; SceneElement(SceneElement const&) = delete; SceneElement& operator=(SceneElement const&) = delete; }; } } #endif // MIR_COMPOSITOR_SCENE_ELEMENT_H_ ./include/server/mir/compositor/display_listener.h0000644000004100000410000000240413115234416022704 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_COMPOSITOR_DISPLAY_LISTENER_H_ #define MIR_COMPOSITOR_DISPLAY_LISTENER_H_ namespace mir { namespace geometry { struct Rectangle; } namespace compositor { class DisplayListener { public: virtual void add_display(geometry::Rectangle const& area) = 0; virtual void remove_display(geometry::Rectangle const& area) = 0; protected: DisplayListener() = default; virtual ~DisplayListener() = default; DisplayListener(DisplayListener const&) = delete; DisplayListener& operator=(DisplayListener const&) = delete; }; } } #endif /* MIR_COMPOSITOR_DISPLAY_LISTENER_H_ */ ./include/server/mir/compositor/scene.h0000644000004100000410000000531113115234664020434 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_COMPOSITOR_SCENE_H_ #define MIR_COMPOSITOR_SCENE_H_ #include "compositor_id.h" #include #include namespace mir { namespace scene { class Observer; } namespace compositor { class SceneElement; using SceneElementSequence = std::vector>; class Scene { public: virtual ~Scene() {} /** * Generate a valid sequence of scene elements based on the current state of the Scene. * \param [in] id An arbitrary unique identifier used to distinguish * separate compositors which need to receive a sequence * for rendering. Calling with the same id will return * a new (different) sequence to that user each time. For * consistency, all callers need to determine their id * in the same way (e.g. always use "this" pointer). * \returns a sequence of SceneElements for the compositor id. The * sequence is in stacking order from back to front. */ virtual SceneElementSequence scene_elements_for(CompositorID id) = 0; /** * Return the number of additional frames that you need to render to get * fully up to date with the latest data in the scene. For a generic * "scene change" this will be just 1. For surfaces that have multiple * frames queued up however, it could be greater than 1. When the result * reaches zero, you know you have consumed all the latest data from the * scene. */ virtual int frames_pending(CompositorID id) const = 0; virtual void register_compositor(CompositorID id) = 0; virtual void unregister_compositor(CompositorID id) = 0; virtual void add_observer(std::shared_ptr const& observer) = 0; virtual void remove_observer(std::weak_ptr const& observer) = 0; protected: Scene() = default; private: Scene(Scene const&) = delete; Scene& operator=(Scene const&) = delete; }; } } #endif /* MIR_COMPOSITOR_SCENE_H_ */ ./include/server/mir/compositor/compositor.h0000644000004100000410000000214213115234416021527 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_COMPOSITOR_COMPOSITOR_H_ #define MIR_COMPOSITOR_COMPOSITOR_H_ namespace mir { namespace compositor { class Compositor { public: virtual ~Compositor() {} virtual void start() = 0; virtual void stop() = 0; protected: Compositor() = default; Compositor(Compositor const&) = delete; Compositor& operator=(Compositor const&) = delete; }; } } #endif // MIR_COMPOSITOR_COMPOSITOR_H_ ./include/server/mir/compositor/compositor_id.h0000644000004100000410000000154613115234416022212 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_COMPOSITOR_COMPOSITOR_ID_H_ #define MIR_COMPOSITOR_COMPOSITOR_ID_H_ namespace mir { namespace compositor { using CompositorID = void const*; } } #endif ./include/server/mir/compositor/display_buffer_compositor_factory.h0000644000004100000410000000302513115234416026335 0ustar www-datawww-data/* * Copyright © 2012-2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths * Alexandros Frantzis */ #ifndef MIR_COMPOSITOR_DISPLAY_BUFFER_COMPOSITOR_FACTORY_H_ #define MIR_COMPOSITOR_DISPLAY_BUFFER_COMPOSITOR_FACTORY_H_ #include namespace mir { namespace graphics { class DisplayBuffer; } namespace compositor { class DisplayBufferCompositor; class DisplayBufferCompositorFactory { public: virtual ~DisplayBufferCompositorFactory() = default; virtual std::unique_ptr create_compositor_for(graphics::DisplayBuffer& display_buffer) = 0; protected: DisplayBufferCompositorFactory() = default; DisplayBufferCompositorFactory& operator=(DisplayBufferCompositorFactory const&) = delete; DisplayBufferCompositorFactory(DisplayBufferCompositorFactory const&) = delete; }; } } #endif /* MIR_COMPOSITOR_DISPLAY_BUFFER_COMPOSITOR_FACTORY_H_ */ ./include/server/mir/shell/0000755000004100000410000000000013115234677016103 5ustar www-datawww-data./include/server/mir/shell/host_lifecycle_event_listener.h0000644000004100000410000000242313115234416024346 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #ifndef MIR_HOST_LIFECYCLE_EVENT_LISTENER_H_ #define MIR_HOST_LIFECYCLE_EVENT_LISTENER_H_ #include "mir_toolkit/common.h" namespace mir { namespace shell { class HostLifecycleEventListener { public: virtual void lifecycle_event_occurred(MirLifecycleState state) = 0; protected: HostLifecycleEventListener() = default; virtual ~HostLifecycleEventListener() = default; HostLifecycleEventListener(HostLifecycleEventListener const&) = delete; HostLifecycleEventListener& operator=(HostLifecycleEventListener const&) = delete; }; } } #endif /* MIR_HOST_LIFECYCLE_EVENT_LISTENER_H_ */ ./include/server/mir/shell/surface_stack_wrapper.h0000644000004100000410000000275113115234416022625 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_SHELL_SURFACE_STACK_WRAPPER_H #define MIR_SHELL_SURFACE_STACK_WRAPPER_H #include "mir/shell/surface_stack.h" namespace mir { namespace shell { class SurfaceStackWrapper : public SurfaceStack { public: explicit SurfaceStackWrapper(std::shared_ptr const& wrapped); void add_surface( std::shared_ptr const&, input::InputReceptionMode new_mode) override; void raise(std::weak_ptr const& surface) override; void raise(SurfaceSet const& surfaces) override; void remove_surface(std::weak_ptr const& surface) override; auto surface_at(geometry::Point) const -> std::shared_ptr override; protected: std::shared_ptr const wrapped; }; } } #endif //MIR_SHELL_SURFACE_STACK_WRAPPER_H ./include/server/mir/shell/window_manager_builder.h0000644000004100000410000000226413115234416022756 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef INCLUDE_SERVER_MIR_SHELL_WINDOW_MANAGER_BUILDER_H_ #define INCLUDE_SERVER_MIR_SHELL_WINDOW_MANAGER_BUILDER_H_ #include #include namespace mir { namespace shell { class WindowManager; class FocusController; /// WindowManagers are built while initializing an AbstractShell, so a builder functor is needed using WindowManagerBuilder = std::function(FocusController* focus_controller)>; } } #endif /* INCLUDE_SERVER_MIR_SHELL_WINDOW_MANAGER_BUILDER_H_ */ ./include/server/mir/shell/display_layout.h0000644000004100000410000000405513115234416021311 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_SHELL_DISPLAY_LAYOUT_H_ #define MIR_SHELL_DISPLAY_LAYOUT_H_ #include "mir/graphics/display_configuration.h" namespace mir { namespace geometry { struct Rectangle; } namespace shell { /** * Interface to the layout of the display outputs. */ class DisplayLayout { public: virtual ~DisplayLayout() = default; /** * Clips a rectangle to the output it is in. * * @param [in,out] rect the rectangle to clip */ virtual void clip_to_output(geometry::Rectangle& rect) = 0; /** * Makes a rectangle take up the whole area of the output it is in. * * @param [in,out] rect the rectangle to make fullscreen */ virtual void size_to_output(geometry::Rectangle& rect) = 0; /** * Places a rectangle in an particular output if the display is known, * otherwise does nothing. * * @param [in] id the id of the output to place the rectangle in * @param [in,out] rect the rectangle to place * @return true iff the display id is recognised */ virtual bool place_in_output(graphics::DisplayConfigurationOutputId id, geometry::Rectangle& rect) = 0; protected: DisplayLayout() = default; DisplayLayout(DisplayLayout const&) = delete; DisplayLayout& operator=(DisplayLayout const&) = delete; }; } } #endif /* MIR_SHELL_DISPLAY_LAYOUT_H_ */ ./include/server/mir/shell/surface_ready_observer.h0000644000004100000410000000333413115234416022771 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_SHELL_SURFACE_READY_OBSERVER_H_ #define MIR_SHELL_SURFACE_READY_OBSERVER_H_ #include "mir/scene/null_surface_observer.h" #include #include namespace mir { namespace scene { class Session; class Surface; } namespace geometry { struct Size; } namespace shell { class SurfaceReadyObserver : public scene::NullSurfaceObserver, public std::enable_shared_from_this { public: using ActivateFunction = std::function const& session, std::shared_ptr const& surface)>; SurfaceReadyObserver( ActivateFunction const& activate, std::shared_ptr const& session, std::shared_ptr const& surface); ~SurfaceReadyObserver(); private: void frame_posted(int, geometry::Size const&) override; ActivateFunction const activate; std::weak_ptr const session; std::weak_ptr const surface; }; } } #endif /* MIR_SHELL_SURFACE_READY_OBSERVER_H_ */ ./include/server/mir/shell/surface_specification.h0000644000004100000410000000724713115234664022612 0ustar www-datawww-data/* * Copyright © 2015-2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_SHELL_SURFACE_SPECIFICATION_H_ #define MIR_SHELL_SURFACE_SPECIFICATION_H_ #include "mir/optional_value.h" #include "mir_toolkit/common.h" #include "mir/frontend/surface_id.h" #include "mir/frontend/buffer_stream_id.h" #include "mir/geometry/point.h" #include "mir/geometry/displacement.h" #include "mir/graphics/buffer_properties.h" #include "mir/graphics/display_configuration.h" #include #include namespace mir { namespace graphics { class CursorImage; } namespace scene { class Surface; } namespace shell { struct SurfaceAspectRatio { unsigned width; unsigned height; }; struct StreamSpecification { frontend::BufferStreamId stream_id; geometry::Displacement displacement; optional_value size; }; struct StreamCursor { frontend::BufferStreamId stream_id; geometry::Displacement hotspot; }; /// Specification of surface properties requested by client struct SurfaceSpecification { bool is_empty() const; optional_value width; optional_value height; optional_value pixel_format; optional_value buffer_usage; optional_value name; optional_value output_id; optional_value type; optional_value state; optional_value preferred_orientation; optional_value parent_id; optional_value aux_rect; optional_value edge_attachment; optional_value placement_hints; optional_value surface_placement_gravity; optional_value aux_rect_placement_gravity; optional_value aux_rect_placement_offset_x; optional_value aux_rect_placement_offset_y; optional_value min_width; optional_value min_height; optional_value max_width; optional_value max_height; optional_value width_inc; optional_value height_inc; optional_value min_aspect; optional_value max_aspect; optional_value> streams; optional_value> parent; optional_value> input_shape; // TODO scene::SurfaceCreationParameters overlaps this content but has additional fields: // geometry::Point top_left; // input::InputReceptionMode input_mode; // // it also has size instead of width + height // Maybe SurfaceCreationParameters /HasA/ SurfaceSpecification? optional_value shell_chrome; optional_value confine_pointer; optional_value> cursor_image; optional_value stream_cursor; }; } } #endif /* MIR_SHELL_SURFACE_SPECIFICATION_H_ */ ./include/server/mir/shell/input_targeter.h0000644000004100000410000000246613115234416021307 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_SHELL_INPUT_TARGETER_H_ #define MIR_SHELL_INPUT_TARGETER_H_ #include namespace mir { namespace input { class Surface; } namespace shell { /// An interface used to control the selection of keyboard input focus. class InputTargeter { public: virtual ~InputTargeter() = default; virtual void set_focus(std::shared_ptr const& focus_surface) = 0; virtual void clear_focus() = 0; protected: InputTargeter() = default; InputTargeter(InputTargeter const&) = delete; InputTargeter& operator=(InputTargeter const&) = delete; }; } } // namespace mir #endif // MIR_SHELL_INPUT_TARGETER_H_ ./include/server/mir/shell/abstract_shell.h0000644000004100000410000001266113115234664021250 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_SHELL_ABSTRACT_SHELL_H_ #define MIR_SHELL_ABSTRACT_SHELL_H_ #include "mir/shell/shell.h" #include "mir/shell/window_manager_builder.h" #include "mir/scene/surface_observer.h" #include namespace mir { namespace input { class Seat; } namespace shell { class ShellReport; class WindowManager; /// Minimal Shell implementation with none of the necessary window management logic class AbstractShell : public virtual Shell, public virtual FocusController { public: AbstractShell( std::shared_ptr const& input_targeter, std::shared_ptr const& surface_stack, std::shared_ptr const& session_coordinator, std::shared_ptr const& prompt_session_manager, std::shared_ptr const& report, WindowManagerBuilder const& wm_builder, std::shared_ptr const& seat); ~AbstractShell() noexcept; std::shared_ptr open_session( pid_t client_pid, std::string const& name, std::shared_ptr const& sink) override; void close_session(std::shared_ptr const& session) override; frontend::SurfaceId create_surface( std::shared_ptr const& session, scene::SurfaceCreationParameters const& params, std::shared_ptr const& sink) override; void modify_surface(std::shared_ptr const& session, std::shared_ptr const& surface, SurfaceSpecification const& modifications) override; void destroy_surface(std::shared_ptr const& session, frontend::SurfaceId surface) override; int set_surface_attribute( std::shared_ptr const& session, std::shared_ptr const& surface, MirWindowAttrib attrib, int value) override; int get_surface_attribute( std::shared_ptr const& surface, MirWindowAttrib attrib) override; void raise_surface( std::shared_ptr const& session, std::shared_ptr const& surface, uint64_t timestamp) override; std::shared_ptr start_prompt_session_for( std::shared_ptr const& session, scene::PromptSessionCreationParameters const& params) override; void add_prompt_provider_for( std::shared_ptr const& prompt_session, std::shared_ptr const& session) override; void stop_prompt_session(std::shared_ptr const& prompt_session) override; /** @name these come from FocusController * Focus changes are notified to the derived class via the private setting_focus_to() * functions. * \note I think the FocusController interface is unnecessary as: * 1. the functions are only meaningful in the context of implementing a Shell * 2. the implementation of these functions is Shell behaviour * Simply providing them as part of AbstractShell is probably adequate. * @{ */ void focus_next_session() override; std::shared_ptr focused_session() const override; // More useful than FocusController::set_focus_to()! void set_focus_to( std::shared_ptr const& focus_session, std::shared_ptr const& focus_surface) override; // The surface with focus std::shared_ptr focused_surface() const override; auto surface_at(geometry::Point cursor) const -> std::shared_ptr override; void raise(SurfaceSet const& surfaces) override; /** @} */ void add_display(geometry::Rectangle const& area) override; void remove_display(geometry::Rectangle const& area) override; bool handle(MirEvent const& event) override; void update_focused_surface_confined_region(); protected: std::shared_ptr const input_targeter; std::shared_ptr const surface_stack; std::shared_ptr const session_coordinator; std::shared_ptr const prompt_session_manager; std::shared_ptr const window_manager; std::shared_ptr const seat; private: std::shared_ptr const report; std::mutex mutable focus_mutex; std::weak_ptr focus_surface; std::weak_ptr focus_session; std::shared_ptr focus_surface_observer; void set_focus_to_locked( std::unique_lock const& lock, std::shared_ptr const& focus_session, std::shared_ptr const& focus_surface); }; } } #endif /* MIR_SHELL_ABSTRACT_SHELL_H_ */ ./include/server/mir/shell/shell_wrapper.h0000644000004100000410000000657313115234664021132 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_SHELL_SHELL_WRAPPER_H_ #define MIR_SHELL_SHELL_WRAPPER_H_ #include "mir/shell/shell.h" namespace mir { namespace shell { class ShellWrapper : public Shell { public: explicit ShellWrapper(std::shared_ptr const& wrapped); void focus_next_session() override; std::shared_ptr focused_session() const override; void set_focus_to( std::shared_ptr const& focus_session, std::shared_ptr const& focus_surface) override; std::shared_ptr focused_surface() const override; auto surface_at(geometry::Point cursor) const -> std::shared_ptr override; void raise(SurfaceSet const& surfaces) override; std::shared_ptr open_session( pid_t client_pid, std::string const& name, std::shared_ptr const& sink) override; void close_session(std::shared_ptr const& session) override; std::shared_ptr start_prompt_session_for( std::shared_ptr const& session, scene::PromptSessionCreationParameters const& params) override; void add_prompt_provider_for( std::shared_ptr const& prompt_session, std::shared_ptr const& session) override; void stop_prompt_session(std::shared_ptr const& prompt_session) override; frontend::SurfaceId create_surface( std::shared_ptr const& session, scene::SurfaceCreationParameters const& params, std::shared_ptr const& sink) override; void modify_surface(std::shared_ptr const& session, std::shared_ptr const& surface, SurfaceSpecification const& modifications) override; void destroy_surface(std::shared_ptr const& session, frontend::SurfaceId surface) override; int set_surface_attribute( std::shared_ptr const& session, std::shared_ptr const& surface, MirWindowAttrib attrib, int value) override; int get_surface_attribute( std::shared_ptr const& surface, MirWindowAttrib attrib) override; void raise_surface( std::shared_ptr const& session, std::shared_ptr const& surface, uint64_t timestamp) override; void add_display(geometry::Rectangle const& area) override; void remove_display(geometry::Rectangle const& area) override; bool handle(MirEvent const& event) override; protected: std::shared_ptr const wrapped; }; } } #endif /* MIR_SHELL_SHELL_WRAPPER_H_ */ ./include/server/mir/shell/system_compositor_window_manager.h0000644000004100000410000000766413115234664025150 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_SHELL_SYSTEM_COMPOSITOR_WINDOW_MANAGER_H_ #define MIR_SHELL_SYSTEM_COMPOSITOR_WINDOW_MANAGER_H_ #include "mir/shell/window_manager.h" #include "mir/graphics/display_configuration.h" #include #include namespace mir { namespace scene { class SessionCoordinator; } namespace shell { class FocusController; class DisplayLayout; /** Minimal window management for system compositing. */ class SystemCompositorWindowManager : public WindowManager { public: SystemCompositorWindowManager( FocusController* focus_controller, std::shared_ptr const& display_layout, std::shared_ptr const& session_coordinator); /** @name Customization points * These are the likely events that a system compositor will care about * @{ */ /// Called when a session first connects (before any surfaces are ready) virtual void on_session_added(std::shared_ptr const& session) const; /// Called when a session disconnects virtual void on_session_removed(std::shared_ptr const& session) const; /// Called the first time each surface owned by the session posts its first buffer virtual void on_session_ready(std::shared_ptr const& session) const; /** @} */ protected: FocusController* const focus_controller; std::shared_ptr const display_layout; std::shared_ptr const session_coordinator; private: void add_session(std::shared_ptr const& session) override; void remove_session(std::shared_ptr const& session) override; frontend::SurfaceId add_surface( std::shared_ptr const& session, scene::SurfaceCreationParameters const& params, std::function const& session, scene::SurfaceCreationParameters const& params)> const& build) override; void modify_surface( std::shared_ptr const& session, std::shared_ptr const& surface, SurfaceSpecification const& modifications) override; void remove_surface( std::shared_ptr const& session, std::weak_ptr const& surface) override; void add_display(geometry::Rectangle const& area) override; void remove_display(geometry::Rectangle const& area) override; bool handle_keyboard_event(MirKeyboardEvent const* event) override; bool handle_touch_event(MirTouchEvent const* event) override; bool handle_pointer_event(MirPointerEvent const* event) override; void handle_raise_surface( std::shared_ptr const& session, std::shared_ptr const& surface, uint64_t timestamp) override; int set_surface_attribute( std::shared_ptr const& session, std::shared_ptr const& surface, MirWindowAttrib attrib, int value) override; using OutputMap = std::map, graphics::DisplayConfigurationOutputId, std::owner_less>>; std::mutex mutable mutex; OutputMap output_map; }; } } #endif /* MIR_SHELL_SYSTEM_COMPOSITOR_WINDOW_MANAGER_H_ */ ./include/server/mir/shell/focus_controller.h0000644000004100000410000000406413115234416021631 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_SHELL_FOCUS_CONTROLLER_H_ #define MIR_SHELL_FOCUS_CONTROLLER_H_ #include #include namespace mir { namespace geometry { struct Point; } namespace scene { class Session; class Surface; } namespace shell { using SurfaceSet = std::set, std::owner_less>>; // TODO I don't think this interface serves a meaningful purpose // TODO (It is referenced by a couple of example WindowManagers, and // TODO to get the active session in unity-system-compositor.) // TODO I think there's a better approach possible. class FocusController { public: virtual ~FocusController() = default; virtual void focus_next_session() = 0; virtual auto focused_session() const -> std::shared_ptr = 0; virtual void set_focus_to( std::shared_ptr const& focus_session, std::shared_ptr const& focus_surface) = 0; virtual std::shared_ptr focused_surface() const = 0; virtual auto surface_at(geometry::Point cursor) const -> std::shared_ptr = 0; virtual void raise(SurfaceSet const& surfaces) = 0; protected: FocusController() = default; FocusController(FocusController const&) = delete; FocusController& operator=(FocusController const&) = delete; }; } } // namespace mir #endif // MIR_SHELL_FOCUS_CONTROLLER_H_ ./include/server/mir/shell/shell_report.h0000644000004100000410000000541713115234664020761 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_SHELL_SHELL_REPORT_H #define MIR_SHELL_SHELL_REPORT_H #include "mir/frontend/surface_id.h" #include "mir_toolkit/common.h" #include #include namespace mir { namespace geometry { struct Rectangle; } namespace scene { class PromptSession; class Session; class Surface; struct SurfaceCreationParameters; } namespace shell { struct SurfaceSpecification; /// @cond using SurfaceSet = std::set, std::owner_less>>; /// @endcond class ShellReport { public: virtual void opened_session(scene::Session const& session) = 0; virtual void closing_session(scene::Session const& session) = 0; virtual void created_surface( scene::Session const& session, frontend::SurfaceId surface_id) = 0; virtual void update_surface( scene::Session const& session, scene::Surface const& surface, SurfaceSpecification const& modifications) = 0; virtual void update_surface( scene::Session const& session, scene::Surface const& surface, MirWindowAttrib attrib, int value) = 0; virtual void destroying_surface( scene::Session const& session, frontend::SurfaceId surface) = 0; virtual void started_prompt_session( scene::PromptSession const& prompt_session, scene::Session const& session) = 0; virtual void added_prompt_provider( scene::PromptSession const& prompt_session, scene::Session const& session) = 0; virtual void stopping_prompt_session( scene::PromptSession const& prompt_session) = 0; virtual void adding_display(geometry::Rectangle const& area) = 0; virtual void removing_display(geometry::Rectangle const& area) = 0; virtual void input_focus_set_to( scene::Session const* focus_session, scene::Surface const* focus_surface) = 0; virtual void surfaces_raised(SurfaceSet const& surfaces) = 0; ShellReport() = default; virtual ~ShellReport() = default; ShellReport(ShellReport const&) = delete; ShellReport& operator=(ShellReport const&) = delete; }; } } #endif //MIR_SHELL_SHELL_REPORT_H ./include/server/mir/shell/surface_stack.h0000644000004100000410000000347713115234416021073 0ustar www-datawww-data/* * Copyright © 2013-15 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_SHELL_SURFACE_COORDINATOR_H_ #define MIR_SHELL_SURFACE_COORDINATOR_H_ #include #include namespace mir { namespace geometry { class Point; } namespace input { enum class InputReceptionMode; } namespace scene { class Surface; struct SurfaceCreationParameters; class SurfaceObserver; class Session; } namespace shell { class SurfaceStack { public: using SurfaceSet = std::set, std::owner_less>>; virtual void add_surface( std::shared_ptr const&, input::InputReceptionMode new_mode) = 0; virtual void raise(std::weak_ptr const& surface) = 0; virtual void raise(SurfaceSet const& surfaces) = 0; virtual void remove_surface(std::weak_ptr const& surface) = 0; virtual auto surface_at(geometry::Point) const -> std::shared_ptr = 0; protected: SurfaceStack() = default; virtual ~SurfaceStack() = default; SurfaceStack(SurfaceStack const&) = delete; SurfaceStack& operator=(SurfaceStack const&) = delete; }; } } #endif /* MIR_SHELL_SURFACE_COORDINATOR_H_ */ ./include/server/mir/shell/persistent_surface_store.h0000644000004100000410000000656713115234416023405 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_SHELL_PERSISTENT_SURFACE_STORE_H_ #define MIR_SHELL_PERSISTENT_SURFACE_STORE_H_ #include #include #include #include namespace mir { namespace scene { class Surface; } namespace shell { /** * A store for Surface information divorced from the lifetime of any given Session * * This provides the backing for persistent references to Surface objects, * both across client Sessions and across shell restarts, for features such as * surface position/size restoration. * * \todo Persistence across shell restarts is as-yet unimplemented. */ class PersistentSurfaceStore { public: class Id; virtual ~PersistentSurfaceStore() = default; /** * \brief Acquire ID for a Surface * \param [in] surface Surface to query or generate an ID for * \return The ID for this surface. * \note If \arg surface has not yet had an ID generated, this generates its ID. * \note This does not extend the lifetime of \arg surface. */ virtual Id id_for_surface(std::shared_ptr const& surface) = 0; /** * \brief Lookup Surface by ID. * \param [in] id ID of surface to lookup * \return The surface with ID \arg id. If this surface has been destroyed, * but the store retains a reference, returns nullptr. * \throws std::out_of_range if the store has no reference for a surface with \arg id. */ virtual std::shared_ptr surface_for_id(Id const& id) const = 0; }; } } namespace std { template<> struct hash; } namespace mir { namespace shell { class PersistentSurfaceStore::Id final { public: /** * \brief Generate a new, unique Id. */ Id(); /** * \brief Construct an Id from its serialized string form * \param serialized_form [in] The previously-serialized Id * \throw std::invalid_argument if \arg serialized_form is not parseable as an Id. */ Id(std::string const& serialized_form); Id(Id const& rhs); Id& operator=(Id const& rhs); bool operator==(Id const& rhs) const; /** * \brief Serialize to a UTF-8 string * \return A string representation of the Id; this is guaranteed to be valid UTF-8 */ std::string serialize_to_string() const; private: friend struct std::hash; uuid_t uuid; }; } } namespace std { template<> struct hash { typedef mir::shell::PersistentSurfaceStore::Id argument_type; typedef std::size_t result_type; result_type operator()(argument_type const& uuid) const; }; } #endif // MIR_SHELL_PERSISTENT_SURFACE_STORE_H_ ./include/server/mir/shell/window_manager.h0000644000004100000410000000562613115234664021262 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_SHELL_WINDOW_MANAGER_H_ #define MIR_SHELL_WINDOW_MANAGER_H_ #include "mir/frontend/surface_id.h" #include "mir_toolkit/common.h" #include "mir_toolkit/event.h" #include namespace mir { namespace geometry { struct Rectangle; } namespace scene { class Session; class Surface; struct SurfaceCreationParameters; } namespace shell { struct SurfaceSpecification; /// interface to provide window management logic class WindowManager { public: virtual void add_session(std::shared_ptr const& session) = 0; virtual void remove_session(std::shared_ptr const& session) = 0; virtual frontend::SurfaceId add_surface( std::shared_ptr const& session, scene::SurfaceCreationParameters const& params, std::function const& session, scene::SurfaceCreationParameters const& params)> const& build) = 0; virtual void modify_surface( std::shared_ptr const& session, std::shared_ptr const& surface, SurfaceSpecification const& modifications) = 0; virtual void remove_surface( std::shared_ptr const& session, std::weak_ptr const& surface) = 0; virtual void add_display(geometry::Rectangle const& area) = 0; virtual void remove_display(geometry::Rectangle const& area) = 0; virtual bool handle_keyboard_event(MirKeyboardEvent const* event) = 0; virtual bool handle_touch_event(MirTouchEvent const* event) = 0; virtual bool handle_pointer_event(MirPointerEvent const* event) = 0; virtual int set_surface_attribute( std::shared_ptr const& session, std::shared_ptr const& surface, MirWindowAttrib attrib, int value) = 0; virtual void handle_raise_surface( std::shared_ptr const& session, std::shared_ptr const& surface, uint64_t timestamp) = 0; virtual ~WindowManager() = default; WindowManager() = default; WindowManager(WindowManager const&) = delete; WindowManager& operator=(WindowManager const&) = delete; }; } } #endif /* MIR_SHELL_WINDOW_MANAGER_H_ */ ./include/server/mir/shell/display_configuration_controller.h0000644000004100000410000000401213115234664025104 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_SHELL_DISPLAY_CONFIGURATION_CONTROLLER_H_ #define MIR_SHELL_DISPLAY_CONFIGURATION_CONTROLLER_H_ #include namespace mir { namespace graphics { class DisplayConfiguration; } namespace shell { class DisplayConfigurationController { public: DisplayConfigurationController() = default; virtual ~DisplayConfigurationController() = default; DisplayConfigurationController(DisplayConfigurationController const&) = delete; DisplayConfigurationController& operator=(DisplayConfigurationController const&) = delete; /** * Set the base display configuration. * * This is the display configuration that is used by default, but will be * overridden by a client's requested configuration if that client is focused. * * \param [in] conf The new display configuration to set */ virtual void set_base_configuration( std::shared_ptr const& conf) = 0; /** * Get the base display configuration. * * This is the display configuration that is used by default, but will be * overridden by a client's requested configuration if that client is focused. */ virtual std::shared_ptr base_configuration() = 0; }; } } #endif //MIR_SHELL_DISPLAY_CONFIGURATION_CONTROLLER_H_ ./include/server/mir/shell/shell.h0000644000004100000410000000647713115234664017375 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_SHELL_SHELL_H_ #define MIR_SHELL_SHELL_H_ #include "mir/shell/focus_controller.h" #include "mir/input/event_filter.h" #include "mir/frontend/surface_id.h" #include "mir/compositor/display_listener.h" #include "mir_toolkit/common.h" #include namespace mir { namespace frontend { class EventSink; } namespace geometry { struct Rectangle; } namespace scene { class PromptSession; class PromptSessionManager; class PromptSessionCreationParameters; class SessionCoordinator; class Surface; struct SurfaceCreationParameters; } namespace shell { class InputTargeter; struct SurfaceSpecification; class SurfaceStack; class Shell : public virtual FocusController, public virtual input::EventFilter, public virtual compositor::DisplayListener { public: /** @name these functions support frontend requests * @{ */ virtual std::shared_ptr open_session( pid_t client_pid, std::string const& name, std::shared_ptr const& sink) = 0; virtual void close_session(std::shared_ptr const& session) = 0; virtual std::shared_ptr start_prompt_session_for( std::shared_ptr const& session, scene::PromptSessionCreationParameters const& params) = 0; virtual void add_prompt_provider_for( std::shared_ptr const& prompt_session, std::shared_ptr const& session) = 0; virtual void stop_prompt_session(std::shared_ptr const& prompt_session) = 0; virtual frontend::SurfaceId create_surface( std::shared_ptr const& session, scene::SurfaceCreationParameters const& params, std::shared_ptr const& sink) = 0; virtual void modify_surface( std::shared_ptr const& session, std::shared_ptr const& surface, shell::SurfaceSpecification const& modifications) = 0; virtual void destroy_surface(std::shared_ptr const& session, frontend::SurfaceId surface) = 0; virtual int set_surface_attribute( std::shared_ptr const& session, std::shared_ptr const& surface, MirWindowAttrib attrib, int value) = 0; virtual int get_surface_attribute( std::shared_ptr const& surface, MirWindowAttrib attrib) = 0; virtual void raise_surface( std::shared_ptr const& session, std::shared_ptr const& surface, uint64_t timestamp) = 0; /** @} */ }; } } #endif /* MIR_SHELL_SHELL_H_ */ ./include/server/mir/observer_registrar.h0000644000004100000410000000604013115234664021052 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_OBSERVER_REGISTRAR_H_ #define MIR_OBSERVER_REGISTRAR_H_ #include namespace mir { class Executor; /** * Register observers for a subsystem. * * \tparam Observer The Observer type to register */ template class ObserverRegistrar { public: /** * Add an observer to the set notified of all observations * * The ObserverRegistrar does not take any ownership of \p observer, and will * automatically remove it when \p observer expires. * * \param [in] observer The observer to register */ virtual void register_interest(std::weak_ptr const& observer) = 0; /** * Add an observer with specified execution environment * * This is threadsafe and can be called in any context. * * The ObserverRegistrar does not take any ownership of \p observer, and will * automatically remove it when \p observer expires. * * All calls to \p observer methods are performed in the context of * \p executor. * * The \p executor should process work in a delayed fashion. Particularly, * executor::spawn(work) is expected to \b not run \p work in the current * stack. Eager execution of work may result in deadlocks if calls to the * observer result in calls into the ObserverRegistrar. * * \param [in] observer The observer to register * \param [in] executor Execution environment for calls to \p observer methods. * The caller is responsible for ensuring \p executor outlives * \p observer. */ virtual void register_interest( std::weak_ptr const& observer, Executor& executor) = 0; /** * Remove an observer from the set notified of all observations. * * This is threadsafe and can be called in any context. * It is \b not guaranteed that methods of \p observer will not be called after * this returns. * * \param observer [in] The observer to unregister */ virtual void unregister_interest(Observer const& observer) = 0; protected: ObserverRegistrar() = default; virtual ~ObserverRegistrar() = default; ObserverRegistrar(ObserverRegistrar const&) = delete; ObserverRegistrar& operator=(ObserverRegistrar const&) = delete; }; } #endif //MIR_OBSERVER_REGISTRAR_H_ ./include/server/mir/graphics/0000755000004100000410000000000013115234677016574 5ustar www-datawww-data./include/server/mir/graphics/default_display_configuration_policy.h0000644000004100000410000000321013115234416026407 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_DEFAULT_DISPLAY_CONFIGURATION_POLICY_H_ #define MIR_GRAPHICS_DEFAULT_DISPLAY_CONFIGURATION_POLICY_H_ #include "mir/graphics/display_configuration_policy.h" namespace mir { namespace graphics { /** @name default DisplayConfigurationPolicy options. * Some simple default implementations: Mir will default to CloneDisplayConfigurationPolicy, * The others are plausible defaults for display servers that don't want to do anything * more sophisticated. * @{ */ /// All screens placed at (0, 0) class CloneDisplayConfigurationPolicy : public DisplayConfigurationPolicy { public: void apply_to(DisplayConfiguration& conf); }; /// Each screen placed to the right of the previous one class SideBySideDisplayConfigurationPolicy : public DisplayConfigurationPolicy { public: void apply_to(graphics::DisplayConfiguration& conf); }; /// Just use the first screen class SingleDisplayConfigurationPolicy : public DisplayConfigurationPolicy { public: void apply_to(graphics::DisplayConfiguration& conf); }; /** @} */ } } #endif /* MIR_GRAPHICS_DEFAULT_DISPLAY_CONFIGURATION_POLICY_H_ */ ./include/server/mir/graphics/display_configuration_observer.h0000644000004100000410000001112013115234664025237 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_GRAPHICS_DISPLAY_CONFIGURATION_OBSERVER_ #define MIR_GRAPHICS_DISPLAY_CONFIGURATION_OBSERVER_ #include #include namespace mir { namespace frontend { class Session; } namespace graphics { class DisplayConfiguration; class DisplayConfigurationObserver { public: /** * Notification of the initial display configuration. * * This is called exactly once, at server startup. * * \param [in] config The initial configuration */ virtual void initial_configuration(std::shared_ptr const& config) = 0; /** * Notification after every successful display configuration. * * This is called once per successful display configuration, after it has been applied * to the hardware. * * \param [in] config The configuration that has just been applied. */ virtual void configuration_applied(std::shared_ptr const& config) = 0; /** * Notification after updating base display configuration. * * \param [in] config The configuration that has just been updated. */ virtual void base_configuration_updated(std::shared_ptr const& base_config) = 0; /** * Notification after updating the session display configuration. * * \param [in] session The session that is updating its display configuration. * \param [in] config The configuration that is being applied to the session. */ virtual void session_configuration_applied(std::shared_ptr const& session, std::shared_ptr const& config) = 0; /** * Notification after removing the session display configuration. * * \param [in] session The session that is removing its display configuration. */ virtual void session_configuration_removed(std::shared_ptr const& session) = 0; /** * Notification after every failed display configuration attempt. * * This is called if the graphics platform throws an exception when trying * to configure the hardware. * * In this case the previous display configuration has been re-applied. * * \param [in] attempted The display configuration that failed to apply. * \param [in] error The exception thrown by the graphics platform. */ virtual void configuration_failed( std::shared_ptr const& attempted, std::exception const& error) = 0; /** * Notification after a failed display configuration with failed recovery. * * This is called if the graphics platform throws an exception when trying * to configure the hardware \b and has thrown an exception when trying * to re-apply the previous configuration. * * When this call is made it is unknown what state the display hardware is in, * but it's unlikely to be displaying any image to the user. * * As there is no sensible behaviour for Mir to have in this case, the shell * should respond to this either by trying to guess a safe configuration, * by switching to some other display mechanism, or by terminating. * * \param [in] failed_fallback The fallback display configuration that failed to apply. * \param error The exception thrown by the graphics platform. */ virtual void catastrophic_configuration_error( std::shared_ptr const& failed_fallback, std::exception const& error) = 0; protected: DisplayConfigurationObserver() = default; virtual ~DisplayConfigurationObserver() = default; DisplayConfigurationObserver(DisplayConfigurationObserver const&) = delete; DisplayConfigurationObserver& operator=(DisplayConfigurationObserver const&) = delete; }; } } #endif //MIR_GRAPHICS_DISPLAY_CONFIGURATION_OBSERVER_ ./include/server/mir/server_action_queue.h0000644000004100000410000000252213115234416021204 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_SERVER_ACTION_QUEUE_H_ #define MIR_SERVER_ACTION_QUEUE_H_ #include namespace mir { typedef std::function ServerAction; class ServerActionQueue { public: virtual ~ServerActionQueue() = default; virtual void enqueue(void const* owner, ServerAction const& action) = 0; virtual void pause_processing_for(void const* owner) = 0; virtual void resume_processing_for(void const* owner) = 0; protected: ServerActionQueue() = default; ServerActionQueue(ServerActionQueue const&) = delete; ServerActionQueue& operator=(ServerActionQueue const&) = delete; }; } #endif /* MIR_SERVER_ACTION_QUEUE_H_ */ ./include/server/mir/executor.h0000644000004100000410000000330713115234664017002 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_EXECUTOR_H_ #define MIR_EXECUTOR_H_ #include namespace mir { /** * An executor abstraction mostly compatible with C++ proposal N4414 * * As specified in http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0008r0.pdf * * This should hopefully be compatible with whatever the C++ Executors and Schedulers group * come up with as a final design, and will eventually be replaced by the standard version. * * If not, this minimal interface should be easy to implement on top of whatever emerges * from the standards body. */ class Executor { public: /** * Schedule some function to be called sometime in the future. * * It is expected that this \b not eagerly execute, and will return * \b before work() is executed. * * \param [in] work Function to execute in Executor specified environment. */ virtual void spawn(std::function&& work) = 0; protected: virtual ~Executor() = default; }; } #endif // MIR_EXECUTOR_H_ ./include/server/mir/input/0000755000004100000410000000000013115234677016133 5ustar www-datawww-data./include/server/mir/input/input_dispatcher.h0000644000004100000410000000257213115234416021646 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_INPUT_INPUT_DISPATCHER_H #define MIR_INPUT_INPUT_DISPATCHER_H #include #include "mir_toolkit/event.h" namespace mir { namespace input { /*! * \brief The InputDispatchers role is to decide what should happen with user input events. * * It will receive MirEvents with either MirMotionEvent or MirKeyboardEvent inside. The InputDispatcher * implementation shall either handle the input without informing any clients or pick a client * surface and send the event to it. */ class InputDispatcher { public: virtual bool dispatch(MirEvent const& event) = 0; virtual void start() = 0; virtual void stop() = 0; virtual ~InputDispatcher() = default; }; } } #endif ./include/server/mir/input/cursor_listener.h0000644000004100000410000000240013115234416021511 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_INPUT_CURSOR_LISTENER_H_ #define MIR_INPUT_CURSOR_LISTENER_H_ namespace mir { namespace input { /// An interface for listening to absolute cursor events (without context): For example to update /// the position of the visible cursor. class CursorListener { public: virtual ~CursorListener() = default; virtual void cursor_moved_to(float abs_x, float abs_y) = 0; protected: CursorListener() = default; CursorListener(CursorListener const&) = delete; CursorListener& operator=(CursorListener const&) = delete; }; } } #endif // MIR_INPUT_CURSOR_LISTENER_H_ ./include/server/mir/input/seat_observer.h0000644000004100000410000000324513115234664021147 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Brandon Schaefer */ #ifndef MIR_INPUT_SEAT_OBSERVER_H_ #define MIR_INPUT_SEAT_OBSERVER_H_ #include #include class MirEvent; namespace mir { namespace geometry { class Rectangles; class Rectangle; } namespace input { class SeatObserver { public: virtual ~SeatObserver() = default; virtual void seat_add_device(uint64_t id) = 0; virtual void seat_remove_device(uint64_t id) = 0; virtual void seat_dispatch_event(MirEvent const* event) = 0; virtual void seat_get_rectangle_for(uint64_t id, geometry::Rectangle const& out_rect) = 0; virtual void seat_set_key_state(uint64_t id, std::vector const& scan_codes) = 0; virtual void seat_set_pointer_state(uint64_t id, unsigned buttons) = 0; virtual void seat_set_cursor_position(float cursor_x, float cursor_y) = 0; virtual void seat_set_confinement_region_called(geometry::Rectangles const& regions) = 0; virtual void seat_reset_confinement_regions() = 0; }; } } #endif /* MIR_INPUT_SEAT_OBSERVER_H_ */ ./include/server/mir/input/cursor_images.h0000644000004100000410000000303713115234416021140 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_INPUT_CURSOR_IMAGES_H_ #define MIR_INPUT_CURSOR_IMAGES_H_ #include "mir/geometry/size.h" #include #include namespace mir { namespace graphics { class CursorImage; } namespace input { /// CursorImages is used to lookup cursor images from the system theme. geometry::Size const default_cursor_size{geometry::Width{24}, geometry::Height{24}}; class CursorImages { public: virtual ~CursorImages() = default; /// Looks up the image for a named cursor. Cursor names /// follow the XCursor naming conventions. virtual std::shared_ptr image(std::string const& cursor_name, geometry::Size const& size) = 0; protected: CursorImages() = default; CursorImages(CursorImages const&) = delete; CursorImages& operator=(CursorImages const&) = delete; }; } } #endif /* MIR_INPUT_CURSOR_IMAGES_H_ */ ./include/server/mir/input/device.h0000644000004100000410000000350113115234664017536 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_DEVICE_H_ #define MIR_INPUT_DEVICE_H_ #include "mir/input/device_capability.h" #include "mir_toolkit/event.h" #include "mir/optional_value.h" #include class MirPointerConfig; class MirTouchpadConfig; class MirKeyboardConfig; namespace mir { namespace input { class Device { public: Device() = default; virtual ~Device() = default; virtual MirInputDeviceId id() const = 0; virtual DeviceCapabilities capabilities() const = 0; virtual std::string name() const = 0; virtual std::string unique_id() const = 0; virtual mir::optional_value pointer_configuration() const = 0; virtual void apply_pointer_configuration(MirPointerConfig const&) = 0; virtual mir::optional_value touchpad_configuration() const = 0; virtual void apply_touchpad_configuration(MirTouchpadConfig const&) = 0; virtual optional_value keyboard_configuration() const = 0; virtual void apply_keyboard_configuration(MirKeyboardConfig const&) = 0; private: Device(Device const&) = delete; Device& operator=(Device const&) = delete; }; } } #endif ./include/server/mir/input/input_reception_mode.h0000644000004100000410000000162113115234416022506 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_INPUT_RECEPTION_MODE_H_ #define MIR_INPUT_RECEPTION_MODE_H_ namespace mir { namespace input { enum class InputReceptionMode { normal, receives_all_input }; } } #endif /* MIR_INPUT_RECEPTION_MODE_H_ */ ./include/server/mir/input/event_filter.h0000644000004100000410000000225713115234416020767 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_INPUT_EVENT_FILTER_H_ #define MIR_INPUT_EVENT_FILTER_H_ #include "mir_toolkit/event.h" namespace mir { namespace input { class EventFilter { public: virtual ~EventFilter() = default; // \return true indicates the event was consumed by the filter virtual bool handle(MirEvent const& event) = 0; protected: EventFilter() = default; EventFilter(const EventFilter&) = delete; EventFilter& operator=(const EventFilter&) = delete; }; } } #endif // MIR_INPUT_EVENT_FILTER_H_ ./include/server/mir/input/input_manager.h0000644000004100000410000000232113115234664021127 0ustar www-datawww-data/* * Copyright © 2012, 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr * Daniel d'Andradra * Andreas Pokorny */ #ifndef MIR_INPUT_INPUT_MANAGER_H_ #define MIR_INPUT_INPUT_MANAGER_H_ namespace mir { namespace input { class InputManager { public: virtual void start() = 0; virtual void stop() = 0; protected: InputManager() {}; virtual ~InputManager() {} InputManager(const InputManager&) = delete; InputManager& operator=(const InputManager&) = delete; }; } } #endif // MIR_INPUT_INPUT_MANAGER ./include/server/mir/input/input_device_hub.h0000644000004100000410000000273113115234664021617 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_INPUT_INPUT_DEVICE_HUB_H_ #define MIR_INPUT_INPUT_DEVICE_HUB_H_ #include namespace mir { namespace input { class Device; class InputDeviceInfo; class InputDeviceObserver; class InputDeviceHub { public: InputDeviceHub() = default; virtual ~InputDeviceHub() = default; virtual void add_observer(std::shared_ptr const&) = 0; virtual void remove_observer(std::weak_ptr const&) = 0; virtual void for_each_input_device(std::function const& callback) = 0; virtual void for_each_mutable_input_device(std::function const& callback) = 0; InputDeviceHub(InputDeviceHub const&) = delete; InputDeviceHub& operator=(InputDeviceHub const&) = delete; }; } } #endif ./include/server/mir/input/touch_visualizer.h0000644000004100000410000000351313115234416021674 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_INPUT_TOUCH_VISUALIZER_H_ #define MIR_INPUT_TOUCH_VISUALIZER_H_ #include "mir/geometry/point.h" #include namespace mir { namespace input { /// An interface for listening to a low level stream of touches, in order to provide // a "spot" style visualization. class TouchVisualizer { public: virtual ~TouchVisualizer() = default; struct Spot { geometry::Point touch_location; // If pressure is zero, the touch-point can be interpreted as a hover. float pressure; }; // Toggle visualization of touches virtual void enable() = 0; virtual void disable() = 0; // Visualize a given set of touches statelessly. virtual void visualize_touches(std::vector const& touches) = 0; protected: TouchVisualizer() = default; TouchVisualizer(const TouchVisualizer&) = delete; TouchVisualizer& operator=(const TouchVisualizer&) = delete; }; inline bool operator==(TouchVisualizer::Spot const &lhs, TouchVisualizer::Spot const& rhs) { return lhs.touch_location == rhs.touch_location && lhs.pressure == rhs.pressure; } } } #endif // MIR_INPUT_TOUCH_VISUALIZER_H_ ./include/server/mir/input/input_channel.h0000644000004100000410000000230113115234416021116 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_INPUT_INPUT_CHANNEL_H_ #define MIR_INPUT_INPUT_CHANNEL_H_ namespace mir { namespace input { /// Encapsulates a paired set of fd's suitable for input communication. class InputChannel { public: virtual ~InputChannel() {} virtual int client_fd() const = 0; virtual int server_fd() const = 0; protected: InputChannel() = default; InputChannel(InputChannel const&) = delete; InputChannel& operator=(InputChannel const&) = delete; }; } } // namespace mir #endif // MIR_INPUT_INPUT_CHANNEL_H_ ./include/server/mir/input/input_device_observer.h0000644000004100000410000000265213115234416022665 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_INPUT_INPUT_DEVICE_OBSERVER_H_ #define MIR_INPUT_INPUT_DEVICE_OBSERVER_H_ #include namespace mir { namespace input { class Device; class InputDeviceObserver { public: InputDeviceObserver() = default; virtual ~InputDeviceObserver() = default; virtual void device_added(std::shared_ptr const& device) = 0; virtual void device_changed(std::shared_ptr const& device) = 0; virtual void device_removed(std::shared_ptr const& device) = 0; /*! * Called after every group of changes. */ virtual void changes_complete() = 0; InputDeviceObserver(InputDeviceObserver const&) = delete; InputDeviceObserver& operator=(InputDeviceObserver const&) = delete; }; } } #endif ./include/server/mir/input/composite_event_filter.h0000644000004100000410000000217313115234416023046 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_INPUT_COMPOSITE_EVENT_FILTER_H_ #define MIR_INPUT_COMPOSITE_EVENT_FILTER_H_ #include "mir/input/event_filter.h" #include namespace mir { namespace input { class CompositeEventFilter : public EventFilter { public: virtual void append(std::shared_ptr const& filter) = 0; virtual void prepend(std::shared_ptr const& filter) = 0; }; } } #endif /* MIR_INPUT_COMPOSITE_EVENT_FILTER_H_ */ ./include/server/mir/input/surface.h0000644000004100000410000000331513115234416017725 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_INPUT_SURFACE_H_ #define MIR_INPUT_SURFACE_H_ #include "mir/geometry/point.h" #include "mir/geometry/rectangle.h" #include "mir/input/input_reception_mode.h" #include "mir_toolkit/event.h" #include #include namespace mir { namespace graphics { class CursorImage; } namespace scene { class SurfaceObserver; } namespace input { class InputChannel; class Surface { public: virtual std::string name() const = 0; virtual geometry::Rectangle input_bounds() const = 0; virtual bool input_area_contains(geometry::Point const& point) const = 0; virtual std::shared_ptr input_channel() const = 0; virtual std::shared_ptr cursor_image() const = 0; virtual InputReceptionMode reception_mode() const = 0; virtual void consume(MirEvent const* event) = 0; protected: Surface() = default; virtual ~Surface() = default; Surface(const Surface&) = delete; Surface& operator=(const Surface& ) = delete; }; } } #endif /* MIR_INPUT_SURFACE_H_ */ ./include/server/mir/time/0000755000004100000410000000000013115234677015732 5ustar www-datawww-data./include/server/mir/time/alarm_factory.h0000644000004100000410000000455113115234664020727 0ustar www-datawww-data/* * Copyright © 2014-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers * Alberto Aguirre */ #ifndef MIR_TIME_ALARM_FACTORY_H_ #define MIR_TIME_ALARM_FACTORY_H_ #include "mir/time/alarm.h" #include #include #include namespace mir { class LockableCallback; namespace time { class Alarm; class AlarmFactory { public: virtual ~AlarmFactory() = default; /** * \brief Create an Alarm that will not fire until scheduled * * \param callback Function to call when the Alarm signals * * \return A handle to an Alarm that can later be scheduled */ virtual std::unique_ptr create_alarm(std::function const& callback) = 0; /** * \brief Create an Alarm that will not fire until scheduled * * A LockableCallback allows the user to preserve lock ordering * in situations where Alarm methods need to be called under external lock * and the callback implementation needs to run code protected by the same * lock. An alarm implementation may have internal locks of its own, which * maybe acquired during callback dispatching; to preserve lock ordering * LockableCallback::lock is invoked during callback dispatch before * any internal locks are acquired. * * \param callback Function to call when the Alarm signals * \return A handle to an Alarm that can later be scheduled */ virtual std::unique_ptr create_alarm(std::unique_ptr callback) = 0; protected: AlarmFactory() = default; AlarmFactory(AlarmFactory const&) = delete; AlarmFactory& operator=(AlarmFactory const&) = delete; }; } } #endif // MIR_TIME_ALARM_FACTORY_H_ ./include/server/mir/time/alarm.h0000644000004100000410000000475513115234416017201 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_TIME_ALARM_H_ #define MIR_TIME_ALARM_H_ #include "mir/time/types.h" namespace mir { namespace time { /** * A one-shot, resettable handle to trigger a callback at a later time * \note All members of Alarm are threadsafe * \note All members of Alarm are safe to call from the Alarm's callback */ class Alarm { public: enum State { pending, /**< Will trigger the callback at some point in the future */ cancelled, /**< The callback has been cancelled before being triggered */ triggered /**< The callback has been called */ }; Alarm() = default; /** * \note Destruction of the Alarm guarantees that the callback will not subsequently be called */ virtual ~Alarm() = default; /** * Cancels a pending alarm * * \note Has no effect if the Alarm is in the Triggered state. * \note cancel() is idempotent * * \return True iff the state of the Alarm is now Cancelled */ virtual bool cancel() = 0; virtual State state() const = 0; /** * Reschedule the alarm * \param delay Delay, in milliseconds, before the Alarm will be triggered * \return True if this reschedule supersedes a previous not-yet-triggered timeout * * \note This cancels any previous timeout set. */ virtual bool reschedule_in(std::chrono::milliseconds delay) = 0; /** * Reschedule the alarm * \param timeout Time point when the alarm should be triggered * \return True if this reschedule supersedes a previous not-yet-triggered timeout * * \note This cancels any previous timeout set. */ virtual bool reschedule_for(Timestamp timeout) = 0; Alarm(Alarm const&) = delete; Alarm& operator=(Alarm const&) = delete; }; } } #endif ./include/server/mir/server.h0000644000004100000410000004664213115234664016463 0ustar www-datawww-data/* * Copyright © 2014-2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored By: Alan Griffiths */ #ifndef MIR_SERVER_H_ #define MIR_SERVER_H_ #include "mir/shell/window_manager_builder.h" #include "mir_toolkit/common.h" #include #include #include namespace mir { template class ObserverRegistrar; namespace compositor { class Compositor; class DisplayBufferCompositorFactory; class CompositorReport; } namespace frontend { class SessionAuthorizer; class Session; class SessionMediatorObserver; } namespace graphics { class Cursor; class Platform; class Display; class GLConfig; class DisplayConfigurationPolicy; class DisplayConfigurationObserver; } namespace input { class CompositeEventFilter; class InputDispatcher; class CursorListener; class CursorImages; class TouchVisualizer; class InputDeviceHub;} namespace logging { class Logger; } namespace options { class Option; } namespace cookie { using Secret = std::vector; class Authority; } namespace shell { class DisplayLayout; class DisplayConfigurationController; class FocusController; class HostLifecycleEventListener; class InputTargeter; class PersistentSurfaceStore; class Shell; class SurfaceStack; } namespace scene { class ApplicationNotRespondingDetector; class BufferStreamFactory; class PromptSessionListener; class PromptSessionManager; class SessionListener; class SessionCoordinator; class SurfaceFactory; class CoordinateTranslator; } namespace input { class SeatObserver; } class Fd; class MainLoop; class ServerStatusListener; enum class OptionType { null, integer, string, boolean }; /// Customise and run a Mir server. class Server { public: Server(); /** @name Essential operations * These are the commands used to run and stop. * @{ */ /// set the command line. /// This must remain valid while apply_settings() and run() are called. void set_command_line(int argc, char const* argv[]); /// Applies any configuration options, hooks, or custom implementations. /// Must be called before calling run() or accessing any mir subsystems. void apply_settings(); /// The pixel formats that may be used when creating surfaces auto supported_pixel_formats() const -> std::vector; /// Run the Mir server until it exits void run(); /// Tell the Mir server to exit void stop(); /// returns true if and only if server exited normally. Otherwise false. bool exited_normally(); /** @} */ /** @name Configuration options * These functions allow customization of the handling of configuration * options. The add and set functions should be called before apply_settings() * otherwise they throw a std::logic_error. * @{ */ /// Add user configuration option(s) to Mir's option handling. /// These will be resolved during initialisation from the command line, /// environment variables, a config file or the supplied default. void add_configuration_option( std::string const& option, std::string const& description, int default_value); /// Add user configuration option(s) to Mir's option handling. /// These will be resolved during initialisation from the command line, /// environment variables, a config file or the supplied default. void add_configuration_option( std::string const& option, std::string const& description, double default_value); /// Add user configuration option(s) to Mir's option handling. /// These will be resolved during initialisation from the command line, /// environment variables, a config file or the supplied default. void add_configuration_option( std::string const& option, std::string const& description, std::string const& default_value); /// Add user configuration option(s) to Mir's option handling. /// These will be resolved during initialisation from the command line, /// environment variables, a config file or the supplied default. void add_configuration_option( std::string const& option, std::string const& description, char const* default_value); /// Add user configuration option(s) to Mir's option handling. /// These will be resolved during initialisation from the command line, /// environment variables, a config file or the supplied default. void add_configuration_option( std::string const& option, std::string const& description, bool default_value); /// Add user configuration option(s) to Mir's option handling. /// These will be resolved during initialisation from the command line, /// environment variables, a config file or the supplied default. void add_configuration_option( std::string const& option, std::string const& description, OptionType type); /// Set a handler for any command line options Mir does not recognise. /// This will be invoked if any unrecognised options are found during initialisation. /// Any unrecognised arguments are passed to this function. The pointers remain valid /// for the duration of the call only. /// If set_command_line_handler is not called the default action is to exit by /// throwing mir::AbnormalExit (which will be handled by the exception handler prior to /// exiting run(). void set_command_line_handler( std::function const& command_line_hander); /// Set the configuration filename. /// This will be searched for and parsed in the standard locations. Vis: /// 1. $XDG_CONFIG_HOME (if set, otherwise $HOME/.config (if set)) /// 2. $XDG_CONFIG_DIRS (if set, otherwise /etc/xdg) void set_config_filename(std::string const& config_file); /// Returns the configuration options. /// This will be null before initialization starts. It will be available /// when the init_callback has been invoked (and thereafter until the server exits). auto get_options() const -> std::shared_ptr; /** @} */ /** @name Using hooks into the run() logic * These allow the user to insert logic into startup or error handling. * For obvious reasons they should be called before run(). * @{ */ /// Add a callback to be invoked when the settings have been applied, but before /// the server has been initialized. This allows client code to get access Mir objects. /// If multiple callbacks are added they will be invoked in the sequence added. void add_pre_init_callback(std::function const& pre_init_callback); /// Add a callback to be invoked when the server has been initialized, /// but before it starts. This allows client code to get access Mir objects. /// If multiple callbacks are added they will be invoked in the sequence added. void add_init_callback(std::function const& init_callback); /// Add a callback to be invoked when the server is about to stop, /// If multiple callbacks are added they will be invoked in the reverse sequence added. void add_stop_callback(std::function const& stop_callback); /// Set a handler for exceptions. This is invoked in a catch (...) block and /// the exception can be re-thrown to retrieve type information. /// The default action is to call mir::report_exception(std::cerr) void set_exception_handler(std::function const& exception_handler); /// Functor for processing SIGTERM or SIGINT /// This will not be called directly by a signal handler: arbitrary functions may be invoked. using Terminator = std::function; /// Set handler for termination requests. /// terminator will be called following receipt of SIGTERM or SIGINT. /// The default terminator stop()s the server, replacements should probably /// do the same in addition to any additional shutdown logic. void set_terminator(Terminator const& terminator); /// Functor for processing fatal signals for any "emergency cleanup". /// That is: SIGQUIT, SIGABRT, SIGFPE, SIGSEGV & SIGBUS /// /// \warning This will be called directly by a signal handler: /// Only async-signal-safe functions may be called using EmergencyCleanupHandler = std::function; /// Add cleanup for abnormal terminations. /// handler will be called on receipt of a fatal signal after which the /// default signal-handler will terminate the process. void add_emergency_cleanup(EmergencyCleanupHandler const& handler); /** @} */ /** @name Providing custom implementation * Provide alternative implementations of Mir subsystems: the functors will be invoked * during initialization of the Mir server (or when accessor methods are called). * They should be called before apply_settings() otherwise they throw a std::logic_error. * @{ */ /// Each of the override functions takes a builder functor of the same form /// \note If a null pointer is returned by the builder the default is used instead. template using Builder = std::function()>; /// Sets an override functor for creating the compositor. void override_the_compositor(Builder const& compositor_builder); /// Sets an override functor for creating the cursor images. void override_the_cursor_images(Builder const& cursor_images_builder); /// Sets an override functor for creating the per-display rendering code. void override_the_display_buffer_compositor_factory( Builder const& compositor_builder); /// Sets an override functor for creating the gl config. void override_the_gl_config(Builder const& gl_config_builder); /// Sets an override functor for creating the cookie authority. /// A secret can be saved and any process this secret is shared /// with can verify Mir-generated cookies, or produce their own. void override_the_cookie_authority(Builder const& cookie_authority_builder); /// Sets an override functor for creating the coordinate translator. void override_the_coordinate_translator( Builder const& coordinate_translator_builder); /// Sets an override functor for creating the host lifecycle event listener. void override_the_host_lifecycle_event_listener( Builder const& host_lifecycle_event_listener_builder); /// Sets an override functor for creating the input dispatcher. void override_the_input_dispatcher(Builder const& input_dispatcher_builder); /// Sets an override functor for creating the logger. void override_the_logger(Builder const& logger_builder); /// Sets an override functor for creating the prompt session listener. void override_the_prompt_session_listener(Builder const& prompt_session_listener_builder); /// Sets an override functor for creating the prompt session manager. void override_the_prompt_session_manager(Builder const& prompt_session_manager_builder); /// Sets an override functor for creating the status listener. void override_the_server_status_listener(Builder const& server_status_listener_builder); /// Sets an override functor for creating the session authorizer. void override_the_session_authorizer(Builder const& session_authorizer_builder); /// Sets an override functor for creating the session listener. void override_the_session_listener(Builder const& session_listener_builder); /// Sets an override functor for creating the shell. void override_the_shell(Builder const& wrapper); /// Sets an override functor for creating the window manager. void override_the_window_manager_builder(shell::WindowManagerBuilder const wmb); /// Sets an override functor for creating the application not responding detector. void override_the_application_not_responding_detector( Builder const& anr_detector_builder); /// Sets an override functor for creating the persistent_surface_store void override_the_persistent_surface_store(Builder const& persistent_surface_store); /// Each of the wrap functions takes a wrapper functor of the same form template using Wrapper = std::function(std::shared_ptr const&)>; /// Sets a wrapper functor for creating the cursor. void wrap_cursor(Wrapper const& cursor_builder); /// Sets a wrapper functor for creating the cursor listener. void wrap_cursor_listener(Wrapper const& wrapper); /// Sets a wrapper functor for creating the per-display rendering code. void wrap_display_buffer_compositor_factory( Wrapper const& wrapper); /// Sets a wrapper functor for creating the display configuration policy. void wrap_display_configuration_policy(Wrapper const& wrapper); /// Sets a wrapper functor for creating the shell. void wrap_shell(Wrapper const& wrapper); /// Sets a wrapper functor for creating the surface stack. void wrap_surface_stack(Wrapper const& surface_stack); /// Sets a wrapper functor for creating the application not responding detector. void wrap_application_not_responding_detector(Wrapper const & anr_detector); /** @} */ /** @name Getting access to Mir subsystems * These may be invoked by the functors that provide alternative implementations of * Mir subsystems. * They should only be used after apply_settings() is called - otherwise they throw * a std::logic_error. * @{ */ /// \return the compositor. auto the_compositor() const -> std::shared_ptr; /// \return the compositor report. auto the_compositor_report() const -> std::shared_ptr; /// \return the composite event filter. auto the_composite_event_filter() const -> std::shared_ptr; /// \return the cursor listener. auto the_cursor_listener() const -> std::shared_ptr; /// \return the cursor auto the_cursor() const -> std::shared_ptr; /// \return the focus controller. auto the_focus_controller() const -> std::shared_ptr; /// \return the graphics display. auto the_display() const -> std::shared_ptr; auto the_display_configuration_controller() const -> std::shared_ptr; /// \return the GL config. auto the_gl_config() const -> std::shared_ptr; /// \return the graphics platform. auto the_graphics_platform() const -> std::shared_ptr; /// \return the input targeter. auto the_input_targeter() const -> std::shared_ptr; /// \return the logger. auto the_logger() const -> std::shared_ptr; /// \return the main loop. auto the_main_loop() const -> std::shared_ptr; /// \return the prompt session listener. auto the_prompt_session_listener() const -> std::shared_ptr; /// \return the prompt session manager. auto the_prompt_session_manager() const ->std::shared_ptr; /// \return the session authorizer. auto the_session_authorizer() const -> std::shared_ptr; /// \return the session coordinator. auto the_session_coordinator() const -> std::shared_ptr; /// \return the session listener. auto the_session_listener() const -> std::shared_ptr; /// \return the shell. auto the_shell() const -> std::shared_ptr; /// \return the display layout. auto the_shell_display_layout() const -> std::shared_ptr; /// \return the buffer stream factory auto the_buffer_stream_factory() const -> std::shared_ptr; /// \return the surface factory auto the_surface_factory() const -> std::shared_ptr; /// \return the surface stack. auto the_surface_stack() const -> std::shared_ptr; /// \return the touch visualizer. auto the_touch_visualizer() const -> std::shared_ptr; /// \return the input device hub auto the_input_device_hub() const -> std::shared_ptr; /// \return the application not responding detector auto the_application_not_responding_detector() const -> std::shared_ptr; /// \return the persistent surface store auto the_persistent_surface_store() const -> std::shared_ptr; /// \return a registrar to add and remove DisplayConfigurationChangeObservers auto the_display_configuration_observer_registrar() const -> std::shared_ptr>; /// \return a registrar to add and remove SeatObservers auto the_seat_observer_registrar() const -> std::shared_ptr>; /// \return a registrar to add and remove SessionMediatorObservers auto the_session_mediator_observer_registrar() const -> std::shared_ptr>; /** @} */ /** @name Client side support * These facilitate use of the server through the client API. * They should be called while the server is running (i.e. run() has been called and * not exited) otherwise they throw a std::logic_error. * @{ */ using ConnectHandler = std::function const& session)>; /// Get a file descriptor that can be used to connect a client /// It can be passed to another process, or used directly with mir_connect() /// using the format "fd://%d". auto open_client_socket() -> Fd; /// Get a file descriptor that can be used to connect a client /// It can be passed to another process, or used directly with mir_connect() /// using the format "fd://%d". /// \param connect_handler callback to be invoked when the client connects auto open_client_socket(ConnectHandler const& connect_handler) -> Fd; /// Get a file descriptor that can be used to connect a prompt provider /// It can be passed to another process, or used directly with mir_connect() /// using the format "fd://%d". auto open_prompt_socket() -> Fd; /** @} */ private: struct ServerConfiguration; struct Self; std::shared_ptr const self; }; } #endif /* SERVER_H_ */ ./include/server/mir/lockable_callback.h0000644000004100000410000000221413115234416020523 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Alberto Aguirre */ #ifndef MIR_LOCKABLE_CALLBACK_H_ #define MIR_LOCKABLE_CALLBACK_H_ namespace mir { class LockableCallback { public: virtual ~LockableCallback() = default; virtual void operator()() = 0; virtual void lock() = 0; virtual void unlock() = 0; protected: LockableCallback() = default; LockableCallback(LockableCallback const&) = delete; LockableCallback& operator=(LockableCallback const&) = delete; }; } #endif /* MIR_LOCKABLE_CALLBACK_H_ */ ./include/common/0000755000004100000410000000000013115234677014167 5ustar www-datawww-data./include/common/mir/0000755000004100000410000000000013115234677014756 5ustar www-datawww-data./include/common/mir/flags.h0000644000004100000410000001064313115234664016223 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored By: Andreas Pokorny */ #ifndef MIR_FLAGS_H_ #define MIR_FLAGS_H_ #include namespace mir { /*! * Treat an enumeration, scoped and unscoped, like a set of flags. * * For scoped enumerations, there are optional bitwise operators available * that can be enabled by declaring a function within the namespace of the * enumeration (here Enum): * \code * Enum mir_enable_enum_bit_operators(Enum); * \endcode */ template struct Flags { using value_type = typename std::underlying_type::type; explicit constexpr Flags(value_type flag_value = 0) noexcept : flag_value{flag_value} {} constexpr Flags(Enum flag_value) noexcept : flag_value{static_cast(flag_value)} {} constexpr Flags operator|(Flags other) const noexcept { return Flags(flag_value|other.flag_value); } constexpr Flags operator&(Flags other) const noexcept { return Flags(flag_value & other.flag_value); } constexpr Flags operator^(Flags other) const noexcept { return Flags(flag_value ^ other.flag_value); } // those mutating operators could be trated as constexpr with c++14 Flags& operator|=(Flags other) noexcept { flag_value |= other.flag_value; return *this; } Flags operator&=(Flags other) noexcept { flag_value &= other.flag_value; return *this; } Flags operator^=(Flags other) noexcept { flag_value ^= other.flag_value; return *this; } constexpr bool operator==(Flags other) const noexcept { return flag_value == other.flag_value; } constexpr bool operator!=(Flags other) const noexcept { return flag_value != other.flag_value; } constexpr value_type value() const noexcept { return flag_value; } private: value_type flag_value; }; template constexpr Flags operator|(Flags flags, Enum e) noexcept { return Flags(flags.value() | static_cast(e)); } template constexpr Flags operator|(Enum e, Flags flags) noexcept { return Flags(flags.value() | static_cast(e)); } template constexpr Enum operator&(Enum e, Flags flags) noexcept { return static_cast(flags.value() & static_cast(e)); } template constexpr Enum operator&(Flags flags, Enum e) noexcept { return static_cast(flags.value() & static_cast(e)); } template constexpr bool operator==(Flags flags, Enum e) noexcept { return e == static_cast(flags.value()); } template constexpr bool operator==(Enum e, Flags flags) noexcept { return e == static_cast(flags.value()); } template constexpr bool contains(Flags flags, Enum e) noexcept { return e == static_cast(flags.value() & static_cast(e)); } } template constexpr mir::Flags(0)))> operator|(Enum lhs, Enum rhs) noexcept { return mir::Flags(lhs) | mir::Flags(rhs); } template constexpr mir::Flags(0)))> operator&(Enum lhs, Enum rhs) noexcept { return mir::Flags(lhs) & mir::Flags(rhs); } template constexpr mir::Flags(0)))> operator^(Enum lhs, Enum rhs) noexcept { return mir::Flags(lhs) ^ mir::Flags(rhs); } #endif ./include/common/mir/events/0000755000004100000410000000000013115234665016257 5ustar www-datawww-data./include/common/mir/events/contact_state.h0000644000004100000410000000301213115234664021256 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Andreas Pokorny */ #ifndef MIR_EVENTS_CONTACT_STATE_H_ #define MIR_EVENTS_CONTACT_STATE_H_ #include "mir_toolkit/event.h" namespace mir { namespace events { struct ContactState { MirTouchId touch_id; MirTouchAction action; MirTouchTooltype tooltype; float x; float y; float pressure; float touch_major; float touch_minor; float orientation; }; inline bool operator==(ContactState const& lhs, ContactState const & rhs) { return lhs.touch_id == rhs.touch_id && lhs.action == rhs.action && lhs.tooltype == rhs.tooltype && lhs.x == rhs.x && lhs.y == rhs.y && lhs.pressure == rhs.pressure && lhs.touch_major == rhs.touch_major && lhs.touch_minor == rhs.touch_minor && lhs.orientation == rhs.orientation; } } } #endif // MIR_EVENTS_CONTACT_STATE_H_ ./include/common/mir/events/input_device_state.h0000644000004100000410000000201313115234664022301 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Andreas Pokorny */ #ifndef MIR_INPUT_DEVICE_STATE_H_ #define MIR_INPUT_DEVICE_STATE_H_ #include "mir_toolkit/event.h" #include namespace mir { namespace events { struct InputDeviceState { MirInputDeviceId id; std::vector pressed_keys; MirPointerButtons buttons; }; } } #endif // MIR_INPUT_DEVICE_STATE_H_ ./include/common/mir/frontend/0000755000004100000410000000000013115234420016557 5ustar www-datawww-data./include/common/mir/frontend/surface_id.h0000644000004100000410000000177013115234416021046 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_FRONTEND_SURFACE_ID_H_ #define MIR_FRONTEND_SURFACE_ID_H_ #include "mir/int_wrapper.h" namespace mir { namespace frontend { namespace detail { struct SessionsSurfaceIdTag; } typedef IntWrapper SurfaceId; } } // namespace mir #endif // MIR_FRONTEND_SURFACE_ID_H_ ./include/common/mir/frontend/buffer_stream_id.h0000644000004100000410000000203113115234416022231 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_FRONTEND_BUFFER_STREAM_ID_H_ #define MIR_FRONTEND_BUFFER_STREAM_ID_H_ #include "mir/int_wrapper.h" namespace mir { namespace frontend { namespace detail { struct SessionsBufferStreamIdTag; } typedef IntWrapper BufferStreamId; } } // namespace mir #endif // MIR_FRONTEND_BUFFER_STREAM_ID_H_ ./include/common/mir/module_deleter.h0000644000004100000410000000530213115234416020107 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_MODULE_DELETER_H_ #define MIR_MODULE_DELETER_H_ #include namespace mir { class SharedLibrary; namespace detail { class RefCountedLibrary { public: RefCountedLibrary(void* address); RefCountedLibrary(RefCountedLibrary const&); ~RefCountedLibrary(); RefCountedLibrary& operator=(RefCountedLibrary const&); private: std::shared_ptr internal_state; }; } template struct ModuleDeleter : std::default_delete { ModuleDeleter() : library(nullptr) {} template ModuleDeleter(ModuleDeleter const& other) : std::default_delete{other}, library{other.get_library()} { } detail::RefCountedLibrary get_library() const { return library; } protected: ModuleDeleter(void *address_in_module) : library{address_in_module} { } private: detail::RefCountedLibrary library; }; /*! * \brief Use UniqueModulePtr to ensure that your loadable libray outlives * instances created within it. * * Use mir::make_module_ptr(...) or pass a function from your library to the * constructor, to increase the lifetime of your library: * \code * mir::UniqueModulePtr library_entry_point() * { * return mir::UniqueModulePtr(new Implementation, &library_entry_point); * } * \endcode * * The default constructor will not try to infer the dynamic library. */ template using UniqueModulePtr = std::unique_ptr>; namespace { /*! * \brief make_unique like creation function for UniqueModulePtr */ template inline auto make_module_ptr(Args&&... args) -> UniqueModulePtr { struct Deleter : ModuleDeleter { Deleter(void* address) : ModuleDeleter(address) {} } deleter(reinterpret_cast(&make_module_ptr)); return UniqueModulePtr(new Type(std::forward(args)...), std::move(deleter)); } } } #endif ./include/common/mir/assert_module_entry_point.h0000644000004100000410000000211413115234416022414 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_ASSERT_MODULE_ENTRY_POINT_H_ #define MIR_ASSERT_MODULE_ENTRY_POINT_H_ #include namespace mir { template void assert_entry_point_signature(EntryPoint) { static_assert(std::is_same::value, "Signature of platform entry point does not match."); } } #endif ./include/common/mir/shared_library.h0000644000004100000410000000366313115234416020120 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_SHARED_LIBRARY_H_ #define MIR_SHARED_LIBRARY_H_ #include namespace mir { class SharedLibrary { public: explicit SharedLibrary(char const* library_name); explicit SharedLibrary(std::string const& library_name); ~SharedLibrary() noexcept; template FunctionPtr load_function(char const* function_name) const { FunctionPtr result{}; (void*&)result = load_symbol(function_name); return result; } template FunctionPtr load_function(std::string const& function_name) const { return load_function(function_name.c_str()); } template FunctionPtr load_function(std::string const& function_name, std::string const& version) const { FunctionPtr result{}; (void*&)result = load_symbol(function_name.c_str(), version.c_str()); return result; } private: void* const so; void* load_symbol(char const* function_name) const; void* load_symbol(char const* function_name, char const* version) const; SharedLibrary(SharedLibrary const&) = delete; SharedLibrary& operator=(SharedLibrary const&) = delete; }; } #endif /* MIR_SHARED_LIBRARY_H_ */ ./include/common/mir/dispatch/0000755000004100000410000000000013115234677016555 5ustar www-datawww-data./include/common/mir/dispatch/multiplexing_dispatchable.h0000644000004100000410000000672113115234664024154 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_DISPATCH_MULTIPLEXING_DISPATCHABLE_H_ #define MIR_DISPATCH_MULTIPLEXING_DISPATCHABLE_H_ #include "mir/dispatch/dispatchable.h" #include "mir/posix_rw_mutex.h" #include #include #include #include #include namespace mir { namespace dispatch { /** * \brief How concurrent dispatch should be handled */ enum class DispatchReentrancy { sequential, /**< The dispatch function is guaranteed not to be called * while a thread is currently running it. */ reentrant /**< The dispatch function may be called on multiple threads * simultaneously */ }; /** * \brief An adaptor that combines multiple Dispatchables into a single Dispatchable * \note Instances are fully thread-safe. */ class MultiplexingDispatchable final : public Dispatchable { public: MultiplexingDispatchable(); MultiplexingDispatchable(std::initializer_list> dispatchees); virtual ~MultiplexingDispatchable() noexcept; MultiplexingDispatchable& operator=(MultiplexingDispatchable const&) = delete; MultiplexingDispatchable(MultiplexingDispatchable const&) = delete; Fd watch_fd() const override; bool dispatch(FdEvents events) override; FdEvents relevant_events() const override; /** * \brief Add a dispatchable to the adaptor * \param [in] dispatchee Dispatchable to add. The Dispatchable's dispatch() * function will not be called reentrantly. */ void add_watch(std::shared_ptr const& dispatchee); /** * \brief Add a dispatchable to the adaptor, specifying the reentrancy of dispatch() */ void add_watch(std::shared_ptr const& dispatchee, DispatchReentrancy reentrancy); /** * \brief Add a simple callback to the adaptor * \param [in] fd File descriptor to monitor for readability * \param [in] callback Callback to fire when \p fd becomes readable. * This callback is not called reentrantly. */ void add_watch(Fd const& fd, std::function const& callback); /** * \brief Remove a watch from the dispatchable * \param [in] dispatchee Dispatchable to remove */ void remove_watch(std::shared_ptr const& dispatchee); /** * \brief Remove a watch by file-descriptor * \param [in] fd File descriptor of watch to remove. */ void remove_watch(Fd const& fd); private: PosixRWMutex lifetime_mutex; std::list, bool>> dispatchee_holder; Fd epoll_fd; }; } } #endif // MIR_DISPATCH_MULTIPLEXING_DISPATCHABLE_H_ ./include/common/mir/dispatch/dispatchable.h0000644000004100000410000000476713115234664021363 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_DISPATCH_DISPATCHABLE_H_ #define MIR_DISPATCH_DISPATCHABLE_H_ #include "mir/fd.h" namespace mir { namespace dispatch { enum FdEvent : uint32_t { readable = 1<<0, writable = 1<<1, remote_closed = 1<<2, error = 1<<3 }; using FdEvents = uint32_t; class Dispatchable { public: Dispatchable() = default; virtual ~Dispatchable() = default; Dispatchable& operator=(Dispatchable const&) = delete; Dispatchable(Dispatchable const&) = delete; /** * \brief Get a poll()able file descriptor * \return A file descriptor usable with poll() or equivalent function calls. * relevant_events() contains the set of event types to watch for. */ virtual Fd watch_fd() const = 0; /** * \brief Dispatch one pending event * \param [in] events The set of events current on the file-descriptor * \returns False iff no more events will be produced by this Dispatchable. * Dispatch should no longer be called. * \note This will dispatch at most one event. If there are multiple events * specified in \p events (eg: readable | remote_closed) then dispatch * will process only one. * \note It is harmless to call dispatch() with an event that does not contain * any of the events from relevant_events(). The function will do * nothing in such a case. * \note An implementation of dispatch() MUST handle FdEvent::error, * if only to return false and terminate further event dispatch. */ virtual bool dispatch(FdEvents events) = 0; /** * \brief The set of file-descriptor events this Dispatchable handles. */ virtual FdEvents relevant_events() const = 0; }; } } #endif // MIR_DISPATCH_DISPATCHABLE_H_ ./include/common/mir/dispatch/threaded_dispatcher.h0000644000004100000410000000354513115234416022712 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_DISPATCH_SIMPLE_DISPATCH_THREAD_H_ #define MIR_DISPATCH_SIMPLE_DISPATCH_THREAD_H_ #include #include #include #include #include #include #include "mir/dispatch/multiplexing_dispatchable.h" #include "mir/fd.h" namespace mir { namespace dispatch { class Dispatchable; class ThreadedDispatcher { public: ThreadedDispatcher(std::string const& name, std::shared_ptr const& dispatchee); ThreadedDispatcher(std::string const& name, std::shared_ptr const& dispatchee, std::function const& exception_handler); ~ThreadedDispatcher() noexcept; void add_thread(); void remove_thread(); class ThreadShutdownRequestHandler; private: std::string const name_base; std::shared_ptr thread_exiter; std::shared_ptr dispatcher; std::mutex thread_pool_mutex; std::vector threadpool; std::function const exception_handler; }; } } #endif // MIR_DISPATCH_SIMPLE_DISPATCH_THREAD_H_ ./include/common/mir/dispatch/readable_fd.h0000644000004100000410000000235313115234416021130 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_DISPATCH_READABLE_FD_H_ #define MIR_DISPATCH_READABLE_FD_H_ #include "mir/dispatch/dispatchable.h" #include "mir/fd.h" #include namespace mir { namespace dispatch { class ReadableFd : public Dispatchable { public: ReadableFd(Fd fd, std::function const& on_readable); Fd watch_fd() const override; bool dispatch(FdEvents events) override; FdEvents relevant_events() const override; private: mir::Fd fd; std::function readable; }; } } #endif // MIR_DISPATCH_READABLE_FD_H_ ./include/common/mir/dispatch/action_queue.h0000644000004100000410000000252313115234416021400 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_DISPATCH_ACTION_QUEUE_H_ #define MIR_DISPATCH_ACTION_QUEUE_H_ #include "mir/fd.h" #include "mir/dispatch/dispatchable.h" #include #include namespace mir { namespace dispatch { class ActionQueue : public Dispatchable { public: ActionQueue(); Fd watch_fd() const override; void enqueue(std::function const& action); bool dispatch(FdEvents events) override; FdEvents relevant_events() const override; private: bool consume(); void wake(); mir::Fd event_fd; std::mutex list_lock; std::list> actions; }; } } #endif // MIR_DISPATCH_ACTION_QUEUE_H_ ./include/common/mir/uncaught.h0000644000004100000410000000243013115234416016733 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_CLIENT_API_HELPERS_H_ #define MIR_CLIENT_API_HELPERS_H_ #include #include "mir/log.h" #define MIR_LOG_UNCAUGHT_EXCEPTION(ex) { \ mir::log_error("Caught exception at client library boundary (in %s): %s", \ __FUNCTION__, boost::diagnostic_information(ex).c_str()); } #define MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(ex) { \ mir::log_error("Caught exception at Mir/EGL driver boundary (in %s): %s", \ __FUNCTION__, boost::diagnostic_information(ex).c_str()); } #endif // MIR_CLIENT_API_HELPERS_H_ ./include/common/mir/logging/0000755000004100000410000000000013115234417016374 5ustar www-datawww-data./include/common/mir/logging/logger.h0000644000004100000410000000374013115234416020027 0ustar www-datawww-data/* * Copyright © 2012-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Thomas Voß */ #ifndef MIR_LOGGING_LOGGER_H_ #define MIR_LOGGING_LOGGER_H_ #include #include namespace mir { namespace logging { enum class Severity { critical = 0, error = 1, warning = 2, informational = 3, debug = 4 }; // A facade to shield the inner core of mir to prevent an actual // logging framework from leaking implementation detail. class Logger { public: virtual void log(Severity severity, const std::string& message, const std::string& component) = 0; /* * Those playing at home may wonder why we're saying the 4th argument is the format string, * when it's the 3rd argument in the signature. * * The answer, of course, is that the attribute doesn't know about the implicit * 'this' first parameter of C++! */ virtual void log(char const* component, Severity severity, char const* format, ...) __attribute__ ((format (printf, 4, 5))); protected: Logger() {} virtual ~Logger() = default; Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete; }; void log(Severity severity, const std::string& message, const std::string& component); void set_logger(std::shared_ptr const& new_logger); } } #endif // MIR_LOGGING_LOGGER_H_ ./include/common/mir/libname.h0000644000004100000410000000171513115234416016531 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_LIBNAME_H #define MIR_LIBNAME_H namespace mir { namespace detail { char const* libname_impl(void* libname); } namespace { inline char const* libname() { return detail::libname_impl(reinterpret_cast(&libname)); } } } #endif //MIR_LIBNAME_H_H ./include/common/mir/log.h0000644000004100000410000000560113115234416015701 0ustar www-datawww-data/* * Convenience functions to make logging in Mir easy * ~~~ * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Author: Daniel van Vugt */ #ifndef MIR_LOG_H_ #define MIR_LOG_H_ #include "mir/logging/logger.h" // for Severity #include #include namespace mir { void logv(logging::Severity sev, const char *component, char const* fmt, va_list va); void log(logging::Severity sev, const char *component, char const* fmt, ...); void log(logging::Severity sev, const char *component, std::string const& message); #ifndef MIR_LOG_COMPONENT #ifdef MIR_LOG_COMPONENT_FALLBACK #define MIR_LOG_COMPONENT MIR_LOG_COMPONENT_FALLBACK #endif #endif #ifdef MIR_LOG_COMPONENT namespace { // Isolated namespace so that the component string is always correct for // where it's used. inline void log_info(std::string const& message) { ::mir::log(::mir::logging::Severity::informational, MIR_LOG_COMPONENT, message); } template void log_info(char const* fmt, Args&&... args) { ::mir::log(::mir::logging::Severity::informational, MIR_LOG_COMPONENT, fmt, std::forward(args)...); } template void log_error(char const* fmt, Args&&... args) { ::mir::log(::mir::logging::Severity::error, MIR_LOG_COMPONENT, fmt, std::forward(args)...); } template inline void log_debug(char const* fmt, Args&&... args) { ::mir::log(::mir::logging::Severity::debug, MIR_LOG_COMPONENT, fmt, std::forward(args)...); } inline void log_critical(std::string const& message) { ::mir::log(::mir::logging::Severity::critical, MIR_LOG_COMPONENT, message); } inline void log_error(std::string const& message) { ::mir::log(::mir::logging::Severity::error, MIR_LOG_COMPONENT, message); } inline void log_warning(std::string const& message) { ::mir::log(::mir::logging::Severity::warning, MIR_LOG_COMPONENT, message); } template void log_warning(char const* fmt, Args&&... args) { ::mir::log(::mir::logging::Severity::warning, MIR_LOG_COMPONENT, fmt, std::forward(args)...); } } // (nested anonymous) namespace #endif } // namespace mir #endif // MIR_LOG_H_ ./include/common/mir/graphics/0000755000004100000410000000000013115234677016556 5ustar www-datawww-data./include/common/mir/graphics/native_buffer.h0000644000004100000410000000207313115234664021544 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_NATIVE_BUFFER_H_ #define MIR_GRAPHICS_NATIVE_BUFFER_H_ namespace mir { namespace graphics { class NativeBuffer { protected: NativeBuffer() = default; virtual ~NativeBuffer() = default; NativeBuffer(NativeBuffer const&) = delete; NativeBuffer operator=(NativeBuffer const&) = delete; }; } } #endif /* MIR_GRAPHICS_NATIVE_BUFFER_H_ */ ./include/common/mir/cached_ptr.h0000644000004100000410000000243413115234416017215 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_CACHED_PTR_H_ #define MIR_CACHED_PTR_H_ #include #include namespace mir { template class CachedPtr { std::weak_ptr cache; CachedPtr(CachedPtr const&) = delete; CachedPtr& operator=(CachedPtr const&) = delete; public: CachedPtr() = default; std::shared_ptr operator()(std::function()> make) { auto result = cache.lock(); if (!result) { cache = result = make(); } return result; } }; } // namespace mir #endif // MIR_CACHED_PTR_H_ ./include/common/mir/input/0000755000004100000410000000000013115234676016114 5ustar www-datawww-data./include/common/mir/input/mir_touchscreen_config.h0000644000004100000410000000377713115234664023016 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_TOUCH_SCREEN_CONFIGURATION_H_ #define MIR_INPUT_TOUCH_SCREEN_CONFIGURATION_H_ #include "mir_toolkit/common.h" #include "mir_toolkit/mir_input_device_types.h" #include #include struct MirTouchscreenConfig { MirTouchscreenConfig(); ~MirTouchscreenConfig(); MirTouchscreenConfig(MirTouchscreenConfig const&); MirTouchscreenConfig(MirTouchscreenConfig &&); MirTouchscreenConfig& operator=(MirTouchscreenConfig const&); MirTouchscreenConfig(uint32_t output_id, MirTouchscreenMappingMode mode); /** * Configures the output the device coordinates should be aligned to. * * This element is only relevant when mapping_mode is set to * mir_touchscreen_mapping_mode_to_output. */ uint32_t output_id() const; void output_id(uint32_t); /** * Configure the type of coordinate mapping to be used for this input * device. */ MirTouchscreenMappingMode mapping_mode() const; void mapping_mode(MirTouchscreenMappingMode); bool operator==(MirTouchscreenConfig const& other) const; bool operator!=(MirTouchscreenConfig const& other) const; private: struct Implementation; std::unique_ptr impl; }; std::ostream& operator<<(std::ostream& out, MirTouchscreenConfig const& conf); #endif ./include/common/mir/input/mir_input_config.h0000644000004100000410000000724113115234664021621 0ustar www-datawww-data/** * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored By: Andreas Pokorny */ #ifndef MIR_INPUT_INPUT_CONFIGURATION_H #define MIR_INPUT_INPUT_CONFIGURATION_H #include "mir_toolkit/mir_input_device_types.h" #include "mir/input/device_capability.h" #include #include #include #include struct MirPointerConfig; struct MirTouchpadConfig; struct MirKeyboardConfig; struct MirTouchscreenConfig; class MirInputDevice { public: MirInputDevice(); MirInputDevice(MirInputDeviceId id, mir::input::DeviceCapabilities caps, std::string const& name, std::string const& unique_id); MirInputDevice(MirInputDevice && conf); MirInputDevice(MirInputDevice const& conf); MirInputDevice& operator=(MirInputDevice const& conf); ~MirInputDevice(); MirInputDeviceId id() const; mir::input::DeviceCapabilities capabilities() const; std::string const& name() const; std::string const& unique_id() const; bool has_touchpad_config() const; MirTouchpadConfig& touchpad_config(); MirTouchpadConfig const& touchpad_config() const; void set_touchpad_config(MirTouchpadConfig const& conf); bool has_keyboard_config() const; MirKeyboardConfig& keyboard_config(); MirKeyboardConfig const& keyboard_config() const; void set_keyboard_config(MirKeyboardConfig const& conf); bool has_pointer_config() const; MirPointerConfig& pointer_config(); MirPointerConfig const& pointer_config() const; void set_pointer_config(MirPointerConfig const& conf); bool has_touchscreen_config() const; MirTouchscreenConfig& touchscreen_config(); MirTouchscreenConfig const& touchscreen_config() const; void set_touchscreen_config(MirTouchscreenConfig const& conf); bool operator==(MirInputDevice const& rhs) const; bool operator!=(MirInputDevice const& rhs) const; private: struct Implementation; std::unique_ptr impl; }; class MirInputConfig { public: MirInputConfig(); MirInputConfig(MirInputConfig && conf); MirInputConfig(MirInputConfig const& conf); MirInputConfig& operator=(MirInputConfig const& conf); ~MirInputConfig(); void add_device_config(MirInputDevice const& conf); MirInputDevice* get_device_config_by_id(MirInputDeviceId id); MirInputDevice const* get_device_config_by_id(MirInputDeviceId id) const; MirInputDevice& get_device_config_by_index(size_t pos); MirInputDevice const& get_device_config_by_index(size_t pos) const; void remove_device_by_id(MirInputDeviceId id); size_t size() const; void for_each(std::function const& visitor) const; void for_each(std::function const& visitor); bool operator==(MirInputConfig const& rhs) const; bool operator!=(MirInputConfig const& rhs) const; using value_type = MirInputDevice; private: struct Implementation; std::unique_ptr impl; }; std::ostream& operator<<(std::ostream&, MirInputDevice const&); std::ostream& operator<<(std::ostream&, MirInputConfig const&); #endif ./include/common/mir/input/mir_pointer_config.h0000644000004100000410000000537213115234664022145 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_POINTER_CONFIGURATION_H_ #define MIR_INPUT_POINTER_CONFIGURATION_H_ #include "mir_toolkit/common.h" #include "mir_toolkit/mir_input_device_types.h" #include #include struct MirPointerConfig { MirPointerConfig(); ~MirPointerConfig(); MirPointerConfig(MirPointerConfig const& cp); MirPointerConfig(MirPointerConfig && cp); MirPointerConfig& operator=(MirPointerConfig const& cp); MirPointerConfig(MirPointerHandedness handedness, MirPointerAcceleration acceleration, double acceleration_bias, double horizontal_scroll_scale, double vertical_scroll_scale); /*! * Configure which button shall be used as primary button. That way the input device is configured to be either * right or left handed. */ MirPointerHandedness handedness() const; void handedness(MirPointerHandedness); /*! * Configure cursor acceleration profile */ MirPointerAcceleration acceleration() const; void acceleration(MirPointerAcceleration); /*! * Configures the intensity of the cursor acceleration. Values within the range of [-1, 1] are allowed. * - 0: default acceleration * - [-1, 0): reduced acceleration * - (0, 1]: increased acceleration */ double cursor_acceleration_bias() const; void cursor_acceleration_bias(double); /*! * Configures a signed scale of the horizontal scrolling. Use negative values to configure 'natural scrolling' */ double horizontal_scroll_scale() const; void horizontal_scroll_scale(double); /*! * Configures a signed scale of the vertical scrolling. Use negative values to configure 'natural scrolling' */ double vertical_scroll_scale() const; void vertical_scroll_scale(double); bool operator==(MirPointerConfig const& rhs) const; bool operator!=(MirPointerConfig const& rhs) const; private: struct Implementation; std::unique_ptr impl; }; std::ostream& operator<<(std::ostream& out, MirPointerConfig const& rhs); #endif ./include/common/mir/input/device_capability.h0000644000004100000410000000251113115234416021714 0ustar www-datawww-data/* * Copyright © 2014-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_INPUT_DEVICE_CAPABILITY_H_ #define MIR_INPUT_DEVICE_CAPABILITY_H_ #include "mir/flags.h" #include namespace mir { namespace input { enum class DeviceCapability : uint32_t { unknown = 0, pointer = 1<<1, keyboard = 1<<2, touchpad = 1<<3, touchscreen = 1<<4, gamepad = 1<<5, joystick = 1<<6, switch_ = 1<<7, multitouch = 1<<8, // multitouch capable alpha_numeric = 1<<9 // enough keys for text entry }; DeviceCapability mir_enable_enum_bit_operators(DeviceCapability); using DeviceCapabilities = mir::Flags; } } #endif ./include/common/mir/input/mir_touchpad_config.h0000644000004100000410000000636413115234664022276 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_TOUCH_PAD_CONFIGURATION_H_ #define MIR_INPUT_TOUCH_PAD_CONFIGURATION_H_ #include "mir_toolkit/common.h" #include "mir_toolkit/mir_input_device_types.h" #include #include struct MirTouchpadConfig { MirTouchpadConfig(); MirTouchpadConfig(MirTouchpadConfig && other); MirTouchpadConfig(MirTouchpadConfig const& other); MirTouchpadConfig& operator=(MirTouchpadConfig const& other); ~MirTouchpadConfig(); MirTouchpadConfig(MirTouchpadClickModes click_mode, MirTouchpadScrollModes scroll_mode, int button_down_scroll_button, bool tap_to_click, bool disable_while_typing, bool disable_with_mouse, bool middle_mouse_button_emulation); /*! * The click mode defines when the touchpad generates software emulated button events. */ MirTouchpadClickModes click_mode() const; void click_mode(MirTouchpadClickModes) ; /*! * The scroll mode defines when the touchpad generates scroll events instead of pointer motion events. */ MirTouchpadScrollModes scroll_mode() const; void scroll_mode(MirTouchpadScrollModes); /*! * Configures the button used for the on-button-down scroll mode */ int button_down_scroll_button() const; void button_down_scroll_button(int); /*! * When tap to click is enabled the system will interpret short finger touch down/up sequences as button clicks. */ bool tap_to_click() const; void tap_to_click(bool); /*! * Emulates a middle mouse button press when the left and right buttons on a touchpad are pressed. */ bool middle_mouse_button_emulation() const; void middle_mouse_button_emulation(bool); /*! * When disable-with-mouse is enabled the touchpad will stop to emit user input events when another pointing device is plugged in. */ bool disable_with_mouse() const; void disable_with_mouse(bool); /*! * When disable-with-mouse is enabled the touchpad will stop to emit user input events when the user starts to use a keyboard and a short period after. */ bool disable_while_typing() const; void disable_while_typing(bool); bool operator==(MirTouchpadConfig const& rhs) const; bool operator!=(MirTouchpadConfig const& rhs) const; private: struct Implementation; std::unique_ptr impl; }; std::ostream& operator<<(std::ostream& out, MirTouchpadConfig const& conf); #endif ./include/common/mir/input/keymap.h0000644000004100000410000000365213115234664017556 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_KEYMAP_H_ #define MIR_INPUT_KEYMAP_H_ #include #include namespace mir { namespace input { struct Keymap { Keymap() = default; Keymap(std::string&& model, std::string&& layout, std::string&& variant, std::string&& options) : model{model}, layout{layout}, variant{variant}, options{options} { } Keymap(std::string const& model, std::string const& layout, std::string const& variant, std::string const& options) : model{model}, layout{layout}, variant{variant}, options{options} { } std::string model{"pc105+inet"}; std::string layout{"us"}; std::string variant; std::string options; }; inline bool operator==(Keymap const& lhs, Keymap const& rhs) { return lhs.model == rhs.model && lhs.layout == rhs.layout && lhs.variant == rhs.variant && lhs.options == rhs.options; } inline bool operator!=(Keymap const& lhs, Keymap const& rhs) { return !(lhs == rhs); } inline std::ostream& operator<<(std::ostream &out, Keymap const& rhs) { return out << rhs.model << "-" << rhs.layout << "-"<< rhs.variant << "-" << rhs.options; } } } #endif ./include/common/mir/input/mir_keyboard_config.h0000644000004100000410000000323413115234664022260 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Andreas Pokorny */ #ifndef MIR_INPUT_KEYBOARD_CONFIGURATION_H_ #define MIR_INPUT_KEYBOARD_CONFIGURATION_H_ #include "mir_toolkit/common.h" #include "mir_toolkit/mir_input_device_types.h" #include "mir/input/keymap.h" #include #include /* * Keyboard device configuration. */ struct MirKeyboardConfig { MirKeyboardConfig(); ~MirKeyboardConfig(); MirKeyboardConfig(mir::input::Keymap&& keymap); MirKeyboardConfig(MirKeyboardConfig&& other); MirKeyboardConfig(MirKeyboardConfig const& other); MirKeyboardConfig& operator=(MirKeyboardConfig const& other); mir::input::Keymap const& device_keymap() const; void device_keymap(mir::input::Keymap const& ); bool operator==(MirKeyboardConfig const& rhs) const; bool operator!=(MirKeyboardConfig const& rhs) const; private: struct Implementation; std::unique_ptr impl; }; std::ostream& operator<<(std::ostream& out, MirKeyboardConfig const& keyboard); #endif ./include/common/mir/input/mir_input_config_serialization.h0000644000004100000410000000201113115234664024544 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored By: Andreas Pokorny */ #ifndef MIR_INPUT_INPUT_CONFIG_SERIALIZATION_H #define MIR_INPUT_INPUT_CONFIG_SERIALIZATION_H #include class MirInputConfig; namespace mir { namespace input { std::string serialize_input_config(MirInputConfig const& config); MirInputConfig deserialize_input_config(std::string const& buffer); } } #endif ./include/common/mir/fd.h0000644000004100000410000000320713115234416015511 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_FD_H_ #define MIR_FD_H_ #include namespace mir { //TODO: remove once mir::Fd is used more pervasively. // some existing code does not really allow us to transfer or share the ownership // of the fd. Constructing using mir::Fd(IntOwnedFd(int)) will help transition the existing // code to using the mir::Fd type properly. struct IntOwnedFd { int int_owned_fd; }; class Fd { public: //transfer ownership of the POD-int to the object. The int no longer needs close()ing, //and has the lifetime of the Fd object. explicit Fd(int fd); explicit Fd(IntOwnedFd); static int const invalid{-1}; Fd(); //Initializes fd to the mir::Fd::invalid; Fd(Fd&&); Fd(Fd const&) = default; Fd& operator=(Fd); //bit of a convenient kludge. take care not to close or otherwise destroy the FD. operator int() const; private: std::shared_ptr fd; }; } // namespace mir #endif // MIR_FD_H_ ./include/common/mir/time/0000755000004100000410000000000013115234677015714 5ustar www-datawww-data./include/common/mir/time/types.h0000644000004100000410000000167313115234416017227 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_TIME_TYPES_H_ #define MIR_TIME_TYPES_H_ #include namespace mir { namespace time { using Timestamp = std::chrono::steady_clock::time_point; using Duration = std::chrono::steady_clock::duration; } } #endif ./include/common/mir/time/posix_timestamp.h0000644000004100000410000000765513115234664021323 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_TIME_POSIX_TIMESTAMP_H_ #define MIR_TIME_POSIX_TIMESTAMP_H_ #include #include #include namespace mir { namespace time { /* * We need absolute precision here so sadly can't use high-level C++ clocks... * - Graphics frame timing needs support for at least the kernel clocks * CLOCK_REALTIME and CLOCK_MONOTONIC, to be selected at runtime, whereas * std::chrono does not support CLOCK_REALTIME or easily switching clocks. * - mir::time::Timestamp is relative to the (wrong) epoch of steady_clock, * so converting to/from mir::time::Timestamp would be dangerously * inaccurate at best. */ struct PosixTimestamp { clockid_t clock_id; std::chrono::nanoseconds nanoseconds; PosixTimestamp() : clock_id{CLOCK_MONOTONIC}, nanoseconds{0} {} PosixTimestamp(clockid_t clk, std::chrono::nanoseconds ns) : clock_id{clk}, nanoseconds{ns} {} PosixTimestamp(clockid_t clk, struct timespec const& ts) : clock_id{clk}, nanoseconds{ts.tv_sec*1000000000LL + ts.tv_nsec} {} static PosixTimestamp now(clockid_t clock_id) { struct timespec ts; clock_gettime(clock_id, &ts); return PosixTimestamp(clock_id, ts); } }; inline void assert_same_clock(PosixTimestamp const& a, PosixTimestamp const& b) { if (a.clock_id != b.clock_id) throw std::logic_error("Can't compare different time domains"); } inline bool operator==(PosixTimestamp const& a, PosixTimestamp const& b) { return a.clock_id == b.clock_id && a.nanoseconds == b.nanoseconds; } inline PosixTimestamp operator-(PosixTimestamp const& a, std::chrono::nanoseconds b) { return PosixTimestamp(a.clock_id, a.nanoseconds - b); } inline std::chrono::nanoseconds operator-(PosixTimestamp const& a, PosixTimestamp const& b) { assert_same_clock(a, b); return a.nanoseconds - b.nanoseconds; } inline PosixTimestamp operator+(PosixTimestamp const& a, std::chrono::nanoseconds b) { return PosixTimestamp(a.clock_id, a.nanoseconds + b); } inline std::chrono::nanoseconds operator%(PosixTimestamp const& a, std::chrono::nanoseconds b) { return std::chrono::nanoseconds(a.nanoseconds.count() % b.count()); } inline bool operator>(PosixTimestamp const& a, PosixTimestamp const& b) { assert_same_clock(a, b); return a.nanoseconds > b.nanoseconds; } inline bool operator<(PosixTimestamp const& a, PosixTimestamp const& b) { assert_same_clock(a, b); return a.nanoseconds < b.nanoseconds; } inline bool operator>=(PosixTimestamp const& a, PosixTimestamp const& b) { assert_same_clock(a, b); return a.nanoseconds >= b.nanoseconds; } inline bool operator<=(PosixTimestamp const& a, PosixTimestamp const& b) { assert_same_clock(a, b); return a.nanoseconds <= b.nanoseconds; } inline void sleep_until(PosixTimestamp const& t) { long long ns = t.nanoseconds.count(); struct timespec ts; ts.tv_sec = ns / 1000000000LL; ts.tv_nsec = ns % 1000000000LL; while (EINTR == clock_nanosleep(t.clock_id, TIMER_ABSTIME, &ts, NULL)) {} } }} // namespace mir::time #endif // MIR_TIME_POSIX_TIMESTAMP_H_ ./include/common/mir/posix_rw_mutex.h0000644000004100000410000000340313115234664020217 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_POSIX_RW_MUTEX_H_ #define MIR_POSIX_RW_MUTEX_H_ #include namespace mir { /** * Implementation of the Mutex and SharedMutex C++14 concepts via POSIX pthread rwlock * * The advantages of using this over std::shared_timed_mutex are: * a) The type of rwlock can be selected (as per pthread_rwlock_attr_setkind_np) * b) As per POSIX, read locks are recursive rather than undefined behaviour */ class PosixRWMutex { public: enum class Type { Default, PreferReader, PreferWriterNonRecursive }; PosixRWMutex(); PosixRWMutex(Type type); ~PosixRWMutex(); PosixRWMutex(PosixRWMutex const&) = delete; PosixRWMutex& operator=(PosixRWMutex const&) = delete; /* * SharedMutex concept implementation */ void lock_shared(); bool try_lock_shared(); void unlock_shared(); /* * Mutex concept implementation */ void lock(); bool try_lock(); void unlock(); private: pthread_rwlock_t mutex; }; } #endif //MIR_POSIX_RW_MUTEX_H_ ./include/common/mir/raii.h0000644000004100000410000000532413115234416016046 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_RAII_H_ #define MIR_RAII_H_ #include #include namespace mir { /// Utilities for exception safe use of paired function calls namespace raii { template struct PairedCalls { PairedCalls(Creator&& creator, Deleter&& deleter) : deleter(std::move(deleter)), owner(true) { creator(); } PairedCalls(PairedCalls&& that) : deleter(that.deleter), owner(that.owner) { that.owner = false; } ~PairedCalls() { if (owner) deleter(); } private: PairedCalls(PairedCalls const& that) = delete; PairedCalls& operator=(PairedCalls const& that) = delete; Deleter const deleter; bool owner; }; /** * Creates an RAII object from a creator and deleter. * If creator returns a pointer type then the returned object * is a std::unique_ptr initialized with the pointer and deleter. * Otherwise, the returned object calls creator on construction and deleter on destruction * * \param creator called to initialize the returned object * \param deleter called to finalize the returned object */ template inline auto paired_calls(Creator&& creator, Deleter&& deleter) -> std::unique_ptr::type, Deleter> { return {creator(), deleter}; } ///\overload template inline auto paired_calls(Creator&& creator, Deleter&& deleter) -> typename std::enable_if< std::is_void::value, PairedCalls>::type { return {std::move(creator), std::move(deleter)}; } /** * Creates an RAII object from an owning pointer and deleter. * The returned object is a std::unique_ptr initialized with the pointer and deleter. * * \param owned the object to take ownership of * \param deleter called to finalize the owned object */ template inline auto deleter_for(Owned* owned, Deleter&& deleter) -> std::unique_ptr { return {owned, deleter}; } } } #endif /* MIR_RAII_H_ */ ./include/common/mir_toolkit/0000755000004100000410000000000013115234665016520 5ustar www-datawww-data./cross-compile-chroot.sh0000755000004100000410000001107013115234664015661 0ustar www-datawww-data#!/bin/bash # build script to compile Mir for armhf devices # set -e usage() { echo "usage: $(basename $0) [-a ] [-c] [-h] [-d ] [-u]" echo " -a Specify target architecture (armhf/arm64/powerpc/ppc64el/amd64/i386/host)" echo " -c Clean before building" echo " -d Select the distribution to build for (vivid/wily/xenial)" echo " -h This message" echo " -u Update partial chroot directory" } clean_build_dir() { rm -rf ${1} mkdir ${1} } # Default to a dist-agnostic directory name so as to not break Jenkins right now BUILD_DIR=build-android-arm NUM_JOBS=$(( $(grep -c ^processor /proc/cpuinfo) + 1 )) _do_update_chroot=0 # Default to vivid as we don't seem to have any working wily devices right now dist=vivid clean=0 update_build_dir=0 enable_tests=yes target_arch=armhf while getopts "a:cd:hut:" OPTNAME do case $OPTNAME in a ) target_arch=${OPTARG} update_build_dir=1 ;; c ) clean=1 ;; d ) dist=${OPTARG} update_build_dir=1 ;; u ) _do_update_chroot=1 ;; h ) usage exit 0 ;; : ) echo "Parameter -${OPTARG} needs an argument" usage exit 1; ;; t ) enable_tests=${OPTARG} ;; * ) echo "invalid option specified" usage exit 1 ;; esac done shift $((${OPTIND}-1)) if [ "${target_arch}" = "host" ]; then target_arch=`dpkg-architecture -qDEB_HOST_ARCH` fi if [ ${clean} -ne 0 ]; then clean_build_dir ${BUILD_DIR} fi if [ ${update_build_dir} -eq 1 ]; then BUILD_DIR=build-${target_arch}-${dist} fi if [ "${MIR_CHROOT}" = "" ]; then export MIR_CHROOT=~/.cache/mir-${target_arch}-chroot-${dist} fi if [ ! -d ${MIR_CHROOT} ]; then echo "no partial chroot dir detected. attempting to create one" _do_update_chroot=1 fi if [ ! -d ${BUILD_DIR} ]; then mkdir ${BUILD_DIR} fi echo "Building for distro: $dist" echo "Using MIR_CHROOT: ${MIR_CHROOT}" additional_repositories= if [ ${dist} == "vivid" ] ; then additional_repositories="-r http://ppa.launchpad.net/ci-train-ppa-service/stable-phone-overlay/ubuntu" fi gcc_variant= if [ "${dist}" = "vivid" ]; then gcc_variant=-4.9 elif [ "${dist}" = "wily" -o "${dist}" = "xenial" ]; then gcc_variant=-5 elif [ "${dist}" = "yakkety" -o "${dist}" = "zesty" ]; then gcc_variant=-6 fi case ${target_arch} in armhf ) target_machine=arm-linux-gnueabihf mir_platform="android;mesa-kms" ;; amd64 ) target_machine=x86_64-linux-gnu mir_platform="android;mesa-kms" ;; i386 ) target_machine=i386-linux-gnu mir_platform="android;mesa-kms" ;; arm64 ) target_machine=aarch64-linux-gnu mir_platform=mesa-kms ;; ppc64el ) target_machine=powerpc64le-linux-gnu mir_platform=mesa-kms ;; powerpc ) target_machine=powerpc-linux-gnu mir_platform=mesa-kms ;; * ) mir_platform=mesa-kms # A good guess (assuming you have dpkg-architecture) target_machine=`dpkg-architecture -A${target_arch} -qDEB_HOST_MULTIARCH` || { echo "Unknown architecture ${target_arch}" usage exit 1 } ;; esac echo "Target architecture: ${target_arch}" echo "Target machine: ${target_machine}" if [ ${_do_update_chroot} -eq 1 ] ; then pushd tools > /dev/null ./setup-partial-armhf-chroot.sh -d ${dist} -a ${target_arch} ${additional_repositories} ${MIR_CHROOT} popd > /dev/null # force a clean build after an update, since CMake cache maybe out of date clean_build_dir ${BUILD_DIR} fi pushd ${BUILD_DIR} > /dev/null export PKG_CONFIG_PATH="${MIR_CHROOT}/usr/lib/pkgconfig:${MIR_CHROOT}/usr/lib/${target_machine}/pkgconfig" export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 export PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 export PKG_CONFIG_SYSROOT_DIR=$MIR_CHROOT export PKG_CONFIG_EXECUTABLE=`which pkg-config` export MIR_TARGET_MACHINE=${target_machine} export MIR_GCC_VARIANT=${gcc_variant} export CMAKE_PREFIX_PATH=$MIR_CHROOT/usr/lib/${target_machine}/cmake echo "Using PKG_CONFIG_PATH: $PKG_CONFIG_PATH" echo "Using PKG_CONFIG_EXECUTABLE: $PKG_CONFIG_EXECUTABLE" cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/LinuxCrossCompile.cmake \ -DMIR_PLATFORM=${mir_platform} -DMIR_ENABLE_TESTS=${enable_tests}\ -DMIR_USE_PRECOMPILED_HEADERS=OFF \ .. make -j${NUM_JOBS} $@ popd > /dev/null ./guides/0000755000004100000410000000000013115234417012524 5ustar www-datawww-data./guides/CMakeLists.txt0000644000004100000410000000225413115234416015266 0ustar www-datawww-dataADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_BINARY_DIR}/doc/html/cppguide/index.html # The output directories are created implicitly by CMake backend machinery # and there seem to be race conditions where the command is sometimes run # before its output directory exists. As a quick hack always create # the subdir before running the command. COMMAND mkdir -p ${CMAKE_BINARY_DIR}/doc/html/cppguide/ COMMAND xsltproc -o ${CMAKE_BINARY_DIR}/doc/html/cppguide/index.html ${CMAKE_CURRENT_SOURCE_DIR}/styleguide.xsl ${CMAKE_CURRENT_SOURCE_DIR}/cppguide.xml DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/styleguide.xsl ${CMAKE_CURRENT_SOURCE_DIR}/cppguide.xml ) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_BINARY_DIR}/doc/html/cppguide/styleguide.css # See discussion above. COMMAND mkdir -p ${CMAKE_BINARY_DIR}/doc/html/cppguide COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/styleguide.css ${CMAKE_CURRENT_SOURCE_DIR}/favicon.ico ${CMAKE_BINARY_DIR}/doc/html/cppguide/ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/styleguide.css ) ADD_CUSTOM_TARGET(guides DEPENDS ${CMAKE_BINARY_DIR}/doc/html/cppguide/index.html ${CMAKE_BINARY_DIR}/doc/html/cppguide/styleguide.css) ./guides/favicon.ico0000644000004100000410000000217613115234416014652 0ustar www-datawww-data h(  5f"dLL"df0`LLLLLLLLf8tLLLLLLLL:u`LLLLo6jLLf5LLL[fT)cLLN+\LLUX\PX#^LLh`LL}O|LLLL@qLL(hO}@qPLLLLL=o0gLL SLO|ULLLL RLLO"dLLuLLLLfLL(hfLLVX'aZl-eLLx0NLL9l[Q~#^LLN*bLLLNlQ~NLrD|LLLLLLLNF}qQLLLLLLQq&r2oMM2or&./guides/styleguide.xsl0000644000004100000410000011076413115234416015442 0ustar www-datawww-data <xsl:value-of select="@title"/>

Each style point has a summary for which additional information is available by toggling the accompanying arrow button that looks this way: . You may toggle all summaries with the big arrow button:

Toggle all summaries

Parting Words

javascript:ShowHideByName(' ',' ') ?showone=# link
display: inline display: none

Definition:

Pros:

Cons:

Decision:

TODO:


           
           
           
           
             
               
               
             
           
         

           
           
           
           
             
               
               
             
           
         

             
           

                             
                           
Table of Contents
_
./guides/cppguide.xml0000644000004100000410000042654213115234416015062 0ustar www-datawww-data

Revision 4.2

Tim Penhey
Neil J. Patel
Thomas Voss
This style guide contains many details that are initially hidden from view. They are marked by the triangle icon, which you see here on your left. Click it now. You should see "Hooray" appear below.

Hooray! Now you know you can expand points to get more details. Alternatively, there's an "expand all" at the top of this document.

As every C++ programmer knows, the language has many powerful features, but this power brings with it complexity, which in turn can make code more bug-prone and harder to read and maintain.

The goal of this guide is to manage this complexity by describing in detail the dos and don'ts of writing C++ code. These rules exist to keep the code base manageable while still allowing coders to use C++ language features productively.

Style, also known as readability, is what we call the conventions that govern our C++ code. The term Style is a bit of a misnomer, since these conventions cover far more than just source file formatting.

One way in which we keep the code base manageable is by enforcing consistency. It is very important that any programmer be able to look at another's code and quickly understand it. Maintaining a uniform style and following conventions means that we can more easily use "pattern-matching" to infer what various symbols are and what invariants are true about them. Creating common, required idioms and patterns makes code much easier to understand. In some cases there might be good arguments for changing certain style rules, but we nonetheless keep things as they are in order to preserve consistency.

Another issue this guide addresses is that of C++ feature bloat. C++ is a huge language with many advanced features. In some cases we constrain, or even ban, use of certain features. We do this to keep code simple and to avoid the various common errors and problems that these features can cause. This guide lists these features and explains why their use is restricted.

Note that this guide is not a C++ tutorial: we assume that the reader is familiar with the language.

In general, every .cpp file should have an associated .h file. There are some common exceptions, such as unit tests and small .cpp files containing just a main() function.

Correct use of header files can make a huge difference to the readability, size and performance of your code.

The following rules will guide you through the various pitfalls of using header files.

All header files should have #define guards to prevent multiple inclusion. The format of the symbol name should be <PROJECT>_<PATH>_<FILE>_H_.

To guarantee uniqueness, they should be based on the full path in a project's source tree. For example, the file foo/src/bar/baz.h in project foo should have the following guard:

#ifndef FOO_BAR_BAZ_H_ #define FOO_BAR_BAZ_H_ ... #endif // FOO_BAR_BAZ_H_
Don't use an #include when a forward declaration would suffice.

When you include a header file you introduce a dependency that will cause your code to be recompiled whenever the header file changes. If your header file includes other header files, any change to those files will cause any code that includes your header to be recompiled. Therefore, we prefer to minimize includes, particularly includes of header files in other header files.

You can significantly reduce the number of header files you need to include in your own header files by using forward declarations. For example, if your header file uses the File class in ways that do not require access to the declaration of the File class, your header file can just forward declare class File; instead of having to #include "file/base/file.h".

How can we use a class Foo in a header file without access to its definition?

  • We can declare data members of type Foo* or Foo&.
  • We can declare (but not define) functions with arguments, and/or return values, of type Foo. (One exception is if an argument Foo or Foo const& has a non-explicit, one-argument constructor, in which case we need the full definition to support automatic type conversion.)
  • We can declare static data members of type Foo. This is because static data members are defined outside the class definition.

On the other hand, you must include the header file for Foo if your class subclasses Foo or has a data member of type Foo.

Sometimes it makes sense to have pointer (or better, unique_ptr) members instead of object members. However, this complicates code readability and imposes a performance penalty, so avoid doing this transformation if the only purpose is to minimize includes in header files.

Of course, .cpp files typically do require the definitions of the classes they use, and usually have to include several header files.

If you use a symbol Foo in your source file, you should bring in a definition for Foo yourself, either via an #include or via a forward declaration. Do not depend on the symbol being brought in transitively via headers not directly included. One exception is if Foo is used in myfile.cpp, it's ok to #include (or forward-declare) Foo in myfile.h, instead of myfile.cpp.
Define functions inline only when they are small, say, 10 lines or less. You can declare functions in a way that allows the compiler to expand them inline rather than calling them through the usual function call mechanism. Inlining a function can generate more efficient object code, as long as the inlined function is small. Feel free to inline accessors and mutators, and other short, performance-critical functions. Overuse of inlining can actually make programs slower. Depending on a function's size, inlining it can cause the code size to increase or decrease. Inlining a very small accessor function will usually decrease code size while inlining a very large function can dramatically increase code size. On modern processors smaller code usually runs faster due to better use of the instruction cache.

A decent rule of thumb is to not inline a function if it is more than 10 lines long. Beware of destructors, which are often longer than they appear because of implicit member- and base-destructor calls!

Another useful rule of thumb: it's typically not cost effective to inline functions with loops or switch statements (unless, in the common case, the loop or switch statement is never executed).

It is important to know that functions are not always inlined even if they are declared as such; for example, virtual and recursive functions are not normally inlined. Usually recursive functions should not be inline. The main reason for making a virtual function inline is to place its definition in the class, either for convenience or to document its behavior, e.g., for accessors and mutators.

You may use file names with a -inl.h suffix to define complex inline functions when needed.

The definition of an inline function needs to be in a header file, so that the compiler has the definition available for inlining at the call sites. However, implementation code properly belongs in .cpp files, and we do not like to have much actual code in .h files unless there is a readability or performance advantage.

If an inline function definition is short, with very little, if any, logic in it, you should put the code in your .h file. For example, accessors and mutators should certainly be inside a class definition. More complex inline functions may also be put in a .h file for the convenience of the implementer and callers, though if this makes the .h file too unwieldy you can instead put that code in a separate -inl.h file. This separates the implementation from the class definition, while still allowing the implementation to be included where necessary.

Another use of -inl.h files is for definitions of function templates. This can be used to keep your template definitions easy to read.

Do not forget that a -inl.h file requires a #define guard just like any other header file.

When defining a function, parameter order is: outputs, then inputs.

Parameters to C/C++ functions are either input to the function, output from the function, or both. Input parameters are usually values or const references, while output and input/output parameters will be non-const references or pointers to non-const. When ordering function parameters, put all output parameters before any input-only parameters. In particular, do not add new parameters to the end of the function just because they are new; place new output parameters before the input-only parameters.

This is not a hard-and-fast rule. Parameters that are both input and output (often classes/structs) muddy the waters, and, as always, consistency with related functions may require you to bend the rule.

Use standard order for readability and to avoid hidden dependencies: your project's public .h, your project's private .h, other libraries' .h, .C library, C++ library,

All of a project's header files should be listed as descendants of the project's source directory without use of UNIX directory shortcuts . (the current directory) or .. (the parent directory). For example, my-awesome-project/src/base/logging.h should be included as

#include "base/logging.h"

In dir/foo.cpp or dir/foo_test.cpp, whose main purpose is to implement or test the stuff in dir2/foo2.h, order your includes as follows:

  1. dir2/foo2.h (preferred location — see details below).
  2. Your project's public .h files.
  3. Your project's private .h files.
  4. Other libraries' .h files.
  5. C system files.
  6. C++ system files.

The preferred ordering reduces hidden dependencies. We want every header file to be compilable on its own. The easiest way to achieve this is to make sure that every one of them is the first .h file #included in some .cpp.

dir/foo.cpp and dir2/foo2.h are often in the same directory (e.g. base/test_basictypes.cpp and base/basictypes.h), but can be in different directories too.

Within each section it is nice to order the includes alphabetically.

For example, the includes in my-awesome-project/src/foo/internal/fooserver.cpp might look like this:

#include "foo/public/fooserver.h" // Preferred location. #include "base/basictypes.h" #include "base/commandlineflags.h" #include "foo/public/bar.h" #include <sys/types.h> #include <unistd.h> #include <hash_map> #include <vector>
Unnamed namespaces in .cpp files are encouraged. With named namespaces, choose the name based on the project, and possibly its path. Do not use a using-directive in a header file. Namespaces subdivide the global scope into distinct, named scopes, and so are useful for preventing name collisions in the global scope.

Namespaces provide a (hierarchical) axis of naming, in addition to the (also hierarchical) name axis provided by classes.

For example, if two different projects have a class Foo in the global scope, these symbols may collide at compile time or at runtime. If each project places their code in a namespace, project1::Foo and project2::Foo are now distinct symbols that do not collide.

Namespaces can be confusing, because they provide an additional (hierarchical) axis of naming, in addition to the (also hierarchical) name axis provided by classes.

Use of unnamed spaces in header files can easily cause violations of the C++ One Definition Rule (ODR).

Use namespaces according to the policy described below.

  • Unnamed namespaces are allowed and even encouraged in .cpp files, to avoid runtime naming conflicts: namespace // This is in a .cpp file. { // The content of a namespace is not indented enum { UNUSED, EOF, ERROR }; // Commonly used tokens. bool AtEof() { return pos_ == EOF; } // Uses our namespace's EOF. } // namespace

    However, file-scope declarations that are associated with a particular class may be declared in that class as types, static data members or static member functions rather than as members of an unnamed namespace. Terminate the unnamed namespace as shown, with a comment // namespace.

  • Do not use unnamed namespaces in .h files.

Named namespaces should be used as follows:

  • Namespaces wrap the entire source file after includes, gflags definitions/declarations, and forward declarations of classes from other namespaces: // In the .h file namespace mynamespace { // All declarations are within the namespace scope. // Notice the lack of indentation. class MyClass { public: ... void foo(); }; } // namespace mynamespace // In the .cpp file namespace mynamespace { // Definition of functions is within scope of the namespace. void MyClass::foo() { ... } } // namespace mynamespace

    The typical .cpp file might have more complex detail, including the need to reference classes in other namespaces.

    #include "a.h" DEFINE_BOOL(someflag, false, "dummy flag"); class C; // Forward declaration of class C in the global namespace. namespace a { class A; } // Forward declaration of a::A. namespace b { ...code for b... // Code goes against the left margin. } // namespace b
  • Do not declare anything in namespace std, not even forward declarations of standard library classes. Declaring entities in namespace std is undefined behavior, i.e., not portable. To declare entities from the standard library, include the appropriate header file.
  • You may use a using-directive to make all names from a namespace available, but only in a source file.
  • You may use a using-declaration anywhere in a .cpp file, and in functions, methods or classes in .h files. // OK in .cpp files. // Must be in a function, method or class in .h files. using ::foo::bar;
  • Namespace aliases are allowed anywhere in a .cpp file, anywhere inside the named namespace that wraps an entire .h file, and in functions and methods. // Shorten access to some commonly used names in .cpp files. namespace fbz = ::foo::bar::baz; // Shorten access to some commonly used names (in a .h file). namespace librarian { // The following alias is available to all files including // this header (in namespace librarian): // alias names should therefore be chosen consistently // within a project. namespace pd_s = ::pipeline_diagnostics::sidetable; inline void my_inline_function() { // namespace alias local to a function (or method). namespace fbz = ::foo::bar::baz; ... } } // namespace librarian

    Note that an alias in a .h file is visible to everyone #including that file, so public headers (those available outside a project) and headers transitively #included by them, should avoid defining aliases, as part of the general goal of keeping public APIs as small as possible.

Although you may use public nested classes when they are part of an interface, consider a namespace to keep declarations out of the global scope. A class can define another class within it; this is also called a member class. class Foo { private: // Bar is a member class, nested within Foo. class Bar { ... }; }; This is useful when the nested (or member) class is only used by the enclosing class; making it a member puts it in the enclosing class scope rather than polluting the outer scope with the class name. Nested classes can be forward declared within the enclosing class and then defined in the .cpp file to avoid including the nested class definition in the enclosing class declaration, since the nested class definition is usually only relevant to the implementation. Nested classes can be forward-declared only within the definition of the enclosing class. Thus, any header file manipulating a Foo::Bar* pointer will have to include the full class declaration for Foo. Do not make nested classes public unless they are actually part of the interface, e.g., a class that holds a set of options for some method. Prefer nonmember functions within a namespace or static member functions to global functions; use completely global functions rarely. Nonmember and static member functions can be useful in some situations. Putting nonmember functions in a namespace avoids polluting the global namespace. Nonmember and static member functions may make more sense as members of a new class, especially if they access external resources or have significant dependencies.

Sometimes it is useful, or even necessary, to define a function not bound to a class instance. Such a function can be either a static member or a nonmember function. Nonmember functions should not depend on external variables, and should nearly always exist in a namespace. Rather than creating classes only to group static member functions which do not share static data, use namespaces instead.

Functions defined in the same compilation unit as production classes may introduce unnecessary coupling and link-time dependencies when directly called from other compilation units; static member functions are particularly susceptible to this. Consider extracting a new class, or placing the functions in a namespace possibly in a separate library.

If you must define a nonmember function and it is only needed in its .cpp file, use an unnamed namespace or static linkage (eg static int foo() {...}) to limit its scope.

Place a function's variables in the narrowest scope possible, and initialize variables in the declaration.

C++ allows you to declare variables anywhere in a function. We encourage you to declare them in as local a scope as possible, and as close to the first use as possible. This makes it easier for the reader to find the declaration and see what type the variable is and what it was initialized to. In particular, initialization should be used instead of declaration and assignment, e.g.

int i; i = f(); // Bad -- initialization separate from declaration. int j = g(); // Good -- declaration has initialization.

Note that gcc implements for (int i = 0; i < 10; ++i) correctly (the scope of i is only the scope of the for loop), so you can then reuse i in another for loop in the same scope. It also correctly scopes declarations in if and while statements, e.g.

while (char const* p = strchr(str, '/')) str = p + 1;

There is one caveat: if the variable is an object, its constructor is invoked every time it enters scope and is created, and its destructor is invoked every time it goes out of scope.

// Inefficient implementation: for (int i = 0; i < 1000000; ++i) { Foo f; // My ctor and dtor get called 1000000 times each. f.do_something(i); }

It may be more efficient to declare such a variable used in a loop outside that loop:

Foo f; // My ctor and dtor get called once each. for (int i = 0; i < 1000000; ++i) { f.do_something(i); }
Classes are the fundamental unit of code in C++. Naturally, we use them extensively. This section lists the main dos and don'ts you should follow when writing a class. The purpose of a constructor is to initialise a class so that its invariants hold. For value classes it is worth having a cheap default constructor. It is possible to perform initialization in the body of the constructor. Convenience in typing. No need to worry about whether the class has been initialized or not. The problems with doing work in constructors are:
  • If the work calls virtual functions, these calls will not get dispatched to the subclass implementations. Future modification to your class can quietly introduce this problem even if your class is not currently subclassed, causing much confusion.
  • If someone creates a global variable of this type (which is against the rules, but still), the constructor code will be called before main(), possibly breaking some implicit assumptions in the constructor code.
Constructors should not make virtual calls to functions, access potentially uninitialized global variables, etc.
You must define a default constructor if your class defines member variables of POD types and has no other constructors. Otherwise the compiler will do it for you, badly. The default constructor is called when we create a class object with no arguments. It is always called when calling new[] (for arrays). Initializing structures by default makes debugging much easier. Extra work for you, the code writer.

If your class defines POD member variables and has no other constructors you must define a default constructor (one that takes no arguments). It should initialize the object in such a way that its internal state is consistent and valid.

The reason for this is that if you have no other constructors and do not define a default constructor, the compiler will generate one for you. This compiler generated constructor may not initialize your object sensibly.

If your class is composed from and/or inherits from an existing class or classes but you add no new member variables, you are not required to have a default constructor.

If your class has value semantics then consider making the class invariants such that the default constructor is cheap. For example, initialising member pointers to nullptr and allocating on first use.

Use the C++ keyword explicit for constructors with one argument. Normally, if a constructor takes one argument, it can be used as a conversion. For instance, if you define Foo::Foo(string name) and then pass a string to a function that expects a Foo, the constructor will be called to convert the string into a Foo and will pass the Foo to your function for you. This can be convenient but is also a source of trouble when things get converted and new objects created without you meaning them to. Declaring a constructor explicit prevents it from being invoked implicitly as a conversion. Avoids undesirable conversions. Avoids desirable conversions.

We require all single argument constructors to be explicit. Always put explicit in front of one-argument constructors in the class definition: explicit Foo(string name);

The exception is copy constructors, which, in the rare cases when we allow them, should probably not be explicit. Classes that are intended to be transparent wrappers around other classes are also exceptions. Such exceptions should be clearly marked with comments.

Provide a copy constructor and assignment operator only when necessary. Otherwise, disable them with the help of = delete;. The copy constructor and assignment operator are used to create copies of objects. The copy constructor is implicitly invoked by the compiler in some situations, e.g. passing objects by value. Copy constructors make it easy to copy objects. STL containers require that all contents be copyable and assignable. Copy constructors can be more efficient than CopyFrom()-style workarounds because they combine construction with copying, the compiler can elide them in some contexts, and they make it easier to avoid heap allocation. Implicit copying of objects in C++ is a rich source of bugs and of performance problems. It also reduces readability, as it becomes hard to track which objects are being passed around by value as opposed to by reference, and therefore where changes to an object are reflected.

Few classes need to be copyable. Most should have neither a copy constructor nor an assignment operator. In many situations, a pointer or reference will work just as well as a copied value, with better performance. For example, you can pass function parameters by reference or pointer instead of by value, and you can store pointers rather than objects in an STL container.

If your class needs to be copyable, prefer providing a copy method, such as CopyFrom() or Clone(), rather than a copy constructor, because such methods cannot be invoked implicitly. If a copy method is insufficient in your situation (e.g. for performance reasons, or because your class needs to be stored by value in an STL container), provide both a copy constructor and assignment operator.

If your class does not need a copy constructor or assignment operator, you must explicitly disable them.

Use a struct only for passive objects that carry data; everything else is a class.

The struct and class keywords behave almost identically in C++. We add our own semantic meanings to each keyword, so you should use the appropriate keyword for the data-type you're defining.

structs should be used for passive objects that carry data, and may have associated constants, but lack any functionality other than access/setting the data members. The accessing/setting of fields is done by directly accessing the fields rather than through method invocations. Methods should not provide behavior but should only be used to set up the data members, e.g., constructor, destructor, initialize(), reset(), validate().

If more functionality is required, a class is more appropriate. If in doubt, make it a class.

For consistency with STL, you can use struct instead of class for functors and traits.

Composition is often more appropriate than inheritance. When using inheritance, make it public. When a sub-class inherits from a base class, it includes the definitions of all the data and operations that the parent base class defines. In practice, inheritance is used in two major ways in C++: implementation inheritance, in which actual code is inherited by the child, and interface inheritance, in which only method names are inherited. Implementation inheritance reduces code size by re-using the base class code as it specializes an existing type. Because inheritance is a compile-time declaration, you and the compiler can understand the operation and detect errors. Interface inheritance can be used to programmatically enforce that a class expose a particular API. Again, the compiler can detect errors, in this case, when a class does not define a necessary method of the API. For implementation inheritance, because the code implementing a sub-class is spread between the base and the sub-class, it can be more difficult to understand an implementation. The sub-class cannot override functions that are not virtual, so the sub-class cannot change implementation. The base class may also define some data members, so that specifies physical layout of the base class.

All inheritance should be public. If you want to do private inheritance, you should be including an instance of the base class as a member instead.

Do not overuse implementation inheritance. Composition is often more appropriate. Try to restrict use of inheritance to the "is-a" case: Bar subclasses Foo if it can reasonably be said that Bar "is a kind of" Foo.

Make your destructor virtual if necessary. If your class has virtual methods, its destructor should be virtual.

Limit the use of protected to those member functions that might need to be accessed from subclasses. Note that data members should be private.

When redefining an inherited virtual method (both pure and non-pure), explicitly declare it override in the declaration of the derived class. Rationale: using override allows the compiler to consistently detect attempts to override methods that have been changed or completely removed. It also makes it straightforward for a reader to determine if a method is virtual or not.

Only very rarely is multiple inheritance of implementation actually useful. We allow multiple inheritance only when at most one of the base classes has an implementation; all other base classes must be interface classes. Multiple inheritance allows a sub-class to have more than one base class. We distinguish between base classes that are interfaces and those that have an implementation. Multiple implementation inheritance may let you re-use even more code than single inheritance (see Inheritance). Only very rarely is multiple implementation inheritance actually useful. When multiple implementation inheritance seems like the solution, you can usually find a different, more explicit, and cleaner solution. Multiple inheritance is allowed only when all superclasses, with the possible exception of the first one, are interfaces. Classes that satisfy certain conditions are interfaces.

A class is an interface if it meets the following requirements:

  • It has only public pure virtual ("= 0") methods and static methods (but see below for destructor).
  • It may not have non-static data members.
  • It need not have any constructors defined. If a constructor is provided, it must take no arguments and it must be protected.
  • If it is a subclass, it may only be derived from classes that satisfy these conditions.

An interface class can never be directly instantiated because of the pure virtual method(s) it declares. To make sure all implementations of the interface can be destroyed correctly, they must also declare a virtual, or protected, destructor (in an exception to the first rule, this should not be pure). See Stroustrup, The C++ Programming Language, 3rd edition, section 12.4 for details.

Overload operators where appropriate. A class can define that operators such as + and / operate on the class as if it were a built-in type. Can make code appear more intuitive because a class will behave in the same way as built-in types (such as int). Overloaded operators are more playful names for functions that are less-colorfully named, such as equals() or add(). For some template functions to work correctly, you may need to define operators. While operator overloading can make code more intuitive, it has several drawbacks:
  • It can fool our intuition into thinking that expensive operations are cheap, built-in operations.
  • It is much harder to find the call sites for overloaded operators. Searching for Equals() is much easier than searching for relevant invocations of ==.
  • Some operators work on pointers too, making it easy to introduce bugs. Foo + 4 may do one thing, while &Foo + 4 does something totally different. The compiler does not complain for either of these, making this very hard to debug.
Overloading also has surprising ramifications. For instance, if a class overloads unary operator&, it cannot safely be forward-declared.

In general, do overload operators where appropriate.

See also Copy Constructors and Function Overloading.

Make data members private, and provide access to them through accessor functions as needed (for technical reasons, we allow data members of a test fixture class to be protected when using Google Test). Typically a variable would be called foo and the accessor function get_foo(). You may also want a mutator function set_foo(). Exception: static const data members need not be private.

The definitions of accessors are usually inlined in the header file.

See also Inheritance and Function Names.

Use the specified order of declarations within a class: public: before private:, methods before data members (variables), etc.

Your class definition should start with its public: section, followed by its protected: section and then its private: section. If any of these sections are empty, omit them.

Within each section, the declarations generally should be in the following order:

  • Typedefs and Enums
  • Constants (static const data members)
  • Constructors
  • Destructor
  • Methods, including static methods
  • Data Members (except static const data members)

Friend declarations should always be in the private section, and the DISALLOW_COPY_AND_ASSIGN macro invocation should be at the end of the private: section. It should be the last thing in the class. See Copy Constructors.

Method definitions in the corresponding .cpp file should be the same as the declaration order, as much as possible.

Do not put large method definitions inline in the class definition. Usually, only trivial or performance-critical, and very short, methods may be defined inline. See Inline Functions for more details.

Prefer small and focused functions.

We recognize that long functions are sometimes appropriate, so no hard limit is placed on functions length. If a function exceeds about 40 lines, think about whether it can be broken up without harming the structure of the program.

Even if your long function works perfectly now, someone modifying it in a few months may add new behavior. This could result in bugs that are hard to find. Keeping your functions short and simple makes it easier for other people to read and modify your code.

You could find long and complicated functions when working with some code. Do not be intimidated by modifying existing code: if working with such a function proves to be difficult, you find that errors are hard to debug, or you want to use a piece of it in several different contexts, consider breaking up the function into smaller and more manageable pieces.

Most parameters passed by reference should be labeled const. In C, if a function needs to modify a variable, the parameter must use a pointer, eg int foo(int *pval). In C++, the function can alternatively declare a reference parameter: int foo(int& val). Defining a parameter as reference avoids ugly code like (*pval)++. Necessary for some applications like copy constructors. Makes it clear, unlike with pointers, that NULL is not a possible value. References can be confusing, as they have value syntax but pointer semantics.

Within function parameter lists all references must be const:

void foo(string const& in, string* out);

In fact it is a very strong convention in Unity code that input arguments are values or const references while output arguments are pointers. Input parameters may be const pointers. Non-const reference parameters are allowed but there must be a valid reason for it, a strong preference is given to const reference parameters.

One case when you might want an input parameter to be a const pointer is if you want to emphasize that the argument is not copied, so it must exist for the lifetime of the object; it is usually best to document this in comments as well. STL adapters such as bind2nd and mem_fun do not permit reference parameters, so you must declare functions with pointer parameters in these cases, too.

Use overloaded functions (including constructors) only if a reader looking at a call site can get a good idea of what is happening without having to first figure out exactly which overload is being called.

You may write a function that takes a string const& and overload it with another that takes char const*.

class MyClass { public: void analyze(string const& text); void analyze(char const* text, size_t textlen); };
Overloading can make code more intuitive by allowing an identically-named function to take different arguments. It may be necessary for templatized code, and it can be convenient for Visitors. If a function is overloaded by the argument types alone, a reader may have to understand C++'s complex matching rules in order to tell what's going on. Also many people are confused by the semantics of inheritance if a derived class overrides only some of the variants of a function. If you want to overload a function, consider qualifying the name with some information about the arguments, e.g., append_string(), AppendInt() rather than just append().
We do not allow default function parameters, except in a few uncommon situations explained below. Often you have a function that uses lots of default values, but occasionally you want to override the defaults. Default parameters allow an easy way to do this without having to define many functions for the rare exceptions. People often figure out how to use an API by looking at existing code that uses it. Default parameters are more difficult to maintain because copy-and-paste from previous code may not reveal all the parameters. Copy-and-pasting of code segments can cause major problems when the default arguments are not appropriate for the new code.

Except as described below, we require all arguments to be explicitly specified, to force programmers to consider the API and the values they are passing for each argument rather than silently accepting defaults they may not be aware of.

One specific exception is when default arguments are used to simulate variable-length argument lists.

// Support up to 4 params by using a default empty AlphaNum. string str_cat(AlphaNum const& a, AlphaNum const& b = gEmptyAlphaNum, AlphaNum const& c = gEmptyAlphaNum, AlphaNum const& d = gEmptyAlphaNum);
We do not allow variable-length arrays or alloca(). Variable-length arrays have natural-looking syntax. Both variable-length arrays and alloca() are very efficient. Variable-length arrays and alloca are not part of Standard C++. More importantly, they allocate a data-dependent amount of stack space that can trigger difficult-to-find memory overwriting bugs: "It ran fine on my machine, but dies mysteriously in production". Use a safe allocator instead, such as unique_ptr. We allow use of friend classes and functions, within reason.

Friends should usually be defined in the same file so that the reader does not have to look in another file to find uses of the private members of a class. A common use of friend is to have a FooBuilder class be a friend of Foo so that it can construct the inner state of Foo correctly, without exposing this state to the world. In some cases it may be useful to make a unit test class a friend of the class it tests.

Friends extend, but do not break, the encapsulation boundary of a class. In some cases this is better than making a member public when you want to give only one other class access to it. However, most classes should interact with other classes solely through their public members.

Use C++ casts like static_cast<>(). Do not use other cast formats like int y = (int)x; or int y = int(x);. C++ introduced a different cast system from C that distinguishes the types of cast operations. The problem with C casts is the ambiguity of the operation; sometimes you are doing a conversion (e.g., (int)3.5) and sometimes you are doing a cast (e.g., (int)"hello"); C++ casts avoid this. Additionally C++ casts are more visible when searching for them. The syntax is nasty.

Do not use C-style casts. Instead, use these C++-style casts.

  • Use static_cast as the equivalent of a C-style cast that does value conversion, or when you need to explicitly up-cast a pointer from a class to its superclass.
  • Use const_cast to remove the const qualifier (see const).
  • Use reinterpret_cast to do unsafe conversions of pointer types to and from integer and other pointer types. Use this only if you know what you are doing and you understand the aliasing issues.
  • Do not use dynamic_cast except in test code. If you need to know type information at runtime in this way outside of a unit test, you probably have a design flaw.
Use streams only for logging. Streams are a replacement for printf() and scanf(). With streams, you do not need to know the type of the object you are printing. You do not have problems with format strings not matching the argument list. (Though with gcc, you do not have that problem with printf either.) Streams have automatic constructors and destructors that open and close the relevant files. Streams make it difficult to do functionality like pread(). Some formatting (particularly the common format string idiom %.*s) is difficult if not impossible to do efficiently using streams without using printf-like hacks. Streams do not support operator reordering (the %1s directive), which is helpful for internationalization.

Do not use streams, except where required by a logging interface. Use printf-like routines instead.

There are various pros and cons to using streams, but in this case, as in many other cases, consistency trumps the debate. Do not use streams in your code.

There has been debate on this issue, so this explains the reasoning in greater depth. Recall the Only One Way guiding principle: we want to make sure that whenever we do a certain type of I/O, the code looks the same in all those places. Because of this, we do not want to allow users to decide between using streams or using printf plus Read/Write/etc. Instead, we should settle on one or the other. We made an exception for logging because it is a pretty specialized application, and for historical reasons.

Proponents of streams have argued that streams are the obvious choice of the two, but the issue is not actually so clear. For every advantage of streams they point out, there is an equivalent disadvantage. The biggest advantage is that you do not need to know the type of the object to be printing. This is a fair point. But, there is a downside: you can easily use the wrong type, and the compiler will not warn you. It is easy to make this kind of mistake without knowing when using streams.

cout << this; // Prints the address cout << *this; // Prints the contents

The compiler does not generate an error because << has been overloaded. We discourage overloading for just this reason.

Some say printf formatting is ugly and hard to read, but streams are often no better. Consider the following two fragments, both with the same typo. Which is easier to discover?

cerr << "Error connecting to '" << foo->bar()->hostname.first << ":" << foo->bar()->hostname.second << ": " << strerror(errno); fprintf(stderr, "Error connecting to '%s:%u: %s", foo->bar()->hostname.first, foo->bar()->hostname.second, strerror(errno));

And so on and so forth for any issue you might bring up. (You could argue, "Things would be better with the right wrappers," but if it is true for one scheme, is it not also true for the other? Also, remember the goal is to make the language smaller, not add yet more machinery that someone has to learn.)

Either path would yield different advantages and disadvantages, and there is not a clearly superior solution. The simplicity doctrine mandates we settle on one of them though, and the majority decision was on printf + read/write.

Use prefix form (++i) of the increment and decrement operators with iterators and other template objects. When a variable is incremented (++i or i++) or decremented (--i or i--) and the value of the expression is not used, one must decide whether to preincrement (decrement) or postincrement (decrement). When the return value is ignored, the "pre" form (++i) is never less efficient than the "post" form (i++), and is often more efficient. This is because post-increment (or decrement) requires a copy of i to be made, which is the value of the expression. If i is an iterator or other non-scalar type, copying i could be expensive. Since the two types of increment behave the same when the value is ignored, why not just always pre-increment? The tradition developed, in C, of using post-increment when the expression value is not used, especially in for loops. Some find post-increment easier to read, since the "subject" (i) precedes the "verb" (++), just like in English. For simple scalar (non-object) values there is no reason to prefer one form and we allow either. For iterators and other template types, use pre-increment. We strongly recommend that you use const whenever it makes sense to do so. Declared variables and parameters can be preceded by the keyword const to indicate the variables are not changed (e.g., int const foo). Class functions can have the const qualifier to indicate the function does not change the state of the class member variables (e.g., class Foo { int bar(char c) const; };). Easier for people to understand how variables are being used. Allows the compiler to do better type checking, and, conceivably, generate better code. Helps people convince themselves of program correctness because they know the functions they call are limited in how they can modify your variables. Helps people know what functions are safe to use without locks in multi-threaded programs. const is viral: if you pass a const variable to a function, that function must have const in its prototype (or the variable will need a const_cast). This can be a particular problem when calling library functions.

const variables, data members, methods and arguments add a level of compile-time type checking; it is better to detect errors as soon as possible. Therefore we strongly recommend that you use const whenever it makes sense to do so:

  • If a function does not modify an argument passed by reference or by pointer, that argument should be const.
  • Declare methods to be const whenever possible. Accessors should almost always be const. Other methods should be const if they do not modify any data members, do not call any non-const methods, and do not return a non-const pointer or non-const reference to a data member.
  • Consider making data members const whenever they do not need to be modified after construction.

However, do not go crazy with const. Something like int const* const* const x; is likely overkill, even if it accurately describes how const x is. Focus on what's really useful to know: in this case, int const** x is probably sufficient.

The mutable keyword is allowed but is unsafe when used with threads, so thread safety should be carefully considered first.

We favor the form int const* foo to const int* foo. This keeps the const with the type modifier (& or *).

That said, while we encourage putting const after the type, we do not require it. But be consistent with the code around you!

Use built-in C++ integer types, both signed and unsigned int. Use more specific types like size_t where appropriate. If a program needs a variable of a different size, use a precise-width integer type from <cstdint>, such as int16_t. C++ does not specify the sizes of its integer types. Typically people assume that short is 16 bits, int is 32 bits, long is 32 bits and long long is 64 bits. Uniformity of declaration. The sizes of integral types in C++ can vary based on compiler and architecture.

<cstdint> defines types like int16_t, uint32_t, int64_t, etc. You should always use those in preference to short, unsigned long long and the like, when you need a guarantee on the size of an integer. When appropriate, you are welcome to use standard types like size_t and ptrdiff_t.

For integers we know can be "big", use int64_t.

Code should be 64-bit and 32-bit friendly. Bear in mind problems of printing, comparisons, and structure alignment.
  • printf() specifiers for some types are not cleanly portable between 32-bit and 64-bit systems. C99 defines some portable format specifiers. Unfortunately, MSVC 7.1 does not understand some of these specifiers and the standard is missing a few, so we have to define our own ugly versions in some cases (in the style of the standard include file inttypes.h):

    // printf macros for size_t, in the style of inttypes.h #ifdef _LP64 #define __PRIS_PREFIX "z" #else #define __PRIS_PREFIX #endif // Use these macros after a % in a printf format string // to get correct 32/64 bit behavior, like this: // size_t size = records.size(); // printf("%"PRIuS"\n", size); #define PRIdS __PRIS_PREFIX "d" #define PRIxS __PRIS_PREFIX "x" #define PRIuS __PRIS_PREFIX "u" #define PRIXS __PRIS_PREFIX "X" #define PRIoS __PRIS_PREFIX "o"
    Type DO NOT use DO use Notes
    void* (or any pointer) %lx %p
    int64_t %qd, %lld %"PRId64"
    uint64_t %qu, %llu, %llx %"PRIu64", %"PRIx64"
    size_t %u %"PRIuS", %"PRIxS" C99 specifies %zu
    ptrdiff_t %d %"PRIdS" C99 specifies %zd

    Note that the PRI* macros expand to independent strings which are concatenated by the compiler. Hence if you are using a non-constant format string, you need to insert the value of the macro into the format, rather than the name. It is still possible, as usual, to include length specifiers, etc., after the % when using the PRI* macros. So, e.g. printf("x = %30"PRIuS"\n", x) would expand on 32-bit Linux to printf("x = %30" "u" "\n", x), which the compiler will treat as printf("x = %30u\n", x).

  • Remember that sizeof(void*) != sizeof(int). Use intptr_t if you want a pointer-sized integer.
  • You may need to be careful with structure alignments, particularly for structures being stored on disk. Any class/structure with a int64_t/uint64_t member will by default end up being 8-byte aligned on a 64-bit system. If you have such structures being shared on disk between 32-bit and 64-bit code, you will need to ensure that they are packed the same on both architectures. Most compilers offer a way to alter structure alignment. For gcc, you can use __attribute__((packed)). MSVC offers #pragma pack() and __declspec(align()).
  • Use the LL or ULL suffixes as needed to create 64-bit constants. For example: int64_t my_value = 0x123456789LL; uint64_t my_mask = 3ULL << 48;
  • If you really need different code on 32-bit and 64-bit systems, use #ifdef _LP64 to choose between the code variants. (But please avoid this if possible, and keep any such changes localized.)
Be very cautious with macros. Prefer inline functions, enums, and const variables to macros.

Macros mean that the code you see is not the same as the code the compiler sees. This can introduce unexpected behavior, especially since macros have global scope.

Luckily, macros are not nearly as necessary in C++ as they are in C. Instead of using a macro to inline performance-critical code, use an inline function. Instead of using a macro to store a constant, use a const variable. Instead of using a macro to "abbreviate" a long variable name, use a reference. Instead of using a macro to conditionally compile code ... well, don't do that at all (except, of course, for the #define guards to prevent double inclusion of header files). It makes testing much more difficult.

Macros can do things these other techniques cannot, and you do see them in the codebase, especially in the lower-level libraries. And some of their special features (like stringifying, concatenation, and so forth) are not available through the language proper. But before using a macro, consider carefully whether there's a non-macro way to achieve the same result.

The following usage pattern will avoid many problems with macros; if you use macros, follow it whenever possible:

  • Don't define macros in a .h file.
  • #define macros right before you use them, and #undef them right after.
  • Do not just #undef an existing macro before replacing it with your own; instead, pick a name that's likely to be unique.
  • Try not to use macros that expand to unbalanced C++ constructs, or at least document that behavior well.
  • Prefer not using ## to generate function/class/variable names.
Use 0 for integers, 0.0 for reals, nullptr for pointers, and '\0' for chars.

Use 0 for integers and 0.0 for reals. This is not controversial.

For pointers (address values), C++11 added the nullptr construct. This allows the compiler to do additional checks, and is the preferred NULL pointer value.

Use '\0' for chars. This is the correct type and also makes code more readable.

Use sizeof(varname) instead of sizeof(type) whenever possible.

Use sizeof(varname) because it will update appropriately if the type of the variable changes. sizeof(type) may make sense in some cases, but should generally be avoided because it can fall out of sync if the variable's type changes.

Struct data; memset(&data, 0, sizeof(data)); memset(&data, 0, sizeof(Struct));

Use C++11 features wherever appropriate. C++11 is the current ISO C++ standard. It contains significant changes both to the language and libraries from the older standard.

The most important consistency rules are those that govern naming. The style of a name immediately informs us what sort of thing the named entity is: a type, a variable, a function, a constant, a macro, etc., without requiring us to search for the declaration of that entity. The pattern-matching engine in our brains relies a great deal on these naming rules.

Naming rules are pretty arbitrary, but we feel that consistency is more important than individual preferences in this area, so regardless of whether you find them sensible or not, the rules are the rules.

Function names, variable names, and filenames should be descriptive; eschew abbreviation. Types and variables should be nouns, while functions should be "command" verbs.

Give as descriptive a name as possible, within reason. Do not worry about saving horizontal space as it is far more important to make your code immediately understandable by a new reader. Examples of well-chosen names:

int num_errors; // Good. int num_completed_connections; // Good.

Poorly-chosen names use ambiguous abbreviations or arbitrary characters that do not convey meaning:

int n; // Bad - meaningless. int nerr; // Bad - ambiguous abbreviation. int n_comp_conns; // Bad - ambiguous abbreviation.

Type and variable names should typically be nouns: e.g., FileOpener, num_errors.

Function names should typically be imperative (that is they should be commands): e.g., open_file(), set_num_errors(). There is an exception for accessors, which, described more completely in Function Names, should be named the same as the variable they access.

Do not use abbreviations unless they are extremely well known outside your project. For example:

// Good // These show proper names with no abbreviations. int num_dns_connections; // Most people know what "DNS" stands for. int price_count_reader; // OK, price count. Makes sense. // Bad! // Abbreviations can be confusing or ambiguous outside a small group. int wgc_connections; // Only your group knows what this stands for. int pc_reader; // Lots of things can be abbreviated "pc".

Never abbreviate by leaving out letters:

int error_count; // Good. int error_cnt; // Bad.
Filenames should be all lowercase and can include underscores (_) or dashes (-). Follow the convention that your project uses. If there is no consistent local pattern to follow, prefer "_".

Examples of acceptable file names:

my_useful_class.cpp
my-useful-class.cpp
myusefulclass.cpp
test_myusefulclass.cpp // _unittest and _regtest are deprecated.

C++ files should end in .cpp and header files should end in .h.

Do not use filenames that already exist in /usr/include, such as db.h.

In general, make your filenames very specific. For example, use http_server_logs.h rather than logs.h. A very common case is to have a pair of files called, e.g., foo_bar.h and foo_bar.cpp, defining a class called FooBar.

Inline functions must be in a .h file. If your inline functions are very short, they should go directly into your .h file. However, if your inline functions include a lot of code, they may go into a third file that ends in -inl.h. In a class with a lot of inline code, your class could have three files:

url_table.h // The class declaration. url_table.cpp // The class definition. url_table-inl.h // Inline functions that include lots of code.

See also the section -inl.h Files

Type names start with a capital letter and have a capital letter for each new word, with no underscores: MyExcitingClass, MyExcitingEnum.

The names of all types — classes, structs, typedefs, and enums — have the same naming convention. Type names should start with a capital letter and have a capital letter for each new word. No underscores. For example:

// classes and structs class UrlTable ... class UrlTableTester ... struct UrlTableProperties ... // typedefs typedef hash_map<UrlTableProperties*, string> PropertiesMap; // enums enum UrlTableErrors ...
Variable names are all lowercase, with underscores between words. Class member variables follow this convention. For instance: my_exciting_local_variable, my_exciting_member_variable.

For example:

string table_name; // OK - uses underscore. string tablename; // OK - all lowercase. string tableName; // Bad - mixed case.

Data members (also called instance variables or member variables) are lowercase with optional underscores like regular variable names.

string table_name; // OK - underscore at end. string tablename; // OK.

Data members in structs should be named like regular variables.

struct UrlTableProperties { string name; int num_entries; }

See Structs vs. Classes for a discussion of when to use a struct versus a class.

There are no special requirements for global variables, which should be rare in any case, but if you use one, consider prefixing it with g_ or some other marker to easily distinguish it from local variables.

Name constants like other variables, using all lowercase, with underscores between words. default_width.

It is distracting that whether a variable is "const" affects the name.

auto const match = map.find(value); int const width{1024}; int height{900};
Regular functions, accessors, and mutators are all lowercase, with underscores between words.

Functions and accessors are all lowercase, with underscores between words.

If your function crashes upon an error, you should append _or_die to the function name. This only applies to functions which could be used by production code and to errors that are reasonably likely to occur during normal operation.

add_table_entry() delete_url() open_file_or_die()

Accessors and mutators (get and set functions) should follow the naming conventions for regular functions.

class MyClass { public: ... int get_num_entries() const { return num_entries; } void set_num_entries(int value) { num_entries = value; } private: int num_entries; };
Namespace names are all lower-case, and based on project names and possibly their directory structure: my_awesome_project.

See Namespaces for a discussion of namespaces and how to name them.

Enumerators should be named like member variables: out_of_memory, enclosed within an enum class.

Preferably, the individual enumerators should be named like class data members. The enumeration name, UrlTableErrors, is a type, and therefore mixed case.

enum class UrlTableErrors { ok, out_of_memory, malformed_input, };
You're not really going to define a macro, are you? If you do, they're like this: MY_MACRO_THAT_SCARES_SMALL_CHILDREN.

Please see the description of macros; in general macros should not be used. However, if they are absolutely needed, then they should be named with all capitals and underscores.

#define ROUND(x) ... #define PI_ROUNDED 3.0
If you are naming something that is analogous to an existing C or C++ entity then you can follow the existing naming convention scheme.

bigopen()
function name, follows form of open()
uint
typedef
bigpos
struct or class, follows form of pos
sparse_hash_map
STL-like entity; follows STL naming conventions
LONGLONG_MAX
a constant, as in INT_MAX

Though a pain to write, comments are absolutely vital to keeping our code readable. The following rules describe what you should comment and where. But remember: while comments are very important, the best code is self-documenting. Giving sensible names to types and variables is much better than using obscure names that you must then explain through comments.

When writing your comments, write for your audience: the next contributor who will need to understand your code. Be generous — the next one may be you!

Use either the // or /* */ syntax, as long as you are consistent.

You can use either the // or the /* */ syntax; however, // is much more common. Be consistent with how you comment and what style you use where.

Start each file with a copyright notice, followed by a description of the contents of the file.

Every file should contain the following items, in order:

  • a optional mode line, // -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
  • a copyright statement (for example, Copyright (C) 2011 Canonical Ltd)
  • the license boilerplate.
  • an author line to identify the original author of the file

If you make significant changes to a file that someone else originally wrote, add yourself to the author line. This can be very helpful when another contributor has questions about the file and needs to know whom to contact about it.

Every file should have a comment at the top, below the copyright notice and author line, that describes the contents of the file.

Generally a .h file will describe the classes that are declared in the file with an overview of what they are for and how they are used. A .cpp file should contain more information about implementation details or discussions of tricky algorithms. If you feel the implementation details or a discussion of the algorithms would be useful for someone reading the .h, feel free to put it there instead, but mention in the .cpp that the documentation is in the .h file.

Do not duplicate comments in both the .h and the .cpp. Duplicated comments diverge.

Every class definition should have an accompanying comment that describes what it is for and how it should be used. // Iterates over the contents of a GargantuanTable. Sample usage: // GargantuanTableIterator* iter = table->new_iterator(); // for (iter->seek("foo"); !iter->done(); iter->next()) // { // process(iter->key(), iter->value()); // } // delete iter; class GargantuanTableIterator { ... };

If you have already described a class in detail in the comments at the top of your file feel free to simply state "See comment at top of file for a complete description", but be sure to have some sort of comment.

Document the synchronization assumptions the class makes, if any. If an instance of the class can be accessed by multiple threads, take extra care to document the rules and invariants surrounding multithreaded use.

Declaration comments describe use of the function; comments at the definition of a function describe operation.

Every function declaration should have comments immediately preceding it that describe what the function does and how to use it. These comments should be descriptive ("Opens the file") rather than imperative ("Open the file"); the comment describes the function, it does not tell the function what to do. In general, these comments do not describe how the function performs its task. Instead, that should be left to comments in the function definition.

Types of things to mention in comments at the function declaration:

  • What the inputs and outputs are.
  • For class member functions: whether the object remembers reference arguments beyond the duration of the method call, and whether it will free them or not.
  • If the function allocates memory that the caller must free.
  • Whether any of the arguments can be NULL.
  • If there are any performance implications of how a function is used.
  • If the function is re-entrant. What are its synchronization assumptions?

Here is an example:

// Returns an iterator for this table. It is the client's // responsibility to delete the iterator when it is done with it, // and it must not use the iterator once the GargantuanTable object // on which the iterator was created has been deleted. // // The iterator is initially positioned at the beginning of the table. // // This method is equivalent to: // Iterator* iter = table->new_iterator(); // iter->seek(""); // return iter; // If you are going to immediately seek to another place in the // returned iterator, it will be faster to use new_iterator() // and avoid the extra seek. Iterator* get_iterator() const;

However, do not be unnecessarily verbose or state the completely obvious. Notice below that it is not necessary to say "returns false otherwise" because this is implied.

// Returns true if the table cannot hold any more entries. bool is_table_full();

When commenting constructors and destructors, remember that the person reading your code knows what constructors and destructors are for, so comments that just say something like "destroys this object" are not useful. Document what constructors do with their arguments (for example, if they take ownership of pointers), and what cleanup the destructor does. If this is trivial, just skip the comment. It is quite common for destructors not to have a header comment.

Each function definition should have a comment describing what the function does if there's anything tricky about how it does its job. For example, in the definition comment you might describe any coding tricks you use, give an overview of the steps you go through, or explain why you chose to implement the function in the way you did rather than using a viable alternative. For instance, you might mention why it must acquire a lock for the first half of the function but why it is not needed for the second half.

Note you should not just repeat the comments given with the function declaration, in the .h file or wherever. It's okay to recapitulate briefly what the function does, but the focus of the comments should be on how it does it.

In general the actual name of the variable should be descriptive enough to give a good idea of what the variable is used for. In certain cases, more comments are required.

Each class data member (also called an instance variable or member variable) should have a comment describing what it is used for. If the variable can take sentinel values with special meanings, such as NULL or -1, document this. For example:

private: // Keeps track of the total number of entries in the table. // Used to ensure we do not go over the limit. -1 means // that we don't yet know how many entries the table has. int num_total_entries;

As with data members, all global variables should have a comment describing what they are and what they are used for. For example:

// The total number of tests cases that we run through in this regression test. const int number_of_test_cases = 6;
In your implementation you should have comments in tricky, non-obvious, interesting, or important parts of your code.

Tricky or complicated code blocks should have comments before them. Example:

// Divide result by two, taking into account that x // contains the carry from the add. for (int i = 0; i < result->size(); i++) { x = (x << 8) + (*result)[i]; (*result)[i] = x >> 1; x &= 1; }

Also, lines that are non-obvious should get a comment at the end of the line. These end-of-line comments should be separated from the code by 2 spaces. Example:

// If we have enough memory, mmap the data portion too. mmap_budget = max<int64>(0, mmap_budget - index_->length()); if (mmap_budget >= data_size_ && !mmap_data(mmap_chunk_bytes, mlock)) return; // Error already logged.

Note that there are both comments that describe what the code is doing, and comments that mention that an error has already been logged when the function returns.

If you have several comments on subsequent lines, it can often be more readable to line them up:

do_something(); // Comment here so the comments line up. do_Something_else_that_is_longer(); // Comment here so there are two spaces between // the code and the comment. { // Three space before comment when opening a new scope is allowed, // thus the comment lines up with the following comments and code. do_something_else(); // Two spaces before line comments normally. }

When you pass in nullptr, boolean, or literal integer values to functions, you should consider adding a comment about what they are, or make your code self-documenting by using constants. For example, compare:

bool success = calculate_something(interesting_value, 10, false, nullptr); // What are these arguments??

versus:

bool success = calculate_something(interesting_value, 10, // Default base value. false, // Not the first time we're calling this. nullptr); // No callback.

Or alternatively, constants or self-describing variables:

int const default_base_value = 10; bool const first_time_calling = false; Callback* null_callback = nullptr; bool success = calculate_something(interesting_value, default_base_value, first_time_calling, null_callback);

Note that you should never describe the code itself. Assume that the person reading the code knows C++ better than you do, even though he or she does not know what you are trying to do:

// Now go through the b array and make sure that if i occurs, // the next element is i+1. ... // Geez. What a useless comment.
Pay attention to punctuation, spelling, and grammar; it is easier to read well-written comments than badly written ones.

Comments should usually be written as complete sentences with proper capitalization and periods at the end. Shorter comments, such as comments at the end of a line of code, can sometimes be less formal, but you should be consistent with your style. Complete sentences are more readable, and they provide some assurance that the comment is complete and not an unfinished thought.

Although it can be frustrating to have a code reviewer point out that you are using a comma when you should be using a semicolon, it is very important that source code maintain a high level of clarity and readability. Proper punctuation, spelling, and grammar help with that goal.

Use TODO comments for code that is temporary, a short-term solution, or good-enough but not perfect.

TODOs should include the string TODO in all caps, followed by the name, e-mail address, or other identifier of the person who can best provide context about the problem referenced by the TODO. A colon is optional. The main purpose is to have a consistent TODO format that can be searched to find the person who can provide more details upon request. A TODO is not a commitment that the person referenced will fix the problem. Thus when you create a TODO, it is almost always your name that is given.

// TODO(kl@gmail.com): Use a "*" here for concatenation operator. // TODO(Zeke) change this to use relations.

If your TODO is of the form "At a future date do something" make sure that you either include a very specific date ("Fix by November 2005") or a very specific event ("Remove this code when all clients can handle XML responses.").

Mark deprecated interface points with DEPRECATED comments.

You can mark an interface as deprecated by writing a comment containing the word DEPRECATED in all caps. The comment goes either before the declaration of the interface or on the same line as the declaration.

After the word DEPRECATED, write your name, e-mail address, or other identifier in parentheses.

A deprecation comment must include simple, clear directions for people to fix their callsites. In C++, you can implement a deprecated function as an inline function that calls the new interface point.

Marking an interface point DEPRECATED will not magically cause any callsites to change. If you want people to actually stop using the deprecated facility, you will have to fix the callsites yourself or recruit a crew to help you.

New code should not contain calls to deprecated interface points. Use the new interface point instead. If you cannot understand the directions, find the person who created the deprecation and ask them for help using the new interface point.

Coding style and formatting are pretty arbitrary, but a project is much easier to follow if everyone uses the same style. Individuals may not agree with every aspect of the formatting rules, and some of the rules may take some getting used to, but it is important that all project contributors follow the style rules so that they can all read and understand everyone's code easily.

Each line of text in your code should be at most 120 characters long.

We recognize that this rule is controversial, with so much existing code already adhering to a maximum line length of 80 characters. However, we favor sensible naming of variables and functions over the limit of 80 characters.

Those who favor this rule argue that it is rude to force them to resize their windows and there is no need for anything longer. Some folks are used to having several code windows side-by-side, and thus don't have room to widen their windows in any case. People set up their work environment assuming a particular maximum window width, and 80 columns has been the traditional standard. Why change it? Proponents of change argue that a wider line can make code more readable. The 80-column limit is an hidebound throwback to 1960s mainframes; modern equipment has wide screens that can easily show longer lines.

120 characters is the maximum.

Non-ASCII characters should be rare, and must use UTF-8 formatting.

You shouldn't hard-code user-facing text in source, even English, so use of non-ASCII characters should be rare. However, in certain cases it is appropriate to include such words in your code. For example, if your code parses data files from foreign sources, it may be appropriate to hard-code the non-ASCII string(s) used in those data files as delimiters. More commonly, unit test code (which does not need to be localized) might contain non-ASCII strings. In such cases, you should use UTF-8, since that is an encoding understood by most tools able to handle more than just ASCII. Hex encoding is also OK, and encouraged where it enhances readability — for example, "\xEF\xBB\xBF" is the Unicode zero-width no-break space character, which would be invisible if included in the source as straight UTF-8.

Use only spaces, and indent 4 spaces at a time.

We use spaces for indentation. Do not use tabs in your code. You should set your editor to emit spaces when you hit the tab key.

Return type on the same line as function name, parameters on the same line if they fit.

Functions look like this:

ReturnType ClassName::function_name(Type par_name1, Type par_name2) { do_something(); ... }

or:

ReturnType ClassName::really_long_function_name(Type par_name1, Type par_name2, Type par_name3) { do_something(); ... }

or:

ReturnType LongClassName::really_really_really_long_function_name( Type par_name1, // 4 space indent Type par_name2, Type par_name3) { do_something(); // 4 space indent ... }

Some points to note:

  • The return type is always on the same line as the function name.
  • The open parenthesis is always on the same line as the function name.
  • There is never a space between the function name and the open parenthesis.
  • There is never a space between the parentheses and the parameters.
  • The open curly brace is always on the line following the last parameter.
  • The close curly brace is either on the last line by itself or (if other style rules permit) on the same line as the open curly brace.
  • All parameters should be named, with identical names in the declaration and implementation. (Except where unused parameters are suppressed in the implementation.)
  • All parameters should be in a single line if possible, otherwise:
    • Wrap groups of parameters into the next line, and align the first wrapped parameter to the first parameter in the previous line.
    • Place each parameter in a separate line and indent each with 4 spaces.

If your function is const, the const keyword should be on the same line as the last parameter:

// Everything in this function signature fits on a single line ReturnType function_name(Type par) const { ... } // This function signature requires multiple lines, but // the const keyword is on the line with the last parameter. ReturnType really_long_function_name(Type par1, Type par2) const { ... }

If some parameters are unused, comment out the variable name in the function definition:

// Always have named parameters in interfaces. class Shape { public: virtual void rotate(double radians) = 0; } // Always have named parameters in the declaration. class Circle : public Shape { public: virtual void rotate(double radians); } // Comment out unused named parameters in definitions. void Circle::rotate(double /*radians*/) {} // Bad - if someone wants to implement later, it's not clear what the // variable means. void Circle::rotate(double) {}
On one line if it fits; otherwise, wrap arguments at the parenthesis.

Function calls have the following format:

bool retval = do_something(argument1, argument2, argument3);

If the arguments do not all fit on one line, they should be broken up onto multiple lines, with each subsequent line aligned with the first argument. Do not add spaces after the open paren or before the close paren:

bool retval = do_something(averyveryveryverylongargument1, argument2, argument3);

If the function has many arguments, consider having one per line if this makes the code more readable:

bool retval = do_something(argument1, argument2, argument3, argument4);

If the function signature is so long that it cannot fit within the maximum line length, you may place all arguments on subsequent lines:

if (...) { ... ... if (...) { do_something_that_requires_a_long_function_name( very_long_argument1, // 4 space indent argument2, argument3, argument4); } }
Prefer no spaces inside parentheses. The else keyword belongs on a new line. if (condition) // no spaces inside parentheses { ... // 4 space indent. } else // The else goes on a new line. { ... }

Note that in all cases you must have a space between the if and the open parenthesis.

if(condition) // Bad - space missing after IF. if (condition) // Good - proper space after IF.

Short conditional statements may be written on one line if this enhances readability. You may use this only when the line is brief and the statement does not use the else clause.

if (x == foo) return new Foo(); if (x == bar) return new Bar();

This is not allowed when the if statement has an else:

// Not allowed - IF statement on one line when there is an ELSE clause if (x) do_this(); else do_that();

In general, curly braces are not required for single-line statements, but they are allowed if you like them; conditional or loop statements with complex conditions or statements may be more readable with curly braces. Some projects require that an if must always always have an accompanying brace.

if (condition) do_something(); // 4 space indent. if (condition) { do_something(); // 4 space indent. }

However, if one part of an if-else statement uses curly braces, the other part must too:

// Not allowed - curly on IF but not ELSE if (condition) { foo; } else bar; // Not allowed - curly on ELSE but not IF if (condition) foo; else { bar; } // Curly braces around both IF and ELSE required because // one of the clauses used braces. if (condition) { foo; } else { bar; }
Switch statements may use braces for blocks. Empty loop bodies should use {} or continue.

case blocks in switch statements can have curly braces or not, depending on your preference. If you do include curly braces they should be placed as shown below.

If not conditional on an enumerated value, switch statements should always have a default case (in the case of an enumerated value, the compiler will warn you if any values are not handled). If the default case should never execute, simply assert:

switch (var) { case 0: // no indent ... // 4 space indent break; case 1: { ... break; } default: assert(false); }

Empty loop bodies should use {} or continue, but not a single semicolon.

while (condition) { // Repeat test until it returns false. } for (int i = 0; i < some_number_with_descriptive_name; ++i) {} // Good - empty body. while (condition) continue; // Good - continue indicates no logic. while (condition); // Bad - looks like part of do/while loop.
No spaces around period or arrow. Pointer operators do not have trailing spaces.

The following are examples of correctly-formatted pointer and reference expressions:

x = *p; p = &x; x = r.y; x = r->y;

Note that:

  • There are no spaces around the period or arrow when accessing a member.
  • Pointer operators have no space after the * or &.

When declaring a pointer variable or argument, you should place the asterisk adjacent to the type:

// These are fine char* c; string const& str; char * c; // Bad - spaces on both sides of * char *c ; // Bad - * next to variable name string const & str; // Bad - spaces on both sides of &

You should do this consistently within a single file, so, when modifying an existing file, use the style in that file.

When you have a boolean expression that is longer than the standard line length, be consistent in how you break up the lines.

In this example, the logical AND operator is always at the end of the lines:

if (this_one_thing > this_other_thing && a_third_thing == a_fourth_thing && yet_another && last_one) { ... }

Note that when the code wraps in this example, both of the && logical AND operators are at the end of the line. Feel free to insert extra parentheses judiciously, because they can be very helpful in increasing readability when used appropriately. Also note that you should always use the punctuation operators, such as && and ~, rather than the word operators, such as and and compl.

Do not needlessly surround the return expression with parentheses.

Use parentheses in return expr; only where you would use them in x = expr;.

return result; // No parentheses in the simple case. return (some_long_condition && // Parentheses ok to make a complex another_condition); // expression more readable. return (value); // You wouldn't write var = (value); return(result); // return is not a function!
Use {}.

You may choose between = and (); the following are all correct:

//C++11: default initialization using {} int n{5}; //zero initialization: n is initialized to 5 int* p{}; //initialized to nullptr double d{}; //initialized to 0.0 char s[12]{}; //all 12 chars are initialized to '\0' string s{}; //same as: string s; string name{"Some Name"}; char* p=new char [5]{}; // all five chars are initialized to '\0'
The hash mark that starts a preprocessor directive should always be at the beginning of the line.

Even when preprocessor directives are within the body of indented code, the directives should start at the beginning of the line.

// Good - directives at beginning of line if (lopsided_score) { #if DISASTER_PENDING // Correct -- Starts at beginning of line drop_everything(); # if NOTIFY // OK but not required -- Spaces after # notify_client(); # endif #endif back_to_normal(); } // Bad - indented directives if (lopsided_score) { #if DISASTER_PENDING // Wrong! The "#if" should be at beginning of line drop_everything(); #endif // Wrong! Do not indent "#endif" back_to_normal(); }
Sections in public, protected and private order.

The basic format for a class declaration (lacking the comments, see Class Comments for a discussion of what comments are needed) is:

class MyClass : public OtherClass { public: MyClass(); // Regular 4 space indent. explicit MyClass(int var); ~MyClass() {} void some_function(); void some_function_that_does_nothing() {} void set_some_var(int var) { some_var_ = var; } int some_var() const { return some_var_; } private: MyClass(MyClass const&) = delete; MyClass& operator=(MyClass const&) = delete; bool some_internal_function(); int some_var_; int some_other_var; };

Things to note:

  • Any base class name should be on the same line as the subclass name, subject to the 80-column limit.
  • The public:, protected:, and private: keywords are not indented.
  • Except for the first instance, these keywords should be preceded by a blank line. This rule is optional in small classes.
  • Do not leave a blank line after these keywords.
  • The public section should be first, followed by the protected and finally the private section.
  • See Declaration Order for rules on ordering declarations within each of these sections.
Constructor initializer lists can be all on one line or with subsequent lines indented four spaces.

There are three acceptable formats for initializer lists:

// When it all fits on one line: MyClass::MyClass(int var) : some_var_(var), some_other_var_(var + 1) {}

or

// When it requires multiple lines, indent 4 spaces, putting the colon on // the constructor declaration line and commas at the end of the line. MyClass::MyClass(int var) : some_var_(var), // 4 space indent some_other_var_(var + 1) { ... do_something(); ... }

or

// When it requires multiple lines, indent 4 spaces, putting the colon on // the first initializer line and commas at the end of the line. MyClass::MyClass(int var) : some_var_(var), // 4 space indent some_other_var_(var + 1) { ... do_something(); ... }
The contents of namespaces are not indented.

Namespaces do not add an extra level of indentation. For example, use:

namespace { void foo() // Correct. No extra indentation within namespace. { ... } } // namespace

Do not indent within a namespace:

namespace { // Wrong. Indented when it should not be. void foo() { ... } } // namespace

When declaring nested namespaces, put each namespace on its own line, with the opening brace on the line following.

namespace foo { namespace bar {
Use of horizontal whitespace depends on location. Never put trailing whitespace at the end of a line. int i = 0; // Semicolons usually have no space before them. int x[] = { 0 }; // Spaces inside braces for array initialization are int x[] = {0}; // optional. If you use them, put them on both sides! // Spaces around the colon in inheritance and initializer lists. class Foo : public Bar { public: // For inline function implementations, put spaces between the braces // and the implementation itself. Foo(int b) : Bar(), baz_(b) {} // No spaces inside empty braces. void reset() { baz_ = 0; } // Spaces separating braces from implementation. ...

Adding trailing whitespace can cause extra work for others editing the same file, when they merge, as can removing existing trailing whitespace. So: Don't introduce trailing whitespace. Remove it if you're already changing that line, or do it in a separate clean-up operation (preferably when no-one else is working on the file).

x = 0; // Assignment operators always have spaces around // them. x = -5; // No spaces separating unary operators and their ++x; // arguments. if (x && !y) ... v = w * x + y / z; // Binary operators usually have spaces around them, v = w*x + y/z; // but it's okay to remove spaces around factors. v = w * (x + z); // Parentheses should have no spaces inside them. vector<string> x; // No spaces inside the angle y = static_cast<char*>(x); // brackets (< and >), before // <, or between >( in a cast. vector<char*> x; // Spaces between type and pointer are // okay, but be consistent. set<list<string>> x; // C++11 now allows >> to close templates. set<list<string> > x; // Older C++ requiree a space in > >, and is allowed.
Minimize use of vertical whitespace but apply it to enhance readability.

This is more a principle than a rule: don't use blank lines when you don't have to. In particular, don't put more than one or two blank lines between functions, resist starting functions with a blank line, don't end functions with a blank line, and be discriminating with your use of blank lines inside functions.

The basic principle is: The more code that fits on one screen, the easier it is to follow and understand the control flow of the program. Of course, readability can suffer from code being too dense as well as too spread out, so use your judgement. But in general, minimize use of vertical whitespace.

Some rules of thumb to help when blank lines may be useful:

  • Blank lines at the beginning or end of a function very rarely help readability.
  • Blank lines inside a chain of if-else blocks may well help readability.

The coding conventions described above are mandatory. However, like all good rules, these sometimes have exceptions, which we discuss here.

You may diverge from the rules when dealing with code that does not conform to this style guide.

If you find yourself modifying code that was written to specifications other than those presented by this guide, you may have to diverge from these rules in order to stay consistent with the local conventions in that code. If you are in doubt about how to do this, ask the original author or the person currently responsible for the code. Remember that consistency includes local consistency, too.

Use common sense and BE CONSISTENT.

If you are editing code, take a few minutes to look at the code around you and determine its style. If they use spaces around their if clauses, you should, too. If their comments have little boxes of stars around them, make your comments have little boxes of stars around them too.

The point of having style guidelines is to have a common vocabulary of coding so people can concentrate on what you are saying, rather than on how you are saying it. We present global style rules here so people know the vocabulary. But local style is also important. If code you add to a file looks drastically different from the existing code around it, the discontinuity throws readers out of their rhythm when they go to read it. Try to avoid this.

OK, enough writing about writing code; the code itself is much more interesting. Have fun!

./guides/styleguide.css0000644000004100000410000000443613115234416015422 0ustar www-datawww-databody { background-color: #fff; color: #333; font-family: Ubuntu,Arial,sans-serif; font-size: 10pt; margin-right: 100px; margin-left: 100px; } h1, h2, h3, h4, h5, h6, .toc_title { color: #dd4814; margin-top: 2em; margin-bottom: 1em; } h1 { text-align: center; font-size: 18pt; } h2, .toc_title { font-weight: bold; font-size: 12pt; margin-left: -40px; } h3, h4, h5, h6 { font-size: 10pt; margin-left: -20px; } .toc_category, .toc_stylepoint { font-size: 10pt; padding-top: .3em; padding-bottom: .3em; } table { border-collapse: collapse; } td, th { border: 1px solid #ccc; padding: 2px 12px; font-size: 10pt; } .toc td, .toc th { border-width: 1px 5px; } code, samp, var { color: #060; } pre { font-size: 10pt; display: block; color: #060; background-color: #f8fff8; border-color: #f0fff0; border-style: solid; border-top-width: 1px; border-bottom-width: 1px; border-right-width: 1px; border-left-width: 5px; padding-left: 12px; padding-right: 12px; padding-top: 4px; padding-bottom: 4px; } pre.badcode { color: #c00; background-color: #fff8f8; border-color: #fff0f0; } .showhide_button { float: left; cursor: pointer; border-width: 1px; border-style: solid; border-color: #ddd #aaa #aaa #ddd; padding: 0 3px 1px; margin: 0 4px 8px 0; border-radius: 3px; -webkit-border-radius: 3px; -moz-border-radius: 3px; } .link_button { float: left; display: none; background-color: #f8f8ff; border-color: #f0f0ff; border-style: solid; border-width: 1px; font-size: 75%; margin-top: 0; margin-left: -50px; padding: 4px; border-radius: 3px; -webkit-border-radius: 3px; -moz-border-radius: 3px; } address { text-align: right; } hr { margin-top: 3.5em; border-width: 1px; color: #fff; } .stylepoint_section { display: block; margin-bottom: 1em; color: #772953; font-family: Ubuntu,Arial,sans-serif; font-size: 90%; font-weight: bold; margin-left: -2%; } .stylepoint_subsection { color: #667799; font-family: Ubuntu,Arial,sans-serif; font-size: 90%; font-weight: bold; margin-left: -1%; } .stylepoint_subsubsection { color: #667799; font-family: Ubuntu,Arial,sans-serif; font-size: 80%; font-weight: bold; margin-left: 0; } .revision { text-align: right; } ./src/0000755000004100000410000000000013115234677012043 5ustar www-datawww-data./src/CMakeLists.txt0000644000004100000410000000422613115234664014603 0ustar www-datawww-data# We need MIRPLATFORM_ABI in both libmirplatform and the platform implementations. set(MIRPLATFORM_ABI 15) # Add the cookie implementation before exposing any APIs add_subdirectory(cookie/) # We need MIR_CLIENT_PLATFORM_PATH in both libmirclient and the platform # implementations set(MIR_CLIENT_PLATFORM_PATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/mir/client-platform ) # Add the core and platform implementations before exposing any private APIs add_subdirectory(core) add_subdirectory(platforms/) # the src/include/... directories should be private to the implementation include_directories(${PROJECT_SOURCE_DIR}/src/include/common) set(MIR_GENERATED_INCLUDE_DIRECTORIES) add_subdirectory(capnproto/) add_subdirectory(common/) add_subdirectory(protobuf/) include_directories(${MIR_GENERATED_INCLUDE_DIRECTORIES}) add_subdirectory(platform/) add_subdirectory(server/) add_subdirectory(client/) add_subdirectory(utils/) add_subdirectory(renderer/) add_subdirectory(renderers/) add_subdirectory(gl/) add_executable(wrapper wrapper.c) target_compile_definitions(wrapper PUBLIC EXECUTABLE_FORMAT=\"%s.bin\" _DEFAULT_SOURCE _BSD_SOURCE) set( MIR_GENERATED_INCLUDE_DIRECTORIES ${MIR_GENERATED_INCLUDE_DIRECTORIES} PARENT_SCOPE) set(MIR_SERVER_OBJECTS ${MIR_SERVER_OBJECTS} PARENT_SCOPE) set(MIR_SERVER_REFERENCES ${MIR_SERVER_REFERENCES} PARENT_SCOPE) set(MIR_PLATFORM_OBJECTS ${MIR_PLATFORM_OBJECTS} PARENT_SCOPE) set(MIR_PLATFORM_REFERENCES ${MIR_PLATFORM_REFERENCES} PARENT_SCOPE) set(MIR_CLIENT_PLATFORM_PATH ${MIR_CLIENT_PLATFORM_PATH} PARENT_SCOPE) set(MIR_SERVER_PLATFORM_PATH ${MIR_SERVER_PLATFORM_PATH} PARENT_SCOPE) # We need the ABI versions in the tests set(MIR_SERVER_GRAPHICS_PLATFORM_ABI ${MIR_SERVER_GRAPHICS_PLATFORM_ABI} PARENT_SCOPE) set(MIR_SERVER_INPUT_PLATFORM_ABI ${MIR_SERVER_INPUT_PLATFORM_ABI} PARENT_SCOPE) set(MIR_SERVER_GRAPHICS_PLATFORM_VERSION ${MIR_SERVER_GRAPHICS_PLATFORM_VERSION} PARENT_SCOPE) set(MIR_CLIENT_PLATFORM_ABI ${MIR_CLIENT_PLATFORM_ABI} PARENT_SCOPE) set(MIR_INPUT_PLATFORM_VERSION_SCRIPT ${MIR_INPUT_PLATFORM_VERSION_SCRIPT} PARENT_SCOPE) set(MIR_CLIENT_PLATFORM_VERSION ${MIR_CLIENT_PLATFORM_VERSION} PARENT_SCOPE) ./src/platform/0000755000004100000410000000000013115234677013667 5ustar www-datawww-data./src/platform/CMakeLists.txt0000644000004100000410000000314513115234664016426 0ustar www-datawww-dataadd_definitions(-DMIR_LOG_COMPONENT_FALLBACK="mirplatform") include_directories( ${PROJECT_SOURCE_DIR}/include/platform ${PROJECT_SOURCE_DIR}/src/include/platform ) set(symbol_map ${CMAKE_CURRENT_SOURCE_DIR}/symbols.map) add_definitions(-DMIR_SERVER_PLATFORM_PATH="${MIR_SERVER_PLATFORM_PATH}") add_definitions(-DMIR_SERVER_GRAPHICS_PLATFORM_VERSION="${MIR_SERVER_GRAPHICS_PLATFORM_VERSION}") set(MIR_PLATFORM_OBJECTS $ $ $ ) set(MIR_PLATFORM_REFERENCES ${EGL_LDFLAGS} ${EGL_LIBRARIES} ${GL_LDFLAGS} ${GL_LIBRARIES} ) add_subdirectory(graphics/) add_subdirectory(options) add_subdirectory(udev) set(MIR_PLATFORM_OBJECTS ${MIR_PLATFORM_OBJECTS} PARENT_SCOPE) set(MIR_PLATFORM_REFERENCES ${MIR_PLATFORM_REFERENCES} PARENT_SCOPE) add_library(mirplatform SHARED ${MIR_PLATFORM_OBJECTS} ) target_link_libraries(mirplatform mircommon ${MIR_PLATFORM_REFERENCES} ) set_target_properties( mirplatform PROPERTIES SOVERSION ${MIRPLATFORM_ABI} LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${symbol_map}" LINK_DEPENDS ${symbol_map} ) install(TARGETS mirplatform LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) set(INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include/mirplatform") set(COMMON_INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include/mircommon") set(LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/mirplatform.pc.in ${CMAKE_CURRENT_BINARY_DIR}/mirplatform.pc ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/mirplatform.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) ./src/platform/symbols.map0000644000004100000410000003233013115234664016053 0ustar www-datawww-dataMIRPLATFORM_0.26 { global: extern "C++" { # The following symbols come from running a script over the generated docs. Vis: # ../tools/process_doxygen_xml.py doc/xml/*.xml | grep "^mirplatform public" | sed "s/mirplatform public: / /" | sort mir::graphics::BufferBasic::BufferBasic*; mir::graphics::Buffer::Buffer*; mir::graphics::Buffer::id*; mir::graphics::Buffer::native_buffer_base*; mir::graphics::Buffer::native_buffer_handle*; mir::graphics::Buffer::pixel_format*; mir::graphics::Buffer::size*; mir::graphics::Cursor::?Cursor*; mir::graphics::Cursor::Cursor*; mir::graphics::Cursor::hide*; mir::graphics::CursorImage::as_argb_8888*; mir::graphics::CursorImage::?CursorImage*; mir::graphics::CursorImage::CursorImage*; mir::graphics::CursorImage::hotspot*; mir::graphics::CursorImage::operator*; mir::graphics::CursorImage::size*; mir::graphics::Cursor::move_to*; mir::graphics::Cursor::operator*; mir::graphics::Cursor::show*; mir::graphics::DisplayBuffer::DisplayBuffer*; mir::graphics::DisplayBuffer::native_display_buffer*; mir::graphics::DisplayBuffer::operator*; mir::graphics::DisplayBuffer::orientation*; mir::graphics::DisplayBuffer::overlay*; mir::graphics::DisplayBuffer::view_area*; mir::graphics::Display::configuration*; mir::graphics::DisplayConfiguration::DisplayConfiguration*; mir::graphics::DisplayConfiguration::for_each_card*; mir::graphics::DisplayConfiguration::for_each_output*; mir::graphics::DisplayConfiguration::operator*; mir::graphics::DisplayConfigurationOutput::extents*; mir::graphics::DisplayConfigurationOutput::valid*; mir::graphics::DisplayConfigurationPolicy::apply_to*; mir::graphics::DisplayConfigurationPolicy::?DisplayConfigurationPolicy*; mir::graphics::DisplayConfigurationPolicy::DisplayConfigurationPolicy*; mir::graphics::DisplayConfigurationPolicy::operator*; mir::graphics::DisplayConfiguration::valid*; mir::graphics::Display::configure*; mir::graphics::Display::create_gl_context*; mir::graphics::Display::create_hardware_cursor*; mir::graphics::Display::Display*; mir::graphics::Display::for_each_display_buffer*; mir::graphics::Display::native_display*; mir::graphics::Display::pause*; mir::graphics::Display::register_configuration_change_handler*; mir::graphics::Display::register_pause_resume_handlers*; mir::graphics::Display::resume*; mir::graphics::EventHandlerRegister::?EventHandlerRegister*; mir::graphics::EventHandlerRegister::EventHandlerRegister*; mir::graphics::EventHandlerRegister::operator*; mir::graphics::EventHandlerRegister::register_fd_handler*; mir::graphics::EventHandlerRegister::register_signal_handler*; mir::graphics::EventHandlerRegister::unregister_fd_handler*; mir::graphics::GammaCurves::GammaCurves*; mir::graphics::GLConfig::depth_buffer_bits*; mir::graphics::GLConfig::?GLConfig*; mir::graphics::GLConfig::GLConfig*; mir::graphics::GLConfig::operator*; mir::graphics::GLConfig::stencil_buffer_bits*; mir::graphics::GraphicBufferAllocator::alloc_buffer*; mir::graphics::GraphicBufferAllocator::?GraphicBufferAllocator*; mir::graphics::GraphicBufferAllocator::GraphicBufferAllocator*; mir::graphics::GraphicBufferAllocator::operator*; mir::graphics::GraphicBufferAllocator::supported_pixel_formats*; mir::graphics::LinearGammaLUTs::LinearGammaLUTs*; mir::graphics::module_for_device*; mir::graphics::operator*; mir::graphics::Platform::create_buffer_allocator*; mir::graphics::Platform::create_display*; mir::graphics::PlatformIpcOperations::connection_ipc_package*; mir::graphics::PlatformIpcOperations::operator*; mir::graphics::PlatformIpcOperations::pack_buffer*; mir::graphics::PlatformIpcOperations::?PlatformIpcOperations*; mir::graphics::PlatformIpcOperations::PlatformIpcOperations*; mir::graphics::PlatformIpcOperations::unpack_buffer*; mir::graphics::Platform::make_ipc_operations*; mir::graphics::Platform::operator*; mir::graphics::Platform::Platform*; mir::graphics::Renderable::alpha*; mir::graphics::Renderable::buffer*; mir::graphics::Renderable::buffers_ready_for_compositor*; mir::graphics::Renderable::id*; mir::graphics::Renderable::operator*; mir::graphics::Renderable::?Renderable*; mir::graphics::Renderable::Renderable*; mir::graphics::Renderable::screen_position*; mir::graphics::Renderable::shaped*; mir::graphics::Renderable::transformation*; mir::graphics::Renderable::swap_interval*; mir::graphics::UserDisplayConfigurationOutput::extents*; mir::graphics::UserDisplayConfigurationOutput::UserDisplayConfigurationOutput*; mir::options::arw_server_socket_opt*; # Why are server-only options here in libmirplatform?... mir::options::composite_delay_opt*; mir::options::compositor_report_opt*; mir::options::Configuration::?Configuration*; mir::options::Configuration::Configuration*; mir::options::Configuration::operator*; mir::options::Configuration::the_options*; mir::options::connector_report_opt*; mir::options::DefaultConfiguration::add_options*; mir::options::DefaultConfiguration::?DefaultConfiguration*; mir::options::DefaultConfiguration::DefaultConfiguration*; mir::options::DefaultConfiguration::parse_arguments*; mir::options::DefaultConfiguration::parse_config_file*; mir::options::DefaultConfiguration::parse_environment*; mir::options::DefaultConfiguration::the_options*; mir::options::display_report_opt*; mir::options::debug_opt*; mir::options::nbuffers_opt*; mir::options::enable_input_opt*; mir::options::enable_key_repeat_opt*; mir::options::fatal_except_opt*; mir::options::frontend_threads_opt*; mir::options::glog*; mir::options::glog_log_dir*; mir::options::glog_minloglevel*; mir::options::glog_stderrthreshold*; mir::options::platform_path*; mir::options::host_socket_opt*; mir::options::nested_passthrough_opt*; mir::options::input_report_opt*; mir::options::legacy_input_report_opt*; mir::options::seat_report_opt*; mir::options::log_opt_value*; mir::options::lttng_opt_value*; mir::options::msg_processor_report_opt*; mir::options::name_opt*; mir::options::no_server_socket_opt*; mir::options::platform_input_lib*; mir::options::off_opt_value*; mir::options::Option::get*; mir::options::Option::is_set*; mir::options::Option::operator*; mir::options::Option::?Option*; mir::options::Option::Option*; mir::options::platform_graphics_lib*; mir::options::ProgramOption::get*; mir::options::ProgramOption::is_set*; mir::options::ProgramOption::parse_arguments*; mir::options::ProgramOption::parse_environment*; mir::options::ProgramOption::parse_file*; mir::options::ProgramOption::ProgramOption*; mir::options::ProgramOption::unparsed_command_line*; mir::options::prompt_socket_opt*; mir::options::scene_report_opt*; mir::options::server_socket_opt*; mir::options::session_mediator_report_opt*; mir::options::shared_library_prober_report_opt*; mir::options::shell_report_opt; mir::options::touchspots_opt*; non-virtual?thunk?to?mir::graphics::Cursor::?Cursor*; non-virtual?thunk?to?mir::graphics::CursorImage::?CursorImage*; non-virtual?thunk?to?mir::graphics::DisplayConfigurationPolicy::?DisplayConfigurationPolicy*; non-virtual?thunk?to?mir::graphics::DisplayConfiguration::valid*; non-virtual?thunk?to?mir::graphics::EventHandlerRegister::?EventHandlerRegister*; non-virtual?thunk?to?mir::graphics::GLConfig::?GLConfig*; non-virtual?thunk?to?mir::graphics::GraphicBufferAllocator::?GraphicBufferAllocator*; non-virtual?thunk?to?mir::graphics::PlatformIpcOperations::?PlatformIpcOperations*; non-virtual?thunk?to?mir::graphics::Renderable::?Renderable*; non-virtual?thunk?to?mir::options::Configuration::?Configuration*; non-virtual?thunk?to?mir::options::DefaultConfiguration::?DefaultConfiguration*; non-virtual?thunk?to?mir::options::DefaultConfiguration::parse_arguments*; non-virtual?thunk?to?mir::options::DefaultConfiguration::parse_config_file*; non-virtual?thunk?to?mir::options::DefaultConfiguration::parse_environment*; non-virtual?thunk?to?mir::options::DefaultConfiguration::the_options*; non-virtual?thunk?to?mir::options::Option::?Option*; non-virtual?thunk?to?mir::options::ProgramOption::get*; non-virtual?thunk?to?mir::options::ProgramOption::is_set*; typeinfo?for?mir::AbnormalExit; typeinfo?for?mir::FatalErrorStrategy; typeinfo?for?mir::graphics::Buffer; typeinfo?for?mir::graphics::BufferBasic; typeinfo?for?mir::graphics::BufferProperties; typeinfo?for?mir::graphics::Cursor; typeinfo?for?mir::graphics::CursorImage; typeinfo?for?mir::graphics::Display; typeinfo?for?mir::graphics::DisplayBuffer; typeinfo?for?mir::graphics::DisplayConfiguration; typeinfo?for?mir::graphics::DisplayConfigurationCard; typeinfo?for?mir::graphics::DisplayConfigurationMode; typeinfo?for?mir::graphics::DisplayConfigurationOutput; typeinfo?for?mir::graphics::DisplayConfigurationPolicy; typeinfo?for?mir::graphics::EventHandlerRegister; typeinfo?for?mir::graphics::GLConfig; typeinfo?for?mir::graphics::GraphicBufferAllocator; typeinfo?for?mir::graphics::Platform; typeinfo?for?mir::graphics::PlatformIpcOperations; typeinfo?for?mir::graphics::PlatformIPCPackage; typeinfo?for?mir::graphics::Renderable; typeinfo?for?mir::graphics::UserDisplayConfigurationOutput; typeinfo?for?mir::options::Configuration; typeinfo?for?mir::options::DefaultConfiguration; typeinfo?for?mir::options::Option; typeinfo?for?mir::options::ProgramOption; vtable?for?mir::AbnormalExit; vtable?for?mir::FatalErrorStrategy; vtable?for?mir::graphics::Buffer; vtable?for?mir::graphics::BufferBasic; vtable?for?mir::graphics::BufferProperties; vtable?for?mir::graphics::Cursor; vtable?for?mir::graphics::CursorImage; vtable?for?mir::graphics::Display; vtable?for?mir::graphics::DisplayBuffer; vtable?for?mir::graphics::DisplayConfiguration; vtable?for?mir::graphics::DisplayConfigurationCard; vtable?for?mir::graphics::DisplayConfigurationMode; vtable?for?mir::graphics::DisplayConfigurationOutput; vtable?for?mir::graphics::DisplayConfigurationPolicy; vtable?for?mir::graphics::EventHandlerRegister; vtable?for?mir::graphics::GLConfig; vtable?for?mir::graphics::GraphicBufferAllocator; vtable?for?mir::graphics::Platform; vtable?for?mir::graphics::PlatformIpcOperations; vtable?for?mir::graphics::PlatformIPCPackage; vtable?for?mir::graphics::Renderable; vtable?for?mir::graphics::UserDisplayConfigurationOutput; vtable?for?mir::options::Configuration; vtable?for?mir::options::DefaultConfiguration; vtable?for?mir::options::Option; vtable?for?mir::options::ProgramOption; # These are "private" (declared in src/include) but are used by libmirserver. # They are also likely to be needed by any 3rd party "graphics platform" # implementation. They should probably become public at some stage. mir::graphics::alpha_channel_depth*; mir::graphics::blue_channel_depth*; mir::graphics::contains_alpha*; mir::graphics::EGLExtensions::EGLExtensions*; mir::graphics::EGLContextStore::?EGLContextStore*; mir::graphics::EGLContextStore::EGLContextStore*; mir::graphics::EGLContextStore::EGLContextStore*; mir::graphics::EGLContextStore::operator*; mir::graphics::EGLSurfaceStore::?EGLSurfaceStore*; mir::graphics::EGLSurfaceStore::EGLSurfaceStore*; mir::graphics::EGLSurfaceStore::EGLSurfaceStore*; mir::graphics::EGLSurfaceStore::operator*; mir::graphics::egl_category*; mir::graphics::green_channel_depth*; mir::graphics::OverlappingOutputGroup::bounding_rectangle*; mir::graphics::OverlappingOutputGroup::for_each_output*; mir::graphics::OverlappingOutputGrouping::for_each_group*; mir::graphics::OverlappingOutputGrouping::OverlappingOutputGrouping*; mir::graphics::red_channel_depth*; mir::graphics::tessellate_renderable_into_rectangle*; mir::udev::Context::?Context*; mir::udev::Context::Context*; mir::udev::Context::ctx*; mir::udev::Enumerator::begin*; mir::udev::Enumerator::end*; mir::udev::Enumerator::?Enumerator*; mir::udev::Enumerator::Enumerator*; mir::udev::Enumerator::iterator::operator*; mir::udev::Enumerator::match_parent*; mir::udev::Enumerator::match_subsystem*; mir::udev::Enumerator::match_sysname*; mir::udev::Enumerator::scan_devices*; mir::udev::Monitor::enable*; mir::udev::Monitor::fd*; mir::udev::Monitor::filter_by_subsystem*; mir::udev::Monitor::?Monitor*; mir::udev::Monitor::Monitor*; mir::udev::Monitor::process_events*; mir::udev::operator*; # Android input platform symbols android::getAbsAxisUsage*; android::getInputDeviceConfigurationFilePathByDeviceIdentifier*; android::isEligibleBuiltInKeyboard*; __android_log_assert; __android_log_print; mir::graphics::AtomicFrame::load*; mir::graphics::AtomicFrame::store*; mir::graphics::AtomicFrame::increment* }; local: *; }; ./src/platform/udev/0000755000004100000410000000000013115234420014614 5ustar www-datawww-data./src/platform/udev/CMakeLists.txt0000644000004100000410000000027513115234416017365 0ustar www-datawww-dataadd_library(mirudev OBJECT udev_wrapper.cpp ) list(APPEND MIR_PLATFORM_REFERENCES ${UDEV_LDFLAGS} ${UDEV_LIBRARIES}) set(MIR_PLATFORM_REFERENCES ${MIR_PLATFORM_REFERENCES} PARENT_SCOPE) ./src/platform/udev/udev_wrapper.cpp0000644000004100000410000001667613115234416020050 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #include "mir/udev/wrapper.h" #include #include #include namespace mu = mir::udev; ///////////////////// // Device ///////////////////// namespace { class DeviceImpl : public mu::Device { public: DeviceImpl(udev_device *dev); virtual ~DeviceImpl() noexcept; virtual char const* subsystem() const override; virtual char const* devtype() const override; virtual char const* devpath() const override; virtual char const* devnode() const override; virtual char const* property(char const*) const override; udev_device* const dev; }; DeviceImpl::DeviceImpl(udev_device *dev) : dev(dev) { if (!dev) BOOST_THROW_EXCEPTION(std::runtime_error("Udev device does not exist")); udev_ref(udev_device_get_udev(dev)); } DeviceImpl::~DeviceImpl() noexcept { udev_unref(udev_device_get_udev(dev)); udev_device_unref(dev); } char const* DeviceImpl::subsystem() const { return udev_device_get_subsystem(dev); } char const* DeviceImpl::devtype() const { return udev_device_get_devtype(dev); } char const* DeviceImpl::devpath() const { return udev_device_get_devpath(dev); } char const* DeviceImpl::devnode() const { return udev_device_get_devnode(dev); } char const* DeviceImpl::property(char const* name) const { return udev_device_get_property_value(dev, name); } } bool mu::operator==(mu::Device const& lhs, mu::Device const& rhs) { // The device path is unique return strcmp(lhs.devpath(), rhs.devpath()) == 0; } bool mu::operator!=(mu::Device const& lhs, mu::Device const& rhs) { return !(lhs == rhs); } //////////////////////// // Enumerator //////////////////////// mu::Enumerator::iterator::iterator () : entry(nullptr) { } mu::Enumerator::iterator::iterator (std::shared_ptr const& ctx, udev_list_entry* entry) : ctx(ctx), entry(entry) { if (entry) current = ctx->device_from_syspath(udev_list_entry_get_name(entry)); } void mu::Enumerator::iterator::increment() { entry = udev_list_entry_get_next(entry); if (entry) { try { current = ctx->device_from_syspath(udev_list_entry_get_name(entry)); } catch (std::runtime_error) { // The Device throws a runtime_error if the device does not exist // This can happen if it has been removed since the iterator was created. // If this happens, move on to the next device. increment(); } } else { current.reset(); } } mu::Enumerator::iterator& mu::Enumerator::iterator::operator++() { increment(); return *this; } mu::Enumerator::iterator mu::Enumerator::iterator::operator++(int) { auto tmp = *this; increment(); return tmp; } bool mu::Enumerator::iterator::operator==(mu::Enumerator::iterator const& rhs) const { return this->entry == rhs.entry; } bool mu::Enumerator::iterator::operator!=(mu::Enumerator::iterator const& rhs) const { return !(*this == rhs); } mu::Device const& mu::Enumerator::iterator::operator*() const { return *current; } mu::Device const* mu::Enumerator::iterator::operator->() const { return current.get(); } mu::Enumerator::Enumerator(std::shared_ptr const& ctx) : ctx(ctx), enumerator(udev_enumerate_new(ctx->ctx())), scanned(false) { } mu::Enumerator::~Enumerator() noexcept { udev_enumerate_unref(enumerator); } void mu::Enumerator::scan_devices() { udev_enumerate_scan_devices(enumerator); scanned = true; } void mu::Enumerator::match_subsystem(std::string const& subsystem) { udev_enumerate_add_match_subsystem(enumerator, subsystem.c_str()); } void mu::Enumerator::match_parent(mu::Device const& parent) { udev_enumerate_add_match_parent(enumerator, dynamic_cast(parent).dev); } void mu::Enumerator::match_sysname(std::string const& sysname) { udev_enumerate_add_match_sysname(enumerator, sysname.c_str()); } mu::Enumerator::iterator mu::Enumerator::begin() { if (!scanned) BOOST_THROW_EXCEPTION(std::logic_error("Attempted to iterate over udev devices without first scanning")); return iterator(ctx, udev_enumerate_get_list_entry(enumerator)); } mu::Enumerator::iterator mu::Enumerator::end() { return iterator(); } /////////////////// // Context /////////////////// mu::Context::Context() : context(udev_new()) { if (!context) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create udev context")); } mu::Context::~Context() noexcept { udev_unref(context); } std::shared_ptr mu::Context::device_from_syspath(std::string const& syspath) { return std::make_shared(udev_device_new_from_syspath(context, syspath.c_str())); } udev* mu::Context::ctx() const { return context; } /////////////////// // Monitor /////////////////// mu::Monitor::Monitor(mu::Context const& ctx) : monitor(udev_monitor_new_from_netlink(ctx.ctx(), "udev")), enabled(false) { if (!monitor) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create udev_monitor")); udev_ref(udev_monitor_get_udev(monitor)); } mu::Monitor::~Monitor() noexcept { udev_unref(udev_monitor_get_udev(monitor)); udev_monitor_unref(monitor); } void mu::Monitor::enable(void) { udev_monitor_enable_receiving(monitor); enabled = true; } static mu::Monitor::EventType action_to_event_type(const char* action) { if (strcmp(action, "add") == 0) return mu::Monitor::EventType::ADDED; if (strcmp(action, "remove") == 0) return mu::Monitor::EventType::REMOVED; if (strcmp(action, "change") == 0) return mu::Monitor::EventType::CHANGED; BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Unknown udev action encountered: ") + action)); } void mu::Monitor::process_events(std::function const& handler) const { udev_device *dev; do { dev = udev_monitor_receive_device(monitor); if (dev != nullptr) handler(action_to_event_type(udev_device_get_action(dev)), DeviceImpl(dev)); } while (dev != nullptr); } int mu::Monitor::fd(void) const { return udev_monitor_get_fd(monitor); } void mu::Monitor::filter_by_subsystem(std::string const& subsystem) { udev_monitor_filter_add_match_subsystem_devtype(monitor, subsystem.c_str(), nullptr); if (enabled) udev_monitor_filter_update(monitor); } void mu::Monitor::filter_by_subsystem_and_type(std::string const& subsystem, std::string const& devtype) { udev_monitor_filter_add_match_subsystem_devtype(monitor, subsystem.c_str(), devtype.c_str()); if (enabled) udev_monitor_filter_update(monitor); } ./src/platform/options/0000755000004100000410000000000013115234677015362 5ustar www-datawww-data./src/platform/options/CMakeLists.txt0000644000004100000410000000020013115234416020101 0ustar www-datawww-dataset( CHOICE_SOURCES program_option.cpp default_configuration.cpp ) add_library(miroptions OBJECT ${CHOICE_SOURCES} ) ./src/platform/options/default_configuration.cpp0000644000004100000410000003311313115234664022436 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #include "mir/shared_library.h" #include "mir/options/default_configuration.h" #include "mir/graphics/platform.h" #include "mir/default_configuration.h" #include "mir/abnormal_exit.h" #include "mir/shared_library_prober.h" #include "mir/logging/null_shared_library_prober_report.h" #include "mir/graphics/platform_probe.h" namespace mo = mir::options; char const* const mo::server_socket_opt = "file,f"; char const* const mo::prompt_socket_opt = "prompt-file,p"; char const* const mo::no_server_socket_opt = "no-file"; char const* const mo::arw_server_socket_opt = "arw-file"; char const* const mo::enable_input_opt = "enable-input,i"; char const* const mo::session_mediator_report_opt = "session-mediator-report"; char const* const mo::msg_processor_report_opt = "msg-processor-report"; char const* const mo::compositor_report_opt = "compositor-report"; char const* const mo::display_report_opt = "display-report"; char const* const mo::legacy_input_report_opt = "legacy-input-report"; char const* const mo::connector_report_opt = "connector-report"; char const* const mo::scene_report_opt = "scene-report"; char const* const mo::input_report_opt = "input-report"; char const* const mo::seat_report_opt = "seat-report"; char const* const mo::shared_library_prober_report_opt = "shared-library-prober-report"; char const* const mo::shell_report_opt = "shell-report"; char const* const mo::host_socket_opt = "host-socket"; char const* const mo::nested_passthrough_opt = "nested-passthrough"; char const* const mo::frontend_threads_opt = "ipc-thread-pool"; char const* const mo::name_opt = "name"; char const* const mo::touchspots_opt = "enable-touchspots"; char const* const mo::fatal_except_opt = "on-fatal-error-except"; char const* const mo::debug_opt = "debug"; char const* const mo::composite_delay_opt = "composite-delay"; char const* const mo::enable_key_repeat_opt = "enable-key-repeat"; char const* const mo::off_opt_value = "off"; char const* const mo::log_opt_value = "log"; char const* const mo::lttng_opt_value = "lttng"; char const* const mo::platform_graphics_lib = "platform-graphics-lib"; char const* const mo::platform_input_lib = "platform-input-lib"; char const* const mo::platform_path = "platform-path"; namespace { bool const enable_input_default = true; } mo::DefaultConfiguration::DefaultConfiguration(int argc, char const* argv[]) : DefaultConfiguration(argc, argv, std::string{}) { } mo::DefaultConfiguration::DefaultConfiguration( int argc, char const* argv[], std::string const& config_file) : DefaultConfiguration(argc, argv, [](int argc, char const* const* argv) { if (argc) { std::ostringstream help_text; help_text << "Unknown command line options:"; for (auto opt = argv; opt != argv+argc ; ++opt) help_text << ' ' << *opt; BOOST_THROW_EXCEPTION(mir::AbnormalExit(help_text.str())); } }, config_file) { } mo::DefaultConfiguration::DefaultConfiguration( int argc, char const* argv[], std::function const& handler) : DefaultConfiguration(argc, argv, handler, std::string{}) { } namespace { std::string description_text(char const* program, std::string const& config_file) { std::string result{ "Command-line options (e.g. \"--host-socket=/tmp/mir_socket\").\n\n" "Environment variables capitalise long form with prefix \"MIR_SERVER_\" and \"_\" in place of \"-\".\n" "(E.g. \"MIR_SERVER_HOST_SOCKET=/tmp/mir_socket\")\n\n"}; if (program) result = std::string{"usage: "} + program + " [options]\n\n" + result; if (!config_file.empty()) result += "Config file entries are long form (e.g. \"host-socket=/tmp/mir_socket\").\n" "The config file (" + config_file + ") is located via the XDG Base Directory Specification.\n" "($XDG_CONFIG_HOME or $HOME/.config followed by $XDG_CONFIG_DIRS)\n\n"; return result + "user options"; } } mo::DefaultConfiguration::DefaultConfiguration( int argc, char const* argv[], std::function const& handler, std::string const& config_file) : config_file{config_file}, argc(argc), argv(argv), unparsed_arguments_handler{handler}, program_options(std::make_shared( description_text(argv[0], config_file))) { using namespace options; namespace po = boost::program_options; add_options() (host_socket_opt, po::value(), "Host socket filename") (server_socket_opt, po::value()->default_value(::mir::default_server_socket), "Socket filename [string:default=$XDG_RUNTIME_DIR/mir_socket or /tmp/mir_socket]") (no_server_socket_opt, "Do not provide a socket filename for client connections") (arw_server_socket_opt, "Make socket filename globally rw (equivalent to chmod a=rw)") (prompt_socket_opt, "Provide a \"..._trusted\" filename for prompt helper connections") (platform_graphics_lib, po::value(), "Library to use for platform graphics support (default: autodetect)") (platform_input_lib, po::value(), "Library to use for platform input support (default: input-stub.so)") (platform_path, po::value()->default_value(MIR_SERVER_PLATFORM_PATH), "Directory to look for platform libraries (default: " MIR_SERVER_PLATFORM_PATH ")") (enable_input_opt, po::value()->default_value(enable_input_default), "Enable input.") (compositor_report_opt, po::value()->default_value(off_opt_value), "Compositor reporting [{log,lttng,off}]") (connector_report_opt, po::value()->default_value(off_opt_value), "How to handle the Connector report. [{log,lttng,off}]") (display_report_opt, po::value()->default_value(off_opt_value), "How to handle the Display report. [{log,lttng,off}]") (input_report_opt, po::value()->default_value(off_opt_value), "How to handle to Input report. [{log,lttng,off}]") (legacy_input_report_opt, po::value()->default_value(off_opt_value), "How to handle the Legacy Input report. [{log,off}]") (seat_report_opt, po::value()->default_value(off_opt_value), "How to handle to Seat report. [{log,off}]") (session_mediator_report_opt, po::value()->default_value(off_opt_value), "How to handle the SessionMediator report. [{log,lttng,off}]") (msg_processor_report_opt, po::value()->default_value(off_opt_value), "How to handle the MessageProcessor report. [{log,lttng,off}]") (scene_report_opt, po::value()->default_value(off_opt_value), "How to handle the scene report. [{log,lttng,off}]") (shared_library_prober_report_opt, po::value()->default_value(log_opt_value), "How to handle the SharedLibraryProber report. [{log,lttng,off}]") (shell_report_opt, po::value()->default_value(off_opt_value), "How to handle the Shell report. [{log,off}]") (composite_delay_opt, po::value()->default_value(0), "Compositor frame delay in milliseconds (how long to wait for new " "frames from clients before compositing). Higher values result in " "lower latency but risk causing frame skipping. " "Default: A negative value means decide automatically.") (name_opt, po::value(), "When nested, the name Mir uses when registering with the host.") (nested_passthrough_opt, po::value()->default_value(true), "When nested, attempt to pass a client's graphics content directly to the host" " to avoid a composition pass") (touchspots_opt, "Display visualization of touchspots (e.g. for screencasting).") (enable_key_repeat_opt, po::value()->default_value(true), "Enable server generated key repeat") (fatal_except_opt, "On \"fatal error\" conditions [e.g. drivers behaving " "in unexpected ways] throw an exception (instead of a core dump)") (debug_opt, "Enable extra development debugging. " "This is only interesting for people doing Mir server or client development."); add_platform_options(); } void mo::DefaultConfiguration::add_platform_options() { namespace po = boost::program_options; po::options_description program_options; program_options.add_options() (platform_graphics_lib, po::value(), ""); program_options.add_options() (platform_path, po::value()->default_value(MIR_SERVER_PLATFORM_PATH), ""); mo::ProgramOption options; options.parse_arguments(program_options, argc, argv); // TODO: We should just load all the platform plugins we can and present their options. auto env_libname = ::getenv("MIR_SERVER_PLATFORM_GRAPHICS_LIB"); auto env_libpath = ::getenv("MIR_SERVER_PLATFORM_PATH"); try { if (options.is_set(platform_graphics_lib)) { platform_graphics_library = std::make_shared(options.get(platform_graphics_lib)); } else if (env_libname) { platform_graphics_library = std::make_shared(std::string{env_libname}); } else { mir::logging::NullSharedLibraryProberReport null_report; auto const plugin_path = env_libpath ? env_libpath : options.get(platform_path); auto plugins = mir::libraries_for_path(plugin_path, null_report); platform_graphics_library = mir::graphics::module_for_device(plugins, options); } auto add_platform_options = platform_graphics_library->load_function("add_graphics_platform_options", MIR_SERVER_GRAPHICS_PLATFORM_VERSION); add_platform_options(*this->program_options); } catch(...) { // We don't actually care at this point if this failed. // Maybe we've been pointed at the wrong place. Maybe this platform doesn't actually // *have* platform-specific options. // Regardless, if we need a platform and can't find one then we'll bail later // in startup with a useful error. } } boost::program_options::options_description_easy_init mo::DefaultConfiguration::add_options() { if (options) BOOST_THROW_EXCEPTION(std::logic_error("add_options() must be called before the_options()")); return program_options->add_options(); } std::shared_ptr mo::DefaultConfiguration::the_options() const { if (!options) { auto options = std::make_shared(); parse_arguments(*program_options, *options, argc, argv); parse_environment(*program_options, *options); parse_config_file(*program_options, *options); this->options = options; } return options; } void mo::DefaultConfiguration::parse_arguments( boost::program_options::options_description desc, mo::ProgramOption& options, int argc, char const* argv[]) const { namespace po = boost::program_options; try { desc.add_options() ("help,h", "this help text"); options.parse_arguments(desc, argc, argv); auto const unparsed_arguments = options.unparsed_command_line(); std::vector tokens; for (auto const& token : unparsed_arguments) tokens.push_back(token.c_str()); if (!tokens.empty()) unparsed_arguments_handler(tokens.size(), tokens.data()); if (options.is_set("help")) { std::ostringstream help_text; help_text << desc; BOOST_THROW_EXCEPTION(mir::AbnormalExit(help_text.str())); } } catch (po::error const& error) { std::ostringstream help_text; help_text << "Failed to parse command line options: " << error.what() << "." << std::endl << desc; BOOST_THROW_EXCEPTION(mir::AbnormalExit(help_text.str())); } } void mo::DefaultConfiguration::parse_environment( boost::program_options::options_description& desc, mo::ProgramOption& options) const { options.parse_environment(desc, "MIR_SERVER_"); } void mo::DefaultConfiguration::parse_config_file( boost::program_options::options_description& desc, mo::ProgramOption& options) const { if (!config_file.empty()) options.parse_file(desc, config_file); } ./src/platform/options/program_option.cpp0000644000004100000410000001056713115234416021125 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #include "mir/options/program_option.h" #include "mir/log.h" #include #include #include namespace mo = mir::options; namespace po = boost::program_options; namespace { std::string parse_name(std::string name) { return name.substr(0, name.find_first_of(',')); } } mo::ProgramOption::ProgramOption() { } void mo::ProgramOption::parse_arguments( po::options_description const& desc, int argc, char const* argv[]) { auto parsed_command_line = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); po::store(parsed_command_line, options); po::notify(options); unparsed_tokens = collect_unrecognized(parsed_command_line.options, po::include_positional); } std::vector mo::ProgramOption::unparsed_command_line() const { return unparsed_tokens; } void mo::ProgramOption::parse_environment( po::options_description const& desc, char const* prefix) { auto parsed_options = po::parse_environment( desc, [=](std::string const& from) -> std::string { auto const sizeof_prefix = strlen(prefix); if (from.length() < sizeof_prefix || 0 != from.find(prefix)) return std::string(); std::string result(from, sizeof_prefix); for(auto& ch : result) { if (ch == '_') ch = '-'; else ch = std::tolower(ch, std::locale::classic()); // avoid current locale } return result; }); po::store(parsed_options, options); } void mo::ProgramOption::parse_file( po::options_description const& config_file_desc, std::string const& name) { std::string config_roots; if (auto config_home = getenv("XDG_CONFIG_HOME")) (config_roots = config_home) += ":"; else if (auto home = getenv("HOME")) (config_roots = home) += "/.config:"; if (auto config_dirs = getenv("XDG_CONFIG_DIRS")) config_roots += config_dirs; else config_roots += "/etc/xdg"; std::istringstream config_stream(config_roots); /* Read options from config files */ for (std::string config_root; getline(config_stream, config_root, ':');) { auto const& filename = config_root + "/" + name; try { std::ifstream file(filename); po::store(po::parse_config_file(file, config_file_desc, true), options); } catch (const po::error& error) { log_warning("Error in %s: %s", filename.c_str(), error.what()); } } po::notify(options); } bool mo::ProgramOption::is_set(char const* name) const { return options.count(parse_name(name)); } bool mo::ProgramOption::get(char const* name, bool default_) const { auto const parsed_name = parse_name(name); if (options.count(parsed_name)) { return options[parsed_name].as(); } return default_; } std::string mo::ProgramOption::get(char const* name, char const* default_) const { auto const parsed_name = parse_name(name); if (options.count(parsed_name)) { return options[parsed_name].as(); } return default_; } int mo::ProgramOption::get(char const* name, int default_) const { auto const parsed_name = parse_name(name); if (options.count(parsed_name)) { return options[parsed_name].as(); } return default_; } boost::any const& mo::ProgramOption::get(char const* name) const { auto const parsed_name = parse_name(name); if (options.count(parsed_name)) { return options[parsed_name].value(); } static boost::any const default_; return default_; } ./src/platform/mirplatform.pc.in0000644000004100000410000000041013115234664017143 0ustar www-datawww-dataprefix=@PREFIX@ exec_prefix=@EXEC_PREFIX@ libdir=@LIBDIR@ includedir=@INCLUDEDIR@ Name: mirplatform Description: Mir platform library Version: @MIR_VERSION@ Requires: mircore Libs: -L@LIBDIR@ -lmirplatform -lmircommon Cflags: -I@INCLUDEDIR@ -I@COMMON_INCLUDEDIR@ ./src/platform/graphics/0000755000004100000410000000000013115234677015467 5ustar www-datawww-data./src/platform/graphics/CMakeLists.txt0000644000004100000410000000074213115234664020226 0ustar www-datawww-datainclude_directories(${GL_INCLUDE_DIRS}) set( GRAPHICS_SOURCES egl_extensions.cpp egl_resources.cpp egl_error.cpp display_configuration.cpp gamma_curves.cpp buffer_basic.cpp pixel_format_utils.cpp overlapping_output_grouping.cpp platform_probe.cpp atomic_frame.cpp ${PROJECT_SOURCE_DIR}/include/platform/mir/graphics/display.h ) add_library(mirplatformgraphicscommon OBJECT ${GRAPHICS_SOURCES} ) set(symbol_map ${CMAKE_CURRENT_SOURCE_DIR}/symbols.map) ./src/platform/graphics/platform_probe.cpp0000644000004100000410000000453613115234416021205 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #include "mir/log.h" #include "mir/graphics/platform.h" #include "mir/graphics/platform_probe.h" #include std::shared_ptr mir::graphics::module_for_device(std::vector> const& modules, mir::options::ProgramOption const& options) { mir::graphics::PlatformPriority best_priority_so_far = mir::graphics::unsupported; std::shared_ptr best_module_so_far; for (auto& module : modules) { try { auto probe = module->load_function( "probe_graphics_platform", MIR_SERVER_GRAPHICS_PLATFORM_VERSION); auto module_priority = probe(options); if (module_priority > best_priority_so_far) { best_priority_so_far = module_priority; best_module_so_far = module; } auto describe = module->load_function( "describe_graphics_module", MIR_SERVER_GRAPHICS_PLATFORM_VERSION); auto desc = describe(); mir::log_info("Found graphics driver: %s (version %d.%d.%d)", desc->name, desc->major_version, desc->minor_version, desc->micro_version); } catch (std::runtime_error const&) { } } if (best_priority_so_far > mir::graphics::unsupported) { return best_module_so_far; } BOOST_THROW_EXCEPTION((std::runtime_error{"Failed to find platform for current system"})); } ./src/platform/graphics/buffer_basic.cpp0000644000004100000410000000200013115234416020564 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #include "mir/graphics/buffer_basic.h" #include namespace mg = mir::graphics; namespace { mg::BufferID generate_next_buffer_id() { static std::atomic next_id{0}; return mg::BufferID(next_id.fetch_add(1)); } } mg::BufferBasic::BufferBasic() : buffer_id(generate_next_buffer_id()) { } ./src/platform/graphics/egl_extensions.cpp0000644000004100000410000000355013115234664021220 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #include "mir/graphics/egl_extensions.h" #include #include namespace mg=mir::graphics; mg::EGLExtensions::EGLExtensions() : eglCreateImageKHR{ reinterpret_cast(eglGetProcAddress("eglCreateImageKHR"))}, eglDestroyImageKHR{ reinterpret_cast(eglGetProcAddress("eglDestroyImageKHR"))}, /* * TODO: Find a non-ES GL equivalent for glEGLImageTargetTexture2DOES * It's the LAST remaining ES-specific function. Although Mesa lets you use * it in full GL, it theoretically should not work. Mesa just lets you * mix ES and GL code. But other drivers won't be so lenient. */ glEGLImageTargetTexture2DOES{ reinterpret_cast(eglGetProcAddress("glEGLImageTargetTexture2DOES"))} { if (!eglCreateImageKHR || !eglDestroyImageKHR) BOOST_THROW_EXCEPTION(std::runtime_error("EGL implementation doesn't support EGLImage")); if (!glEGLImageTargetTexture2DOES) BOOST_THROW_EXCEPTION(std::runtime_error("GLES2 implementation doesn't support updating a texture from an EGLImage")); } ./src/platform/graphics/atomic_frame.cpp0000644000004100000410000000254413115234664020622 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #include "mir/graphics/atomic_frame.h" #include "mir/log.h" namespace mir { namespace graphics { Frame AtomicFrame::load() const { std::lock_guard lock(mutex); return frame; } void AtomicFrame::store(Frame const& f) { std::lock_guard lock(mutex); frame = f; } void AtomicFrame::increment_now() { std::lock_guard lock(mutex); frame.ust = Frame::Timestamp::now(frame.ust.clock_id); frame.msc++; } void AtomicFrame::increment_with_timestamp(Frame::Timestamp t) { std::lock_guard lock(mutex); frame.ust = t; frame.msc++; } }} // namespace mir::graphics ./src/platform/graphics/pixel_format_utils.cpp0000644000004100000410000000410213115234416022070 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #include "mir/graphics/pixel_format_utils.h" namespace { const struct { MirPixelFormat mir_format; int red_bits, green_bits, blue_bits, alpha_bits; } detail[mir_pixel_formats] = { {mir_pixel_format_invalid, 0,0,0,0}, {mir_pixel_format_abgr_8888, 8,8,8,8}, {mir_pixel_format_xbgr_8888, 8,8,8,0}, {mir_pixel_format_argb_8888, 8,8,8,8}, {mir_pixel_format_xrgb_8888, 8,8,8,0}, {mir_pixel_format_bgr_888, 8,8,8,0}, {mir_pixel_format_rgb_888, 8,8,8,0}, {mir_pixel_format_rgb_565, 5,6,5,0}, {mir_pixel_format_rgba_5551, 5,5,5,1}, {mir_pixel_format_rgba_4444, 4,4,4,4}, }; } // anonymous namespace namespace mir { namespace graphics { bool valid_pixel_format(MirPixelFormat f) { return f > mir_pixel_format_invalid && f < mir_pixel_formats && detail[f].mir_format == f; } int red_channel_depth(MirPixelFormat f) { return valid_pixel_format(f) ? detail[f].red_bits : 0; } int green_channel_depth(MirPixelFormat f) { return valid_pixel_format(f) ? detail[f].green_bits : 0; } int blue_channel_depth(MirPixelFormat f) { return valid_pixel_format(f) ? detail[f].blue_bits : 0; } int alpha_channel_depth(MirPixelFormat f) { return valid_pixel_format(f) ? detail[f].alpha_bits : 0; } bool contains_alpha(MirPixelFormat format) { return alpha_channel_depth(format); } } } // namespace mir::graphics ./src/platform/graphics/display_configuration.cpp0000644000004100000410000002220713115234664022566 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "mir/graphics/display_configuration.h" #include "mir/output_type_names.h" #include #include namespace mg = mir::graphics; namespace { class StreamPropertiesRecovery { public: StreamPropertiesRecovery(std::ostream& stream) : stream(stream), flags{stream.flags()}, precision{stream.precision()} { } ~StreamPropertiesRecovery() { stream.precision(precision); stream.flags(flags); } private: std::ostream& stream; std::ios_base::fmtflags const flags; std::streamsize const precision; }; } std::ostream& mg::operator<<(std::ostream& out, mg::DisplayConfigurationCard const& val) { return out << "{ id: " << val.id << " max_simultaneous_outputs: " << val.max_simultaneous_outputs << " }" << std::endl; } std::ostream& mg::operator<<(std::ostream& out, mg::DisplayConfigurationMode const& val) { StreamPropertiesRecovery const stream_properties_recovery{out}; out.precision(1); out.setf(std::ios_base::fixed); return out << val.size.width << "x" << val.size.height << "@" << val.vrefresh_hz; } namespace { char const* as_string(MirFormFactor form_factor) { switch (form_factor) { case mir_form_factor_monitor: return "monitor"; case mir_form_factor_projector: return "projector"; case mir_form_factor_tv: return "TV"; case mir_form_factor_phone: return "phone"; case mir_form_factor_tablet: return "tablet"; default: return "UNKNOWN"; } } } std::ostream& mg::operator<<(std::ostream& out, mg::DisplayConfigurationOutput const& val) { out << "{\n\tid: " << val.id << "\n\tcard_id: " << val.card_id << "\n\ttype: " << mir::output_type_name(static_cast(val.type)) << "\n\tmodes: [ "; for (size_t i = 0; i < val.modes.size(); ++i) { out << val.modes[i]; if (i != val.modes.size() - 1) out << ", "; } out << "]" << std::endl; out << "\tpreferred_mode: " << val.preferred_mode_index << std::endl; out << "\tphysical_size_mm: " << val.physical_size_mm.width << "x" << val.physical_size_mm.height << std::endl; out << "\tconnected: " << (val.connected ? "true" : "false") << std::endl; out << "\tused: " << (val.used ? "true" : "false") << std::endl; out << "\ttop_left: " << val.top_left << std::endl; out << "\tcurrent_mode: " << val.current_mode_index << " ("; if (val.current_mode_index < val.modes.size()) out << val.modes[val.current_mode_index]; else out << "none"; out << ")" << std::endl; out << "\tscale: " << val.scale << std::endl; out << "\tform factor: " << as_string(val.form_factor) << std::endl; out << "\torientation: " << val.orientation << '\n'; out << "}" << std::endl; return out; } std::ostream& mg::operator<<(std::ostream& out, mg::DisplayConfiguration const& val) { val.for_each_card([&out](auto card) { out << card << std::endl; }); val.for_each_output([&out](DisplayConfigurationOutput const& output) { out << output << std::endl; }); return out; } bool mg::operator==(mg::DisplayConfigurationCard const& val1, mg::DisplayConfigurationCard const& val2) { return (val1.id == val2.id) && (val1.max_simultaneous_outputs == val2.max_simultaneous_outputs); } bool mg::operator!=(mg::DisplayConfigurationCard const& val1, mg::DisplayConfigurationCard const& val2) { return !(val1 == val2); } bool mg::operator==(mg::DisplayConfigurationMode const& val1, mg::DisplayConfigurationMode const& val2) { return (val1.size == val2.size) && (val1.vrefresh_hz == val2.vrefresh_hz); } bool mg::operator!=(mg::DisplayConfigurationMode const& val1, mg::DisplayConfigurationMode const& val2) { return !(val1 == val2); } bool mg::operator==(mg::DisplayConfigurationOutput const& val1, mg::DisplayConfigurationOutput const& val2) { bool equal{(val1.id == val2.id) && (val1.card_id == val2.card_id) && (val1.type == val2.type) && (val1.physical_size_mm == val2.physical_size_mm) && (val1.preferred_mode_index == val2.preferred_mode_index) && (val1.connected == val2.connected) && (val1.used == val2.used) && (val1.top_left == val2.top_left) && (val1.orientation == val2.orientation) && (val1.current_mode_index == val2.current_mode_index) && (val1.modes.size() == val2.modes.size()) && (val1.scale == val2.scale) && (val1.form_factor == val2.form_factor)}; if (equal) { for (size_t i = 0; i < val1.modes.size(); i++) { equal = equal && (val1.modes[i] == val2.modes[i]); if (!equal) break; } } return equal; } bool mg::operator!=(mg::DisplayConfigurationOutput const& val1, mg::DisplayConfigurationOutput const& val2) { return !(val1 == val2); } bool mg::operator==(DisplayConfiguration const& lhs, DisplayConfiguration const& rhs) { std::vector lhs_cards; std::vector lhs_outputs; lhs.for_each_card([&lhs_cards](DisplayConfigurationCard const& card) { lhs_cards.emplace_back(card); }); lhs.for_each_output([&lhs_outputs](DisplayConfigurationOutput const& output) { lhs_outputs.emplace_back(output); }); std::vector rhs_cards; std::vector rhs_outputs; rhs.for_each_card([&rhs_cards](DisplayConfigurationCard const& card) { rhs_cards.emplace_back(card); }); rhs.for_each_output([&rhs_outputs](DisplayConfigurationOutput const& output) { rhs_outputs.emplace_back(output); }); return lhs_cards == rhs_cards && lhs_outputs == rhs_outputs; } bool mg::operator!=(DisplayConfiguration const& lhs, DisplayConfiguration const& rhs) { return !(lhs == rhs); } namespace { mir::geometry::Rectangle extents_of( std::vector const& modes, size_t current_mode_index, MirOrientation orientation, mir::geometry::Point top_left) { if (current_mode_index >= modes.size()) return mir::geometry::Rectangle(); auto const& size = modes[current_mode_index].size; if (orientation == mir_orientation_normal || orientation == mir_orientation_inverted) { return {top_left, size}; } else { return {top_left, {size.height.as_int(), size.width.as_int()}}; } } } mir::geometry::Rectangle mg::DisplayConfigurationOutput::extents() const { return extents_of(modes, current_mode_index, orientation, top_left); } bool mg::DisplayConfigurationOutput::valid() const { if (!connected) return !used; auto const& f = std::find(pixel_formats.begin(), pixel_formats.end(), current_format); if (f == pixel_formats.end()) return false; auto nmodes = modes.size(); if (current_mode_index >= nmodes) return false; return true; } bool mg::DisplayConfiguration::valid() const { bool all_valid = true; for_each_output([&all_valid](DisplayConfigurationOutput const& out) { if (!out.valid()) all_valid = false; }); return all_valid; } mg::UserDisplayConfigurationOutput::UserDisplayConfigurationOutput( DisplayConfigurationOutput& master) : id(master.id), card_id(master.card_id), type(master.type), pixel_formats(master.pixel_formats), modes(master.modes), preferred_mode_index(master.preferred_mode_index), physical_size_mm(master.physical_size_mm), connected(master.connected), used(master.used), top_left(master.top_left), current_mode_index(master.current_mode_index), current_format(master.current_format), power_mode(master.power_mode), orientation(master.orientation), scale(master.scale), form_factor(master.form_factor), subpixel_arrangement(master.subpixel_arrangement), gamma(master.gamma), gamma_supported(master.gamma_supported), edid(*reinterpret_cast*>(&master.edid)) { } mir::geometry::Rectangle mg::UserDisplayConfigurationOutput::extents() const { return extents_of(modes, current_mode_index, orientation, top_left); } ./src/platform/graphics/egl_resources.cpp0000644000004100000410000000524013115234416021024 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "mir/graphics/egl_resources.h" #include "mir/graphics/egl_error.h" #include #include namespace mg = mir::graphics; /******************* * EGLContextStore * *******************/ mg::EGLContextStore::EGLContextStore(EGLDisplay egl_display, EGLContext egl_context) : egl_display_{egl_display}, egl_context_{egl_context} { if (egl_context_ == EGL_NO_CONTEXT) BOOST_THROW_EXCEPTION(mg::egl_error("Could not create egl context")); } mg::EGLContextStore::~EGLContextStore() noexcept { if (egl_context_ != EGL_NO_CONTEXT) eglDestroyContext(egl_display_, egl_context_); } mg::EGLContextStore::EGLContextStore(EGLContextStore&& other) : egl_display_{other.egl_display_}, egl_context_{other.egl_context_} { other.egl_display_ = EGL_NO_DISPLAY; other.egl_context_ = EGL_NO_CONTEXT; } mg::EGLContextStore::operator EGLContext() const { return egl_context_; } /******************* * EGLSurfaceStore * *******************/ mg::EGLSurfaceStore::EGLSurfaceStore(EGLDisplay egl_display, EGLSurface egl_surface, enum AllowNoSurface allow_no_surface) : egl_display_{egl_display}, egl_surface_{egl_surface} { if (egl_surface_ == EGL_NO_SURFACE && !allow_no_surface) BOOST_THROW_EXCEPTION(mg::egl_error("Could not create egl surface")); } mg::EGLSurfaceStore::EGLSurfaceStore(EGLDisplay egl_display, EGLSurface egl_surface) : EGLSurfaceStore(egl_display, egl_surface, DisallowNoSurface) { } mg::EGLSurfaceStore::EGLSurfaceStore(EGLSurfaceStore&& other) : egl_display_{other.egl_display_}, egl_surface_{other.egl_surface_} { other.egl_display_ = EGL_NO_DISPLAY; other.egl_surface_ = EGL_NO_SURFACE; } mg::EGLSurfaceStore::~EGLSurfaceStore() noexcept { if (egl_surface_ != EGL_NO_SURFACE) eglDestroySurface(egl_display_, egl_surface_); } mg::EGLSurfaceStore::operator EGLSurface() const { return egl_surface_; } ./src/platform/graphics/gamma_curves.cpp0000644000004100000410000000340313115234664020640 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Brandon Schaefer */ #include "mir/graphics/gamma_curves.h" #include #include #include namespace mg = mir::graphics; namespace { mg::GammaCurves make_linear_ramp(int size) { if (size < 2) BOOST_THROW_EXCEPTION(std::logic_error("gamma LUT size is too small")); mg::GammaCurve ramp(size); auto const step = std::numeric_limits::max() / (size - 1); mg::GammaCurve::value_type n = 0; std::generate(ramp.begin(), ramp.end(), [&n, step]{ auto current = n; n += step; return current; }); return {ramp, ramp, ramp}; } } mg::GammaCurves::GammaCurves(GammaCurve const& red, GammaCurve const& green, GammaCurve const& blue) : red(red), green(green), blue(blue) { if (red.size() != green.size() || green.size() != blue.size()) { BOOST_THROW_EXCEPTION(std::logic_error("Different gamma LUT sizes")); } } mg::LinearGammaLUTs::LinearGammaLUTs(int size) : GammaCurves(make_linear_ramp(size)) { } ./src/platform/graphics/egl_error.cpp0000644000004100000410000000520013115234664020144 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "mir/graphics/egl_error.h" #include #include /* * The version of eglext in vivid-overlay is too old to contain these * defines, so provide them if missing */ #ifndef EGL_BAD_DEVICE_EXT #define EGL_BAD_DEVICE_EXT 0x322B #endif #ifndef EGL_BAD_STREAM_KHR #define EGL_BAD_STREAM_KHR 0x321B #endif #ifndef EGL_BAD_STATE_KHR #define EGL_BAD_STATE_KHR 0x321C #endif namespace { std::string to_hex_string(int n) { std::stringstream ss; ss << std::showbase << std::hex << n; return ss.str(); } struct egl_category : std::error_category { const char* name() const noexcept override { return "egl"; } std::string message(int ev) const override { #define CASE_FOR_ERROR(error) \ case error: return #error " (" + to_hex_string(error) + ")"; switch (ev) { CASE_FOR_ERROR(EGL_SUCCESS) CASE_FOR_ERROR(EGL_NOT_INITIALIZED) CASE_FOR_ERROR(EGL_BAD_ACCESS) CASE_FOR_ERROR(EGL_BAD_ALLOC) CASE_FOR_ERROR(EGL_BAD_ATTRIBUTE) CASE_FOR_ERROR(EGL_BAD_CONFIG) CASE_FOR_ERROR(EGL_BAD_CONTEXT) CASE_FOR_ERROR(EGL_BAD_CURRENT_SURFACE) CASE_FOR_ERROR(EGL_BAD_DISPLAY) CASE_FOR_ERROR(EGL_BAD_MATCH) CASE_FOR_ERROR(EGL_BAD_NATIVE_PIXMAP) CASE_FOR_ERROR(EGL_BAD_NATIVE_WINDOW) CASE_FOR_ERROR(EGL_BAD_PARAMETER) CASE_FOR_ERROR(EGL_BAD_SURFACE) CASE_FOR_ERROR(EGL_CONTEXT_LOST) CASE_FOR_ERROR(EGL_BAD_DEVICE_EXT) CASE_FOR_ERROR(EGL_BAD_STREAM_KHR) CASE_FOR_ERROR(EGL_BAD_STATE_KHR) default: return "Unknown error (" + to_hex_string(ev) + ")"; } #undef CASE_ERROR } }; } std::error_category const& mir::graphics::egl_category() { static class egl_category const egl_category_instance{}; return egl_category_instance; } ./src/platform/graphics/overlapping_output_grouping.cpp0000644000004100000410000001072313115234416024045 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "mir/graphics/overlapping_output_grouping.h" #include "mir/graphics/display_configuration.h" #include "mir/geometry/rectangle.h" #include "mir/geometry/rectangles.h" #include namespace mg = mir::graphics; namespace geom = mir::geometry; namespace { struct DCOutputHash { size_t operator()(mg::DisplayConfigurationOutput const& o) const { return o.id.as_value(); } }; struct DCOutputEqual { bool operator()(mg::DisplayConfigurationOutput const& o1, mg::DisplayConfigurationOutput const& o2) const { return o1.id == o2.id; } }; } /************************** * OverlappingOutputGroup * **************************/ geom::Rectangle mg::OverlappingOutputGroup::bounding_rectangle() const { geom::Rectangles rectangles; for (auto const& output : outputs) rectangles.add(output.extents()); return rectangles.bounding_rectangle(); } void mg::OverlappingOutputGroup::for_each_output( std::function const& f) const { for (auto const& output : outputs) f(output); } /***************************** * OverlappingOutputGrouping * *****************************/ mg::OverlappingOutputGrouping::OverlappingOutputGrouping(DisplayConfiguration const& conf) { conf.for_each_output([&](DisplayConfigurationOutput const& conf_output) { if (conf_output.connected && conf_output.used && conf_output.power_mode == mir_power_mode_on && conf_output.current_mode_index < conf_output.modes.size()) { add_output(conf_output); } }); } void mg::OverlappingOutputGrouping::for_each_group( std::function const& f) { for (auto const& g : groups) f(g); } void mg::OverlappingOutputGrouping::add_output(DisplayConfigurationOutput const& conf_output) { std::vector overlapping_groups; geom::Rectangle const& rect_output = conf_output.extents(); /* * Find which groups the configuration overlaps with. Search in reverse * so that we get the indices in reverse sorted order, so we can erase * groups easily in the next step. */ for (int i = groups.size() - 1; i >= 0; i--) { bool found_overlap{false}; groups[i].for_each_output( [&](DisplayConfigurationOutput const& conf_o) { /* * Prevent grouping of outputs when they have differing * orientations. It's safer to assume the hardware can't * handle it for now... until proven otherwise. */ if (conf_o.extents().overlaps(rect_output) && conf_o.orientation == conf_output.orientation) found_overlap = true; }); if (found_overlap == true) overlapping_groups.push_back(i); } /* Unite the groups */ if (overlapping_groups.size() > 0) { std::unordered_set new_group; for (auto i : overlapping_groups) { groups[i].for_each_output([&](DisplayConfigurationOutput const& conf_o) { new_group.insert(conf_o); }); /* * Erase the processed group. We can do this safely since the group indices * are in reverse sorted order. */ groups.erase(groups.begin() + i); } new_group.insert(conf_output); groups.push_back(OverlappingOutputGroup{new_group.begin(), new_group.end()}); } else { std::vector v{conf_output}; groups.push_back(OverlappingOutputGroup{v.begin(), v.end()}); } } ./src/platforms/0000755000004100000410000000000013115234677014052 5ustar www-datawww-data./src/platforms/CMakeLists.txt0000644000004100000410000000545713115234664016621 0ustar www-datawww-data# This needs to change whenever the ABI between the platform # modules and the server changes in an incompatible way. # This ABI is much smaller than the full libmirplatform ABI. # # TODO: Add an extra driver-ABI check target. set(MIR_SERVER_INPUT_PLATFORM_ABI 6) set(MIR_SERVER_INPUT_PLATFORM_STANZA_VERSION 0.25) set(MIR_SERVER_INPUT_PLATFORM_ABI ${MIR_SERVER_INPUT_PLATFORM_ABI} PARENT_SCOPE) set(MIR_SERVER_INPUT_PLATFORM_VERSION "MIR_INPUT_PLATFORM_${MIR_SERVER_INPUT_PLATFORM_STANZA_VERSION}") set(MIR_SERVER_INPUT_PLATFORM_VERSION ${MIR_SERVER_INPUT_PLATFORM_VERSION} PARENT_SCOPE) set(MIR_SERVER_GRAPHICS_PLATFORM_ABI 12) set(MIR_SERVER_GRAPHICS_PLATFORM_STANZA_VERSION 0.26) set(MIR_SERVER_GRAPHICS_PLATFORM_ABI ${MIR_SERVER_GRAPHICS_PLATFORM_ABI} PARENT_SCOPE) set(MIR_SERVER_GRAPHICS_PLATFORM_VERSION "MIR_GRAPHICS_PLATFORM_${MIR_SERVER_GRAPHICS_PLATFORM_STANZA_VERSION}") set(MIR_SERVER_GRAPHICS_PLATFORM_VERSION ${MIR_SERVER_GRAPHICS_PLATFORM_VERSION} PARENT_SCOPE) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/input_platform_symbols.map.in ${CMAKE_CURRENT_BINARY_DIR}/input_platform_symbols.map) set(MIR_INPUT_PLATFORM_VERSION_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/input_platform_symbols.map) set(MIR_INPUT_PLATFORM_VERSION_SCRIPT ${MIR_INPUT_PLATFORM_VERSION_SCRIPT} PARENT_SCOPE) set(MIR_SERVER_PLATFORM_PATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/mir/server-platform ) set(MIR_SERVER_PLATFORM_PATH ${MIR_SERVER_PLATFORM_PATH} PARENT_SCOPE ) set(MIR_CLIENT_PLATFORM_ABI 5) set(MIR_CLIENT_PLATFORM_STANZA_VERSION 5) set(MIR_CLIENT_PLATFORM_ABI ${MIR_CLIENT_PLATFORM_ABI} PARENT_SCOPE) set(MIR_CLIENT_PLATFORM_VERSION "MIR_CLIENT_PLATFORM_${MIR_CLIENT_PLATFORM_STANZA_VERSION}") set(MIR_CLIENT_PLATFORM_VERSION ${MIR_CLIENT_PLATFORM_VERSION} PARENT_SCOPE) set(server_common_include_dirs ${PROJECT_SOURCE_DIR}/include/platform ${PROJECT_SOURCE_DIR}/include/renderers/gl ${PROJECT_SOURCE_DIR}/include/renderers/sw ) # TODO platform implementations shouldn't depend on private APIs set(server_common_include_dirs ${server_common_include_dirs} ${CMAKE_CURRENT_SOURCE_DIR}/common/server ${PROJECT_SOURCE_DIR}/src/include/platform ) set(server_symbol_map ${CMAKE_CURRENT_SOURCE_DIR}/common/server/symbols.map) set(client_common_include_dirs ${PROJECT_SOURCE_DIR}/include/client ${CMAKE_CURRENT_SOURCE_DIR}/common/client ) # TODO client platform implementations shouldn't depend on private APIs set(client_common_include_dirs ${client_common_include_dirs} ${PROJECT_SOURCE_DIR}/src/include/client ) add_subdirectory(common/) if (MIR_BUILD_PLATFORM_MESA_KMS OR MIR_BUILD_PLATFORM_MESA_X11) add_subdirectory(mesa/) endif() if (MIR_BUILD_PLATFORM_ANDROID) add_subdirectory(android/) endif() if (MIR_BUILD_PLATFORM_EGLSTREAM_KMS) add_subdirectory(eglstream-kms) endif() add_subdirectory(evdev/) ./src/platforms/android/0000755000004100000410000000000013115234416015461 5ustar www-datawww-data./src/platforms/android/CMakeLists.txt0000644000004100000410000000044113115234416020220 0ustar www-datawww-dataadd_definitions(-DANDROID) include_directories(SYSTEM ${LIBHARDWARE_INCLUDE_DIRS}) include_directories( ${server_common_include_dirs} include/ ) add_subdirectory(server/) add_subdirectory(client/) add_subdirectory(common/) if (MIR_ENABLE_TESTS) add_subdirectory(utils/) endif() ./src/platforms/android/include/0000755000004100000410000000000013115234677017115 5ustar www-datawww-data./src/platforms/android/include/mir_native_window.h0000644000004100000410000000420213115234664023004 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_MIR_NATIVE_WINDOW_H_ #define MIR_GRAPHICS_ANDROID_MIR_NATIVE_WINDOW_H_ #include #include #include #include namespace mir { namespace graphics { namespace android { class AndroidDriverInterpreter; class SyncFileOps; class NativeWindowReport; class MirNativeWindow : public ANativeWindow { public: explicit MirNativeWindow( std::shared_ptr const& interpreter, std::shared_ptr const& report); int query(int key, int* value) const; int perform(int key, va_list args ); int dequeueBuffer(struct ANativeWindowBuffer** buffer, int* fence); int dequeueBufferAndWait(struct ANativeWindowBuffer** buffer); int queueBuffer(struct ANativeWindowBuffer* buffer, int fence); int queueBufferDeprecated(struct ANativeWindowBuffer* buffer); int cancelBuffer(struct ANativeWindowBuffer* buffer, int fence); int cancelBufferDeprecated(struct ANativeWindowBuffer* buffer); int setSwapInterval(int interval); void use_native_surface(std::shared_ptr const& interpreter); private: std::shared_ptr driver_interpreter; std::shared_ptr const report; std::shared_ptr const sync_ops; std::vector cancelled_buffers; }; } } } #endif /* MIR_GRAPHICS_ANDROID_MIR_NATIVE_WINDOW_H_ */ ./src/platforms/android/include/command_stream_sync.h0000644000004100000410000000316613115234416023310 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_COMMAND_STREAM_SYNC_H_ #define MIR_GRAPHICS_COMMAND_STREAM_SYNC_H_ #include namespace mir { namespace graphics { class CommandStreamSync { public: //insert a sync object into the GL command stream of the current context. // \warning the calling thread should have a current egl context and display virtual void raise() = 0; // remove fence without waiting. virtual void reset() = 0; //wait for fence. // \ param [in] ns The amount of time to wait for the fence to become signalled // \ returns true if the fence was signalled, false if timeout virtual bool wait_for(std::chrono::nanoseconds ns) = 0; virtual ~CommandStreamSync() = default; CommandStreamSync() = default; CommandStreamSync(CommandStreamSync const&) = delete; CommandStreamSync& operator=(CommandStreamSync const&) = delete; }; } } #endif /* MIR_GRAPHICS_COMMAND_STREAM_SYNC_H_ */ ./src/platforms/android/include/egl_sync_extensions.h0000644000004100000410000000262513115234664023351 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_EGL_SYNC_EXTENSIONS_H_ #define MIR_GRAPHICS_EGL_SYNC_EXTENSIONS_H_ #ifndef GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES #endif #define EGL_EGLEXT_PROTOTYPES //Xenial egl has started needing a header (android/native_window.h) //That we don't have in the android-headers package yet. #include #include #include #include namespace mir { namespace graphics { struct EGLSyncExtensions { EGLSyncExtensions(); PFNEGLCREATESYNCKHRPROC const eglCreateSyncKHR; PFNEGLDESTROYIMAGEKHRPROC const eglDestroySyncKHR; PFNEGLCLIENTWAITSYNCKHRPROC const eglClientWaitSyncKHR; }; } } #endif /* MIR_GRAPHICS_EGL_SYNC_EXTENSIONS_H_ */ ./src/platforms/android/include/sync_fence.h0000644000004100000410000000352113115234664021377 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_SYNC_FENCE_H_ #define MIR_GRAPHICS_ANDROID_SYNC_FENCE_H_ #include "fence.h" #include "mir/fd.h" #include namespace mir { namespace graphics { namespace android { class SyncFileOps { public: virtual ~SyncFileOps() = default; virtual int ioctl(int, int, void*) = 0; virtual int dup(int) = 0; virtual int close(int) = 0; }; class RealSyncFileOps : public SyncFileOps { public: int ioctl(int fd, int req, void* dat); int dup(int fd); int close(int fd); }; class SyncFence : public Fence { public: explicit SyncFence(std::shared_ptr const&, Fd fd); void wait() override; bool wait_for(std::chrono::milliseconds) override; void reset_fence() override; void merge_with(NativeFence& merge_fd) override; NativeFence copy_native_handle() const override; NativeFence native_handle() const override; private: SyncFence(SyncFence const&) = delete; SyncFence& operator=(SyncFence const&) = delete; Fd fence_fd; std::shared_ptr const ops; int const infinite_timeout = -1; }; } } } #endif /* MIR_GRAPHICS_ANDROID_SYNC_FENCE_H_ */ ./src/platforms/android/include/android/0000755000004100000410000000000013115234417020525 5ustar www-datawww-data./src/platforms/android/include/android/native_window.h0000644000004100000410000000147713115234416023563 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ //NOTE: this file exists to workaround a xenial packaging issue //described in LP: #1539571 #include "system/window.h" ./src/platforms/android/include/native_buffer.h0000644000004100000410000000414513115234664022105 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_NATIVE_BUFFER_H_ #define MIR_GRAPHICS_ANDROID_NATIVE_BUFFER_H_ #include "mir/graphics/native_buffer.h" #include "fence.h" #include #include namespace mir { namespace graphics { namespace android { enum class BufferAccess { read, write }; class NativeBuffer : public graphics::NativeBuffer { public: virtual ~NativeBuffer() = default; virtual ANativeWindowBuffer* anwb() const = 0; virtual buffer_handle_t handle() const = 0; virtual android::NativeFence copy_fence() const = 0; virtual android::NativeFence fence() const = 0; virtual void ensure_available_for(android::BufferAccess intent) = 0; virtual bool ensure_available_for(android::BufferAccess intent, std::chrono::milliseconds timeout) = 0; virtual void update_usage(android::NativeFence& fence, android::BufferAccess current_usage) = 0; virtual void reset_fence() = 0; virtual void lock_for_gpu() = 0; virtual void wait_for_unlock_by_gpu() = 0; protected: NativeBuffer() = default; NativeBuffer(NativeBuffer const&) = delete; NativeBuffer& operator=(NativeBuffer const&) = delete; }; android::NativeBuffer* to_native_buffer_checked(graphics::NativeBuffer* buffer); std::shared_ptr to_native_buffer_checked( std::shared_ptr const& buffer); } } } #endif /* MIR_GRAPHICS_ANDROID_NATIVE_BUFFER_H_ */ ./src/platforms/android/include/android_driver_interpreter.h0000644000004100000410000000337613115234664024711 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_DRIVER_INTERPRETER_H_ #define MIR_GRAPHICS_ANDROID_DRIVER_INTERPRETER_H_ #include "native_buffer.h" #include #include "mir/geometry/size.h" #include namespace mir { namespace graphics { namespace android { class AndroidDriverInterpreter { public: virtual NativeBuffer* driver_requests_buffer() = 0; virtual void driver_returns_buffer(ANativeWindowBuffer*, int fence) = 0; virtual void dispatch_driver_request_format(int format) = 0; virtual void dispatch_driver_request_buffer_count(unsigned int count) = 0; virtual void dispatch_driver_request_buffer_size(geometry::Size size) = 0; virtual int driver_requests_info(int key) const = 0; virtual void sync_to_display(bool sync) = 0; protected: AndroidDriverInterpreter() {}; virtual ~AndroidDriverInterpreter() {}; AndroidDriverInterpreter(AndroidDriverInterpreter const&) = delete; AndroidDriverInterpreter& operator=(AndroidDriverInterpreter const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DRIVER_INTERPRETER_H_ */ ./src/platforms/android/include/android_native_buffer.h0000644000004100000410000000451113115234664023602 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_ANDROID_NATIVE_BUFFER_H_ #define MIR_GRAPHICS_ANDROID_ANDROID_NATIVE_BUFFER_H_ #include "native_buffer.h" #include #include namespace mir { namespace graphics { class CommandStreamSync; namespace android { class Fence; struct AndroidNativeBuffer : public NativeBuffer { AndroidNativeBuffer( std::shared_ptr const& handle, std::shared_ptr const& cmdstream_sync, std::shared_ptr const& fence, BufferAccess fence_access); ANativeWindowBuffer* anwb() const; buffer_handle_t handle() const; NativeFence copy_fence() const; NativeFence fence() const; void ensure_available_for(BufferAccess); bool ensure_available_for(android::BufferAccess intent, std::chrono::milliseconds timeout); void update_usage(NativeFence& merge_fd, BufferAccess); void reset_fence(); void lock_for_gpu(); void wait_for_unlock_by_gpu(); private: std::shared_ptr cmdstream_sync; std::shared_ptr fence_; BufferAccess access; std::shared_ptr native_window_buffer; }; struct RefCountedNativeBuffer : public ANativeWindowBuffer { RefCountedNativeBuffer(std::shared_ptr const& handle); void driver_reference(); void driver_dereference(); void mir_dereference(); private: ~RefCountedNativeBuffer() = default; std::shared_ptr const handle_resource; std::mutex mutex; bool mir_reference; int driver_references; }; } } } #endif /* MIR_GRAPHICS_ANDROID_ANDROID_NATIVE_BUFFER_H_ */ ./src/platforms/android/include/native_window_report.h0000644000004100000410000000561513115234664023541 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_NATIVE_WINDOW_REPORT_H_ #define MIR_GRAPHICS_ANDROID_NATIVE_WINDOW_REPORT_H_ #include #include #include namespace mir { namespace logging { class Logger; } namespace graphics { namespace android { enum class BufferEvent { Queue, Dequeue, Cancel }; class NativeWindowReport { public: NativeWindowReport() = default; virtual ~NativeWindowReport() = default; virtual void buffer_event(BufferEvent type, ANativeWindow const* win, ANativeWindowBuffer* buf, int fence) const = 0; virtual void buffer_event(BufferEvent type, ANativeWindow const* win, ANativeWindowBuffer* buf) const = 0; virtual void query_event(ANativeWindow const* win, int type, int result) const = 0; virtual void perform_event(ANativeWindow const* win, int type, std::vector const& args) const = 0; private: NativeWindowReport(NativeWindowReport const&) = delete; NativeWindowReport& operator=(NativeWindowReport const&) = delete; }; class NullNativeWindowReport : public NativeWindowReport { void buffer_event(BufferEvent type, ANativeWindow const* win, ANativeWindowBuffer* buf, int fence) const override; void buffer_event(BufferEvent type, ANativeWindow const* win, ANativeWindowBuffer* buf) const override; void query_event(ANativeWindow const* win, int type, int result) const override; void perform_event(ANativeWindow const* win, int type, std::vector const& args) const override; }; class ConsoleNativeWindowReport : public NativeWindowReport { public: ConsoleNativeWindowReport(std::shared_ptr const&); void buffer_event(BufferEvent type, ANativeWindow const* win, ANativeWindowBuffer* buf, int fence) const override; void buffer_event(BufferEvent type, ANativeWindow const* win, ANativeWindowBuffer* buf) const override; void query_event(ANativeWindow const* win, int type, int result) const override; void perform_event(ANativeWindow const* win, int type, std::vector const& args) const override; private: std::shared_ptr const logger; std::string const component_name = "AndroidNativeWindow"; }; } } } #endif /* MIR_GRAPHICS_ANDROID_NATIVE_WINDOW_REPORT_H_ */ ./src/platforms/android/include/egl_sync_fence.h0000644000004100000410000000343513115234416022225 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_EGL_SYNC_FENCE_H_ #define MIR_GRAPHICS_EGL_SYNC_FENCE_H_ #include "egl_sync_extensions.h" #include "command_stream_sync.h" #include #include namespace mir { namespace graphics { class NullCommandSync : public CommandStreamSync { void raise() override; void reset() override; bool wait_for(std::chrono::nanoseconds ns) override; }; class EGLSyncFence : public CommandStreamSync { public: EGLSyncFence(std::shared_ptr const&); ~EGLSyncFence(); void raise() override; void reset() override; bool wait_for(std::chrono::nanoseconds ns) override; private: void reset(std::unique_lock const&); bool wait_for(std::unique_lock const&, std::chrono::nanoseconds ns); std::shared_ptr const egl; std::chrono::nanoseconds const default_timeout{ std::chrono::duration_cast(std::chrono::milliseconds(1))}; std::mutex mutex; EGLDisplay fence_display; EGLSyncKHR sync_point; }; } } #endif /* MIR_GRAPHICS_EGL_SYNC_FENCE_H_ */ ./src/platforms/android/include/fence.h0000644000004100000410000000274613115234664020353 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_FENCE_H_ #define MIR_GRAPHICS_ANDROID_FENCE_H_ #include namespace mir { namespace graphics { namespace android { //TODO: (kdub) remove this type in favor of mir::Fd typedef int NativeFence; class Fence { public: virtual ~Fence() = default; virtual void wait() = 0; virtual bool wait_for(std::chrono::milliseconds) = 0; virtual void reset_fence() = 0; //TODO: (kdub) use the Fd type instead of NativeFence virtual void merge_with(NativeFence& merge_fd) = 0; virtual NativeFence copy_native_handle() const = 0; virtual NativeFence native_handle() const = 0; protected: Fence() = default; Fence(Fence const&) = delete; Fence& operator=(Fence const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_FENCE_H_ */ ./src/platforms/android/include/android_format_conversion-inl.h0000644000004100000410000000536413115234664025307 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_ANDROID_FORMAT_CONVERSION_INL_H_ #define MIR_GRAPHICS_ANDROID_ANDROID_FORMAT_CONVERSION_INL_H_ #include "mir/graphics/buffer_properties.h" #include "mir_toolkit/common.h" #include // to fix missing #includes in graphics.h #include #include namespace mir { namespace graphics { namespace android { inline static int to_android_format(MirPixelFormat format) { switch(format) { case mir_pixel_format_abgr_8888: return HAL_PIXEL_FORMAT_RGBA_8888; case mir_pixel_format_xbgr_8888: return HAL_PIXEL_FORMAT_RGBX_8888; case mir_pixel_format_argb_8888: return HAL_PIXEL_FORMAT_BGRA_8888; case mir_pixel_format_xrgb_8888: return HAL_PIXEL_FORMAT_BGRA_8888; case mir_pixel_format_rgb_888: return HAL_PIXEL_FORMAT_RGB_888; case mir_pixel_format_rgb_565: return HAL_PIXEL_FORMAT_RGB_565; default: return 0; } } inline static MirPixelFormat to_mir_format(int format) { switch(format) { case HAL_PIXEL_FORMAT_RGBA_8888: return mir_pixel_format_abgr_8888; case HAL_PIXEL_FORMAT_RGBX_8888: return mir_pixel_format_xbgr_8888; case HAL_PIXEL_FORMAT_BGRA_8888: return mir_pixel_format_argb_8888; case HAL_PIXEL_FORMAT_RGB_888: return mir_pixel_format_rgb_888; case HAL_PIXEL_FORMAT_RGB_565: return mir_pixel_format_rgb_565; default: return mir_pixel_format_invalid; } } inline static uint32_t convert_to_android_usage(BufferUsage usage) { switch (usage) { case BufferUsage::hardware: return (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER); case BufferUsage::software: return (GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE); default: return -1; } } } } } #endif /* MIR_GRAPHICS_ANDROID_ANDROID_FORMAT_CONVERSION_INL_H_ */ ./src/platforms/android/utils/0000755000004100000410000000000013115234677016632 5ustar www-datawww-data./src/platforms/android/utils/CMakeLists.txt0000644000004100000410000000221213115234664021363 0ustar www-datawww-datalist( APPEND ANDROID_DIAGNOSTICS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_android_hardware_sanity.cpp ${CMAKE_CURRENT_SOURCE_DIR}/patterns.cpp ) add_definitions(-DMIR_SERVER_GRAPHICS_PLATFORM_VERSION="${MIR_SERVER_GRAPHICS_PLATFORM_VERSION}") include_directories( ${PROJECT_SOURCE_DIR}/include/server ${PROJECT_SOURCE_DIR}/include/client ${PROJECT_SOURCE_DIR}/include/platform ${PROJECT_SOURCE_DIR}/src/include/common ${PROJECT_SOURCE_DIR}/include/test ${PROJECT_SOURCE_DIR}/tests/include ${PROJECT_SOURCE_DIR}/src/include/server ${PROJECT_SOURCE_DIR}/examples ${PROJECT_SOURCE_DIR}/src/platforms/android/include ) add_executable( mir_android_diagnostics ${ANDROID_DIAGNOSTICS_SRCS}) target_link_libraries( mir_android_diagnostics mirserver mirdraw mir-test-static mir-test-framework-static ${LIBHARDWARE_LIBRARIES} ) mir_add_wrapped_executable(mir_demo_standalone_render_overlays render_overlays.cpp ) target_link_libraries(mir_demo_standalone_render_overlays mirclient mircommon mirplatform ) install(PROGRAMS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/mir_android_diagnostics DESTINATION ${CMAKE_INSTALL_BINDIR} ) ./src/platforms/android/utils/draw_pattern_checkered-inl.h0000644000004100000410000000451313115234416024244 0ustar www-datawww-data/* * Copyright © 2012-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir_toolkit/common.h" template DrawPatternCheckered::DrawPatternCheckered(uint32_t (&pattern) [Rows][Cols]) { for (size_t i=0; i void DrawPatternCheckered::draw(MirGraphicsRegion const& region) const { if (region.pixel_format != mir_pixel_format_abgr_8888) throw(std::runtime_error("cannot draw region, incorrect format")); auto bpp = MIR_BYTES_PER_PIXEL(mir_pixel_format_abgr_8888); for(int i=0; i < region.width; i++) { for(int j=0; j(®ion.vaddr[j*region.stride + (i * bpp)]); *pixel = color_pattern[key_row][key_col]; } } } template bool DrawPatternCheckered::check(MirGraphicsRegion const& region) const { if (region.pixel_format != mir_pixel_format_abgr_8888) throw(std::runtime_error("cannot check region, incorrect format")); auto bpp = MIR_BYTES_PER_PIXEL(mir_pixel_format_abgr_8888); for(int i=0; i< region.width; i++) { for(int j=0; j(®ion.vaddr[j*region.stride + (i * bpp)]); if ( *pixel != color_pattern[key_row][key_col] ) { return false; } } } return true; } ./src/platforms/android/utils/patterns.cpp0000644000004100000410000000370613115234416021173 0ustar www-datawww-data/* * Copyright © 2012-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "patterns.h" #include "mir_toolkit/common.h" namespace mt=mir::test; mt::DrawPatternSolid::DrawPatternSolid(uint32_t color_value) : color_value(color_value) { } void mt::DrawPatternSolid::draw(MirGraphicsRegion const& region) const { if (region.pixel_format != mir_pixel_format_abgr_8888 ) throw(std::runtime_error("cannot draw region, incorrect format")); auto bpp = MIR_BYTES_PER_PIXEL(mir_pixel_format_abgr_8888); for(auto i = 0; i < region.height; i++) { for(auto j = 0; j < region.width; j++) { uint32_t *pixel = (uint32_t*) ®ion.vaddr[i*region.stride + (j * bpp)]; *pixel = color_value; } } } bool mt::DrawPatternSolid::check(MirGraphicsRegion const& region) const { if (region.pixel_format != mir_pixel_format_abgr_8888 ) throw(std::runtime_error("cannot check region, incorrect format")); auto bpp = MIR_BYTES_PER_PIXEL(mir_pixel_format_abgr_8888); for(auto i = 0; i < region.height; i++) { for(auto j = 0; j < region.width; j++) { uint32_t *pixel = (uint32_t*) ®ion.vaddr[i*region.stride + (j * bpp)]; if (*pixel != color_value) { return false; } } } return true; } ./src/platforms/android/utils/test_android_hardware_sanity.cpp0000644000004100000410000002671113115234664025264 0ustar www-datawww-data/* * Copyright © 2012-2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/default_server_configuration.h" #include "mir/compositor/compositor.h" #include "mir/compositor/scene.h" #include "mir/compositor/scene_element.h" #include "mir/graphics/renderable.h" #include "mir/graphics/display.h" #include "mir/graphics/platform.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "mir/graphics/buffer.h" #include "mir/graphics/buffer_properties.h" #include "mir/renderer/sw/pixel_source.h" #include "mir_test_framework/server_runner.h" #include "mir/test/validity_matchers.h" #include "mir/test/as_render_target.h" #include "patterns.h" #include "graphics.h" #include #include namespace mtf = mir_test_framework; namespace mt = mir::test; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace mc = mir::compositor; namespace mrs = mir::renderer::software; namespace { static int test_width = 300; static int test_height = 200; static uint32_t pattern [2][2] = {{0x12345678, 0x23456789}, {0x34567890, 0x45678901}}; static mt::DrawPatternCheckered<2,2> draw_pattern(pattern); MirPixelFormat select_format_for_visual_id(int visual_id) { if (visual_id == 5) return mir_pixel_format_argb_8888; if (visual_id == 1) return mir_pixel_format_abgr_8888; return mir_pixel_format_invalid; } struct NoCompositingServer : mir::DefaultServerConfiguration { NoCompositingServer(int argc, char const* argv[]) : DefaultServerConfiguration(argc, argv) { } std::shared_ptr the_cursor() override { return nullptr; } std::shared_ptr the_compositor() override { struct NullCompositor : mc::Compositor { void start() override {}; void stop() override {}; }; return compositor( [this]() { return std::make_shared(); }); } }; struct Runner : mtf::ServerRunner { mir::DefaultServerConfiguration& server_config() override { return config; } char const* argv = "./aa"; NoCompositingServer config{1, &argv}; }; struct AndroidMirDiagnostics : testing::Test { static void SetUpTestCase() { runner = std::make_unique(); runner->start_server(); } static void TearDownTestCase() { runner->stop_server(); runner.reset(); } static std::unique_ptr runner; geom::Size size{334, 122}; MirPixelFormat pf = mir_pixel_format_abgr_8888; mg::BufferProperties sw_properties{size, pf, mg::BufferUsage::software}; mg::BufferProperties hw_properties{size, pf, mg::BufferUsage::hardware}; }; std::unique_ptr AndroidMirDiagnostics::runner; } TEST_F(AndroidMirDiagnostics, client_can_draw_with_cpu) { auto connection = mir_connect_sync(runner->new_connection().c_str(), "test_renderer"); EXPECT_THAT(connection, IsValid()); auto const spec = mir_create_normal_window_spec( connection, test_width, test_height); mir_window_spec_set_pixel_format(spec, mir_pixel_format_abgr_8888); mir_window_spec_set_buffer_usage(spec, mir_buffer_usage_software); auto const window = mir_create_window_sync(spec); mir_window_spec_release(spec); EXPECT_THAT(window, IsValid()); MirGraphicsRegion graphics_region; mir_buffer_stream_get_graphics_region(mir_window_get_buffer_stream(window), &graphics_region); draw_pattern.draw(graphics_region); mir_buffer_stream_swap_buffers_sync(mir_window_get_buffer_stream(window)); auto scene = runner->config.the_scene(); auto seq = scene->scene_elements_for(this); ASSERT_THAT(seq, testing::SizeIs(1)); auto buffer = seq[0]->renderable()->buffer(); auto valid_content = false; auto pixel_source = dynamic_cast(buffer->native_buffer_base()); ASSERT_THAT(pixel_source, testing::Ne(nullptr)); pixel_source->read([&](unsigned char const* data){ MirGraphicsRegion region{ buffer->size().width.as_int(), buffer->size().height.as_int(), pixel_source->stride().as_int(), buffer->pixel_format(), reinterpret_cast(const_cast(data))}; valid_content = draw_pattern.check(region); }); EXPECT_TRUE(valid_content); mir_window_release_sync(window); mir_connection_release(connection); } TEST_F(AndroidMirDiagnostics, client_can_draw_with_gpu) { auto connection = mir_connect_sync(runner->new_connection().c_str(), "test_renderer"); EXPECT_THAT(connection, IsValid()); int major, minor, n, visual_id; EGLContext context; EGLSurface egl_surface; EGLConfig egl_config; EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BUFFER_SIZE, 32, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; auto native_display = mir_connection_get_egl_native_display(connection); auto egl_display = eglGetDisplay(native_display); eglInitialize(egl_display, &major, &minor); eglChooseConfig(egl_display, attribs, &egl_config, 1, &n); eglGetConfigAttrib(egl_display, egl_config, EGL_NATIVE_VISUAL_ID, &visual_id); auto const spec = mir_create_normal_window_spec(connection, test_width, test_height); mir_window_spec_set_pixel_format(spec, select_format_for_visual_id(visual_id)); auto const mir_surface = mir_create_window_sync(spec); mir_window_spec_release(spec); EXPECT_THAT(mir_surface, IsValid()); auto native_window = static_cast( mir_buffer_stream_get_egl_native_window(mir_window_get_buffer_stream(mir_surface))); egl_surface = eglCreateWindowSurface(egl_display, egl_config, native_window, NULL); context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attribs); eglMakeCurrent(egl_display, egl_surface, egl_surface, context); glClearColor(0.0, 1.0, 0.0, 1.0); //green glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(egl_display, egl_surface); auto scene = runner->config.the_scene(); auto seq = scene->scene_elements_for(this); ASSERT_THAT(seq, testing::SizeIs(1)); auto buffer = seq[0]->renderable()->buffer(); auto valid_content = false; auto pixel_source = dynamic_cast(buffer->native_buffer_base()); ASSERT_THAT(pixel_source, testing::Ne(nullptr)); pixel_source->read([&](unsigned char const* data){ MirGraphicsRegion region{ buffer->size().width.as_int(), buffer->size().height.as_int(), pixel_source->stride().as_int(), buffer->pixel_format(), reinterpret_cast(const_cast(data))}; mt::DrawPatternSolid green_pattern(0xFF00FF00); valid_content = green_pattern.check(region); }); EXPECT_TRUE(valid_content); mir_window_release_sync(mir_surface); mir_connection_release(connection); } TEST_F(AndroidMirDiagnostics, display_can_post) { auto display = runner->config.the_display(); display->for_each_display_sync_group([](mg::DisplaySyncGroup& group) { group.for_each_display_buffer([](mg::DisplayBuffer& buffer) { auto const render_target = mt::as_render_target(buffer); render_target->make_current(); mir::draw::glAnimationBasic gl_animation; gl_animation.init_gl(); gl_animation.render_gl(); render_target->swap_buffers(); gl_animation.render_gl(); render_target->swap_buffers(); }); group.post(); }); } TEST_F(AndroidMirDiagnostics, display_can_post_overlay) { auto buffer = runner->config.the_buffer_allocator()->alloc_buffer(sw_properties); struct BasicRenderable : mg::Renderable { BasicRenderable(std::shared_ptr const& buffer) : buffer_(buffer) { } unsigned int swap_interval() const override { return 1u; } ID id() const override { return this; } std::shared_ptr buffer() const override { return buffer_; } geom::Rectangle screen_position() const override { return {{0,0}, buffer_->size()} ; } float alpha() const override { return 1.0f; } glm::mat4 transformation() const override { return trans; } bool shaped() const override { return false; } std::shared_ptr const buffer_; glm::mat4 const trans; }; auto display = runner->config.the_display(); display->for_each_display_sync_group([](mg::DisplaySyncGroup& group) { group.for_each_display_buffer([](mg::DisplayBuffer& db) { mt::as_render_target(db)->make_current(); auto area = db.view_area(); mg::BufferProperties properties{ area.size, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware}; auto buffer = runner->config.the_buffer_allocator()->alloc_buffer(properties); mg::RenderableList list{ std::make_shared(buffer) }; db.overlay(list); }); group.post(); }); } TEST_F(AndroidMirDiagnostics, can_allocate_sw_buffer) { using namespace testing; auto buffer = runner->config.the_buffer_allocator()->alloc_buffer(sw_properties); EXPECT_NE(nullptr, buffer); int i = 0; bool valid_content = false; std::vector px( buffer->size().height.as_int() * buffer->size().width.as_int() * MIR_BYTES_PER_PIXEL(buffer->pixel_format())); uint32_t green{0x00FF00FF}; mt::DrawPatternSolid green_pattern(green); std::generate(px.begin(), px.end(), [&i]{ if(i++ % 2) return 0x00; else return 0xFF; }); auto pixel_source = dynamic_cast(buffer->native_buffer_base()); ASSERT_THAT(pixel_source, testing::Ne(nullptr)); pixel_source->write(px.data(), px.size()); pixel_source->read([&](unsigned char const* data){ MirGraphicsRegion region{ buffer->size().width.as_int(), buffer->size().height.as_int(), pixel_source->stride().as_int(), buffer->pixel_format(), reinterpret_cast(const_cast(data))}; valid_content = green_pattern.check(region); }); EXPECT_TRUE(valid_content); } TEST_F(AndroidMirDiagnostics, can_allocate_hw_buffer) { using namespace testing; //TODO: kdub it is a bit trickier to test that a gpu can render... just check creation for now auto test_buffer = runner->config.the_buffer_allocator()->alloc_buffer(hw_properties); EXPECT_NE(nullptr, test_buffer); // Workaround for lp:1502782 test_buffer.reset(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } ./src/platforms/android/utils/patterns.h0000644000004100000410000000401013115234416020625 0ustar www-datawww-data/* * Copyright © 2012-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_TEST_DRAW_PATTERNS_H #define MIR_TEST_DRAW_PATTERNS_H #include "mir_toolkit/mir_client_library.h" #include #include #include #include namespace mir { namespace test { class DrawPattern { public: virtual ~DrawPattern() {}; virtual void draw(MirGraphicsRegion const& region) const = 0; virtual bool check(MirGraphicsRegion const& region) const = 0; protected: DrawPattern() = default; DrawPattern(DrawPattern const&) = delete; DrawPattern& operator=(DrawPattern const&) = delete; }; class DrawPatternSolid : public DrawPattern { public: /* todo: should construct with a color value type, not an uint32 */ DrawPatternSolid(uint32_t color_value); void draw(MirGraphicsRegion const& region) const; bool check(MirGraphicsRegion const& region) const; private: const uint32_t color_value; }; template class DrawPatternCheckered : public DrawPattern { public: /* todo: should construct with a color value type, not an uint32 */ DrawPatternCheckered(uint32_t (&pattern) [Rows][Cols]); void draw(MirGraphicsRegion const& region) const; bool check(MirGraphicsRegion const& region) const; private: uint32_t color_pattern [Rows][Cols]; }; #include "draw_pattern_checkered-inl.h" } } #endif /*MIR_TEST_DRAW_PATTERNS_H */ ./src/platforms/android/utils/render_overlays.cpp0000644000004100000410000002212713115234664022541 0ustar www-datawww-data/* * Copyright © 2012, 2014, 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/options/default_configuration.h" #include "mir/shared_library_prober.h" #include "mir/graphics/display.h" #include "mir/graphics/renderable.h" #include "mir/graphics/display_buffer.h" #include "mir/graphics/platform.h" #include "mir/graphics/platform_probe.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "mir/graphics/buffer_properties.h" #include "mir/graphics/gl_config.h" #include "mir/graphics/display_report.h" #include "mir/renderer/gl/render_target.h" #include "mir/renderer/sw/pixel_source.h" #include "mir_image.h" #include "as_render_target.h" #include "mir/logging/null_shared_library_prober_report.h" #include "mir/logging/dumb_console_logger.h" #include "GLES2/gl2.h" #include #include #include namespace mg=mir::graphics; namespace mo=mir::options; namespace geom=mir::geometry; namespace me=mir::examples; namespace mrs = mir::renderer::software; namespace { volatile std::sig_atomic_t running = true; void signal_handler(int /*signum*/) { running = false; } class PixelBufferABGR { public: PixelBufferABGR(geom::Size sz, uint32_t color) : size{sz.width.as_uint32_t() * sz.height.as_uint32_t()}, data{new uint32_t[size]} { fill(color); } void fill(uint32_t color) { for(auto i = 0u; i < size; i++) data[i] = color; } unsigned char* pixels() { return reinterpret_cast(data.get()); } size_t pixel_size() { return size * sizeof(uint32_t); } private: size_t size; std::unique_ptr data; }; class DemoOverlayClient { public: DemoOverlayClient( mg::GraphicBufferAllocator& buffer_allocator, mg::BufferProperties const& buffer_properties, uint32_t color) : front_buffer(buffer_allocator.alloc_buffer(buffer_properties)), back_buffer(buffer_allocator.alloc_buffer(buffer_properties)), color{color}, last_tick{std::chrono::high_resolution_clock::now()}, pixel_buffer{buffer_properties.size, color} { } void update_green_channel() { char green_value = (color >> 8) & 0xFF; green_value += compute_update_value(); color &= 0xFFFF00FF; color |= (green_value << 8); pixel_buffer.fill(color); if (auto pixel_source = dynamic_cast(back_buffer->native_buffer_base())) pixel_source->write(pixel_buffer.pixels(), pixel_buffer.pixel_size()); std::swap(front_buffer, back_buffer); } std::shared_ptr last_rendered() { return front_buffer; } private: int compute_update_value() { float const update_ratio{3.90625}; //this will give an update of 256 in 1s auto current_tick = std::chrono::high_resolution_clock::now(); auto elapsed_ms = std::chrono::duration_cast( current_tick - last_tick).count(); float update_value = elapsed_ms / update_ratio; last_tick = current_tick; return static_cast(update_value); } std::shared_ptr front_buffer; std::shared_ptr back_buffer; unsigned int color; std::chrono::time_point last_tick; PixelBufferABGR pixel_buffer; }; class DemoRenderable : public mg::Renderable { public: DemoRenderable(std::shared_ptr const& client, geom::Rectangle rect) : client(client), position(rect) { } unsigned int swap_interval() const override { return 1u; } ID id() const override { return this; } std::shared_ptr buffer() const override { return client->last_rendered(); } geom::Rectangle screen_position() const override { return position; } float alpha() const override { return 1.0f; } glm::mat4 transformation() const override { return trans; } bool shaped() const override { return false; } private: std::shared_ptr const client; geom::Rectangle const position; glm::mat4 const trans; }; void render_loop(mir::graphics::Display& display, mir::graphics::GraphicBufferAllocator& allocator) { /* Set up graceful exit on SIGINT and SIGTERM */ struct sigaction sa; sa.sa_handler = signal_handler; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); mg::BufferProperties buffer_properties{ geom::Size{512, 512}, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware }; auto client1 = std::make_shared(allocator, buffer_properties, 0xFF0000FF); auto client2 = std::make_shared(allocator, buffer_properties, 0xFFFFFF00); mg::RenderableList renderlist { std::make_shared(client1, geom::Rectangle{{0,0} , buffer_properties.size}), std::make_shared(client2, geom::Rectangle{{80,80} , buffer_properties.size}) }; while (running) { client1->update_green_channel(); client2->update_green_channel(); display.for_each_display_sync_group([&](mg::DisplaySyncGroup& group) { group.for_each_display_buffer([&](mg::DisplayBuffer& buffer) { // TODO: Is make_current() really needed here? me::as_render_target(buffer)->make_current(); buffer.overlay(renderlist); }); group.post(); }); } } struct GLConfig : mg::GLConfig { int depth_buffer_bits() const override { return 0; } int stencil_buffer_bits() const override { return 0; } }; struct DisplayReport : mg::DisplayReport { void report_successful_setup_of_native_resources() override {} void report_successful_egl_make_current_on_construction() override {} void report_successful_egl_buffer_swap_on_construction() override {} void report_successful_display_construction() override {} void report_egl_configuration(EGLDisplay, EGLConfig) override {} void report_vsync(unsigned int, mg::Frame const&) override {} void report_successful_drm_mode_set_crtc_on_construction() override {} void report_drm_master_failure(int) override {} void report_vt_switch_away_failure() override {} void report_vt_switch_back_failure() override {} }; } int main(int argc, char const** argv) try { mir::logging::NullSharedLibraryProberReport null_report; auto const logger = std::make_shared(); auto config = std::make_unique(argc, argv); auto options = static_cast(config.get())->the_options(); auto const& path = options->get(mo::platform_path); auto platforms = mir::libraries_for_path(path, null_report); if (platforms.empty()) throw std::runtime_error("no platform modules detected"); auto platform_library = mg::module_for_device( platforms, dynamic_cast(*options)); auto describe_fn = platform_library->load_function( "describe_graphics_module", MIR_SERVER_GRAPHICS_PLATFORM_VERSION); auto description = describe_fn(); std::cout << "Loaded module: " << description->file << "\n\t" << "module name: " << description->name << "version: " << description->major_version << "." << description->minor_version << "." << description->micro_version << std::endl; auto platform_fn = platform_library->load_function( "create_host_platform", MIR_SERVER_GRAPHICS_PLATFORM_VERSION); auto platform = platform_fn(options, nullptr, std::make_shared(), logger); //Strange issues going on here with dlopen() + hybris (which uses gnu_indirect_functions) //https://github.com/libhybris/libhybris/issues/315 //calling a GLES function here makes everything resolve correctly. glGetString(GL_EXTENSIONS); auto allocator = platform->create_buffer_allocator(); auto display = platform->create_display(nullptr, std::make_shared()); render_loop(*display, *allocator); return EXIT_SUCCESS; } catch (std::exception& e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; } catch (...) { std::cerr << "unknown exception" << std::endl; return EXIT_FAILURE; } ./src/platforms/android/client/0000755000004100000410000000000013115234677016750 5ustar www-datawww-data./src/platforms/android/client/CMakeLists.txt0000644000004100000410000000215113115234664021503 0ustar www-datawww-datainclude_directories(${client_common_include_dirs}) include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/3rd_party/android-deps) add_definitions(-DANDROID) set(symbol_map ${CMAKE_CURRENT_SOURCE_DIR}/symbols.map) add_library(mirclientplatformandroidobjects OBJECT buffer.cpp android_client_buffer_factory.cpp gralloc_registrar.cpp android_client_platform.cpp client_platform_factory.cpp egl_native_surface_interpreter.cpp android_native_display_container.cpp ) add_library(mirclientplatformandroid MODULE $ ) set_target_properties( mirclientplatformandroid PROPERTIES OUTPUT_NAME android LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/client-modules PREFIX "" SUFFIX ".so.${MIR_CLIENT_PLATFORM_ABI}" LINK_FLAGS "-Wl,--version-script,${symbol_map}" LINK_DEPENDS ${symbol_map} ) target_link_libraries(mirclientplatformandroid mirclient client_platform_common mirsharedandroid-static ${LIBHARDWARE_LIBRARIES} ${EGL_LDFLAGS} ${EGL_LIBRARIES} ) install(TARGETS mirclientplatformandroid LIBRARY DESTINATION ${MIR_CLIENT_PLATFORM_PATH}) ./src/platforms/android/client/android_native_display_container.h0000644000004100000410000000332013115234416025663 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_CLIENT_ANDROID_NATIVE_DISPLAY_CONTAINER_H_ #define MIR_CLIENT_ANDROID_NATIVE_DISPLAY_CONTAINER_H_ #include "mir/egl_native_display_container.h" #include "mir_toolkit/client_types.h" #include #include namespace mir { namespace client { namespace android { class AndroidNativeDisplayContainer : public EGLNativeDisplayContainer { public: AndroidNativeDisplayContainer(); virtual ~AndroidNativeDisplayContainer(); MirEGLNativeDisplayType create(ClientPlatform* platform) override; void release(MirEGLNativeDisplayType display) override; bool validate(MirEGLNativeDisplayType display) const override; protected: AndroidNativeDisplayContainer(AndroidNativeDisplayContainer const&) = delete; AndroidNativeDisplayContainer& operator=(AndroidNativeDisplayContainer const&) = delete; private: std::mutex mutable guard; std::unordered_set valid_displays; }; } } } // namespace mir #endif // MIR_CLIENT_ANDROID_NATIVE_DISPLAY_CONTAINER_H_ ./src/platforms/android/client/symbols.map0000644000004100000410000000015013115234416021122 0ustar www-datawww-dataMIR_CLIENT_PLATFORM_5 { global: create_client_platform; is_appropriate_module; local: *; }; ./src/platforms/android/client/android_client_buffer_factory.h0000644000004100000410000000335213115234664025156 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Christopher James Halse Rogers */ #ifndef MIR_CLIENT_ANDROID_ANDROID_BUFFER_FACTORY_H_ #define MIR_CLIENT_ANDROID_ANDROID_BUFFER_FACTORY_H_ #include #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/common.h" #include "mir/geometry/size.h" #include "mir/client_buffer_factory.h" namespace mir { namespace client { class ClientBuffer; namespace android { class BufferRegistrar; class AndroidClientBufferFactory : public ClientBufferFactory { public: explicit AndroidClientBufferFactory( std::shared_ptr const& registrar); std::shared_ptr create_buffer( std::shared_ptr const& package, geometry::Size size, MirPixelFormat pf) override; std::shared_ptr create_buffer( std::shared_ptr const& package, unsigned int native_pf, unsigned int native_flags) override; private: std::shared_ptr const registrar; }; } } } #endif /* MIR_CLIENT_ANDROID_ANDROID_BUFFER_FACTORY_H_ */ ./src/platforms/android/client/android_native_display_container.cpp0000644000004100000410000000450213115234416026221 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #include "android_native_display_container.h" #include "mir_toolkit/mir_client_library.h" #include namespace mcl = mir::client; namespace mcla = mcl::android; namespace { // default_display_container needs to live until the library is unloaded std::mutex default_display_container_mutex; mcla::AndroidNativeDisplayContainer* default_display_container{nullptr}; extern "C" int __attribute__((destructor)) destroy() { std::lock_guard lock(default_display_container_mutex); delete default_display_container; return 0; } } mcl::EGLNativeDisplayContainer& mcl::EGLNativeDisplayContainer::instance() { std::lock_guard lock(default_display_container_mutex); if (!default_display_container) default_display_container = new mcla::AndroidNativeDisplayContainer; return *default_display_container; } mcla::AndroidNativeDisplayContainer::AndroidNativeDisplayContainer() { } mcla::AndroidNativeDisplayContainer::~AndroidNativeDisplayContainer() { } bool mcla::AndroidNativeDisplayContainer::validate(MirEGLNativeDisplayType display) const { std::lock_guard lg(guard); return (valid_displays.find(display) != valid_displays.end()); } MirEGLNativeDisplayType mcla::AndroidNativeDisplayContainer::create(ClientPlatform* platform) { std::lock_guard lg(guard); auto egl_display = static_cast(platform); valid_displays.insert(egl_display); return egl_display; } void mcla::AndroidNativeDisplayContainer::release(MirEGLNativeDisplayType display) { std::lock_guard lg(guard); valid_displays.erase(display); } ./src/platforms/android/client/buffer.cpp0000644000004100000410000000652713115234664020733 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/graphics/platform_ipc_operations.h" #include "android_native_buffer.h" #include "sync_fence.h" #include "mir_toolkit/mir_client_library.h" #include "buffer_registrar.h" #include "buffer.h" #include #include namespace mcl=mir::client; namespace mcla=mir::client::android; namespace geom=mir::geometry; namespace mg=mir::graphics; namespace mga=mir::graphics::android; mcla::Buffer::Buffer( std::shared_ptr const& registrar, MirBufferPackage const& package, MirPixelFormat pf) : buffer_registrar{registrar}, native_buffer{registrar->register_buffer(package, pf)}, buffer_pf(pf), buffer_stride{package.stride}, buffer_size{package.width, package.height}, creation_package(package) { } std::shared_ptr mcla::Buffer::secure_for_cpu_write() { auto rect = geom::Rectangle{geom::Point{0, 0}, size()}; auto vaddr = buffer_registrar->secure_for_cpu(native_buffer, rect); auto region = std::make_shared(); region->vaddr = vaddr; region->width = rect.size.width; region->height = rect.size.height; region->stride = stride(); region->format = buffer_pf; return region; } geom::Size mcla::Buffer::size() const { return buffer_size; } geom::Stride mcla::Buffer::stride() const { return buffer_stride; } MirPixelFormat mcla::Buffer::pixel_format() const { return buffer_pf; } std::shared_ptr mcla::Buffer::native_buffer_handle() const { return native_buffer; } void mcla::Buffer::update_from(MirBufferPackage const& update_package) { if ((update_package.flags & mir_buffer_flag_fenced) && (update_package.fd_items != 0)) { auto fence_fd = update_package.fd[0]; native_buffer->update_usage(fence_fd, mga::BufferAccess::read); } } void mcla::Buffer::fill_update_msg(MirBufferPackage& message) { message.data_items = 0; auto fence = native_buffer->copy_fence(); if (fence > 0) { message.flags = mir_buffer_flag_fenced; message.fd[0] = fence; message.fd_items = 1; } else { message.flags = 0; message.fd_items = 0; } } void mcla::Buffer::egl_image_creation_parameters( EGLenum* type, EGLClientBuffer* client_buffer, EGLint** attr) { static EGLint image_attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; *type = EGL_NATIVE_BUFFER_ANDROID; *client_buffer = native_buffer->anwb(); *attr = image_attrs; } MirBufferPackage* mcla::Buffer::package() const { return const_cast(&creation_package); } ./src/platforms/android/client/android_client_platform.cpp0000644000004100000410000002436713115234664024346 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #define MIR_LOG_COMPONENT "android extension" #include "mir_native_window.h" #include "android_format_conversion-inl.h" #include "mir/client_context.h" #include "mir/mir_buffer.h" #include "mir/mir_render_surface.h" #include "mir/client_buffer.h" #include "mir/mir_buffer_stream.h" #include "android_client_platform.h" #include "gralloc_registrar.h" #include "android_client_buffer_factory.h" #include "egl_native_surface_interpreter.h" #include "native_window_report.h" #include "android_format_conversion-inl.h" #include #include #include "mir/weak_egl.h" #include "mir_toolkit/mir_connection.h" #include "mir/uncaught.h" #include #include namespace mcl=mir::client; namespace mcla=mir::client::android; namespace mga=mir::graphics::android; namespace { void* native_display_type(MirConnection*) noexcept { static EGLNativeDisplayType type = EGL_DEFAULT_DISPLAY; return &type; } ANativeWindowBuffer* create_anwb(MirBuffer* b) noexcept try { auto buffer = reinterpret_cast(b); auto native = mga::to_native_buffer_checked(buffer->client_buffer()->native_buffer_handle()); return native->anwb(); } catch (std::exception& ex) { MIR_LOG_UNCAUGHT_EXCEPTION(ex); return nullptr; } void destroy_anwb(ANativeWindowBuffer*) noexcept { } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" ANativeWindow* create_anw( MirRenderSurface* rs_key, int width, int height, unsigned int hal_pixel_format, unsigned int gralloc_usage_flags) { auto format = mga::to_mir_format(hal_pixel_format); if (format == mir_pixel_format_invalid) return nullptr; //TODO: will be able to pass through the actual requested flags once buffers have generic flags. MirBufferUsage usage; if (gralloc_usage_flags & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) usage = mir_buffer_usage_software; else if (gralloc_usage_flags == (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER)) usage = mir_buffer_usage_hardware; else return nullptr; auto rs = mcl::render_surface_lookup(rs_key); if (!rs) return nullptr; auto buffer_stream = rs->get_buffer_stream(width, height, format, usage); return static_cast(buffer_stream->egl_native_window()); } #pragma GCC diagnostic pop void destroy_anw(ANativeWindow*) { } int get_fence(MirBuffer* b) noexcept try { if (!b) std::abort(); auto buffer = reinterpret_cast(b); auto native = mga::to_native_buffer_checked(buffer->client_buffer()->native_buffer_handle()); return native->fence(); } catch (std::exception const& ex) { MIR_LOG_UNCAUGHT_EXCEPTION(ex); return mir::Fd::invalid; } bool validate_access(MirBufferAccess access) { return access == mir_none || access == mir_read || access == mir_read_write; } void associate_fence(MirBuffer* b, int fence, MirBufferAccess access) noexcept try { if (!b || !validate_access(access)) std::abort(); auto buffer = reinterpret_cast(b); auto native_buffer = mga::to_native_buffer_checked(buffer->client_buffer()->native_buffer_handle()); mga::NativeFence f = fence; if (fence <= mir::Fd::invalid) native_buffer->reset_fence(); else if (access == mir_read) native_buffer->update_usage(f, mga::BufferAccess::read); else if (access == mir_read_write) native_buffer->update_usage(f, mga::BufferAccess::write); else BOOST_THROW_EXCEPTION(std::invalid_argument("invalid MirBufferAccess")); } catch (std::exception const& ex) { MIR_LOG_UNCAUGHT_EXCEPTION(ex); } int wait_for_access(MirBuffer* b, MirBufferAccess access, int timeout) noexcept try { if (!b || !validate_access(access)) std::abort(); auto buffer = reinterpret_cast(b); auto native_buffer = mga::to_native_buffer_checked(buffer->client_buffer()->native_buffer_handle()); // could use std::chrono::floor once we're using C++17 auto ns = std::chrono::nanoseconds(timeout); auto ms = std::chrono::duration_cast(ns); if (ms > ns) ms = ms - std::chrono::milliseconds{1}; bool rc = true; if (access == mir_read) rc = native_buffer->ensure_available_for(mga::BufferAccess::read, ms); if (access == mir_read_write) rc = native_buffer->ensure_available_for(mga::BufferAccess::write, ms); return rc; } catch (std::exception const& ex) { MIR_LOG_UNCAUGHT_EXCEPTION(ex); return -1; } void create_buffer( MirConnection* connection, int width, int height, unsigned int hal_pixel_format, unsigned int gralloc_usage_flags, MirBufferCallback available_callback, void* available_context) { auto context = mcl::to_client_context(connection); context->allocate_buffer( mir::geometry::Size{width, height}, hal_pixel_format, gralloc_usage_flags, available_callback, available_context); } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" MirBufferStream* get_hw_stream( MirRenderSurface* rs_key, int width, int height, MirPixelFormat format) { auto rs = mcl::render_surface_lookup(rs_key); if (!rs) return nullptr; return rs->get_buffer_stream(width, height, format, mir_buffer_usage_hardware); } #pragma GCC diagnostic pop } mcla::AndroidClientPlatform::AndroidClientPlatform( ClientContext* const context, std::shared_ptr const& logger) : context{context}, logger{logger}, native_display{std::make_shared(EGL_DEFAULT_DISPLAY)}, android_types_extension{native_display_type, create_anw, destroy_anw, create_anwb, destroy_anwb}, fence_extension{get_fence, associate_fence, wait_for_access}, buffer_extension{create_buffer}, hw_stream{get_hw_stream} { } std::shared_ptr mcla::AndroidClientPlatform::create_buffer_factory() { const hw_module_t *hw_module; int error = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &hw_module); if (error < 0) { BOOST_THROW_EXCEPTION(std::runtime_error("Could not open hardware module")); } gralloc_module_t* gr_dev = (gralloc_module_t*) hw_module; /* we use an empty deleter because hw_get_module does not give us the ownership of the ptr */ auto gralloc_dev = std::shared_ptr(gr_dev, [](auto){}); auto registrar = std::make_shared(gralloc_dev); return std::make_shared(registrar); } void mcla::AndroidClientPlatform::use_egl_native_window(std::shared_ptr native_window, EGLNativeSurface* surface) { auto anw = std::static_pointer_cast(native_window); anw->use_native_surface(std::make_shared(*surface)); } std::shared_ptr mcla::AndroidClientPlatform::create_egl_native_window(EGLNativeSurface* surface) { auto log = getenv("MIR_CLIENT_ANDROID_WINDOW_REPORT"); std::shared_ptr report; char const* on_val = "log"; if (log && !strncmp(log, on_val, strlen(on_val))) report = std::make_shared(logger); else report = std::make_shared(); std::shared_ptr surface_interpreter; if (surface) surface_interpreter = std::make_shared(*surface); else surface_interpreter = std::make_shared(); return std::make_shared(surface_interpreter, report); } std::shared_ptr mcla::AndroidClientPlatform::create_egl_native_display() { return native_display; } MirPlatformType mcla::AndroidClientPlatform::platform_type() const { return mir_platform_type_android; } void mcla::AndroidClientPlatform::populate(MirPlatformPackage& package) const { context->populate_server_package(package); } MirPlatformMessage* mcla::AndroidClientPlatform::platform_operation( MirPlatformMessage const*) { return nullptr; } MirNativeBuffer* mcla::AndroidClientPlatform::convert_native_buffer(graphics::NativeBuffer* buf) const { return mga::to_native_buffer_checked(buf)->anwb(); } MirPixelFormat mcla::AndroidClientPlatform::get_egl_pixel_format( EGLDisplay disp, EGLConfig conf) const { MirPixelFormat mir_format = mir_pixel_format_invalid; // EGL_KHR_platform_android says this will always work... EGLint vis = 0; mcl::WeakEGL weak; if (weak.eglGetConfigAttrib(disp, conf, EGL_NATIVE_VISUAL_ID, &vis)) mir_format = mir::graphics::android::to_mir_format(vis); return mir_format; } void* mcla::AndroidClientPlatform::request_interface(char const* name, int version) { if (!strcmp(name, "mir_extension_android_egl") && (version == 1)) return &android_types_extension; if (!strcmp(name, "mir_extension_android_buffer") && (version == 1)) return &buffer_extension; if (!strcmp(name, "mir_extension_fenced_buffers") && version == 1) return &fence_extension; if (!strcmp(name, "mir_extension_hardware_buffer_stream") && (version == 1)) return &hw_stream; return nullptr; } uint32_t mcla::AndroidClientPlatform::native_format_for(MirPixelFormat format) const { return mga::to_android_format(format); } uint32_t mcla::AndroidClientPlatform::native_flags_for(MirBufferUsage usage, mir::geometry::Size) const { return mga::convert_to_android_usage(static_cast(usage)); } ./src/platforms/android/client/android_client_buffer_factory.cpp0000644000004100000410000000333113115234664025506 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Christopher James Halse Rogers */ #include "android_client_buffer_factory.h" #include "android_format_conversion-inl.h" #include "buffer_registrar.h" #include "buffer.h" namespace mcl=mir::client; namespace mcla=mir::client::android; namespace geom=mir::geometry; namespace mga=mir::graphics::android; mcla::AndroidClientBufferFactory::AndroidClientBufferFactory( std::shared_ptr const& buffer_registrar) : registrar(buffer_registrar) { } std::shared_ptr mcla::AndroidClientBufferFactory::create_buffer(std::shared_ptr const& package, geom::Size size, MirPixelFormat pf) { (void)size; // TODO: remove this unused parameter return std::make_shared(registrar, *package, pf); } std::shared_ptr mcla::AndroidClientBufferFactory::create_buffer( std::shared_ptr const& package, unsigned int native_pf, unsigned int) { return std::make_shared(registrar, *package, mga::to_mir_format(native_pf)); } ./src/platforms/android/client/gralloc_registrar.h0000644000004100000410000000273313115234664022627 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #ifndef MIR_CLIENT_ANDROID_GRALLOC_REGISTRAR_H_ #define MIR_CLIENT_ANDROID_GRALLOC_REGISTRAR_H_ #include "buffer_registrar.h" #include namespace mir { namespace client { namespace android { class GrallocRegistrar : public BufferRegistrar { public: GrallocRegistrar(std::shared_ptr const& gralloc_dev); std::shared_ptr register_buffer( MirBufferPackage const& package, MirPixelFormat pf) const; std::shared_ptr secure_for_cpu( std::shared_ptr const& handle, geometry::Rectangle const); private: std::shared_ptr gralloc_module; }; } } } #endif /* MIR_CLIENT_ANDROID_GRALLOC_REGISTRAR_H_ */ ./src/platforms/android/client/buffer.h0000644000004100000410000000440213115234664020366 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #ifndef MIR_CLIENT_ANDROID_ANDROID_CLIENT_BUFFER_H_ #define MIR_CLIENT_ANDROID_ANDROID_CLIENT_BUFFER_H_ #include "android_native_buffer.h" #include "mir/aging_buffer.h" #include "mir/fd.h" #include #include namespace mir { namespace client { namespace android { class BufferRegistrar; class Buffer : public AgingBuffer { public: Buffer( std::shared_ptr const& registrar, MirBufferPackage const& package, MirPixelFormat pf); std::shared_ptr secure_for_cpu_write() override; geometry::Size size() const override; geometry::Stride stride() const override; MirPixelFormat pixel_format() const override; std::shared_ptr native_buffer_handle() const override; void update_from(MirBufferPackage const& update_package) override; void fill_update_msg(MirBufferPackage& message) override; MirBufferPackage* package() const override; void egl_image_creation_parameters(EGLenum*, EGLClientBuffer*, EGLint**) override; Buffer(const Buffer&) = delete; Buffer& operator=(const Buffer&) = delete; private: void pack_native_window_buffer(); mir::Fd mutable api_user_fence; std::shared_ptr const buffer_registrar; std::shared_ptr const native_buffer; MirPixelFormat const buffer_pf; geometry::Stride const buffer_stride; geometry::Size const buffer_size; MirBufferPackage const creation_package; }; } } } #endif /* MIR_CLIENT_ANDROID_ANDROID_CLIENT_BUFFER_H_ */ ./src/platforms/android/client/egl_native_surface_interpreter.cpp0000644000004100000410000000722513115234664025726 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "egl_native_surface_interpreter.h" #include "sync_fence.h" #include "mir/client_buffer.h" #include #include #include #include namespace mcla=mir::client::android; namespace mga=mir::graphics::android; mcla::EGLNativeSurfaceInterpreter::EGLNativeSurfaceInterpreter(EGLNativeSurface& surface) : surface(surface), driver_pixel_format(-1), sync_ops(std::make_shared()), hardware_bits( GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER ), software_bits( GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE ) { } mga::NativeBuffer* mcla::EGLNativeSurfaceInterpreter::driver_requests_buffer() { auto buffer = surface.get_current_buffer(); auto buffer_to_driver = mga::to_native_buffer_checked(buffer->native_buffer_handle()); ANativeWindowBuffer* anwb = buffer_to_driver->anwb(); anwb->format = driver_pixel_format; return buffer_to_driver.get(); } void mcla::EGLNativeSurfaceInterpreter::driver_returns_buffer(ANativeWindowBuffer*, int fence_fd) { //TODO: pass fence to server instead of waiting here mga::SyncFence sync_fence(sync_ops, mir::Fd(fence_fd)); sync_fence.wait(); surface.swap_buffers_sync(); } void mcla::EGLNativeSurfaceInterpreter::dispatch_driver_request_format(int format) { driver_pixel_format = format; } int mcla::EGLNativeSurfaceInterpreter::driver_requests_info(int key) const { switch (key) { case NATIVE_WINDOW_WIDTH: case NATIVE_WINDOW_DEFAULT_WIDTH: return surface.get_parameters().width; case NATIVE_WINDOW_HEIGHT: case NATIVE_WINDOW_DEFAULT_HEIGHT: return surface.get_parameters().height; case NATIVE_WINDOW_FORMAT: return driver_pixel_format; case NATIVE_WINDOW_TRANSFORM_HINT: return 0; case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: return 2; case NATIVE_WINDOW_CONCRETE_TYPE: return NATIVE_WINDOW_SURFACE; case NATIVE_WINDOW_CONSUMER_USAGE_BITS: if (surface.get_parameters().buffer_usage == mir_buffer_usage_hardware) return hardware_bits; else return software_bits; default: throw std::runtime_error("driver requested unsupported query"); } } void mcla::EGLNativeSurfaceInterpreter::sync_to_display(bool should_sync) { surface.request_and_wait_for_configure(mir_window_attrib_swapinterval, should_sync); } void mcla::EGLNativeSurfaceInterpreter::dispatch_driver_request_buffer_count(unsigned int count) { surface.set_buffer_cache_size(count); } void mcla::EGLNativeSurfaceInterpreter::dispatch_driver_request_buffer_size(geometry::Size size) { auto params = surface.get_parameters(); if (geometry::Size{params.width, params.height} == size) return; surface.set_size(size); } ./src/platforms/android/client/gralloc_registrar.cpp0000644000004100000410000001270113115234664023156 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/graphics/platform_ipc_operations.h" #include "egl_sync_fence.h" #include "android_native_buffer.h" #include "sync_fence.h" #include "gralloc_registrar.h" #include "mir/client_buffer.h" #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace mcl = mir::client; namespace mcla = mir::client::android; namespace geom = mir::geometry; namespace { struct NativeHandleDeleter { NativeHandleDeleter(const std::shared_ptr& mod) : module(mod) {} void operator()(const native_handle_t* t) { module->unregisterBuffer(module.get(), t); for (auto i = 0; i < t->numFds; i++) { close(t->data[i]); } ::operator delete(const_cast(t)); } private: const std::shared_ptr module; }; } mcla::GrallocRegistrar::GrallocRegistrar(const std::shared_ptr& gr_module) : gralloc_module(gr_module) { } namespace { std::shared_ptr create_native_buffer( std::shared_ptr const& handle, std::shared_ptr const& fence, MirBufferPackage const& package, MirPixelFormat pf) { auto ops = std::make_shared(); auto anwb = std::shared_ptr( new mga::RefCountedNativeBuffer(handle), [](mga::RefCountedNativeBuffer* buffer) { buffer->mir_dereference(); }); anwb->width = package.width; anwb->height = package.height; //note: mir uses stride in bytes, ANativeWindowBuffer needs it in pixel units. some drivers care //about byte-stride, they will pass stride via ANativeWindowBuffer::handle (which is opaque to us) anwb->stride = package.stride / MIR_BYTES_PER_PIXEL(pf); anwb->usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER; anwb->handle = handle.get(); auto sync = std::make_shared(); //no need for eglsync client side return std::make_shared(anwb, sync, fence, mga::BufferAccess::read); } } std::shared_ptr mcla::GrallocRegistrar::register_buffer( MirBufferPackage const& package, MirPixelFormat pf) const { auto fence_present = package.flags & mir_buffer_flag_fenced; int native_handle_header_size = sizeof(native_handle_t); int total_size = sizeof(int) * (package.fd_items + package.data_items + native_handle_header_size); native_handle_t* handle = static_cast(::operator new(total_size)); handle->version = native_handle_header_size; std::shared_ptr fence; if (fence_present) { auto ops = std::make_shared(); fence = std::make_shared(ops, mir::Fd(package.fd[0])); handle->numFds = package.fd_items - 1; for (auto i = 1; i < handle->numFds; i++) handle->data[i - 1] = package.fd[i]; } else { auto ops = std::make_shared(); fence = std::make_shared(ops, mir::Fd(mir::Fd::invalid)); handle->numFds = package.fd_items; for (auto i = 0; i < handle->numFds; i++) handle->data[i] = package.fd[i]; } handle->numInts = package.data_items; for (auto i = 0; i < handle->numInts; i++) handle->data[handle->numFds+i] = package.data[i]; if (gralloc_module->registerBuffer(gralloc_module.get(), handle)) { ::operator delete(handle); BOOST_THROW_EXCEPTION(std::runtime_error("error registering graphics buffer for client use\n")); } NativeHandleDeleter del(gralloc_module); return create_native_buffer(std::shared_ptr(handle, del), fence, package, pf); } std::shared_ptr mcla::GrallocRegistrar::secure_for_cpu( std::shared_ptr const& handle, geometry::Rectangle const rect) { char* vaddr; int usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; int width = rect.size.width.as_uint32_t(); int height = rect.size.height.as_uint32_t(); int top = rect.top_left.x.as_uint32_t(); int left = rect.top_left.y.as_uint32_t(); if ( gralloc_module->lock(gralloc_module.get(), handle->handle(), usage, top, left, width, height, (void**) &vaddr) ) BOOST_THROW_EXCEPTION(std::runtime_error("error securing buffer for client cpu use")); auto module = gralloc_module; return std::shared_ptr(vaddr, [module, handle](char*) { module->unlock(module.get(), handle->handle()); //we didn't alloc region(just mapped it), so we don't delete }); } ./src/platforms/android/client/client_platform_factory.cpp0000644000004100000410000000376013115234664024367 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "mir/client_platform_factory.h" #include "mir_toolkit/client_types.h" #include "mir/client_context.h" #include "mir/assert_module_entry_point.h" #include "android_client_platform.h" #include #include #include namespace mcl = mir::client; namespace mcla = mcl::android; mir::UniqueModulePtr create_client_platform(mcl::ClientContext* context, std::shared_ptr const& logger) { mir::assert_entry_point_signature(&create_client_platform); MirPlatformPackage platform; context->populate_server_package(platform); if (platform.data_items != 0 || platform.fd_items != 0) { BOOST_THROW_EXCEPTION((std::runtime_error{"Attempted to create Android client platform on non-Android server"})); } return mir::make_module_ptr(context, logger); } bool is_appropriate_module(mcl::ClientContext* context) { mir::assert_entry_point_signature(&is_appropriate_module); MirModuleProperties server_graphics_module; context->populate_graphics_module(server_graphics_module); return (strncmp("mir:android", server_graphics_module.name, strlen("mir:android")) == 0); } ./src/platforms/android/client/android_client_platform.h0000644000004100000410000000522613115234664024004 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_CLIENT_ANDROID_ANDROID_CLIENT_PLATFORM_H_ #define MIR_CLIENT_ANDROID_ANDROID_CLIENT_PLATFORM_H_ #include "mir/client_platform.h" #include "mir_toolkit/extensions/fenced_buffers.h" #include "mir_toolkit/extensions/android_egl.h" #include "mir_toolkit/extensions/android_buffer.h" #include "mir_toolkit/extensions/hardware_buffer_stream.h" namespace mir { namespace logging { class Logger; } namespace client { namespace android { class AndroidClientPlatform : public ClientPlatform { public: AndroidClientPlatform(ClientContext* const context, std::shared_ptr const& logger); MirPlatformType platform_type() const override; void populate(MirPlatformPackage& package) const override; MirPlatformMessage* platform_operation(MirPlatformMessage const* request) override; std::shared_ptr create_buffer_factory() override; void* request_interface(char const* name, int version) override; std::shared_ptr create_egl_native_window(EGLNativeSurface* surface) override; void use_egl_native_window(std::shared_ptr native_window, EGLNativeSurface* surface) override; std::shared_ptr create_egl_native_display() override; MirNativeBuffer* convert_native_buffer(graphics::NativeBuffer*) const override; MirPixelFormat get_egl_pixel_format(EGLDisplay, EGLConfig) const override; uint32_t native_format_for(MirPixelFormat) const override; uint32_t native_flags_for(MirBufferUsage, mir::geometry::Size) const override; private: ClientContext* const context; std::shared_ptr const logger; std::shared_ptr const native_display; MirExtensionAndroidEGLV1 android_types_extension; MirExtensionFencedBuffersV1 fence_extension; MirExtensionAndroidBufferV1 buffer_extension; MirExtensionHardwareBufferStreamV1 hw_stream; }; } } } #endif /* MIR_CLIENT_ANDROID_ANDROID_CLIENT_PLATFORM_H_ */ ./src/platforms/android/client/egl_native_surface_interpreter.h0000644000004100000410000000535513115234664025375 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_CLIENT_NATIVE_ANDROID_EGL_NATIVE_SURFACE_INTERPRETER_H_ #define MIR_CLIENT_NATIVE_ANDROID_EGL_NATIVE_SURFACE_INTERPRETER_H_ #include "android_driver_interpreter.h" #include "mir/egl_native_surface.h" #include namespace mir { namespace graphics { namespace android { class SyncFileOps; } } namespace client { namespace android { class ErrorDriverInterpreter : public graphics::android::AndroidDriverInterpreter { public: #define THROW_EXCEPTION \ { \ BOOST_THROW_EXCEPTION(std::logic_error("error: use_egl_native_window(...) has not yet been called"));\ } graphics::android::NativeBuffer* driver_requests_buffer() override THROW_EXCEPTION void driver_returns_buffer(ANativeWindowBuffer*, int) override THROW_EXCEPTION void dispatch_driver_request_format(int) override THROW_EXCEPTION void dispatch_driver_request_buffer_count(unsigned int) override THROW_EXCEPTION void dispatch_driver_request_buffer_size(geometry::Size) override THROW_EXCEPTION int driver_requests_info(int) const override THROW_EXCEPTION void sync_to_display(bool) override THROW_EXCEPTION #undef THROW_EXCEPTION }; class EGLNativeSurfaceInterpreter : public graphics::android::AndroidDriverInterpreter { public: explicit EGLNativeSurfaceInterpreter(EGLNativeSurface& surface); graphics::android::NativeBuffer* driver_requests_buffer() override; void driver_returns_buffer(ANativeWindowBuffer*, int fence_fd) override; void dispatch_driver_request_format(int format) override; void dispatch_driver_request_buffer_count(unsigned int count) override; void dispatch_driver_request_buffer_size(geometry::Size size) override; int driver_requests_info(int key) const override; void sync_to_display(bool) override; private: EGLNativeSurface& surface; int driver_pixel_format; std::shared_ptr const sync_ops; unsigned int const hardware_bits; unsigned int const software_bits; }; } } } #endif /* MIR_CLIENT_NATIVE_ANDROID_EGL_NATIVE_SURFACE_INTERPRETER_H_ */ ./src/platforms/android/client/buffer_registrar.h0000644000004100000410000000324013115234664022447 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #ifndef MIR_CLIENT_ANDROID_BUFFER_REGISTRAR_H_ #define MIR_CLIENT_ANDROID_BUFFER_REGISTRAR_H_ #include "mir_toolkit/common.h" #include #include "native_buffer.h" #include "mir/geometry/rectangle.h" #include #include namespace mir { namespace client { class MemoryRegion; namespace android { class BufferRegistrar { public: virtual ~BufferRegistrar() = default; virtual std::shared_ptr register_buffer( MirBufferPackage const& package, MirPixelFormat pf) const = 0; virtual std::shared_ptr secure_for_cpu( std::shared_ptr const& handle, geometry::Rectangle const) = 0; protected: BufferRegistrar() = default; BufferRegistrar(BufferRegistrar const&) = delete; BufferRegistrar& operator=(BufferRegistrar const&) = delete; }; } } } #endif /* MIR_CLIENT_ANDROID_BUFFER_REGISTRAR_H_ */ ./src/platforms/android/server/0000755000004100000410000000000013115234677017000 5ustar www-datawww-data./src/platforms/android/server/resource_factory.h0000644000004100000410000000241213115234416022515 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_RESOURCE_FACTORY_H_ #define MIR_GRAPHICS_ANDROID_RESOURCE_FACTORY_H_ #include "display_resource_factory.h" namespace mir { namespace graphics { namespace android { class ResourceFactory : public DisplayResourceFactory { public: //native allocations std::tuple, HwcVersion> create_hwc_wrapper( std::shared_ptr const&) const override; std::shared_ptr create_fb_native_device() const override; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DEFAULT_FRAMEBUFFER_FACTORY_H_ */ ./src/platforms/android/server/hwc_fb_device.h0000644000004100000410000000400413115234664021712 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_HWC_FB_DEVICE_H_ #define MIR_GRAPHICS_ANDROID_HWC_FB_DEVICE_H_ #include "mir/graphics/frame.h" #include "display_device.h" #include "hardware/gralloc.h" #include "hardware/fb.h" #include "mir/raii.h" #include "display_name.h" #include #include namespace mir { namespace graphics { namespace android { class HwcWrapper; class HwcFbDevice : public DisplayDevice { public: HwcFbDevice(std::shared_ptr const& hwc_wrapper, std::shared_ptr const& fb_device); bool compatible_renderlist(RenderableList const& renderlist) override; void commit(std::list const& contents) override; std::chrono::milliseconds recommended_sleep() const override; bool can_swap_buffers() const override; private: void content_cleared() override; std::shared_ptr const hwc_wrapper; std::shared_ptr const fb_device; static int const num_displays{1}; mir::raii::PairedCalls, std::function> vsync_subscription; std::mutex vsync_wait_mutex; std::condition_variable vsync_trigger; bool vsync_occurred; void notify_vsync(DisplayName, graphics::Frame::Timestamp); }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_FB_DEVICE_H_ */ ./src/platforms/android/server/hwc_wrapper.h0000644000004100000410000000544213115234664021473 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_HWC_WRAPPER_H_ #define MIR_GRAPHICS_ANDROID_HWC_WRAPPER_H_ #include "mir/graphics/frame.h" #include "mir/int_wrapper.h" #include "display_name.h" #include "power_mode.h" #include #include #include struct hwc_display_contents_1; namespace mir { namespace graphics { namespace android { struct ConfigIdTag; typedef IntWrapper ConfigId; struct HWCCallbacks; class HwcWrapper { public: virtual ~HwcWrapper() = default; virtual void prepare(std::array const&) const = 0; virtual void set(std::array const&) const = 0; //receive vsync, invalidate, and hotplug events from the driver. //As with the HWC api, these events MUST NOT call-back to the other functions in HwcWrapper. virtual void subscribe_to_events( void const* subscriber, std::function const& vsync_callback, std::function const& hotplug_callback, std::function const& invalidate_callback) = 0; virtual void unsubscribe_from_events(void const* subscriber) noexcept = 0; virtual void vsync_signal_on(DisplayName) const = 0; virtual void vsync_signal_off(DisplayName) const = 0; virtual void display_on(DisplayName) const = 0; virtual void display_off(DisplayName) const = 0; virtual std::vector display_configs(DisplayName) const = 0; virtual int display_attributes( DisplayName, ConfigId, uint32_t const* attributes, int32_t* values) const = 0; virtual void power_mode(DisplayName, PowerMode mode) const = 0; virtual bool has_active_config(DisplayName) const = 0; virtual ConfigId active_config_for(DisplayName name) const = 0; virtual void set_active_config(DisplayName name, ConfigId id) const = 0; protected: HwcWrapper() = default; HwcWrapper& operator=(HwcWrapper const&) = delete; HwcWrapper(HwcWrapper const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_WRAPPER_H_ */ ./src/platforms/android/server/CMakeLists.txt0000644000004100000410000000360013115234664021533 0ustar www-datawww-datainclude_directories( ${PROJECT_SOURCE_DIR}/src/include/gl ) include_directories( ${EGL_INCLUDE_DIRS} ${GLESv2_INCLUDE_DIRS} ${ANDROID_PROPERTIES_INCLUDE_DIRS} ) include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/3rd_party/android-deps) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") add_library(mirplatformgraphicsandroidobjects OBJECT platform.cpp graphic_buffer_allocator.cpp buffer.cpp display.cpp display_group.cpp display_configuration.cpp display_buffer.cpp hal_component_factory.cpp hwc_layerlist.cpp hwc_layers.cpp hwc_fb_device.cpp hwc_loggers.cpp hwc_device.cpp gralloc_module.cpp server_render_window.cpp resource_factory.cpp framebuffers.cpp fb_device.cpp interpreter_cache.cpp gl_context.cpp device_quirks.cpp real_hwc_wrapper.cpp hwc_fallback_gl_renderer.cpp ipc_operations.cpp hwc_blanking_control.cpp egl_sync_factory.cpp virtual_output.cpp ) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/symbols.map.in ${CMAKE_CURRENT_BINARY_DIR}/symbols.map) set(symbol_map ${CMAKE_CURRENT_BINARY_DIR}/symbols.map) add_library(mirplatformgraphicsandroid SHARED $ $ ) target_link_libraries( mirplatformgraphicsandroid mirsharedandroid-static mirplatform ${Boost_PROGRAM_OPTIONS_LIBRARY} ${LIBHARDWARE_LIBRARIES} ${EGL_LDFLAGS} ${EGL_LIBRARIES} ${GLESv2_LDFLAGS} ${GLESv2_LIBRARIES} ${ANDROID_PROPERTIES_LDFLAGS} ) set_target_properties( mirplatformgraphicsandroid PROPERTIES OUTPUT_NAME graphics-android LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/server-modules PREFIX "" SUFFIX ".so.${MIR_SERVER_GRAPHICS_PLATFORM_ABI}" LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${symbol_map}" LINK_DEPENDS ${symbol_map} ) install(TARGETS mirplatformgraphicsandroid LIBRARY DESTINATION ${MIR_SERVER_PLATFORM_PATH}) ./src/platforms/android/server/display_resource_factory.h0000644000004100000410000000340413115234664024251 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_DISPLAY_RESOURCE_FACTORY_H_ #define MIR_GRAPHICS_ANDROID_DISPLAY_RESOURCE_FACTORY_H_ #include #include #include #include namespace mir { namespace graphics { class Display; class DisplayReport; namespace android { class DisplayDevice; class FramebufferBundle; class HwcWrapper; class LayerAdapter; class HwcReport; enum HwcVersion { hwc10, hwc11, hwc12, hwc13, hwc14, hwc15, unknown }; class DisplayResourceFactory { public: virtual ~DisplayResourceFactory() = default; virtual std::tuple, HwcVersion> create_hwc_wrapper( std::shared_ptr const&) const = 0; virtual std::shared_ptr create_fb_native_device() const = 0; protected: DisplayResourceFactory() = default; DisplayResourceFactory& operator=(DisplayResourceFactory const&) = delete; DisplayResourceFactory(DisplayResourceFactory const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_FRAMEBUFFER_FACTORY_H_ */ ./src/platforms/android/server/gralloc_module.cpp0000644000004100000410000000633013115234664022472 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #include "egl_sync_fence.h" #include "android_native_buffer.h" #include "sync_fence.h" #include "android_format_conversion-inl.h" #include "gralloc_module.h" #include "device_quirks.h" #include "cmdstream_sync_factory.h" #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace geom=mir::geometry; namespace { struct AndroidBufferHandleDeleter { AndroidBufferHandleDeleter(std::shared_ptr const& alloc_dev) : alloc_device(alloc_dev) {} void operator()(native_handle_t const* t) { alloc_device->free(alloc_device.get(), t); } private: std::shared_ptr const alloc_device; }; } mga::GrallocModule::GrallocModule( std::shared_ptr const& alloc_device, std::shared_ptr const& sync_factory, std::shared_ptr const& quirks) : alloc_dev(alloc_device), sync_factory(sync_factory), quirks(quirks) { } std::shared_ptr mga::GrallocModule::alloc_buffer( geometry::Size size, uint32_t format, uint32_t usage_flag) { buffer_handle_t buf_handle = NULL; auto stride = 0; auto width = static_cast(size.width.as_uint32_t()); auto height = static_cast(size.height.as_uint32_t()); auto ret = alloc_dev->alloc(alloc_dev.get(), quirks->aligned_width(width), height, format, usage_flag, &buf_handle, &stride); if (( ret ) || (buf_handle == NULL) || (stride == 0)) { BOOST_THROW_EXCEPTION( boost::enable_error_info(std::runtime_error("buffer allocation failed\n")) << boost::errinfo_errno(-ret)); } AndroidBufferHandleDeleter del1(alloc_dev); std::shared_ptr handle(buf_handle, del1); auto ops = std::make_shared(); auto fence = std::make_shared(ops, mir::Fd()); auto anwb = std::shared_ptr( new mga::RefCountedNativeBuffer(handle), [](mga::RefCountedNativeBuffer* buffer) { buffer->mir_dereference(); }); anwb->width = width; anwb->height = height; anwb->stride = stride; anwb->handle = buf_handle; anwb->format = format; anwb->usage = usage_flag; return std::make_shared(anwb, sync_factory->create_command_stream_sync(), fence, mga::BufferAccess::read); } ./src/platforms/android/server/power_mode.h0000644000004100000410000000214313115234416021300 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alberto Aguirre */ #ifndef MIR_GRAPHICS_ANDROID_POWER_MODE_H_ #define MIR_GRAPHICS_ANDROID_POWER_MODE_H_ #include namespace mir { namespace graphics { namespace android { enum class PowerMode { off = HWC_POWER_MODE_OFF, doze = HWC_POWER_MODE_DOZE, normal = HWC_POWER_MODE_NORMAL, doze_suspend = HWC_POWER_MODE_DOZE_SUSPEND }; } } } #endif /* MIR_GRAPHICS_ANDROID_POWER_MODE_H_ */ ./src/platforms/android/server/server_render_window.h0000644000004100000410000000403613115234664023404 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_SERVER_RENDER_WINDOW_H_ #define MIR_GRAPHICS_ANDROID_SERVER_RENDER_WINDOW_H_ #include "android_driver_interpreter.h" #include "device_quirks.h" #include "mir_toolkit/common.h" #include namespace mir { namespace graphics { namespace android { class FramebufferBundle; class InterpreterResourceCache; class ServerRenderWindow : public AndroidDriverInterpreter { public: ServerRenderWindow(std::shared_ptr const& fb_bundle, MirPixelFormat format, std::shared_ptr const&, DeviceQuirks& quirks); graphics::android::NativeBuffer* driver_requests_buffer() override; void driver_returns_buffer(ANativeWindowBuffer*, int fence_fd) override; void dispatch_driver_request_format(int format) override; void dispatch_driver_request_buffer_count(unsigned int count) override; void dispatch_driver_request_buffer_size(geometry::Size size) override; int driver_requests_info(int key) const override; void sync_to_display(bool sync) override; private: std::shared_ptr const fb_bundle; std::shared_ptr const resource_cache; int format; bool const clear_fence; }; } } } #endif /* MIR_GRAPHICS_ANDROID_SERVER_RENDER_WINDOW_H_ */ ./src/platforms/android/server/hwc_device.h0000644000004100000410000000343613115234416021246 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_HWC_DEVICE_H_ #define MIR_GRAPHICS_ANDROID_HWC_DEVICE_H_ #include "mir_toolkit/common.h" #include "sync_fence.h" #include "display_device.h" #include "hwc_layerlist.h" #include #include namespace mir { namespace graphics { class Buffer; namespace android { class SyncFileOps; class HwcWrapper; class HwcConfiguration; class HwcDevice : public DisplayDevice { public: HwcDevice(std::shared_ptr const& hwc_wrapper); bool compatible_renderlist(RenderableList const& renderlist) override; void commit(std::list const& contents) override; void content_cleared() override; std::chrono::milliseconds recommended_sleep() const override; bool can_swap_buffers() const override; private: bool buffer_is_onscreen(Buffer const&) const; std::vector> onscreen_overlay_buffers; std::shared_ptr const hwc_wrapper; std::shared_ptr const sync_ops; std::chrono::milliseconds recommend_sleep{0}; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_DEVICE_H_ */ ./src/platforms/android/server/framebuffers.cpp0000644000004100000410000000362213115234416022145 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #include "framebuffers.h" #include "graphic_buffer_allocator.h" namespace mg = mir::graphics; namespace mga=mir::graphics::android; namespace geom=mir::geometry; mga::Framebuffers::Framebuffers( mga::GraphicBufferAllocator& buffer_allocator, geom::Size size, MirPixelFormat format, unsigned int num_framebuffers) : size{size} { for(auto i = 0u; i < num_framebuffers; i++) queue.push(buffer_allocator.alloc_framebuffer(size, format)); } geom::Size mga::Framebuffers::fb_size() { return size; } std::shared_ptr mga::Framebuffers::buffer_for_render() { std::unique_lock lk(queue_lock); while (buffer_being_rendered) { cv.wait(lk); } buffer_being_rendered = queue.front(); queue.pop(); return std::shared_ptr(buffer_being_rendered.get(), [this](mg::Buffer*) { std::unique_lock lk(queue_lock); queue.push(buffer_being_rendered); buffer_being_rendered.reset(); cv.notify_all(); }); } std::shared_ptr mga::Framebuffers::last_rendered_buffer() { std::unique_lock lk(queue_lock); return queue.back(); } ./src/platforms/android/server/hwc_loggers.h0000644000004100000410000000567013115234416021453 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_HWC_LOGGERS_H_ #define MIR_GRAPHICS_ANDROID_HWC_LOGGERS_H_ #include "hwc_report.h" namespace mir { namespace graphics { namespace android { class HwcFormattedLogger : public HwcReport { public: HwcFormattedLogger() = default; void report_list_submitted_to_prepare( std::array const& displays) const override; void report_prepare_done( std::array const& displays) const override; void report_set_list( std::array const& displays) const override; void report_set_done( std::array const& displays) const override; void report_overlay_optimization(OverlayOptimization optimization_option) const override; void report_display_on() const override; void report_display_off() const override; void report_vsync_on() const override; void report_vsync_off() const override; void report_hwc_version(HwcVersion) const override; void report_legacy_fb_module() const override; void report_power_mode(PowerMode mode) const override; }; class NullHwcReport : public HwcReport { public: NullHwcReport() = default; void report_list_submitted_to_prepare( std::array const&) const override; void report_prepare_done( std::array const&) const override; void report_set_list( std::array const&) const override; void report_set_done( std::array const&) const override; void report_overlay_optimization(OverlayOptimization) const override; void report_display_on() const override; void report_display_off() const override; void report_vsync_on() const override; void report_vsync_off() const override; void report_hwc_version(HwcVersion) const override; void report_legacy_fb_module() const override; void report_power_mode(PowerMode mode) const override; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_LOGGERS_H_ */ ./src/platforms/android/server/gralloc.h0000644000004100000410000000242413115234664020572 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_GRALLOC_H_ #define MIR_GRAPHICS_ANDROID_GRALLOC_H_ #include "mir/graphics/buffer_properties.h" #include namespace mir { namespace graphics { namespace android { class NativeBuffer; class Gralloc { public: virtual std::shared_ptr alloc_buffer( geometry::Size size, uint32_t android_format, uint32_t usage_bitmask) = 0; protected: Gralloc() = default; virtual ~Gralloc() {} Gralloc(const Gralloc&) = delete; Gralloc& operator=(const Gralloc&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_GRALLOC_H_ */ ./src/platforms/android/server/hwc_fallback_gl_renderer.h0000644000004100000410000000421313115234664024115 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_HWC_FALLBACK_GL_RENDERER_H_ #define MIR_GRAPHICS_ANDROID_HWC_FALLBACK_GL_RENDERER_H_ #include "mir/geometry/rectangle.h" #include "mir/geometry/displacement.h" #include "mir/gl/program.h" #include "mir/gl/texture_cache.h" #include "mir/graphics/renderable.h" #include "mir/renderer/gl/context.h" #include namespace mir { namespace gl { class ProgramFactory; } namespace graphics { namespace android { class SwappingGLContext; class RenderableListCompositor { public: virtual ~RenderableListCompositor() = default; virtual void render(RenderableList const&, geometry::Displacement list_offset, SwappingGLContext const&) const = 0; protected: RenderableListCompositor() = default; private: RenderableListCompositor(RenderableListCompositor const&) = delete; RenderableListCompositor& operator=(RenderableListCompositor const&) = delete; }; class HWCFallbackGLRenderer : public RenderableListCompositor { public: HWCFallbackGLRenderer( gl::ProgramFactory const& program_factory, renderer::gl::Context const& gl_context, geometry::Rectangle const& screen_position); void render(RenderableList const&, geometry::Displacement, SwappingGLContext const&) const; private: std::unique_ptr program; std::unique_ptr texture_cache; GLint position_attr; GLint texcoord_attr; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_FALLBACK_GL_RENDERER_H_ */ ./src/platforms/android/server/ipc_operations.cpp0000644000004100000410000000562213115234664022523 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/graphics/platform_ipc_package.h" #include "mir/module_properties.h" #include "mir/graphics/buffer.h" #include "mir/graphics/buffer_ipc_message.h" #include "mir/graphics/platform_operation_message.h" #include "mir/libname.h" #include "mir_toolkit/mir_native_buffer.h" #include "android_native_buffer.h" #include "ipc_operations.h" #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; void mga::IpcOperations::pack_buffer(BufferIpcMessage& msg, Buffer const& buffer, BufferIpcMsgType msg_type) const { auto native_buffer = mga::to_native_buffer_checked(buffer.native_buffer_handle()); native_buffer->wait_for_unlock_by_gpu(); mir::Fd fence_fd(native_buffer->copy_fence()); if (fence_fd != mir::Fd::invalid) { msg.pack_flags(mir_buffer_flag_fenced); msg.pack_fd(fence_fd); } else { msg.pack_flags(0); } if (msg_type == mg::BufferIpcMsgType::full_msg) { auto buffer_handle = native_buffer->handle(); int offset = 0; for(auto i = 0; i < buffer_handle->numFds; i++) { msg.pack_fd(mir::Fd(IntOwnedFd{buffer_handle->data[offset++]})); } for(auto i = 0; i < buffer_handle->numInts; i++) { msg.pack_data(buffer_handle->data[offset++]); } mir::geometry::Stride byte_stride{ native_buffer->anwb()->stride * MIR_BYTES_PER_PIXEL(buffer.pixel_format())}; msg.pack_stride(byte_stride); msg.pack_size(buffer.size()); } } void mga::IpcOperations::unpack_buffer(BufferIpcMessage&, Buffer const&) const { } namespace { mir::ModuleProperties const properties = { "mir:android", MIR_VERSION_MAJOR, MIR_VERSION_MINOR, MIR_VERSION_MICRO, mir::libname() }; } std::shared_ptr mga::IpcOperations::connection_ipc_package() { return std::make_shared(&properties); } mg::PlatformOperationMessage mga::IpcOperations::platform_operation( unsigned int const, mg::PlatformOperationMessage const&) { BOOST_THROW_EXCEPTION(std::invalid_argument("android platform does not support any platform operations")); } ./src/platforms/android/server/hwc_report.h0000644000004100000410000000446013115234416021320 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_HWC_REPORT_H_ #define MIR_GRAPHICS_ANDROID_HWC_REPORT_H_ #include "overlay_optimization.h" #include "display_resource_factory.h" #include "power_mode.h" #include namespace mir { namespace graphics { namespace android { class HwcReport { public: virtual ~HwcReport() = default; virtual void report_list_submitted_to_prepare( std::array const& displays) const = 0; virtual void report_prepare_done( std::array const& displays) const = 0; virtual void report_set_list( std::array const& displays) const = 0; virtual void report_set_done( std::array const& displays) const = 0; virtual void report_overlay_optimization(OverlayOptimization optimization_option) const = 0; virtual void report_display_on() const = 0; virtual void report_display_off() const = 0; virtual void report_vsync_on() const = 0; virtual void report_vsync_off() const = 0; virtual void report_hwc_version(HwcVersion) const = 0; virtual void report_legacy_fb_module() const = 0; virtual void report_power_mode(PowerMode mode) const = 0; void set_version(HwcVersion version) { hwc_version = version; } protected: HwcReport() = default; HwcReport& operator=(HwcReport const&) = delete; HwcReport(HwcReport const&) = delete; HwcVersion hwc_version{unknown}; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_REPORT_H_ */ ./src/platforms/android/server/interpreter_resource_cache.h0000644000004100000410000000316413115234664024546 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_INTERPRETER_RESOURCE_CACHE_H_ #define MIR_GRAPHICS_ANDROID_INTERPRETER_RESOURCE_CACHE_H_ #include #include namespace mir { namespace graphics { class Buffer; namespace android { class NativeBuffer; class InterpreterResourceCache { public: InterpreterResourceCache() {} virtual void store_buffer(std::shared_ptrconst& buffer, std::shared_ptr const& key) = 0; virtual std::shared_ptr retrieve_buffer(ANativeWindowBuffer* key) = 0; virtual void update_native_fence(ANativeWindowBuffer* key, int fence) = 0; protected: virtual ~InterpreterResourceCache() {} InterpreterResourceCache(const InterpreterResourceCache&) = delete; InterpreterResourceCache& operator=(const InterpreterResourceCache&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_INTERPRETER_RESOURCE_CACHE_H_ */ ./src/platforms/android/server/graphic_buffer_allocator.cpp0000644000004100000410000001102513115234664024505 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #include "mir/graphics/platform.h" #include "mir/graphics/egl_extensions.h" #include "mir/graphics/buffer_properties.h" #include "mir/graphics/buffer_ipc_message.h" #include "cmdstream_sync_factory.h" #include "sync_fence.h" #include "android_native_buffer.h" #include "graphic_buffer_allocator.h" #include "gralloc_module.h" #include "buffer.h" #include "device_quirks.h" #include "egl_sync_fence.h" #include "android_format_conversion-inl.h" #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace geom = mir::geometry; namespace { void alloc_dev_deleter(alloc_device_t* t) { /* android takes care of delete for us */ t->common.close((hw_device_t*)t); } void null_alloc_dev_deleter(alloc_device_t*) { } } mga::GraphicBufferAllocator::GraphicBufferAllocator( std::shared_ptr const& cmdstream_sync_factory, std::shared_ptr const& quirks) : egl_extensions(std::make_shared()), cmdstream_sync_factory(cmdstream_sync_factory), quirks(quirks) { int err; err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &hw_module); if (err < 0) BOOST_THROW_EXCEPTION(std::runtime_error("Could not open hardware module")); struct alloc_device_t* alloc_dev; err = hw_module->methods->open(hw_module, GRALLOC_HARDWARE_GPU0, (struct hw_device_t**) &alloc_dev); if (err < 0) BOOST_THROW_EXCEPTION(std::runtime_error("Could not open hardware module")); /* note for future use: at this point, the hardware module should be filled with vendor information that we can determine different courses of action based upon */ std::shared_ptr alloc_dev_ptr( alloc_dev, quirks->gralloc_cannot_be_closed_safely() ? null_alloc_dev_deleter : alloc_dev_deleter); alloc_device = std::make_shared( alloc_dev_ptr, cmdstream_sync_factory, quirks); } std::shared_ptr mga::GraphicBufferAllocator::alloc_buffer( mg::BufferProperties const& properties) { return std::make_shared( reinterpret_cast(hw_module), alloc_device->alloc_buffer( properties.size, mga::to_android_format(properties.format), mga::convert_to_android_usage(properties.usage)), egl_extensions); } std::shared_ptr mga::GraphicBufferAllocator::alloc_framebuffer( geometry::Size size, MirPixelFormat pf) { return std::make_shared( reinterpret_cast(hw_module), alloc_device->alloc_buffer( size, mga::to_android_format(pf), quirks->fb_gralloc_bits()), egl_extensions); } std::vector mga::GraphicBufferAllocator::supported_pixel_formats() { static std::vector const pixel_formats{ mir_pixel_format_abgr_8888, mir_pixel_format_xbgr_8888, mir_pixel_format_rgb_888, mir_pixel_format_rgb_565 }; return pixel_formats; } std::shared_ptr mga::GraphicBufferAllocator::alloc_software_buffer( geometry::Size size, MirPixelFormat format) { return std::make_shared( reinterpret_cast(hw_module), alloc_device->alloc_buffer( size, mga::to_android_format(format), mga::convert_to_android_usage(mg::BufferUsage::software)), egl_extensions); } std::shared_ptr mga::GraphicBufferAllocator::alloc_buffer( geometry::Size size, uint32_t native_format, uint32_t native_flags) { return std::make_shared( reinterpret_cast(hw_module), alloc_device->alloc_buffer(size, native_format, native_flags), egl_extensions); } ./src/platforms/android/server/buffer.cpp0000644000004100000410000001421113115234416020743 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #include "mir/graphics/egl_extensions.h" #include "mir/graphics/egl_error.h" #include "native_buffer.h" #include "sync_fence.h" #include "android_format_conversion-inl.h" #include "buffer.h" #include #include #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace geom=mir::geometry; mga::Buffer::Buffer(gralloc_module_t const* hw_module, std::shared_ptr const& buffer_handle, std::shared_ptr const& extensions) : hw_module(hw_module), native_buffer(buffer_handle), egl_extensions(extensions) { } mga::Buffer::~Buffer() { for(auto& it : egl_image_map) { EGLDisplay disp = it.first.first; egl_extensions->eglDestroyImageKHR(disp, it.second); } } geom::Size mga::Buffer::size() const { ANativeWindowBuffer *anwb = native_buffer->anwb(); return {anwb->width, anwb->height}; } geom::Stride mga::Buffer::stride() const { ANativeWindowBuffer *anwb = native_buffer->anwb(); return geom::Stride{anwb->stride * MIR_BYTES_PER_PIXEL(pixel_format())}; } MirPixelFormat mga::Buffer::pixel_format() const { ANativeWindowBuffer *anwb = native_buffer->anwb(); return mga::to_mir_format(anwb->format); } void mga::Buffer::gl_bind_to_texture() { std::unique_lock lk(content_lock); bind(lk); secure_for_render(lk); } void mga::Buffer::bind() { std::unique_lock lk(content_lock); bind(lk); } void mga::Buffer::bind(std::unique_lock const&) { native_buffer->ensure_available_for(mga::BufferAccess::read); DispContextPair current { eglGetCurrentDisplay(), eglGetCurrentContext() }; if (current.first == EGL_NO_DISPLAY) { BOOST_THROW_EXCEPTION(std::runtime_error("cannot bind buffer to texture without EGL context")); } static const EGLint image_attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; EGLImageKHR image; auto it = egl_image_map.find(current); if (it == egl_image_map.end()) { image = egl_extensions->eglCreateImageKHR( current.first, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, native_buffer->anwb(), image_attrs); if (image == EGL_NO_IMAGE_KHR) { BOOST_THROW_EXCEPTION(mg::egl_error("error binding buffer to texture")); } egl_image_map[current] = image; } else /* already had it in map */ { image = it->second; } egl_extensions->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); } std::shared_ptr mga::Buffer::native_buffer_handle() const { std::unique_lock lk(content_lock); auto native_resource = std::shared_ptr( native_buffer.get(), [this](NativeBuffer*) { content_lock.unlock(); }); //lock remains in effect until the native handle is released lk.release(); return native_resource; } void mga::Buffer::write(unsigned char const* data, size_t data_size) { std::unique_lock lk(content_lock); native_buffer->ensure_available_for(mga::BufferAccess::write); auto bpp = MIR_BYTES_PER_PIXEL(pixel_format()); size_t buffer_size_bytes = size().height.as_int() * size().width.as_int() * bpp; if (buffer_size_bytes != data_size) BOOST_THROW_EXCEPTION(std::logic_error("Size of pixels is not equal to size of buffer")); char* vaddr{nullptr}; int usage = GRALLOC_USAGE_SW_WRITE_OFTEN; int width = size().width.as_uint32_t(); int height = size().height.as_uint32_t(); int top = 0; int left = 0; if (hw_module->lock( hw_module, native_buffer->handle(), usage, top, left, width, height, reinterpret_cast(&vaddr)) || !vaddr) BOOST_THROW_EXCEPTION(std::runtime_error("error securing buffer for client cpu use")); // Copy line by line in case of stride != width*bpp for (int i = 0; i < height; i++) { int line_offset_in_buffer = stride().as_uint32_t()*i; int line_offset_in_source = bpp*width*i; memcpy(vaddr + line_offset_in_buffer, data + line_offset_in_source, width * bpp); } hw_module->unlock(hw_module, native_buffer->handle()); } void mga::Buffer::read(std::function const& do_with_data) { std::unique_lock lk(content_lock); native_buffer->ensure_available_for(mga::BufferAccess::read); auto buffer_size = size(); unsigned char* vaddr{nullptr}; int usage = GRALLOC_USAGE_SW_READ_OFTEN; int width = buffer_size.width.as_uint32_t(); int height = buffer_size.height.as_uint32_t(); int top = 0; int left = 0; if ((hw_module->lock( hw_module, native_buffer->handle(), usage, top, left, width, height, reinterpret_cast(&vaddr)) ) || !vaddr) BOOST_THROW_EXCEPTION(std::runtime_error("error securing buffer for client cpu use")); do_with_data(vaddr); hw_module->unlock(hw_module, native_buffer->handle()); } mg::NativeBufferBase* mga::Buffer::native_buffer_base() { return this; } void mga::Buffer::secure_for_render() { std::unique_lock lk(content_lock); secure_for_render(lk); } void mga::Buffer::secure_for_render(std::unique_lock const&) { native_buffer->lock_for_gpu(); } ./src/platforms/android/server/device_quirks.cpp0000644000004100000410000002131113115234664022333 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include #include #include "mir/graphics/display_report.h" #include "mir/graphics/gl_config.h" #include "gl_context.h" #include "device_quirks.h" #include "hardware/gralloc.h" #include "mir/raii.h" #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace mo = mir::options; int mga::PropertiesOps::property_get( char const* key, char* value, char const* default_value) const { return ::property_get(key, value, default_value); } namespace { char const* const num_framebuffers_opt = "enable-num-framebuffers-quirk"; char const* const gralloc_cannot_be_closed_safely_opt = "enable-gralloc-cannot-be-closed-safely-quirk"; char const* const width_alignment_opt = "enable-width-alignment-quirk"; char const* const fb_ion_heap_opt = "fb-ion-heap"; char const* const working_egl_sync_opt = "use-eglsync-quirk"; std::string const egl_sync_default = "default"; std::string const egl_sync_force_on = "force_on"; std::string const egl_sync_force_off = "force_off"; std::string determine_device_name(mga::PropertiesWrapper const& properties) { char const default_value[] = ""; char value[PROP_VALUE_MAX] = ""; char const key[] = "ro.product.device"; properties.property_get(key, value, default_value); return std::string{value}; } unsigned int num_framebuffers_for(std::string const& device_name, bool quirk_enabled) { if (quirk_enabled && device_name == "mx3") return 3; else return 2; } bool gralloc_cannot_be_closed_safely_for(std::string const& device_name, bool quirk_enabled) { return quirk_enabled && device_name == "krillin"; } bool clear_fb_context_fence_for(std::string const& device_name) { return device_name == "krillin" || device_name == "arale" || device_name == "manta"; } bool device_has_fb_ion_heap(std::string const& device_name, bool quirk_enabled) { return quirk_enabled && (device_name != "Aquaris_M10_FHD"); } bool device_has_working_egl_sync(mga::GPUInfo const& gpu_info, std::string const& option) { if (option == egl_sync_force_on) return true; if (option == egl_sync_force_off) return false; //TODO: we need a richer way to detect device classes //mali devices are have sync disabled due to high cost (500us) in hybris while using the //sync extensions. We should re-enable sync once the cost can be minimized. //powervr devices have some problems with depth-buffer ordering once EGL_KHR_fence_sync if (gpu_info.gl_vendor == "Qualcomm") return true; return false; } struct NullReport : mg::DisplayReport { void report_successful_setup_of_native_resources() override {}; void report_successful_egl_make_current_on_construction() override {}; void report_successful_egl_buffer_swap_on_construction() override {}; void report_successful_display_construction() override {}; void report_egl_configuration(EGLDisplay, EGLConfig) override {}; void report_vsync(unsigned int, mg::Frame const&) override {}; void report_successful_drm_mode_set_crtc_on_construction() override {}; void report_drm_master_failure(int) override {}; void report_vt_switch_away_failure() override {}; void report_vt_switch_back_failure() override {}; } report; struct Config : mg::GLConfig { int depth_buffer_bits() const override { return 0; } int stencil_buffer_bits() const override { return 0; } } config; mga::GPUInfo query_gl_for_gpu_info() { std::string vendor; std::string renderer; if (auto vendor_string = glGetString(GL_VENDOR)) vendor = std::string((char*)vendor_string); if (auto renderer_string = glGetString(GL_RENDERER)) renderer = std::string((char*)renderer_string); return { std::move(vendor), std::move(renderer) }; } mga::GPUInfo determine_gpu_info(mir::renderer::gl::Context const& context) { EGLDisplay current_display = eglGetCurrentDisplay(); EGLContext current_context = eglGetCurrentContext(); EGLSurface current_surface_read = eglGetCurrentSurface(EGL_READ); EGLSurface current_surface_draw = eglGetCurrentSurface(EGL_DRAW); if (current_context == EGL_NO_CONTEXT) { auto current = mir::raii::paired_calls( [&] { context.make_current(); }, [&] { eglMakeCurrent(current_display, current_surface_draw, current_surface_read, current_context); }); return query_gl_for_gpu_info(); } else { return query_gl_for_gpu_info(); } } } mga::DeviceQuirks::DeviceQuirks( PropertiesWrapper const& properties, mir::renderer::gl::Context const& context) : device_name(determine_device_name(properties)), gpu_info(determine_gpu_info(context)), num_framebuffers_(num_framebuffers_for(device_name, true)), gralloc_cannot_be_closed_safely_(gralloc_cannot_be_closed_safely_for(device_name, true)), enable_width_alignment_quirk{true}, clear_fb_context_fence_{clear_fb_context_fence_for(device_name)}, fb_ion_heap_{device_has_fb_ion_heap(device_name, true)}, working_egl_sync_{device_has_working_egl_sync(gpu_info, egl_sync_default)} { } mga::DeviceQuirks::DeviceQuirks(PropertiesWrapper const& properties) : DeviceQuirks(properties, mga::PbufferGLContext{config, report}) { } mga::DeviceQuirks::DeviceQuirks(PropertiesWrapper const& properties, mo::Option const& options) : device_name(determine_device_name(properties)), gpu_info(determine_gpu_info(mga::PbufferGLContext(config, report))), num_framebuffers_(num_framebuffers_for(device_name, options.get(num_framebuffers_opt, true))), gralloc_cannot_be_closed_safely_(gralloc_cannot_be_closed_safely_for(device_name, options.get(gralloc_cannot_be_closed_safely_opt, true))), enable_width_alignment_quirk(options.get(width_alignment_opt, true)), clear_fb_context_fence_{clear_fb_context_fence_for(device_name)}, fb_ion_heap_{device_has_fb_ion_heap(device_name, options.get(fb_ion_heap_opt, true))}, working_egl_sync_{device_has_working_egl_sync( gpu_info, options.get(working_egl_sync_opt, egl_sync_default.c_str()))} { } unsigned int mga::DeviceQuirks::num_framebuffers() const { return num_framebuffers_; } bool mga::DeviceQuirks::gralloc_cannot_be_closed_safely() const { return gralloc_cannot_be_closed_safely_; } int mga::DeviceQuirks::aligned_width(int width) const { if (enable_width_alignment_quirk && width == 720 && device_name == "vegetahd") return 736; return width; } bool mga::DeviceQuirks::clear_fb_context_fence() const { return clear_fb_context_fence_; } int mga::DeviceQuirks::fb_gralloc_bits() const { if (fb_ion_heap_) return GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB; return GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_TEXTURE; } bool mga::DeviceQuirks::working_egl_sync() const { return working_egl_sync_; } void mga::DeviceQuirks::add_options(boost::program_options::options_description& config) { config.add_options() (num_framebuffers_opt, boost::program_options::value()->default_value(true), "[platform-specific] Enable allocating 3 framebuffers (MX3 quirk) [{true,false}]") (gralloc_cannot_be_closed_safely_opt, boost::program_options::value()->default_value(true), "[platform-specific] Only close gralloc if it is safe to do so (krillin quirk) [{true,false}]") (width_alignment_opt, boost::program_options::value()->default_value(true), "[platform-specific] Enable width alignment (vegetahd quirk) [{true,false}]") (fb_ion_heap_opt, boost::program_options::value()->default_value(true), "[platform-specific] device has ion heap for framebuffer allocation available [{true, false}]") (working_egl_sync_opt, boost::program_options::value()->default_value(egl_sync_default), "[platform-specific] use KHR_reusable_sync extension [{default, force_on, force_off}]"); } ./src/platforms/android/server/fb_device.cpp0000644000004100000410000001075313115234664021414 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/graphics/buffer.h" #include "native_buffer.h" #include "sync_fence.h" #include "swapping_gl_context.h" #include "android_format_conversion-inl.h" #include "fb_device.h" #include "framebuffer_bundle.h" #include "buffer.h" #include "mir/geometry/length.h" #include #include #include namespace mg = mir::graphics; namespace mga=mir::graphics::android; namespace geom=mir::geometry; mga::FbControl::FbControl(std::shared_ptr const& fbdev) : fb_device(fbdev) { if (fb_device->setSwapInterval) fb_device->setSwapInterval(fb_device.get(), 1); } void mga::FbControl::power_mode(DisplayName display, MirPowerMode mode) { if (display != mga::DisplayName::primary) BOOST_THROW_EXCEPTION(std::runtime_error("fb device cannot activate non-primary display")); int enable = 0; if (mode == mir_power_mode_on) enable = 1; if (fb_device->enableScreen) fb_device->enableScreen(fb_device.get(), enable); } mg::DisplayConfigurationOutput mga::FbControl::active_config_for(DisplayName display_name) { auto const connected = (display_name == DisplayName::primary); geom::Length length_x_inches{0, geom::Length::Units::inches}; geom::Length length_y_inches{0, geom::Length::Units::inches}; if (fb_device->xdpi != 0) length_x_inches = geom::Length(fb_device->width / fb_device->xdpi, geom::Length::Units::inches); if (fb_device->ydpi != 0) length_y_inches = geom::Length(fb_device->height / fb_device->ydpi, geom::Length::Units::inches); geom::Size display_size_mm{ length_x_inches.as(geom::Length::Units::millimetres), length_y_inches.as(geom::Length::Units::millimetres), }; return { as_output_id(display_name), mg::DisplayConfigurationCardId{0}, mg::DisplayConfigurationOutputType::lvds, std::vector{mga::to_mir_format(fb_device->format)}, std::vector{ mg::DisplayConfigurationMode{{fb_device->width, fb_device->height}, fb_device->fps} }, 0, display_size_mm, connected, connected, {0,0}, 0, mga::to_mir_format(fb_device->format), mir_power_mode_on, mir_orientation_normal, 1.0f, mir_form_factor_phone, mir_subpixel_arrangement_unknown, {}, mir_output_gamma_unsupported, {} }; } mga::ConfigChangeSubscription mga::FbControl::subscribe_to_config_changes( std::function const&, std::function const&) { return nullptr; } mga::FBDevice::FBDevice(std::shared_ptr const& fbdev) : fb_device(fbdev) { } void mga::FBDevice::commit(std::list const& contents) { auto primary_contents = std::find_if(contents.begin(), contents.end(), [](mga::DisplayContents const& c) { return (c.name == mga::DisplayName::primary); }); if (primary_contents == contents.end()) return; auto& context = primary_contents->context; auto const& buffer = context.last_rendered_buffer(); auto native_buffer = mga::to_native_buffer_checked(buffer->native_buffer_handle()); native_buffer->ensure_available_for(mga::BufferAccess::read); if (fb_device->post(fb_device.get(), native_buffer->handle()) != 0) { BOOST_THROW_EXCEPTION(std::runtime_error("error posting with fb device")); } } bool mga::FBDevice::compatible_renderlist(RenderableList const&) { return false; } void mga::FBDevice::content_cleared() { } std::chrono::milliseconds mga::FBDevice::recommended_sleep() const { return std::chrono::milliseconds::zero(); } bool mga::FBDevice::can_swap_buffers() const { return true; } ./src/platforms/android/server/real_hwc_wrapper.h0000644000004100000410000000641313115234664022475 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_REAL_HWC_WRAPPER_H_ #define MIR_GRAPHICS_ANDROID_REAL_HWC_WRAPPER_H_ #include "hwc_wrapper.h" #include #include #include #include #include namespace mir { namespace graphics { namespace android { class HwcReport; class RealHwcWrapper; struct HwcCallbacks { hwc_procs_t hooks; RealHwcWrapper* self; }; class RealHwcWrapper : public HwcWrapper { public: RealHwcWrapper( //should probably be unique_ptr std::shared_ptr const& hwc_device, std::shared_ptr const& report); ~RealHwcWrapper(); void subscribe_to_events( void const* subscriber, std::function const& vsync_callback, std::function const& hotplug_callback, std::function const& invalidate_callback) override; void unsubscribe_from_events(void const* subscriber) noexcept override; void prepare(std::array const&) const override; void set(std::array const&) const override; void vsync_signal_on(DisplayName) const override; void vsync_signal_off(DisplayName) const override; void display_on(DisplayName) const override; void display_off(DisplayName) const override; std::vector display_configs(DisplayName) const override; int display_attributes( DisplayName, ConfigId, uint32_t const* attributes, int32_t* values) const override; void power_mode(DisplayName , PowerMode mode) const override; bool has_active_config(DisplayName name) const override; ConfigId active_config_for(DisplayName name) const override; void set_active_config(DisplayName name, ConfigId id) const override; void vsync(DisplayName, graphics::Frame::Timestamp) noexcept; void hotplug(DisplayName, bool) noexcept; void invalidate() noexcept; bool display_connected(DisplayName) const; private: std::shared_ptr const hwc_device; std::shared_ptr const report; std::mutex callback_map_lock; struct Callbacks { std::function vsync; std::function hotplug; std::function invalidate; }; std::unordered_map callback_map; std::atomic is_plugged[HWC_NUM_DISPLAY_TYPES]; }; } } } #endif /* MIR_GRAPHICS_ANDROID_REAL_HWC_WRAPPER_H_ */ ./src/platforms/android/server/display_name.h0000644000004100000410000000253313115234416021610 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_DISPLAY_NAME_H_ #define MIR_GRAPHICS_ANDROID_DISPLAY_NAME_H_ #include "mir/graphics/display_configuration.h" #include namespace mir { namespace graphics { namespace android { enum class DisplayName { primary = HWC_DISPLAY_PRIMARY, external = HWC_DISPLAY_EXTERNAL, virt = HWC_DISPLAY_VIRTUAL }; inline auto as_output_id(DisplayName name) -> DisplayConfigurationOutputId { return DisplayConfigurationOutputId{1 + static_cast(name)}; } inline auto as_hwc_display(DisplayName name) -> int { return static_cast(name); } } } } #endif /* MIR_GRAPHICS_ANDROID_DISPLAY_NAME_H_ */ ./src/platforms/android/server/hwc_device.cpp0000644000004100000410000001201613115234664021600 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #include "swapping_gl_context.h" #include "hwc_device.h" #include "hwc_layerlist.h" #include "hwc_wrapper.h" #include "framebuffer_bundle.h" #include "buffer.h" #include "hwc_fallback_gl_renderer.h" #include "mir/raii.h" #include #include #include #include namespace mg = mir::graphics; namespace mga=mir::graphics::android; namespace geom = mir::geometry; namespace { bool plane_alpha_is_translucent(mg::Renderable const& renderable) { float static const tolerance { 1.0f/(2.0 * static_cast(std::numeric_limits::max())) }; return (renderable.alpha() < 1.0f - tolerance); } } bool mga::HwcDevice::compatible_renderlist(RenderableList const& list) { if (list.empty()) return false; for (auto const& renderable : list) { //TODO: enable planeAlpha for (hwc version >= 1.2), 90 deg rotation static glm::mat4 const identity; if (plane_alpha_is_translucent(*renderable) || renderable->transformation() != identity) { return false; } } return true; } mga::HwcDevice::HwcDevice(std::shared_ptr const& hwc_wrapper) : hwc_wrapper(hwc_wrapper) { } bool mga::HwcDevice::buffer_is_onscreen(mg::Buffer const& buffer) const { /* check the handles, as the buffer ptrs might change between sets */ auto const handle = buffer.native_buffer_handle().get(); auto it = std::find_if( onscreen_overlay_buffers.begin(), onscreen_overlay_buffers.end(), [&handle](std::shared_ptr const& b) { return (handle == b->native_buffer_handle().get()); }); return it != onscreen_overlay_buffers.end(); } void mga::HwcDevice::commit(std::list const& contents) { std::array lists{{ nullptr, nullptr, nullptr }}; std::vector> next_onscreen_overlay_buffers; for (auto& content : contents) { if (content.name == mga::DisplayName::primary) lists[HWC_DISPLAY_PRIMARY] = content.list.native_list(); else if (content.name == mga::DisplayName::external) lists[HWC_DISPLAY_EXTERNAL] = content.list.native_list(); content.list.setup_fb(content.context.last_rendered_buffer()); } hwc_wrapper->prepare(lists); bool purely_overlays = true; for (auto& content : contents) { if (content.list.needs_swapbuffers()) { auto rejected_renderables = content.list.rejected_renderables(); if (!rejected_renderables.empty()) { auto current_context = mir::raii::paired_calls( [&]{ content.context.make_current(); }, [&]{ content.context.release_current(); }); content.compositor.render(std::move(rejected_renderables), content.list_offset, content.context); } content.list.setup_fb(content.context.last_rendered_buffer()); content.list.swap_occurred(); purely_overlays = false; } //setup overlays for (auto& layer : content.list) { auto buffer = layer.layer.buffer(); if (layer.layer.is_overlay() && buffer) { if (!buffer_is_onscreen(*buffer)) layer.layer.set_acquirefence(); next_onscreen_overlay_buffers.push_back(buffer); } } } hwc_wrapper->set(lists); onscreen_overlay_buffers = std::move(next_onscreen_overlay_buffers); for (auto& content : contents) { for (auto& it : content.list) it.layer.release_buffer(); mir::Fd retire_fd(content.list.retirement_fence()); } /* * Test results (how long can we sleep for without missing a frame?): * arale: 10ms (TODO: Find out why arale is so slow) * mako: 15ms * krillin: 11ms (to be fair, the display is 67Hz) */ using namespace std; recommend_sleep = purely_overlays ? 10ms : 0ms; } std::chrono::milliseconds mga::HwcDevice::recommended_sleep() const { return recommend_sleep; } void mga::HwcDevice::content_cleared() { onscreen_overlay_buffers.clear(); } bool mga::HwcDevice::can_swap_buffers() const { return true; } ./src/platforms/android/server/hwc_loggers.cpp0000644000004100000410000002722313115234664022011 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "hwc_loggers.h" #include #include namespace mga=mir::graphics::android; namespace { std::string const separator{" | "}; int const layer_num_column_size{2}; int const blending_column_size{8}; int const rotation_column_size{9}; int const rect_entry_column_size{4}; int const type_column_size{9}; class StreamFormatter { public: StreamFormatter(std::ostream& str, unsigned int const width, std::ios_base::fmtflags flags) : stream(str), old_width(stream.width(width)), old_flags(stream.setf(flags,std::ios::adjustfield)) { } ~StreamFormatter() { stream.setf(old_flags, std::ios::adjustfield); stream.width(old_width); } private: std::ostream& stream; unsigned int const old_width; std::ios_base::fmtflags const old_flags; }; struct DisplayName{ unsigned int const name; }; std::ostream& operator<<(std::ostream& str, DisplayName d) { if (d.name == HWC_DISPLAY_PRIMARY) str << "primary "; if (d.name == HWC_DISPLAY_EXTERNAL) str << "external"; return str; } struct LayerNumber{ unsigned int const num; }; std::ostream& operator<<(std::ostream& str, LayerNumber l) { StreamFormatter stream_format(str, layer_num_column_size, std::ios_base::right); return str << l.num % 100; } struct HwcRotation{ unsigned int const key; }; std::ostream& operator<<(std::ostream& str, HwcRotation rotation_key) { StreamFormatter stream_format(str, rotation_column_size, std::ios_base::left); switch(rotation_key.key) { case 0: return str << std::string{"NONE"}; case HWC_TRANSFORM_ROT_90: return str << std::string{"ROT_90"}; case HWC_TRANSFORM_ROT_180: return str << std::string{"ROT_180"}; case HWC_TRANSFORM_ROT_270: return str << std::string{"ROT_270"}; default: return str << std::string{"UNKNOWN"}; } } struct HwcBlending{ int const key; }; std::ostream& operator<<(std::ostream& str, HwcBlending blending_key) { StreamFormatter stream_format(str, blending_column_size, std::ios_base::left); switch(blending_key.key) { case HWC_BLENDING_NONE: return str << std::string{"NONE"}; case HWC_BLENDING_PREMULT: return str << std::string{"PREMULT"}; case HWC_BLENDING_COVERAGE: return str << std::string{"COVERAGE"}; default: return str << std::string{"UNKNOWN"}; } } struct HwcType{ int const type; unsigned int const flags; }; std::ostream& operator<<(std::ostream& str, HwcType type) { StreamFormatter stream_format(str, type_column_size, std::ios_base::left); switch(type.type) { case HWC_OVERLAY: return str << std::string{"OVERLAY"}; case HWC_FRAMEBUFFER: if (type.flags == HWC_SKIP_LAYER) return str << std::string{"FORCE_GL"}; else return str << std::string{"GL_RENDER"}; case HWC_FRAMEBUFFER_TARGET: return str << std::string{"FB_TARGET"}; default: return str << std::string{"UNKNOWN"}; } } struct HwcRectMember { int member; }; std::ostream& operator<<(std::ostream& str, HwcRectMember rect) { StreamFormatter stream_format(str, rect_entry_column_size, std::ios_base::right); return str << rect.member; } struct HwcRect { hwc_rect_t const& rect; }; std::ostream& operator<<(std::ostream& str, HwcRect r) { return str << "{" << HwcRectMember{r.rect.left} << "," << HwcRectMember{r.rect.top} << "," << HwcRectMember{r.rect.right} << "," << HwcRectMember{r.rect.bottom} << "}"; } struct HwcFloatRectMember { float member; }; std::ostream& operator<<(std::ostream& str, HwcFloatRectMember rect) { StreamFormatter stream_format(str, rect_entry_column_size, std::ios_base::right); return str << rect.member; } struct HwcFloatRect { hwc_frect_t const& rect; }; std::ostream& operator<<(std::ostream& str, HwcFloatRect r) { return str << "{" << HwcFloatRectMember{r.rect.left} << "," << HwcFloatRectMember{r.rect.top} << "," << HwcFloatRectMember{r.rect.right} << "," << HwcFloatRectMember{r.rect.bottom} << "}"; } std::ostream& operator<<(std::ostream& str, mga::OverlayOptimization opt) { if (opt == mga::OverlayOptimization::enabled) return str << "ON"; else return str << "OFF"; } std::ostream& operator<<(std::ostream& str, mga::HwcVersion version) { switch (version) { case mga::HwcVersion::hwc10: str << "1.0"; break; case mga::HwcVersion::hwc11: str << "1.1"; break; case mga::HwcVersion::hwc12: str << "1.2"; break; case mga::HwcVersion::hwc13: str << "1.3"; break; case mga::HwcVersion::hwc14: str << "1.4"; break; case mga::HwcVersion::hwc15: str << "1.5"; break; default: break; } return str; } std::ostream& operator<<(std::ostream& str, mga::PowerMode power_mode) { switch (power_mode) { case mga::PowerMode::off: str << "off"; break; case mga::PowerMode::doze: str << "doze"; break; case mga::PowerMode::normal: str << "on(normal)"; break; case mga::PowerMode::doze_suspend: str << "doze(suspend)"; break; default: break; } return str; } } void mga::HwcFormattedLogger::report_list_submitted_to_prepare( std::array const& displays) const { std::cout << "before prepare():" << std::endl << " # | display | Type | pos {l,t,r,b} | crop {l,t,r,b} | transform | blending | " << std::endl; for(auto i = 0u; i < displays.size(); i++) { if (!displays[i]) continue; for(auto j = 0u; j < displays[i]->numHwLayers; j++) { std::cout << LayerNumber{j} << separator << DisplayName{i} << separator << HwcType{displays[i]->hwLayers[j].compositionType, displays[i]->hwLayers[j].flags} << separator << HwcRect{displays[i]->hwLayers[j].displayFrame} << separator; if (hwc_version < HwcVersion::hwc13) std::cout << HwcRect{displays[i]->hwLayers[j].sourceCrop}; else std::cout << HwcFloatRect{displays[i]->hwLayers[j].sourceCropf}; std::cout << separator << HwcRotation{displays[i]->hwLayers[j].transform} << separator << HwcBlending{displays[i]->hwLayers[j].blending} << separator << std::endl; } } } void mga::HwcFormattedLogger::report_prepare_done( std::array const& displays) const { std::cout << "after prepare():" << std::endl << " # | display | Type | " << std::endl; for(auto i = 0u; i < displays.size(); i++) { if (!displays[i]) continue; for(auto j = 0u; j < displays[i]->numHwLayers; j++) std::cout << LayerNumber{j} << separator << DisplayName{i} << separator << HwcType{displays[i]->hwLayers[j].compositionType, displays[i]->hwLayers[j].flags} << separator << std::endl; } } void mga::HwcFormattedLogger::report_set_list( std::array const& displays) const { std::cout << "set list():" << std::endl << " # | display | Type | handle | acquireFenceFd" << std::endl; for(auto i = 0u; i < displays.size(); i++) { if (!displays[i]) continue; for(auto j = 0u; j < displays[i]->numHwLayers; j++) std::cout << LayerNumber{j} << separator << DisplayName{i} << separator << HwcType{displays[i]->hwLayers[j].compositionType, displays[i]->hwLayers[j].flags} << separator << displays[i]->hwLayers[j].handle << separator << displays[i]->hwLayers[j].acquireFenceFd << std::endl; } } void mga::HwcFormattedLogger::report_set_done( std::array const& displays) const { std::cout << "after set():" << std::endl << " # | display | releaseFenceFd" << std::endl; for(auto i = 0u; i < displays.size(); i++) { if (!displays[i]) continue; for(auto j = 0u; j < displays[i]->numHwLayers; j++) std::cout << LayerNumber{j} << separator << DisplayName{i} << separator << displays[i]->hwLayers[j].releaseFenceFd << std::endl; } } void mga::HwcFormattedLogger::report_overlay_optimization(OverlayOptimization overlay_optimization) const { std::cout << "HWC overlay optimizations are " << overlay_optimization << std::endl; } void mga::HwcFormattedLogger::report_display_on() const { std::cout << "HWC: display on" << std::endl; } void mga::HwcFormattedLogger::report_display_off() const { std::cout << "HWC: display off" << std::endl; } void mga::HwcFormattedLogger::report_vsync_on() const { std::cout << "HWC: vsync signal on" << std::endl; } void mga::HwcFormattedLogger::report_vsync_off() const { std::cout << "HWC: vsync signal off" << std::endl; } void mga::HwcFormattedLogger::report_hwc_version(mga::HwcVersion version) const { std::cout << "HWC version " << version << std::endl; } void mga::HwcFormattedLogger::report_legacy_fb_module() const { std::cout << "Legacy FB module" << std::endl; } void mga::HwcFormattedLogger::report_power_mode(PowerMode mode) const { std::cout << "HWC: power mode: " << mode << std::endl; } void mga::NullHwcReport::report_list_submitted_to_prepare( std::array const&) const {} void mga::NullHwcReport::report_prepare_done( std::array const&) const {} void mga::NullHwcReport::report_set_list( std::array const&) const {} void mga::NullHwcReport::report_set_done( std::array const&) const {} void mga::NullHwcReport::report_overlay_optimization(OverlayOptimization) const {} void mga::NullHwcReport::report_display_on() const {} void mga::NullHwcReport::report_display_off() const {} void mga::NullHwcReport::report_vsync_on() const {} void mga::NullHwcReport::report_vsync_off() const {} void mga::NullHwcReport::report_hwc_version(mga::HwcVersion) const {} void mga::NullHwcReport::report_legacy_fb_module() const {} void mga::NullHwcReport::report_power_mode(PowerMode) const {} ./src/platforms/android/server/hwc_fb_device.cpp0000644000004100000410000000753313115234664022257 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #include "hwc_fb_device.h" #include "framebuffer_bundle.h" #include "hwc_wrapper.h" #include "hwc_fallback_gl_renderer.h" #include "mir/graphics/buffer.h" #include "native_buffer.h" #include "android_format_conversion-inl.h" #include "swapping_gl_context.h" #include "hwc_layerlist.h" #include #include #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace geom = mir::geometry; mga::HwcFbDevice::HwcFbDevice( std::shared_ptr const& hwc_wrapper, std::shared_ptr const& fb_device) : hwc_wrapper(hwc_wrapper), fb_device(fb_device), vsync_subscription{ [hwc_wrapper, this]{ using namespace std::placeholders; hwc_wrapper->subscribe_to_events(this, std::bind(&mga::HwcFbDevice::notify_vsync, this, _1, _2), [](mga::DisplayName, bool){}, []{}); }, [hwc_wrapper, this]{ hwc_wrapper->unsubscribe_from_events(this); } } { } void mga::HwcFbDevice::commit(std::list const& contents) { auto primary_contents = std::find_if(contents.begin(), contents.end(), [](mga::DisplayContents const& c) { return (c.name == mga::DisplayName::primary); }); if (primary_contents == contents.end()) return; auto& layer_list = primary_contents->list; auto& context = primary_contents->context; layer_list.setup_fb(context.last_rendered_buffer()); if (auto display_list = layer_list.native_list()) { hwc_wrapper->prepare({{display_list, nullptr, nullptr}}); display_list->dpy = eglGetCurrentDisplay(); display_list->sur = eglGetCurrentSurface(EGL_DRAW); //set() may affect EGL state by calling eglSwapBuffers. //HWC 1.0 is the only version of HWC that can do this. hwc_wrapper->set({{display_list, nullptr, nullptr}}); } else { std::stringstream ss; ss << "error accessing list during hwc prepare()"; BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } auto& buffer = *context.last_rendered_buffer(); auto native_buffer = mga::to_native_buffer_checked(buffer.native_buffer_handle()); native_buffer->ensure_available_for(mga::BufferAccess::read); if (fb_device->post(fb_device.get(), native_buffer->handle()) != 0) { BOOST_THROW_EXCEPTION(std::runtime_error("error posting with fb device")); } std::unique_lock lk(vsync_wait_mutex); vsync_occurred = false; vsync_trigger.wait(lk, [this]{return vsync_occurred;}); } void mga::HwcFbDevice::notify_vsync(mga::DisplayName, mg::Frame::Timestamp) { std::unique_lock lk(vsync_wait_mutex); vsync_occurred = true; vsync_trigger.notify_all(); } bool mga::HwcFbDevice::compatible_renderlist(RenderableList const&) { return false; } void mga::HwcFbDevice::content_cleared() { } std::chrono::milliseconds mga::HwcFbDevice::recommended_sleep() const { return std::chrono::milliseconds::zero(); } bool mga::HwcFbDevice::can_swap_buffers() const { return false; } ./src/platforms/android/server/display_configuration.h0000644000004100000410000000475013115234416023542 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef MIR_GRAPHICS_ANDROID_DISPLAY_CONFIGURATION_H_ #define MIR_GRAPHICS_ANDROID_DISPLAY_CONFIGURATION_H_ #include "mir/graphics/display_configuration.h" #include "hwc_configuration.h" #include namespace mir { namespace graphics { namespace android { class DisplayConfiguration : public graphics::DisplayConfiguration { public: DisplayConfiguration(DisplayConfigurationOutput primary, MirPowerMode primary_mode, DisplayConfigurationOutput external, MirPowerMode external_mode); DisplayConfiguration(DisplayConfigurationOutput primary, MirPowerMode primary_mode, DisplayConfigurationOutput external, MirPowerMode external_mode, DisplayConfigurationOutput virt_config); DisplayConfiguration(DisplayConfiguration const& other); DisplayConfiguration& operator=(DisplayConfiguration const& other); virtual ~DisplayConfiguration() = default; void for_each_card(std::function f) const override; void for_each_output(std::function f) const override; void for_each_output(std::function f) override; std::unique_ptr clone() const override; DisplayConfigurationOutput& primary(); DisplayConfigurationOutput& external(); DisplayConfigurationOutput& virt(); DisplayConfigurationOutput& operator[](DisplayConfigurationOutputId const&); void set_virtual_output_to(int width, int height); void disable_virtual_output(); private: std::array configurations; DisplayConfigurationCard card; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DISPLAY_CONFIGURATION_H_ */ ./src/platforms/android/server/cmdstream_sync_factory.h0000644000004100000410000000320113115234416023676 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_CMDSTREAM_SYNC_FACTORY_H_ #define MIR_GRAPHICS_ANDROID_CMDSTREAM_SYNC_FACTORY_H_ #include namespace mir { namespace graphics { class CommandStreamSync; namespace android { class CommandStreamSyncFactory { public: virtual ~CommandStreamSyncFactory() = default; virtual std::unique_ptr create_command_stream_sync() = 0; protected: CommandStreamSyncFactory() = default; CommandStreamSyncFactory(CommandStreamSyncFactory const&) = delete; CommandStreamSyncFactory& operator=(CommandStreamSyncFactory const&) = delete; }; class EGLSyncFactory : public CommandStreamSyncFactory { std::unique_ptr create_command_stream_sync() override; }; class NullCommandStreamSyncFactory : public CommandStreamSyncFactory { std::unique_ptr create_command_stream_sync() override; }; } } } #endif /* MIR_GRAPHICS_ANDROID_CMDSTREAM_SYNC_FACTORY_H_ */ ./src/platforms/android/server/hwc_layers.h0000644000004100000410000000667613115234664021324 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_HWC_LAYERS_H_ #define MIR_GRAPHICS_ANDROID_HWC_LAYERS_H_ #include "mir/graphics/renderable.h" #include "fence.h" #include "mir/geometry/rectangle.h" #include #include #include #include #include namespace mir { namespace graphics { class Renderable; class Buffer; namespace android { enum LayerType { gl_rendered, overlay, framebuffer_target, skip }; class LayerAdapter { public: virtual void fill_source_crop(hwc_layer_1_t&, geometry::Rectangle const& crop_size) const = 0; virtual bool needs_fb_target() const = 0; virtual ~LayerAdapter() = default; LayerAdapter() = default; LayerAdapter(LayerAdapter const&) = delete; LayerAdapter& operator=(LayerAdapter const&) = delete; }; //HWC 1.0 has int sourceCrop and no fbtarget class Hwc10Adapter : public LayerAdapter { void fill_source_crop(hwc_layer_1_t&, geometry::Rectangle const& crop_size) const override; bool needs_fb_target() const override; }; //HWC 1.1 to 1.2 have int sourceCrop and fbtarget class IntegerSourceCrop : public LayerAdapter { void fill_source_crop(hwc_layer_1_t&, geometry::Rectangle const& crop_size) const override; bool needs_fb_target() const override; }; //HWC 1.3 and later have float sourceCrop and fbtarget class FloatSourceCrop : public LayerAdapter { void fill_source_crop(hwc_layer_1_t&, geometry::Rectangle const& crop_size) const override; bool needs_fb_target() const override; }; class HWCLayer { public: HWCLayer( std::shared_ptr const&, std::shared_ptr const& list, size_t layer_index); HWCLayer( std::shared_ptr const&, std::shared_ptr const& list, size_t layer_index, LayerType, geometry::Rectangle const& screen_position, bool alpha_enabled, std::shared_ptr const& buffer); HWCLayer& operator=(HWCLayer && layer); HWCLayer(HWCLayer && layer); HWCLayer& operator=(HWCLayer const& layer) = delete; HWCLayer(HWCLayer const& layer) = delete; bool setup_layer( LayerType type, geometry::Rectangle const& position, bool alpha_enabled, std::shared_ptr const& buffer); bool is_overlay() const; bool needs_gl_render() const; void set_acquirefence(); void release_buffer(); std::shared_ptr buffer(); private: std::shared_ptr layer_adapter; hwc_layer_1_t* hwc_layer; std::shared_ptr hwc_list; hwc_rect_t visible_rect; std::shared_ptr associated_buffer; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_LAYERS_H_ */ ./src/platforms/android/server/display_buffer.h0000644000004100000410000000610513115234664022145 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_DISPLAY_BUFFER_H_ #define MIR_GRAPHICS_ANDROID_DISPLAY_BUFFER_H_ #include "configurable_display_buffer.h" #include "mir/graphics/egl_resources.h" #include "mir/gl/program_factory.h" #include "mir/renderer/gl/render_target.h" #include "display_configuration.h" #include "gl_context.h" #include "hwc_fallback_gl_renderer.h" #include "overlay_optimization.h" #include namespace mir { namespace graphics { namespace android { class DisplayDevice; class FramebufferBundle; class LayerList; class DisplayBuffer : public ConfigurableDisplayBuffer, public NativeDisplayBuffer, public renderer::gl::RenderTarget { public: //TODO: could probably just take the HalComponentFactory to reduce the // number of dependencies DisplayBuffer( DisplayName, std::unique_ptr layer_list, std::shared_ptr const& fb_bundle, std::shared_ptr const& display_device, std::shared_ptr const& native_window, GLContext const& shared_gl_context, gl::ProgramFactory const& program_factory, MirOrientation orientation, geometry::Displacement offset, OverlayOptimization overlay_option); geometry::Rectangle view_area() const override; void make_current() override; void release_current() override; void swap_buffers() override; bool overlay(RenderableList const& renderlist) override; void bind() override; MirOrientation orientation() const override; MirMirrorMode mirror_mode() const override; NativeDisplayBuffer* native_display_buffer() override; void configure(MirPowerMode power_mode, MirOrientation orientation, geometry::Displacement) override; DisplayContents contents() override; MirPowerMode power_mode() const override; private: DisplayName display_name; std::unique_ptr layer_list; std::shared_ptr const fb_bundle; std::shared_ptr const display_device; std::shared_ptr const native_window; FramebufferGLContext gl_context; HWCFallbackGLRenderer overlay_program; bool overlay_enabled; MirOrientation orientation_; geometry::Displacement offset_from_origin; MirPowerMode power_mode_; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DISPLAY_BUFFER_H_ */ ./src/platforms/android/server/hwc_layers.cpp0000644000004100000410000001615513115234664021650 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/graphics/renderable.h" #include "mir/graphics/buffer.h" #include "sync_fence.h" #include "native_buffer.h" #include "hwc_layerlist.h" #include #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace geom=mir::geometry; namespace { decltype(hwc_layer_1_t::planeAlpha) static const plane_alpha_max{ std::numeric_limits::max() }; } void mga::FloatSourceCrop::fill_source_crop( hwc_layer_1_t& hwc_layer, geometry::Rectangle const& crop_rect) const { hwc_layer.sourceCropf = { static_cast(crop_rect.top_left.x.as_int()), static_cast(crop_rect.top_left.y.as_int()), static_cast(crop_rect.size.width.as_int()), static_cast(crop_rect.size.height.as_int()) }; } bool mga::FloatSourceCrop::needs_fb_target() const { return true; } void mga::IntegerSourceCrop::fill_source_crop( hwc_layer_1_t& hwc_layer, geometry::Rectangle const& crop_rect) const { hwc_layer.sourceCropi = { crop_rect.top_left.x.as_int(), crop_rect.top_left.y.as_int(), crop_rect.size.width.as_int(), crop_rect.size.height.as_int() }; } bool mga::IntegerSourceCrop::needs_fb_target() const { return true; } void mga::Hwc10Adapter::fill_source_crop( hwc_layer_1_t& hwc_layer, geometry::Rectangle const& crop_rect) const { hwc_layer.sourceCropi = { crop_rect.top_left.x.as_int(), crop_rect.top_left.y.as_int(), crop_rect.size.width.as_int(), crop_rect.size.height.as_int() }; } bool mga::Hwc10Adapter::needs_fb_target() const { return false; } mga::HWCLayer& mga::HWCLayer::operator=(HWCLayer && other) { layer_adapter = std::move(other.layer_adapter); hwc_layer = other.hwc_layer; hwc_list = std::move(other.hwc_list); visible_rect = std::move(other.visible_rect); associated_buffer = std::move(other.associated_buffer); return *this; } mga::HWCLayer::HWCLayer(HWCLayer && other) : layer_adapter{std::move(other.layer_adapter)}, hwc_layer(std::move(other.hwc_layer)), hwc_list(std::move(other.hwc_list)), visible_rect(std::move(other.visible_rect)), associated_buffer(other.associated_buffer) { } mga::HWCLayer::HWCLayer( std::shared_ptr const& layer_adapter, std::shared_ptr const& list, size_t layer_index) : layer_adapter(layer_adapter), hwc_layer(&list->hwLayers[layer_index]), hwc_list(list) { memset(hwc_layer, 0, sizeof(hwc_layer_1_t)); memset(&visible_rect, 0, sizeof(hwc_rect_t)); hwc_layer->hints = 0; hwc_layer->transform = 0; hwc_layer->acquireFenceFd = -1; hwc_layer->releaseFenceFd = -1; hwc_layer->blending = HWC_BLENDING_NONE; hwc_layer->planeAlpha = plane_alpha_max; hwc_layer->visibleRegionScreen.numRects=1; hwc_layer->visibleRegionScreen.rects= &visible_rect; } mga::HWCLayer::HWCLayer( std::shared_ptr const& layer_adapter, std::shared_ptr const& list, size_t layer_index, LayerType type, geometry::Rectangle const& position, bool alpha_enabled, std::shared_ptr const& buffer) : HWCLayer(layer_adapter, list, layer_index) { setup_layer(type, position, alpha_enabled, buffer); } bool mga::HWCLayer::needs_gl_render() const { return (hwc_layer->compositionType == HWC_FRAMEBUFFER); } bool mga::HWCLayer::is_overlay() const { return (hwc_layer->compositionType == HWC_OVERLAY); } void mga::HWCLayer::release_buffer() { if ((hwc_layer->compositionType != HWC_FRAMEBUFFER) && associated_buffer) { auto native_buffer = mga::to_native_buffer_checked(associated_buffer->native_buffer_handle()); native_buffer->update_usage(hwc_layer->releaseFenceFd, mga::BufferAccess::read); hwc_layer->releaseFenceFd = -1; hwc_layer->acquireFenceFd = -1; } associated_buffer.reset(); } std::shared_ptr mga::HWCLayer::buffer() { return associated_buffer; } bool mga::HWCLayer::setup_layer( LayerType type, geometry::Rectangle const& position, bool alpha_enabled, std::shared_ptr const& buffer) { if (type != mga::LayerType::skip) associated_buffer = buffer; bool needs_commit = needs_gl_render(); hwc_layer->flags = 0; switch(type) { case mga::LayerType::skip: hwc_layer->compositionType = HWC_FRAMEBUFFER; hwc_layer->flags = HWC_SKIP_LAYER; break; case mga::LayerType::gl_rendered: hwc_layer->compositionType = HWC_FRAMEBUFFER; break; case mga::LayerType::framebuffer_target: hwc_layer->compositionType = HWC_FRAMEBUFFER_TARGET; break; case mga::LayerType::overlay: //driver is the only one who can set to overlay default: BOOST_THROW_EXCEPTION(std::logic_error("invalid layer type")); } if (alpha_enabled) hwc_layer->blending = HWC_BLENDING_PREMULT; else hwc_layer->blending = HWC_BLENDING_NONE; hwc_layer->planeAlpha = plane_alpha_max; /* note, if the sourceCrop and DisplayFrame sizes differ, the output will be linearly scaled */ hwc_layer->displayFrame = { position.top_left.x.as_int(), position.top_left.y.as_int(), position.bottom_right().x.as_int(), position.bottom_right().y.as_int() }; geom::Rectangle crop_rect{{0,0}, buffer->size()}; layer_adapter->fill_source_crop(*hwc_layer, crop_rect); hwc_layer->surfaceDamage = { 0, nullptr }; visible_rect = hwc_layer->displayFrame; auto native_buffer = mga::to_native_buffer_checked(buffer->native_buffer_handle()); needs_commit |= (hwc_layer->handle != native_buffer->handle()); hwc_layer->handle = native_buffer->handle(); return needs_commit; } void mga::HWCLayer::set_acquirefence() { hwc_layer->releaseFenceFd = -1; hwc_layer->acquireFenceFd = -1; //we shouldn't be copying the FD unless the HWC has marked this as a buffer its interested in. //we disregard fences that haven't changed, as the hwc will still own the buffer if (!needs_gl_render() && associated_buffer) { auto native_buffer = mga::to_native_buffer_checked(associated_buffer->native_buffer_handle()); hwc_layer->acquireFenceFd = native_buffer->copy_fence(); } } ./src/platforms/android/server/graphic_buffer_allocator.h0000644000004100000410000000442713115234664024162 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #ifndef MIR_PLATFORM_ANDROID_GRAPHIC_BUFFER_ALLOCATOR_H_ #define MIR_PLATFORM_ANDROID_GRAPHIC_BUFFER_ALLOCATOR_H_ #include // to fix missing #includes in graphics.h from hardware.h #include #include "mir_toolkit/mir_native_buffer.h" #include "mir/graphics/buffer_properties.h" #include "mir/graphics/graphic_buffer_allocator.h" namespace mir { namespace graphics { class EGLExtensions; namespace android { class Gralloc; class DeviceQuirks; class CommandStreamSyncFactory; class GraphicBufferAllocator: public graphics::GraphicBufferAllocator { public: GraphicBufferAllocator( std::shared_ptr const& cmdstream_sync_factory, std::shared_ptr const& quirks); std::shared_ptr alloc_buffer( graphics::BufferProperties const& buffer_properties) override; std::shared_ptr alloc_buffer(geometry::Size, uint32_t format, uint32_t flags) override; std::shared_ptr alloc_software_buffer(geometry::Size, MirPixelFormat) override; std::shared_ptr alloc_framebuffer( geometry::Size sz, MirPixelFormat pf); std::vector supported_pixel_formats() override; private: const hw_module_t *hw_module; std::shared_ptr alloc_device; std::shared_ptr const egl_extensions; std::shared_ptr const cmdstream_sync_factory; std::shared_ptr const quirks; }; } } } #endif /* MIR_PLATFORM_ANDROID_GRAPHIC_BUFFER_ALLOCATOR_H_ */ ./src/platforms/android/server/swapping_gl_context.h0000644000004100000410000000262313115234416023221 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_SWAPPING_GL_CONTEXT_H_ #define MIR_GRAPHICS_ANDROID_SWAPPING_GL_CONTEXT_H_ #include namespace mir { namespace graphics { class Buffer; namespace android { class SwappingGLContext { public: virtual ~SwappingGLContext() = default; virtual void make_current() const = 0; virtual void release_current() const = 0; virtual void swap_buffers() const = 0; virtual std::shared_ptr last_rendered_buffer() const = 0; protected: SwappingGLContext() = default; SwappingGLContext(SwappingGLContext const&) = delete; SwappingGLContext& operator=(SwappingGLContext const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_SWAPPING_GL_CONTEXT_H_ */ ./src/platforms/android/server/virtual_output.h0000644000004100000410000000250513115234416022250 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alberto Aguirre */ #ifndef MIR_GRAPHICS_ANDROID_VIRTUAL_OUTPUT_H_ #define MIR_GRAPHICS_ANDROID_VIRTUAL_OUTPUT_H_ #include "mir/graphics/virtual_output.h" #include namespace mir { namespace graphics { namespace android { class VirtualOutput : public graphics::VirtualOutput { public: explicit VirtualOutput(std::function enable_virtual_output, std::function disable_virtual_output); ~VirtualOutput(); void enable() override; void disable() override; private: std::function enable_virtual_output; std::function disable_virtual_output; }; } } } #endif ./src/platforms/android/server/gralloc_module.h0000644000004100000410000000324213115234664022136 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_GRALLOC_MODULE_H_ #define MIR_GRAPHICS_ANDROID_GRALLOC_MODULE_H_ #include "gralloc.h" #include #include namespace mir { namespace graphics { namespace android { class DeviceQuirks; class CommandStreamSyncFactory; class GrallocModule : public Gralloc { public: explicit GrallocModule( std::shared_ptr const& alloc_device, std::shared_ptr const& cmdstream_sync_factory, std::shared_ptr const& quirks); std::shared_ptr alloc_buffer(geometry::Size, uint32_t android_format, uint32_t usage_bitmask) override; private: std::shared_ptr alloc_dev; std::shared_ptr const sync_factory; std::shared_ptr const quirks; unsigned int convert_to_android_usage(BufferUsage usage); }; } } } #endif /* MIR_GRAPHICS_ANDROID_GRALLOC_MODULE_H_ */ ./src/platforms/android/server/hal_component_factory.cpp0000644000004100000410000001443513115234664024064 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "fb_device.h" #include "device_quirks.h" #include "hal_component_factory.h" #include "display_resource_factory.h" #include "display_buffer.h" #include "display_device.h" #include "framebuffers.h" #include "real_hwc_wrapper.h" #include "hwc_report.h" #include "hwc_configuration.h" #include "hwc_layers.h" #include "hwc_device.h" #include "hwc_fb_device.h" #include "graphic_buffer_allocator.h" #include "cmdstream_sync_factory.h" #include "android_format_conversion-inl.h" #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace geom = mir::geometry; mga::HalComponentFactory::HalComponentFactory( std::shared_ptr const& res_factory, std::shared_ptr const& hwc_report, std::shared_ptr const& quirks) : res_factory(res_factory), hwc_report(hwc_report), force_backup_display(false), num_framebuffers{quirks->num_framebuffers()}, working_egl_sync(quirks->working_egl_sync()), hwc_version{mga::HwcVersion::unknown} { try { std::tie(hwc_wrapper, hwc_version) = res_factory->create_hwc_wrapper(hwc_report); hwc_report->set_version(hwc_version); } catch (...) { force_backup_display = true; } if (force_backup_display || hwc_version == mga::HwcVersion::hwc10) { fb_native = res_factory->create_fb_native_device(); //guarantee always 2 fb's allocated num_framebuffers = std::max(2u, static_cast(fb_native->numFramebuffers)); } command_stream_sync_factory = create_command_stream_sync_factory(); buffer_allocator = std::make_shared( command_stream_sync_factory, quirks); } std::unique_ptr mga::HalComponentFactory::create_command_stream_sync() { return command_stream_sync_factory->create_command_stream_sync(); } std::unique_ptr mga::HalComponentFactory::create_command_stream_sync_factory() { if ((hwc_version == mga::HwcVersion::hwc10) || !working_egl_sync) return std::make_unique(); try { return std::make_unique(); } catch (std::runtime_error&) { return std::make_unique(); } } std::unique_ptr mga::HalComponentFactory::create_framebuffers(mg::DisplayConfigurationOutput const& config) { return std::unique_ptr(new mga::Framebuffers( *buffer_allocator, config.modes[config.current_mode_index].size, config.current_format, num_framebuffers)); } std::unique_ptr mga::HalComponentFactory::create_layer_list() { geom::Displacement offset{0,0}; if (force_backup_display) return std::unique_ptr( new mga::LayerList(std::make_shared(), {}, offset)); switch (hwc_version) { case mga::HwcVersion::hwc10: return std::unique_ptr( new mga::LayerList(std::make_shared(), {}, offset)); case mga::HwcVersion::hwc11: case mga::HwcVersion::hwc12: return std::unique_ptr( new mga::LayerList(std::make_shared(), {}, offset)); case mga::HwcVersion::hwc13: case mga::HwcVersion::hwc14: case mga::HwcVersion::hwc15: return std::unique_ptr( new mga::LayerList(std::make_shared(), {}, offset)); case mga::HwcVersion::unknown: default: BOOST_THROW_EXCEPTION(std::runtime_error("unknown or unsupported hwc version")); } } std::unique_ptr mga::HalComponentFactory::create_display_device() { if (force_backup_display) { hwc_report->report_legacy_fb_module(); return std::unique_ptr{new mga::FBDevice(fb_native)}; } else { hwc_report->report_hwc_version(hwc_version); switch (hwc_version) { case mga::HwcVersion::hwc10: return std::unique_ptr{ new mga::HwcFbDevice(hwc_wrapper, fb_native)}; case mga::HwcVersion::hwc11: case mga::HwcVersion::hwc12: case mga::HwcVersion::hwc13: case mga::HwcVersion::hwc14: case mga::HwcVersion::hwc15: return std::unique_ptr( new mga::HwcDevice(hwc_wrapper)); case mga::HwcVersion::unknown: default: BOOST_THROW_EXCEPTION(std::runtime_error("unknown or unsupported hwc version")); } } } std::unique_ptr mga::HalComponentFactory::create_hwc_configuration() { if (force_backup_display) return std::unique_ptr(new mga::FbControl(fb_native)); else if (hwc_version == mga::HwcVersion::hwc10) return std::unique_ptr(new mga::HwcBlankingControl(hwc_wrapper, mga::to_mir_format(fb_native->format))); else if (hwc_version < mga::HwcVersion::hwc14) return std::unique_ptr(new mga::HwcBlankingControl(hwc_wrapper)); else return std::unique_ptr(new mga::HwcPowerModeControl(hwc_wrapper)); } std::shared_ptr mga::HalComponentFactory::the_buffer_allocator() { return buffer_allocator; } ./src/platforms/android/server/virtual_output.cpp0000644000004100000410000000234013115234416022600 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alberto Aguirre */ #include "virtual_output.h" namespace mga=mir::graphics::android; mga::VirtualOutput::VirtualOutput(std::function enable_virtual_output, std::function disable_virtual_output) : enable_virtual_output{enable_virtual_output}, disable_virtual_output{disable_virtual_output} { } mga::VirtualOutput::~VirtualOutput() { disable(); } void mga::VirtualOutput::enable() { enable_virtual_output(); } void mga::VirtualOutput::disable() { disable_virtual_output(); } ./src/platforms/android/server/platform.cpp0000644000004100000410000002252513115234664021332 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Alexandros Frantzis */ #include "platform.h" #include "graphic_buffer_allocator.h" #include "resource_factory.h" #include "display.h" #include "hal_component_factory.h" #include "hwc_loggers.h" #include "ipc_operations.h" #include "sync_fence.h" #include "native_buffer.h" #include "native_window_report.h" #include "mir/graphics/platform_ipc_package.h" #include "mir/graphics/buffer_ipc_message.h" #include "mir/graphics/buffer_id.h" #include "mir/graphics/display_report.h" #include "mir/gl/default_program_factory.h" #include "mir/options/option.h" #include "mir/options/configuration.h" #include "mir/abnormal_exit.h" #include "mir/assert_module_entry_point.h" #include "mir/libname.h" #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mf=mir::frontend; namespace mo = mir::options; namespace { char const* const hwc_log_opt = "hwc-report"; char const* const hwc_overlay_opt = "disable-overlays"; char const* const fb_native_window_report_opt = "report-fb-native-window"; std::shared_ptr make_hwc_report(mo::Option const& options) { if (!options.is_set(hwc_log_opt)) return std::make_shared(); auto opt = options.get(hwc_log_opt); if (opt == mo::log_opt_value) return std::make_shared(); else if (opt == mo::off_opt_value) return std::make_shared(); else throw mir::AbnormalExit( std::string("Invalid hwc-report option: " + opt + " (valid options are: \"" + mo::off_opt_value + "\" and \"" + mo::log_opt_value + "\")")); } std::shared_ptr make_native_window_report( mo::Option const& options, std::shared_ptr const& logger) { if (options.is_set(fb_native_window_report_opt) && options.get(fb_native_window_report_opt) == mo::log_opt_value) return std::make_shared(logger); else return std::make_shared(); } mga::OverlayOptimization should_use_overlay_optimization(mo::Option const& options) { if (!options.is_set(hwc_overlay_opt)) return mga::OverlayOptimization::enabled; if (options.get(hwc_overlay_opt)) return mga::OverlayOptimization::disabled; else return mga::OverlayOptimization::enabled; } } mga::Platform::Platform( std::shared_ptr const& buffer_allocator, std::shared_ptr const& display_buffer_builder, std::shared_ptr const& display_report, std::shared_ptr const& native_window_report, mga::OverlayOptimization overlay_option, std::shared_ptr const& quirks) : buffer_allocator(buffer_allocator), display_buffer_builder(display_buffer_builder), display_report(display_report), quirks(quirks), native_window_report(native_window_report), overlay_option(overlay_option) { } mir::UniqueModulePtr mga::Platform::create_buffer_allocator() { struct WrappingGraphicsBufferAllocator : mg::GraphicBufferAllocator { WrappingGraphicsBufferAllocator( std::shared_ptr const& allocator) : allocator(allocator) { } std::shared_ptr alloc_buffer( mg::BufferProperties const& buffer_properties) override { return allocator->alloc_buffer(buffer_properties); } std::vector supported_pixel_formats() override { return allocator->supported_pixel_formats(); } std::shared_ptr alloc_buffer( mir::geometry::Size size, uint32_t format, uint32_t flags) override { return allocator->alloc_buffer(size, format, flags); } std::shared_ptr alloc_software_buffer(mir::geometry::Size size, MirPixelFormat format) override { return allocator->alloc_software_buffer(size, format); } std::shared_ptr const allocator; }; return make_module_ptr(buffer_allocator); } mir::UniqueModulePtr mga::Platform::create_display( std::shared_ptr const&, std::shared_ptr const& gl_config) { auto const program_factory = std::make_shared(); return mir::make_module_ptr( display_buffer_builder, program_factory, gl_config, display_report, native_window_report, overlay_option); } mir::UniqueModulePtr mga::Platform::make_ipc_operations() const { return mir::make_module_ptr(); } mir::UniqueModulePtr create_host_platform( std::shared_ptr const& options, std::shared_ptr const&, std::shared_ptr const& display_report, std::shared_ptr const& logger) { mir::assert_entry_point_signature(&create_host_platform); auto quirks = std::make_shared(mga::PropertiesOps{}, *options); auto hwc_report = make_hwc_report(*options); auto overlay_option = should_use_overlay_optimization(*options); hwc_report->report_overlay_optimization(overlay_option); auto display_resource_factory = std::make_shared(); auto component_factory = std::make_shared( display_resource_factory, hwc_report, quirks); return mir::make_module_ptr( component_factory->the_buffer_allocator(), component_factory, display_report, make_native_window_report(*options, logger), overlay_option, quirks); } mir::UniqueModulePtr create_guest_platform( std::shared_ptr const& display_report, std::shared_ptr const&) { mir::assert_entry_point_signature(&create_guest_platform); //TODO: actually allow disabling quirks for guest platform auto quirks = std::make_shared(mga::PropertiesOps{}); std::shared_ptr sync_factory; if (quirks->working_egl_sync()) sync_factory = std::make_shared(); else sync_factory = std::make_shared(); //TODO: remove nullptr parameter once platform classes are sorted. // mg::NativePlatform cannot create a display anyways, so it doesnt need a display builder auto const buffer_allocator = std::make_shared(sync_factory, quirks); return mir::make_module_ptr( buffer_allocator, nullptr, display_report, std::make_shared(), mga::OverlayOptimization::disabled, quirks); } void add_graphics_platform_options( boost::program_options::options_description& config) { mir::assert_entry_point_signature(&add_graphics_platform_options); config.add_options() (hwc_log_opt, boost::program_options::value()->default_value(std::string{mo::off_opt_value}), "[platform-specific] How to handle the HWC logging report. [{log,off}]") (fb_native_window_report_opt, boost::program_options::value()->default_value(std::string{mo::off_opt_value}), "[platform-specific] whether to log the EGLNativeWindowType backed by the framebuffer [{log,off}]") (hwc_overlay_opt, boost::program_options::value()->default_value(false), "[platform-specific] Whether to disable overlay optimizations [{on,off}]"); mga::DeviceQuirks::add_options(config); } mg::PlatformPriority probe_graphics_platform(mo::ProgramOption const& /*options*/) { mir::assert_entry_point_signature(&probe_graphics_platform); int err; hw_module_t const* hw_module; err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &hw_module); return err < 0 ? mg::PlatformPriority::unsupported : mg::PlatformPriority::best; } namespace { mir::ModuleProperties const description = { "mir:android", MIR_VERSION_MAJOR, MIR_VERSION_MINOR, MIR_VERSION_MICRO, mir::libname() }; } mir::ModuleProperties const* describe_graphics_module() { mir::assert_entry_point_signature(&describe_graphics_module); return &description; } ./src/platforms/android/server/server_render_window.cpp0000644000004100000410000000741113115234664023737 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #include "mir/graphics/buffer.h" #include "sync_fence.h" #include "android_format_conversion-inl.h" #include "server_render_window.h" #include "framebuffer_bundle.h" #include "buffer.h" #include "interpreter_resource_cache.h" #include #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace geom=mir::geometry; mga::ServerRenderWindow::ServerRenderWindow( std::shared_ptr const& fb_bundle, MirPixelFormat format, std::shared_ptr const& cache, DeviceQuirks& quirks) : fb_bundle(fb_bundle), resource_cache(cache), format(mga::to_android_format(format)), clear_fence(quirks.clear_fb_context_fence()) { } mga::NativeBuffer* mga::ServerRenderWindow::driver_requests_buffer() { auto buffer = fb_bundle->buffer_for_render(); auto handle = mga::to_native_buffer_checked(buffer->native_buffer_handle()); resource_cache->store_buffer(buffer, handle); return handle.get(); } void mga::ServerRenderWindow::driver_returns_buffer(ANativeWindowBuffer* buffer, int fence_fd) { //depending on the quirk, some mali drivers won't synchronize the fb context fence before posting. //if this bug is present, we synchronize here to avoid tearing or other artifacts. if (clear_fence) mga::SyncFence(std::make_shared(), mir::Fd(fence_fd)).wait(); else resource_cache->update_native_fence(buffer, fence_fd); resource_cache->retrieve_buffer(buffer); } void mga::ServerRenderWindow::dispatch_driver_request_format(int request_format) { format = request_format; } void mga::ServerRenderWindow::dispatch_driver_request_buffer_size(geometry::Size) { } int mga::ServerRenderWindow::driver_requests_info(int key) const { geom::Size size; switch(key) { case NATIVE_WINDOW_DEFAULT_WIDTH: case NATIVE_WINDOW_WIDTH: size = fb_bundle->fb_size(); return size.width.as_uint32_t(); case NATIVE_WINDOW_DEFAULT_HEIGHT: case NATIVE_WINDOW_HEIGHT: size = fb_bundle->fb_size(); return size.height.as_uint32_t(); case NATIVE_WINDOW_FORMAT: return format; case NATIVE_WINDOW_TRANSFORM_HINT: return 0; case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: return 1; case NATIVE_WINDOW_CONCRETE_TYPE: return NATIVE_WINDOW_FRAMEBUFFER; case NATIVE_WINDOW_CONSUMER_USAGE_BITS: return GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB; default: { std::stringstream sstream; sstream << "driver requests info we dont provide. key: " << key; BOOST_THROW_EXCEPTION(std::runtime_error(sstream.str())); } } } void mga::ServerRenderWindow::sync_to_display(bool) { } void mga::ServerRenderWindow::dispatch_driver_request_buffer_count(unsigned int) { //note: Haven't seen a good reason to honor this request for a fb context } ./src/platforms/android/server/ipc_operations.h0000644000004100000410000000260013115234416022154 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_IPC_OPERATIONS_H_ #define MIR_GRAPHICS_ANDROID_IPC_OPERATIONS_H_ #include "mir/graphics/platform_ipc_operations.h" namespace mir { namespace graphics { namespace android { class IpcOperations : public PlatformIpcOperations { public: void pack_buffer(BufferIpcMessage&, Buffer const&, BufferIpcMsgType) const override; void unpack_buffer(BufferIpcMessage&, Buffer const&) const override; std::shared_ptr connection_ipc_package() override; PlatformOperationMessage platform_operation( unsigned int const opcode, PlatformOperationMessage const& message) override; }; } } } #endif /* MIR_GRAPHICS_ANDROID_IPC_OPERATIONS_H_ */ ./src/platforms/android/server/display_configuration.cpp0000644000004100000410000001252213115234664024076 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "display_configuration.h" #include namespace mg = mir::graphics; namespace mga = mg::android; namespace geom = mir::geometry; namespace { enum DisplayIds { primary_id, external_id, virtual_id, max_displays }; mg::DisplayConfigurationOutput make_virtual_config() { auto const name = mga::DisplayName::virt; double const vrefresh_hz{60.0}; geom::Size const mm_size{660, 370}; auto const display_format = mir_pixel_format_argb_8888; geom::Point const origin{0,0}; auto const external_mode = mir_power_mode_off; size_t const preferred_format_index{0}; size_t const preferred_mode_index{0}; bool const connected{false}; auto const type = mg::DisplayConfigurationOutputType::virt; auto const form_factor = mir_form_factor_monitor; float const scale{1.0f}; auto const subpixel_arrangement = mir_subpixel_arrangement_unknown; std::vector external_modes; external_modes.emplace_back(mg::DisplayConfigurationMode{{1920,1080}, vrefresh_hz}); return { as_output_id(name), mg::DisplayConfigurationCardId{0}, type, {display_format}, external_modes, preferred_mode_index, mm_size, connected, connected, origin, preferred_format_index, display_format, external_mode, mir_orientation_normal, scale, form_factor, subpixel_arrangement, {}, mir_output_gamma_unsupported, {} }; } } mga::DisplayConfiguration::DisplayConfiguration( mg::DisplayConfigurationOutput primary_config, MirPowerMode primary_mode, mg::DisplayConfigurationOutput external_config, MirPowerMode external_mode) : DisplayConfiguration(primary_config, primary_mode, external_config, external_mode, make_virtual_config()) { } mga::DisplayConfiguration::DisplayConfiguration( mg::DisplayConfigurationOutput primary_config, MirPowerMode primary_mode, mg::DisplayConfigurationOutput external_config, MirPowerMode external_mode, mg::DisplayConfigurationOutput virt_config) : configurations{ {std::move(primary_config), std::move(external_config), std::move(virt_config)} }, card{mg::DisplayConfigurationCardId{0}, max_displays} { primary().power_mode = primary_mode; external().power_mode = external_mode; } mga::DisplayConfiguration::DisplayConfiguration(DisplayConfiguration const& other) : mg::DisplayConfiguration(), configurations(other.configurations), card(other.card) { } mga::DisplayConfiguration& mga::DisplayConfiguration::operator=(DisplayConfiguration const& other) { if (&other != this) { configurations = other.configurations; card = other.card; } return *this; } void mga::DisplayConfiguration::for_each_card(std::function f) const { f(card); } void mga::DisplayConfiguration::for_each_output(std::function f) const { for (auto const& configuration : configurations) f(configuration); } void mga::DisplayConfiguration::for_each_output(std::function f) { for (auto& configuration : configurations) { mg::UserDisplayConfigurationOutput user(configuration); f(user); } } std::unique_ptr mga::DisplayConfiguration::clone() const { return std::make_unique(*this); } mg::DisplayConfigurationOutput& mga::DisplayConfiguration::primary() { return configurations[primary_id]; } mg::DisplayConfigurationOutput& mga::DisplayConfiguration::external() { return configurations[external_id]; } mg::DisplayConfigurationOutput& mga::DisplayConfiguration::virt() { return configurations[virtual_id]; } mg::DisplayConfigurationOutput& mga::DisplayConfiguration::operator[](mg::DisplayConfigurationOutputId const& disp_id) { auto id = disp_id.as_value() - 1; if (id != primary_id && id != external_id && id != virtual_id) BOOST_THROW_EXCEPTION(std::invalid_argument("invalid display id")); return configurations[id]; } void mga::DisplayConfiguration::set_virtual_output_to(int width, int height) { auto& virt_config = virt(); virt_config.connected = true; virt_config.used = true; virt_config.power_mode = mir_power_mode_on; virt_config.modes[0].size = {width, height}; } void mga::DisplayConfiguration::disable_virtual_output() { auto& virt_config = virt(); virt_config.connected = false; virt_config.used = false; virt_config.power_mode = mir_power_mode_off; } ./src/platforms/android/server/display_device.h0000644000004100000410000000451413115234416022130 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_DISPLAY_SUPPORT_PROVIDER_H_ #define MIR_GRAPHICS_ANDROID_DISPLAY_SUPPORT_PROVIDER_H_ #include "mir/geometry/displacement.h" #include "mir/graphics/renderable.h" #include "mir_toolkit/common.h" #include "display_name.h" #include #include #include namespace mir { namespace graphics { class Buffer; class Renderable; namespace android { class RenderableListCompositor; class SwappingGLContext; class LayerList; struct DisplayContents { DisplayName name; LayerList& list; geometry::Displacement list_offset; SwappingGLContext& context; RenderableListCompositor& compositor; }; class DisplayDevice { public: virtual ~DisplayDevice() = default; /* \returns true if the DisplayDevice can support the renderlist false if the display device cannot support drawing the given renderlist. */ virtual bool compatible_renderlist(RenderableList const& renderlist) = 0; /* post the layer list to the display, optionally drawing using the context/compositor if * instructed to by the driver */ virtual void commit(std::list const& contents) = 0; //notify the DisplayDevice that the screen content was cleared in a way other than the above fns virtual void content_cleared() = 0; virtual std::chrono::milliseconds recommended_sleep() const = 0; virtual bool can_swap_buffers() const = 0; protected: DisplayDevice() = default; DisplayDevice& operator=(DisplayDevice const&) = delete; DisplayDevice(DisplayDevice const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DISPLAY_SUPPORT_PROVIDER_H_ */ ./src/platforms/android/server/framebuffer_bundle.h0000644000004100000410000000266213115234416022763 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_FRAMEBUFFER_BUNDLE_H_ #define MIR_GRAPHICS_ANDROID_FRAMEBUFFER_BUNDLE_H_ #include "mir_toolkit/common.h" #include "mir/geometry/size.h" #include namespace mir { namespace graphics { class Buffer; namespace android { class FramebufferBundle{ public: virtual ~FramebufferBundle() = default; virtual geometry::Size fb_size() = 0; virtual std::shared_ptr buffer_for_render() = 0; virtual std::shared_ptr last_rendered_buffer() = 0; protected: FramebufferBundle() = default; FramebufferBundle(FramebufferBundle const&) = delete; FramebufferBundle& operator=(FramebufferBundle const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_FRAMEBUFFER_BUNDLE_H_ */ ./src/platforms/android/server/display_device_exceptions.h0000644000004100000410000000246013115234416024367 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alberto Aguirre */ #ifndef MIR_GRAPHICS_ANDROID_DISPLAY_DEVICE_EXCEPTIONS_H_ #define MIR_GRAPHICS_ANDROID_DISPLAY_DEVICE_EXCEPTIONS_H_ #include #include namespace mir { namespace graphics { namespace android { class DisplayDisconnectedException : public std::runtime_error { public: DisplayDisconnectedException(std::string const& message) : std::runtime_error(message) {} }; class ExternalDisplayError : public std::runtime_error { public: ExternalDisplayError(std::string const& message) : std::runtime_error(message) {} }; } } } #endif /* MIR_GRAPHICS_ANDROID_DISPLAY_DEVICE_EXCEPTIONS_H_ */ ./src/platforms/android/server/hwc_layerlist.cpp0000644000004100000410000001474013115234416022352 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/graphics/renderable.h" #include "mir/graphics/buffer.h" #include "sync_fence.h" #include "native_buffer.h" #include "hwc_layerlist.h" #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace geom=mir::geometry; namespace { std::shared_ptr generate_hwc_list(size_t needed_size) { /* hwc layer list uses hwLayers[0] at the end of the struct */ auto struct_size = sizeof(hwc_display_contents_1_t) + sizeof(hwc_layer_1_t)*(needed_size); auto new_hwc_representation = std::shared_ptr( static_cast( ::operator new(struct_size))); new_hwc_representation->numHwLayers = needed_size; new_hwc_representation->retireFenceFd = -1; new_hwc_representation->flags = HWC_GEOMETRY_CHANGED; //aosp exynos hwc in particular, checks that these fields are non-null in hwc1.1, although //these fields are deprecated in hwc1.1 and later. static int fake_egl_values = 0; new_hwc_representation->dpy = &fake_egl_values; new_hwc_representation->sur = &fake_egl_values; return new_hwc_representation; } } mga::HwcLayerEntry::HwcLayerEntry(HWCLayer && layer, bool needs_commit) : layer(std::move(layer)), needs_commit{needs_commit} { } size_t mga::LayerList::additional_layers_for(mga::LayerList::Mode mode) { switch (mode) { case Mode::skip_and_target: return 2; case Mode::skip_only: case Mode::target_only: return 1; default: case Mode::no_extra_layers: return 0; } } void mga::LayerList::update_list_mode(mg::RenderableList const& renderlist) { if (renderlist.empty() && layer_adapter->needs_fb_target()) mode = Mode::skip_and_target; else if (!renderlist.empty() && layer_adapter->needs_fb_target()) mode = Mode::target_only; else if (renderlist.empty() && !layer_adapter->needs_fb_target()) mode = Mode::skip_only; else mode = Mode::no_extra_layers; } void mga::LayerList::update_list(RenderableList const& renderlist, geometry::Displacement offset) { renderable_list = renderlist; update_list_mode(renderlist); size_t additional_layers = additional_layers_for(mode); size_t needed_size = renderlist.size() + additional_layers; if ((!hwc_representation) || hwc_representation->numHwLayers != needed_size) { hwc_representation = generate_hwc_list(needed_size); } if (layers.size() == needed_size) { auto it = layers.begin(); for(auto renderable : renderlist) { auto position = renderable->screen_position(); position.top_left = position.top_left - offset; it->needs_commit = it->layer.setup_layer( mga::LayerType::gl_rendered, position, renderable->shaped(), // TODO: support alpha() in future too renderable->buffer()); it++; } } else { std::list new_layers; auto i = 0u; for(auto const& renderable : renderlist) { auto position = renderable->screen_position(); position.top_left = position.top_left - offset; new_layers.emplace_back( mga::HWCLayer( layer_adapter, hwc_representation, i++, mga::LayerType::gl_rendered, position, renderable->shaped(), // TODO: support alpha() in future renderable->buffer()), true); } for(; i < needed_size; i++) { new_layers.emplace_back(mga::HWCLayer(layer_adapter, hwc_representation, i), false); } layers = std::move(new_layers); } } std::list::iterator mga::LayerList::begin() { return layers.begin(); } std::list::iterator mga::LayerList::end() { return layers.end(); } hwc_display_contents_1_t* mga::LayerList::native_list() { return hwc_representation.get(); } mga::NativeFence mga::LayerList::retirement_fence() { renderable_list.clear(); return hwc_representation->retireFenceFd; } mga::LayerList::LayerList( std::shared_ptr const& layer_adapter, RenderableList const& renderlist, geometry::Displacement list_offset) : layer_adapter{layer_adapter} { update_list(renderlist, list_offset); } bool mga::LayerList::needs_swapbuffers() { bool any_rendered = false; for (auto const& layer : layers) any_rendered |= layer.layer.needs_gl_render(); return any_rendered; } mg::RenderableList mga::LayerList::rejected_renderables() { mg::RenderableList rejected_renderables; auto it = layers.begin(); for (auto const& renderable : renderable_list) { if (it->layer.needs_gl_render()) rejected_renderables.push_back(renderable); it++; } return rejected_renderables; } void mga::LayerList::setup_fb(std::shared_ptr const& fb) { geom::Rectangle const disp_frame{{0,0}, {fb->size()}}; auto it = layers.begin(); std::advance(it, renderable_list.size()); if (mode == Mode::skip_only) { it->layer.setup_layer(mga::LayerType::skip, disp_frame, false, fb); } else if (mode == Mode::target_only) { it->layer.setup_layer(mga::LayerType::framebuffer_target, disp_frame, false, fb); } else if (mode == Mode::skip_and_target) { it++->layer.setup_layer(mga::LayerType::skip, disp_frame, false, fb); it->layer.setup_layer(mga::LayerType::framebuffer_target, disp_frame, false, fb); } } void mga::LayerList::swap_occurred() { if ((mode == Mode::target_only) || (mode == Mode::skip_and_target)) layers.back().layer.set_acquirefence(); } ./src/platforms/android/server/display.cpp0000644000004100000410000003525413115234664021156 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/graphics/platform.h" #include "mir/graphics/frame.h" #include "display_configuration.h" #include "mir/graphics/display_report.h" #include "mir/graphics/display_buffer.h" #include "mir/graphics/egl_resources.h" #include "display.h" #include "virtual_output.h" #include "display_component_factory.h" #include "interpreter_cache.h" #include "server_render_window.h" #include "display_buffer.h" #include "hwc_layerlist.h" #include "mir_native_window.h" #include "mir/geometry/rectangle.h" #include "mir/graphics/event_handler_register.h" #include "mir/gl/program_factory.h" #include "mir/fd.h" #include #include #include #include "mir/geometry/dimensions.h" namespace mga=mir::graphics::android; namespace mgl=mir::gl; namespace mg=mir::graphics; namespace geom=mir::geometry; struct mga::DisplayChangePipe { DisplayChangePipe() { int pipes_raw[2] {-1, -1}; if (::pipe2(pipes_raw, O_CLOEXEC | O_NONBLOCK)) BOOST_THROW_EXCEPTION(std::runtime_error("failed to create display change pipe")); read_pipe = mir::Fd{pipes_raw[0]}; write_pipe = mir::Fd{pipes_raw[1]}; } void notify_change() { if (::write(write_pipe, &data, sizeof(data)) == -1) BOOST_THROW_EXCEPTION(std::runtime_error("failed to write to display change pipe")); } void ack_change() { char tmp{'b'}; if (::read(read_pipe, &tmp, sizeof(tmp)) == -1) BOOST_THROW_EXCEPTION(std::runtime_error("failed to read from display change pipe")); } mir::Fd read_pipe; mir::Fd write_pipe; char const data{'a'}; }; namespace { void power_mode( mga::DisplayName name, mga::HwcConfiguration& control, mg::DisplayConfigurationOutput& config, MirPowerMode intended_mode) { if (config.power_mode != intended_mode) { control.power_mode(name, intended_mode); config.power_mode = intended_mode; } } void power_mode_safe( mga::DisplayName name, mga::HwcConfiguration& control, mg::DisplayConfigurationOutput& config, MirPowerMode intended_mode) noexcept try { power_mode(name, control, config, intended_mode); } catch (...) {} void set_powermode_all_displays( mga::HwcConfiguration& control, mga::DisplayConfiguration& config, MirPowerMode intended_mode) noexcept { power_mode_safe(mga::DisplayName::primary, control, config.primary(), intended_mode); if (config.external().connected) power_mode_safe(mga::DisplayName::external, control, config.external(), intended_mode); } std::unique_ptr create_display_buffer( std::shared_ptr const& display_device, mga::DisplayName name, mga::DisplayComponentFactory& display_buffer_builder, mg::DisplayConfigurationOutput const& config, std::shared_ptr const& gl_program_factory, mga::PbufferGLContext const& gl_context, geom::Displacement displacement, std::shared_ptr const& report, mga::OverlayOptimization overlay_option) { std::shared_ptr fbs{display_buffer_builder.create_framebuffers(config)}; auto cache = std::make_shared(); mga::DeviceQuirks quirks(mga::PropertiesOps{}, gl_context); auto interpreter = std::make_shared(fbs, config.current_format, cache, quirks); auto native_window = std::make_shared(interpreter, report); return std::unique_ptr(new mga::DisplayBuffer( name, display_buffer_builder.create_layer_list(), fbs, display_device, native_window, gl_context, *gl_program_factory, config.orientation, displacement, overlay_option)); } } mga::Display::Display( std::shared_ptr const& display_buffer_builder, std::shared_ptr const& gl_program_factory, std::shared_ptr const& gl_config, std::shared_ptr const& display_report, std::shared_ptr const& native_window_report, mga::OverlayOptimization overlay_option) : display_report{display_report}, native_window_report{native_window_report}, display_buffer_builder{display_buffer_builder}, hwc_config{display_buffer_builder->create_hwc_configuration()}, hotplug_subscription{hwc_config->subscribe_to_config_changes( std::bind(&mga::Display::on_hotplug, this), std::bind(&mga::Display::on_vsync, this, std::placeholders::_1, std::placeholders::_2))}, config( hwc_config->active_config_for(mga::DisplayName::primary), mir_power_mode_off, hwc_config->active_config_for(mga::DisplayName::external), mir_power_mode_off), gl_context{config.primary().current_format, *gl_config, *display_report}, display_device(display_buffer_builder->create_display_device()), display_change_pipe(new DisplayChangePipe), gl_program_factory(gl_program_factory), displays( display_device, create_display_buffer( display_device, mga::DisplayName::primary, *display_buffer_builder, config.primary(), gl_program_factory, gl_context, geom::Displacement{0,0}, native_window_report, overlay_option), [this] { on_hotplug(); }), //Recover from exception by forcing a configuration change overlay_option(overlay_option) { //Some drivers (depending on kernel state) incorrectly report an error code indicating that the display is already on. Ignore the first failure. set_powermode_all_displays(*hwc_config, config, mir_power_mode_on); if (config.external().connected) { displays.add(mga::DisplayName::external, create_display_buffer( display_device, mga::DisplayName::external, *display_buffer_builder, config.external(), gl_program_factory, gl_context, geom::Displacement{0,0}, native_window_report, overlay_option)); } display_report->report_successful_setup_of_native_resources(); gl_context.make_current(); display_report->report_successful_egl_make_current_on_construction(); display_report->report_successful_display_construction(); } mga::Display::~Display() noexcept { set_powermode_all_displays(*hwc_config, config, mir_power_mode_off); } void mga::Display::update_configuration(std::lock_guard const&) const { if (configuration_dirty) { auto external_config = hwc_config->active_config_for(mga::DisplayName::external); if (external_config.connected) power_mode(mga::DisplayName::external, *hwc_config, config.external(), mir_power_mode_on); else config.external().power_mode = mir_power_mode_off; config = mga::DisplayConfiguration( hwc_config->active_config_for(mga::DisplayName::primary), config.primary().power_mode, std::move(external_config), config.external().power_mode, config.virt()); configuration_dirty = false; } } void mga::Display::for_each_display_sync_group(std::function const& f) { std::lock_guard lock{configuration_mutex}; f(displays); } std::unique_ptr mga::Display::configuration() const { std::lock_guard lock{configuration_mutex}; update_configuration(lock); return std::unique_ptr(new mga::DisplayConfiguration(config)); } void mga::Display::configure(mg::DisplayConfiguration const& new_configuration) { std::lock_guard lock{configuration_mutex}; configure_locked(new_configuration, lock); } //NOTE: We avoid calling back to hwc from within the hotplug callback. Only arrange for an update. void mga::Display::on_hotplug() { std::lock_guard lock{configuration_mutex}; configuration_dirty = true; display_change_pipe->notify_change(); } void mga::Display::on_vsync(DisplayName name, mg::Frame::Timestamp timestamp) { std::lock_guard lock{vsync_mutex}; /* * XXX It's presently useful but idealistically inefficient that we * get a callback on every frame, even when the compositor is idle. * (LP: #1374318) * Although we possibly shouldn't fix that at all because the * call to increment_with_timestamp would produce incorrect MSC values * if it were to miss a physical frame. The X11 platform has that * problem already, but it's less important for production use than * Android. */ auto& f = last_frame[as_output_id(name).as_value()]; f.increment_with_timestamp(timestamp); display_report->report_vsync(as_output_id(name).as_value(), f.load()); } mg::Frame mga::Display::last_frame_on(unsigned output_id) const { std::lock_guard lock{vsync_mutex}; auto last = last_frame.find(output_id); if (last == last_frame.end()) return {}; // Not an error. It might be a valid output_id pre-vsync else return last->second.load(); } void mga::Display::register_configuration_change_handler( EventHandlerRegister& event_handler, DisplayConfigurationChangeHandler const& change_handler) { event_handler.register_fd_handler({display_change_pipe->read_pipe}, this, make_module_ptr>( [change_handler, this](int) { change_handler(); display_change_pipe->ack_change(); })); } void mga::Display::register_pause_resume_handlers( EventHandlerRegister& /*handlers*/, DisplayPauseHandler const& /*pause_handler*/, DisplayResumeHandler const& /*resume_handler*/) { } void mga::Display::pause() { } void mga::Display::resume() { } auto mga::Display::create_hardware_cursor(std::shared_ptr const& /* initial_image */) -> std::shared_ptr { return nullptr; } std::unique_ptr mga::Display::create_virtual_output(int width, int height) { auto enable_virtual_output = [this, width, height] { config.set_virtual_output_to(width, height); on_hotplug(); }; auto disable_virtual_output = [this] { config.disable_virtual_output(); on_hotplug(); }; return {std::make_unique(enable_virtual_output, disable_virtual_output)}; } mg::NativeDisplay* mga::Display::native_display() { return this; } std::unique_ptr mga::Display::create_gl_context() { return std::make_unique(gl_context); } bool mga::Display::apply_if_configuration_preserves_display_buffers( mg::DisplayConfiguration const& conf) { /* * We never invalidate display buffers based on the configuration to apply. * * The only way we invalidate a display buffer is if we detect that a previously-connected * external display has been removed. In that case, regardless of whether or not it's enabled * in the configuration, we destroy the display. * * Take the configuration lock to ensure consistency between our checking for external * connections and configure's checking. */ std::lock_guard lock{configuration_mutex}; if (!config.external().connected || displays.display_present(mga::DisplayName::external)) { configure_locked(conf, lock); return true; } return false; } void mga::Display::configure_locked( mir::graphics::DisplayConfiguration const& new_configuration, std::lock_guard const&) { using namespace geometry; if (!new_configuration.valid()) BOOST_THROW_EXCEPTION(std::logic_error("Invalid or inconsistent display configuration")); if ((config.external().connected) && !displays.display_present(mga::DisplayName::external)) displays.add( mga::DisplayName::external, create_display_buffer( display_device, mga::DisplayName::external, *display_buffer_builder, config.external(), gl_program_factory, gl_context, config.external().top_left - origin, native_window_report, overlay_option)); if ((!config.external().connected) && displays.display_present(mga::DisplayName::external)) displays.remove(mga::DisplayName::external); new_configuration.for_each_output( [this](mg::DisplayConfigurationOutput const& output) { if (output.current_format != config[output.id].current_format) BOOST_THROW_EXCEPTION(std::logic_error("could not change display buffer format")); config[output.id].orientation = output.orientation; config[output.id].form_factor = output.form_factor; config[output.id].scale = output.scale; geom::Displacement offset(output.top_left - origin); config[output.id].top_left = output.top_left; if (config.primary().id == output.id) { power_mode(mga::DisplayName::primary, *hwc_config, config.primary(), output.power_mode); displays.configure(mga::DisplayName::primary, output.power_mode, output.orientation, offset); } else if (config.external().id == output.id && config.external().connected) { power_mode(mga::DisplayName::external, *hwc_config, config.external(), output.power_mode); displays.configure(mga::DisplayName::external, output.power_mode, output.orientation, offset); } }); } ./src/platforms/android/server/display.h0000644000004100000410000001061713115234664020617 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_DISPLAY_H_ #define MIR_GRAPHICS_ANDROID_DISPLAY_H_ #include "mir/graphics/display.h" #include "mir/graphics/frame.h" #include "mir/graphics/atomic_frame.h" #include "mir/renderer/gl/context_source.h" #include "gl_context.h" #include "display_group.h" #include "hwc_configuration.h" #include "display_configuration.h" #include "overlay_optimization.h" #include #include #include #include namespace mir { namespace gl { class ProgramFactory; } namespace graphics { class DisplayReport; class GLConfig; namespace android { class DisplayComponentFactory; class DisplaySupportProvider; class ConfigurableDisplayBuffer; class DisplayChangePipe; class DisplayDevice; class NativeWindowReport; class Display : public graphics::Display, public graphics::NativeDisplay, public renderer::gl::ContextSource { public: explicit Display( std::shared_ptr const& display_buffer_builder, std::shared_ptr const& gl_program_factory, std::shared_ptr const& gl_config, std::shared_ptr const& display_report, std::shared_ptr const& native_window_report, OverlayOptimization overlay_option); ~Display() noexcept; void for_each_display_sync_group(std::function const& f) override; std::unique_ptr configuration() const override; bool apply_if_configuration_preserves_display_buffers(graphics::DisplayConfiguration const& conf) override; void configure(graphics::DisplayConfiguration const&) override; void register_configuration_change_handler( EventHandlerRegister& handlers, DisplayConfigurationChangeHandler const& conf_change_handler) override; void register_pause_resume_handlers( EventHandlerRegister& handlers, DisplayPauseHandler const& pause_handler, DisplayResumeHandler const& resume_handler) override; void pause() override; void resume() override; std::shared_ptr create_hardware_cursor(std::shared_ptr const& initial_image) override; std::unique_ptr create_virtual_output(int width, int height) override; NativeDisplay* native_display() override; std::unique_ptr create_gl_context() override; Frame last_frame_on(unsigned output_id) const override; private: void on_hotplug(); void on_vsync(DisplayName, graphics::Frame::Timestamp); geometry::Point const origin{0,0}; std::shared_ptr const display_report; std::shared_ptr const native_window_report; std::shared_ptr const display_buffer_builder; std::mutex mutable configuration_mutex; bool mutable configuration_dirty{false}; std::unique_ptr const hwc_config; ConfigChangeSubscription const hotplug_subscription; DisplayConfiguration mutable config; PbufferGLContext gl_context; std::shared_ptr display_device; std::unique_ptr display_change_pipe; std::shared_ptr const gl_program_factory; DisplayGroup mutable displays; OverlayOptimization const overlay_option; void update_configuration(std::lock_guard const&) const; void configure_locked( graphics::DisplayConfiguration const& new_configuration, std::lock_guard const&); std::mutex mutable vsync_mutex; std::unordered_map last_frame; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DISPLAY_H_ */ ./src/platforms/android/server/hwc_fallback_gl_renderer.cpp0000644000004100000410000001151513115234664024453 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/gl/program_factory.h" #include "mir/gl/texture.h" #include "mir/gl/tessellation_helpers.h" #include "mir/renderer/gl/context.h" #include "hwc_fallback_gl_renderer.h" #include "swapping_gl_context.h" #include "buffer.h" #define GLM_FORCE_RADIANS #define GLM_PRECISION_MEDIUMP_FLOAT #include #include #include #include namespace mg = mir::graphics; namespace mgl = mir::gl; namespace mga = mir::graphics::android; namespace geom = mir::geometry; namespace { std::string const vertex_shader { "attribute vec3 position;\n" "attribute vec2 texcoord;\n" "uniform mat4 display_transform;\n" "varying vec2 v_texcoord;\n" "void main() {\n" " gl_Position = display_transform * vec4(position, 1.0);\n" " v_texcoord = texcoord;\n" "}\n" }; std::string const fragment_shader { "precision mediump float;\n" "uniform sampler2D tex;\n" "varying vec2 v_texcoord;\n" "void main() {\n" " gl_FragColor = texture2D(tex, v_texcoord);\n" "}\n" }; void set_display_transform(GLint uniform_loc, geom::Rectangle const& rect) { glm::mat4 disp_transform(1.0); disp_transform = glm::translate(disp_transform, glm::vec3{-1.0, 1.0, 0.0}); disp_transform = glm::scale( disp_transform, glm::vec3{2.0/rect.size.width.as_int(), -2.0/rect.size.height.as_int(), 1.0}); glUniformMatrix4fv(uniform_loc, 1, GL_FALSE, glm::value_ptr(disp_transform)); } } mga::HWCFallbackGLRenderer::HWCFallbackGLRenderer( gl::ProgramFactory const& factory, renderer::gl::Context const& context, geom::Rectangle const& screen_pos) { context.make_current(); program = factory.create_gl_program(vertex_shader, fragment_shader); texture_cache = factory.create_texture_cache(); glUseProgram(*program); auto display_transform_uniform = glGetUniformLocation(*program, "display_transform"); set_display_transform(display_transform_uniform, screen_pos); position_attr = glGetAttribLocation(*program, "position"); texcoord_attr = glGetAttribLocation(*program, "texcoord"); auto tex_loc = glGetUniformLocation(*program, "tex"); glUniform1i(tex_loc, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glUseProgram(0); context.release_current(); } void mga::HWCFallbackGLRenderer::render( RenderableList const& renderlist, geom::Displacement offset, SwappingGLContext const& context) const { glUseProgram(*program); /* NOTE: some HWC implementations rely on the framebuffer target layer * being cleared to transparent black. eg, in mixed-mode composition, * krillin actually arranges the fb_target in the topmost level of its * display controller and relies on blending to make the overlays appear * /under/ the gl layer. (lp: #1378326) */ glClearColor(0.0, 0.0, 0.0, 0.0); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClear(GL_COLOR_BUFFER_BIT); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnableVertexAttribArray(position_attr); glEnableVertexAttribArray(texcoord_attr); for(auto const& renderable : renderlist) { if (renderable->shaped()) // TODO: support alpha() in future glEnable(GL_BLEND); else glDisable(GL_BLEND); auto const primitive = mgl::tessellate_renderable_into_rectangle(*renderable, offset); glVertexAttribPointer(position_attr, 3, GL_FLOAT, GL_FALSE, sizeof(mgl::Vertex), &primitive.vertices[0].position); //TODO: (kdub) scaling or pi/2 rotation eventually. for now, all quads get same texcoords glVertexAttribPointer(texcoord_attr, 2, GL_FLOAT, GL_FALSE, sizeof(mgl::Vertex), &primitive.vertices[0].texcoord); texture_cache->load(*renderable)->bind(); glDrawArrays(primitive.type, 0, primitive.nvertices); } glDisableVertexAttribArray(texcoord_attr); glDisableVertexAttribArray(position_attr); context.swap_buffers(); texture_cache->drop_unused(); glUseProgram(0); } ./src/platforms/android/server/buffer.h0000644000004100000410000000535313115234664020424 0ustar www-datawww-data/* * Copyright © 2012,2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_BUFFER_H_ #define MIR_GRAPHICS_ANDROID_BUFFER_H_ #include "mir/graphics/buffer_basic.h" #include "mir/renderer/gl/texture_source.h" #include "mir/renderer/sw/pixel_source.h" #include #include #include #include #ifndef GL_GLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES #endif #define EGL_EGLEXT_PROTOTYPES #include #include namespace mir { namespace graphics { struct EGLExtensions; namespace android { class NativeBuffer; class Buffer: public BufferBasic, public NativeBufferBase, public renderer::gl::TextureSource, public renderer::software::PixelSource { public: Buffer(gralloc_module_t const* hw_module, std::shared_ptr const& buffer_handle, std::shared_ptr const& extensions); ~Buffer(); geometry::Size size() const override; geometry::Stride stride() const override; MirPixelFormat pixel_format() const override; void gl_bind_to_texture() override; void bind() override; void secure_for_render() override; //note, you will get the native representation of an android buffer, including //the fences associated with the buffer. You must close these fences std::shared_ptr native_buffer_handle() const override; void write(unsigned char const* pixels, size_t size) override; void read(std::function const&) override; NativeBufferBase* native_buffer_base() override; private: void bind(std::unique_lock const&); void secure_for_render(std::unique_lock const&); gralloc_module_t const* hw_module; typedef std::pair DispContextPair; std::map egl_image_map; std::mutex mutable content_lock; std::shared_ptr native_buffer; std::shared_ptr egl_extensions; }; } } } #endif /* MIR_GRAPHICS_ANDROID_BUFFER_H_ */ ./src/platforms/android/server/platform.h0000644000004100000410000000466313115234664021002 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_ANDROID_PLATFORM_H_ #define MIR_GRAPHICS_ANDROID_PLATFORM_H_ #include "mir/graphics/platform.h" #include "device_quirks.h" #include "overlay_optimization.h" namespace mir { namespace graphics { class DisplayReport; namespace android { class GraphicBufferAllocator; class FramebufferFactory; class DisplayComponentFactory; class CommandStreamSyncFactory; class NativeWindowReport; class Platform : public graphics::Platform { public: Platform( std::shared_ptr const& buffer_allocator, std::shared_ptr const& display_buffer_builder, std::shared_ptr const& display_report, std::shared_ptr const& native_window_report, OverlayOptimization overlay_option, std::shared_ptr const& quirks); /* From Platform */ UniqueModulePtr create_buffer_allocator() override; UniqueModulePtr create_display( std::shared_ptr const&, std::shared_ptr const& /*gl_config*/) override; UniqueModulePtr make_ipc_operations() const override; private: std::shared_ptr const buffer_allocator; std::shared_ptr const display_buffer_builder; std::shared_ptr const display_report; std::shared_ptr const ipc_operations; std::shared_ptr const quirks; std::shared_ptr const native_window_report; OverlayOptimization const overlay_option; }; } } } #endif /* MIR_GRAPHICS_ANDROID_PLATFORM_H_ */ ./src/platforms/android/server/gl_context.h0000644000004100000410000000552413115234664021321 0ustar www-datawww-data/* * Copyright © 2013-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_GL_CONTEXT_H_ #define MIR_GRAPHICS_ANDROID_GL_CONTEXT_H_ #include "mir/renderer/gl/context.h" #include "mir/graphics/egl_resources.h" #include "swapping_gl_context.h" #include "mir_toolkit/common.h" #include namespace mir { namespace graphics { class DisplayReport; class GLConfig; namespace android { class FramebufferBundle; //helper base class that doesn't have an egl surface. class GLContext : public renderer::gl::Context { public: ~GLContext(); protected: GLContext(MirPixelFormat display_format, GLConfig const& gl_config, DisplayReport& report); GLContext(GLConfig const& gl_config, DisplayReport& report); GLContext(GLContext const& shared_gl_context); void release_current() const override; using renderer::gl::Context::make_current; void make_current(EGLSurface) const; EGLDisplay const egl_display; EGLConfig const egl_config; EGLContextStore const egl_context; private: bool const own_display; }; class PbufferGLContext : public GLContext { public: PbufferGLContext(MirPixelFormat display_format, GLConfig const& gl_config, DisplayReport& report); PbufferGLContext(GLConfig const& gl_config, DisplayReport& report); PbufferGLContext(PbufferGLContext const& shared_gl_context); void make_current() const override; void release_current() const override; private: EGLSurfaceStore const egl_surface; }; class FramebufferGLContext : public GLContext, public SwappingGLContext { public: FramebufferGLContext(GLContext const& shared_gl_context, std::shared_ptr const& fb_bundle, std::shared_ptr const& native_window); void make_current() const override; void release_current() const override; void swap_buffers() const override; std::shared_ptr last_rendered_buffer() const override; private: std::shared_ptr const fb_bundle; EGLSurfaceStore const egl_surface; }; } } } #endif /* MIR_GRAPHICS_ANDROID_GL_CONTEXT_H_ */ ./src/platforms/android/server/display_group.cpp0000644000004100000410000000714613115234416022364 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "display_group.h" #include "configurable_display_buffer.h" #include "display_device_exceptions.h" #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace geom = mir::geometry; mga::DisplayGroup::DisplayGroup( std::shared_ptr const& device, std::unique_ptr primary_buffer, ExceptionHandler const& exception_handler) : device(device), exception_handler(exception_handler) { dbs.emplace(std::make_pair(mga::DisplayName::primary, std::move(primary_buffer))); } mga::DisplayGroup::DisplayGroup( std::shared_ptr const& device, std::unique_ptr primary_buffer) : DisplayGroup(device, std::move(primary_buffer), []{}) { } void mga::DisplayGroup::for_each_display_buffer(std::function const& f) { std::unique_lock lk(guard); for(auto const& db : dbs) if (db.second->power_mode() != mir_power_mode_off) f(*db.second); } void mga::DisplayGroup::add(DisplayName name, std::unique_ptr buffer) { std::unique_lock lk(guard); dbs.emplace(std::make_pair(name, std::move(buffer))); } void mga::DisplayGroup::remove(DisplayName name) { if (name == mga::DisplayName::primary) BOOST_THROW_EXCEPTION(std::logic_error("cannot remove primary display")); std::unique_lock lk(guard); auto it = dbs.find(name); if (it != dbs.end()) dbs.erase(it); } bool mga::DisplayGroup::display_present(DisplayName name) const { std::unique_lock lk(guard); return (dbs.end() != dbs.find(name)); } void mga::DisplayGroup::configure( DisplayName name, MirPowerMode mode, MirOrientation orientation, geom::Displacement offset) { std::unique_lock lk(guard); auto it = dbs.find(name); if (it != dbs.end()) it->second->configure(mode, orientation, offset); } void mga::DisplayGroup::post() { std::list contents; { std::unique_lock lk(guard); for(auto const& db : dbs) contents.emplace_back(db.second->contents()); } try { device->commit(contents); } catch (mga::DisplayDisconnectedException const&) { //Ignore disconnect errors as they are not fatal } catch (mga::ExternalDisplayError const&) { //NOTE: We allow Display to inject an error handler (which can then attempt to recover // from this error) as post is called directly by the compositor and we don't want to propagate // handling of android platform specific exceptions in mir core. exception_handler(); } } std::chrono::milliseconds mga::DisplayGroup::recommended_sleep() const { return device->recommended_sleep(); } ./src/platforms/android/server/real_hwc_wrapper.cpp0000644000004100000410000002615613115234664023036 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/graphics/frame.h" #include "real_hwc_wrapper.h" #include "hwc_report.h" #include "display_device_exceptions.h" #include #include #include #include namespace mg = mir::graphics; namespace mga=mir::graphics::android; namespace { int num_displays(std::array const& displays) { return std::distance(displays.begin(), std::find_if(displays.begin(), displays.end(), [](hwc_display_contents_1_t* d){ return d == nullptr; })); } mga::DisplayName display_name(int raw_name) { switch(raw_name) { default: case HWC_DISPLAY_PRIMARY: return mga::DisplayName::primary; case HWC_DISPLAY_EXTERNAL: return mga::DisplayName::external; case HWC_DISPLAY_VIRTUAL: return mga::DisplayName::virt; } } //note: The destruction ordering of RealHwcWrapper should be enough to ensure that the //callbacks are not called after the hwc module is closed. However, some badly synchronized //drivers continue to call the hooks for a short period after we call close(). (LP: 1364637) static std::mutex callback_lock; static void invalidate_hook(const struct hwc_procs* procs) { mga::HwcCallbacks const* callbacks{nullptr}; std::unique_lock lk(callback_lock); if ((callbacks = reinterpret_cast(procs)) && callbacks->self) callbacks->self->invalidate(); } static void vsync_hook(const struct hwc_procs* procs, int display, int64_t timestamp) { mga::HwcCallbacks const* callbacks{nullptr}; std::unique_lock lk(callback_lock); if ((callbacks = reinterpret_cast(procs)) && callbacks->self) { // hwcomposer.h says the clock used is CLOCK_MONOTONIC, and testing // on various devices confirms this is the case... mg::Frame::Timestamp hwc_time{CLOCK_MONOTONIC, std::chrono::nanoseconds{timestamp}}; callbacks->self->vsync(display_name(display), hwc_time); } } static void hotplug_hook(const struct hwc_procs* procs, int display, int connected) { mga::HwcCallbacks const* callbacks{nullptr}; std::unique_lock lk(callback_lock); if ((callbacks = reinterpret_cast(procs)) && callbacks->self) callbacks->self->hotplug(display_name(display), connected); } static mga::HwcCallbacks hwc_callbacks{{invalidate_hook, vsync_hook, hotplug_hook}, nullptr}; } mga::RealHwcWrapper::RealHwcWrapper( std::shared_ptr const& hwc_device, std::shared_ptr const& report) : hwc_device(hwc_device), report(report) { std::unique_lock lk(callback_lock); hwc_callbacks.self = this; hwc_device->registerProcs(hwc_device.get(), reinterpret_cast(&hwc_callbacks)); is_plugged[HWC_DISPLAY_PRIMARY].store(true); is_plugged[HWC_DISPLAY_EXTERNAL].store(false); is_plugged[HWC_DISPLAY_VIRTUAL].store(true); } mga::RealHwcWrapper::~RealHwcWrapper() { std::unique_lock lk(callback_lock); hwc_callbacks.self = nullptr; } void mga::RealHwcWrapper::prepare( std::array const& displays) const { report->report_list_submitted_to_prepare(displays); if (auto rc = hwc_device->prepare(hwc_device.get(), num_displays(displays), const_cast(displays.data()))) { std::stringstream ss; ss << "error during hwc prepare(). rc = " << std::hex << rc; BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } report->report_prepare_done(displays); } void mga::RealHwcWrapper::set( std::array const& displays) const { report->report_set_list(displays); auto const num_displays = ::num_displays(displays); if (auto rc = hwc_device->set(hwc_device.get(), num_displays, const_cast(displays.data()))) { std::stringstream ss; ss << "error during hwc set(). rc = " << std::hex << rc; if (num_displays > 1) { if (!display_connected(DisplayName::external)) BOOST_THROW_EXCEPTION(mga::DisplayDisconnectedException(ss.str())); else BOOST_THROW_EXCEPTION(mga::ExternalDisplayError(ss.str())); } BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } report->report_set_done(displays); } void mga::RealHwcWrapper::vsync_signal_on(DisplayName display_name) const { if (auto rc = hwc_device->eventControl(hwc_device.get(), as_hwc_display(display_name), HWC_EVENT_VSYNC, 1)) { std::stringstream ss; ss << "error turning vsync signal on. rc = " << std::hex << rc; BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } report->report_vsync_on(); } void mga::RealHwcWrapper::vsync_signal_off(DisplayName display_name) const { if (auto rc = hwc_device->eventControl(hwc_device.get(), as_hwc_display(display_name), HWC_EVENT_VSYNC, 0)) { std::stringstream ss; ss << "error turning vsync signal off. rc = " << std::hex << rc; BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } report->report_vsync_off(); } void mga::RealHwcWrapper::display_on(DisplayName display_name) const { if (auto rc = hwc_device->blank(hwc_device.get(), as_hwc_display(display_name), 0)) { std::stringstream ss; ss << "error turning display on. rc = " << std::hex << rc; BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } report->report_display_on(); } void mga::RealHwcWrapper::display_off(DisplayName display_name) const { if (auto rc = hwc_device->blank(hwc_device.get(), as_hwc_display(display_name), 1)) { std::stringstream ss; ss << "error turning display off. rc = " << std::hex << rc; BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } report->report_display_off(); } void mga::RealHwcWrapper::subscribe_to_events( void const* subscriber, std::function const& vsync, std::function const& hotplug, std::function const& invalidate) { std::unique_lock lk(callback_map_lock); callback_map[subscriber] = {vsync, hotplug, invalidate}; } void mga::RealHwcWrapper::unsubscribe_from_events(void const* subscriber) noexcept { std::unique_lock lk(callback_map_lock); auto it = callback_map.find(subscriber); if (it != callback_map.end()) callback_map.erase(it); } void mga::RealHwcWrapper::vsync(DisplayName name, mg::Frame::Timestamp timestamp) noexcept { std::unique_lock lk(callback_map_lock); for(auto const& callbacks : callback_map) { try { callbacks.second.vsync(name, timestamp); } catch (...) { } } } void mga::RealHwcWrapper::hotplug(DisplayName name, bool connected) noexcept { is_plugged[mga::as_hwc_display(name)].store(connected); std::unique_lock lk(callback_map_lock); for(auto const& callbacks : callback_map) { try { callbacks.second.hotplug(name, connected); } catch (...) { } } } void mga::RealHwcWrapper::invalidate() noexcept { std::unique_lock lk(callback_map_lock); for(auto const& callbacks : callback_map) { try { callbacks.second.invalidate(); } catch (...) { } } } std::vector mga::RealHwcWrapper::display_configs(DisplayName display_name) const { //Check first if display is unplugged, as some hw composers incorrectly report display configurations //when they have already triggered an unplug event. if (!is_plugged[mga::as_hwc_display(display_name)].load()) return {}; //No way to get the number of display configs. SF uses 128 possible spots, but that seems excessive. static size_t const max_configs = 16; size_t num_configs = max_configs; static uint32_t display_config[max_configs] = {}; if (hwc_device->getDisplayConfigs(hwc_device.get(), as_hwc_display(display_name), display_config, &num_configs)) return {}; auto i = 0u; std::vector config_ids{std::min(max_configs, num_configs)}; for(auto& id : config_ids) id = mga::ConfigId{display_config[i++]}; return config_ids; } int mga::RealHwcWrapper::display_attributes( DisplayName display_name, ConfigId config, uint32_t const* attributes, int32_t* values) const { return hwc_device->getDisplayAttributes( hwc_device.get(), as_hwc_display(display_name), config.as_value(), attributes, values); } void mga::RealHwcWrapper::power_mode(DisplayName display_name, PowerMode mode) const { if (auto rc = hwc_device->setPowerMode(hwc_device.get(), as_hwc_display(display_name), static_cast(mode))) { std::stringstream ss; ss << "error setting power mode. rc = " << std::hex << rc; BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } report->report_power_mode(mode); } bool mga::RealHwcWrapper::has_active_config(DisplayName display_name) const { int const no_active_config = -1; return hwc_device->getActiveConfig(hwc_device.get(), as_hwc_display(display_name)) != no_active_config; } mga::ConfigId mga::RealHwcWrapper::active_config_for(DisplayName display_name) const { int id = hwc_device->getActiveConfig(hwc_device.get(), as_hwc_display(display_name)); if (id == -1) { std::stringstream ss; ss << "No active configuration for display: " << as_hwc_display(display_name); BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } return mga::ConfigId{static_cast(id)}; } void mga::RealHwcWrapper::set_active_config(DisplayName display_name, ConfigId id) const { int rc = hwc_device->setActiveConfig(hwc_device.get(), as_hwc_display(display_name), id.as_value()); if (rc < 0) BOOST_THROW_EXCEPTION(std::system_error(rc, std::system_category(), "unable to set active display config")); } bool mga::RealHwcWrapper::display_connected(DisplayName display_name) const { size_t num_configs = 0; return hwc_device->getDisplayConfigs(hwc_device.get(), as_hwc_display(display_name), nullptr, &num_configs) == 0; } ./src/platforms/android/server/display_group.h0000644000004100000410000000431113115234416022020 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_DISPLAY_GROUP_H_ #define MIR_GRAPHICS_ANDROID_DISPLAY_GROUP_H_ #include "mir_toolkit/common.h" #include "mir/graphics/display.h" #include "mir/geometry/displacement.h" #include "display_name.h" #include #include namespace mir { namespace graphics { namespace android { class ConfigurableDisplayBuffer; class DisplayDevice; class DisplayGroup : public graphics::DisplaySyncGroup { public: using ExceptionHandler = std::function; DisplayGroup( std::shared_ptr const& device, std::unique_ptr primary_buffer, ExceptionHandler const& handler); DisplayGroup( std::shared_ptr const& device, std::unique_ptr primary_buffer); void for_each_display_buffer(std::function const& f) override; void post() override; std::chrono::milliseconds recommended_sleep() const override; void add(DisplayName name, std::unique_ptr buffer); void remove(DisplayName name); void configure(DisplayName name, MirPowerMode, MirOrientation, geometry::Displacement); bool display_present(DisplayName name) const; private: std::mutex mutable guard; std::shared_ptr const device; std::map> dbs; ExceptionHandler const exception_handler; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DISPLAY_GROUP_H_ */ ./src/platforms/android/server/display_component_factory.h0000644000004100000410000000362113115234416024420 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_ANDROID_DISPLAY_COMPONENT_FACTORY_H_ #define MIR_GRAPHICS_ANDROID_DISPLAY_COMPONENT_FACTORY_H_ #include "egl_sync_fence.h" #include "display_device.h" #include "framebuffer_bundle.h" #include namespace mir { namespace graphics { class DisplayConfigurationOutput; class CommandStreamSync; class GraphicBufferAllocator; namespace android { class HwcConfiguration; //TODO: this name needs improvement. class DisplayComponentFactory { public: virtual ~DisplayComponentFactory() = default; virtual std::unique_ptr create_framebuffers(DisplayConfigurationOutput const&) = 0; virtual std::unique_ptr create_display_device() = 0; virtual std::unique_ptr create_hwc_configuration() = 0; virtual std::unique_ptr create_layer_list() = 0; virtual std::shared_ptr the_buffer_allocator() = 0; protected: DisplayComponentFactory() = default; DisplayComponentFactory(DisplayComponentFactory const&) = delete; DisplayComponentFactory& operator=(DisplayComponentFactory const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DISPLAY_COMPONENT_FACTORY_H_ */ ./src/platforms/android/server/framebuffers.h0000644000004100000410000000327613115234416021617 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_FB_SIMPLE_SWAPPER_H_ #define MIR_GRAPHICS_ANDROID_FB_SIMPLE_SWAPPER_H_ #include "framebuffer_bundle.h" #include #include #include #include #include #include namespace mir { namespace graphics { namespace android { class GraphicBufferAllocator; class Framebuffers : public FramebufferBundle { public: Framebuffers( GraphicBufferAllocator& buffer_allocator, geometry::Size size, MirPixelFormat format, unsigned int num_framebuffers); geometry::Size fb_size() override; std::shared_ptr buffer_for_render() override; std::shared_ptr last_rendered_buffer() override; private: geometry::Size size; std::mutex queue_lock; std::shared_ptr buffer_being_rendered; std::condition_variable cv; std::queue> queue; }; } } } #endif /* MIR_GRAPHICS_ANDROID_FB_SIMPLE_SWAPPER_H_ */ ./src/platforms/android/server/gl_context.cpp0000644000004100000410000001757713115234664021667 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "gl_context.h" #include "framebuffer_bundle.h" #include "android_format_conversion-inl.h" #include "mir/graphics/display_report.h" #include "mir/graphics/gl_config.h" #include "mir/graphics/egl_error.h" #include #include #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace { static EGLint const default_egl_context_attr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; static EGLint const dummy_pbuffer_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; static EGLDisplay create_and_initialize_display() { EGLint major, minor; auto egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (egl_display == EGL_NO_DISPLAY) BOOST_THROW_EXCEPTION(mg::egl_error("eglGetDisplay failed")); if (eglInitialize(egl_display, &major, &minor) == EGL_FALSE) BOOST_THROW_EXCEPTION(mg::egl_error("eglInitialize failure")); if ((major != 1) || (minor != 4)) BOOST_THROW_EXCEPTION(std::runtime_error("must have EGL 1.4")); return egl_display; } /* the minimum requirement is to have EGL_WINDOW_BIT and EGL_OPENGL_ES2_BIT, and to select a config whose pixel format matches that of the framebuffer. */ EGLConfig select_egl_config_with_format( EGLDisplay egl_display, MirPixelFormat display_format, mg::GLConfig const& gl_config) { EGLint const required_egl_config_attr [] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_DEPTH_SIZE, gl_config.depth_buffer_bits(), EGL_STENCIL_SIZE, gl_config.stencil_buffer_bits(), EGL_NONE }; int required_visual_id = mga::to_android_format(display_format); int num_potential_configs; EGLint num_match_configs; eglGetConfigs(egl_display, NULL, 0, &num_potential_configs); std::vector config_slots(num_potential_configs); eglChooseConfig(egl_display, required_egl_config_attr, config_slots.data(), num_potential_configs, &num_match_configs); config_slots.resize(num_match_configs); auto const pegl_config = std::find_if(begin(config_slots), end(config_slots), [&](EGLConfig& current) -> bool { int visual_id; eglGetConfigAttrib(egl_display, current, EGL_NATIVE_VISUAL_ID, &visual_id); return (visual_id == required_visual_id); }); if (pegl_config == end(config_slots)) BOOST_THROW_EXCEPTION(std::runtime_error("could not select EGL config for use with framebuffer")); return *pegl_config; } //Sometimes it's useful not to specify a format when one doesn't know which format to use yet. //This is used by DeviceQuirks to create a context for finding out GL vendor and renderer. EGLConfig select_egl_config_with_any_format( EGLDisplay egl_display, mg::GLConfig const& gl_config) { EGLint const required_egl_config_attr [] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_DEPTH_SIZE, gl_config.depth_buffer_bits(), EGL_STENCIL_SIZE, gl_config.stencil_buffer_bits(), EGL_NONE }; EGLConfig the_config; EGLint num_returned_config; eglChooseConfig(egl_display, required_egl_config_attr, &the_config, 1, &num_returned_config); if (num_returned_config != 1) BOOST_THROW_EXCEPTION(std::runtime_error("could not select EGL config")); return the_config; } } void mga::GLContext::make_current(EGLSurface egl_surface) const { if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) == EGL_FALSE) { BOOST_THROW_EXCEPTION( mg::egl_error("could not activate surface with eglMakeCurrent")); } } void mga::GLContext::release_current() const { eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } mga::GLContext::~GLContext() { if (eglGetCurrentContext() == egl_context) release_current(); if (own_display) eglTerminate(egl_display); } mga::GLContext::GLContext( MirPixelFormat display_format, mg::GLConfig const& gl_config, mg::DisplayReport& report) : egl_display(create_and_initialize_display()), egl_config(select_egl_config_with_format(egl_display, display_format, gl_config)), egl_context{egl_display, eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, default_egl_context_attr)}, own_display(true) { report.report_egl_configuration(egl_display, egl_config); } mga::GLContext::GLContext(mg::GLConfig const& gl_config, mg::DisplayReport& report) : egl_display(create_and_initialize_display()), egl_config(select_egl_config_with_any_format(egl_display, gl_config)), egl_context{egl_display, eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, default_egl_context_attr)}, own_display(true) { report.report_egl_configuration(egl_display, egl_config); } mga::GLContext::GLContext(GLContext const& shared_gl_context) : mir::renderer::gl::Context(), egl_display(shared_gl_context.egl_display), egl_config(shared_gl_context.egl_config), egl_context{egl_display, eglCreateContext(egl_display, egl_config, shared_gl_context.egl_context, default_egl_context_attr)}, own_display(false) { } mga::PbufferGLContext::PbufferGLContext( MirPixelFormat display_format, mg::GLConfig const& gl_config, mg::DisplayReport& report) : GLContext(display_format, gl_config, report), egl_surface{egl_display, eglCreatePbufferSurface(egl_display, egl_config, dummy_pbuffer_attribs)} { } mga::PbufferGLContext::PbufferGLContext(mg::GLConfig const& gl_config, mg::DisplayReport& report) : GLContext(gl_config, report), egl_surface{egl_display, eglCreatePbufferSurface(egl_display, egl_config, dummy_pbuffer_attribs)} { } mga::PbufferGLContext::PbufferGLContext(PbufferGLContext const& shared_gl_context) : GLContext(shared_gl_context), egl_surface{egl_display, eglCreatePbufferSurface(egl_display, egl_config, dummy_pbuffer_attribs)} { } void mga::PbufferGLContext::make_current() const { GLContext::make_current(egl_surface); } void mga::PbufferGLContext::release_current() const { GLContext::release_current(); } mga::FramebufferGLContext::FramebufferGLContext( GLContext const& shared_gl_context, std::shared_ptr const& fb_bundle, std::shared_ptr const& native_window) : GLContext(shared_gl_context), fb_bundle(fb_bundle), egl_surface{egl_display, eglCreateWindowSurface(egl_display, egl_config, native_window.get(), NULL)} { } void mga::FramebufferGLContext::swap_buffers() const { if (eglSwapBuffers(egl_display, egl_surface) == EGL_FALSE) BOOST_THROW_EXCEPTION(mg::egl_error("eglSwapBuffers failure")); } std::shared_ptr mga::FramebufferGLContext::last_rendered_buffer() const { return fb_bundle->last_rendered_buffer(); } void mga::FramebufferGLContext::make_current() const { GLContext::make_current(egl_surface); } void mga::FramebufferGLContext::release_current() const { GLContext::release_current(); } ./src/platforms/android/server/egl_sync_factory.cpp0000644000004100000410000000242613115234416023031 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "cmdstream_sync_factory.h" #include "egl_sync_fence.h" namespace mg = mir::graphics; namespace mga = mir::graphics::android; std::unique_ptr mga::EGLSyncFactory::create_command_stream_sync() { try { return std::make_unique(std::make_shared()); } catch (std::runtime_error&) { return std::make_unique(); } } std::unique_ptr mga::NullCommandStreamSyncFactory::create_command_stream_sync() { return std::make_unique(); } ./src/platforms/android/server/hwc_blanking_control.cpp0000644000004100000410000002424413115234664023674 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "hwc_configuration.h" #include "hwc_wrapper.h" #include "mir/raii.h" #include "android_format_conversion-inl.h" #include "mir/geometry/length.h" #include #include #include #include #include #include #define MIR_LOG_COMPONENT "android/server" #include "mir/log.h" namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace geom = mir::geometry; namespace { MirPixelFormat determine_hwc_fb_format() { static EGLint const fb_egl_config_attr [] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_FRAMEBUFFER_TARGET_ANDROID, EGL_TRUE, EGL_RECORDABLE_ANDROID, EGL_TRUE, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_NONE }; EGLConfig fb_egl_config; int matching_configs; EGLint major, minor; auto egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(egl_display, &major, &minor); eglChooseConfig(egl_display, fb_egl_config_attr, &fb_egl_config, 1, &matching_configs); MirPixelFormat fb_format; if (matching_configs) { int visual_id; eglGetConfigAttrib(egl_display, fb_egl_config, EGL_NATIVE_VISUAL_ID, &visual_id); fb_format = mga::to_mir_format(visual_id); mir::log_info("Found %d matching egl configs", matching_configs); mir::log_info("Android visual ID for selected display format : %d", visual_id); } else { mir::log_info("No matching egl configs found"); //we couldn't figure out the fb format via egl. In this case, we //assume abgr_8888. HWC api really should provide this information directly. fb_format = mir_pixel_format_abgr_8888; } mir::log_info("Selected Mir display format : %d", fb_format); eglTerminate(egl_display); return fb_format; } using namespace std::chrono; template double period_to_hz(duration period_duration) { if (period_duration.count() <= 0) return 0.0; return duration{1} / period_duration; } } mga::HwcBlankingControl::HwcBlankingControl( std::shared_ptr const& hwc_device) : hwc_device{hwc_device}, off{false}, format(determine_hwc_fb_format()) { } mga::HwcBlankingControl::HwcBlankingControl( std::shared_ptr const& hwc_device, MirPixelFormat format) : hwc_device{hwc_device}, off{false}, format{format} { } void mga::HwcBlankingControl::power_mode(DisplayName display_name, MirPowerMode mode_request) { if (mode_request == mir_power_mode_on) { hwc_device->display_on(display_name); hwc_device->vsync_signal_on(display_name); off = false; } //suspend, standby, and off all count as off else if (!off) { hwc_device->vsync_signal_off(display_name); hwc_device->display_off(display_name); off = true; } } namespace { int dpi_to_mm(uint32_t dpi, int pixel_num) { if (dpi == 0) return 0; float dpi_inches = dpi / 1000.0f; //android multiplies by 1000 geom::Length length(pixel_num / dpi_inches, geom::Length::Units::inches); return length.as(geom::Length::Units::millimetres); } mg::DisplayConfigurationOutput populate_config( mga::DisplayName name, geom::Size pixel_size, double vrefresh_hz, geom::Size mm_size, MirPowerMode external_mode, MirPixelFormat display_format, bool connected) { geom::Point const origin{0,0}; size_t const preferred_format_index{0}; size_t const preferred_mode_index{0}; std::vector external_modes; if (connected) external_modes.emplace_back(mg::DisplayConfigurationMode{pixel_size, vrefresh_hz}); auto type = mg::DisplayConfigurationOutputType::lvds; auto form_factor = mir_form_factor_phone; if (name == mga::DisplayName::external) { type = mg::DisplayConfigurationOutputType::displayport; form_factor = mir_form_factor_monitor; } return { as_output_id(name), mg::DisplayConfigurationCardId{0}, type, {display_format}, external_modes, preferred_mode_index, mm_size, connected, connected, origin, preferred_format_index, display_format, external_mode, mir_orientation_normal, 1.0f, form_factor, mir_subpixel_arrangement_unknown, {}, mir_output_gamma_unsupported, {} }; } mg::DisplayConfigurationOutput display_config_for( mga::DisplayName display_name, mga::ConfigId id, MirPixelFormat format, std::shared_ptr const& hwc_device ) { /* note: some drivers (qcom msm8960) choke if this is not the same size array as the one surfaceflinger submits */ static uint32_t const attributes[] = { HWC_DISPLAY_WIDTH, HWC_DISPLAY_HEIGHT, HWC_DISPLAY_VSYNC_PERIOD, HWC_DISPLAY_DPI_X, HWC_DISPLAY_DPI_Y, HWC_DISPLAY_NO_ATTRIBUTE, }; int32_t values[sizeof(attributes) / sizeof (attributes[0])] = {}; auto rc = hwc_device->display_attributes(display_name, id, attributes, values); if (rc < 0) { if (display_name == mga::DisplayName::primary) BOOST_THROW_EXCEPTION(std::system_error(rc, std::system_category(), "primary display disconnected")); else return populate_config(display_name, {0,0}, 0.0f, {0,0}, mir_power_mode_off, mir_pixel_format_invalid, false); } return populate_config( display_name, {values[0], values[1]}, period_to_hz(std::chrono::nanoseconds{values[2]}), {dpi_to_mm(values[3], values[0]), dpi_to_mm(values[4], values[1])}, mir_power_mode_off, format, true); } mga::ConfigChangeSubscription subscribe_to_config_changes( std::shared_ptr const& hwc_device, void const* subscriber, std::function const& hotplug, std::function const& vsync) { return std::make_shared< mir::raii::PairedCalls, std::function>>( [hotplug, vsync, subscriber, hwc_device]{ hwc_device->subscribe_to_events(subscriber, [vsync](mga::DisplayName name, mg::Frame::Timestamp ts){ vsync(name, ts); }, [hotplug](mga::DisplayName, bool){ hotplug(); }, []{}); }, [subscriber, hwc_device]{ hwc_device->unsubscribe_from_events(subscriber); }); } } mg::DisplayConfigurationOutput mga::HwcBlankingControl::active_config_for(DisplayName display_name) { auto configs = hwc_device->display_configs(display_name); if (configs.empty()) { if (display_name == mga::DisplayName::primary) BOOST_THROW_EXCEPTION(std::runtime_error("primary display disconnected")); else return populate_config(display_name, {0,0}, 0.0f, {0,0}, mir_power_mode_off, mir_pixel_format_invalid, false); } return display_config_for(display_name, configs.front(), format, hwc_device); } mga::ConfigChangeSubscription mga::HwcBlankingControl::subscribe_to_config_changes( std::function const& hotplug, std::function const& vsync) { return ::subscribe_to_config_changes(hwc_device, this, hotplug, vsync); } mga::HwcPowerModeControl::HwcPowerModeControl( std::shared_ptr const& hwc_device) : hwc_device{hwc_device}, format(determine_hwc_fb_format()) { } void mga::HwcPowerModeControl::power_mode(DisplayName display_name, MirPowerMode mode_request) { PowerMode mode; switch (mode_request) { case mir_power_mode_on: mode = PowerMode::normal; break; case mir_power_mode_standby: mode = PowerMode::doze; break; case mir_power_mode_suspend: mode = PowerMode::doze_suspend; break; case mir_power_mode_off: mode = PowerMode::off; break; default: BOOST_THROW_EXCEPTION(std::logic_error("Invalid power mode")); } hwc_device->power_mode(display_name, mode); } mg::DisplayConfigurationOutput mga::HwcPowerModeControl::active_config_for(DisplayName display_name) { auto configs = hwc_device->display_configs(display_name); if (configs.empty()) { if (display_name == mga::DisplayName::primary) BOOST_THROW_EXCEPTION(std::runtime_error("primary display disconnected")); else return populate_config(display_name, {0,0}, 0.0f, {0,0}, mir_power_mode_off, mir_pixel_format_invalid, false); } /* the first config is the active one in hwc 1.1 to hwc 1.3. */ ConfigId active_config_id = configs.front(); if (hwc_device->has_active_config(display_name)) { active_config_id = hwc_device->active_config_for(display_name); } else { //If no active config, just choose the first from the list hwc_device->set_active_config(display_name, configs.front()); } return display_config_for(display_name, active_config_id, format, hwc_device); } mga::ConfigChangeSubscription mga::HwcPowerModeControl::subscribe_to_config_changes( std::function const& hotplug, std::function const& vsync) { return ::subscribe_to_config_changes(hwc_device, this, hotplug, vsync); } ./src/platforms/android/server/interpreter_cache.h0000644000004100000410000000305513115234664022636 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_INTERPRETER_CACHE_H_ #define MIR_GRAPHICS_ANDROID_INTERPRETER_CACHE_H_ #include "interpreter_resource_cache.h" #include namespace mir { namespace graphics { namespace android { class InterpreterCache : public InterpreterResourceCache { public: InterpreterCache() {} void store_buffer(std::shared_ptrconst& buffer, std::shared_ptr const& key); std::shared_ptr retrieve_buffer(ANativeWindowBuffer* key); void update_native_fence(ANativeWindowBuffer* key, int fence); private: std::unordered_map> buffers_in_driver; std::unordered_map> native_buffers; }; } } } #endif /* MIR_GRAPHICS_ANDROID_INTERPRETER_CACHE_H_ */ ./src/platforms/android/server/device_quirks.h0000644000004100000410000000535113115234664022006 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_DEVICE_QUIRKS_H_ #define MIR_GRAPHICS_ANDROID_DEVICE_QUIRKS_H_ #include #include namespace boost{ namespace program_options {class options_description;}} namespace mir { namespace options{ class Option; } namespace renderer{ namespace gl{ class Context; }} namespace graphics { namespace android { class PropertiesWrapper { public: PropertiesWrapper() = default; virtual ~PropertiesWrapper() = default; virtual int property_get( char const* key, char* value, char const* default_value) const = 0; private: PropertiesWrapper(PropertiesWrapper const&) = delete; PropertiesWrapper& operator=(PropertiesWrapper const&) = delete; }; class PropertiesOps : public PropertiesWrapper { public: int property_get( char const* key, char* value, char const* default_value) const; }; struct GPUInfo { std::string const gl_vendor; std::string const gl_renderer; }; class DeviceQuirks { public: DeviceQuirks(PropertiesWrapper const& properties); DeviceQuirks(PropertiesWrapper const& properties, mir::options::Option const& options); DeviceQuirks(PropertiesWrapper const& properties, renderer::gl::Context const& context); unsigned int num_framebuffers() const; bool gralloc_cannot_be_closed_safely() const; int aligned_width(int width) const; bool clear_fb_context_fence() const; int fb_gralloc_bits() const; bool working_egl_sync() const; static void add_options(boost::program_options::options_description& config); private: DeviceQuirks(DeviceQuirks const&) = delete; DeviceQuirks & operator=(DeviceQuirks const&) = delete; std::string const device_name; GPUInfo const gpu_info; unsigned int const num_framebuffers_; bool const gralloc_cannot_be_closed_safely_; bool const enable_width_alignment_quirk; bool const clear_fb_context_fence_; bool const fb_ion_heap_; bool const working_egl_sync_; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DEVICE_QUIRKS_H_ */ ./src/platforms/android/server/display_buffer.cpp0000644000004100000410000001045213115234664022500 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "framebuffer_bundle.h" #include "display_buffer.h" #include "display_device.h" #include "hwc_layerlist.h" #include #include #include #include namespace mg=mir::graphics; namespace mgl=mir::gl; namespace mga=mir::graphics::android; namespace geom=mir::geometry; mga::DisplayBuffer::DisplayBuffer( mga::DisplayName display_name, std::unique_ptr layer_list, std::shared_ptr const& fb_bundle, std::shared_ptr const& display_device, std::shared_ptr const& native_window, mga::GLContext const& shared_gl_context, mgl::ProgramFactory const& program_factory, MirOrientation orientation, geom::Displacement offset, mga::OverlayOptimization overlay_option) : display_name(display_name), layer_list(std::move(layer_list)), fb_bundle{fb_bundle}, display_device{display_device}, native_window{native_window}, gl_context{shared_gl_context, fb_bundle, native_window}, overlay_program{program_factory, gl_context, geom::Rectangle{{0,0},fb_bundle->fb_size()}}, overlay_enabled{overlay_option == mga::OverlayOptimization::enabled}, orientation_{orientation}, offset_from_origin{offset}, power_mode_{mir_power_mode_on} { } geom::Rectangle mga::DisplayBuffer::view_area() const { auto const& size = fb_bundle->fb_size(); int width = size.width.as_int(); int height = size.height.as_int(); if (orientation_ == mir_orientation_left || orientation_ == mir_orientation_right) std::swap(width, height); geom::Point origin; return {origin + offset_from_origin, {width,height}}; } void mga::DisplayBuffer::make_current() { gl_context.make_current(); } void mga::DisplayBuffer::release_current() { gl_context.release_current(); } bool mga::DisplayBuffer::overlay(RenderableList const& renderlist) { if (!overlay_enabled || !display_device->compatible_renderlist(renderlist) || orientation_ != mir_orientation_normal) return false; layer_list->update_list(renderlist, offset_from_origin); bool needs_commit{false}; for (auto& layer : *layer_list) needs_commit |= layer.needs_commit; return needs_commit; } void mga::DisplayBuffer::swap_buffers() { layer_list->update_list({}, offset_from_origin); //HWC 1.0 cannot call eglSwapBuffers() on the display context if (display_device->can_swap_buffers()) gl_context.swap_buffers(); } void mga::DisplayBuffer::bind() { } MirOrientation mga::DisplayBuffer::orientation() const { /* * android::DisplayBuffer is aways created with physical width/height * (not rotated). So we just need to pass through the desired rotation * and let the renderer do it. * If and when we choose to implement HWC rotation, this may change. */ return orientation_; } MirMirrorMode mga::DisplayBuffer::mirror_mode() const { return mir_mirror_mode_none; } void mga::DisplayBuffer::configure(MirPowerMode power_mode, MirOrientation orientation, geom::Displacement offset) { power_mode_ = power_mode; offset_from_origin = offset; if (power_mode_ != mir_power_mode_on) display_device->content_cleared(); orientation_ = orientation; } mga::DisplayContents mga::DisplayBuffer::contents() { return mga::DisplayContents{display_name, *layer_list, offset_from_origin, gl_context, overlay_program}; } MirPowerMode mga::DisplayBuffer::power_mode() const { return power_mode_; } mg::NativeDisplayBuffer* mga::DisplayBuffer::native_display_buffer() { return this; } ./src/platforms/android/server/resource_factory.cpp0000644000004100000410000000665513115234664023072 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #include "mir_native_window.h" #include "sync_fence.h" #include "buffer.h" #include "resource_factory.h" #include "fb_device.h" #include "server_render_window.h" #include "hwc_device.h" #include "hwc_fb_device.h" #include "hwc_layerlist.h" #include "display.h" #include "real_hwc_wrapper.h" #include #include #include namespace mg = mir::graphics; namespace mga=mir::graphics::android; std::shared_ptr mga::ResourceFactory::create_fb_native_device() const { hw_module_t const* module; framebuffer_device_t* fbdev_raw; auto rc = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); if ((rc != 0) || (module == nullptr) || (framebuffer_open(module, &fbdev_raw) != 0) ) { BOOST_THROW_EXCEPTION(std::runtime_error("display factory cannot create fb display")); } return std::shared_ptr(fbdev_raw, [](struct framebuffer_device_t* fbdevice) { fbdevice->common.close((hw_device_t*) fbdevice); }); } std::tuple, mga::HwcVersion> mga::ResourceFactory::create_hwc_wrapper(std::shared_ptr const& hwc_report) const { //TODO: could probably be collapsed further into HwcWrapper's constructor hwc_composer_device_1* hwc_device_raw = nullptr; hw_module_t const *module; int rc = hw_get_module(HWC_HARDWARE_MODULE_ID, &module); if ((rc != 0) || (module == nullptr) || (!module->methods) || !(module->methods->open) || module->methods->open(module, HWC_HARDWARE_COMPOSER, reinterpret_cast(&hwc_device_raw)) || (hwc_device_raw == nullptr)) { BOOST_THROW_EXCEPTION(std::runtime_error("error opening hwc hal")); } auto hwc_native = std::shared_ptr(hwc_device_raw, [](hwc_composer_device_1* device) { device->common.close((hw_device_t*) device); }); auto version = mga::HwcVersion::hwc10; switch(hwc_native->common.version) { case HWC_DEVICE_API_VERSION_1_0: version = mga::HwcVersion::hwc10; break; case HWC_DEVICE_API_VERSION_1_1: version = mga::HwcVersion::hwc11; break; case HWC_DEVICE_API_VERSION_1_2: version = mga::HwcVersion::hwc12; break; case HWC_DEVICE_API_VERSION_1_3: version = mga::HwcVersion::hwc13; break; case HWC_DEVICE_API_VERSION_1_4: version = mga::HwcVersion::hwc14; break; case HWC_DEVICE_API_VERSION_1_5: version = mga::HwcVersion::hwc15; break; default: version = mga::HwcVersion::unknown; break; } return std::make_tuple( std::make_shared(hwc_native, hwc_report), version); } ./src/platforms/android/server/hwc_layerlist.h0000644000004100000410000000463713115234416022023 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_HWC_LAYERLIST_H_ #define MIR_GRAPHICS_ANDROID_HWC_LAYERLIST_H_ #include "fence.h" #include "mir/geometry/rectangle.h" #include "mir/geometry/displacement.h" #include "hwc_layers.h" #include #include #include #include #include namespace mir { namespace graphics { class Renderable; class Buffer; namespace android { struct HwcLayerEntry { HwcLayerEntry(HWCLayer && layer, bool needs_commit); HWCLayer layer; bool needs_commit; }; class LayerList { public: LayerList( std::shared_ptr const& layer_adapter, RenderableList const& renderlist, geometry::Displacement list_offset); void update_list(RenderableList const& renderlist, geometry::Displacement list_offset); std::list::iterator begin(); std::list::iterator end(); RenderableList rejected_renderables(); void setup_fb(std::shared_ptr const& fb_target); bool needs_swapbuffers(); void swap_occurred(); hwc_display_contents_1_t* native_list(); NativeFence retirement_fence(); private: LayerList& operator=(LayerList const&) = delete; LayerList(LayerList const&) = delete; RenderableList renderable_list; void update_list_mode(RenderableList const& renderlist); std::shared_ptr const layer_adapter; std::list layers; std::shared_ptr hwc_representation; enum Mode { no_extra_layers, skip_only, target_only, skip_and_target } mode; size_t additional_layers_for(Mode mode); }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_LAYERLIST_H_ */ ./src/platforms/android/server/interpreter_cache.cpp0000644000004100000410000000412213115234664023165 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "sync_fence.h" #include "native_buffer.h" #include "interpreter_cache.h" #include #include namespace mg = mir::graphics; namespace mga=mir::graphics::android; void mga::InterpreterCache::store_buffer(std::shared_ptrconst& buffer, std::shared_ptr const& key) { native_buffers[key->anwb()] = key; buffers_in_driver[key->anwb()] = buffer; } std::shared_ptr mga::InterpreterCache::retrieve_buffer(ANativeWindowBuffer* returned_handle) { auto buffer_it = buffers_in_driver.find(returned_handle); auto native_it = native_buffers.find(returned_handle); if ((buffer_it == buffers_in_driver.end()) || (native_it == native_buffers.end())) { BOOST_THROW_EXCEPTION(std::runtime_error("driver is returning buffers it never was given!")); } native_buffers.erase(native_it); auto buffer_out = buffer_it->second; buffers_in_driver.erase(buffer_it); return buffer_out; } void mga::InterpreterCache::update_native_fence(ANativeWindowBuffer* key, int fence) { auto native_it = native_buffers.find(key); if (native_it == native_buffers.end()) { BOOST_THROW_EXCEPTION(std::runtime_error("driver is returning buffers it never was given!")); } auto native_buffer = native_it->second; native_buffer->update_usage(fence, mga::BufferAccess::write); } ./src/platforms/android/server/configurable_display_buffer.h0000644000004100000410000000244113115234416024657 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_CONFIGURABLE_DISPLAY_BUFFER_H_ #define MIR_GRAPHICS_ANDROID_CONFIGURABLE_DISPLAY_BUFFER_H_ #include "mir/graphics/display_buffer.h" #include "display_device.h" namespace mir { namespace graphics { namespace android { class ConfigurableDisplayBuffer : public graphics::DisplayBuffer { public: virtual void configure(MirPowerMode power_mode, MirOrientation orientation, geometry::Displacement) = 0; virtual DisplayContents contents() = 0; virtual MirPowerMode power_mode() const = 0; }; } } } #endif /* MIR_GRAPHICS_ANDROID_CONFIGURABLE_DISPLAY_BUFFER_H_ */ ./src/platforms/android/server/fb_device.h0000644000004100000410000000375013115234664021060 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_FB_DEVICE_H_ #define MIR_GRAPHICS_ANDROID_FB_DEVICE_H_ #include "display_device.h" #include "hwc_configuration.h" #include #include namespace mir { namespace graphics { namespace android { class FbControl : public HwcConfiguration { public: FbControl(std::shared_ptr const& fbdev); void power_mode(DisplayName, MirPowerMode) override; DisplayConfigurationOutput active_config_for(DisplayName) override; ConfigChangeSubscription subscribe_to_config_changes( std::function const& hotplug_cb, std::function const& vsync_cb) override; private: std::shared_ptr const fb_device; }; class FBDevice : public DisplayDevice { public: FBDevice(std::shared_ptr const& fbdev); bool compatible_renderlist(RenderableList const& renderlist) override; void commit(std::list const& contents) override; std::chrono::milliseconds recommended_sleep() const override; bool can_swap_buffers() const override; private: std::shared_ptr const fb_device; void content_cleared() override; }; } } } #endif /* MIR_GRAPHICS_ANDROID_FB_DEVICE_H_ */ ./src/platforms/android/server/symbols.map.in0000644000004100000410000000033113115234416021560 0ustar www-datawww-data@MIR_SERVER_GRAPHICS_PLATFORM_VERSION@ { global: add_graphics_platform_options; create_host_platform; create_guest_platform; probe_graphics_platform; describe_graphics_module; local: *; }; ./src/platforms/android/server/overlay_optimization.h0000644000004100000410000000175213115234416023434 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_OVERLAY_OPTIMIZATION_H_ #define MIR_GRAPHICS_ANDROID_OVERLAY_OPTIMIZATION_H_ namespace mir { namespace graphics { namespace android { enum class OverlayOptimization { disabled, enabled }; } } } #endif /* MIR_GRAPHICS_ANDROID_OVERLAY_OPTIMIZATION_H_ */ ./src/platforms/android/server/hwc_configuration.h0000644000004100000410000000600113115234664022652 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_ANDROID_HWC_CONFIGURATION_H_ #define MIR_GRAPHICS_ANDROID_HWC_CONFIGURATION_H_ #include "mir/graphics/display_configuration.h" #include "mir/graphics/frame.h" #include "mir/geometry/size.h" #include "display_name.h" #include #include namespace mir { namespace graphics { namespace android { using ConfigChangeSubscription = std::shared_ptr; //interface adapting for the blanking interface differences between fb, HWC 1.0-1.3, and HWC 1.4+ class HwcConfiguration { public: virtual ~HwcConfiguration() = default; virtual void power_mode(DisplayName, MirPowerMode) = 0; virtual DisplayConfigurationOutput active_config_for(DisplayName) = 0; virtual ConfigChangeSubscription subscribe_to_config_changes( std::function const& hotplug_cb, std::function const& vsync_cb) = 0; protected: HwcConfiguration() = default; HwcConfiguration(HwcConfiguration const&) = delete; HwcConfiguration& operator=(HwcConfiguration const&) = delete; }; class HwcWrapper; class HwcBlankingControl : public HwcConfiguration { public: HwcBlankingControl(std::shared_ptr const&); HwcBlankingControl(std::shared_ptr const&, MirPixelFormat format); void power_mode(DisplayName, MirPowerMode) override; DisplayConfigurationOutput active_config_for(DisplayName) override; ConfigChangeSubscription subscribe_to_config_changes( std::function const& hotplug_cb, std::function const& vsync_cb) override; private: std::shared_ptr const hwc_device; bool off; MirPixelFormat format; }; class HwcWrapper; class HwcPowerModeControl : public HwcConfiguration { public: HwcPowerModeControl(std::shared_ptr const&); void power_mode(DisplayName, MirPowerMode) override; DisplayConfigurationOutput active_config_for(DisplayName) override; ConfigChangeSubscription subscribe_to_config_changes( std::function const& hotplug_cb, std::function const& vsync_cb) override; private: std::shared_ptr const hwc_device; MirPixelFormat format; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_CONFIGURATION_H_ */ ./src/platforms/android/server/hal_component_factory.h0000644000004100000410000000535113115234416023521 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_ANDROID_HAL_COMPONENT_FACTORY_H_ #define MIR_GRAPHICS_ANDROID_HAL_COMPONENT_FACTORY_H_ #include "cmdstream_sync_factory.h" #include "display_component_factory.h" #include "display_resource_factory.h" namespace mir { namespace graphics { class DisplayReport; namespace android { class FramebufferBundle; class DisplayResourceFactory; class DisplayDevice; class HwcWrapper; class HwcReport; class DeviceQuirks; class CommandStreamSyncFactory; class GraphicBufferAllocator; //NOTE: this should be the only class that inspects the HWC version and assembles //the components accordingly class HalComponentFactory : public DisplayComponentFactory, public CommandStreamSyncFactory { public: HalComponentFactory( std::shared_ptr const& res_factory, std::shared_ptr const& hwc_report, std::shared_ptr const& quirks); std::unique_ptr create_command_stream_sync() override; std::unique_ptr create_framebuffers(DisplayConfigurationOutput const&) override; std::unique_ptr create_display_device() override; std::unique_ptr create_hwc_configuration() override; std::unique_ptr create_layer_list() override; std::shared_ptr the_buffer_allocator() override; private: std::unique_ptr create_command_stream_sync_factory(); std::shared_ptr const res_factory; std::shared_ptr const hwc_report; std::shared_ptr framebuffers; bool force_backup_display; size_t num_framebuffers; bool working_egl_sync; std::shared_ptr hwc_wrapper; std::shared_ptr fb_native; HwcVersion hwc_version; std::shared_ptr buffer_allocator; std::shared_ptr command_stream_sync_factory; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HAL_COMPONENT_FACTORY_H_ */ ./src/platforms/android/common/0000755000004100000410000000000013115234677016762 5ustar www-datawww-data./src/platforms/android/common/CMakeLists.txt0000644000004100000410000000047413115234664021523 0ustar www-datawww-datainclude_directories( ${server_common_include_dirs} include/ ) add_definitions( -DANDROID ) add_library( mirsharedandroid-static STATIC mir_native_window.cpp refcounted_buffer.cpp android_native_buffer.cpp syncfence.cpp egl_sync_fence.cpp egl_sync_extensions.cpp native_window_report.cpp ) ./src/platforms/android/common/native_window_report.cpp0000644000004100000410000001263313115234664023737 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/logging/logger.h" #include "native_window_report.h" #include #define CASE_KEY(var) case var: return out << #var; namespace mga = mir::graphics::android; namespace { struct NativePerformKey { int key; }; struct NativeQueryKey { int key; }; std::ostream& operator<<(std::ostream& out, NativeQueryKey key) { switch (key.key) { CASE_KEY(NATIVE_WINDOW_WIDTH) CASE_KEY(NATIVE_WINDOW_HEIGHT) CASE_KEY(NATIVE_WINDOW_FORMAT) CASE_KEY(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS) CASE_KEY(NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER) CASE_KEY(NATIVE_WINDOW_CONCRETE_TYPE) CASE_KEY(NATIVE_WINDOW_DEFAULT_WIDTH) CASE_KEY(NATIVE_WINDOW_DEFAULT_HEIGHT) CASE_KEY(NATIVE_WINDOW_TRANSFORM_HINT) CASE_KEY(NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND) CASE_KEY(NATIVE_WINDOW_CONSUMER_USAGE_BITS) CASE_KEY(NATIVE_WINDOW_STICKY_TRANSFORM) CASE_KEY(NATIVE_WINDOW_DEFAULT_DATASPACE) CASE_KEY(NATIVE_WINDOW_BUFFER_AGE) default: return out << "unknown query key: " << key.key; } } std::ostream& operator<<(std::ostream& out, NativePerformKey key) { switch (key.key) { CASE_KEY(NATIVE_WINDOW_SET_USAGE) CASE_KEY(NATIVE_WINDOW_CONNECT) CASE_KEY(NATIVE_WINDOW_DISCONNECT) CASE_KEY(NATIVE_WINDOW_SET_CROP) CASE_KEY(NATIVE_WINDOW_SET_BUFFER_COUNT) CASE_KEY(NATIVE_WINDOW_SET_BUFFERS_GEOMETRY) CASE_KEY(NATIVE_WINDOW_SET_BUFFERS_TRANSFORM) CASE_KEY(NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP) CASE_KEY(NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS) CASE_KEY(NATIVE_WINDOW_SET_BUFFERS_FORMAT) CASE_KEY(NATIVE_WINDOW_SET_SCALING_MODE) CASE_KEY(NATIVE_WINDOW_LOCK) CASE_KEY(NATIVE_WINDOW_UNLOCK_AND_POST) CASE_KEY(NATIVE_WINDOW_API_CONNECT) CASE_KEY(NATIVE_WINDOW_API_DISCONNECT) CASE_KEY(NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS) CASE_KEY(NATIVE_WINDOW_SET_POST_TRANSFORM_CROP) CASE_KEY(NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM) CASE_KEY(NATIVE_WINDOW_SET_SIDEBAND_STREAM) CASE_KEY(NATIVE_WINDOW_SET_BUFFERS_DATASPACE) CASE_KEY(NATIVE_WINDOW_SET_SURFACE_DAMAGE) default: return out << "unknown perform key: " << key.key; } } std::ostream& operator<<(std::ostream& out, mga::BufferEvent type) { switch (type) { case mga::BufferEvent::Queue: return out << "queueBuffer"; case mga::BufferEvent::Dequeue: return out << "dequeueBuffer"; case mga::BufferEvent::Cancel: return out << "cancelBuffer"; default: return out; } } std::ostream& operator<<(std::ostream& out, ANativeWindow const* window) { return out << "addr (" << static_cast(window) << "): "; } } mga::ConsoleNativeWindowReport::ConsoleNativeWindowReport( std::shared_ptr const& logger) : logger(logger) { } void mga::ConsoleNativeWindowReport::buffer_event( BufferEvent type, ANativeWindow const* win, ANativeWindowBuffer* buf, int fence) const { std::stringstream str; str << win << type << ": " << buf << ", fence: "; if ( fence > 0 ) str << fence; else str << "none"; logger->log(mir::logging::Severity::debug, str.str(), component_name); } void mga::ConsoleNativeWindowReport::buffer_event( BufferEvent type, ANativeWindow const* win, ANativeWindowBuffer* buf) const { std::stringstream str; str << win << type << "_deprecated: " << buf; logger->log(mir::logging::Severity::debug, str.str(), component_name); } void mga::ConsoleNativeWindowReport::query_event(ANativeWindow const* win, int type, int result) const { std::stringstream str; str << std::hex << win << "query: " << NativeQueryKey{type} << ": result: 0x" << result; logger->log(mir::logging::Severity::debug, str.str(), component_name); } void mga::ConsoleNativeWindowReport::perform_event( ANativeWindow const* win, int type, std::vector const& args) const { std::stringstream str; str << std::hex << win << "perform: " << NativePerformKey{type} << ": "; for (auto i = 0u; i < args.size(); i++) { if (i != 0u) str << ", "; str << "0x" << args[i]; } logger->log(mir::logging::Severity::debug, str.str(), component_name); } void mga::NullNativeWindowReport::buffer_event(mga::BufferEvent, ANativeWindow const*, ANativeWindowBuffer*, int) const { } void mga::NullNativeWindowReport::buffer_event(mga::BufferEvent, ANativeWindow const*, ANativeWindowBuffer*) const { } void mga::NullNativeWindowReport::query_event(ANativeWindow const*, int, int) const { } void mga::NullNativeWindowReport::perform_event(ANativeWindow const*, int, std::vector const&) const { } ./src/platforms/android/common/egl_sync_fence.cpp0000644000004100000410000000516113115234416022423 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "egl_sync_fence.h" #include #define MIR_LOG_COMPONENT "egl sync fence" #include "mir/log.h" #include namespace mg = mir::graphics; void mg::NullCommandSync::raise() { } void mg::NullCommandSync::reset() { } bool mg::NullCommandSync::wait_for(std::chrono::nanoseconds) { return true; } mg::EGLSyncFence::EGLSyncFence(std::shared_ptr const& egl) : egl(egl), fence_display(EGL_NO_DISPLAY), sync_point(EGL_NO_SYNC_KHR) { } mg::EGLSyncFence::~EGLSyncFence() { reset(); } void mg::EGLSyncFence::raise() { std::unique_lock lk(mutex); wait_for(lk, default_timeout); fence_display = eglGetCurrentDisplay(); if (fence_display == EGL_NO_DISPLAY) { log_error("no current display"); } sync_point = egl->eglCreateSyncKHR(fence_display, EGL_SYNC_FENCE_KHR, NULL); if (sync_point == EGL_NO_SYNC_KHR) { std::stringstream str; str << "failed to add sync point to command buffer: 0x" << std::hex << eglGetError(); log_error(str.str()); } } void mg::EGLSyncFence::reset() { std::unique_lock lk(mutex); reset(lk); } void mg::EGLSyncFence::reset(std::unique_lock const&) { if (sync_point != EGL_NO_SYNC_KHR) { egl->eglDestroySyncKHR(fence_display, sync_point); fence_display = EGL_NO_DISPLAY; sync_point = EGL_NO_SYNC_KHR; } } bool mg::EGLSyncFence::wait_for(std::chrono::nanoseconds ns) { std::unique_lock lk(mutex); return wait_for(lk, ns); } bool mg::EGLSyncFence::wait_for( std::unique_lock const& lk, std::chrono::nanoseconds ns) { auto status = EGL_CONDITION_SATISFIED_KHR; if (sync_point != EGL_NO_SYNC_KHR) { status = egl->eglClientWaitSyncKHR(fence_display, sync_point, 0, ns.count()); reset(lk); } return status == EGL_CONDITION_SATISFIED_KHR; } ./src/platforms/android/common/mir_native_window.cpp0000644000004100000410000002403013115234664023205 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir_native_window.h" #include "android_driver_interpreter.h" #include "sync_fence.h" #include "native_window_report.h" #define MIR_LOG_COMPONENT "AndroidWindow" #include "mir/uncaught.h" #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace { static int query_static(const ANativeWindow* anw, int key, int* value); static int perform_static(ANativeWindow* anw, int key, ...); static int setSwapInterval_static (struct ANativeWindow* window, int interval); static int dequeueBuffer_deprecated_static (struct ANativeWindow* window, struct ANativeWindowBuffer** buffer); static int dequeueBuffer_static (struct ANativeWindow* window, struct ANativeWindowBuffer** buffer, int* fence_fd); static int lockBuffer_static(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer); static int queueBuffer_deprecated_static(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer); static int queueBuffer_static(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer, int fence_fd); static int cancelBuffer_static(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer, int fence_fd); static int cancelBuffer_deprecated_static(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer); static void incRef(android_native_base_t*) { } int query_static(const ANativeWindow* anw, int key, int* value) { auto self = static_cast(anw); return self->query(key, value); } int perform_static(ANativeWindow* window, int key, ...) { va_list args; va_start(args, key); auto self = static_cast(window); auto ret = self->perform(key, args); va_end(args); return ret; } int dequeueBuffer_deprecated_static (struct ANativeWindow* window, struct ANativeWindowBuffer** buffer) { auto self = static_cast(window); return self->dequeueBufferAndWait(buffer); } int dequeueBuffer_static (struct ANativeWindow* window, struct ANativeWindowBuffer** buffer, int* fence_fd) { auto self = static_cast(window); return self->dequeueBuffer(buffer, fence_fd); } int queueBuffer_deprecated_static(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer) { auto self = static_cast(window); return self->queueBufferDeprecated(buffer); } int queueBuffer_static(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer, int fence_fd) { auto self = static_cast(window); return self->queueBuffer(buffer, fence_fd); } int setSwapInterval_static (struct ANativeWindow* window, int interval) { auto self = static_cast(window); return self->setSwapInterval(interval); } /* lockBuffer, and cancelBuffer don't seem to being called by the driver. for now just return without calling into MirNativeWindow */ int lockBuffer_static(struct ANativeWindow* /*window*/, struct ANativeWindowBuffer* /*buffer*/) { return 0; } int cancelBuffer_deprecated_static(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer) { auto self = static_cast(window); return self->cancelBufferDeprecated(buffer); } int cancelBuffer_static(struct ANativeWindow* window, struct ANativeWindowBuffer* buffer, int fence_fd) { auto self = static_cast(window); return self->cancelBuffer(buffer, fence_fd); } } mga::MirNativeWindow::MirNativeWindow( std::shared_ptr const& interpreter, std::shared_ptr const& report) : driver_interpreter(interpreter), report(report), sync_ops(std::make_shared()) { ANativeWindow::query = &query_static; ANativeWindow::perform = &perform_static; ANativeWindow::setSwapInterval = &setSwapInterval_static; ANativeWindow::dequeueBuffer_DEPRECATED = &dequeueBuffer_deprecated_static; ANativeWindow::dequeueBuffer = &dequeueBuffer_static; ANativeWindow::lockBuffer_DEPRECATED = &lockBuffer_static; ANativeWindow::queueBuffer_DEPRECATED = &queueBuffer_deprecated_static; ANativeWindow::queueBuffer = &queueBuffer_static; ANativeWindow::cancelBuffer_DEPRECATED = &cancelBuffer_deprecated_static; ANativeWindow::cancelBuffer = &cancelBuffer_static; ANativeWindow::common.incRef = &incRef; ANativeWindow::common.decRef = &incRef; const_cast(ANativeWindow::minSwapInterval) = 0; const_cast(ANativeWindow::maxSwapInterval) = 1; } int mga::MirNativeWindow::setSwapInterval(int interval) try { driver_interpreter->sync_to_display(interval != 0); return 0; } catch (std::exception const& e) { MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(e); return -1; } int mga::MirNativeWindow::dequeueBuffer(struct ANativeWindowBuffer** buffer_to_driver, int* fence_fd) try { if (cancelled_buffers.size() != 0) { *buffer_to_driver = cancelled_buffers.back(); cancelled_buffers.pop_back(); *fence_fd = -1; //no fence associated with cancelled buffers } else { auto buffer = driver_interpreter->driver_requests_buffer(); //EGL driver is responsible for closing this native handle *fence_fd = buffer->copy_fence(); *buffer_to_driver = buffer->anwb(); } report->buffer_event(mga::BufferEvent::Dequeue, this, *buffer_to_driver, *fence_fd); return 0; } catch (std::exception const& e) { MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(e); return -1; } int mga::MirNativeWindow::dequeueBufferAndWait(struct ANativeWindowBuffer** buffer_to_driver) try { if (cancelled_buffers.size() != 0) { *buffer_to_driver = cancelled_buffers.back(); cancelled_buffers.pop_back(); } else { auto buffer = driver_interpreter->driver_requests_buffer(); *buffer_to_driver = buffer->anwb(); buffer->ensure_available_for(mga::BufferAccess::write); } report->buffer_event(mga::BufferEvent::Dequeue, this, *buffer_to_driver); return 0; } catch (std::exception const& e) { MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(e); return -1; } int mga::MirNativeWindow::queueBuffer(struct ANativeWindowBuffer* buffer, int fence) try { report->buffer_event(mga::BufferEvent::Queue, this, buffer, fence); driver_interpreter->driver_returns_buffer(buffer, fence); return 0; } catch (std::exception const& e) { MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(e); return -1; } int mga::MirNativeWindow::queueBufferDeprecated(struct ANativeWindowBuffer* buffer) try { report->buffer_event(mga::BufferEvent::Queue, this, buffer); driver_interpreter->driver_returns_buffer(buffer, -1); return 0; } catch (std::exception const& e) { MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(e); return -1; } int mga::MirNativeWindow::cancelBuffer(struct ANativeWindowBuffer* buffer, int fence) try { report->buffer_event(mga::BufferEvent::Cancel, this, buffer, fence); mga::SyncFence sync_fence(sync_ops, mir::Fd(fence)); sync_fence.wait(); cancelled_buffers.push_back(buffer); return 0; } catch (std::exception const& e) { MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(e); return -1; } int mga::MirNativeWindow::cancelBufferDeprecated(struct ANativeWindowBuffer* buffer) try { report->buffer_event(mga::BufferEvent::Cancel, this, buffer); cancelled_buffers.push_back(buffer); return 0; } catch (std::exception const& e) { MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(e); return -1; } int mga::MirNativeWindow::query(int key, int* value) const try { *value = driver_interpreter->driver_requests_info(key); report->query_event(this, key, *value); return 0; } catch (std::exception const& e) { MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(e); return -1; } int mga::MirNativeWindow::perform(int key, va_list arg_list ) try { int ret = 0; va_list args; va_copy(args, arg_list); switch(key) { case NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS: { auto width = va_arg(args, int); auto height = va_arg(args, int); driver_interpreter->dispatch_driver_request_buffer_size({width, height}); break; } case NATIVE_WINDOW_SET_BUFFERS_FORMAT: { auto format = va_arg(args, int); driver_interpreter->dispatch_driver_request_format(format); report->perform_event(this, key, {format}); break; } case NATIVE_WINDOW_SET_BUFFER_COUNT: { auto count = va_arg(args, int); driver_interpreter->dispatch_driver_request_buffer_count(count); report->perform_event(this, key, {count}); break; } default: { report->perform_event(this, key, {}); break; } } va_end(args); return ret; } catch (std::exception const& e) { MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(e); return -1; } void mga::MirNativeWindow::use_native_surface( std::shared_ptr const& interpreter) { driver_interpreter = interpreter; } ./src/platforms/android/common/egl_sync_extensions.cpp0000644000004100000410000000260713115234416023544 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "egl_sync_extensions.h" #include #include namespace mg=mir::graphics; mg::EGLSyncExtensions::EGLSyncExtensions() : eglCreateSyncKHR{ reinterpret_cast(eglGetProcAddress("eglCreateSyncKHR"))}, eglDestroySyncKHR{ reinterpret_cast(eglGetProcAddress("eglDestroySyncKHR"))}, eglClientWaitSyncKHR{ reinterpret_cast(eglGetProcAddress("eglClientWaitSyncKHR"))} { if (!eglCreateSyncKHR || !eglDestroySyncKHR || !eglClientWaitSyncKHR) BOOST_THROW_EXCEPTION(std::runtime_error("EGL doesn't support the KHR_reusable_sync extension")); } ./src/platforms/android/common/syncfence.cpp0000644000004100000410000000477113115234664021450 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "sync_fence.h" #include #include #include // This will come from /usr/include/android{,-19}/ namespace mga = mir::graphics::android; mga::SyncFence::SyncFence(std::shared_ptr const& ops, Fd fd) : fence_fd(std::move(fd)), ops(ops) { } void mga::SyncFence::wait() { if (fence_fd > 0) { int timeout = infinite_timeout; ops->ioctl(fence_fd, SYNC_IOC_WAIT, &timeout); fence_fd = mir::Fd(Fd::invalid); } } bool mga::SyncFence::wait_for(std::chrono::milliseconds ms) { int timed_out = 0; if (fence_fd > 0) { int timeout = ms.count(); timed_out = ops->ioctl(fence_fd, SYNC_IOC_WAIT, &timeout); fence_fd = mir::Fd(Fd::invalid); } return timed_out >= 0; } void mga::SyncFence::reset_fence() { fence_fd = mir::Fd(mir::Fd::invalid); } void mga::SyncFence::merge_with(NativeFence& merge_fd) { if (merge_fd < 0) { return; } if (fence_fd < 0) { //our fence was invalid, adopt the other fence fence_fd = mir::Fd(merge_fd); } else { //both fences were valid, must merge struct sync_merge_data data { merge_fd, "mirfence", infinite_timeout }; ops->ioctl(fence_fd, static_cast(SYNC_IOC_MERGE), &data); ops->close(merge_fd); fence_fd = mir::Fd(data.fence); } merge_fd = -1; } mga::NativeFence mga::SyncFence::copy_native_handle() const { return ops->dup(fence_fd); } mga::NativeFence mga::SyncFence::native_handle() const { return fence_fd; } int mga::RealSyncFileOps::ioctl(int fd, int req, void* dat) { return ::ioctl(fd, req, dat); } int mga::RealSyncFileOps::dup(int fd) { return ::dup(fd); } int mga::RealSyncFileOps::close(int fd) { return ::close(fd); } ./src/platforms/android/common/refcounted_buffer.cpp0000644000004100000410000000367013115234416023152 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "android_native_buffer.h" namespace mga=mir::graphics::android; namespace { static void incref_hook(struct android_native_base_t* base) { auto buffer = reinterpret_cast(base); buffer->driver_reference(); } void decref_hook(struct android_native_base_t* base) { auto buffer = reinterpret_cast(base); buffer->driver_dereference(); } } void mga::RefCountedNativeBuffer::driver_reference() { std::unique_lock lk(mutex); driver_references++; } void mga::RefCountedNativeBuffer::driver_dereference() { std::unique_lock lk(mutex); driver_references--; if ((!mir_reference) && (driver_references == 0)) { lk.unlock(); delete this; } } void mga::RefCountedNativeBuffer::mir_dereference() { std::unique_lock lk(mutex); mir_reference = false; if (driver_references == 0) { lk.unlock(); delete this; } } mga::RefCountedNativeBuffer::RefCountedNativeBuffer( std::shared_ptr const& handle) : handle_resource(handle), mir_reference(true), driver_references(0) { common.incRef = incref_hook; common.decRef = decref_hook; } ./src/platforms/android/common/android_native_buffer.cpp0000644000004100000410000000617713115234664024014 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "command_stream_sync.h" #include "android_native_buffer.h" #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; mga::AndroidNativeBuffer::AndroidNativeBuffer( std::shared_ptr const& anwb, std::shared_ptr const& cmdstream_sync, std::shared_ptr const& fence, BufferAccess access) : cmdstream_sync(cmdstream_sync), fence_(fence), access(access), native_window_buffer(anwb) { } void mga::AndroidNativeBuffer::ensure_available_for(BufferAccess intent) { if ((access == mga::BufferAccess::read) && (intent == mga::BufferAccess::read)) return; fence_->wait(); } bool mga::AndroidNativeBuffer::ensure_available_for(BufferAccess intent, std::chrono::milliseconds ms) { if ((access == mga::BufferAccess::read) && (intent == mga::BufferAccess::read)) return true; return fence_->wait_for(ms); } void mga::AndroidNativeBuffer::update_usage(NativeFence& merge_fd, BufferAccess updated_access) { fence_->merge_with(merge_fd); access = updated_access; } void mga::AndroidNativeBuffer::reset_fence() { fence_->reset_fence(); } ANativeWindowBuffer* mga::AndroidNativeBuffer::anwb() const { return native_window_buffer.get(); } buffer_handle_t mga::AndroidNativeBuffer::handle() const { return native_window_buffer->handle; } mga::NativeFence mga::AndroidNativeBuffer::copy_fence() const { return fence_->copy_native_handle(); } mga::NativeFence mga::AndroidNativeBuffer::fence() const { return fence_->native_handle(); } void mga::AndroidNativeBuffer::lock_for_gpu() { cmdstream_sync->raise(); } void mga::AndroidNativeBuffer::wait_for_unlock_by_gpu() { using namespace std::chrono; cmdstream_sync->wait_for(duration_cast(seconds(2))); } mga::NativeBuffer* mga::to_native_buffer_checked(mg::NativeBuffer* buffer) { if (auto native = dynamic_cast(buffer)) return native; BOOST_THROW_EXCEPTION(std::invalid_argument("cannot downcast mg::NativeBuffer to android::NativeBuffer")); } std::shared_ptr mga::to_native_buffer_checked(std::shared_ptr const& buffer) { if (auto native = std::dynamic_pointer_cast(buffer)) return native; BOOST_THROW_EXCEPTION(std::invalid_argument("cannot downcast mg::NativeBuffer to android::NativeBuffer")); } ./src/platforms/mesa/0000755000004100000410000000000013115234677014777 5ustar www-datawww-data./src/platforms/mesa/CMakeLists.txt0000644000004100000410000000117313115234664017535 0ustar www-datawww-dataset(INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/mir-client-platform-mesa.pc.in ${CMAKE_CURRENT_BINARY_DIR}/mir-client-platform-mesa.pc @ONLY ) include_directories( ${CMAKE_SOURCE_DIR}/include/platforms/mesa ${PROJECT_SOURCE_DIR}/src/platforms/mesa/include/ ) add_subdirectory(common/) add_subdirectory(server/) add_subdirectory(client/) install( DIRECTORY ${CMAKE_SOURCE_DIR}/include/platforms/mesa/mir_toolkit DESTINATION "include/mirplatform" ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/mir-client-platform-mesa.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) ./src/platforms/mesa/include/0000755000004100000410000000000013115234667016421 5ustar www-datawww-data./src/platforms/mesa/include/native_buffer.h0000644000004100000410000000225613115234664021413 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_MESA_NATIVE_BUFFER_H_ #define MIR_GRAPHICS_MESA_NATIVE_BUFFER_H_ #include #include "mir/graphics/native_buffer.h" #include #include namespace mir { namespace graphics { namespace mesa { struct NativeBuffer : graphics::NativeBuffer, MirBufferPackage { struct gbm_bo *bo; bool is_gbm_buffer; uint32_t native_format; uint32_t native_flags; }; } } } #endif /* MIR_GRAPHICS_MESA_NATIVE_BUFFER_H_ */ ./src/platforms/mesa/include/gbm_format_conversions.h0000644000004100000410000000226213115234664023336 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois * */ #ifndef MIR_GRAPHICS_MESA_GBM_FORMAT_CONVERSIONS_H_ #define MIR_GRAPHICS_MESA_GBM_FORMAT_CONVERSIONS_H_ #include #include #include namespace mir { namespace graphics { namespace mesa { enum : uint32_t { invalid_gbm_format = std::numeric_limits::max() }; MirPixelFormat gbm_format_to_mir_format(uint32_t format); uint32_t mir_format_to_gbm_format(MirPixelFormat format); } } } #endif /* MIR_GRAPHICS_MESA_GBM_FORMAT_CONVERSIONS_H_ */ ./src/platforms/mesa/mir-client-platform-mesa.pc.in0000644000004100000410000000030713115234416022527 0ustar www-datawww-dataincludedir=@INCLUDEDIR@/mirplatform Name: mir-client-platform-mesa Description: Mir Mesa client platform development files Version: @MIR_VERSION@ Requires.private: mirclient Cflags: -I${includedir} ./src/platforms/mesa/client/0000755000004100000410000000000013115234677016255 5ustar www-datawww-data./src/platforms/mesa/client/CMakeLists.txt0000644000004100000410000000174713115234664021022 0ustar www-datawww-datainclude_directories(${client_common_include_dirs}) include_directories( ${DRM_INCLUDE_DIRS} ${EGL_INCLUDE_DIRS} ) set(symbol_map ${CMAKE_CURRENT_SOURCE_DIR}/symbols.map) add_library(mirclientplatformmesaobjects OBJECT client_platform_factory.cpp client_platform.cpp client_buffer_factory.cpp client_buffer.cpp mesa_native_display_container.cpp native_surface.cpp ) add_library(mirclientplatformmesa MODULE $ ) set_target_properties( mirclientplatformmesa PROPERTIES OUTPUT_NAME mesa LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/client-modules PREFIX "" SUFFIX ".so.${MIR_CLIENT_PLATFORM_ABI}" LINK_FLAGS "-Wl,--version-script,${symbol_map}" LINK_DEPENDS ${symbol_map} ) target_link_libraries(mirclientplatformmesa mirclient mirsharedmesa-static client_platform_common ${DRM_LDFLAGS} ${DRM_LIBRARIES} ) install(TARGETS mirclientplatformmesa LIBRARY DESTINATION ${MIR_CLIENT_PLATFORM_PATH}) ./src/platforms/mesa/client/symbols.map0000644000004100000410000000030313115234416020427 0ustar www-datawww-dataMIR_CLIENT_PLATFORM_5 { global: create_client_platform; is_appropriate_module; # Needed by our Mesa EGL platform mir_client_mesa_egl_native_display_is_valid; local: *; }; ./src/platforms/mesa/client/mesa_native_display_container.cpp0000644000004100000410000000634413115234416025041 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #include "mesa_native_display_container.h" #include "mir/client_platform.h" #include #include #include namespace mcl = mir::client; namespace mclm = mcl::mesa; namespace { extern "C" { static int egl_display_get_platform(MirMesaEGLNativeDisplay* display, MirPlatformPackage* package) { auto platform = static_cast(display->context); platform->populate(*package); return MIR_MESA_TRUE; } int mir_client_mesa_egl_native_display_is_valid(MirMesaEGLNativeDisplay* display) { return mcl::EGLNativeDisplayContainer::instance().validate(display); } } // default_display_container needs to live until the library is unloaded std::mutex default_display_container_mutex; mclm::MesaNativeDisplayContainer* default_display_container{nullptr}; extern "C" int __attribute__((destructor)) destroy() { std::lock_guard lock(default_display_container_mutex); delete default_display_container; return 0; } } mcl::EGLNativeDisplayContainer& mcl::EGLNativeDisplayContainer::instance() { std::lock_guard lock(default_display_container_mutex); if (!default_display_container) default_display_container = new mclm::MesaNativeDisplayContainer; return *default_display_container; } mclm::MesaNativeDisplayContainer::MesaNativeDisplayContainer() { } mclm::MesaNativeDisplayContainer::~MesaNativeDisplayContainer() { std::lock_guard lg(guard); for (auto display : valid_displays) { delete static_cast(display); } } bool mclm::MesaNativeDisplayContainer::validate(MirEGLNativeDisplayType display) const { std::lock_guard lg(guard); return (valid_displays.find(display) != valid_displays.end()); } MirEGLNativeDisplayType mclm::MesaNativeDisplayContainer::create(client::ClientPlatform* platform) { MirMesaEGLNativeDisplay* display = new MirMesaEGLNativeDisplay(); display->display_get_platform = egl_display_get_platform; display->context = platform; std::lock_guard lg(guard); auto egl_display = static_cast(display); valid_displays.insert(egl_display); return egl_display; } void mclm::MesaNativeDisplayContainer::release(MirEGLNativeDisplayType display) { std::lock_guard lg(guard); auto it = valid_displays.find(display); if (it == valid_displays.end()) return; delete static_cast(*it); valid_displays.erase(it); } ./src/platforms/mesa/client/mesa_native_display_container.h0000644000004100000410000000346713115234416024511 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Robert Carr */ #ifndef MIR_CLIENT_MESA_MESA_NATIVE_DISPLAY_CONTAINER_H_ #define MIR_CLIENT_MESA_MESA_NATIVE_DISPLAY_CONTAINER_H_ #include "mir/egl_native_display_container.h" #include "mir_toolkit/client_types.h" #include "mir_toolkit/mesa/native_display.h" #include #include namespace mir { namespace client { namespace mesa { class MesaNativeDisplayContainer : public EGLNativeDisplayContainer { public: MesaNativeDisplayContainer(); virtual ~MesaNativeDisplayContainer(); MirEGLNativeDisplayType create(client::ClientPlatform* platform); void release(MirEGLNativeDisplayType display); bool validate(MirEGLNativeDisplayType display) const; protected: MesaNativeDisplayContainer(MesaNativeDisplayContainer const&) = delete; MesaNativeDisplayContainer& operator=(MesaNativeDisplayContainer const&) = delete; private: std::mutex mutable guard; std::unordered_set valid_displays; }; extern "C" int mir_client_mesa_egl_native_display_is_valid(MirMesaEGLNativeDisplay* display); } } } // namespace mir #endif // MIR_CLIENT_MESA_MESA_NATIVE_DISPLAY_CONTAINER_H_ ./src/platforms/mesa/client/client_platform.h0000644000004100000410000000543313115234664021611 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_CLIENT_MESA_CLIENT_PLATFORM_H_ #define MIR_CLIENT_MESA_CLIENT_PLATFORM_H_ #include "mir/client_platform.h" #include "mir_toolkit/extensions/mesa_drm_auth.h" #include "mir_toolkit/extensions/set_gbm_device.h" #include "mir_toolkit/extensions/gbm_buffer.h" #include "mir_toolkit/extensions/hardware_buffer_stream.h" struct gbm_device; namespace mir { namespace client { class EGLNativeDisplayContainer; namespace mesa { class BufferFileOps; class ClientPlatform : public client::ClientPlatform { public: ClientPlatform(ClientContext* const context, std::shared_ptr const& buffer_file_ops, EGLNativeDisplayContainer& display_container); MirPlatformType platform_type() const override; void populate(MirPlatformPackage& package) const override; MirPlatformMessage* platform_operation(MirPlatformMessage const* request) override; std::shared_ptr create_buffer_factory() override; void* request_interface(char const* name, int version) override; std::shared_ptr create_egl_native_window(EGLNativeSurface* surface) override; void use_egl_native_window(std::shared_ptr native_window, EGLNativeSurface* surface) override; std::shared_ptr create_egl_native_display() override; MirNativeBuffer* convert_native_buffer(graphics::NativeBuffer*) const override; MirPixelFormat get_egl_pixel_format(EGLDisplay, EGLConfig) const override; void set_gbm_device(gbm_device*); uint32_t native_format_for(MirPixelFormat) const override; uint32_t native_flags_for(MirBufferUsage, mir::geometry::Size) const override; private: ClientContext* const context; std::shared_ptr const buffer_file_ops; EGLNativeDisplayContainer& display_container; gbm_device* gbm_dev; MirExtensionMesaDRMAuthV1 drm_extensions; MirExtensionSetGbmDeviceV1 mesa_auth; MirExtensionGbmBufferV1 gbm_buffer1; MirExtensionGbmBufferV2 gbm_buffer2; MirExtensionHardwareBufferStreamV1 hw_stream; }; } } } #endif /* MIR_CLIENT_MESA_CLIENT_PLATFORM_H_ */ ./src/platforms/mesa/client/client_platform.cpp0000644000004100000410000003261213115234664022143 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir_toolkit/mir_client_library.h" #include "client_platform.h" #include "client_buffer_factory.h" #include "mesa_native_display_container.h" #include "native_surface.h" #include "mir/client_buffer_factory.h" #include "mir/client_context.h" #include "mir/client_buffer.h" #include "mir/mir_render_surface.h" #include "mir/mir_buffer.h" #include "mir/weak_egl.h" #include "mir/platform_message.h" #include "mir_toolkit/mesa/platform_operation.h" #include "native_buffer.h" #include "gbm_format_conversions.h" #include #include #include #include #include namespace mgm=mir::graphics::mesa; namespace mcl=mir::client; namespace mclm=mir::client::mesa; namespace geom=mir::geometry; namespace { struct NativeDisplayDeleter { NativeDisplayDeleter(mcl::EGLNativeDisplayContainer& container) : container(container) { } void operator() (EGLNativeDisplayType* p) { auto display = *(reinterpret_cast(p)); container.release(display); delete p; } mcl::EGLNativeDisplayContainer& container; }; constexpr size_t division_ceiling(size_t a, size_t b) { return ((a - 1) / b) + 1; } struct AuthFdContext { MirAuthFdCallback cb; void* context; }; void auth_fd_cb( MirConnection*, MirPlatformMessage* reply, void* context) { AuthFdContext* ctx = reinterpret_cast(context); int auth_fd{-1}; if (reply->fds.size() == 1) auth_fd = reply->fds[0]; ctx->cb(auth_fd, ctx->context); delete ctx; } void auth_fd_ext(MirConnection* conn, MirAuthFdCallback cb, void* context) { auto connection = reinterpret_cast(conn); MirPlatformMessage msg(MirMesaPlatformOperation::auth_fd); auto ctx = new AuthFdContext{cb, context}; connection->platform_operation(&msg, auth_fd_cb, ctx); } struct AuthMagicContext { MirAuthMagicCallback cb; void* context; }; void auth_magic_cb(MirConnection*, MirPlatformMessage* reply, void* context) { AuthMagicContext* ctx = reinterpret_cast(context); int auth_magic_response{-1}; if (reply->data.size() == sizeof(auth_magic_response)) memcpy(&auth_magic_response, reply->data.data(), sizeof(auth_magic_response)); ctx->cb(auth_magic_response, ctx->context); delete ctx; } void auth_magic_ext(MirConnection* conn, int magic, MirAuthMagicCallback cb, void* context) { auto connection = reinterpret_cast(conn); MirPlatformMessage msg(MirMesaPlatformOperation::auth_magic); auto m = reinterpret_cast(&magic); msg.data.assign(m, m + sizeof(magic)); auto ctx = new AuthMagicContext{cb, context}; connection->platform_operation(&msg, auth_magic_cb, ctx); } void set_device(gbm_device* device, void* context) { auto platform = reinterpret_cast(context); platform->set_gbm_device(device); } void allocate_buffer_gbm( MirConnection* connection, uint32_t width, uint32_t height, uint32_t gbm_pixel_format, uint32_t gbm_bo_flags, MirBufferCallback available_callback, void* available_context) { auto context = mcl::to_client_context(connection); context->allocate_buffer( mir::geometry::Size{width, height}, gbm_pixel_format, gbm_bo_flags, available_callback, available_context); } void allocate_buffer_gbm_legacy( MirConnection* connection, int width, int height, unsigned int gbm_pixel_format, unsigned int gbm_bo_flags, MirBufferCallback available_callback, void* available_context) { allocate_buffer_gbm( connection, static_cast(width), static_cast(height), static_cast(gbm_pixel_format), static_cast(gbm_bo_flags), available_callback, available_context); } MirBuffer* allocate_buffer_gbm_sync( MirConnection* connection, uint32_t width, uint32_t height, uint32_t gbm_pixel_format, uint32_t gbm_bo_flags) try { struct BufferSync { void set_buffer(MirBuffer* b) { std::unique_lock lk(mutex); buffer = b; cv.notify_all(); } MirBuffer* wait_for_buffer() { std::unique_lock lk(mutex); cv.wait(lk, [this]{ return buffer; }); return buffer; } private: std::mutex mutex; std::condition_variable cv; MirBuffer* buffer = nullptr; } sync; allocate_buffer_gbm( connection, width, height, gbm_pixel_format, gbm_bo_flags, [](auto* b, auto* context){ reinterpret_cast(context)->set_buffer(b); }, &sync); return sync.wait_for_buffer(); } catch (...) { return nullptr; } bool is_gbm_importable(MirBuffer* b) try { if (!b) return false; auto buffer = reinterpret_cast(b); auto native = dynamic_cast(buffer->client_buffer()->native_buffer_handle().get()); if (!native) return false; return native->is_gbm_buffer; } catch (...) { return false; } int import_fd(MirBuffer* b) try { if (!is_gbm_importable(b)) return -1; auto buffer = reinterpret_cast(b); auto native = dynamic_cast(buffer->client_buffer()->native_buffer_handle().get()); return native->fd[0]; } catch (...) { return -1; } uint32_t buffer_stride(MirBuffer* b) try { if (!is_gbm_importable(b)) return 0; auto buffer = reinterpret_cast(b); auto native = dynamic_cast(buffer->client_buffer()->native_buffer_handle().get()); return native->stride; } catch (...) { return 0; } uint32_t buffer_format(MirBuffer* b) try { if (!is_gbm_importable(b)) return 0; auto buffer = reinterpret_cast(b); auto native = dynamic_cast(buffer->client_buffer()->native_buffer_handle().get()); return native->native_format; } catch (...) { return 0; } uint32_t buffer_flags(MirBuffer* b) try { if (!is_gbm_importable(b)) return 0; auto buffer = reinterpret_cast(b); auto native = dynamic_cast(buffer->client_buffer()->native_buffer_handle().get()); return native->native_flags; } catch (...) { return 0; } unsigned int buffer_age(MirBuffer* b) try { if (!is_gbm_importable(b)) return 0; auto buffer = reinterpret_cast(b); auto native = dynamic_cast(buffer->client_buffer()->native_buffer_handle().get()); return native->age; } catch (...) { return 0; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" MirBufferStream* get_hw_stream( MirRenderSurface* rs_key, int width, int height, MirPixelFormat format) { auto rs = mcl::render_surface_lookup(rs_key); if (!rs) return nullptr; return rs->get_buffer_stream(width, height, format, mir_buffer_usage_hardware); } #pragma GCC diagnostic pop } void mclm::ClientPlatform::set_gbm_device(gbm_device* device) { gbm_dev = device; } mclm::ClientPlatform::ClientPlatform( ClientContext* const context, std::shared_ptr const& buffer_file_ops, mcl::EGLNativeDisplayContainer& display_container) : context{context}, buffer_file_ops{buffer_file_ops}, display_container(display_container), gbm_dev{nullptr}, drm_extensions{auth_fd_ext, auth_magic_ext}, mesa_auth{set_device, this}, gbm_buffer1{allocate_buffer_gbm_legacy}, gbm_buffer2{allocate_buffer_gbm, allocate_buffer_gbm_sync, is_gbm_importable, import_fd, buffer_stride, buffer_format, buffer_flags, buffer_age}, hw_stream{get_hw_stream} { } std::shared_ptr mclm::ClientPlatform::create_buffer_factory() { return std::make_shared(buffer_file_ops); } void mclm::ClientPlatform::use_egl_native_window(std::shared_ptr native_window, EGLNativeSurface* surface) { auto mnw = std::static_pointer_cast(native_window); mnw->use_native_surface(surface); } std::shared_ptr mclm::ClientPlatform::create_egl_native_window(EGLNativeSurface* client_surface) { return std::make_shared(client_surface); } std::shared_ptr mclm::ClientPlatform::create_egl_native_display() { MirEGLNativeDisplayType *mir_native_display = new MirEGLNativeDisplayType; *mir_native_display = display_container.create(this); auto egl_native_display = reinterpret_cast(mir_native_display); return std::shared_ptr(egl_native_display, NativeDisplayDeleter(display_container)); } MirPlatformType mclm::ClientPlatform::platform_type() const { return mir_platform_type_gbm; } void mclm::ClientPlatform::populate(MirPlatformPackage& package) const { size_t constexpr pointer_size_in_ints = division_ceiling(sizeof(gbm_dev), sizeof(int)); context->populate_server_package(package); auto const total_data_size = package.data_items + pointer_size_in_ints; if (gbm_dev && total_data_size <= mir_platform_package_max) { int gbm_ptr[pointer_size_in_ints]{}; std::memcpy(&gbm_ptr, &gbm_dev, sizeof(gbm_dev)); for (auto i : gbm_ptr) package.data[package.data_items++] = i; } } MirPlatformMessage* mclm::ClientPlatform::platform_operation( MirPlatformMessage const* msg) { if (msg->opcode == MirMesaPlatformOperation::set_gbm_device && msg->data.size() == sizeof(MirMesaSetGBMDeviceRequest)) { MirMesaSetGBMDeviceRequest set_gbm_device_request{nullptr}; std::memcpy(&set_gbm_device_request, msg->data.data(), msg->data.size()); gbm_dev = set_gbm_device_request.device; static int const success{0}; MirMesaSetGBMDeviceResponse response{success}; auto response_msg = new MirPlatformMessage(msg->opcode); auto r = reinterpret_cast(&response); response_msg->data.assign(r, r + sizeof(response)); return response_msg; } return nullptr; } MirNativeBuffer* mclm::ClientPlatform::convert_native_buffer(graphics::NativeBuffer* buf) const { if (auto native = dynamic_cast(buf)) return native; BOOST_THROW_EXCEPTION(std::invalid_argument("could not convert NativeBuffer")); } MirPixelFormat mclm::ClientPlatform::get_egl_pixel_format( EGLDisplay disp, EGLConfig conf) const { MirPixelFormat mir_format = mir_pixel_format_invalid; /* * This is based on gbm_dri_is_format_supported() however we can't call it * via the public API gbm_device_is_format_supported because that is * too buggy right now (LP: #1473901). * * Ideally Mesa should implement EGL_NATIVE_VISUAL_ID for all platforms * to explicitly return the exact GBM pixel format. But it doesn't do that * yet (for most platforms). It does however successfully return zero for * EGL_NATIVE_VISUAL_ID, so ignore that for now. */ EGLint r = 0, g = 0, b = 0, a = 0; mcl::WeakEGL weak; weak.eglGetConfigAttrib(disp, conf, EGL_RED_SIZE, &r); weak.eglGetConfigAttrib(disp, conf, EGL_GREEN_SIZE, &g); weak.eglGetConfigAttrib(disp, conf, EGL_BLUE_SIZE, &b); weak.eglGetConfigAttrib(disp, conf, EGL_ALPHA_SIZE, &a); if (r == 8 && g == 8 && b == 8) { // GBM is very limited, which at least makes this simple... if (a == 8) mir_format = mir_pixel_format_argb_8888; else if (a == 0) mir_format = mir_pixel_format_xrgb_8888; } return mir_format; } void* mclm::ClientPlatform::request_interface(char const* extension_name, int version) { if (!strcmp("mir_extension_mesa_drm_auth", extension_name) && (version == 1)) return &drm_extensions; if (!strcmp(extension_name, "mir_extension_set_gbm_device") && (version == 1)) return &mesa_auth; if (!strcmp(extension_name, "mir_extension_gbm_buffer") && (version == 1)) return &gbm_buffer1; if (!strcmp(extension_name, "mir_extension_gbm_buffer") && (version == 2)) return &gbm_buffer2; if (!strcmp(extension_name, "mir_extension_hardware_buffer_stream") && (version == 1)) return &hw_stream; return nullptr; } uint32_t mclm::ClientPlatform::native_format_for(MirPixelFormat format) const { return mgm::mir_format_to_gbm_format(format); } uint32_t mclm::ClientPlatform::native_flags_for(MirBufferUsage, mir::geometry::Size size) const { uint32_t bo_flags{GBM_BO_USE_RENDERING}; if (size.width.as_uint32_t() >= 800 && size.height.as_uint32_t() >= 600) bo_flags |= GBM_BO_USE_SCANOUT; return bo_flags; } ./src/platforms/mesa/client/buffer_file_ops.h0000644000004100000410000000246713115234416021557 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_CLIENT_MESA_BUFFER_FILE_OPS_ #define MIR_CLIENT_MESA_BUFFER_FILE_OPS_ #include namespace mir { namespace client { namespace mesa { class BufferFileOps { public: virtual ~BufferFileOps() = default; virtual int close(int fd) const = 0; virtual void* map(int fd, off_t offset, size_t size) const = 0; virtual void unmap(void* addr, size_t size) const = 0; protected: BufferFileOps() = default; BufferFileOps(BufferFileOps const&) = delete; BufferFileOps& operator=(BufferFileOps const&) = delete; }; } } } #endif /* MIR_CLIENT_MESA_BUFFER_FILE_OPS_ */ ./src/platforms/mesa/client/client_buffer.cpp0000644000004100000410000001515713115234664021575 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir_toolkit/mir_client_library.h" #include "client_buffer.h" #include "buffer_file_ops.h" #include "gbm_format_conversions.h" #include #include #include #include #include namespace mcl=mir::client; namespace mclm=mir::client::mesa; namespace geom=mir::geometry; namespace { struct NullDeleter { void operator()(char *) const {} }; struct ShmMemoryRegion : mcl::MemoryRegion { ShmMemoryRegion(std::shared_ptr const& buffer_file_ops, int buffer_fd, geom::Size const& size_param, geom::Stride stride_param, MirPixelFormat format_param) : buffer_file_ops{buffer_file_ops}, size_in_bytes{size_param.height.as_uint32_t() * stride_param.as_uint32_t()} { static off_t const map_offset = 0; width = size_param.width; height = size_param.height; stride = stride_param; format = format_param; void* map = buffer_file_ops->map(buffer_fd, map_offset, size_in_bytes); if (map == MAP_FAILED) { std::string msg("Failed to mmap buffer"); BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error(msg)) << boost::errinfo_errno(errno)); } vaddr = std::shared_ptr(static_cast(map), NullDeleter()); } ~ShmMemoryRegion() { buffer_file_ops->unmap(vaddr.get(), size_in_bytes); } std::shared_ptr const buffer_file_ops; size_t const size_in_bytes; }; std::shared_ptr to_native_buffer( MirBufferPackage const& package, bool gbm, uint32_t native_format, uint32_t native_flags) { auto buffer = std::make_shared(); *static_cast(buffer.get()) = package; buffer->is_gbm_buffer = gbm; buffer->native_format = native_format; buffer->native_flags = native_flags; return buffer; } } mclm::ClientBuffer::ClientBuffer( std::shared_ptr const& buffer_file_ops, std::shared_ptr const& package, geom::Size size, MirPixelFormat pf) : buffer_file_ops{buffer_file_ops}, creation_package{to_native_buffer(*package, false, 0, 0)}, rect({geom::Point{0, 0}, size}), buffer_pf{pf}, egl_image_attrs{ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_WIDTH, static_cast(creation_package->width), EGL_HEIGHT, static_cast(creation_package->height), EGL_LINUX_DRM_FOURCC_EXT, static_cast(mir::graphics::mesa::mir_format_to_gbm_format(buffer_pf)), EGL_DMA_BUF_PLANE0_FD_EXT, creation_package->fd[0], EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, EGL_DMA_BUF_PLANE0_PITCH_EXT, static_cast(creation_package->stride), EGL_NONE} { if (pf == mir_pixel_format_invalid) BOOST_THROW_EXCEPTION(std::invalid_argument("cannot create buffer with mir_pixel_format_invalid")); if (package->fd_items != 1) { BOOST_THROW_EXCEPTION(std::runtime_error( "Buffer package does not contain the expected number of fd items")); } } mclm::ClientBuffer::ClientBuffer( std::shared_ptr const& buffer_file_ops, std::shared_ptr const& package, geometry::Size size, unsigned int native_pf, unsigned int native_flags) : buffer_file_ops{buffer_file_ops}, creation_package{to_native_buffer(*package, true, native_pf, native_flags)}, rect({geom::Point{0, 0}, size}), buffer_pf{mir::graphics::mesa::gbm_format_to_mir_format(native_pf)}, egl_image_attrs{ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_WIDTH, static_cast(creation_package->width), EGL_HEIGHT, static_cast(creation_package->height), EGL_LINUX_DRM_FOURCC_EXT, static_cast(native_pf), EGL_DMA_BUF_PLANE0_FD_EXT, creation_package->fd[0], EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, EGL_DMA_BUF_PLANE0_PITCH_EXT, static_cast(creation_package->stride), EGL_NONE} { } mclm::ClientBuffer::~ClientBuffer() noexcept { // TODO (@raof): Error reporting? It should not be possible for this to fail; if it does, // something's seriously wrong. buffer_file_ops->close(creation_package->fd[0]); } std::shared_ptr mclm::ClientBuffer::secure_for_cpu_write() { int const buffer_fd = creation_package->fd[0]; return std::make_shared(buffer_file_ops, buffer_fd, size(), stride(), pixel_format()); } geom::Size mclm::ClientBuffer::size() const { return rect.size; } geom::Stride mclm::ClientBuffer::stride() const { return geom::Stride{creation_package->stride}; } MirPixelFormat mclm::ClientBuffer::pixel_format() const { return buffer_pf; } std::shared_ptr mclm::ClientBuffer::native_buffer_handle() const { creation_package->age = age(); return creation_package; } void mclm::ClientBuffer::update_from(MirBufferPackage const&) { } void mclm::ClientBuffer::fill_update_msg(MirBufferPackage& package) { package.data_items = 0; package.fd_items = 0; } MirBufferPackage* mclm::ClientBuffer::package() const { if (auto native = dynamic_cast(native_buffer_handle().get())) return native; BOOST_THROW_EXCEPTION(std::invalid_argument("could not convert NativeBuffer")); } void mclm::ClientBuffer::egl_image_creation_parameters( EGLenum* type, EGLClientBuffer* client_buffer, EGLint** attrs) { *attrs = egl_image_attrs.data(); *type = EGL_LINUX_DMA_BUF_EXT; *client_buffer = nullptr; } ./src/platforms/mesa/client/client_buffer.h0000644000004100000410000000450013115234664021230 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Kevin DuBois */ #ifndef MIR_CLIENT_MESA_CLIENT_BUFFER_H_ #define MIR_CLIENT_MESA_CLIENT_BUFFER_H_ #include "mir/aging_buffer.h" #include "mir_toolkit/mir_client_library.h" #include "mir/geometry/rectangle.h" #include "native_buffer.h" #include #include namespace mir { namespace client { namespace mesa { class BufferFileOps; class ClientBuffer : public AgingBuffer { public: ClientBuffer(std::shared_ptr const& buffer_file_ops, std::shared_ptr const& buffer_package, geometry::Size size, MirPixelFormat pf); ClientBuffer(std::shared_ptr const& buffer_file_ops, std::shared_ptr const& buffer_package, geometry::Size size, unsigned int native_pf, unsigned int native_flags); ~ClientBuffer() noexcept; std::shared_ptr secure_for_cpu_write(); geometry::Size size() const; geometry::Stride stride() const; MirPixelFormat pixel_format() const; std::shared_ptr native_buffer_handle() const; void update_from(MirBufferPackage const&); void fill_update_msg(MirBufferPackage&); MirBufferPackage* package() const; void egl_image_creation_parameters(EGLenum*, EGLClientBuffer*, EGLint**); private: std::shared_ptr const buffer_file_ops; std::shared_ptr const creation_package; geometry::Rectangle const rect; MirPixelFormat const buffer_pf; std::vector egl_image_attrs; }; } } } #endif /* MIR_CLIENT_MESA_CLIENT_BUFFER_H_ */ ./src/platforms/mesa/client/client_buffer_factory.h0000644000004100000410000000307013115234664022760 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Christopher James Halse Rogers */ #ifndef MIR_CLIENT_MESA_CLIENT_BUFFER_FACTORY_H_ #define MIR_CLIENT_MESA_CLIENT_BUFFER_FACTORY_H_ #include "mir/client_buffer_factory.h" namespace mir { namespace client { namespace mesa { class BufferFileOps; class ClientBufferFactory : public client::ClientBufferFactory { public: explicit ClientBufferFactory(std::shared_ptr const& buffer_file_ops); std::shared_ptr create_buffer( std::shared_ptr const& package, geometry::Size size, MirPixelFormat pf); std::shared_ptr create_buffer( std::shared_ptr const& package, unsigned int native_pf, unsigned int native_flags); private: std::shared_ptr const buffer_file_ops; }; } } } #endif /* MIR_CLIENT_MESA_CLIENT_BUFFER_FACTORY_H_ */ ./src/platforms/mesa/client/native_surface.h0000644000004100000410000000255413115234664021426 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_CLIENT_MESA_NATIVE_SURFACES_H_ #define MIR_CLIENT_MESA_NATIVE_SURFACES_H_ #include "mir_toolkit/mesa/native_display.h" #include "mir/egl_native_surface.h" namespace mir { namespace client { namespace mesa { class NativeSurface : public MirMesaEGLNativeSurface { public: explicit NativeSurface(EGLNativeSurface*); int advance_buffer(MirBufferPackage* buffer_package); int get_parameters(MirWindowParameters* surface_parameters); int set_swapinterval(int interval); void use_native_surface(EGLNativeSurface* native_surface); private: bool starting; EGLNativeSurface* surface; }; } } } #endif /* MIR_CLIENT_MESA_NATIVE_SURFACE_H_ */ ./src/platforms/mesa/client/client_buffer_factory.cpp0000644000004100000410000000340013115234664023310 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Christopher James Halse Rogers */ #include "client_buffer_factory.h" #include "client_buffer.h" namespace mcl=mir::client; namespace mclm=mir::client::mesa; mclm::ClientBufferFactory::ClientBufferFactory( std::shared_ptr const& buffer_file_ops) : buffer_file_ops{buffer_file_ops} { } std::shared_ptr mclm::ClientBufferFactory::create_buffer( std::shared_ptr const& package, geometry::Size size, MirPixelFormat pf) { (void)size; // TODO: remove this unused parameter return std::make_shared( buffer_file_ops, package, geometry::Size{package->width, package->height}, pf); } std::shared_ptr mclm::ClientBufferFactory::create_buffer( std::shared_ptr const& package, unsigned int native_pf, unsigned int native_flags) { return std::make_shared( buffer_file_ops, package, geometry::Size{package->width, package->height}, native_pf, native_flags); } ./src/platforms/mesa/client/native_surface.cpp0000644000004100000410000000733413115234664021762 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #define MIR_LOG_COMPONENT "Mesa/NativeSurface" #include #include "native_buffer.h" #include "mir/client_buffer.h" #include "mir/uncaught.h" #include "native_surface.h" namespace mclm=mir::client::mesa; #define THROW_IF_NULL(s) \ if (!(s)) \ throw std::logic_error("error: use_egl_native_window(...) has not yet been called"); namespace { static int advance_buffer_static(MirMesaEGLNativeSurface* surface, MirBufferPackage* buffer_package) { auto s = static_cast(surface); return s->advance_buffer(buffer_package); } static int get_parameters_static(MirMesaEGLNativeSurface* surface, MirWindowParameters* surface_parameters) { auto s = static_cast(surface); return s->get_parameters(surface_parameters); } static int set_swapinterval_static(MirMesaEGLNativeSurface* surface, int interval) { auto s = static_cast(surface); return s->set_swapinterval(interval); } } mclm::NativeSurface::NativeSurface(EGLNativeSurface* surface) : starting(true), surface(surface) { surface_advance_buffer = advance_buffer_static; surface_get_parameters = get_parameters_static; surface_set_swapinterval = set_swapinterval_static; } int mclm::NativeSurface::advance_buffer(MirBufferPackage* buffer_package) try { THROW_IF_NULL(surface); /* * At present dri2_create_mir_window_surface will trigger * mir_advance_colour_buffer which will land here. Since we're still * creating the window, we don't have any buffers we want the server to * composite, so avoid sending a request to the server on startup: */ if (starting) starting = false; else surface->swap_buffers_sync(); auto buffer = surface->get_current_buffer(); auto buffer_to_driver = std::dynamic_pointer_cast( buffer->native_buffer_handle()); if (!buffer_to_driver) return MIR_MESA_FALSE; *buffer_package = *buffer_to_driver; return MIR_MESA_TRUE; } catch (std::exception const& e) { MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(e); return MIR_MESA_FALSE; } int mclm::NativeSurface::get_parameters(MirWindowParameters* surface_parameters) try { THROW_IF_NULL(surface); auto params = surface->get_parameters(); memcpy(surface_parameters, ¶ms, sizeof(MirWindowParameters)); return MIR_MESA_TRUE; } catch (std::exception const& e) { MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(e); return MIR_MESA_FALSE; } int mclm::NativeSurface::set_swapinterval(int interval) try { THROW_IF_NULL(surface); if ((interval < 0) || (interval > 1)) return MIR_MESA_FALSE; surface->request_and_wait_for_configure(mir_window_attrib_swapinterval, interval); return MIR_MESA_TRUE; } catch (std::exception const& e) { MIR_LOG_DRIVER_BOUNDARY_EXCEPTION(e); return MIR_MESA_FALSE; } void mclm::NativeSurface::use_native_surface(EGLNativeSurface* native_surface) { surface = native_surface; } ./src/platforms/mesa/client/client_platform_factory.cpp0000644000004100000410000000673113115234664023675 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "mir/client_platform_factory.h" #include "client_platform.h" #include "mir_toolkit/client_types.h" #include "mir/client_context.h" #include "buffer_file_ops.h" #include "mir/egl_native_display_container.h" #include "mir/assert_module_entry_point.h" #include "mir/module_deleter.h" #include #include #include #include #include #include namespace mcl = mir::client; namespace mclm = mcl::mesa; namespace { // Re-export our own symbols from mesa.so.N globally so that Mesa itself can // find them with a simple dlsym(NULL,) void ensure_loaded_with_rtld_global_mesa_client() { Dl_info info; dladdr(reinterpret_cast(&ensure_loaded_with_rtld_global_mesa_client), &info); void* reexport_self_global = dlopen(info.dli_fname, RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL); // Yes, RTLD_NOLOAD does increase the ref count. So dlclose... if (reexport_self_global) dlclose(reexport_self_global); } struct RealBufferFileOps : public mclm::BufferFileOps { int close(int fd) const { while (::close(fd) == -1) { // Retry on EINTR, return error on anything else if (errno != EINTR) return errno; } return 0; } void* map(int fd, off_t offset, size_t size) const { return mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); } void unmap(void* addr, size_t size) const { munmap(addr, size); } }; } mir::UniqueModulePtr create_client_platform( mcl::ClientContext* context, std::shared_ptr const& /*logger*/) { mir::assert_entry_point_signature(&create_client_platform); ensure_loaded_with_rtld_global_mesa_client(); MirPlatformPackage package; context->populate_server_package(package); if (package.data_items != 0 || package.fd_items != 1) { BOOST_THROW_EXCEPTION((std::runtime_error{"Attempted to create Mesa client platform on non-Mesa server"})); } auto buffer_file_ops = std::make_shared(); return mir::make_module_ptr( context, buffer_file_ops, mcl::EGLNativeDisplayContainer::instance()); } bool is_appropriate_module(mcl::ClientContext* context) { mir::assert_entry_point_signature(&is_appropriate_module); MirModuleProperties server_graphics_module; context->populate_graphics_module(server_graphics_module); // We may in future wish to compare versions, but the mesa server/mesa client interface hasn't // changed in ages. return (strncmp("mir:mesa", server_graphics_module.name, strlen("mir:mesa")) == 0); } ./src/platforms/mesa/server/0000755000004100000410000000000013115234677016305 5ustar www-datawww-data./src/platforms/mesa/server/CMakeLists.txt0000644000004100000410000000101713115234664021040 0ustar www-datawww-dataif (MIR_BUILD_PLATFORM_MESA_KMS) add_subdirectory(kms/) endif() if (MIR_BUILD_PLATFORM_MESA_X11) add_subdirectory(x11/) endif() include_directories( ${server_common_include_dirs} ${DRM_INCLUDE_DIRS} ) add_library( mirsharedmesaservercommon-static STATIC buffer_allocator.cpp display_helpers.cpp drm_close_threadsafe.cpp gbm_buffer.cpp ipc_operations.cpp software_buffer.cpp ) target_link_libraries( mirsharedmesaservercommon-static mirsharedmesa-static server_platform_common kms_utils ) ./src/platforms/mesa/server/x11/0000755000004100000410000000000013115234677016716 5ustar www-datawww-data./src/platforms/mesa/server/x11/CMakeLists.txt0000644000004100000410000000250113115234664021450 0ustar www-datawww-dataadd_subdirectory(graphics/) add_subdirectory(input/) add_library( mirplatformservermesax11sharedresources OBJECT X11_resources.cpp ) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/symbols.map.in ${CMAKE_CURRENT_BINARY_DIR}/symbols.map) set(symbol_map ${CMAKE_CURRENT_BINARY_DIR}/symbols.map) add_library(mirplatformservermesax11 MODULE $ $ $ $ $ ) target_link_libraries( mirplatformservermesax11 PRIVATE mirplatform ${EGL_LDFLAGS} ${EGL_LIBRARIES} ${GL_LDFLAGS} ${GL_LIBRARIES} X11 mirsharedmesaservercommon-static ${Boost_PROGRAM_OPTIONS_LIBRARY} ${DRM_LDFLAGS} ${DRM_LIBRARIES} ${GBM_LDFLAGS} ${GBM_LIBRARIES} ) set_target_properties( mirplatformservermesax11 PROPERTIES OUTPUT_NAME server-mesa-x11 LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/server-modules PREFIX "" SUFFIX ".so.${MIR_SERVER_GRAPHICS_PLATFORM_ABI}" LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${symbol_map}" LINK_DEPENDS ${symbol_map} ) install(TARGETS mirplatformservermesax11 LIBRARY DESTINATION ${MIR_SERVER_PLATFORM_PATH}) ./src/platforms/mesa/server/x11/X11_resources.cpp0000644000004100000410000000317513115234416022062 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #define MIR_LOG_COMPONENT "x11-error" #include "mir/log.h" #include "X11_resources.h" namespace mx = mir::X; //Force synchronous Xlib operation - for debugging //#define FORCE_SYNCHRONOUS int mx::mir_x11_error_handler(Display* dpy, XErrorEvent* eev) { char msg[80]; XGetErrorText(dpy, eev->error_code, msg, sizeof(msg)); log_error("X11 error %d (%s): request %d.%d\n", eev->error_code, msg, eev->request_code, eev->minor_code); return 0; } std::shared_ptr<::Display> mx::X11Resources::get_conn() { if (auto conn = connection.lock()) return conn; XInitThreads(); XSetErrorHandler(mir_x11_error_handler); std::shared_ptr<::Display> new_conn{ XOpenDisplay(nullptr), [](::Display* display) { if (display) XCloseDisplay(display); }}; #ifdef FORCE_SYNCHRONOUS if (new_conn) XSynchronize(new_conn.get(), True); #endif connection = new_conn; return new_conn; } ./src/platforms/mesa/server/x11/graphics/0000755000004100000410000000000013115234677020516 5ustar www-datawww-data./src/platforms/mesa/server/x11/graphics/graphics.cpp0000644000004100000410000000764613115234664023033 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #include "mir/graphics/display_report.h" #include "mir/options/option.h" #include "platform.h" #include "guest_platform.h" #include "../X11_resources.h" #include "mir/module_deleter.h" #include "mir/assert_module_entry_point.h" #include "mir/libname.h" #include namespace mo = mir::options; namespace mg = mir::graphics; namespace mx = mir::X; namespace mgx = mg::X; namespace geom = mir::geometry; mx::X11Resources x11_resources; namespace { char const* x11_displays_option_name{"x11-displays"}; } mir::UniqueModulePtr create_host_platform( std::shared_ptr const& options, std::shared_ptr const&, std::shared_ptr const& report, std::shared_ptr const& /*logger*/) { mir::assert_entry_point_signature(&create_host_platform); if (!x11_resources.get_conn()) BOOST_THROW_EXCEPTION(std::runtime_error("Need valid x11 display")); auto display_dims_str = options->get(x11_displays_option_name); auto pos = display_dims_str.find('x'); if (pos == std::string::npos) BOOST_THROW_EXCEPTION(std::runtime_error("Malformed display size option")); return mir::make_module_ptr( x11_resources.get_conn(), geom::Size{std::stoi(display_dims_str.substr(0, pos)), std::stoi(display_dims_str.substr(pos+1, display_dims_str.find(':')))}, report ); } mir::UniqueModulePtr create_guest_platform( std::shared_ptr const& /*report*/, std::shared_ptr const& nested_context) { mir::assert_entry_point_signature(&create_guest_platform); return mir::make_module_ptr(nested_context); } void add_graphics_platform_options(boost::program_options::options_description& config) { mir::assert_entry_point_signature(&add_graphics_platform_options); config.add_options() (x11_displays_option_name, boost::program_options::value()->default_value("1280x1024"), "[mir-on-X specific] WIDTHxHEIGHT of \"display\" window."); } mg::PlatformPriority probe_graphics_platform(mo::ProgramOption const& /*options*/) { mir::assert_entry_point_signature(&probe_graphics_platform); auto dpy = XOpenDisplay(nullptr); if (dpy) { XCloseDisplay(dpy); auto udev = std::make_shared(); mir::udev::Enumerator drm_devices{udev}; drm_devices.match_subsystem("drm"); drm_devices.match_sysname("renderD[0-9]*"); drm_devices.scan_devices(); if (drm_devices.begin() != drm_devices.end()) return mg::PlatformPriority::supported; } return mg::PlatformPriority::unsupported; } namespace { mir::ModuleProperties const description = { "mir:mesa-x11", MIR_VERSION_MAJOR, MIR_VERSION_MINOR, MIR_VERSION_MICRO, mir::libname() }; } mir::ModuleProperties const* describe_graphics_module() { mir::assert_entry_point_signature(&describe_graphics_module); return &description; } ./src/platforms/mesa/server/x11/graphics/CMakeLists.txt0000644000004100000410000000101213115234664023244 0ustar www-datawww-datainclude_directories( ${server_common_include_dirs} ${PROJECT_SOURCE_DIR}/include/platform ${PROJECT_SOURCE_DIR}/include/client ../.. ) include_directories( ${DRM_INCLUDE_DIRS} ${EGL_INCLUDE_DIRS} ${GL_INCLUDE_DIRS} ${UDEV_INCLUDE_DIRS} ) add_library( mirplatformgraphicsmesax11objects OBJECT platform.cpp guest_platform.cpp display.cpp display_configuration.cpp display_buffer.cpp egl_helper.cpp ) add_library( mirplatformgraphicsmesax11objects-symbols OBJECT graphics.cpp ) ./src/platforms/mesa/server/x11/graphics/egl_helper.cpp0000644000004100000410000001343013115234664023325 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #include "egl_helper.h" #include "mir/graphics/gl_config.h" #include "mir/graphics/egl_error.h" #include namespace mg = mir::graphics; namespace mgx = mg::X; namespace mgxh = mgx::helpers; mgxh::EGLHelper::EGLHelper(GLConfig const& gl_config) : depth_buffer_bits{gl_config.depth_buffer_bits()}, stencil_buffer_bits{gl_config.stencil_buffer_bits()}, egl_display{EGL_NO_DISPLAY}, egl_config{0}, egl_context{EGL_NO_CONTEXT}, egl_surface{EGL_NO_SURFACE}, should_terminate_egl{false} { } void mgxh::EGLHelper::setup(::Display* const x_dpy) { eglBindAPI(MIR_SERVER_EGL_OPENGL_API); static const EGLint context_attr[] = { #if MIR_SERVER_EGL_OPENGL_BIT == EGL_OPENGL_ES2_BIT EGL_CONTEXT_CLIENT_VERSION, 2, #endif EGL_NONE }; setup_internal(x_dpy, true); egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attr); if (egl_context == EGL_NO_CONTEXT) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context")); } void mgxh::EGLHelper::setup(::Display* const x_dpy, EGLContext shared_context) { eglBindAPI(MIR_SERVER_EGL_OPENGL_API); static const EGLint context_attr[] = { #if MIR_SERVER_EGL_OPENGL_BIT == EGL_OPENGL_ES2_BIT EGL_CONTEXT_CLIENT_VERSION, 2, #endif EGL_NONE }; setup_internal(x_dpy, false); egl_context = eglCreateContext(egl_display, egl_config, shared_context, context_attr); if (egl_context == EGL_NO_CONTEXT) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context")); } void mgxh::EGLHelper::setup(::Display* const x_dpy, Window win, EGLContext shared_context) { eglBindAPI(MIR_SERVER_EGL_OPENGL_API); static const EGLint context_attr[] = { #if MIR_SERVER_EGL_OPENGL_BIT == EGL_OPENGL_ES2_BIT EGL_CONTEXT_CLIENT_VERSION, 2, #endif EGL_NONE }; setup_internal(x_dpy, false); egl_surface = eglCreateWindowSurface(egl_display, egl_config, win, nullptr); if(egl_surface == EGL_NO_SURFACE) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL window surface")); egl_context = eglCreateContext(egl_display, egl_config, shared_context, context_attr); if (egl_context == EGL_NO_CONTEXT) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context")); } mgxh::EGLHelper::~EGLHelper() noexcept { if (egl_display != EGL_NO_DISPLAY) { if (egl_context != EGL_NO_CONTEXT) { eglBindAPI(MIR_SERVER_EGL_OPENGL_API); if (eglGetCurrentContext() == egl_context) eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(egl_display, egl_context); } if (egl_surface != EGL_NO_SURFACE) eglDestroySurface(egl_display, egl_surface); if (should_terminate_egl) eglTerminate(egl_display); } } bool mgxh::EGLHelper::swap_buffers() { auto ret = eglSwapBuffers(egl_display, egl_surface); return (ret == EGL_TRUE); } bool mgxh::EGLHelper::make_current() const { auto ret = eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context); eglBindAPI(MIR_SERVER_EGL_OPENGL_API); return (ret == EGL_TRUE); } bool mgxh::EGLHelper::release_current() const { auto ret = eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); return (ret == EGL_TRUE); } void mgxh::EGLHelper::setup_internal(::Display* const x_dpy, bool initialize) { EGLint const config_attr[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, depth_buffer_bits, EGL_STENCIL_SIZE, stencil_buffer_bits, EGL_RENDERABLE_TYPE, MIR_SERVER_EGL_OPENGL_BIT, EGL_NONE }; static const EGLint required_egl_version_major = 1; static const EGLint required_egl_version_minor = 4; EGLint num_egl_configs; egl_display = eglGetDisplay(static_cast(x_dpy)); if (egl_display == EGL_NO_DISPLAY) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to get EGL display")); if (initialize) { EGLint major, minor; if (eglInitialize(egl_display, &major, &minor) == EGL_FALSE) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to initialize EGL display")); if ((major < required_egl_version_major) || (major == required_egl_version_major && minor < required_egl_version_minor)) { BOOST_THROW_EXCEPTION( boost::enable_error_info(std::runtime_error("Incompatible EGL version"))); // TODO: Insert egl version major and minor into exception } should_terminate_egl = true; } if (eglChooseConfig(egl_display, config_attr, &egl_config, 1, &num_egl_configs) == EGL_FALSE || num_egl_configs != 1) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to choose ARGB EGL config")); } } void mgxh::EGLHelper::report_egl_configuration(std::function f) { f(egl_display, egl_config); } ./src/platforms/mesa/server/x11/graphics/guest_platform.cpp0000644000004100000410000000372713115234664024262 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Cemil Azizoglu */ #include "guest_platform.h" #include "ipc_operations.h" #include "buffer_allocator.h" #include "mir/graphics/nested_context.h" #include #include namespace mg = mir::graphics; namespace mgx = mg::X; namespace mgm = mg::mesa; mgx::GuestPlatform::GuestPlatform( std::shared_ptr const& /*nested_context*/) : udev{std::make_shared()}, drm{std::make_shared(mesa::helpers::DRMNodeToUse::render)} { drm->setup(udev); gbm.setup(*drm); } mir::UniqueModulePtr mgx::GuestPlatform::create_buffer_allocator() { return make_module_ptr( gbm.device, mgm::BypassOption::prohibited, mgm::BufferImportMethod::dma_buf); } mir::UniqueModulePtr mgx::GuestPlatform::make_ipc_operations() const { return make_module_ptr(drm); } mir::UniqueModulePtr mgx::GuestPlatform::create_display( std::shared_ptr const&, std::shared_ptr const&) { BOOST_THROW_EXCEPTION(std::runtime_error("Guest platform cannot create display\n")); } ./src/platforms/mesa/server/x11/graphics/display_configuration.h0000644000004100000410000000365713115234664025272 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu * */ #ifndef MIR_GRAPHICS_X_DISPLAY_CONFIGURATION_H_ #define MIR_GRAPHICS_X_DISPLAY_CONFIGURATION_H_ #include "mir/graphics/display_configuration.h" #include "mir/geometry/size.h" namespace mir { namespace graphics { namespace X { class DisplayConfiguration : public graphics::DisplayConfiguration { public: DisplayConfiguration(MirPixelFormat pf, mir::geometry::Size const pixels, mir::geometry::Size const size_mm, float const scale, MirOrientation orientation); DisplayConfiguration(DisplayConfiguration const&); virtual ~DisplayConfiguration() = default; void for_each_card(std::function f) const override; void for_each_output(std::function f) const override; void for_each_output(std::function f) override; std::unique_ptr clone() const override; static DisplayConfigurationOutputId const the_output_id; private: DisplayConfigurationOutput configuration; DisplayConfigurationCard card; }; } } } #endif /* MIR_GRAPHICS_X_DISPLAY_CONFIGURATION_H_ */ ./src/platforms/mesa/server/x11/graphics/display_buffer.h0000644000004100000410000000537413115234664023672 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu * */ #ifndef MIR_GRAPHICS_X_DISPLAY_BUFFER_H_ #define MIR_GRAPHICS_X_DISPLAY_BUFFER_H_ #include "mir/graphics/display_buffer.h" #include "mir/graphics/display.h" #include "mir/renderer/gl/render_target.h" #include "egl_helper.h" #include #include namespace mir { namespace graphics { class AtomicFrame; class GLConfig; class DisplayReport; namespace X { class DisplayBuffer : public graphics::DisplayBuffer, public graphics::DisplaySyncGroup, public graphics::NativeDisplayBuffer, public renderer::gl::RenderTarget { public: DisplayBuffer( ::Display* const x_dpy, Window const win, geometry::Size const sz, EGLContext const shared_context, std::shared_ptr const& f, std::shared_ptr const& r, MirOrientation const o, GLConfig const& gl_config); geometry::Rectangle view_area() const override; void make_current() override; void release_current() override; void swap_buffers() override; void bind() override; bool overlay(RenderableList const& renderlist) override; void set_orientation(MirOrientation const new_orientation); void for_each_display_buffer( std::function const& f) override; void post() override; std::chrono::milliseconds recommended_sleep() const override; MirOrientation orientation() const override; MirMirrorMode mirror_mode() const override; NativeDisplayBuffer* native_display_buffer() override; private: geometry::Size const size; std::shared_ptr const report; MirOrientation orientation_; helpers::EGLHelper egl; std::shared_ptr const last_frame; typedef EGLBoolean (EGLAPIENTRY EglGetSyncValuesCHROMIUM) (EGLDisplay dpy, EGLSurface surface, int64_t *ust, int64_t *msc, int64_t *sbc); EglGetSyncValuesCHROMIUM* eglGetSyncValues; }; } } } #endif /* MIR_GRAPHICS_X_DISPLAY_BUFFER_H_ */ ./src/platforms/mesa/server/x11/graphics/platform.cpp0000644000004100000410000000420313115234664023041 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #include "platform.h" #include "display.h" #include "buffer_allocator.h" #include "ipc_operations.h" namespace mg = mir::graphics; namespace mgm = mg::mesa; namespace mgx = mg::X; namespace geom = mir::geometry; mgx::Platform::Platform(std::shared_ptr<::Display> const& conn, geom::Size const size, std::shared_ptr const& report) : x11_connection{conn}, udev{std::make_shared()}, drm{std::make_shared(mesa::helpers::DRMNodeToUse::render)}, report{report}, size{size} { if (!x11_connection) BOOST_THROW_EXCEPTION(std::runtime_error("Need valid x11 display")); drm->setup(udev); gbm.setup(*drm); } mir::UniqueModulePtr mgx::Platform::create_buffer_allocator() { return make_module_ptr(gbm.device, mgm::BypassOption::prohibited, mgm::BufferImportMethod::dma_buf); } mir::UniqueModulePtr mgx::Platform::create_display( std::shared_ptr const& /*initial_conf_policy*/, std::shared_ptr const& gl_config) { return make_module_ptr(x11_connection.get(), size, gl_config, report); } mir::UniqueModulePtr mgx::Platform::make_ipc_operations() const { return make_module_ptr(drm); } ./src/platforms/mesa/server/x11/graphics/display_configuration.cpp0000644000004100000410000000504213115234664025613 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu * */ #include "display_configuration.h" #include namespace mg = mir::graphics; namespace mgx = mg::X; namespace geom = mir::geometry; mg::DisplayConfigurationOutputId const mgx::DisplayConfiguration::the_output_id{1}; mgx::DisplayConfiguration::DisplayConfiguration(MirPixelFormat pf, geom::Size const pixels, geom::Size const size, const float scale, MirOrientation orientation) : configuration{ the_output_id, mg::DisplayConfigurationCardId{0}, mg::DisplayConfigurationOutputType::unknown, {pf}, //TODO: query fps {mg::DisplayConfigurationMode{pixels, 60.0}}, 0, size, true, true, geom::Point{0, 0}, 0, pf, mir_power_mode_on, orientation, scale, mir_form_factor_monitor, mir_subpixel_arrangement_unknown, {}, mir_output_gamma_unsupported, {}}, card{mg::DisplayConfigurationCardId{0}, 1} { } mgx::DisplayConfiguration::DisplayConfiguration(DisplayConfiguration const& other) : mg::DisplayConfiguration(), configuration(other.configuration), card(other.card) { } void mgx::DisplayConfiguration::for_each_card(std::function f) const { f(card); } void mgx::DisplayConfiguration::for_each_output(std::function f) const { f(configuration); } void mgx::DisplayConfiguration::for_each_output(std::function f) { mg::UserDisplayConfigurationOutput user(configuration); f(user); } std::unique_ptr mgx::DisplayConfiguration::clone() const { return std::make_unique(*this); } ./src/platforms/mesa/server/x11/graphics/display.cpp0000644000004100000410000002610013115234664022662 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #include "mir/graphics/platform.h" #include "mir/graphics/display_report.h" #include "mir/graphics/egl_error.h" #include "mir/graphics/virtual_output.h" #include "mir/renderer/gl/context.h" #include "mir/graphics/gl_config.h" #include "mir/graphics/atomic_frame.h" #include "display_configuration.h" #include "display.h" #include "display_buffer.h" #include #include #define MIR_LOG_COMPONENT "x11-display" #include "mir/log.h" namespace mg=mir::graphics; namespace mgx=mg::X; namespace geom=mir::geometry; namespace { geom::Size clip_to_display(Display *dpy, geom::Size requested_size) { unsigned int screen_width, screen_height, uint_dummy; int int_dummy; Window window_dummy; int const border = 150; XGetGeometry(dpy, XDefaultRootWindow(dpy), &window_dummy, &int_dummy, &int_dummy, &screen_width, &screen_height, &uint_dummy, &uint_dummy); mir::log_info("Screen resolution = %dx%d", screen_width, screen_height); if ((screen_width < requested_size.width.as_uint32_t()+border) || (screen_height < requested_size.height.as_uint32_t()+border)) { mir::log_info(" ... is smaller than the requested size (%dx%d) plus border (%d). Clipping to (%dx%d).", requested_size.width.as_uint32_t(), requested_size.height.as_uint32_t(), border, screen_width-border, screen_height-border); return geom::Size{screen_width-border, screen_height-border}; } return requested_size; } auto get_pixel_width(Display *dpy) { auto screen = XDefaultScreenOfDisplay(dpy); return float(screen->mwidth) / screen->width; } auto get_pixel_height(Display *dpy) { auto screen = XDefaultScreenOfDisplay(dpy); return float(screen->mheight) / screen->height; } class XGLContext : public mir::renderer::gl::Context { public: XGLContext(::Display* const x_dpy, std::shared_ptr const& gl_config, EGLContext const shared_ctx) : egl{*gl_config} { egl.setup(x_dpy, shared_ctx); } ~XGLContext() = default; void make_current() const override { egl.make_current(); } void release_current() const override { egl.release_current(); } private: mgx::helpers::EGLHelper egl; }; } mgx::X11Window::X11Window(::Display* x_dpy, EGLDisplay egl_dpy, geom::Size const size, EGLConfig const egl_cfg) : x_dpy{x_dpy} { auto root = XDefaultRootWindow(x_dpy); EGLint vid; if (!eglGetConfigAttrib(egl_dpy, egl_cfg, EGL_NATIVE_VISUAL_ID, &vid)) BOOST_THROW_EXCEPTION(mg::egl_error("Cannot get config attrib")); XVisualInfo visTemplate; std::memset(&visTemplate, 0, sizeof visTemplate); int num_visuals = 0; visTemplate.visualid = vid; auto visInfo = XGetVisualInfo(x_dpy, VisualIDMask, &visTemplate, &num_visuals); if (!visInfo || !num_visuals) BOOST_THROW_EXCEPTION(mg::egl_error("Cannot get visual info, or no matching visuals")); mir::log_info("%d visual(s) found", num_visuals); mir::log_info("Using the first one :"); mir::log_info("ID\t\t:\t%d", visInfo->visualid); mir::log_info("screen\t:\t%d", visInfo->screen); mir::log_info("depth\t\t:\t%d", visInfo->depth); mir::log_info("red_mask\t:\t0x%0X", visInfo->red_mask); mir::log_info("green_mask\t:\t0x%0X", visInfo->green_mask); mir::log_info("blue_mask\t:\t0x%0X", visInfo->blue_mask); mir::log_info("colormap_size\t:\t%d", visInfo->colormap_size); mir::log_info("bits_per_rgb\t:\t%d", visInfo->bits_per_rgb); r_mask = visInfo->red_mask; XSetWindowAttributes attr; std::memset(&attr, 0, sizeof(attr)); attr.background_pixel = 0; attr.border_pixel = 0; attr.colormap = XCreateColormap(x_dpy, root, visInfo->visual, AllocNone); attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask; auto mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; win = XCreateWindow(x_dpy, root, 0, 0, size.width.as_int(), size.height.as_int(), 0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr); XFree(visInfo); { char const * const title = "Mir On X"; XSizeHints sizehints; // TODO: Due to a bug, resize doesn't work after XGrabKeyboard under Unity. // For now, make window unresizeable. // http://stackoverflow.com/questions/14555703/x11-unable-to-move-window-after-xgrabkeyboard sizehints.base_width = size.width.as_int(); sizehints.base_height = size.height.as_int(); sizehints.min_width = size.width.as_int(); sizehints.min_height = size.height.as_int(); sizehints.max_width = size.width.as_int(); sizehints.max_height = size.height.as_int(); sizehints.flags = PSize | PMinSize | PMaxSize; XSetNormalHints(x_dpy, win, &sizehints); XSetStandardProperties(x_dpy, win, title, title, None, (char **)NULL, 0, &sizehints); XWMHints wm_hints = { (InputHint|StateHint), // fields in this structure that are defined True, // does this application rely on the window manager // to get keyboard input? Yes, if this is False, // XGrabKeyboard doesn't work reliably. NormalState, // initial_state 0, // icon_pixmap 0, // icon_window 0, 0, // initial position of icon 0, // pixmap to be used as mask for icon_pixmap 0 // id of related window_group }; XSetWMHints(x_dpy, win, &wm_hints); Atom wmDeleteMessage = XInternAtom(x_dpy, "WM_DELETE_WINDOW", False); XSetWMProtocols(x_dpy, win, &wmDeleteMessage, 1); } XMapWindow(x_dpy, win); XEvent xev; do { XNextEvent(x_dpy, &xev); } while (xev.type != Expose); } mgx::X11Window::~X11Window() { XDestroyWindow(x_dpy, win); } mgx::X11Window::operator Window() const { return win; } unsigned long mgx::X11Window::red_mask() const { return r_mask; } mgx::Display::Display(::Display* x_dpy, geom::Size const requested_size, std::shared_ptr const& gl_config, std::shared_ptr const& report) : shared_egl{*gl_config}, x_dpy{x_dpy}, actual_size{clip_to_display(x_dpy, requested_size)}, gl_config{gl_config}, pixel_width{get_pixel_width(x_dpy)}, pixel_height{get_pixel_height(x_dpy)}, scale{1.0f}, report{report}, orientation{mir_orientation_normal}, last_frame{std::make_shared()} { shared_egl.setup(x_dpy); win = std::make_unique(x_dpy, shared_egl.display(), actual_size, shared_egl.config()); auto red_mask = win->red_mask(); pf = (red_mask == 0xFF0000 ? mir_pixel_format_argb_8888 : mir_pixel_format_abgr_8888); display_buffer = std::make_unique( x_dpy, *win, actual_size, shared_egl.context(), last_frame, report, orientation, *gl_config); shared_egl.make_current(); report->report_successful_display_construction(); } mgx::Display::~Display() noexcept { } void mgx::Display::for_each_display_sync_group(std::function const& f) { f(*display_buffer); } std::unique_ptr mgx::Display::configuration() const { return std::make_unique( pf, actual_size, geom::Size{actual_size.width * pixel_width, actual_size.height * pixel_height}, scale, orientation); } void mgx::Display::configure(mg::DisplayConfiguration const& new_configuration) { if (!new_configuration.valid()) { BOOST_THROW_EXCEPTION( std::logic_error("Invalid or inconsistent display configuration")); } MirOrientation o = mir_orientation_normal; float new_scale = scale; new_configuration.for_each_output([&](DisplayConfigurationOutput const& conf_output) { o = conf_output.orientation; new_scale = conf_output.scale; }); orientation = o; display_buffer->set_orientation(orientation); scale = new_scale; } void mgx::Display::register_configuration_change_handler( EventHandlerRegister& /* event_handler*/, DisplayConfigurationChangeHandler const& /*change_handler*/) { } void mgx::Display::register_pause_resume_handlers( EventHandlerRegister& /*handlers*/, DisplayPauseHandler const& /*pause_handler*/, DisplayResumeHandler const& /*resume_handler*/) { } void mgx::Display::pause() { BOOST_THROW_EXCEPTION(std::runtime_error("'Display::pause()' not yet supported on x11 platform")); } void mgx::Display::resume() { BOOST_THROW_EXCEPTION(std::runtime_error("'Display::resume()' not yet supported on x11 platform")); } auto mgx::Display::create_hardware_cursor(std::shared_ptr const& /* initial_image */) -> std::shared_ptr { return nullptr; } std::unique_ptr mgx::Display::create_virtual_output(int /*width*/, int /*height*/) { return nullptr; } mg::NativeDisplay* mgx::Display::native_display() { return this; } std::unique_ptr mgx::Display::create_gl_context() { return std::make_unique(x_dpy, gl_config, shared_egl.context()); } bool mgx::Display::apply_if_configuration_preserves_display_buffers( mg::DisplayConfiguration const& /*conf*/) { return false; } mg::Frame mgx::Display::last_frame_on(unsigned) const { return last_frame->load(); } ./src/platforms/mesa/server/x11/graphics/display.h0000644000004100000410000000711613115234664022335 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #ifndef MIR_GRAPHICS_X_DISPLAY_H_ #define MIR_GRAPHICS_X_DISPLAY_H_ #include "mir/graphics/display.h" #include "mir/geometry/size.h" #include "mir/renderer/gl/context_source.h" #include "mir_toolkit/common.h" #include "egl_helper.h" #include #include #include #include namespace mir { namespace graphics { class AtomicFrame; class GLConfig; class DisplayReport; namespace X { class DisplayBuffer; class X11Window { public: X11Window(::Display* const x_dpy, EGLDisplay egl_dpy, geometry::Size const size, EGLConfig const egl_cfg); ~X11Window(); operator Window() const; unsigned long red_mask() const; private: ::Display* const x_dpy; Window win; unsigned long r_mask; }; class Display : public graphics::Display, public graphics::NativeDisplay, public renderer::gl::ContextSource { public: explicit Display(::Display* x_dpy, geometry::Size const requested_size, std::shared_ptr const& gl_config, std::shared_ptr const& report); ~Display() noexcept; void for_each_display_sync_group(std::function const& f) override; std::unique_ptr configuration() const override; bool apply_if_configuration_preserves_display_buffers(graphics::DisplayConfiguration const& conf) override; void configure(graphics::DisplayConfiguration const&) override; void register_configuration_change_handler( EventHandlerRegister& handlers, DisplayConfigurationChangeHandler const& conf_change_handler) override; void register_pause_resume_handlers( EventHandlerRegister& handlers, DisplayPauseHandler const& pause_handler, DisplayResumeHandler const& resume_handler) override; void pause() override; void resume() override; std::shared_ptr create_hardware_cursor(std::shared_ptr const& initial_image) override; std::unique_ptr create_virtual_output(int width, int height) override; NativeDisplay* native_display() override; std::unique_ptr create_gl_context() override; Frame last_frame_on(unsigned output_id) const override; private: helpers::EGLHelper shared_egl; ::Display* const x_dpy; mir::geometry::Size const actual_size; std::shared_ptr const gl_config; float pixel_width; float pixel_height; float scale; std::unique_ptr win; MirPixelFormat pf; std::shared_ptr const report; MirOrientation orientation; //TODO: keep entire current display configuration std::shared_ptr last_frame; std::unique_ptr display_buffer; }; } } } #endif /* MIR_GRAPHICS_X_DISPLAY_H_ */ ./src/platforms/mesa/server/x11/graphics/platform.h0000644000004100000410000000374013115234664022513 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #ifndef MIR_GRAPHICS_X_PLATFORM_H_ #define MIR_GRAPHICS_X_PLATFORM_H_ #include "mir/graphics/display_report.h" #include "mir/graphics/platform.h" #include "display_helpers.h" #include "mir/geometry/size.h" #include #include namespace mir { namespace graphics { namespace X { class Platform : public graphics::Platform { public: explicit Platform(std::shared_ptr<::Display> const& conn, mir::geometry::Size const size, std::shared_ptr const& report); ~Platform() = default; /* From Platform */ UniqueModulePtr create_buffer_allocator() override; UniqueModulePtr create_display( std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config) override; UniqueModulePtr make_ipc_operations() const override; private: std::shared_ptr<::Display> const x11_connection; std::shared_ptr udev; std::shared_ptr const drm; std::shared_ptr const report; mesa::helpers::GBMHelper gbm; mir::geometry::Size const size; }; } } } #endif /* MIR_GRAPHICS_X_PLATFORM_H_ */ ./src/platforms/mesa/server/x11/graphics/guest_platform.h0000644000004100000410000000311613115234664023717 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Cemil Azizoglu */ #ifndef MIR_GRAPHICS_X_GUEST_PLATFORM_H_ #define MIR_GRAPHICS_X_GUEST_PLATFORM_H_ #include "mir/graphics/platform.h" #include "display_helpers.h" namespace mir { namespace graphics { namespace X { class GuestPlatform : public graphics::Platform { public: GuestPlatform(std::shared_ptr const& /*nested_context*/); UniqueModulePtr create_buffer_allocator() override; UniqueModulePtr make_ipc_operations() const override; UniqueModulePtr create_display( std::shared_ptr const&, std::shared_ptr const&) override; private: std::shared_ptr udev; std::shared_ptr const drm; graphics::mesa::helpers::GBMHelper gbm; }; } } } #endif // MIR_GRAPHICS_X_GUEST_PLATFORM_H_ ./src/platforms/mesa/server/x11/graphics/display_buffer.cpp0000644000004100000410000001420513115234664024216 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu * */ #include "mir/graphics/atomic_frame.h" #include "mir/fatal.h" #include "display_buffer.h" #include "display_configuration.h" #include "mir/graphics/display_report.h" #include namespace mg=mir::graphics; namespace mgx=mg::X; namespace geom=mir::geometry; mgx::DisplayBuffer::DisplayBuffer(::Display* const x_dpy, Window const win, geom::Size const sz, EGLContext const shared_context, std::shared_ptr const& f, std::shared_ptr const& r, MirOrientation const o, GLConfig const& gl_config) : size{sz}, report{r}, orientation_{o}, egl{gl_config}, last_frame{f}, eglGetSyncValues{nullptr} { egl.setup(x_dpy, win, shared_context); egl.report_egl_configuration( [&r] (EGLDisplay disp, EGLConfig cfg) { r->report_egl_configuration(disp, cfg); }); /* * EGL_CHROMIUM_sync_control is an EGL extension that Google invented/copied * so they could switch Chrome(ium) from GLX to EGL: * * https://bugs.chromium.org/p/chromium/issues/detail?id=366935 * https://www.opengl.org/registry/specs/OML/glx_sync_control.txt * * Most noteworthy is that the EGL extension only has one function, as * Google realized that's all you need. You do not need wait functions or * events if you already have accurate timestamps and the ability to sleep * with high precision. In fact sync logic in clients will have higher * precision if you implement the wait yourself relative to the correct * kernel clock, than using IPC to implement the wait on the server. * * EGL_CHROMIUM_sync_control never got formally standardized and no longer * needs to be since they switched ChromeOS over to Freon (native KMS). * However this remains the correct and only way of doing it in EGL on X11. * AFAIK the only existing implementation is Mesa. */ auto const extensions = eglQueryString(egl.display(), EGL_EXTENSIONS); auto const extension = "EGL_CHROMIUM_sync_control"; auto const found = strstr(extensions, extension); if (found) { char end = found[strlen(extension)]; if (end == '\0' || end == ' ') eglGetSyncValues = reinterpret_cast( eglGetProcAddress("eglGetSyncValuesCHROMIUM")); } } geom::Rectangle mgx::DisplayBuffer::view_area() const { switch (orientation_) { case mir_orientation_left: case mir_orientation_right: return {{0,0}, {size.height.as_int(), size.width.as_int()}}; default: return {{0,0}, size}; } } void mgx::DisplayBuffer::make_current() { if (!egl.make_current()) fatal_error("Failed to make EGL surface current"); } void mgx::DisplayBuffer::release_current() { egl.release_current(); } bool mgx::DisplayBuffer::overlay(RenderableList const& /*renderlist*/) { return false; } void mgx::DisplayBuffer::swap_buffers() { if (!egl.swap_buffers()) fatal_error("Failed to perform buffer swap"); /* * It would be nice to call this on demand as required. However the * implementation requires an EGL context. So for simplicity we call it here * on every frame. * This does mean the current last_frame will be a bit out of date if * the compositor missed a frame. But that doesn't actually matter because * the consequence of that would be the client scheduling the next frame * immediately without waiting, which is probably ideal anyway. */ int64_t ust_us, msc, sbc; if (eglGetSyncValues && eglGetSyncValues(egl.display(), egl.surface(), &ust_us, &msc, &sbc)) { std::chrono::nanoseconds const ust_ns{ust_us * 1000}; mg::Frame frame; frame.msc = msc; frame.ust = {CLOCK_MONOTONIC, ust_ns}; last_frame->store(frame); (void)sbc; // unused } else // Extension not available? Fall back to a reasonable estimate: { last_frame->increment_now(); } /* * Admittedly we are not a real display and will miss some real vsyncs * but this is best-effort. And besides, we don't want Mir reporting all * real vsyncs because that would mean the compositor never sleeps. */ report->report_vsync(mgx::DisplayConfiguration::the_output_id.as_value(), last_frame->load()); } void mgx::DisplayBuffer::bind() { } MirOrientation mgx::DisplayBuffer::orientation() const { return orientation_; } MirMirrorMode mgx::DisplayBuffer::mirror_mode() const { return mir_mirror_mode_none; } void mgx::DisplayBuffer::set_orientation(MirOrientation const new_orientation) { orientation_ = new_orientation; } mg::NativeDisplayBuffer* mgx::DisplayBuffer::native_display_buffer() { return this; } void mgx::DisplayBuffer::for_each_display_buffer( std::function const& f) { f(*this); } void mgx::DisplayBuffer::post() { } std::chrono::milliseconds mgx::DisplayBuffer::recommended_sleep() const { return std::chrono::milliseconds::zero(); } ./src/platforms/mesa/server/x11/graphics/egl_helper.h0000644000004100000410000000401213115234664022766 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #ifndef MIR_GRAPHICS_X11_EGL_HELPER_H_ #define MIR_GRAPHICS_X11_EGL_HELPER_H_ #include #include #include namespace mir { namespace graphics { class GLConfig; namespace X { namespace helpers { class EGLHelper { public: EGLHelper(GLConfig const& gl_config); ~EGLHelper() noexcept; EGLHelper(const EGLHelper&) = delete; EGLHelper& operator=(const EGLHelper&) = delete; void setup(::Display* const x_dpy); void setup(::Display* const x_dpy, EGLContext shared_context); void setup(::Display* const x_dpy, Window win, EGLContext shared_context); bool swap_buffers(); bool make_current() const; bool release_current() const; EGLContext context() { return egl_context; } EGLDisplay display() { return egl_display; } EGLConfig config() { return egl_config; } EGLSurface surface() const { return egl_surface; } void report_egl_configuration(std::function); private: void setup_internal(::Display* const x_dpy, bool initialize); EGLint const depth_buffer_bits; EGLint const stencil_buffer_bits; EGLDisplay egl_display; EGLConfig egl_config; EGLContext egl_context; EGLSurface egl_surface; bool should_terminate_egl; }; } } } } #endif /* MIR_GRAPHICS_X11_EGL_HELPER_H_ */ ./src/platforms/mesa/server/x11/X11_resources.h0000644000004100000410000000203513115234416021521 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #ifndef MIR_X11_RESOURCES_H_ #define MIR_X11_RESOURCES_H_ #include namespace mir { namespace X { int mir_x11_error_handler(Display* dpy, XErrorEvent* eev); class X11Resources { public: std::shared_ptr<::Display> get_conn(); private: std::weak_ptr<::Display> connection; }; } } #endif /* MIR_X11_RESOURCES_H_ */ ./src/platforms/mesa/server/x11/input/0000755000004100000410000000000013115234677020055 5ustar www-datawww-data./src/platforms/mesa/server/x11/input/CMakeLists.txt0000644000004100000410000000041413115234416022603 0ustar www-datawww-datainclude_directories( ${server_common_include_dirs} ${PROJECT_SOURCE_DIR}/include/client ) add_library( mirplatforminputmesax11objects OBJECT input_platform.cpp input_device.cpp ) add_library( mirplatforminputmesax11objects-symbols OBJECT input.cpp ) ./src/platforms/mesa/server/x11/input/input.cpp0000644000004100000410000000470413115234416021714 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #include "input_platform.h" #include "../X11_resources.h" #include "mir/module_properties.h" #include "mir/assert_module_entry_point.h" #include "mir/libname.h" namespace mo = mir::options; namespace mi = mir::input; namespace mx = mir::X; namespace mix = mi::X; extern mx::X11Resources x11_resources; mir::UniqueModulePtr create_input_platform( mo::Option const& /*options*/, std::shared_ptr const& /*emergency_cleanup_registry*/, std::shared_ptr const& input_device_registry, std::shared_ptr const& /*report*/) { mir::assert_entry_point_signature(&create_input_platform); return mir::make_module_ptr(input_device_registry, x11_resources.get_conn()); } void add_input_platform_options( boost::program_options::options_description& /*config*/) { mir::assert_entry_point_signature(&add_input_platform_options); } mi::PlatformPriority probe_input_platform( mo::Option const& options) { mir::assert_entry_point_signature(&probe_input_platform); if (options.is_set("host-socket") || options.is_set("vt")) return mi::PlatformPriority::unsupported; auto display_available = x11_resources.get_conn() != nullptr; if (display_available) return mi::PlatformPriority::best; else return mi::PlatformPriority::unsupported; } namespace { mir::ModuleProperties const description = { "mir:x11-input", MIR_VERSION_MAJOR, MIR_VERSION_MINOR, MIR_VERSION_MICRO, mir::libname() }; } mir::ModuleProperties const* describe_input_module() { mir::assert_entry_point_signature(&describe_input_module); return &description; } ./src/platforms/mesa/server/x11/input/input_device.cpp0000644000004100000410000001367313115234664023245 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #include "input_device.h" #include "mir/input/pointer_settings.h" #include "mir/input/touchpad_settings.h" #include "mir/input/input_device_info.h" #include "mir/input/device_capability.h" #include "mir/input/event_builder.h" #include "mir/input/input_sink.h" #include namespace mi = mir::input; namespace geom = mir::geometry; namespace mix = mi::X; namespace { MirPointerButtons to_mir_button(int button) { auto const button_side = 8; auto const button_extra = 9; if (button == Button1) return mir_pointer_button_primary; if (button == Button2) // tertiary (middle) button is Button2 in X return mir_pointer_button_tertiary; if (button == Button3) return mir_pointer_button_secondary; if (button == button_side) return mir_pointer_button_side; if (button == button_extra) return mir_pointer_button_extra; return 0; } MirPointerButtons to_mir_button_state(int x_button_key_state) { MirPointerButtons button_state = 0; if (x_button_key_state & Button1Mask) button_state |= mir_pointer_button_primary; if (x_button_key_state & Button2Mask) button_state |= mir_pointer_button_tertiary; if (x_button_key_state & Button3Mask) button_state |= mir_pointer_button_secondary; if (x_button_key_state & Button4Mask) button_state |= mir_pointer_button_back; if (x_button_key_state & Button5Mask) button_state |= mir_pointer_button_forward; return button_state; } } mix::XInputDevice::XInputDevice(InputDeviceInfo const& device_info) : info(device_info) { } void mix::XInputDevice::start(InputSink* input_sink, EventBuilder* event_builder) { sink = input_sink; builder = event_builder; } void mix::XInputDevice::stop() { sink = nullptr; builder = nullptr; } mi::InputDeviceInfo mix::XInputDevice::get_device_info() { // TODO Make use if X11-XInput2 to get raw device information // and support other devices than just the unified pointer and // keyboards. return info; } mir::optional_value mix::XInputDevice::get_pointer_settings() const { mir::optional_value ret; if (contains(info.capabilities, DeviceCapability::pointer)) ret = PointerSettings(); return ret; } void mix::XInputDevice::apply_settings(PointerSettings const&) { } mir::optional_value mix::XInputDevice::get_touchpad_settings() const { optional_value ret; if (contains(info.capabilities, DeviceCapability::touchpad)) ret = TouchpadSettings(); return ret; } void mix::XInputDevice::apply_settings(TouchpadSettings const&) { } bool mix::XInputDevice::started() const { return sink && builder; } void mix::XInputDevice::key_press(std::chrono::nanoseconds event_time, xkb_keysym_t key_sym, int32_t key_code) { sink->handle_input( *builder->key_event( event_time, mir_keyboard_action_down, key_sym, key_code ) ); } void mix::XInputDevice::key_release(std::chrono::nanoseconds event_time, xkb_keysym_t key_sym, int32_t key_code) { sink->handle_input( *builder->key_event( event_time, mir_keyboard_action_up, key_sym, key_code ) ); } void mix::XInputDevice::update_button_state(int button) { button_state = to_mir_button_state(button); } void mix::XInputDevice::pointer_press(std::chrono::nanoseconds event_time, int button, mir::geometry::Point const& pos, mir::geometry::Displacement scroll) { button_state |= to_mir_button(button); auto const movement = pos - pointer_pos; pointer_pos = pos; sink->handle_input( *builder->pointer_event( event_time, mir_pointer_action_button_down, button_state, pointer_pos.x.as_int(), pointer_pos.y.as_int(), scroll.dx.as_int(), scroll.dy.as_int(), movement.dx.as_int(), movement.dy.as_int() ) ); } void mix::XInputDevice::pointer_release(std::chrono::nanoseconds event_time, int button, mir::geometry::Point const& pos, mir::geometry::Displacement scroll) { button_state &= ~to_mir_button(button); auto const movement = pos - pointer_pos; pointer_pos = pos; sink->handle_input( *builder->pointer_event( event_time, mir_pointer_action_button_up, button_state, pointer_pos.x.as_int(), pointer_pos.y.as_int(), scroll.dx.as_int(), scroll.dy.as_int(), movement.dx.as_int(), movement.dy.as_int() ) ); } void mix::XInputDevice::pointer_motion(std::chrono::nanoseconds event_time, mir::geometry::Point const& pos, mir::geometry::Displacement scroll) { auto const movement = pos - pointer_pos; pointer_pos = pos; sink->handle_input( *builder->pointer_event( event_time, mir_pointer_action_motion, button_state, pointer_pos.x.as_int(), pointer_pos.y.as_int(), scroll.dx.as_int(), scroll.dy.as_int(), movement.dx.as_int(), movement.dy.as_int() ) ); } ./src/platforms/mesa/server/x11/input/input_platform.h0000644000004100000410000000333013115234664023264 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #ifndef MIR_INPUT_X_INPUT_PLATFORM_H_ #define MIR_INPUT_X_INPUT_PLATFORM_H_ #include "mir/input/platform.h" #include #include namespace mir { namespace dispatch { class ReadableFd; } namespace input { namespace X { class XInputDevice; class XInputPlatform : public input::Platform { public: explicit XInputPlatform( std::shared_ptr const& input_device_registry, std::shared_ptr<::Display> const& conn); ~XInputPlatform() = default; std::shared_ptr dispatchable() override; void start() override; void stop() override; private: void process_input_event(); std::shared_ptr<::Display> x11_connection; std::shared_ptr const xcon_dispatchable; std::shared_ptr const registry; std::shared_ptr const core_keyboard; std::shared_ptr const core_pointer; bool kbd_grabbed; bool ptr_grabbed; }; } } } #endif // MIR_INPUT_X_INPUT_PLATFORM_H_ ./src/platforms/mesa/server/x11/input/input_platform.cpp0000644000004100000410000002572213115234664023630 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #include "input_platform.h" #include "input_device.h" #include "mir/input/input_device_registry.h" #include "mir/input/input_device_info.h" #include "mir/dispatch/readable_fd.h" #define MIR_LOG_COMPONENT "x11-input" #include "mir/log.h" #include #include #include #include #include #include #include // Uncomment for verbose output with log_info. //#define MIR_ON_X11_INPUT_VERBOSE // Due to a bug in Unity when keyboard is grabbed, // client cannot be resized. This helps in debugging. #define GRAB_KBD namespace mi = mir::input; namespace geom = mir::geometry; namespace md = mir::dispatch; namespace mix = mi::X; mix::XInputPlatform::XInputPlatform(std::shared_ptr const& input_device_registry, std::shared_ptr<::Display> const& conn) : x11_connection{conn}, xcon_dispatchable(std::make_shared( mir::Fd{mir::IntOwnedFd{XConnectionNumber(conn.get())}}, [this]() { process_input_event(); })), registry(input_device_registry), core_keyboard(std::make_shared( mi::InputDeviceInfo{"x11-keyboard-device", "x11-key-dev-1", mi::DeviceCapability::keyboard})), core_pointer(std::make_shared( mi::InputDeviceInfo{"x11-mouse-device", "x11-mouse-dev-1", mi::DeviceCapability::pointer})), kbd_grabbed{false}, ptr_grabbed{false} { } void mix::XInputPlatform::start() { registry->add_device(core_keyboard); registry->add_device(core_pointer); } std::shared_ptr mix::XInputPlatform::dispatchable() { return xcon_dispatchable; } void mix::XInputPlatform::stop() { registry->remove_device(core_keyboard); registry->remove_device(core_pointer); } void mix::XInputPlatform::process_input_event() { while(XPending(x11_connection.get())) { // This code is based on : // https://tronche.com/gui/x/xlib/events/keyboard-pointer/keyboard-pointer.html XEvent xev; XNextEvent(x11_connection.get(), &xev); if (core_keyboard->started() && core_pointer->started()) { switch (xev.type) { #ifdef GRAB_KBD case FocusIn: { if (!kbd_grabbed) { auto const& xfiev = xev.xfocus; XGrabKeyboard(xfiev.display, xfiev.window, True, GrabModeAsync, GrabModeAsync, CurrentTime); kbd_grabbed = true; } break; } case FocusOut: { if (kbd_grabbed) { auto const& xfoev = xev.xfocus; XUngrabKeyboard(xfoev.display, CurrentTime); kbd_grabbed = false; } break; } #endif case EnterNotify: { if (!ptr_grabbed && kbd_grabbed) { auto const& xenev = xev.xcrossing; XGrabPointer(xenev.display, xenev.window, True, 0, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); ptr_grabbed = true; } break; } case LeaveNotify: { if (ptr_grabbed) { auto const& xlnev = xev.xcrossing; XUngrabPointer(xlnev.display, CurrentTime); ptr_grabbed = false; } break; } case KeyPress: case KeyRelease: { auto & xkev = xev.xkey; static const int STRMAX = 32; char str[STRMAX]; KeySym keysym; #ifdef MIR_ON_X11_INPUT_VERBOSE mir::log_info("X11 key event :" " type=%s, serial=%u, send_event=%d, display=%p, window=%p," " root=%p, subwindow=%p, time=%d, x=%d, y=%d, x_root=%d," " y_root=%d, state=0x%0X, keycode=%d, same_screen=%d", xkev.type == KeyPress ? "down" : "up", xkev.serial, xkev.send_event, xkev.display, xkev.window, xkev.root, xkev.subwindow, xkev.time, xkev.x, xkev.y, xkev.x_root, xkev.y_root, xkev.state, xkev.keycode, xkev.same_screen); auto count = #endif XLookupString(&xkev, str, STRMAX, &keysym, NULL); auto const event_time = std::chrono::duration_cast( std::chrono::milliseconds{xkev.time}); #ifdef MIR_ON_X11_INPUT_VERBOSE for (int i=0; ikey_press(event_time, keysym, xkev.keycode - 8); else core_keyboard->key_release(event_time, keysym, xkev.keycode - 8); break; } case ButtonPress: case ButtonRelease: { auto const& xbev = xev.xbutton; auto const up = Button4, down = Button5, left = 6, right = 7; #ifdef MIR_ON_X11_INPUT_VERBOSE mir::log_info("X11 button event :" " type=%s, serial=%u, send_event=%d, display=%p, window=%p," " root=%p, subwindow=%p, time=%d, x=%d, y=%d, x_root=%d," " y_root=%d, state=0x%0X, button=%d, same_screen=%d", xbev.type == ButtonPress ? "down" : "up", xbev.serial, xbev.send_event, xbev.display, xbev.window, xbev.root, xbev.subwindow, xbev.time, xbev.x, xbev.y, xbev.x_root, xbev.y_root, xbev.state, xbev.button, xbev.same_screen); #endif if (xbev.type == ButtonRelease && xbev.button >= up && xbev.button <= right) { #ifdef MIR_ON_X11_INPUT_VERBOSE mir::log_info("Swallowed"); #endif break; } auto const event_time = std::chrono::duration_cast(std::chrono::milliseconds{xbev.time}); core_pointer->update_button_state(xbev.state); if (xbev.button >= up && xbev.button <= right) { // scroll event core_pointer->pointer_motion( event_time, geom::Point{xbev.x, xbev.y}, geom::Displacement{xbev.button == right ? 1 : xbev.button == left ? -1 : 0, xbev.button == up ? 1 : xbev.button == down ? -1 : 0}); } else { if (xbev.type == ButtonPress) core_pointer->pointer_press( event_time, xbev.button, geom::Point{xbev.x, xbev.y}, geom::Displacement{0, 0}); else core_pointer->pointer_release( event_time, xbev.button, geom::Point{xbev.x, xbev.y}, geom::Displacement{0, 0}); } break; } case MotionNotify: { auto const& xmev = xev.xmotion; #ifdef MIR_ON_X11_INPUT_VERBOSE mir::log_info("X11 motion event :" " type=motion, serial=%u, send_event=%d, display=%p, window=%p," " root=%p, subwindow=%p, time=%d, x=%d, y=%d, x_root=%d," " y_root=%d, state=0x%0X, is_hint=%s, same_screen=%d", xmev.serial, xmev.send_event, xmev.display, xmev.window, xmev.root, xmev.subwindow, xmev.time, xmev.x, xmev.y, xmev.x_root, xmev.y_root, xmev.state, xmev.is_hint == NotifyNormal ? "no" : "yes", xmev.same_screen); #endif core_pointer->update_button_state(xmev.state); core_pointer->pointer_motion( std::chrono::milliseconds{xmev.time}, geom::Point{xmev.x, xmev.y}, geom::Displacement{0, 0}); break; } case ConfigureNotify: { #ifdef MIR_ON_X11_INPUT_VERBOSE auto const& xcev = xev.xconfigure; mir::log_info("Window size : %dx%d", xcev.width, xcev.height); #endif break; } case MappingNotify: #ifdef MIR_ON_X11_INPUT_VERBOSE mir::log_info("Keyboard mapping changed at server. Refreshing the cache."); #endif XRefreshKeyboardMapping(&(xev.xmapping)); break; case ClientMessage: mir::log_info("Exiting"); kill(getpid(), SIGTERM); break; default: #ifdef MIR_ON_X11_INPUT_VERBOSE mir::log_info("Uninteresting event : %08X", xev.type); #endif break; } } else mir::log_error("input event received with no sink to handle it"); } } ./src/platforms/mesa/server/x11/input/input_device.h0000644000004100000410000000501613115234416022675 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #ifndef MIR_INPUT_X_INPUT_DEVICE_H_ #define MIR_INPUT_X_INPUT_DEVICE_H_ #include "mir/input/input_device.h" #include "mir/input/input_device_info.h" #include "mir_toolkit/event.h" #include "mir/geometry/point.h" #include "mir/geometry/displacement.h" #include "mir/optional_value.h" #include namespace mir { namespace input { namespace X { class XInputDevice : public input::InputDevice { public: XInputDevice(InputDeviceInfo const& info); std::shared_ptr dispatchable(); void start(InputSink* destination, EventBuilder* builder) override; void stop() override; InputDeviceInfo get_device_info() override; optional_value get_pointer_settings() const override; void apply_settings(PointerSettings const& settings) override; optional_value get_touchpad_settings() const override; void apply_settings(TouchpadSettings const& settings) override; bool started() const; void key_press(std::chrono::nanoseconds event_time, xkb_keysym_t key_sym, int32_t key_code); void key_release(std::chrono::nanoseconds event_time, xkb_keysym_t key_sym, int32_t key_code); void update_button_state(int button); void pointer_press(std::chrono::nanoseconds event_time, int button, mir::geometry::Point const& pos, mir::geometry::Displacement scroll); void pointer_release(std::chrono::nanoseconds event_time, int button, mir::geometry::Point const& pos, mir::geometry::Displacement scroll); void pointer_motion(std::chrono::nanoseconds event_time, mir::geometry::Point const& pos, mir::geometry::Displacement scroll); private: MirPointerButtons button_state{0}; InputSink* sink{nullptr}; EventBuilder* builder{nullptr}; geometry::Point pointer_pos; InputDeviceInfo info; }; } } } #endif // MIR_INPUT_X_INPUT_DEVICE_H_ ./src/platforms/mesa/server/x11/symbols.map.in0000644000004100000410000000057613115234416021511 0ustar www-datawww-data@MIR_SERVER_GRAPHICS_PLATFORM_VERSION@ { global: add_graphics_platform_options; probe_graphics_platform; create_host_platform; create_guest_platform; describe_graphics_module; local: *; }; @MIR_SERVER_INPUT_PLATFORM_VERSION@ { global: add_input_platform_options; create_input_platform; probe_input_platform; describe_input_module; local: *; }; ./src/platforms/mesa/server/ipc_operations.cpp0000644000004100000410000001146413115234664022031 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/graphics/buffer.h" #include "mir/graphics/buffer_ipc_message.h" #include "mir/graphics/platform_ipc_package.h" #include "mir/graphics/platform.h" #include "mir/graphics/nested_context.h" #include "mir/graphics/platform_operation_message.h" #include "mir/libname.h" #include "display_helpers.h" #include "drm_authentication.h" #include "drm_close_threadsafe.h" #include "ipc_operations.h" #include "mir_toolkit/mesa/platform_operation.h" #include "native_buffer.h" #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace { mir::ModuleProperties const description = { "mir:mesa", MIR_VERSION_MAJOR, MIR_VERSION_MINOR, MIR_VERSION_MICRO, mir::libname() }; struct MesaPlatformIPCPackage : public mg::PlatformIPCPackage { MesaPlatformIPCPackage(int drm_auth_fd) : mg::PlatformIPCPackage(&description) { ipc_fds.push_back(drm_auth_fd); } ~MesaPlatformIPCPackage() { if (ipc_fds.size() > 0 && ipc_fds[0] >= 0) mgm::drm_close_threadsafe(ipc_fds[0]); } }; } mgm::IpcOperations::IpcOperations(std::shared_ptr const& drm) : drm{drm} { } void mgm::IpcOperations::pack_buffer( mg::BufferIpcMessage& packer, Buffer const& buffer, BufferIpcMsgType msg_type) const { if (msg_type == mg::BufferIpcMsgType::full_msg) { auto native_handle = std::dynamic_pointer_cast(buffer.native_buffer_handle()); if (!native_handle) BOOST_THROW_EXCEPTION(std::invalid_argument("could not convert NativeBuffer")); for(auto i=0; idata_items; i++) { packer.pack_data(native_handle->data[i]); } for(auto i=0; ifd_items; i++) { packer.pack_fd(mir::Fd(IntOwnedFd{native_handle->fd[i]})); } packer.pack_stride(mir::geometry::Stride{native_handle->stride}); packer.pack_flags(native_handle->flags); packer.pack_size(buffer.size()); } } void mgm::IpcOperations::unpack_buffer(BufferIpcMessage&, Buffer const&) const { } mg::PlatformOperationMessage mgm::IpcOperations::platform_operation( unsigned int const op, mg::PlatformOperationMessage const& request) { if (op == MirMesaPlatformOperation::auth_magic) { MirMesaAuthMagicRequest auth_magic_request; if (request.data.size() == sizeof(auth_magic_request)) { std::memcpy(&auth_magic_request, request.data.data(), request.data.size()); } else { BOOST_THROW_EXCEPTION( std::runtime_error("Invalid request message for auth_magic platform operation")); } MirMesaAuthMagicResponse auth_magic_response{-1}; try { drm->auth_magic(auth_magic_request.magic); auth_magic_response.status = 0; } catch (std::exception const& e) { auto errno_ptr = boost::get_error_info(e); if (errno_ptr != nullptr) auth_magic_response.status = *errno_ptr; else throw; } mg::PlatformOperationMessage response_msg; response_msg.data.resize(sizeof(auth_magic_response)); std::memcpy(response_msg.data.data(), &auth_magic_response, sizeof(auth_magic_response)); return response_msg; } else if (op == MirMesaPlatformOperation::auth_fd) { if (request.data.size() != 0 || request.fds.size() != 0) { BOOST_THROW_EXCEPTION( std::runtime_error("Invalid request message for auth_fd platform operation")); } return mg::PlatformOperationMessage{{},{drm->authenticated_fd()}}; } else { BOOST_THROW_EXCEPTION( std::runtime_error("Invalid platform operation")); } } std::shared_ptr mgm::IpcOperations::connection_ipc_package() { return std::make_shared(drm->authenticated_fd()); } ./src/platforms/mesa/server/kms/0000755000004100000410000000000013115234677017077 5ustar www-datawww-data./src/platforms/mesa/server/kms/CMakeLists.txt0000644000004100000410000000356013115234664021637 0ustar www-datawww-datainclude_directories( ${server_common_include_dirs} ${PROJECT_SOURCE_DIR}/include/client .. ) include_directories( ${DRM_INCLUDE_DIRS} ${GBM_INCLUDE_DIRS} ${EGL_INCLUDE_DIRS} ${GL_INCLUDE_DIRS} ${UDEV_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/include/client ) # gbm.h and drm.h have trailing commas at the end of enum definitions # This is valid C99, but g++ 4.4 flags it as an error with -pedantic string(REPLACE "-pedantic" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) add_definitions( -D__GBM__ -DMIR_LOG_COMPONENT_FALLBACK="mesa-kms" ) add_library( mirplatformgraphicsmesakmsobjects OBJECT bypass.cpp cursor.cpp display.cpp display_buffer.cpp guest_platform.cpp kms_page_flipper.cpp linux_virtual_terminal.cpp nested_authentication.cpp platform.cpp real_kms_display_configuration.cpp real_kms_output.cpp real_kms_output_container.cpp ) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/symbols.map.in ${CMAKE_CURRENT_BINARY_DIR}/symbols.map ) set(symbol_map ${CMAKE_CURRENT_BINARY_DIR}/symbols.map) add_library(mirplatformgraphicsmesakms MODULE platform_symbols.cpp $ ) target_link_libraries( mirplatformgraphicsmesakms PRIVATE mirplatform mirsharedmesaservercommon-static ${Boost_PROGRAM_OPTIONS_LIBRARY} ${DRM_LDFLAGS} ${DRM_LIBRARIES} ${GBM_LDFLAGS} ${GBM_LIBRARIES} ${EGL_LDFLAGS} ${EGL_LIBRARIES} ${GL_LDFLAGS} ${GL_LIBRARIES} ) set_target_properties( mirplatformgraphicsmesakms PROPERTIES OUTPUT_NAME graphics-mesa-kms LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/server-modules PREFIX "" SUFFIX ".so.${MIR_SERVER_GRAPHICS_PLATFORM_ABI}" LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${symbol_map}" LINK_DEPENDS ${symbol_map} ) install(TARGETS mirplatformgraphicsmesakms LIBRARY DESTINATION ${MIR_SERVER_PLATFORM_PATH}) ./src/platforms/mesa/server/kms/nested_authentication.cpp0000644000004100000410000000435713115234664024171 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "mir/graphics/nested_context.h" #include "mir/graphics/platform_operation_message.h" #include "nested_authentication.h" #include "mir_toolkit/mesa/platform_operation.h" #include "mir_toolkit/extensions/mesa_drm_auth.h" #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace { std::shared_ptr load_extension(mg::NestedContext& context) { auto ext = context.auth_extension(); if (!ext.is_set()) BOOST_THROW_EXCEPTION(std::runtime_error("No mesa_drm_auth extension. Perhaps the host is not using the mesa platform")); return ext.value(); } } mgm::NestedAuthentication::NestedAuthentication( std::shared_ptr const& nested_context) : nested_context{nested_context}, auth_extension(load_extension(*nested_context)) { } void mgm::NestedAuthentication::auth_magic(drm_magic_t magic) { static int const success{0}; auto rc = auth_extension->auth_magic(magic); if (rc != success) { BOOST_THROW_EXCEPTION( std::system_error(rc, std::system_category(), "Nested server failed to authenticate DRM device magic cookie")); } } mir::Fd mgm::NestedAuthentication::authenticated_fd() { auto fd = auth_extension->auth_fd(); if (fd <= mir::Fd::invalid) BOOST_THROW_EXCEPTION(std::runtime_error("Nested server failed to get authenticated DRM fd")); return fd; } ./src/platforms/mesa/server/kms/real_kms_output.cpp0000644000004100000410000002115713115234664023022 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "real_kms_output.h" #include "page_flipper.h" #include "kms-utils/kms_connector.h" #include "mir/fatal.h" #include "mir/log.h" #include // strcmp #include #include namespace mg = mir::graphics; namespace mgm = mg::mesa; namespace mgk = mg::kms; namespace geom = mir::geometry; mgm::RealKMSOutput::RealKMSOutput(int drm_fd, uint32_t connector_id, std::shared_ptr const& page_flipper) : drm_fd{drm_fd}, connector_id{connector_id}, page_flipper{page_flipper}, connector(), mode_index{0}, current_crtc(), saved_crtc(), using_saved_crtc{true}, has_cursor_{false}, power_mode(mir_power_mode_on) { reset(); kms::DRMModeResources resources{drm_fd}; if (connector->encoder_id) { auto encoder = resources.encoder(connector->encoder_id); if (encoder->crtc_id) { saved_crtc = *resources.crtc(encoder->crtc_id); } } } mgm::RealKMSOutput::~RealKMSOutput() { restore_saved_crtc(); } void mgm::RealKMSOutput::reset() { kms::DRMModeResources resources{drm_fd}; /* Update the connector to ensure we have the latest information */ try { connector = resources.connector(connector_id); } catch (std::exception const& e) { fatal_error(e.what()); } // TODO: What if we can't locate the DPMS property? for (int i = 0; i < connector->count_props; i++) { auto prop = drmModeGetProperty(drm_fd, connector->props[i]); if (prop && (prop->flags & DRM_MODE_PROP_ENUM)) { if (!strcmp(prop->name, "DPMS")) { dpms_enum_id = connector->props[i]; drmModeFreeProperty(prop); break; } drmModeFreeProperty(prop); } } /* Discard previously current crtc */ current_crtc = nullptr; } geom::Size mgm::RealKMSOutput::size() const { drmModeModeInfo const& mode(connector->modes[mode_index]); return {mode.hdisplay, mode.vdisplay}; } int mgm::RealKMSOutput::max_refresh_rate() const { drmModeModeInfo const& current_mode = connector->modes[mode_index]; return current_mode.vrefresh; } void mgm::RealKMSOutput::configure(geom::Displacement offset, size_t kms_mode_index) { fb_offset = offset; mode_index = kms_mode_index; } bool mgm::RealKMSOutput::set_crtc(uint32_t fb_id) { if (!ensure_crtc()) { mir::log_error("Output %s has no associated CRTC to set a framebuffer on", mgk::connector_name(connector).c_str()); return false; } auto ret = drmModeSetCrtc(drm_fd, current_crtc->crtc_id, fb_id, fb_offset.dx.as_int(), fb_offset.dy.as_int(), &connector->connector_id, 1, &connector->modes[mode_index]); if (ret) { current_crtc = nullptr; return false; } using_saved_crtc = false; return true; } void mgm::RealKMSOutput::clear_crtc() { try { ensure_crtc(); } catch (...) { /* * In order to actually clear the output, we need to have a crtc * connected to the output/connector so that we can disconnect * it. However, not being able to get a crtc is OK, since it means * that the output cannot be displaying anything anyway. */ return; } auto result = drmModeSetCrtc(drm_fd, current_crtc->crtc_id, 0, 0, 0, nullptr, 0, nullptr); if (result) { fatal_error("Couldn't clear output %s (drmModeSetCrtc = %d)", mgk::connector_name(connector).c_str(), result); } current_crtc = nullptr; } bool mgm::RealKMSOutput::schedule_page_flip(uint32_t fb_id) { std::unique_lock lg(power_mutex); if (power_mode != mir_power_mode_on) return true; if (!current_crtc) { mir::log_error("Output %s has no associated CRTC to schedule page flips on", mgk::connector_name(connector).c_str()); return false; } return page_flipper->schedule_flip(current_crtc->crtc_id, fb_id, connector_id); } void mgm::RealKMSOutput::wait_for_page_flip() { std::unique_lock lg(power_mutex); if (power_mode != mir_power_mode_on) return; if (!current_crtc) { fatal_error("Output %s has no associated CRTC to wait on", mgk::connector_name(connector).c_str()); } last_frame_.store(page_flipper->wait_for_flip(current_crtc->crtc_id)); } mg::Frame mgm::RealKMSOutput::last_frame() const { return last_frame_.load(); } void mgm::RealKMSOutput::set_cursor(gbm_bo* buffer) { if (current_crtc) { has_cursor_ = true; if (auto result = drmModeSetCursor( drm_fd, current_crtc->crtc_id, gbm_bo_get_handle(buffer).u32, gbm_bo_get_width(buffer), gbm_bo_get_height(buffer))) { has_cursor_ = false; mir::log_warning("set_cursor: drmModeSetCursor failed (%s)", strerror(-result)); } } } void mgm::RealKMSOutput::move_cursor(geometry::Point destination) { if (current_crtc) { if (auto result = drmModeMoveCursor(drm_fd, current_crtc->crtc_id, destination.x.as_uint32_t(), destination.y.as_uint32_t())) { mir::log_warning("move_cursor: drmModeMoveCursor failed (%s)", strerror(-result)); } } } void mgm::RealKMSOutput::clear_cursor() { if (current_crtc) { auto result = drmModeSetCursor(drm_fd, current_crtc->crtc_id, 0, 0, 0); if (result) mir::log_warning("clear_cursor: drmModeSetCursor failed (%s)", strerror(-result)); has_cursor_ = false; } } bool mgm::RealKMSOutput::has_cursor() const { return has_cursor_; } bool mgm::RealKMSOutput::ensure_crtc() { /* Nothing to do if we already have a crtc */ if (current_crtc) return true; /* If the output is not connected there is nothing to do */ if (connector->connection != DRM_MODE_CONNECTED) return false; current_crtc = mgk::find_crtc_for_connector(drm_fd, connector); return (current_crtc != nullptr); } void mgm::RealKMSOutput::restore_saved_crtc() { if (!using_saved_crtc) { drmModeSetCrtc(drm_fd, saved_crtc.crtc_id, saved_crtc.buffer_id, saved_crtc.x, saved_crtc.y, &connector->connector_id, 1, &saved_crtc.mode); using_saved_crtc = true; } } void mgm::RealKMSOutput::set_power_mode(MirPowerMode mode) { std::lock_guard lg(power_mutex); if (power_mode != mode) { power_mode = mode; drmModeConnectorSetProperty(drm_fd, connector_id, dpms_enum_id, mode); } } void mgm::RealKMSOutput::set_gamma(mg::GammaCurves const& gamma) { if (!ensure_crtc()) { mir::log_warning("Output %s has no associated CRTC to set gamma on", mgk::connector_name(connector).c_str()); return; } if (gamma.red.size() != gamma.green.size() || gamma.green.size() != gamma.blue.size()) { BOOST_THROW_EXCEPTION( std::invalid_argument("set_gamma: mismatch gamma LUT sizes")); } int ret = drmModeCrtcSetGamma( drm_fd, current_crtc->crtc_id, gamma.red.size(), const_cast(gamma.red.data()), const_cast(gamma.green.data()), const_cast(gamma.blue.data())); int err = -ret; if (err) mir::log_warning("drmModeCrtcSetGamma failed: %s", strerror(err)); // TODO: return bool in future? Then do what with it? } ./src/platforms/mesa/server/kms/linux_virtual_terminal.h0000644000004100000410000000703413115234416024043 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_LINUX_VIRTUAL_TERMINAL_H_ #define MIR_GRAPHICS_MESA_LINUX_VIRTUAL_TERMINAL_H_ #include "virtual_terminal.h" #include #include #include #include namespace mir { namespace graphics { class DisplayReport; namespace mesa { class VTFileOperations { public: virtual ~VTFileOperations() = default; virtual int open(char const* pathname, int flags) = 0; virtual int close(int fd) = 0; virtual int ioctl(int d, int request, int val) = 0; virtual int ioctl(int d, int request, void* p_val) = 0; virtual int tcsetattr(int d, int acts, const struct termios *tcattr) = 0; virtual int tcgetattr(int d, struct termios *tcattr) = 0; protected: VTFileOperations() = default; VTFileOperations(VTFileOperations const&) = delete; VTFileOperations& operator=(VTFileOperations const&) = delete; }; class PosixProcessOperations { public: virtual ~PosixProcessOperations() = default; virtual pid_t getpid() const = 0; virtual pid_t getppid() const = 0; virtual pid_t getpgid(pid_t process) const = 0; virtual pid_t getsid(pid_t process) const = 0; virtual int setpgid(pid_t process, pid_t group) = 0; virtual pid_t setsid() = 0; protected: PosixProcessOperations() = default; PosixProcessOperations(PosixProcessOperations const&) = delete; PosixProcessOperations& operator=(PosixProcessOperations const&) = delete; }; class LinuxVirtualTerminal : public VirtualTerminal { public: LinuxVirtualTerminal(std::shared_ptr const& fops, std::unique_ptr pops, int vt_number, std::shared_ptr const& report); ~LinuxVirtualTerminal() noexcept(true); void set_graphics_mode() override; void register_switch_handlers( EventHandlerRegister& handlers, std::function const& switch_away, std::function const& switch_back) override; void restore() override; private: class FDWrapper { public: FDWrapper(std::shared_ptr const& fops, int fd) : fops{fops}, fd_{fd} { } ~FDWrapper() { if (fd_ >= 0) fops->close(fd_); } int fd() const { return fd_; } private: std::shared_ptr const fops; int const fd_; }; int find_active_vt_number(); int open_vt(int vt_number); std::shared_ptr const fops; std::unique_ptr const pops; std::shared_ptr const report; FDWrapper const vt_fd; int prev_kd_mode; struct vt_mode prev_vt_mode; int prev_tty_mode; struct termios prev_tcattr; bool active; }; } } } #endif /* MIR_GRAPHICS_MESA_LINUX_VIRTUAL_TERMINAL_H_ */ ./src/platforms/mesa/server/kms/guest_platform.cpp0000644000004100000410000000567713115234664022651 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Eleni Maria Stea * Alan Griffiths */ #include "guest_platform.h" #include "nested_authentication.h" #include "ipc_operations.h" #include "buffer_allocator.h" #include "mir/graphics/nested_context.h" #include "mir/graphics/platform_operation_message.h" #include "mir_toolkit/mesa/platform_operation.h" #include "mir_toolkit/extensions/set_gbm_device.h" #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mg::mesa; namespace { //TODO: construction for mclm::ClientPlatform is roundabout/2-step. // Might be better for the extension to be a different way to allocate // MirConnection, but beyond scope of work. void set_guest_gbm_device(mg::NestedContext& nested_context, gbm_device* device) { std::string const msg{"Nested Mir failed to set the gbm device."}; auto ext = nested_context.set_gbm_extension(); if (ext.is_set()) ext.value()->set_gbm_device(device); else BOOST_THROW_EXCEPTION(std::runtime_error("Nested Mir failed to set the gbm device.")); } } mgm::GuestPlatform::GuestPlatform( std::shared_ptr const& nested_context) : nested_context{nested_context} { auto ext = nested_context->auth_extension(); if (!ext.is_set()) BOOST_THROW_EXCEPTION(std::runtime_error("could not access drm auth fd")); gbm.setup(ext.value()->auth_fd()); set_guest_gbm_device(*nested_context, gbm.device); } mir::UniqueModulePtr mgm::GuestPlatform::create_buffer_allocator() { return mir::make_module_ptr(gbm.device, mgm::BypassOption::prohibited, mgm::BufferImportMethod::gbm_native_pixmap); } mir::UniqueModulePtr mgm::GuestPlatform::make_ipc_operations() const { return mir::make_module_ptr( std::make_shared(nested_context)); } mir::UniqueModulePtr mgm::GuestPlatform::create_display( std::shared_ptr const&, std::shared_ptr const& /*gl_config*/) { BOOST_THROW_EXCEPTION(std::runtime_error("mgm::GuestPlatform cannot create display\n")); } ./src/platforms/mesa/server/kms/cursor.cpp0000644000004100000410000002313013115234664021113 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #include "cursor.h" #include "platform.h" #include "kms_output.h" #include "kms_output_container.h" #include "kms_display_configuration.h" #include "mir/geometry/rectangle.h" #include "mir/graphics/cursor_image.h" #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mg::mesa; namespace geom = mir::geometry; namespace { const uint64_t fallback_cursor_size = 64; char const* const mir_drm_cursor_64x64 = "MIR_DRM_CURSOR_64x64"; // Transforms a relative position within the display bounds described by \a rect which is rotated with \a orientation geom::Displacement transform(geom::Rectangle const& rect, geom::Displacement const& vector, MirOrientation orientation) { switch(orientation) { case mir_orientation_left: return {vector.dy.as_int(), rect.size.width.as_int() -vector.dx.as_int()}; case mir_orientation_inverted: return {rect.size.width.as_int() -vector.dx.as_int(), rect.size.height.as_int() - vector.dy.as_int()}; case mir_orientation_right: return {rect.size.height.as_int() -vector.dy.as_int(), vector.dx.as_int()}; default: case mir_orientation_normal: return vector; } } // support for older drm headers #ifndef DRM_CAP_CURSOR_WIDTH #define DRM_CAP_CURSOR_WIDTH 0x8 #define DRM_CAP_CURSOR_HEIGHT 0x9 #endif // In certain combinations of DRI backends and drivers GBM // returns a stride size that matches the requested buffers size, // instead of the underlying buffer: // https://bugs.freedesktop.org/show_bug.cgi?id=89164 int get_drm_cursor_height(int fd) { // on some older hardware drm incorrectly reports the cursor size bool const force_64x64_cursor = getenv(mir_drm_cursor_64x64); uint64_t height = fallback_cursor_size; if (!force_64x64_cursor) drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &height); return int(height); } int get_drm_cursor_width(int fd) { // on some older hardware drm incorrectly reports the cursor size bool const force_64x64_cursor = getenv(mir_drm_cursor_64x64); uint64_t width = fallback_cursor_size; if (!force_64x64_cursor) drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &width); return int(width); } } mgm::Cursor::GBMBOWrapper::GBMBOWrapper(gbm_device* gbm) : buffer(gbm_bo_create( gbm, get_drm_cursor_width(gbm_device_get_fd(gbm)), get_drm_cursor_height(gbm_device_get_fd(gbm)), GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE)) { if (!buffer) BOOST_THROW_EXCEPTION(std::runtime_error("failed to create gbm buffer")); } inline mgm::Cursor::GBMBOWrapper::operator gbm_bo*() { return buffer; } inline mgm::Cursor::GBMBOWrapper::~GBMBOWrapper() { gbm_bo_destroy(buffer); } mgm::Cursor::Cursor( gbm_device* gbm, KMSOutputContainer& output_container, std::shared_ptr const& current_configuration, std::shared_ptr const& initial_image) : output_container(output_container), current_position(), visible(true), last_set_failed(false), buffer(gbm), buffer_width(gbm_bo_get_width(buffer)), buffer_height(gbm_bo_get_height(buffer)), current_configuration(current_configuration) { show(*initial_image); if (last_set_failed) throw std::runtime_error("Initial KMS cursor set failed"); } mgm::Cursor::~Cursor() noexcept { hide(); } void mgm::Cursor::write_buffer_data_locked(std::lock_guard const&, void const* data, size_t count) { if (auto result = gbm_bo_write(buffer, data, count)) { BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error("failed to initialize gbm buffer")) << (boost::error_info(result))); } } void mgm::Cursor::pad_and_write_image_data_locked(std::lock_guard const& lg, CursorImage const& image) { auto image_argb = static_cast(image.as_argb_8888()); auto image_width = image.size().width.as_uint32_t(); auto image_height = image.size().height.as_uint32_t(); auto image_stride = image_width * 4; if (image_width > buffer_width || image_height > buffer_height) { BOOST_THROW_EXCEPTION(std::logic_error("Image is too big for GBM cursor buffer")); } size_t buffer_stride = gbm_bo_get_stride(buffer); // in bytes size_t padded_size = buffer_stride * buffer_height; auto padded = std::unique_ptr(new uint8_t[padded_size]); size_t rhs_padding = buffer_stride - image_stride; uint8_t* dest = &padded[0]; uint8_t const* src = image_argb; for (unsigned int y = 0; y < image_height; y++) { memcpy(dest, src, image_stride); memset(dest + image_stride, 0, rhs_padding); dest += buffer_stride; src += image_stride; } memset(dest, 0, buffer_stride * (buffer_height - image_height)); write_buffer_data_locked(lg, &padded[0], padded_size); } void mgm::Cursor::show() { std::lock_guard lg(guard); if (!visible) { visible = true; place_cursor_at_locked(lg, current_position, ForceState); } } void mgm::Cursor::show(CursorImage const& cursor_image) { std::lock_guard lg(guard); auto const& size = cursor_image.size(); if (size != geometry::Size{buffer_width, buffer_height}) { pad_and_write_image_data_locked(lg, cursor_image); } else { auto const count = size.width.as_uint32_t() * size.height.as_uint32_t() * sizeof(uint32_t); write_buffer_data_locked(lg, cursor_image.as_argb_8888(), count); } hotspot = cursor_image.hotspot(); // The hotspot may have changed so we need to call drmModeSetCursor again if the cursor was already visible. if (visible) place_cursor_at_locked(lg, current_position, ForceState); // Writing the data could throw an exception so lets // hold off on setting visible until after we have succeeded. visible = true; } void mgm::Cursor::move_to(geometry::Point position) { place_cursor_at(position, UpdateState); } void mir::graphics::mesa::Cursor::suspend() { std::lock_guard lg(guard); output_container.for_each_output( [&](KMSOutput& output) { output.clear_cursor(); }); } void mgm::Cursor::resume() { place_cursor_at(current_position, ForceState); } void mgm::Cursor::hide() { std::lock_guard lg(guard); visible = false; output_container.for_each_output( [&](KMSOutput& output) { output.clear_cursor(); }); } void mgm::Cursor::for_each_used_output( std::function const& f) { current_configuration->with_current_configuration_do( [this,&f](KMSDisplayConfiguration const& kms_conf) { kms_conf.for_each_output([&](DisplayConfigurationOutput const& conf_output) { if (conf_output.used) { uint32_t const connector_id = kms_conf.get_kms_connector_id(conf_output.id); auto output = output_container.get_kms_output_for(connector_id); f(*output, conf_output.extents(), conf_output.orientation); } }); }); } void mgm::Cursor::place_cursor_at( geometry::Point position, ForceCursorState force_state) { std::lock_guard lg(guard); place_cursor_at_locked(lg, position, force_state); } void mgm::Cursor::place_cursor_at_locked( std::lock_guard const&, geometry::Point position, ForceCursorState force_state) { current_position = position; if (!visible) return; bool set_on_all_outputs = true; for_each_used_output([&](KMSOutput& output, geom::Rectangle const& output_rect, MirOrientation orientation) { if (output_rect.contains(position)) { auto dp = transform(output_rect, position - output_rect.top_left, orientation); // It's a little strange that we implement hotspot this way as there is // drmModeSetCursor2 with hotspot support. However it appears to not actually // work on radeon and intel. There also seems to be precedent in weston for // implementing hotspot in this fashion. output.move_cursor(geom::Point{} + dp - hotspot); if (force_state || !output.has_cursor()) // TODO - or if orientation had changed - then set buffer.. { output.set_cursor(buffer); if (!output.has_cursor()) set_on_all_outputs = false; } } else { if (force_state || output.has_cursor()) { output.clear_cursor(); } } }); last_set_failed = !set_on_all_outputs; } ./src/platforms/mesa/server/kms/real_kms_output_container.cpp0000644000004100000410000000313213115234416025050 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "real_kms_output_container.h" #include "real_kms_output.h" namespace mgm = mir::graphics::mesa; mgm::RealKMSOutputContainer::RealKMSOutputContainer( int drm_fd, std::shared_ptr const& page_flipper) : drm_fd{drm_fd}, page_flipper{page_flipper} { } std::shared_ptr mgm::RealKMSOutputContainer::get_kms_output_for(uint32_t connector_id) { std::shared_ptr output; auto output_iter = outputs.find(connector_id); if (output_iter == outputs.end()) { output = std::make_shared(drm_fd, connector_id, page_flipper); outputs[connector_id] = output; } else { output = output_iter->second; } return output; } void mgm::RealKMSOutputContainer::for_each_output(std::function functor) const { for(auto& pair: outputs) functor(*pair.second); } ./src/platforms/mesa/server/kms/nested_authentication.h0000644000004100000410000000253613115234664023633 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_MESA_NESTED_AUTHENTICATION_H_ #define MIR_GRAPHICS_MESA_NESTED_AUTHENTICATION_H_ #include "drm_authentication.h" namespace mir { namespace graphics { class NestedContext; class MesaAuthExtension; namespace mesa { class NestedAuthentication : public DRMAuthentication { public: NestedAuthentication(std::shared_ptr const& nested_context); void auth_magic(drm_magic_t magic) override; mir::Fd authenticated_fd() override; private: std::shared_ptr const nested_context; std::shared_ptr const auth_extension; }; } } } #endif /* MIR_GRAPHICS_MESA_NESTED_AUTHENTICATION_H_ */ ./src/platforms/mesa/server/kms/virtual_terminal.h0000644000004100000410000000272013115234416022621 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_VIRTUAL_TERMINAL_H_ #define MIR_GRAPHICS_MESA_VIRTUAL_TERMINAL_H_ #include namespace mir { namespace graphics { class EventHandlerRegister; namespace mesa { class VirtualTerminal { public: virtual ~VirtualTerminal() = default; virtual void set_graphics_mode() = 0; virtual void register_switch_handlers( EventHandlerRegister& handlers, std::function const& switch_away, std::function const& switch_back) = 0; virtual void restore() = 0; protected: VirtualTerminal() = default; VirtualTerminal(VirtualTerminal const&) = delete; VirtualTerminal& operator=(VirtualTerminal const&) = delete; }; } } } #endif /* MIR_GRAPHICS_MESA_VIRTUAL_TERMINAL_H_ */ ./src/platforms/mesa/server/kms/kms_page_flipper.cpp0000644000004100000410000001354713115234664023120 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "kms_page_flipper.h" #include "mir/graphics/display_report.h" #include #include #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace { void page_flip_handler(int /*fd*/, unsigned int seq, unsigned int sec, unsigned int usec, void* data) { auto page_flip_data = static_cast(data); std::chrono::nanoseconds ns{sec*1000000000LL + usec*1000LL}; page_flip_data->flipper->notify_page_flip(page_flip_data->crtc_id, seq, ns); } } mgm::KMSPageFlipper::KMSPageFlipper( int drm_fd, std::shared_ptr const& report) : drm_fd{drm_fd}, report{report}, pending_page_flips(), worker_tid() { uint64_t mono = 0; if (drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &mono) || !mono) clock_id = CLOCK_REALTIME; else clock_id = CLOCK_MONOTONIC; } bool mgm::KMSPageFlipper::schedule_flip(uint32_t crtc_id, uint32_t fb_id, uint32_t connector_id) { std::unique_lock lock{pf_mutex}; if (pending_page_flips.find(crtc_id) != pending_page_flips.end()) BOOST_THROW_EXCEPTION(std::logic_error("Page flip for crtc_id is already scheduled")); pending_page_flips[crtc_id] = PageFlipEventData{crtc_id, connector_id, this}; /* * It appears we can't tell the difference between flipping being * unsupported or failing for other reasons. On VirtualBox this always * fails with -22 (Invalid argument) despite the arguments being * apparently valid. */ auto ret = drmModePageFlip(drm_fd, crtc_id, fb_id, DRM_MODE_PAGE_FLIP_EVENT, &pending_page_flips[crtc_id]); if (ret) pending_page_flips.erase(crtc_id); return (ret == 0); } mg::Frame mgm::KMSPageFlipper::wait_for_flip(uint32_t crtc_id) { drmEventContext evctx; memset(&evctx, 0, sizeof evctx); evctx.version = 2; // We only support the old v2 page_flip_handler evctx.page_flip_handler = &page_flip_handler; static std::thread::id const invalid_tid; { std::unique_lock lock{pf_mutex}; /* * While another thread is the worker (it is controlling the * page flip event loop) and our event has not arrived, wait. */ while (worker_tid != invalid_tid && !page_flip_is_done(crtc_id)) pf_cv.wait(lock); /* If the page flip we are waiting for has arrived we are done. */ if (page_flip_is_done(crtc_id)) return completed_page_flips[crtc_id]; /* ...otherwise we become the worker */ worker_tid = std::this_thread::get_id(); } /* Only the worker thread reaches this point */ bool done{false}; while (!done) { fd_set fds; FD_ZERO(&fds); FD_SET(drm_fd, &fds); /* * Wait for a page flip event. When we get a page flip event, * page_flip_handler(), called through drmHandleEvent(), will update * the pending_page_flips map. */ auto ret = select(drm_fd + 1, &fds, nullptr, nullptr, nullptr); { std::unique_lock lock{pf_mutex}; if (ret > 0) { drmHandleEvent(drm_fd, &evctx); } else if (ret < 0 && errno != EINTR) { std::string const msg("Error while waiting for page-flip event"); BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error(msg)) << boost::errinfo_errno(errno)); } done = page_flip_is_done(crtc_id); /* Give up loop control if we are done */ if (done) worker_tid = invalid_tid; } /* * Wake up other (non-worker) threads, so they can check whether * their page-flip events have arrived, or whether they can become * the worker (see pf_cv.wait(lock) above). */ pf_cv.notify_all(); } return completed_page_flips[crtc_id]; } std::thread::id mgm::KMSPageFlipper::debug_get_worker_tid() { std::unique_lock lock{pf_mutex}; return worker_tid; } /* This method should be called with the 'pf_mutex' locked */ bool mgm::KMSPageFlipper::page_flip_is_done(uint32_t crtc_id) { return pending_page_flips.find(crtc_id) == pending_page_flips.end(); } void mgm::KMSPageFlipper::notify_page_flip(uint32_t crtc_id, int64_t msc, std::chrono::nanoseconds ust) { auto pending = pending_page_flips.find(crtc_id); if (pending != pending_page_flips.end()) { auto& frame = completed_page_flips[crtc_id]; frame.msc = msc; frame.ust = {clock_id, ust}; report->report_vsync(pending->second.connector_id, frame); pending_page_flips.erase(pending); } } ./src/platforms/mesa/server/kms/kms_page_flipper.h0000644000004100000410000000377613115234664022570 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_KMS_PAGE_FLIPPER_H_ #define MIR_GRAPHICS_MESA_KMS_PAGE_FLIPPER_H_ #include "page_flipper.h" #include #include #include #include #include #include #include namespace mir { namespace graphics { class DisplayReport; namespace mesa { class KMSPageFlipper; struct PageFlipEventData { uint32_t crtc_id; uint32_t connector_id; KMSPageFlipper* flipper; }; class KMSPageFlipper : public PageFlipper { public: KMSPageFlipper(int drm_fd, std::shared_ptr const& report); bool schedule_flip(uint32_t crtc_id, uint32_t fb_id, uint32_t connector_id) override; Frame wait_for_flip(uint32_t crtc_id) override; std::thread::id debug_get_worker_tid(); void notify_page_flip(uint32_t crtc_id, int64_t msc, std::chrono::nanoseconds ust); private: bool page_flip_is_done(uint32_t crtc_id); int const drm_fd; std::shared_ptr const report; std::unordered_map pending_page_flips; std::unordered_map completed_page_flips; std::mutex pf_mutex; std::condition_variable pf_cv; std::thread::id worker_tid; clockid_t clock_id; }; } } } #endif /* MIR_GRAPHICS_MESA_KMS_PAGE_FLIPPER_H_ */ ./src/platforms/mesa/server/kms/display_buffer.h0000644000004100000410000000735313115234664022252 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_DISPLAY_BUFFER_H_ #define MIR_GRAPHICS_MESA_DISPLAY_BUFFER_H_ #include "mir/graphics/display_buffer.h" #include "mir/graphics/display.h" #include "mir/renderer/gl/render_target.h" #include "display_helpers.h" #include "platform_common.h" #include #include #include namespace mir { namespace graphics { class DisplayReport; class GLConfig; namespace mesa { class Platform; class BufferObject; class KMSOutput; class DisplayBuffer : public graphics::DisplayBuffer, public graphics::DisplaySyncGroup, public graphics::NativeDisplayBuffer, public renderer::gl::RenderTarget { public: DisplayBuffer(BypassOption bypass_options, std::shared_ptr const& drm, std::shared_ptr const& gbm, std::shared_ptr const& listener, std::vector> const& outputs, GBMSurfaceUPtr surface_gbm, geometry::Rectangle const& area, MirOrientation rot, GLConfig const& gl_config, EGLContext shared_context); ~DisplayBuffer(); geometry::Rectangle view_area() const override; void make_current() override; void release_current() override; void swap_buffers() override; bool overlay(RenderableList const& renderlist) override; void bind() override; void for_each_display_buffer( std::function const& f) override; void post() override; std::chrono::milliseconds recommended_sleep() const override; MirOrientation orientation() const override; MirMirrorMode mirror_mode() const override; NativeDisplayBuffer* native_display_buffer() override; void set_orientation(MirOrientation const rot, geometry::Rectangle const& a); void schedule_set_crtc(); void wait_for_page_flip(); private: BufferObject* get_front_buffer_object(); BufferObject* get_buffer_object(struct gbm_bo *bo); bool schedule_page_flip(BufferObject* bufobj); void set_crtc(BufferObject const*); BufferObject* visible_composite_frame; BufferObject* scheduled_composite_frame; std::shared_ptr visible_bypass_frame, scheduled_bypass_frame; std::shared_ptr bypass_buf{nullptr}; BufferObject* bypass_bufobj{nullptr}; std::shared_ptr const listener; BypassOption bypass_option; /* DRM helper from mgm::Platform */ std::shared_ptr const drm; std::shared_ptr const gbm; std::vector> outputs; GBMSurfaceUPtr surface_gbm; helpers::EGLHelper egl; geometry::Rectangle area; uint32_t fb_width, fb_height; MirOrientation rotation; std::atomic needs_set_crtc; std::chrono::milliseconds recommend_sleep{0}; bool page_flips_pending; }; } } } #endif /* MIR_GRAPHICS_MESA_DISPLAY_BUFFER_H_ */ ./src/platforms/mesa/server/kms/cursor.h0000644000004100000410000000642613115234664020571 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_GRAPHICS_MESA_CURSOR_H_ #define MIR_GRAPHICS_MESA_CURSOR_H_ #include "mir/graphics/cursor.h" #include "mir/geometry/point.h" #include "mir/geometry/displacement.h" #include "mir_toolkit/common.h" #include #include #include namespace mir { namespace geometry { struct Rectangle; } namespace graphics { class CursorImage; namespace mesa { class KMSOutputContainer; class KMSOutput; class KMSDisplayConfiguration; class GBMPlatform; class CurrentConfiguration { public: virtual ~CurrentConfiguration() = default; virtual void with_current_configuration_do( std::function const& exec) = 0; protected: CurrentConfiguration() = default; CurrentConfiguration(CurrentConfiguration const&) = delete; CurrentConfiguration& operator=(CurrentConfiguration const&) = delete; }; class Cursor : public graphics::Cursor { public: Cursor( gbm_device* device, KMSOutputContainer& output_container, std::shared_ptr const& current_configuration, std::shared_ptr const& cursor_image); ~Cursor() noexcept; void show() override; void show(CursorImage const& cursor_image) override; void hide() override; void move_to(geometry::Point position) override; void suspend(); void resume(); private: enum ForceCursorState { UpdateState, ForceState }; void for_each_used_output(std::function const& f); void place_cursor_at(geometry::Point position, ForceCursorState force_state); void place_cursor_at_locked(std::lock_guard const&, geometry::Point position, ForceCursorState force_state); void write_buffer_data_locked(std::lock_guard const&, void const* data, size_t count); void pad_and_write_image_data_locked(std::lock_guard const&, CursorImage const& image); std::mutex guard; KMSOutputContainer& output_container; geometry::Point current_position; geometry::Displacement hotspot; bool visible; bool last_set_failed; struct GBMBOWrapper { GBMBOWrapper(gbm_device* gbm); operator gbm_bo*(); ~GBMBOWrapper(); private: gbm_bo* buffer; GBMBOWrapper(GBMBOWrapper const&) = delete; GBMBOWrapper& operator=(GBMBOWrapper const&) = delete; } buffer; uint32_t buffer_width; uint32_t buffer_height; std::shared_ptr const current_configuration; }; } } } #endif /* MIR_GRAPHICS_MESA_CURSOR_H_ */ ./src/platforms/mesa/server/kms/kms_output.h0000644000004100000410000000450213115234664021457 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_KMS_OUTPUT_H_ #define MIR_GRAPHICS_MESA_KMS_OUTPUT_H_ #include "mir/geometry/size.h" #include "mir/geometry/point.h" #include "mir/geometry/displacement.h" #include "mir/graphics/display_configuration.h" #include "mir/graphics/frame.h" #include "mir_toolkit/common.h" #include namespace mir { namespace graphics { namespace mesa { class KMSOutput { public: virtual ~KMSOutput() = default; virtual void reset() = 0; virtual void configure(geometry::Displacement fb_offset, size_t kms_mode_index) = 0; virtual geometry::Size size() const = 0; /** * Approximate maximum refresh rate of this output to within 1Hz. * Typically the rate is fixed (e.g. 60Hz) but it may also be variable as * in Nvidia G-Sync/AMD FreeSync/VESA Adaptive Sync. So this function * returns the maximum rate to expect. */ virtual int max_refresh_rate() const = 0; virtual bool set_crtc(uint32_t fb_id) = 0; virtual void clear_crtc() = 0; virtual bool schedule_page_flip(uint32_t fb_id) = 0; virtual void wait_for_page_flip() = 0; virtual void set_cursor(gbm_bo* buffer) = 0; virtual void move_cursor(geometry::Point destination) = 0; virtual void clear_cursor() = 0; virtual bool has_cursor() const = 0; virtual void set_power_mode(MirPowerMode mode) = 0; virtual void set_gamma(GammaCurves const& gamma) = 0; virtual Frame last_frame() const = 0; protected: KMSOutput() = default; KMSOutput(const KMSOutput&) = delete; KMSOutput& operator=(const KMSOutput&) = delete; }; } } } #endif /* MIR_GRAPHICS_MESA_KMS_OUTPUT_H_ */ ./src/platforms/mesa/server/kms/kms_display_configuration.h0000644000004100000410000000252513115234416024511 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_KMS_DISPLAY_CONFIGURATION_H_ #define MIR_GRAPHICS_MESA_KMS_DISPLAY_CONFIGURATION_H_ #include "mir/graphics/display_configuration.h" namespace mir { namespace graphics { namespace mesa { class DRMModeResources; class KMSDisplayConfiguration : public DisplayConfiguration { public: virtual uint32_t get_kms_connector_id(DisplayConfigurationOutputId id) const = 0; virtual size_t get_kms_mode_index(DisplayConfigurationOutputId id, size_t conf_mode_index) const = 0; virtual void update() = 0; }; } } } #endif /* MIR_GRAPHICS_MESA_KMS_DISPLAY_CONFIGURATION_H_ */ ./src/platforms/mesa/server/kms/real_kms_display_configuration.cpp0000644000004100000410000003365513115234664026064 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "real_kms_display_configuration.h" #include "kms-utils/drm_mode_resources.h" #include "mir/graphics/pixel_format_utils.h" #include "mir/log.h" #include #include #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace mgk = mir::graphics::kms; namespace geom = mir::geometry; namespace { bool kms_modes_are_equal(drmModeModeInfo const& info1, drmModeModeInfo const& info2) { return (info1.clock == info2.clock && info1.hdisplay == info2.hdisplay && info1.hsync_start == info2.hsync_start && info1.hsync_end == info2.hsync_end && info1.htotal == info2.htotal && info1.hskew == info2.hskew && info1.vdisplay == info2.vdisplay && info1.vsync_start == info2.vsync_start && info1.vsync_end == info2.vsync_end && info1.vtotal == info2.vtotal); } double calculate_vrefresh_hz(drmModeModeInfo const& mode) { if (mode.htotal == 0 || mode.vtotal == 0) return 0.0; /* mode.clock is in KHz */ double hz = (mode.clock * 100000LL / ((long)mode.htotal * (long)mode.vtotal) ) / 100.0; // Actually we don't need floating point at all for this... // TODO: Consider converting our structs to fixed-point ints return hz; } mg::DisplayConfigurationOutputType kms_connector_type_to_output_type(uint32_t connector_type) { return static_cast(connector_type); } MirSubpixelArrangement kms_subpixel_to_mir_subpixel(uint32_t subpixel) { switch (subpixel) { case DRM_MODE_SUBPIXEL_UNKNOWN: return mir_subpixel_arrangement_unknown; case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB: return mir_subpixel_arrangement_horizontal_rgb; case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR: return mir_subpixel_arrangement_horizontal_bgr; case DRM_MODE_SUBPIXEL_VERTICAL_RGB: return mir_subpixel_arrangement_vertical_rgb; case DRM_MODE_SUBPIXEL_VERTICAL_BGR: return mir_subpixel_arrangement_vertical_bgr; case DRM_MODE_SUBPIXEL_NONE: return mir_subpixel_arrangement_none; default: return mir_subpixel_arrangement_unknown; } } } mgm::RealKMSDisplayConfiguration::RealKMSDisplayConfiguration(int drm_fd) : drm_fd{drm_fd} { update(); } mgm::RealKMSDisplayConfiguration::RealKMSDisplayConfiguration( RealKMSDisplayConfiguration const& conf) : KMSDisplayConfiguration(), drm_fd{conf.drm_fd}, card(conf.card), outputs{conf.outputs} { } mgm::RealKMSDisplayConfiguration& mgm::RealKMSDisplayConfiguration::operator=( RealKMSDisplayConfiguration const& conf) { if (&conf != this) { drm_fd = conf.drm_fd; card = conf.card; outputs = conf.outputs; } return *this; } void mgm::RealKMSDisplayConfiguration::for_each_card( std::function f) const { f(card); } void mgm::RealKMSDisplayConfiguration::for_each_output( std::function f) const { for (auto const& output : outputs) f(output); } void mgm::RealKMSDisplayConfiguration::for_each_output( std::function f) { for (auto& output : outputs) { UserDisplayConfigurationOutput user(output); f(user); } } std::unique_ptr mgm::RealKMSDisplayConfiguration::clone() const { return std::make_unique(*this); } uint32_t mgm::RealKMSDisplayConfiguration::get_kms_connector_id( DisplayConfigurationOutputId id) const { auto iter = find_output_with_id(id); if (iter == outputs.end()) { BOOST_THROW_EXCEPTION( std::runtime_error("Failed to find DisplayConfigurationOutput with provided id")); } return id.as_value(); } size_t mgm::RealKMSDisplayConfiguration::get_kms_mode_index( DisplayConfigurationOutputId id, size_t conf_mode_index) const { auto iter = find_output_with_id(id); if (iter == outputs.end() || conf_mode_index >= iter->modes.size()) { BOOST_THROW_EXCEPTION( std::runtime_error("Failed to find valid mode index for DisplayConfigurationOutput with provided id/mode_index")); } return conf_mode_index; } void mgm::RealKMSDisplayConfiguration::update() { kms::DRMModeResources resources{drm_fd}; size_t max_outputs = std::min(resources.num_crtcs(), resources.num_connectors()); card = {DisplayConfigurationCardId{0}, max_outputs}; resources.for_each_connector([&](kms::DRMModeConnectorUPtr connector) { add_or_update_output(resources, *connector); }); } namespace { std::vector edid_for_connector(int drm_fd, uint32_t connector_id) { std::vector edid; mgk::ObjectProperties connector_props{ drm_fd, connector_id, DRM_MODE_OBJECT_CONNECTOR}; if (connector_props.has_property("EDID")) { /* * We don't technically need the property information here, but query it * anyway so we can detect if our assumptions about DRM behaviour * become invalid. */ auto property = mgk::DRMModePropertyUPtr{ drmModeGetProperty(drm_fd, connector_props.id_for("EDID")), &drmModeFreeProperty}; if (!property) { mir::log_warning( "Failed to get EDID property for connector %u: %i (%s)", connector_id, errno, ::strerror(errno)); return edid; } if (!drm_property_type_is(property.get(), DRM_MODE_PROP_BLOB)) { mir::log_warning( "EDID property on connector %u has unexpected type %u", connector_id, property->flags); return edid; } // A property ID of 0 means invalid. if (connector_props["EDID"] == 0) { /* * Log a debug message only. This will trigger for broken monitors which * don't provide an EDID, which is not as unusual as you might think... */ mir::log_debug("No EDID data available on connector %u", connector_id); return edid; } auto blob = drmModeGetPropertyBlob(drm_fd, connector_props["EDID"]); if (!blob) { mir::log_warning( "Failed to get EDID property blob for connector %u: %i (%s)", connector_id, errno, ::strerror(errno)); return edid; } edid.reserve(blob->length); edid.insert(edid.begin(), reinterpret_cast(blob->data), reinterpret_cast(blob->data) + blob->length); drmModeFreePropertyBlob(blob); edid.shrink_to_fit(); } return edid; } } void mgm::RealKMSDisplayConfiguration::add_or_update_output( kms::DRMModeResources const& resources, drmModeConnector const& connector) { DisplayConfigurationOutputId id{static_cast(connector.connector_id)}; DisplayConfigurationCardId card_id{0}; DisplayConfigurationOutputType const type{ kms_connector_type_to_output_type(connector.connector_type)}; geom::Size physical_size{connector.mmWidth, connector.mmHeight}; bool connected{connector.connection == DRM_MODE_CONNECTED}; uint32_t const invalid_mode_index = std::numeric_limits::max(); uint32_t current_mode_index{invalid_mode_index}; uint32_t preferred_mode_index{invalid_mode_index}; std::vector modes; std::vector formats {mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888}; std::vector edid; if (connected) { /* Only ask for the EDID on connected outputs. There's obviously no monitor EDID * when there is no monitor connected! */ edid = edid_for_connector(drm_fd, connector.connector_id); } drmModeModeInfo current_mode_info = drmModeModeInfo(); GammaCurves gamma; /* Get information about the current mode */ if (connector.encoder_id) { auto encoder = resources.encoder(connector.encoder_id); if (encoder->crtc_id) { current_mode_info = resources.crtc(encoder->crtc_id)->mode; auto crtc = resources.crtc(encoder->crtc_id); if (crtc->gamma_size > 0) gamma = mg::LinearGammaLUTs(crtc->gamma_size); } } /* Add all the available modes and find the current and preferred one */ for (int m = 0; m < connector.count_modes; m++) { drmModeModeInfo& mode_info = connector.modes[m]; geom::Size size{mode_info.hdisplay, mode_info.vdisplay}; double vrefresh_hz = calculate_vrefresh_hz(mode_info); modes.push_back({size, vrefresh_hz}); if (kms_modes_are_equal(mode_info, current_mode_info)) current_mode_index = m; if ((mode_info.type & DRM_MODE_TYPE_PREFERRED) == DRM_MODE_TYPE_PREFERRED) preferred_mode_index = m; } /* Add or update the output */ auto iter = find_output_with_id(id); if (iter == outputs.end()) { outputs.push_back({id, card_id, type, formats, modes, preferred_mode_index, physical_size, connected, false, geom::Point(), current_mode_index, mir_pixel_format_xrgb_8888, mir_power_mode_on, mir_orientation_normal, 1.0f, mir_form_factor_monitor, kms_subpixel_to_mir_subpixel(connector.subpixel), gamma, mir_output_gamma_supported, std::move(edid)}); } else { auto& output = *iter; if (current_mode_index != invalid_mode_index) { output.current_mode_index = current_mode_index; } else if (!modes.empty() && // If empty retain old current_mode_index! ( output.current_mode_index >= modes.size() || output.modes[output.current_mode_index] != modes[output.current_mode_index])) { // current_mode_index is invalid and the definition of the old // current mode has also changed (different display plugged in) // so fall back to the preferred mode... output.current_mode_index = preferred_mode_index; } // else output.current_mode_index is correct and unchanged. output.modes = modes; output.preferred_mode_index = preferred_mode_index; output.physical_size_mm = physical_size; output.connected = connected; output.current_format = mir_pixel_format_xrgb_8888; output.subpixel_arrangement = kms_subpixel_to_mir_subpixel(connector.subpixel); output.gamma = gamma; output.edid = edid; } } std::vector::iterator mgm::RealKMSDisplayConfiguration::find_output_with_id(mg::DisplayConfigurationOutputId id) { return std::find_if(outputs.begin(), outputs.end(), [id](DisplayConfigurationOutput const& output) { return output.id == id; }); } std::vector::const_iterator mgm::RealKMSDisplayConfiguration::find_output_with_id(mg::DisplayConfigurationOutputId id) const { return std::find_if(outputs.begin(), outputs.end(), [id](DisplayConfigurationOutput const& output) { return output.id == id; }); } // Compatibility means conf1 can be attained from conf2 (and vice versa) // without recreating the display buffers (e.g. conf1 and conf2 are identical // except one of the outputs of conf1 is rotated w.r.t. that of conf2). If // the two outputs differ in their power state, the display buffers would need // to be allocated/destroyed, and hence should not be considered compatible. bool mgm::compatible(mgm::RealKMSDisplayConfiguration const& conf1, mgm::RealKMSDisplayConfiguration const& conf2) { bool compatible{(conf1.drm_fd == conf2.drm_fd) && (conf1.card == conf2.card) && (conf1.outputs.size() == conf2.outputs.size())}; if (compatible) { unsigned int const count = conf1.outputs.size(); for (unsigned int i = 0; i < count; ++i) { compatible &= (conf1.outputs[i].power_mode == conf2.outputs[i].power_mode); if (compatible) { auto clone = conf2.outputs[i]; // ignore difference in orientation, scale factor, form factor, subpixel arrangement clone.orientation = conf1.outputs[i].orientation; clone.subpixel_arrangement = conf1.outputs[i].subpixel_arrangement; clone.scale = conf1.outputs[i].scale; clone.form_factor = conf1.outputs[i].form_factor; compatible &= (conf1.outputs[i] == clone); } else break; } } return compatible; } ./src/platforms/mesa/server/kms/platform.cpp0000644000004100000410000000567413115234664021437 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "platform.h" #include "guest_platform.h" #include "buffer_allocator.h" #include "display.h" #include "linux_virtual_terminal.h" #include "ipc_operations.h" #include "mir/graphics/platform_ipc_operations.h" #include "mir/graphics/native_buffer.h" #include "mir/emergency_cleanup_registry.h" #include "mir/udev/wrapper.h" #include #include namespace mg = mir::graphics; namespace mgm = mg::mesa; namespace mgmh = mgm::helpers; mgm::Platform::Platform(std::shared_ptr const& listener, std::shared_ptr const& vt, EmergencyCleanupRegistry& emergency_cleanup_registry, BypassOption bypass_option) : udev{std::make_shared()}, drm{std::make_shared(mgmh::DRMNodeToUse::card)}, gbm{std::make_shared()}, listener{listener}, vt{vt}, bypass_option_{bypass_option} { drm->setup(udev); gbm->setup(*drm); std::weak_ptr weak_vt = vt; std::weak_ptr weak_drm = drm; emergency_cleanup_registry.add( make_module_ptr( [weak_vt,weak_drm] { if (auto const vt = weak_vt.lock()) try { vt->restore(); } catch (...) {} if (auto const drm = weak_drm.lock()) try { drm->drop_master(); } catch (...) {} })); } mir::UniqueModulePtr mgm::Platform::create_buffer_allocator() { return make_module_ptr(gbm->device, bypass_option_, mgm::BufferImportMethod::gbm_native_pixmap); } mir::UniqueModulePtr mgm::Platform::create_display( std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config) { return make_module_ptr(drm, gbm, vt, bypass_option_, initial_conf_policy, gl_config, listener); } mir::UniqueModulePtr mgm::Platform::make_ipc_operations() const { return make_module_ptr(drm); } mgm::BypassOption mgm::Platform::bypass_option() const { return bypass_option_; } ./src/platforms/mesa/server/kms/real_kms_output_container.h0000644000004100000410000000273513115234416024525 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_REAL_KMS_OUTPUT_CONTAINER_H_ #define MIR_GRAPHICS_MESA_REAL_KMS_OUTPUT_CONTAINER_H_ #include "kms_output_container.h" #include namespace mir { namespace graphics { namespace mesa { class PageFlipper; class RealKMSOutputContainer : public KMSOutputContainer { public: RealKMSOutputContainer(int drm_fd, std::shared_ptr const& page_flipper); std::shared_ptr get_kms_output_for(uint32_t connector_id); void for_each_output(std::function functor) const; private: int const drm_fd; std::unordered_map> outputs; std::shared_ptr const page_flipper; }; } } } #endif /* MIR_GRAPHICS_MESA_REAL_KMS_OUTPUT_CONTAINER_H_ */ ./src/platforms/mesa/server/kms/real_kms_display_configuration.h0000644000004100000410000000503713115234664025522 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_REAL_KMS_DISPLAY_CONFIGURATION_H_ #define MIR_GRAPHICS_MESA_REAL_KMS_DISPLAY_CONFIGURATION_H_ #include "kms_display_configuration.h" #include "kms-utils/drm_mode_resources.h" #include namespace mir { namespace graphics { namespace mesa { class RealKMSDisplayConfiguration : public KMSDisplayConfiguration { friend bool compatible(RealKMSDisplayConfiguration const& conf1, RealKMSDisplayConfiguration const& conf2); public: RealKMSDisplayConfiguration(int drm_fd); RealKMSDisplayConfiguration(RealKMSDisplayConfiguration const& conf); RealKMSDisplayConfiguration& operator=(RealKMSDisplayConfiguration const& conf); void for_each_card(std::function f) const override; void for_each_output(std::function f) const override; void for_each_output(std::function f) override; std::unique_ptr clone() const override; uint32_t get_kms_connector_id(DisplayConfigurationOutputId id) const override; size_t get_kms_mode_index(DisplayConfigurationOutputId id, size_t conf_mode_index) const override; void update() override; private: void add_or_update_output(kms::DRMModeResources const& resources, drmModeConnector const& connector); std::vector::iterator find_output_with_id(DisplayConfigurationOutputId id); std::vector::const_iterator find_output_with_id(DisplayConfigurationOutputId id) const; int drm_fd; DisplayConfigurationCard card; std::vector outputs; }; bool compatible(RealKMSDisplayConfiguration const& conf1, RealKMSDisplayConfiguration const& conf2); } } } #endif /* MIR_GRAPHICS_MESA_REAL_KMS_DISPLAY_CONFIGURATION_H_ */ ./src/platforms/mesa/server/kms/display.cpp0000644000004100000410000003446013115234664021253 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "display.h" #include "cursor.h" #include "platform.h" #include "display_buffer.h" #include "kms_display_configuration.h" #include "kms_output.h" #include "kms_page_flipper.h" #include "virtual_terminal.h" #include "mir/graphics/overlapping_output_grouping.h" #include "mir/graphics/event_handler_register.h" #include "mir/graphics/virtual_output.h" #include "mir/graphics/display_report.h" #include "mir/graphics/display_configuration_policy.h" #include "mir/geometry/rectangle.h" #include "mir/renderer/gl/context.h" #include #include #include #include #include namespace mgm = mir::graphics::mesa; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace { int errno_from_exception(std::exception const& e) { auto errno_ptr = boost::get_error_info(e); return (errno_ptr != nullptr) ? *errno_ptr : -1; } class GBMGLContext : public mir::renderer::gl::Context { public: GBMGLContext(mgm::helpers::GBMHelper const& gbm, mg::GLConfig const& gl_config, EGLContext shared_context) : egl{gl_config} { egl.setup(gbm, shared_context); } void make_current() const override { egl.make_current(); } void release_current() const override { egl.release_current(); } private: mgm::helpers::EGLHelper egl; }; } mgm::Display::Display(std::shared_ptr const& drm, std::shared_ptr const& gbm, std::shared_ptr const& vt, mgm::BypassOption bypass_option, std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config, std::shared_ptr const& listener) : drm(drm), gbm(gbm), vt(vt), listener(listener), monitor(mir::udev::Context()), shared_egl{*gl_config}, output_container{drm->fd, std::make_shared(drm->fd, listener)}, current_display_configuration{drm->fd}, dirty_configuration{false}, bypass_option(bypass_option), gl_config{gl_config} { vt->set_graphics_mode(); shared_egl.setup(*gbm); monitor.filter_by_subsystem_and_type("drm", "drm_minor"); monitor.enable(); initial_conf_policy->apply_to(current_display_configuration); configure(current_display_configuration); shared_egl.make_current(); } // please don't remove this empty destructor, it's here for the // unique ptr!! if you accidentally remove it you will get a not // so relevant linker error about some missing headers mgm::Display::~Display() { } void mgm::Display::for_each_display_sync_group( std::function const& f) { std::lock_guard lg{configuration_mutex}; for (auto& db_ptr : display_buffers) f(*db_ptr); } std::unique_ptr mgm::Display::configuration() const { std::lock_guard lg{configuration_mutex}; if (dirty_configuration) { /* Give back a copy of the latest configuration information */ current_display_configuration.update(); dirty_configuration = false; } return std::unique_ptr( new mgm::RealKMSDisplayConfiguration(current_display_configuration) ); } void mgm::Display::configure(mg::DisplayConfiguration const& conf) { if (!conf.valid()) { BOOST_THROW_EXCEPTION( std::logic_error("Invalid or inconsistent display configuration")); } { std::lock_guard lock{configuration_mutex}; configure_locked(dynamic_cast(conf), lock); } if (auto c = cursor.lock()) c->resume(); } void mgm::Display::register_configuration_change_handler( EventHandlerRegister& handlers, DisplayConfigurationChangeHandler const& conf_change_handler) { handlers.register_fd_handler( {monitor.fd()}, this, make_module_ptr>( [conf_change_handler, this](int) { monitor.process_events([conf_change_handler, this] (mir::udev::Monitor::EventType, mir::udev::Device const&) { dirty_configuration = true; conf_change_handler(); }); })); } void mgm::Display::register_pause_resume_handlers( EventHandlerRegister& handlers, DisplayPauseHandler const& pause_handler, DisplayResumeHandler const& resume_handler) { vt->register_switch_handlers(handlers, pause_handler, resume_handler); } void mgm::Display::pause() { try { if (auto c = cursor.lock()) c->suspend(); drm->drop_master(); } catch(std::runtime_error const& e) { listener->report_drm_master_failure(errno_from_exception(e)); throw; } } void mgm::Display::resume() { try { drm->set_master(); } catch(std::runtime_error const& e) { listener->report_drm_master_failure(errno_from_exception(e)); throw; } { std::lock_guard lg{configuration_mutex}; /* * After resuming (e.g. because we switched back to the display server VT) * we need to reset the CRTCs. For active displays we schedule a CRTC reset * on the next swap. For connected but unused outputs we clear the CRTC. */ for (auto& db_ptr : display_buffers) db_ptr->schedule_set_crtc(); clear_connected_unused_outputs(); } if (auto c = cursor.lock()) c->resume(); } auto mgm::Display::create_hardware_cursor(std::shared_ptr const& initial_image) -> std::shared_ptr { // There is only one hardware cursor. We do not keep a strong reference to it in the display though, // if no other component of Mir is interested (i.e. the input stack does not keep a reference to send // position updates) we must be configured not to use a cursor and thusly let it deallocate. std::shared_ptr locked_cursor = cursor.lock(); if (!locked_cursor) { class KMSCurrentConfiguration : public CurrentConfiguration { public: KMSCurrentConfiguration(Display& display) : display(display) { } void with_current_configuration_do( std::function const& exec) { std::lock_guard lg{display.configuration_mutex}; exec(display.current_display_configuration); } private: Display& display; }; try { locked_cursor = std::make_shared(gbm->device, output_container, std::make_shared(*this), initial_image); } catch (std::runtime_error const&) { // That's OK, we don't need a hardware cursor. Returning null // is allowed and will trigger a fallback to software. } cursor = locked_cursor; } return locked_cursor; } void mgm::Display::clear_connected_unused_outputs() { current_display_configuration.for_each_output([&](DisplayConfigurationOutput const& conf_output) { /* * An output may be unused either because it's explicitly not used * (DisplayConfigurationOutput::used) or because its power mode is * not mir_power_mode_on. */ if (conf_output.connected && (!conf_output.used || (conf_output.power_mode != mir_power_mode_on))) { uint32_t const connector_id = current_display_configuration.get_kms_connector_id(conf_output.id); auto kms_output = output_container.get_kms_output_for(connector_id); kms_output->clear_crtc(); kms_output->set_power_mode(conf_output.power_mode); kms_output->set_gamma(conf_output.gamma); } }); } std::unique_ptr mgm::Display::create_virtual_output(int /*width*/, int /*height*/) { return nullptr; } mg::NativeDisplay* mgm::Display::native_display() { return this; } std::unique_ptr mgm::Display::create_gl_context() { return std::make_unique(*gbm, *gl_config, shared_egl.context()); } bool mgm::Display::apply_if_configuration_preserves_display_buffers( mg::DisplayConfiguration const& conf) { auto const& new_kms_conf = dynamic_cast(conf); std::lock_guard lock{configuration_mutex}; if (compatible(current_display_configuration, new_kms_conf)) { configure_locked(new_kms_conf, lock); return true; } return false; } mg::Frame mgm::Display::last_frame_on(unsigned output_id) const { auto output = output_container.get_kms_output_for(output_id); return output->last_frame(); } void mgm::Display::configure_locked( mgm::RealKMSDisplayConfiguration const& kms_conf, std::lock_guard const&) { // Treat the current_display_configuration as incompatible with itself, // before it's fully constructed, to force proper initialization. bool const comp{ (&kms_conf != ¤t_display_configuration) && compatible(kms_conf, current_display_configuration)}; std::vector> display_buffers_new; if (!comp) { /* * Notice for a little while here we will have duplicate * DisplayBuffers attached to each output, and the display_buffers_new * will take over the outputs before the old display_buffers are * destroyed. So to avoid page flipping confusion in-between, make * sure we wait for all pending page flips to finish before the * display_buffers_new are created and take control of the outputs. */ for (auto& db : display_buffers) db->wait_for_page_flip(); /* Reset the state of all outputs */ kms_conf.for_each_output( [&](DisplayConfigurationOutput const& conf_output) { uint32_t const connector_id = current_display_configuration.get_kms_connector_id(conf_output.id); auto kms_output = output_container.get_kms_output_for(connector_id); kms_output->clear_cursor(); kms_output->reset(); }); } /* Set up used outputs */ OverlappingOutputGrouping grouping{kms_conf}; auto group_idx = 0; grouping.for_each_group( [&](OverlappingOutputGroup const& group) { auto bounding_rect = group.bounding_rectangle(); std::vector> kms_outputs; MirOrientation orientation = mir_orientation_normal; group.for_each_output( [&](DisplayConfigurationOutput const& conf_output) { uint32_t const connector_id = kms_conf.get_kms_connector_id(conf_output.id); auto kms_output = output_container.get_kms_output_for(connector_id); auto const mode_index = kms_conf.get_kms_mode_index(conf_output.id, conf_output.current_mode_index); kms_output->configure(conf_output.top_left - bounding_rect.top_left, mode_index); if (!comp) { kms_output->set_power_mode(conf_output.power_mode); kms_output->set_gamma(conf_output.gamma); kms_outputs.push_back(kms_output); } /* * Presently OverlappingOutputGroup guarantees all grouped * outputs have the same orientation. */ orientation = conf_output.orientation; }); if (comp) { display_buffers[group_idx++]->set_orientation(orientation, bounding_rect); } else { uint32_t width = bounding_rect.size.width.as_uint32_t(); uint32_t height = bounding_rect.size.height.as_uint32_t(); if (orientation == mir_orientation_left || orientation == mir_orientation_right) { std::swap(width, height); } auto surface = gbm->create_scanout_surface(width, height); std::unique_ptr db{ new DisplayBuffer{bypass_option, drm, gbm, listener, kms_outputs, std::move(surface), bounding_rect, orientation, *gl_config, shared_egl.context()}}; display_buffers_new.push_back(std::move(db)); } }); if (!comp) display_buffers = std::move(display_buffers_new); /* Store applied configuration */ current_display_configuration = kms_conf; if (!comp) /* Clear connected but unused outputs */ clear_connected_unused_outputs(); } ./src/platforms/mesa/server/kms/display.h0000644000004100000410000001004613115234664020712 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_DISPLAY_H_ #define MIR_GRAPHICS_MESA_DISPLAY_H_ #include "mir/graphics/display.h" #include "mir/renderer/gl/context_source.h" #include "real_kms_output_container.h" #include "real_kms_display_configuration.h" #include "display_helpers.h" #include "platform_common.h" #include #include #include namespace mir { namespace geometry { struct Rectangle; } namespace graphics { class DisplayReport; class DisplayBuffer; class DisplayConfigurationPolicy; class EventHandlerRegister; class GLConfig; namespace mesa { namespace helpers { class DRMHelper; class GBMHelper; } class DisplayBuffer; class VirtualTerminal; class KMSOutput; class Cursor; class Display : public graphics::Display, public graphics::NativeDisplay, public renderer::gl::ContextSource { public: Display(std::shared_ptr const& drm, std::shared_ptr const& gbm, std::shared_ptr const& vt, BypassOption bypass_option, std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config, std::shared_ptr const& listener); ~Display(); geometry::Rectangle view_area() const; void for_each_display_sync_group( std::function const& f) override; std::unique_ptr configuration() const override; bool apply_if_configuration_preserves_display_buffers(DisplayConfiguration const& conf) override; void configure(DisplayConfiguration const& conf) override; void register_configuration_change_handler( EventHandlerRegister& handlers, DisplayConfigurationChangeHandler const& conf_change_handler) override; void register_pause_resume_handlers( EventHandlerRegister& handlers, DisplayPauseHandler const& pause_handler, DisplayResumeHandler const& resume_handler) override; void pause() override; void resume() override; std::shared_ptr create_hardware_cursor(std::shared_ptr const& initial_image) override; std::unique_ptr create_virtual_output(int width, int height) override; NativeDisplay* native_display() override; std::unique_ptr create_gl_context() override; Frame last_frame_on(unsigned output_id) const override; private: void clear_connected_unused_outputs(); mutable std::mutex configuration_mutex; std::shared_ptr const drm; std::shared_ptr const gbm; std::shared_ptr const vt; std::shared_ptr const listener; mir::udev::Monitor monitor; helpers::EGLHelper shared_egl; std::vector> display_buffers; mutable RealKMSOutputContainer output_container; mutable RealKMSDisplayConfiguration current_display_configuration; mutable std::atomic dirty_configuration; void configure_locked( RealKMSDisplayConfiguration const& conf, std::lock_guard const&); BypassOption bypass_option; std::weak_ptr cursor; std::shared_ptr const gl_config; }; } } } #endif /* MIR_GRAPHICS_MESA_DISPLAY_H_ */ ./src/platforms/mesa/server/kms/platform.h0000644000004100000410000000412713115234664021074 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_PLATFORM_H_ #define MIR_GRAPHICS_MESA_PLATFORM_H_ #include "mir/graphics/platform.h" #include "platform_common.h" #include "display_helpers.h" namespace mir { class EmergencyCleanupRegistry; namespace graphics { namespace mesa { class VirtualTerminal; class InternalNativeDisplay; class Platform : public graphics::Platform { public: explicit Platform(std::shared_ptr const& reporter, std::shared_ptr const& vt, EmergencyCleanupRegistry& emergency_cleanup_registry, BypassOption bypass_option); /* From Platform */ UniqueModulePtr create_buffer_allocator() override; UniqueModulePtr create_display( std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config) override; UniqueModulePtr make_ipc_operations() const override; std::shared_ptr udev; std::shared_ptr const drm; std::shared_ptr const gbm; std::shared_ptr const listener; std::shared_ptr const vt; BypassOption bypass_option() const; private: BypassOption const bypass_option_; }; } } } #endif /* MIR_GRAPHICS_MESA_PLATFORM_H_ */ ./src/platforms/mesa/server/kms/platform_symbols.cpp0000644000004100000410000001733213115234664023201 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #include "platform.h" #include "guest_platform.h" #include "linux_virtual_terminal.h" #include "mir/options/program_option.h" #include "mir/options/option.h" #include "mir/udev/wrapper.h" #include "mir/module_deleter.h" #include "mir/assert_module_entry_point.h" #include "mir/libname.h" #include #include #include namespace mg = mir::graphics; namespace mgm = mg::mesa; namespace mo = mir::options; namespace { char const* bypass_option_name{"bypass"}; char const* vt_option_name{"vt"}; char const* host_socket{"host-socket"}; struct RealVTFileOperations : public mgm::VTFileOperations { int open(char const* pathname, int flags) { return ::open(pathname, flags); } int close(int fd) { return ::close(fd); } int ioctl(int d, int request, int val) { return ::ioctl(d, request, val); } int ioctl(int d, int request, void* p_val) { return ::ioctl(d, request, p_val); } int tcsetattr(int d, int acts, const struct termios *tcattr) { return ::tcsetattr(d, acts, tcattr); } int tcgetattr(int d, struct termios *tcattr) { return ::tcgetattr(d, tcattr); } }; struct RealPosixProcessOperations : public mgm::PosixProcessOperations { pid_t getpid() const override { return ::getpid(); } pid_t getppid() const override { return ::getppid(); } pid_t getpgid(pid_t process) const override { return ::getpgid(process); } pid_t getsid(pid_t process) const override { return ::getsid(process); } int setpgid(pid_t process, pid_t group) override { return ::setpgid(process, group); } pid_t setsid() override { return ::setsid(); } }; } mir::UniqueModulePtr create_host_platform( std::shared_ptr const& options, std::shared_ptr const& emergency_cleanup_registry, std::shared_ptr const& report, std::shared_ptr const& /*logger*/) { mir::assert_entry_point_signature(&create_host_platform); // ensure mesa finds the mesa mir-platform symbols auto real_fops = std::make_shared(); auto real_pops = std::unique_ptr(new RealPosixProcessOperations{}); auto vt = std::make_shared( real_fops, std::move(real_pops), options->get(vt_option_name), report); auto bypass_option = mgm::BypassOption::allowed; if (!options->get(bypass_option_name)) bypass_option = mgm::BypassOption::prohibited; return mir::make_module_ptr( report, vt, *emergency_cleanup_registry, bypass_option); } void add_graphics_platform_options(boost::program_options::options_description& config) { mir::assert_entry_point_signature(&add_graphics_platform_options); config.add_options() (vt_option_name, boost::program_options::value()->default_value(0), "[platform-specific] VT to run on or 0 to use current.") (bypass_option_name, boost::program_options::value()->default_value(true), "[platform-specific] utilize the bypass optimization for fullscreen surfaces."); } mg::PlatformPriority probe_graphics_platform(mo::ProgramOption const& options) { mir::assert_entry_point_signature(&probe_graphics_platform); auto const unparsed_arguments = options.unparsed_command_line(); auto platform_option_used = false; for (auto const& token : unparsed_arguments) { if (token == (std::string("--") + vt_option_name)) platform_option_used = true; } if (options.is_set(vt_option_name)) platform_option_used = true; auto nested = options.is_set(host_socket); auto udev = std::make_shared(); mir::udev::Enumerator drm_devices{udev}; drm_devices.match_subsystem("drm"); drm_devices.match_sysname("card[0-9]*"); drm_devices.scan_devices(); if (drm_devices.begin() == drm_devices.end()) return mg::PlatformPriority::unsupported; // We also require GBM EGL platform auto const* client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); if (!client_extensions) { // Doesn't support EGL client extensions; Mesa does, so this is unlikely to be mesa. return mg::PlatformPriority::unsupported; } if (strstr(client_extensions, "EGL_MESA_platform_gbm") == nullptr) { // No platform_gbm support, so we can't work. return mg::PlatformPriority::unsupported; } // Check for master int tmp_fd = -1; for (auto& device : drm_devices) { tmp_fd = open(device.devnode(), O_RDWR | O_CLOEXEC); if (tmp_fd >= 0) break; } if (nested && platform_option_used) return mg::PlatformPriority::best; if (nested) return mg::PlatformPriority::supported; if (tmp_fd >= 0) { if (drmSetMaster(tmp_fd) >= 0) { drmDropMaster(tmp_fd); drmClose(tmp_fd); return mg::PlatformPriority::best; } else drmClose(tmp_fd); } if (platform_option_used) return mg::PlatformPriority::best; /* We failed to set mastership. However, still on most systems mesa-kms * is the right driver to choose. Landing here just means the user did * not specify --vt or is running from ssh. Still in most cases mesa-kms * is the correct option so give it a go. Better to fail trying to switch * VTs (and tell the user that) than to refuse to load the correct * driver at all. (LP: #1528082) * * Just make sure we are below PlatformPriority::supported in case * mesa-x11 or android can be used instead. * * TODO: Revisit the priority terminology. having a range of values between * "supported" and "unsupported" is potentially confusing. * TODO: Revisit the return code of this function. We document that * integer values outside the enum are allowed but C++ disallows it * without a cast. So we should return an int or typedef to int * instead. */ return static_cast( mg::PlatformPriority::supported - 1); } namespace { mir::ModuleProperties const description = { "mir:mesa-kms", MIR_VERSION_MAJOR, MIR_VERSION_MINOR, MIR_VERSION_MICRO, mir::libname() }; } mir::ModuleProperties const* describe_graphics_module() { mir::assert_entry_point_signature(&describe_graphics_module); return &description; } mir::UniqueModulePtr create_guest_platform( std::shared_ptr const&, std::shared_ptr const& nested_context) { mir::assert_entry_point_signature(&create_guest_platform); return mir::make_module_ptr(nested_context); } ./src/platforms/mesa/server/kms/guest_platform.h0000644000004100000410000000322713115234664022303 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Eleni Maria Stea * Alan Griffiths */ #ifndef MIR_GRAPHICS_MESA_GUEST_PLATFORM_H_ #define MIR_GRAPHICS_MESA_GUEST_PLATFORM_H_ #include "mir/graphics/platform.h" #include "mir/graphics/platform_ipc_package.h" #include "display_helpers.h" namespace mir { namespace graphics { namespace mesa { class InternalNativeDisplay; class GuestPlatform : public graphics::Platform { public: GuestPlatform(std::shared_ptr const& nested_context_arg); UniqueModulePtr create_buffer_allocator() override; UniqueModulePtr make_ipc_operations() const override; UniqueModulePtr create_display( std::shared_ptr const&, std::shared_ptr const& /*gl_config*/) override; private: std::shared_ptr const nested_context; helpers::GBMHelper gbm; }; } } } #endif // MIR_GRAPHICS_MESA_GUEST_PLATFORM_H_ ./src/platforms/mesa/server/kms/bypass.cpp0000644000004100000410000000320013115234664021073 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #include "mir/graphics/renderable.h" #include "mir/graphics/display_buffer.h" #include "bypass.h" using namespace mir; namespace mgm = mir::graphics::mesa; mgm::BypassMatch::BypassMatch(geometry::Rectangle const& rect) : view_area(rect), bypass_is_feasible(true) { } bool mgm::BypassMatch::operator()(std::shared_ptr const& renderable) { //we've already eliminated bypass as a possibility if (!bypass_is_feasible) return false; //offscreen surfaces don't affect if bypass is possible if (!view_area.overlaps(renderable->screen_position())) return false; auto const is_opaque = !((renderable->alpha() != 1.0f) || renderable->shaped()); auto const fits = (renderable->screen_position() == view_area); auto const is_orthogonal = (renderable->transformation() == identity); bypass_is_feasible = (is_opaque && fits && is_orthogonal); return bypass_is_feasible; } ./src/platforms/mesa/server/kms/bypass.h0000644000004100000410000000233313115234416020541 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_GRAPHICS_MESA_BYPASS_H_ #define MIR_GRAPHICS_MESA_BYPASS_H_ #include "mir/graphics/renderable.h" namespace mir { namespace graphics { namespace mesa { class BypassMatch { public: BypassMatch(geometry::Rectangle const& rect); bool operator()(std::shared_ptr const&); private: geometry::Rectangle const view_area; bool bypass_is_feasible; glm::mat4 const identity; }; } // namespace mesa } // namespace graphics } // namespace mir #endif // MIR_GRAPHICS_MESA_BYPASS_H_ ./src/platforms/mesa/server/kms/display_buffer.cpp0000644000004100000410000003311413115234664022577 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "display_buffer.h" #include "kms_output.h" #include "mir/graphics/display_report.h" #include "bypass.h" #include "gbm_buffer.h" #include "mir/fatal.h" #include "mir/log.h" #include "native_buffer.h" #include #include MIR_SERVER_GL_H #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace geom = mir::geometry; class mgm::BufferObject { public: BufferObject(gbm_surface* surface, gbm_bo* bo, uint32_t drm_fb_id) : surface{surface}, bo{bo}, drm_fb_id{drm_fb_id} { } ~BufferObject() { if (drm_fb_id) { int drm_fd = gbm_device_get_fd(gbm_bo_get_device(bo)); drmModeRmFB(drm_fd, drm_fb_id); } } void release() const { gbm_surface_release_buffer(surface, bo); } uint32_t get_drm_fb_id() const { return drm_fb_id; } private: gbm_surface *surface; gbm_bo *bo; uint32_t drm_fb_id; }; namespace { void bo_user_data_destroy(gbm_bo* /*bo*/, void *data) { auto bufobj = static_cast(data); delete bufobj; } void ensure_egl_image_extensions() { std::string ext_string; const char* exts = reinterpret_cast(glGetString(GL_EXTENSIONS)); if (exts) ext_string = exts; if (ext_string.find("GL_OES_EGL_image") == std::string::npos) BOOST_THROW_EXCEPTION(std::runtime_error("GLES2 implementation doesn't support GL_OES_EGL_image extension")); } } mgm::DisplayBuffer::DisplayBuffer( mgm::BypassOption option, std::shared_ptr const& drm, std::shared_ptr const& gbm, std::shared_ptr const& listener, std::vector> const& outputs, GBMSurfaceUPtr surface_gbm_param, geom::Rectangle const& area, MirOrientation rot, GLConfig const& gl_config, EGLContext shared_context) : visible_composite_frame{nullptr}, scheduled_composite_frame{nullptr}, listener(listener), bypass_option(option), drm(drm), gbm(gbm), outputs(outputs), surface_gbm{std::move(surface_gbm_param)}, egl{gl_config}, area(area), rotation(rot), needs_set_crtc{false}, page_flips_pending{false} { uint32_t area_width = area.size.width.as_uint32_t(); uint32_t area_height = area.size.height.as_uint32_t(); if (rotation == mir_orientation_left || rotation == mir_orientation_right) { fb_width = area_height; fb_height = area_width; } else { fb_width = area_width; fb_height = area_height; } egl.setup(*gbm, surface_gbm.get(), shared_context); listener->report_successful_setup_of_native_resources(); make_current(); listener->report_successful_egl_make_current_on_construction(); ensure_egl_image_extensions(); glClear(GL_COLOR_BUFFER_BIT); if (!egl.swap_buffers()) fatal_error("Failed to perform initial surface buffer swap"); listener->report_successful_egl_buffer_swap_on_construction(); scheduled_composite_frame = get_front_buffer_object(); if (!scheduled_composite_frame) fatal_error("Failed to get frontbuffer"); set_crtc(scheduled_composite_frame); release_current(); listener->report_successful_drm_mode_set_crtc_on_construction(); listener->report_successful_display_construction(); egl.report_egl_configuration( [&listener] (EGLDisplay disp, EGLConfig cfg) { listener->report_egl_configuration(disp, cfg); }); } mgm::DisplayBuffer::~DisplayBuffer() { /* * There is no need to destroy visible_composite_frame manually. * It will be destroyed when its gbm_surface gets destroyed. */ if (visible_composite_frame) visible_composite_frame->release(); if (scheduled_composite_frame) scheduled_composite_frame->release(); } geom::Rectangle mgm::DisplayBuffer::view_area() const { return area; } MirOrientation mgm::DisplayBuffer::orientation() const { // Tell the renderer to do the rotation, since we're not doing it here. return rotation; } MirMirrorMode mgm::DisplayBuffer::mirror_mode() const { return mir_mirror_mode_none; } void mgm::DisplayBuffer::set_orientation(MirOrientation const rot, geometry::Rectangle const& a) { rotation = rot; area = a; } bool mgm::DisplayBuffer::overlay(RenderableList const& renderable_list) { if ((rotation == mir_orientation_normal) && (bypass_option == mgm::BypassOption::allowed)) { mgm::BypassMatch bypass_match(area); auto bypass_it = std::find_if(renderable_list.rbegin(), renderable_list.rend(), bypass_match); if (bypass_it != renderable_list.rend()) { auto bypass_buffer = (*bypass_it)->buffer(); auto native = std::dynamic_pointer_cast(bypass_buffer->native_buffer_handle()); if (!native) BOOST_THROW_EXCEPTION(std::invalid_argument("could not convert NativeBuffer")); if (native->flags & mir_buffer_flag_can_scanout && bypass_buffer->size() == geom::Size{fb_width,fb_height}) { if (auto bufobj = get_buffer_object(native->bo)) { bypass_buf = bypass_buffer; bypass_bufobj = bufobj; return true; } } } } bypass_buf = nullptr; bypass_bufobj = nullptr; return false; } void mgm::DisplayBuffer::for_each_display_buffer( std::function const& f) { f(*this); } void mgm::DisplayBuffer::swap_buffers() { if (!egl.swap_buffers()) fatal_error("Failed to perform buffer swap"); bypass_buf = nullptr; bypass_bufobj = nullptr; } void mgm::DisplayBuffer::set_crtc(BufferObject const* forced_frame) { for (auto& output : outputs) { /* * Note that failure to set the CRTC is not a fatal error. This can * happen under normal conditions when resizing VirtualBox (which * actually removes and replaces the virtual output each time so * sometimes it's really not there). Xorg often reports similar * errors, and it's not fatal. */ if (!output->set_crtc(forced_frame->get_drm_fb_id())) mir::log_error("Failed to set DRM CRTC. " "Screen contents may be incomplete. " "Try plugging the monitor in again."); } } void mgm::DisplayBuffer::post() { /* * We might not have waited for the previous frame to page flip yet. * This is good because it maximizes the time available to spend rendering * each frame. Just remember wait_for_page_flip() must be called at some * point before the next schedule_page_flip(). */ wait_for_page_flip(); mgm::BufferObject *bufobj; if (bypass_buf) { bufobj = bypass_bufobj; } else { bufobj = get_front_buffer_object(); if (!bufobj) fatal_error("Failed to get front buffer object"); } /* * Try to schedule a page flip as first preference to avoid tearing. * [will complete in a background thread] */ if (!needs_set_crtc && !schedule_page_flip(bufobj)) needs_set_crtc = true; /* * Fallback blitting: Not pretty, since it may tear. VirtualBox seems * to need to do this on every frame. [will complete in this thread] */ if (needs_set_crtc) { set_crtc(bufobj); needs_set_crtc = false; } using namespace std; // For operator""ms() // Predicted worst case render time for the next frame... auto predicted_render_time = 50ms; if (bypass_buf) { /* * For composited frames we defer wait_for_page_flip till just before * the next frame, but not for bypass frames. Deferring the flip of * bypass frames would increase the time we held * visible_bypass_frame unacceptably, resulting in client stuttering * unless we allocate more buffers (which I'm trying to avoid). * Also, bypass does not need the deferred page flip because it has * no compositing/rendering step for which to save time for. */ scheduled_bypass_frame = bypass_buf; wait_for_page_flip(); // It's very likely the next frame will be bypassed like this one so // we only need time for kernel page flip scheduling... predicted_render_time = 5ms; } else { /* * Not in clone mode? We can afford to wait for the page flip then, * making us double-buffered (noticeably less laggy than the triple * buffering that clone mode requires). */ scheduled_composite_frame = bufobj; if (outputs.size() == 1) wait_for_page_flip(); /* * TODO: If you're optimistic about your GPU performance and/or * measure it carefully you may wish to set predicted_render_time * to a lower value here for lower latency. * *predicted_render_time = 9ms; // e.g. about the same as Weston */ } // Buffer lifetimes are managed exclusively by scheduled*/visible* now bypass_buf = nullptr; bypass_bufobj = nullptr; recommend_sleep = 0ms; if (outputs.size() == 1) { auto const& output = outputs.front(); auto const min_frame_interval = 1000ms / output->max_refresh_rate(); if (predicted_render_time < min_frame_interval) recommend_sleep = min_frame_interval - predicted_render_time; } } std::chrono::milliseconds mgm::DisplayBuffer::recommended_sleep() const { return recommend_sleep; } mgm::BufferObject* mgm::DisplayBuffer::get_front_buffer_object() { auto front = gbm_surface_lock_front_buffer(surface_gbm.get()); auto ret = get_buffer_object(front); if (!ret) gbm_surface_release_buffer(surface_gbm.get(), front); return ret; } mgm::BufferObject* mgm::DisplayBuffer::get_buffer_object( struct gbm_bo *bo) { if (!bo) return nullptr; /* * Check if we have already set up this gbm_bo (the gbm implementation is * free to reuse gbm_bos). If so, return the associated BufferObject. */ auto bufobj = static_cast(gbm_bo_get_user_data(bo)); if (bufobj) return bufobj; uint32_t fb_id{0}; uint32_t handles[4] = {gbm_bo_get_handle(bo).u32, 0, 0, 0}; uint32_t strides[4] = {gbm_bo_get_stride(bo), 0, 0, 0}; uint32_t offsets[4] = {0, 0, 0, 0}; auto format = gbm_bo_get_format(bo); /* * Mir might use the old GBM_BO_ enum formats, but KMS and the rest of * the world need fourcc formats, so convert... */ if (format == GBM_BO_FORMAT_XRGB8888) format = GBM_FORMAT_XRGB8888; else if (format == GBM_BO_FORMAT_ARGB8888) format = GBM_FORMAT_ARGB8888; /* Create a KMS FB object with the gbm_bo attached to it. */ auto ret = drmModeAddFB2(drm->fd, fb_width, fb_height, format, handles, strides, offsets, &fb_id, 0); if (ret) return nullptr; /* Create a BufferObject and associate it with the gbm_bo */ bufobj = new BufferObject{surface_gbm.get(), bo, fb_id}; gbm_bo_set_user_data(bo, bufobj, bo_user_data_destroy); return bufobj; } bool mgm::DisplayBuffer::schedule_page_flip(BufferObject* bufobj) { /* * Schedule the current front buffer object for display. Note that * the page flip is asynchronous and synchronized with vertical refresh. */ for (auto& output : outputs) { if (output->schedule_page_flip(bufobj->get_drm_fb_id())) page_flips_pending = true; } return page_flips_pending; } void mgm::DisplayBuffer::wait_for_page_flip() { if (page_flips_pending) { for (auto& output : outputs) output->wait_for_page_flip(); page_flips_pending = false; } if (scheduled_bypass_frame || scheduled_composite_frame) { // Why are both of these grouped into a single statement? // Because in either case both types of frame need releasing each time. visible_bypass_frame = scheduled_bypass_frame; scheduled_bypass_frame = nullptr; if (visible_composite_frame) visible_composite_frame->release(); visible_composite_frame = scheduled_composite_frame; scheduled_composite_frame = nullptr; } } void mgm::DisplayBuffer::make_current() { if (!egl.make_current()) { fatal_error("Failed to make EGL surface current"); } } void mgm::DisplayBuffer::bind() { } void mgm::DisplayBuffer::release_current() { egl.release_current(); } void mgm::DisplayBuffer::schedule_set_crtc() { needs_set_crtc = true; } mg::NativeDisplayBuffer* mgm::DisplayBuffer::native_display_buffer() { return this; } ./src/platforms/mesa/server/kms/linux_virtual_terminal.cpp0000644000004100000410000002174413115234664024407 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "linux_virtual_terminal.h" #include "mir/graphics/display_report.h" #include "mir/graphics/event_handler_register.h" #include #include #include #include #include #include #include #include #include #include #include namespace mgm = mir::graphics::mesa; mgm::LinuxVirtualTerminal::LinuxVirtualTerminal(std::shared_ptr const& fops, std::unique_ptr pops, int vt_number, std::shared_ptr const& report) : fops{fops}, pops{std::move(pops)}, report{report}, vt_fd{fops, open_vt(vt_number)}, prev_kd_mode{0}, prev_vt_mode(), prev_tty_mode(), prev_tcattr(), active{true} { struct termios tcattr; if (fops->ioctl(vt_fd.fd(), KDGETMODE, &prev_kd_mode) < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to get current VT mode")) << boost::errinfo_errno(errno)); } if (fops->ioctl(vt_fd.fd(), VT_GETMODE, &prev_vt_mode) < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to get the current VT")) << boost::errinfo_errno(errno)); } if (fops->ioctl(vt_fd.fd(), KDGKBMODE, &prev_tty_mode) < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to get the current TTY mode")) << boost::errinfo_errno(errno)); } if (fops->ioctl(vt_fd.fd(), KDSKBMODE, K_OFF) < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to mute keyboard")) << boost::errinfo_errno(errno)); } fops->tcgetattr(vt_fd.fd(), &prev_tcattr); tcattr = prev_tcattr; tcattr.c_iflag = IGNPAR | IGNBRK; cfsetispeed(&tcattr, B9600); tcattr.c_oflag = 0; cfsetospeed(&tcattr, B9600); tcattr.c_cflag = CREAD | CS8; tcattr.c_lflag = 0; tcattr.c_cc[VTIME] = 0; tcattr.c_cc[VMIN] = 1; fops->tcsetattr(vt_fd.fd(), TCSANOW, &tcattr); } mgm::LinuxVirtualTerminal::~LinuxVirtualTerminal() noexcept(true) { restore(); } void mgm::LinuxVirtualTerminal::set_graphics_mode() { if (fops->ioctl(vt_fd.fd(), KDSETMODE, KD_GRAPHICS) < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to set VT to graphics mode")) << boost::errinfo_errno(errno)); } } void mgm::LinuxVirtualTerminal::register_switch_handlers( EventHandlerRegister& handlers, std::function const& switch_away, std::function const& switch_back) { handlers.register_signal_handler( {SIGUSR1}, make_module_ptr>( [this, switch_away, switch_back](int) { if (!active) { if (!switch_back()) report->report_vt_switch_back_failure(); fops->ioctl(vt_fd.fd(), VT_RELDISP, VT_ACKACQ); active = true; } else { static int const disallow_switch{0}; static int const allow_switch{1}; int action; if (switch_away()) { action = allow_switch; active = false; } else { action = disallow_switch; report->report_vt_switch_away_failure(); } fops->ioctl(vt_fd.fd(), VT_RELDISP, action); } })); struct vt_mode vtm { VT_PROCESS, 0, SIGUSR1, SIGUSR1, 0 }; if (fops->ioctl(vt_fd.fd(), VT_SETMODE, &vtm) < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to set the current VT mode")) << boost::errinfo_errno(errno)); } } void mgm::LinuxVirtualTerminal::restore() { if (vt_fd.fd() >= 0) { fops->tcsetattr(vt_fd.fd(), TCSANOW, &prev_tcattr); fops->ioctl(vt_fd.fd(), KDSKBMODE, prev_tty_mode); fops->ioctl(vt_fd.fd(), KDSETMODE, prev_kd_mode); /* * Only restore the previous mode if it was VT_AUTO. VT_PROCESS mode is * always bound to the calling process, so "restoring" VT_PROCESS will * not work; it will just bind the notification signals to our process * again. Not "restoring" VT_PROCESS also ensures we don't mess up the * VT state of the previous controlling process, in case it had set * VT_PROCESS and we fail during setup. */ if (prev_vt_mode.mode == VT_AUTO) fops->ioctl(vt_fd.fd(), VT_SETMODE, &prev_vt_mode); } } int mgm::LinuxVirtualTerminal::find_active_vt_number() { static std::vector const paths{"/dev/tty", "/dev/tty0"}; int active_vt{-1}; for (auto& p : paths) { auto fd = fops->open(p.c_str(), O_RDONLY); if (fd < 0) fd = fops->open(p.c_str(), O_WRONLY); if (fd >= 0) { struct vt_stat vts; auto status = fops->ioctl(fd, VT_GETSTATE, &vts); fops->close(fd); if (status >= 0) { active_vt = vts.v_active; break; } } } if (active_vt < 0) { BOOST_THROW_EXCEPTION( std::runtime_error("Failed to find the current VT")); } return active_vt; } int mgm::LinuxVirtualTerminal::open_vt(int vt_number) { auto activate = true; if (vt_number <= 0) { vt_number = find_active_vt_number(); activate = false; } std::stringstream vt_path_stream; vt_path_stream << "/dev/tty" << vt_number; std::string const active_vt_path{vt_path_stream.str()}; if (activate) { // we should only try to create a new session in order to become the session // and group leader if we are not already the session leader if (pops->getpid() != pops->getsid(0)) { if (pops->getpid() == pops->getpgid(0) && pops->setpgid(0, pops->getpgid(pops->getppid())) < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to stop being a process group")) << boost::errinfo_errno(errno)); } /* become process group leader */ if (pops->setsid() < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to become session leader")) << boost::errinfo_errno(errno)); } } } auto vt_fd = fops->open(active_vt_path.c_str(), O_RDONLY | O_NDELAY); if (vt_fd < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to open current VT")) << boost::errinfo_file_name(active_vt_path) << boost::errinfo_errno(errno)); } if (activate) { auto status = fops->ioctl(vt_fd, VT_ACTIVATE, vt_number); if (status < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to activate VT")) << boost::errinfo_file_name(active_vt_path) << boost::errinfo_errno(errno)); } status = fops->ioctl(vt_fd, VT_WAITACTIVE, vt_number); if (status < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to wait for VT to become active")) << boost::errinfo_file_name(active_vt_path) << boost::errinfo_errno(errno)); } } return vt_fd; } ./src/platforms/mesa/server/kms/real_kms_output.h0000644000004100000410000000467113115234664022471 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_REAL_KMS_OUTPUT_H_ #define MIR_GRAPHICS_MESA_REAL_KMS_OUTPUT_H_ #include "mir/graphics/atomic_frame.h" #include "kms_output.h" #include "kms-utils/drm_mode_resources.h" #include #include namespace mir { namespace graphics { namespace mesa { class PageFlipper; class RealKMSOutput : public KMSOutput { public: RealKMSOutput(int drm_fd, uint32_t connector_id, std::shared_ptr const& page_flipper); ~RealKMSOutput(); void reset() override; void configure(geometry::Displacement fb_offset, size_t kms_mode_index) override; geometry::Size size() const override; int max_refresh_rate() const override; bool set_crtc(uint32_t fb_id) override; void clear_crtc() override; bool schedule_page_flip(uint32_t fb_id) override; void wait_for_page_flip() override; void set_cursor(gbm_bo* buffer) override; void move_cursor(geometry::Point destination) override; void clear_cursor() override; bool has_cursor() const override; void set_power_mode(MirPowerMode mode) override; void set_gamma(GammaCurves const& gamma) override; Frame last_frame() const override; private: bool ensure_crtc(); void restore_saved_crtc(); int const drm_fd; uint32_t const connector_id; std::shared_ptr const page_flipper; kms::DRMModeConnectorUPtr connector; size_t mode_index; geometry::Displacement fb_offset; kms::DRMModeCrtcUPtr current_crtc; drmModeCrtc saved_crtc; bool using_saved_crtc; bool has_cursor_; MirPowerMode power_mode; int dpms_enum_id; std::mutex power_mutex; AtomicFrame last_frame_; }; } } } #endif /* MIR_GRAPHICS_MESA_REAL_KMS_OUTPUT_H_ */ ./src/platforms/mesa/server/kms/page_flipper.h0000644000004100000410000000245613115234664021710 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_PAGE_FLIPPER_H_ #define MIR_GRAPHICS_MESA_PAGE_FLIPPER_H_ #include "mir/graphics/frame.h" #include namespace mir { namespace graphics { namespace mesa { class PageFlipper { public: virtual ~PageFlipper() {} virtual bool schedule_flip(uint32_t crtc_id, uint32_t fb_id, uint32_t connector_id) = 0; virtual Frame wait_for_flip(uint32_t crtc_id) = 0; protected: PageFlipper() = default; PageFlipper(PageFlipper const&) = delete; PageFlipper& operator=(PageFlipper const&) = delete; }; } } } #endif /* MIR_GRAPHICS_MESA_PAGE_FLIPPER_H_ */ ./src/platforms/mesa/server/kms/symbols.map.in0000644000004100000410000000033113115234664021664 0ustar www-datawww-data@MIR_SERVER_GRAPHICS_PLATFORM_VERSION@ { global: add_graphics_platform_options; create_host_platform; create_guest_platform; probe_graphics_platform; describe_graphics_module; local: *; }; ./src/platforms/mesa/server/kms/kms_output_container.h0000644000004100000410000000263213115234416023516 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_KMS_OUTPUT_CONTAINER_H_ #define MIR_GRAPHICS_MESA_KMS_OUTPUT_CONTAINER_H_ #include #include namespace mir { namespace graphics { namespace mesa { class KMSOutput; class KMSOutputContainer { public: virtual ~KMSOutputContainer() = default; virtual std::shared_ptr get_kms_output_for(uint32_t connector_id) = 0; virtual void for_each_output(std::function functor) const = 0; protected: KMSOutputContainer() = default; KMSOutputContainer(KMSOutputContainer const&) = delete; KMSOutputContainer& operator=(KMSOutputContainer const&) = delete; }; } } } #endif /* MIR_GRAPHICS_MESA_KMS_OUTPUT_CONTAINER_H_ */ ./src/platforms/mesa/server/buffer_allocator.h0000644000004100000410000000425513115234664021771 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_GRAPHICS_MESA_BUFFER_ALLOCATOR_H_ #define MIR_GRAPHICS_MESA_BUFFER_ALLOCATOR_H_ #include "platform_common.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "mir/graphics/buffer_id.h" #include "mir_toolkit/mir_native_buffer.h" #pragma GCC diagnostic push #pragma GCC diagnostic warning "-Wall" #include #pragma GCC diagnostic pop #include namespace mir { namespace graphics { struct EGLExtensions; namespace mesa { enum class BufferImportMethod { gbm_native_pixmap, dma_buf }; class BufferAllocator: public graphics::GraphicBufferAllocator { public: BufferAllocator(gbm_device* device, BypassOption bypass_option, BufferImportMethod const buffer_import_method); std::shared_ptr alloc_buffer( geometry::Size size, uint32_t native_format, uint32_t native_flags) override; std::shared_ptr alloc_software_buffer(geometry::Size size, MirPixelFormat) override; std::shared_ptr alloc_buffer(graphics::BufferProperties const& buffer_properties) override; std::vector supported_pixel_formats() override; private: std::shared_ptr alloc_hardware_buffer( graphics::BufferProperties const& buffer_properties); gbm_device* const device; std::shared_ptr const egl_extensions; BypassOption const bypass_option; BufferImportMethod const buffer_import_method; }; } } } #endif // MIR_GRAPHICS_MESA_BUFFER_ALLOCATOR_H_ ./src/platforms/mesa/server/drm_close_threadsafe.cpp0000644000004100000410000000171213115234416023136 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "drm_close_threadsafe.h" #include #include namespace mgm = mir::graphics::mesa; int mgm::drm_close_threadsafe(int fd) { static std::mutex m; std::lock_guard lg{m}; return drmClose(fd); } ./src/platforms/mesa/server/software_buffer.h0000644000004100000410000000254613115234664021644 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_MESA_SOFTWARE_BUFFER_H_ #define MIR_GRAPHICS_MESA_SOFTWARE_BUFFER_H_ #include "shm_buffer.h" namespace mir { namespace graphics { namespace common { class ShmFile; } namespace mesa { class SoftwareBuffer: public common::ShmBuffer { public: SoftwareBuffer( std::unique_ptr shm_file, geometry::Size const& size, MirPixelFormat const& pixel_format); std::shared_ptr native_buffer_handle() const override; private: std::shared_ptr create_native_buffer(); std::shared_ptr const native_buffer; }; } } } #endif // MIR_GRAPHICS_MESA_SOFTWARE_BUFFER_H_ ./src/platforms/mesa/server/gbm_buffer.h0000644000004100000410000000411413115234664020550 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Christopher James Halse Rogers */ #ifndef MIR_GRAPHICS_MESA_GBM_BUFFER_H_ #define MIR_GRAPHICS_MESA_GBM_BUFFER_H_ #include "mir/graphics/buffer_basic.h" #include "mir/renderer/gl/texture_source.h" #include #include #include namespace mir { namespace graphics { namespace common { class BufferTextureBinder; } namespace mesa { class GBMBuffer: public BufferBasic, public NativeBufferBase, public renderer::gl::TextureSource { public: GBMBuffer(std::shared_ptr const& handle, uint32_t bo_flags, std::unique_ptr texture_binder); GBMBuffer(const GBMBuffer&) = delete; ~GBMBuffer(); GBMBuffer& operator=(const GBMBuffer&) = delete; virtual geometry::Size size() const override; virtual geometry::Stride stride() const; virtual MirPixelFormat pixel_format() const override; virtual std::shared_ptr native_buffer_handle() const override; virtual void gl_bind_to_texture() override; virtual void bind() override; virtual void secure_for_render() override; NativeBufferBase* native_buffer_base() override; private: std::shared_ptr const gbm_handle; uint32_t bo_flags; std::unique_ptr const texture_binder; int prime_fd; }; } } } #endif // MIR_GRAPHICS_MESA_GBM_BUFFER_H_ ./src/platforms/mesa/server/drm_authentication.h0000644000004100000410000000243013115234416022325 0ustar www-datawww-data/* * Copyright © 2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_MESA_DRM_AUTHENTICATION_H_ #define MIR_GRAPHICS_MESA_DRM_AUTHENTICATION_H_ #include #include "mir/fd.h" namespace mir { namespace graphics { namespace mesa { class DRMAuthentication { public: DRMAuthentication() = default; virtual ~DRMAuthentication() = default; DRMAuthentication(DRMAuthentication const&) = delete; DRMAuthentication& operator=(DRMAuthentication const&) = delete; virtual void auth_magic(drm_magic_t magic) = 0; virtual mir::Fd authenticated_fd() = 0; }; } } } #endif /* MIR_GRAPHICS_MESA_DRM_AUTHENTICATION_H_ */ ./src/platforms/mesa/server/drm_close_threadsafe.h0000644000004100000410000000172213115234416022604 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_DRM_CLOSE_THREADSAFE_H_ #define MIR_GRAPHICS_MESA_DRM_CLOSE_THREADSAFE_H_ namespace mir { namespace graphics { namespace mesa { int drm_close_threadsafe(int fd); } } } #endif /* MIR_GRAPHICS_MESA_DRM_CLOSE_THREADSAFE_H_ */ ./src/platforms/mesa/server/gbm_buffer.cpp0000644000004100000410000000605413115234664021110 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Christopher James Halse Rogers * Alexandros Frantzis */ #include "gbm_buffer.h" #include "buffer_texture_binder.h" #include "native_buffer.h" #include "gbm_format_conversions.h" #include #include #include #include namespace mg=mir::graphics; namespace mgm=mir::graphics::mesa; namespace mgc = mir::graphics::common; namespace geom=mir::geometry; mgm::GBMBuffer::GBMBuffer(std::shared_ptr const& handle, uint32_t bo_flags, std::unique_ptr texture_binder) : gbm_handle{handle}, bo_flags{bo_flags}, texture_binder{std::move(texture_binder)}, prime_fd{-1} { auto device = gbm_bo_get_device(gbm_handle.get()); auto gem_handle = gbm_bo_get_handle(gbm_handle.get()).u32; auto drm_fd = gbm_device_get_fd(device); auto ret = drmPrimeHandleToFD(drm_fd, gem_handle, DRM_CLOEXEC, &prime_fd); if (ret) { std::string const msg("Failed to get PRIME fd from gbm bo"); BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), msg})); } } mgm::GBMBuffer::~GBMBuffer() { if (prime_fd >= 0) close(prime_fd); } geom::Size mgm::GBMBuffer::size() const { return {gbm_bo_get_width(gbm_handle.get()), gbm_bo_get_height(gbm_handle.get())}; } geom::Stride mgm::GBMBuffer::stride() const { return geom::Stride(gbm_bo_get_stride(gbm_handle.get())); } MirPixelFormat mgm::GBMBuffer::pixel_format() const { return gbm_format_to_mir_format(gbm_bo_get_format(gbm_handle.get())); } void mgm::GBMBuffer::gl_bind_to_texture() { texture_binder->gl_bind_to_texture(); } std::shared_ptr mgm::GBMBuffer::native_buffer_handle() const { auto temp = std::make_shared(); temp->fd_items = 1; temp->fd[0] = prime_fd; temp->stride = stride().as_uint32_t(); temp->flags = (bo_flags & GBM_BO_USE_SCANOUT) ? mir_buffer_flag_can_scanout : 0; temp->bo = gbm_handle.get(); auto const& dim = size(); temp->width = dim.width.as_int(); temp->height = dim.height.as_int(); return temp; } mg::NativeBufferBase* mgm::GBMBuffer::native_buffer_base() { return this; } void mgm::GBMBuffer::secure_for_render() { } void mgm::GBMBuffer::bind() { gl_bind_to_texture(); } ./src/platforms/mesa/server/ipc_operations.h0000644000004100000410000000311713115234416021465 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_MESA_IPC_OPERATIONS_H_ #define MIR_GRAPHICS_MESA_IPC_OPERATIONS_H_ #include "mir/graphics/platform_ipc_operations.h" namespace mir { namespace graphics { class NestedContext; namespace mesa { class DRMAuthentication; class IpcOperations : public PlatformIpcOperations { public: IpcOperations(std::shared_ptr const& drm); void pack_buffer(BufferIpcMessage& message, Buffer const& buffer, BufferIpcMsgType msg_type) const override; void unpack_buffer(BufferIpcMessage& message, Buffer const& buffer) const override; std::shared_ptr connection_ipc_package() override; PlatformOperationMessage platform_operation( unsigned int const opcode, PlatformOperationMessage const& message) override; private: std::shared_ptr const drm; }; } } } #endif /* MIR_GRAPHICS_MESA_IPC_OPERATIONS_H_ */ ./src/platforms/mesa/server/display_helpers.h0000644000004100000410000000657613115234664021657 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_DISPLAY_HELPERS_H_ #define MIR_GRAPHICS_MESA_DISPLAY_HELPERS_H_ #include "drm_authentication.h" #include "mir/udev/wrapper.h" #include #include #pragma GCC diagnostic push #pragma GCC diagnostic warning "-Wall" #include #pragma GCC diagnostic pop #include #include namespace mir { namespace graphics { class GLConfig; namespace mesa { typedef std::unique_ptr> GBMSurfaceUPtr; namespace helpers { enum class DRMNodeToUse { render, card }; class DRMHelper : public DRMAuthentication { public: DRMHelper(DRMNodeToUse const node_to_use) : fd{-1}, node_to_use{node_to_use} {} ~DRMHelper(); DRMHelper(const DRMHelper &) = delete; DRMHelper& operator=(const DRMHelper&) = delete; void setup(std::shared_ptr const& udev); mir::Fd authenticated_fd(); void auth_magic(drm_magic_t magic); void drop_master() const; void set_master() const; int fd; DRMNodeToUse const node_to_use; private: // TODO: This herustic is temporary; should be replaced with // handling >1 DRM device. int is_appropriate_device(std::shared_ptr const& udev, mir::udev::Device const& dev); int count_connections(int fd); int open_drm_device(std::shared_ptr const& udev); }; class GBMHelper { public: GBMHelper() : device{0} {} ~GBMHelper(); GBMHelper(const GBMHelper&) = delete; GBMHelper& operator=(const GBMHelper&) = delete; void setup(const DRMHelper& drm); void setup(int drm_fd); GBMSurfaceUPtr create_scanout_surface(uint32_t width, uint32_t height); gbm_device* device; }; class EGLHelper { public: EGLHelper(GLConfig const& gl_config); ~EGLHelper() noexcept; EGLHelper(const EGLHelper&) = delete; EGLHelper& operator=(const EGLHelper&) = delete; void setup(GBMHelper const& gbm); void setup(GBMHelper const& gbm, EGLContext shared_context); void setup(GBMHelper const& gbm, gbm_surface* surface_gbm, EGLContext shared_context); bool swap_buffers(); bool make_current() const; bool release_current() const; EGLContext context() { return egl_context; } void report_egl_configuration(std::function); private: void setup_internal(GBMHelper const& gbm, bool initialize); EGLint const depth_buffer_bits; EGLint const stencil_buffer_bits; EGLDisplay egl_display; EGLConfig egl_config; EGLContext egl_context; EGLSurface egl_surface; bool should_terminate_egl; }; } } } } #endif /* MIR_GRAPHICS_MESA_DISPLAY_HELPERS_H_ */ ./src/platforms/mesa/server/buffer_allocator.cpp0000644000004100000410000002573613115234664022333 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Christopher James Halse Rogers */ #include "buffer_allocator.h" #include "gbm_buffer.h" #include "buffer_texture_binder.h" #include "anonymous_shm_file.h" #include "shm_buffer.h" #include "display_helpers.h" #include "software_buffer.h" #include "gbm_format_conversions.h" #include "mir/graphics/egl_extensions.h" #include "mir/graphics/egl_error.h" #include "mir/graphics/buffer_properties.h" #include "mir/graphics/buffer_ipc_message.h" #include #include #include #include #include MIR_SERVER_GL_H #include MIR_SERVER_GLEXT_H #include #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mg::mesa; namespace mgc = mg::common; namespace geom = mir::geometry; namespace { class EGLImageBufferTextureBinder : public mgc::BufferTextureBinder { public: EGLImageBufferTextureBinder(std::shared_ptr const& gbm_bo, std::shared_ptr const& egl_extensions) : bo{gbm_bo}, egl_extensions{egl_extensions}, egl_image{EGL_NO_IMAGE_KHR} { } ~EGLImageBufferTextureBinder() { if (egl_image != EGL_NO_IMAGE_KHR) egl_extensions->eglDestroyImageKHR(egl_display, egl_image); } void gl_bind_to_texture() override { ensure_egl_image(); egl_extensions->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image); } protected: virtual void ensure_egl_image() = 0; std::shared_ptr const bo; std::shared_ptr const egl_extensions; EGLDisplay egl_display; EGLImageKHR egl_image; }; class NativePixmapTextureBinder : public EGLImageBufferTextureBinder { public: NativePixmapTextureBinder(std::shared_ptr const& gbm_bo, std::shared_ptr const& egl_extensions) : EGLImageBufferTextureBinder(gbm_bo, egl_extensions) { } private: void ensure_egl_image() { if (egl_image == EGL_NO_IMAGE_KHR) { eglBindAPI(MIR_SERVER_EGL_OPENGL_API); egl_display = eglGetCurrentDisplay(); gbm_bo* bo_raw{bo.get()}; const EGLint image_attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; egl_image = egl_extensions->eglCreateImageKHR(egl_display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, reinterpret_cast(bo_raw), image_attrs); if (egl_image == EGL_NO_IMAGE_KHR) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGLImage")); } } }; class DMABufTextureBinder : public EGLImageBufferTextureBinder { public: DMABufTextureBinder(std::shared_ptr const& gbm_bo, std::shared_ptr const& egl_extensions) : EGLImageBufferTextureBinder(gbm_bo, egl_extensions) { } private: void ensure_egl_image() { if (egl_image == EGL_NO_IMAGE_KHR) { eglBindAPI(MIR_SERVER_EGL_OPENGL_API); egl_display = eglGetCurrentDisplay(); gbm_bo* bo_raw{bo.get()}; auto device = gbm_bo_get_device(bo_raw); auto gem_handle = gbm_bo_get_handle(bo_raw).u32; auto drm_fd = gbm_device_get_fd(device); int raw_fd = -1; auto ret = drmPrimeHandleToFD(drm_fd, gem_handle, DRM_CLOEXEC, &raw_fd); prime_fd = mir::Fd{raw_fd}; if (ret) { std::string const msg("Failed to get PRIME fd from gbm bo"); BOOST_THROW_EXCEPTION( std::system_error(errno, std::system_category(), "Failed to get PRIME fd from gbm bo")); } const EGLint image_attrs_X[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_WIDTH, static_cast(gbm_bo_get_width(bo_raw)), EGL_HEIGHT, static_cast(gbm_bo_get_height(bo_raw)), EGL_LINUX_DRM_FOURCC_EXT, static_cast(gbm_bo_get_format(bo_raw)), EGL_DMA_BUF_PLANE0_FD_EXT, prime_fd, EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, EGL_DMA_BUF_PLANE0_PITCH_EXT, static_cast(gbm_bo_get_stride(bo_raw)), EGL_NONE }; egl_image = egl_extensions->eglCreateImageKHR(egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, static_cast(nullptr), image_attrs_X); if (egl_image == EGL_NO_IMAGE_KHR) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGLImage")); } } mir::Fd prime_fd; }; struct GBMBODeleter { void operator()(gbm_bo* handle) const { if (handle) gbm_bo_destroy(handle); } }; auto make_texture_binder( mgm::BufferImportMethod const buffer_import_method, std::shared_ptr const& bo, std::shared_ptr const& egl_extensions) -> std::unique_ptr { if (buffer_import_method == mgm::BufferImportMethod::dma_buf) return std::make_unique(bo, egl_extensions); else return std::make_unique(bo, egl_extensions); } } mgm::BufferAllocator::BufferAllocator( gbm_device* device, BypassOption bypass_option, mgm::BufferImportMethod const buffer_import_method) : device(device), egl_extensions(std::make_shared()), bypass_option(buffer_import_method == mgm::BufferImportMethod::dma_buf ? mgm::BypassOption::prohibited : bypass_option), buffer_import_method(buffer_import_method) { } std::shared_ptr mgm::BufferAllocator::alloc_buffer( BufferProperties const& buffer_properties) { std::shared_ptr buffer; if (buffer_properties.usage == BufferUsage::software) buffer = alloc_software_buffer(buffer_properties.size, buffer_properties.format); else buffer = alloc_hardware_buffer(buffer_properties); return buffer; } std::shared_ptr mgm::BufferAllocator::alloc_hardware_buffer( BufferProperties const& buffer_properties) { uint32_t bo_flags{GBM_BO_USE_RENDERING}; uint32_t const gbm_format = mgm::mir_format_to_gbm_format(buffer_properties.format); /* * Bypass is generally only beneficial to hardware buffers where the * blitting happens on the GPU. For software buffers it is slower to blit * individual pixels from CPU to GPU memory, so don't do it. * Also try to avoid allocating scanout buffers for small surfaces that * are unlikely to ever be fullscreen. * * TODO: The client will have to be more intelligent about when to use * GBM_BO_USE_SCANOUT in conjunction with mir_extension_gbm_buffer. * That may have to come after buffer reallocation support (surface * resizing). The client may also want to check for * mir_surface_state_fullscreen later when it's fully wired up. */ if ((bypass_option == mgm::BypassOption::allowed) && buffer_properties.size.width.as_uint32_t() >= 800 && buffer_properties.size.height.as_uint32_t() >= 600) { bo_flags |= GBM_BO_USE_SCANOUT; } return alloc_buffer(buffer_properties.size, gbm_format, bo_flags); } std::shared_ptr mgm::BufferAllocator::alloc_buffer( geom::Size size, uint32_t native_format, uint32_t native_flags) { gbm_bo *bo_raw = gbm_bo_create( device, size.width.as_uint32_t(), size.height.as_uint32_t(), native_format, native_flags); if (!bo_raw) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create GBM buffer object")); std::shared_ptr bo{bo_raw, GBMBODeleter()}; return std::make_shared( bo, native_flags, make_texture_binder(buffer_import_method, bo, egl_extensions)); } std::shared_ptr mgm::BufferAllocator::alloc_software_buffer( geom::Size size, MirPixelFormat format) { if (!mgc::ShmBuffer::supports(format)) { BOOST_THROW_EXCEPTION( std::runtime_error( "Trying to create SHM buffer with unsupported pixel format")); } auto const stride = geom::Stride{MIR_BYTES_PER_PIXEL(format) * size.width.as_uint32_t()}; size_t const size_in_bytes = stride.as_int() * size.height.as_int(); return std::make_shared( std::make_unique(size_in_bytes), size, format); } std::vector mgm::BufferAllocator::supported_pixel_formats() { /* * supported_pixel_formats() is kind of a kludge. The right answer depends * on whether you're using hardware or software, and it depends on * the usage type (e.g. scanout). In the future it's also expected to * depend on the GPU model in use at runtime. * To be precise, ShmBuffer now supports OpenGL compositing of all * but one MirPixelFormat (bgr_888). But GBM only supports [AX]RGB. * So since we don't yet have an adequate API in place to query what the * intended usage will be, we need to be conservative and report the * intersection of ShmBuffer and GBM's pixel format support. That is * just these two. Be aware however you can create a software surface * with almost any pixel format and it will also work... * TODO: Convert this to a loop that just queries the intersection of * gbm_device_is_format_supported and ShmBuffer::supports(), however not * yet while the former is buggy. (FIXME: LP: #1473901) */ static std::vector const pixel_formats{ mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888 }; return pixel_formats; } ./src/platforms/mesa/server/platform_common.h0000644000004100000410000000171713115234416021647 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Cemil Azizoglu */ #ifndef MIR_GRAPHICS_MESA_PLATFORM_COMMON_H_ #define MIR_GRAPHICS_MESA_PLATFORM_COMMON_H_ namespace mir { namespace graphics { namespace mesa { enum class BypassOption { allowed, prohibited }; } } } #endif /* MIR_GRAPHICS_MESA_PLATFORM_COMMON_H_ */ ./src/platforms/mesa/server/display_helpers.cpp0000644000004100000410000003313213115234664022176 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "display_helpers.h" #include "drm_close_threadsafe.h" #include "kms-utils/drm_mode_resources.h" #include "mir/graphics/gl_config.h" #include "mir/graphics/egl_error.h" #include "mir/udev/wrapper.h" #include #include #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace mgmh = mir::graphics::mesa::helpers; /************* * DRMHelper * *************/ void mgmh::DRMHelper::setup(std::shared_ptr const& udev) { fd = open_drm_device(udev); if (fd < 0) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to open DRM device\n")); } mir::Fd mgmh::DRMHelper::authenticated_fd() { /* We must have our own device fd first, so that it has become the DRM master */ if (fd < 0) BOOST_THROW_EXCEPTION( std::runtime_error( "Tried to get authenticated DRM fd before setting up the DRM master")); if (node_to_use == DRMNodeToUse::render) return mir::Fd{IntOwnedFd{dup(fd)}}; char* busid = drmGetBusid(fd); if (!busid) BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to get BusID of DRM device")) << boost::errinfo_errno(errno)); int auth_fd = drmOpen(NULL, busid); drmFreeBusid(busid); if (auth_fd < 0) BOOST_THROW_EXCEPTION( std::runtime_error("Failed to open DRM device for authenticated fd")); if (fcntl(auth_fd, F_SETFD, fcntl(auth_fd, F_GETFD) | FD_CLOEXEC) == -1) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to set FD_CLOEXEC for authenticated drm fd"))); } drm_magic_t magic; int ret = -1; if ((ret = drmGetMagic(auth_fd, &magic)) < 0) { close(auth_fd); BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to get DRM device magic cookie")) << boost::errinfo_errno(-ret)); } if ((ret = drmAuthMagic(fd, magic)) < 0) { close(auth_fd); BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to authenticate DRM device magic cookie")) << boost::errinfo_errno(-ret)); } //TODO: remove IntOwnedFd, its how the code works now though return mir::Fd{IntOwnedFd{auth_fd}}; } void mgmh::DRMHelper::auth_magic(drm_magic_t magic) { /* We must have our own device fd first, so that it has become the DRM master */ if (fd < 0) { BOOST_THROW_EXCEPTION( std::runtime_error( "Tried to authenticate magic cookie before setting up the DRM master")); } int ret = drmAuthMagic(fd, magic); if (ret < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to authenticate DRM device magic cookie")) << boost::errinfo_errno(-ret)); } } void mgmh::DRMHelper::drop_master() const { /* We must have our own device fd first, so that it has become the DRM master */ if (fd < 0) { BOOST_THROW_EXCEPTION( std::runtime_error("Tried to drop DRM master without a DRM device")); } int ret = drmDropMaster(fd); if (ret < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to drop DRM master")) << boost::errinfo_errno(errno)); } } void mgmh::DRMHelper::set_master() const { /* We must have our own device fd first, so that it has become the DRM master */ if (fd < 0) { BOOST_THROW_EXCEPTION( std::runtime_error("Tried to set DRM master without a DRM device")); } int ret = drmSetMaster(fd); if (ret < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to set DRM master")) << boost::errinfo_errno(errno)); } } int mgmh::DRMHelper::is_appropriate_device(std::shared_ptr const& udev, mir::udev::Device const& drm_device) { mir::udev::Enumerator children(udev); children.match_parent(drm_device); char const* devtype = drm_device.devtype(); if (!devtype || strcmp(devtype, "drm_minor")) return EINVAL; children.scan_devices(); for (auto& device : children) { // For some reason udev regards the device as a parent of itself // If there are any other children, they should be outputs. if (device != drm_device) return 0; } return ENOMEDIUM; } int mgmh::DRMHelper::count_connections(int fd) { kms::DRMModeResources resources{fd}; int n_connected = 0; resources.for_each_connector([&](kms::DRMModeConnectorUPtr connector) { if (connector->connection == DRM_MODE_CONNECTED) n_connected++; }); return n_connected; } int mgmh::DRMHelper::open_drm_device(std::shared_ptr const& udev) { int tmp_fd = -1; int error = ENODEV; //Default error is "there are no DRM devices" mir::udev::Enumerator devices(udev); devices.match_subsystem("drm"); if (node_to_use == DRMNodeToUse::render) devices.match_sysname("renderD[0-9]*"); else devices.match_sysname("card[0-9]*"); devices.scan_devices(); for(auto& device : devices) { if ((node_to_use == DRMNodeToUse::card) && (error = is_appropriate_device(udev, device))) continue; // If directly opening the DRM device is good enough for X it's good enough for us! tmp_fd = open(device.devnode(), O_RDWR | O_CLOEXEC); if (tmp_fd < 0) { error = errno; continue; } if (node_to_use == DRMNodeToUse::card) { // Check that the drm device is usable by setting the interface version we use (1.4) drmSetVersion sv; sv.drm_di_major = 1; sv.drm_di_minor = 4; sv.drm_dd_major = -1; /* Don't care */ sv.drm_dd_minor = -1; /* Don't care */ if ((error = -drmSetInterfaceVersion(tmp_fd, &sv))) { close(tmp_fd); tmp_fd = -1; continue; } // Stop if this device has connections to display on if (count_connections(tmp_fd) > 0) break; close(tmp_fd); tmp_fd = -1; } else break; } if (tmp_fd < 0) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Error opening DRM device")) << boost::errinfo_errno(error)); } return tmp_fd; } mgmh::DRMHelper::~DRMHelper() { if (fd >= 0) mgm::drm_close_threadsafe(fd); } /************* * GBMHelper * *************/ void mgmh::GBMHelper::setup(const DRMHelper& drm) { device = gbm_create_device(drm.fd); if (!device) BOOST_THROW_EXCEPTION( std::runtime_error("Failed to create GBM device")); } void mgmh::GBMHelper::setup(int drm_fd) { device = gbm_create_device(drm_fd); if(!device) BOOST_THROW_EXCEPTION( std::runtime_error("Failed to create GBM device")); } mgm::GBMSurfaceUPtr mgmh::GBMHelper::create_scanout_surface(uint32_t width, uint32_t height) { auto surface_raw = gbm_surface_create(device, width, height, GBM_BO_FORMAT_XRGB8888, GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING); auto gbm_surface_deleter = [](gbm_surface *p) { if (p) gbm_surface_destroy(p); }; GBMSurfaceUPtr surface{surface_raw, gbm_surface_deleter}; if (!surface) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create GBM scanout surface")); return surface; } mgmh::GBMHelper::~GBMHelper() { if (device) gbm_device_destroy(device); } /************* * EGLHelper * *************/ mgmh::EGLHelper::EGLHelper(GLConfig const& gl_config) : depth_buffer_bits{gl_config.depth_buffer_bits()}, stencil_buffer_bits{gl_config.stencil_buffer_bits()}, egl_display{EGL_NO_DISPLAY}, egl_config{0}, egl_context{EGL_NO_CONTEXT}, egl_surface{EGL_NO_SURFACE}, should_terminate_egl{false} { } void mgmh::EGLHelper::setup(GBMHelper const& gbm) { eglBindAPI(MIR_SERVER_EGL_OPENGL_API); static const EGLint context_attr[] = { #if MIR_SERVER_EGL_OPENGL_BIT == EGL_OPENGL_ES2_BIT EGL_CONTEXT_CLIENT_VERSION, 2, #endif EGL_NONE }; setup_internal(gbm, true); egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attr); if (egl_context == EGL_NO_CONTEXT) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context")); } void mgmh::EGLHelper::setup(GBMHelper const& gbm, EGLContext shared_context) { eglBindAPI(MIR_SERVER_EGL_OPENGL_API); static const EGLint context_attr[] = { #if MIR_SERVER_EGL_OPENGL_BIT == EGL_OPENGL_ES2_BIT EGL_CONTEXT_CLIENT_VERSION, 2, #endif EGL_NONE }; setup_internal(gbm, false); egl_context = eglCreateContext(egl_display, egl_config, shared_context, context_attr); if (egl_context == EGL_NO_CONTEXT) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context")); } void mgmh::EGLHelper::setup(GBMHelper const& gbm, gbm_surface* surface_gbm, EGLContext shared_context) { eglBindAPI(MIR_SERVER_EGL_OPENGL_API); static const EGLint context_attr[] = { #if MIR_SERVER_EGL_OPENGL_BIT == EGL_OPENGL_ES2_BIT EGL_CONTEXT_CLIENT_VERSION, 2, #endif EGL_NONE }; setup_internal(gbm, false); egl_surface = eglCreateWindowSurface(egl_display, egl_config, surface_gbm, nullptr); if(egl_surface == EGL_NO_SURFACE) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL window surface")); egl_context = eglCreateContext(egl_display, egl_config, shared_context, context_attr); if (egl_context == EGL_NO_CONTEXT) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context")); } mgmh::EGLHelper::~EGLHelper() noexcept { if (egl_display != EGL_NO_DISPLAY) { if (egl_context != EGL_NO_CONTEXT) { eglBindAPI(MIR_SERVER_EGL_OPENGL_API); if (eglGetCurrentContext() == egl_context) eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(egl_display, egl_context); } if (egl_surface != EGL_NO_SURFACE) eglDestroySurface(egl_display, egl_surface); if (should_terminate_egl) eglTerminate(egl_display); } } bool mgmh::EGLHelper::swap_buffers() { auto ret = eglSwapBuffers(egl_display, egl_surface); return (ret == EGL_TRUE); } bool mgmh::EGLHelper::make_current() const { auto ret = eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context); eglBindAPI(MIR_SERVER_EGL_OPENGL_API); return (ret == EGL_TRUE); } bool mgmh::EGLHelper::release_current() const { auto ret = eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); return (ret == EGL_TRUE); } void mgmh::EGLHelper::setup_internal(GBMHelper const& gbm, bool initialize) { EGLint const config_attr[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 5, EGL_BLUE_SIZE, 5, EGL_ALPHA_SIZE, 0, EGL_DEPTH_SIZE, depth_buffer_bits, EGL_STENCIL_SIZE, stencil_buffer_bits, EGL_RENDERABLE_TYPE, MIR_SERVER_EGL_OPENGL_BIT, EGL_NONE }; static const EGLint required_egl_version_major = 1; static const EGLint required_egl_version_minor = 4; EGLint num_egl_configs; egl_display = eglGetDisplay(static_cast(gbm.device)); if (egl_display == EGL_NO_DISPLAY) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to get EGL display")); if (initialize) { EGLint major, minor; if (eglInitialize(egl_display, &major, &minor) == EGL_FALSE) BOOST_THROW_EXCEPTION(mg::egl_error("Failed to initialize EGL display")); if ((major < required_egl_version_major) || (major == required_egl_version_major && minor < required_egl_version_minor)) { BOOST_THROW_EXCEPTION( boost::enable_error_info(std::runtime_error("Incompatible EGL version"))); // TODO: Insert egl version major and minor into exception } should_terminate_egl = true; } if (eglChooseConfig(egl_display, config_attr, &egl_config, 1, &num_egl_configs) == EGL_FALSE || num_egl_configs != 1) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to choose ARGB EGL config")); } } void mgmh::EGLHelper::report_egl_configuration(std::function f) { f(egl_display, egl_config); } ./src/platforms/mesa/server/software_buffer.cpp0000644000004100000410000000303013115234664022164 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "software_buffer.h" #include "shm_file.h" #include "native_buffer.h" namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace mgc = mir::graphics::common; namespace geom = mir::geometry; mgm::SoftwareBuffer::SoftwareBuffer( std::unique_ptr shm_file, geom::Size const& size, MirPixelFormat const& pixel_format) : ShmBuffer(std::move(shm_file), size, pixel_format), native_buffer(create_native_buffer()) { } std::shared_ptr mgm::SoftwareBuffer::create_native_buffer() { auto buffer = std::make_shared(); *static_cast(buffer.get()) = *to_mir_buffer_package(); buffer->bo = nullptr; return buffer; } std::shared_ptr mgm::SoftwareBuffer::native_buffer_handle() const { return native_buffer; } ./src/platforms/mesa/common/0000755000004100000410000000000013115234667016266 5ustar www-datawww-data./src/platforms/mesa/common/CMakeLists.txt0000644000004100000410000000032313115234664021021 0ustar www-datawww-datainclude_directories( ${PROJECT_SOURCE_DIR}/include/client ${PROJECT_SOURCE_DIR}/src/platforms/mesa/include/ ${DRM_INCLUDE_DIRS} ) add_library( mirsharedmesa-static STATIC gbm_format_conversions.cpp ) ./src/platforms/mesa/common/gbm_format_conversions.cpp0000644000004100000410000000546413115234664023545 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois * */ #include "gbm_format_conversions.h" #include #include namespace mgm = mir::graphics::mesa; MirPixelFormat mgm::gbm_format_to_mir_format(uint32_t format) { MirPixelFormat pf; switch (format) { case GBM_BO_FORMAT_ARGB8888: case GBM_FORMAT_ARGB8888: pf = mir_pixel_format_argb_8888; break; case GBM_BO_FORMAT_XRGB8888: case GBM_FORMAT_XRGB8888: pf = mir_pixel_format_xrgb_8888; break; case GBM_FORMAT_ABGR8888: pf = mir_pixel_format_abgr_8888; break; case GBM_FORMAT_XBGR8888: pf = mir_pixel_format_xbgr_8888; break; case GBM_FORMAT_BGR888: pf = mir_pixel_format_bgr_888; break; case GBM_FORMAT_RGB888: pf = mir_pixel_format_rgb_888; break; case GBM_FORMAT_RGB565: pf = mir_pixel_format_rgb_565; break; case GBM_FORMAT_RGBA5551: pf = mir_pixel_format_rgba_5551; break; case GBM_FORMAT_RGBA4444: pf = mir_pixel_format_rgba_4444; break; default: pf = mir_pixel_format_invalid; break; } return pf; } uint32_t mgm::mir_format_to_gbm_format(MirPixelFormat format) { uint32_t gbm_pf; switch (format) { case mir_pixel_format_argb_8888: gbm_pf = GBM_FORMAT_ARGB8888; break; case mir_pixel_format_xrgb_8888: gbm_pf = GBM_FORMAT_XRGB8888; break; case mir_pixel_format_abgr_8888: gbm_pf = GBM_FORMAT_ABGR8888; break; case mir_pixel_format_xbgr_8888: gbm_pf = GBM_FORMAT_XBGR8888; break; case mir_pixel_format_bgr_888: gbm_pf = GBM_FORMAT_BGR888; break; case mir_pixel_format_rgb_888: gbm_pf = GBM_FORMAT_RGB888; break; case mir_pixel_format_rgb_565: gbm_pf = GBM_FORMAT_RGB565; break; case mir_pixel_format_rgba_5551: gbm_pf = GBM_FORMAT_RGBA5551; break; case mir_pixel_format_rgba_4444: gbm_pf = GBM_FORMAT_RGBA4444; break; default: gbm_pf = mgm::invalid_gbm_format; break; } return gbm_pf; } ./src/platforms/evdev/0000755000004100000410000000000013115234677015163 5ustar www-datawww-data./src/platforms/evdev/libinput_ptr.h0000644000004100000410000000206713115234416020043 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_INPUT_EVDEV_LIBINPUT_PTR_H_ #define MIR_INPUT_EVDEV_LIBINPUT_PTR_H_ #include "mir_toolkit/event.h" #include #include struct libinput; struct udev; namespace mir { namespace input { namespace evdev { using LibInputPtr = std::unique_ptr; LibInputPtr make_libinput(::udev* context); } } } #endif ./src/platforms/evdev/CMakeLists.txt0000644000004100000410000000275013115234664017723 0ustar www-datawww-datapkg_check_modules(LIBINPUT REQUIRED libinput) if ("${LIBINPUT_VERSION}" VERSION_LESS "1.1") add_definitions(-DMIR_LIBINPUT_HAS_ACCEL_PROFILE=0) else () add_definitions(-DMIR_LIBINPUT_HAS_ACCEL_PROFILE=1) endif () include_directories( ${LIBINPUT_CFLAGS} ${PROJECT_SOURCE_DIR}/include/platform ${PROJECT_SOURCE_DIR}/src/include/platform # udev Context ${PROJECT_SOURCE_DIR}/src/include/common # raii.h ${PROJECT_SOURCE_DIR}/include/common ${PROJECT_SOURCE_DIR}/include/client ) add_library(mirevdevutilsobjects OBJECT evdev_device_detection.cpp button_utils.cpp ) add_library(mirplatforminputevdevobjects OBJECT libinput_device.cpp libinput_device_ptr.cpp libinput_ptr.cpp platform.cpp ) add_library(mirplatforminputevdev MODULE platform_factory.cpp $ $ ) set_target_properties( mirplatforminputevdev PROPERTIES OUTPUT_NAME input-evdev LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/server-modules PREFIX "" SUFFIX ".so.${MIR_SERVER_INPUT_PLATFORM_ABI}" LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${MIR_INPUT_PLATFORM_VERSION_SCRIPT}" LINK_DEPENDS ${MIR_INPUT_PLATFORM_VERSION_SCRIPT} ) target_link_libraries(mirplatforminputevdev mirplatform # udev wrapper ${Boost_PROGRAM_OPTIONS_LIBRARY} ${LIBINPUT_LDFLAGS} ${LIBINPUT_LIBRARIES} ) install(TARGETS mirplatforminputevdev LIBRARY DESTINATION ${MIR_SERVER_PLATFORM_PATH}) ./src/platforms/evdev/libinput_device.h0000644000004100000410000000663613115234664020510 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_INPUT_EVDEV_LIBINPUT_DEVICE_H_ #define MIR_INPUT_EVDEV_LIBINPUT_DEVICE_H_ #include "libinput_ptr.h" #include "libinput_device_ptr.h" #include "mir/input/event_builder.h" #include "mir/input/input_device.h" #include "mir/input/input_device_info.h" #include "mir/geometry/point.h" #include #include struct libinput_event; struct libinput_event_keyboard; struct libinput_event_touch; struct libinput_event_pointer; struct libinput_device_group; namespace mir { namespace input { class InputReport; namespace evdev { struct PointerState; struct KeyboardState; class LibInputDevice : public input::InputDevice { public: LibInputDevice(std::shared_ptr const& report, LibInputDevicePtr dev); ~LibInputDevice(); void start(InputSink* sink, EventBuilder* builder) override; void stop() override; InputDeviceInfo get_device_info() override; optional_value get_pointer_settings() const override; void apply_settings(PointerSettings const&) override; optional_value get_touchpad_settings() const override; void apply_settings(TouchpadSettings const&) override; void process_event(libinput_event* event); ::libinput_device* device() const; ::libinput_device_group* group(); void add_device_of_group(LibInputDevicePtr ptr); private: EventUPtr convert_event(libinput_event_keyboard* keyboard); EventUPtr convert_button_event(libinput_event_pointer* pointer); EventUPtr convert_motion_event(libinput_event_pointer* pointer); EventUPtr convert_absolute_motion_event(libinput_event_pointer* pointer); EventUPtr convert_axis_event(libinput_event_pointer* pointer); EventUPtr convert_touch_frame(libinput_event_touch* touch); void handle_touch_down(libinput_event_touch* touch); void handle_touch_up(libinput_event_touch* touch); void handle_touch_motion(libinput_event_touch* touch); void update_device_info(); std::shared_ptr report; std::shared_ptr<::libinput> lib; std::vector devices; std::shared_ptr dispatchable_fd; InputSink* sink{nullptr}; EventBuilder* builder{nullptr}; InputDeviceInfo info; mir::geometry::Point pointer_pos; MirPointerButtons button_state; double vertical_scroll_scale{1.0}; double horizontal_scroll_scale{1.0}; struct ContactData { ContactData() {} MirTouchAction action{mir_touch_action_change}; float x{0}, y{0}, major{0}, minor{0}, pressure{0}, orientation{0}; }; std::map last_seen_properties; void update_contact_data(ContactData &data, MirTouchAction action, libinput_event_touch* touch); }; } } } #endif ./src/platforms/evdev/libinput_ptr.cpp0000644000004100000410000000351013115234416020370 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #include "libinput.h" #include "libinput_ptr.h" #include #include #include #include #include #include namespace mie = mir::input::evdev; namespace { int use_monotonic_clock(int evdev) { if (evdev != -1) { int const clockId = CLOCK_MONOTONIC; // Switch each evdev 'client' to MONOTONIC ioctl(evdev, EVIOCSCLOCKID, &clockId); } return evdev; } int fd_open(const char* path, int flags, void* /*userdata*/) { return use_monotonic_clock(::open(path, flags)); } void fd_close(int fd, void* /*userdata*/) { ::close(fd); } const libinput_interface fd_ops = {fd_open, fd_close}; char const default_seat[] = "seat0"; } mie::LibInputPtr mie::make_libinput(udev* context) { auto ret = mie::LibInputPtr{libinput_udev_create_context(&fd_ops, nullptr, context), libinput_unref}; // Temporary technical debt - pick the first seat as default. if (libinput_udev_assign_seat(ret.get(), default_seat) != 0) BOOST_THROW_EXCEPTION(std::runtime_error("Failure assigning udev seat")); return ret; } ./src/platforms/evdev/libinput_device.cpp0000644000004100000410000004751013115234664021037 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #include "libinput_device.h" #include "libinput_ptr.h" #include "libinput_device_ptr.h" #include "evdev_device_detection.h" #include "button_utils.h" #include "mir/input/input_sink.h" #include "mir/input/input_report.h" #include "mir/input/device_capability.h" #include "mir/input/pointer_settings.h" #include "mir/input/touchpad_settings.h" #include "mir/input/input_device_info.h" #include "mir/events/event_builders.h" #include "mir/geometry/displacement.h" #include "mir/dispatch/dispatchable.h" #include "mir/fd.h" #define MIR_LOG_COMPONENT "evdev" #include "mir/log.h" #include "mir/raii.h" #include #include // only used to get constants for input reports #include #include #include #include #include namespace md = mir::dispatch; namespace mi = mir::input; namespace mie = mi::evdev; using namespace std::literals::chrono_literals; mie::LibInputDevice::LibInputDevice(std::shared_ptr const& report, LibInputDevicePtr dev) : report{report}, pointer_pos{0, 0}, button_state{0} { add_device_of_group(std::move(dev)); } void mie::LibInputDevice::add_device_of_group(LibInputDevicePtr dev) { devices.emplace_back(std::move(dev)); update_device_info(); } mie::LibInputDevice::~LibInputDevice() = default; void mie::LibInputDevice::start(InputSink* sink, EventBuilder* builder) { this->sink = sink; this->builder = builder; } void mie::LibInputDevice::stop() { sink = nullptr; builder = nullptr; } void mie::LibInputDevice::process_event(libinput_event* event) { if (!sink) return; try { switch(libinput_event_get_type(event)) { case LIBINPUT_EVENT_KEYBOARD_KEY: sink->handle_input(*convert_event(libinput_event_get_keyboard_event(event))); break; case LIBINPUT_EVENT_POINTER_MOTION: sink->handle_input(*convert_motion_event(libinput_event_get_pointer_event(event))); break; case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: sink->handle_input(*convert_absolute_motion_event(libinput_event_get_pointer_event(event))); break; case LIBINPUT_EVENT_POINTER_BUTTON: sink->handle_input(*convert_button_event(libinput_event_get_pointer_event(event))); break; case LIBINPUT_EVENT_POINTER_AXIS: sink->handle_input(*convert_axis_event(libinput_event_get_pointer_event(event))); break; // touch events are processed as a batch of changes over all touch pointts case LIBINPUT_EVENT_TOUCH_DOWN: handle_touch_down(libinput_event_get_touch_event(event)); break; case LIBINPUT_EVENT_TOUCH_UP: handle_touch_up(libinput_event_get_touch_event(event)); break; case LIBINPUT_EVENT_TOUCH_MOTION: handle_touch_motion(libinput_event_get_touch_event(event)); break; case LIBINPUT_EVENT_TOUCH_CANCEL: // Not yet provided by libinput. break; case LIBINPUT_EVENT_TOUCH_FRAME: sink->handle_input(*convert_touch_frame(libinput_event_get_touch_event(event))); break; default: break; } } catch(std::exception const& error) { mir::log_error("Failure processing input event received from libinput: " + boost::diagnostic_information(error)); } } mir::EventUPtr mie::LibInputDevice::convert_event(libinput_event_keyboard* keyboard) { std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_keyboard_get_time_usec(keyboard)); auto const action = libinput_event_keyboard_get_key_state(keyboard) == LIBINPUT_KEY_STATE_PRESSED ? mir_keyboard_action_down : mir_keyboard_action_up; auto const code = libinput_event_keyboard_get_key(keyboard); report->received_event_from_kernel(time.count(), EV_KEY, code, action); return builder->key_event(time, action, xkb_keysym_t{0}, code); } mir::EventUPtr mie::LibInputDevice::convert_button_event(libinput_event_pointer* pointer) { std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_pointer_get_time_usec(pointer)); auto const button = libinput_event_pointer_get_button(pointer); auto const action = (libinput_event_pointer_get_button_state(pointer) == LIBINPUT_BUTTON_STATE_PRESSED)? mir_pointer_action_button_down : mir_pointer_action_button_up; auto const do_not_swap_buttons = mir_pointer_handedness_right; auto const pointer_button = mie::to_pointer_button(button, do_not_swap_buttons); auto const relative_x_value = 0.0f; auto const relative_y_value = 0.0f; auto const hscroll_value = 0.0f; auto const vscroll_value = 0.0f; report->received_event_from_kernel(time.count(), EV_KEY, pointer_button, action); if (action == mir_pointer_action_button_down) button_state = MirPointerButton(button_state | uint32_t(pointer_button)); else button_state = MirPointerButton(button_state & ~uint32_t(pointer_button)); return builder->pointer_event(time, action, button_state, hscroll_value, vscroll_value, relative_x_value, relative_y_value); } mir::EventUPtr mie::LibInputDevice::convert_motion_event(libinput_event_pointer* pointer) { std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_pointer_get_time_usec(pointer)); auto const action = mir_pointer_action_motion; auto const hscroll_value = 0.0f; auto const vscroll_value = 0.0f; report->received_event_from_kernel(time.count(), EV_REL, 0, 0); return builder->pointer_event(time, action, button_state, hscroll_value, vscroll_value, libinput_event_pointer_get_dx(pointer), libinput_event_pointer_get_dy(pointer)); } mir::EventUPtr mie::LibInputDevice::convert_absolute_motion_event(libinput_event_pointer* pointer) { // a pointing device that emits absolute coordinates std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_pointer_get_time_usec(pointer)); auto const action = mir_pointer_action_motion; auto const hscroll_value = 0.0f; auto const vscroll_value = 0.0f; auto const screen = sink->bounding_rectangle(); uint32_t const width = screen.size.width.as_int(); uint32_t const height = screen.size.height.as_int(); auto abs_x = libinput_event_pointer_get_absolute_x_transformed(pointer, width); auto abs_y = libinput_event_pointer_get_absolute_y_transformed(pointer, height); report->received_event_from_kernel(time.count(), EV_ABS, 0, 0); auto const old_pointer_pos = pointer_pos; pointer_pos = mir::geometry::Point{abs_x, abs_y}; auto const movement = pointer_pos - old_pointer_pos; return builder->pointer_event(time, action, button_state, abs_x, abs_y, hscroll_value, vscroll_value, movement.dx.as_int(), movement.dy.as_int()); } mir::EventUPtr mie::LibInputDevice::convert_axis_event(libinput_event_pointer* pointer) { std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_pointer_get_time_usec(pointer)); auto const action = mir_pointer_action_motion; auto const relative_x_value = 0.0f; auto const relative_y_value = 0.0f; auto hscroll_value = 0.0f; auto vscroll_value = 0.0f; if (libinput_event_pointer_get_axis_source(pointer) == LIBINPUT_POINTER_AXIS_SOURCE_WHEEL) { if (libinput_event_pointer_has_axis(pointer, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) hscroll_value = horizontal_scroll_scale * libinput_event_pointer_get_axis_value_discrete( pointer, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); if (libinput_event_pointer_has_axis(pointer, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) vscroll_value = -vertical_scroll_scale * libinput_event_pointer_get_axis_value_discrete( pointer, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); } else { // by default libinput assumes that wheel ticks represent a rotation of 15 degrees. This relation // is used to map wheel rotations to 'scroll units'. To map the immediate scroll units received // from gesture based scrolling we invert that transformation here. auto const scroll_units_to_ticks = 15.0f; if (libinput_event_pointer_has_axis(pointer, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) hscroll_value = horizontal_scroll_scale * libinput_event_pointer_get_axis_value(pointer, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL) / scroll_units_to_ticks; if (libinput_event_pointer_has_axis(pointer, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) vscroll_value = -vertical_scroll_scale * libinput_event_pointer_get_axis_value(pointer, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL) / scroll_units_to_ticks; } report->received_event_from_kernel(time.count(), EV_REL, 0, 0); return builder->pointer_event(time, action, button_state, hscroll_value, vscroll_value, relative_x_value, relative_y_value); } mir::EventUPtr mie::LibInputDevice::convert_touch_frame(libinput_event_touch* touch) { std::chrono::nanoseconds const time = std::chrono::microseconds(libinput_event_touch_get_time_usec(touch)); report->received_event_from_kernel(time.count(), EV_SYN, 0, 0); // TODO make libinput indicate tool type auto const tool = mir_touch_tooltype_finger; std::vector contacts; for(auto it = begin(last_seen_properties); it != end(last_seen_properties);) { auto & id = it->first; auto & data = it->second; contacts.push_back(events::ContactState{ id, data.action, tool, data.x, data.y, data.pressure, data.major, data.minor, data.orientation}); if (data.action == mir_touch_action_down) data.action = mir_touch_action_change; if (data.action == mir_touch_action_up) it = last_seen_properties.erase(it); else ++it; } return builder->touch_event(time, contacts); } void mie::LibInputDevice::handle_touch_down(libinput_event_touch* touch) { MirTouchId const id = libinput_event_touch_get_slot(touch); update_contact_data(last_seen_properties[id], mir_touch_action_down, touch); } void mie::LibInputDevice::handle_touch_up(libinput_event_touch* touch) { MirTouchId const id = libinput_event_touch_get_slot(touch); last_seen_properties[id].action = mir_touch_action_up; } void mie::LibInputDevice::update_contact_data(ContactData & data, MirTouchAction action, libinput_event_touch* touch) { auto const screen = sink->bounding_rectangle(); uint32_t const width = screen.size.width.as_int(); uint32_t const height = screen.size.height.as_int(); data.action = action; data.pressure = libinput_event_touch_get_pressure(touch); data.x = libinput_event_touch_get_x_transformed(touch, width); data.y = libinput_event_touch_get_y_transformed(touch, height); data.major = libinput_event_touch_get_major_transformed(touch, width, height); data.minor = libinput_event_touch_get_minor_transformed(touch, width, height); } void mie::LibInputDevice::handle_touch_motion(libinput_event_touch* touch) { MirTouchId const id = libinput_event_touch_get_slot(touch); update_contact_data(last_seen_properties[id], mir_touch_action_change, touch); } mi::InputDeviceInfo mie::LibInputDevice::get_device_info() { return info; } void mie::LibInputDevice::update_device_info() { auto dev = device(); std::string name = libinput_device_get_name(dev); std::stringstream unique_id(name); unique_id << '-' << libinput_device_get_sysname(dev) << '-' << libinput_device_get_id_vendor(dev) << '-' << libinput_device_get_id_product(dev); mi::DeviceCapabilities caps; using Caps = mi::DeviceCapabilities; using Mapping = std::pair; auto const mappings = { Mapping{"ID_INPUT_MOUSE", mi::DeviceCapability::pointer}, Mapping{"ID_INPUT_TOUCHSCREEN", mi::DeviceCapability::touchscreen}, Mapping{"ID_INPUT_TOUCHPAD", Caps(mi::DeviceCapability::touchpad) | mi::DeviceCapability::pointer}, Mapping{"ID_INPUT_JOYSTICK", mi::DeviceCapability::joystick}, Mapping{"ID_INPUT_KEY", mi::DeviceCapability::keyboard}, Mapping{"ID_INPUT_KEYBOARD", mi::DeviceCapability::alpha_numeric}, }; for (auto const& dev : devices) { auto const u_dev = mir::raii::deleter_for(libinput_device_get_udev_device(dev.get()), &udev_device_unref); for (auto const& mapping : mappings) { int detected = 0; auto value = udev_device_get_property_value(u_dev.get(), mapping.first); if (!value) continue; std::stringstream property_value(value); property_value >> detected; if (!property_value.fail() && detected) caps |= mapping.second; } } info = mi::InputDeviceInfo{name, unique_id.str(), caps}; } libinput_device_group* mie::LibInputDevice::group() { return libinput_device_get_device_group(device()); } libinput_device* mie::LibInputDevice::device() const { return devices.front().get(); } mir::optional_value mie::LibInputDevice::get_pointer_settings() const { if (!contains(info.capabilities, mi::DeviceCapability::pointer)) return {}; mi::PointerSettings settings; auto dev = device(); auto const left_handed = (libinput_device_config_left_handed_get(dev) == 1); settings.handedness = left_handed? mir_pointer_handedness_left : mir_pointer_handedness_right; #if MIR_LIBINPUT_HAS_ACCEL_PROFILE if (libinput_device_config_accel_get_profile(dev) == LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT) #endif settings.acceleration = mir_pointer_acceleration_none; #if MIR_LIBINPUT_HAS_ACCEL_PROFILE else settings.acceleration = mir_pointer_acceleration_adaptive; #endif settings.cursor_acceleration_bias = libinput_device_config_accel_get_speed(dev); settings.vertical_scroll_scale = vertical_scroll_scale; settings.horizontal_scroll_scale = horizontal_scroll_scale; return settings; } void mie::LibInputDevice::apply_settings(mir::input::PointerSettings const& settings) { if (!contains(info.capabilities, mi::DeviceCapability::pointer)) return; auto dev = device(); #if MIR_LIBINPUT_HAS_ACCEL_PROFILE auto accel_profile = settings.acceleration == mir_pointer_acceleration_adaptive ? LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE : LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT; #endif libinput_device_config_accel_set_speed(dev, settings.cursor_acceleration_bias); libinput_device_config_left_handed_set(dev, mir_pointer_handedness_left == settings.handedness); vertical_scroll_scale = settings.vertical_scroll_scale; horizontal_scroll_scale = settings.horizontal_scroll_scale; #if MIR_LIBINPUT_HAS_ACCEL_PROFILE libinput_device_config_accel_set_profile(dev, accel_profile); #endif } mir::optional_value mie::LibInputDevice::get_touchpad_settings() const { if (!contains(info.capabilities, mi::DeviceCapability::touchpad)) return {}; auto dev = device(); auto click_modes = libinput_device_config_click_get_method(dev); auto scroll_modes = libinput_device_config_scroll_get_method(dev); TouchpadSettings settings; settings.click_mode = mir_touchpad_click_mode_none; if (click_modes & LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS) settings.click_mode |= mir_touchpad_click_mode_area_to_click; if (click_modes & LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) settings.click_mode |= mir_touchpad_click_mode_finger_count; settings.scroll_mode = mir_touchpad_scroll_mode_none; if (scroll_modes & LIBINPUT_CONFIG_SCROLL_2FG) settings.scroll_mode |= mir_touchpad_scroll_mode_two_finger_scroll; if (scroll_modes & LIBINPUT_CONFIG_SCROLL_EDGE) settings.scroll_mode |= mir_touchpad_scroll_mode_edge_scroll; if (scroll_modes & LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) settings.scroll_mode |= mir_touchpad_scroll_mode_button_down_scroll; settings.tap_to_click = libinput_device_config_tap_get_enabled(dev) == LIBINPUT_CONFIG_TAP_ENABLED; settings.disable_while_typing = libinput_device_config_dwt_get_enabled(dev) == LIBINPUT_CONFIG_DWT_ENABLED; settings.disable_with_mouse = libinput_device_config_send_events_get_mode(dev) == LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE; settings.middle_mouse_button_emulation = libinput_device_config_middle_emulation_get_enabled(dev) == LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; return settings; } void mie::LibInputDevice::apply_settings(mi::TouchpadSettings const& settings) { auto dev = device(); uint32_t click_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE; if (settings.click_mode & mir_touchpad_click_mode_area_to_click) click_method |= LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; if (settings.click_mode & mir_touchpad_click_mode_finger_count) click_method |= LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER; uint32_t scroll_method = LIBINPUT_CONFIG_CLICK_METHOD_NONE; if (settings.scroll_mode & mir_touchpad_scroll_mode_button_down_scroll) { scroll_method |= LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN; libinput_device_config_scroll_set_button(dev, settings.button_down_scroll_button); } if (settings.scroll_mode & mir_touchpad_scroll_mode_edge_scroll) scroll_method |= LIBINPUT_CONFIG_SCROLL_EDGE; if (settings.scroll_mode & mir_touchpad_scroll_mode_two_finger_scroll) scroll_method |= LIBINPUT_CONFIG_SCROLL_2FG; libinput_device_config_click_set_method(dev, static_cast(click_method)); libinput_device_config_scroll_set_method(dev, static_cast(scroll_method)); libinput_device_config_tap_set_enabled( dev, settings.tap_to_click ? LIBINPUT_CONFIG_TAP_ENABLED : LIBINPUT_CONFIG_TAP_DISABLED); libinput_device_config_dwt_set_enabled( dev, settings.disable_while_typing ? LIBINPUT_CONFIG_DWT_ENABLED : LIBINPUT_CONFIG_DWT_DISABLED); libinput_device_config_send_events_set_mode(dev, settings.disable_with_mouse ? LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE : LIBINPUT_CONFIG_SEND_EVENTS_ENABLED); libinput_device_config_middle_emulation_set_enabled(dev, settings.middle_mouse_button_emulation ? LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED : LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED); } ./src/platforms/evdev/platform_factory.cpp0000644000004100000410000000611213115234416021231 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #include "platform.h" #include "mir/udev/wrapper.h" #include "mir/fd.h" #include "mir/assert_module_entry_point.h" #include "mir/libname.h" #include #include #include #include #include #include namespace mo = mir::options; namespace mi = mir::input; namespace mu = mir::udev; namespace mie = mi::evdev; namespace { char const* const host_socket_opt = "host-socket"; mir::ModuleProperties const description = { "mir:evdev-input", MIR_VERSION_MAJOR, MIR_VERSION_MINOR, MIR_VERSION_MICRO, mir::libname() }; bool can_open_input_devices() { mu::Enumerator input_enumerator{std::make_shared()}; input_enumerator.match_subsystem("input"); input_enumerator.scan_devices(); bool device_found = false; for (auto& device : input_enumerator) { if (device.devnode() != nullptr) { device_found = true; mir::Fd input_device(::open(device.devnode(), O_RDONLY|O_NONBLOCK)); if (input_device > 0) return true; } } return ! device_found; } } mir::UniqueModulePtr create_input_platform( mo::Option const& /*options*/, std::shared_ptr const& /*emergency_cleanup_registry*/, std::shared_ptr const& input_device_registry, std::shared_ptr const& report) { mir::assert_entry_point_signature(&create_input_platform); return mir::make_module_ptr(input_device_registry, report, std::make_unique()); } void add_input_platform_options( boost::program_options::options_description& /*config*/) { mir::assert_entry_point_signature(&add_input_platform_options); // no options to add yet } mi::PlatformPriority probe_input_platform( mo::Option const& options) { mir::assert_entry_point_signature(&probe_input_platform); if (options.is_set(host_socket_opt)) { return mi::PlatformPriority::unsupported; } if (can_open_input_devices()) return mi::PlatformPriority::supported; return mi::PlatformPriority::unsupported; } mir::ModuleProperties const* describe_input_module() { mir::assert_entry_point_signature(&describe_input_module); return &description; } ./src/platforms/evdev/libinput_device_ptr.h0000644000004100000410000000250413115234416021356 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_INPUT_EVDEV_LIBINPUT_DEVICE_PTR_H_ #define MIR_INPUT_EVDEV_LIBINPUT_DEVICE_PTR_H_ #include struct libinput_device; struct libinput; namespace mir { namespace input { namespace evdev { struct LibInputDeviceDeleter { LibInputDeviceDeleter(std::shared_ptr<::libinput> const& lib) : lib{lib} {} void operator()(::libinput_device* device) const; std::shared_ptr<::libinput> const lib; }; using LibInputDevicePtr = std::unique_ptr; LibInputDevicePtr make_libinput_device(std::shared_ptr<::libinput> const& lib, libinput_device* dev); } } } #endif ./src/platforms/evdev/evdev_device_detection.cpp0000644000004100000410000001363213115234416022351 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #include "evdev_device_detection.h" #include "mir/fd.h" #include #include #include #include #include #include #include #include #include namespace mi = mir::input; namespace mie = mi::evdev; namespace { struct DeviceInfo { DeviceInfo(mir::Fd const& fd); uint8_t key_bit_mask[(KEY_MAX+1)/8]; uint8_t abs_bit_mask[(ABS_MAX+1)/8]; uint8_t rel_bit_mask[(REL_MAX+1)/8]; uint8_t sw_bit_mask[(SW_MAX+1)/8]; uint8_t property_bit_mask[(INPUT_PROP_MAX+1)/8]; }; DeviceInfo::DeviceInfo(mir::Fd const& fd) { auto const get_bitmask = [&](int bit, size_t size, uint8_t* buf) -> void { if(ioctl(fd, EVIOCGBIT(bit, size), buf) < 1) BOOST_THROW_EXCEPTION( std::system_error(std::error_code(errno, std::system_category()), "Failed to query input device")); }; get_bitmask(EV_KEY, sizeof key_bit_mask, key_bit_mask); get_bitmask(EV_REL, sizeof rel_bit_mask, rel_bit_mask); get_bitmask(EV_ABS, sizeof abs_bit_mask, abs_bit_mask); get_bitmask(EV_SW, sizeof sw_bit_mask, sw_bit_mask); if (ioctl(fd, EVIOCGPROP(sizeof property_bit_mask), property_bit_mask) < 1) BOOST_THROW_EXCEPTION( std::system_error(std::error_code(errno, std::system_category()), "Failed to query devices properties")); } constexpr size_t end_index_of(size_t bit) { return (bit + 7) / 8; } constexpr size_t start_index_of(size_t bit) { return bit / 8; } inline bool get_bit(uint8_t const* array, size_t bit) { return array[bit / 8] & (1 << (bit % 8)); } inline size_t get_num_bits(uint8_t const* array, std::initializer_list bits) { size_t ret = 0; for (auto const bit : bits) ret += get_bit(array, bit); return ret; } bool contains_non_zero(uint8_t const* array, int first, int last) { return std::any_of(array + first, array + last, [](uint8_t item) { return item!=0;}); } bool all_bits_set(uint8_t const* array, int first, int last) { for (auto index = first; index != last; ++ index) { if (!get_bit(array, index)) return false; } return true; } mi::DeviceCapabilities evaluate_device_capabilities(DeviceInfo const& info) { mi::DeviceCapabilities caps; bool const has_keys = contains_non_zero(info.key_bit_mask, 0, end_index_of(BTN_MISC)) || contains_non_zero(info.key_bit_mask, start_index_of(KEY_OK), sizeof info.key_bit_mask); bool const has_alpha_numeric = all_bits_set(info.key_bit_mask, KEY_1, KEY_EQUAL) && all_bits_set(info.key_bit_mask, KEY_Q, KEY_P) && all_bits_set(info.key_bit_mask, KEY_A, KEY_L) && all_bits_set(info.key_bit_mask, KEY_Z, KEY_M); bool const has_gamepad_buttons = contains_non_zero(info.key_bit_mask, start_index_of(BTN_MISC), end_index_of(BTN_MOUSE)) || contains_non_zero(info.key_bit_mask, start_index_of(BTN_JOYSTICK), end_index_of(BTN_DIGI)); bool const has_coordinates = get_bit(info.abs_bit_mask, ABS_X) && get_bit(info.abs_bit_mask, ABS_Y); bool const has_mt_coordinates = get_bit(info.abs_bit_mask, ABS_MT_POSITION_X) && get_bit(info.abs_bit_mask, ABS_MT_POSITION_Y); bool const is_direct = get_bit(info.property_bit_mask, INPUT_PROP_DIRECT); bool const finger_but_no_pen = get_bit(info.key_bit_mask, BTN_TOOL_FINGER) && !get_bit(info.key_bit_mask, BTN_TOOL_PEN); bool const has_touch = get_bit(info.key_bit_mask, BTN_TOUCH); bool const is_mouse = get_bit(info.key_bit_mask, BTN_MOUSE) && get_bit(info.rel_bit_mask, REL_X) && get_bit(info.rel_bit_mask, REL_Y); bool const is_touchpad = finger_but_no_pen && !is_direct && (has_coordinates || has_mt_coordinates); bool const has_joystick_axis = 0 < get_num_bits( info.abs_bit_mask, {ABS_Z, ABS_RX, ABS_RY, ABS_RZ, ABS_THROTTLE, ABS_RUDDER, ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y, ABS_HAT3X, ABS_HAT3Y, ABS_TILT_X, ABS_TILT_Y }); if (has_keys || has_gamepad_buttons) caps |= mi::DeviceCapability::keyboard; if (has_alpha_numeric) caps |= mi::DeviceCapability::alpha_numeric; if (is_mouse) caps |= mi::DeviceCapability::pointer; if (is_touchpad) caps |= mi::DeviceCapability::touchpad | mi::DeviceCapability::pointer; else if (has_touch && ((has_mt_coordinates && !has_gamepad_buttons) || has_coordinates)) caps |= mi::DeviceCapability::touchscreen; if (has_joystick_axis || (!has_touch && has_coordinates)) caps |= mi::DeviceCapability::joystick; if (has_gamepad_buttons) caps |= mi::DeviceCapability::gamepad; return caps; } } mi::DeviceCapabilities mie::detect_device_capabilities(char const* device) { mir::Fd input_device(::open(device, O_RDONLY|O_NONBLOCK)); if (input_device < 0) BOOST_THROW_EXCEPTION( std::system_error(std::error_code(errno, std::system_category()), "Failed to open input device")); DeviceInfo info(input_device); return evaluate_device_capabilities(info); } ./src/platforms/evdev/platform.cpp0000644000004100000410000001343713115234664017517 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #include "platform.h" #include "libinput_device.h" #include "libinput_ptr.h" #include "mir/udev/wrapper.h" #include "mir/dispatch/dispatchable.h" #include "mir/dispatch/readable_fd.h" #include "mir/dispatch/multiplexing_dispatchable.h" #include "mir/module_properties.h" #include "mir/assert_module_entry_point.h" #include "mir/input/input_device_registry.h" #include "mir/input/input_device.h" #include "mir/input/input_report.h" #include "mir/fd.h" #include "mir/raii.h" #define MIR_LOG_COMPONENT "evdev-input" #include "mir/log.h" #include #include #include #include namespace mi = mir::input; namespace md = mir::dispatch; namespace mu = mir::udev; namespace mie = mi::evdev; namespace { std::string describe(libinput_device* dev) { auto const udev_dev = mir::raii::deleter_for(libinput_device_get_udev_device(dev), &udev_device_unref); std::string desc(udev_device_get_devnode(udev_dev.get())); char const * const model = udev_device_get_property_value(udev_dev.get(), "ID_MODEL"); if (model) desc += ": " + std::string(model); // Yes, we could use std::replace but this will compile smaller and faster for (auto &c : desc) if (c == '_') c = ' '; return desc; } } // namespace mie::Platform::Platform(std::shared_ptr const& registry, std::shared_ptr const& report, std::unique_ptr&& udev_context) : report(report), udev_context(std::move(udev_context)), input_device_registry(registry), platform_dispatchable{std::make_shared()} { } std::shared_ptr mie::Platform::dispatchable() { return platform_dispatchable; } void mie::Platform::start() { lib = make_libinput(udev_context->ctx()); libinput_dispatchable = std::make_shared( Fd{IntOwnedFd{libinput_get_fd(lib.get())}}, [this]{process_input_events();} ); platform_dispatchable->add_watch(libinput_dispatchable); process_input_events(); } void mie::Platform::process_input_events() { int status = libinput_dispatch(lib.get()); if (status != 0) BOOST_THROW_EXCEPTION(boost::enable_error_info(std::runtime_error("libinput_dispatch_failed")) << boost::errinfo_errno(-status)); using EventType = std::unique_ptr; auto next_event = [lilib=lib.get()] { return EventType(libinput_get_event(lilib), libinput_event_destroy); }; while(auto ev = next_event()) { auto type = libinput_event_get_type(ev.get()); auto device = libinput_event_get_device(ev.get()); if (type == LIBINPUT_EVENT_DEVICE_ADDED) { device_added(device); } else if(type == LIBINPUT_EVENT_DEVICE_REMOVED) { device_removed(device); } else { auto dev = find_device( libinput_device_get_device_group(device)); if (dev != end(devices)) (*dev)->process_event(ev.get()); } } } void mie::Platform::device_added(libinput_device* dev) { auto device_ptr = make_libinput_device(lib, dev); log_info("Added %s", describe(dev).c_str()); auto device_it = find_device(libinput_device_get_device_group(device_ptr.get())); if (end(devices) != device_it) { (*device_it)->add_device_of_group(move(device_ptr)); log_debug("Device %s is part of an already opened device group", libinput_device_get_sysname(dev)); return; } try { devices.emplace_back(std::make_shared(report, move(device_ptr))); input_device_registry->add_device(devices.back()); report->opened_input_device(libinput_device_get_sysname(dev), "evdev-input"); } catch(...) { mir::log_error("Failure opening device %s", libinput_device_get_sysname(dev)); report->failed_to_open_input_device(libinput_device_get_sysname(dev), "evdev-input"); } } void mie::Platform::device_removed(libinput_device* dev) { auto known_device_pos = find_device(libinput_device_get_device_group(dev)); if (known_device_pos == end(devices)) return; input_device_registry->remove_device(*known_device_pos); devices.erase(known_device_pos); log_info("Removed %s", describe(dev).c_str()); } auto mie::Platform::find_device(libinput_device_group const* devgroup) -> decltype(devices)::iterator { if (devgroup == nullptr) return end(devices); return std::find_if( begin(devices), end(devices), [devgroup](auto const& item) { return devgroup == item->group(); } ); } void mie::Platform::stop() { platform_dispatchable->remove_watch(libinput_dispatchable); while (!devices.empty()) { input_device_registry->remove_device(devices.back()); devices.pop_back(); } libinput_dispatchable.reset(); lib.reset(); } ./src/platforms/evdev/libinput_device_ptr.cpp0000644000004100000410000000220513115234416021707 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #include "libinput.h" #include "libinput_device_ptr.h" namespace mie = mir::input::evdev; void mie::LibInputDeviceDeleter::operator()(::libinput_device* device) const { libinput_device_unref(device); } mie::LibInputDevicePtr mie::make_libinput_device(std::shared_ptr const& lib, libinput_device* dev) { auto ret = mie::LibInputDevicePtr(dev, lib); if (ret) libinput_device_ref(ret.get()); return ret; } ./src/platforms/evdev/platform.h0000644000004100000410000000446613115234416017161 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_INPUT_EVDEV_PLATFORM_H_ #define MIR_INPUT_EVDEV_PLATFORM_H_ #include "libinput_ptr.h" #include "libinput_device_ptr.h" #include "mir/input/platform.h" #include struct libinput_device_group; struct libinput_device; namespace mir { namespace udev { class Device; class Monitor; class Context; } namespace dispatch { class MultiplexingDispatchable; class ReadableFd; } namespace input { class InputDeviceRegistry; namespace evdev { struct MonitorDispatchable; class LibInputDevice; class Platform : public input::Platform { public: Platform(std::shared_ptr const& registry, std::shared_ptr const& report, std::unique_ptr&& udev_context); std::shared_ptr dispatchable() override; void start() override; void stop() override; private: void scan_for_devices(); void device_added(libinput_device* dev); void device_removed(libinput_device* dev); void process_input_events(); std::shared_ptr create_device(udev::Device const& dev) const; std::shared_ptr const report; std::shared_ptr const udev_context; std::shared_ptr const input_device_registry; std::shared_ptr const platform_dispatchable; std::shared_ptr<::libinput> lib; std::shared_ptr libinput_dispatchable; std::vector> devices; auto find_device(libinput_device_group const* group) -> decltype(devices)::iterator; }; } } } #endif ./src/platforms/evdev/button_utils.cpp0000644000004100000410000000320513115234416020411 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #include "button_utils.h" #include "boost/throw_exception.hpp" #include "linux/input.h" #include namespace mie = mir::input::evdev; MirPointerButton mie::to_pointer_button(int button, MirPointerHandedness handedness) { switch(button) { case BTN_LEFT: return (handedness == mir_pointer_handedness_right) ? mir_pointer_button_primary : mir_pointer_button_secondary; case BTN_RIGHT: return (handedness == mir_pointer_handedness_right) ? mir_pointer_button_secondary : mir_pointer_button_primary; case BTN_MIDDLE: return mir_pointer_button_tertiary; case BTN_BACK: return mir_pointer_button_back; case BTN_FORWARD: return mir_pointer_button_forward; case BTN_SIDE: return mir_pointer_button_side; case BTN_EXTRA: return mir_pointer_button_extra; case BTN_TASK: return mir_pointer_button_task; } BOOST_THROW_EXCEPTION(std::runtime_error("Invalid mouse button")); } ./src/platforms/evdev/evdev_device_detection.h0000644000004100000410000000173413115234416022016 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_INPUT_EVDEV_DEVICE_DETECTION_H_ #define MIR_INPUT_EVDEV_DEVICE_DETECTION_H_ #include "mir/input/device_capability.h" namespace mir { namespace input { namespace evdev { input::DeviceCapabilities detect_device_capabilities(char const* device); } } } #endif ./src/platforms/evdev/button_utils.h0000644000004100000410000000174613115234416020066 0ustar www-datawww-data/* * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Authored by: Andreas Pokorny */ #ifndef MIR_INPUT_EVDEV_BUTTON_UTILS_H_ #define MIR_INPUT_EVDEV_BUTTON_UTILS_H_ #include "mir_toolkit/event.h" #include "mir_toolkit/mir_input_device.h" namespace mir { namespace input { namespace evdev { MirPointerButton to_pointer_button(int button, MirPointerHandedness handedness); } } } #endif ./src/platforms/eglstream-kms/0000755000004100000410000000000013115234667016624 5ustar www-datawww-data./src/platforms/eglstream-kms/CMakeLists.txt0000644000004100000410000000021413115234664021356 0ustar www-datawww-datainclude_directories(include/) add_definitions(-DMIR_LOG_COMPONENT_FALLBACK="eglstream") add_subdirectory(client/) add_subdirectory(server/) ./src/platforms/eglstream-kms/include/0000755000004100000410000000000013115234667020247 5ustar www-datawww-data./src/platforms/eglstream-kms/include/native_buffer.h0000644000004100000410000000220713115234664023235 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_GRAPHICS_MESA_NATIVE_BUFFER_H_ #define MIR_GRAPHICS_MESA_NATIVE_BUFFER_H_ #include "mir_toolkit/mir_native_buffer.h" #include "mir/graphics/native_buffer.h" namespace mir { namespace graphics { namespace eglstream { //TODO: a class that allows access to a mgc::ShmFile seems like the appropriate internal type. struct NativeBuffer : graphics::NativeBuffer, MirBufferPackage { }; } } } #endif /* MIR_GRAPHICS_MESA_NATIVE_BUFFER_H_ */ ./src/platforms/eglstream-kms/client/0000755000004100000410000000000013115234667020102 5ustar www-datawww-data./src/platforms/eglstream-kms/client/CMakeLists.txt0000644000004100000410000000167213115234664022645 0ustar www-datawww-datainclude_directories(${client_common_include_dirs}) include_directories( ${DRM_INCLUDE_DIRS} ${EGL_INCLUDE_DIRS} ) set(symbol_map ${CMAKE_CURRENT_SOURCE_DIR}/symbols.map) add_library(mirclientplatformeglstreamobjects OBJECT client_platform_factory.cpp client_platform.cpp client_buffer_factory.cpp client_buffer.cpp ) add_library(mirclientplatformeglstream MODULE $ ) set_target_properties( mirclientplatformeglstream PROPERTIES OUTPUT_NAME eglstream LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/client-modules PREFIX "" SUFFIX ".so.${MIR_CLIENT_PLATFORM_ABI}" LINK_FLAGS "-Wl,--version-script,${symbol_map}" LINK_DEPENDS ${symbol_map} ) target_link_libraries(mirclientplatformeglstream mirclient client_platform_common ${DRM_LDFLAGS} ${DRM_LIBRARIES} ) install(TARGETS mirclientplatformeglstream LIBRARY DESTINATION ${MIR_CLIENT_PLATFORM_PATH}) ./src/platforms/eglstream-kms/client/symbols.map0000644000004100000410000000015413115234664022266 0ustar www-datawww-dataMIR_CLIENT_PLATFORM_5 { global: create_client_platform; is_appropriate_module; local: *; }; ./src/platforms/eglstream-kms/client/client_platform.h0000644000004100000410000000375413115234664023443 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_CLIENT_EGLSTREAM_CLIENT_PLATFORM_H_ #define MIR_CLIENT_EGLSTREAM_CLIENT_PLATFORM_H_ #include "mir/client_platform.h" namespace mir { namespace client { namespace eglstream { class ClientPlatform : public client::ClientPlatform { public: ClientPlatform(ClientContext* const); MirPlatformType platform_type() const override; void populate(MirPlatformPackage& package) const override; MirPlatformMessage* platform_operation(MirPlatformMessage const* request) override; std::shared_ptr create_buffer_factory() override; void* request_interface(char const* name, int version) override; std::shared_ptr create_egl_native_window(EGLNativeSurface *surface) override; void use_egl_native_window(std::shared_ptr native_window, EGLNativeSurface* surface) override; std::shared_ptr create_egl_native_display() override; MirNativeBuffer* convert_native_buffer(graphics::NativeBuffer*) const override; MirPixelFormat get_egl_pixel_format(EGLDisplay, EGLConfig) const override; uint32_t native_format_for(MirPixelFormat) const override; uint32_t native_flags_for(MirBufferUsage, mir::geometry::Size) const override; }; } } } #endif /* MIR_CLIENT_EGLSTREAM_CLIENT_PLATFORM_H_ */ ./src/platforms/eglstream-kms/client/client_platform.cpp0000644000004100000410000000546513115234664023777 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #include "mir_toolkit/mir_client_library.h" #include "client_platform.h" #include "client_buffer_factory.h" #include "mir/client_buffer_factory.h" #include "mir/client_context.h" #include "native_buffer.h" #include #include namespace mcl=mir::client; namespace mcle=mir::client::eglstream; namespace geom=mir::geometry; mcle::ClientPlatform::ClientPlatform(ClientContext* const) { } std::shared_ptr mcle::ClientPlatform::create_buffer_factory() { return std::make_shared(); } void mcle::ClientPlatform::use_egl_native_window(std::shared_ptr /*native_window*/, EGLNativeSurface* /*surface*/) { } std::shared_ptr mcle::ClientPlatform::create_egl_native_window(EGLNativeSurface* /*surface*/) { return nullptr; } std::shared_ptr mcle::ClientPlatform::create_egl_native_display() { return nullptr; } MirPlatformType mcle::ClientPlatform::platform_type() const { return mir_platform_type_eglstream; } void mcle::ClientPlatform::populate(MirPlatformPackage& /*package*/) const { } MirPlatformMessage* mcle::ClientPlatform::platform_operation(MirPlatformMessage const* /*msg*/) { return nullptr; } MirNativeBuffer* mcle::ClientPlatform::convert_native_buffer(graphics::NativeBuffer* buf) const { if (auto native = dynamic_cast(buf)) return native; BOOST_THROW_EXCEPTION(std::invalid_argument("could not convert to NativeBuffer")); } MirPixelFormat mcle::ClientPlatform::get_egl_pixel_format( EGLDisplay /*disp*/, EGLConfig /*conf*/) const { BOOST_THROW_EXCEPTION(std::runtime_error{"EGL support unimplemented"}); } void* mcle::ClientPlatform::request_interface(char const*, int) { return nullptr; } uint32_t mcle::ClientPlatform::native_format_for(MirPixelFormat) const { BOOST_THROW_EXCEPTION(std::runtime_error{"no buffer support"}); } uint32_t mcle::ClientPlatform::native_flags_for(MirBufferUsage, mir::geometry::Size) const { BOOST_THROW_EXCEPTION(std::runtime_error{"no buffer support"}); } ./src/platforms/eglstream-kms/client/client_buffer.cpp0000644000004100000410000001006413115234664023413 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #include "mir_toolkit/mir_client_library.h" #include "client_buffer.h" #include #include #include #include #include namespace mcl=mir::client; namespace mcle=mir::client::eglstream; namespace geom=mir::geometry; namespace { struct ShmMemoryRegion : mcl::MemoryRegion { ShmMemoryRegion( int buffer_fd, geom::Size const& size_param, geom::Stride stride_param, MirPixelFormat format_param) : size_in_bytes{size_param.height.as_uint32_t() * stride_param.as_uint32_t()} { static off_t const map_offset = 0; width = size_param.width; height = size_param.height; stride = stride_param; format = format_param; void* map = mmap( nullptr, size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, buffer_fd, map_offset); if (map == MAP_FAILED) { BOOST_THROW_EXCEPTION(( std::system_error{errno, std::system_category(), "Failed to mmap buffer"})); } vaddr = std::shared_ptr(static_cast(map), [](auto*) noexcept {}); } ~ShmMemoryRegion() { munmap(vaddr.get(), size_in_bytes); } size_t const size_in_bytes; }; std::shared_ptr to_native_buffer(MirBufferPackage const& package) { auto buffer = std::make_shared(); *static_cast(buffer.get()) = package; return buffer; } } mcle::ClientBuffer::ClientBuffer( std::shared_ptr const& package, geom::Size size, MirPixelFormat pf) : creation_package{to_native_buffer(*package)}, rect({geom::Point{0, 0}, size}), buffer_pf{pf} { if (package->fd_items != 1) { BOOST_THROW_EXCEPTION(std::runtime_error( "Buffer package does not contain the expected number of fd items")); } } mcle::ClientBuffer::~ClientBuffer() noexcept { // TODO (@raof): Error reporting? It should not be possible for this to fail; if it does, // something's seriously wrong. close(creation_package->fd[0]); } std::shared_ptr mcle::ClientBuffer::secure_for_cpu_write() { int const buffer_fd = creation_package->fd[0]; return std::make_shared( buffer_fd, size(), stride(), pixel_format()); } geom::Size mcle::ClientBuffer::size() const { return rect.size; } geom::Stride mcle::ClientBuffer::stride() const { return geom::Stride{creation_package->stride}; } MirPixelFormat mcle::ClientBuffer::pixel_format() const { return buffer_pf; } std::shared_ptr mcle::ClientBuffer::native_buffer_handle() const { creation_package->age = age(); return creation_package; } void mcle::ClientBuffer::update_from(MirBufferPackage const&) { } void mcle::ClientBuffer::fill_update_msg(MirBufferPackage& package) { package.data_items = 0; package.fd_items = 0; } MirBufferPackage* mcle::ClientBuffer::package() const { return creation_package.get(); } void mcle::ClientBuffer::egl_image_creation_parameters(EGLenum*, EGLClientBuffer*, EGLint**) { BOOST_THROW_EXCEPTION(std::invalid_argument("not implemented yet")); } ./src/platforms/eglstream-kms/client/client_buffer.h0000644000004100000410000000363613115234664023067 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Christopher James Halse Rogers */ #ifndef MIR_CLIENT_EGLSTREAM_CLIENT_BUFFER_H_ #define MIR_CLIENT_EGLSTREAM_CLIENT_BUFFER_H_ #include "mir/aging_buffer.h" #include "mir_toolkit/mir_client_library.h" #include "mir/geometry/rectangle.h" #include "native_buffer.h" #include namespace mir { namespace client { namespace eglstream { class ClientBuffer : public AgingBuffer { public: ClientBuffer( std::shared_ptr const& buffer_package, geometry::Size size, MirPixelFormat pf); ~ClientBuffer() noexcept; std::shared_ptr secure_for_cpu_write(); geometry::Size size() const; geometry::Stride stride() const; MirPixelFormat pixel_format() const; std::shared_ptr native_buffer_handle() const; void update_from(MirBufferPackage const&); void fill_update_msg(MirBufferPackage&); MirBufferPackage* package() const; void egl_image_creation_parameters(EGLenum*, EGLClientBuffer*, EGLint**); private: std::shared_ptr const creation_package; geometry::Rectangle const rect; MirPixelFormat const buffer_pf; }; } } } #endif /* MIR_CLIENT_EGLSTREAM_CLIENT_BUFFER_H_ */ ./src/platforms/eglstream-kms/client/client_buffer_factory.h0000644000004100000410000000271113115234664024607 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Christopher James Halse Rogers */ #ifndef MIR_CLIENT_EGLSTREAM_CLIENT_BUFFER_FACTORY_H_ #define MIR_CLIENT_EGLSTREAM_CLIENT_BUFFER_FACTORY_H_ #include "mir/client_buffer_factory.h" namespace mir { namespace client { namespace eglstream { class ClientBufferFactory : public client::ClientBufferFactory { public: ClientBufferFactory() = default; std::shared_ptr create_buffer( std::shared_ptr const& package, geometry::Size size, MirPixelFormat pf) override; std::shared_ptr create_buffer( std::shared_ptr const& package, unsigned int native_pf, unsigned int native_flags) override; }; } } } #endif /* MIR_CLIENT_EGLSTREAM_CLIENT_BUFFER_FACTORY_H_ */ ./src/platforms/eglstream-kms/client/client_buffer_factory.cpp0000644000004100000410000000274213115234664025146 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Christopher James Halse Rogers */ #include "client_buffer_factory.h" #include "client_buffer.h" #include #include namespace mcl=mir::client; namespace mcle=mir::client::eglstream; std::shared_ptr mcle::ClientBufferFactory::create_buffer( std::shared_ptr const& package, geometry::Size /*size*/, MirPixelFormat pf) { return std::make_shared( package, geometry::Size{package->width, package->height}, pf); } std::shared_ptr mcle::ClientBufferFactory::create_buffer( std::shared_ptr const&, unsigned int, unsigned int) { BOOST_THROW_EXCEPTION(std::runtime_error("no native buffers on eglstream platform")); } ./src/platforms/eglstream-kms/client/client_platform_factory.cpp0000644000004100000410000000356613115234664025526 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #include "mir/client_platform_factory.h" #include "client_platform.h" #include "mir_toolkit/client_types.h" #include "mir/client_context.h" #include "mir/egl_native_display_container.h" #include "mir/assert_module_entry_point.h" #include "mir/module_deleter.h" #include "mir_toolkit/mir_client_library.h" #include namespace mcl = mir::client; namespace mcle = mcl::eglstream; namespace { bool is_eglstream_server(mcl::ClientContext* context) { MirModuleProperties module_properties; context->populate_graphics_module(module_properties); return strncmp(module_properties.name, "mir:eglstream", strlen("mir:eglstream")) == 0; } } mir::UniqueModulePtr create_client_platform( mcl::ClientContext* context, std::shared_ptr const& /*logger*/) { mir::assert_entry_point_signature(&create_client_platform); return mir::make_module_ptr(context); } bool is_appropriate_module(mcl::ClientContext* context) { mir::assert_entry_point_signature(&is_appropriate_module); return is_eglstream_server(context); } ./src/platforms/eglstream-kms/server/0000755000004100000410000000000013115234667020132 5ustar www-datawww-data./src/platforms/eglstream-kms/server/CMakeLists.txt0000644000004100000410000000271113115234664022670 0ustar www-datawww-datainclude_directories( ${server_common_include_dirs} ${DRM_INCLUDE_DIRS} ${GBM_INCLUDE_DIRS} ${EGL_INCLUDE_DIRS} ${GLESv2_INCLUDE_DIRS} ${EPOXY_INCLUDE_DIRS} ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/symbols.map.in ${CMAKE_CURRENT_BINARY_DIR}/symbols.map ) set(symbol_map ${CMAKE_CURRENT_BINARY_DIR}/symbols.map) add_library(mirplatformgraphicseglstreamkmsobjects OBJECT platform_symbols.cpp platform.cpp buffer_allocator.cpp buffer_allocator.h display.cpp display.h kms_display_configuration.h kms_display_configuration.cpp egl_output.h egl_output.cpp software_buffer.cpp ) add_library(mirplatformgraphicseglstreamkms MODULE $ ) target_link_libraries( mirplatformgraphicseglstreamkms PRIVATE mirplatform server_platform_common kms_utils ${Boost_PROGRAM_OPTIONS_LIBRARY} ${DRM_LDFLAGS} ${DRM_LIBRARIES} ${EGL_LDFLAGS} ${EGL_LIBRARIES} ${GLESv2_LDFLAGS} ${GLESv2_LIBRARIES} ${EPOXY_LDFLAGS} ${EPOXY_LIBRARIES} ) set_target_properties( mirplatformgraphicseglstreamkms PROPERTIES OUTPUT_NAME graphics-eglstream-kms LIBRARY_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/server-modules PREFIX "" SUFFIX ".so.${MIR_SERVER_GRAPHICS_PLATFORM_ABI}" LINK_FLAGS "-Wl,--exclude-libs=ALL -Wl,--version-script,${symbol_map}" LINK_DEPENDS ${symbol_map} ) install(TARGETS mirplatformgraphicseglstreamkms LIBRARY DESTINATION ${MIR_SERVER_PLATFORM_PATH}) ./src/platforms/eglstream-kms/server/buffer_allocator.h0000644000004100000410000000305013115234664023607 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_PLATFORMS_EGLSTREAM_BUFFER_ALLOCATOR_ #define MIR_PLATFORMS_EGLSTREAM_BUFFER_ALLOCATOR_ #include "mir/graphics/graphic_buffer_allocator.h" #include "mir/graphics/buffer_id.h" #include namespace mir { namespace graphics { namespace eglstream { class BufferAllocator: public graphics::GraphicBufferAllocator { public: BufferAllocator(); std::shared_ptr alloc_buffer(graphics::BufferProperties const& buffer_properties) override; std::shared_ptr alloc_software_buffer(geometry::Size size, MirPixelFormat format) override; std::shared_ptr alloc_buffer( geometry::Size size, uint32_t native_format, uint32_t native_flags) override; std::vector supported_pixel_formats() override; }; } } } #endif // MIR_PLATFORMS_EGLSTREAM_BUFFER_ALLOCATOR_ ./src/platforms/eglstream-kms/server/kms_display_configuration.cpp0000644000004100000410000002450313115234664026105 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #include #include "kms_display_configuration.h" #include "kms-utils/drm_mode_resources.h" #include "mir/graphics/pixel_format_utils.h" #include "mir/graphics/egl_error.h" #include #include #include #include #include namespace mg = mir::graphics; namespace mge = mir::graphics::eglstream; namespace mgk = mir::graphics::kms; namespace geom = mir::geometry; namespace { bool kms_modes_are_equal(drmModeModeInfo const& info1, drmModeModeInfo const& info2) { return (info1.clock == info2.clock && info1.hdisplay == info2.hdisplay && info1.hsync_start == info2.hsync_start && info1.hsync_end == info2.hsync_end && info1.htotal == info2.htotal && info1.hskew == info2.hskew && info1.vdisplay == info2.vdisplay && info1.vsync_start == info2.vsync_start && info1.vsync_end == info2.vsync_end && info1.vtotal == info2.vtotal); } double calculate_vrefresh_hz(drmModeModeInfo const& mode) { if (mode.htotal == 0 || mode.vtotal == 0) return 0.0; /* mode.clock is in KHz */ double hz = (mode.clock * 100000LL / ((long)mode.htotal * (long)mode.vtotal) ) / 100.0; // Actually we don't need floating point at all for this... // TODO: Consider converting our structs to fixed-point ints return hz; } mg::DisplayConfigurationOutputType kms_connector_type_to_output_type(uint32_t connector_type) { return static_cast(connector_type); } std::vector> create_outputs(int drm_fd, EGLDisplay display) { mgk::DRMModeResources resources{drm_fd}; std::vector> outputs; for (auto const& connector : resources.connectors()) { EGLOutputPortEXT port; int num_ports; EGLAttrib const select_connector[] = { EGL_DRM_CONNECTOR_EXT, static_cast(connector->connector_id), EGL_NONE }; if (eglGetOutputPortsEXT(display, select_connector, &port, 1, &num_ports) != EGL_TRUE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to find EGLOutputPort corresponding to DRM connector")); } if (num_ports != 1) { BOOST_THROW_EXCEPTION(std::runtime_error("Failed to find EGLOutputPort corresponding to DRM connector")); } outputs.push_back(std::make_shared(drm_fd, display, port)); auto& output = outputs.back(); // TODO: This should all be owned by mgek::EGLOutput output->id = mg::DisplayConfigurationOutputId{static_cast(connector->connector_id)}; output->card_id = mg::DisplayConfigurationCardId{0}; output->type = kms_connector_type_to_output_type(connector->connector_type); output->physical_size_mm = geom::Size{connector->mmWidth, connector->mmHeight}; output->connected = connector->connection == DRM_MODE_CONNECTED; output->pixel_formats = { mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888 }; uint32_t const invalid_mode_index = std::numeric_limits::max(); output->current_mode_index = invalid_mode_index; output->preferred_mode_index = invalid_mode_index; /* Get information about the current mode */ mgk::DRMModeCrtcUPtr current_crtc; if (connector->encoder_id) { auto encoder = mgk::get_encoder(drm_fd, connector->encoder_id); if (encoder->crtc_id) { current_crtc = mgk::get_crtc(drm_fd, encoder->crtc_id); } } /* Add all the available modes and find the current and preferred one */ for (int m = 0; m < connector->count_modes; m++) { drmModeModeInfo &mode_info = connector->modes[m]; geom::Size size{mode_info.hdisplay, mode_info.vdisplay}; double vrefresh_hz = calculate_vrefresh_hz(mode_info); output->modes.push_back({size, vrefresh_hz}); if (current_crtc && kms_modes_are_equal(mode_info, current_crtc->mode)) output->current_mode_index = m; if ((mode_info.type & DRM_MODE_TYPE_PREFERRED) == DRM_MODE_TYPE_PREFERRED) output->preferred_mode_index = m; } output->current_format = mir_pixel_format_xrgb_8888; output->power_mode = mir_power_mode_on; output->orientation = mir_orientation_normal; output->scale = 1.0f; output->form_factor = mir_form_factor_monitor; output->used = false; } return outputs; } mg::DisplayConfigurationCard create_card(int drm_fd) { mgk::DRMModeResources resources{drm_fd}; size_t max_outputs = std::min(resources.num_crtcs(), resources.num_connectors()); return {mg::DisplayConfigurationCardId{0}, max_outputs}; } } mge::KMSDisplayConfiguration::KMSDisplayConfiguration(int drm_fd, EGLDisplay dpy) : drm_fd{drm_fd}, card{create_card(drm_fd)}, outputs{create_outputs(drm_fd, dpy)} { update(); } mge::KMSDisplayConfiguration::KMSDisplayConfiguration( KMSDisplayConfiguration const& conf) : mg::DisplayConfiguration(), drm_fd{conf.drm_fd}, card(conf.card), outputs{conf.outputs} { } void mge::KMSDisplayConfiguration::for_each_card( std::function f) const { f(card); } void mge::KMSDisplayConfiguration::for_each_output( std::function f) const { for (auto const& output : outputs) f(*output); } void mge::KMSDisplayConfiguration::for_each_output( std::function f) { for (auto& output : outputs) { UserDisplayConfigurationOutput user(*output); f(user); } } std::unique_ptr mge::KMSDisplayConfiguration::clone() const { return std::make_unique(*this); } uint32_t mge::KMSDisplayConfiguration::get_kms_connector_id( DisplayConfigurationOutputId id) const { auto iter = find_output_with_id(id); if (iter == outputs.end()) { BOOST_THROW_EXCEPTION( std::out_of_range("Failed to find DisplayConfigurationOutput with provided id")); } return id.as_value(); } size_t mge::KMSDisplayConfiguration::get_kms_mode_index( DisplayConfigurationOutputId id, size_t conf_mode_index) const { auto iter = find_output_with_id(id); if (iter == outputs.end() || conf_mode_index >= (*iter)->modes.size()) { BOOST_THROW_EXCEPTION( std::out_of_range("Failed to find valid mode index for DisplayConfigurationOutput with provided id/mode_index")); } return conf_mode_index; } void mge::KMSDisplayConfiguration::update() { mgk::DRMModeResources resources{drm_fd}; for (auto const& connector : resources.connectors()) { update_output(resources, connector, **find_output_with_id(DisplayConfigurationOutputId(connector->connector_id))); }; } void mge::KMSDisplayConfiguration::for_each_output( std::function const& f) const { for (auto const& output : outputs) { f(*output); } } void mge::KMSDisplayConfiguration::update_output( mgk::DRMModeResources const& resources, mgk::DRMModeConnectorUPtr const& connector, kms::EGLOutput& output) { output.physical_size_mm = geom::Size{connector->mmWidth, connector->mmHeight}; output.connected = connector->connection == DRM_MODE_CONNECTED; uint32_t const invalid_mode_index = std::numeric_limits::max(); output.modes.clear(); output.current_mode_index = invalid_mode_index; drmModeModeInfo* current_mode_info{nullptr}; mgk::DRMModeCrtcUPtr current_crtc; if (connector->encoder_id) { auto encoder = resources.encoder(connector->encoder_id); if (encoder->crtc_id) { current_crtc = resources.crtc(encoder->crtc_id); current_mode_info = ¤t_crtc->mode; } } /* Add all the available modes and find the current and preferred one */ for (int m = 0; m < connector->count_modes; m++) { drmModeModeInfo& mode_info = connector->modes[m]; geom::Size size{mode_info.hdisplay, mode_info.vdisplay}; double vrefresh_hz = calculate_vrefresh_hz(mode_info); output.modes.push_back({size, vrefresh_hz}); if (current_mode_info && kms_modes_are_equal(mode_info, *current_mode_info)) output.current_mode_index = m; if ((mode_info.type & DRM_MODE_TYPE_PREFERRED) == DRM_MODE_TYPE_PREFERRED) output.preferred_mode_index = m; } if (output.modes.empty()) { output.preferred_mode_index = invalid_mode_index; } output.physical_size_mm = geom::Size{connector->mmWidth, connector->mmHeight}; } std::vector>::iterator mge::KMSDisplayConfiguration::find_output_with_id(mg::DisplayConfigurationOutputId id) { return std::find_if( outputs.begin(), outputs.end(), [id](std::shared_ptr const& output) { return output->id == id; }); } std::vector>::const_iterator mge::KMSDisplayConfiguration::find_output_with_id(mg::DisplayConfigurationOutputId id) const { return std::find_if( outputs.begin(), outputs.end(), [id](std::shared_ptr const& output) { return output->id == id; }); } ./src/platforms/eglstream-kms/server/software_buffer.h0000644000004100000410000000257613115234664023475 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #ifndef MIR_PLATFORMS_EGLSTREAM_SOFTWARE_BUFFER_H_ #define MIR_PLATFORMS_EGLSTREAM_SOFTWARE_BUFFER_H_ #include "shm_buffer.h" namespace mir { namespace graphics { namespace common { class ShmFile; } namespace eglstream { class SoftwareBuffer: public common::ShmBuffer { public: SoftwareBuffer( std::unique_ptr shm_file, geometry::Size const& size, MirPixelFormat const& pixel_format); std::shared_ptr native_buffer_handle() const override; private: std::shared_ptr create_native_handle(); std::shared_ptr const native_handle; }; } } } #endif /* MIR_PLATFORMS_EGLSTREAM_SOFTWARE_BUFFER_H_ */ ./src/platforms/eglstream-kms/server/egl_output.h0000644000004100000410000000361413115234664022473 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_GRAPHICS_EGLSTREAM_KMS_OUTPUT_H_ #define MIR_GRAPHICS_EGLSTREAM_KMS_OUTPUT_H_ #include "kms-utils/drm_mode_resources.h" #include "mir/geometry/size.h" #include "mir/geometry/point.h" #include "mir/geometry/displacement.h" #include "mir/graphics/display_configuration.h" #include "mir_toolkit/common.h" #include namespace mir { namespace graphics { namespace eglstream { namespace kms { class EGLOutput : public DisplayConfigurationOutput { public: EGLOutput(int drm_fd, EGLDisplay dpy, EGLOutputPortEXT connector); ~EGLOutput() noexcept(false); void reset(); void configure(size_t kms_mode_index); geometry::Size size() const; int max_refresh_rate() const; EGLOutputLayerEXT output_layer() const; void clear_crtc(); void set_power_mode(MirPowerMode mode); private: void restore_saved_crtc(); int const drm_fd; EGLDisplay display; EGLOutputPortEXT port; EGLOutputLayerEXT layer; graphics::kms::DRMModeConnectorUPtr connector; size_t mode_index; drmModeCrtc saved_crtc; bool using_saved_crtc; int dpms_enum_id; }; } } } } #endif /* MIR_GRAPHICS_EGLSTREAM_KMS_KMS_OUTPUT_H_ */ ./src/platforms/eglstream-kms/server/kms_display_configuration.h0000644000004100000410000000464513115234664025557 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_PLATFORMS_EGLSTREAM_KMS_KMS_DISPLAY_CONFIGURATION_H_ #define MIR_PLATFORMS_EGLSTREAM_KMS_KMS_DISPLAY_CONFIGURATION_H_ #include "egl_output.h" #include "mir/graphics/display_configuration.h" #include namespace mir { namespace graphics { namespace eglstream { class KMSDisplayConfiguration : public DisplayConfiguration { public: KMSDisplayConfiguration(int drm_fd, EGLDisplay dpy); KMSDisplayConfiguration(KMSDisplayConfiguration const& conf); void for_each_card(std::function f) const override; void for_each_output(std::function f) const override; void for_each_output(std::function f) override; std::unique_ptr clone() const override; uint32_t get_kms_connector_id(DisplayConfigurationOutputId id) const; size_t get_kms_mode_index(DisplayConfigurationOutputId id, size_t conf_mode_index) const; void update(); void for_each_output(std::function const& f) const; private: void update_output( graphics::kms::DRMModeResources const& resources, graphics::kms::DRMModeConnectorUPtr const& connector, kms::EGLOutput& output); std::vector>::iterator find_output_with_id(DisplayConfigurationOutputId id); std::vector>::const_iterator find_output_with_id(DisplayConfigurationOutputId id) const; int drm_fd; DisplayConfigurationCard const card; std::vector> outputs; }; } } } #endif // MIR_PLATFORMS_EGLSTREAM_KMS_KMS_DISPLAY_CONFIGURATION_H_ ./src/platforms/eglstream-kms/server/platform.cpp0000644000004100000410000001274013115234664022463 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #include #include "platform.h" #include "buffer_allocator.h" #include "display.h" #include "mir/graphics/platform_ipc_operations.h" #include "mir/graphics/platform_ipc_package.h" #include "mir/graphics/platform_operation_message.h" #include "mir/graphics/buffer_ipc_message.h" #include "native_buffer.h" #include "mir/graphics/egl_error.h" #include #include #include namespace mg = mir::graphics; namespace mge = mir::graphics::eglstream; namespace { // Our copy of eglext.h doesn't have this? int const EGL_DRM_MASTER_FD_EXT{0x333C}; char const* drm_node_for_device(EGLDeviceEXT device) { auto const device_path = eglQueryDeviceStringEXT(device, EGL_DRM_DEVICE_FILE_EXT); if (!device_path) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to determine DRM device node path from EGLDevice")); } return device_path; } } mge::Platform::Platform( EGLDeviceEXT device, std::shared_ptr const& /*emergency_cleanup_registry*/, std::shared_ptr const& /*report*/) : display{EGL_NO_DISPLAY}, drm_node{open(drm_node_for_device(device), O_RDWR | O_CLOEXEC)} { using namespace std::literals; if (drm_node == mir::Fd::invalid) { BOOST_THROW_EXCEPTION(std::system_error( errno, std::system_category(), "Failed to open DRM device "s + drm_node_for_device(device))); } if (drmSetMaster(drm_node)) { BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to acquire DRM master"})); } int const drm_node_attrib[] = { EGL_DRM_MASTER_FD_EXT, static_cast(drm_node), EGL_NONE }; display = eglGetPlatformDisplayEXT(EGL_PLATFORM_DEVICE_EXT, device, drm_node_attrib); if (display == EGL_NO_DISPLAY) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGLDisplay on the EGLDeviceEXT")); } EGLint major{1}; EGLint minor{4}; auto const required_egl_version_major = major; auto const required_egl_version_minor = minor; if (eglInitialize(display, &major, &minor) != EGL_TRUE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to initialise EGL")); } if ((major < required_egl_version_major) || (major == required_egl_version_major && minor < required_egl_version_minor)) { BOOST_THROW_EXCEPTION((std::runtime_error{ "Incompatible EGL version"s + "Wanted 1.4, got " + std::to_string(major) + "." + std::to_string(minor)})); } } mir::UniqueModulePtr mge::Platform::create_buffer_allocator() { return mir::make_module_ptr(); } mir::UniqueModulePtr mge::Platform::create_display( std::shared_ptr const& configuration_policy, std::shared_ptr const& gl_config) { return mir::make_module_ptr(drm_node, display, configuration_policy, *gl_config); } mir::UniqueModulePtr mge::Platform::make_ipc_operations() const { class NoIPCOperations : public mg::PlatformIpcOperations { public: void pack_buffer(BufferIpcMessage& packer, Buffer const& buffer, BufferIpcMsgType msg_type) const override { if (msg_type == mg::BufferIpcMsgType::full_msg) { auto native_handle = std::dynamic_pointer_cast(buffer.native_buffer_handle()); if (!native_handle) BOOST_THROW_EXCEPTION(std::invalid_argument{"could not convert NativeBuffer"}); for(auto i=0; idata_items; i++) { packer.pack_data(native_handle->data[i]); } for(auto i=0; ifd_items; i++) { packer.pack_fd(mir::Fd(IntOwnedFd{native_handle->fd[i]})); } packer.pack_stride(mir::geometry::Stride{native_handle->stride}); packer.pack_flags(native_handle->flags); packer.pack_size(buffer.size()); } } void unpack_buffer(BufferIpcMessage& /*message*/, Buffer const& /*buffer*/) const override { } std::shared_ptr connection_ipc_package() override { return std::make_shared(describe_graphics_module()); } PlatformOperationMessage platform_operation(unsigned int const /*opcode*/, PlatformOperationMessage const& /*message*/) override { BOOST_THROW_EXCEPTION(std::runtime_error{"No platform operations implemented"}); } }; return mir::make_module_ptr(); } ./src/platforms/eglstream-kms/server/display.cpp0000644000004100000410000002501313115234664022301 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #include #include "display.h" #include "egl_output.h" #include "kms-utils/drm_mode_resources.h" #include "mir/graphics/display_configuration.h" #include "mir/graphics/display_configuration_policy.h" #include "mir/graphics/overlapping_output_grouping.h" #include "mir/graphics/gl_config.h" #include "mir/graphics/virtual_output.h" #include "mir/graphics/egl_error.h" #include "mir/graphics/display_buffer.h" #include "mir/renderer/gl/render_target.h" #include "mir/renderer/gl/context.h" #include #include #include #include #include namespace mg = mir::graphics; namespace mge = mir::graphics::eglstream; namespace mgk = mir::graphics::kms; namespace { EGLConfig choose_config(EGLDisplay display, mg::GLConfig const& requested_config) { EGLint const config_attr[] = { EGL_SURFACE_TYPE, EGL_STREAM_BIT_KHR, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 0, EGL_DEPTH_SIZE, requested_config.depth_buffer_bits(), EGL_STENCIL_SIZE, requested_config.stencil_buffer_bits(), EGL_RENDERABLE_TYPE, MIR_SERVER_EGL_OPENGL_BIT, EGL_NONE }; EGLint num_egl_configs; EGLConfig egl_config; if (eglChooseConfig(display, config_attr, &egl_config, 1, &num_egl_configs) != EGL_TRUE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to chose EGL config")); } else if (num_egl_configs != 1) { BOOST_THROW_EXCEPTION(std::runtime_error{"Failed to find compatible EGL config"}); } return egl_config; } EGLContext create_context(EGLDisplay display, EGLConfig config) { eglBindAPI(MIR_SERVER_EGL_OPENGL_API); EGLint const context_attr[] = { #if MIR_SERVER_EGL_OPENGL_BIT == EGL_OPENGL_ES2_BIT EGL_CONTEXT_CLIENT_VERSION, 2, #endif EGL_NONE }; EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attr); if (context == EGL_NO_CONTEXT) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context")); } return context; } EGLContext create_context(EGLDisplay display, EGLConfig config, EGLContext shared_context) { eglBindAPI(MIR_SERVER_EGL_OPENGL_API); EGLint const context_attr[] = { #if MIR_SERVER_EGL_OPENGL_BIT == EGL_OPENGL_ES2_BIT EGL_CONTEXT_CLIENT_VERSION, 2, #endif EGL_NONE }; EGLContext context = eglCreateContext(display, config, shared_context, context_attr); if (context == EGL_NO_CONTEXT) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGL context")); } return context; } class DisplayBuffer : public mg::DisplaySyncGroup, public mg::DisplayBuffer, public mg::NativeDisplayBuffer, public mir::renderer::gl::RenderTarget { public: DisplayBuffer(EGLDisplay dpy, EGLContext ctx, EGLConfig config, mge::kms::EGLOutput const& output) : dpy{dpy}, ctx{create_context(dpy, config, ctx)}, layer{output.output_layer()}, view_area_{output.top_left, output.size()} { EGLint const stream_attribs[] = { EGL_STREAM_FIFO_LENGTH_KHR, 1, EGL_NONE }; output_stream = eglCreateStreamKHR(dpy, stream_attribs); if (output_stream == EGL_NO_STREAM_KHR) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGLStream")); } EGLAttrib swap_interval; if (eglQueryOutputLayerAttribEXT(dpy, layer, EGL_SWAP_INTERVAL_EXT, &swap_interval) != EGL_TRUE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to query swap interval")); } if (eglOutputLayerAttribEXT(dpy, layer, EGL_SWAP_INTERVAL_EXT, 1) != EGL_TRUE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to set swap interval")); } if (eglStreamConsumerOutputEXT(dpy, output_stream, output.output_layer()) == EGL_FALSE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to attach EGLStream to output")); }; EGLint const surface_attribs[] = { EGL_WIDTH, output.size().width.as_int(), EGL_HEIGHT, output.size().height.as_int(), EGL_NONE, }; surface = eglCreateStreamProducerSurfaceKHR(dpy, config, output_stream, surface_attribs); if (surface == EGL_NO_SURFACE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create StreamProducerSurface")); } } /* gl::RenderTarget */ void make_current() override { if (eglMakeCurrent(dpy, surface, surface, ctx) != EGL_TRUE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to make context current")); } } void release_current() override { if (eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to release context")); } } void swap_buffers() override { if (eglSwapBuffers(dpy, surface) != EGL_TRUE) { BOOST_THROW_EXCEPTION(mg::egl_error("eglSwapBuffers failed")); } } mir::geometry::Rectangle view_area() const override { return view_area_; } bool overlay(const mir::graphics::RenderableList& /*renderlist*/) override { return false; } MirOrientation orientation() const override { return mir_orientation_normal; } MirMirrorMode mirror_mode() const override { return mir_mirror_mode_none; } mir::graphics::NativeDisplayBuffer* native_display_buffer() override { return this; } void for_each_display_buffer(const std::function& f) override { f(*this); } void post() override { } void bind() override { } std::chrono::milliseconds recommended_sleep() const override { return std::chrono::milliseconds{0}; } private: EGLDisplay dpy; EGLContext ctx; EGLOutputLayerEXT layer; mir::geometry::Rectangle const view_area_; EGLStreamKHR output_stream; EGLSurface surface; }; } mge::Display::Display( mir::Fd drm_node, EGLDisplay display, std::shared_ptr const& configuration_policy, GLConfig const& gl_conf) : drm_node{drm_node}, display{display}, config{choose_config(display, gl_conf)}, context{create_context(display, config)}, display_configuration{this->drm_node, display} { auto ret = drmSetClientCap(drm_node, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); if (ret != 0) { BOOST_THROW_EXCEPTION(std::system_error(-ret, std::system_category(), "Request for Universal Planes support failed")); } ret = drmSetClientCap(drm_node, DRM_CLIENT_CAP_ATOMIC, 1); if (ret != 0) { BOOST_THROW_EXCEPTION(std::system_error(-ret, std::system_category(), "Request for Atomic Modesetting support failed")); } configuration_policy->apply_to(display_configuration); configure(display_configuration); } void mge::Display::for_each_display_sync_group(const std::function& f) { for (auto& group : active_sync_groups) { f(*group); } } std::unique_ptr mge::Display::configuration() const { return display_configuration.clone(); } void mge::Display::configure(DisplayConfiguration const& conf) { auto kms_conf = dynamic_cast(conf); active_sync_groups.clear(); kms_conf.for_each_output([this, &conf](kms::EGLOutput const& output) { if (output.used) { const_cast(output).configure(output.current_mode_index); active_sync_groups.emplace_back(std::make_unique<::DisplayBuffer>(display, context, config, output)); } }); } void mge::Display::register_configuration_change_handler( EventHandlerRegister& /*handlers*/, DisplayConfigurationChangeHandler const& /*conf_change_handler*/) { } void mge::Display::register_pause_resume_handlers( EventHandlerRegister& /*handlers*/, DisplayPauseHandler const& /*pause_handler*/, DisplayResumeHandler const& /*resume_handler*/) { } void mge::Display::pause() { } void mge::Display::resume() { } std::shared_ptr mge::Display::create_hardware_cursor( std::shared_ptr const& /*initial_image*/) { // TODO: Find the cursor plane, and use it. return nullptr; } std::unique_ptr mge::Display::create_virtual_output(int /*width*/, int /*height*/) { return nullptr; } mg::NativeDisplay* mge::Display::native_display() { return this; } std::unique_ptr mge::Display::create_gl_context() { class GLContext : public renderer::gl::Context { public: GLContext(EGLDisplay display, EGLContext context) : display{display}, context{context} { } void make_current() const override { eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, context); } void release_current() const override { eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } private: EGLDisplay display; EGLContext context; }; return std::make_unique(display, context); } bool mge::Display::apply_if_configuration_preserves_display_buffers( mg::DisplayConfiguration const& /*conf*/) { return false; } mg::Frame mge::Display::last_frame_on(unsigned) const { /* * TODO: Implement this later when we have the hardware + driver to test on. * If no proper hardware counters are available, just call * AtomicFrame.increment_now() in post() above. */ return {}; } ./src/platforms/eglstream-kms/server/display.h0000644000004100000410000000554713115234664021760 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_PLATFORMS_EGLSTREAM_KMS_DISPLAY_H_ #define MIR_PLATFORMS_EGLSTREAM_KMS_DISPLAY_H_ #include "mir/graphics/display.h" #include "kms_display_configuration.h" #include "mir/fd.h" #include "mir/renderer/gl/context_source.h" namespace mir { namespace graphics { class DisplayConfigurationPolicy; class GLConfig; namespace eglstream { class Display : public mir::graphics::Display, public mir::graphics::NativeDisplay, public mir::renderer::gl::ContextSource { public: Display( mir::Fd drm_node, EGLDisplay display, std::shared_ptr const& configuration_policy, GLConfig const& gl_conf); void for_each_display_sync_group(const std::function& f) override; std::unique_ptr configuration() const override; bool apply_if_configuration_preserves_display_buffers(DisplayConfiguration const& conf) override; void configure(DisplayConfiguration const& conf) override; void register_configuration_change_handler(EventHandlerRegister& handlers, DisplayConfigurationChangeHandler const& conf_change_handler) override; void register_pause_resume_handlers(EventHandlerRegister& handlers, DisplayPauseHandler const& pause_handler, DisplayResumeHandler const& resume_handler) override; void pause() override; void resume() override; std::shared_ptr create_hardware_cursor(std::shared_ptr const& initial_image) override; std::unique_ptr create_virtual_output(int width, int height) override; NativeDisplay* native_display() override; std::unique_ptr create_gl_context() override; Frame last_frame_on(unsigned output_id) const override; private: mir::Fd const drm_node; EGLDisplay display; EGLConfig config; EGLContext context; KMSDisplayConfiguration display_configuration; std::vector> active_sync_groups; std::shared_ptr const configuration_policy; }; } } } #endif // MIR_PLATFORMS_EGLSTREAM_KMS_DISPLAY_H_ ./src/platforms/eglstream-kms/server/egl_output.cpp0000644000004100000410000002520413115234664023025 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #include #include "egl_output.h" #include "mir/graphics/egl_error.h" #include "kms-utils/kms_connector.h" #include #include #include #include #include #include #include #include namespace mg = mir::graphics; namespace mge = mg::eglstream; namespace mgek = mge::kms; namespace mgk = mg::kms; namespace geom = mir::geometry; namespace { namespace { class DumbFb { public: DumbFb(int drm_fd, uint32_t width, uint32_t height) : drm_fd{drm_fd} { struct drm_mode_create_dumb params = {}; params.bpp = 32; params.height = height; params.width = width; if (ioctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, ¶ms) != 0) { BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to create dumb buffer"})); } gem_handle = params.handle; pitch_ = params.pitch; auto ret = drmModeAddFB(drm_fd, width, height, 24, 32, params.pitch, params.handle, &fb_id); if (ret) { BOOST_THROW_EXCEPTION((std::system_error{-ret, std::system_category(), "Failed to attach dumb buffer to FB"})); } struct drm_mode_map_dumb map_request = {}; map_request.handle = gem_handle; ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_request); if (ret) { BOOST_THROW_EXCEPTION((std::system_error{-ret, std::system_category(), "Failed to map dumb buffer"})); } auto map = mmap(0, params.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_fd, map_request.offset); if (map == MAP_FAILED) { BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to mmap() buffer"})); } } ~DumbFb() noexcept(false) { struct drm_mode_destroy_dumb params = { gem_handle }; if (ioctl(drm_fd, DRM_IOCTL_MODE_DESTROY_DUMB, ¶ms) != 0) { if (!std::uncaught_exception()) { BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to destroy dumb buffer"})); } } } uint32_t handle() const { return gem_handle; } uint32_t pitch() const { return pitch_; } uint32_t id() const { return fb_id; } private: int const drm_fd; uint32_t fb_id; uint32_t gem_handle; uint32_t pitch_; }; } uint32_t kms_id_from_port(EGLDisplay dpy, EGLOutputPortEXT port) { EGLAttrib kms_connector_id; if (eglQueryOutputPortAttribEXT(dpy, port, EGL_DRM_CONNECTOR_EXT, &kms_connector_id) != EGL_TRUE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to get EGLOutputPort → KMS connector ID mapping")); } return static_cast(kms_connector_id); } void refresh_connector(int drm_fd, mgk::DRMModeConnectorUPtr& connector) { connector = mgk::get_connector(drm_fd, connector->connector_id); } } mgek::EGLOutput::EGLOutput( int drm_fd, EGLDisplay dpy, EGLOutputPortEXT connector) : drm_fd{drm_fd}, display{dpy}, port{connector}, connector{mgk::get_connector(drm_fd, kms_id_from_port(dpy, port))} { } mgek::EGLOutput::~EGLOutput() noexcept(false) { auto const uncaught_exception = std::uncaught_exception(); try { restore_saved_crtc(); } catch(...) { if (!uncaught_exception) { throw; } } } void mgek::EGLOutput::reset() { /* Update the connector to ensure we have the latest information */ refresh_connector(drm_fd, connector); // TODO: What if we can't locate the DPMS property? // TODO: Replace with mgk::ObjectProperties for (int i = 0; i < connector->count_props; i++) { auto prop = drmModeGetProperty(drm_fd, connector->props[i]); if (prop && (prop->flags & DRM_MODE_PROP_ENUM)) { if (!strcmp(prop->name, "DPMS")) { dpms_enum_id = connector->props[i]; drmModeFreeProperty(prop); break; } drmModeFreeProperty(prop); } } } geom::Size mgek::EGLOutput::size() const { drmModeModeInfo const& mode = connector->modes[mode_index]; return {mode.hdisplay, mode.vdisplay}; } int mgek::EGLOutput::max_refresh_rate() const { drmModeModeInfo const& current_mode = connector->modes[mode_index]; return current_mode.vrefresh; } void mgek::EGLOutput::configure(size_t kms_mode_index) { mode_index = kms_mode_index; auto const width = connector->modes[kms_mode_index].hdisplay; auto const height = connector->modes[kms_mode_index].vdisplay; std::unique_ptr request{drmModeAtomicAlloc(), &drmModeAtomicFree}; mgk::DRMModeCrtcUPtr crtc; mgk::DRMModePlaneUPtr plane; std::tie(crtc, plane) = mgk::find_crtc_with_primary_plane(drm_fd, connector); auto const crtc_id = crtc->crtc_id; uint32_t mode_id{0}; auto ret = drmModeCreatePropertyBlob( drm_fd, &connector->modes[kms_mode_index], sizeof(connector->modes[kms_mode_index]), &mode_id); if (ret != 0) { BOOST_THROW_EXCEPTION( std::system_error(-ret, std::system_category(), "Failed to create DRM Mode property blob")); } DumbFb dummy{drm_fd, width, height}; mgk::ObjectProperties crtc_props{drm_fd, crtc_id, DRM_MODE_OBJECT_CRTC}; /* Activate the CRTC and set the mode */ drmModeAtomicAddProperty(request.get(), crtc_id, crtc_props.id_for("MODE_ID"), mode_id); drmModeAtomicAddProperty(request.get(), crtc_id, crtc_props.id_for("ACTIVE"), 1); /* Set CRTC for the output */ auto const connector_id = connector->connector_id; mgk::ObjectProperties connector_props{drm_fd, connector_id, DRM_MODE_OBJECT_CONNECTOR}; drmModeAtomicAddProperty(request.get(), connector_id, connector_props.id_for("CRTC_ID"), crtc_id); /* Set up the output plane... */ auto const plane_id = plane->plane_id; mgk::ObjectProperties plane_props{drm_fd, plane_id, DRM_MODE_OBJECT_PLANE}; /* Source viewport. Coordinates are 16.16 fixed point format */ drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("SRC_X"), 0); drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("SRC_Y"), 0); drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("SRC_W"), width << 16); drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("SRC_H"), height << 16); /* Destination viewport. Coordinates are *not* 16.16 */ drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("CRTC_X"), 0); drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("CRTC_Y"), 0); drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("CRTC_W"), width); drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("CRTC_H"), height); /* Set a surface for the plane, and connect to the CRTC */ drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("FB_ID"), dummy.id()); drmModeAtomicAddProperty(request.get(), plane_id, plane_props.id_for("CRTC_ID"), crtc_id); /* We don't monitor the DRM events (yet), so have no userdata */ ret = drmModeAtomicCommit(drm_fd, request.get(), DRM_MODE_ATOMIC_ALLOW_MODESET, nullptr); if (ret != 0) { BOOST_THROW_EXCEPTION( std::system_error(-ret, std::system_category(), "Failed to commit atomic KMS configuration change")); } EGLAttrib const crtc_filter[] = { EGL_DRM_PLANE_EXT, static_cast(plane_id), EGL_NONE}; int found_layers{0}; if (eglGetOutputLayersEXT(display, crtc_filter, &layer, 1, &found_layers) != EGL_TRUE) { BOOST_THROW_EXCEPTION((mg::egl_error("Failed to find EGLOutputEXT corresponding to DRM CRTC"))); } if (found_layers != 1) { BOOST_THROW_EXCEPTION(std::runtime_error{"Failed to find EGLOutputEXT corresponding to DRM CRTC"}); } using_saved_crtc = false; } EGLOutputLayerEXT mgek::EGLOutput::output_layer() const { return layer; } void mgek::EGLOutput::clear_crtc() { using namespace std::string_literals; mgk::DRMModeCrtcUPtr crtc; try { crtc = mgk::find_crtc_for_connector(drm_fd, connector); } catch (std::runtime_error const&) { /* * In order to actually clear the output, we need to have a crtc * connected to the output/connector so that we can disconnect * it. However, not being able to get a crtc is OK, since it means * that the output cannot be displaying anything anyway. */ return; } auto const crtc_id = crtc->crtc_id; auto result = drmModeSetCrtc(drm_fd, crtc_id, 0, 0, 0, nullptr, 0, nullptr); if (result) { BOOST_THROW_EXCEPTION(( std::system_error{ -result, std::system_category(), "Couldn't clear output "s + mgk::connector_name(connector)})); } } void mgek::EGLOutput::restore_saved_crtc() { if (!using_saved_crtc) { auto result = drmModeSetCrtc( drm_fd, saved_crtc.crtc_id, saved_crtc.buffer_id, saved_crtc.x, saved_crtc.y, &connector->connector_id, 1, &saved_crtc.mode); if (result != 0) { BOOST_THROW_EXCEPTION((std::system_error{-result, std::system_category(), "Failed to set CRTC"})); } using_saved_crtc = true; } } void mgek::EGLOutput::set_power_mode(MirPowerMode mode) { auto ret = drmModeConnectorSetProperty( drm_fd, connector->connector_id, dpms_enum_id, mode); if (ret) { BOOST_THROW_EXCEPTION((std::system_error{-ret, std::system_category(), "Failed to set output power mode"})); } } ./src/platforms/eglstream-kms/server/platform.h0000644000004100000410000000360313115234664022126 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_PLATFORMS_EGLSTREAM_KMS_PLATFORM_H_ #define MIR_PLATFORMS_EGLSTREAM_KMS_PLATFORM_H_ #include "mir/graphics/platform.h" #include "mir/options/option.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "mir/graphics/display.h" #include "mir/graphics/platform_ipc_operations.h" #include "mir/fd.h" #include #include namespace mir { namespace graphics { namespace eglstream { class Platform : public mir::graphics::Platform { public: Platform( EGLDeviceEXT device, std::shared_ptr const& /*emergency_cleanup_registry*/, std::shared_ptr const& /*report*/); ~Platform() = default; UniqueModulePtr create_buffer_allocator() override; UniqueModulePtr create_display( std::shared_ptr const& /*initial_conf_policy*/, std::shared_ptr const& /*gl_config*/) override; UniqueModulePtr make_ipc_operations() const override; private: EGLDisplay display; mir::Fd const drm_node; }; } } } #endif // MIR_PLATFORMS_EGLSTREAM_KMS_PLATFORM_H_ ./src/platforms/eglstream-kms/server/platform_symbols.cpp0000644000004100000410000001367013115234664024236 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #include #include "platform.h" #include "mir/graphics/platform.h" #include "mir/options/option.h" #include "mir/module_deleter.h" #include "mir/assert_module_entry_point.h" #include "mir/libname.h" #include "mir/log.h" #include "mir/graphics/egl_error.h" #include #include #include #include #include namespace mg = mir::graphics; namespace mo = mir::options; namespace mge = mir::graphics::eglstream; mir::UniqueModulePtr create_host_platform( std::shared_ptr const&, std::shared_ptr const& emergency_cleanup_registry, std::shared_ptr const& report, std::shared_ptr const& /*logger*/) { mir::assert_entry_point_signature(&create_host_platform); int device_count{0}; if (eglQueryDevicesEXT(0, nullptr, &device_count) != EGL_TRUE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to query device count with eglQueryDevicesEXT")); } auto devices = std::make_unique(device_count); if (eglQueryDevicesEXT(device_count, devices.get(), &device_count) != EGL_TRUE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to get device list with eglQueryDevicesEXT")); } auto device = std::find_if(devices.get(), devices.get() + device_count, [](EGLDeviceEXT device) { auto device_extensions = eglQueryDeviceStringEXT(device, EGL_EXTENSIONS); if (device_extensions) { return strstr(device_extensions, "EGL_EXT_device_drm") != NULL; } return false; }); if (device == (devices.get() + device_count)) { BOOST_THROW_EXCEPTION(std::runtime_error("Couldn't find EGLDeviceEXT supporting EGL_EXT_device_drm?")); } return mir::make_module_ptr(*device, emergency_cleanup_registry, report); } void add_graphics_platform_options(boost::program_options::options_description& /*config*/) { mir::assert_entry_point_signature(&add_graphics_platform_options); } mg::PlatformPriority probe_graphics_platform(mo::ProgramOption const& /*options*/) { mir::assert_entry_point_signature(&probe_graphics_platform); std::vector missing_extensions; for (char const* extension : { "EGL_EXT_platform_base", "EGL_EXT_platform_device", "EGL_EXT_device_base",}) { if (!epoxy_has_egl_extension(EGL_NO_DISPLAY, extension)) { missing_extensions.push_back(extension); } } if (!missing_extensions.empty()) { std::stringstream message; message << "Missing required extension" << (missing_extensions.size() > 1 ? "s:" : ":"); for (auto missing_extension : missing_extensions) { message << " " << missing_extension; } mir::log_debug("EGLStream platform is unsupported: %s", message.str().c_str()); return mg::PlatformPriority::unsupported; } int device_count{0}; if (eglQueryDevicesEXT(0, nullptr, &device_count) != EGL_TRUE) { mir::log_info("Platform claims to support EGL_EXT_device_base, but " "eglQueryDevicesEXT falied: %s", mg::egl_category().message(eglGetError()).c_str()); return mg::PlatformPriority::unsupported; } auto devices = std::make_unique(device_count); if (eglQueryDevicesEXT(device_count, devices.get(), &device_count) != EGL_TRUE) { BOOST_THROW_EXCEPTION(mg::egl_error("Failed to get device list with eglQueryDevicesEXT")); } if (std::none_of(devices.get(), devices.get() + device_count, [](EGLDeviceEXT device) { auto device_extensions = eglQueryDeviceStringEXT(device, EGL_EXTENSIONS); if (device_extensions) { mir::log_debug("Found EGLDeviceEXT with device extensions: %s", device_extensions); return strstr(device_extensions, "EGL_EXT_device_drm") != NULL; } else { mir::log_debug("Found EGLDeviceEXT with no device extensions"); return false; } })) { mir::log_debug("EGLDeviceEXTs found, but none support required " "EGL_EXT_device_drm extension"); return mg::PlatformPriority::unsupported; } return mg::PlatformPriority::best; } namespace { mir::ModuleProperties const description = { "mir:eglstream-kms", MIR_VERSION_MAJOR, MIR_VERSION_MINOR, MIR_VERSION_MICRO, mir::libname() }; } mir::ModuleProperties const* describe_graphics_module() { mir::assert_entry_point_signature(&describe_graphics_module); return &description; } mir::UniqueModulePtr create_guest_platform( std::shared_ptr const&, std::shared_ptr const& /*nested_context*/) { mir::assert_entry_point_signature(&create_guest_platform); return nullptr; } ./src/platforms/eglstream-kms/server/buffer_allocator.cpp0000644000004100000410000000500713115234664024146 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Christopher James Halse Rogers */ #include "buffer_allocator.h" #include "buffer_texture_binder.h" #include "anonymous_shm_file.h" #include "shm_buffer.h" #include "mir/graphics/buffer_properties.h" #include "software_buffer.h" #include #include #include #include namespace mg = mir::graphics; namespace mge = mg::eglstream; namespace mgc = mg::common; namespace geom = mir::geometry; mge::BufferAllocator::BufferAllocator() { } std::shared_ptr mge::BufferAllocator::alloc_buffer( BufferProperties const& buffer_properties) { if (buffer_properties.usage == mg::BufferUsage::software) return alloc_software_buffer(buffer_properties.size, buffer_properties.format); BOOST_THROW_EXCEPTION(std::runtime_error("platform incapable of creating hardware buffers")); } std::shared_ptr mge::BufferAllocator::alloc_software_buffer(geom::Size size, MirPixelFormat format) { if (!mgc::ShmBuffer::supports(format)) { BOOST_THROW_EXCEPTION( std::runtime_error( "Trying to create SHM buffer with unsupported pixel format")); } auto const stride = geom::Stride{ MIR_BYTES_PER_PIXEL(format) * size.width.as_uint32_t() }; size_t const size_in_bytes = stride.as_int() * size.height.as_int(); return std::make_shared( std::make_unique(size_in_bytes), size, format); } std::vector mge::BufferAllocator::supported_pixel_formats() { // Lazy return {mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888}; } std::shared_ptr mge::BufferAllocator::alloc_buffer(geometry::Size, uint32_t, uint32_t) { BOOST_THROW_EXCEPTION(std::runtime_error("platform incapable of creating buffers")); } ./src/platforms/eglstream-kms/server/symbols.map.in0000644000004100000410000000033113115234664022720 0ustar www-datawww-data@MIR_SERVER_GRAPHICS_PLATFORM_VERSION@ { global: add_graphics_platform_options; create_host_platform; create_guest_platform; probe_graphics_platform; describe_graphics_module; local: *; }; ./src/platforms/eglstream-kms/server/software_buffer.cpp0000644000004100000410000000300313115234664024012 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Kevin DuBois */ #include "software_buffer.h" #include "shm_file.h" #include "native_buffer.h" namespace mg = mir::graphics; namespace mge = mir::graphics::eglstream; namespace mgc = mir::graphics::common; namespace geom = mir::geometry; mge::SoftwareBuffer::SoftwareBuffer( std::unique_ptr shm_file, geom::Size const& size, MirPixelFormat const& pixel_format) : ShmBuffer(std::move(shm_file), size, pixel_format), native_handle(create_native_handle()) { } std::shared_ptr mge::SoftwareBuffer::create_native_handle() { auto buffer = std::make_shared(); *static_cast(buffer.get())= *to_mir_buffer_package(); return buffer; } std::shared_ptr mge::SoftwareBuffer::native_buffer_handle() const { return native_handle; } ./src/platforms/input_platform_symbols.map.in0000644000004100000410000000024313115234416021757 0ustar www-datawww-data@MIR_SERVER_INPUT_PLATFORM_VERSION@ { global: add_input_platform_options; create_input_platform; probe_input_platform; describe_input_module; }; ./src/platforms/common/0000755000004100000410000000000013115234677015342 5ustar www-datawww-data./src/platforms/common/CMakeLists.txt0000644000004100000410000000006713115234664020101 0ustar www-datawww-dataadd_subdirectory(client/mir) add_subdirectory(server/) ./src/platforms/common/client/0000755000004100000410000000000013115234413016604 5ustar www-datawww-data./src/platforms/common/client/mir/0000755000004100000410000000000013115234420017371 5ustar www-datawww-data./src/platforms/common/client/mir/CMakeLists.txt0000644000004100000410000000030713115234416022136 0ustar www-datawww-datainclude_directories(${PROJECT_SOURCE_DIR}/src/include/client) include_directories(${PROJECT_SOURCE_DIR}/include/client) add_library(client_platform_common STATIC aging_buffer.cpp weak_egl.cpp ) ./src/platforms/common/client/mir/weak_egl.cpp0000644000004100000410000000352113115234416021661 0ustar www-datawww-data/* * EGL without any linkage requirements! * ~~~ * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #include "weak_egl.h" #include namespace mir { namespace client { WeakEGL::WeakEGL() : egl1(nullptr) , pGetConfigAttrib(nullptr) { } WeakEGL::~WeakEGL() { if (egl1) dlclose(egl1); } EGLBoolean WeakEGL::eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value) { if (find("eglGetConfigAttrib", (void**)&pGetConfigAttrib)) return pGetConfigAttrib(dpy, config, attribute, value); else return EGL_FALSE; } bool WeakEGL::find(char const* name, void** func) { if (!*func) { // RTLD_DEFAULT is first choice to support wrappers like MockEGL if (!(*func = dlsym(RTLD_DEFAULT, name))) { // This will work more in real-world situations if the library // is hidden behind an RTLD_LOCAL (e.g. a Qt plugin) if (!egl1) egl1 = dlopen("libEGL.so.1", RTLD_NOLOAD|RTLD_LAZY); if (egl1) *func = dlsym(egl1, name); } } return *func != nullptr; } }} // namespace mir::client ./src/platforms/common/client/mir/aging_buffer.h0000644000004100000410000000214613115234416022170 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_CLIENT_AGING_BUFFER_H_ #define MIR_CLIENT_AGING_BUFFER_H_ #include "mir/client_buffer.h" namespace mir { namespace client { class AgingBuffer : public ClientBuffer { public: uint32_t age() const override; void increment_age() override; void mark_as_submitted() override; private: uint32_t buffer_age{0}; }; } } #endif /* MIR_CLIENT_AGING_BUFFER_H_ */ ./src/platforms/common/client/mir/aging_buffer.cpp0000644000004100000410000000177613115234416022533 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #include "aging_buffer.h" namespace mcl = mir::client; uint32_t mcl::AgingBuffer::age() const { return buffer_age; } void mcl::AgingBuffer::increment_age() { if (buffer_age != 0) ++buffer_age; } void mcl::AgingBuffer::mark_as_submitted() { buffer_age = 1; } ./src/platforms/common/client/mir/weak_egl.h0000644000004100000410000000253513115234416021332 0ustar www-datawww-data/* * EGL without any linkage requirements! * ~~~ * Copyright © 2015 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Daniel van Vugt */ #ifndef MIR_CLIENT_WEAK_EGL_H_ #define MIR_CLIENT_WEAK_EGL_H_ #include #include namespace mir { namespace client { class WeakEGL { public: WeakEGL(); ~WeakEGL(); EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value); private: bool find(char const* name, void** func); void* egl1; EGLBoolean (*pGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value); }; }} // namespace mir::client #endif // MIR_CLIENT_WEAK_EGL_H_ ./src/platforms/common/server/0000755000004100000410000000000013115234667016647 5ustar www-datawww-data./src/platforms/common/server/CMakeLists.txt0000644000004100000410000000071013115234664021402 0ustar www-datawww-dataif (MIR_BUILD_PLATFORM_MESA_KMS OR MIR_BUILD_PLATFORM_MESA_X11 OR MIR_BUILD_PLATFORM_EGLSTREAM_KMS) add_subdirectory(kms-utils/) endif() include_directories( ${server_common_include_dirs} ${GL_INCLUDE_DIRS} ) add_library(server_platform_common STATIC anonymous_shm_file.cpp shm_buffer.cpp shm_file.h ) target_link_libraries( server_platform_common ${KMS_UTILS_STATIC_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${GL_LDFLAGS} ${GL_LIBRARIES} ) ./src/platforms/common/server/shm_buffer.cpp0000644000004100000410000001253313115234664021474 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Alexandros Frantzis */ #include "shm_file.h" #include "shm_buffer.h" #include "buffer_texture_binder.h" #include MIR_SERVER_GL_H #include MIR_SERVER_GLEXT_H #include #include #include #include namespace mg=mir::graphics; namespace mgc = mir::graphics::common; namespace geom = mir::geometry; namespace { bool get_gl_pixel_format(MirPixelFormat mir_format, GLenum& gl_format, GLenum& gl_type) { #if __BYTE_ORDER == __LITTLE_ENDIAN GLenum const argb = GL_BGRA_EXT; GLenum const abgr = GL_RGBA; #elif __BYTE_ORDER == __BIG_ENDIAN // TODO: Big endian support GLenum const argb = GL_INVALID_ENUM; GLenum const abgr = GL_INVALID_ENUM; //GLenum const rgba = GL_RGBA; //GLenum const bgra = GL_BGRA_EXT; #endif static const struct { MirPixelFormat mir_format; GLenum gl_format, gl_type; } mapping[mir_pixel_formats] = { {mir_pixel_format_invalid, GL_INVALID_ENUM, GL_INVALID_ENUM}, {mir_pixel_format_abgr_8888, abgr, GL_UNSIGNED_BYTE}, {mir_pixel_format_xbgr_8888, abgr, GL_UNSIGNED_BYTE}, {mir_pixel_format_argb_8888, argb, GL_UNSIGNED_BYTE}, {mir_pixel_format_xrgb_8888, argb, GL_UNSIGNED_BYTE}, {mir_pixel_format_bgr_888, GL_INVALID_ENUM, GL_INVALID_ENUM}, {mir_pixel_format_rgb_888, GL_RGB, GL_UNSIGNED_BYTE}, {mir_pixel_format_rgb_565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, {mir_pixel_format_rgba_5551, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, {mir_pixel_format_rgba_4444, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}, }; if (mir_format > mir_pixel_format_invalid && mir_format < mir_pixel_formats && mapping[mir_format].mir_format == mir_format) // just a sanity check { gl_format = mapping[mir_format].gl_format; gl_type = mapping[mir_format].gl_type; } else { gl_format = GL_INVALID_ENUM; gl_type = GL_INVALID_ENUM; } return gl_format != GL_INVALID_ENUM && gl_type != GL_INVALID_ENUM; } } // anonymous namespace bool mgc::ShmBuffer::supports(MirPixelFormat mir_format) { GLenum gl_format, gl_type; return get_gl_pixel_format(mir_format, gl_format, gl_type); } mgc::ShmBuffer::ShmBuffer( std::unique_ptr shm_file, geom::Size const& size, MirPixelFormat const& pixel_format) : shm_file{std::move(shm_file)}, size_{size}, pixel_format_{pixel_format}, stride_{MIR_BYTES_PER_PIXEL(pixel_format_) * size_.width.as_uint32_t()}, pixels{this->shm_file->base_ptr()} { } mgc::ShmBuffer::~ShmBuffer() noexcept { } geom::Size mgc::ShmBuffer::size() const { return size_; } geom::Stride mgc::ShmBuffer::stride() const { return stride_; } MirPixelFormat mgc::ShmBuffer::pixel_format() const { return pixel_format_; } void mgc::ShmBuffer::gl_bind_to_texture() { GLenum format, type; if (get_gl_pixel_format(pixel_format_, format, type)) { /* * All existing Mir logic assumes that strides are whole multiples of * pixels. And OpenGL defaults to expecting strides are multiples of * 4 bytes. These assumptions used to be compatible when we only had * 4-byte pixels but now we support 2/3-byte pixels we need to be more * careful... */ glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, format, size_.width.as_int(), size_.height.as_int(), 0, format, type, pixels); } } std::shared_ptr mgc::ShmBuffer::to_mir_buffer_package() const { auto native_buffer = std::make_shared(); native_buffer->fd_items = 1; native_buffer->fd[0] = shm_file->fd(); native_buffer->stride = stride().as_uint32_t(); native_buffer->flags = 0; auto const& dim = size(); native_buffer->width = dim.width.as_int(); native_buffer->height = dim.height.as_int(); return native_buffer; } void mgc::ShmBuffer::write(unsigned char const* data, size_t data_size) { if (data_size != stride_.as_uint32_t()*size().height.as_uint32_t()) BOOST_THROW_EXCEPTION(std::logic_error("Size is not equal to number of pixels in buffer")); memcpy(pixels, data, data_size); } void mgc::ShmBuffer::read(std::function const& do_with_pixels) { do_with_pixels(static_cast(pixels)); } mg::NativeBufferBase* mgc::ShmBuffer::native_buffer_base() { return this; } void mgc::ShmBuffer::bind() { gl_bind_to_texture(); } void mgc::ShmBuffer::secure_for_render() { } ./src/platforms/common/server/buffer_texture_binder.h0000644000004100000410000000234613115234664023376 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_BUFFER_TEXTURE_BINDER_H_ #define MIR_GRAPHICS_MESA_BUFFER_TEXTURE_BINDER_H_ namespace mir { namespace graphics { namespace common { class BufferTextureBinder { public: virtual ~BufferTextureBinder() {} virtual void gl_bind_to_texture() = 0; protected: BufferTextureBinder() = default; BufferTextureBinder(BufferTextureBinder const&) = delete; BufferTextureBinder& operator=(BufferTextureBinder const&) = delete; }; } } } #endif /* MIR_GRAPHICS_MESA_BUFFER_TEXTURE_BINDER_H_ */ ./src/platforms/common/server/anonymous_shm_file.h0000644000004100000410000000271613115234664022721 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_ANONYMOUS_SHM_FILE_H_ #define MIR_GRAPHICS_MESA_ANONYMOUS_SHM_FILE_H_ #include "shm_file.h" #include "mir/fd.h" namespace mir { namespace graphics { namespace common { namespace detail { class MapHandle { public: MapHandle(int fd, size_t size); ~MapHandle() noexcept; operator void*() const; private: MapHandle(MapHandle const&) = delete; MapHandle& operator=(MapHandle const&) = delete; size_t const size; void* const mapping; }; } class AnonymousShmFile : public ShmFile { public: AnonymousShmFile(size_t size); void* base_ptr() const; int fd() const; private: Fd const fd_; detail::MapHandle const mapping; }; } } } #endif /* MIR_GRAPHICS_MESA_ANONYMOUS_SHM_FILE_H_ */ ./src/platforms/common/server/kms-utils/0000755000004100000410000000000013115234667020577 5ustar www-datawww-data./src/platforms/common/server/kms-utils/CMakeLists.txt0000644000004100000410000000065113115234664023336 0ustar www-datawww-datainclude_directories( ${DRM_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/src/include/common ) set(KMS_UTILS_STATIC_LIBRARY "kms_utils") set(KMS_UTILS_STATIC_LIBRARY ${KMS_UTILS_STATIC_LIBRARY} PARENT_SCOPE) add_library(${KMS_UTILS_STATIC_LIBRARY} STATIC drm_mode_resources.cpp drm_mode_resources.h kms_connector.cpp kms_connector.h ) target_link_libraries(${KMS_UTILS_STATIC_LIBRARY} ${DRM_LDFLAGS} ${DRM_LIBRARIES} ) ./src/platforms/common/server/kms-utils/drm_mode_resources.cpp0000644000004100000410000004157213115234664025171 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #include "drm_mode_resources.h" #include #include namespace mgk = mir::graphics::kms; namespace mgkd = mgk::detail; namespace { mgk::DRMModeResUPtr resources_for_drm_node(int drm_fd) { errno = 0; mgk::DRMModeResUPtr resources{drmModeGetResources(drm_fd), &drmModeFreeResources}; if (!resources) { if (errno == 0) { // drmModeGetResources either sets errno, or has failed in malloc() errno = ENOMEM; } BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Couldn't get DRM resources"})); } return resources; } mgk::DRMModePlaneResUPtr planes_for_drm_node(int drm_fd) { errno = 0; mgk::DRMModePlaneResUPtr resources{drmModeGetPlaneResources(drm_fd), &drmModeFreePlaneResources}; if (!resources) { if (errno == 0) { // drmModeGetPlaneResources either sets errno, or has failed in malloc() errno = ENOMEM; } BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Couldn't get DRM plane resources"})); } return resources; } } mgk::PlaneResources::PlaneResources(int drm_fd) : drm_fd{drm_fd}, resources{planes_for_drm_node(drm_fd)} { } auto mgk::PlaneResources::planes() const -> detail::ObjectCollection { return detail::ObjectCollection{ drm_fd, resources->planes, resources->planes + resources->count_planes}; } mgk::DRMModeResources::DRMModeResources(int drm_fd) : drm_fd{drm_fd}, resources{resources_for_drm_node(drm_fd)} { } void mgk::DRMModeResources::for_each_connector(std::function const& f) const { for (int i = 0; i < resources->count_connectors; i++) { f(get_connector(drm_fd, resources->connectors[i])); } } void mgk::DRMModeResources::for_each_encoder(std::function const& f) const { for (int i = 0; i < resources->count_encoders; i++) { f(get_encoder(drm_fd, resources->encoders[i])); } } void mgk::DRMModeResources::for_each_crtc(std::function const& f) const { for (int i = 0; i < resources->count_crtcs; i++) { f(get_crtc(drm_fd, resources->crtcs[i])); } } size_t mgk::DRMModeResources::num_connectors() const { return resources->count_connectors; } size_t mgk::DRMModeResources::num_encoders() const { return resources->count_encoders; } size_t mgk::DRMModeResources::num_crtcs() const { return resources->count_crtcs; } mgk::DRMModeConnectorUPtr mgk::DRMModeResources::connector(uint32_t id) const { return get_connector(drm_fd, id); } mgk::DRMModeEncoderUPtr mgk::DRMModeResources::encoder(uint32_t id) const { return get_encoder(drm_fd, id); } mgk::DRMModeCrtcUPtr mgk::DRMModeResources::crtc(uint32_t id) const { return get_crtc(drm_fd, id); } mgk::DRMModeConnectorUPtr mgk::get_connector(int drm_fd, uint32_t id) { errno = 0; DRMModeConnectorUPtr connector{drmModeGetConnector(drm_fd, id), &drmModeFreeConnector}; if (!connector) { if (errno == 0) { // drmModeGetConnector either sets errno, or has failed in malloc() errno = ENOMEM; } BOOST_THROW_EXCEPTION(( std::system_error{errno, std::system_category(), "Failed to get DRM connector"})); } return connector; } mgk::DRMModeEncoderUPtr mgk::get_encoder(int drm_fd, uint32_t id) { errno = 0; DRMModeEncoderUPtr encoder{drmModeGetEncoder(drm_fd, id), &drmModeFreeEncoder}; if (!encoder) { if (errno == 0) { // drmModeGetEncoder either sets errno, or has failed in malloc() errno = ENOMEM; } BOOST_THROW_EXCEPTION(( std::system_error{errno, std::system_category(), "Failed to get DRM encoder"})); } return encoder; } mgk::DRMModeCrtcUPtr mgk::get_crtc(int drm_fd, uint32_t id) { errno = 0; DRMModeCrtcUPtr crtc{drmModeGetCrtc(drm_fd, id), &drmModeFreeCrtc}; if (!crtc) { if (errno == 0) { // drmModeGetCrtc either sets errno, or has failed in malloc() errno = ENOMEM; } BOOST_THROW_EXCEPTION(( std::system_error{errno, std::system_category(), "Failed to get DRM crtc"})); } return crtc; } mgk::DRMModePlaneUPtr mgk::get_plane(int drm_fd, uint32_t id) { errno = 0; DRMModePlaneUPtr plane{drmModeGetPlane(drm_fd, id), &drmModeFreePlane}; if (!plane) { if (errno == 0) { // drmModeGetPlane either sets errno, or has failed in malloc() errno = ENOMEM; } BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to get DRM plane"})); } return plane; } namespace { mgk::DRMModePropertyUPtr get_property(int drm_fd, uint32_t id) { errno = 0; mgk::DRMModePropertyUPtr prop{drmModeGetProperty(drm_fd, id), &drmModeFreeProperty}; if (!prop) { if (errno == 0) { // drmModeGetProperty either sets errno, or has failed in malloc() errno = ENOMEM; } BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to get DRM plane"})); } return prop; } mgk::DRMModeObjectPropsUPtr get_object_properties( int drm_fd, uint32_t object_id, uint32_t object_type) { errno = 0; mgk::DRMModeObjectPropsUPtr props{ drmModeObjectGetProperties(drm_fd, object_id, object_type), &drmModeFreeObjectProperties}; if (!props) { if (errno == 0) { // drmModeGetObjectProperties either sets errno, or has failed in malloc() errno = ENOMEM; } BOOST_THROW_EXCEPTION((std::system_error{errno, std::system_category(), "Failed to get DRM object properties"})); } return props; } std::unordered_map extract_properties( int drm_fd, mgk::DRMModeObjectPropsUPtr const& properties) { std::unordered_map property_map; for (auto i = 0u; i < properties->count_props; ++i) { auto prop = get_property(drm_fd, properties->props[i]); property_map[prop->name] = { prop->prop_id, properties->prop_values[i] }; } return property_map; } } mgk::ObjectProperties::ObjectProperties( int drm_fd, uint32_t object_id, uint32_t object_type) : properties_table{extract_properties(drm_fd, get_object_properties(drm_fd, object_id, object_type))} { } mgk::ObjectProperties::ObjectProperties( int drm_fd, DRMModePlaneUPtr const& plane) : ObjectProperties(drm_fd, plane->plane_id, DRM_MODE_OBJECT_PLANE) { } uint64_t mgk::ObjectProperties::operator[](char const* name) const { return properties_table.at(name).value; } uint32_t mgk::ObjectProperties::id_for(char const* property_name) const { return properties_table.at(property_name).id; } bool mgk::ObjectProperties::has_property(char const* property_name) const { return properties_table.count(property_name) > 0; } auto mgk::ObjectProperties::begin() const -> std::unordered_map::const_iterator { return properties_table.begin(); } auto mgk::ObjectProperties::end() const -> std::unordered_map::const_iterator { return properties_table.end(); } auto mgk::DRMModeResources::connectors() const -> detail::ObjectCollection { return detail::ObjectCollection{drm_fd, resources->connectors, resources->connectors + resources->count_connectors}; } auto mgk::DRMModeResources::encoders() const -> detail::ObjectCollection { return detail::ObjectCollection{drm_fd, resources->encoders, resources->encoders + resources->count_encoders}; } auto mgk::DRMModeResources::crtcs() const -> detail::ObjectCollection { return detail::ObjectCollection{drm_fd, resources->crtcs, resources->encoders + resources->count_crtcs}; } template mgkd::ObjectCollection::ObjectCollection(int drm_fd, uint32_t* begin, uint32_t* end) : drm_fd{drm_fd}, begin_{begin}, end_{end} { } template auto mgkd::ObjectCollection::begin() -> iterator { return iterator(drm_fd, begin_); } template auto mgkd::ObjectCollection::begin() -> iterator; template auto mgkd::ObjectCollection::begin() -> iterator; template auto mgkd::ObjectCollection::begin() -> iterator; template auto mgkd::ObjectCollection::begin() -> iterator; template auto mgkd::ObjectCollection::end() -> iterator { return iterator(drm_fd, end_); } template auto mgkd::ObjectCollection::end() -> iterator; template auto mgkd::ObjectCollection::end() -> iterator; template auto mgkd::ObjectCollection::end() -> iterator; template auto mgkd::ObjectCollection::end() -> iterator; template mgkd::ObjectCollection::iterator::iterator(iterator const& from) : drm_fd{from.drm_fd}, id_ptr{from.id_ptr} { } template mgkd::ObjectCollection::iterator::iterator(iterator const&); template mgkd::ObjectCollection::iterator::iterator(iterator const&); template mgkd::ObjectCollection::iterator::iterator(iterator const&); template mgkd::ObjectCollection::iterator::iterator(iterator const&); template auto mgkd::ObjectCollection::iterator::operator=(iterator const& rhs) -> iterator& { drm_fd = rhs.drm_fd; id_ptr = rhs.id_ptr; current.reset(); return *this; } template auto mgkd::ObjectCollection::iterator::operator=(iterator const&) -> iterator&; template auto mgkd::ObjectCollection::iterator::operator=(iterator const&) -> iterator&; template auto mgkd::ObjectCollection::iterator::operator=(iterator const&) -> iterator&; template auto mgkd::ObjectCollection::iterator::operator=(iterator const&) -> iterator&; template mgkd::ObjectCollection::iterator::iterator( int drm_fd, uint32_t* id_ptr) : drm_fd{drm_fd}, id_ptr{id_ptr} { } template mgkd::ObjectCollection::iterator::iterator(int, uint32_t*); template mgkd::ObjectCollection::iterator::iterator(int, uint32_t*); template mgkd::ObjectCollection::iterator::iterator(int, uint32_t*); template mgkd::ObjectCollection::iterator::iterator(int, uint32_t*); template auto mgkd::ObjectCollection::iterator::operator++() -> iterator& { ++id_ptr; current.reset(); return *this; } template auto mgkd::ObjectCollection::iterator::operator++() -> iterator&; template auto mgkd::ObjectCollection::iterator::operator++() -> iterator&; template auto mgkd::ObjectCollection::iterator::operator++() -> iterator&; template auto mgkd::ObjectCollection::iterator::operator++() -> iterator&; template auto mgkd::ObjectCollection::iterator::operator++(int) -> iterator { iterator copy(drm_fd, id_ptr); ++id_ptr; current.reset(); return copy; } template auto mgkd::ObjectCollection::iterator::operator++(int) -> iterator; template auto mgkd::ObjectCollection::iterator::operator++(int) -> iterator; template auto mgkd::ObjectCollection::iterator::operator++(int) -> iterator; template auto mgkd::ObjectCollection::iterator::operator++(int) -> iterator; template auto mgkd::ObjectCollection::iterator::operator*() const -> DRMUPtr& { if (!current) { current = (*object_constructor)(drm_fd, *id_ptr); } return current; } template auto mgkd::ObjectCollection::iterator::operator*() const -> DRMModeConnectorUPtr&; template auto mgkd::ObjectCollection::iterator::operator*() const -> DRMModeEncoderUPtr&; template auto mgkd::ObjectCollection::iterator::operator*() const -> DRMModeCrtcUPtr&; template auto mgkd::ObjectCollection::iterator::operator*() const -> DRMModePlaneUPtr&; template auto mgkd::ObjectCollection::iterator::operator->() const -> DRMUPtr* { if (!current) { current = (*object_constructor)(drm_fd, *id_ptr); } return ¤t; } template auto mgkd::ObjectCollection::iterator::operator->() const -> DRMModeConnectorUPtr*; template auto mgkd::ObjectCollection::iterator::operator->() const -> DRMModeEncoderUPtr*; template auto mgkd::ObjectCollection::iterator::operator->() const -> DRMModeCrtcUPtr*; template auto mgkd::ObjectCollection::iterator::operator->() const -> DRMModePlaneUPtr*; template bool mgkd::ObjectCollection::iterator::operator==(iterator const& rhs) const { return rhs.id_ptr == id_ptr; } template bool mgkd::ObjectCollection::iterator::operator==(iterator const&) const; template bool mgkd::ObjectCollection::iterator::operator==(iterator const&) const; template bool mgkd::ObjectCollection::iterator::operator==(iterator const&) const; template bool mgkd::ObjectCollection::iterator::operator==(iterator const&) const; template bool mgkd::ObjectCollection::iterator::operator!=(iterator const& rhs) const { return !(*this == rhs); } template bool mgkd::ObjectCollection::iterator::operator!=(iterator const&) const; template bool mgkd::ObjectCollection::iterator::operator!=(iterator const&) const; template bool mgkd::ObjectCollection::iterator::operator!=(iterator const&) const; template bool mgkd::ObjectCollection::iterator::operator!=(iterator const&) const; ./src/platforms/common/server/kms-utils/kms_connector.cpp0000644000004100000410000001412213115234664024144 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #include "kms_connector.h" #include "mir/output_type_names.h" #include #include namespace mgk = mir::graphics::kms; namespace { bool encoder_is_used(mgk::DRMModeResources const& resources, uint32_t encoder_id) { if (encoder_id == 0) { BOOST_THROW_EXCEPTION(std::invalid_argument{"Attempted to query an encoder with invalid ID 0"}); } for (auto const& connector : resources.connectors()) { if (connector->encoder_id == encoder_id && connector->connection == DRM_MODE_CONNECTED) { auto encoder = resources.encoder(connector->encoder_id); if (encoder->crtc_id) { return true; } } } return false; } bool crtc_is_used(mgk::DRMModeResources const& resources, uint32_t crtc_id) { for (auto const& connector : resources.connectors()) { if (connector->connection == DRM_MODE_CONNECTED) { if (connector->encoder_id) { auto encoder = resources.encoder(connector->encoder_id); if (encoder->crtc_id == crtc_id) { return true; } } } } return false; } std::vector connector_available_encoders(mgk::DRMModeResources const& resources, drmModeConnector const* connector) { std::vector encoders; for (int i = 0; i < connector->count_encoders; i++) { if (!encoder_is_used(resources, connector->encoders[i])) encoders.push_back(resources.encoder(connector->encoders[i])); } return encoders; } bool encoder_supports_crtc_index(drmModeEncoder const* encoder, uint32_t crtc_index) { return (encoder->possible_crtcs & (1 << crtc_index)); } } std::string mgk::connector_name(mgk::DRMModeConnectorUPtr const& connector) { std::string name = mir::output_type_name(connector->connector_type); name += '-'; name += std::to_string(connector->connector_type_id); return name; } namespace { std::tuple find_crtc_and_index_for_connector( mgk::DRMModeResources const& resources, mgk::DRMModeConnectorUPtr const& connector) { int crtc_index = 0; auto const encoders = connector_available_encoders(resources, connector.get()); for (auto& crtc : resources.crtcs()) { if (!crtc_is_used(resources, crtc->crtc_id)) { for (auto& enc : encoders) { if (encoder_supports_crtc_index(enc.get(), crtc_index)) { return std::tuple{std::move(crtc), crtc_index}; } } } crtc_index++; } BOOST_THROW_EXCEPTION(std::runtime_error{"Failed to find CRTC"}); } } mgk::DRMModeCrtcUPtr mgk::find_crtc_for_connector(int drm_fd, mgk::DRMModeConnectorUPtr const& connector) { mgk::DRMModeResources resources{drm_fd}; /* If there is already a CRTC connected we can just return it */ if (connector->encoder_id) { auto encoder = resources.encoder(connector->encoder_id); if (encoder->crtc_id) { return resources.crtc(encoder->crtc_id); } } return std::get<0>(find_crtc_and_index_for_connector(resources, connector)); } auto mgk::find_crtc_with_primary_plane( int drm_fd, mgk::DRMModeConnectorUPtr const& connector) -> std::pair { /* * TODO: This currently has a sequential find-crtc-then-find-primary-plane-for-it algorithm. * This is needlessly restrictive - it will fail if the first available CRTC found doesn't have * an appropriate primary plane, even if other CRTCs are available and do have an appropriate plane. */ DRMModeCrtcUPtr crtc; DRMModeResources resources{drm_fd}; int crtc_index{-1}; /* If there's already a CRTC connected, find it */ if (connector->encoder_id) { auto encoder = get_encoder(drm_fd, connector->encoder_id); if (encoder->crtc_id) { /* There's already a CRTC connected; we only need to find its index */ auto our_crtc = std::find_if( resources.crtcs().begin(), resources.crtcs().end(), [crtc_id = encoder->crtc_id](mgk::DRMModeCrtcUPtr& crtc) { return crtc_id == crtc->crtc_id; }); if (our_crtc == resources.crtcs().end()) { BOOST_THROW_EXCEPTION(std::runtime_error{"Failed to find index of CRTC?!"}); } crtc = std::move(*our_crtc); crtc_index = std::distance(resources.crtcs().begin(), our_crtc); } } if (!crtc) { std::tie(crtc, crtc_index) = find_crtc_and_index_for_connector(resources, connector); } mgk::PlaneResources plane_res{drm_fd}; for (auto& plane : plane_res.planes()) { if (plane->possible_crtcs & (1 << crtc_index)) { ObjectProperties plane_props{drm_fd, plane->plane_id, DRM_MODE_OBJECT_PLANE}; if (plane_props["type"] == DRM_PLANE_TYPE_PRIMARY) { return std::make_pair(std::move(crtc), std::move(plane)); } } } BOOST_THROW_EXCEPTION(std::runtime_error{"Could not find primary plane for CRTC"}); } ./src/platforms/common/server/kms-utils/kms_connector.h0000644000004100000410000000400713115234664023612 0ustar www-datawww-data/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_GRAPHICS_COMMON_KMS_UTILS_KMS_CONNECTOR_H_ #define MIR_GRAPHICS_COMMON_KMS_UTILS_KMS_CONNECTOR_H_ #include "drm_mode_resources.h" #include #include #include namespace mir { namespace graphics { namespace kms { std::string connector_name(DRMModeConnectorUPtr const& connector); /** * Finds the first available CRTC that can drive Connector * * \note This only finds the first available connector. It does not * check whether currently-assigned resources could be reassigned, * so it's possible for this to fail even if it would be possible for * the total configuration to be set given global knowledge. * \param [in] drm_fd File descriptor to DRM node * \param [in] connector Connector to find a CRTC for. * \returns The first available CRTC which can display an image on connector. * The returned UPtr is guaranteed non-null. * \throws A std::runtime_error if there are no available CRTCs. */ DRMModeCrtcUPtr find_crtc_for_connector( int drm_fd, DRMModeConnectorUPtr const& connector); std::pair find_crtc_with_primary_plane( int drm_fd, DRMModeConnectorUPtr const& connector); } } } #endif //MIR_GRAPHICS_COMMON_KMS_UTILS_KMS_CONNECTOR_H ./src/platforms/common/server/kms-utils/drm_mode_resources.h0000644000004100000410000001163513115234664024633 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alexandros Frantzis */ #ifndef MIR_GRAPHICS_COMMON_KMS_UTILS_DRM_MODE_RESOURCES_H_ #define MIR_GRAPHICS_COMMON_KMS_UTILS_DRM_MODE_RESOURCES_H_ #include #include #include #include #include namespace mir { namespace graphics { namespace kms { typedef std::unique_ptr> DRMModeCrtcUPtr; typedef std::unique_ptr> DRMModeEncoderUPtr; typedef std::unique_ptr> DRMModeConnectorUPtr; typedef std::unique_ptr DRMModeResUPtr; typedef std::unique_ptr DRMModePlaneResUPtr; typedef std::unique_ptr> DRMModePlaneUPtr; typedef std::unique_ptr DRMModeObjectPropsUPtr; typedef std::unique_ptr DRMModePropertyUPtr; DRMModeConnectorUPtr get_connector(int drm_fd, uint32_t id); DRMModeEncoderUPtr get_encoder(int drm_fd, uint32_t id); DRMModeCrtcUPtr get_crtc(int drm_fd, uint32_t id); DRMModePlaneUPtr get_plane(int drm_fd, uint32_t id); class DRMModeResources; class PlaneResources; namespace detail { template class ObjectCollection { public: class iterator : public std::iterator { public: iterator(iterator const& from); iterator& operator=(iterator const& rhs); iterator& operator++(); iterator operator++(int); bool operator==(iterator const& rhs) const; bool operator!=(iterator const& rhs) const; DRMUPtr& operator*() const; DRMUPtr* operator->() const; private: friend class ObjectCollection; iterator(int drm_fd, uint32_t* id_ptr); int drm_fd; uint32_t* id_ptr; DRMUPtr mutable current; }; iterator begin(); iterator end(); private: friend class mir::graphics::kms::DRMModeResources; friend class mir::graphics::kms::PlaneResources; ObjectCollection(int drm_fd, uint32_t* begin, uint32_t* end); int const drm_fd; uint32_t* const begin_; uint32_t* const end_; }; } class ObjectProperties { public: struct Prop { uint32_t id; uint64_t value; }; ObjectProperties(int drm_fd, uint32_t object_id, uint32_t object_type); ObjectProperties(int drm_fd, DRMModePlaneUPtr const& plane); ObjectProperties(int drm_fd, DRMModeCrtcUPtr const& crtc); ObjectProperties(int drm_fd, DRMModeConnectorUPtr const& connector); uint64_t operator[](char const* name) const; uint32_t id_for(char const* property_name) const; bool has_property(char const* property_name) const; std::unordered_map::const_iterator begin() const; std::unordered_map::const_iterator end() const; private: std::unordered_map const properties_table; }; class PlaneResources { public: explicit PlaneResources(int drm_fd); detail::ObjectCollection planes() const; private: int const drm_fd; DRMModePlaneResUPtr const resources; }; class DRMModeResources { public: explicit DRMModeResources(int drm_fd); void for_each_connector(std::function const& f) const; void for_each_encoder(std::function const& f) const; void for_each_crtc(std::function const& f) const; size_t num_connectors() const; size_t num_encoders() const; size_t num_crtcs() const; DRMModeConnectorUPtr connector(uint32_t id) const; DRMModeEncoderUPtr encoder(uint32_t id) const; DRMModeCrtcUPtr crtc(uint32_t id) const; detail::ObjectCollection connectors() const; detail::ObjectCollection encoders() const; detail::ObjectCollection crtcs() const; private: int const drm_fd; DRMModeResUPtr const resources; }; } } } #endif /* MIR_GRAPHICS_COMMON_KMS_UTILS_DRM_MODE_RESOURCES_H_ */ ./src/platforms/common/server/anonymous_shm_file.cpp0000644000004100000410000000640213115234664023250 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Alexandros Frantzis */ #include "anonymous_shm_file.h" #include #include #include #include #include #include #include #include namespace mgc = mir::graphics::common; namespace { bool error_indicates_tmpfile_not_supported(int error) { return error == EISDIR || // Directory exists, but no support for O_TMPFILE error == ENOENT || // Directory doesn't exist, and no support for O_TMPFILE error == EOPNOTSUPP || // Filesystem that directory resides on does not support O_TMPFILE error == EINVAL; // There apparently exists at least one development board that has a kernel // that incorrectly returns EINVAL. Yay. } mir::Fd create_anonymous_file(size_t size) { auto raw_fd = open("/dev/shm", O_TMPFILE | O_RDWR | O_EXCL | O_CLOEXEC, S_IRWXU); // Workaround for filesystems that don't support O_TMPFILE if (raw_fd == -1 && error_indicates_tmpfile_not_supported(errno)) { char template_filename[] = "/dev/shm/mir-buffer-XXXXXX"; raw_fd = mkostemp(template_filename, O_CLOEXEC); if (raw_fd != -1) { if (unlink(template_filename) < 0) { close(raw_fd); raw_fd = -1; } } } if (raw_fd == -1) { BOOST_THROW_EXCEPTION( std::system_error(errno, std::system_category(), "Failed to open temporary file")); } mir::Fd fd = mir::Fd{raw_fd}; if (ftruncate(fd, size) == -1) { BOOST_THROW_EXCEPTION( std::system_error(errno, std::system_category(), "Failed to resize temporary file")); } return fd; } } /************* * MapHandle * *************/ mgc::detail::MapHandle::MapHandle(int fd, size_t size) : size{size}, mapping{mmap(nullptr, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)} { if (mapping == MAP_FAILED) BOOST_THROW_EXCEPTION( std::system_error(errno, std::system_category(), "Failed to map file")); } mgc::detail::MapHandle::~MapHandle() noexcept { munmap(mapping, size); } mgc::detail::MapHandle::operator void*() const { return mapping; } /******************** * AnonymousShmFile * ********************/ mgc::AnonymousShmFile::AnonymousShmFile(size_t size) : fd_{create_anonymous_file(size)}, mapping{fd_, size} { } void* mgc::AnonymousShmFile::base_ptr() const { return mapping; } int mgc::AnonymousShmFile::fd() const { return fd_; } ./src/platforms/common/server/shm_file.h0000644000004100000410000000225113115234664020603 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_SHM_FILE_H_ #define MIR_GRAPHICS_MESA_SHM_FILE_H_ #include namespace mir { namespace graphics { namespace common { class ShmFile { public: virtual ~ShmFile() = default; virtual void* base_ptr() const = 0; virtual int fd() const = 0; protected: ShmFile() = default; ShmFile(ShmFile const&) = delete; ShmFile& operator=(ShmFile const&) = delete; }; } } } #endif /* MIR_GRAPHICS_MESA_SHM_FILE_H_ */ ./src/platforms/common/server/shm_buffer.h0000644000004100000410000000506213115234664021140 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: * Alexandros Frantzis */ #ifndef MIR_GRAPHICS_MESA_SHM_BUFFER_H_ #define MIR_GRAPHICS_MESA_SHM_BUFFER_H_ #include "mir/graphics/buffer_basic.h" #include "mir/geometry/dimensions.h" #include "mir/geometry/size.h" #include "mir_toolkit/common.h" #include "mir/renderer/gl/texture_source.h" #include "mir_toolkit/mir_native_buffer.h" #include "mir/renderer/sw/pixel_source.h" namespace mir { namespace graphics { namespace common { class ShmFile; class ShmBuffer : public BufferBasic, public NativeBufferBase, public renderer::gl::TextureSource, public renderer::software::PixelSource { public: static bool supports(MirPixelFormat); ~ShmBuffer() noexcept; geometry::Size size() const override; geometry::Stride stride() const override; MirPixelFormat pixel_format() const override; void gl_bind_to_texture() override; void bind() override; void secure_for_render() override; void write(unsigned char const* data, size_t size) override; void read(std::function const& do_with_pixels) override; NativeBufferBase* native_buffer_base() override; //each platform will have to return the NativeBuffer type that the platform has defined. virtual std::shared_ptr native_buffer_handle() const override = 0; protected: ShmBuffer(std::unique_ptr shm_file, geometry::Size const& size, MirPixelFormat const& pixel_format); std::shared_ptr to_mir_buffer_package() const; private: ShmBuffer(ShmBuffer const&) = delete; ShmBuffer& operator=(ShmBuffer const&) = delete; std::unique_ptr const shm_file; geometry::Size const size_; MirPixelFormat const pixel_format_; geometry::Stride const stride_; void* const pixels; }; } } } #endif /* MIR_GRAPHICS_MESA_SHM_BUFFER_H_ */ ./src/protobuf/0000755000004100000410000000000013115234677013703 5ustar www-datawww-data./src/protobuf/CMakeLists.txt0000644000004100000410000000174413115234664016445 0ustar www-datawww-datainclude_directories( ${PROTOBUF_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) set( MIR_PROTOBUF_PROTOCOL_SPEC mir_protobuf_wire.proto mir_protobuf.proto ) protobuf_generate_cpp( GENERATED_PROTOBUF_SRCS GENERATED_PROTOBUF_HDRS ${MIR_PROTOBUF_PROTOCOL_SPEC} ) set(symbol_map ${CMAKE_SOURCE_DIR}/src/protobuf/symbols.map) add_library(mirprotobuf SHARED google_protobuf_guard.cpp ${GENERATED_PROTOBUF_SRCS} ${GENERATED_PROTOBUF_HDRS} ) target_link_libraries( mirprotobuf ${PROTOBUF_LITE_LIBRARIES} ) set(MIRPROTOBUF_ABI 3) set_target_properties( mirprotobuf PROPERTIES SOVERSION ${MIRPROTOBUF_ABI} LINK_FLAGS "-Wl,--version-script,${symbol_map}" LINK_DEPENDS ${symbol_map} ) # Export the include directories list(APPEND MIR_GENERATED_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_BINARY_DIR}) set( MIR_GENERATED_INCLUDE_DIRECTORIES ${MIR_GENERATED_INCLUDE_DIRECTORIES} PARENT_SCOPE) install( TARGETS mirprotobuf LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) ./src/protobuf/symbols.map0000644000004100000410000016270513115234664016101 0ustar www-datawww-dataMIR_PROTOBUF_3 { global: extern "C++" { mir::protobuf::BufferAllocation::?BufferAllocation*; mir::protobuf::BufferAllocation::BufferAllocation*; mir::protobuf::BufferAllocation::ByteSize*; mir::protobuf::BufferAllocation::CheckTypeAndMergeFrom*; mir::protobuf::BufferAllocation::Clear*; mir::protobuf::BufferAllocation::CopyFrom*; mir::protobuf::BufferAllocation::default_instance*; mir::protobuf::BufferAllocation::DiscardUnknownFields*; mir::protobuf::BufferAllocation::GetTypeName*; mir::protobuf::BufferAllocation::IsInitialized*; mir::protobuf::BufferAllocation::kBufferRequestsFieldNumber*; mir::protobuf::BufferAllocation::kIdFieldNumber*; mir::protobuf::BufferAllocation::MergeFrom*; mir::protobuf::BufferAllocation::MergePartialFromCodedStream*; mir::protobuf::BufferAllocation::New*; mir::protobuf::BufferAllocation::SerializeWithCachedSizes*; mir::protobuf::BufferAllocation::Swap*; mir::protobuf::Buffer::?Buffer*; mir::protobuf::Buffer::Buffer*; mir::protobuf::Buffer::ByteSize*; mir::protobuf::Buffer::CheckTypeAndMergeFrom*; mir::protobuf::Buffer::Clear*; mir::protobuf::Buffer::CopyFrom*; mir::protobuf::Buffer::default_instance*; mir::protobuf::Buffer::DiscardUnknownFields*; mir::protobuf::Buffer::GetTypeName*; mir::protobuf::Buffer::IsInitialized*; mir::protobuf::Buffer::kBufferIdFieldNumber*; mir::protobuf::Buffer::kDataFieldNumber*; mir::protobuf::Buffer::kErrorFieldNumber*; mir::protobuf::Buffer::kFdFieldNumber*; mir::protobuf::Buffer::kFdsOnSideChannelFieldNumber*; mir::protobuf::Buffer::kFlagsFieldNumber*; mir::protobuf::Buffer::kHeightFieldNumber*; mir::protobuf::Buffer::kStrideFieldNumber*; mir::protobuf::Buffer::kWidthFieldNumber*; mir::protobuf::Buffer::MergeFrom*; mir::protobuf::Buffer::MergePartialFromCodedStream*; mir::protobuf::Buffer::New*; mir::protobuf::BufferOperation_IsValid*; mir::protobuf::BufferOperation_MIN*; mir::protobuf::BufferOperation_ARRAYSIZE*; mir::protobuf::BufferOperation_MAX*; mir::protobuf::BufferRelease::?BufferRelease*; mir::protobuf::BufferRelease::BufferRelease*; mir::protobuf::BufferRelease::ByteSize*; mir::protobuf::BufferRelease::CheckTypeAndMergeFrom*; mir::protobuf::BufferRelease::Clear*; mir::protobuf::BufferRelease::CopyFrom*; mir::protobuf::BufferRelease::default_instance*; mir::protobuf::BufferRelease::DiscardUnknownFields*; mir::protobuf::BufferRelease::GetTypeName*; mir::protobuf::BufferRelease::IsInitialized*; mir::protobuf::BufferRelease::kBuffersFieldNumber*; mir::protobuf::BufferRelease::MergeFrom*; mir::protobuf::BufferRelease::MergePartialFromCodedStream*; mir::protobuf::BufferRelease::New*; mir::protobuf::BufferRelease::SerializeWithCachedSizes*; mir::protobuf::BufferRelease::Swap*; mir::protobuf::BufferRequest::?BufferRequest*; mir::protobuf::BufferRequest::BufferRequest*; mir::protobuf::BufferRequest::ByteSize*; mir::protobuf::BufferRequest::CheckTypeAndMergeFrom*; mir::protobuf::BufferRequest::Clear*; mir::protobuf::BufferRequest::CopyFrom*; mir::protobuf::BufferRequest::default_instance*; mir::protobuf::BufferRequest::DiscardUnknownFields*; mir::protobuf::BufferRequest::GetTypeName*; mir::protobuf::BufferRequest::IsInitialized*; mir::protobuf::BufferRequest::kBufferFieldNumber*; mir::protobuf::BufferRequest::kIdFieldNumber*; mir::protobuf::BufferRequest::MergeFrom*; mir::protobuf::BufferRequest::MergePartialFromCodedStream*; mir::protobuf::BufferRequest::New*; mir::protobuf::BufferRequest::SerializeWithCachedSizes*; mir::protobuf::BufferRequest::Swap*; mir::protobuf::Buffer::SerializeWithCachedSizes*; mir::protobuf::BufferStream::?BufferStream*; mir::protobuf::BufferStream::BufferStream*; mir::protobuf::BufferStream::ByteSize*; mir::protobuf::BufferStream::CheckTypeAndMergeFrom*; mir::protobuf::BufferStream::Clear*; mir::protobuf::BufferStream::CopyFrom*; mir::protobuf::BufferStream::default_instance*; mir::protobuf::BufferStream::DiscardUnknownFields*; mir::protobuf::BufferStream::GetTypeName*; mir::protobuf::BufferStreamId::?BufferStreamId*; mir::protobuf::BufferStreamId::BufferStreamId*; mir::protobuf::BufferStreamId::ByteSize*; mir::protobuf::BufferStreamId::CheckTypeAndMergeFrom*; mir::protobuf::BufferStreamId::Clear*; mir::protobuf::BufferStreamId::CopyFrom*; mir::protobuf::BufferStreamId::default_instance*; mir::protobuf::BufferStreamId::DiscardUnknownFields*; mir::protobuf::BufferStreamId::GetTypeName*; mir::protobuf::BufferStreamId::IsInitialized*; mir::protobuf::BufferStreamId::kValueFieldNumber*; mir::protobuf::BufferStreamId::MergeFrom*; mir::protobuf::BufferStreamId::MergePartialFromCodedStream*; mir::protobuf::BufferStreamId::New*; mir::protobuf::BufferStreamId::SerializeWithCachedSizes*; mir::protobuf::BufferStreamId::Swap*; mir::protobuf::BufferStream::IsInitialized*; mir::protobuf::BufferStream::kBufferFieldNumber*; mir::protobuf::BufferStream::kBufferUsageFieldNumber*; mir::protobuf::BufferStream::kErrorFieldNumber*; mir::protobuf::BufferStream::kIdFieldNumber*; mir::protobuf::BufferStream::kPixelFormatFieldNumber*; mir::protobuf::BufferStream::MergeFrom*; mir::protobuf::BufferStream::MergePartialFromCodedStream*; mir::protobuf::BufferStream::New*; mir::protobuf::BufferStreamParameters::?BufferStreamParameters*; mir::protobuf::BufferStreamParameters::BufferStreamParameters*; mir::protobuf::BufferStreamParameters::ByteSize*; mir::protobuf::BufferStreamParameters::CheckTypeAndMergeFrom*; mir::protobuf::BufferStreamParameters::Clear*; mir::protobuf::BufferStreamParameters::CopyFrom*; mir::protobuf::BufferStreamParameters::default_instance*; mir::protobuf::BufferStreamParameters::DiscardUnknownFields*; mir::protobuf::BufferStreamParameters::GetTypeName*; mir::protobuf::BufferStreamParameters::IsInitialized*; mir::protobuf::BufferStreamParameters::kBufferUsageFieldNumber*; mir::protobuf::BufferStreamParameters::kHeightFieldNumber*; mir::protobuf::BufferStreamParameters::kPixelFormatFieldNumber*; mir::protobuf::BufferStreamParameters::kWidthFieldNumber*; mir::protobuf::BufferStreamParameters::MergeFrom*; mir::protobuf::BufferStreamParameters::MergePartialFromCodedStream*; mir::protobuf::BufferStreamParameters::New*; mir::protobuf::BufferStreamParameters::SerializeWithCachedSizes*; mir::protobuf::BufferStreamParameters::Swap*; mir::protobuf::BufferStream::SerializeWithCachedSizes*; mir::protobuf::BufferStream::Swap*; mir::protobuf::Buffer::Swap*; mir::protobuf::Connection::ByteSize*; mir::protobuf::Connection::CheckTypeAndMergeFrom*; mir::protobuf::Connection::Clear*; mir::protobuf::Connection::?Connection*; mir::protobuf::Connection::Connection*; mir::protobuf::Connection::CopyFrom*; mir::protobuf::Connection::default_instance*; mir::protobuf::Connection::DiscardUnknownFields*; mir::protobuf::Connection::GetTypeName*; mir::protobuf::Connection::IsInitialized*; mir::protobuf::Connection::kDisplayConfigurationFieldNumber*; mir::protobuf::Connection::kDisplayOutputFieldNumber*; mir::protobuf::Connection::kErrorFieldNumber*; mir::protobuf::Connection::kPlatformFieldNumber*; mir::protobuf::Connection::kSurfacePixelFormatFieldNumber*; mir::protobuf::Connection::MergeFrom*; mir::protobuf::Connection::MergePartialFromCodedStream*; mir::protobuf::Connection::New*; mir::protobuf::Connection::SerializeWithCachedSizes*; mir::protobuf::Connection::Swap*; mir::protobuf::ConnectParameters::ByteSize*; mir::protobuf::ConnectParameters::CheckTypeAndMergeFrom*; mir::protobuf::ConnectParameters::Clear*; mir::protobuf::ConnectParameters::?ConnectParameters*; mir::protobuf::ConnectParameters::ConnectParameters*; mir::protobuf::ConnectParameters::CopyFrom*; mir::protobuf::ConnectParameters::default_instance*; mir::protobuf::ConnectParameters::DiscardUnknownFields*; mir::protobuf::ConnectParameters::GetTypeName*; mir::protobuf::ConnectParameters::IsInitialized*; mir::protobuf::ConnectParameters::kApplicationNameFieldNumber*; mir::protobuf::ConnectParameters::MergeFrom*; mir::protobuf::ConnectParameters::MergePartialFromCodedStream*; mir::protobuf::ConnectParameters::New*; mir::protobuf::ConnectParameters::SerializeWithCachedSizes*; mir::protobuf::ConnectParameters::Swap*; mir::protobuf::Cookie::ByteSize*; mir::protobuf::Cookie::CheckTypeAndMergeFrom*; mir::protobuf::Cookie::Clear*; mir::protobuf::Cookie::CopyFrom*; mir::protobuf::Cookie::default_instance*; mir::protobuf::Cookie::DiscardUnknownFields*; mir::protobuf::Cookie::GetTypeName*; mir::protobuf::Cookie::IsInitialized*; mir::protobuf::Cookie::kTimestampFieldNumber*; mir::protobuf::Cookie::kMacFieldNumber*; mir::protobuf::Cookie::MergeFrom*; mir::protobuf::Cookie::MergePartialFromCodedStream*; mir::protobuf::Cookie::New*; mir::protobuf::Cookie::?Cookie*; mir::protobuf::Cookie::Cookie*; mir::protobuf::Cookie::SerializeWithCachedSizes*; mir::protobuf::Cookie::Swap*; mir::protobuf::CoordinateTranslationRequest::ByteSize*; mir::protobuf::CoordinateTranslationRequest::CheckTypeAndMergeFrom*; mir::protobuf::CoordinateTranslationRequest::Clear*; mir::protobuf::CoordinateTranslationRequest::?CoordinateTranslationRequest*; mir::protobuf::CoordinateTranslationRequest::CoordinateTranslationRequest*; mir::protobuf::CoordinateTranslationRequest::CopyFrom*; mir::protobuf::CoordinateTranslationRequest::default_instance*; mir::protobuf::CoordinateTranslationRequest::DiscardUnknownFields*; mir::protobuf::CoordinateTranslationRequest::GetTypeName*; mir::protobuf::CoordinateTranslationRequest::IsInitialized*; mir::protobuf::CoordinateTranslationRequest::kSurfaceidFieldNumber*; mir::protobuf::CoordinateTranslationRequest::kXFieldNumber*; mir::protobuf::CoordinateTranslationRequest::kYFieldNumber*; mir::protobuf::CoordinateTranslationRequest::MergeFrom*; mir::protobuf::CoordinateTranslationRequest::MergePartialFromCodedStream*; mir::protobuf::CoordinateTranslationRequest::New*; mir::protobuf::CoordinateTranslationRequest::SerializeWithCachedSizes*; mir::protobuf::CoordinateTranslationRequest::Swap*; mir::protobuf::CoordinateTranslationResponse::ByteSize*; mir::protobuf::CoordinateTranslationResponse::CheckTypeAndMergeFrom*; mir::protobuf::CoordinateTranslationResponse::Clear*; mir::protobuf::CoordinateTranslationResponse::?CoordinateTranslationResponse*; mir::protobuf::CoordinateTranslationResponse::CoordinateTranslationResponse*; mir::protobuf::CoordinateTranslationResponse::CopyFrom*; mir::protobuf::CoordinateTranslationResponse::default_instance*; mir::protobuf::CoordinateTranslationResponse::DiscardUnknownFields*; mir::protobuf::CoordinateTranslationResponse::GetTypeName*; mir::protobuf::CoordinateTranslationResponse::IsInitialized*; mir::protobuf::CoordinateTranslationResponse::kErrorFieldNumber*; mir::protobuf::CoordinateTranslationResponse::kXFieldNumber*; mir::protobuf::CoordinateTranslationResponse::kYFieldNumber*; mir::protobuf::CoordinateTranslationResponse::MergeFrom*; mir::protobuf::CoordinateTranslationResponse::MergePartialFromCodedStream*; mir::protobuf::CoordinateTranslationResponse::New*; mir::protobuf::CoordinateTranslationResponse::SerializeWithCachedSizes*; mir::protobuf::CoordinateTranslationResponse::Swap*; mir::protobuf::CursorSetting::ByteSize*; mir::protobuf::CursorSetting::CheckTypeAndMergeFrom*; mir::protobuf::CursorSetting::Clear*; mir::protobuf::CursorSetting::CopyFrom*; mir::protobuf::CursorSetting::?CursorSetting*; mir::protobuf::CursorSetting::CursorSetting*; mir::protobuf::CursorSetting::default_instance*; mir::protobuf::CursorSetting::DiscardUnknownFields*; mir::protobuf::CursorSetting::GetTypeName*; mir::protobuf::CursorSetting::IsInitialized*; mir::protobuf::CursorSetting::kBufferStreamFieldNumber*; mir::protobuf::CursorSetting::kHotspotXFieldNumber*; mir::protobuf::CursorSetting::kHotspotYFieldNumber*; mir::protobuf::CursorSetting::kNameFieldNumber*; mir::protobuf::CursorSetting::kSurfaceidFieldNumber*; mir::protobuf::CursorSetting::MergeFrom*; mir::protobuf::CursorSetting::MergePartialFromCodedStream*; mir::protobuf::CursorSetting::New*; mir::protobuf::CursorSetting::SerializeWithCachedSizes*; mir::protobuf::CursorSetting::Swap*; mir::protobuf::DisplayCard::ByteSize*; mir::protobuf::DisplayCard::CheckTypeAndMergeFrom*; mir::protobuf::DisplayCard::Clear*; mir::protobuf::DisplayCard::CopyFrom*; mir::protobuf::DisplayCard::default_instance*; mir::protobuf::DisplayCard::DiscardUnknownFields*; mir::protobuf::DisplayCard::?DisplayCard*; mir::protobuf::DisplayCard::DisplayCard*; mir::protobuf::DisplayCard::GetTypeName*; mir::protobuf::DisplayCard::IsInitialized*; mir::protobuf::DisplayCard::kCardIdFieldNumber*; mir::protobuf::DisplayCard::kMaxSimultaneousOutputsFieldNumber*; mir::protobuf::DisplayCard::MergeFrom*; mir::protobuf::DisplayCard::MergePartialFromCodedStream*; mir::protobuf::DisplayCard::New*; mir::protobuf::DisplayCard::SerializeWithCachedSizes*; mir::protobuf::DisplayCard::Swap*; mir::protobuf::DisplayConfiguration::ByteSize*; mir::protobuf::DisplayConfiguration::CheckTypeAndMergeFrom*; mir::protobuf::DisplayConfiguration::Clear*; mir::protobuf::DisplayConfiguration::CopyFrom*; mir::protobuf::DisplayConfiguration::default_instance*; mir::protobuf::DisplayConfiguration::DiscardUnknownFields*; mir::protobuf::DisplayConfiguration::?DisplayConfiguration*; mir::protobuf::DisplayConfiguration::DisplayConfiguration*; mir::protobuf::DisplayConfiguration::GetTypeName*; mir::protobuf::DisplayConfiguration::IsInitialized*; mir::protobuf::DisplayConfiguration::kDisplayCardFieldNumber*; mir::protobuf::DisplayConfiguration::kDisplayOutputFieldNumber*; mir::protobuf::DisplayConfiguration::kErrorFieldNumber*; mir::protobuf::DisplayConfiguration::MergeFrom*; mir::protobuf::DisplayConfiguration::MergePartialFromCodedStream*; mir::protobuf::DisplayConfiguration::New*; mir::protobuf::DisplayConfiguration::SerializeWithCachedSizes*; mir::protobuf::DisplayConfiguration::Swap*; mir::protobuf::DisplayMode::ByteSize*; mir::protobuf::DisplayMode::CheckTypeAndMergeFrom*; mir::protobuf::DisplayMode::Clear*; mir::protobuf::DisplayMode::CopyFrom*; mir::protobuf::DisplayMode::default_instance*; mir::protobuf::DisplayMode::DiscardUnknownFields*; mir::protobuf::DisplayMode::?DisplayMode*; mir::protobuf::DisplayMode::DisplayMode*; mir::protobuf::DisplayMode::GetTypeName*; mir::protobuf::DisplayMode::IsInitialized*; mir::protobuf::DisplayMode::kHorizontalResolutionFieldNumber*; mir::protobuf::DisplayMode::kRefreshRateFieldNumber*; mir::protobuf::DisplayMode::kVerticalResolutionFieldNumber*; mir::protobuf::DisplayMode::MergeFrom*; mir::protobuf::DisplayMode::MergePartialFromCodedStream*; mir::protobuf::DisplayMode::New*; mir::protobuf::DisplayMode::SerializeWithCachedSizes*; mir::protobuf::DisplayMode::Swap*; mir::protobuf::DisplayOutput::ByteSize*; mir::protobuf::DisplayOutput::CheckTypeAndMergeFrom*; mir::protobuf::DisplayOutput::Clear*; mir::protobuf::DisplayOutput::CopyFrom*; mir::protobuf::DisplayOutput::default_instance*; mir::protobuf::DisplayOutput::DiscardUnknownFields*; mir::protobuf::DisplayOutput::?DisplayOutput*; mir::protobuf::DisplayOutput::DisplayOutput*; mir::protobuf::DisplayOutput::GetTypeName*; mir::protobuf::DisplayOutput::IsInitialized*; mir::protobuf::DisplayOutput::kCardIdFieldNumber*; mir::protobuf::DisplayOutput::kConnectedFieldNumber*; mir::protobuf::DisplayOutput::kCurrentFormatFieldNumber*; mir::protobuf::DisplayOutput::kCurrentModeFieldNumber*; mir::protobuf::DisplayOutput::kModeFieldNumber*; mir::protobuf::DisplayOutput::kOrientationFieldNumber*; mir::protobuf::DisplayOutput::kOutputIdFieldNumber*; mir::protobuf::DisplayOutput::kPhysicalHeightMmFieldNumber*; mir::protobuf::DisplayOutput::kPhysicalWidthMmFieldNumber*; mir::protobuf::DisplayOutput::kPixelFormatFieldNumber*; mir::protobuf::DisplayOutput::kPositionXFieldNumber*; mir::protobuf::DisplayOutput::kPositionYFieldNumber*; mir::protobuf::DisplayOutput::kPowerModeFieldNumber*; mir::protobuf::DisplayOutput::kPreferredModeFieldNumber*; mir::protobuf::DisplayOutput::kTypeFieldNumber*; mir::protobuf::DisplayOutput::kUsedFieldNumber*; mir::protobuf::DisplayOutput::MergeFrom*; mir::protobuf::DisplayOutput::MergePartialFromCodedStream*; mir::protobuf::DisplayOutput::New*; mir::protobuf::DisplayOutput::SerializeWithCachedSizes*; mir::protobuf::DisplayOutput::Swap*; mir::protobuf::Event::ByteSize*; mir::protobuf::Event::CheckTypeAndMergeFrom*; mir::protobuf::Event::Clear*; mir::protobuf::Event::CopyFrom*; mir::protobuf::Event::default_instance*; mir::protobuf::Event::DiscardUnknownFields*; mir::protobuf::Event::?Event*; mir::protobuf::Event::Event*; mir::protobuf::Event::GetTypeName*; mir::protobuf::Event::IsInitialized*; mir::protobuf::Event::kRawFieldNumber*; mir::protobuf::Event::MergeFrom*; mir::protobuf::Event::MergePartialFromCodedStream*; mir::protobuf::Event::New*; mir::protobuf::EventSequence::ByteSize*; mir::protobuf::EventSequence::CheckTypeAndMergeFrom*; mir::protobuf::EventSequence::Clear*; mir::protobuf::EventSequence::CopyFrom*; mir::protobuf::EventSequence::default_instance*; mir::protobuf::EventSequence::DiscardUnknownFields*; mir::protobuf::EventSequence::?EventSequence*; mir::protobuf::EventSequence::EventSequence*; mir::protobuf::EventSequence::GetTypeName*; mir::protobuf::EventSequence::IsInitialized*; mir::protobuf::EventSequence::kBufferRequestFieldNumber*; mir::protobuf::EventSequence::kDisplayConfigurationFieldNumber*; mir::protobuf::EventSequence::kErrorFieldNumber*; mir::protobuf::EventSequence::kEventFieldNumber*; mir::protobuf::EventSequence::kLifecycleEventFieldNumber*; mir::protobuf::EventSequence::kPingEventFieldNumber*; mir::protobuf::EventSequence::MergeFrom*; mir::protobuf::EventSequence::MergePartialFromCodedStream*; mir::protobuf::EventSequence::New*; mir::protobuf::EventSequence::SerializeWithCachedSizes*; mir::protobuf::EventSequence::Swap*; mir::protobuf::Event::SerializeWithCachedSizes*; mir::protobuf::Event::Swap*; mir::protobuf::InputDeviceEvent::?InputDeviceEvent*; mir::protobuf::InputDeviceEvent::InputDeviceEvent*; mir::protobuf::InputDeviceEvent::New*; mir::protobuf::InputDeviceEvent::Swap*; mir::protobuf::InputDeviceInfo::?InputDeviceInfo*; mir::protobuf::InputDeviceInfo::InputDeviceInfo*; mir::protobuf::InputDeviceInfo::New*; mir::protobuf::InputDeviceInfo::Swap*; mir::protobuf::LifecycleEvent::ByteSize*; mir::protobuf::LifecycleEvent::CheckTypeAndMergeFrom*; mir::protobuf::LifecycleEvent::Clear*; mir::protobuf::LifecycleEvent::CopyFrom*; mir::protobuf::LifecycleEvent::default_instance*; mir::protobuf::LifecycleEvent::DiscardUnknownFields*; mir::protobuf::LifecycleEvent::GetTypeName*; mir::protobuf::LifecycleEvent::IsInitialized*; mir::protobuf::LifecycleEvent::kErrorFieldNumber*; mir::protobuf::LifecycleEvent::kNewStateFieldNumber*; mir::protobuf::LifecycleEvent::?LifecycleEvent*; mir::protobuf::LifecycleEvent::LifecycleEvent*; mir::protobuf::LifecycleEvent::MergeFrom*; mir::protobuf::LifecycleEvent::MergePartialFromCodedStream*; mir::protobuf::LifecycleEvent::New*; mir::protobuf::LifecycleEvent::SerializeWithCachedSizes*; mir::protobuf::LifecycleEvent::Swap*; mir::protobuf::PersistentSurfaceId::ByteSize*; mir::protobuf::PersistentSurfaceId::CheckTypeAndMergeFrom*; mir::protobuf::PersistentSurfaceId::Clear*; mir::protobuf::PersistentSurfaceId::CopyFrom*; mir::protobuf::PersistentSurfaceId::default_instance*; mir::protobuf::PersistentSurfaceId::DiscardUnknownFields*; mir::protobuf::PersistentSurfaceId::GetTypeName*; mir::protobuf::PersistentSurfaceId::IsInitialized*; mir::protobuf::PersistentSurfaceId::kErrorFieldNumber*; mir::protobuf::PersistentSurfaceId::kValueFieldNumber*; mir::protobuf::PersistentSurfaceId::MergeFrom*; mir::protobuf::PersistentSurfaceId::MergePartialFromCodedStream*; mir::protobuf::PersistentSurfaceId::New*; mir::protobuf::PersistentSurfaceId::?PersistentSurfaceId*; mir::protobuf::PersistentSurfaceId::PersistentSurfaceId*; mir::protobuf::PersistentSurfaceId::SerializeWithCachedSizes*; mir::protobuf::PersistentSurfaceId::Swap*; mir::protobuf::PingEvent::ByteSize*; mir::protobuf::PingEvent::CheckTypeAndMergeFrom*; mir::protobuf::PingEvent::Clear*; mir::protobuf::PingEvent::CopyFrom*; mir::protobuf::PingEvent::default_instance*; mir::protobuf::PingEvent::DiscardUnknownFields*; mir::protobuf::PingEvent::GetTypeName*; mir::protobuf::PingEvent::IsInitialized*; mir::protobuf::PingEvent::kSerialFieldNumber*; mir::protobuf::PingEvent::MergeFrom*; mir::protobuf::PingEvent::MergePartialFromCodedStream*; mir::protobuf::PingEvent::New*; mir::protobuf::PingEvent::?PingEvent*; mir::protobuf::PingEvent::PingEvent*; mir::protobuf::PingEvent::SerializeWithCachedSizes*; mir::protobuf::PingEvent::Swap*; mir::protobuf::Platform::ByteSize*; mir::protobuf::Platform::CheckTypeAndMergeFrom*; mir::protobuf::Platform::Clear*; mir::protobuf::Platform::CopyFrom*; mir::protobuf::Platform::default_instance*; mir::protobuf::Platform::DiscardUnknownFields*; mir::protobuf::Platform::GetTypeName*; mir::protobuf::Platform::IsInitialized*; mir::protobuf::Platform::kDataFieldNumber*; mir::protobuf::Platform::kErrorFieldNumber*; mir::protobuf::Platform::kFdFieldNumber*; mir::protobuf::Platform::kFdsOnSideChannelFieldNumber*; mir::protobuf::Platform::MergeFrom*; mir::protobuf::Platform::MergePartialFromCodedStream*; mir::protobuf::Platform::New*; mir::protobuf::PlatformOperationMessage::ByteSize*; mir::protobuf::PlatformOperationMessage::CheckTypeAndMergeFrom*; mir::protobuf::PlatformOperationMessage::Clear*; mir::protobuf::PlatformOperationMessage::CopyFrom*; mir::protobuf::PlatformOperationMessage::default_instance*; mir::protobuf::PlatformOperationMessage::DiscardUnknownFields*; mir::protobuf::PlatformOperationMessage::GetTypeName*; mir::protobuf::PlatformOperationMessage::IsInitialized*; mir::protobuf::PlatformOperationMessage::kDataFieldNumber*; mir::protobuf::PlatformOperationMessage::kErrorFieldNumber*; mir::protobuf::PlatformOperationMessage::kFdFieldNumber*; mir::protobuf::PlatformOperationMessage::kFdsOnSideChannelFieldNumber*; mir::protobuf::PlatformOperationMessage::kOpcodeFieldNumber*; mir::protobuf::PlatformOperationMessage::MergeFrom*; mir::protobuf::PlatformOperationMessage::MergePartialFromCodedStream*; mir::protobuf::PlatformOperationMessage::New*; mir::protobuf::PlatformOperationMessage::?PlatformOperationMessage*; mir::protobuf::PlatformOperationMessage::PlatformOperationMessage*; mir::protobuf::PlatformOperationMessage::SerializeWithCachedSizes*; mir::protobuf::PlatformOperationMessage::Swap*; mir::protobuf::Platform::?Platform*; mir::protobuf::Platform::Platform*; mir::protobuf::Platform::SerializeWithCachedSizes*; mir::protobuf::Platform::Swap*; mir::protobuf::PromptSessionParameters::ByteSize*; mir::protobuf::PromptSessionParameters::CheckTypeAndMergeFrom*; mir::protobuf::PromptSessionParameters::Clear*; mir::protobuf::PromptSessionParameters::CopyFrom*; mir::protobuf::PromptSessionParameters::default_instance*; mir::protobuf::PromptSessionParameters::DiscardUnknownFields*; mir::protobuf::PromptSessionParameters::GetTypeName*; mir::protobuf::PromptSessionParameters::IsInitialized*; mir::protobuf::PromptSessionParameters::kApplicationPidFieldNumber*; mir::protobuf::PromptSessionParameters::MergeFrom*; mir::protobuf::PromptSessionParameters::MergePartialFromCodedStream*; mir::protobuf::PromptSessionParameters::New*; mir::protobuf::PromptSessionParameters::?PromptSessionParameters*; mir::protobuf::PromptSessionParameters::PromptSessionParameters*; mir::protobuf::PromptSessionParameters::SerializeWithCachedSizes*; mir::protobuf::PromptSessionParameters::Swap*; mir::protobuf::protobuf_AddDesc_mir_5fprotobuf_2eproto*; mir::protobuf::protobuf_AssignDesc_mir_5fprotobuf_2eproto*; mir::protobuf::protobuf_ShutdownFile_mir_5fprotobuf_2eproto*; mir::protobuf::RaiseRequest::ByteSize*; mir::protobuf::RaiseRequest::CheckTypeAndMergeFrom*; mir::protobuf::RaiseRequest::Clear*; mir::protobuf::RaiseRequest::CopyFrom*; mir::protobuf::RaiseRequest::default_instance*; mir::protobuf::RaiseRequest::DiscardUnknownFields*; mir::protobuf::RaiseRequest::GetTypeName*; mir::protobuf::RaiseRequest::IsInitialized*; mir::protobuf::RaiseRequest::kCookieFieldNumber*; mir::protobuf::RaiseRequest::kSurfaceIdFieldNumber*; mir::protobuf::RaiseRequest::MergeFrom*; mir::protobuf::RaiseRequest::MergePartialFromCodedStream*; mir::protobuf::RaiseRequest::New*; mir::protobuf::RaiseRequest::?RaiseRequest*; mir::protobuf::RaiseRequest::RaiseRequest*; mir::protobuf::RaiseRequest::SerializeWithCachedSizes*; mir::protobuf::RaiseRequest::Swap*; mir::protobuf::Rectangle::ByteSize*; mir::protobuf::Rectangle::CheckTypeAndMergeFrom*; mir::protobuf::Rectangle::Clear*; mir::protobuf::Rectangle::CopyFrom*; mir::protobuf::Rectangle::default_instance*; mir::protobuf::Rectangle::DiscardUnknownFields*; mir::protobuf::Rectangle::GetTypeName*; mir::protobuf::Rectangle::IsInitialized*; mir::protobuf::Rectangle::kHeightFieldNumber*; mir::protobuf::Rectangle::kLeftFieldNumber*; mir::protobuf::Rectangle::kTopFieldNumber*; mir::protobuf::Rectangle::kWidthFieldNumber*; mir::protobuf::Rectangle::MergeFrom*; mir::protobuf::Rectangle::MergePartialFromCodedStream*; mir::protobuf::Rectangle::New*; mir::protobuf::Rectangle::?Rectangle*; mir::protobuf::Rectangle::Rectangle*; mir::protobuf::Rectangle::SerializeWithCachedSizes*; mir::protobuf::Rectangle::Swap*; mir::protobuf::Screencast::ByteSize*; mir::protobuf::Screencast::CheckTypeAndMergeFrom*; mir::protobuf::Screencast::Clear*; mir::protobuf::Screencast::CopyFrom*; mir::protobuf::Screencast::default_instance*; mir::protobuf::Screencast::DiscardUnknownFields*; mir::protobuf::Screencast::GetTypeName*; mir::protobuf::ScreencastId::ByteSize*; mir::protobuf::ScreencastId::CheckTypeAndMergeFrom*; mir::protobuf::ScreencastId::Clear*; mir::protobuf::ScreencastId::CopyFrom*; mir::protobuf::ScreencastId::default_instance*; mir::protobuf::ScreencastId::DiscardUnknownFields*; mir::protobuf::ScreencastId::GetTypeName*; mir::protobuf::ScreencastId::IsInitialized*; mir::protobuf::ScreencastId::kValueFieldNumber*; mir::protobuf::ScreencastId::MergeFrom*; mir::protobuf::ScreencastId::MergePartialFromCodedStream*; mir::protobuf::ScreencastId::New*; mir::protobuf::ScreencastId::?ScreencastId*; mir::protobuf::ScreencastId::ScreencastId*; mir::protobuf::ScreencastId::SerializeWithCachedSizes*; mir::protobuf::ScreencastId::Swap*; mir::protobuf::Screencast::IsInitialized*; mir::protobuf::Screencast::kBufferFieldNumber*; mir::protobuf::Screencast::kBufferStreamFieldNumber*; mir::protobuf::Screencast::kErrorFieldNumber*; mir::protobuf::Screencast::kScreencastIdFieldNumber*; mir::protobuf::Screencast::MergeFrom*; mir::protobuf::Screencast::MergePartialFromCodedStream*; mir::protobuf::Screencast::New*; mir::protobuf::ScreencastParameters::ByteSize*; mir::protobuf::ScreencastParameters::CheckTypeAndMergeFrom*; mir::protobuf::ScreencastParameters::Clear*; mir::protobuf::ScreencastParameters::CopyFrom*; mir::protobuf::ScreencastParameters::default_instance*; mir::protobuf::ScreencastParameters::DiscardUnknownFields*; mir::protobuf::ScreencastParameters::GetTypeName*; mir::protobuf::ScreencastParameters::IsInitialized*; mir::protobuf::ScreencastParameters::kHeightFieldNumber*; mir::protobuf::ScreencastParameters::kPixelFormatFieldNumber*; mir::protobuf::ScreencastParameters::kRegionFieldNumber*; mir::protobuf::ScreencastParameters::kWidthFieldNumber*; mir::protobuf::ScreencastParameters::MergeFrom*; mir::protobuf::ScreencastParameters::MergePartialFromCodedStream*; mir::protobuf::ScreencastParameters::New*; mir::protobuf::ScreencastParameters::?ScreencastParameters*; mir::protobuf::ScreencastParameters::ScreencastParameters*; mir::protobuf::ScreencastParameters::SerializeWithCachedSizes*; mir::protobuf::ScreencastParameters::Swap*; mir::protobuf::Screencast::?Screencast*; mir::protobuf::Screencast::Screencast*; mir::protobuf::Screencast::SerializeWithCachedSizes*; mir::protobuf::Screencast::Swap*; mir::protobuf::SocketFD::ByteSize*; mir::protobuf::SocketFD::CheckTypeAndMergeFrom*; mir::protobuf::SocketFD::Clear*; mir::protobuf::SocketFD::CopyFrom*; mir::protobuf::SocketFD::default_instance*; mir::protobuf::SocketFD::DiscardUnknownFields*; mir::protobuf::SocketFD::GetTypeName*; mir::protobuf::SocketFD::IsInitialized*; mir::protobuf::SocketFD::kErrorFieldNumber*; mir::protobuf::SocketFD::kFdFieldNumber*; mir::protobuf::SocketFD::kFdsOnSideChannelFieldNumber*; mir::protobuf::SocketFD::MergeFrom*; mir::protobuf::SocketFD::MergePartialFromCodedStream*; mir::protobuf::SocketFD::New*; mir::protobuf::SocketFDRequest::ByteSize*; mir::protobuf::SocketFDRequest::CheckTypeAndMergeFrom*; mir::protobuf::SocketFDRequest::Clear*; mir::protobuf::SocketFDRequest::CopyFrom*; mir::protobuf::SocketFDRequest::default_instance*; mir::protobuf::SocketFDRequest::DiscardUnknownFields*; mir::protobuf::SocketFDRequest::GetTypeName*; mir::protobuf::SocketFDRequest::IsInitialized*; mir::protobuf::SocketFDRequest::kNumberFieldNumber*; mir::protobuf::SocketFDRequest::MergeFrom*; mir::protobuf::SocketFDRequest::MergePartialFromCodedStream*; mir::protobuf::SocketFDRequest::New*; mir::protobuf::SocketFDRequest::SerializeWithCachedSizes*; mir::protobuf::SocketFDRequest::?SocketFDRequest*; mir::protobuf::SocketFDRequest::SocketFDRequest*; mir::protobuf::SocketFDRequest::Swap*; mir::protobuf::SocketFD::SerializeWithCachedSizes*; mir::protobuf::SocketFD::?SocketFD*; mir::protobuf::SocketFD::SocketFD*; mir::protobuf::SocketFD::Swap*; mir::protobuf::static_descriptor_initializer_mir_5fprotobuf_2eproto_*; mir::protobuf::StreamConfiguration::ByteSize*; mir::protobuf::StreamConfiguration::CheckTypeAndMergeFrom*; mir::protobuf::StreamConfiguration::Clear*; mir::protobuf::StreamConfiguration::CopyFrom*; mir::protobuf::StreamConfiguration::default_instance*; mir::protobuf::StreamConfiguration::DiscardUnknownFields*; mir::protobuf::StreamConfiguration::GetTypeName*; mir::protobuf::StreamConfiguration::IsInitialized*; mir::protobuf::StreamConfiguration::kDisplacementXFieldNumber*; mir::protobuf::StreamConfiguration::kDisplacementYFieldNumber*; mir::protobuf::StreamConfiguration::kIdFieldNumber*; mir::protobuf::StreamConfiguration::MergeFrom*; mir::protobuf::StreamConfiguration::MergePartialFromCodedStream*; mir::protobuf::StreamConfiguration::New*; mir::protobuf::StreamConfiguration::SerializeWithCachedSizes*; mir::protobuf::StreamConfiguration::?StreamConfiguration*; mir::protobuf::StreamConfiguration::StreamConfiguration*; mir::protobuf::StreamConfiguration::Swap*; mir::protobuf::StructuredError::StructuredError*; mir::protobuf::SurfaceAspectRatio::ByteSize*; mir::protobuf::SurfaceAspectRatio::CheckTypeAndMergeFrom*; mir::protobuf::SurfaceAspectRatio::Clear*; mir::protobuf::SurfaceAspectRatio::CopyFrom*; mir::protobuf::SurfaceAspectRatio::default_instance*; mir::protobuf::SurfaceAspectRatio::DiscardUnknownFields*; mir::protobuf::SurfaceAspectRatio::GetTypeName*; mir::protobuf::SurfaceAspectRatio::IsInitialized*; mir::protobuf::SurfaceAspectRatio::kHeightFieldNumber*; mir::protobuf::SurfaceAspectRatio::kWidthFieldNumber*; mir::protobuf::SurfaceAspectRatio::MergeFrom*; mir::protobuf::SurfaceAspectRatio::MergePartialFromCodedStream*; mir::protobuf::SurfaceAspectRatio::New*; mir::protobuf::SurfaceAspectRatio::SerializeWithCachedSizes*; mir::protobuf::SurfaceAspectRatio::?SurfaceAspectRatio*; mir::protobuf::SurfaceAspectRatio::SurfaceAspectRatio*; mir::protobuf::SurfaceAspectRatio::Swap*; mir::protobuf::Surface::ByteSize*; mir::protobuf::Surface::CheckTypeAndMergeFrom*; mir::protobuf::Surface::Clear*; mir::protobuf::Surface::CopyFrom*; mir::protobuf::Surface::default_instance*; mir::protobuf::Surface::DiscardUnknownFields*; mir::protobuf::Surface::GetTypeName*; mir::protobuf::SurfaceId::ByteSize*; mir::protobuf::SurfaceId::CheckTypeAndMergeFrom*; mir::protobuf::SurfaceId::Clear*; mir::protobuf::SurfaceId::CopyFrom*; mir::protobuf::SurfaceId::default_instance*; mir::protobuf::SurfaceId::DiscardUnknownFields*; mir::protobuf::SurfaceId::GetTypeName*; mir::protobuf::SurfaceId::IsInitialized*; mir::protobuf::SurfaceId::kValueFieldNumber*; mir::protobuf::SurfaceId::MergeFrom*; mir::protobuf::SurfaceId::MergePartialFromCodedStream*; mir::protobuf::SurfaceId::New*; mir::protobuf::SurfaceId::SerializeWithCachedSizes*; mir::protobuf::SurfaceId::?SurfaceId*; mir::protobuf::SurfaceId::SurfaceId*; mir::protobuf::SurfaceId::Swap*; mir::protobuf::Surface::IsInitialized*; mir::protobuf::Surface::kAttributesFieldNumber*; mir::protobuf::Surface::kBufferFieldNumber*; mir::protobuf::Surface::kBufferStreamFieldNumber*; mir::protobuf::Surface::kBufferUsageFieldNumber*; mir::protobuf::Surface::kErrorFieldNumber*; mir::protobuf::Surface::kFdFieldNumber*; mir::protobuf::Surface::kFdsOnSideChannelFieldNumber*; mir::protobuf::Surface::kHeightFieldNumber*; mir::protobuf::Surface::kIdFieldNumber*; mir::protobuf::Surface::kPixelFormatFieldNumber*; mir::protobuf::Surface::kWidthFieldNumber*; mir::protobuf::Surface::MergeFrom*; mir::protobuf::Surface::MergePartialFromCodedStream*; mir::protobuf::SurfaceModifications::ByteSize*; mir::protobuf::SurfaceModifications::CheckTypeAndMergeFrom*; mir::protobuf::SurfaceModifications::Clear*; mir::protobuf::SurfaceModifications::CopyFrom*; mir::protobuf::SurfaceModifications::default_instance*; mir::protobuf::SurfaceModifications::DiscardUnknownFields*; mir::protobuf::SurfaceModifications::GetTypeName*; mir::protobuf::SurfaceModifications::IsInitialized*; mir::protobuf::SurfaceModifications::kSurfaceIdFieldNumber*; mir::protobuf::SurfaceModifications::kSurfaceSpecificationFieldNumber*; mir::protobuf::SurfaceModifications::MergeFrom*; mir::protobuf::SurfaceModifications::MergePartialFromCodedStream*; mir::protobuf::SurfaceModifications::New*; mir::protobuf::SurfaceModifications::SerializeWithCachedSizes*; mir::protobuf::SurfaceModifications::?SurfaceModifications*; mir::protobuf::SurfaceModifications::SurfaceModifications*; mir::protobuf::SurfaceModifications::Swap*; mir::protobuf::Surface::New*; mir::protobuf::SurfaceParameters::ByteSize*; mir::protobuf::SurfaceParameters::CheckTypeAndMergeFrom*; mir::protobuf::SurfaceParameters::Clear*; mir::protobuf::SurfaceParameters::CopyFrom*; mir::protobuf::SurfaceParameters::default_instance*; mir::protobuf::SurfaceParameters::DiscardUnknownFields*; mir::protobuf::SurfaceParameters::GetTypeName*; mir::protobuf::SurfaceParameters::IsInitialized*; mir::protobuf::SurfaceParameters::kAuxRectFieldNumber*; mir::protobuf::SurfaceParameters::kBufferUsageFieldNumber*; mir::protobuf::SurfaceParameters::kEdgeAttachmentFieldNumber*; mir::protobuf::SurfaceParameters::kHeightFieldNumber*; mir::protobuf::SurfaceParameters::kHeightIncFieldNumber*; mir::protobuf::SurfaceParameters::kInputShapeFieldNumber*; mir::protobuf::SurfaceParameters::kMaxAspectFieldNumber*; mir::protobuf::SurfaceParameters::kMaxHeightFieldNumber*; mir::protobuf::SurfaceParameters::kMaxWidthFieldNumber*; mir::protobuf::SurfaceParameters::kMinAspectFieldNumber*; mir::protobuf::SurfaceParameters::kMinHeightFieldNumber*; mir::protobuf::SurfaceParameters::kMinWidthFieldNumber*; mir::protobuf::SurfaceParameters::kOutputIdFieldNumber*; mir::protobuf::SurfaceParameters::kParentIdFieldNumber*; mir::protobuf::SurfaceParameters::kParentPersistentIdFieldNumber*; mir::protobuf::SurfaceParameters::kPixelFormatFieldNumber*; mir::protobuf::SurfaceParameters::kPrefOrientationFieldNumber*; mir::protobuf::SurfaceParameters::kStateFieldNumber*; mir::protobuf::SurfaceParameters::kSurfaceNameFieldNumber*; mir::protobuf::SurfaceParameters::kTypeFieldNumber*; mir::protobuf::SurfaceParameters::kWidthFieldNumber*; mir::protobuf::SurfaceParameters::kWidthIncFieldNumber*; mir::protobuf::SurfaceParameters::MergeFrom*; mir::protobuf::SurfaceParameters::MergePartialFromCodedStream*; mir::protobuf::SurfaceParameters::New*; mir::protobuf::SurfaceParameters::SerializeWithCachedSizes*; mir::protobuf::SurfaceParameters::?SurfaceParameters*; mir::protobuf::SurfaceParameters::SurfaceParameters*; mir::protobuf::SurfaceParameters::Swap*; mir::protobuf::Surface::SerializeWithCachedSizes*; mir::protobuf::SurfaceSetting::ByteSize*; mir::protobuf::SurfaceSetting::CheckTypeAndMergeFrom*; mir::protobuf::SurfaceSetting::Clear*; mir::protobuf::SurfaceSetting::CopyFrom*; mir::protobuf::SurfaceSetting::default_instance*; mir::protobuf::SurfaceSetting::DiscardUnknownFields*; mir::protobuf::SurfaceSetting::GetTypeName*; mir::protobuf::SurfaceSetting::IsInitialized*; mir::protobuf::SurfaceSetting::kAttribFieldNumber*; mir::protobuf::SurfaceSetting::kErrorFieldNumber*; mir::protobuf::SurfaceSetting::kIvalueFieldNumber*; mir::protobuf::SurfaceSetting::kSurfaceidFieldNumber*; mir::protobuf::SurfaceSetting::MergeFrom*; mir::protobuf::SurfaceSetting::MergePartialFromCodedStream*; mir::protobuf::SurfaceSetting::New*; mir::protobuf::SurfaceSetting::SerializeWithCachedSizes*; mir::protobuf::SurfaceSetting::?SurfaceSetting*; mir::protobuf::SurfaceSetting::SurfaceSetting*; mir::protobuf::SurfaceSetting::Swap*; mir::protobuf::SurfaceSpecification::ByteSize*; mir::protobuf::SurfaceSpecification::CheckTypeAndMergeFrom*; mir::protobuf::SurfaceSpecification::Clear*; mir::protobuf::SurfaceSpecification::CopyFrom*; mir::protobuf::SurfaceSpecification::default_instance*; mir::protobuf::SurfaceSpecification::DiscardUnknownFields*; mir::protobuf::SurfaceSpecification::GetTypeName*; mir::protobuf::SurfaceSpecification::IsInitialized*; mir::protobuf::SurfaceSpecification::kAuxRectFieldNumber*; mir::protobuf::SurfaceSpecification::kBufferUsageFieldNumber*; mir::protobuf::SurfaceSpecification::kEdgeAttachmentFieldNumber*; mir::protobuf::SurfaceSpecification::kHeightFieldNumber*; mir::protobuf::SurfaceSpecification::kHeightIncFieldNumber*; mir::protobuf::SurfaceSpecification::kInputShapeFieldNumber*; mir::protobuf::SurfaceSpecification::kMaxAspectFieldNumber*; mir::protobuf::SurfaceSpecification::kMaxHeightFieldNumber*; mir::protobuf::SurfaceSpecification::kMaxWidthFieldNumber*; mir::protobuf::SurfaceSpecification::kMinAspectFieldNumber*; mir::protobuf::SurfaceSpecification::kMinHeightFieldNumber*; mir::protobuf::SurfaceSpecification::kMinWidthFieldNumber*; mir::protobuf::SurfaceSpecification::kNameFieldNumber*; mir::protobuf::SurfaceSpecification::kOutputIdFieldNumber*; mir::protobuf::SurfaceSpecification::kParentIdFieldNumber*; mir::protobuf::SurfaceSpecification::kParentPersistentIdFieldNumber*; mir::protobuf::SurfaceSpecification::kPixelFormatFieldNumber*; mir::protobuf::SurfaceSpecification::kPreferredOrientationFieldNumber*; mir::protobuf::SurfaceSpecification::kStateFieldNumber*; mir::protobuf::SurfaceSpecification::kStreamFieldNumber*; mir::protobuf::SurfaceSpecification::kTypeFieldNumber*; mir::protobuf::SurfaceSpecification::kWidthFieldNumber*; mir::protobuf::SurfaceSpecification::kWidthIncFieldNumber*; mir::protobuf::SurfaceSpecification::MergeFrom*; mir::protobuf::SurfaceSpecification::MergePartialFromCodedStream*; mir::protobuf::SurfaceSpecification::New*; mir::protobuf::SurfaceSpecification::SerializeWithCachedSizes*; mir::protobuf::SurfaceSpecification::?SurfaceSpecification*; mir::protobuf::SurfaceSpecification::SurfaceSpecification*; mir::protobuf::SurfaceSpecification::Swap*; mir::protobuf::Surface::?Surface*; mir::protobuf::Surface::Surface*; mir::protobuf::Surface::Swap*; mir::protobuf::Void::ByteSize*; mir::protobuf::Void::CheckTypeAndMergeFrom*; mir::protobuf::Void::Clear*; mir::protobuf::Void::CopyFrom*; mir::protobuf::Void::default_instance*; mir::protobuf::Void::DiscardUnknownFields*; mir::protobuf::Void::GetTypeName*; mir::protobuf::Void::IsInitialized*; mir::protobuf::Void::kErrorFieldNumber*; mir::protobuf::Void::MergeFrom*; mir::protobuf::Void::MergePartialFromCodedStream*; mir::protobuf::Void::New*; mir::protobuf::Void::SerializeWithCachedSizes*; mir::protobuf::Void::Swap*; mir::protobuf::Void::?Void*; mir::protobuf::Void::Void*; mir::protobuf::wire::Invocation::ByteSize*; mir::protobuf::wire::Invocation::CheckTypeAndMergeFrom*; mir::protobuf::wire::Invocation::Clear*; mir::protobuf::wire::Invocation::CopyFrom*; mir::protobuf::wire::Invocation::default_instance*; mir::protobuf::wire::Invocation::DiscardUnknownFields*; mir::protobuf::wire::Invocation::GetTypeName*; mir::protobuf::wire::Invocation::?Invocation*; mir::protobuf::wire::Invocation::Invocation*; mir::protobuf::wire::Invocation::IsInitialized*; mir::protobuf::wire::Invocation::kIdFieldNumber*; mir::protobuf::wire::Invocation::kMethodNameFieldNumber*; mir::protobuf::wire::Invocation::kParametersFieldNumber*; mir::protobuf::wire::Invocation::kProtocolVersionFieldNumber*; mir::protobuf::wire::Invocation::kSideChannelFdsFieldNumber*; mir::protobuf::wire::Invocation::MergeFrom*; mir::protobuf::wire::Invocation::MergePartialFromCodedStream*; mir::protobuf::wire::Invocation::New*; mir::protobuf::wire::Invocation::SerializeWithCachedSizes*; mir::protobuf::wire::Invocation::Swap*; mir::protobuf::wire::protobuf_AddDesc_mir_5fprotobuf_5fwire_2eproto*; mir::protobuf::wire::protobuf_AssignDesc_mir_5fprotobuf_5fwire_2eproto*; mir::protobuf::wire::protobuf_ShutdownFile_mir_5fprotobuf_5fwire_2eproto*; mir::protobuf::wire::Result::ByteSize*; mir::protobuf::wire::Result::CheckTypeAndMergeFrom*; mir::protobuf::wire::Result::Clear*; mir::protobuf::wire::Result::CopyFrom*; mir::protobuf::wire::Result::default_instance*; mir::protobuf::wire::Result::DiscardUnknownFields*; mir::protobuf::wire::Result::GetTypeName*; mir::protobuf::wire::Result::IsInitialized*; mir::protobuf::wire::Result::kEventsFieldNumber*; mir::protobuf::wire::Result::kIdFieldNumber*; mir::protobuf::wire::Result::kResponseFieldNumber*; mir::protobuf::wire::Result::MergeFrom*; mir::protobuf::wire::Result::MergePartialFromCodedStream*; mir::protobuf::wire::Result::New*; mir::protobuf::wire::Result::?Result*; mir::protobuf::wire::Result::Result*; mir::protobuf::wire::Result::SerializeWithCachedSizes*; mir::protobuf::wire::Result::Swap*; mir::protobuf::wire::static_descriptor_initializer_mir_5fprotobuf_5fwire_2eproto_*; non-virtual?thunk?to?mir::protobuf::BufferAllocation::?BufferAllocation*; non-virtual?thunk?to?mir::protobuf::Buffer::?Buffer*; non-virtual?thunk?to?mir::protobuf::BufferRelease::?BufferRelease*; non-virtual?thunk?to?mir::protobuf::BufferRequest::?BufferRequest*; non-virtual?thunk?to?mir::protobuf::BufferStream::?BufferStream*; non-virtual?thunk?to?mir::protobuf::BufferStreamId::?BufferStreamId*; non-virtual?thunk?to?mir::protobuf::BufferStreamParameters::?BufferStreamParameters*; non-virtual?thunk?to?mir::protobuf::Cookie::?Cookie*; non-virtual?thunk?to?mir::protobuf::Connection::?Connection*; non-virtual?thunk?to?mir::protobuf::ConnectParameters::?ConnectParameters*; non-virtual?thunk?to?mir::protobuf::CoordinateTranslationRequest::?CoordinateTranslationRequest*; non-virtual?thunk?to?mir::protobuf::CoordinateTranslationResponse::?CoordinateTranslationResponse*; non-virtual?thunk?to?mir::protobuf::CursorSetting::?CursorSetting*; non-virtual?thunk?to?mir::protobuf::DisplayCard::?DisplayCard*; non-virtual?thunk?to?mir::protobuf::DisplayConfiguration::?DisplayConfiguration*; non-virtual?thunk?to?mir::protobuf::DisplayMode::?DisplayMode*; non-virtual?thunk?to?mir::protobuf::DisplayOutput::?DisplayOutput*; non-virtual?thunk?to?mir::protobuf::Event::?Event*; non-virtual?thunk?to?mir::protobuf::EventSequence::?EventSequence*; non-virtual?thunk?to?mir::protobuf::LifecycleEvent::?LifecycleEvent*; non-virtual?thunk?to?mir::protobuf::PersistentSurfaceId::?PersistentSurfaceId*; non-virtual?thunk?to?mir::protobuf::PingEvent::?PingEvent*; non-virtual?thunk?to?mir::protobuf::PlatformOperationMessage::?PlatformOperationMessage*; non-virtual?thunk?to?mir::protobuf::Platform::?Platform*; non-virtual?thunk?to?mir::protobuf::PromptSessionParameters::?PromptSessionParameters*; non-virtual?thunk?to?mir::protobuf::RaiseRequest::?RaiseRequest*; non-virtual?thunk?to?mir::protobuf::Rectangle::?Rectangle*; non-virtual?thunk?to?mir::protobuf::ScreencastId::?ScreencastId*; non-virtual?thunk?to?mir::protobuf::ScreencastParameters::?ScreencastParameters*; non-virtual?thunk?to?mir::protobuf::Screencast::?Screencast*; non-virtual?thunk?to?mir::protobuf::SocketFDRequest::?SocketFDRequest*; non-virtual?thunk?to?mir::protobuf::SocketFD::?SocketFD*; non-virtual?thunk?to?mir::protobuf::StreamConfiguration::?StreamConfiguration*; non-virtual?thunk?to?mir::protobuf::SurfaceAspectRatio::?SurfaceAspectRatio*; non-virtual?thunk?to?mir::protobuf::SurfaceId::?SurfaceId*; non-virtual?thunk?to?mir::protobuf::SurfaceModifications::?SurfaceModifications*; non-virtual?thunk?to?mir::protobuf::SurfaceParameters::?SurfaceParameters*; non-virtual?thunk?to?mir::protobuf::SurfaceSetting::?SurfaceSetting*; non-virtual?thunk?to?mir::protobuf::SurfaceSpecification::?SurfaceSpecification*; non-virtual?thunk?to?mir::protobuf::Surface::?Surface*; non-virtual?thunk?to?mir::protobuf::Void::?Void*; non-virtual?thunk?to?mir::protobuf::wire::Invocation::?Invocation*; non-virtual?thunk?to?mir::protobuf::wire::Result::?Result*; typeinfo?for?mir::protobuf::Buffer; typeinfo?for?mir::protobuf::BufferAllocation; typeinfo?for?mir::protobuf::BufferRelease; typeinfo?for?mir::protobuf::BufferRequest; typeinfo?for?mir::protobuf::BufferStream; typeinfo?for?mir::protobuf::BufferStreamId; typeinfo?for?mir::protobuf::BufferStreamParameters; typeinfo?for?mir::protobuf::Cookie; typeinfo?for?mir::protobuf::Connection; typeinfo?for?mir::protobuf::ConnectParameters; typeinfo?for?mir::protobuf::CoordinateTranslationRequest; typeinfo?for?mir::protobuf::CoordinateTranslationResponse; typeinfo?for?mir::protobuf::CursorSetting; typeinfo?for?mir::protobuf::DisplayCard; typeinfo?for?mir::protobuf::DisplayConfiguration; typeinfo?for?mir::protobuf::DisplayMode; typeinfo?for?mir::protobuf::DisplayOutput; typeinfo?for?mir::protobuf::Event; typeinfo?for?mir::protobuf::EventSequence; typeinfo?for?mir::protobuf::InputDeviceEvent; typeinfo?for?mir::protobuf::InputDeviceInfo; typeinfo?for?mir::protobuf::LifecycleEvent; typeinfo?for?mir::protobuf::PersistentSurfaceId; typeinfo?for?mir::protobuf::PingEvent; typeinfo?for?mir::protobuf::Platform; typeinfo?for?mir::protobuf::PlatformOperationMessage; typeinfo?for?mir::protobuf::PromptSessionParameters; typeinfo?for?mir::protobuf::RaiseRequest; typeinfo?for?mir::protobuf::Rectangle; typeinfo?for?mir::protobuf::Screencast; typeinfo?for?mir::protobuf::ScreencastId; typeinfo?for?mir::protobuf::ScreencastParameters; typeinfo?for?mir::protobuf::SocketFD; typeinfo?for?mir::protobuf::SocketFDRequest; typeinfo?for?mir::protobuf::StaticDescriptorInitializer_mir_5fprotobuf_2eproto; typeinfo?for?mir::protobuf::StreamConfiguration; typeinfo?for?mir::protobuf::Surface; typeinfo?for?mir::protobuf::SurfaceAspectRatio; typeinfo?for?mir::protobuf::SurfaceId; typeinfo?for?mir::protobuf::SurfaceModifications; typeinfo?for?mir::protobuf::SurfaceParameters; typeinfo?for?mir::protobuf::SurfaceSetting; typeinfo?for?mir::protobuf::SurfaceSpecification; typeinfo?for?mir::protobuf::Void; typeinfo?for?mir::protobuf::wire::Invocation; typeinfo?for?mir::protobuf::wire::Result; typeinfo?for?mir::protobuf::wire::StaticDescriptorInitializer_mir_5fprotobuf_5fwire_2eproto; vtable?for?mir::protobuf::Buffer; vtable?for?mir::protobuf::BufferAllocation; vtable?for?mir::protobuf::BufferRelease; vtable?for?mir::protobuf::BufferRequest; vtable?for?mir::protobuf::BufferStream; vtable?for?mir::protobuf::BufferStreamId; vtable?for?mir::protobuf::BufferStreamParameters; vtable?for?mir::protobuf::Cookie; vtable?for?mir::protobuf::Connection; vtable?for?mir::protobuf::ConnectParameters; vtable?for?mir::protobuf::CoordinateTranslationRequest; vtable?for?mir::protobuf::CoordinateTranslationResponse; vtable?for?mir::protobuf::CursorSetting; vtable?for?mir::protobuf::DisplayCard; vtable?for?mir::protobuf::DisplayConfiguration; vtable?for?mir::protobuf::DisplayMode; vtable?for?mir::protobuf::DisplayOutput; vtable?for?mir::protobuf::Event; vtable?for?mir::protobuf::EventSequence; vtable?for?mir::protobuf::InputDeviceEvent; vtable?for?mir::protobuf::InputDeviceInfo; vtable?for?mir::protobuf::LifecycleEvent; vtable?for?mir::protobuf::PersistentSurfaceId; vtable?for?mir::protobuf::PingEvent; vtable?for?mir::protobuf::Platform; vtable?for?mir::protobuf::PlatformOperationMessage; vtable?for?mir::protobuf::PromptSessionParameters; vtable?for?mir::protobuf::RaiseRequest; vtable?for?mir::protobuf::Rectangle; vtable?for?mir::protobuf::Screencast; vtable?for?mir::protobuf::ScreencastId; vtable?for?mir::protobuf::ScreencastParameters; vtable?for?mir::protobuf::SocketFD; vtable?for?mir::protobuf::SocketFDRequest; vtable?for?mir::protobuf::StaticDescriptorInitializer_mir_5fprotobuf_2eproto; vtable?for?mir::protobuf::StreamConfiguration; vtable?for?mir::protobuf::Surface; vtable?for?mir::protobuf::SurfaceAspectRatio; vtable?for?mir::protobuf::SurfaceId; vtable?for?mir::protobuf::SurfaceModifications; vtable?for?mir::protobuf::SurfaceParameters; vtable?for?mir::protobuf::SurfaceSetting; vtable?for?mir::protobuf::SurfaceSpecification; vtable?for?mir::protobuf::Void; vtable?for?mir::protobuf::wire::Invocation; vtable?for?mir::protobuf::wire::Result; vtable?for?mir::protobuf::wire::StaticDescriptorInitializer_mir_5fprotobuf_5fwire_2eproto; }; local: *; }; MIR_PROTOBUF_3v19 { global: extern "C++" { mir::protobuf::ModuleProperties::ByteSize*; mir::protobuf::ModuleProperties::CheckTypeAndMergeFrom*; mir::protobuf::ModuleProperties::Clear*; mir::protobuf::ModuleProperties::?ModuleProperties*; mir::protobuf::ModuleProperties::ModuleProperties*; mir::protobuf::ModuleProperties::CopyFrom*; mir::protobuf::ModuleProperties::default_instance*; mir::protobuf::ModuleProperties::DiscardUnknownFields*; mir::protobuf::ModuleProperties::GetTypeName*; mir::protobuf::ModuleProperties::IsInitialized*; mir::protobuf::ModuleProperties::kDisplayConfigurationFieldNumber*; mir::protobuf::ModuleProperties::kDisplayOutputFieldNumber*; mir::protobuf::ModuleProperties::kErrorFieldNumber*; mir::protobuf::ModuleProperties::kPlatformFieldNumber*; mir::protobuf::ModuleProperties::kSurfacePixelFormatFieldNumber*; mir::protobuf::ModuleProperties::MergeFrom*; mir::protobuf::ModuleProperties::MergePartialFromCodedStream*; mir::protobuf::ModuleProperties::New*; mir::protobuf::ModuleProperties::SerializeWithCachedSizes*; mir::protobuf::ModuleProperties::Swap*; typeinfo?for?mir::protobuf::ModuleProperties; }; } MIR_PROTOBUF_3; MIR_PROTOBUF_0.22 { # New symbols in Mir 0.22 global: extern "C++" { mir::protobuf::PreviewConfiguration::ByteSize*; mir::protobuf::PreviewConfiguration::CheckTypeAndMergeFrom*; mir::protobuf::PreviewConfiguration::Clear*; mir::protobuf::PreviewConfiguration::CopyFrom*; mir::protobuf::PreviewConfiguration::default_instance*; mir::protobuf::PreviewConfiguration::DiscardUnknownFields*; mir::protobuf::PreviewConfiguration::?PreviewConfiguration*; mir::protobuf::PreviewConfiguration::PreviewConfiguration*; mir::protobuf::PreviewConfiguration::GetTypeName*; mir::protobuf::PreviewConfiguration::IsInitialized*; mir::protobuf::PreviewConfiguration::MergeFrom*; mir::protobuf::PreviewConfiguration::MergePartialFromCodedStream*; mir::protobuf::PreviewConfiguration::New*; mir::protobuf::PreviewConfiguration::SerializeWithCachedSizes*; mir::protobuf::PreviewConfiguration::Swap*; non-virtual?thunk?to?mir::protobuf::PreviewConfiguration::?PreviewConfiguration*; typeinfo?for?mir::protobuf::PreviewConfiguration; vtable?for?mir::protobuf::PreviewConfiguration; }; } MIR_PROTOBUF_3v19; MIR_PROTOBUF_0.26 { global: extern "C++" { mir::protobuf::InputDeviceInfo::MergeFrom*; mir::protobuf::InputDeviceInfo::default_instance_; mir::protobuf::PointerConfiguration::?PointerConfiguration*; mir::protobuf::PointerConfiguration::PointerConfiguration*; mir::protobuf::PointerConfiguration::default_instance_; mir::protobuf::TouchpadConfiguration::TouchpadConfiguration*; mir::protobuf::TouchpadConfiguration::?TouchpadConfiguration*; mir::protobuf::TouchpadConfiguration::default_instance_; mir::protobuf::PointerConfiguration::?PointerConfiguration*; mir::protobuf::InputDeviceInfo::CopyFrom*; mir::protobuf::InputDevices::Clear*; mir::protobuf::InputDevices::CopyFrom*; mir::protobuf::InputDevices::InputDevices*; mir::protobuf::InputDevices::?InputDevices*; mir::protobuf::InputDevices::MergeFrom*; mir::protobuf::InputDevices::New*; mir::protobuf::InputDevices::default_instance_; mir::protobuf::PointerConfiguration::CopyFrom*; mir::protobuf::TouchpadConfiguration::CopyFrom*; typeinfo?for?mir::protobuf::InputDevices; vtable?for?mir::protobuf::InputDevices; mir::protobuf::ScreencastRequest::ByteSize*; mir::protobuf::ScreencastRequest::CheckTypeAndMergeFrom*; mir::protobuf::ScreencastRequest::Clear*; mir::protobuf::ScreencastRequest::CopyFrom*; mir::protobuf::ScreencastRequest::default_instance*; mir::protobuf::ScreencastRequest::DiscardUnknownFields*; mir::protobuf::ScreencastRequest::GetTypeName*; mir::protobuf::ScreencastRequest::IsInitialized*; mir::protobuf::ScreencastRequest::kBufferIdFieldNumber*; mir::protobuf::ScreencastRequest::kIdFieldNumber*; mir::protobuf::ScreencastRequest::MergeFrom*; mir::protobuf::ScreencastRequest::MergePartialFromCodedStream*; mir::protobuf::ScreencastRequest::New*; mir::protobuf::ScreencastRequest::?ScreencastRequest*; mir::protobuf::ScreencastRequest::ScreencastRequest*; mir::protobuf::ScreencastRequest::SerializeWithCachedSizes*; mir::protobuf::ScreencastRequest::Swap*; typeinfo?for?mir::protobuf::ScreencastRequest; vtable?for?mir::protobuf::ScreencastRequest; non-virtual?thunk?to?mir::protobuf::ScreencastRequest::?ScreencastRequest*; mir::protobuf::PromptSession::ByteSize*; mir::protobuf::PromptSession::CheckTypeAndMergeFrom*; mir::protobuf::PromptSession::Clear*; mir::protobuf::PromptSession::CopyFrom*; mir::protobuf::PromptSession::default_instance*; mir::protobuf::PromptSession::DiscardUnknownFields*; mir::protobuf::PromptSession::GetTypeName*; mir::protobuf::PromptSession::IsInitialized*; mir::protobuf::PromptSession::kApplicationPidFieldNumber*; mir::protobuf::PromptSession::MergeFrom*; mir::protobuf::PromptSession::MergePartialFromCodedStream*; mir::protobuf::PromptSession::New*; mir::protobuf::PromptSession::?PromptSession*; mir::protobuf::PromptSession::PromptSession*; mir::protobuf::PromptSession::SerializeWithCachedSizes*; mir::protobuf::PromptSession::Swap*; non-virtual?thunk?to?mir::protobuf::PromptSession::?PromptSession*; typeinfo?for?mir::protobuf::PromptSession; vtable?for?mir::protobuf::PromptSession; }; } MIR_PROTOBUF_0.22; ./src/protobuf/mir_protobuf_wire.proto0000644000004100000410000000071513115234664020524 0ustar www-datawww-datasyntax = "proto2"; option optimize_for = LITE_RUNTIME; package mir.protobuf.wire; message Invocation { required uint32 id = 1; required string method_name = 2; required bytes parameters = 3; required uint32 protocol_version = 4; optional uint32 side_channel_fds = 5; } message Result { // Invocation results have id and response. optional uint32 id = 1; optional bytes response = 2; // Events are in events. repeated bytes events = 3; } ./src/protobuf/mir_protobuf.proto0000644000004100000410000003017613115234664017502 0ustar www-datawww-datasyntax = "proto2"; option optimize_for = LITE_RUNTIME; package mir.protobuf; // Outside of the IPC code no-one should care as this is all wrapped up. // But for the following result messages we either populate the "real" // attributes or, in the case of an error, the error attribute. So the // attributes are all "optional" (or "repeated"). message StructuredError { optional uint32 domain = 1; optional uint32 code = 2; } message ConnectParameters { required string application_name = 1; } message SurfaceParameters { required int32 width = 1; required int32 height = 2; required int32 pixel_format = 3; required int32 buffer_usage = 4; optional string surface_name = 5; optional uint32 output_id = 6; optional int32 type = 7; optional int32 state = 8; optional int32 pref_orientation = 9; optional int32 parent_id = 10; optional Rectangle aux_rect = 11; optional int32 edge_attachment = 12; optional int32 min_width = 13; optional int32 min_height = 14; optional int32 max_width = 15; optional int32 max_height = 16; optional int32 width_inc = 17; optional int32 height_inc = 18; optional SurfaceAspectRatio min_aspect = 19; optional SurfaceAspectRatio max_aspect = 20; optional PersistentSurfaceId parent_persistent_id = 21; repeated Rectangle input_shape = 22; optional int32 shell_chrome = 24; repeated StreamConfiguration stream = 25; optional int32 confine_pointer = 26; optional int32 placement_hints = 27; optional int32 surface_placement_gravity = 28; optional int32 aux_rect_placement_gravity = 29; optional int32 aux_rect_placement_offset_x = 30; optional int32 aux_rect_placement_offset_y = 31; } message SurfaceAspectRatio { required uint32 width = 1; required uint32 height = 2; } // If and when we break our protocol backward-compatibility, this could be // merged with SurfaceParameters... message SurfaceSpecification { optional int32 width = 1; optional int32 height = 2; optional int32 pixel_format = 3; optional int32 buffer_usage = 4; optional string name = 5; optional uint32 output_id = 6; optional int32 type = 7; optional int32 state = 8; optional int32 preferred_orientation = 9; optional int32 parent_id = 10; optional Rectangle aux_rect = 11; optional int32 edge_attachment = 12; optional int32 min_width = 13; optional int32 min_height = 14; optional int32 max_width = 15; optional int32 max_height = 16; optional int32 width_inc = 17; optional int32 height_inc = 18; optional SurfaceAspectRatio min_aspect = 19; optional SurfaceAspectRatio max_aspect = 20; repeated StreamConfiguration stream = 21; optional PersistentSurfaceId parent_persistent_id = 22; repeated Rectangle input_shape = 23; optional int32 shell_chrome = 24; optional int32 confine_pointer = 25; // Intentionally missing 26 to get any further additions in line with SurfaceParameters optional int32 placement_hints = 27; optional int32 surface_placement_gravity = 28; optional int32 aux_rect_placement_gravity = 29; optional int32 aux_rect_placement_offset_x = 30; optional int32 aux_rect_placement_offset_y = 31; optional string cursor_name = 32; optional BufferStreamId cursor_id = 33; optional int32 hotspot_x = 34; optional int32 hotspot_y = 35; } message StreamConfiguration { optional BufferStreamId id = 1; optional int32 displacement_x = 2; optional int32 displacement_y = 3; optional int32 swapinterval = 4; optional float scale = 5; optional int32 width = 6; optional int32 height = 7; optional string error = 127; optional StructuredError structured_error = 128; }; message SurfaceModifications { required SurfaceId surface_id = 1; required SurfaceSpecification surface_specification = 2; } message SurfaceId { required int32 value = 1; }; message PersistentSurfaceId { optional string value = 1; optional string error = 127; optional StructuredError structured_error = 128; }; message BufferStreamId { required int32 value = 1; }; message BufferStreamParameters { required int32 width = 1; required int32 height = 2; optional int32 pixel_format = 3; optional int32 buffer_usage = 4; optional uint32 native_format = 5; optional uint32 flags = 6; }; message BufferAllocation { optional BufferStreamId id = 1; repeated BufferStreamParameters buffer_requests = 2; }; message BufferRelease { repeated Buffer buffers = 1; optional BufferStreamId id = 2; }; enum BufferOperation { add = 0; update = 1; remove = 2; }; message BufferRequest { optional BufferStreamId id = 1; optional Buffer buffer = 2; optional BufferOperation operation = 3; }; message Buffer { optional int32 buffer_id = 1; repeated sint32 fd = 2; repeated int32 data = 3; optional int32 fds_on_side_channel = 4; optional int32 stride = 5; optional uint32 flags = 6; optional int32 width = 7; optional int32 height = 8; optional string error = 127; optional StructuredError structured_error = 128; } message ModuleProperties { required string name = 1; required uint32 major_version = 2; required uint32 minor_version = 3; required uint32 micro_version = 4; required string file = 5; }; message Platform { repeated sint32 fd = 1; repeated int32 data = 2; optional int32 fds_on_side_channel = 3; optional ModuleProperties graphics_module = 4; optional string error = 127; optional StructuredError structured_error = 128; } message DisplayCard { required uint32 card_id = 1; required uint32 max_simultaneous_outputs = 2; } message DisplayMode { optional uint32 vertical_resolution = 1; optional uint32 horizontal_resolution = 2; optional double refresh_rate = 3; } message DisplayOutput { repeated uint32 pixel_format = 1; optional uint32 current_format = 2; repeated DisplayMode mode = 3; optional uint32 current_mode = 4; optional sint32 position_x = 5; optional sint32 position_y = 6; optional uint32 card_id = 7; optional uint32 output_id = 8; optional uint32 connected = 9; optional uint32 used = 10; optional uint32 physical_width_mm = 11; optional uint32 physical_height_mm = 12; optional uint32 type = 13; optional uint32 preferred_mode = 14; optional uint32 power_mode = 15; optional sint32 orientation = 16; optional float scale_factor = 17; optional uint32 form_factor = 18; optional uint32 subpixel_arrangement = 19; optional bytes gamma_red = 20; optional bytes gamma_green = 21; optional bytes gamma_blue = 22; optional uint32 gamma_supported = 23; optional bytes edid = 24; optional string model = 25; } message Connection { optional Platform platform = 1; // optional DisplayInfo display_info = 2; repeated DisplayOutput display_output = 3; optional DisplayConfiguration display_configuration = 4; repeated uint32 surface_pixel_format = 5; optional InputDevices input_devices = 6; optional string input_configuration = 7; optional bool coordinate_translation_present = 8; optional string error = 127; optional StructuredError structured_error = 128; } message BufferStream { optional BufferStreamId id = 1; optional int32 pixel_format = 2; optional int32 buffer_usage = 3; optional Buffer buffer = 4; optional string error = 127; optional StructuredError structured_error = 128; } message Surface { optional SurfaceId id = 1; optional int32 width = 2; optional int32 height = 3; optional int32 pixel_format = 4; optional int32 buffer_usage = 5; optional Buffer buffer = 6; repeated sint32 fd = 7; optional int32 fds_on_side_channel = 8; repeated SurfaceSetting attributes = 9; optional BufferStream buffer_stream = 10; optional string error = 127; optional StructuredError structured_error = 128; } message Void { optional string error = 127; optional StructuredError structured_error = 128; } message SurfaceSetting { optional SurfaceId surfaceid = 1; optional int32 attrib = 2; optional int32 ivalue = 3; // optional string svalue = 4; // Expected for future use optional string error = 127; optional StructuredError structured_error = 128; } message Event { optional bytes raw = 1; // MirEvent structure } message DisplayConfiguration { repeated DisplayOutput display_output = 1; repeated DisplayCard display_card = 2; optional string error = 127; optional StructuredError structured_error = 128; } message PreviewConfiguration { optional DisplayConfiguration configuration = 1; optional int32 timeout = 2; } message LifecycleEvent { required uint32 new_state = 1; // State transition optional string error = 127; optional StructuredError structured_error = 128; } message PingEvent { optional int32 serial = 1; // Identifier for this ping } message EventSequence { repeated Event event = 1; optional DisplayConfiguration display_configuration = 2; optional LifecycleEvent lifecycle_event = 3; optional BufferRequest buffer_request = 4; optional PingEvent ping_event = 5; optional InputDevices input_devices = 6; optional string input_configuration = 7; optional string error = 127; optional StructuredError structured_error = 128; } message Rectangle { required int32 left = 1; required int32 top = 2; required uint32 width = 3; required uint32 height = 4; } message ScreencastParameters { required Rectangle region = 1; required uint32 width = 2; required uint32 height = 3; required int32 pixel_format = 4; optional uint32 num_buffers = 5; optional int32 mirror_mode = 6; } message ScreencastId { required uint32 value = 1; } message ScreencastRequest { optional ScreencastId id = 1; optional uint32 buffer_id = 2; } message Screencast { optional ScreencastId screencast_id = 1; optional Buffer buffer = 2; optional BufferStream buffer_stream = 3; optional string error = 127; optional StructuredError structured_error = 128; } message CursorSetting { required SurfaceId surfaceid = 1; // No name is interpreted as disabled cursor. optional string name = 2; // If we supply a buffer stream we must supply hotspot x and y optional BufferStreamId buffer_stream = 3; optional int32 hotspot_x = 4; optional int32 hotspot_y = 5; } message SocketFDRequest { required int32 number = 1; required int32 prompt_session_id = 2; } message SocketFD { repeated sint32 fd = 1; optional int32 fds_on_side_channel = 2; optional string error = 127; optional StructuredError structured_error = 128; } message PromptSessionParameters { required int32 application_pid = 1; } message PromptSession { optional int32 id = 1; optional string error = 127; optional StructuredError structured_error = 128; } message PlatformOperationMessage { optional uint32 opcode = 1; optional bytes data = 2; repeated sint32 fd = 3; optional int32 fds_on_side_channel = 4; optional string error = 127; optional StructuredError structured_error = 128; } message CoordinateTranslationRequest { required SurfaceId surfaceid = 1; required int32 x = 2; required int32 y = 3; } message CoordinateTranslationResponse { optional int32 x = 1; optional int32 y = 2; optional string error = 127; optional StructuredError structured_error = 128; } message Cookie { required bytes cookie = 1; } message RaiseRequest { required Cookie cookie = 1; required SurfaceId surface_id = 2; } message InputDevices { repeated InputDeviceInfo device_info = 1; } message InputDeviceInfo { optional int64 id = 1; optional uint32 capabilities = 2; optional string name = 3; optional string unique_id = 4; optional PointerConfiguration pointer_configuration = 5; optional TouchpadConfiguration touchpad_configuration = 6; } message PointerConfiguration { optional uint32 handedness = 1; optional uint32 acceleration = 2; optional double acceleration_bias = 3; optional double horizontal_scroll_scale = 4; optional double vertical_scroll_scale = 5; } message TouchpadConfiguration { optional uint32 click_modes = 1; optional uint32 scroll_modes = 2; optional int32 button_down_scroll_button = 3; optional uint32 tap_to_click = 4; optional uint32 middle_mouse_button_emulation = 5; optional uint32 disable_with_mouse = 6; optional uint32 disable_while_typing = 7; } ./src/protobuf/google_protobuf_guard.cpp0000644000004100000410000000217013115234416020754 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #include extern "C" int __attribute__((constructor)) init_google_protobuf() { GOOGLE_PROTOBUF_VERIFY_VERSION; return 0; } extern "C" int __attribute__((destructor)) shutdown_google_protobuf() { google::protobuf::ShutdownProtobufLibrary(); return 0; } // Preserve ABI namespace mir { namespace protobuf { void google_protobuf_guard(); }} void mir::protobuf::google_protobuf_guard() { } ./src/include/0000755000004100000410000000000013115234413013452 5ustar www-datawww-data./src/include/platform/0000755000004100000410000000000013115234413015276 5ustar www-datawww-data./src/include/platform/mir/0000755000004100000410000000000013115234417016071 5ustar www-datawww-data./src/include/platform/mir/udev/0000755000004100000410000000000013115234420017026 5ustar www-datawww-data./src/include/platform/mir/udev/wrapper.h0000644000004100000410000000677113115234416020677 0ustar www-datawww-data/* * Copyright © 2013 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Christopher James Halse Rogers */ #ifndef MIR_UDEV_WRAPPER_H_ #define MIR_UDEV_WRAPPER_H_ #include #include namespace mir { namespace udev { class Device; class Enumerator; class Context { public: Context(); ~Context() noexcept; Context(Context const&) = delete; Context& operator=(Context const&) = delete; std::shared_ptr device_from_syspath(std::string const& syspath); ::udev* ctx() const; private: ::udev* const context; }; class Device { public: virtual ~Device() = default; Device(Device const&) = delete; Device& operator=(Device const&) = delete; virtual char const* subsystem() const = 0; virtual char const* devtype() const = 0; virtual char const* devpath() const = 0; virtual char const* devnode() const = 0; virtual char const* property(char const *name) const = 0; protected: Device() = default; }; bool operator==(Device const& lhs, Device const& rhs); bool operator!=(Device const& lhs, Device const& rhs); class Enumerator { public: Enumerator(std::shared_ptr const& ctx); ~Enumerator() noexcept; Enumerator(Enumerator const&) = delete; Enumerator& operator=(Enumerator const&) = delete; void scan_devices(); void match_subsystem(std::string const& subsystem); void match_parent(Device const& parent); void match_sysname(std::string const& sysname); class iterator : public std::iterator { public: iterator& operator++(); iterator operator++(int); bool operator==(iterator const& rhs) const; bool operator!=(iterator const& rhs) const; Device const& operator*() const; Device const* operator->() const; private: friend class Enumerator; iterator (); iterator (std::shared_ptr const& ctx, udev_list_entry* entry); void increment(); std::shared_ptr ctx; udev_list_entry* entry; std::shared_ptr current; }; iterator begin(); iterator end(); private: std::shared_ptr const ctx; udev_enumerate* const enumerator; bool scanned; }; class Monitor { public: enum EventType { ADDED, REMOVED, CHANGED, }; Monitor(const Context& ctx); ~Monitor() noexcept; Monitor(Monitor const&) = delete; Monitor& operator=(Monitor const&) = delete; void enable(void); int fd(void) const; void filter_by_subsystem(std::string const& subsystem); void filter_by_subsystem_and_type(std::string const& subsystem, std::string const& devtype); void process_events(std::function const& handler) const; private: udev_monitor* const monitor; bool enabled; }; } } #endif // MIR_UDEV_WRAPPER_H_ ./src/include/platform/mir/options/0000755000004100000410000000000013115234677017574 5ustar www-datawww-data./src/include/platform/mir/options/program_option.h0000644000004100000410000000370013115234416022773 0ustar www-datawww-data/* * Copyright © 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_OPTIONS_PROGRAM_OPTION_H_ #define MIR_OPTIONS_PROGRAM_OPTION_H_ #include "mir/options/option.h" #include #include namespace mir { namespace options { class ProgramOption : public Option { public: ProgramOption(); void parse_arguments( boost::program_options::options_description const& description, int argc, char const* argv[]); void parse_environment( boost::program_options::options_description const& description, char const* prefix); void parse_file( boost::program_options::options_description const& description, std::string const& filename); bool is_set(char const* name) const override; bool get(char const* name, bool default_) const override; std::string get(char const*, char const* default_) const override; int get(char const* name, int default_) const override; boost::any const& get(char const* name) const override; using Option::get; std::vector unparsed_command_line() const; private: boost::program_options::variables_map options; std::vector unparsed_tokens; }; } } #endif /* MIR_OPTIONS_PROGRAM_OPTION_H_ */ ./src/include/platform/mir/options/default_configuration.h0000644000004100000410000000572013115234416024313 0ustar www-datawww-data/* * Copyright © 2013-2014 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * * Authored by: Alan Griffiths */ #ifndef MIR_OPTIONS_DEFAULT_CONFIGURATION_H_ #define MIR_OPTIONS_DEFAULT_CONFIGURATION_H_ #include "mir/options/configuration.h" #include "mir/options/program_option.h" #include namespace mir { class SharedLibrary; namespace options { class DefaultConfiguration : public Configuration { public: DefaultConfiguration(int argc, char const* argv[]); DefaultConfiguration(int argc, char const* argv[], std::string const& config_file); DefaultConfiguration( int argc, char const* argv[], std::function const& handler); DefaultConfiguration( int argc, char const* argv[], std::function const& handler, std::string const& config_file); virtual ~DefaultConfiguration() = default; // add_options() allows users to add their own options. This MUST be called // before the first invocation of the_options() - typically during initialization. boost::program_options::options_description_easy_init add_options(); private: // MUST be the first member to ensure it's destroyed last, lest we attempt to // call destructors in DSOs we've unloaded. std::shared_ptr platform_graphics_library; std::string const config_file; void add_platform_options(); // accessed via the base interface, when access to add_options() has been "lost" std::shared_ptr the_options() const override; virtual void parse_arguments( boost::program_options::options_description desc, ProgramOption& options, int argc, char const* argv[]) const; virtual void parse_environment( boost::program_options::options_description& desc, ProgramOption& options) const; virtual void parse_config_file( boost::program_options::options_description& desc, ProgramOption& options) const; int const argc; char const** const argv; std::function const unparsed_arguments_handler; std::shared_ptr const program_options; std::shared_ptr