mir-0.1.8+14.04.20140411/0000755000015301777760000000000012322054703014677 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tools/0000755000015301777760000000000012322054703016037 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tools/valgrind_suppressions_armhf0000644000015301777760000000344312322054247023611 0ustar pbusernogroup00000000000000# ld { ld_value4 Memcheck:Value4 obj:/lib/arm-linux-gnueabihf/ld-2.*.so } { ld_cond Memcheck:Cond obj:/lib/arm-linux-gnueabihf/ld-2.*.so } { ld_open Memcheck:Param open(filename) obj:/lib/arm-linux-gnueabihf/ld-2.*.so } { ld_getcwd Memcheck:Param getcwd(buf) obj:/lib/arm-linux-gnueabihf/ld-2.*.so } { ld_stat64 Memcheck:Param stat64(file_name) obj:/lib/arm-linux-gnueabihf/ld-2.*.so } # Android libs { android_cond Memcheck:Cond obj:/android/system/*.so } # libc { libc_freeres_value4 Memcheck:Value4 ... fun:__libc_freeres ... } { libc_freeres_cond Memcheck:Cond ... fun:__libc_freeres ... } # libgcc_s { libgcc_s_value4 Memcheck:Value4 ... obj:/lib/arm-linux-gnueabihf/libgcc_s.so.1 } { libgcc_s_cond Memcheck:Cond ... obj:/lib/arm-linux-gnueabihf/libgcc_s.so.1 } # libdl # Valgrind thinks that dlopen returns an uninitialized # value, so all dlsym calls cause spurious memory errors # since they use that value. { dlopen_cond Memcheck:Cond ... fun:dlopen@@GLIBC_2.4 ... } { dlsym_value4 Memcheck:Value4 ... fun:dlsym ... } { dlsym_cond Memcheck:Cond ... fun:dlsym ... } { dlopen_cond Memcheck:Cond fun:calloc fun:_dl_new_object ... } # mir::SharedLibrary # Valgrind thinks that dlopen returns an uninitialized # value, so all checks using that value cause spurious # memory errors. { mir_sharedlibrary_cond Memcheck:Cond fun:_ZN3mir13SharedLibraryC1EPKc ... } # glib is not valgrind-friendly { glib_create_type_instance Memcheck:Addr4 fun:g_type_create_instance } { glib_slice_alloc0 Memcheck:Addr4 fun:memset fun:g_slice_alloc0 } mir-0.1.8+14.04.20140411/tools/vera++/0000755000015301777760000000000012322054703017122 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tools/vera++/profiles/0000755000015301777760000000000012322054703020745 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tools/vera++/profiles/mir_vera_profile0000644000015301777760000000033712322054223024214 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh set rules { F001 L001 L002 L005 L006 T002 T003 T004 T005 T006 T007 T008 T009 T011 T013 T015 T017 T018 MIR001 } mir-0.1.8+14.04.20140411/tools/vera++/CMakeLists.txt0000644000015301777760000000161212322054223021657 0ustar pbusernogroup00000000000000find_program(VERA_EXECUTABLE vera++) if(VERA_EXECUTABLE) message(STATUS "vera++ available - enabling make target style_check") add_custom_target( style_check COMMAND "find" "${CMAKE_SOURCE_DIR}/include" "-name" "'*.h'" "|" "xargs" "vera++" "-profile" "mir_vera_profile" COMMAND "find" "${CMAKE_SOURCE_DIR}/src" "-name" "'*.h'" "|" "xargs" "vera++" "-profile" "mir_vera_profile" COMMAND "find" "${CMAKE_SOURCE_DIR}/src" "-name" "'*.cpp'" "|" "xargs" "vera++" "-profile" "mir_vera_profile" COMMAND "find" "${CMAKE_SOURCE_DIR}/tests" "-name" "'*.h'" "|" "xargs" "vera++" "-profile" "mir_vera_profile" COMMAND "find" "${CMAKE_SOURCE_DIR}/tests" "-name" "'*.cpp'" "|" "xargs" "vera++" "-profile" "mir_vera_profile" WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" ) else() message(WARNING "vera++ not available - disabling make target style_check") endif(VERA_EXECUTABLE) mir-0.1.8+14.04.20140411/tools/vera++/scripts/0000755000015301777760000000000012322054703020611 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/0000755000015301777760000000000012322054703021743 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T008.tcl0000755000015301777760000000142612322054223023105 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Keywords catch, for, if and while should be followed by a single space foreach f [getSourceFileNames] { foreach t [getTokens $f 1 0 -1 -1 {catch for if switch while}] { set keyword [lindex $t 0] set line [lindex $t 1] set column [lindex $t 2] set followingTokens [getTokens $f $line [expr $column + [string length $keyword]] [expr $line + 1] -1 {}] if {[llength $followingTokens] < 2} { report $f $line "keyword '${keyword}' not followed by a single space" } else { if {[list [lindex [lindex $followingTokens 0] 0] [lindex [lindex $followingTokens 1] 0]] != [list " " "("]} { report $f $line "keyword '${keyword}' not followed by a single space" } } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T010.tcl0000755000015301777760000000055412322054223023077 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Identifiers should not be composed of 'l' and 'O' characters only foreach file [getSourceFileNames] { foreach t [getTokens $file 1 0 -1 -1 {identifier}] { set value [lindex $t 0] if [regexp {^(l|O)+$} $value] { report $file [lindex $t 1] "identifier should not be composed of only 'l' and 'O'" } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/MIR001.tcl0000755000015301777760000000340512322054223023321 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # 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: Alexandros Frantzis # Left parenthesis should not be followed by whitespace # Right parenthesis should not be preceded by whitespace foreach f [getSourceFileNames] { foreach t [getTokens $f 1 0 -1 -1 {leftparen rightparen}] { set line [lindex $t 1] set column [lindex $t 2] set tokenType [lindex $t 3] if {$tokenType == "leftparen"} { set following [getTokens $f $line [expr $column + 1] [expr $line + 1] -1 {}] if {$following != {}} { set firstFollowing [lindex [lindex $following 0] 3] if {$firstFollowing == "space"} { report $f $line "left parenthesis should not be followed by whitespace" } } } if {$tokenType == "rightparen"} { set preceding [getTokens $f $line 0 $line $column {}] set lastPreceding [lindex [lindex $preceding end] 3] if {[llength $preceding] > 1 && $lastPreceding == "space"} { report $f $line "right parenthesis should not be preceded by whitespace" } } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/F001.tcl0000755000015301777760000000105112322054223023052 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Source files should not use the '\r' (CR) character foreach fileName [getSourceFileNames] { set file [open $fileName "r"] fconfigure $file -translation lf set line [gets $file] set lineCounter 1 while {![eof $file]} { set pos [string first "\r" $line] if {$pos != -1 && $pos != [expr [string length $line] - 1]} { report $fileName $lineCounter "\\r (CR) detected in isolation at position ${pos}" } set line [gets $file] incr lineCounter } close $file } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T005.tcl0000755000015301777760000000143412322054223023101 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Keywords break and continue should be immediately followed by a semicolon foreach f [getSourceFileNames] { foreach t [getTokens $f 1 0 -1 -1 {break continue}] { set keyword [lindex $t 0] set line [lindex $t 1] set column [lindex $t 2] set semicolons [getTokens $f $line [expr $column + [string length $keyword]] [expr $line + 1] 0 {semicolon}] if {$semicolons == {}} { report $f $line "keyword '${keyword}' not immediately followed by a semicolon" } else { set semColumn [lindex [lindex $semicolons 0] 2] if {$semColumn != $column + [string length $keyword]} { report $f $line "keyword '${keyword}' not immediately followed by a semicolon" } } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/L005.tcl0000755000015301777760000000161712322054223023074 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # There should not be too many consecutive empty lines set maxEmptyLines [getParameter "max-consecutive-empty-lines" 2] foreach f [getSourceFileNames] { set lineNumber 1 set emptyCount 0 set reported false foreach line [getAllLines $f] { if {[string trim $line] == ""} { incr emptyCount if {$emptyCount > $maxEmptyLines && $reported == "false"} { report $f $lineNumber "too many consecutive empty lines" set reported true } } else { set emptyCount 0 set reported false } incr lineNumber } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/L004.tcl0000755000015301777760000000054612322054223023073 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Line cannot be too long set maxLength [getParameter "max-line-length" 100] foreach f [getSourceFileNames] { set lineNumber 1 foreach line [getAllLines $f] { if {[string length $line] > $maxLength} { report $f $lineNumber "line is longer than ${maxLength} characters" } incr lineNumber } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/L003.tcl0000755000015301777760000000071612322054223023071 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # No leading and no trailing empty lines foreach f [getSourceFileNames] { set lineCount [getLineCount $f] if {$lineCount > 0} { set firstLine [getLine $f 1] if {[string trim $firstLine] == ""} { report $f 1 "leading empty line(s)" } set lastLine [getLine $f $lineCount] if {[string trim $lastLine] == ""} { report $f $lineCount "trailing empty line(s)" } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T003.tcl0000755000015301777760000000224612322054223023101 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Some keywords should be followed by a single space set keywords { case class enum explicit extern goto new struct union using } proc isKeyword {s} { global keywords return [expr [lsearch $keywords $s] != -1] } set state "other" foreach f [getSourceFileNames] { foreach t [getTokens $f 1 0 -1 -1 {}] { set tokenValue [lindex $t 0] set tokenName [lindex $t 3] if {$state == "keyword"} { if {$tokenName == "space" && $tokenValue == " "} { set state "space" } else { report $f $lineNumber "keyword \'${keywordValue}\' not followed by a single space" set state "other" } } elseif {$state == "space"} { if {$tokenName == "newline"} { report $f $lineNumber "keyword \'${keywordValue}\' not followed by a single space" } set state "other" } else { if [isKeyword $tokenName] { set state "keyword" set lineNumber [lindex $t 1] set keywordValue [lindex $t 0] } } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/L001.tcl0000755000015301777760000000102412322054223023060 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # No trailing whitespace set strictMode [getParameter "strict-trailing-space" 0] foreach f [getSourceFileNames] { set lineNumber 1 set previousIndent "" foreach line [getAllLines $f] { if [regexp {^.*[[:space:]]+$} $line] { if {$strictMode || [string trim $line] != "" || $line != $previousIndent} { report $f $lineNumber "trailing whitespace" } } regexp {^([[:space:]]*).*$} $line dummy previousIndent incr lineNumber } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/L002.tcl0000755000015301777760000000041412322054223023063 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Don't use tab characters foreach f [getSourceFileNames] { set lineNumber 1 foreach line [getAllLines $f] { if [regexp {\t} $line] { report $f $lineNumber "horizontal tab used" } incr lineNumber } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T015.tcl0000755000015301777760000000341312322054223023101 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # HTML links in comments and string literals should be correct set urlRe {<[[:space:]]*[^>]*[[:space:]]+(?:HREF|SRC)[[:space:]]*=[[:space:]]*\"([^\"]*)\"} foreach file [getSourceFileNames] { foreach token [getTokens $file 1 0 -1 -1 {ccomment cppcomment stringlit}] { set tokenValue [lindex $token 0] if {[regexp -nocase $urlRe $tokenValue dummy link] == 1} { if {[string index $link 0] == "\#" || [string first "mailto:" $link] == 0 || [string first "http:" $link] == 0 || [string first "https:" $link] == 0 || [string first "ftp:" $link] == 0 || [string first "news:" $link] == 0 || [string first "javascript:" $link] == 0} { continue } set lineNumber [lindex $token 1] if {[string first "file:" $link] == 0} { report $file $lineNumber "URL links to files are not allowed" continue } if {[regexp {[ \<\>\'\{\}\|\\\^\[\]]} $link] == 1} { report $file $lineNumber "URL link contains illegal character(s)" continue } set plainLink $link set pos [string first "\#" $link] if {$pos != -1} { set plainLink [string range $link 0 [expr $pos - 1]] } if {[string first "\#" $link [expr $pos + 1]] != -1} { report $file $lineNumber "URL link contains invalid bookmark" } set completeLink [file join [file dirname $file] $plainLink] if {[file isfile $completeLink] == 0} { report $file $lineNumber "URL points to non-existing file" } } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T009.tcl0000755000015301777760000000207412322054223023106 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Comma should not be preceded by whitespace, but should be followed by one foreach f [getSourceFileNames] { foreach t [getTokens $f 1 0 -1 -1 {comma}] { set line [lindex $t 1] set column [lindex $t 2] set preceding [getTokens $f $line 0 $line $column {}] if {$preceding == {}} { report $f $line "comma should not be preceded by whitespace" } else { set lastPreceding [lindex [lindex $preceding end] 3] if {$lastPreceding == "space"} { report $f $line "comma should not be preceded by whitespace" } } set following [getTokens $f $line [expr $column + 1] [expr $line + 1] -1 {}] if {$following != {}} { set firstFollowing [lindex [lindex $following 0] 3] if {$firstFollowing != "space" && $firstFollowing != "newline" && !($lastPreceding == "operator" && $firstFollowing == "leftparen")} { report $f $line "comma should be followed by whitespace" } } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/F002.tcl0000755000015301777760000000333312322054223023060 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # File names should be well-formed set maxDirectoryDepth [getParameter "max-directory-depth" 8] set maxDirnameLength [getParameter "max-dirname-length" 31] set maxFilenameLength [getParameter "max-filename-length" 31] set maxPathLength [getParameter "max-path-length" 100] foreach fileName [getSourceFileNames] { if {[string length $fileName] > $maxPathLength} { report $fileName 1 "path name too long" } set dirDepth 0 foreach dir [file split [file dirname $fileName]] { if {$dir == "/" || $dir == "." || $dir == ".."} { continue } incr dirDepth if {[string length $dir] > $maxDirnameLength} { report $fileName 1 "directory name component too long" break } set first [string index $dir 0] if {[string is alpha $first] == 0 && $first != "_"} { report $fileName 1 "directory name should start with alphabetic character or underscore" break } if {[string first "." $dir] != -1} { report $fileName 1 "directory name should not contain the dot" break } } if {$dirDepth >= $maxDirectoryDepth} { report $fileName 1 "directory structure too deep" } set leafName [file tail $fileName] if {[string length $leafName] > $maxFilenameLength} { report $fileName 1 "file name too long" } set first [string index $leafName 0] if {[string is alpha $first] == 0 && $first != "_"} { report $fileName 1 "file name should start with alphabetic character or underscore" } if {[llength [split $leafName .]] > 2} { report $fileName 1 "file name should not contain more than one dot" } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T012.tcl0000755000015301777760000000057612322054223023105 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Negation operator should not be used in its short form foreach file [getSourceFileNames] { foreach negation [getTokens $file 1 0 -1 -1 {not}] { set value [lindex $negation 0] if {$value == "!"} { set lineNumber [lindex $negation 1] report $file $lineNumber "negation operator used in its short form" } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T002.tcl0000755000015301777760000000327612322054223023104 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Reserved names should not be used for preprocessor macros set keywords { asm auto bool break case catch char class const const_cast continue default delete goto do double dynamic_cast else enum explicit export extern false float for friend if inline int long mutable namespace new operator private protected public register reinterpret_cast return short signed sizeof static static_cast struct switch template this throw true try typedef typeid typename union unsigned using virtual void volatile wchar_t while and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq } foreach f [getSourceFileNames] { foreach t [getTokens $f 1 0 -1 -1 {pp_define}] { set lineNumber [lindex $t 1] set line [getLine $f $lineNumber] set rest [string trimleft [string range $line \ [expr [lindex $t 2] + [string length [lindex $t 0]]] end]] set macroName [string range $rest 0 [expr [string wordend $rest 0] - 1]] if {([regexp {^_} $macroName] && [string is upper -strict [string index $macroName 1]]) || [string first "__" $macroName] != -1} { report $f $lineNumber "reserved name used for macro (incorrect use of underscore)" } if {[lsearch $keywords $macroName] != -1} { report $f $lineNumber "reserved name used for macro (keyword or alternative token redefined)" } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/DUMP.tcl0000755000015301777760000000050612322054223023215 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh foreach f [getSourceFileNames] { puts "Tokens in file ${f}:" foreach t [getTokens $f 1 0 -1 -1 {}] { set value [lindex $t 0] set line [lindex $t 1] set column [lindex $t 2] set name [lindex $t 3] puts "${line}/${column}\t${name}\t${value}" } puts "" } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T018.tcl0000755000015301777760000000124512322054223023105 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # using namespace are not allowed in header files foreach fileName [getSourceFileNames] { set extension [file extension $fileName] if {[lsearch {.h .hh .hpp .hxx .ipp} $extension] != -1} { set state "start" foreach token [getTokens $fileName 1 0 -1 -1 {using namespace identifier}] { set type [lindex $token 3] if {$state == "using" && $type == "namespace"} { report $fileName $usingLine "using namespace not allowed in header file" } if {$type == "using"} { set usingLine [lindex $token 1] } set state $type } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T016.tcl0000755000015301777760000000126612322054223023106 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Calls to min/max should be protected against accidental macro substitution foreach file [getSourceFileNames] { foreach identifier [getTokens $file 1 0 -1 -1 {identifier}] { set value [lindex $identifier 0] if {$value == "min" || $value == "max"} { set lineNumber [lindex $identifier 1] set columnNumber [expr [lindex $identifier 2] + [string length $value]] set restOfLine [string range [getLine $file $lineNumber] $columnNumber end] if {[regexp {^[[:space:]]*\(} $restOfLine] == 1} { report $file $lineNumber "min/max potential macro substitution problem" } } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T019.tcl0000755000015301777760000000177512322054223023116 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # control structures should have complete curly-braced block of code foreach fileName [getSourceFileNames] { set state "start" foreach token [getTokens $fileName 1 0 -1 -1 {for if while leftparen rightparen leftbrace semicolon}] { set type [lindex $token 3] if {$state == "control"} { if {$type == "leftparen"} { incr parenCount } elseif {$type == "rightparen"} { incr parenCount -1 if {$parenCount == 0} { set state "expectedblock" } } } elseif {$state == "expectedblock"} { if {$type != "leftbrace"} { set line [lindex $token 1] report $fileName $line "full block {} expected in the control structure" } set state "block" } if {$type == "for" || $type == "if" || $type == "while"} { set parenCount 0 set state "control" } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/L006.tcl0000755000015301777760000000041012322054223023063 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Source file should not be too long set maxLines [getParameter "max-file-length" 2000] foreach f [getSourceFileNames] { set length [getLineCount $f] if {$length > $maxLines} { report $f $length "source file is too long" } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T013.tcl0000755000015301777760000000070612322054223023101 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Source files should contain the copyright notice foreach file [getSourceFileNames] { set found false foreach comment [getTokens $file 1 0 -1 -1 {ccomment cppcomment}] { set value [lindex $comment 0] if {[string first "copyright" [string tolower $value]] != -1} { set found true break } } if {$found == false} { report $file 1 "no copyright notice found" } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T006.tcl0000755000015301777760000000155112322054223023102 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Keywords return and throw should be immediately followed by a semicolon or a single space foreach f [getSourceFileNames] { foreach t [getTokens $f 1 0 -1 -1 {return throw}] { set keyword [lindex $t 0] set line [lindex $t 1] set column [lindex $t 2] set followingTokens [getTokens $f $line [expr $column + [string length $keyword]] [expr $line + 1] 0 {}] if {$followingTokens == {}} { report $f $line "keyword '${keyword}' not immediately followed by a semicolon or a single space" } else { set first [lindex [lindex $followingTokens 0] 0] if {$first != ";" && $first != " " && !($keyword == "throw" && $first == "(")} { report $f $line "keyword '${keyword}' not immediately followed by a semicolon or a single space" } } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T011.tcl0000755000015301777760000000326312322054223023100 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Curly brackets from the same pair should be either in the same line or in the same column proc acceptPairs {} { global file parens index end while {$index != $end} { set nextToken [lindex $parens $index] set tokenValue [lindex $nextToken 0] if {$tokenValue == "\{"} { incr index set leftParenLine [lindex $nextToken 1] set leftParenColumn [lindex $nextToken 2] acceptPairs if {$index == $end} { report $file $leftParenLine "opening curly bracket is not closed" return } set nextToken [lindex $parens $index] incr index set tokenValue [lindex $nextToken 0] set rightParenLine [lindex $nextToken 1] set rightParenColumn [lindex $nextToken 2] if {($leftParenLine != $rightParenLine) && ($leftParenColumn != $rightParenColumn)} { # make an exception for line continuation set leftLine [getLine $file $leftParenLine] set rightLine [getLine $file $rightParenLine] if {[string index $leftLine end] != "\\" && [string index $rightLine end] != "\\"} { report $file $rightParenLine "closing curly bracket not in the same line or column" } } } else { return } } } foreach file [getSourceFileNames] { set parens [getTokens $file 1 0 -1 -1 {leftbrace rightbrace}] set index 0 set end [llength $parens] acceptPairs if {$index != $end} { report $file [lindex [lindex $parens $index] 1] "excessive closing bracket?" } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T004.tcl0000755000015301777760000000325412322054223023102 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Some keywords should be immediately followed by a colon set keywords { default private protected public } proc isKeyword {s} { global keywords return [expr [lsearch $keywords $s] != -1] } foreach f [getSourceFileNames] { set lastKeywordLine 0 set lastKeywordColumn 0 set lastKeywordValue "" set last "" foreach t [getTokens $f 1 0 -1 -1 [concat $keywords colon]] { set tokenValue [lindex $t 0] set tokenName [lindex $t 3] if {$tokenName == "colon"} { if {$last == "keyword" && $lastKeywordLine != 0} { set line [lindex $t 1] set column [lindex $t 2] if {$line != $lastKeywordLine || $column != [expr $lastKeywordColumn + [string length $lastKeywordValue]]} { set nonWhiteFound "false" foreach tb [getTokens $f $lastKeywordLine [expr $lastKeywordColumn + 1] $line $column {}] { set tbName [lindex $tb 3] if {[lsearch {space newline ccomment cppcomment} $tbName] == -1} { set nonWhiteFound "true" break } } if {$nonWhiteFound == "false"} { report $f $line "colon not immediately after the \'$lastKeywordValue\' keyword" } } } set last "colon" } else { set lastKeywordLine [lindex $t 1] set lastKeywordColumn [lindex $t 2] set lastKeywordValue $tokenValue set last "keyword" } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T007.tcl0000755000015301777760000000164512322054223023107 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Semicolons should not be isolated by spaces or comments from the rest of the code foreach f [getSourceFileNames] { foreach t [getTokens $f 1 0 -1 -1 {semicolon}] { set line [lindex $t 1] set column [lindex $t 2] set previousTokens [getTokens $f $line 0 $line $column {}] if {$previousTokens == {}} { report $f $line "semicolon is isolated from other tokens" } else { set lastToken [lindex $previousTokens end] set lastName [lindex $lastToken 3] if {[lsearch {space ccomment} $lastName] != -1} { set forTokens [getTokens $f $line 0 $line $column {for leftparen}] if {[list [lindex [lindex $forTokens 0] 3] [lindex [lindex $forTokens 1] 3]] != {for leftparen}} { report $f $line "semicolon is isolated from other tokens" } } } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T001.tcl0000755000015301777760000000060712322054223023076 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # One-line comments should not have forced continuation foreach f [getSourceFileNames] { foreach t [getTokens $f 1 0 -1 -1 {cppcomment}] { set lineNumber [lindex $t 1] set wholeLine [getLine $f $lineNumber] if {[string index $wholeLine end] == "\\"} { report $f $lineNumber "line-continuation in one-line comment" } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T017.tcl0000755000015301777760000000127612322054223023110 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Unnamed namespaces are not allowed in header files foreach fileName [getSourceFileNames] { set extension [file extension $fileName] if {[lsearch {.h .hh .hpp .hxx .ipp} $extension] != -1} { set state "start" foreach token [getTokens $fileName 1 0 -1 -1 {namespace identifier leftbrace}] { set type [lindex $token 3] if {$state == "namespace" && $type == "leftbrace"} { report $fileName $namespaceLine "unnamed namespace not allowed in header file" } if {$type == "namespace"} { set namespaceLine [lindex $token 1] } set state $type } } } mir-0.1.8+14.04.20140411/tools/vera++/scripts/rules/T014.tcl0000755000015301777760000000073512322054223023104 0ustar pbusernogroup00000000000000#!/usr/bin/tclsh # Source files should refer the Boost Software License foreach file [getSourceFileNames] { set found false foreach comment [getTokens $file 1 0 -1 -1 {ccomment cppcomment}] { set value [lindex $comment 0] if {[string first "Boost Software License" $value] != -1} { set found true break } } if {$found == false} { report $file 1 "no reference to the Boost Software License found" } } mir-0.1.8+14.04.20140411/tools/vera++/LICENSE_1_0.txt0000644000015301777760000000247212322054223021406 0ustar pbusernogroup00000000000000Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. mir-0.1.8+14.04.20140411/tools/valgrind_suppressions_generic0000644000015301777760000000022312322054247024121 0ustar pbusernogroup00000000000000{ Supress incorrect unaddressable memory warning about EVIOCSSUSPENDBLOCK ioctl Memcheck:Param ioctl(generic) fun:ioctl fun:ioctl } mir-0.1.8+14.04.20140411/tools/install_on_android.sh0000755000015301777760000000305212322054223022235 0ustar pbusernogroup00000000000000#!/bin/bash # build script for Mir on android arm devices # script assumes that the Mir dependencies are already set up on the device. # if they are not set up, see the setup-android-dependencies.sh script # test run requires package 'android-tools-adb' # test also assumes that the device is rooted and accessible over the adb bridge # # todo: this script should become part of the 'make install'/'make test' system # set -e if [ -z ${1} ]; then BUILD_DIR=build-android-arm else BUILD_DIR=${1} fi pushd ${BUILD_DIR} > /dev/null # # Upload and run the tests! # Requires: https://wiki.canonical.com/ProductStrategyTeam/Android/Deploy # RUN_DIR=/tmp/mirtest adb wait-for-device adb root adb wait-for-device adb shell mkdir -p ${RUN_DIR} for x in bin/mir_acceptance_tests \ bin/mir_integration_tests \ bin/mir_unit_tests \ lib/libmirclient.so.* \ lib/libmirprotobuf.so.* \ lib/libmirplatform.so \ lib/libmirplatformgraphics.so \ lib/libmirclientplatform.so \ lib/libmirserver.so.* do adb push $x ${RUN_DIR} done echo "cd ${RUN_DIR}; export GTEST_OUTPUT=xml:./; export LD_LIBRARY_PATH=.; ./mir_unit_tests; ./mir_integration_tests; ./mir_acceptance_tests; exit; exit" | adb shell adb pull "${RUN_DIR}/mir_acceptance_tests.xml" adb pull "${RUN_DIR}/mir_integration_tests.xml" adb pull "${RUN_DIR}/mir_unit_tests.xml" popd > /dev/null mir-0.1.8+14.04.20140411/tools/setup-android-dependencies.sh0000755000015301777760000000105012322054223023571 0ustar pbusernogroup00000000000000#!/bin/bash # build script for Mir on android arm devices # test run requires package 'android-tools-adb' # test also assumes that the device is rooted and accessible over the adb bridge # # todo: this script should become part of the 'make install'/'make test' system # set -e pushd /tmp > /dev/null echo "apt-get -y install libprotobuf7 \ libgoogle-glog0 \ libboost-program-options1.53.0 \ libboost-system1.53.0 exit" | adb shell popd > /dev/null mir-0.1.8+14.04.20140411/tools/CMakeLists.txt0000644000015301777760000000003112322054223020566 0ustar pbusernogroup00000000000000add_subdirectory(vera++) mir-0.1.8+14.04.20140411/tools/setup-partial-armhf-chroot.sh0000755000015301777760000000340512322054223023556 0ustar pbusernogroup00000000000000#!/bin/bash set -e if [ -z ${1} ]; then echo "please supply directory to create partial chroot in. (eg, ./setup-partial-armhf-chroot.sh mychroot-dir)" exit fi echo "creating phablet-compatible armhf partial chroot for mir compilation in directory ${1}" if [ ! -d ${1} ]; then mkdir -p ${1} fi DEBCONTROL=$(pwd)/../debian/control pushd ${1} > /dev/null # Empty dpkg status file, so that ALL dependencies are listed with dpkg-checkbuilddeps echo "" > status # Manual error code checking is needed for dpkg-checkbuilddeps set +e # Parse dependencies from debian/control # dpkg-checkbuilddeps returns 1 when dependencies are not met and the list is sent to stderr builddeps=$(dpkg-checkbuilddeps -a armhf --admindir=. ${DEBCONTROL} 2>&1 ) if [ $? -ne 1 ] ; then echo "${builddeps}" exit 2 fi # now turn exit on error option set -e # Sanitize dependencies list for submission to debootstrap # build-essential is not needed as we are cross-compiling builddeps=$(echo ${builddeps} | sed -e 's/dpkg-checkbuilddeps://g' -e 's/Unmet build dependencies://g' -e 's/build-essential:native//g') builddeps=$(echo ${builddeps} | sed 's/([^)]*)//g') builddeps=$(echo ${builddeps} | sed 's/ /,/g') fakeroot debootstrap --include=${builddeps} --arch=armhf --download-only --variant=buildd trusty . # Remove libc libraries that confuse the cross-compiler rm var/cache/apt/archives/libc-dev*.deb rm var/cache/apt/archives/libc6*.deb for deb in var/cache/apt/archives/* ; do if [ ! -d ${deb} ] ; then echo "unpacking: ${deb}" dpkg -x ${deb} . fi done # Fix up symlinks which asssumed the usual root path for broken_symlink in $(find . -name \*.so -type l -xtype l) ; do ln -sf $(pwd)$(readlink ${broken_symlink}) ${broken_symlink} done popd > /dev/null mir-0.1.8+14.04.20140411/benchmarks/0000755000015301777760000000000012322054703017014 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/benchmarks/memory/0000755000015301777760000000000012322054703020324 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/benchmarks/memory/CMakeLists.txt0000644000015301777760000000241512322054223023063 0ustar pbusernogroup00000000000000find_program( VALGRIND_EXECUTABLE valgrind ) if(NOT VALGRIND_EXECUTABLE) message("valgrind not found, disabling memory benchmarks") else() set(MEMORY_BENCHMARKS_SOCKET "/tmp/benchmarks.memory.socket.mir") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/benchmark.sh.in ${CMAKE_CURRENT_BINARY_DIR}/benchmark.sh ) add_custom_target( memory_benchmark_one_server_one_client "${CMAKE_CURRENT_BINARY_DIR}/benchmark.sh" 1 100 one_server_one_client_results_for_client one_server_one_client_results_for_server ) add_custom_target( memory_benchmark_one_server_multiple_clients "${CMAKE_CURRENT_BINARY_DIR}/benchmark.sh" 10 100 one_server_multiple_clients_results_for_client one_server_multiple_clients_results_for_server ) add_custom_target( memory_benchmark_one_server_multiple_clients_heavy_load "${CMAKE_CURRENT_BINARY_DIR}/benchmark.sh" 20 100 one_server_multiple_clients_heavy_load_results_for_client one_server_multiple_clients_heavy_load_results_for_server ) add_custom_target( memory_benchmarks DEPENDS memory_benchmark_one_server_one_client memory_benchmark_one_server_multiple_clients memory_benchmark_one_server_multiple_clients_heavy_load ) endif() mir-0.1.8+14.04.20140411/benchmarks/memory/benchmark.sh.in0000755000015301777760000000130212322054223023213 0ustar pbusernogroup00000000000000#!/bin/bash # Starting the server server_fn=@CMAKE_CURRENT_BINARY_DIR@/massif_$4 @VALGRIND_EXECUTABLE@ --tool=massif --pages-as-heap=yes --massif-out-file=`echo $server_fn`.out @EXECUTABLE_OUTPUT_PATH@/mir -f @MEMORY_BENCHMARKS_SOCKET@ & server_pid=$! sleep 5 # Starting the clients fn=@CMAKE_CURRENT_BINARY_DIR@/massif_$3 seq 1 $1 | xargs -I {} -n 1 -P $1 @VALGRIND_EXECUTABLE@ --tool=massif --pages-as-heap=yes --massif-out-file=`echo $fn`.out.{} @EXECUTABLE_OUTPUT_PATH@/mir_demo_client -f @MEMORY_BENCHMARKS_SOCKET@ -c $2 kill $server_pid # This is extremely ugly, but we need to introduce some latency to account # for the fact that we fire up multiple mir instances in rapid succession. sleep 5 mir-0.1.8+14.04.20140411/benchmarks/android-input/0000755000015301777760000000000012322054703021571 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/benchmarks/android-input/input_reader_perf.cpp0000644000015301777760000001323612322054223025774 0ustar pbusernogroup00000000000000/* * 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 d'Andrada */ // android-input #include #include #include #include #include // local #include "ntrig_input_events.h" using namespace android; using mir::input::android::FakeEventHub; using std::chrono::duration; using std::chrono::duration_cast; using std::chrono::steady_clock; using std::cout; using std::endl; // --- FakeInputReaderPolicy --- class FakeInputReaderPolicy : public InputReaderPolicyInterface { InputReaderConfiguration mConfig; Vector mInputDevices; protected: virtual ~FakeInputReaderPolicy() { } public: FakeInputReaderPolicy() {} void setDisplayInfo(int32_t displayId, int32_t width, int32_t height, int32_t orientation) { // Set the size of both the internal and external display at the same time. mConfig.setDisplayInfo(displayId, false /*external*/, width, height, orientation); mConfig.setDisplayInfo(displayId, true /*external*/, width, height, orientation); } const InputReaderConfiguration* getReaderConfiguration() const { return &mConfig; } const Vector& getInputDevices() const { return mInputDevices; } private: virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) { *outConfig = mConfig; } sp obtainPointerController(int32_t deviceId) override { (void)deviceId; return sp(); } virtual void notifyInputDevicesChanged(const Vector& inputDevices) { mInputDevices = inputDevices; } sp getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) override { (void) inputDeviceDescriptor; return NULL; } String8 getDeviceAlias(const InputDeviceIdentifier& identifier) override { (void)identifier; return String8(); } }; // --- FakeInputListener --- class InputListener : public android::InputListenerInterface { public: InputListener() {} virtual ~InputListener() {} void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override { (void)args; } void notifyKey(const NotifyKeyArgs* /*args*/) override {} void notifyMotion(const NotifyMotionArgs* args) override; void notifySwitch(const NotifySwitchArgs* /*args*/) override {} void notifyDeviceReset(const NotifyDeviceResetArgs* /*args*/) override {} }; void InputListener::notifyMotion(const NotifyMotionArgs* args) { (void)args; } // --- main, etc --- int main(int argc, char *argv[]) { (void)argc; (void)argv; const int32_t DEVICE_ID = 2; const int32_t DISPLAY_ID = 0; sp fakeEventHub = new FakeEventHub; fakeEventHub->addDevice(DEVICE_ID, String8("N-Trig MultiTouch"), INPUT_DEVICE_CLASS_TOUCH_MT); fakeEventHub->addConfigurationProperty(DEVICE_ID, "touch.deviceType", "touchScreen"); fakeEventHub->addConfigurationProperty(DEVICE_ID, "device.internal", "1"); fakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); fakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_X, 0, 9600, 0, 0, 28); fakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_Y, 0, 7200, 0, 0, 37); fakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR, 0, 9600, 0, 0, 50); fakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR, 0, 7200, 0, 0, 37); fakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_ORIENTATION, 0, 1, 0, 0, 0); sp fakePolicy = new FakeInputReaderPolicy; fakePolicy->setDisplayInfo(DISPLAY_ID, 1024, 768, DISPLAY_ORIENTATION_0); sp listener = new InputListener; int32_t total_duration = 0; int32_t execution_number; const int32_t execution_count = 10; for (execution_number = 1; execution_number <= execution_count; ++execution_number) { size_t i = 0; while (gInputEvents[i].nsecs > 0) { fakeEventHub->synthesize_event(gInputEvents[i].nsecs, DEVICE_ID, gInputEvents[i].type, gInputEvents[i].code, gInputEvents[i].value); ++i; } sp inputReader = new InputReader(fakeEventHub, fakePolicy, listener); steady_clock::time_point t0 = steady_clock::now(); while (fakeEventHub->eventsQueueSize() > 0) { inputReader->loopOnce(); } steady_clock::time_point t1 = steady_clock::now(); auto time_span = duration_cast(t1 - t0); cout << "Run " << execution_number << ": Took " << time_span.count() << " milliseconds to process all input events." << endl; total_duration += time_span.count(); } int32_t average_duration = total_duration / execution_count; cout << "Average: " << average_duration << " milliseconds." << endl; return 0; } mir-0.1.8+14.04.20140411/benchmarks/android-input/ntrig_input_events.h0000644000015301777760000137650612322054223025707 0ustar pbusernogroup00000000000000/* * 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 d'Andrada */ #ifndef NTRIG_INPUT_EVENTS_H_ #define NTRIG_INPUT_EVENTS_H_ #include struct InputEventData { int64_t nsecs; int32_t type; int32_t code; int32_t value; }; /* Events recorded from an N-Trig touchscreen. Frantically tapping and sliding fingers (up to 5 or 6 at the same time) for half a minute or so. */ struct InputEventData gInputEvents[] = { {INT64_C(1380575033089701000), 0x0003, 0x0035, 384}, {INT64_C(1380575033089701000), 0x0003, 0x0036, 4392}, {INT64_C(1380575033089701000), 0x0003, 0x0034, 0}, {INT64_C(1380575033089701000), 0x0003, 0x0030, 320}, {INT64_C(1380575033089701000), 0x0003, 0x0031, 128}, {INT64_C(1380575033089701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033089701000), 0x0000, 0x0000, 0}, {INT64_C(1380575033095703000), 0x0003, 0x0000, 896}, {INT64_C(1380575033095703000), 0x0003, 0x0001, 5484}, {INT64_C(1380575033095703000), 0x0003, 0x0035, 896}, {INT64_C(1380575033095703000), 0x0003, 0x0036, 5484}, {INT64_C(1380575033095703000), 0x0003, 0x0034, 0}, {INT64_C(1380575033095703000), 0x0003, 0x0030, 480}, {INT64_C(1380575033095703000), 0x0003, 0x0031, 128}, {INT64_C(1380575033095703000), 0x0000, 0x0002, 0}, {INT64_C(1380575033095703000), 0x0003, 0x0035, 384}, {INT64_C(1380575033095703000), 0x0003, 0x0036, 4395}, {INT64_C(1380575033095703000), 0x0003, 0x0034, 0}, {INT64_C(1380575033095703000), 0x0003, 0x0030, 320}, {INT64_C(1380575033095703000), 0x0003, 0x0031, 128}, {INT64_C(1380575033095703000), 0x0000, 0x0002, 0}, {INT64_C(1380575033095703000), 0x0003, 0x0035, 2884}, {INT64_C(1380575033095703000), 0x0003, 0x0036, 1440}, {INT64_C(1380575033095703000), 0x0003, 0x0034, 1}, {INT64_C(1380575033095703000), 0x0003, 0x0030, 256}, {INT64_C(1380575033095703000), 0x0003, 0x0031, 160}, {INT64_C(1380575033095703000), 0x0000, 0x0002, 0}, {INT64_C(1380575033095703000), 0x0001, 0x014d, 1}, {INT64_C(1380575033095703000), 0x0001, 0x014a, 1}, {INT64_C(1380575033095703000), 0x0000, 0x0000, 0}, {INT64_C(1380575033109702000), 0x0003, 0x0001, 5481}, {INT64_C(1380575033109702000), 0x0003, 0x0035, 896}, {INT64_C(1380575033109702000), 0x0003, 0x0036, 5481}, {INT64_C(1380575033109702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033109702000), 0x0003, 0x0030, 480}, {INT64_C(1380575033109702000), 0x0003, 0x0031, 128}, {INT64_C(1380575033109702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033109702000), 0x0003, 0x0035, 384}, {INT64_C(1380575033109702000), 0x0003, 0x0036, 4395}, {INT64_C(1380575033109702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033109702000), 0x0003, 0x0030, 320}, {INT64_C(1380575033109702000), 0x0003, 0x0031, 128}, {INT64_C(1380575033109702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033109702000), 0x0003, 0x0035, 2892}, {INT64_C(1380575033109702000), 0x0003, 0x0036, 1509}, {INT64_C(1380575033109702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033109702000), 0x0003, 0x0030, 320}, {INT64_C(1380575033109702000), 0x0003, 0x0031, 256}, {INT64_C(1380575033109702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033109702000), 0x0000, 0x0000, 0}, {INT64_C(1380575033115702000), 0x0003, 0x0001, 5470}, {INT64_C(1380575033115702000), 0x0003, 0x0035, 896}, {INT64_C(1380575033115702000), 0x0003, 0x0036, 5470}, {INT64_C(1380575033115702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033115702000), 0x0003, 0x0030, 480}, {INT64_C(1380575033115702000), 0x0003, 0x0031, 128}, {INT64_C(1380575033115702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033115702000), 0x0003, 0x0035, 512}, {INT64_C(1380575033115702000), 0x0003, 0x0036, 4409}, {INT64_C(1380575033115702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033115702000), 0x0003, 0x0030, 320}, {INT64_C(1380575033115702000), 0x0003, 0x0031, 128}, {INT64_C(1380575033115702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033115702000), 0x0003, 0x0035, 2888}, {INT64_C(1380575033115702000), 0x0003, 0x0036, 1521}, {INT64_C(1380575033115702000), 0x0003, 0x0034, 1}, {INT64_C(1380575033115702000), 0x0003, 0x0030, 384}, {INT64_C(1380575033115702000), 0x0003, 0x0031, 320}, {INT64_C(1380575033115702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033115702000), 0x0000, 0x0000, 0}, {INT64_C(1380575033127702000), 0x0003, 0x0001, 5469}, {INT64_C(1380575033127702000), 0x0003, 0x0035, 896}, {INT64_C(1380575033127702000), 0x0003, 0x0036, 5469}, {INT64_C(1380575033127702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033127702000), 0x0003, 0x0030, 480}, {INT64_C(1380575033127702000), 0x0003, 0x0031, 128}, {INT64_C(1380575033127702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033127702000), 0x0003, 0x0035, 512}, {INT64_C(1380575033127702000), 0x0003, 0x0036, 4400}, {INT64_C(1380575033127702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033127702000), 0x0003, 0x0030, 320}, {INT64_C(1380575033127702000), 0x0003, 0x0031, 128}, {INT64_C(1380575033127702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033127702000), 0x0003, 0x0035, 2896}, {INT64_C(1380575033127702000), 0x0003, 0x0036, 1517}, {INT64_C(1380575033127702000), 0x0003, 0x0034, 1}, {INT64_C(1380575033127702000), 0x0003, 0x0030, 384}, {INT64_C(1380575033127702000), 0x0003, 0x0031, 320}, {INT64_C(1380575033127702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033127702000), 0x0000, 0x0000, 0}, {INT64_C(1380575033133703000), 0x0003, 0x0000, 990}, {INT64_C(1380575033133703000), 0x0003, 0x0001, 5443}, {INT64_C(1380575033133703000), 0x0003, 0x0035, 990}, {INT64_C(1380575033133703000), 0x0003, 0x0036, 5443}, {INT64_C(1380575033133703000), 0x0003, 0x0034, 0}, {INT64_C(1380575033133703000), 0x0003, 0x0030, 480}, {INT64_C(1380575033133703000), 0x0003, 0x0031, 256}, {INT64_C(1380575033133703000), 0x0000, 0x0002, 0}, {INT64_C(1380575033133703000), 0x0003, 0x0035, 512}, {INT64_C(1380575033133703000), 0x0003, 0x0036, 4370}, {INT64_C(1380575033133703000), 0x0003, 0x0034, 0}, {INT64_C(1380575033133703000), 0x0003, 0x0030, 480}, {INT64_C(1380575033133703000), 0x0003, 0x0031, 128}, {INT64_C(1380575033133703000), 0x0000, 0x0002, 0}, {INT64_C(1380575033133703000), 0x0003, 0x0035, 2903}, {INT64_C(1380575033133703000), 0x0003, 0x0036, 1522}, {INT64_C(1380575033133703000), 0x0003, 0x0034, 1}, {INT64_C(1380575033133703000), 0x0003, 0x0030, 384}, {INT64_C(1380575033133703000), 0x0003, 0x0031, 320}, {INT64_C(1380575033133703000), 0x0000, 0x0002, 0}, {INT64_C(1380575033133703000), 0x0000, 0x0000, 0}, {INT64_C(1380575033145698000), 0x0003, 0x0000, 1024}, {INT64_C(1380575033145698000), 0x0003, 0x0001, 5428}, {INT64_C(1380575033145698000), 0x0003, 0x0035, 1024}, {INT64_C(1380575033145698000), 0x0003, 0x0036, 5428}, {INT64_C(1380575033145698000), 0x0003, 0x0034, 0}, {INT64_C(1380575033145698000), 0x0003, 0x0030, 480}, {INT64_C(1380575033145698000), 0x0003, 0x0031, 128}, {INT64_C(1380575033145698000), 0x0000, 0x0002, 0}, {INT64_C(1380575033145698000), 0x0003, 0x0035, 640}, {INT64_C(1380575033145698000), 0x0003, 0x0036, 4384}, {INT64_C(1380575033145698000), 0x0003, 0x0034, 0}, {INT64_C(1380575033145698000), 0x0003, 0x0030, 480}, {INT64_C(1380575033145698000), 0x0003, 0x0031, 128}, {INT64_C(1380575033145698000), 0x0000, 0x0002, 0}, {INT64_C(1380575033145698000), 0x0003, 0x0035, 2911}, {INT64_C(1380575033145698000), 0x0003, 0x0036, 1530}, {INT64_C(1380575033145698000), 0x0003, 0x0034, 1}, {INT64_C(1380575033145698000), 0x0003, 0x0030, 384}, {INT64_C(1380575033145698000), 0x0003, 0x0031, 320}, {INT64_C(1380575033145698000), 0x0000, 0x0002, 0}, {INT64_C(1380575033145698000), 0x0000, 0x0000, 0}, {INT64_C(1380575033151702000), 0x0003, 0x0000, 1089}, {INT64_C(1380575033151702000), 0x0003, 0x0001, 5391}, {INT64_C(1380575033151702000), 0x0003, 0x0035, 1089}, {INT64_C(1380575033151702000), 0x0003, 0x0036, 5391}, {INT64_C(1380575033151702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033151702000), 0x0003, 0x0030, 480}, {INT64_C(1380575033151702000), 0x0003, 0x0031, 256}, {INT64_C(1380575033151702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033151702000), 0x0003, 0x0035, 640}, {INT64_C(1380575033151702000), 0x0003, 0x0036, 4364}, {INT64_C(1380575033151702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033151702000), 0x0003, 0x0030, 480}, {INT64_C(1380575033151702000), 0x0003, 0x0031, 128}, {INT64_C(1380575033151702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033151702000), 0x0003, 0x0035, 979}, {INT64_C(1380575033151702000), 0x0003, 0x0036, 4320}, {INT64_C(1380575033151702000), 0x0003, 0x0034, 1}, {INT64_C(1380575033151702000), 0x0003, 0x0030, 256}, {INT64_C(1380575033151702000), 0x0003, 0x0031, 160}, {INT64_C(1380575033151702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033151702000), 0x0003, 0x0035, 2919}, {INT64_C(1380575033151702000), 0x0003, 0x0036, 1522}, {INT64_C(1380575033151702000), 0x0003, 0x0034, 1}, {INT64_C(1380575033151702000), 0x0003, 0x0030, 384}, {INT64_C(1380575033151702000), 0x0003, 0x0031, 320}, {INT64_C(1380575033151702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033151702000), 0x0000, 0x0000, 0}, {INT64_C(1380575033165702000), 0x0003, 0x0000, 1152}, {INT64_C(1380575033165702000), 0x0003, 0x0001, 5369}, {INT64_C(1380575033165702000), 0x0003, 0x0035, 1152}, {INT64_C(1380575033165702000), 0x0003, 0x0036, 5369}, {INT64_C(1380575033165702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033165702000), 0x0003, 0x0030, 320}, {INT64_C(1380575033165702000), 0x0003, 0x0031, 128}, {INT64_C(1380575033165702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033165702000), 0x0003, 0x0035, 782}, {INT64_C(1380575033165702000), 0x0003, 0x0036, 4361}, {INT64_C(1380575033165702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033165702000), 0x0003, 0x0030, 640}, {INT64_C(1380575033165702000), 0x0003, 0x0031, 256}, {INT64_C(1380575033165702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033165702000), 0x0003, 0x0035, 1007}, {INT64_C(1380575033165702000), 0x0003, 0x0036, 3040}, {INT64_C(1380575033165702000), 0x0003, 0x0034, 1}, {INT64_C(1380575033165702000), 0x0003, 0x0030, 384}, {INT64_C(1380575033165702000), 0x0003, 0x0031, 160}, {INT64_C(1380575033165702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033165702000), 0x0003, 0x0035, 2930}, {INT64_C(1380575033165702000), 0x0003, 0x0036, 1526}, {INT64_C(1380575033165702000), 0x0003, 0x0034, 1}, {INT64_C(1380575033165702000), 0x0003, 0x0030, 384}, {INT64_C(1380575033165702000), 0x0003, 0x0031, 320}, {INT64_C(1380575033165702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033165702000), 0x0000, 0x0000, 0}, {INT64_C(1380575033171701000), 0x0003, 0x0000, 1235}, {INT64_C(1380575033171701000), 0x0003, 0x0001, 5346}, {INT64_C(1380575033171701000), 0x0003, 0x0035, 1235}, {INT64_C(1380575033171701000), 0x0003, 0x0036, 5346}, {INT64_C(1380575033171701000), 0x0003, 0x0034, 0}, {INT64_C(1380575033171701000), 0x0003, 0x0030, 320}, {INT64_C(1380575033171701000), 0x0003, 0x0031, 256}, {INT64_C(1380575033171701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033171701000), 0x0003, 0x0035, 832}, {INT64_C(1380575033171701000), 0x0003, 0x0036, 4324}, {INT64_C(1380575033171701000), 0x0003, 0x0034, 0}, {INT64_C(1380575033171701000), 0x0003, 0x0030, 480}, {INT64_C(1380575033171701000), 0x0003, 0x0031, 384}, {INT64_C(1380575033171701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033171701000), 0x0003, 0x0035, 1068}, {INT64_C(1380575033171701000), 0x0003, 0x0036, 2960}, {INT64_C(1380575033171701000), 0x0003, 0x0034, 0}, {INT64_C(1380575033171701000), 0x0003, 0x0030, 320}, {INT64_C(1380575033171701000), 0x0003, 0x0031, 256}, {INT64_C(1380575033171701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033171701000), 0x0003, 0x0035, 2944}, {INT64_C(1380575033171701000), 0x0003, 0x0036, 1520}, {INT64_C(1380575033171701000), 0x0003, 0x0034, 1}, {INT64_C(1380575033171701000), 0x0003, 0x0030, 384}, {INT64_C(1380575033171701000), 0x0003, 0x0031, 320}, {INT64_C(1380575033171701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033171701000), 0x0000, 0x0000, 0}, {INT64_C(1380575033183702000), 0x0003, 0x0000, 1280}, {INT64_C(1380575033183702000), 0x0003, 0x0001, 5327}, {INT64_C(1380575033183702000), 0x0003, 0x0035, 1280}, {INT64_C(1380575033183702000), 0x0003, 0x0036, 5327}, {INT64_C(1380575033183702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033183702000), 0x0003, 0x0030, 320}, {INT64_C(1380575033183702000), 0x0003, 0x0031, 128}, {INT64_C(1380575033183702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033183702000), 0x0003, 0x0035, 930}, {INT64_C(1380575033183702000), 0x0003, 0x0036, 4306}, {INT64_C(1380575033183702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033183702000), 0x0003, 0x0030, 480}, {INT64_C(1380575033183702000), 0x0003, 0x0031, 256}, {INT64_C(1380575033183702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033183702000), 0x0003, 0x0035, 1158}, {INT64_C(1380575033183702000), 0x0003, 0x0036, 2957}, {INT64_C(1380575033183702000), 0x0003, 0x0034, 1}, {INT64_C(1380575033183702000), 0x0003, 0x0030, 384}, {INT64_C(1380575033183702000), 0x0003, 0x0031, 320}, {INT64_C(1380575033183702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033183702000), 0x0003, 0x0035, 2949}, {INT64_C(1380575033183702000), 0x0003, 0x0036, 1515}, {INT64_C(1380575033183702000), 0x0003, 0x0034, 1}, {INT64_C(1380575033183702000), 0x0003, 0x0030, 384}, {INT64_C(1380575033183702000), 0x0003, 0x0031, 320}, {INT64_C(1380575033183702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033183702000), 0x0000, 0x0000, 0}, {INT64_C(1380575033203704000), 0x0003, 0x0000, 2546}, {INT64_C(1380575033203704000), 0x0003, 0x0001, 6080}, {INT64_C(1380575033203704000), 0x0003, 0x0035, 2546}, {INT64_C(1380575033203704000), 0x0003, 0x0036, 6080}, {INT64_C(1380575033203704000), 0x0003, 0x0034, 1}, {INT64_C(1380575033203704000), 0x0003, 0x0030, 384}, {INT64_C(1380575033203704000), 0x0003, 0x0031, 160}, {INT64_C(1380575033203704000), 0x0000, 0x0002, 0}, {INT64_C(1380575033203704000), 0x0003, 0x0035, 1408}, {INT64_C(1380575033203704000), 0x0003, 0x0036, 5220}, {INT64_C(1380575033203704000), 0x0003, 0x0034, 0}, {INT64_C(1380575033203704000), 0x0003, 0x0030, 320}, {INT64_C(1380575033203704000), 0x0003, 0x0031, 128}, {INT64_C(1380575033203704000), 0x0000, 0x0002, 0}, {INT64_C(1380575033203704000), 0x0003, 0x0035, 1023}, {INT64_C(1380575033203704000), 0x0003, 0x0036, 4254}, {INT64_C(1380575033203704000), 0x0003, 0x0034, 1}, {INT64_C(1380575033203704000), 0x0003, 0x0030, 512}, {INT64_C(1380575033203704000), 0x0003, 0x0031, 320}, {INT64_C(1380575033203704000), 0x0000, 0x0002, 0}, {INT64_C(1380575033203704000), 0x0003, 0x0035, 1260}, {INT64_C(1380575033203704000), 0x0003, 0x0036, 2962}, {INT64_C(1380575033203704000), 0x0003, 0x0034, 1}, {INT64_C(1380575033203704000), 0x0003, 0x0030, 384}, {INT64_C(1380575033203704000), 0x0003, 0x0031, 320}, {INT64_C(1380575033203704000), 0x0000, 0x0002, 0}, {INT64_C(1380575033203704000), 0x0003, 0x0035, 2967}, {INT64_C(1380575033203704000), 0x0003, 0x0036, 1519}, {INT64_C(1380575033203704000), 0x0003, 0x0034, 1}, {INT64_C(1380575033203704000), 0x0003, 0x0030, 384}, {INT64_C(1380575033203704000), 0x0003, 0x0031, 320}, {INT64_C(1380575033203704000), 0x0000, 0x0002, 0}, {INT64_C(1380575033203704000), 0x0000, 0x0000, 0}, {INT64_C(1380575033221704000), 0x0003, 0x0000, 2708}, {INT64_C(1380575033221704000), 0x0003, 0x0001, 5972}, {INT64_C(1380575033221704000), 0x0003, 0x0035, 2708}, {INT64_C(1380575033221704000), 0x0003, 0x0036, 5972}, {INT64_C(1380575033221704000), 0x0003, 0x0034, 1}, {INT64_C(1380575033221704000), 0x0003, 0x0030, 384}, {INT64_C(1380575033221704000), 0x0003, 0x0031, 320}, {INT64_C(1380575033221704000), 0x0000, 0x0002, 0}, {INT64_C(1380575033221704000), 0x0003, 0x0035, 1536}, {INT64_C(1380575033221704000), 0x0003, 0x0036, 5196}, {INT64_C(1380575033221704000), 0x0003, 0x0034, 0}, {INT64_C(1380575033221704000), 0x0003, 0x0030, 320}, {INT64_C(1380575033221704000), 0x0003, 0x0031, 128}, {INT64_C(1380575033221704000), 0x0000, 0x0002, 0}, {INT64_C(1380575033221704000), 0x0003, 0x0035, 1147}, {INT64_C(1380575033221704000), 0x0003, 0x0036, 4227}, {INT64_C(1380575033221704000), 0x0003, 0x0034, 0}, {INT64_C(1380575033221704000), 0x0003, 0x0030, 480}, {INT64_C(1380575033221704000), 0x0003, 0x0031, 384}, {INT64_C(1380575033221704000), 0x0000, 0x0002, 0}, {INT64_C(1380575033221704000), 0x0003, 0x0035, 1355}, {INT64_C(1380575033221704000), 0x0003, 0x0036, 2952}, {INT64_C(1380575033221704000), 0x0003, 0x0034, 1}, {INT64_C(1380575033221704000), 0x0003, 0x0030, 384}, {INT64_C(1380575033221704000), 0x0003, 0x0031, 320}, {INT64_C(1380575033221704000), 0x0000, 0x0002, 0}, {INT64_C(1380575033221704000), 0x0003, 0x0035, 2980}, {INT64_C(1380575033221704000), 0x0003, 0x0036, 1600}, {INT64_C(1380575033221704000), 0x0003, 0x0034, 1}, {INT64_C(1380575033221704000), 0x0003, 0x0030, 256}, {INT64_C(1380575033221704000), 0x0003, 0x0031, 160}, {INT64_C(1380575033221704000), 0x0000, 0x0002, 0}, {INT64_C(1380575033221704000), 0x0000, 0x0000, 0}, {INT64_C(1380575033239700000), 0x0003, 0x0000, 2880}, {INT64_C(1380575033239700000), 0x0003, 0x0001, 5825}, {INT64_C(1380575033239700000), 0x0003, 0x0035, 2880}, {INT64_C(1380575033239700000), 0x0003, 0x0036, 5825}, {INT64_C(1380575033239700000), 0x0003, 0x0034, 1}, {INT64_C(1380575033239700000), 0x0003, 0x0030, 384}, {INT64_C(1380575033239700000), 0x0003, 0x0031, 320}, {INT64_C(1380575033239700000), 0x0000, 0x0002, 0}, {INT64_C(1380575033239700000), 0x0003, 0x0035, 1664}, {INT64_C(1380575033239700000), 0x0003, 0x0036, 5067}, {INT64_C(1380575033239700000), 0x0003, 0x0034, 0}, {INT64_C(1380575033239700000), 0x0003, 0x0030, 320}, {INT64_C(1380575033239700000), 0x0003, 0x0031, 128}, {INT64_C(1380575033239700000), 0x0000, 0x0002, 0}, {INT64_C(1380575033239700000), 0x0003, 0x0035, 1271}, {INT64_C(1380575033239700000), 0x0003, 0x0036, 4153}, {INT64_C(1380575033239700000), 0x0003, 0x0034, 0}, {INT64_C(1380575033239700000), 0x0003, 0x0030, 480}, {INT64_C(1380575033239700000), 0x0003, 0x0031, 384}, {INT64_C(1380575033239700000), 0x0000, 0x0002, 0}, {INT64_C(1380575033239700000), 0x0003, 0x0035, 1470}, {INT64_C(1380575033239700000), 0x0003, 0x0036, 2920}, {INT64_C(1380575033239700000), 0x0003, 0x0034, 0}, {INT64_C(1380575033239700000), 0x0003, 0x0030, 320}, {INT64_C(1380575033239700000), 0x0003, 0x0031, 256}, {INT64_C(1380575033239700000), 0x0000, 0x0002, 0}, {INT64_C(1380575033239700000), 0x0000, 0x0000, 0}, {INT64_C(1380575033259698000), 0x0003, 0x0000, 3092}, {INT64_C(1380575033259698000), 0x0003, 0x0001, 5655}, {INT64_C(1380575033259698000), 0x0003, 0x0035, 3092}, {INT64_C(1380575033259698000), 0x0003, 0x0036, 5655}, {INT64_C(1380575033259698000), 0x0003, 0x0034, 1}, {INT64_C(1380575033259698000), 0x0003, 0x0030, 384}, {INT64_C(1380575033259698000), 0x0003, 0x0031, 320}, {INT64_C(1380575033259698000), 0x0000, 0x0002, 0}, {INT64_C(1380575033259698000), 0x0003, 0x0035, 1792}, {INT64_C(1380575033259698000), 0x0003, 0x0036, 5031}, {INT64_C(1380575033259698000), 0x0003, 0x0034, 0}, {INT64_C(1380575033259698000), 0x0003, 0x0030, 320}, {INT64_C(1380575033259698000), 0x0003, 0x0031, 128}, {INT64_C(1380575033259698000), 0x0000, 0x0002, 0}, {INT64_C(1380575033259698000), 0x0003, 0x0035, 1367}, {INT64_C(1380575033259698000), 0x0003, 0x0036, 4076}, {INT64_C(1380575033259698000), 0x0003, 0x0034, 0}, {INT64_C(1380575033259698000), 0x0003, 0x0030, 320}, {INT64_C(1380575033259698000), 0x0003, 0x0031, 256}, {INT64_C(1380575033259698000), 0x0000, 0x0002, 0}, {INT64_C(1380575033259698000), 0x0003, 0x0035, 1571}, {INT64_C(1380575033259698000), 0x0003, 0x0036, 2880}, {INT64_C(1380575033259698000), 0x0003, 0x0034, 1}, {INT64_C(1380575033259698000), 0x0003, 0x0030, 384}, {INT64_C(1380575033259698000), 0x0003, 0x0031, 160}, {INT64_C(1380575033259698000), 0x0000, 0x0002, 0}, {INT64_C(1380575033259698000), 0x0000, 0x0000, 0}, {INT64_C(1380575033277700000), 0x0003, 0x0000, 3205}, {INT64_C(1380575033277700000), 0x0003, 0x0001, 5524}, {INT64_C(1380575033277700000), 0x0003, 0x0035, 3205}, {INT64_C(1380575033277700000), 0x0003, 0x0036, 5524}, {INT64_C(1380575033277700000), 0x0003, 0x0034, 1}, {INT64_C(1380575033277700000), 0x0003, 0x0030, 384}, {INT64_C(1380575033277700000), 0x0003, 0x0031, 320}, {INT64_C(1380575033277700000), 0x0000, 0x0002, 0}, {INT64_C(1380575033277700000), 0x0003, 0x0035, 1917}, {INT64_C(1380575033277700000), 0x0003, 0x0036, 4998}, {INT64_C(1380575033277700000), 0x0003, 0x0034, 0}, {INT64_C(1380575033277700000), 0x0003, 0x0030, 320}, {INT64_C(1380575033277700000), 0x0003, 0x0031, 256}, {INT64_C(1380575033277700000), 0x0000, 0x0002, 0}, {INT64_C(1380575033277700000), 0x0003, 0x0035, 1492}, {INT64_C(1380575033277700000), 0x0003, 0x0036, 4039}, {INT64_C(1380575033277700000), 0x0003, 0x0034, 1}, {INT64_C(1380575033277700000), 0x0003, 0x0030, 384}, {INT64_C(1380575033277700000), 0x0003, 0x0031, 320}, {INT64_C(1380575033277700000), 0x0000, 0x0002, 0}, {INT64_C(1380575033277700000), 0x0003, 0x0035, 1632}, {INT64_C(1380575033277700000), 0x0003, 0x0036, 2880}, {INT64_C(1380575033277700000), 0x0003, 0x0034, 1}, {INT64_C(1380575033277700000), 0x0003, 0x0030, 256}, {INT64_C(1380575033277700000), 0x0003, 0x0031, 160}, {INT64_C(1380575033277700000), 0x0000, 0x0002, 0}, {INT64_C(1380575033277700000), 0x0000, 0x0000, 0}, {INT64_C(1380575033295702000), 0x0003, 0x0000, 3335}, {INT64_C(1380575033295702000), 0x0003, 0x0001, 5418}, {INT64_C(1380575033295702000), 0x0003, 0x0035, 3335}, {INT64_C(1380575033295702000), 0x0003, 0x0036, 5418}, {INT64_C(1380575033295702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033295702000), 0x0003, 0x0030, 480}, {INT64_C(1380575033295702000), 0x0003, 0x0031, 384}, {INT64_C(1380575033295702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033295702000), 0x0003, 0x0035, 2033}, {INT64_C(1380575033295702000), 0x0003, 0x0036, 4960}, {INT64_C(1380575033295702000), 0x0003, 0x0034, 1}, {INT64_C(1380575033295702000), 0x0003, 0x0030, 256}, {INT64_C(1380575033295702000), 0x0003, 0x0031, 160}, {INT64_C(1380575033295702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033295702000), 0x0003, 0x0035, 1612}, {INT64_C(1380575033295702000), 0x0003, 0x0036, 4024}, {INT64_C(1380575033295702000), 0x0003, 0x0034, 1}, {INT64_C(1380575033295702000), 0x0003, 0x0030, 384}, {INT64_C(1380575033295702000), 0x0003, 0x0031, 320}, {INT64_C(1380575033295702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033295702000), 0x0003, 0x0035, 1778}, {INT64_C(1380575033295702000), 0x0003, 0x0036, 2880}, {INT64_C(1380575033295702000), 0x0003, 0x0034, 1}, {INT64_C(1380575033295702000), 0x0003, 0x0030, 256}, {INT64_C(1380575033295702000), 0x0003, 0x0031, 160}, {INT64_C(1380575033295702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033295702000), 0x0000, 0x0000, 0}, {INT64_C(1380575033315701000), 0x0003, 0x0000, 3436}, {INT64_C(1380575033315701000), 0x0003, 0x0001, 5290}, {INT64_C(1380575033315701000), 0x0003, 0x0035, 3436}, {INT64_C(1380575033315701000), 0x0003, 0x0036, 5290}, {INT64_C(1380575033315701000), 0x0003, 0x0034, 0}, {INT64_C(1380575033315701000), 0x0003, 0x0030, 480}, {INT64_C(1380575033315701000), 0x0003, 0x0031, 384}, {INT64_C(1380575033315701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033315701000), 0x0003, 0x0035, 2143}, {INT64_C(1380575033315701000), 0x0003, 0x0036, 4852}, {INT64_C(1380575033315701000), 0x0003, 0x0034, 0}, {INT64_C(1380575033315701000), 0x0003, 0x0030, 320}, {INT64_C(1380575033315701000), 0x0003, 0x0031, 256}, {INT64_C(1380575033315701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033315701000), 0x0003, 0x0035, 1725}, {INT64_C(1380575033315701000), 0x0003, 0x0036, 3922}, {INT64_C(1380575033315701000), 0x0003, 0x0034, 0}, {INT64_C(1380575033315701000), 0x0003, 0x0030, 480}, {INT64_C(1380575033315701000), 0x0003, 0x0031, 256}, {INT64_C(1380575033315701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033315701000), 0x0000, 0x0000, 0}, {INT64_C(1380575033333701000), 0x0003, 0x0000, 3556}, {INT64_C(1380575033333701000), 0x0003, 0x0001, 5166}, {INT64_C(1380575033333701000), 0x0003, 0x0035, 3556}, {INT64_C(1380575033333701000), 0x0003, 0x0036, 5166}, {INT64_C(1380575033333701000), 0x0003, 0x0034, 1}, {INT64_C(1380575033333701000), 0x0003, 0x0030, 384}, {INT64_C(1380575033333701000), 0x0003, 0x0031, 320}, {INT64_C(1380575033333701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033333701000), 0x0003, 0x0035, 2258}, {INT64_C(1380575033333701000), 0x0003, 0x0036, 4701}, {INT64_C(1380575033333701000), 0x0003, 0x0034, 0}, {INT64_C(1380575033333701000), 0x0003, 0x0030, 320}, {INT64_C(1380575033333701000), 0x0003, 0x0031, 256}, {INT64_C(1380575033333701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033333701000), 0x0003, 0x0035, 1816}, {INT64_C(1380575033333701000), 0x0003, 0x0036, 3867}, {INT64_C(1380575033333701000), 0x0003, 0x0034, 0}, {INT64_C(1380575033333701000), 0x0003, 0x0030, 480}, {INT64_C(1380575033333701000), 0x0003, 0x0031, 384}, {INT64_C(1380575033333701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033333701000), 0x0000, 0x0000, 0}, {INT64_C(1380575033351701000), 0x0003, 0x0000, 3647}, {INT64_C(1380575033351701000), 0x0003, 0x0001, 4988}, {INT64_C(1380575033351701000), 0x0003, 0x0035, 3647}, {INT64_C(1380575033351701000), 0x0003, 0x0036, 4988}, {INT64_C(1380575033351701000), 0x0003, 0x0034, 0}, {INT64_C(1380575033351701000), 0x0003, 0x0030, 640}, {INT64_C(1380575033351701000), 0x0003, 0x0031, 512}, {INT64_C(1380575033351701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033351701000), 0x0003, 0x0035, 2370}, {INT64_C(1380575033351701000), 0x0003, 0x0036, 4653}, {INT64_C(1380575033351701000), 0x0003, 0x0034, 0}, {INT64_C(1380575033351701000), 0x0003, 0x0030, 480}, {INT64_C(1380575033351701000), 0x0003, 0x0031, 256}, {INT64_C(1380575033351701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033351701000), 0x0003, 0x0035, 1869}, {INT64_C(1380575033351701000), 0x0003, 0x0036, 3764}, {INT64_C(1380575033351701000), 0x0003, 0x0034, 0}, {INT64_C(1380575033351701000), 0x0003, 0x0030, 480}, {INT64_C(1380575033351701000), 0x0003, 0x0031, 256}, {INT64_C(1380575033351701000), 0x0000, 0x0002, 0}, {INT64_C(1380575033351701000), 0x0000, 0x0000, 0}, {INT64_C(1380575033371700000), 0x0003, 0x0000, 3702}, {INT64_C(1380575033371700000), 0x0003, 0x0001, 4870}, {INT64_C(1380575033371700000), 0x0003, 0x0035, 3702}, {INT64_C(1380575033371700000), 0x0003, 0x0036, 4870}, {INT64_C(1380575033371700000), 0x0003, 0x0034, 0}, {INT64_C(1380575033371700000), 0x0003, 0x0030, 640}, {INT64_C(1380575033371700000), 0x0003, 0x0031, 384}, {INT64_C(1380575033371700000), 0x0000, 0x0002, 0}, {INT64_C(1380575033371700000), 0x0003, 0x0035, 2430}, {INT64_C(1380575033371700000), 0x0003, 0x0036, 4539}, {INT64_C(1380575033371700000), 0x0003, 0x0034, 1}, {INT64_C(1380575033371700000), 0x0003, 0x0030, 384}, {INT64_C(1380575033371700000), 0x0003, 0x0031, 320}, {INT64_C(1380575033371700000), 0x0000, 0x0002, 0}, {INT64_C(1380575033371700000), 0x0003, 0x0035, 1966}, {INT64_C(1380575033371700000), 0x0003, 0x0036, 3704}, {INT64_C(1380575033371700000), 0x0003, 0x0034, 1}, {INT64_C(1380575033371700000), 0x0003, 0x0030, 384}, {INT64_C(1380575033371700000), 0x0003, 0x0031, 320}, {INT64_C(1380575033371700000), 0x0000, 0x0002, 0}, {INT64_C(1380575033371700000), 0x0000, 0x0000, 0}, {INT64_C(1380575033389702000), 0x0003, 0x0000, 3747}, {INT64_C(1380575033389702000), 0x0003, 0x0001, 4748}, {INT64_C(1380575033389702000), 0x0003, 0x0035, 3747}, {INT64_C(1380575033389702000), 0x0003, 0x0036, 4748}, {INT64_C(1380575033389702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033389702000), 0x0003, 0x0030, 640}, {INT64_C(1380575033389702000), 0x0003, 0x0031, 384}, {INT64_C(1380575033389702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033389702000), 0x0003, 0x0035, 2518}, {INT64_C(1380575033389702000), 0x0003, 0x0036, 4442}, {INT64_C(1380575033389702000), 0x0003, 0x0034, 0}, {INT64_C(1380575033389702000), 0x0003, 0x0030, 480}, {INT64_C(1380575033389702000), 0x0003, 0x0031, 256}, {INT64_C(1380575033389702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033389702000), 0x0003, 0x0035, 2068}, {INT64_C(1380575033389702000), 0x0003, 0x0036, 3680}, {INT64_C(1380575033389702000), 0x0003, 0x0034, 1}, {INT64_C(1380575033389702000), 0x0003, 0x0030, 256}, {INT64_C(1380575033389702000), 0x0003, 0x0031, 160}, {INT64_C(1380575033389702000), 0x0000, 0x0002, 0}, {INT64_C(1380575033389702000), 0x0000, 0x0000, 0}, {INT64_C(1380575033407698000), 0x0003, 0x0000, 3775}, {INT64_C(1380575033407698000), 0x0003, 0x0001, 4583}, {INT64_C(1380575033407698000), 0x0003, 0x0035, 3775}, {INT64_C(1380575033407698000), 0x0003, 0x0036, 4583}, {INT64_C(1380575033407698000), 0x0003, 0x0034, 0}, {INT64_C(1380575033407698000), 0x0003, 0x0030, 320}, {INT64_C(1380575033407698000), 0x0003, 0x0031, 256}, {INT64_C(1380575033407698000), 0x0000, 0x0002, 0}, {INT64_C(1380575033407698000), 0x0003, 0x0035, 2588}, {INT64_C(1380575033407698000), 0x0003, 0x0036, 4314}, {INT64_C(1380575033407698000), 0x0003, 0x0034, 0}, {INT64_C(1380575033407698000), 0x0003, 0x0030, 480}, {INT64_C(1380575033407698000), 0x0003, 0x0031, 256}, {INT64_C(1380575033407698000), 0x0000, 0x0002, 0}, {INT64_C(1380575033407698000), 0x0000, 0x0000, 0}, {INT64_C(1380575033501694000), 0x0001, 0x014d, 0}, {INT64_C(1380575033501694000), 0x0001, 0x014a, 0}, {INT64_C(1380575033501694000), 0x0000, 0x0000, 0}, {INT64_C(1380575034867687000), 0x0003, 0x0035, 1455}, {INT64_C(1380575034867687000), 0x0003, 0x0036, 4248}, {INT64_C(1380575034867687000), 0x0003, 0x0034, 0}, {INT64_C(1380575034867687000), 0x0003, 0x0030, 640}, {INT64_C(1380575034867687000), 0x0003, 0x0031, 256}, {INT64_C(1380575034867687000), 0x0000, 0x0002, 0}, {INT64_C(1380575034867687000), 0x0000, 0x0000, 0}, {INT64_C(1380575034873691000), 0x0003, 0x0000, 1497}, {INT64_C(1380575034873691000), 0x0003, 0x0001, 5657}, {INT64_C(1380575034873691000), 0x0003, 0x0035, 1497}, {INT64_C(1380575034873691000), 0x0003, 0x0036, 5657}, {INT64_C(1380575034873691000), 0x0003, 0x0034, 0}, {INT64_C(1380575034873691000), 0x0003, 0x0030, 320}, {INT64_C(1380575034873691000), 0x0003, 0x0031, 256}, {INT64_C(1380575034873691000), 0x0000, 0x0002, 0}, {INT64_C(1380575034873691000), 0x0003, 0x0035, 1464}, {INT64_C(1380575034873691000), 0x0003, 0x0036, 4234}, {INT64_C(1380575034873691000), 0x0003, 0x0034, 0}, {INT64_C(1380575034873691000), 0x0003, 0x0030, 320}, {INT64_C(1380575034873691000), 0x0003, 0x0031, 256}, {INT64_C(1380575034873691000), 0x0000, 0x0002, 0}, {INT64_C(1380575034873691000), 0x0001, 0x014d, 1}, {INT64_C(1380575034873691000), 0x0001, 0x014a, 1}, {INT64_C(1380575034873691000), 0x0000, 0x0000, 0}, {INT64_C(1380575034885687000), 0x0003, 0x0000, 1499}, {INT64_C(1380575034885687000), 0x0003, 0x0001, 5656}, {INT64_C(1380575034885687000), 0x0003, 0x0035, 1499}, {INT64_C(1380575034885687000), 0x0003, 0x0036, 5656}, {INT64_C(1380575034885687000), 0x0003, 0x0034, 0}, {INT64_C(1380575034885687000), 0x0003, 0x0030, 320}, {INT64_C(1380575034885687000), 0x0003, 0x0031, 256}, {INT64_C(1380575034885687000), 0x0000, 0x0002, 0}, {INT64_C(1380575034885687000), 0x0003, 0x0035, 1470}, {INT64_C(1380575034885687000), 0x0003, 0x0036, 4249}, {INT64_C(1380575034885687000), 0x0003, 0x0034, 0}, {INT64_C(1380575034885687000), 0x0003, 0x0030, 480}, {INT64_C(1380575034885687000), 0x0003, 0x0031, 256}, {INT64_C(1380575034885687000), 0x0000, 0x0002, 0}, {INT64_C(1380575034885687000), 0x0000, 0x0000, 0}, {INT64_C(1380575034891689000), 0x0003, 0x0000, 1502}, {INT64_C(1380575034891689000), 0x0003, 0x0001, 5651}, {INT64_C(1380575034891689000), 0x0003, 0x0035, 1502}, {INT64_C(1380575034891689000), 0x0003, 0x0036, 5651}, {INT64_C(1380575034891689000), 0x0003, 0x0034, 0}, {INT64_C(1380575034891689000), 0x0003, 0x0030, 320}, {INT64_C(1380575034891689000), 0x0003, 0x0031, 256}, {INT64_C(1380575034891689000), 0x0000, 0x0002, 0}, {INT64_C(1380575034891689000), 0x0003, 0x0035, 1480}, {INT64_C(1380575034891689000), 0x0003, 0x0036, 4242}, {INT64_C(1380575034891689000), 0x0003, 0x0034, 0}, {INT64_C(1380575034891689000), 0x0003, 0x0030, 480}, {INT64_C(1380575034891689000), 0x0003, 0x0031, 256}, {INT64_C(1380575034891689000), 0x0000, 0x0002, 0}, {INT64_C(1380575034891689000), 0x0000, 0x0000, 0}, {INT64_C(1380575034905690000), 0x0003, 0x0000, 1509}, {INT64_C(1380575034905690000), 0x0003, 0x0001, 5634}, {INT64_C(1380575034905690000), 0x0003, 0x0035, 1509}, {INT64_C(1380575034905690000), 0x0003, 0x0036, 5634}, {INT64_C(1380575034905690000), 0x0003, 0x0034, 0}, {INT64_C(1380575034905690000), 0x0003, 0x0030, 320}, {INT64_C(1380575034905690000), 0x0003, 0x0031, 256}, {INT64_C(1380575034905690000), 0x0000, 0x0002, 0}, {INT64_C(1380575034905690000), 0x0003, 0x0035, 1485}, {INT64_C(1380575034905690000), 0x0003, 0x0036, 4226}, {INT64_C(1380575034905690000), 0x0003, 0x0034, 0}, {INT64_C(1380575034905690000), 0x0003, 0x0030, 320}, {INT64_C(1380575034905690000), 0x0003, 0x0031, 256}, {INT64_C(1380575034905690000), 0x0000, 0x0002, 0}, {INT64_C(1380575034905690000), 0x0000, 0x0000, 0}, {INT64_C(1380575034911691000), 0x0003, 0x0000, 1526}, {INT64_C(1380575034911691000), 0x0003, 0x0001, 5648}, {INT64_C(1380575034911691000), 0x0003, 0x0035, 1526}, {INT64_C(1380575034911691000), 0x0003, 0x0036, 5648}, {INT64_C(1380575034911691000), 0x0003, 0x0034, 1}, {INT64_C(1380575034911691000), 0x0003, 0x0030, 384}, {INT64_C(1380575034911691000), 0x0003, 0x0031, 320}, {INT64_C(1380575034911691000), 0x0000, 0x0002, 0}, {INT64_C(1380575034911691000), 0x0003, 0x0035, 1506}, {INT64_C(1380575034911691000), 0x0003, 0x0036, 4228}, {INT64_C(1380575034911691000), 0x0003, 0x0034, 0}, {INT64_C(1380575034911691000), 0x0003, 0x0030, 640}, {INT64_C(1380575034911691000), 0x0003, 0x0031, 384}, {INT64_C(1380575034911691000), 0x0000, 0x0002, 0}, {INT64_C(1380575034911691000), 0x0003, 0x0035, 3160}, {INT64_C(1380575034911691000), 0x0003, 0x0036, 1760}, {INT64_C(1380575034911691000), 0x0003, 0x0034, 1}, {INT64_C(1380575034911691000), 0x0003, 0x0030, 256}, {INT64_C(1380575034911691000), 0x0003, 0x0031, 160}, {INT64_C(1380575034911691000), 0x0000, 0x0002, 0}, {INT64_C(1380575034911691000), 0x0000, 0x0000, 0}, {INT64_C(1380575034923690000), 0x0003, 0x0000, 1556}, {INT64_C(1380575034923690000), 0x0003, 0x0001, 5636}, {INT64_C(1380575034923690000), 0x0003, 0x0035, 1556}, {INT64_C(1380575034923690000), 0x0003, 0x0036, 5636}, {INT64_C(1380575034923690000), 0x0003, 0x0034, 0}, {INT64_C(1380575034923690000), 0x0003, 0x0030, 480}, {INT64_C(1380575034923690000), 0x0003, 0x0031, 384}, {INT64_C(1380575034923690000), 0x0000, 0x0002, 0}, {INT64_C(1380575034923690000), 0x0003, 0x0035, 1538}, {INT64_C(1380575034923690000), 0x0003, 0x0036, 4245}, {INT64_C(1380575034923690000), 0x0003, 0x0034, 0}, {INT64_C(1380575034923690000), 0x0003, 0x0030, 640}, {INT64_C(1380575034923690000), 0x0003, 0x0031, 384}, {INT64_C(1380575034923690000), 0x0000, 0x0002, 0}, {INT64_C(1380575034923690000), 0x0003, 0x0035, 3175}, {INT64_C(1380575034923690000), 0x0003, 0x0036, 1760}, {INT64_C(1380575034923690000), 0x0003, 0x0034, 1}, {INT64_C(1380575034923690000), 0x0003, 0x0030, 384}, {INT64_C(1380575034923690000), 0x0003, 0x0031, 160}, {INT64_C(1380575034923690000), 0x0000, 0x0002, 0}, {INT64_C(1380575034923690000), 0x0000, 0x0000, 0}, {INT64_C(1380575034929691000), 0x0003, 0x0000, 1593}, {INT64_C(1380575034929691000), 0x0003, 0x0001, 5609}, {INT64_C(1380575034929691000), 0x0003, 0x0035, 1593}, {INT64_C(1380575034929691000), 0x0003, 0x0036, 5609}, {INT64_C(1380575034929691000), 0x0003, 0x0034, 0}, {INT64_C(1380575034929691000), 0x0003, 0x0030, 480}, {INT64_C(1380575034929691000), 0x0003, 0x0031, 256}, {INT64_C(1380575034929691000), 0x0000, 0x0002, 0}, {INT64_C(1380575034929691000), 0x0003, 0x0035, 1557}, {INT64_C(1380575034929691000), 0x0003, 0x0036, 4216}, {INT64_C(1380575034929691000), 0x0003, 0x0034, 0}, {INT64_C(1380575034929691000), 0x0003, 0x0030, 480}, {INT64_C(1380575034929691000), 0x0003, 0x0031, 384}, {INT64_C(1380575034929691000), 0x0000, 0x0002, 0}, {INT64_C(1380575034929691000), 0x0003, 0x0035, 3162}, {INT64_C(1380575034929691000), 0x0003, 0x0036, 1760}, {INT64_C(1380575034929691000), 0x0003, 0x0034, 1}, {INT64_C(1380575034929691000), 0x0003, 0x0030, 384}, {INT64_C(1380575034929691000), 0x0003, 0x0031, 160}, {INT64_C(1380575034929691000), 0x0000, 0x0002, 0}, {INT64_C(1380575034929691000), 0x0000, 0x0000, 0}, {INT64_C(1380575034943688000), 0x0003, 0x0000, 1635}, {INT64_C(1380575034943688000), 0x0003, 0x0001, 5570}, {INT64_C(1380575034943688000), 0x0003, 0x0035, 1635}, {INT64_C(1380575034943688000), 0x0003, 0x0036, 5570}, {INT64_C(1380575034943688000), 0x0003, 0x0034, 0}, {INT64_C(1380575034943688000), 0x0003, 0x0030, 480}, {INT64_C(1380575034943688000), 0x0003, 0x0031, 256}, {INT64_C(1380575034943688000), 0x0000, 0x0002, 0}, {INT64_C(1380575034943688000), 0x0003, 0x0035, 1587}, {INT64_C(1380575034943688000), 0x0003, 0x0036, 4208}, {INT64_C(1380575034943688000), 0x0003, 0x0034, 0}, {INT64_C(1380575034943688000), 0x0003, 0x0030, 480}, {INT64_C(1380575034943688000), 0x0003, 0x0031, 256}, {INT64_C(1380575034943688000), 0x0000, 0x0002, 0}, {INT64_C(1380575034943688000), 0x0003, 0x0035, 3170}, {INT64_C(1380575034943688000), 0x0003, 0x0036, 1760}, {INT64_C(1380575034943688000), 0x0003, 0x0034, 1}, {INT64_C(1380575034943688000), 0x0003, 0x0030, 384}, {INT64_C(1380575034943688000), 0x0003, 0x0031, 160}, {INT64_C(1380575034943688000), 0x0000, 0x0002, 0}, {INT64_C(1380575034943688000), 0x0000, 0x0000, 0}, {INT64_C(1380575034949687000), 0x0003, 0x0000, 1684}, {INT64_C(1380575034949687000), 0x0003, 0x0001, 5538}, {INT64_C(1380575034949687000), 0x0003, 0x0035, 1684}, {INT64_C(1380575034949687000), 0x0003, 0x0036, 5538}, {INT64_C(1380575034949687000), 0x0003, 0x0034, 0}, {INT64_C(1380575034949687000), 0x0003, 0x0030, 320}, {INT64_C(1380575034949687000), 0x0003, 0x0031, 256}, {INT64_C(1380575034949687000), 0x0000, 0x0002, 0}, {INT64_C(1380575034949687000), 0x0003, 0x0035, 1622}, {INT64_C(1380575034949687000), 0x0003, 0x0036, 4204}, {INT64_C(1380575034949687000), 0x0003, 0x0034, 0}, {INT64_C(1380575034949687000), 0x0003, 0x0030, 480}, {INT64_C(1380575034949687000), 0x0003, 0x0031, 384}, {INT64_C(1380575034949687000), 0x0000, 0x0002, 0}, {INT64_C(1380575034949687000), 0x0003, 0x0035, 3175}, {INT64_C(1380575034949687000), 0x0003, 0x0036, 1760}, {INT64_C(1380575034949687000), 0x0003, 0x0034, 1}, {INT64_C(1380575034949687000), 0x0003, 0x0030, 384}, {INT64_C(1380575034949687000), 0x0003, 0x0031, 160}, {INT64_C(1380575034949687000), 0x0000, 0x0002, 0}, {INT64_C(1380575034949687000), 0x0000, 0x0000, 0}, {INT64_C(1380575034961692000), 0x0003, 0x0000, 1715}, {INT64_C(1380575034961692000), 0x0003, 0x0001, 5512}, {INT64_C(1380575034961692000), 0x0003, 0x0035, 1715}, {INT64_C(1380575034961692000), 0x0003, 0x0036, 5512}, {INT64_C(1380575034961692000), 0x0003, 0x0034, 0}, {INT64_C(1380575034961692000), 0x0003, 0x0030, 320}, {INT64_C(1380575034961692000), 0x0003, 0x0031, 256}, {INT64_C(1380575034961692000), 0x0000, 0x0002, 0}, {INT64_C(1380575034961692000), 0x0003, 0x0035, 1664}, {INT64_C(1380575034961692000), 0x0003, 0x0036, 4169}, {INT64_C(1380575034961692000), 0x0003, 0x0034, 0}, {INT64_C(1380575034961692000), 0x0003, 0x0030, 480}, {INT64_C(1380575034961692000), 0x0003, 0x0031, 384}, {INT64_C(1380575034961692000), 0x0000, 0x0002, 0}, {INT64_C(1380575034961692000), 0x0003, 0x0035, 3182}, {INT64_C(1380575034961692000), 0x0003, 0x0036, 1760}, {INT64_C(1380575034961692000), 0x0003, 0x0034, 1}, {INT64_C(1380575034961692000), 0x0003, 0x0030, 384}, {INT64_C(1380575034961692000), 0x0003, 0x0031, 160}, {INT64_C(1380575034961692000), 0x0000, 0x0002, 0}, {INT64_C(1380575034961692000), 0x0000, 0x0000, 0}, {INT64_C(1380575034979688000), 0x0003, 0x0000, 1754}, {INT64_C(1380575034979688000), 0x0003, 0x0001, 5481}, {INT64_C(1380575034979688000), 0x0003, 0x0035, 1754}, {INT64_C(1380575034979688000), 0x0003, 0x0036, 5481}, {INT64_C(1380575034979688000), 0x0003, 0x0034, 0}, {INT64_C(1380575034979688000), 0x0003, 0x0030, 480}, {INT64_C(1380575034979688000), 0x0003, 0x0031, 256}, {INT64_C(1380575034979688000), 0x0000, 0x0002, 0}, {INT64_C(1380575034979688000), 0x0003, 0x0035, 1716}, {INT64_C(1380575034979688000), 0x0003, 0x0036, 4144}, {INT64_C(1380575034979688000), 0x0003, 0x0034, 0}, {INT64_C(1380575034979688000), 0x0003, 0x0030, 480}, {INT64_C(1380575034979688000), 0x0003, 0x0031, 256}, {INT64_C(1380575034979688000), 0x0000, 0x0002, 0}, {INT64_C(1380575034979688000), 0x0003, 0x0035, 3190}, {INT64_C(1380575034979688000), 0x0003, 0x0036, 1838}, {INT64_C(1380575034979688000), 0x0003, 0x0034, 1}, {INT64_C(1380575034979688000), 0x0003, 0x0030, 384}, {INT64_C(1380575034979688000), 0x0003, 0x0031, 320}, {INT64_C(1380575034979688000), 0x0000, 0x0002, 0}, {INT64_C(1380575034979688000), 0x0000, 0x0000, 0}, {INT64_C(1380575034999689000), 0x0003, 0x0000, 1812}, {INT64_C(1380575034999689000), 0x0003, 0x0001, 5461}, {INT64_C(1380575034999689000), 0x0003, 0x0035, 1812}, {INT64_C(1380575034999689000), 0x0003, 0x0036, 5461}, {INT64_C(1380575034999689000), 0x0003, 0x0034, 0}, {INT64_C(1380575034999689000), 0x0003, 0x0030, 480}, {INT64_C(1380575034999689000), 0x0003, 0x0031, 256}, {INT64_C(1380575034999689000), 0x0000, 0x0002, 0}, {INT64_C(1380575034999689000), 0x0003, 0x0035, 1747}, {INT64_C(1380575034999689000), 0x0003, 0x0036, 4125}, {INT64_C(1380575034999689000), 0x0003, 0x0034, 0}, {INT64_C(1380575034999689000), 0x0003, 0x0030, 480}, {INT64_C(1380575034999689000), 0x0003, 0x0031, 384}, {INT64_C(1380575034999689000), 0x0000, 0x0002, 0}, {INT64_C(1380575034999689000), 0x0003, 0x0035, 3194}, {INT64_C(1380575034999689000), 0x0003, 0x0036, 1826}, {INT64_C(1380575034999689000), 0x0003, 0x0034, 1}, {INT64_C(1380575034999689000), 0x0003, 0x0030, 384}, {INT64_C(1380575034999689000), 0x0003, 0x0031, 320}, {INT64_C(1380575034999689000), 0x0000, 0x0002, 0}, {INT64_C(1380575034999689000), 0x0000, 0x0000, 0}, {INT64_C(1380575035017687000), 0x0003, 0x0000, 1835}, {INT64_C(1380575035017687000), 0x0003, 0x0001, 5409}, {INT64_C(1380575035017687000), 0x0003, 0x0035, 1835}, {INT64_C(1380575035017687000), 0x0003, 0x0036, 5409}, {INT64_C(1380575035017687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035017687000), 0x0003, 0x0030, 480}, {INT64_C(1380575035017687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035017687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035017687000), 0x0003, 0x0035, 1803}, {INT64_C(1380575035017687000), 0x0003, 0x0036, 4096}, {INT64_C(1380575035017687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035017687000), 0x0003, 0x0030, 480}, {INT64_C(1380575035017687000), 0x0003, 0x0031, 384}, {INT64_C(1380575035017687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035017687000), 0x0003, 0x0035, 3189}, {INT64_C(1380575035017687000), 0x0003, 0x0036, 1829}, {INT64_C(1380575035017687000), 0x0003, 0x0034, 1}, {INT64_C(1380575035017687000), 0x0003, 0x0030, 384}, {INT64_C(1380575035017687000), 0x0003, 0x0031, 320}, {INT64_C(1380575035017687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035017687000), 0x0000, 0x0000, 0}, {INT64_C(1380575035035689000), 0x0003, 0x0000, 1891}, {INT64_C(1380575035035689000), 0x0003, 0x0001, 5369}, {INT64_C(1380575035035689000), 0x0003, 0x0035, 1891}, {INT64_C(1380575035035689000), 0x0003, 0x0036, 5369}, {INT64_C(1380575035035689000), 0x0003, 0x0034, 0}, {INT64_C(1380575035035689000), 0x0003, 0x0030, 480}, {INT64_C(1380575035035689000), 0x0003, 0x0031, 256}, {INT64_C(1380575035035689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035035689000), 0x0003, 0x0035, 1859}, {INT64_C(1380575035035689000), 0x0003, 0x0036, 4078}, {INT64_C(1380575035035689000), 0x0003, 0x0034, 0}, {INT64_C(1380575035035689000), 0x0003, 0x0030, 480}, {INT64_C(1380575035035689000), 0x0003, 0x0031, 256}, {INT64_C(1380575035035689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035035689000), 0x0003, 0x0035, 3194}, {INT64_C(1380575035035689000), 0x0003, 0x0036, 1835}, {INT64_C(1380575035035689000), 0x0003, 0x0034, 1}, {INT64_C(1380575035035689000), 0x0003, 0x0030, 384}, {INT64_C(1380575035035689000), 0x0003, 0x0031, 320}, {INT64_C(1380575035035689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035035689000), 0x0000, 0x0000, 0}, {INT64_C(1380575035055688000), 0x0003, 0x0000, 2676}, {INT64_C(1380575035055688000), 0x0003, 0x0001, 5920}, {INT64_C(1380575035055688000), 0x0003, 0x0035, 2676}, {INT64_C(1380575035055688000), 0x0003, 0x0036, 5920}, {INT64_C(1380575035055688000), 0x0003, 0x0034, 1}, {INT64_C(1380575035055688000), 0x0003, 0x0030, 256}, {INT64_C(1380575035055688000), 0x0003, 0x0031, 160}, {INT64_C(1380575035055688000), 0x0000, 0x0002, 0}, {INT64_C(1380575035055688000), 0x0003, 0x0035, 1960}, {INT64_C(1380575035055688000), 0x0003, 0x0036, 5322}, {INT64_C(1380575035055688000), 0x0003, 0x0034, 0}, {INT64_C(1380575035055688000), 0x0003, 0x0030, 480}, {INT64_C(1380575035055688000), 0x0003, 0x0031, 256}, {INT64_C(1380575035055688000), 0x0000, 0x0002, 0}, {INT64_C(1380575035055688000), 0x0003, 0x0035, 1932}, {INT64_C(1380575035055688000), 0x0003, 0x0036, 4045}, {INT64_C(1380575035055688000), 0x0003, 0x0034, 1}, {INT64_C(1380575035055688000), 0x0003, 0x0030, 384}, {INT64_C(1380575035055688000), 0x0003, 0x0031, 320}, {INT64_C(1380575035055688000), 0x0000, 0x0002, 0}, {INT64_C(1380575035055688000), 0x0003, 0x0035, 3190}, {INT64_C(1380575035055688000), 0x0003, 0x0036, 1832}, {INT64_C(1380575035055688000), 0x0003, 0x0034, 1}, {INT64_C(1380575035055688000), 0x0003, 0x0030, 384}, {INT64_C(1380575035055688000), 0x0003, 0x0031, 320}, {INT64_C(1380575035055688000), 0x0000, 0x0002, 0}, {INT64_C(1380575035055688000), 0x0000, 0x0000, 0}, {INT64_C(1380575035073692000), 0x0003, 0x0000, 2709}, {INT64_C(1380575035073692000), 0x0003, 0x0001, 5760}, {INT64_C(1380575035073692000), 0x0003, 0x0035, 2709}, {INT64_C(1380575035073692000), 0x0003, 0x0036, 5760}, {INT64_C(1380575035073692000), 0x0003, 0x0034, 1}, {INT64_C(1380575035073692000), 0x0003, 0x0030, 256}, {INT64_C(1380575035073692000), 0x0003, 0x0031, 160}, {INT64_C(1380575035073692000), 0x0000, 0x0002, 0}, {INT64_C(1380575035073692000), 0x0003, 0x0035, 2025}, {INT64_C(1380575035073692000), 0x0003, 0x0036, 5259}, {INT64_C(1380575035073692000), 0x0003, 0x0034, 0}, {INT64_C(1380575035073692000), 0x0003, 0x0030, 480}, {INT64_C(1380575035073692000), 0x0003, 0x0031, 256}, {INT64_C(1380575035073692000), 0x0000, 0x0002, 0}, {INT64_C(1380575035073692000), 0x0003, 0x0035, 2005}, {INT64_C(1380575035073692000), 0x0003, 0x0036, 4008}, {INT64_C(1380575035073692000), 0x0003, 0x0034, 0}, {INT64_C(1380575035073692000), 0x0003, 0x0030, 320}, {INT64_C(1380575035073692000), 0x0003, 0x0031, 256}, {INT64_C(1380575035073692000), 0x0000, 0x0002, 0}, {INT64_C(1380575035073692000), 0x0003, 0x0035, 3194}, {INT64_C(1380575035073692000), 0x0003, 0x0036, 1836}, {INT64_C(1380575035073692000), 0x0003, 0x0034, 1}, {INT64_C(1380575035073692000), 0x0003, 0x0030, 384}, {INT64_C(1380575035073692000), 0x0003, 0x0031, 320}, {INT64_C(1380575035073692000), 0x0000, 0x0002, 0}, {INT64_C(1380575035073692000), 0x0000, 0x0000, 0}, {INT64_C(1380575035091689000), 0x0003, 0x0000, 2091}, {INT64_C(1380575035091689000), 0x0003, 0x0001, 5173}, {INT64_C(1380575035091689000), 0x0003, 0x0035, 2091}, {INT64_C(1380575035091689000), 0x0003, 0x0036, 5173}, {INT64_C(1380575035091689000), 0x0003, 0x0034, 0}, {INT64_C(1380575035091689000), 0x0003, 0x0030, 320}, {INT64_C(1380575035091689000), 0x0003, 0x0031, 256}, {INT64_C(1380575035091689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035091689000), 0x0003, 0x0035, 2066}, {INT64_C(1380575035091689000), 0x0003, 0x0036, 3894}, {INT64_C(1380575035091689000), 0x0003, 0x0034, 1}, {INT64_C(1380575035091689000), 0x0003, 0x0030, 384}, {INT64_C(1380575035091689000), 0x0003, 0x0031, 320}, {INT64_C(1380575035091689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035091689000), 0x0003, 0x0035, 3180}, {INT64_C(1380575035091689000), 0x0003, 0x0036, 1843}, {INT64_C(1380575035091689000), 0x0003, 0x0034, 1}, {INT64_C(1380575035091689000), 0x0003, 0x0030, 384}, {INT64_C(1380575035091689000), 0x0003, 0x0031, 320}, {INT64_C(1380575035091689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035091689000), 0x0000, 0x0000, 0}, {INT64_C(1380575035111689000), 0x0003, 0x0000, 2816}, {INT64_C(1380575035111689000), 0x0003, 0x0001, 5542}, {INT64_C(1380575035111689000), 0x0003, 0x0035, 2816}, {INT64_C(1380575035111689000), 0x0003, 0x0036, 5542}, {INT64_C(1380575035111689000), 0x0003, 0x0034, 0}, {INT64_C(1380575035111689000), 0x0003, 0x0030, 320}, {INT64_C(1380575035111689000), 0x0003, 0x0031, 128}, {INT64_C(1380575035111689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035111689000), 0x0003, 0x0035, 2138}, {INT64_C(1380575035111689000), 0x0003, 0x0036, 5130}, {INT64_C(1380575035111689000), 0x0003, 0x0034, 0}, {INT64_C(1380575035111689000), 0x0003, 0x0030, 320}, {INT64_C(1380575035111689000), 0x0003, 0x0031, 256}, {INT64_C(1380575035111689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035111689000), 0x0003, 0x0035, 2116}, {INT64_C(1380575035111689000), 0x0003, 0x0036, 3849}, {INT64_C(1380575035111689000), 0x0003, 0x0034, 0}, {INT64_C(1380575035111689000), 0x0003, 0x0030, 320}, {INT64_C(1380575035111689000), 0x0003, 0x0031, 256}, {INT64_C(1380575035111689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035111689000), 0x0003, 0x0035, 3189}, {INT64_C(1380575035111689000), 0x0003, 0x0036, 1837}, {INT64_C(1380575035111689000), 0x0003, 0x0034, 1}, {INT64_C(1380575035111689000), 0x0003, 0x0030, 384}, {INT64_C(1380575035111689000), 0x0003, 0x0031, 320}, {INT64_C(1380575035111689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035111689000), 0x0000, 0x0000, 0}, {INT64_C(1380575035129691000), 0x0003, 0x0000, 2890}, {INT64_C(1380575035129691000), 0x0003, 0x0001, 5440}, {INT64_C(1380575035129691000), 0x0003, 0x0035, 2890}, {INT64_C(1380575035129691000), 0x0003, 0x0036, 5440}, {INT64_C(1380575035129691000), 0x0003, 0x0034, 1}, {INT64_C(1380575035129691000), 0x0003, 0x0030, 256}, {INT64_C(1380575035129691000), 0x0003, 0x0031, 160}, {INT64_C(1380575035129691000), 0x0000, 0x0002, 0}, {INT64_C(1380575035129691000), 0x0003, 0x0035, 2191}, {INT64_C(1380575035129691000), 0x0003, 0x0036, 5020}, {INT64_C(1380575035129691000), 0x0003, 0x0034, 1}, {INT64_C(1380575035129691000), 0x0003, 0x0030, 384}, {INT64_C(1380575035129691000), 0x0003, 0x0031, 320}, {INT64_C(1380575035129691000), 0x0000, 0x0002, 0}, {INT64_C(1380575035129691000), 0x0003, 0x0035, 2186}, {INT64_C(1380575035129691000), 0x0003, 0x0036, 3750}, {INT64_C(1380575035129691000), 0x0003, 0x0034, 1}, {INT64_C(1380575035129691000), 0x0003, 0x0030, 384}, {INT64_C(1380575035129691000), 0x0003, 0x0031, 320}, {INT64_C(1380575035129691000), 0x0000, 0x0002, 0}, {INT64_C(1380575035129691000), 0x0003, 0x0035, 3190}, {INT64_C(1380575035129691000), 0x0003, 0x0036, 1837}, {INT64_C(1380575035129691000), 0x0003, 0x0034, 1}, {INT64_C(1380575035129691000), 0x0003, 0x0030, 512}, {INT64_C(1380575035129691000), 0x0003, 0x0031, 320}, {INT64_C(1380575035129691000), 0x0000, 0x0002, 0}, {INT64_C(1380575035129691000), 0x0000, 0x0000, 0}, {INT64_C(1380575035147689000), 0x0003, 0x0000, 2944}, {INT64_C(1380575035147689000), 0x0003, 0x0001, 5361}, {INT64_C(1380575035147689000), 0x0003, 0x0035, 2944}, {INT64_C(1380575035147689000), 0x0003, 0x0036, 5361}, {INT64_C(1380575035147689000), 0x0003, 0x0034, 0}, {INT64_C(1380575035147689000), 0x0003, 0x0030, 320}, {INT64_C(1380575035147689000), 0x0003, 0x0031, 128}, {INT64_C(1380575035147689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035147689000), 0x0003, 0x0035, 2244}, {INT64_C(1380575035147689000), 0x0003, 0x0036, 4981}, {INT64_C(1380575035147689000), 0x0003, 0x0034, 0}, {INT64_C(1380575035147689000), 0x0003, 0x0030, 320}, {INT64_C(1380575035147689000), 0x0003, 0x0031, 256}, {INT64_C(1380575035147689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035147689000), 0x0003, 0x0035, 2240}, {INT64_C(1380575035147689000), 0x0003, 0x0036, 3724}, {INT64_C(1380575035147689000), 0x0003, 0x0034, 0}, {INT64_C(1380575035147689000), 0x0003, 0x0030, 320}, {INT64_C(1380575035147689000), 0x0003, 0x0031, 256}, {INT64_C(1380575035147689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035147689000), 0x0003, 0x0035, 3189}, {INT64_C(1380575035147689000), 0x0003, 0x0036, 1837}, {INT64_C(1380575035147689000), 0x0003, 0x0034, 1}, {INT64_C(1380575035147689000), 0x0003, 0x0030, 384}, {INT64_C(1380575035147689000), 0x0003, 0x0031, 320}, {INT64_C(1380575035147689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035147689000), 0x0000, 0x0000, 0}, {INT64_C(1380575035167689000), 0x0003, 0x0000, 2996}, {INT64_C(1380575035167689000), 0x0003, 0x0001, 5256}, {INT64_C(1380575035167689000), 0x0003, 0x0035, 2996}, {INT64_C(1380575035167689000), 0x0003, 0x0036, 5256}, {INT64_C(1380575035167689000), 0x0003, 0x0034, 0}, {INT64_C(1380575035167689000), 0x0003, 0x0030, 480}, {INT64_C(1380575035167689000), 0x0003, 0x0031, 384}, {INT64_C(1380575035167689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035167689000), 0x0003, 0x0035, 2306}, {INT64_C(1380575035167689000), 0x0003, 0x0036, 4882}, {INT64_C(1380575035167689000), 0x0003, 0x0034, 1}, {INT64_C(1380575035167689000), 0x0003, 0x0030, 384}, {INT64_C(1380575035167689000), 0x0003, 0x0031, 320}, {INT64_C(1380575035167689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035167689000), 0x0003, 0x0035, 2305}, {INT64_C(1380575035167689000), 0x0003, 0x0036, 3680}, {INT64_C(1380575035167689000), 0x0003, 0x0034, 1}, {INT64_C(1380575035167689000), 0x0003, 0x0030, 384}, {INT64_C(1380575035167689000), 0x0003, 0x0031, 160}, {INT64_C(1380575035167689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035167689000), 0x0003, 0x0035, 3187}, {INT64_C(1380575035167689000), 0x0003, 0x0036, 1845}, {INT64_C(1380575035167689000), 0x0003, 0x0034, 1}, {INT64_C(1380575035167689000), 0x0003, 0x0030, 384}, {INT64_C(1380575035167689000), 0x0003, 0x0031, 320}, {INT64_C(1380575035167689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035167689000), 0x0000, 0x0000, 0}, {INT64_C(1380575035185687000), 0x0003, 0x0000, 3080}, {INT64_C(1380575035185687000), 0x0003, 0x0001, 5142}, {INT64_C(1380575035185687000), 0x0003, 0x0035, 3080}, {INT64_C(1380575035185687000), 0x0003, 0x0036, 5142}, {INT64_C(1380575035185687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035185687000), 0x0003, 0x0030, 480}, {INT64_C(1380575035185687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035185687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035185687000), 0x0003, 0x0035, 2369}, {INT64_C(1380575035185687000), 0x0003, 0x0036, 4817}, {INT64_C(1380575035185687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035185687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035185687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035185687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035185687000), 0x0003, 0x0035, 2381}, {INT64_C(1380575035185687000), 0x0003, 0x0036, 3558}, {INT64_C(1380575035185687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035185687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035185687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035185687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035185687000), 0x0000, 0x0000, 0}, {INT64_C(1380575035203687000), 0x0003, 0x0000, 3160}, {INT64_C(1380575035203687000), 0x0003, 0x0001, 5010}, {INT64_C(1380575035203687000), 0x0003, 0x0035, 3160}, {INT64_C(1380575035203687000), 0x0003, 0x0036, 5010}, {INT64_C(1380575035203687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035203687000), 0x0003, 0x0030, 480}, {INT64_C(1380575035203687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035203687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035203687000), 0x0003, 0x0035, 2459}, {INT64_C(1380575035203687000), 0x0003, 0x0036, 4676}, {INT64_C(1380575035203687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035203687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035203687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035203687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035203687000), 0x0000, 0x0000, 0}, {INT64_C(1380575035223689000), 0x0003, 0x0000, 3228}, {INT64_C(1380575035223689000), 0x0003, 0x0001, 4848}, {INT64_C(1380575035223689000), 0x0003, 0x0035, 3228}, {INT64_C(1380575035223689000), 0x0003, 0x0036, 4848}, {INT64_C(1380575035223689000), 0x0003, 0x0034, 0}, {INT64_C(1380575035223689000), 0x0003, 0x0030, 640}, {INT64_C(1380575035223689000), 0x0003, 0x0031, 256}, {INT64_C(1380575035223689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035223689000), 0x0003, 0x0035, 2564}, {INT64_C(1380575035223689000), 0x0003, 0x0036, 4446}, {INT64_C(1380575035223689000), 0x0003, 0x0034, 0}, {INT64_C(1380575035223689000), 0x0003, 0x0030, 480}, {INT64_C(1380575035223689000), 0x0003, 0x0031, 384}, {INT64_C(1380575035223689000), 0x0000, 0x0002, 0}, {INT64_C(1380575035223689000), 0x0000, 0x0000, 0}, {INT64_C(1380575035241682000), 0x0003, 0x0000, 3357}, {INT64_C(1380575035241682000), 0x0003, 0x0001, 4677}, {INT64_C(1380575035241682000), 0x0003, 0x0035, 3357}, {INT64_C(1380575035241682000), 0x0003, 0x0036, 4677}, {INT64_C(1380575035241682000), 0x0003, 0x0034, 0}, {INT64_C(1380575035241682000), 0x0003, 0x0030, 320}, {INT64_C(1380575035241682000), 0x0003, 0x0031, 256}, {INT64_C(1380575035241682000), 0x0000, 0x0002, 0}, {INT64_C(1380575035241682000), 0x0000, 0x0000, 0}, {INT64_C(1380575035335683000), 0x0001, 0x014d, 0}, {INT64_C(1380575035335683000), 0x0001, 0x014a, 0}, {INT64_C(1380575035335683000), 0x0000, 0x0000, 0}, {INT64_C(1380575035659684000), 0x0003, 0x0000, 6528}, {INT64_C(1380575035659684000), 0x0003, 0x0001, 5874}, {INT64_C(1380575035659684000), 0x0003, 0x0035, 6528}, {INT64_C(1380575035659684000), 0x0003, 0x0036, 5874}, {INT64_C(1380575035659684000), 0x0003, 0x0034, 0}, {INT64_C(1380575035659684000), 0x0003, 0x0030, 320}, {INT64_C(1380575035659684000), 0x0003, 0x0031, 128}, {INT64_C(1380575035659684000), 0x0000, 0x0002, 0}, {INT64_C(1380575035659684000), 0x0001, 0x014d, 1}, {INT64_C(1380575035659684000), 0x0001, 0x014a, 1}, {INT64_C(1380575035659684000), 0x0000, 0x0000, 0}, {INT64_C(1380575035673684000), 0x0003, 0x0001, 5846}, {INT64_C(1380575035673684000), 0x0003, 0x0035, 6528}, {INT64_C(1380575035673684000), 0x0003, 0x0036, 5846}, {INT64_C(1380575035673684000), 0x0003, 0x0034, 0}, {INT64_C(1380575035673684000), 0x0003, 0x0030, 320}, {INT64_C(1380575035673684000), 0x0003, 0x0031, 128}, {INT64_C(1380575035673684000), 0x0000, 0x0002, 0}, {INT64_C(1380575035673684000), 0x0003, 0x0035, 3659}, {INT64_C(1380575035673684000), 0x0003, 0x0036, 5348}, {INT64_C(1380575035673684000), 0x0003, 0x0034, 1}, {INT64_C(1380575035673684000), 0x0003, 0x0030, 384}, {INT64_C(1380575035673684000), 0x0003, 0x0031, 320}, {INT64_C(1380575035673684000), 0x0000, 0x0002, 0}, {INT64_C(1380575035673684000), 0x0000, 0x0000, 0}, {INT64_C(1380575035679687000), 0x0003, 0x0001, 5837}, {INT64_C(1380575035679687000), 0x0003, 0x0035, 6528}, {INT64_C(1380575035679687000), 0x0003, 0x0036, 5837}, {INT64_C(1380575035679687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035679687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035679687000), 0x0003, 0x0031, 128}, {INT64_C(1380575035679687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035679687000), 0x0003, 0x0035, 3642}, {INT64_C(1380575035679687000), 0x0003, 0x0036, 5359}, {INT64_C(1380575035679687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035679687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035679687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035679687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035679687000), 0x0003, 0x0035, 3759}, {INT64_C(1380575035679687000), 0x0003, 0x0036, 1651}, {INT64_C(1380575035679687000), 0x0003, 0x0034, 1}, {INT64_C(1380575035679687000), 0x0003, 0x0030, 512}, {INT64_C(1380575035679687000), 0x0003, 0x0031, 320}, {INT64_C(1380575035679687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035679687000), 0x0000, 0x0000, 0}, {INT64_C(1380575035691685000), 0x0003, 0x0001, 5752}, {INT64_C(1380575035691685000), 0x0003, 0x0035, 6528}, {INT64_C(1380575035691685000), 0x0003, 0x0036, 5752}, {INT64_C(1380575035691685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035691685000), 0x0003, 0x0030, 480}, {INT64_C(1380575035691685000), 0x0003, 0x0031, 128}, {INT64_C(1380575035691685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035691685000), 0x0003, 0x0035, 3640}, {INT64_C(1380575035691685000), 0x0003, 0x0036, 5348}, {INT64_C(1380575035691685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035691685000), 0x0003, 0x0030, 480}, {INT64_C(1380575035691685000), 0x0003, 0x0031, 384}, {INT64_C(1380575035691685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035691685000), 0x0003, 0x0035, 3754}, {INT64_C(1380575035691685000), 0x0003, 0x0036, 1661}, {INT64_C(1380575035691685000), 0x0003, 0x0034, 1}, {INT64_C(1380575035691685000), 0x0003, 0x0030, 512}, {INT64_C(1380575035691685000), 0x0003, 0x0031, 320}, {INT64_C(1380575035691685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035691685000), 0x0000, 0x0000, 0}, {INT64_C(1380575035697686000), 0x0003, 0x0000, 4368}, {INT64_C(1380575035697686000), 0x0003, 0x0001, 6400}, {INT64_C(1380575035697686000), 0x0003, 0x0035, 4368}, {INT64_C(1380575035697686000), 0x0003, 0x0036, 6400}, {INT64_C(1380575035697686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035697686000), 0x0003, 0x0030, 256}, {INT64_C(1380575035697686000), 0x0003, 0x0031, 160}, {INT64_C(1380575035697686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035697686000), 0x0003, 0x0035, 6471}, {INT64_C(1380575035697686000), 0x0003, 0x0036, 5548}, {INT64_C(1380575035697686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035697686000), 0x0003, 0x0030, 640}, {INT64_C(1380575035697686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035697686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035697686000), 0x0003, 0x0035, 3642}, {INT64_C(1380575035697686000), 0x0003, 0x0036, 5340}, {INT64_C(1380575035697686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035697686000), 0x0003, 0x0030, 384}, {INT64_C(1380575035697686000), 0x0003, 0x0031, 320}, {INT64_C(1380575035697686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035697686000), 0x0003, 0x0035, 3763}, {INT64_C(1380575035697686000), 0x0003, 0x0036, 1652}, {INT64_C(1380575035697686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035697686000), 0x0003, 0x0030, 512}, {INT64_C(1380575035697686000), 0x0003, 0x0031, 320}, {INT64_C(1380575035697686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035697686000), 0x0000, 0x0000, 0}, {INT64_C(1380575035709683000), 0x0003, 0x0000, 4339}, {INT64_C(1380575035709683000), 0x0003, 0x0035, 4339}, {INT64_C(1380575035709683000), 0x0003, 0x0036, 6400}, {INT64_C(1380575035709683000), 0x0003, 0x0034, 1}, {INT64_C(1380575035709683000), 0x0003, 0x0030, 384}, {INT64_C(1380575035709683000), 0x0003, 0x0031, 160}, {INT64_C(1380575035709683000), 0x0000, 0x0002, 0}, {INT64_C(1380575035709683000), 0x0003, 0x0035, 5176}, {INT64_C(1380575035709683000), 0x0003, 0x0036, 6400}, {INT64_C(1380575035709683000), 0x0003, 0x0034, 1}, {INT64_C(1380575035709683000), 0x0003, 0x0030, 256}, {INT64_C(1380575035709683000), 0x0003, 0x0031, 160}, {INT64_C(1380575035709683000), 0x0000, 0x0002, 0}, {INT64_C(1380575035709683000), 0x0003, 0x0035, 3649}, {INT64_C(1380575035709683000), 0x0003, 0x0036, 5336}, {INT64_C(1380575035709683000), 0x0003, 0x0034, 1}, {INT64_C(1380575035709683000), 0x0003, 0x0030, 384}, {INT64_C(1380575035709683000), 0x0003, 0x0031, 320}, {INT64_C(1380575035709683000), 0x0000, 0x0002, 0}, {INT64_C(1380575035709683000), 0x0003, 0x0035, 6454}, {INT64_C(1380575035709683000), 0x0003, 0x0036, 5352}, {INT64_C(1380575035709683000), 0x0003, 0x0034, 0}, {INT64_C(1380575035709683000), 0x0003, 0x0030, 480}, {INT64_C(1380575035709683000), 0x0003, 0x0031, 256}, {INT64_C(1380575035709683000), 0x0000, 0x0002, 0}, {INT64_C(1380575035709683000), 0x0003, 0x0035, 3768}, {INT64_C(1380575035709683000), 0x0003, 0x0036, 1661}, {INT64_C(1380575035709683000), 0x0003, 0x0034, 1}, {INT64_C(1380575035709683000), 0x0003, 0x0030, 512}, {INT64_C(1380575035709683000), 0x0003, 0x0031, 320}, {INT64_C(1380575035709683000), 0x0000, 0x0002, 0}, {INT64_C(1380575035709683000), 0x0000, 0x0000, 0}, {INT64_C(1380575035715688000), 0x0003, 0x0000, 4323}, {INT64_C(1380575035715688000), 0x0003, 0x0001, 6354}, {INT64_C(1380575035715688000), 0x0003, 0x0035, 4323}, {INT64_C(1380575035715688000), 0x0003, 0x0036, 6354}, {INT64_C(1380575035715688000), 0x0003, 0x0034, 1}, {INT64_C(1380575035715688000), 0x0003, 0x0030, 384}, {INT64_C(1380575035715688000), 0x0003, 0x0031, 320}, {INT64_C(1380575035715688000), 0x0000, 0x0002, 0}, {INT64_C(1380575035715688000), 0x0003, 0x0035, 5186}, {INT64_C(1380575035715688000), 0x0003, 0x0036, 6349}, {INT64_C(1380575035715688000), 0x0003, 0x0034, 0}, {INT64_C(1380575035715688000), 0x0003, 0x0030, 320}, {INT64_C(1380575035715688000), 0x0003, 0x0031, 256}, {INT64_C(1380575035715688000), 0x0000, 0x0002, 0}, {INT64_C(1380575035715688000), 0x0003, 0x0035, 3641}, {INT64_C(1380575035715688000), 0x0003, 0x0036, 5308}, {INT64_C(1380575035715688000), 0x0003, 0x0034, 0}, {INT64_C(1380575035715688000), 0x0003, 0x0030, 320}, {INT64_C(1380575035715688000), 0x0003, 0x0031, 256}, {INT64_C(1380575035715688000), 0x0000, 0x0002, 0}, {INT64_C(1380575035715688000), 0x0003, 0x0035, 6430}, {INT64_C(1380575035715688000), 0x0003, 0x0036, 5194}, {INT64_C(1380575035715688000), 0x0003, 0x0034, 0}, {INT64_C(1380575035715688000), 0x0003, 0x0030, 320}, {INT64_C(1380575035715688000), 0x0003, 0x0031, 256}, {INT64_C(1380575035715688000), 0x0000, 0x0002, 0}, {INT64_C(1380575035715688000), 0x0003, 0x0035, 3779}, {INT64_C(1380575035715688000), 0x0003, 0x0036, 1660}, {INT64_C(1380575035715688000), 0x0003, 0x0034, 1}, {INT64_C(1380575035715688000), 0x0003, 0x0030, 512}, {INT64_C(1380575035715688000), 0x0003, 0x0031, 320}, {INT64_C(1380575035715688000), 0x0000, 0x0002, 0}, {INT64_C(1380575035715688000), 0x0000, 0x0000, 0}, {INT64_C(1380575035727687000), 0x0003, 0x0000, 4304}, {INT64_C(1380575035727687000), 0x0003, 0x0001, 6312}, {INT64_C(1380575035727687000), 0x0003, 0x0035, 4304}, {INT64_C(1380575035727687000), 0x0003, 0x0036, 6312}, {INT64_C(1380575035727687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035727687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035727687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035727687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035727687000), 0x0003, 0x0035, 5186}, {INT64_C(1380575035727687000), 0x0003, 0x0036, 6277}, {INT64_C(1380575035727687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035727687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035727687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035727687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035727687000), 0x0003, 0x0035, 3610}, {INT64_C(1380575035727687000), 0x0003, 0x0036, 5219}, {INT64_C(1380575035727687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035727687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035727687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035727687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035727687000), 0x0003, 0x0035, 6400}, {INT64_C(1380575035727687000), 0x0003, 0x0036, 5048}, {INT64_C(1380575035727687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035727687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035727687000), 0x0003, 0x0031, 128}, {INT64_C(1380575035727687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035727687000), 0x0003, 0x0035, 3776}, {INT64_C(1380575035727687000), 0x0003, 0x0036, 1658}, {INT64_C(1380575035727687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035727687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035727687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035727687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035727687000), 0x0000, 0x0000, 0}, {INT64_C(1380575035733686000), 0x0003, 0x0000, 4292}, {INT64_C(1380575035733686000), 0x0003, 0x0001, 6240}, {INT64_C(1380575035733686000), 0x0003, 0x0035, 4292}, {INT64_C(1380575035733686000), 0x0003, 0x0036, 6240}, {INT64_C(1380575035733686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035733686000), 0x0003, 0x0030, 256}, {INT64_C(1380575035733686000), 0x0003, 0x0031, 160}, {INT64_C(1380575035733686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035733686000), 0x0003, 0x0035, 5184}, {INT64_C(1380575035733686000), 0x0003, 0x0036, 6240}, {INT64_C(1380575035733686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035733686000), 0x0003, 0x0030, 256}, {INT64_C(1380575035733686000), 0x0003, 0x0031, 160}, {INT64_C(1380575035733686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035733686000), 0x0003, 0x0035, 3567}, {INT64_C(1380575035733686000), 0x0003, 0x0036, 5157}, {INT64_C(1380575035733686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035733686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035733686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035733686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035733686000), 0x0003, 0x0035, 6400}, {INT64_C(1380575035733686000), 0x0003, 0x0036, 4898}, {INT64_C(1380575035733686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035733686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035733686000), 0x0003, 0x0031, 128}, {INT64_C(1380575035733686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035733686000), 0x0003, 0x0035, 3789}, {INT64_C(1380575035733686000), 0x0003, 0x0036, 1600}, {INT64_C(1380575035733686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035733686000), 0x0003, 0x0030, 256}, {INT64_C(1380575035733686000), 0x0003, 0x0031, 160}, {INT64_C(1380575035733686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035733686000), 0x0000, 0x0000, 0}, {INT64_C(1380575035747687000), 0x0003, 0x0000, 4294}, {INT64_C(1380575035747687000), 0x0003, 0x0001, 6175}, {INT64_C(1380575035747687000), 0x0003, 0x0035, 4294}, {INT64_C(1380575035747687000), 0x0003, 0x0036, 6175}, {INT64_C(1380575035747687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035747687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035747687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035747687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035747687000), 0x0003, 0x0035, 5184}, {INT64_C(1380575035747687000), 0x0003, 0x0036, 6175}, {INT64_C(1380575035747687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035747687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035747687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035747687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035747687000), 0x0003, 0x0035, 3558}, {INT64_C(1380575035747687000), 0x0003, 0x0036, 5031}, {INT64_C(1380575035747687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035747687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035747687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035747687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035747687000), 0x0003, 0x0035, 6400}, {INT64_C(1380575035747687000), 0x0003, 0x0036, 4806}, {INT64_C(1380575035747687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035747687000), 0x0003, 0x0030, 480}, {INT64_C(1380575035747687000), 0x0003, 0x0031, 128}, {INT64_C(1380575035747687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035747687000), 0x0003, 0x0035, 3801}, {INT64_C(1380575035747687000), 0x0003, 0x0036, 1600}, {INT64_C(1380575035747687000), 0x0003, 0x0034, 1}, {INT64_C(1380575035747687000), 0x0003, 0x0030, 256}, {INT64_C(1380575035747687000), 0x0003, 0x0031, 160}, {INT64_C(1380575035747687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035747687000), 0x0000, 0x0000, 0}, {INT64_C(1380575035765686000), 0x0003, 0x0000, 4285}, {INT64_C(1380575035765686000), 0x0003, 0x0001, 6151}, {INT64_C(1380575035765686000), 0x0003, 0x0035, 4285}, {INT64_C(1380575035765686000), 0x0003, 0x0036, 6151}, {INT64_C(1380575035765686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035765686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035765686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035765686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035765686000), 0x0003, 0x0035, 5179}, {INT64_C(1380575035765686000), 0x0003, 0x0036, 6115}, {INT64_C(1380575035765686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035765686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035765686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035765686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035765686000), 0x0003, 0x0035, 3527}, {INT64_C(1380575035765686000), 0x0003, 0x0036, 4976}, {INT64_C(1380575035765686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035765686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035765686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035765686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035765686000), 0x0003, 0x0035, 6329}, {INT64_C(1380575035765686000), 0x0003, 0x0036, 4747}, {INT64_C(1380575035765686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035765686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035765686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035765686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035765686000), 0x0003, 0x0035, 3824}, {INT64_C(1380575035765686000), 0x0003, 0x0036, 1600}, {INT64_C(1380575035765686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035765686000), 0x0003, 0x0030, 384}, {INT64_C(1380575035765686000), 0x0003, 0x0031, 160}, {INT64_C(1380575035765686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035765686000), 0x0000, 0x0000, 0}, {INT64_C(1380575035785686000), 0x0003, 0x0000, 4290}, {INT64_C(1380575035785686000), 0x0003, 0x0001, 6054}, {INT64_C(1380575035785686000), 0x0003, 0x0035, 4290}, {INT64_C(1380575035785686000), 0x0003, 0x0036, 6054}, {INT64_C(1380575035785686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035785686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035785686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035785686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035785686000), 0x0003, 0x0035, 5173}, {INT64_C(1380575035785686000), 0x0003, 0x0036, 6033}, {INT64_C(1380575035785686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035785686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035785686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035785686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035785686000), 0x0003, 0x0035, 3512}, {INT64_C(1380575035785686000), 0x0003, 0x0036, 4947}, {INT64_C(1380575035785686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035785686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035785686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035785686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035785686000), 0x0003, 0x0035, 6290}, {INT64_C(1380575035785686000), 0x0003, 0x0036, 4683}, {INT64_C(1380575035785686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035785686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035785686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035785686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035785686000), 0x0003, 0x0035, 3875}, {INT64_C(1380575035785686000), 0x0003, 0x0036, 1760}, {INT64_C(1380575035785686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035785686000), 0x0003, 0x0030, 384}, {INT64_C(1380575035785686000), 0x0003, 0x0031, 160}, {INT64_C(1380575035785686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035785686000), 0x0000, 0x0000, 0}, {INT64_C(1380575035803686000), 0x0003, 0x0000, 4263}, {INT64_C(1380575035803686000), 0x0003, 0x0001, 6023}, {INT64_C(1380575035803686000), 0x0003, 0x0035, 4263}, {INT64_C(1380575035803686000), 0x0003, 0x0036, 6023}, {INT64_C(1380575035803686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035803686000), 0x0003, 0x0030, 384}, {INT64_C(1380575035803686000), 0x0003, 0x0031, 320}, {INT64_C(1380575035803686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035803686000), 0x0003, 0x0035, 5167}, {INT64_C(1380575035803686000), 0x0003, 0x0036, 5984}, {INT64_C(1380575035803686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035803686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035803686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035803686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035803686000), 0x0003, 0x0035, 3508}, {INT64_C(1380575035803686000), 0x0003, 0x0036, 4910}, {INT64_C(1380575035803686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035803686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035803686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035803686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035803686000), 0x0003, 0x0035, 6272}, {INT64_C(1380575035803686000), 0x0003, 0x0036, 4545}, {INT64_C(1380575035803686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035803686000), 0x0003, 0x0030, 480}, {INT64_C(1380575035803686000), 0x0003, 0x0031, 128}, {INT64_C(1380575035803686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035803686000), 0x0003, 0x0035, 3902}, {INT64_C(1380575035803686000), 0x0003, 0x0036, 1760}, {INT64_C(1380575035803686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035803686000), 0x0003, 0x0030, 512}, {INT64_C(1380575035803686000), 0x0003, 0x0031, 160}, {INT64_C(1380575035803686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035803686000), 0x0000, 0x0000, 0}, {INT64_C(1380575035821685000), 0x0003, 0x0000, 4239}, {INT64_C(1380575035821685000), 0x0003, 0x0001, 5992}, {INT64_C(1380575035821685000), 0x0003, 0x0035, 4239}, {INT64_C(1380575035821685000), 0x0003, 0x0036, 5992}, {INT64_C(1380575035821685000), 0x0003, 0x0034, 1}, {INT64_C(1380575035821685000), 0x0003, 0x0030, 384}, {INT64_C(1380575035821685000), 0x0003, 0x0031, 320}, {INT64_C(1380575035821685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035821685000), 0x0003, 0x0035, 5175}, {INT64_C(1380575035821685000), 0x0003, 0x0036, 5949}, {INT64_C(1380575035821685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035821685000), 0x0003, 0x0030, 320}, {INT64_C(1380575035821685000), 0x0003, 0x0031, 256}, {INT64_C(1380575035821685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035821685000), 0x0003, 0x0035, 3503}, {INT64_C(1380575035821685000), 0x0003, 0x0036, 4876}, {INT64_C(1380575035821685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035821685000), 0x0003, 0x0030, 320}, {INT64_C(1380575035821685000), 0x0003, 0x0031, 256}, {INT64_C(1380575035821685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035821685000), 0x0003, 0x0035, 6272}, {INT64_C(1380575035821685000), 0x0003, 0x0036, 4480}, {INT64_C(1380575035821685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035821685000), 0x0003, 0x0030, 640}, {INT64_C(1380575035821685000), 0x0003, 0x0031, 128}, {INT64_C(1380575035821685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035821685000), 0x0003, 0x0035, 3921}, {INT64_C(1380575035821685000), 0x0003, 0x0036, 1760}, {INT64_C(1380575035821685000), 0x0003, 0x0034, 1}, {INT64_C(1380575035821685000), 0x0003, 0x0030, 384}, {INT64_C(1380575035821685000), 0x0003, 0x0031, 160}, {INT64_C(1380575035821685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035821685000), 0x0000, 0x0000, 0}, {INT64_C(1380575035841686000), 0x0003, 0x0000, 4221}, {INT64_C(1380575035841686000), 0x0003, 0x0001, 5960}, {INT64_C(1380575035841686000), 0x0003, 0x0035, 4221}, {INT64_C(1380575035841686000), 0x0003, 0x0036, 5960}, {INT64_C(1380575035841686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035841686000), 0x0003, 0x0030, 384}, {INT64_C(1380575035841686000), 0x0003, 0x0031, 320}, {INT64_C(1380575035841686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035841686000), 0x0003, 0x0035, 5172}, {INT64_C(1380575035841686000), 0x0003, 0x0036, 5920}, {INT64_C(1380575035841686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035841686000), 0x0003, 0x0030, 256}, {INT64_C(1380575035841686000), 0x0003, 0x0031, 160}, {INT64_C(1380575035841686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035841686000), 0x0003, 0x0035, 3494}, {INT64_C(1380575035841686000), 0x0003, 0x0036, 4839}, {INT64_C(1380575035841686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035841686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035841686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035841686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035841686000), 0x0003, 0x0035, 6210}, {INT64_C(1380575035841686000), 0x0003, 0x0036, 4404}, {INT64_C(1380575035841686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035841686000), 0x0003, 0x0030, 480}, {INT64_C(1380575035841686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035841686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035841686000), 0x0003, 0x0035, 3955}, {INT64_C(1380575035841686000), 0x0003, 0x0036, 1847}, {INT64_C(1380575035841686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035841686000), 0x0003, 0x0030, 384}, {INT64_C(1380575035841686000), 0x0003, 0x0031, 320}, {INT64_C(1380575035841686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035841686000), 0x0000, 0x0000, 0}, {INT64_C(1380575035859686000), 0x0003, 0x0000, 4200}, {INT64_C(1380575035859686000), 0x0003, 0x0001, 5878}, {INT64_C(1380575035859686000), 0x0003, 0x0035, 4200}, {INT64_C(1380575035859686000), 0x0003, 0x0036, 5878}, {INT64_C(1380575035859686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035859686000), 0x0003, 0x0030, 512}, {INT64_C(1380575035859686000), 0x0003, 0x0031, 320}, {INT64_C(1380575035859686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035859686000), 0x0003, 0x0035, 5161}, {INT64_C(1380575035859686000), 0x0003, 0x0036, 5839}, {INT64_C(1380575035859686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035859686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035859686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035859686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035859686000), 0x0003, 0x0035, 3500}, {INT64_C(1380575035859686000), 0x0003, 0x0036, 4797}, {INT64_C(1380575035859686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035859686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035859686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035859686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035859686000), 0x0003, 0x0035, 6152}, {INT64_C(1380575035859686000), 0x0003, 0x0036, 4357}, {INT64_C(1380575035859686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035859686000), 0x0003, 0x0030, 640}, {INT64_C(1380575035859686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035859686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035859686000), 0x0003, 0x0035, 4006}, {INT64_C(1380575035859686000), 0x0003, 0x0036, 1889}, {INT64_C(1380575035859686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035859686000), 0x0003, 0x0030, 512}, {INT64_C(1380575035859686000), 0x0003, 0x0031, 320}, {INT64_C(1380575035859686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035859686000), 0x0000, 0x0000, 0}, {INT64_C(1380575035877685000), 0x0003, 0x0000, 4174}, {INT64_C(1380575035877685000), 0x0003, 0x0001, 5842}, {INT64_C(1380575035877685000), 0x0003, 0x0035, 4174}, {INT64_C(1380575035877685000), 0x0003, 0x0036, 5842}, {INT64_C(1380575035877685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035877685000), 0x0003, 0x0030, 320}, {INT64_C(1380575035877685000), 0x0003, 0x0031, 256}, {INT64_C(1380575035877685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035877685000), 0x0003, 0x0035, 5149}, {INT64_C(1380575035877685000), 0x0003, 0x0036, 5739}, {INT64_C(1380575035877685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035877685000), 0x0003, 0x0030, 480}, {INT64_C(1380575035877685000), 0x0003, 0x0031, 256}, {INT64_C(1380575035877685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035877685000), 0x0003, 0x0035, 3485}, {INT64_C(1380575035877685000), 0x0003, 0x0036, 4762}, {INT64_C(1380575035877685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035877685000), 0x0003, 0x0030, 320}, {INT64_C(1380575035877685000), 0x0003, 0x0031, 256}, {INT64_C(1380575035877685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035877685000), 0x0003, 0x0035, 4152}, {INT64_C(1380575035877685000), 0x0003, 0x0036, 4230}, {INT64_C(1380575035877685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035877685000), 0x0003, 0x0030, 320}, {INT64_C(1380575035877685000), 0x0003, 0x0031, 256}, {INT64_C(1380575035877685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035877685000), 0x0003, 0x0035, 6144}, {INT64_C(1380575035877685000), 0x0003, 0x0036, 4218}, {INT64_C(1380575035877685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035877685000), 0x0003, 0x0030, 480}, {INT64_C(1380575035877685000), 0x0003, 0x0031, 128}, {INT64_C(1380575035877685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035877685000), 0x0003, 0x0035, 4067}, {INT64_C(1380575035877685000), 0x0003, 0x0036, 1920}, {INT64_C(1380575035877685000), 0x0003, 0x0034, 1}, {INT64_C(1380575035877685000), 0x0003, 0x0030, 384}, {INT64_C(1380575035877685000), 0x0003, 0x0031, 160}, {INT64_C(1380575035877685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035877685000), 0x0000, 0x0000, 0}, {INT64_C(1380575035897685000), 0x0003, 0x0000, 4161}, {INT64_C(1380575035897685000), 0x0003, 0x0001, 5725}, {INT64_C(1380575035897685000), 0x0003, 0x0035, 4161}, {INT64_C(1380575035897685000), 0x0003, 0x0036, 5725}, {INT64_C(1380575035897685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035897685000), 0x0003, 0x0030, 480}, {INT64_C(1380575035897685000), 0x0003, 0x0031, 384}, {INT64_C(1380575035897685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035897685000), 0x0003, 0x0035, 5120}, {INT64_C(1380575035897685000), 0x0003, 0x0036, 5655}, {INT64_C(1380575035897685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035897685000), 0x0003, 0x0030, 320}, {INT64_C(1380575035897685000), 0x0003, 0x0031, 128}, {INT64_C(1380575035897685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035897685000), 0x0003, 0x0035, 3465}, {INT64_C(1380575035897685000), 0x0003, 0x0036, 4669}, {INT64_C(1380575035897685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035897685000), 0x0003, 0x0030, 480}, {INT64_C(1380575035897685000), 0x0003, 0x0031, 384}, {INT64_C(1380575035897685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035897685000), 0x0003, 0x0035, 6066}, {INT64_C(1380575035897685000), 0x0003, 0x0036, 4142}, {INT64_C(1380575035897685000), 0x0003, 0x0034, 0}, {INT64_C(1380575035897685000), 0x0003, 0x0030, 480}, {INT64_C(1380575035897685000), 0x0003, 0x0031, 256}, {INT64_C(1380575035897685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035897685000), 0x0003, 0x0035, 4110}, {INT64_C(1380575035897685000), 0x0003, 0x0036, 1920}, {INT64_C(1380575035897685000), 0x0003, 0x0034, 1}, {INT64_C(1380575035897685000), 0x0003, 0x0030, 384}, {INT64_C(1380575035897685000), 0x0003, 0x0031, 160}, {INT64_C(1380575035897685000), 0x0000, 0x0002, 0}, {INT64_C(1380575035897685000), 0x0000, 0x0000, 0}, {INT64_C(1380575035915686000), 0x0003, 0x0000, 4130}, {INT64_C(1380575035915686000), 0x0003, 0x0001, 5646}, {INT64_C(1380575035915686000), 0x0003, 0x0035, 4130}, {INT64_C(1380575035915686000), 0x0003, 0x0036, 5646}, {INT64_C(1380575035915686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035915686000), 0x0003, 0x0030, 480}, {INT64_C(1380575035915686000), 0x0003, 0x0031, 384}, {INT64_C(1380575035915686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035915686000), 0x0003, 0x0035, 5080}, {INT64_C(1380575035915686000), 0x0003, 0x0036, 5530}, {INT64_C(1380575035915686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035915686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035915686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035915686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035915686000), 0x0003, 0x0035, 3455}, {INT64_C(1380575035915686000), 0x0003, 0x0036, 4588}, {INT64_C(1380575035915686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035915686000), 0x0003, 0x0030, 384}, {INT64_C(1380575035915686000), 0x0003, 0x0031, 320}, {INT64_C(1380575035915686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035915686000), 0x0003, 0x0035, 6016}, {INT64_C(1380575035915686000), 0x0003, 0x0036, 4070}, {INT64_C(1380575035915686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035915686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035915686000), 0x0003, 0x0031, 128}, {INT64_C(1380575035915686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035915686000), 0x0003, 0x0035, 4122}, {INT64_C(1380575035915686000), 0x0003, 0x0036, 2048}, {INT64_C(1380575035915686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035915686000), 0x0003, 0x0030, 384}, {INT64_C(1380575035915686000), 0x0003, 0x0031, 320}, {INT64_C(1380575035915686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035915686000), 0x0000, 0x0000, 0}, {INT64_C(1380575035933684000), 0x0003, 0x0000, 4068}, {INT64_C(1380575035933684000), 0x0003, 0x0001, 5519}, {INT64_C(1380575035933684000), 0x0003, 0x0035, 4068}, {INT64_C(1380575035933684000), 0x0003, 0x0036, 5519}, {INT64_C(1380575035933684000), 0x0003, 0x0034, 0}, {INT64_C(1380575035933684000), 0x0003, 0x0030, 640}, {INT64_C(1380575035933684000), 0x0003, 0x0031, 256}, {INT64_C(1380575035933684000), 0x0000, 0x0002, 0}, {INT64_C(1380575035933684000), 0x0003, 0x0035, 5080}, {INT64_C(1380575035933684000), 0x0003, 0x0036, 5383}, {INT64_C(1380575035933684000), 0x0003, 0x0034, 0}, {INT64_C(1380575035933684000), 0x0003, 0x0030, 480}, {INT64_C(1380575035933684000), 0x0003, 0x0031, 256}, {INT64_C(1380575035933684000), 0x0000, 0x0002, 0}, {INT64_C(1380575035933684000), 0x0003, 0x0035, 3456}, {INT64_C(1380575035933684000), 0x0003, 0x0036, 4450}, {INT64_C(1380575035933684000), 0x0003, 0x0034, 0}, {INT64_C(1380575035933684000), 0x0003, 0x0030, 320}, {INT64_C(1380575035933684000), 0x0003, 0x0031, 128}, {INT64_C(1380575035933684000), 0x0000, 0x0002, 0}, {INT64_C(1380575035933684000), 0x0003, 0x0035, 4149}, {INT64_C(1380575035933684000), 0x0003, 0x0036, 2080}, {INT64_C(1380575035933684000), 0x0003, 0x0034, 1}, {INT64_C(1380575035933684000), 0x0003, 0x0030, 256}, {INT64_C(1380575035933684000), 0x0003, 0x0031, 160}, {INT64_C(1380575035933684000), 0x0000, 0x0002, 0}, {INT64_C(1380575035933684000), 0x0000, 0x0000, 0}, {INT64_C(1380575035953686000), 0x0003, 0x0000, 4063}, {INT64_C(1380575035953686000), 0x0003, 0x0001, 5398}, {INT64_C(1380575035953686000), 0x0003, 0x0035, 4063}, {INT64_C(1380575035953686000), 0x0003, 0x0036, 5398}, {INT64_C(1380575035953686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035953686000), 0x0003, 0x0030, 480}, {INT64_C(1380575035953686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035953686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035953686000), 0x0003, 0x0035, 5059}, {INT64_C(1380575035953686000), 0x0003, 0x0036, 5328}, {INT64_C(1380575035953686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035953686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035953686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035953686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035953686000), 0x0003, 0x0035, 3432}, {INT64_C(1380575035953686000), 0x0003, 0x0036, 4345}, {INT64_C(1380575035953686000), 0x0003, 0x0034, 0}, {INT64_C(1380575035953686000), 0x0003, 0x0030, 320}, {INT64_C(1380575035953686000), 0x0003, 0x0031, 256}, {INT64_C(1380575035953686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035953686000), 0x0003, 0x0035, 4172}, {INT64_C(1380575035953686000), 0x0003, 0x0036, 2080}, {INT64_C(1380575035953686000), 0x0003, 0x0034, 1}, {INT64_C(1380575035953686000), 0x0003, 0x0030, 256}, {INT64_C(1380575035953686000), 0x0003, 0x0031, 160}, {INT64_C(1380575035953686000), 0x0000, 0x0002, 0}, {INT64_C(1380575035953686000), 0x0000, 0x0000, 0}, {INT64_C(1380575035971687000), 0x0003, 0x0000, 4044}, {INT64_C(1380575035971687000), 0x0003, 0x0001, 5267}, {INT64_C(1380575035971687000), 0x0003, 0x0035, 4044}, {INT64_C(1380575035971687000), 0x0003, 0x0036, 5267}, {INT64_C(1380575035971687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035971687000), 0x0003, 0x0030, 480}, {INT64_C(1380575035971687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035971687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035971687000), 0x0003, 0x0035, 5042}, {INT64_C(1380575035971687000), 0x0003, 0x0036, 5164}, {INT64_C(1380575035971687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035971687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035971687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035971687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035971687000), 0x0003, 0x0035, 3402}, {INT64_C(1380575035971687000), 0x0003, 0x0036, 4174}, {INT64_C(1380575035971687000), 0x0003, 0x0034, 0}, {INT64_C(1380575035971687000), 0x0003, 0x0030, 320}, {INT64_C(1380575035971687000), 0x0003, 0x0031, 256}, {INT64_C(1380575035971687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035971687000), 0x0003, 0x0035, 4209}, {INT64_C(1380575035971687000), 0x0003, 0x0036, 2080}, {INT64_C(1380575035971687000), 0x0003, 0x0034, 1}, {INT64_C(1380575035971687000), 0x0003, 0x0030, 256}, {INT64_C(1380575035971687000), 0x0003, 0x0031, 160}, {INT64_C(1380575035971687000), 0x0000, 0x0002, 0}, {INT64_C(1380575035971687000), 0x0000, 0x0000, 0}, {INT64_C(1380575035989681000), 0x0003, 0x0000, 4020}, {INT64_C(1380575035989681000), 0x0003, 0x0001, 5097}, {INT64_C(1380575035989681000), 0x0003, 0x0035, 4020}, {INT64_C(1380575035989681000), 0x0003, 0x0036, 5097}, {INT64_C(1380575035989681000), 0x0003, 0x0034, 0}, {INT64_C(1380575035989681000), 0x0003, 0x0030, 640}, {INT64_C(1380575035989681000), 0x0003, 0x0031, 384}, {INT64_C(1380575035989681000), 0x0000, 0x0002, 0}, {INT64_C(1380575035989681000), 0x0003, 0x0035, 5015}, {INT64_C(1380575035989681000), 0x0003, 0x0036, 4901}, {INT64_C(1380575035989681000), 0x0003, 0x0034, 0}, {INT64_C(1380575035989681000), 0x0003, 0x0030, 640}, {INT64_C(1380575035989681000), 0x0003, 0x0031, 256}, {INT64_C(1380575035989681000), 0x0000, 0x0002, 0}, {INT64_C(1380575035989681000), 0x0000, 0x0000, 0}, {INT64_C(1380575036009685000), 0x0003, 0x0000, 3961}, {INT64_C(1380575036009685000), 0x0003, 0x0001, 4913}, {INT64_C(1380575036009685000), 0x0003, 0x0035, 3961}, {INT64_C(1380575036009685000), 0x0003, 0x0036, 4913}, {INT64_C(1380575036009685000), 0x0003, 0x0034, 0}, {INT64_C(1380575036009685000), 0x0003, 0x0030, 640}, {INT64_C(1380575036009685000), 0x0003, 0x0031, 384}, {INT64_C(1380575036009685000), 0x0000, 0x0002, 0}, {INT64_C(1380575036009685000), 0x0003, 0x0035, 4947}, {INT64_C(1380575036009685000), 0x0003, 0x0036, 4742}, {INT64_C(1380575036009685000), 0x0003, 0x0034, 0}, {INT64_C(1380575036009685000), 0x0003, 0x0030, 320}, {INT64_C(1380575036009685000), 0x0003, 0x0031, 256}, {INT64_C(1380575036009685000), 0x0000, 0x0002, 0}, {INT64_C(1380575036009685000), 0x0000, 0x0000, 0}, {INT64_C(1380575036027682000), 0x0003, 0x0000, 3882}, {INT64_C(1380575036027682000), 0x0003, 0x0001, 4672}, {INT64_C(1380575036027682000), 0x0003, 0x0035, 3882}, {INT64_C(1380575036027682000), 0x0003, 0x0036, 4672}, {INT64_C(1380575036027682000), 0x0003, 0x0034, 0}, {INT64_C(1380575036027682000), 0x0003, 0x0030, 320}, {INT64_C(1380575036027682000), 0x0003, 0x0031, 256}, {INT64_C(1380575036027682000), 0x0000, 0x0002, 0}, {INT64_C(1380575036027682000), 0x0003, 0x0035, 4899}, {INT64_C(1380575036027682000), 0x0003, 0x0036, 4577}, {INT64_C(1380575036027682000), 0x0003, 0x0034, 0}, {INT64_C(1380575036027682000), 0x0003, 0x0030, 480}, {INT64_C(1380575036027682000), 0x0003, 0x0031, 256}, {INT64_C(1380575036027682000), 0x0000, 0x0002, 0}, {INT64_C(1380575036027682000), 0x0000, 0x0000, 0}, {INT64_C(1380575036045681000), 0x0003, 0x0000, 4833}, {INT64_C(1380575036045681000), 0x0003, 0x0001, 4427}, {INT64_C(1380575036045681000), 0x0003, 0x0035, 4833}, {INT64_C(1380575036045681000), 0x0003, 0x0036, 4427}, {INT64_C(1380575036045681000), 0x0003, 0x0034, 0}, {INT64_C(1380575036045681000), 0x0003, 0x0030, 480}, {INT64_C(1380575036045681000), 0x0003, 0x0031, 256}, {INT64_C(1380575036045681000), 0x0000, 0x0002, 0}, {INT64_C(1380575036045681000), 0x0000, 0x0000, 0}, {INT64_C(1380575036065680000), 0x0003, 0x0000, 4630}, {INT64_C(1380575036065680000), 0x0003, 0x0001, 4180}, {INT64_C(1380575036065680000), 0x0003, 0x0035, 4630}, {INT64_C(1380575036065680000), 0x0003, 0x0036, 4180}, {INT64_C(1380575036065680000), 0x0003, 0x0034, 0}, {INT64_C(1380575036065680000), 0x0003, 0x0030, 320}, {INT64_C(1380575036065680000), 0x0003, 0x0031, 256}, {INT64_C(1380575036065680000), 0x0000, 0x0002, 0}, {INT64_C(1380575036065680000), 0x0000, 0x0000, 0}, {INT64_C(1380575036157678000), 0x0001, 0x014d, 0}, {INT64_C(1380575036157678000), 0x0001, 0x014a, 0}, {INT64_C(1380575036157678000), 0x0000, 0x0000, 0}, {INT64_C(1380575036533677000), 0x0003, 0x0035, 952}, {INT64_C(1380575036533677000), 0x0003, 0x0036, 3520}, {INT64_C(1380575036533677000), 0x0003, 0x0034, 1}, {INT64_C(1380575036533677000), 0x0003, 0x0030, 256}, {INT64_C(1380575036533677000), 0x0003, 0x0031, 160}, {INT64_C(1380575036533677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036533677000), 0x0000, 0x0000, 0}, {INT64_C(1380575036539679000), 0x0003, 0x0000, 1080}, {INT64_C(1380575036539679000), 0x0003, 0x0001, 4927}, {INT64_C(1380575036539679000), 0x0003, 0x0035, 1080}, {INT64_C(1380575036539679000), 0x0003, 0x0036, 4927}, {INT64_C(1380575036539679000), 0x0003, 0x0034, 0}, {INT64_C(1380575036539679000), 0x0003, 0x0030, 480}, {INT64_C(1380575036539679000), 0x0003, 0x0031, 256}, {INT64_C(1380575036539679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036539679000), 0x0003, 0x0035, 973}, {INT64_C(1380575036539679000), 0x0003, 0x0036, 3520}, {INT64_C(1380575036539679000), 0x0003, 0x0034, 1}, {INT64_C(1380575036539679000), 0x0003, 0x0030, 256}, {INT64_C(1380575036539679000), 0x0003, 0x0031, 160}, {INT64_C(1380575036539679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036539679000), 0x0001, 0x014d, 1}, {INT64_C(1380575036539679000), 0x0001, 0x014a, 1}, {INT64_C(1380575036539679000), 0x0000, 0x0000, 0}, {INT64_C(1380575036551678000), 0x0003, 0x0000, 1103}, {INT64_C(1380575036551678000), 0x0003, 0x0001, 4910}, {INT64_C(1380575036551678000), 0x0003, 0x0035, 1103}, {INT64_C(1380575036551678000), 0x0003, 0x0036, 4910}, {INT64_C(1380575036551678000), 0x0003, 0x0034, 0}, {INT64_C(1380575036551678000), 0x0003, 0x0030, 640}, {INT64_C(1380575036551678000), 0x0003, 0x0031, 384}, {INT64_C(1380575036551678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036551678000), 0x0003, 0x0035, 1045}, {INT64_C(1380575036551678000), 0x0003, 0x0036, 3520}, {INT64_C(1380575036551678000), 0x0003, 0x0034, 1}, {INT64_C(1380575036551678000), 0x0003, 0x0030, 384}, {INT64_C(1380575036551678000), 0x0003, 0x0031, 160}, {INT64_C(1380575036551678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036551678000), 0x0000, 0x0000, 0}, {INT64_C(1380575036557678000), 0x0003, 0x0000, 1193}, {INT64_C(1380575036557678000), 0x0003, 0x0001, 4862}, {INT64_C(1380575036557678000), 0x0003, 0x0035, 1193}, {INT64_C(1380575036557678000), 0x0003, 0x0036, 4862}, {INT64_C(1380575036557678000), 0x0003, 0x0034, 0}, {INT64_C(1380575036557678000), 0x0003, 0x0030, 480}, {INT64_C(1380575036557678000), 0x0003, 0x0031, 384}, {INT64_C(1380575036557678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036557678000), 0x0003, 0x0035, 1121}, {INT64_C(1380575036557678000), 0x0003, 0x0036, 3401}, {INT64_C(1380575036557678000), 0x0003, 0x0034, 1}, {INT64_C(1380575036557678000), 0x0003, 0x0030, 384}, {INT64_C(1380575036557678000), 0x0003, 0x0031, 320}, {INT64_C(1380575036557678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036557678000), 0x0000, 0x0000, 0}, {INT64_C(1380575036571678000), 0x0003, 0x0000, 1247}, {INT64_C(1380575036571678000), 0x0003, 0x0001, 4815}, {INT64_C(1380575036571678000), 0x0003, 0x0035, 1247}, {INT64_C(1380575036571678000), 0x0003, 0x0036, 4815}, {INT64_C(1380575036571678000), 0x0003, 0x0034, 0}, {INT64_C(1380575036571678000), 0x0003, 0x0030, 640}, {INT64_C(1380575036571678000), 0x0003, 0x0031, 256}, {INT64_C(1380575036571678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036571678000), 0x0003, 0x0035, 1221}, {INT64_C(1380575036571678000), 0x0003, 0x0036, 3363}, {INT64_C(1380575036571678000), 0x0003, 0x0034, 0}, {INT64_C(1380575036571678000), 0x0003, 0x0030, 320}, {INT64_C(1380575036571678000), 0x0003, 0x0031, 256}, {INT64_C(1380575036571678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036571678000), 0x0000, 0x0000, 0}, {INT64_C(1380575036577674000), 0x0003, 0x0000, 1984}, {INT64_C(1380575036577674000), 0x0003, 0x0001, 5275}, {INT64_C(1380575036577674000), 0x0003, 0x0035, 1984}, {INT64_C(1380575036577674000), 0x0003, 0x0036, 5275}, {INT64_C(1380575036577674000), 0x0003, 0x0034, 0}, {INT64_C(1380575036577674000), 0x0003, 0x0030, 320}, {INT64_C(1380575036577674000), 0x0003, 0x0031, 256}, {INT64_C(1380575036577674000), 0x0000, 0x0002, 0}, {INT64_C(1380575036577674000), 0x0003, 0x0035, 1358}, {INT64_C(1380575036577674000), 0x0003, 0x0036, 4718}, {INT64_C(1380575036577674000), 0x0003, 0x0034, 0}, {INT64_C(1380575036577674000), 0x0003, 0x0030, 640}, {INT64_C(1380575036577674000), 0x0003, 0x0031, 256}, {INT64_C(1380575036577674000), 0x0000, 0x0002, 0}, {INT64_C(1380575036577674000), 0x0003, 0x0035, 1333}, {INT64_C(1380575036577674000), 0x0003, 0x0036, 3360}, {INT64_C(1380575036577674000), 0x0003, 0x0034, 1}, {INT64_C(1380575036577674000), 0x0003, 0x0030, 256}, {INT64_C(1380575036577674000), 0x0003, 0x0031, 160}, {INT64_C(1380575036577674000), 0x0000, 0x0002, 0}, {INT64_C(1380575036577674000), 0x0000, 0x0000, 0}, {INT64_C(1380575036589676000), 0x0003, 0x0000, 2048}, {INT64_C(1380575036589676000), 0x0003, 0x0001, 5240}, {INT64_C(1380575036589676000), 0x0003, 0x0035, 2048}, {INT64_C(1380575036589676000), 0x0003, 0x0036, 5240}, {INT64_C(1380575036589676000), 0x0003, 0x0034, 0}, {INT64_C(1380575036589676000), 0x0003, 0x0030, 320}, {INT64_C(1380575036589676000), 0x0003, 0x0031, 128}, {INT64_C(1380575036589676000), 0x0000, 0x0002, 0}, {INT64_C(1380575036589676000), 0x0003, 0x0035, 1466}, {INT64_C(1380575036589676000), 0x0003, 0x0036, 4659}, {INT64_C(1380575036589676000), 0x0003, 0x0034, 0}, {INT64_C(1380575036589676000), 0x0003, 0x0030, 640}, {INT64_C(1380575036589676000), 0x0003, 0x0031, 384}, {INT64_C(1380575036589676000), 0x0000, 0x0002, 0}, {INT64_C(1380575036589676000), 0x0003, 0x0035, 1417}, {INT64_C(1380575036589676000), 0x0003, 0x0036, 3200}, {INT64_C(1380575036589676000), 0x0003, 0x0034, 1}, {INT64_C(1380575036589676000), 0x0003, 0x0030, 384}, {INT64_C(1380575036589676000), 0x0003, 0x0031, 160}, {INT64_C(1380575036589676000), 0x0000, 0x0002, 0}, {INT64_C(1380575036589676000), 0x0000, 0x0000, 0}, {INT64_C(1380575036595680000), 0x0003, 0x0000, 2170}, {INT64_C(1380575036595680000), 0x0003, 0x0001, 5172}, {INT64_C(1380575036595680000), 0x0003, 0x0035, 2170}, {INT64_C(1380575036595680000), 0x0003, 0x0036, 5172}, {INT64_C(1380575036595680000), 0x0003, 0x0034, 0}, {INT64_C(1380575036595680000), 0x0003, 0x0030, 480}, {INT64_C(1380575036595680000), 0x0003, 0x0031, 256}, {INT64_C(1380575036595680000), 0x0000, 0x0002, 0}, {INT64_C(1380575036595680000), 0x0003, 0x0035, 1593}, {INT64_C(1380575036595680000), 0x0003, 0x0036, 4599}, {INT64_C(1380575036595680000), 0x0003, 0x0034, 0}, {INT64_C(1380575036595680000), 0x0003, 0x0030, 800}, {INT64_C(1380575036595680000), 0x0003, 0x0031, 256}, {INT64_C(1380575036595680000), 0x0000, 0x0002, 0}, {INT64_C(1380575036595680000), 0x0003, 0x0035, 1559}, {INT64_C(1380575036595680000), 0x0003, 0x0036, 3200}, {INT64_C(1380575036595680000), 0x0003, 0x0034, 1}, {INT64_C(1380575036595680000), 0x0003, 0x0030, 384}, {INT64_C(1380575036595680000), 0x0003, 0x0031, 160}, {INT64_C(1380575036595680000), 0x0000, 0x0002, 0}, {INT64_C(1380575036595680000), 0x0000, 0x0000, 0}, {INT64_C(1380575036607679000), 0x0003, 0x0000, 2269}, {INT64_C(1380575036607679000), 0x0003, 0x0001, 5126}, {INT64_C(1380575036607679000), 0x0003, 0x0035, 2269}, {INT64_C(1380575036607679000), 0x0003, 0x0036, 5126}, {INT64_C(1380575036607679000), 0x0003, 0x0034, 0}, {INT64_C(1380575036607679000), 0x0003, 0x0030, 320}, {INT64_C(1380575036607679000), 0x0003, 0x0031, 256}, {INT64_C(1380575036607679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036607679000), 0x0003, 0x0035, 1722}, {INT64_C(1380575036607679000), 0x0003, 0x0036, 4535}, {INT64_C(1380575036607679000), 0x0003, 0x0034, 0}, {INT64_C(1380575036607679000), 0x0003, 0x0030, 640}, {INT64_C(1380575036607679000), 0x0003, 0x0031, 256}, {INT64_C(1380575036607679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036607679000), 0x0003, 0x0035, 1685}, {INT64_C(1380575036607679000), 0x0003, 0x0036, 3123}, {INT64_C(1380575036607679000), 0x0003, 0x0034, 1}, {INT64_C(1380575036607679000), 0x0003, 0x0030, 384}, {INT64_C(1380575036607679000), 0x0003, 0x0031, 320}, {INT64_C(1380575036607679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036607679000), 0x0000, 0x0000, 0}, {INT64_C(1380575036613679000), 0x0003, 0x0000, 2418}, {INT64_C(1380575036613679000), 0x0003, 0x0001, 5026}, {INT64_C(1380575036613679000), 0x0003, 0x0035, 2418}, {INT64_C(1380575036613679000), 0x0003, 0x0036, 5026}, {INT64_C(1380575036613679000), 0x0003, 0x0034, 0}, {INT64_C(1380575036613679000), 0x0003, 0x0030, 320}, {INT64_C(1380575036613679000), 0x0003, 0x0031, 256}, {INT64_C(1380575036613679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036613679000), 0x0003, 0x0035, 1848}, {INT64_C(1380575036613679000), 0x0003, 0x0036, 4494}, {INT64_C(1380575036613679000), 0x0003, 0x0034, 0}, {INT64_C(1380575036613679000), 0x0003, 0x0030, 800}, {INT64_C(1380575036613679000), 0x0003, 0x0031, 256}, {INT64_C(1380575036613679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036613679000), 0x0003, 0x0035, 1844}, {INT64_C(1380575036613679000), 0x0003, 0x0036, 3106}, {INT64_C(1380575036613679000), 0x0003, 0x0034, 0}, {INT64_C(1380575036613679000), 0x0003, 0x0030, 320}, {INT64_C(1380575036613679000), 0x0003, 0x0031, 256}, {INT64_C(1380575036613679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036613679000), 0x0000, 0x0000, 0}, {INT64_C(1380575036627676000), 0x0003, 0x0000, 2574}, {INT64_C(1380575036627676000), 0x0003, 0x0001, 4994}, {INT64_C(1380575036627676000), 0x0003, 0x0035, 2574}, {INT64_C(1380575036627676000), 0x0003, 0x0036, 4994}, {INT64_C(1380575036627676000), 0x0003, 0x0034, 0}, {INT64_C(1380575036627676000), 0x0003, 0x0030, 320}, {INT64_C(1380575036627676000), 0x0003, 0x0031, 256}, {INT64_C(1380575036627676000), 0x0000, 0x0002, 0}, {INT64_C(1380575036627676000), 0x0003, 0x0035, 2003}, {INT64_C(1380575036627676000), 0x0003, 0x0036, 4454}, {INT64_C(1380575036627676000), 0x0003, 0x0034, 0}, {INT64_C(1380575036627676000), 0x0003, 0x0030, 640}, {INT64_C(1380575036627676000), 0x0003, 0x0031, 256}, {INT64_C(1380575036627676000), 0x0000, 0x0002, 0}, {INT64_C(1380575036627676000), 0x0003, 0x0035, 1992}, {INT64_C(1380575036627676000), 0x0003, 0x0036, 3101}, {INT64_C(1380575036627676000), 0x0003, 0x0034, 0}, {INT64_C(1380575036627676000), 0x0003, 0x0030, 320}, {INT64_C(1380575036627676000), 0x0003, 0x0031, 256}, {INT64_C(1380575036627676000), 0x0000, 0x0002, 0}, {INT64_C(1380575036627676000), 0x0000, 0x0000, 0}, {INT64_C(1380575036645678000), 0x0003, 0x0000, 2722}, {INT64_C(1380575036645678000), 0x0003, 0x0001, 4901}, {INT64_C(1380575036645678000), 0x0003, 0x0035, 2722}, {INT64_C(1380575036645678000), 0x0003, 0x0036, 4901}, {INT64_C(1380575036645678000), 0x0003, 0x0034, 0}, {INT64_C(1380575036645678000), 0x0003, 0x0030, 320}, {INT64_C(1380575036645678000), 0x0003, 0x0031, 256}, {INT64_C(1380575036645678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036645678000), 0x0003, 0x0035, 2147}, {INT64_C(1380575036645678000), 0x0003, 0x0036, 4438}, {INT64_C(1380575036645678000), 0x0003, 0x0034, 0}, {INT64_C(1380575036645678000), 0x0003, 0x0030, 640}, {INT64_C(1380575036645678000), 0x0003, 0x0031, 256}, {INT64_C(1380575036645678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036645678000), 0x0003, 0x0035, 2135}, {INT64_C(1380575036645678000), 0x0003, 0x0036, 3040}, {INT64_C(1380575036645678000), 0x0003, 0x0034, 1}, {INT64_C(1380575036645678000), 0x0003, 0x0030, 256}, {INT64_C(1380575036645678000), 0x0003, 0x0031, 160}, {INT64_C(1380575036645678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036645678000), 0x0000, 0x0000, 0}, {INT64_C(1380575036663674000), 0x0003, 0x0000, 2901}, {INT64_C(1380575036663674000), 0x0003, 0x0035, 2901}, {INT64_C(1380575036663674000), 0x0003, 0x0036, 4901}, {INT64_C(1380575036663674000), 0x0003, 0x0034, 0}, {INT64_C(1380575036663674000), 0x0003, 0x0030, 320}, {INT64_C(1380575036663674000), 0x0003, 0x0031, 256}, {INT64_C(1380575036663674000), 0x0000, 0x0002, 0}, {INT64_C(1380575036663674000), 0x0003, 0x0035, 2359}, {INT64_C(1380575036663674000), 0x0003, 0x0036, 4389}, {INT64_C(1380575036663674000), 0x0003, 0x0034, 0}, {INT64_C(1380575036663674000), 0x0003, 0x0030, 640}, {INT64_C(1380575036663674000), 0x0003, 0x0031, 384}, {INT64_C(1380575036663674000), 0x0000, 0x0002, 0}, {INT64_C(1380575036663674000), 0x0003, 0x0035, 2334}, {INT64_C(1380575036663674000), 0x0003, 0x0036, 3040}, {INT64_C(1380575036663674000), 0x0003, 0x0034, 1}, {INT64_C(1380575036663674000), 0x0003, 0x0030, 384}, {INT64_C(1380575036663674000), 0x0003, 0x0031, 160}, {INT64_C(1380575036663674000), 0x0000, 0x0002, 0}, {INT64_C(1380575036663674000), 0x0000, 0x0000, 0}, {INT64_C(1380575036683678000), 0x0003, 0x0000, 3055}, {INT64_C(1380575036683678000), 0x0003, 0x0001, 4870}, {INT64_C(1380575036683678000), 0x0003, 0x0035, 3055}, {INT64_C(1380575036683678000), 0x0003, 0x0036, 4870}, {INT64_C(1380575036683678000), 0x0003, 0x0034, 0}, {INT64_C(1380575036683678000), 0x0003, 0x0030, 320}, {INT64_C(1380575036683678000), 0x0003, 0x0031, 256}, {INT64_C(1380575036683678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036683678000), 0x0003, 0x0035, 2529}, {INT64_C(1380575036683678000), 0x0003, 0x0036, 4402}, {INT64_C(1380575036683678000), 0x0003, 0x0034, 0}, {INT64_C(1380575036683678000), 0x0003, 0x0030, 640}, {INT64_C(1380575036683678000), 0x0003, 0x0031, 384}, {INT64_C(1380575036683678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036683678000), 0x0003, 0x0035, 2512}, {INT64_C(1380575036683678000), 0x0003, 0x0036, 3040}, {INT64_C(1380575036683678000), 0x0003, 0x0034, 1}, {INT64_C(1380575036683678000), 0x0003, 0x0030, 384}, {INT64_C(1380575036683678000), 0x0003, 0x0031, 160}, {INT64_C(1380575036683678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036683678000), 0x0000, 0x0000, 0}, {INT64_C(1380575036701677000), 0x0003, 0x0000, 3245}, {INT64_C(1380575036701677000), 0x0003, 0x0001, 4880}, {INT64_C(1380575036701677000), 0x0003, 0x0035, 3245}, {INT64_C(1380575036701677000), 0x0003, 0x0036, 4880}, {INT64_C(1380575036701677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036701677000), 0x0003, 0x0030, 320}, {INT64_C(1380575036701677000), 0x0003, 0x0031, 256}, {INT64_C(1380575036701677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036701677000), 0x0003, 0x0035, 2738}, {INT64_C(1380575036701677000), 0x0003, 0x0036, 4444}, {INT64_C(1380575036701677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036701677000), 0x0003, 0x0030, 480}, {INT64_C(1380575036701677000), 0x0003, 0x0031, 256}, {INT64_C(1380575036701677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036701677000), 0x0003, 0x0035, 2690}, {INT64_C(1380575036701677000), 0x0003, 0x0036, 3040}, {INT64_C(1380575036701677000), 0x0003, 0x0034, 1}, {INT64_C(1380575036701677000), 0x0003, 0x0030, 384}, {INT64_C(1380575036701677000), 0x0003, 0x0031, 160}, {INT64_C(1380575036701677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036701677000), 0x0000, 0x0000, 0}, {INT64_C(1380575036719678000), 0x0003, 0x0000, 3436}, {INT64_C(1380575036719678000), 0x0003, 0x0001, 4891}, {INT64_C(1380575036719678000), 0x0003, 0x0035, 3436}, {INT64_C(1380575036719678000), 0x0003, 0x0036, 4891}, {INT64_C(1380575036719678000), 0x0003, 0x0034, 0}, {INT64_C(1380575036719678000), 0x0003, 0x0030, 320}, {INT64_C(1380575036719678000), 0x0003, 0x0031, 256}, {INT64_C(1380575036719678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036719678000), 0x0003, 0x0035, 2892}, {INT64_C(1380575036719678000), 0x0003, 0x0036, 4516}, {INT64_C(1380575036719678000), 0x0003, 0x0034, 0}, {INT64_C(1380575036719678000), 0x0003, 0x0030, 480}, {INT64_C(1380575036719678000), 0x0003, 0x0031, 384}, {INT64_C(1380575036719678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036719678000), 0x0003, 0x0035, 2872}, {INT64_C(1380575036719678000), 0x0003, 0x0036, 3200}, {INT64_C(1380575036719678000), 0x0003, 0x0034, 1}, {INT64_C(1380575036719678000), 0x0003, 0x0030, 256}, {INT64_C(1380575036719678000), 0x0003, 0x0031, 160}, {INT64_C(1380575036719678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036719678000), 0x0000, 0x0000, 0}, {INT64_C(1380575036739674000), 0x0003, 0x0000, 3648}, {INT64_C(1380575036739674000), 0x0003, 0x0001, 4982}, {INT64_C(1380575036739674000), 0x0003, 0x0035, 3648}, {INT64_C(1380575036739674000), 0x0003, 0x0036, 4982}, {INT64_C(1380575036739674000), 0x0003, 0x0034, 0}, {INT64_C(1380575036739674000), 0x0003, 0x0030, 320}, {INT64_C(1380575036739674000), 0x0003, 0x0031, 256}, {INT64_C(1380575036739674000), 0x0000, 0x0002, 0}, {INT64_C(1380575036739674000), 0x0003, 0x0035, 3056}, {INT64_C(1380575036739674000), 0x0003, 0x0036, 4599}, {INT64_C(1380575036739674000), 0x0003, 0x0034, 0}, {INT64_C(1380575036739674000), 0x0003, 0x0030, 640}, {INT64_C(1380575036739674000), 0x0003, 0x0031, 256}, {INT64_C(1380575036739674000), 0x0000, 0x0002, 0}, {INT64_C(1380575036739674000), 0x0000, 0x0000, 0}, {INT64_C(1380575036757679000), 0x0003, 0x0000, 3861}, {INT64_C(1380575036757679000), 0x0003, 0x0001, 5088}, {INT64_C(1380575036757679000), 0x0003, 0x0035, 3861}, {INT64_C(1380575036757679000), 0x0003, 0x0036, 5088}, {INT64_C(1380575036757679000), 0x0003, 0x0034, 0}, {INT64_C(1380575036757679000), 0x0003, 0x0030, 480}, {INT64_C(1380575036757679000), 0x0003, 0x0031, 256}, {INT64_C(1380575036757679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036757679000), 0x0003, 0x0035, 3290}, {INT64_C(1380575036757679000), 0x0003, 0x0036, 4771}, {INT64_C(1380575036757679000), 0x0003, 0x0034, 0}, {INT64_C(1380575036757679000), 0x0003, 0x0030, 640}, {INT64_C(1380575036757679000), 0x0003, 0x0031, 384}, {INT64_C(1380575036757679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036757679000), 0x0003, 0x0035, 3290}, {INT64_C(1380575036757679000), 0x0003, 0x0036, 3360}, {INT64_C(1380575036757679000), 0x0003, 0x0034, 1}, {INT64_C(1380575036757679000), 0x0003, 0x0030, 256}, {INT64_C(1380575036757679000), 0x0003, 0x0031, 160}, {INT64_C(1380575036757679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036757679000), 0x0000, 0x0000, 0}, {INT64_C(1380575036775678000), 0x0003, 0x0000, 4087}, {INT64_C(1380575036775678000), 0x0003, 0x0001, 5170}, {INT64_C(1380575036775678000), 0x0003, 0x0035, 4087}, {INT64_C(1380575036775678000), 0x0003, 0x0036, 5170}, {INT64_C(1380575036775678000), 0x0003, 0x0034, 0}, {INT64_C(1380575036775678000), 0x0003, 0x0030, 480}, {INT64_C(1380575036775678000), 0x0003, 0x0031, 256}, {INT64_C(1380575036775678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036775678000), 0x0003, 0x0035, 3504}, {INT64_C(1380575036775678000), 0x0003, 0x0036, 4907}, {INT64_C(1380575036775678000), 0x0003, 0x0034, 1}, {INT64_C(1380575036775678000), 0x0003, 0x0030, 384}, {INT64_C(1380575036775678000), 0x0003, 0x0031, 320}, {INT64_C(1380575036775678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036775678000), 0x0003, 0x0035, 3408}, {INT64_C(1380575036775678000), 0x0003, 0x0036, 3656}, {INT64_C(1380575036775678000), 0x0003, 0x0034, 0}, {INT64_C(1380575036775678000), 0x0003, 0x0030, 320}, {INT64_C(1380575036775678000), 0x0003, 0x0031, 256}, {INT64_C(1380575036775678000), 0x0000, 0x0002, 0}, {INT64_C(1380575036775678000), 0x0000, 0x0000, 0}, {INT64_C(1380575036795676000), 0x0003, 0x0000, 3681}, {INT64_C(1380575036795676000), 0x0003, 0x0001, 5065}, {INT64_C(1380575036795676000), 0x0003, 0x0035, 3681}, {INT64_C(1380575036795676000), 0x0003, 0x0036, 5065}, {INT64_C(1380575036795676000), 0x0003, 0x0034, 0}, {INT64_C(1380575036795676000), 0x0003, 0x0030, 480}, {INT64_C(1380575036795676000), 0x0003, 0x0031, 384}, {INT64_C(1380575036795676000), 0x0000, 0x0002, 0}, {INT64_C(1380575036795676000), 0x0003, 0x0035, 4231}, {INT64_C(1380575036795676000), 0x0003, 0x0036, 5233}, {INT64_C(1380575036795676000), 0x0003, 0x0034, 0}, {INT64_C(1380575036795676000), 0x0003, 0x0030, 320}, {INT64_C(1380575036795676000), 0x0003, 0x0031, 256}, {INT64_C(1380575036795676000), 0x0000, 0x0002, 0}, {INT64_C(1380575036795676000), 0x0000, 0x0000, 0}, {INT64_C(1380575036813677000), 0x0003, 0x0000, 3875}, {INT64_C(1380575036813677000), 0x0003, 0x0001, 5189}, {INT64_C(1380575036813677000), 0x0003, 0x0035, 3875}, {INT64_C(1380575036813677000), 0x0003, 0x0036, 5189}, {INT64_C(1380575036813677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036813677000), 0x0003, 0x0030, 480}, {INT64_C(1380575036813677000), 0x0003, 0x0031, 256}, {INT64_C(1380575036813677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036813677000), 0x0003, 0x0035, 4457}, {INT64_C(1380575036813677000), 0x0003, 0x0036, 5316}, {INT64_C(1380575036813677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036813677000), 0x0003, 0x0030, 320}, {INT64_C(1380575036813677000), 0x0003, 0x0031, 256}, {INT64_C(1380575036813677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036813677000), 0x0003, 0x0035, 3721}, {INT64_C(1380575036813677000), 0x0003, 0x0036, 3895}, {INT64_C(1380575036813677000), 0x0003, 0x0034, 1}, {INT64_C(1380575036813677000), 0x0003, 0x0030, 384}, {INT64_C(1380575036813677000), 0x0003, 0x0031, 320}, {INT64_C(1380575036813677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036813677000), 0x0000, 0x0000, 0}, {INT64_C(1380575036833638000), 0x0003, 0x0000, 4558}, {INT64_C(1380575036833638000), 0x0003, 0x0001, 5390}, {INT64_C(1380575036833638000), 0x0003, 0x0035, 4558}, {INT64_C(1380575036833638000), 0x0003, 0x0036, 5390}, {INT64_C(1380575036833638000), 0x0003, 0x0034, 0}, {INT64_C(1380575036833638000), 0x0003, 0x0030, 320}, {INT64_C(1380575036833638000), 0x0003, 0x0031, 256}, {INT64_C(1380575036833638000), 0x0000, 0x0002, 0}, {INT64_C(1380575036833638000), 0x0003, 0x0035, 3978}, {INT64_C(1380575036833638000), 0x0003, 0x0036, 5210}, {INT64_C(1380575036833638000), 0x0003, 0x0034, 1}, {INT64_C(1380575036833638000), 0x0003, 0x0030, 384}, {INT64_C(1380575036833638000), 0x0003, 0x0031, 320}, {INT64_C(1380575036833638000), 0x0000, 0x0002, 0}, {INT64_C(1380575036833638000), 0x0003, 0x0035, 3804}, {INT64_C(1380575036833638000), 0x0003, 0x0036, 3909}, {INT64_C(1380575036833638000), 0x0003, 0x0034, 0}, {INT64_C(1380575036833638000), 0x0003, 0x0030, 320}, {INT64_C(1380575036833638000), 0x0003, 0x0031, 256}, {INT64_C(1380575036833638000), 0x0000, 0x0002, 0}, {INT64_C(1380575036833638000), 0x0000, 0x0000, 0}, {INT64_C(1380575036851679000), 0x0003, 0x0000, 4061}, {INT64_C(1380575036851679000), 0x0003, 0x0001, 5228}, {INT64_C(1380575036851679000), 0x0003, 0x0035, 4061}, {INT64_C(1380575036851679000), 0x0003, 0x0036, 5228}, {INT64_C(1380575036851679000), 0x0003, 0x0034, 0}, {INT64_C(1380575036851679000), 0x0003, 0x0030, 480}, {INT64_C(1380575036851679000), 0x0003, 0x0031, 256}, {INT64_C(1380575036851679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036851679000), 0x0003, 0x0035, 4628}, {INT64_C(1380575036851679000), 0x0003, 0x0036, 5376}, {INT64_C(1380575036851679000), 0x0003, 0x0034, 0}, {INT64_C(1380575036851679000), 0x0003, 0x0030, 320}, {INT64_C(1380575036851679000), 0x0003, 0x0031, 256}, {INT64_C(1380575036851679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036851679000), 0x0003, 0x0035, 3840}, {INT64_C(1380575036851679000), 0x0003, 0x0036, 3921}, {INT64_C(1380575036851679000), 0x0003, 0x0034, 0}, {INT64_C(1380575036851679000), 0x0003, 0x0030, 320}, {INT64_C(1380575036851679000), 0x0003, 0x0031, 128}, {INT64_C(1380575036851679000), 0x0000, 0x0002, 0}, {INT64_C(1380575036851679000), 0x0000, 0x0000, 0}, {INT64_C(1380575036869677000), 0x0003, 0x0000, 4089}, {INT64_C(1380575036869677000), 0x0003, 0x0001, 5207}, {INT64_C(1380575036869677000), 0x0003, 0x0035, 4089}, {INT64_C(1380575036869677000), 0x0003, 0x0036, 5207}, {INT64_C(1380575036869677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036869677000), 0x0003, 0x0030, 640}, {INT64_C(1380575036869677000), 0x0003, 0x0031, 256}, {INT64_C(1380575036869677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036869677000), 0x0003, 0x0035, 4665}, {INT64_C(1380575036869677000), 0x0003, 0x0036, 5375}, {INT64_C(1380575036869677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036869677000), 0x0003, 0x0030, 320}, {INT64_C(1380575036869677000), 0x0003, 0x0031, 256}, {INT64_C(1380575036869677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036869677000), 0x0003, 0x0035, 3840}, {INT64_C(1380575036869677000), 0x0003, 0x0036, 3906}, {INT64_C(1380575036869677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036869677000), 0x0003, 0x0030, 320}, {INT64_C(1380575036869677000), 0x0003, 0x0031, 128}, {INT64_C(1380575036869677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036869677000), 0x0000, 0x0000, 0}, {INT64_C(1380575036889677000), 0x0003, 0x0000, 4664}, {INT64_C(1380575036889677000), 0x0003, 0x0001, 5363}, {INT64_C(1380575036889677000), 0x0003, 0x0035, 4664}, {INT64_C(1380575036889677000), 0x0003, 0x0036, 5363}, {INT64_C(1380575036889677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036889677000), 0x0003, 0x0030, 320}, {INT64_C(1380575036889677000), 0x0003, 0x0031, 256}, {INT64_C(1380575036889677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036889677000), 0x0003, 0x0035, 4102}, {INT64_C(1380575036889677000), 0x0003, 0x0036, 5192}, {INT64_C(1380575036889677000), 0x0003, 0x0034, 1}, {INT64_C(1380575036889677000), 0x0003, 0x0030, 384}, {INT64_C(1380575036889677000), 0x0003, 0x0031, 320}, {INT64_C(1380575036889677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036889677000), 0x0003, 0x0035, 3790}, {INT64_C(1380575036889677000), 0x0003, 0x0036, 3863}, {INT64_C(1380575036889677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036889677000), 0x0003, 0x0030, 320}, {INT64_C(1380575036889677000), 0x0003, 0x0031, 256}, {INT64_C(1380575036889677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036889677000), 0x0000, 0x0000, 0}, {INT64_C(1380575036907677000), 0x0003, 0x0000, 4074}, {INT64_C(1380575036907677000), 0x0003, 0x0001, 5192}, {INT64_C(1380575036907677000), 0x0003, 0x0035, 4074}, {INT64_C(1380575036907677000), 0x0003, 0x0036, 5192}, {INT64_C(1380575036907677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036907677000), 0x0003, 0x0030, 640}, {INT64_C(1380575036907677000), 0x0003, 0x0031, 384}, {INT64_C(1380575036907677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036907677000), 0x0003, 0x0035, 4658}, {INT64_C(1380575036907677000), 0x0003, 0x0036, 5348}, {INT64_C(1380575036907677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036907677000), 0x0003, 0x0030, 320}, {INT64_C(1380575036907677000), 0x0003, 0x0031, 256}, {INT64_C(1380575036907677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036907677000), 0x0000, 0x0000, 0}, {INT64_C(1380575036925676000), 0x0003, 0x0000, 4636}, {INT64_C(1380575036925676000), 0x0003, 0x0001, 5349}, {INT64_C(1380575036925676000), 0x0003, 0x0035, 4636}, {INT64_C(1380575036925676000), 0x0003, 0x0036, 5349}, {INT64_C(1380575036925676000), 0x0003, 0x0034, 0}, {INT64_C(1380575036925676000), 0x0003, 0x0030, 320}, {INT64_C(1380575036925676000), 0x0003, 0x0031, 256}, {INT64_C(1380575036925676000), 0x0000, 0x0002, 0}, {INT64_C(1380575036925676000), 0x0003, 0x0035, 4022}, {INT64_C(1380575036925676000), 0x0003, 0x0036, 5086}, {INT64_C(1380575036925676000), 0x0003, 0x0034, 0}, {INT64_C(1380575036925676000), 0x0003, 0x0030, 480}, {INT64_C(1380575036925676000), 0x0003, 0x0031, 256}, {INT64_C(1380575036925676000), 0x0000, 0x0002, 0}, {INT64_C(1380575036925676000), 0x0000, 0x0000, 0}, {INT64_C(1380575036945669000), 0x0003, 0x0000, 4654}, {INT64_C(1380575036945669000), 0x0003, 0x0001, 5277}, {INT64_C(1380575036945669000), 0x0003, 0x0035, 4654}, {INT64_C(1380575036945669000), 0x0003, 0x0036, 5277}, {INT64_C(1380575036945669000), 0x0003, 0x0034, 0}, {INT64_C(1380575036945669000), 0x0003, 0x0030, 320}, {INT64_C(1380575036945669000), 0x0003, 0x0031, 256}, {INT64_C(1380575036945669000), 0x0000, 0x0002, 0}, {INT64_C(1380575036945669000), 0x0003, 0x0035, 3865}, {INT64_C(1380575036945669000), 0x0003, 0x0036, 4862}, {INT64_C(1380575036945669000), 0x0003, 0x0034, 0}, {INT64_C(1380575036945669000), 0x0003, 0x0030, 480}, {INT64_C(1380575036945669000), 0x0003, 0x0031, 384}, {INT64_C(1380575036945669000), 0x0000, 0x0002, 0}, {INT64_C(1380575036945669000), 0x0000, 0x0000, 0}, {INT64_C(1380575036963675000), 0x0003, 0x0000, 4641}, {INT64_C(1380575036963675000), 0x0003, 0x0001, 5111}, {INT64_C(1380575036963675000), 0x0003, 0x0035, 4641}, {INT64_C(1380575036963675000), 0x0003, 0x0036, 5111}, {INT64_C(1380575036963675000), 0x0003, 0x0034, 0}, {INT64_C(1380575036963675000), 0x0003, 0x0030, 320}, {INT64_C(1380575036963675000), 0x0003, 0x0031, 256}, {INT64_C(1380575036963675000), 0x0000, 0x0002, 0}, {INT64_C(1380575036963675000), 0x0003, 0x0035, 3644}, {INT64_C(1380575036963675000), 0x0003, 0x0036, 4550}, {INT64_C(1380575036963675000), 0x0003, 0x0034, 1}, {INT64_C(1380575036963675000), 0x0003, 0x0030, 512}, {INT64_C(1380575036963675000), 0x0003, 0x0031, 480}, {INT64_C(1380575036963675000), 0x0000, 0x0002, 0}, {INT64_C(1380575036963675000), 0x0000, 0x0000, 0}, {INT64_C(1380575036981677000), 0x0003, 0x0000, 4506}, {INT64_C(1380575036981677000), 0x0003, 0x0001, 4763}, {INT64_C(1380575036981677000), 0x0003, 0x0035, 4506}, {INT64_C(1380575036981677000), 0x0003, 0x0036, 4763}, {INT64_C(1380575036981677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036981677000), 0x0003, 0x0030, 320}, {INT64_C(1380575036981677000), 0x0003, 0x0031, 256}, {INT64_C(1380575036981677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036981677000), 0x0003, 0x0035, 3456}, {INT64_C(1380575036981677000), 0x0003, 0x0036, 4183}, {INT64_C(1380575036981677000), 0x0003, 0x0034, 0}, {INT64_C(1380575036981677000), 0x0003, 0x0030, 640}, {INT64_C(1380575036981677000), 0x0003, 0x0031, 384}, {INT64_C(1380575036981677000), 0x0000, 0x0002, 0}, {INT64_C(1380575036981677000), 0x0000, 0x0000, 0}, {INT64_C(1380575037001676000), 0x0003, 0x0000, 4354}, {INT64_C(1380575037001676000), 0x0003, 0x0001, 4440}, {INT64_C(1380575037001676000), 0x0003, 0x0035, 4354}, {INT64_C(1380575037001676000), 0x0003, 0x0036, 4440}, {INT64_C(1380575037001676000), 0x0003, 0x0034, 0}, {INT64_C(1380575037001676000), 0x0003, 0x0030, 480}, {INT64_C(1380575037001676000), 0x0003, 0x0031, 256}, {INT64_C(1380575037001676000), 0x0000, 0x0002, 0}, {INT64_C(1380575037001676000), 0x0003, 0x0035, 3292}, {INT64_C(1380575037001676000), 0x0003, 0x0036, 4000}, {INT64_C(1380575037001676000), 0x0003, 0x0034, 1}, {INT64_C(1380575037001676000), 0x0003, 0x0030, 256}, {INT64_C(1380575037001676000), 0x0003, 0x0031, 160}, {INT64_C(1380575037001676000), 0x0000, 0x0002, 0}, {INT64_C(1380575037001676000), 0x0000, 0x0000, 0}, {INT64_C(1380575037019675000), 0x0003, 0x0000, 4229}, {INT64_C(1380575037019675000), 0x0003, 0x0001, 4085}, {INT64_C(1380575037019675000), 0x0003, 0x0035, 4229}, {INT64_C(1380575037019675000), 0x0003, 0x0036, 4085}, {INT64_C(1380575037019675000), 0x0003, 0x0034, 0}, {INT64_C(1380575037019675000), 0x0003, 0x0030, 480}, {INT64_C(1380575037019675000), 0x0003, 0x0031, 384}, {INT64_C(1380575037019675000), 0x0000, 0x0002, 0}, {INT64_C(1380575037019675000), 0x0003, 0x0035, 3169}, {INT64_C(1380575037019675000), 0x0003, 0x0036, 3680}, {INT64_C(1380575037019675000), 0x0003, 0x0034, 1}, {INT64_C(1380575037019675000), 0x0003, 0x0030, 256}, {INT64_C(1380575037019675000), 0x0003, 0x0031, 160}, {INT64_C(1380575037019675000), 0x0000, 0x0002, 0}, {INT64_C(1380575037019675000), 0x0000, 0x0000, 0}, {INT64_C(1380575037113670000), 0x0001, 0x014d, 0}, {INT64_C(1380575037113670000), 0x0001, 0x014a, 0}, {INT64_C(1380575037113670000), 0x0000, 0x0000, 0}, {INT64_C(1380575037493671000), 0x0003, 0x0000, 1090}, {INT64_C(1380575037493671000), 0x0003, 0x0001, 4241}, {INT64_C(1380575037493671000), 0x0003, 0x0035, 1090}, {INT64_C(1380575037493671000), 0x0003, 0x0036, 4241}, {INT64_C(1380575037493671000), 0x0003, 0x0034, 0}, {INT64_C(1380575037493671000), 0x0003, 0x0030, 320}, {INT64_C(1380575037493671000), 0x0003, 0x0031, 256}, {INT64_C(1380575037493671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037493671000), 0x0001, 0x014d, 1}, {INT64_C(1380575037493671000), 0x0001, 0x014a, 1}, {INT64_C(1380575037493671000), 0x0000, 0x0000, 0}, {INT64_C(1380575037505672000), 0x0003, 0x0000, 1317}, {INT64_C(1380575037505672000), 0x0003, 0x0001, 5657}, {INT64_C(1380575037505672000), 0x0003, 0x0035, 1317}, {INT64_C(1380575037505672000), 0x0003, 0x0036, 5657}, {INT64_C(1380575037505672000), 0x0003, 0x0034, 0}, {INT64_C(1380575037505672000), 0x0003, 0x0030, 320}, {INT64_C(1380575037505672000), 0x0003, 0x0031, 256}, {INT64_C(1380575037505672000), 0x0000, 0x0002, 0}, {INT64_C(1380575037505672000), 0x0003, 0x0035, 1096}, {INT64_C(1380575037505672000), 0x0003, 0x0036, 4255}, {INT64_C(1380575037505672000), 0x0003, 0x0034, 0}, {INT64_C(1380575037505672000), 0x0003, 0x0030, 800}, {INT64_C(1380575037505672000), 0x0003, 0x0031, 256}, {INT64_C(1380575037505672000), 0x0000, 0x0002, 0}, {INT64_C(1380575037505672000), 0x0000, 0x0000, 0}, {INT64_C(1380575037511672000), 0x0003, 0x0000, 1356}, {INT64_C(1380575037511672000), 0x0003, 0x0001, 5613}, {INT64_C(1380575037511672000), 0x0003, 0x0035, 1356}, {INT64_C(1380575037511672000), 0x0003, 0x0036, 5613}, {INT64_C(1380575037511672000), 0x0003, 0x0034, 0}, {INT64_C(1380575037511672000), 0x0003, 0x0030, 480}, {INT64_C(1380575037511672000), 0x0003, 0x0031, 256}, {INT64_C(1380575037511672000), 0x0000, 0x0002, 0}, {INT64_C(1380575037511672000), 0x0003, 0x0035, 1110}, {INT64_C(1380575037511672000), 0x0003, 0x0036, 4224}, {INT64_C(1380575037511672000), 0x0003, 0x0034, 0}, {INT64_C(1380575037511672000), 0x0003, 0x0030, 640}, {INT64_C(1380575037511672000), 0x0003, 0x0031, 256}, {INT64_C(1380575037511672000), 0x0000, 0x0002, 0}, {INT64_C(1380575037511672000), 0x0000, 0x0000, 0}, {INT64_C(1380575037525671000), 0x0003, 0x0000, 1389}, {INT64_C(1380575037525671000), 0x0003, 0x0001, 5544}, {INT64_C(1380575037525671000), 0x0003, 0x0035, 1389}, {INT64_C(1380575037525671000), 0x0003, 0x0036, 5544}, {INT64_C(1380575037525671000), 0x0003, 0x0034, 0}, {INT64_C(1380575037525671000), 0x0003, 0x0030, 480}, {INT64_C(1380575037525671000), 0x0003, 0x0031, 256}, {INT64_C(1380575037525671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037525671000), 0x0003, 0x0035, 1175}, {INT64_C(1380575037525671000), 0x0003, 0x0036, 4198}, {INT64_C(1380575037525671000), 0x0003, 0x0034, 0}, {INT64_C(1380575037525671000), 0x0003, 0x0030, 480}, {INT64_C(1380575037525671000), 0x0003, 0x0031, 256}, {INT64_C(1380575037525671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037525671000), 0x0000, 0x0000, 0}, {INT64_C(1380575037531669000), 0x0003, 0x0000, 1464}, {INT64_C(1380575037531669000), 0x0003, 0x0001, 5491}, {INT64_C(1380575037531669000), 0x0003, 0x0035, 1464}, {INT64_C(1380575037531669000), 0x0003, 0x0036, 5491}, {INT64_C(1380575037531669000), 0x0003, 0x0034, 0}, {INT64_C(1380575037531669000), 0x0003, 0x0030, 480}, {INT64_C(1380575037531669000), 0x0003, 0x0031, 256}, {INT64_C(1380575037531669000), 0x0000, 0x0002, 0}, {INT64_C(1380575037531669000), 0x0003, 0x0035, 1247}, {INT64_C(1380575037531669000), 0x0003, 0x0036, 4147}, {INT64_C(1380575037531669000), 0x0003, 0x0034, 0}, {INT64_C(1380575037531669000), 0x0003, 0x0030, 480}, {INT64_C(1380575037531669000), 0x0003, 0x0031, 256}, {INT64_C(1380575037531669000), 0x0000, 0x0002, 0}, {INT64_C(1380575037531669000), 0x0000, 0x0000, 0}, {INT64_C(1380575037543669000), 0x0003, 0x0000, 1520}, {INT64_C(1380575037543669000), 0x0003, 0x0001, 5427}, {INT64_C(1380575037543669000), 0x0003, 0x0035, 1520}, {INT64_C(1380575037543669000), 0x0003, 0x0036, 5427}, {INT64_C(1380575037543669000), 0x0003, 0x0034, 0}, {INT64_C(1380575037543669000), 0x0003, 0x0030, 480}, {INT64_C(1380575037543669000), 0x0003, 0x0031, 256}, {INT64_C(1380575037543669000), 0x0000, 0x0002, 0}, {INT64_C(1380575037543669000), 0x0003, 0x0035, 1313}, {INT64_C(1380575037543669000), 0x0003, 0x0036, 4108}, {INT64_C(1380575037543669000), 0x0003, 0x0034, 0}, {INT64_C(1380575037543669000), 0x0003, 0x0030, 480}, {INT64_C(1380575037543669000), 0x0003, 0x0031, 256}, {INT64_C(1380575037543669000), 0x0000, 0x0002, 0}, {INT64_C(1380575037543669000), 0x0000, 0x0000, 0}, {INT64_C(1380575037549671000), 0x0003, 0x0000, 1615}, {INT64_C(1380575037549671000), 0x0003, 0x0001, 5379}, {INT64_C(1380575037549671000), 0x0003, 0x0035, 1615}, {INT64_C(1380575037549671000), 0x0003, 0x0036, 5379}, {INT64_C(1380575037549671000), 0x0003, 0x0034, 0}, {INT64_C(1380575037549671000), 0x0003, 0x0030, 320}, {INT64_C(1380575037549671000), 0x0003, 0x0031, 256}, {INT64_C(1380575037549671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037549671000), 0x0003, 0x0035, 1422}, {INT64_C(1380575037549671000), 0x0003, 0x0036, 4070}, {INT64_C(1380575037549671000), 0x0003, 0x0034, 1}, {INT64_C(1380575037549671000), 0x0003, 0x0030, 384}, {INT64_C(1380575037549671000), 0x0003, 0x0031, 320}, {INT64_C(1380575037549671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037549671000), 0x0000, 0x0000, 0}, {INT64_C(1380575037563633000), 0x0003, 0x0000, 1726}, {INT64_C(1380575037563633000), 0x0003, 0x0001, 5345}, {INT64_C(1380575037563633000), 0x0003, 0x0035, 1726}, {INT64_C(1380575037563633000), 0x0003, 0x0036, 5345}, {INT64_C(1380575037563633000), 0x0003, 0x0034, 0}, {INT64_C(1380575037563633000), 0x0003, 0x0030, 320}, {INT64_C(1380575037563633000), 0x0003, 0x0031, 256}, {INT64_C(1380575037563633000), 0x0000, 0x0002, 0}, {INT64_C(1380575037563633000), 0x0003, 0x0035, 1531}, {INT64_C(1380575037563633000), 0x0003, 0x0036, 4067}, {INT64_C(1380575037563633000), 0x0003, 0x0034, 0}, {INT64_C(1380575037563633000), 0x0003, 0x0030, 480}, {INT64_C(1380575037563633000), 0x0003, 0x0031, 384}, {INT64_C(1380575037563633000), 0x0000, 0x0002, 0}, {INT64_C(1380575037563633000), 0x0000, 0x0000, 0}, {INT64_C(1380575037569672000), 0x0003, 0x0000, 1839}, {INT64_C(1380575037569672000), 0x0003, 0x0001, 5311}, {INT64_C(1380575037569672000), 0x0003, 0x0035, 1839}, {INT64_C(1380575037569672000), 0x0003, 0x0036, 5311}, {INT64_C(1380575037569672000), 0x0003, 0x0034, 0}, {INT64_C(1380575037569672000), 0x0003, 0x0030, 480}, {INT64_C(1380575037569672000), 0x0003, 0x0031, 256}, {INT64_C(1380575037569672000), 0x0000, 0x0002, 0}, {INT64_C(1380575037569672000), 0x0003, 0x0035, 1667}, {INT64_C(1380575037569672000), 0x0003, 0x0036, 4048}, {INT64_C(1380575037569672000), 0x0003, 0x0034, 1}, {INT64_C(1380575037569672000), 0x0003, 0x0030, 384}, {INT64_C(1380575037569672000), 0x0003, 0x0031, 320}, {INT64_C(1380575037569672000), 0x0000, 0x0002, 0}, {INT64_C(1380575037569672000), 0x0000, 0x0000, 0}, {INT64_C(1380575037581672000), 0x0003, 0x0000, 1965}, {INT64_C(1380575037581672000), 0x0003, 0x0001, 5222}, {INT64_C(1380575037581672000), 0x0003, 0x0035, 1965}, {INT64_C(1380575037581672000), 0x0003, 0x0036, 5222}, {INT64_C(1380575037581672000), 0x0003, 0x0034, 0}, {INT64_C(1380575037581672000), 0x0003, 0x0030, 480}, {INT64_C(1380575037581672000), 0x0003, 0x0031, 256}, {INT64_C(1380575037581672000), 0x0000, 0x0002, 0}, {INT64_C(1380575037581672000), 0x0003, 0x0035, 1802}, {INT64_C(1380575037581672000), 0x0003, 0x0036, 4048}, {INT64_C(1380575037581672000), 0x0003, 0x0034, 1}, {INT64_C(1380575037581672000), 0x0003, 0x0030, 512}, {INT64_C(1380575037581672000), 0x0003, 0x0031, 320}, {INT64_C(1380575037581672000), 0x0000, 0x0002, 0}, {INT64_C(1380575037581672000), 0x0000, 0x0000, 0}, {INT64_C(1380575037599670000), 0x0003, 0x0000, 2107}, {INT64_C(1380575037599670000), 0x0003, 0x0001, 5194}, {INT64_C(1380575037599670000), 0x0003, 0x0035, 2107}, {INT64_C(1380575037599670000), 0x0003, 0x0036, 5194}, {INT64_C(1380575037599670000), 0x0003, 0x0034, 0}, {INT64_C(1380575037599670000), 0x0003, 0x0030, 480}, {INT64_C(1380575037599670000), 0x0003, 0x0031, 256}, {INT64_C(1380575037599670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037599670000), 0x0003, 0x0035, 1944}, {INT64_C(1380575037599670000), 0x0003, 0x0036, 4032}, {INT64_C(1380575037599670000), 0x0003, 0x0034, 1}, {INT64_C(1380575037599670000), 0x0003, 0x0030, 384}, {INT64_C(1380575037599670000), 0x0003, 0x0031, 320}, {INT64_C(1380575037599670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037599670000), 0x0000, 0x0000, 0}, {INT64_C(1380575037619670000), 0x0003, 0x0000, 2272}, {INT64_C(1380575037619670000), 0x0003, 0x0001, 5174}, {INT64_C(1380575037619670000), 0x0003, 0x0035, 2272}, {INT64_C(1380575037619670000), 0x0003, 0x0036, 5174}, {INT64_C(1380575037619670000), 0x0003, 0x0034, 0}, {INT64_C(1380575037619670000), 0x0003, 0x0030, 480}, {INT64_C(1380575037619670000), 0x0003, 0x0031, 256}, {INT64_C(1380575037619670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037619670000), 0x0003, 0x0035, 2109}, {INT64_C(1380575037619670000), 0x0003, 0x0036, 4005}, {INT64_C(1380575037619670000), 0x0003, 0x0034, 0}, {INT64_C(1380575037619670000), 0x0003, 0x0030, 320}, {INT64_C(1380575037619670000), 0x0003, 0x0031, 256}, {INT64_C(1380575037619670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037619670000), 0x0000, 0x0000, 0}, {INT64_C(1380575037637665000), 0x0003, 0x0000, 2459}, {INT64_C(1380575037637665000), 0x0003, 0x0001, 5169}, {INT64_C(1380575037637665000), 0x0003, 0x0035, 2459}, {INT64_C(1380575037637665000), 0x0003, 0x0036, 5169}, {INT64_C(1380575037637665000), 0x0003, 0x0034, 0}, {INT64_C(1380575037637665000), 0x0003, 0x0030, 480}, {INT64_C(1380575037637665000), 0x0003, 0x0031, 256}, {INT64_C(1380575037637665000), 0x0000, 0x0002, 0}, {INT64_C(1380575037637665000), 0x0003, 0x0035, 2306}, {INT64_C(1380575037637665000), 0x0003, 0x0036, 4011}, {INT64_C(1380575037637665000), 0x0003, 0x0034, 1}, {INT64_C(1380575037637665000), 0x0003, 0x0030, 384}, {INT64_C(1380575037637665000), 0x0003, 0x0031, 320}, {INT64_C(1380575037637665000), 0x0000, 0x0002, 0}, {INT64_C(1380575037637665000), 0x0000, 0x0000, 0}, {INT64_C(1380575037655672000), 0x0003, 0x0000, 2638}, {INT64_C(1380575037655672000), 0x0003, 0x0001, 5177}, {INT64_C(1380575037655672000), 0x0003, 0x0035, 2638}, {INT64_C(1380575037655672000), 0x0003, 0x0036, 5177}, {INT64_C(1380575037655672000), 0x0003, 0x0034, 0}, {INT64_C(1380575037655672000), 0x0003, 0x0030, 480}, {INT64_C(1380575037655672000), 0x0003, 0x0031, 256}, {INT64_C(1380575037655672000), 0x0000, 0x0002, 0}, {INT64_C(1380575037655672000), 0x0003, 0x0035, 2479}, {INT64_C(1380575037655672000), 0x0003, 0x0036, 4008}, {INT64_C(1380575037655672000), 0x0003, 0x0034, 1}, {INT64_C(1380575037655672000), 0x0003, 0x0030, 384}, {INT64_C(1380575037655672000), 0x0003, 0x0031, 320}, {INT64_C(1380575037655672000), 0x0000, 0x0002, 0}, {INT64_C(1380575037655672000), 0x0000, 0x0000, 0}, {INT64_C(1380575037675669000), 0x0003, 0x0000, 2799}, {INT64_C(1380575037675669000), 0x0003, 0x0001, 5187}, {INT64_C(1380575037675669000), 0x0003, 0x0035, 2799}, {INT64_C(1380575037675669000), 0x0003, 0x0036, 5187}, {INT64_C(1380575037675669000), 0x0003, 0x0034, 0}, {INT64_C(1380575037675669000), 0x0003, 0x0030, 480}, {INT64_C(1380575037675669000), 0x0003, 0x0031, 256}, {INT64_C(1380575037675669000), 0x0000, 0x0002, 0}, {INT64_C(1380575037675669000), 0x0003, 0x0035, 2636}, {INT64_C(1380575037675669000), 0x0003, 0x0036, 4033}, {INT64_C(1380575037675669000), 0x0003, 0x0034, 1}, {INT64_C(1380575037675669000), 0x0003, 0x0030, 384}, {INT64_C(1380575037675669000), 0x0003, 0x0031, 320}, {INT64_C(1380575037675669000), 0x0000, 0x0002, 0}, {INT64_C(1380575037675669000), 0x0000, 0x0000, 0}, {INT64_C(1380575037693671000), 0x0003, 0x0000, 2987}, {INT64_C(1380575037693671000), 0x0003, 0x0001, 5211}, {INT64_C(1380575037693671000), 0x0003, 0x0035, 2987}, {INT64_C(1380575037693671000), 0x0003, 0x0036, 5211}, {INT64_C(1380575037693671000), 0x0003, 0x0034, 1}, {INT64_C(1380575037693671000), 0x0003, 0x0030, 384}, {INT64_C(1380575037693671000), 0x0003, 0x0031, 320}, {INT64_C(1380575037693671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037693671000), 0x0003, 0x0035, 2814}, {INT64_C(1380575037693671000), 0x0003, 0x0036, 4069}, {INT64_C(1380575037693671000), 0x0003, 0x0034, 1}, {INT64_C(1380575037693671000), 0x0003, 0x0030, 384}, {INT64_C(1380575037693671000), 0x0003, 0x0031, 320}, {INT64_C(1380575037693671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037693671000), 0x0000, 0x0000, 0}, {INT64_C(1380575037711668000), 0x0003, 0x0000, 3169}, {INT64_C(1380575037711668000), 0x0003, 0x0001, 5234}, {INT64_C(1380575037711668000), 0x0003, 0x0035, 3169}, {INT64_C(1380575037711668000), 0x0003, 0x0036, 5234}, {INT64_C(1380575037711668000), 0x0003, 0x0034, 0}, {INT64_C(1380575037711668000), 0x0003, 0x0030, 480}, {INT64_C(1380575037711668000), 0x0003, 0x0031, 256}, {INT64_C(1380575037711668000), 0x0000, 0x0002, 0}, {INT64_C(1380575037711668000), 0x0003, 0x0035, 3013}, {INT64_C(1380575037711668000), 0x0003, 0x0036, 4106}, {INT64_C(1380575037711668000), 0x0003, 0x0034, 0}, {INT64_C(1380575037711668000), 0x0003, 0x0030, 320}, {INT64_C(1380575037711668000), 0x0003, 0x0031, 256}, {INT64_C(1380575037711668000), 0x0000, 0x0002, 0}, {INT64_C(1380575037711668000), 0x0000, 0x0000, 0}, {INT64_C(1380575037731665000), 0x0003, 0x0000, 3390}, {INT64_C(1380575037731665000), 0x0003, 0x0001, 5329}, {INT64_C(1380575037731665000), 0x0003, 0x0035, 3390}, {INT64_C(1380575037731665000), 0x0003, 0x0036, 5329}, {INT64_C(1380575037731665000), 0x0003, 0x0034, 0}, {INT64_C(1380575037731665000), 0x0003, 0x0030, 480}, {INT64_C(1380575037731665000), 0x0003, 0x0031, 256}, {INT64_C(1380575037731665000), 0x0000, 0x0002, 0}, {INT64_C(1380575037731665000), 0x0003, 0x0035, 3207}, {INT64_C(1380575037731665000), 0x0003, 0x0036, 4193}, {INT64_C(1380575037731665000), 0x0003, 0x0034, 0}, {INT64_C(1380575037731665000), 0x0003, 0x0030, 480}, {INT64_C(1380575037731665000), 0x0003, 0x0031, 384}, {INT64_C(1380575037731665000), 0x0000, 0x0002, 0}, {INT64_C(1380575037731665000), 0x0000, 0x0000, 0}, {INT64_C(1380575037749669000), 0x0003, 0x0000, 3612}, {INT64_C(1380575037749669000), 0x0003, 0x0001, 5382}, {INT64_C(1380575037749669000), 0x0003, 0x0035, 3612}, {INT64_C(1380575037749669000), 0x0003, 0x0036, 5382}, {INT64_C(1380575037749669000), 0x0003, 0x0034, 0}, {INT64_C(1380575037749669000), 0x0003, 0x0030, 480}, {INT64_C(1380575037749669000), 0x0003, 0x0031, 384}, {INT64_C(1380575037749669000), 0x0000, 0x0002, 0}, {INT64_C(1380575037749669000), 0x0003, 0x0035, 3376}, {INT64_C(1380575037749669000), 0x0003, 0x0036, 4262}, {INT64_C(1380575037749669000), 0x0003, 0x0034, 0}, {INT64_C(1380575037749669000), 0x0003, 0x0030, 480}, {INT64_C(1380575037749669000), 0x0003, 0x0031, 256}, {INT64_C(1380575037749669000), 0x0000, 0x0002, 0}, {INT64_C(1380575037749669000), 0x0000, 0x0000, 0}, {INT64_C(1380575037767673000), 0x0003, 0x0000, 3798}, {INT64_C(1380575037767673000), 0x0003, 0x0001, 5445}, {INT64_C(1380575037767673000), 0x0003, 0x0035, 3798}, {INT64_C(1380575037767673000), 0x0003, 0x0036, 5445}, {INT64_C(1380575037767673000), 0x0003, 0x0034, 0}, {INT64_C(1380575037767673000), 0x0003, 0x0030, 480}, {INT64_C(1380575037767673000), 0x0003, 0x0031, 256}, {INT64_C(1380575037767673000), 0x0000, 0x0002, 0}, {INT64_C(1380575037767673000), 0x0003, 0x0035, 3500}, {INT64_C(1380575037767673000), 0x0003, 0x0036, 4318}, {INT64_C(1380575037767673000), 0x0003, 0x0034, 0}, {INT64_C(1380575037767673000), 0x0003, 0x0030, 480}, {INT64_C(1380575037767673000), 0x0003, 0x0031, 256}, {INT64_C(1380575037767673000), 0x0000, 0x0002, 0}, {INT64_C(1380575037767673000), 0x0000, 0x0000, 0}, {INT64_C(1380575037787670000), 0x0003, 0x0000, 3939}, {INT64_C(1380575037787670000), 0x0003, 0x0001, 5479}, {INT64_C(1380575037787670000), 0x0003, 0x0035, 3939}, {INT64_C(1380575037787670000), 0x0003, 0x0036, 5479}, {INT64_C(1380575037787670000), 0x0003, 0x0034, 0}, {INT64_C(1380575037787670000), 0x0003, 0x0030, 480}, {INT64_C(1380575037787670000), 0x0003, 0x0031, 384}, {INT64_C(1380575037787670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037787670000), 0x0003, 0x0035, 3617}, {INT64_C(1380575037787670000), 0x0003, 0x0036, 4307}, {INT64_C(1380575037787670000), 0x0003, 0x0034, 0}, {INT64_C(1380575037787670000), 0x0003, 0x0030, 640}, {INT64_C(1380575037787670000), 0x0003, 0x0031, 384}, {INT64_C(1380575037787670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037787670000), 0x0000, 0x0000, 0}, {INT64_C(1380575037805668000), 0x0003, 0x0000, 4021}, {INT64_C(1380575037805668000), 0x0003, 0x0001, 5463}, {INT64_C(1380575037805668000), 0x0003, 0x0035, 4021}, {INT64_C(1380575037805668000), 0x0003, 0x0036, 5463}, {INT64_C(1380575037805668000), 0x0003, 0x0034, 0}, {INT64_C(1380575037805668000), 0x0003, 0x0030, 480}, {INT64_C(1380575037805668000), 0x0003, 0x0031, 384}, {INT64_C(1380575037805668000), 0x0000, 0x0002, 0}, {INT64_C(1380575037805668000), 0x0003, 0x0035, 3680}, {INT64_C(1380575037805668000), 0x0003, 0x0036, 4315}, {INT64_C(1380575037805668000), 0x0003, 0x0034, 0}, {INT64_C(1380575037805668000), 0x0003, 0x0030, 480}, {INT64_C(1380575037805668000), 0x0003, 0x0031, 256}, {INT64_C(1380575037805668000), 0x0000, 0x0002, 0}, {INT64_C(1380575037805668000), 0x0000, 0x0000, 0}, {INT64_C(1380575037825670000), 0x0003, 0x0000, 4043}, {INT64_C(1380575037825670000), 0x0003, 0x0001, 5446}, {INT64_C(1380575037825670000), 0x0003, 0x0035, 4043}, {INT64_C(1380575037825670000), 0x0003, 0x0036, 5446}, {INT64_C(1380575037825670000), 0x0003, 0x0034, 0}, {INT64_C(1380575037825670000), 0x0003, 0x0030, 480}, {INT64_C(1380575037825670000), 0x0003, 0x0031, 256}, {INT64_C(1380575037825670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037825670000), 0x0003, 0x0035, 3688}, {INT64_C(1380575037825670000), 0x0003, 0x0036, 4266}, {INT64_C(1380575037825670000), 0x0003, 0x0034, 0}, {INT64_C(1380575037825670000), 0x0003, 0x0030, 320}, {INT64_C(1380575037825670000), 0x0003, 0x0031, 256}, {INT64_C(1380575037825670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037825670000), 0x0000, 0x0000, 0}, {INT64_C(1380575037843671000), 0x0003, 0x0000, 5346}, {INT64_C(1380575037843671000), 0x0003, 0x0001, 5920}, {INT64_C(1380575037843671000), 0x0003, 0x0035, 5346}, {INT64_C(1380575037843671000), 0x0003, 0x0036, 5920}, {INT64_C(1380575037843671000), 0x0003, 0x0034, 1}, {INT64_C(1380575037843671000), 0x0003, 0x0030, 256}, {INT64_C(1380575037843671000), 0x0003, 0x0031, 160}, {INT64_C(1380575037843671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037843671000), 0x0003, 0x0035, 4045}, {INT64_C(1380575037843671000), 0x0003, 0x0036, 5412}, {INT64_C(1380575037843671000), 0x0003, 0x0034, 0}, {INT64_C(1380575037843671000), 0x0003, 0x0030, 480}, {INT64_C(1380575037843671000), 0x0003, 0x0031, 256}, {INT64_C(1380575037843671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037843671000), 0x0003, 0x0035, 3680}, {INT64_C(1380575037843671000), 0x0003, 0x0036, 4238}, {INT64_C(1380575037843671000), 0x0003, 0x0034, 0}, {INT64_C(1380575037843671000), 0x0003, 0x0030, 320}, {INT64_C(1380575037843671000), 0x0003, 0x0031, 256}, {INT64_C(1380575037843671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037843671000), 0x0000, 0x0000, 0}, {INT64_C(1380575037861671000), 0x0003, 0x0000, 5331}, {INT64_C(1380575037861671000), 0x0003, 0x0035, 5331}, {INT64_C(1380575037861671000), 0x0003, 0x0036, 5920}, {INT64_C(1380575037861671000), 0x0003, 0x0034, 1}, {INT64_C(1380575037861671000), 0x0003, 0x0030, 256}, {INT64_C(1380575037861671000), 0x0003, 0x0031, 160}, {INT64_C(1380575037861671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037861671000), 0x0003, 0x0035, 4032}, {INT64_C(1380575037861671000), 0x0003, 0x0036, 5394}, {INT64_C(1380575037861671000), 0x0003, 0x0034, 0}, {INT64_C(1380575037861671000), 0x0003, 0x0030, 480}, {INT64_C(1380575037861671000), 0x0003, 0x0031, 384}, {INT64_C(1380575037861671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037861671000), 0x0003, 0x0035, 3626}, {INT64_C(1380575037861671000), 0x0003, 0x0036, 4133}, {INT64_C(1380575037861671000), 0x0003, 0x0034, 0}, {INT64_C(1380575037861671000), 0x0003, 0x0030, 480}, {INT64_C(1380575037861671000), 0x0003, 0x0031, 256}, {INT64_C(1380575037861671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037861671000), 0x0000, 0x0000, 0}, {INT64_C(1380575037881670000), 0x0003, 0x0000, 5314}, {INT64_C(1380575037881670000), 0x0003, 0x0035, 5314}, {INT64_C(1380575037881670000), 0x0003, 0x0036, 5920}, {INT64_C(1380575037881670000), 0x0003, 0x0034, 1}, {INT64_C(1380575037881670000), 0x0003, 0x0030, 256}, {INT64_C(1380575037881670000), 0x0003, 0x0031, 160}, {INT64_C(1380575037881670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037881670000), 0x0003, 0x0035, 4019}, {INT64_C(1380575037881670000), 0x0003, 0x0036, 5377}, {INT64_C(1380575037881670000), 0x0003, 0x0034, 0}, {INT64_C(1380575037881670000), 0x0003, 0x0030, 480}, {INT64_C(1380575037881670000), 0x0003, 0x0031, 384}, {INT64_C(1380575037881670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037881670000), 0x0003, 0x0035, 3502}, {INT64_C(1380575037881670000), 0x0003, 0x0036, 4008}, {INT64_C(1380575037881670000), 0x0003, 0x0034, 0}, {INT64_C(1380575037881670000), 0x0003, 0x0030, 320}, {INT64_C(1380575037881670000), 0x0003, 0x0031, 256}, {INT64_C(1380575037881670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037881670000), 0x0000, 0x0000, 0}, {INT64_C(1380575037899668000), 0x0003, 0x0000, 5263}, {INT64_C(1380575037899668000), 0x0003, 0x0035, 5263}, {INT64_C(1380575037899668000), 0x0003, 0x0036, 5920}, {INT64_C(1380575037899668000), 0x0003, 0x0034, 1}, {INT64_C(1380575037899668000), 0x0003, 0x0030, 256}, {INT64_C(1380575037899668000), 0x0003, 0x0031, 160}, {INT64_C(1380575037899668000), 0x0000, 0x0002, 0}, {INT64_C(1380575037899668000), 0x0003, 0x0035, 3897}, {INT64_C(1380575037899668000), 0x0003, 0x0036, 5275}, {INT64_C(1380575037899668000), 0x0003, 0x0034, 0}, {INT64_C(1380575037899668000), 0x0003, 0x0030, 480}, {INT64_C(1380575037899668000), 0x0003, 0x0031, 256}, {INT64_C(1380575037899668000), 0x0000, 0x0002, 0}, {INT64_C(1380575037899668000), 0x0000, 0x0000, 0}, {INT64_C(1380575037917670000), 0x0003, 0x0000, 5032}, {INT64_C(1380575037917670000), 0x0003, 0x0001, 5760}, {INT64_C(1380575037917670000), 0x0003, 0x0035, 5032}, {INT64_C(1380575037917670000), 0x0003, 0x0036, 5760}, {INT64_C(1380575037917670000), 0x0003, 0x0034, 1}, {INT64_C(1380575037917670000), 0x0003, 0x0030, 256}, {INT64_C(1380575037917670000), 0x0003, 0x0031, 160}, {INT64_C(1380575037917670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037917670000), 0x0003, 0x0035, 3698}, {INT64_C(1380575037917670000), 0x0003, 0x0036, 5078}, {INT64_C(1380575037917670000), 0x0003, 0x0034, 0}, {INT64_C(1380575037917670000), 0x0003, 0x0030, 480}, {INT64_C(1380575037917670000), 0x0003, 0x0031, 384}, {INT64_C(1380575037917670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037917670000), 0x0003, 0x0035, 3328}, {INT64_C(1380575037917670000), 0x0003, 0x0036, 3699}, {INT64_C(1380575037917670000), 0x0003, 0x0034, 0}, {INT64_C(1380575037917670000), 0x0003, 0x0030, 320}, {INT64_C(1380575037917670000), 0x0003, 0x0031, 128}, {INT64_C(1380575037917670000), 0x0000, 0x0002, 0}, {INT64_C(1380575037917670000), 0x0000, 0x0000, 0}, {INT64_C(1380575037937671000), 0x0003, 0x0000, 4875}, {INT64_C(1380575037937671000), 0x0003, 0x0001, 5551}, {INT64_C(1380575037937671000), 0x0003, 0x0035, 4875}, {INT64_C(1380575037937671000), 0x0003, 0x0036, 5551}, {INT64_C(1380575037937671000), 0x0003, 0x0034, 0}, {INT64_C(1380575037937671000), 0x0003, 0x0030, 320}, {INT64_C(1380575037937671000), 0x0003, 0x0031, 256}, {INT64_C(1380575037937671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037937671000), 0x0003, 0x0035, 3504}, {INT64_C(1380575037937671000), 0x0003, 0x0036, 4892}, {INT64_C(1380575037937671000), 0x0003, 0x0034, 0}, {INT64_C(1380575037937671000), 0x0003, 0x0030, 480}, {INT64_C(1380575037937671000), 0x0003, 0x0031, 384}, {INT64_C(1380575037937671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037937671000), 0x0003, 0x0035, 3157}, {INT64_C(1380575037937671000), 0x0003, 0x0036, 3520}, {INT64_C(1380575037937671000), 0x0003, 0x0034, 1}, {INT64_C(1380575037937671000), 0x0003, 0x0030, 256}, {INT64_C(1380575037937671000), 0x0003, 0x0031, 160}, {INT64_C(1380575037937671000), 0x0000, 0x0002, 0}, {INT64_C(1380575037937671000), 0x0000, 0x0000, 0}, {INT64_C(1380575037955668000), 0x0003, 0x0000, 4686}, {INT64_C(1380575037955668000), 0x0003, 0x0001, 5448}, {INT64_C(1380575037955668000), 0x0003, 0x0035, 4686}, {INT64_C(1380575037955668000), 0x0003, 0x0036, 5448}, {INT64_C(1380575037955668000), 0x0003, 0x0034, 0}, {INT64_C(1380575037955668000), 0x0003, 0x0030, 320}, {INT64_C(1380575037955668000), 0x0003, 0x0031, 256}, {INT64_C(1380575037955668000), 0x0000, 0x0002, 0}, {INT64_C(1380575037955668000), 0x0003, 0x0035, 3338}, {INT64_C(1380575037955668000), 0x0003, 0x0036, 4684}, {INT64_C(1380575037955668000), 0x0003, 0x0034, 1}, {INT64_C(1380575037955668000), 0x0003, 0x0030, 384}, {INT64_C(1380575037955668000), 0x0003, 0x0031, 320}, {INT64_C(1380575037955668000), 0x0000, 0x0002, 0}, {INT64_C(1380575037955668000), 0x0000, 0x0000, 0}, {INT64_C(1380575037973669000), 0x0003, 0x0000, 4522}, {INT64_C(1380575037973669000), 0x0003, 0x0001, 5238}, {INT64_C(1380575037973669000), 0x0003, 0x0035, 4522}, {INT64_C(1380575037973669000), 0x0003, 0x0036, 5238}, {INT64_C(1380575037973669000), 0x0003, 0x0034, 0}, {INT64_C(1380575037973669000), 0x0003, 0x0030, 480}, {INT64_C(1380575037973669000), 0x0003, 0x0031, 256}, {INT64_C(1380575037973669000), 0x0000, 0x0002, 0}, {INT64_C(1380575037973669000), 0x0003, 0x0035, 3227}, {INT64_C(1380575037973669000), 0x0003, 0x0036, 4462}, {INT64_C(1380575037973669000), 0x0003, 0x0034, 0}, {INT64_C(1380575037973669000), 0x0003, 0x0030, 480}, {INT64_C(1380575037973669000), 0x0003, 0x0031, 384}, {INT64_C(1380575037973669000), 0x0000, 0x0002, 0}, {INT64_C(1380575037973669000), 0x0000, 0x0000, 0}, {INT64_C(1380575037993669000), 0x0003, 0x0000, 4436}, {INT64_C(1380575037993669000), 0x0003, 0x0001, 5133}, {INT64_C(1380575037993669000), 0x0003, 0x0035, 4436}, {INT64_C(1380575037993669000), 0x0003, 0x0036, 5133}, {INT64_C(1380575037993669000), 0x0003, 0x0034, 0}, {INT64_C(1380575037993669000), 0x0003, 0x0030, 480}, {INT64_C(1380575037993669000), 0x0003, 0x0031, 256}, {INT64_C(1380575037993669000), 0x0000, 0x0002, 0}, {INT64_C(1380575037993669000), 0x0003, 0x0035, 3129}, {INT64_C(1380575037993669000), 0x0003, 0x0036, 4274}, {INT64_C(1380575037993669000), 0x0003, 0x0034, 0}, {INT64_C(1380575037993669000), 0x0003, 0x0030, 480}, {INT64_C(1380575037993669000), 0x0003, 0x0031, 256}, {INT64_C(1380575037993669000), 0x0000, 0x0002, 0}, {INT64_C(1380575037993669000), 0x0000, 0x0000, 0}, {INT64_C(1380575038011670000), 0x0003, 0x0000, 4387}, {INT64_C(1380575038011670000), 0x0003, 0x0001, 4960}, {INT64_C(1380575038011670000), 0x0003, 0x0035, 4387}, {INT64_C(1380575038011670000), 0x0003, 0x0036, 4960}, {INT64_C(1380575038011670000), 0x0003, 0x0034, 1}, {INT64_C(1380575038011670000), 0x0003, 0x0030, 256}, {INT64_C(1380575038011670000), 0x0003, 0x0031, 160}, {INT64_C(1380575038011670000), 0x0000, 0x0002, 0}, {INT64_C(1380575038011670000), 0x0003, 0x0035, 3111}, {INT64_C(1380575038011670000), 0x0003, 0x0036, 4208}, {INT64_C(1380575038011670000), 0x0003, 0x0034, 0}, {INT64_C(1380575038011670000), 0x0003, 0x0030, 480}, {INT64_C(1380575038011670000), 0x0003, 0x0031, 384}, {INT64_C(1380575038011670000), 0x0000, 0x0002, 0}, {INT64_C(1380575038011670000), 0x0000, 0x0000, 0}, {INT64_C(1380575038029668000), 0x0003, 0x0000, 4396}, {INT64_C(1380575038029668000), 0x0003, 0x0001, 4912}, {INT64_C(1380575038029668000), 0x0003, 0x0035, 4396}, {INT64_C(1380575038029668000), 0x0003, 0x0036, 4912}, {INT64_C(1380575038029668000), 0x0003, 0x0034, 0}, {INT64_C(1380575038029668000), 0x0003, 0x0030, 320}, {INT64_C(1380575038029668000), 0x0003, 0x0031, 256}, {INT64_C(1380575038029668000), 0x0000, 0x0002, 0}, {INT64_C(1380575038029668000), 0x0003, 0x0035, 3124}, {INT64_C(1380575038029668000), 0x0003, 0x0036, 4147}, {INT64_C(1380575038029668000), 0x0003, 0x0034, 0}, {INT64_C(1380575038029668000), 0x0003, 0x0030, 480}, {INT64_C(1380575038029668000), 0x0003, 0x0031, 384}, {INT64_C(1380575038029668000), 0x0000, 0x0002, 0}, {INT64_C(1380575038029668000), 0x0000, 0x0000, 0}, {INT64_C(1380575038049668000), 0x0003, 0x0000, 4418}, {INT64_C(1380575038049668000), 0x0003, 0x0001, 4782}, {INT64_C(1380575038049668000), 0x0003, 0x0035, 4418}, {INT64_C(1380575038049668000), 0x0003, 0x0036, 4782}, {INT64_C(1380575038049668000), 0x0003, 0x0034, 0}, {INT64_C(1380575038049668000), 0x0003, 0x0030, 480}, {INT64_C(1380575038049668000), 0x0003, 0x0031, 256}, {INT64_C(1380575038049668000), 0x0000, 0x0002, 0}, {INT64_C(1380575038049668000), 0x0003, 0x0035, 3201}, {INT64_C(1380575038049668000), 0x0003, 0x0036, 4123}, {INT64_C(1380575038049668000), 0x0003, 0x0034, 0}, {INT64_C(1380575038049668000), 0x0003, 0x0030, 480}, {INT64_C(1380575038049668000), 0x0003, 0x0031, 384}, {INT64_C(1380575038049668000), 0x0000, 0x0002, 0}, {INT64_C(1380575038049668000), 0x0000, 0x0000, 0}, {INT64_C(1380575038067667000), 0x0003, 0x0000, 4531}, {INT64_C(1380575038067667000), 0x0003, 0x0001, 4640}, {INT64_C(1380575038067667000), 0x0003, 0x0035, 4531}, {INT64_C(1380575038067667000), 0x0003, 0x0036, 4640}, {INT64_C(1380575038067667000), 0x0003, 0x0034, 1}, {INT64_C(1380575038067667000), 0x0003, 0x0030, 256}, {INT64_C(1380575038067667000), 0x0003, 0x0031, 160}, {INT64_C(1380575038067667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038067667000), 0x0003, 0x0035, 3319}, {INT64_C(1380575038067667000), 0x0003, 0x0036, 4130}, {INT64_C(1380575038067667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038067667000), 0x0003, 0x0030, 480}, {INT64_C(1380575038067667000), 0x0003, 0x0031, 256}, {INT64_C(1380575038067667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038067667000), 0x0000, 0x0000, 0}, {INT64_C(1380575038085668000), 0x0003, 0x0000, 4608}, {INT64_C(1380575038085668000), 0x0003, 0x0001, 4578}, {INT64_C(1380575038085668000), 0x0003, 0x0035, 4608}, {INT64_C(1380575038085668000), 0x0003, 0x0036, 4578}, {INT64_C(1380575038085668000), 0x0003, 0x0034, 0}, {INT64_C(1380575038085668000), 0x0003, 0x0030, 320}, {INT64_C(1380575038085668000), 0x0003, 0x0031, 128}, {INT64_C(1380575038085668000), 0x0000, 0x0002, 0}, {INT64_C(1380575038085668000), 0x0003, 0x0035, 3456}, {INT64_C(1380575038085668000), 0x0003, 0x0036, 4205}, {INT64_C(1380575038085668000), 0x0003, 0x0034, 0}, {INT64_C(1380575038085668000), 0x0003, 0x0030, 480}, {INT64_C(1380575038085668000), 0x0003, 0x0031, 128}, {INT64_C(1380575038085668000), 0x0000, 0x0002, 0}, {INT64_C(1380575038085668000), 0x0000, 0x0000, 0}, {INT64_C(1380575038105667000), 0x0003, 0x0000, 3746}, {INT64_C(1380575038105667000), 0x0003, 0x0001, 4288}, {INT64_C(1380575038105667000), 0x0003, 0x0035, 3746}, {INT64_C(1380575038105667000), 0x0003, 0x0036, 4288}, {INT64_C(1380575038105667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038105667000), 0x0003, 0x0030, 480}, {INT64_C(1380575038105667000), 0x0003, 0x0031, 384}, {INT64_C(1380575038105667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038105667000), 0x0000, 0x0000, 0}, {INT64_C(1380575038123667000), 0x0003, 0x0000, 4014}, {INT64_C(1380575038123667000), 0x0003, 0x0001, 4433}, {INT64_C(1380575038123667000), 0x0003, 0x0035, 4014}, {INT64_C(1380575038123667000), 0x0003, 0x0036, 4433}, {INT64_C(1380575038123667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038123667000), 0x0003, 0x0030, 480}, {INT64_C(1380575038123667000), 0x0003, 0x0031, 384}, {INT64_C(1380575038123667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038123667000), 0x0000, 0x0000, 0}, {INT64_C(1380575038143666000), 0x0003, 0x0000, 4207}, {INT64_C(1380575038143666000), 0x0003, 0x0001, 4612}, {INT64_C(1380575038143666000), 0x0003, 0x0035, 4207}, {INT64_C(1380575038143666000), 0x0003, 0x0036, 4612}, {INT64_C(1380575038143666000), 0x0003, 0x0034, 0}, {INT64_C(1380575038143666000), 0x0003, 0x0030, 480}, {INT64_C(1380575038143666000), 0x0003, 0x0031, 256}, {INT64_C(1380575038143666000), 0x0000, 0x0002, 0}, {INT64_C(1380575038143666000), 0x0000, 0x0000, 0}, {INT64_C(1380575038161599000), 0x0003, 0x0000, 4448}, {INT64_C(1380575038161599000), 0x0003, 0x0001, 4790}, {INT64_C(1380575038161599000), 0x0003, 0x0035, 4448}, {INT64_C(1380575038161599000), 0x0003, 0x0036, 4790}, {INT64_C(1380575038161599000), 0x0003, 0x0034, 0}, {INT64_C(1380575038161599000), 0x0003, 0x0030, 640}, {INT64_C(1380575038161599000), 0x0003, 0x0031, 256}, {INT64_C(1380575038161599000), 0x0000, 0x0002, 0}, {INT64_C(1380575038161599000), 0x0003, 0x0035, 4172}, {INT64_C(1380575038161599000), 0x0003, 0x0036, 3520}, {INT64_C(1380575038161599000), 0x0003, 0x0034, 1}, {INT64_C(1380575038161599000), 0x0003, 0x0030, 256}, {INT64_C(1380575038161599000), 0x0003, 0x0031, 160}, {INT64_C(1380575038161599000), 0x0000, 0x0002, 0}, {INT64_C(1380575038161599000), 0x0000, 0x0000, 0}, {INT64_C(1380575038179665000), 0x0003, 0x0000, 4681}, {INT64_C(1380575038179665000), 0x0003, 0x0001, 5011}, {INT64_C(1380575038179665000), 0x0003, 0x0035, 4681}, {INT64_C(1380575038179665000), 0x0003, 0x0036, 5011}, {INT64_C(1380575038179665000), 0x0003, 0x0034, 0}, {INT64_C(1380575038179665000), 0x0003, 0x0030, 320}, {INT64_C(1380575038179665000), 0x0003, 0x0031, 256}, {INT64_C(1380575038179665000), 0x0000, 0x0002, 0}, {INT64_C(1380575038179665000), 0x0000, 0x0000, 0}, {INT64_C(1380575038199670000), 0x0003, 0x0000, 4842}, {INT64_C(1380575038199670000), 0x0003, 0x0001, 5221}, {INT64_C(1380575038199670000), 0x0003, 0x0035, 4842}, {INT64_C(1380575038199670000), 0x0003, 0x0036, 5221}, {INT64_C(1380575038199670000), 0x0003, 0x0034, 1}, {INT64_C(1380575038199670000), 0x0003, 0x0030, 384}, {INT64_C(1380575038199670000), 0x0003, 0x0031, 320}, {INT64_C(1380575038199670000), 0x0000, 0x0002, 0}, {INT64_C(1380575038199670000), 0x0003, 0x0035, 5888}, {INT64_C(1380575038199670000), 0x0003, 0x0036, 5138}, {INT64_C(1380575038199670000), 0x0003, 0x0034, 0}, {INT64_C(1380575038199670000), 0x0003, 0x0030, 320}, {INT64_C(1380575038199670000), 0x0003, 0x0031, 128}, {INT64_C(1380575038199670000), 0x0000, 0x0002, 0}, {INT64_C(1380575038199670000), 0x0003, 0x0035, 4420}, {INT64_C(1380575038199670000), 0x0003, 0x0036, 4095}, {INT64_C(1380575038199670000), 0x0003, 0x0034, 0}, {INT64_C(1380575038199670000), 0x0003, 0x0030, 320}, {INT64_C(1380575038199670000), 0x0003, 0x0031, 256}, {INT64_C(1380575038199670000), 0x0000, 0x0002, 0}, {INT64_C(1380575038199670000), 0x0000, 0x0000, 0}, {INT64_C(1380575038217671000), 0x0003, 0x0000, 4942}, {INT64_C(1380575038217671000), 0x0003, 0x0001, 5391}, {INT64_C(1380575038217671000), 0x0003, 0x0035, 4942}, {INT64_C(1380575038217671000), 0x0003, 0x0036, 5391}, {INT64_C(1380575038217671000), 0x0003, 0x0034, 0}, {INT64_C(1380575038217671000), 0x0003, 0x0030, 480}, {INT64_C(1380575038217671000), 0x0003, 0x0031, 256}, {INT64_C(1380575038217671000), 0x0000, 0x0002, 0}, {INT64_C(1380575038217671000), 0x0003, 0x0035, 6016}, {INT64_C(1380575038217671000), 0x0003, 0x0036, 5294}, {INT64_C(1380575038217671000), 0x0003, 0x0034, 0}, {INT64_C(1380575038217671000), 0x0003, 0x0030, 480}, {INT64_C(1380575038217671000), 0x0003, 0x0031, 128}, {INT64_C(1380575038217671000), 0x0000, 0x0002, 0}, {INT64_C(1380575038217671000), 0x0003, 0x0035, 4488}, {INT64_C(1380575038217671000), 0x0003, 0x0036, 4265}, {INT64_C(1380575038217671000), 0x0003, 0x0034, 1}, {INT64_C(1380575038217671000), 0x0003, 0x0030, 384}, {INT64_C(1380575038217671000), 0x0003, 0x0031, 320}, {INT64_C(1380575038217671000), 0x0000, 0x0002, 0}, {INT64_C(1380575038217671000), 0x0000, 0x0000, 0}, {INT64_C(1380575038235668000), 0x0003, 0x0000, 5007}, {INT64_C(1380575038235668000), 0x0003, 0x0001, 5547}, {INT64_C(1380575038235668000), 0x0003, 0x0035, 5007}, {INT64_C(1380575038235668000), 0x0003, 0x0036, 5547}, {INT64_C(1380575038235668000), 0x0003, 0x0034, 1}, {INT64_C(1380575038235668000), 0x0003, 0x0030, 384}, {INT64_C(1380575038235668000), 0x0003, 0x0031, 320}, {INT64_C(1380575038235668000), 0x0000, 0x0002, 0}, {INT64_C(1380575038235668000), 0x0003, 0x0035, 6016}, {INT64_C(1380575038235668000), 0x0003, 0x0036, 5376}, {INT64_C(1380575038235668000), 0x0003, 0x0034, 0}, {INT64_C(1380575038235668000), 0x0003, 0x0030, 320}, {INT64_C(1380575038235668000), 0x0003, 0x0031, 128}, {INT64_C(1380575038235668000), 0x0000, 0x0002, 0}, {INT64_C(1380575038235668000), 0x0003, 0x0035, 4489}, {INT64_C(1380575038235668000), 0x0003, 0x0036, 4396}, {INT64_C(1380575038235668000), 0x0003, 0x0034, 0}, {INT64_C(1380575038235668000), 0x0003, 0x0030, 480}, {INT64_C(1380575038235668000), 0x0003, 0x0031, 384}, {INT64_C(1380575038235668000), 0x0000, 0x0002, 0}, {INT64_C(1380575038235668000), 0x0000, 0x0000, 0}, {INT64_C(1380575038255667000), 0x0003, 0x0000, 4968}, {INT64_C(1380575038255667000), 0x0003, 0x0001, 5594}, {INT64_C(1380575038255667000), 0x0003, 0x0035, 4968}, {INT64_C(1380575038255667000), 0x0003, 0x0036, 5594}, {INT64_C(1380575038255667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038255667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038255667000), 0x0003, 0x0031, 256}, {INT64_C(1380575038255667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038255667000), 0x0003, 0x0035, 6016}, {INT64_C(1380575038255667000), 0x0003, 0x0036, 5466}, {INT64_C(1380575038255667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038255667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038255667000), 0x0003, 0x0031, 128}, {INT64_C(1380575038255667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038255667000), 0x0003, 0x0035, 4439}, {INT64_C(1380575038255667000), 0x0003, 0x0036, 4445}, {INT64_C(1380575038255667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038255667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038255667000), 0x0003, 0x0031, 256}, {INT64_C(1380575038255667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038255667000), 0x0000, 0x0000, 0}, {INT64_C(1380575038273669000), 0x0003, 0x0000, 4910}, {INT64_C(1380575038273669000), 0x0003, 0x0001, 5693}, {INT64_C(1380575038273669000), 0x0003, 0x0035, 4910}, {INT64_C(1380575038273669000), 0x0003, 0x0036, 5693}, {INT64_C(1380575038273669000), 0x0003, 0x0034, 0}, {INT64_C(1380575038273669000), 0x0003, 0x0030, 320}, {INT64_C(1380575038273669000), 0x0003, 0x0031, 256}, {INT64_C(1380575038273669000), 0x0000, 0x0002, 0}, {INT64_C(1380575038273669000), 0x0003, 0x0035, 6016}, {INT64_C(1380575038273669000), 0x0003, 0x0036, 5553}, {INT64_C(1380575038273669000), 0x0003, 0x0034, 0}, {INT64_C(1380575038273669000), 0x0003, 0x0030, 320}, {INT64_C(1380575038273669000), 0x0003, 0x0031, 128}, {INT64_C(1380575038273669000), 0x0000, 0x0002, 0}, {INT64_C(1380575038273669000), 0x0003, 0x0035, 4355}, {INT64_C(1380575038273669000), 0x0003, 0x0036, 4539}, {INT64_C(1380575038273669000), 0x0003, 0x0034, 0}, {INT64_C(1380575038273669000), 0x0003, 0x0030, 480}, {INT64_C(1380575038273669000), 0x0003, 0x0031, 256}, {INT64_C(1380575038273669000), 0x0000, 0x0002, 0}, {INT64_C(1380575038273669000), 0x0000, 0x0000, 0}, {INT64_C(1380575038291667000), 0x0003, 0x0000, 4776}, {INT64_C(1380575038291667000), 0x0003, 0x0001, 5733}, {INT64_C(1380575038291667000), 0x0003, 0x0035, 4776}, {INT64_C(1380575038291667000), 0x0003, 0x0036, 5733}, {INT64_C(1380575038291667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038291667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038291667000), 0x0003, 0x0031, 256}, {INT64_C(1380575038291667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038291667000), 0x0003, 0x0035, 6016}, {INT64_C(1380575038291667000), 0x0003, 0x0036, 5632}, {INT64_C(1380575038291667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038291667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038291667000), 0x0003, 0x0031, 128}, {INT64_C(1380575038291667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038291667000), 0x0003, 0x0035, 4196}, {INT64_C(1380575038291667000), 0x0003, 0x0036, 4570}, {INT64_C(1380575038291667000), 0x0003, 0x0034, 1}, {INT64_C(1380575038291667000), 0x0003, 0x0030, 384}, {INT64_C(1380575038291667000), 0x0003, 0x0031, 320}, {INT64_C(1380575038291667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038291667000), 0x0000, 0x0000, 0}, {INT64_C(1380575038311667000), 0x0003, 0x0000, 4528}, {INT64_C(1380575038311667000), 0x0003, 0x0001, 5737}, {INT64_C(1380575038311667000), 0x0003, 0x0035, 4528}, {INT64_C(1380575038311667000), 0x0003, 0x0036, 5737}, {INT64_C(1380575038311667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038311667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038311667000), 0x0003, 0x0031, 256}, {INT64_C(1380575038311667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038311667000), 0x0003, 0x0035, 5825}, {INT64_C(1380575038311667000), 0x0003, 0x0036, 5720}, {INT64_C(1380575038311667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038311667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038311667000), 0x0003, 0x0031, 256}, {INT64_C(1380575038311667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038311667000), 0x0003, 0x0035, 4013}, {INT64_C(1380575038311667000), 0x0003, 0x0036, 4614}, {INT64_C(1380575038311667000), 0x0003, 0x0034, 1}, {INT64_C(1380575038311667000), 0x0003, 0x0030, 384}, {INT64_C(1380575038311667000), 0x0003, 0x0031, 320}, {INT64_C(1380575038311667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038311667000), 0x0000, 0x0000, 0}, {INT64_C(1380575038329664000), 0x0003, 0x0000, 4279}, {INT64_C(1380575038329664000), 0x0003, 0x0001, 5821}, {INT64_C(1380575038329664000), 0x0003, 0x0035, 4279}, {INT64_C(1380575038329664000), 0x0003, 0x0036, 5821}, {INT64_C(1380575038329664000), 0x0003, 0x0034, 0}, {INT64_C(1380575038329664000), 0x0003, 0x0030, 320}, {INT64_C(1380575038329664000), 0x0003, 0x0031, 256}, {INT64_C(1380575038329664000), 0x0000, 0x0002, 0}, {INT64_C(1380575038329664000), 0x0003, 0x0035, 5632}, {INT64_C(1380575038329664000), 0x0003, 0x0036, 5804}, {INT64_C(1380575038329664000), 0x0003, 0x0034, 0}, {INT64_C(1380575038329664000), 0x0003, 0x0030, 320}, {INT64_C(1380575038329664000), 0x0003, 0x0031, 128}, {INT64_C(1380575038329664000), 0x0000, 0x0002, 0}, {INT64_C(1380575038329664000), 0x0003, 0x0035, 3725}, {INT64_C(1380575038329664000), 0x0003, 0x0036, 4640}, {INT64_C(1380575038329664000), 0x0003, 0x0034, 1}, {INT64_C(1380575038329664000), 0x0003, 0x0030, 256}, {INT64_C(1380575038329664000), 0x0003, 0x0031, 160}, {INT64_C(1380575038329664000), 0x0000, 0x0002, 0}, {INT64_C(1380575038329664000), 0x0000, 0x0000, 0}, {INT64_C(1380575038349667000), 0x0003, 0x0000, 4005}, {INT64_C(1380575038349667000), 0x0003, 0x0001, 5844}, {INT64_C(1380575038349667000), 0x0003, 0x0035, 4005}, {INT64_C(1380575038349667000), 0x0003, 0x0036, 5844}, {INT64_C(1380575038349667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038349667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038349667000), 0x0003, 0x0031, 256}, {INT64_C(1380575038349667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038349667000), 0x0003, 0x0035, 5376}, {INT64_C(1380575038349667000), 0x0003, 0x0036, 5888}, {INT64_C(1380575038349667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038349667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038349667000), 0x0003, 0x0031, 128}, {INT64_C(1380575038349667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038349667000), 0x0003, 0x0035, 3456}, {INT64_C(1380575038349667000), 0x0003, 0x0036, 4658}, {INT64_C(1380575038349667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038349667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038349667000), 0x0003, 0x0031, 128}, {INT64_C(1380575038349667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038349667000), 0x0000, 0x0000, 0}, {INT64_C(1380575038367661000), 0x0003, 0x0000, 3748}, {INT64_C(1380575038367661000), 0x0003, 0x0001, 5845}, {INT64_C(1380575038367661000), 0x0003, 0x0035, 3748}, {INT64_C(1380575038367661000), 0x0003, 0x0036, 5845}, {INT64_C(1380575038367661000), 0x0003, 0x0034, 0}, {INT64_C(1380575038367661000), 0x0003, 0x0030, 480}, {INT64_C(1380575038367661000), 0x0003, 0x0031, 256}, {INT64_C(1380575038367661000), 0x0000, 0x0002, 0}, {INT64_C(1380575038367661000), 0x0003, 0x0035, 5036}, {INT64_C(1380575038367661000), 0x0003, 0x0036, 5888}, {INT64_C(1380575038367661000), 0x0003, 0x0034, 0}, {INT64_C(1380575038367661000), 0x0003, 0x0030, 320}, {INT64_C(1380575038367661000), 0x0003, 0x0031, 256}, {INT64_C(1380575038367661000), 0x0000, 0x0002, 0}, {INT64_C(1380575038367661000), 0x0003, 0x0035, 3204}, {INT64_C(1380575038367661000), 0x0003, 0x0036, 4640}, {INT64_C(1380575038367661000), 0x0003, 0x0034, 1}, {INT64_C(1380575038367661000), 0x0003, 0x0030, 256}, {INT64_C(1380575038367661000), 0x0003, 0x0031, 160}, {INT64_C(1380575038367661000), 0x0000, 0x0002, 0}, {INT64_C(1380575038367661000), 0x0000, 0x0000, 0}, {INT64_C(1380575038385667000), 0x0003, 0x0000, 3470}, {INT64_C(1380575038385667000), 0x0003, 0x0001, 5830}, {INT64_C(1380575038385667000), 0x0003, 0x0035, 3470}, {INT64_C(1380575038385667000), 0x0003, 0x0036, 5830}, {INT64_C(1380575038385667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038385667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038385667000), 0x0003, 0x0031, 256}, {INT64_C(1380575038385667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038385667000), 0x0003, 0x0035, 4785}, {INT64_C(1380575038385667000), 0x0003, 0x0036, 5911}, {INT64_C(1380575038385667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038385667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038385667000), 0x0003, 0x0031, 256}, {INT64_C(1380575038385667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038385667000), 0x0003, 0x0035, 2944}, {INT64_C(1380575038385667000), 0x0003, 0x0036, 4537}, {INT64_C(1380575038385667000), 0x0003, 0x0034, 0}, {INT64_C(1380575038385667000), 0x0003, 0x0030, 320}, {INT64_C(1380575038385667000), 0x0003, 0x0031, 128}, {INT64_C(1380575038385667000), 0x0000, 0x0002, 0}, {INT64_C(1380575038385667000), 0x0000, 0x0000, 0}, {INT64_C(1380575038405668000), 0x0003, 0x0000, 4481}, {INT64_C(1380575038405668000), 0x0003, 0x0001, 5915}, {INT64_C(1380575038405668000), 0x0003, 0x0035, 4481}, {INT64_C(1380575038405668000), 0x0003, 0x0036, 5915}, {INT64_C(1380575038405668000), 0x0003, 0x0034, 0}, {INT64_C(1380575038405668000), 0x0003, 0x0030, 320}, {INT64_C(1380575038405668000), 0x0003, 0x0031, 256}, {INT64_C(1380575038405668000), 0x0000, 0x0002, 0}, {INT64_C(1380575038405668000), 0x0003, 0x0035, 3193}, {INT64_C(1380575038405668000), 0x0003, 0x0036, 5705}, {INT64_C(1380575038405668000), 0x0003, 0x0034, 1}, {INT64_C(1380575038405668000), 0x0003, 0x0030, 384}, {INT64_C(1380575038405668000), 0x0003, 0x0031, 320}, {INT64_C(1380575038405668000), 0x0000, 0x0002, 0}, {INT64_C(1380575038405668000), 0x0003, 0x0035, 2688}, {INT64_C(1380575038405668000), 0x0003, 0x0036, 4479}, {INT64_C(1380575038405668000), 0x0003, 0x0034, 0}, {INT64_C(1380575038405668000), 0x0003, 0x0030, 320}, {INT64_C(1380575038405668000), 0x0003, 0x0031, 128}, {INT64_C(1380575038405668000), 0x0000, 0x0002, 0}, {INT64_C(1380575038405668000), 0x0000, 0x0000, 0}, {INT64_C(1380575038423665000), 0x0003, 0x0000, 2944}, {INT64_C(1380575038423665000), 0x0003, 0x0001, 5538}, {INT64_C(1380575038423665000), 0x0003, 0x0035, 2944}, {INT64_C(1380575038423665000), 0x0003, 0x0036, 5538}, {INT64_C(1380575038423665000), 0x0003, 0x0034, 0}, {INT64_C(1380575038423665000), 0x0003, 0x0030, 320}, {INT64_C(1380575038423665000), 0x0003, 0x0031, 128}, {INT64_C(1380575038423665000), 0x0000, 0x0002, 0}, {INT64_C(1380575038423665000), 0x0003, 0x0035, 2434}, {INT64_C(1380575038423665000), 0x0003, 0x0036, 4247}, {INT64_C(1380575038423665000), 0x0003, 0x0034, 0}, {INT64_C(1380575038423665000), 0x0003, 0x0030, 320}, {INT64_C(1380575038423665000), 0x0003, 0x0031, 256}, {INT64_C(1380575038423665000), 0x0000, 0x0002, 0}, {INT64_C(1380575038423665000), 0x0000, 0x0000, 0}, {INT64_C(1380575038441664000), 0x0003, 0x0000, 2738}, {INT64_C(1380575038441664000), 0x0003, 0x0001, 5357}, {INT64_C(1380575038441664000), 0x0003, 0x0035, 2738}, {INT64_C(1380575038441664000), 0x0003, 0x0036, 5357}, {INT64_C(1380575038441664000), 0x0003, 0x0034, 0}, {INT64_C(1380575038441664000), 0x0003, 0x0030, 320}, {INT64_C(1380575038441664000), 0x0003, 0x0031, 256}, {INT64_C(1380575038441664000), 0x0000, 0x0002, 0}, {INT64_C(1380575038441664000), 0x0003, 0x0035, 2304}, {INT64_C(1380575038441664000), 0x0003, 0x0036, 4084}, {INT64_C(1380575038441664000), 0x0003, 0x0034, 0}, {INT64_C(1380575038441664000), 0x0003, 0x0030, 320}, {INT64_C(1380575038441664000), 0x0003, 0x0031, 128}, {INT64_C(1380575038441664000), 0x0000, 0x0002, 0}, {INT64_C(1380575038441664000), 0x0000, 0x0000, 0}, {INT64_C(1380575038461666000), 0x0003, 0x0000, 3839}, {INT64_C(1380575038461666000), 0x0003, 0x0001, 5540}, {INT64_C(1380575038461666000), 0x0003, 0x0035, 3839}, {INT64_C(1380575038461666000), 0x0003, 0x0036, 5540}, {INT64_C(1380575038461666000), 0x0003, 0x0034, 0}, {INT64_C(1380575038461666000), 0x0003, 0x0030, 320}, {INT64_C(1380575038461666000), 0x0003, 0x0031, 256}, {INT64_C(1380575038461666000), 0x0000, 0x0002, 0}, {INT64_C(1380575038461666000), 0x0003, 0x0035, 2602}, {INT64_C(1380575038461666000), 0x0003, 0x0036, 5182}, {INT64_C(1380575038461666000), 0x0003, 0x0034, 0}, {INT64_C(1380575038461666000), 0x0003, 0x0030, 320}, {INT64_C(1380575038461666000), 0x0003, 0x0031, 256}, {INT64_C(1380575038461666000), 0x0000, 0x0002, 0}, {INT64_C(1380575038461666000), 0x0000, 0x0000, 0}, {INT64_C(1380575038479661000), 0x0003, 0x0000, 3720}, {INT64_C(1380575038479661000), 0x0003, 0x0001, 5344}, {INT64_C(1380575038479661000), 0x0003, 0x0035, 3720}, {INT64_C(1380575038479661000), 0x0003, 0x0036, 5344}, {INT64_C(1380575038479661000), 0x0003, 0x0034, 0}, {INT64_C(1380575038479661000), 0x0003, 0x0030, 320}, {INT64_C(1380575038479661000), 0x0003, 0x0031, 256}, {INT64_C(1380575038479661000), 0x0000, 0x0002, 0}, {INT64_C(1380575038479661000), 0x0003, 0x0035, 2523}, {INT64_C(1380575038479661000), 0x0003, 0x0036, 4960}, {INT64_C(1380575038479661000), 0x0003, 0x0034, 1}, {INT64_C(1380575038479661000), 0x0003, 0x0030, 256}, {INT64_C(1380575038479661000), 0x0003, 0x0031, 160}, {INT64_C(1380575038479661000), 0x0000, 0x0002, 0}, {INT64_C(1380575038479661000), 0x0000, 0x0000, 0}, {INT64_C(1380575038497666000), 0x0003, 0x0000, 3673}, {INT64_C(1380575038497666000), 0x0003, 0x0001, 5120}, {INT64_C(1380575038497666000), 0x0003, 0x0035, 3673}, {INT64_C(1380575038497666000), 0x0003, 0x0036, 5120}, {INT64_C(1380575038497666000), 0x0003, 0x0034, 1}, {INT64_C(1380575038497666000), 0x0003, 0x0030, 256}, {INT64_C(1380575038497666000), 0x0003, 0x0031, 160}, {INT64_C(1380575038497666000), 0x0000, 0x0002, 0}, {INT64_C(1380575038497666000), 0x0003, 0x0035, 2486}, {INT64_C(1380575038497666000), 0x0003, 0x0036, 4640}, {INT64_C(1380575038497666000), 0x0003, 0x0034, 1}, {INT64_C(1380575038497666000), 0x0003, 0x0030, 256}, {INT64_C(1380575038497666000), 0x0003, 0x0031, 160}, {INT64_C(1380575038497666000), 0x0000, 0x0002, 0}, {INT64_C(1380575038497666000), 0x0000, 0x0000, 0}, {INT64_C(1380575038517666000), 0x0003, 0x0000, 3674}, {INT64_C(1380575038517666000), 0x0003, 0x0001, 4754}, {INT64_C(1380575038517666000), 0x0003, 0x0035, 3674}, {INT64_C(1380575038517666000), 0x0003, 0x0036, 4754}, {INT64_C(1380575038517666000), 0x0003, 0x0034, 0}, {INT64_C(1380575038517666000), 0x0003, 0x0030, 320}, {INT64_C(1380575038517666000), 0x0003, 0x0031, 256}, {INT64_C(1380575038517666000), 0x0000, 0x0002, 0}, {INT64_C(1380575038517666000), 0x0003, 0x0035, 2526}, {INT64_C(1380575038517666000), 0x0003, 0x0036, 4210}, {INT64_C(1380575038517666000), 0x0003, 0x0034, 0}, {INT64_C(1380575038517666000), 0x0003, 0x0030, 480}, {INT64_C(1380575038517666000), 0x0003, 0x0031, 256}, {INT64_C(1380575038517666000), 0x0000, 0x0002, 0}, {INT64_C(1380575038517666000), 0x0000, 0x0000, 0}, {INT64_C(1380575038535665000), 0x0003, 0x0000, 3745}, {INT64_C(1380575038535665000), 0x0003, 0x0001, 4468}, {INT64_C(1380575038535665000), 0x0003, 0x0035, 3745}, {INT64_C(1380575038535665000), 0x0003, 0x0036, 4468}, {INT64_C(1380575038535665000), 0x0003, 0x0034, 0}, {INT64_C(1380575038535665000), 0x0003, 0x0030, 480}, {INT64_C(1380575038535665000), 0x0003, 0x0031, 256}, {INT64_C(1380575038535665000), 0x0000, 0x0002, 0}, {INT64_C(1380575038535665000), 0x0003, 0x0035, 2628}, {INT64_C(1380575038535665000), 0x0003, 0x0036, 4030}, {INT64_C(1380575038535665000), 0x0003, 0x0034, 0}, {INT64_C(1380575038535665000), 0x0003, 0x0030, 320}, {INT64_C(1380575038535665000), 0x0003, 0x0031, 256}, {INT64_C(1380575038535665000), 0x0000, 0x0002, 0}, {INT64_C(1380575038535665000), 0x0000, 0x0000, 0}, {INT64_C(1380575038553665000), 0x0003, 0x0000, 3843}, {INT64_C(1380575038553665000), 0x0003, 0x0001, 4262}, {INT64_C(1380575038553665000), 0x0003, 0x0035, 3843}, {INT64_C(1380575038553665000), 0x0003, 0x0036, 4262}, {INT64_C(1380575038553665000), 0x0003, 0x0034, 0}, {INT64_C(1380575038553665000), 0x0003, 0x0030, 480}, {INT64_C(1380575038553665000), 0x0003, 0x0031, 256}, {INT64_C(1380575038553665000), 0x0000, 0x0002, 0}, {INT64_C(1380575038553665000), 0x0003, 0x0035, 2770}, {INT64_C(1380575038553665000), 0x0003, 0x0036, 3875}, {INT64_C(1380575038553665000), 0x0003, 0x0034, 0}, {INT64_C(1380575038553665000), 0x0003, 0x0030, 320}, {INT64_C(1380575038553665000), 0x0003, 0x0031, 256}, {INT64_C(1380575038553665000), 0x0000, 0x0002, 0}, {INT64_C(1380575038553665000), 0x0000, 0x0000, 0}, {INT64_C(1380575038573662000), 0x0003, 0x0000, 3970}, {INT64_C(1380575038573662000), 0x0003, 0x0001, 4094}, {INT64_C(1380575038573662000), 0x0003, 0x0035, 3970}, {INT64_C(1380575038573662000), 0x0003, 0x0036, 4094}, {INT64_C(1380575038573662000), 0x0003, 0x0034, 1}, {INT64_C(1380575038573662000), 0x0003, 0x0030, 384}, {INT64_C(1380575038573662000), 0x0003, 0x0031, 320}, {INT64_C(1380575038573662000), 0x0000, 0x0002, 0}, {INT64_C(1380575038573662000), 0x0003, 0x0035, 2922}, {INT64_C(1380575038573662000), 0x0003, 0x0036, 3724}, {INT64_C(1380575038573662000), 0x0003, 0x0034, 1}, {INT64_C(1380575038573662000), 0x0003, 0x0030, 384}, {INT64_C(1380575038573662000), 0x0003, 0x0031, 320}, {INT64_C(1380575038573662000), 0x0000, 0x0002, 0}, {INT64_C(1380575038573662000), 0x0000, 0x0000, 0}, {INT64_C(1380575038591666000), 0x0003, 0x0000, 4091}, {INT64_C(1380575038591666000), 0x0003, 0x0001, 3970}, {INT64_C(1380575038591666000), 0x0003, 0x0035, 4091}, {INT64_C(1380575038591666000), 0x0003, 0x0036, 3970}, {INT64_C(1380575038591666000), 0x0003, 0x0034, 0}, {INT64_C(1380575038591666000), 0x0003, 0x0030, 640}, {INT64_C(1380575038591666000), 0x0003, 0x0031, 256}, {INT64_C(1380575038591666000), 0x0000, 0x0002, 0}, {INT64_C(1380575038591666000), 0x0003, 0x0035, 3072}, {INT64_C(1380575038591666000), 0x0003, 0x0036, 3602}, {INT64_C(1380575038591666000), 0x0003, 0x0034, 0}, {INT64_C(1380575038591666000), 0x0003, 0x0030, 480}, {INT64_C(1380575038591666000), 0x0003, 0x0031, 256}, {INT64_C(1380575038591666000), 0x0000, 0x0002, 0}, {INT64_C(1380575038591666000), 0x0000, 0x0000, 0}, {INT64_C(1380575038609665000), 0x0003, 0x0000, 4224}, {INT64_C(1380575038609665000), 0x0003, 0x0001, 3852}, {INT64_C(1380575038609665000), 0x0003, 0x0035, 4224}, {INT64_C(1380575038609665000), 0x0003, 0x0036, 3852}, {INT64_C(1380575038609665000), 0x0003, 0x0034, 0}, {INT64_C(1380575038609665000), 0x0003, 0x0030, 320}, {INT64_C(1380575038609665000), 0x0003, 0x0031, 128}, {INT64_C(1380575038609665000), 0x0000, 0x0002, 0}, {INT64_C(1380575038609665000), 0x0003, 0x0035, 3328}, {INT64_C(1380575038609665000), 0x0003, 0x0036, 3579}, {INT64_C(1380575038609665000), 0x0003, 0x0034, 0}, {INT64_C(1380575038609665000), 0x0003, 0x0030, 320}, {INT64_C(1380575038609665000), 0x0003, 0x0031, 128}, {INT64_C(1380575038609665000), 0x0000, 0x0002, 0}, {INT64_C(1380575038609665000), 0x0000, 0x0000, 0}, {INT64_C(1380575038629663000), 0x0003, 0x0000, 4576}, {INT64_C(1380575038629663000), 0x0003, 0x0001, 3842}, {INT64_C(1380575038629663000), 0x0003, 0x0035, 4576}, {INT64_C(1380575038629663000), 0x0003, 0x0036, 3842}, {INT64_C(1380575038629663000), 0x0003, 0x0034, 0}, {INT64_C(1380575038629663000), 0x0003, 0x0030, 320}, {INT64_C(1380575038629663000), 0x0003, 0x0031, 256}, {INT64_C(1380575038629663000), 0x0000, 0x0002, 0}, {INT64_C(1380575038629663000), 0x0000, 0x0000, 0}, {INT64_C(1380575038723663000), 0x0001, 0x014d, 0}, {INT64_C(1380575038723663000), 0x0001, 0x014a, 0}, {INT64_C(1380575038723663000), 0x0000, 0x0000, 0}, {INT64_C(1380575039065660000), 0x0003, 0x0000, 6227}, {INT64_C(1380575039065660000), 0x0003, 0x0001, 5508}, {INT64_C(1380575039065660000), 0x0003, 0x0035, 6227}, {INT64_C(1380575039065660000), 0x0003, 0x0036, 5508}, {INT64_C(1380575039065660000), 0x0003, 0x0034, 0}, {INT64_C(1380575039065660000), 0x0003, 0x0030, 480}, {INT64_C(1380575039065660000), 0x0003, 0x0031, 256}, {INT64_C(1380575039065660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039065660000), 0x0001, 0x014d, 1}, {INT64_C(1380575039065660000), 0x0001, 0x014a, 1}, {INT64_C(1380575039065660000), 0x0000, 0x0000, 0}, {INT64_C(1380575039079667000), 0x0003, 0x0000, 5410}, {INT64_C(1380575039079667000), 0x0003, 0x0001, 6080}, {INT64_C(1380575039079667000), 0x0003, 0x0035, 5410}, {INT64_C(1380575039079667000), 0x0003, 0x0036, 6080}, {INT64_C(1380575039079667000), 0x0003, 0x0034, 1}, {INT64_C(1380575039079667000), 0x0003, 0x0030, 256}, {INT64_C(1380575039079667000), 0x0003, 0x0031, 160}, {INT64_C(1380575039079667000), 0x0000, 0x0002, 0}, {INT64_C(1380575039079667000), 0x0003, 0x0035, 6226}, {INT64_C(1380575039079667000), 0x0003, 0x0036, 5427}, {INT64_C(1380575039079667000), 0x0003, 0x0034, 0}, {INT64_C(1380575039079667000), 0x0003, 0x0030, 480}, {INT64_C(1380575039079667000), 0x0003, 0x0031, 256}, {INT64_C(1380575039079667000), 0x0000, 0x0002, 0}, {INT64_C(1380575039079667000), 0x0003, 0x0035, 3742}, {INT64_C(1380575039079667000), 0x0003, 0x0036, 4576}, {INT64_C(1380575039079667000), 0x0003, 0x0034, 0}, {INT64_C(1380575039079667000), 0x0003, 0x0030, 320}, {INT64_C(1380575039079667000), 0x0003, 0x0031, 256}, {INT64_C(1380575039079667000), 0x0000, 0x0002, 0}, {INT64_C(1380575039079667000), 0x0003, 0x0035, 4358}, {INT64_C(1380575039079667000), 0x0003, 0x0036, 1920}, {INT64_C(1380575039079667000), 0x0003, 0x0034, 1}, {INT64_C(1380575039079667000), 0x0003, 0x0030, 384}, {INT64_C(1380575039079667000), 0x0003, 0x0031, 160}, {INT64_C(1380575039079667000), 0x0000, 0x0002, 0}, {INT64_C(1380575039079667000), 0x0000, 0x0000, 0}, {INT64_C(1380575039085662000), 0x0003, 0x0000, 5421}, {INT64_C(1380575039085662000), 0x0003, 0x0035, 5421}, {INT64_C(1380575039085662000), 0x0003, 0x0036, 6080}, {INT64_C(1380575039085662000), 0x0003, 0x0034, 1}, {INT64_C(1380575039085662000), 0x0003, 0x0030, 256}, {INT64_C(1380575039085662000), 0x0003, 0x0031, 160}, {INT64_C(1380575039085662000), 0x0000, 0x0002, 0}, {INT64_C(1380575039085662000), 0x0003, 0x0035, 4394}, {INT64_C(1380575039085662000), 0x0003, 0x0036, 5760}, {INT64_C(1380575039085662000), 0x0003, 0x0034, 1}, {INT64_C(1380575039085662000), 0x0003, 0x0030, 256}, {INT64_C(1380575039085662000), 0x0003, 0x0031, 160}, {INT64_C(1380575039085662000), 0x0000, 0x0002, 0}, {INT64_C(1380575039085662000), 0x0003, 0x0035, 6232}, {INT64_C(1380575039085662000), 0x0003, 0x0036, 5346}, {INT64_C(1380575039085662000), 0x0003, 0x0034, 0}, {INT64_C(1380575039085662000), 0x0003, 0x0030, 320}, {INT64_C(1380575039085662000), 0x0003, 0x0031, 256}, {INT64_C(1380575039085662000), 0x0000, 0x0002, 0}, {INT64_C(1380575039085662000), 0x0003, 0x0035, 3762}, {INT64_C(1380575039085662000), 0x0003, 0x0036, 4514}, {INT64_C(1380575039085662000), 0x0003, 0x0034, 0}, {INT64_C(1380575039085662000), 0x0003, 0x0030, 320}, {INT64_C(1380575039085662000), 0x0003, 0x0031, 256}, {INT64_C(1380575039085662000), 0x0000, 0x0002, 0}, {INT64_C(1380575039085662000), 0x0003, 0x0035, 4357}, {INT64_C(1380575039085662000), 0x0003, 0x0036, 1920}, {INT64_C(1380575039085662000), 0x0003, 0x0034, 1}, {INT64_C(1380575039085662000), 0x0003, 0x0030, 384}, {INT64_C(1380575039085662000), 0x0003, 0x0031, 160}, {INT64_C(1380575039085662000), 0x0000, 0x0002, 0}, {INT64_C(1380575039085662000), 0x0000, 0x0000, 0}, {INT64_C(1380575039097667000), 0x0003, 0x0000, 5418}, {INT64_C(1380575039097667000), 0x0003, 0x0035, 5418}, {INT64_C(1380575039097667000), 0x0003, 0x0036, 6080}, {INT64_C(1380575039097667000), 0x0003, 0x0034, 1}, {INT64_C(1380575039097667000), 0x0003, 0x0030, 256}, {INT64_C(1380575039097667000), 0x0003, 0x0031, 160}, {INT64_C(1380575039097667000), 0x0000, 0x0002, 0}, {INT64_C(1380575039097667000), 0x0003, 0x0035, 4405}, {INT64_C(1380575039097667000), 0x0003, 0x0036, 5760}, {INT64_C(1380575039097667000), 0x0003, 0x0034, 1}, {INT64_C(1380575039097667000), 0x0003, 0x0030, 256}, {INT64_C(1380575039097667000), 0x0003, 0x0031, 160}, {INT64_C(1380575039097667000), 0x0000, 0x0002, 0}, {INT64_C(1380575039097667000), 0x0003, 0x0035, 6242}, {INT64_C(1380575039097667000), 0x0003, 0x0036, 5175}, {INT64_C(1380575039097667000), 0x0003, 0x0034, 0}, {INT64_C(1380575039097667000), 0x0003, 0x0030, 320}, {INT64_C(1380575039097667000), 0x0003, 0x0031, 256}, {INT64_C(1380575039097667000), 0x0000, 0x0002, 0}, {INT64_C(1380575039097667000), 0x0003, 0x0035, 3775}, {INT64_C(1380575039097667000), 0x0003, 0x0036, 4477}, {INT64_C(1380575039097667000), 0x0003, 0x0034, 0}, {INT64_C(1380575039097667000), 0x0003, 0x0030, 480}, {INT64_C(1380575039097667000), 0x0003, 0x0031, 256}, {INT64_C(1380575039097667000), 0x0000, 0x0002, 0}, {INT64_C(1380575039097667000), 0x0003, 0x0035, 4366}, {INT64_C(1380575039097667000), 0x0003, 0x0036, 1920}, {INT64_C(1380575039097667000), 0x0003, 0x0034, 1}, {INT64_C(1380575039097667000), 0x0003, 0x0030, 384}, {INT64_C(1380575039097667000), 0x0003, 0x0031, 160}, {INT64_C(1380575039097667000), 0x0000, 0x0002, 0}, {INT64_C(1380575039097667000), 0x0000, 0x0000, 0}, {INT64_C(1380575039103663000), 0x0003, 0x0000, 5409}, {INT64_C(1380575039103663000), 0x0003, 0x0035, 5409}, {INT64_C(1380575039103663000), 0x0003, 0x0036, 6080}, {INT64_C(1380575039103663000), 0x0003, 0x0034, 1}, {INT64_C(1380575039103663000), 0x0003, 0x0030, 256}, {INT64_C(1380575039103663000), 0x0003, 0x0031, 160}, {INT64_C(1380575039103663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039103663000), 0x0003, 0x0035, 4402}, {INT64_C(1380575039103663000), 0x0003, 0x0036, 5677}, {INT64_C(1380575039103663000), 0x0003, 0x0034, 0}, {INT64_C(1380575039103663000), 0x0003, 0x0030, 320}, {INT64_C(1380575039103663000), 0x0003, 0x0031, 256}, {INT64_C(1380575039103663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039103663000), 0x0003, 0x0035, 6286}, {INT64_C(1380575039103663000), 0x0003, 0x0036, 4997}, {INT64_C(1380575039103663000), 0x0003, 0x0034, 0}, {INT64_C(1380575039103663000), 0x0003, 0x0030, 320}, {INT64_C(1380575039103663000), 0x0003, 0x0031, 256}, {INT64_C(1380575039103663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039103663000), 0x0003, 0x0035, 3797}, {INT64_C(1380575039103663000), 0x0003, 0x0036, 4438}, {INT64_C(1380575039103663000), 0x0003, 0x0034, 0}, {INT64_C(1380575039103663000), 0x0003, 0x0030, 320}, {INT64_C(1380575039103663000), 0x0003, 0x0031, 256}, {INT64_C(1380575039103663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039103663000), 0x0003, 0x0035, 4360}, {INT64_C(1380575039103663000), 0x0003, 0x0036, 1920}, {INT64_C(1380575039103663000), 0x0003, 0x0034, 1}, {INT64_C(1380575039103663000), 0x0003, 0x0030, 384}, {INT64_C(1380575039103663000), 0x0003, 0x0031, 160}, {INT64_C(1380575039103663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039103663000), 0x0000, 0x0000, 0}, {INT64_C(1380575039115660000), 0x0003, 0x0000, 5411}, {INT64_C(1380575039115660000), 0x0003, 0x0001, 5920}, {INT64_C(1380575039115660000), 0x0003, 0x0035, 5411}, {INT64_C(1380575039115660000), 0x0003, 0x0036, 5920}, {INT64_C(1380575039115660000), 0x0003, 0x0034, 1}, {INT64_C(1380575039115660000), 0x0003, 0x0030, 256}, {INT64_C(1380575039115660000), 0x0003, 0x0031, 160}, {INT64_C(1380575039115660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039115660000), 0x0003, 0x0035, 4408}, {INT64_C(1380575039115660000), 0x0003, 0x0036, 5600}, {INT64_C(1380575039115660000), 0x0003, 0x0034, 1}, {INT64_C(1380575039115660000), 0x0003, 0x0030, 256}, {INT64_C(1380575039115660000), 0x0003, 0x0031, 160}, {INT64_C(1380575039115660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039115660000), 0x0003, 0x0035, 6276}, {INT64_C(1380575039115660000), 0x0003, 0x0036, 4591}, {INT64_C(1380575039115660000), 0x0003, 0x0034, 0}, {INT64_C(1380575039115660000), 0x0003, 0x0030, 800}, {INT64_C(1380575039115660000), 0x0003, 0x0031, 256}, {INT64_C(1380575039115660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039115660000), 0x0003, 0x0035, 3798}, {INT64_C(1380575039115660000), 0x0003, 0x0036, 4399}, {INT64_C(1380575039115660000), 0x0003, 0x0034, 0}, {INT64_C(1380575039115660000), 0x0003, 0x0030, 320}, {INT64_C(1380575039115660000), 0x0003, 0x0031, 256}, {INT64_C(1380575039115660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039115660000), 0x0003, 0x0035, 4390}, {INT64_C(1380575039115660000), 0x0003, 0x0036, 1920}, {INT64_C(1380575039115660000), 0x0003, 0x0034, 1}, {INT64_C(1380575039115660000), 0x0003, 0x0030, 384}, {INT64_C(1380575039115660000), 0x0003, 0x0031, 160}, {INT64_C(1380575039115660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039115660000), 0x0000, 0x0000, 0}, {INT64_C(1380575039121663000), 0x0003, 0x0000, 4415}, {INT64_C(1380575039121663000), 0x0003, 0x0001, 5554}, {INT64_C(1380575039121663000), 0x0003, 0x0035, 4415}, {INT64_C(1380575039121663000), 0x0003, 0x0036, 5554}, {INT64_C(1380575039121663000), 0x0003, 0x0034, 0}, {INT64_C(1380575039121663000), 0x0003, 0x0030, 480}, {INT64_C(1380575039121663000), 0x0003, 0x0031, 256}, {INT64_C(1380575039121663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039121663000), 0x0003, 0x0035, 5402}, {INT64_C(1380575039121663000), 0x0003, 0x0036, 5720}, {INT64_C(1380575039121663000), 0x0003, 0x0034, 0}, {INT64_C(1380575039121663000), 0x0003, 0x0030, 320}, {INT64_C(1380575039121663000), 0x0003, 0x0031, 256}, {INT64_C(1380575039121663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039121663000), 0x0003, 0x0035, 3819}, {INT64_C(1380575039121663000), 0x0003, 0x0036, 4347}, {INT64_C(1380575039121663000), 0x0003, 0x0034, 1}, {INT64_C(1380575039121663000), 0x0003, 0x0030, 384}, {INT64_C(1380575039121663000), 0x0003, 0x0031, 320}, {INT64_C(1380575039121663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039121663000), 0x0003, 0x0035, 6236}, {INT64_C(1380575039121663000), 0x0003, 0x0036, 4299}, {INT64_C(1380575039121663000), 0x0003, 0x0034, 0}, {INT64_C(1380575039121663000), 0x0003, 0x0030, 640}, {INT64_C(1380575039121663000), 0x0003, 0x0031, 256}, {INT64_C(1380575039121663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039121663000), 0x0003, 0x0035, 4391}, {INT64_C(1380575039121663000), 0x0003, 0x0036, 1920}, {INT64_C(1380575039121663000), 0x0003, 0x0034, 1}, {INT64_C(1380575039121663000), 0x0003, 0x0030, 384}, {INT64_C(1380575039121663000), 0x0003, 0x0031, 160}, {INT64_C(1380575039121663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039121663000), 0x0000, 0x0000, 0}, {INT64_C(1380575039135664000), 0x0003, 0x0000, 4412}, {INT64_C(1380575039135664000), 0x0003, 0x0001, 5434}, {INT64_C(1380575039135664000), 0x0003, 0x0035, 4412}, {INT64_C(1380575039135664000), 0x0003, 0x0036, 5434}, {INT64_C(1380575039135664000), 0x0003, 0x0034, 0}, {INT64_C(1380575039135664000), 0x0003, 0x0030, 480}, {INT64_C(1380575039135664000), 0x0003, 0x0031, 256}, {INT64_C(1380575039135664000), 0x0000, 0x0002, 0}, {INT64_C(1380575039135664000), 0x0003, 0x0035, 5399}, {INT64_C(1380575039135664000), 0x0003, 0x0036, 5551}, {INT64_C(1380575039135664000), 0x0003, 0x0034, 0}, {INT64_C(1380575039135664000), 0x0003, 0x0030, 320}, {INT64_C(1380575039135664000), 0x0003, 0x0031, 256}, {INT64_C(1380575039135664000), 0x0000, 0x0002, 0}, {INT64_C(1380575039135664000), 0x0003, 0x0035, 3865}, {INT64_C(1380575039135664000), 0x0003, 0x0036, 4181}, {INT64_C(1380575039135664000), 0x0003, 0x0034, 0}, {INT64_C(1380575039135664000), 0x0003, 0x0030, 480}, {INT64_C(1380575039135664000), 0x0003, 0x0031, 256}, {INT64_C(1380575039135664000), 0x0000, 0x0002, 0}, {INT64_C(1380575039135664000), 0x0003, 0x0035, 6165}, {INT64_C(1380575039135664000), 0x0003, 0x0036, 4077}, {INT64_C(1380575039135664000), 0x0003, 0x0034, 0}, {INT64_C(1380575039135664000), 0x0003, 0x0030, 320}, {INT64_C(1380575039135664000), 0x0003, 0x0031, 256}, {INT64_C(1380575039135664000), 0x0000, 0x0002, 0}, {INT64_C(1380575039135664000), 0x0003, 0x0035, 4426}, {INT64_C(1380575039135664000), 0x0003, 0x0036, 1920}, {INT64_C(1380575039135664000), 0x0003, 0x0034, 1}, {INT64_C(1380575039135664000), 0x0003, 0x0030, 384}, {INT64_C(1380575039135664000), 0x0003, 0x0031, 160}, {INT64_C(1380575039135664000), 0x0000, 0x0002, 0}, {INT64_C(1380575039135664000), 0x0000, 0x0000, 0}, {INT64_C(1380575039141663000), 0x0003, 0x0000, 4418}, {INT64_C(1380575039141663000), 0x0003, 0x0001, 5304}, {INT64_C(1380575039141663000), 0x0003, 0x0035, 4418}, {INT64_C(1380575039141663000), 0x0003, 0x0036, 5304}, {INT64_C(1380575039141663000), 0x0003, 0x0034, 0}, {INT64_C(1380575039141663000), 0x0003, 0x0030, 320}, {INT64_C(1380575039141663000), 0x0003, 0x0031, 256}, {INT64_C(1380575039141663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039141663000), 0x0003, 0x0035, 5391}, {INT64_C(1380575039141663000), 0x0003, 0x0036, 5357}, {INT64_C(1380575039141663000), 0x0003, 0x0034, 0}, {INT64_C(1380575039141663000), 0x0003, 0x0030, 320}, {INT64_C(1380575039141663000), 0x0003, 0x0031, 256}, {INT64_C(1380575039141663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039141663000), 0x0003, 0x0035, 3911}, {INT64_C(1380575039141663000), 0x0003, 0x0036, 4001}, {INT64_C(1380575039141663000), 0x0003, 0x0034, 0}, {INT64_C(1380575039141663000), 0x0003, 0x0030, 320}, {INT64_C(1380575039141663000), 0x0003, 0x0031, 256}, {INT64_C(1380575039141663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039141663000), 0x0003, 0x0035, 4493}, {INT64_C(1380575039141663000), 0x0003, 0x0036, 1920}, {INT64_C(1380575039141663000), 0x0003, 0x0034, 1}, {INT64_C(1380575039141663000), 0x0003, 0x0030, 256}, {INT64_C(1380575039141663000), 0x0003, 0x0031, 160}, {INT64_C(1380575039141663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039141663000), 0x0000, 0x0000, 0}, {INT64_C(1380575039153663000), 0x0003, 0x0000, 4379}, {INT64_C(1380575039153663000), 0x0003, 0x0001, 5029}, {INT64_C(1380575039153663000), 0x0003, 0x0035, 4379}, {INT64_C(1380575039153663000), 0x0003, 0x0036, 5029}, {INT64_C(1380575039153663000), 0x0003, 0x0034, 1}, {INT64_C(1380575039153663000), 0x0003, 0x0030, 512}, {INT64_C(1380575039153663000), 0x0003, 0x0031, 320}, {INT64_C(1380575039153663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039153663000), 0x0003, 0x0035, 5331}, {INT64_C(1380575039153663000), 0x0003, 0x0036, 5051}, {INT64_C(1380575039153663000), 0x0003, 0x0034, 0}, {INT64_C(1380575039153663000), 0x0003, 0x0030, 320}, {INT64_C(1380575039153663000), 0x0003, 0x0031, 256}, {INT64_C(1380575039153663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039153663000), 0x0003, 0x0035, 3920}, {INT64_C(1380575039153663000), 0x0003, 0x0036, 3680}, {INT64_C(1380575039153663000), 0x0003, 0x0034, 1}, {INT64_C(1380575039153663000), 0x0003, 0x0030, 256}, {INT64_C(1380575039153663000), 0x0003, 0x0031, 160}, {INT64_C(1380575039153663000), 0x0000, 0x0002, 0}, {INT64_C(1380575039153663000), 0x0000, 0x0000, 0}, {INT64_C(1380575039171660000), 0x0003, 0x0000, 4349}, {INT64_C(1380575039171660000), 0x0003, 0x0001, 4801}, {INT64_C(1380575039171660000), 0x0003, 0x0035, 4349}, {INT64_C(1380575039171660000), 0x0003, 0x0036, 4801}, {INT64_C(1380575039171660000), 0x0003, 0x0034, 0}, {INT64_C(1380575039171660000), 0x0003, 0x0030, 480}, {INT64_C(1380575039171660000), 0x0003, 0x0031, 384}, {INT64_C(1380575039171660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039171660000), 0x0003, 0x0035, 5326}, {INT64_C(1380575039171660000), 0x0003, 0x0036, 4811}, {INT64_C(1380575039171660000), 0x0003, 0x0034, 0}, {INT64_C(1380575039171660000), 0x0003, 0x0030, 480}, {INT64_C(1380575039171660000), 0x0003, 0x0031, 256}, {INT64_C(1380575039171660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039171660000), 0x0000, 0x0000, 0}, {INT64_C(1380575039191661000), 0x0003, 0x0000, 5279}, {INT64_C(1380575039191661000), 0x0003, 0x0001, 4629}, {INT64_C(1380575039191661000), 0x0003, 0x0035, 5279}, {INT64_C(1380575039191661000), 0x0003, 0x0036, 4629}, {INT64_C(1380575039191661000), 0x0003, 0x0034, 0}, {INT64_C(1380575039191661000), 0x0003, 0x0030, 480}, {INT64_C(1380575039191661000), 0x0003, 0x0031, 384}, {INT64_C(1380575039191661000), 0x0000, 0x0002, 0}, {INT64_C(1380575039191661000), 0x0003, 0x0035, 4321}, {INT64_C(1380575039191661000), 0x0003, 0x0036, 4553}, {INT64_C(1380575039191661000), 0x0003, 0x0034, 0}, {INT64_C(1380575039191661000), 0x0003, 0x0030, 480}, {INT64_C(1380575039191661000), 0x0003, 0x0031, 384}, {INT64_C(1380575039191661000), 0x0000, 0x0002, 0}, {INT64_C(1380575039191661000), 0x0000, 0x0000, 0}, {INT64_C(1380575039209660000), 0x0003, 0x0000, 5222}, {INT64_C(1380575039209660000), 0x0003, 0x0001, 4441}, {INT64_C(1380575039209660000), 0x0003, 0x0035, 5222}, {INT64_C(1380575039209660000), 0x0003, 0x0036, 4441}, {INT64_C(1380575039209660000), 0x0003, 0x0034, 1}, {INT64_C(1380575039209660000), 0x0003, 0x0030, 384}, {INT64_C(1380575039209660000), 0x0003, 0x0031, 320}, {INT64_C(1380575039209660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039209660000), 0x0003, 0x0035, 4295}, {INT64_C(1380575039209660000), 0x0003, 0x0036, 4271}, {INT64_C(1380575039209660000), 0x0003, 0x0034, 0}, {INT64_C(1380575039209660000), 0x0003, 0x0030, 320}, {INT64_C(1380575039209660000), 0x0003, 0x0031, 256}, {INT64_C(1380575039209660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039209660000), 0x0000, 0x0000, 0}, {INT64_C(1380575039227657000), 0x0003, 0x0000, 5120}, {INT64_C(1380575039227657000), 0x0003, 0x0001, 4239}, {INT64_C(1380575039227657000), 0x0003, 0x0035, 5120}, {INT64_C(1380575039227657000), 0x0003, 0x0036, 4239}, {INT64_C(1380575039227657000), 0x0003, 0x0034, 0}, {INT64_C(1380575039227657000), 0x0003, 0x0030, 320}, {INT64_C(1380575039227657000), 0x0003, 0x0031, 128}, {INT64_C(1380575039227657000), 0x0000, 0x0002, 0}, {INT64_C(1380575039227657000), 0x0000, 0x0000, 0}, {INT64_C(1380575039321656000), 0x0001, 0x014d, 0}, {INT64_C(1380575039321656000), 0x0001, 0x014a, 0}, {INT64_C(1380575039321656000), 0x0000, 0x0000, 0}, {INT64_C(1380575039589659000), 0x0003, 0x0000, 5116}, {INT64_C(1380575039589659000), 0x0003, 0x0001, 5686}, {INT64_C(1380575039589659000), 0x0003, 0x0035, 5116}, {INT64_C(1380575039589659000), 0x0003, 0x0036, 5686}, {INT64_C(1380575039589659000), 0x0003, 0x0034, 1}, {INT64_C(1380575039589659000), 0x0003, 0x0030, 384}, {INT64_C(1380575039589659000), 0x0003, 0x0031, 320}, {INT64_C(1380575039589659000), 0x0000, 0x0002, 0}, {INT64_C(1380575039589659000), 0x0003, 0x0035, 2240}, {INT64_C(1380575039589659000), 0x0003, 0x0036, 5218}, {INT64_C(1380575039589659000), 0x0003, 0x0034, 0}, {INT64_C(1380575039589659000), 0x0003, 0x0030, 320}, {INT64_C(1380575039589659000), 0x0003, 0x0031, 256}, {INT64_C(1380575039589659000), 0x0000, 0x0002, 0}, {INT64_C(1380575039589659000), 0x0003, 0x0035, 2849}, {INT64_C(1380575039589659000), 0x0003, 0x0036, 1851}, {INT64_C(1380575039589659000), 0x0003, 0x0034, 1}, {INT64_C(1380575039589659000), 0x0003, 0x0030, 384}, {INT64_C(1380575039589659000), 0x0003, 0x0031, 320}, {INT64_C(1380575039589659000), 0x0000, 0x0002, 0}, {INT64_C(1380575039589659000), 0x0001, 0x014d, 1}, {INT64_C(1380575039589659000), 0x0001, 0x014a, 1}, {INT64_C(1380575039589659000), 0x0000, 0x0000, 0}, {INT64_C(1380575039603660000), 0x0003, 0x0000, 5108}, {INT64_C(1380575039603660000), 0x0003, 0x0001, 5677}, {INT64_C(1380575039603660000), 0x0003, 0x0035, 5108}, {INT64_C(1380575039603660000), 0x0003, 0x0036, 5677}, {INT64_C(1380575039603660000), 0x0003, 0x0034, 1}, {INT64_C(1380575039603660000), 0x0003, 0x0030, 384}, {INT64_C(1380575039603660000), 0x0003, 0x0031, 320}, {INT64_C(1380575039603660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039603660000), 0x0003, 0x0035, 2241}, {INT64_C(1380575039603660000), 0x0003, 0x0036, 5218}, {INT64_C(1380575039603660000), 0x0003, 0x0034, 0}, {INT64_C(1380575039603660000), 0x0003, 0x0030, 320}, {INT64_C(1380575039603660000), 0x0003, 0x0031, 256}, {INT64_C(1380575039603660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039603660000), 0x0003, 0x0035, 2864}, {INT64_C(1380575039603660000), 0x0003, 0x0036, 1848}, {INT64_C(1380575039603660000), 0x0003, 0x0034, 1}, {INT64_C(1380575039603660000), 0x0003, 0x0030, 512}, {INT64_C(1380575039603660000), 0x0003, 0x0031, 320}, {INT64_C(1380575039603660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039603660000), 0x0000, 0x0000, 0}, {INT64_C(1380575039609656000), 0x0003, 0x0000, 5105}, {INT64_C(1380575039609656000), 0x0003, 0x0001, 5583}, {INT64_C(1380575039609656000), 0x0003, 0x0035, 5105}, {INT64_C(1380575039609656000), 0x0003, 0x0036, 5583}, {INT64_C(1380575039609656000), 0x0003, 0x0034, 0}, {INT64_C(1380575039609656000), 0x0003, 0x0030, 480}, {INT64_C(1380575039609656000), 0x0003, 0x0031, 384}, {INT64_C(1380575039609656000), 0x0000, 0x0002, 0}, {INT64_C(1380575039609656000), 0x0003, 0x0035, 2257}, {INT64_C(1380575039609656000), 0x0003, 0x0036, 5200}, {INT64_C(1380575039609656000), 0x0003, 0x0034, 0}, {INT64_C(1380575039609656000), 0x0003, 0x0030, 320}, {INT64_C(1380575039609656000), 0x0003, 0x0031, 256}, {INT64_C(1380575039609656000), 0x0000, 0x0002, 0}, {INT64_C(1380575039609656000), 0x0003, 0x0035, 2874}, {INT64_C(1380575039609656000), 0x0003, 0x0036, 1856}, {INT64_C(1380575039609656000), 0x0003, 0x0034, 1}, {INT64_C(1380575039609656000), 0x0003, 0x0030, 512}, {INT64_C(1380575039609656000), 0x0003, 0x0031, 320}, {INT64_C(1380575039609656000), 0x0000, 0x0002, 0}, {INT64_C(1380575039609656000), 0x0000, 0x0000, 0}, {INT64_C(1380575039621660000), 0x0003, 0x0000, 2884}, {INT64_C(1380575039621660000), 0x0003, 0x0001, 6400}, {INT64_C(1380575039621660000), 0x0003, 0x0035, 2884}, {INT64_C(1380575039621660000), 0x0003, 0x0036, 6400}, {INT64_C(1380575039621660000), 0x0003, 0x0034, 1}, {INT64_C(1380575039621660000), 0x0003, 0x0030, 256}, {INT64_C(1380575039621660000), 0x0003, 0x0031, 160}, {INT64_C(1380575039621660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039621660000), 0x0003, 0x0035, 4009}, {INT64_C(1380575039621660000), 0x0003, 0x0036, 6400}, {INT64_C(1380575039621660000), 0x0003, 0x0034, 1}, {INT64_C(1380575039621660000), 0x0003, 0x0030, 256}, {INT64_C(1380575039621660000), 0x0003, 0x0031, 160}, {INT64_C(1380575039621660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039621660000), 0x0003, 0x0035, 5089}, {INT64_C(1380575039621660000), 0x0003, 0x0036, 5453}, {INT64_C(1380575039621660000), 0x0003, 0x0034, 0}, {INT64_C(1380575039621660000), 0x0003, 0x0030, 480}, {INT64_C(1380575039621660000), 0x0003, 0x0031, 384}, {INT64_C(1380575039621660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039621660000), 0x0003, 0x0035, 2272}, {INT64_C(1380575039621660000), 0x0003, 0x0036, 5187}, {INT64_C(1380575039621660000), 0x0003, 0x0034, 0}, {INT64_C(1380575039621660000), 0x0003, 0x0030, 320}, {INT64_C(1380575039621660000), 0x0003, 0x0031, 256}, {INT64_C(1380575039621660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039621660000), 0x0003, 0x0035, 2899}, {INT64_C(1380575039621660000), 0x0003, 0x0036, 1865}, {INT64_C(1380575039621660000), 0x0003, 0x0034, 1}, {INT64_C(1380575039621660000), 0x0003, 0x0030, 512}, {INT64_C(1380575039621660000), 0x0003, 0x0031, 320}, {INT64_C(1380575039621660000), 0x0000, 0x0002, 0}, {INT64_C(1380575039621660000), 0x0000, 0x0000, 0}, {INT64_C(1380575039627662000), 0x0003, 0x0000, 2894}, {INT64_C(1380575039627662000), 0x0003, 0x0035, 2894}, {INT64_C(1380575039627662000), 0x0003, 0x0036, 6400}, {INT64_C(1380575039627662000), 0x0003, 0x0034, 1}, {INT64_C(1380575039627662000), 0x0003, 0x0030, 256}, {INT64_C(1380575039627662000), 0x0003, 0x0031, 160}, {INT64_C(1380575039627662000), 0x0000, 0x0002, 0}, {INT64_C(1380575039627662000), 0x0003, 0x0035, 4013}, {INT64_C(1380575039627662000), 0x0003, 0x0036, 6400}, {INT64_C(1380575039627662000), 0x0003, 0x0034, 1}, {INT64_C(1380575039627662000), 0x0003, 0x0030, 256}, {INT64_C(1380575039627662000), 0x0003, 0x0031, 160}, {INT64_C(1380575039627662000), 0x0000, 0x0002, 0}, {INT64_C(1380575039627662000), 0x0003, 0x0035, 5058}, {INT64_C(1380575039627662000), 0x0003, 0x0036, 5288}, {INT64_C(1380575039627662000), 0x0003, 0x0034, 0}, {INT64_C(1380575039627662000), 0x0003, 0x0030, 800}, {INT64_C(1380575039627662000), 0x0003, 0x0031, 256}, {INT64_C(1380575039627662000), 0x0000, 0x0002, 0}, {INT64_C(1380575039627662000), 0x0003, 0x0035, 2280}, {INT64_C(1380575039627662000), 0x0003, 0x0036, 5095}, {INT64_C(1380575039627662000), 0x0003, 0x0034, 0}, {INT64_C(1380575039627662000), 0x0003, 0x0030, 480}, {INT64_C(1380575039627662000), 0x0003, 0x0031, 256}, {INT64_C(1380575039627662000), 0x0000, 0x0002, 0}, {INT64_C(1380575039627662000), 0x0003, 0x0035, 2935}, {INT64_C(1380575039627662000), 0x0003, 0x0036, 1920}, {INT64_C(1380575039627662000), 0x0003, 0x0034, 1}, {INT64_C(1380575039627662000), 0x0003, 0x0030, 384}, {INT64_C(1380575039627662000), 0x0003, 0x0031, 160}, {INT64_C(1380575039627662000), 0x0000, 0x0002, 0}, {INT64_C(1380575039627662000), 0x0000, 0x0000, 0}, {INT64_C(1380575040145654000), 0x0003, 0x0035, 2272}, {INT64_C(1380575040145654000), 0x0003, 0x0036, 1358}, {INT64_C(1380575040145654000), 0x0003, 0x0034, 1}, {INT64_C(1380575040145654000), 0x0003, 0x0030, 384}, {INT64_C(1380575040145654000), 0x0003, 0x0031, 320}, {INT64_C(1380575040145654000), 0x0000, 0x0002, 0}, {INT64_C(1380575040145654000), 0x0001, 0x014d, 0}, {INT64_C(1380575040145654000), 0x0001, 0x014a, 0}, {INT64_C(1380575040145654000), 0x0000, 0x0000, 0}, {INT64_C(1380575040151655000), 0x0003, 0x0000, 1152}, {INT64_C(1380575040151655000), 0x0003, 0x0001, 5376}, {INT64_C(1380575040151655000), 0x0003, 0x0035, 1152}, {INT64_C(1380575040151655000), 0x0003, 0x0036, 5376}, {INT64_C(1380575040151655000), 0x0003, 0x0034, 0}, {INT64_C(1380575040151655000), 0x0003, 0x0030, 480}, {INT64_C(1380575040151655000), 0x0003, 0x0031, 128}, {INT64_C(1380575040151655000), 0x0000, 0x0002, 0}, {INT64_C(1380575040151655000), 0x0003, 0x0035, 851}, {INT64_C(1380575040151655000), 0x0003, 0x0036, 3917}, {INT64_C(1380575040151655000), 0x0003, 0x0034, 0}, {INT64_C(1380575040151655000), 0x0003, 0x0030, 480}, {INT64_C(1380575040151655000), 0x0003, 0x0031, 256}, {INT64_C(1380575040151655000), 0x0000, 0x0002, 0}, {INT64_C(1380575040151655000), 0x0003, 0x0035, 2242}, {INT64_C(1380575040151655000), 0x0003, 0x0036, 1322}, {INT64_C(1380575040151655000), 0x0003, 0x0034, 1}, {INT64_C(1380575040151655000), 0x0003, 0x0030, 384}, {INT64_C(1380575040151655000), 0x0003, 0x0031, 320}, {INT64_C(1380575040151655000), 0x0000, 0x0002, 0}, {INT64_C(1380575040151655000), 0x0001, 0x014d, 1}, {INT64_C(1380575040151655000), 0x0001, 0x014a, 1}, {INT64_C(1380575040151655000), 0x0000, 0x0000, 0}, {INT64_C(1380575040163650000), 0x0003, 0x0000, 1216}, {INT64_C(1380575040163650000), 0x0003, 0x0001, 5348}, {INT64_C(1380575040163650000), 0x0003, 0x0035, 1216}, {INT64_C(1380575040163650000), 0x0003, 0x0036, 5348}, {INT64_C(1380575040163650000), 0x0003, 0x0034, 0}, {INT64_C(1380575040163650000), 0x0003, 0x0030, 320}, {INT64_C(1380575040163650000), 0x0003, 0x0031, 256}, {INT64_C(1380575040163650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040163650000), 0x0003, 0x0035, 896}, {INT64_C(1380575040163650000), 0x0003, 0x0036, 3898}, {INT64_C(1380575040163650000), 0x0003, 0x0034, 0}, {INT64_C(1380575040163650000), 0x0003, 0x0030, 480}, {INT64_C(1380575040163650000), 0x0003, 0x0031, 128}, {INT64_C(1380575040163650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040163650000), 0x0003, 0x0035, 2317}, {INT64_C(1380575040163650000), 0x0003, 0x0036, 1280}, {INT64_C(1380575040163650000), 0x0003, 0x0034, 1}, {INT64_C(1380575040163650000), 0x0003, 0x0030, 384}, {INT64_C(1380575040163650000), 0x0003, 0x0031, 160}, {INT64_C(1380575040163650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040163650000), 0x0000, 0x0000, 0}, {INT64_C(1380575040169651000), 0x0003, 0x0000, 1322}, {INT64_C(1380575040169651000), 0x0003, 0x0001, 5238}, {INT64_C(1380575040169651000), 0x0003, 0x0035, 1322}, {INT64_C(1380575040169651000), 0x0003, 0x0036, 5238}, {INT64_C(1380575040169651000), 0x0003, 0x0034, 0}, {INT64_C(1380575040169651000), 0x0003, 0x0030, 480}, {INT64_C(1380575040169651000), 0x0003, 0x0031, 256}, {INT64_C(1380575040169651000), 0x0000, 0x0002, 0}, {INT64_C(1380575040169651000), 0x0003, 0x0035, 1009}, {INT64_C(1380575040169651000), 0x0003, 0x0036, 3830}, {INT64_C(1380575040169651000), 0x0003, 0x0034, 0}, {INT64_C(1380575040169651000), 0x0003, 0x0030, 480}, {INT64_C(1380575040169651000), 0x0003, 0x0031, 256}, {INT64_C(1380575040169651000), 0x0000, 0x0002, 0}, {INT64_C(1380575040169651000), 0x0003, 0x0035, 2375}, {INT64_C(1380575040169651000), 0x0003, 0x0036, 1280}, {INT64_C(1380575040169651000), 0x0003, 0x0034, 1}, {INT64_C(1380575040169651000), 0x0003, 0x0030, 256}, {INT64_C(1380575040169651000), 0x0003, 0x0031, 160}, {INT64_C(1380575040169651000), 0x0000, 0x0002, 0}, {INT64_C(1380575040169651000), 0x0000, 0x0000, 0}, {INT64_C(1380575040183654000), 0x0003, 0x0000, 2048}, {INT64_C(1380575040183654000), 0x0003, 0x0001, 5564}, {INT64_C(1380575040183654000), 0x0003, 0x0035, 2048}, {INT64_C(1380575040183654000), 0x0003, 0x0036, 5564}, {INT64_C(1380575040183654000), 0x0003, 0x0034, 0}, {INT64_C(1380575040183654000), 0x0003, 0x0030, 320}, {INT64_C(1380575040183654000), 0x0003, 0x0031, 128}, {INT64_C(1380575040183654000), 0x0000, 0x0002, 0}, {INT64_C(1380575040183654000), 0x0003, 0x0035, 1386}, {INT64_C(1380575040183654000), 0x0003, 0x0036, 5187}, {INT64_C(1380575040183654000), 0x0003, 0x0034, 0}, {INT64_C(1380575040183654000), 0x0003, 0x0030, 320}, {INT64_C(1380575040183654000), 0x0003, 0x0031, 256}, {INT64_C(1380575040183654000), 0x0000, 0x0002, 0}, {INT64_C(1380575040183654000), 0x0003, 0x0035, 1202}, {INT64_C(1380575040183654000), 0x0003, 0x0036, 3783}, {INT64_C(1380575040183654000), 0x0003, 0x0034, 1}, {INT64_C(1380575040183654000), 0x0003, 0x0030, 512}, {INT64_C(1380575040183654000), 0x0003, 0x0031, 480}, {INT64_C(1380575040183654000), 0x0000, 0x0002, 0}, {INT64_C(1380575040183654000), 0x0003, 0x0035, 2464}, {INT64_C(1380575040183654000), 0x0003, 0x0036, 1280}, {INT64_C(1380575040183654000), 0x0003, 0x0034, 1}, {INT64_C(1380575040183654000), 0x0003, 0x0030, 384}, {INT64_C(1380575040183654000), 0x0003, 0x0031, 160}, {INT64_C(1380575040183654000), 0x0000, 0x0002, 0}, {INT64_C(1380575040183654000), 0x0000, 0x0000, 0}, {INT64_C(1380575040189656000), 0x0003, 0x0000, 2176}, {INT64_C(1380575040189656000), 0x0003, 0x0001, 5491}, {INT64_C(1380575040189656000), 0x0003, 0x0035, 2176}, {INT64_C(1380575040189656000), 0x0003, 0x0036, 5491}, {INT64_C(1380575040189656000), 0x0003, 0x0034, 0}, {INT64_C(1380575040189656000), 0x0003, 0x0030, 320}, {INT64_C(1380575040189656000), 0x0003, 0x0031, 128}, {INT64_C(1380575040189656000), 0x0000, 0x0002, 0}, {INT64_C(1380575040189656000), 0x0003, 0x0035, 1519}, {INT64_C(1380575040189656000), 0x0003, 0x0036, 5028}, {INT64_C(1380575040189656000), 0x0003, 0x0034, 0}, {INT64_C(1380575040189656000), 0x0003, 0x0030, 320}, {INT64_C(1380575040189656000), 0x0003, 0x0031, 256}, {INT64_C(1380575040189656000), 0x0000, 0x0002, 0}, {INT64_C(1380575040189656000), 0x0003, 0x0035, 1355}, {INT64_C(1380575040189656000), 0x0003, 0x0036, 3750}, {INT64_C(1380575040189656000), 0x0003, 0x0034, 0}, {INT64_C(1380575040189656000), 0x0003, 0x0030, 480}, {INT64_C(1380575040189656000), 0x0003, 0x0031, 384}, {INT64_C(1380575040189656000), 0x0000, 0x0002, 0}, {INT64_C(1380575040189656000), 0x0003, 0x0035, 2533}, {INT64_C(1380575040189656000), 0x0003, 0x0036, 1280}, {INT64_C(1380575040189656000), 0x0003, 0x0034, 1}, {INT64_C(1380575040189656000), 0x0003, 0x0030, 256}, {INT64_C(1380575040189656000), 0x0003, 0x0031, 160}, {INT64_C(1380575040189656000), 0x0000, 0x0002, 0}, {INT64_C(1380575040189656000), 0x0000, 0x0000, 0}, {INT64_C(1380575040201655000), 0x0003, 0x0000, 1623}, {INT64_C(1380575040201655000), 0x0003, 0x0001, 4954}, {INT64_C(1380575040201655000), 0x0003, 0x0035, 1623}, {INT64_C(1380575040201655000), 0x0003, 0x0036, 4954}, {INT64_C(1380575040201655000), 0x0003, 0x0034, 0}, {INT64_C(1380575040201655000), 0x0003, 0x0030, 480}, {INT64_C(1380575040201655000), 0x0003, 0x0031, 256}, {INT64_C(1380575040201655000), 0x0000, 0x0002, 0}, {INT64_C(1380575040201655000), 0x0003, 0x0035, 1492}, {INT64_C(1380575040201655000), 0x0003, 0x0036, 3721}, {INT64_C(1380575040201655000), 0x0003, 0x0034, 1}, {INT64_C(1380575040201655000), 0x0003, 0x0030, 384}, {INT64_C(1380575040201655000), 0x0003, 0x0031, 320}, {INT64_C(1380575040201655000), 0x0000, 0x0002, 0}, {INT64_C(1380575040201655000), 0x0000, 0x0000, 0}, {INT64_C(1380575040207655000), 0x0003, 0x0000, 2430}, {INT64_C(1380575040207655000), 0x0003, 0x0001, 5317}, {INT64_C(1380575040207655000), 0x0003, 0x0035, 2430}, {INT64_C(1380575040207655000), 0x0003, 0x0036, 5317}, {INT64_C(1380575040207655000), 0x0003, 0x0034, 0}, {INT64_C(1380575040207655000), 0x0003, 0x0030, 480}, {INT64_C(1380575040207655000), 0x0003, 0x0031, 256}, {INT64_C(1380575040207655000), 0x0000, 0x0002, 0}, {INT64_C(1380575040207655000), 0x0003, 0x0035, 1751}, {INT64_C(1380575040207655000), 0x0003, 0x0036, 4903}, {INT64_C(1380575040207655000), 0x0003, 0x0034, 0}, {INT64_C(1380575040207655000), 0x0003, 0x0030, 480}, {INT64_C(1380575040207655000), 0x0003, 0x0031, 384}, {INT64_C(1380575040207655000), 0x0000, 0x0002, 0}, {INT64_C(1380575040207655000), 0x0003, 0x0035, 1624}, {INT64_C(1380575040207655000), 0x0003, 0x0036, 3610}, {INT64_C(1380575040207655000), 0x0003, 0x0034, 1}, {INT64_C(1380575040207655000), 0x0003, 0x0030, 384}, {INT64_C(1380575040207655000), 0x0003, 0x0031, 320}, {INT64_C(1380575040207655000), 0x0000, 0x0002, 0}, {INT64_C(1380575040207655000), 0x0000, 0x0000, 0}, {INT64_C(1380575040219653000), 0x0003, 0x0000, 2560}, {INT64_C(1380575040219653000), 0x0003, 0x0001, 5225}, {INT64_C(1380575040219653000), 0x0003, 0x0035, 2560}, {INT64_C(1380575040219653000), 0x0003, 0x0036, 5225}, {INT64_C(1380575040219653000), 0x0003, 0x0034, 0}, {INT64_C(1380575040219653000), 0x0003, 0x0030, 320}, {INT64_C(1380575040219653000), 0x0003, 0x0031, 128}, {INT64_C(1380575040219653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040219653000), 0x0003, 0x0035, 1886}, {INT64_C(1380575040219653000), 0x0003, 0x0036, 4813}, {INT64_C(1380575040219653000), 0x0003, 0x0034, 0}, {INT64_C(1380575040219653000), 0x0003, 0x0030, 480}, {INT64_C(1380575040219653000), 0x0003, 0x0031, 256}, {INT64_C(1380575040219653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040219653000), 0x0003, 0x0035, 1789}, {INT64_C(1380575040219653000), 0x0003, 0x0036, 3590}, {INT64_C(1380575040219653000), 0x0003, 0x0034, 1}, {INT64_C(1380575040219653000), 0x0003, 0x0030, 384}, {INT64_C(1380575040219653000), 0x0003, 0x0031, 320}, {INT64_C(1380575040219653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040219653000), 0x0000, 0x0000, 0}, {INT64_C(1380575040225654000), 0x0003, 0x0000, 2688}, {INT64_C(1380575040225654000), 0x0003, 0x0001, 5100}, {INT64_C(1380575040225654000), 0x0003, 0x0035, 2688}, {INT64_C(1380575040225654000), 0x0003, 0x0036, 5100}, {INT64_C(1380575040225654000), 0x0003, 0x0034, 0}, {INT64_C(1380575040225654000), 0x0003, 0x0030, 480}, {INT64_C(1380575040225654000), 0x0003, 0x0031, 128}, {INT64_C(1380575040225654000), 0x0000, 0x0002, 0}, {INT64_C(1380575040225654000), 0x0003, 0x0035, 2027}, {INT64_C(1380575040225654000), 0x0003, 0x0036, 4717}, {INT64_C(1380575040225654000), 0x0003, 0x0034, 0}, {INT64_C(1380575040225654000), 0x0003, 0x0030, 480}, {INT64_C(1380575040225654000), 0x0003, 0x0031, 256}, {INT64_C(1380575040225654000), 0x0000, 0x0002, 0}, {INT64_C(1380575040225654000), 0x0003, 0x0035, 1968}, {INT64_C(1380575040225654000), 0x0003, 0x0036, 3570}, {INT64_C(1380575040225654000), 0x0003, 0x0034, 1}, {INT64_C(1380575040225654000), 0x0003, 0x0030, 384}, {INT64_C(1380575040225654000), 0x0003, 0x0031, 320}, {INT64_C(1380575040225654000), 0x0000, 0x0002, 0}, {INT64_C(1380575040225654000), 0x0000, 0x0000, 0}, {INT64_C(1380575040239650000), 0x0003, 0x0000, 2853}, {INT64_C(1380575040239650000), 0x0003, 0x0001, 5006}, {INT64_C(1380575040239650000), 0x0003, 0x0035, 2853}, {INT64_C(1380575040239650000), 0x0003, 0x0036, 5006}, {INT64_C(1380575040239650000), 0x0003, 0x0034, 0}, {INT64_C(1380575040239650000), 0x0003, 0x0030, 320}, {INT64_C(1380575040239650000), 0x0003, 0x0031, 256}, {INT64_C(1380575040239650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040239650000), 0x0003, 0x0035, 2223}, {INT64_C(1380575040239650000), 0x0003, 0x0036, 4599}, {INT64_C(1380575040239650000), 0x0003, 0x0034, 0}, {INT64_C(1380575040239650000), 0x0003, 0x0030, 800}, {INT64_C(1380575040239650000), 0x0003, 0x0031, 384}, {INT64_C(1380575040239650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040239650000), 0x0003, 0x0035, 2134}, {INT64_C(1380575040239650000), 0x0003, 0x0036, 3537}, {INT64_C(1380575040239650000), 0x0003, 0x0034, 1}, {INT64_C(1380575040239650000), 0x0003, 0x0030, 384}, {INT64_C(1380575040239650000), 0x0003, 0x0031, 320}, {INT64_C(1380575040239650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040239650000), 0x0000, 0x0000, 0}, {INT64_C(1380575040257651000), 0x0003, 0x0000, 3054}, {INT64_C(1380575040257651000), 0x0003, 0x0001, 4901}, {INT64_C(1380575040257651000), 0x0003, 0x0035, 3054}, {INT64_C(1380575040257651000), 0x0003, 0x0036, 4901}, {INT64_C(1380575040257651000), 0x0003, 0x0034, 0}, {INT64_C(1380575040257651000), 0x0003, 0x0030, 320}, {INT64_C(1380575040257651000), 0x0003, 0x0031, 256}, {INT64_C(1380575040257651000), 0x0000, 0x0002, 0}, {INT64_C(1380575040257651000), 0x0003, 0x0035, 2397}, {INT64_C(1380575040257651000), 0x0003, 0x0036, 4504}, {INT64_C(1380575040257651000), 0x0003, 0x0034, 0}, {INT64_C(1380575040257651000), 0x0003, 0x0030, 480}, {INT64_C(1380575040257651000), 0x0003, 0x0031, 256}, {INT64_C(1380575040257651000), 0x0000, 0x0002, 0}, {INT64_C(1380575040257651000), 0x0003, 0x0035, 2343}, {INT64_C(1380575040257651000), 0x0003, 0x0036, 3435}, {INT64_C(1380575040257651000), 0x0003, 0x0034, 1}, {INT64_C(1380575040257651000), 0x0003, 0x0030, 384}, {INT64_C(1380575040257651000), 0x0003, 0x0031, 320}, {INT64_C(1380575040257651000), 0x0000, 0x0002, 0}, {INT64_C(1380575040257651000), 0x0000, 0x0000, 0}, {INT64_C(1380575040277653000), 0x0003, 0x0000, 3235}, {INT64_C(1380575040277653000), 0x0003, 0x0001, 4763}, {INT64_C(1380575040277653000), 0x0003, 0x0035, 3235}, {INT64_C(1380575040277653000), 0x0003, 0x0036, 4763}, {INT64_C(1380575040277653000), 0x0003, 0x0034, 0}, {INT64_C(1380575040277653000), 0x0003, 0x0030, 640}, {INT64_C(1380575040277653000), 0x0003, 0x0031, 256}, {INT64_C(1380575040277653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040277653000), 0x0003, 0x0035, 2603}, {INT64_C(1380575040277653000), 0x0003, 0x0036, 4386}, {INT64_C(1380575040277653000), 0x0003, 0x0034, 0}, {INT64_C(1380575040277653000), 0x0003, 0x0030, 800}, {INT64_C(1380575040277653000), 0x0003, 0x0031, 384}, {INT64_C(1380575040277653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040277653000), 0x0003, 0x0035, 2535}, {INT64_C(1380575040277653000), 0x0003, 0x0036, 3400}, {INT64_C(1380575040277653000), 0x0003, 0x0034, 1}, {INT64_C(1380575040277653000), 0x0003, 0x0030, 384}, {INT64_C(1380575040277653000), 0x0003, 0x0031, 320}, {INT64_C(1380575040277653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040277653000), 0x0000, 0x0000, 0}, {INT64_C(1380575040295652000), 0x0003, 0x0000, 3422}, {INT64_C(1380575040295652000), 0x0003, 0x0001, 4635}, {INT64_C(1380575040295652000), 0x0003, 0x0035, 3422}, {INT64_C(1380575040295652000), 0x0003, 0x0036, 4635}, {INT64_C(1380575040295652000), 0x0003, 0x0034, 0}, {INT64_C(1380575040295652000), 0x0003, 0x0030, 640}, {INT64_C(1380575040295652000), 0x0003, 0x0031, 384}, {INT64_C(1380575040295652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040295652000), 0x0003, 0x0035, 2782}, {INT64_C(1380575040295652000), 0x0003, 0x0036, 4307}, {INT64_C(1380575040295652000), 0x0003, 0x0034, 0}, {INT64_C(1380575040295652000), 0x0003, 0x0030, 800}, {INT64_C(1380575040295652000), 0x0003, 0x0031, 256}, {INT64_C(1380575040295652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040295652000), 0x0003, 0x0035, 2724}, {INT64_C(1380575040295652000), 0x0003, 0x0036, 3370}, {INT64_C(1380575040295652000), 0x0003, 0x0034, 1}, {INT64_C(1380575040295652000), 0x0003, 0x0030, 384}, {INT64_C(1380575040295652000), 0x0003, 0x0031, 320}, {INT64_C(1380575040295652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040295652000), 0x0000, 0x0000, 0}, {INT64_C(1380575040313650000), 0x0003, 0x0000, 3601}, {INT64_C(1380575040313650000), 0x0003, 0x0001, 4497}, {INT64_C(1380575040313650000), 0x0003, 0x0035, 3601}, {INT64_C(1380575040313650000), 0x0003, 0x0036, 4497}, {INT64_C(1380575040313650000), 0x0003, 0x0034, 0}, {INT64_C(1380575040313650000), 0x0003, 0x0030, 480}, {INT64_C(1380575040313650000), 0x0003, 0x0031, 384}, {INT64_C(1380575040313650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040313650000), 0x0003, 0x0035, 2982}, {INT64_C(1380575040313650000), 0x0003, 0x0036, 4205}, {INT64_C(1380575040313650000), 0x0003, 0x0034, 0}, {INT64_C(1380575040313650000), 0x0003, 0x0030, 640}, {INT64_C(1380575040313650000), 0x0003, 0x0031, 384}, {INT64_C(1380575040313650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040313650000), 0x0003, 0x0035, 2910}, {INT64_C(1380575040313650000), 0x0003, 0x0036, 3244}, {INT64_C(1380575040313650000), 0x0003, 0x0034, 1}, {INT64_C(1380575040313650000), 0x0003, 0x0030, 384}, {INT64_C(1380575040313650000), 0x0003, 0x0031, 320}, {INT64_C(1380575040313650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040313650000), 0x0000, 0x0000, 0}, {INT64_C(1380575040333652000), 0x0003, 0x0000, 3815}, {INT64_C(1380575040333652000), 0x0003, 0x0001, 4388}, {INT64_C(1380575040333652000), 0x0003, 0x0035, 3815}, {INT64_C(1380575040333652000), 0x0003, 0x0036, 4388}, {INT64_C(1380575040333652000), 0x0003, 0x0034, 0}, {INT64_C(1380575040333652000), 0x0003, 0x0030, 320}, {INT64_C(1380575040333652000), 0x0003, 0x0031, 256}, {INT64_C(1380575040333652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040333652000), 0x0003, 0x0035, 3188}, {INT64_C(1380575040333652000), 0x0003, 0x0036, 4079}, {INT64_C(1380575040333652000), 0x0003, 0x0034, 1}, {INT64_C(1380575040333652000), 0x0003, 0x0030, 512}, {INT64_C(1380575040333652000), 0x0003, 0x0031, 480}, {INT64_C(1380575040333652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040333652000), 0x0003, 0x0035, 3117}, {INT64_C(1380575040333652000), 0x0003, 0x0036, 3200}, {INT64_C(1380575040333652000), 0x0003, 0x0034, 1}, {INT64_C(1380575040333652000), 0x0003, 0x0030, 256}, {INT64_C(1380575040333652000), 0x0003, 0x0031, 160}, {INT64_C(1380575040333652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040333652000), 0x0000, 0x0000, 0}, {INT64_C(1380575040351652000), 0x0003, 0x0000, 3941}, {INT64_C(1380575040351652000), 0x0003, 0x0001, 4289}, {INT64_C(1380575040351652000), 0x0003, 0x0035, 3941}, {INT64_C(1380575040351652000), 0x0003, 0x0036, 4289}, {INT64_C(1380575040351652000), 0x0003, 0x0034, 0}, {INT64_C(1380575040351652000), 0x0003, 0x0030, 320}, {INT64_C(1380575040351652000), 0x0003, 0x0031, 256}, {INT64_C(1380575040351652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040351652000), 0x0000, 0x0000, 0}, {INT64_C(1380575040369652000), 0x0003, 0x0000, 4096}, {INT64_C(1380575040369652000), 0x0003, 0x0001, 4166}, {INT64_C(1380575040369652000), 0x0003, 0x0035, 4096}, {INT64_C(1380575040369652000), 0x0003, 0x0036, 4166}, {INT64_C(1380575040369652000), 0x0003, 0x0034, 0}, {INT64_C(1380575040369652000), 0x0003, 0x0030, 320}, {INT64_C(1380575040369652000), 0x0003, 0x0031, 128}, {INT64_C(1380575040369652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040369652000), 0x0000, 0x0000, 0}, {INT64_C(1380575040463647000), 0x0001, 0x014d, 0}, {INT64_C(1380575040463647000), 0x0001, 0x014a, 0}, {INT64_C(1380575040463647000), 0x0000, 0x0000, 0}, {INT64_C(1380575040669651000), 0x0003, 0x0035, 5861}, {INT64_C(1380575040669651000), 0x0003, 0x0036, 5441}, {INT64_C(1380575040669651000), 0x0003, 0x0034, 0}, {INT64_C(1380575040669651000), 0x0003, 0x0030, 480}, {INT64_C(1380575040669651000), 0x0003, 0x0031, 256}, {INT64_C(1380575040669651000), 0x0000, 0x0002, 0}, {INT64_C(1380575040669651000), 0x0003, 0x0035, 2759}, {INT64_C(1380575040669651000), 0x0003, 0x0036, 5283}, {INT64_C(1380575040669651000), 0x0003, 0x0034, 0}, {INT64_C(1380575040669651000), 0x0003, 0x0030, 320}, {INT64_C(1380575040669651000), 0x0003, 0x0031, 256}, {INT64_C(1380575040669651000), 0x0000, 0x0002, 0}, {INT64_C(1380575040669651000), 0x0003, 0x0035, 3449}, {INT64_C(1380575040669651000), 0x0003, 0x0036, 1480}, {INT64_C(1380575040669651000), 0x0003, 0x0034, 1}, {INT64_C(1380575040669651000), 0x0003, 0x0030, 768}, {INT64_C(1380575040669651000), 0x0003, 0x0031, 480}, {INT64_C(1380575040669651000), 0x0000, 0x0002, 0}, {INT64_C(1380575040669651000), 0x0000, 0x0000, 0}, {INT64_C(1380575040675653000), 0x0003, 0x0000, 3491}, {INT64_C(1380575040675653000), 0x0003, 0x0001, 6400}, {INT64_C(1380575040675653000), 0x0003, 0x0035, 3491}, {INT64_C(1380575040675653000), 0x0003, 0x0036, 6400}, {INT64_C(1380575040675653000), 0x0003, 0x0034, 1}, {INT64_C(1380575040675653000), 0x0003, 0x0030, 512}, {INT64_C(1380575040675653000), 0x0003, 0x0031, 160}, {INT64_C(1380575040675653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040675653000), 0x0003, 0x0035, 2768}, {INT64_C(1380575040675653000), 0x0003, 0x0036, 5228}, {INT64_C(1380575040675653000), 0x0003, 0x0034, 0}, {INT64_C(1380575040675653000), 0x0003, 0x0030, 480}, {INT64_C(1380575040675653000), 0x0003, 0x0031, 256}, {INT64_C(1380575040675653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040675653000), 0x0003, 0x0035, 3564}, {INT64_C(1380575040675653000), 0x0003, 0x0036, 5208}, {INT64_C(1380575040675653000), 0x0003, 0x0034, 0}, {INT64_C(1380575040675653000), 0x0003, 0x0030, 480}, {INT64_C(1380575040675653000), 0x0003, 0x0031, 256}, {INT64_C(1380575040675653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040675653000), 0x0003, 0x0035, 5861}, {INT64_C(1380575040675653000), 0x0003, 0x0036, 5355}, {INT64_C(1380575040675653000), 0x0003, 0x0034, 0}, {INT64_C(1380575040675653000), 0x0003, 0x0030, 480}, {INT64_C(1380575040675653000), 0x0003, 0x0031, 256}, {INT64_C(1380575040675653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040675653000), 0x0003, 0x0035, 3470}, {INT64_C(1380575040675653000), 0x0003, 0x0036, 1592}, {INT64_C(1380575040675653000), 0x0003, 0x0034, 1}, {INT64_C(1380575040675653000), 0x0003, 0x0030, 768}, {INT64_C(1380575040675653000), 0x0003, 0x0031, 480}, {INT64_C(1380575040675653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040675653000), 0x0001, 0x014d, 1}, {INT64_C(1380575040675653000), 0x0001, 0x014a, 1}, {INT64_C(1380575040675653000), 0x0000, 0x0000, 0}, {INT64_C(1380575040689652000), 0x0003, 0x0000, 3511}, {INT64_C(1380575040689652000), 0x0003, 0x0035, 3511}, {INT64_C(1380575040689652000), 0x0003, 0x0036, 6400}, {INT64_C(1380575040689652000), 0x0003, 0x0034, 1}, {INT64_C(1380575040689652000), 0x0003, 0x0030, 384}, {INT64_C(1380575040689652000), 0x0003, 0x0031, 160}, {INT64_C(1380575040689652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040689652000), 0x0003, 0x0035, 2764}, {INT64_C(1380575040689652000), 0x0003, 0x0036, 5214}, {INT64_C(1380575040689652000), 0x0003, 0x0034, 0}, {INT64_C(1380575040689652000), 0x0003, 0x0030, 480}, {INT64_C(1380575040689652000), 0x0003, 0x0031, 256}, {INT64_C(1380575040689652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040689652000), 0x0003, 0x0035, 5797}, {INT64_C(1380575040689652000), 0x0003, 0x0036, 5245}, {INT64_C(1380575040689652000), 0x0003, 0x0034, 0}, {INT64_C(1380575040689652000), 0x0003, 0x0030, 480}, {INT64_C(1380575040689652000), 0x0003, 0x0031, 256}, {INT64_C(1380575040689652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040689652000), 0x0003, 0x0035, 3408}, {INT64_C(1380575040689652000), 0x0003, 0x0036, 1552}, {INT64_C(1380575040689652000), 0x0003, 0x0034, 1}, {INT64_C(1380575040689652000), 0x0003, 0x0030, 640}, {INT64_C(1380575040689652000), 0x0003, 0x0031, 480}, {INT64_C(1380575040689652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040689652000), 0x0000, 0x0000, 0}, {INT64_C(1380575040695653000), 0x0003, 0x0000, 3490}, {INT64_C(1380575040695653000), 0x0003, 0x0001, 6240}, {INT64_C(1380575040695653000), 0x0003, 0x0035, 3490}, {INT64_C(1380575040695653000), 0x0003, 0x0036, 6240}, {INT64_C(1380575040695653000), 0x0003, 0x0034, 1}, {INT64_C(1380575040695653000), 0x0003, 0x0030, 384}, {INT64_C(1380575040695653000), 0x0003, 0x0031, 160}, {INT64_C(1380575040695653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040695653000), 0x0003, 0x0035, 4595}, {INT64_C(1380575040695653000), 0x0003, 0x0036, 6240}, {INT64_C(1380575040695653000), 0x0003, 0x0034, 1}, {INT64_C(1380575040695653000), 0x0003, 0x0030, 256}, {INT64_C(1380575040695653000), 0x0003, 0x0031, 160}, {INT64_C(1380575040695653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040695653000), 0x0003, 0x0035, 2761}, {INT64_C(1380575040695653000), 0x0003, 0x0036, 5200}, {INT64_C(1380575040695653000), 0x0003, 0x0034, 0}, {INT64_C(1380575040695653000), 0x0003, 0x0030, 320}, {INT64_C(1380575040695653000), 0x0003, 0x0031, 256}, {INT64_C(1380575040695653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040695653000), 0x0003, 0x0035, 5760}, {INT64_C(1380575040695653000), 0x0003, 0x0036, 5092}, {INT64_C(1380575040695653000), 0x0003, 0x0034, 0}, {INT64_C(1380575040695653000), 0x0003, 0x0030, 480}, {INT64_C(1380575040695653000), 0x0003, 0x0031, 128}, {INT64_C(1380575040695653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040695653000), 0x0003, 0x0035, 3359}, {INT64_C(1380575040695653000), 0x0003, 0x0036, 1461}, {INT64_C(1380575040695653000), 0x0003, 0x0034, 1}, {INT64_C(1380575040695653000), 0x0003, 0x0030, 512}, {INT64_C(1380575040695653000), 0x0003, 0x0031, 480}, {INT64_C(1380575040695653000), 0x0000, 0x0002, 0}, {INT64_C(1380575040695653000), 0x0000, 0x0000, 0}, {INT64_C(1380575040707652000), 0x0003, 0x0000, 3477}, {INT64_C(1380575040707652000), 0x0003, 0x0035, 3477}, {INT64_C(1380575040707652000), 0x0003, 0x0036, 6240}, {INT64_C(1380575040707652000), 0x0003, 0x0034, 1}, {INT64_C(1380575040707652000), 0x0003, 0x0030, 384}, {INT64_C(1380575040707652000), 0x0003, 0x0031, 160}, {INT64_C(1380575040707652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040707652000), 0x0003, 0x0035, 4582}, {INT64_C(1380575040707652000), 0x0003, 0x0036, 6240}, {INT64_C(1380575040707652000), 0x0003, 0x0034, 1}, {INT64_C(1380575040707652000), 0x0003, 0x0030, 256}, {INT64_C(1380575040707652000), 0x0003, 0x0031, 160}, {INT64_C(1380575040707652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040707652000), 0x0003, 0x0035, 2751}, {INT64_C(1380575040707652000), 0x0003, 0x0036, 5089}, {INT64_C(1380575040707652000), 0x0003, 0x0034, 0}, {INT64_C(1380575040707652000), 0x0003, 0x0030, 320}, {INT64_C(1380575040707652000), 0x0003, 0x0031, 256}, {INT64_C(1380575040707652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040707652000), 0x0003, 0x0035, 5667}, {INT64_C(1380575040707652000), 0x0003, 0x0036, 4955}, {INT64_C(1380575040707652000), 0x0003, 0x0034, 0}, {INT64_C(1380575040707652000), 0x0003, 0x0030, 480}, {INT64_C(1380575040707652000), 0x0003, 0x0031, 256}, {INT64_C(1380575040707652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040707652000), 0x0003, 0x0035, 3456}, {INT64_C(1380575040707652000), 0x0003, 0x0036, 4909}, {INT64_C(1380575040707652000), 0x0003, 0x0034, 0}, {INT64_C(1380575040707652000), 0x0003, 0x0030, 320}, {INT64_C(1380575040707652000), 0x0003, 0x0031, 128}, {INT64_C(1380575040707652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040707652000), 0x0003, 0x0035, 3333}, {INT64_C(1380575040707652000), 0x0003, 0x0036, 1455}, {INT64_C(1380575040707652000), 0x0003, 0x0034, 1}, {INT64_C(1380575040707652000), 0x0003, 0x0030, 512}, {INT64_C(1380575040707652000), 0x0003, 0x0031, 480}, {INT64_C(1380575040707652000), 0x0000, 0x0002, 0}, {INT64_C(1380575040707652000), 0x0000, 0x0000, 0}, {INT64_C(1380575040713650000), 0x0003, 0x0000, 3453}, {INT64_C(1380575040713650000), 0x0003, 0x0001, 6154}, {INT64_C(1380575040713650000), 0x0003, 0x0035, 3453}, {INT64_C(1380575040713650000), 0x0003, 0x0036, 6154}, {INT64_C(1380575040713650000), 0x0003, 0x0034, 1}, {INT64_C(1380575040713650000), 0x0003, 0x0030, 384}, {INT64_C(1380575040713650000), 0x0003, 0x0031, 320}, {INT64_C(1380575040713650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040713650000), 0x0003, 0x0035, 4569}, {INT64_C(1380575040713650000), 0x0003, 0x0036, 6143}, {INT64_C(1380575040713650000), 0x0003, 0x0034, 0}, {INT64_C(1380575040713650000), 0x0003, 0x0030, 320}, {INT64_C(1380575040713650000), 0x0003, 0x0031, 256}, {INT64_C(1380575040713650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040713650000), 0x0003, 0x0035, 2751}, {INT64_C(1380575040713650000), 0x0003, 0x0036, 5038}, {INT64_C(1380575040713650000), 0x0003, 0x0034, 0}, {INT64_C(1380575040713650000), 0x0003, 0x0030, 320}, {INT64_C(1380575040713650000), 0x0003, 0x0031, 256}, {INT64_C(1380575040713650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040713650000), 0x0003, 0x0035, 5583}, {INT64_C(1380575040713650000), 0x0003, 0x0036, 4903}, {INT64_C(1380575040713650000), 0x0003, 0x0034, 0}, {INT64_C(1380575040713650000), 0x0003, 0x0030, 480}, {INT64_C(1380575040713650000), 0x0003, 0x0031, 256}, {INT64_C(1380575040713650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040713650000), 0x0003, 0x0035, 3405}, {INT64_C(1380575040713650000), 0x0003, 0x0036, 4960}, {INT64_C(1380575040713650000), 0x0003, 0x0034, 1}, {INT64_C(1380575040713650000), 0x0003, 0x0030, 256}, {INT64_C(1380575040713650000), 0x0003, 0x0031, 160}, {INT64_C(1380575040713650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040713650000), 0x0003, 0x0035, 3334}, {INT64_C(1380575040713650000), 0x0003, 0x0036, 1491}, {INT64_C(1380575040713650000), 0x0003, 0x0034, 1}, {INT64_C(1380575040713650000), 0x0003, 0x0030, 384}, {INT64_C(1380575040713650000), 0x0003, 0x0031, 320}, {INT64_C(1380575040713650000), 0x0000, 0x0002, 0}, {INT64_C(1380575040713650000), 0x0000, 0x0000, 0}, {INT64_C(1380575041249641000), 0x0003, 0x0035, 3500}, {INT64_C(1380575041249641000), 0x0003, 0x0036, 5341}, {INT64_C(1380575041249641000), 0x0003, 0x0034, 0}, {INT64_C(1380575041249641000), 0x0003, 0x0030, 320}, {INT64_C(1380575041249641000), 0x0003, 0x0031, 256}, {INT64_C(1380575041249641000), 0x0000, 0x0002, 0}, {INT64_C(1380575041249641000), 0x0001, 0x014d, 0}, {INT64_C(1380575041249641000), 0x0001, 0x014a, 0}, {INT64_C(1380575041249641000), 0x0000, 0x0000, 0}, {INT64_C(1380575041255646000), 0x0003, 0x0000, 1475}, {INT64_C(1380575041255646000), 0x0003, 0x0001, 5920}, {INT64_C(1380575041255646000), 0x0003, 0x0035, 1475}, {INT64_C(1380575041255646000), 0x0003, 0x0036, 5920}, {INT64_C(1380575041255646000), 0x0003, 0x0034, 1}, {INT64_C(1380575041255646000), 0x0003, 0x0030, 256}, {INT64_C(1380575041255646000), 0x0003, 0x0031, 160}, {INT64_C(1380575041255646000), 0x0000, 0x0002, 0}, {INT64_C(1380575041255646000), 0x0003, 0x0035, 3501}, {INT64_C(1380575041255646000), 0x0003, 0x0036, 5296}, {INT64_C(1380575041255646000), 0x0003, 0x0034, 0}, {INT64_C(1380575041255646000), 0x0003, 0x0030, 320}, {INT64_C(1380575041255646000), 0x0003, 0x0031, 256}, {INT64_C(1380575041255646000), 0x0000, 0x0002, 0}, {INT64_C(1380575041255646000), 0x0001, 0x014d, 1}, {INT64_C(1380575041255646000), 0x0001, 0x014a, 1}, {INT64_C(1380575041255646000), 0x0000, 0x0000, 0}, {INT64_C(1380575041269649000), 0x0003, 0x0000, 1505}, {INT64_C(1380575041269649000), 0x0003, 0x0035, 1505}, {INT64_C(1380575041269649000), 0x0003, 0x0036, 5920}, {INT64_C(1380575041269649000), 0x0003, 0x0034, 1}, {INT64_C(1380575041269649000), 0x0003, 0x0030, 256}, {INT64_C(1380575041269649000), 0x0003, 0x0031, 160}, {INT64_C(1380575041269649000), 0x0000, 0x0002, 0}, {INT64_C(1380575041269649000), 0x0003, 0x0035, 3520}, {INT64_C(1380575041269649000), 0x0003, 0x0036, 5120}, {INT64_C(1380575041269649000), 0x0003, 0x0034, 1}, {INT64_C(1380575041269649000), 0x0003, 0x0030, 256}, {INT64_C(1380575041269649000), 0x0003, 0x0031, 160}, {INT64_C(1380575041269649000), 0x0000, 0x0002, 0}, {INT64_C(1380575041269649000), 0x0000, 0x0000, 0}, {INT64_C(1380575041275647000), 0x0003, 0x0000, 1522}, {INT64_C(1380575041275647000), 0x0003, 0x0001, 5677}, {INT64_C(1380575041275647000), 0x0003, 0x0035, 1522}, {INT64_C(1380575041275647000), 0x0003, 0x0036, 5677}, {INT64_C(1380575041275647000), 0x0003, 0x0034, 0}, {INT64_C(1380575041275647000), 0x0003, 0x0030, 320}, {INT64_C(1380575041275647000), 0x0003, 0x0031, 256}, {INT64_C(1380575041275647000), 0x0000, 0x0002, 0}, {INT64_C(1380575041275647000), 0x0003, 0x0035, 3516}, {INT64_C(1380575041275647000), 0x0003, 0x0036, 4854}, {INT64_C(1380575041275647000), 0x0003, 0x0034, 0}, {INT64_C(1380575041275647000), 0x0003, 0x0030, 480}, {INT64_C(1380575041275647000), 0x0003, 0x0031, 256}, {INT64_C(1380575041275647000), 0x0000, 0x0002, 0}, {INT64_C(1380575041275647000), 0x0000, 0x0000, 0}, {INT64_C(1380575041287646000), 0x0003, 0x0000, 1583}, {INT64_C(1380575041287646000), 0x0003, 0x0001, 5531}, {INT64_C(1380575041287646000), 0x0003, 0x0035, 1583}, {INT64_C(1380575041287646000), 0x0003, 0x0036, 5531}, {INT64_C(1380575041287646000), 0x0003, 0x0034, 0}, {INT64_C(1380575041287646000), 0x0003, 0x0030, 320}, {INT64_C(1380575041287646000), 0x0003, 0x0031, 256}, {INT64_C(1380575041287646000), 0x0000, 0x0002, 0}, {INT64_C(1380575041287646000), 0x0003, 0x0035, 3519}, {INT64_C(1380575041287646000), 0x0003, 0x0036, 4649}, {INT64_C(1380575041287646000), 0x0003, 0x0034, 0}, {INT64_C(1380575041287646000), 0x0003, 0x0030, 480}, {INT64_C(1380575041287646000), 0x0003, 0x0031, 256}, {INT64_C(1380575041287646000), 0x0000, 0x0002, 0}, {INT64_C(1380575041287646000), 0x0000, 0x0000, 0}, {INT64_C(1380575041293648000), 0x0003, 0x0000, 2576}, {INT64_C(1380575041293648000), 0x0003, 0x0001, 5756}, {INT64_C(1380575041293648000), 0x0003, 0x0035, 2576}, {INT64_C(1380575041293648000), 0x0003, 0x0036, 5756}, {INT64_C(1380575041293648000), 0x0003, 0x0034, 0}, {INT64_C(1380575041293648000), 0x0003, 0x0030, 320}, {INT64_C(1380575041293648000), 0x0003, 0x0031, 256}, {INT64_C(1380575041293648000), 0x0000, 0x0002, 0}, {INT64_C(1380575041293648000), 0x0003, 0x0035, 1595}, {INT64_C(1380575041293648000), 0x0003, 0x0036, 5372}, {INT64_C(1380575041293648000), 0x0003, 0x0034, 0}, {INT64_C(1380575041293648000), 0x0003, 0x0030, 480}, {INT64_C(1380575041293648000), 0x0003, 0x0031, 256}, {INT64_C(1380575041293648000), 0x0000, 0x0002, 0}, {INT64_C(1380575041293648000), 0x0003, 0x0035, 3525}, {INT64_C(1380575041293648000), 0x0003, 0x0036, 4498}, {INT64_C(1380575041293648000), 0x0003, 0x0034, 0}, {INT64_C(1380575041293648000), 0x0003, 0x0030, 480}, {INT64_C(1380575041293648000), 0x0003, 0x0031, 256}, {INT64_C(1380575041293648000), 0x0000, 0x0002, 0}, {INT64_C(1380575041293648000), 0x0000, 0x0000, 0}, {INT64_C(1380575041305648000), 0x0003, 0x0000, 2593}, {INT64_C(1380575041305648000), 0x0003, 0x0001, 5760}, {INT64_C(1380575041305648000), 0x0003, 0x0035, 2593}, {INT64_C(1380575041305648000), 0x0003, 0x0036, 5760}, {INT64_C(1380575041305648000), 0x0003, 0x0034, 1}, {INT64_C(1380575041305648000), 0x0003, 0x0030, 256}, {INT64_C(1380575041305648000), 0x0003, 0x0031, 160}, {INT64_C(1380575041305648000), 0x0000, 0x0002, 0}, {INT64_C(1380575041305648000), 0x0003, 0x0035, 1619}, {INT64_C(1380575041305648000), 0x0003, 0x0036, 5302}, {INT64_C(1380575041305648000), 0x0003, 0x0034, 0}, {INT64_C(1380575041305648000), 0x0003, 0x0030, 320}, {INT64_C(1380575041305648000), 0x0003, 0x0031, 256}, {INT64_C(1380575041305648000), 0x0000, 0x0002, 0}, {INT64_C(1380575041305648000), 0x0003, 0x0035, 3529}, {INT64_C(1380575041305648000), 0x0003, 0x0036, 4388}, {INT64_C(1380575041305648000), 0x0003, 0x0034, 0}, {INT64_C(1380575041305648000), 0x0003, 0x0030, 320}, {INT64_C(1380575041305648000), 0x0003, 0x0031, 256}, {INT64_C(1380575041305648000), 0x0000, 0x0002, 0}, {INT64_C(1380575041305648000), 0x0000, 0x0000, 0}, {INT64_C(1380575041311647000), 0x0003, 0x0000, 2632}, {INT64_C(1380575041311647000), 0x0003, 0x0001, 5539}, {INT64_C(1380575041311647000), 0x0003, 0x0035, 2632}, {INT64_C(1380575041311647000), 0x0003, 0x0036, 5539}, {INT64_C(1380575041311647000), 0x0003, 0x0034, 0}, {INT64_C(1380575041311647000), 0x0003, 0x0030, 320}, {INT64_C(1380575041311647000), 0x0003, 0x0031, 256}, {INT64_C(1380575041311647000), 0x0000, 0x0002, 0}, {INT64_C(1380575041311647000), 0x0003, 0x0035, 1725}, {INT64_C(1380575041311647000), 0x0003, 0x0036, 5126}, {INT64_C(1380575041311647000), 0x0003, 0x0034, 0}, {INT64_C(1380575041311647000), 0x0003, 0x0030, 320}, {INT64_C(1380575041311647000), 0x0003, 0x0031, 256}, {INT64_C(1380575041311647000), 0x0000, 0x0002, 0}, {INT64_C(1380575041311647000), 0x0003, 0x0035, 3544}, {INT64_C(1380575041311647000), 0x0003, 0x0036, 4289}, {INT64_C(1380575041311647000), 0x0003, 0x0034, 0}, {INT64_C(1380575041311647000), 0x0003, 0x0030, 480}, {INT64_C(1380575041311647000), 0x0003, 0x0031, 256}, {INT64_C(1380575041311647000), 0x0000, 0x0002, 0}, {INT64_C(1380575041311647000), 0x0000, 0x0000, 0}, {INT64_C(1380575041325644000), 0x0003, 0x0000, 2674}, {INT64_C(1380575041325644000), 0x0003, 0x0001, 5367}, {INT64_C(1380575041325644000), 0x0003, 0x0035, 2674}, {INT64_C(1380575041325644000), 0x0003, 0x0036, 5367}, {INT64_C(1380575041325644000), 0x0003, 0x0034, 0}, {INT64_C(1380575041325644000), 0x0003, 0x0030, 320}, {INT64_C(1380575041325644000), 0x0003, 0x0031, 256}, {INT64_C(1380575041325644000), 0x0000, 0x0002, 0}, {INT64_C(1380575041325644000), 0x0003, 0x0035, 1754}, {INT64_C(1380575041325644000), 0x0003, 0x0036, 4982}, {INT64_C(1380575041325644000), 0x0003, 0x0034, 0}, {INT64_C(1380575041325644000), 0x0003, 0x0030, 320}, {INT64_C(1380575041325644000), 0x0003, 0x0031, 256}, {INT64_C(1380575041325644000), 0x0000, 0x0002, 0}, {INT64_C(1380575041325644000), 0x0003, 0x0035, 3552}, {INT64_C(1380575041325644000), 0x0003, 0x0036, 4132}, {INT64_C(1380575041325644000), 0x0003, 0x0034, 0}, {INT64_C(1380575041325644000), 0x0003, 0x0030, 480}, {INT64_C(1380575041325644000), 0x0003, 0x0031, 256}, {INT64_C(1380575041325644000), 0x0000, 0x0002, 0}, {INT64_C(1380575041325644000), 0x0000, 0x0000, 0}, {INT64_C(1380575041331646000), 0x0003, 0x0000, 2720}, {INT64_C(1380575041331646000), 0x0003, 0x0001, 5176}, {INT64_C(1380575041331646000), 0x0003, 0x0035, 2720}, {INT64_C(1380575041331646000), 0x0003, 0x0036, 5176}, {INT64_C(1380575041331646000), 0x0003, 0x0034, 0}, {INT64_C(1380575041331646000), 0x0003, 0x0030, 480}, {INT64_C(1380575041331646000), 0x0003, 0x0031, 256}, {INT64_C(1380575041331646000), 0x0000, 0x0002, 0}, {INT64_C(1380575041331646000), 0x0003, 0x0035, 1792}, {INT64_C(1380575041331646000), 0x0003, 0x0036, 4738}, {INT64_C(1380575041331646000), 0x0003, 0x0034, 0}, {INT64_C(1380575041331646000), 0x0003, 0x0030, 640}, {INT64_C(1380575041331646000), 0x0003, 0x0031, 128}, {INT64_C(1380575041331646000), 0x0000, 0x0002, 0}, {INT64_C(1380575041331646000), 0x0003, 0x0035, 3580}, {INT64_C(1380575041331646000), 0x0003, 0x0036, 4016}, {INT64_C(1380575041331646000), 0x0003, 0x0034, 1}, {INT64_C(1380575041331646000), 0x0003, 0x0030, 384}, {INT64_C(1380575041331646000), 0x0003, 0x0031, 320}, {INT64_C(1380575041331646000), 0x0000, 0x0002, 0}, {INT64_C(1380575041331646000), 0x0000, 0x0000, 0}, {INT64_C(1380575041343647000), 0x0003, 0x0000, 2770}, {INT64_C(1380575041343647000), 0x0003, 0x0001, 4967}, {INT64_C(1380575041343647000), 0x0003, 0x0035, 2770}, {INT64_C(1380575041343647000), 0x0003, 0x0036, 4967}, {INT64_C(1380575041343647000), 0x0003, 0x0034, 0}, {INT64_C(1380575041343647000), 0x0003, 0x0030, 640}, {INT64_C(1380575041343647000), 0x0003, 0x0031, 256}, {INT64_C(1380575041343647000), 0x0000, 0x0002, 0}, {INT64_C(1380575041343647000), 0x0003, 0x0035, 1869}, {INT64_C(1380575041343647000), 0x0003, 0x0036, 4493}, {INT64_C(1380575041343647000), 0x0003, 0x0034, 0}, {INT64_C(1380575041343647000), 0x0003, 0x0030, 640}, {INT64_C(1380575041343647000), 0x0003, 0x0031, 256}, {INT64_C(1380575041343647000), 0x0000, 0x0002, 0}, {INT64_C(1380575041343647000), 0x0003, 0x0035, 3582}, {INT64_C(1380575041343647000), 0x0003, 0x0036, 3840}, {INT64_C(1380575041343647000), 0x0003, 0x0034, 1}, {INT64_C(1380575041343647000), 0x0003, 0x0030, 384}, {INT64_C(1380575041343647000), 0x0003, 0x0031, 160}, {INT64_C(1380575041343647000), 0x0000, 0x0002, 0}, {INT64_C(1380575041343647000), 0x0000, 0x0000, 0}, {INT64_C(1380575041361648000), 0x0003, 0x0000, 2809}, {INT64_C(1380575041361648000), 0x0003, 0x0001, 4729}, {INT64_C(1380575041361648000), 0x0003, 0x0035, 2809}, {INT64_C(1380575041361648000), 0x0003, 0x0036, 4729}, {INT64_C(1380575041361648000), 0x0003, 0x0034, 0}, {INT64_C(1380575041361648000), 0x0003, 0x0030, 480}, {INT64_C(1380575041361648000), 0x0003, 0x0031, 384}, {INT64_C(1380575041361648000), 0x0000, 0x0002, 0}, {INT64_C(1380575041361648000), 0x0003, 0x0035, 1915}, {INT64_C(1380575041361648000), 0x0003, 0x0036, 4233}, {INT64_C(1380575041361648000), 0x0003, 0x0034, 0}, {INT64_C(1380575041361648000), 0x0003, 0x0030, 480}, {INT64_C(1380575041361648000), 0x0003, 0x0031, 256}, {INT64_C(1380575041361648000), 0x0000, 0x0002, 0}, {INT64_C(1380575041361648000), 0x0000, 0x0000, 0}, {INT64_C(1380575041381645000), 0x0003, 0x0000, 2880}, {INT64_C(1380575041381645000), 0x0003, 0x0001, 4440}, {INT64_C(1380575041381645000), 0x0003, 0x0035, 2880}, {INT64_C(1380575041381645000), 0x0003, 0x0036, 4440}, {INT64_C(1380575041381645000), 0x0003, 0x0034, 0}, {INT64_C(1380575041381645000), 0x0003, 0x0030, 480}, {INT64_C(1380575041381645000), 0x0003, 0x0031, 256}, {INT64_C(1380575041381645000), 0x0000, 0x0002, 0}, {INT64_C(1380575041381645000), 0x0000, 0x0000, 0}, {INT64_C(1380575041399644000), 0x0003, 0x0000, 2981}, {INT64_C(1380575041399644000), 0x0003, 0x0001, 4126}, {INT64_C(1380575041399644000), 0x0003, 0x0035, 2981}, {INT64_C(1380575041399644000), 0x0003, 0x0036, 4126}, {INT64_C(1380575041399644000), 0x0003, 0x0034, 0}, {INT64_C(1380575041399644000), 0x0003, 0x0030, 320}, {INT64_C(1380575041399644000), 0x0003, 0x0031, 256}, {INT64_C(1380575041399644000), 0x0000, 0x0002, 0}, {INT64_C(1380575041399644000), 0x0000, 0x0000, 0}, {INT64_C(1380575041493641000), 0x0001, 0x014d, 0}, {INT64_C(1380575041493641000), 0x0001, 0x014a, 0}, {INT64_C(1380575041493641000), 0x0000, 0x0000, 0}, {INT64_C(1380575041855641000), 0x0003, 0x0000, 7653}, {INT64_C(1380575041855641000), 0x0003, 0x0001, 4420}, {INT64_C(1380575041855641000), 0x0003, 0x0035, 7653}, {INT64_C(1380575041855641000), 0x0003, 0x0036, 4420}, {INT64_C(1380575041855641000), 0x0003, 0x0034, 0}, {INT64_C(1380575041855641000), 0x0003, 0x0030, 320}, {INT64_C(1380575041855641000), 0x0003, 0x0031, 256}, {INT64_C(1380575041855641000), 0x0000, 0x0002, 0}, {INT64_C(1380575041855641000), 0x0001, 0x014d, 1}, {INT64_C(1380575041855641000), 0x0001, 0x014a, 1}, {INT64_C(1380575041855641000), 0x0000, 0x0000, 0}, {INT64_C(1380575041867642000), 0x0003, 0x0000, 7596}, {INT64_C(1380575041867642000), 0x0003, 0x0001, 4360}, {INT64_C(1380575041867642000), 0x0003, 0x0035, 7596}, {INT64_C(1380575041867642000), 0x0003, 0x0036, 4360}, {INT64_C(1380575041867642000), 0x0003, 0x0034, 0}, {INT64_C(1380575041867642000), 0x0003, 0x0030, 480}, {INT64_C(1380575041867642000), 0x0003, 0x0031, 256}, {INT64_C(1380575041867642000), 0x0000, 0x0002, 0}, {INT64_C(1380575041867642000), 0x0000, 0x0000, 0}, {INT64_C(1380575041873641000), 0x0003, 0x0000, 7552}, {INT64_C(1380575041873641000), 0x0003, 0x0001, 4280}, {INT64_C(1380575041873641000), 0x0003, 0x0035, 7552}, {INT64_C(1380575041873641000), 0x0003, 0x0036, 4280}, {INT64_C(1380575041873641000), 0x0003, 0x0034, 0}, {INT64_C(1380575041873641000), 0x0003, 0x0030, 480}, {INT64_C(1380575041873641000), 0x0003, 0x0031, 128}, {INT64_C(1380575041873641000), 0x0000, 0x0002, 0}, {INT64_C(1380575041873641000), 0x0000, 0x0000, 0}, {INT64_C(1380575041887645000), 0x0003, 0x0000, 5717}, {INT64_C(1380575041887645000), 0x0003, 0x0001, 6240}, {INT64_C(1380575041887645000), 0x0003, 0x0035, 5717}, {INT64_C(1380575041887645000), 0x0003, 0x0036, 6240}, {INT64_C(1380575041887645000), 0x0003, 0x0034, 1}, {INT64_C(1380575041887645000), 0x0003, 0x0030, 256}, {INT64_C(1380575041887645000), 0x0003, 0x0031, 160}, {INT64_C(1380575041887645000), 0x0000, 0x0002, 0}, {INT64_C(1380575041887645000), 0x0003, 0x0035, 6784}, {INT64_C(1380575041887645000), 0x0003, 0x0036, 5759}, {INT64_C(1380575041887645000), 0x0003, 0x0034, 0}, {INT64_C(1380575041887645000), 0x0003, 0x0030, 320}, {INT64_C(1380575041887645000), 0x0003, 0x0031, 128}, {INT64_C(1380575041887645000), 0x0000, 0x0002, 0}, {INT64_C(1380575041887645000), 0x0003, 0x0035, 7552}, {INT64_C(1380575041887645000), 0x0003, 0x0036, 4198}, {INT64_C(1380575041887645000), 0x0003, 0x0034, 0}, {INT64_C(1380575041887645000), 0x0003, 0x0030, 320}, {INT64_C(1380575041887645000), 0x0003, 0x0031, 128}, {INT64_C(1380575041887645000), 0x0000, 0x0002, 0}, {INT64_C(1380575041887645000), 0x0000, 0x0000, 0}, {INT64_C(1380575041893643000), 0x0003, 0x0000, 5696}, {INT64_C(1380575041893643000), 0x0003, 0x0035, 5696}, {INT64_C(1380575041893643000), 0x0003, 0x0036, 6240}, {INT64_C(1380575041893643000), 0x0003, 0x0034, 1}, {INT64_C(1380575041893643000), 0x0003, 0x0030, 256}, {INT64_C(1380575041893643000), 0x0003, 0x0031, 160}, {INT64_C(1380575041893643000), 0x0000, 0x0002, 0}, {INT64_C(1380575041893643000), 0x0003, 0x0035, 7424}, {INT64_C(1380575041893643000), 0x0003, 0x0036, 4135}, {INT64_C(1380575041893643000), 0x0003, 0x0034, 0}, {INT64_C(1380575041893643000), 0x0003, 0x0030, 480}, {INT64_C(1380575041893643000), 0x0003, 0x0031, 128}, {INT64_C(1380575041893643000), 0x0000, 0x0002, 0}, {INT64_C(1380575041893643000), 0x0000, 0x0000, 0}, {INT64_C(1380575041905644000), 0x0003, 0x0000, 5643}, {INT64_C(1380575041905644000), 0x0003, 0x0001, 6080}, {INT64_C(1380575041905644000), 0x0003, 0x0035, 5643}, {INT64_C(1380575041905644000), 0x0003, 0x0036, 6080}, {INT64_C(1380575041905644000), 0x0003, 0x0034, 1}, {INT64_C(1380575041905644000), 0x0003, 0x0030, 384}, {INT64_C(1380575041905644000), 0x0003, 0x0031, 160}, {INT64_C(1380575041905644000), 0x0000, 0x0002, 0}, {INT64_C(1380575041905644000), 0x0003, 0x0035, 4280}, {INT64_C(1380575041905644000), 0x0003, 0x0036, 5280}, {INT64_C(1380575041905644000), 0x0003, 0x0034, 1}, {INT64_C(1380575041905644000), 0x0003, 0x0030, 256}, {INT64_C(1380575041905644000), 0x0003, 0x0031, 160}, {INT64_C(1380575041905644000), 0x0000, 0x0002, 0}, {INT64_C(1380575041905644000), 0x0003, 0x0035, 7300}, {INT64_C(1380575041905644000), 0x0003, 0x0036, 4074}, {INT64_C(1380575041905644000), 0x0003, 0x0034, 0}, {INT64_C(1380575041905644000), 0x0003, 0x0030, 320}, {INT64_C(1380575041905644000), 0x0003, 0x0031, 256}, {INT64_C(1380575041905644000), 0x0000, 0x0002, 0}, {INT64_C(1380575041905644000), 0x0000, 0x0000, 0}, {INT64_C(1380575041911643000), 0x0003, 0x0000, 5572}, {INT64_C(1380575041911643000), 0x0003, 0x0035, 5572}, {INT64_C(1380575041911643000), 0x0003, 0x0036, 6080}, {INT64_C(1380575041911643000), 0x0003, 0x0034, 1}, {INT64_C(1380575041911643000), 0x0003, 0x0030, 256}, {INT64_C(1380575041911643000), 0x0003, 0x0031, 160}, {INT64_C(1380575041911643000), 0x0000, 0x0002, 0}, {INT64_C(1380575041911643000), 0x0003, 0x0035, 6528}, {INT64_C(1380575041911643000), 0x0003, 0x0036, 5489}, {INT64_C(1380575041911643000), 0x0003, 0x0034, 0}, {INT64_C(1380575041911643000), 0x0003, 0x0030, 320}, {INT64_C(1380575041911643000), 0x0003, 0x0031, 128}, {INT64_C(1380575041911643000), 0x0000, 0x0002, 0}, {INT64_C(1380575041911643000), 0x0003, 0x0035, 4213}, {INT64_C(1380575041911643000), 0x0003, 0x0036, 5174}, {INT64_C(1380575041911643000), 0x0003, 0x0034, 1}, {INT64_C(1380575041911643000), 0x0003, 0x0030, 384}, {INT64_C(1380575041911643000), 0x0003, 0x0031, 320}, {INT64_C(1380575041911643000), 0x0000, 0x0002, 0}, {INT64_C(1380575041911643000), 0x0000, 0x0000, 0}, {INT64_C(1380575041923644000), 0x0003, 0x0000, 5494}, {INT64_C(1380575041923644000), 0x0003, 0x0001, 5920}, {INT64_C(1380575041923644000), 0x0003, 0x0035, 5494}, {INT64_C(1380575041923644000), 0x0003, 0x0036, 5920}, {INT64_C(1380575041923644000), 0x0003, 0x0034, 1}, {INT64_C(1380575041923644000), 0x0003, 0x0030, 384}, {INT64_C(1380575041923644000), 0x0003, 0x0031, 160}, {INT64_C(1380575041923644000), 0x0000, 0x0002, 0}, {INT64_C(1380575041923644000), 0x0003, 0x0035, 6528}, {INT64_C(1380575041923644000), 0x0003, 0x0036, 5390}, {INT64_C(1380575041923644000), 0x0003, 0x0034, 0}, {INT64_C(1380575041923644000), 0x0003, 0x0030, 320}, {INT64_C(1380575041923644000), 0x0003, 0x0031, 128}, {INT64_C(1380575041923644000), 0x0000, 0x0002, 0}, {INT64_C(1380575041923644000), 0x0003, 0x0035, 4169}, {INT64_C(1380575041923644000), 0x0003, 0x0036, 5050}, {INT64_C(1380575041923644000), 0x0003, 0x0034, 0}, {INT64_C(1380575041923644000), 0x0003, 0x0030, 480}, {INT64_C(1380575041923644000), 0x0003, 0x0031, 256}, {INT64_C(1380575041923644000), 0x0000, 0x0002, 0}, {INT64_C(1380575041923644000), 0x0003, 0x0035, 7168}, {INT64_C(1380575041923644000), 0x0003, 0x0036, 4010}, {INT64_C(1380575041923644000), 0x0003, 0x0034, 0}, {INT64_C(1380575041923644000), 0x0003, 0x0030, 320}, {INT64_C(1380575041923644000), 0x0003, 0x0031, 128}, {INT64_C(1380575041923644000), 0x0000, 0x0002, 0}, {INT64_C(1380575041923644000), 0x0000, 0x0000, 0}, {INT64_C(1380575041929638000), 0x0003, 0x0000, 5421}, {INT64_C(1380575041929638000), 0x0003, 0x0001, 5829}, {INT64_C(1380575041929638000), 0x0003, 0x0035, 5421}, {INT64_C(1380575041929638000), 0x0003, 0x0036, 5829}, {INT64_C(1380575041929638000), 0x0003, 0x0034, 0}, {INT64_C(1380575041929638000), 0x0003, 0x0030, 320}, {INT64_C(1380575041929638000), 0x0003, 0x0031, 256}, {INT64_C(1380575041929638000), 0x0000, 0x0002, 0}, {INT64_C(1380575041929638000), 0x0003, 0x0035, 6400}, {INT64_C(1380575041929638000), 0x0003, 0x0036, 5337}, {INT64_C(1380575041929638000), 0x0003, 0x0034, 0}, {INT64_C(1380575041929638000), 0x0003, 0x0030, 320}, {INT64_C(1380575041929638000), 0x0003, 0x0031, 128}, {INT64_C(1380575041929638000), 0x0000, 0x0002, 0}, {INT64_C(1380575041929638000), 0x0003, 0x0035, 4110}, {INT64_C(1380575041929638000), 0x0003, 0x0036, 4992}, {INT64_C(1380575041929638000), 0x0003, 0x0034, 1}, {INT64_C(1380575041929638000), 0x0003, 0x0030, 384}, {INT64_C(1380575041929638000), 0x0003, 0x0031, 320}, {INT64_C(1380575041929638000), 0x0000, 0x0002, 0}, {INT64_C(1380575041929638000), 0x0000, 0x0000, 0}, {INT64_C(1380575041943643000), 0x0003, 0x0000, 5338}, {INT64_C(1380575041943643000), 0x0003, 0x0001, 5703}, {INT64_C(1380575041943643000), 0x0003, 0x0035, 5338}, {INT64_C(1380575041943643000), 0x0003, 0x0036, 5703}, {INT64_C(1380575041943643000), 0x0003, 0x0034, 0}, {INT64_C(1380575041943643000), 0x0003, 0x0030, 320}, {INT64_C(1380575041943643000), 0x0003, 0x0031, 256}, {INT64_C(1380575041943643000), 0x0000, 0x0002, 0}, {INT64_C(1380575041943643000), 0x0003, 0x0035, 6334}, {INT64_C(1380575041943643000), 0x0003, 0x0036, 5276}, {INT64_C(1380575041943643000), 0x0003, 0x0034, 0}, {INT64_C(1380575041943643000), 0x0003, 0x0030, 320}, {INT64_C(1380575041943643000), 0x0003, 0x0031, 256}, {INT64_C(1380575041943643000), 0x0000, 0x0002, 0}, {INT64_C(1380575041943643000), 0x0003, 0x0035, 4038}, {INT64_C(1380575041943643000), 0x0003, 0x0036, 4886}, {INT64_C(1380575041943643000), 0x0003, 0x0034, 0}, {INT64_C(1380575041943643000), 0x0003, 0x0030, 480}, {INT64_C(1380575041943643000), 0x0003, 0x0031, 256}, {INT64_C(1380575041943643000), 0x0000, 0x0002, 0}, {INT64_C(1380575041943643000), 0x0000, 0x0000, 0}, {INT64_C(1380575041961639000), 0x0003, 0x0000, 5300}, {INT64_C(1380575041961639000), 0x0003, 0x0001, 5685}, {INT64_C(1380575041961639000), 0x0003, 0x0035, 5300}, {INT64_C(1380575041961639000), 0x0003, 0x0036, 5685}, {INT64_C(1380575041961639000), 0x0003, 0x0034, 0}, {INT64_C(1380575041961639000), 0x0003, 0x0030, 320}, {INT64_C(1380575041961639000), 0x0003, 0x0031, 256}, {INT64_C(1380575041961639000), 0x0000, 0x0002, 0}, {INT64_C(1380575041961639000), 0x0003, 0x0035, 6272}, {INT64_C(1380575041961639000), 0x0003, 0x0036, 5216}, {INT64_C(1380575041961639000), 0x0003, 0x0034, 0}, {INT64_C(1380575041961639000), 0x0003, 0x0030, 320}, {INT64_C(1380575041961639000), 0x0003, 0x0031, 128}, {INT64_C(1380575041961639000), 0x0000, 0x0002, 0}, {INT64_C(1380575041961639000), 0x0003, 0x0035, 3992}, {INT64_C(1380575041961639000), 0x0003, 0x0036, 4794}, {INT64_C(1380575041961639000), 0x0003, 0x0034, 0}, {INT64_C(1380575041961639000), 0x0003, 0x0030, 480}, {INT64_C(1380575041961639000), 0x0003, 0x0031, 384}, {INT64_C(1380575041961639000), 0x0000, 0x0002, 0}, {INT64_C(1380575041961639000), 0x0000, 0x0000, 0}, {INT64_C(1380575041979643000), 0x0003, 0x0000, 5196}, {INT64_C(1380575041979643000), 0x0003, 0x0001, 5551}, {INT64_C(1380575041979643000), 0x0003, 0x0035, 5196}, {INT64_C(1380575041979643000), 0x0003, 0x0036, 5551}, {INT64_C(1380575041979643000), 0x0003, 0x0034, 0}, {INT64_C(1380575041979643000), 0x0003, 0x0030, 320}, {INT64_C(1380575041979643000), 0x0003, 0x0031, 256}, {INT64_C(1380575041979643000), 0x0000, 0x0002, 0}, {INT64_C(1380575041979643000), 0x0003, 0x0035, 6160}, {INT64_C(1380575041979643000), 0x0003, 0x0036, 5160}, {INT64_C(1380575041979643000), 0x0003, 0x0034, 0}, {INT64_C(1380575041979643000), 0x0003, 0x0030, 640}, {INT64_C(1380575041979643000), 0x0003, 0x0031, 256}, {INT64_C(1380575041979643000), 0x0000, 0x0002, 0}, {INT64_C(1380575041979643000), 0x0003, 0x0035, 3884}, {INT64_C(1380575041979643000), 0x0003, 0x0036, 4681}, {INT64_C(1380575041979643000), 0x0003, 0x0034, 1}, {INT64_C(1380575041979643000), 0x0003, 0x0030, 384}, {INT64_C(1380575041979643000), 0x0003, 0x0031, 320}, {INT64_C(1380575041979643000), 0x0000, 0x0002, 0}, {INT64_C(1380575041979643000), 0x0000, 0x0000, 0}, {INT64_C(1380575041999642000), 0x0003, 0x0000, 5092}, {INT64_C(1380575041999642000), 0x0003, 0x0001, 5509}, {INT64_C(1380575041999642000), 0x0003, 0x0035, 5092}, {INT64_C(1380575041999642000), 0x0003, 0x0036, 5509}, {INT64_C(1380575041999642000), 0x0003, 0x0034, 1}, {INT64_C(1380575041999642000), 0x0003, 0x0030, 384}, {INT64_C(1380575041999642000), 0x0003, 0x0031, 320}, {INT64_C(1380575041999642000), 0x0000, 0x0002, 0}, {INT64_C(1380575041999642000), 0x0003, 0x0035, 6091}, {INT64_C(1380575041999642000), 0x0003, 0x0036, 5075}, {INT64_C(1380575041999642000), 0x0003, 0x0034, 0}, {INT64_C(1380575041999642000), 0x0003, 0x0030, 320}, {INT64_C(1380575041999642000), 0x0003, 0x0031, 256}, {INT64_C(1380575041999642000), 0x0000, 0x0002, 0}, {INT64_C(1380575041999642000), 0x0003, 0x0035, 3783}, {INT64_C(1380575041999642000), 0x0003, 0x0036, 4511}, {INT64_C(1380575041999642000), 0x0003, 0x0034, 0}, {INT64_C(1380575041999642000), 0x0003, 0x0030, 480}, {INT64_C(1380575041999642000), 0x0003, 0x0031, 256}, {INT64_C(1380575041999642000), 0x0000, 0x0002, 0}, {INT64_C(1380575041999642000), 0x0000, 0x0000, 0}, {INT64_C(1380575042017645000), 0x0003, 0x0000, 5018}, {INT64_C(1380575042017645000), 0x0003, 0x0001, 5390}, {INT64_C(1380575042017645000), 0x0003, 0x0035, 5018}, {INT64_C(1380575042017645000), 0x0003, 0x0036, 5390}, {INT64_C(1380575042017645000), 0x0003, 0x0034, 1}, {INT64_C(1380575042017645000), 0x0003, 0x0030, 384}, {INT64_C(1380575042017645000), 0x0003, 0x0031, 320}, {INT64_C(1380575042017645000), 0x0000, 0x0002, 0}, {INT64_C(1380575042017645000), 0x0003, 0x0035, 6016}, {INT64_C(1380575042017645000), 0x0003, 0x0036, 5035}, {INT64_C(1380575042017645000), 0x0003, 0x0034, 0}, {INT64_C(1380575042017645000), 0x0003, 0x0030, 320}, {INT64_C(1380575042017645000), 0x0003, 0x0031, 128}, {INT64_C(1380575042017645000), 0x0000, 0x0002, 0}, {INT64_C(1380575042017645000), 0x0003, 0x0035, 3736}, {INT64_C(1380575042017645000), 0x0003, 0x0036, 4384}, {INT64_C(1380575042017645000), 0x0003, 0x0034, 0}, {INT64_C(1380575042017645000), 0x0003, 0x0030, 480}, {INT64_C(1380575042017645000), 0x0003, 0x0031, 384}, {INT64_C(1380575042017645000), 0x0000, 0x0002, 0}, {INT64_C(1380575042017645000), 0x0003, 0x0035, 6664}, {INT64_C(1380575042017645000), 0x0003, 0x0036, 3680}, {INT64_C(1380575042017645000), 0x0003, 0x0034, 1}, {INT64_C(1380575042017645000), 0x0003, 0x0030, 256}, {INT64_C(1380575042017645000), 0x0003, 0x0031, 160}, {INT64_C(1380575042017645000), 0x0000, 0x0002, 0}, {INT64_C(1380575042017645000), 0x0000, 0x0000, 0}, {INT64_C(1380575042037640000), 0x0003, 0x0000, 4932}, {INT64_C(1380575042037640000), 0x0003, 0x0001, 5325}, {INT64_C(1380575042037640000), 0x0003, 0x0035, 4932}, {INT64_C(1380575042037640000), 0x0003, 0x0036, 5325}, {INT64_C(1380575042037640000), 0x0003, 0x0034, 0}, {INT64_C(1380575042037640000), 0x0003, 0x0030, 480}, {INT64_C(1380575042037640000), 0x0003, 0x0031, 256}, {INT64_C(1380575042037640000), 0x0000, 0x0002, 0}, {INT64_C(1380575042037640000), 0x0003, 0x0035, 5937}, {INT64_C(1380575042037640000), 0x0003, 0x0036, 4987}, {INT64_C(1380575042037640000), 0x0003, 0x0034, 0}, {INT64_C(1380575042037640000), 0x0003, 0x0030, 320}, {INT64_C(1380575042037640000), 0x0003, 0x0031, 256}, {INT64_C(1380575042037640000), 0x0000, 0x0002, 0}, {INT64_C(1380575042037640000), 0x0003, 0x0035, 3684}, {INT64_C(1380575042037640000), 0x0003, 0x0036, 4309}, {INT64_C(1380575042037640000), 0x0003, 0x0034, 0}, {INT64_C(1380575042037640000), 0x0003, 0x0030, 640}, {INT64_C(1380575042037640000), 0x0003, 0x0031, 384}, {INT64_C(1380575042037640000), 0x0000, 0x0002, 0}, {INT64_C(1380575042037640000), 0x0000, 0x0000, 0}, {INT64_C(1380575042055641000), 0x0003, 0x0000, 4886}, {INT64_C(1380575042055641000), 0x0003, 0x0001, 5210}, {INT64_C(1380575042055641000), 0x0003, 0x0035, 4886}, {INT64_C(1380575042055641000), 0x0003, 0x0036, 5210}, {INT64_C(1380575042055641000), 0x0003, 0x0034, 0}, {INT64_C(1380575042055641000), 0x0003, 0x0030, 480}, {INT64_C(1380575042055641000), 0x0003, 0x0031, 384}, {INT64_C(1380575042055641000), 0x0000, 0x0002, 0}, {INT64_C(1380575042055641000), 0x0003, 0x0035, 5888}, {INT64_C(1380575042055641000), 0x0003, 0x0036, 4897}, {INT64_C(1380575042055641000), 0x0003, 0x0034, 0}, {INT64_C(1380575042055641000), 0x0003, 0x0030, 640}, {INT64_C(1380575042055641000), 0x0003, 0x0031, 128}, {INT64_C(1380575042055641000), 0x0000, 0x0002, 0}, {INT64_C(1380575042055641000), 0x0003, 0x0035, 3662}, {INT64_C(1380575042055641000), 0x0003, 0x0036, 4216}, {INT64_C(1380575042055641000), 0x0003, 0x0034, 0}, {INT64_C(1380575042055641000), 0x0003, 0x0030, 640}, {INT64_C(1380575042055641000), 0x0003, 0x0031, 384}, {INT64_C(1380575042055641000), 0x0000, 0x0002, 0}, {INT64_C(1380575042055641000), 0x0000, 0x0000, 0}, {INT64_C(1380575042073643000), 0x0003, 0x0000, 4829}, {INT64_C(1380575042073643000), 0x0003, 0x0001, 5185}, {INT64_C(1380575042073643000), 0x0003, 0x0035, 4829}, {INT64_C(1380575042073643000), 0x0003, 0x0036, 5185}, {INT64_C(1380575042073643000), 0x0003, 0x0034, 0}, {INT64_C(1380575042073643000), 0x0003, 0x0030, 480}, {INT64_C(1380575042073643000), 0x0003, 0x0031, 256}, {INT64_C(1380575042073643000), 0x0000, 0x0002, 0}, {INT64_C(1380575042073643000), 0x0003, 0x0035, 5806}, {INT64_C(1380575042073643000), 0x0003, 0x0036, 4846}, {INT64_C(1380575042073643000), 0x0003, 0x0034, 0}, {INT64_C(1380575042073643000), 0x0003, 0x0030, 480}, {INT64_C(1380575042073643000), 0x0003, 0x0031, 256}, {INT64_C(1380575042073643000), 0x0000, 0x0002, 0}, {INT64_C(1380575042073643000), 0x0003, 0x0035, 3636}, {INT64_C(1380575042073643000), 0x0003, 0x0036, 4106}, {INT64_C(1380575042073643000), 0x0003, 0x0034, 0}, {INT64_C(1380575042073643000), 0x0003, 0x0030, 480}, {INT64_C(1380575042073643000), 0x0003, 0x0031, 256}, {INT64_C(1380575042073643000), 0x0000, 0x0002, 0}, {INT64_C(1380575042073643000), 0x0000, 0x0000, 0}, {INT64_C(1380575042093642000), 0x0003, 0x0000, 4802}, {INT64_C(1380575042093642000), 0x0003, 0x0001, 5107}, {INT64_C(1380575042093642000), 0x0003, 0x0035, 4802}, {INT64_C(1380575042093642000), 0x0003, 0x0036, 5107}, {INT64_C(1380575042093642000), 0x0003, 0x0034, 0}, {INT64_C(1380575042093642000), 0x0003, 0x0030, 640}, {INT64_C(1380575042093642000), 0x0003, 0x0031, 256}, {INT64_C(1380575042093642000), 0x0000, 0x0002, 0}, {INT64_C(1380575042093642000), 0x0003, 0x0035, 5785}, {INT64_C(1380575042093642000), 0x0003, 0x0036, 4804}, {INT64_C(1380575042093642000), 0x0003, 0x0034, 0}, {INT64_C(1380575042093642000), 0x0003, 0x0030, 480}, {INT64_C(1380575042093642000), 0x0003, 0x0031, 256}, {INT64_C(1380575042093642000), 0x0000, 0x0002, 0}, {INT64_C(1380575042093642000), 0x0003, 0x0035, 3616}, {INT64_C(1380575042093642000), 0x0003, 0x0036, 4037}, {INT64_C(1380575042093642000), 0x0003, 0x0034, 0}, {INT64_C(1380575042093642000), 0x0003, 0x0030, 320}, {INT64_C(1380575042093642000), 0x0003, 0x0031, 256}, {INT64_C(1380575042093642000), 0x0000, 0x0002, 0}, {INT64_C(1380575042093642000), 0x0003, 0x0035, 6429}, {INT64_C(1380575042093642000), 0x0003, 0x0036, 3680}, {INT64_C(1380575042093642000), 0x0003, 0x0034, 1}, {INT64_C(1380575042093642000), 0x0003, 0x0030, 256}, {INT64_C(1380575042093642000), 0x0003, 0x0031, 160}, {INT64_C(1380575042093642000), 0x0000, 0x0002, 0}, {INT64_C(1380575042093642000), 0x0000, 0x0000, 0}, {INT64_C(1380575042111642000), 0x0003, 0x0000, 4742}, {INT64_C(1380575042111642000), 0x0003, 0x0001, 5009}, {INT64_C(1380575042111642000), 0x0003, 0x0035, 4742}, {INT64_C(1380575042111642000), 0x0003, 0x0036, 5009}, {INT64_C(1380575042111642000), 0x0003, 0x0034, 0}, {INT64_C(1380575042111642000), 0x0003, 0x0030, 480}, {INT64_C(1380575042111642000), 0x0003, 0x0031, 384}, {INT64_C(1380575042111642000), 0x0000, 0x0002, 0}, {INT64_C(1380575042111642000), 0x0003, 0x0035, 5725}, {INT64_C(1380575042111642000), 0x0003, 0x0036, 4766}, {INT64_C(1380575042111642000), 0x0003, 0x0034, 0}, {INT64_C(1380575042111642000), 0x0003, 0x0030, 480}, {INT64_C(1380575042111642000), 0x0003, 0x0031, 256}, {INT64_C(1380575042111642000), 0x0000, 0x0002, 0}, {INT64_C(1380575042111642000), 0x0003, 0x0035, 3582}, {INT64_C(1380575042111642000), 0x0003, 0x0036, 3881}, {INT64_C(1380575042111642000), 0x0003, 0x0034, 1}, {INT64_C(1380575042111642000), 0x0003, 0x0030, 512}, {INT64_C(1380575042111642000), 0x0003, 0x0031, 480}, {INT64_C(1380575042111642000), 0x0000, 0x0002, 0}, {INT64_C(1380575042111642000), 0x0000, 0x0000, 0}, {INT64_C(1380575042129642000), 0x0003, 0x0000, 4696}, {INT64_C(1380575042129642000), 0x0003, 0x0001, 4940}, {INT64_C(1380575042129642000), 0x0003, 0x0035, 4696}, {INT64_C(1380575042129642000), 0x0003, 0x0036, 4940}, {INT64_C(1380575042129642000), 0x0003, 0x0034, 0}, {INT64_C(1380575042129642000), 0x0003, 0x0030, 640}, {INT64_C(1380575042129642000), 0x0003, 0x0031, 256}, {INT64_C(1380575042129642000), 0x0000, 0x0002, 0}, {INT64_C(1380575042129642000), 0x0003, 0x0035, 5693}, {INT64_C(1380575042129642000), 0x0003, 0x0036, 4728}, {INT64_C(1380575042129642000), 0x0003, 0x0034, 0}, {INT64_C(1380575042129642000), 0x0003, 0x0030, 640}, {INT64_C(1380575042129642000), 0x0003, 0x0031, 256}, {INT64_C(1380575042129642000), 0x0000, 0x0002, 0}, {INT64_C(1380575042129642000), 0x0003, 0x0035, 3548}, {INT64_C(1380575042129642000), 0x0003, 0x0036, 3777}, {INT64_C(1380575042129642000), 0x0003, 0x0034, 1}, {INT64_C(1380575042129642000), 0x0003, 0x0030, 384}, {INT64_C(1380575042129642000), 0x0003, 0x0031, 320}, {INT64_C(1380575042129642000), 0x0000, 0x0002, 0}, {INT64_C(1380575042129642000), 0x0000, 0x0000, 0}, {INT64_C(1380575042149639000), 0x0003, 0x0000, 4659}, {INT64_C(1380575042149639000), 0x0003, 0x0001, 4859}, {INT64_C(1380575042149639000), 0x0003, 0x0035, 4659}, {INT64_C(1380575042149639000), 0x0003, 0x0036, 4859}, {INT64_C(1380575042149639000), 0x0003, 0x0034, 0}, {INT64_C(1380575042149639000), 0x0003, 0x0030, 640}, {INT64_C(1380575042149639000), 0x0003, 0x0031, 256}, {INT64_C(1380575042149639000), 0x0000, 0x0002, 0}, {INT64_C(1380575042149639000), 0x0003, 0x0035, 5632}, {INT64_C(1380575042149639000), 0x0003, 0x0036, 4664}, {INT64_C(1380575042149639000), 0x0003, 0x0034, 0}, {INT64_C(1380575042149639000), 0x0003, 0x0030, 480}, {INT64_C(1380575042149639000), 0x0003, 0x0031, 128}, {INT64_C(1380575042149639000), 0x0000, 0x0002, 0}, {INT64_C(1380575042149639000), 0x0003, 0x0035, 3513}, {INT64_C(1380575042149639000), 0x0003, 0x0036, 3705}, {INT64_C(1380575042149639000), 0x0003, 0x0034, 0}, {INT64_C(1380575042149639000), 0x0003, 0x0030, 320}, {INT64_C(1380575042149639000), 0x0003, 0x0031, 256}, {INT64_C(1380575042149639000), 0x0000, 0x0002, 0}, {INT64_C(1380575042149639000), 0x0000, 0x0000, 0}, {INT64_C(1380575042167640000), 0x0003, 0x0000, 4563}, {INT64_C(1380575042167640000), 0x0003, 0x0001, 4754}, {INT64_C(1380575042167640000), 0x0003, 0x0035, 4563}, {INT64_C(1380575042167640000), 0x0003, 0x0036, 4754}, {INT64_C(1380575042167640000), 0x0003, 0x0034, 0}, {INT64_C(1380575042167640000), 0x0003, 0x0030, 640}, {INT64_C(1380575042167640000), 0x0003, 0x0031, 256}, {INT64_C(1380575042167640000), 0x0000, 0x0002, 0}, {INT64_C(1380575042167640000), 0x0003, 0x0035, 5553}, {INT64_C(1380575042167640000), 0x0003, 0x0036, 4597}, {INT64_C(1380575042167640000), 0x0003, 0x0034, 0}, {INT64_C(1380575042167640000), 0x0003, 0x0030, 480}, {INT64_C(1380575042167640000), 0x0003, 0x0031, 256}, {INT64_C(1380575042167640000), 0x0000, 0x0002, 0}, {INT64_C(1380575042167640000), 0x0003, 0x0035, 3496}, {INT64_C(1380575042167640000), 0x0003, 0x0036, 3539}, {INT64_C(1380575042167640000), 0x0003, 0x0034, 0}, {INT64_C(1380575042167640000), 0x0003, 0x0030, 320}, {INT64_C(1380575042167640000), 0x0003, 0x0031, 256}, {INT64_C(1380575042167640000), 0x0000, 0x0002, 0}, {INT64_C(1380575042167640000), 0x0000, 0x0000, 0}, {INT64_C(1380575042185641000), 0x0003, 0x0000, 4501}, {INT64_C(1380575042185641000), 0x0003, 0x0001, 4606}, {INT64_C(1380575042185641000), 0x0003, 0x0035, 4501}, {INT64_C(1380575042185641000), 0x0003, 0x0036, 4606}, {INT64_C(1380575042185641000), 0x0003, 0x0034, 0}, {INT64_C(1380575042185641000), 0x0003, 0x0030, 640}, {INT64_C(1380575042185641000), 0x0003, 0x0031, 256}, {INT64_C(1380575042185641000), 0x0000, 0x0002, 0}, {INT64_C(1380575042185641000), 0x0003, 0x0035, 5436}, {INT64_C(1380575042185641000), 0x0003, 0x0036, 4505}, {INT64_C(1380575042185641000), 0x0003, 0x0034, 0}, {INT64_C(1380575042185641000), 0x0003, 0x0030, 320}, {INT64_C(1380575042185641000), 0x0003, 0x0031, 256}, {INT64_C(1380575042185641000), 0x0000, 0x0002, 0}, {INT64_C(1380575042185641000), 0x0003, 0x0035, 3456}, {INT64_C(1380575042185641000), 0x0003, 0x0036, 3380}, {INT64_C(1380575042185641000), 0x0003, 0x0034, 0}, {INT64_C(1380575042185641000), 0x0003, 0x0030, 320}, {INT64_C(1380575042185641000), 0x0003, 0x0031, 128}, {INT64_C(1380575042185641000), 0x0000, 0x0002, 0}, {INT64_C(1380575042185641000), 0x0000, 0x0000, 0}, {INT64_C(1380575042205640000), 0x0003, 0x0000, 4381}, {INT64_C(1380575042205640000), 0x0003, 0x0001, 4473}, {INT64_C(1380575042205640000), 0x0003, 0x0035, 4381}, {INT64_C(1380575042205640000), 0x0003, 0x0036, 4473}, {INT64_C(1380575042205640000), 0x0003, 0x0034, 0}, {INT64_C(1380575042205640000), 0x0003, 0x0030, 480}, {INT64_C(1380575042205640000), 0x0003, 0x0031, 256}, {INT64_C(1380575042205640000), 0x0000, 0x0002, 0}, {INT64_C(1380575042205640000), 0x0003, 0x0035, 5376}, {INT64_C(1380575042205640000), 0x0003, 0x0036, 4372}, {INT64_C(1380575042205640000), 0x0003, 0x0034, 0}, {INT64_C(1380575042205640000), 0x0003, 0x0030, 320}, {INT64_C(1380575042205640000), 0x0003, 0x0031, 128}, {INT64_C(1380575042205640000), 0x0000, 0x0002, 0}, {INT64_C(1380575042205640000), 0x0003, 0x0035, 3353}, {INT64_C(1380575042205640000), 0x0003, 0x0036, 3218}, {INT64_C(1380575042205640000), 0x0003, 0x0034, 0}, {INT64_C(1380575042205640000), 0x0003, 0x0030, 320}, {INT64_C(1380575042205640000), 0x0003, 0x0031, 256}, {INT64_C(1380575042205640000), 0x0000, 0x0002, 0}, {INT64_C(1380575042205640000), 0x0000, 0x0000, 0}, {INT64_C(1380575042223640000), 0x0003, 0x0000, 4255}, {INT64_C(1380575042223640000), 0x0003, 0x0001, 4312}, {INT64_C(1380575042223640000), 0x0003, 0x0035, 4255}, {INT64_C(1380575042223640000), 0x0003, 0x0036, 4312}, {INT64_C(1380575042223640000), 0x0003, 0x0034, 0}, {INT64_C(1380575042223640000), 0x0003, 0x0030, 640}, {INT64_C(1380575042223640000), 0x0003, 0x0031, 256}, {INT64_C(1380575042223640000), 0x0000, 0x0002, 0}, {INT64_C(1380575042223640000), 0x0003, 0x0035, 5248}, {INT64_C(1380575042223640000), 0x0003, 0x0036, 4160}, {INT64_C(1380575042223640000), 0x0003, 0x0034, 0}, {INT64_C(1380575042223640000), 0x0003, 0x0030, 480}, {INT64_C(1380575042223640000), 0x0003, 0x0031, 128}, {INT64_C(1380575042223640000), 0x0000, 0x0002, 0}, {INT64_C(1380575042223640000), 0x0000, 0x0000, 0}, {INT64_C(1380575042241636000), 0x0003, 0x0000, 4071}, {INT64_C(1380575042241636000), 0x0003, 0x0001, 4135}, {INT64_C(1380575042241636000), 0x0003, 0x0035, 4071}, {INT64_C(1380575042241636000), 0x0003, 0x0036, 4135}, {INT64_C(1380575042241636000), 0x0003, 0x0034, 0}, {INT64_C(1380575042241636000), 0x0003, 0x0030, 480}, {INT64_C(1380575042241636000), 0x0003, 0x0031, 384}, {INT64_C(1380575042241636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042241636000), 0x0003, 0x0035, 5047}, {INT64_C(1380575042241636000), 0x0003, 0x0036, 4059}, {INT64_C(1380575042241636000), 0x0003, 0x0034, 0}, {INT64_C(1380575042241636000), 0x0003, 0x0030, 320}, {INT64_C(1380575042241636000), 0x0003, 0x0031, 256}, {INT64_C(1380575042241636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042241636000), 0x0000, 0x0000, 0}, {INT64_C(1380575042261636000), 0x0003, 0x0000, 3911}, {INT64_C(1380575042261636000), 0x0003, 0x0001, 4011}, {INT64_C(1380575042261636000), 0x0003, 0x0035, 3911}, {INT64_C(1380575042261636000), 0x0003, 0x0036, 4011}, {INT64_C(1380575042261636000), 0x0003, 0x0034, 1}, {INT64_C(1380575042261636000), 0x0003, 0x0030, 512}, {INT64_C(1380575042261636000), 0x0003, 0x0031, 320}, {INT64_C(1380575042261636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042261636000), 0x0003, 0x0035, 4906}, {INT64_C(1380575042261636000), 0x0003, 0x0036, 4000}, {INT64_C(1380575042261636000), 0x0003, 0x0034, 1}, {INT64_C(1380575042261636000), 0x0003, 0x0030, 256}, {INT64_C(1380575042261636000), 0x0003, 0x0031, 160}, {INT64_C(1380575042261636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042261636000), 0x0003, 0x0035, 3079}, {INT64_C(1380575042261636000), 0x0003, 0x0036, 2720}, {INT64_C(1380575042261636000), 0x0003, 0x0034, 1}, {INT64_C(1380575042261636000), 0x0003, 0x0030, 256}, {INT64_C(1380575042261636000), 0x0003, 0x0031, 160}, {INT64_C(1380575042261636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042261636000), 0x0000, 0x0000, 0}, {INT64_C(1380575042279638000), 0x0003, 0x0000, 3712}, {INT64_C(1380575042279638000), 0x0003, 0x0001, 3791}, {INT64_C(1380575042279638000), 0x0003, 0x0035, 3712}, {INT64_C(1380575042279638000), 0x0003, 0x0036, 3791}, {INT64_C(1380575042279638000), 0x0003, 0x0034, 0}, {INT64_C(1380575042279638000), 0x0003, 0x0030, 320}, {INT64_C(1380575042279638000), 0x0003, 0x0031, 128}, {INT64_C(1380575042279638000), 0x0000, 0x0002, 0}, {INT64_C(1380575042279638000), 0x0003, 0x0035, 4758}, {INT64_C(1380575042279638000), 0x0003, 0x0036, 3739}, {INT64_C(1380575042279638000), 0x0003, 0x0034, 1}, {INT64_C(1380575042279638000), 0x0003, 0x0030, 384}, {INT64_C(1380575042279638000), 0x0003, 0x0031, 320}, {INT64_C(1380575042279638000), 0x0000, 0x0002, 0}, {INT64_C(1380575042279638000), 0x0000, 0x0000, 0}, {INT64_C(1380575042297639000), 0x0003, 0x0000, 4485}, {INT64_C(1380575042297639000), 0x0003, 0x0001, 3680}, {INT64_C(1380575042297639000), 0x0003, 0x0035, 4485}, {INT64_C(1380575042297639000), 0x0003, 0x0036, 3680}, {INT64_C(1380575042297639000), 0x0003, 0x0034, 1}, {INT64_C(1380575042297639000), 0x0003, 0x0030, 256}, {INT64_C(1380575042297639000), 0x0003, 0x0031, 160}, {INT64_C(1380575042297639000), 0x0000, 0x0002, 0}, {INT64_C(1380575042297639000), 0x0000, 0x0000, 0}, {INT64_C(1380575042391637000), 0x0001, 0x014d, 0}, {INT64_C(1380575042391637000), 0x0001, 0x014a, 0}, {INT64_C(1380575042391637000), 0x0000, 0x0000, 0}, {INT64_C(1380575042753637000), 0x0003, 0x0000, 3650}, {INT64_C(1380575042753637000), 0x0003, 0x0001, 5703}, {INT64_C(1380575042753637000), 0x0003, 0x0035, 3650}, {INT64_C(1380575042753637000), 0x0003, 0x0036, 5703}, {INT64_C(1380575042753637000), 0x0003, 0x0034, 0}, {INT64_C(1380575042753637000), 0x0003, 0x0030, 320}, {INT64_C(1380575042753637000), 0x0003, 0x0031, 256}, {INT64_C(1380575042753637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042753637000), 0x0003, 0x0035, 1855}, {INT64_C(1380575042753637000), 0x0003, 0x0036, 1920}, {INT64_C(1380575042753637000), 0x0003, 0x0034, 1}, {INT64_C(1380575042753637000), 0x0003, 0x0030, 256}, {INT64_C(1380575042753637000), 0x0003, 0x0031, 160}, {INT64_C(1380575042753637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042753637000), 0x0001, 0x014d, 1}, {INT64_C(1380575042753637000), 0x0001, 0x014a, 1}, {INT64_C(1380575042753637000), 0x0000, 0x0000, 0}, {INT64_C(1380575042765637000), 0x0003, 0x0000, 3658}, {INT64_C(1380575042765637000), 0x0003, 0x0001, 5679}, {INT64_C(1380575042765637000), 0x0003, 0x0035, 3658}, {INT64_C(1380575042765637000), 0x0003, 0x0036, 5679}, {INT64_C(1380575042765637000), 0x0003, 0x0034, 0}, {INT64_C(1380575042765637000), 0x0003, 0x0030, 320}, {INT64_C(1380575042765637000), 0x0003, 0x0031, 256}, {INT64_C(1380575042765637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042765637000), 0x0003, 0x0035, 1856}, {INT64_C(1380575042765637000), 0x0003, 0x0036, 1859}, {INT64_C(1380575042765637000), 0x0003, 0x0034, 0}, {INT64_C(1380575042765637000), 0x0003, 0x0030, 320}, {INT64_C(1380575042765637000), 0x0003, 0x0031, 256}, {INT64_C(1380575042765637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042765637000), 0x0000, 0x0000, 0}, {INT64_C(1380575042771635000), 0x0003, 0x0000, 3674}, {INT64_C(1380575042771635000), 0x0003, 0x0001, 5656}, {INT64_C(1380575042771635000), 0x0003, 0x0035, 3674}, {INT64_C(1380575042771635000), 0x0003, 0x0036, 5656}, {INT64_C(1380575042771635000), 0x0003, 0x0034, 0}, {INT64_C(1380575042771635000), 0x0003, 0x0030, 320}, {INT64_C(1380575042771635000), 0x0003, 0x0031, 256}, {INT64_C(1380575042771635000), 0x0000, 0x0002, 0}, {INT64_C(1380575042771635000), 0x0003, 0x0035, 1856}, {INT64_C(1380575042771635000), 0x0003, 0x0036, 1866}, {INT64_C(1380575042771635000), 0x0003, 0x0034, 0}, {INT64_C(1380575042771635000), 0x0003, 0x0030, 320}, {INT64_C(1380575042771635000), 0x0003, 0x0031, 256}, {INT64_C(1380575042771635000), 0x0000, 0x0002, 0}, {INT64_C(1380575042771635000), 0x0000, 0x0000, 0}, {INT64_C(1380575042785636000), 0x0003, 0x0000, 3713}, {INT64_C(1380575042785636000), 0x0003, 0x0001, 5544}, {INT64_C(1380575042785636000), 0x0003, 0x0035, 3713}, {INT64_C(1380575042785636000), 0x0003, 0x0036, 5544}, {INT64_C(1380575042785636000), 0x0003, 0x0034, 1}, {INT64_C(1380575042785636000), 0x0003, 0x0030, 384}, {INT64_C(1380575042785636000), 0x0003, 0x0031, 320}, {INT64_C(1380575042785636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042785636000), 0x0003, 0x0035, 1851}, {INT64_C(1380575042785636000), 0x0003, 0x0036, 1920}, {INT64_C(1380575042785636000), 0x0003, 0x0034, 1}, {INT64_C(1380575042785636000), 0x0003, 0x0030, 256}, {INT64_C(1380575042785636000), 0x0003, 0x0031, 160}, {INT64_C(1380575042785636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042785636000), 0x0000, 0x0000, 0}, {INT64_C(1380575042791639000), 0x0003, 0x0000, 1453}, {INT64_C(1380575042791639000), 0x0003, 0x0001, 5920}, {INT64_C(1380575042791639000), 0x0003, 0x0035, 1453}, {INT64_C(1380575042791639000), 0x0003, 0x0036, 5920}, {INT64_C(1380575042791639000), 0x0003, 0x0034, 1}, {INT64_C(1380575042791639000), 0x0003, 0x0030, 256}, {INT64_C(1380575042791639000), 0x0003, 0x0031, 160}, {INT64_C(1380575042791639000), 0x0000, 0x0002, 0}, {INT64_C(1380575042791639000), 0x0003, 0x0035, 3753}, {INT64_C(1380575042791639000), 0x0003, 0x0036, 5505}, {INT64_C(1380575042791639000), 0x0003, 0x0034, 0}, {INT64_C(1380575042791639000), 0x0003, 0x0030, 320}, {INT64_C(1380575042791639000), 0x0003, 0x0031, 256}, {INT64_C(1380575042791639000), 0x0000, 0x0002, 0}, {INT64_C(1380575042791639000), 0x0003, 0x0035, 1870}, {INT64_C(1380575042791639000), 0x0003, 0x0036, 1920}, {INT64_C(1380575042791639000), 0x0003, 0x0034, 1}, {INT64_C(1380575042791639000), 0x0003, 0x0030, 256}, {INT64_C(1380575042791639000), 0x0003, 0x0031, 160}, {INT64_C(1380575042791639000), 0x0000, 0x0002, 0}, {INT64_C(1380575042791639000), 0x0000, 0x0000, 0}, {INT64_C(1380575042803636000), 0x0003, 0x0000, 1491}, {INT64_C(1380575042803636000), 0x0003, 0x0001, 5760}, {INT64_C(1380575042803636000), 0x0003, 0x0035, 1491}, {INT64_C(1380575042803636000), 0x0003, 0x0036, 5760}, {INT64_C(1380575042803636000), 0x0003, 0x0034, 1}, {INT64_C(1380575042803636000), 0x0003, 0x0030, 256}, {INT64_C(1380575042803636000), 0x0003, 0x0031, 160}, {INT64_C(1380575042803636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042803636000), 0x0003, 0x0035, 3777}, {INT64_C(1380575042803636000), 0x0003, 0x0036, 5458}, {INT64_C(1380575042803636000), 0x0003, 0x0034, 0}, {INT64_C(1380575042803636000), 0x0003, 0x0030, 320}, {INT64_C(1380575042803636000), 0x0003, 0x0031, 256}, {INT64_C(1380575042803636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042803636000), 0x0000, 0x0000, 0}, {INT64_C(1380575042809639000), 0x0003, 0x0000, 1535}, {INT64_C(1380575042809639000), 0x0003, 0x0001, 5692}, {INT64_C(1380575042809639000), 0x0003, 0x0035, 1535}, {INT64_C(1380575042809639000), 0x0003, 0x0036, 5692}, {INT64_C(1380575042809639000), 0x0003, 0x0034, 0}, {INT64_C(1380575042809639000), 0x0003, 0x0030, 320}, {INT64_C(1380575042809639000), 0x0003, 0x0031, 256}, {INT64_C(1380575042809639000), 0x0000, 0x0002, 0}, {INT64_C(1380575042809639000), 0x0003, 0x0035, 3851}, {INT64_C(1380575042809639000), 0x0003, 0x0036, 5345}, {INT64_C(1380575042809639000), 0x0003, 0x0034, 0}, {INT64_C(1380575042809639000), 0x0003, 0x0030, 320}, {INT64_C(1380575042809639000), 0x0003, 0x0031, 256}, {INT64_C(1380575042809639000), 0x0000, 0x0002, 0}, {INT64_C(1380575042809639000), 0x0003, 0x0035, 1280}, {INT64_C(1380575042809639000), 0x0003, 0x0036, 4393}, {INT64_C(1380575042809639000), 0x0003, 0x0034, 0}, {INT64_C(1380575042809639000), 0x0003, 0x0030, 320}, {INT64_C(1380575042809639000), 0x0003, 0x0031, 128}, {INT64_C(1380575042809639000), 0x0000, 0x0002, 0}, {INT64_C(1380575042809639000), 0x0000, 0x0000, 0}, {INT64_C(1380575042823638000), 0x0003, 0x0000, 1617}, {INT64_C(1380575042823638000), 0x0003, 0x0001, 5578}, {INT64_C(1380575042823638000), 0x0003, 0x0035, 1617}, {INT64_C(1380575042823638000), 0x0003, 0x0036, 5578}, {INT64_C(1380575042823638000), 0x0003, 0x0034, 0}, {INT64_C(1380575042823638000), 0x0003, 0x0030, 480}, {INT64_C(1380575042823638000), 0x0003, 0x0031, 256}, {INT64_C(1380575042823638000), 0x0000, 0x0002, 0}, {INT64_C(1380575042823638000), 0x0003, 0x0035, 3885}, {INT64_C(1380575042823638000), 0x0003, 0x0036, 5236}, {INT64_C(1380575042823638000), 0x0003, 0x0034, 0}, {INT64_C(1380575042823638000), 0x0003, 0x0030, 640}, {INT64_C(1380575042823638000), 0x0003, 0x0031, 256}, {INT64_C(1380575042823638000), 0x0000, 0x0002, 0}, {INT64_C(1380575042823638000), 0x0003, 0x0035, 1347}, {INT64_C(1380575042823638000), 0x0003, 0x0036, 4280}, {INT64_C(1380575042823638000), 0x0003, 0x0034, 1}, {INT64_C(1380575042823638000), 0x0003, 0x0030, 384}, {INT64_C(1380575042823638000), 0x0003, 0x0031, 320}, {INT64_C(1380575042823638000), 0x0000, 0x0002, 0}, {INT64_C(1380575042823638000), 0x0000, 0x0000, 0}, {INT64_C(1380575042829637000), 0x0003, 0x0000, 1662}, {INT64_C(1380575042829637000), 0x0003, 0x0001, 5510}, {INT64_C(1380575042829637000), 0x0003, 0x0035, 1662}, {INT64_C(1380575042829637000), 0x0003, 0x0036, 5510}, {INT64_C(1380575042829637000), 0x0003, 0x0034, 0}, {INT64_C(1380575042829637000), 0x0003, 0x0030, 320}, {INT64_C(1380575042829637000), 0x0003, 0x0031, 256}, {INT64_C(1380575042829637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042829637000), 0x0003, 0x0035, 3940}, {INT64_C(1380575042829637000), 0x0003, 0x0036, 5155}, {INT64_C(1380575042829637000), 0x0003, 0x0034, 0}, {INT64_C(1380575042829637000), 0x0003, 0x0030, 480}, {INT64_C(1380575042829637000), 0x0003, 0x0031, 256}, {INT64_C(1380575042829637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042829637000), 0x0003, 0x0035, 1444}, {INT64_C(1380575042829637000), 0x0003, 0x0036, 4147}, {INT64_C(1380575042829637000), 0x0003, 0x0034, 0}, {INT64_C(1380575042829637000), 0x0003, 0x0030, 480}, {INT64_C(1380575042829637000), 0x0003, 0x0031, 384}, {INT64_C(1380575042829637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042829637000), 0x0000, 0x0000, 0}, {INT64_C(1380575042841637000), 0x0003, 0x0000, 1731}, {INT64_C(1380575042841637000), 0x0003, 0x0001, 5377}, {INT64_C(1380575042841637000), 0x0003, 0x0035, 1731}, {INT64_C(1380575042841637000), 0x0003, 0x0036, 5377}, {INT64_C(1380575042841637000), 0x0003, 0x0034, 0}, {INT64_C(1380575042841637000), 0x0003, 0x0030, 480}, {INT64_C(1380575042841637000), 0x0003, 0x0031, 256}, {INT64_C(1380575042841637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042841637000), 0x0003, 0x0035, 4000}, {INT64_C(1380575042841637000), 0x0003, 0x0036, 5047}, {INT64_C(1380575042841637000), 0x0003, 0x0034, 0}, {INT64_C(1380575042841637000), 0x0003, 0x0030, 480}, {INT64_C(1380575042841637000), 0x0003, 0x0031, 256}, {INT64_C(1380575042841637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042841637000), 0x0003, 0x0035, 1408}, {INT64_C(1380575042841637000), 0x0003, 0x0036, 4064}, {INT64_C(1380575042841637000), 0x0003, 0x0034, 0}, {INT64_C(1380575042841637000), 0x0003, 0x0030, 320}, {INT64_C(1380575042841637000), 0x0003, 0x0031, 128}, {INT64_C(1380575042841637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042841637000), 0x0000, 0x0000, 0}, {INT64_C(1380575042859636000), 0x0003, 0x0000, 1783}, {INT64_C(1380575042859636000), 0x0003, 0x0001, 5269}, {INT64_C(1380575042859636000), 0x0003, 0x0035, 1783}, {INT64_C(1380575042859636000), 0x0003, 0x0036, 5269}, {INT64_C(1380575042859636000), 0x0003, 0x0034, 0}, {INT64_C(1380575042859636000), 0x0003, 0x0030, 480}, {INT64_C(1380575042859636000), 0x0003, 0x0031, 256}, {INT64_C(1380575042859636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042859636000), 0x0003, 0x0035, 4007}, {INT64_C(1380575042859636000), 0x0003, 0x0036, 5002}, {INT64_C(1380575042859636000), 0x0003, 0x0034, 0}, {INT64_C(1380575042859636000), 0x0003, 0x0030, 640}, {INT64_C(1380575042859636000), 0x0003, 0x0031, 256}, {INT64_C(1380575042859636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042859636000), 0x0003, 0x0035, 1588}, {INT64_C(1380575042859636000), 0x0003, 0x0036, 4000}, {INT64_C(1380575042859636000), 0x0003, 0x0034, 1}, {INT64_C(1380575042859636000), 0x0003, 0x0030, 384}, {INT64_C(1380575042859636000), 0x0003, 0x0031, 160}, {INT64_C(1380575042859636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042859636000), 0x0000, 0x0000, 0}, {INT64_C(1380575042879636000), 0x0003, 0x0000, 1846}, {INT64_C(1380575042879636000), 0x0003, 0x0001, 5204}, {INT64_C(1380575042879636000), 0x0003, 0x0035, 1846}, {INT64_C(1380575042879636000), 0x0003, 0x0036, 5204}, {INT64_C(1380575042879636000), 0x0003, 0x0034, 0}, {INT64_C(1380575042879636000), 0x0003, 0x0030, 640}, {INT64_C(1380575042879636000), 0x0003, 0x0031, 256}, {INT64_C(1380575042879636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042879636000), 0x0003, 0x0035, 4038}, {INT64_C(1380575042879636000), 0x0003, 0x0036, 4959}, {INT64_C(1380575042879636000), 0x0003, 0x0034, 0}, {INT64_C(1380575042879636000), 0x0003, 0x0030, 480}, {INT64_C(1380575042879636000), 0x0003, 0x0031, 256}, {INT64_C(1380575042879636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042879636000), 0x0003, 0x0035, 1691}, {INT64_C(1380575042879636000), 0x0003, 0x0036, 4000}, {INT64_C(1380575042879636000), 0x0003, 0x0034, 1}, {INT64_C(1380575042879636000), 0x0003, 0x0030, 256}, {INT64_C(1380575042879636000), 0x0003, 0x0031, 160}, {INT64_C(1380575042879636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042879636000), 0x0000, 0x0000, 0}, {INT64_C(1380575042897636000), 0x0003, 0x0000, 1884}, {INT64_C(1380575042897636000), 0x0003, 0x0001, 5149}, {INT64_C(1380575042897636000), 0x0003, 0x0035, 1884}, {INT64_C(1380575042897636000), 0x0003, 0x0036, 5149}, {INT64_C(1380575042897636000), 0x0003, 0x0034, 0}, {INT64_C(1380575042897636000), 0x0003, 0x0030, 480}, {INT64_C(1380575042897636000), 0x0003, 0x0031, 256}, {INT64_C(1380575042897636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042897636000), 0x0003, 0x0035, 4062}, {INT64_C(1380575042897636000), 0x0003, 0x0036, 4930}, {INT64_C(1380575042897636000), 0x0003, 0x0034, 0}, {INT64_C(1380575042897636000), 0x0003, 0x0030, 640}, {INT64_C(1380575042897636000), 0x0003, 0x0031, 256}, {INT64_C(1380575042897636000), 0x0000, 0x0002, 0}, {INT64_C(1380575042897636000), 0x0000, 0x0000, 0}, {INT64_C(1380575042915637000), 0x0003, 0x0000, 2907}, {INT64_C(1380575042915637000), 0x0003, 0x0001, 5760}, {INT64_C(1380575042915637000), 0x0003, 0x0035, 2907}, {INT64_C(1380575042915637000), 0x0003, 0x0036, 5760}, {INT64_C(1380575042915637000), 0x0003, 0x0034, 1}, {INT64_C(1380575042915637000), 0x0003, 0x0030, 256}, {INT64_C(1380575042915637000), 0x0003, 0x0031, 160}, {INT64_C(1380575042915637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042915637000), 0x0003, 0x0035, 1910}, {INT64_C(1380575042915637000), 0x0003, 0x0036, 5018}, {INT64_C(1380575042915637000), 0x0003, 0x0034, 0}, {INT64_C(1380575042915637000), 0x0003, 0x0030, 480}, {INT64_C(1380575042915637000), 0x0003, 0x0031, 256}, {INT64_C(1380575042915637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042915637000), 0x0003, 0x0035, 4090}, {INT64_C(1380575042915637000), 0x0003, 0x0036, 4879}, {INT64_C(1380575042915637000), 0x0003, 0x0034, 0}, {INT64_C(1380575042915637000), 0x0003, 0x0030, 480}, {INT64_C(1380575042915637000), 0x0003, 0x0031, 256}, {INT64_C(1380575042915637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042915637000), 0x0003, 0x0035, 1840}, {INT64_C(1380575042915637000), 0x0003, 0x0036, 3840}, {INT64_C(1380575042915637000), 0x0003, 0x0034, 1}, {INT64_C(1380575042915637000), 0x0003, 0x0030, 256}, {INT64_C(1380575042915637000), 0x0003, 0x0031, 160}, {INT64_C(1380575042915637000), 0x0000, 0x0002, 0}, {INT64_C(1380575042915637000), 0x0000, 0x0000, 0}, {INT64_C(1380575042935638000), 0x0003, 0x0000, 2944}, {INT64_C(1380575042935638000), 0x0003, 0x0001, 5570}, {INT64_C(1380575042935638000), 0x0003, 0x0035, 2944}, {INT64_C(1380575042935638000), 0x0003, 0x0036, 5570}, {INT64_C(1380575042935638000), 0x0003, 0x0034, 0}, {INT64_C(1380575042935638000), 0x0003, 0x0030, 320}, {INT64_C(1380575042935638000), 0x0003, 0x0031, 128}, {INT64_C(1380575042935638000), 0x0000, 0x0002, 0}, {INT64_C(1380575042935638000), 0x0003, 0x0035, 2014}, {INT64_C(1380575042935638000), 0x0003, 0x0036, 4911}, {INT64_C(1380575042935638000), 0x0003, 0x0034, 0}, {INT64_C(1380575042935638000), 0x0003, 0x0030, 640}, {INT64_C(1380575042935638000), 0x0003, 0x0031, 256}, {INT64_C(1380575042935638000), 0x0000, 0x0002, 0}, {INT64_C(1380575042935638000), 0x0003, 0x0035, 4143}, {INT64_C(1380575042935638000), 0x0003, 0x0036, 4810}, {INT64_C(1380575042935638000), 0x0003, 0x0034, 0}, {INT64_C(1380575042935638000), 0x0003, 0x0030, 480}, {INT64_C(1380575042935638000), 0x0003, 0x0031, 256}, {INT64_C(1380575042935638000), 0x0000, 0x0002, 0}, {INT64_C(1380575042935638000), 0x0003, 0x0035, 1892}, {INT64_C(1380575042935638000), 0x0003, 0x0036, 3840}, {INT64_C(1380575042935638000), 0x0003, 0x0034, 1}, {INT64_C(1380575042935638000), 0x0003, 0x0030, 256}, {INT64_C(1380575042935638000), 0x0003, 0x0031, 160}, {INT64_C(1380575042935638000), 0x0000, 0x0002, 0}, {INT64_C(1380575042935638000), 0x0000, 0x0000, 0}, {INT64_C(1380575042953635000), 0x0003, 0x0000, 2981}, {INT64_C(1380575042953635000), 0x0003, 0x0001, 5475}, {INT64_C(1380575042953635000), 0x0003, 0x0035, 2981}, {INT64_C(1380575042953635000), 0x0003, 0x0036, 5475}, {INT64_C(1380575042953635000), 0x0003, 0x0034, 0}, {INT64_C(1380575042953635000), 0x0003, 0x0030, 320}, {INT64_C(1380575042953635000), 0x0003, 0x0031, 256}, {INT64_C(1380575042953635000), 0x0000, 0x0002, 0}, {INT64_C(1380575042953635000), 0x0003, 0x0035, 2048}, {INT64_C(1380575042953635000), 0x0003, 0x0036, 4809}, {INT64_C(1380575042953635000), 0x0003, 0x0034, 0}, {INT64_C(1380575042953635000), 0x0003, 0x0030, 480}, {INT64_C(1380575042953635000), 0x0003, 0x0031, 128}, {INT64_C(1380575042953635000), 0x0000, 0x0002, 0}, {INT64_C(1380575042953635000), 0x0003, 0x0035, 4173}, {INT64_C(1380575042953635000), 0x0003, 0x0036, 4725}, {INT64_C(1380575042953635000), 0x0003, 0x0034, 0}, {INT64_C(1380575042953635000), 0x0003, 0x0030, 480}, {INT64_C(1380575042953635000), 0x0003, 0x0031, 256}, {INT64_C(1380575042953635000), 0x0000, 0x0002, 0}, {INT64_C(1380575042953635000), 0x0003, 0x0035, 1968}, {INT64_C(1380575042953635000), 0x0003, 0x0036, 3680}, {INT64_C(1380575042953635000), 0x0003, 0x0034, 1}, {INT64_C(1380575042953635000), 0x0003, 0x0030, 256}, {INT64_C(1380575042953635000), 0x0003, 0x0031, 160}, {INT64_C(1380575042953635000), 0x0000, 0x0002, 0}, {INT64_C(1380575042953635000), 0x0000, 0x0000, 0}, {INT64_C(1380575042971635000), 0x0003, 0x0000, 2146}, {INT64_C(1380575042971635000), 0x0003, 0x0001, 4733}, {INT64_C(1380575042971635000), 0x0003, 0x0035, 2146}, {INT64_C(1380575042971635000), 0x0003, 0x0036, 4733}, {INT64_C(1380575042971635000), 0x0003, 0x0034, 0}, {INT64_C(1380575042971635000), 0x0003, 0x0030, 480}, {INT64_C(1380575042971635000), 0x0003, 0x0031, 256}, {INT64_C(1380575042971635000), 0x0000, 0x0002, 0}, {INT64_C(1380575042971635000), 0x0003, 0x0035, 4205}, {INT64_C(1380575042971635000), 0x0003, 0x0036, 4694}, {INT64_C(1380575042971635000), 0x0003, 0x0034, 0}, {INT64_C(1380575042971635000), 0x0003, 0x0030, 480}, {INT64_C(1380575042971635000), 0x0003, 0x0031, 256}, {INT64_C(1380575042971635000), 0x0000, 0x0002, 0}, {INT64_C(1380575042971635000), 0x0003, 0x0035, 2027}, {INT64_C(1380575042971635000), 0x0003, 0x0036, 3680}, {INT64_C(1380575042971635000), 0x0003, 0x0034, 1}, {INT64_C(1380575042971635000), 0x0003, 0x0030, 256}, {INT64_C(1380575042971635000), 0x0003, 0x0031, 160}, {INT64_C(1380575042971635000), 0x0000, 0x0002, 0}, {INT64_C(1380575042971635000), 0x0000, 0x0000, 0}, {INT64_C(1380575042991634000), 0x0003, 0x0000, 2150}, {INT64_C(1380575042991634000), 0x0003, 0x0001, 4596}, {INT64_C(1380575042991634000), 0x0003, 0x0035, 2150}, {INT64_C(1380575042991634000), 0x0003, 0x0036, 4596}, {INT64_C(1380575042991634000), 0x0003, 0x0034, 0}, {INT64_C(1380575042991634000), 0x0003, 0x0030, 640}, {INT64_C(1380575042991634000), 0x0003, 0x0031, 256}, {INT64_C(1380575042991634000), 0x0000, 0x0002, 0}, {INT64_C(1380575042991634000), 0x0003, 0x0035, 4267}, {INT64_C(1380575042991634000), 0x0003, 0x0036, 4563}, {INT64_C(1380575042991634000), 0x0003, 0x0034, 0}, {INT64_C(1380575042991634000), 0x0003, 0x0030, 640}, {INT64_C(1380575042991634000), 0x0003, 0x0031, 384}, {INT64_C(1380575042991634000), 0x0000, 0x0002, 0}, {INT64_C(1380575042991634000), 0x0003, 0x0035, 2073}, {INT64_C(1380575042991634000), 0x0003, 0x0036, 3680}, {INT64_C(1380575042991634000), 0x0003, 0x0034, 1}, {INT64_C(1380575042991634000), 0x0003, 0x0030, 256}, {INT64_C(1380575042991634000), 0x0003, 0x0031, 160}, {INT64_C(1380575042991634000), 0x0000, 0x0002, 0}, {INT64_C(1380575042991634000), 0x0000, 0x0000, 0}, {INT64_C(1380575043009639000), 0x0003, 0x0000, 3137}, {INT64_C(1380575043009639000), 0x0003, 0x0001, 5224}, {INT64_C(1380575043009639000), 0x0003, 0x0035, 3137}, {INT64_C(1380575043009639000), 0x0003, 0x0036, 5224}, {INT64_C(1380575043009639000), 0x0003, 0x0034, 0}, {INT64_C(1380575043009639000), 0x0003, 0x0030, 320}, {INT64_C(1380575043009639000), 0x0003, 0x0031, 256}, {INT64_C(1380575043009639000), 0x0000, 0x0002, 0}, {INT64_C(1380575043009639000), 0x0003, 0x0035, 2248}, {INT64_C(1380575043009639000), 0x0003, 0x0036, 4524}, {INT64_C(1380575043009639000), 0x0003, 0x0034, 0}, {INT64_C(1380575043009639000), 0x0003, 0x0030, 480}, {INT64_C(1380575043009639000), 0x0003, 0x0031, 384}, {INT64_C(1380575043009639000), 0x0000, 0x0002, 0}, {INT64_C(1380575043009639000), 0x0003, 0x0035, 4284}, {INT64_C(1380575043009639000), 0x0003, 0x0036, 4435}, {INT64_C(1380575043009639000), 0x0003, 0x0034, 0}, {INT64_C(1380575043009639000), 0x0003, 0x0030, 640}, {INT64_C(1380575043009639000), 0x0003, 0x0031, 256}, {INT64_C(1380575043009639000), 0x0000, 0x0002, 0}, {INT64_C(1380575043009639000), 0x0000, 0x0000, 0}, {INT64_C(1380575043029636000), 0x0003, 0x0000, 3187}, {INT64_C(1380575043029636000), 0x0003, 0x0001, 5136}, {INT64_C(1380575043029636000), 0x0003, 0x0035, 3187}, {INT64_C(1380575043029636000), 0x0003, 0x0036, 5136}, {INT64_C(1380575043029636000), 0x0003, 0x0034, 0}, {INT64_C(1380575043029636000), 0x0003, 0x0030, 480}, {INT64_C(1380575043029636000), 0x0003, 0x0031, 256}, {INT64_C(1380575043029636000), 0x0000, 0x0002, 0}, {INT64_C(1380575043029636000), 0x0003, 0x0035, 2287}, {INT64_C(1380575043029636000), 0x0003, 0x0036, 4463}, {INT64_C(1380575043029636000), 0x0003, 0x0034, 0}, {INT64_C(1380575043029636000), 0x0003, 0x0030, 480}, {INT64_C(1380575043029636000), 0x0003, 0x0031, 256}, {INT64_C(1380575043029636000), 0x0000, 0x0002, 0}, {INT64_C(1380575043029636000), 0x0003, 0x0035, 4309}, {INT64_C(1380575043029636000), 0x0003, 0x0036, 4333}, {INT64_C(1380575043029636000), 0x0003, 0x0034, 0}, {INT64_C(1380575043029636000), 0x0003, 0x0030, 480}, {INT64_C(1380575043029636000), 0x0003, 0x0031, 384}, {INT64_C(1380575043029636000), 0x0000, 0x0002, 0}, {INT64_C(1380575043029636000), 0x0000, 0x0000, 0}, {INT64_C(1380575043047630000), 0x0003, 0x0000, 3231}, {INT64_C(1380575043047630000), 0x0003, 0x0001, 5041}, {INT64_C(1380575043047630000), 0x0003, 0x0035, 3231}, {INT64_C(1380575043047630000), 0x0003, 0x0036, 5041}, {INT64_C(1380575043047630000), 0x0003, 0x0034, 0}, {INT64_C(1380575043047630000), 0x0003, 0x0030, 480}, {INT64_C(1380575043047630000), 0x0003, 0x0031, 256}, {INT64_C(1380575043047630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043047630000), 0x0003, 0x0035, 2345}, {INT64_C(1380575043047630000), 0x0003, 0x0036, 4386}, {INT64_C(1380575043047630000), 0x0003, 0x0034, 0}, {INT64_C(1380575043047630000), 0x0003, 0x0030, 640}, {INT64_C(1380575043047630000), 0x0003, 0x0031, 384}, {INT64_C(1380575043047630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043047630000), 0x0003, 0x0035, 4331}, {INT64_C(1380575043047630000), 0x0003, 0x0036, 4245}, {INT64_C(1380575043047630000), 0x0003, 0x0034, 0}, {INT64_C(1380575043047630000), 0x0003, 0x0030, 640}, {INT64_C(1380575043047630000), 0x0003, 0x0031, 384}, {INT64_C(1380575043047630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043047630000), 0x0003, 0x0035, 2219}, {INT64_C(1380575043047630000), 0x0003, 0x0036, 3520}, {INT64_C(1380575043047630000), 0x0003, 0x0034, 1}, {INT64_C(1380575043047630000), 0x0003, 0x0030, 256}, {INT64_C(1380575043047630000), 0x0003, 0x0031, 160}, {INT64_C(1380575043047630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043047630000), 0x0000, 0x0000, 0}, {INT64_C(1380575043065636000), 0x0003, 0x0000, 3272}, {INT64_C(1380575043065636000), 0x0003, 0x0001, 4947}, {INT64_C(1380575043065636000), 0x0003, 0x0035, 3272}, {INT64_C(1380575043065636000), 0x0003, 0x0036, 4947}, {INT64_C(1380575043065636000), 0x0003, 0x0034, 0}, {INT64_C(1380575043065636000), 0x0003, 0x0030, 480}, {INT64_C(1380575043065636000), 0x0003, 0x0031, 256}, {INT64_C(1380575043065636000), 0x0000, 0x0002, 0}, {INT64_C(1380575043065636000), 0x0003, 0x0035, 2374}, {INT64_C(1380575043065636000), 0x0003, 0x0036, 4308}, {INT64_C(1380575043065636000), 0x0003, 0x0034, 0}, {INT64_C(1380575043065636000), 0x0003, 0x0030, 480}, {INT64_C(1380575043065636000), 0x0003, 0x0031, 256}, {INT64_C(1380575043065636000), 0x0000, 0x0002, 0}, {INT64_C(1380575043065636000), 0x0003, 0x0035, 4369}, {INT64_C(1380575043065636000), 0x0003, 0x0036, 4157}, {INT64_C(1380575043065636000), 0x0003, 0x0034, 0}, {INT64_C(1380575043065636000), 0x0003, 0x0030, 640}, {INT64_C(1380575043065636000), 0x0003, 0x0031, 384}, {INT64_C(1380575043065636000), 0x0000, 0x0002, 0}, {INT64_C(1380575043065636000), 0x0003, 0x0035, 2240}, {INT64_C(1380575043065636000), 0x0003, 0x0036, 3360}, {INT64_C(1380575043065636000), 0x0003, 0x0034, 1}, {INT64_C(1380575043065636000), 0x0003, 0x0030, 256}, {INT64_C(1380575043065636000), 0x0003, 0x0031, 160}, {INT64_C(1380575043065636000), 0x0000, 0x0002, 0}, {INT64_C(1380575043065636000), 0x0000, 0x0000, 0}, {INT64_C(1380575043085637000), 0x0003, 0x0000, 3297}, {INT64_C(1380575043085637000), 0x0003, 0x0001, 4881}, {INT64_C(1380575043085637000), 0x0003, 0x0035, 3297}, {INT64_C(1380575043085637000), 0x0003, 0x0036, 4881}, {INT64_C(1380575043085637000), 0x0003, 0x0034, 0}, {INT64_C(1380575043085637000), 0x0003, 0x0030, 480}, {INT64_C(1380575043085637000), 0x0003, 0x0031, 256}, {INT64_C(1380575043085637000), 0x0000, 0x0002, 0}, {INT64_C(1380575043085637000), 0x0003, 0x0035, 2402}, {INT64_C(1380575043085637000), 0x0003, 0x0036, 4265}, {INT64_C(1380575043085637000), 0x0003, 0x0034, 0}, {INT64_C(1380575043085637000), 0x0003, 0x0030, 480}, {INT64_C(1380575043085637000), 0x0003, 0x0031, 256}, {INT64_C(1380575043085637000), 0x0000, 0x0002, 0}, {INT64_C(1380575043085637000), 0x0003, 0x0035, 4392}, {INT64_C(1380575043085637000), 0x0003, 0x0036, 4052}, {INT64_C(1380575043085637000), 0x0003, 0x0034, 0}, {INT64_C(1380575043085637000), 0x0003, 0x0030, 480}, {INT64_C(1380575043085637000), 0x0003, 0x0031, 256}, {INT64_C(1380575043085637000), 0x0000, 0x0002, 0}, {INT64_C(1380575043085637000), 0x0003, 0x0035, 2292}, {INT64_C(1380575043085637000), 0x0003, 0x0036, 3360}, {INT64_C(1380575043085637000), 0x0003, 0x0034, 1}, {INT64_C(1380575043085637000), 0x0003, 0x0030, 384}, {INT64_C(1380575043085637000), 0x0003, 0x0031, 160}, {INT64_C(1380575043085637000), 0x0000, 0x0002, 0}, {INT64_C(1380575043085637000), 0x0000, 0x0000, 0}, {INT64_C(1380575043103636000), 0x0003, 0x0000, 3346}, {INT64_C(1380575043103636000), 0x0003, 0x0001, 4801}, {INT64_C(1380575043103636000), 0x0003, 0x0035, 3346}, {INT64_C(1380575043103636000), 0x0003, 0x0036, 4801}, {INT64_C(1380575043103636000), 0x0003, 0x0034, 0}, {INT64_C(1380575043103636000), 0x0003, 0x0030, 480}, {INT64_C(1380575043103636000), 0x0003, 0x0031, 256}, {INT64_C(1380575043103636000), 0x0000, 0x0002, 0}, {INT64_C(1380575043103636000), 0x0003, 0x0035, 2490}, {INT64_C(1380575043103636000), 0x0003, 0x0036, 4193}, {INT64_C(1380575043103636000), 0x0003, 0x0034, 0}, {INT64_C(1380575043103636000), 0x0003, 0x0030, 480}, {INT64_C(1380575043103636000), 0x0003, 0x0031, 384}, {INT64_C(1380575043103636000), 0x0000, 0x0002, 0}, {INT64_C(1380575043103636000), 0x0003, 0x0035, 4416}, {INT64_C(1380575043103636000), 0x0003, 0x0036, 4010}, {INT64_C(1380575043103636000), 0x0003, 0x0034, 0}, {INT64_C(1380575043103636000), 0x0003, 0x0030, 320}, {INT64_C(1380575043103636000), 0x0003, 0x0031, 256}, {INT64_C(1380575043103636000), 0x0000, 0x0002, 0}, {INT64_C(1380575043103636000), 0x0003, 0x0035, 2347}, {INT64_C(1380575043103636000), 0x0003, 0x0036, 3360}, {INT64_C(1380575043103636000), 0x0003, 0x0034, 1}, {INT64_C(1380575043103636000), 0x0003, 0x0030, 256}, {INT64_C(1380575043103636000), 0x0003, 0x0031, 160}, {INT64_C(1380575043103636000), 0x0000, 0x0002, 0}, {INT64_C(1380575043103636000), 0x0000, 0x0000, 0}, {INT64_C(1380575043121634000), 0x0003, 0x0000, 3388}, {INT64_C(1380575043121634000), 0x0003, 0x0001, 4723}, {INT64_C(1380575043121634000), 0x0003, 0x0035, 3388}, {INT64_C(1380575043121634000), 0x0003, 0x0036, 4723}, {INT64_C(1380575043121634000), 0x0003, 0x0034, 0}, {INT64_C(1380575043121634000), 0x0003, 0x0030, 480}, {INT64_C(1380575043121634000), 0x0003, 0x0031, 256}, {INT64_C(1380575043121634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043121634000), 0x0003, 0x0035, 2540}, {INT64_C(1380575043121634000), 0x0003, 0x0036, 4129}, {INT64_C(1380575043121634000), 0x0003, 0x0034, 0}, {INT64_C(1380575043121634000), 0x0003, 0x0030, 480}, {INT64_C(1380575043121634000), 0x0003, 0x0031, 256}, {INT64_C(1380575043121634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043121634000), 0x0003, 0x0035, 4454}, {INT64_C(1380575043121634000), 0x0003, 0x0036, 3845}, {INT64_C(1380575043121634000), 0x0003, 0x0034, 0}, {INT64_C(1380575043121634000), 0x0003, 0x0030, 320}, {INT64_C(1380575043121634000), 0x0003, 0x0031, 256}, {INT64_C(1380575043121634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043121634000), 0x0000, 0x0000, 0}, {INT64_C(1380575043141631000), 0x0003, 0x0000, 3433}, {INT64_C(1380575043141631000), 0x0003, 0x0001, 4600}, {INT64_C(1380575043141631000), 0x0003, 0x0035, 3433}, {INT64_C(1380575043141631000), 0x0003, 0x0036, 4600}, {INT64_C(1380575043141631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043141631000), 0x0003, 0x0030, 480}, {INT64_C(1380575043141631000), 0x0003, 0x0031, 256}, {INT64_C(1380575043141631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043141631000), 0x0003, 0x0035, 2624}, {INT64_C(1380575043141631000), 0x0003, 0x0036, 4021}, {INT64_C(1380575043141631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043141631000), 0x0003, 0x0030, 480}, {INT64_C(1380575043141631000), 0x0003, 0x0031, 256}, {INT64_C(1380575043141631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043141631000), 0x0003, 0x0035, 4504}, {INT64_C(1380575043141631000), 0x0003, 0x0036, 3690}, {INT64_C(1380575043141631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043141631000), 0x0003, 0x0030, 320}, {INT64_C(1380575043141631000), 0x0003, 0x0031, 256}, {INT64_C(1380575043141631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043141631000), 0x0000, 0x0000, 0}, {INT64_C(1380575043159633000), 0x0003, 0x0000, 3533}, {INT64_C(1380575043159633000), 0x0003, 0x0001, 4438}, {INT64_C(1380575043159633000), 0x0003, 0x0035, 3533}, {INT64_C(1380575043159633000), 0x0003, 0x0036, 4438}, {INT64_C(1380575043159633000), 0x0003, 0x0034, 0}, {INT64_C(1380575043159633000), 0x0003, 0x0030, 480}, {INT64_C(1380575043159633000), 0x0003, 0x0031, 256}, {INT64_C(1380575043159633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043159633000), 0x0000, 0x0000, 0}, {INT64_C(1380575043177630000), 0x0003, 0x0000, 3653}, {INT64_C(1380575043177630000), 0x0003, 0x0001, 4244}, {INT64_C(1380575043177630000), 0x0003, 0x0035, 3653}, {INT64_C(1380575043177630000), 0x0003, 0x0036, 4244}, {INT64_C(1380575043177630000), 0x0003, 0x0034, 0}, {INT64_C(1380575043177630000), 0x0003, 0x0030, 320}, {INT64_C(1380575043177630000), 0x0003, 0x0031, 256}, {INT64_C(1380575043177630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043177630000), 0x0000, 0x0000, 0}, {INT64_C(1380575043197633000), 0x0003, 0x0000, 3930}, {INT64_C(1380575043197633000), 0x0003, 0x0001, 4000}, {INT64_C(1380575043197633000), 0x0003, 0x0035, 3930}, {INT64_C(1380575043197633000), 0x0003, 0x0036, 4000}, {INT64_C(1380575043197633000), 0x0003, 0x0034, 1}, {INT64_C(1380575043197633000), 0x0003, 0x0030, 256}, {INT64_C(1380575043197633000), 0x0003, 0x0031, 160}, {INT64_C(1380575043197633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043197633000), 0x0000, 0x0000, 0}, {INT64_C(1380575043289630000), 0x0001, 0x014d, 0}, {INT64_C(1380575043289630000), 0x0001, 0x014a, 0}, {INT64_C(1380575043289630000), 0x0000, 0x0000, 0}, {INT64_C(1380575043559632000), 0x0003, 0x0000, 8902}, {INT64_C(1380575043559632000), 0x0003, 0x0001, 4605}, {INT64_C(1380575043559632000), 0x0003, 0x0035, 8902}, {INT64_C(1380575043559632000), 0x0003, 0x0036, 4605}, {INT64_C(1380575043559632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043559632000), 0x0003, 0x0030, 480}, {INT64_C(1380575043559632000), 0x0003, 0x0031, 256}, {INT64_C(1380575043559632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043559632000), 0x0001, 0x014d, 1}, {INT64_C(1380575043559632000), 0x0001, 0x014a, 1}, {INT64_C(1380575043559632000), 0x0000, 0x0000, 0}, {INT64_C(1380575043571631000), 0x0003, 0x0000, 7095}, {INT64_C(1380575043571631000), 0x0003, 0x0001, 6720}, {INT64_C(1380575043571631000), 0x0003, 0x0035, 7095}, {INT64_C(1380575043571631000), 0x0003, 0x0036, 6720}, {INT64_C(1380575043571631000), 0x0003, 0x0034, 1}, {INT64_C(1380575043571631000), 0x0003, 0x0030, 256}, {INT64_C(1380575043571631000), 0x0003, 0x0031, 160}, {INT64_C(1380575043571631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043571631000), 0x0003, 0x0035, 8258}, {INT64_C(1380575043571631000), 0x0003, 0x0036, 6080}, {INT64_C(1380575043571631000), 0x0003, 0x0034, 1}, {INT64_C(1380575043571631000), 0x0003, 0x0030, 256}, {INT64_C(1380575043571631000), 0x0003, 0x0031, 160}, {INT64_C(1380575043571631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043571631000), 0x0003, 0x0035, 8832}, {INT64_C(1380575043571631000), 0x0003, 0x0036, 4541}, {INT64_C(1380575043571631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043571631000), 0x0003, 0x0030, 640}, {INT64_C(1380575043571631000), 0x0003, 0x0031, 128}, {INT64_C(1380575043571631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043571631000), 0x0000, 0x0000, 0}, {INT64_C(1380575043577630000), 0x0003, 0x0000, 7040}, {INT64_C(1380575043577630000), 0x0003, 0x0035, 7040}, {INT64_C(1380575043577630000), 0x0003, 0x0036, 6720}, {INT64_C(1380575043577630000), 0x0003, 0x0034, 1}, {INT64_C(1380575043577630000), 0x0003, 0x0030, 384}, {INT64_C(1380575043577630000), 0x0003, 0x0031, 160}, {INT64_C(1380575043577630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043577630000), 0x0003, 0x0035, 5275}, {INT64_C(1380575043577630000), 0x0003, 0x0036, 5711}, {INT64_C(1380575043577630000), 0x0003, 0x0034, 1}, {INT64_C(1380575043577630000), 0x0003, 0x0030, 512}, {INT64_C(1380575043577630000), 0x0003, 0x0031, 320}, {INT64_C(1380575043577630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043577630000), 0x0003, 0x0035, 8192}, {INT64_C(1380575043577630000), 0x0003, 0x0036, 5709}, {INT64_C(1380575043577630000), 0x0003, 0x0034, 0}, {INT64_C(1380575043577630000), 0x0003, 0x0030, 320}, {INT64_C(1380575043577630000), 0x0003, 0x0031, 128}, {INT64_C(1380575043577630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043577630000), 0x0003, 0x0035, 8832}, {INT64_C(1380575043577630000), 0x0003, 0x0036, 4486}, {INT64_C(1380575043577630000), 0x0003, 0x0034, 0}, {INT64_C(1380575043577630000), 0x0003, 0x0030, 480}, {INT64_C(1380575043577630000), 0x0003, 0x0031, 128}, {INT64_C(1380575043577630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043577630000), 0x0000, 0x0000, 0}, {INT64_C(1380575043589615000), 0x0003, 0x0000, 7035}, {INT64_C(1380575043589615000), 0x0003, 0x0035, 7035}, {INT64_C(1380575043589615000), 0x0003, 0x0036, 6720}, {INT64_C(1380575043589615000), 0x0003, 0x0034, 1}, {INT64_C(1380575043589615000), 0x0003, 0x0030, 384}, {INT64_C(1380575043589615000), 0x0003, 0x0031, 160}, {INT64_C(1380575043589615000), 0x0000, 0x0002, 0}, {INT64_C(1380575043589615000), 0x0003, 0x0035, 5235}, {INT64_C(1380575043589615000), 0x0003, 0x0036, 5716}, {INT64_C(1380575043589615000), 0x0003, 0x0034, 1}, {INT64_C(1380575043589615000), 0x0003, 0x0030, 512}, {INT64_C(1380575043589615000), 0x0003, 0x0031, 320}, {INT64_C(1380575043589615000), 0x0000, 0x0002, 0}, {INT64_C(1380575043589615000), 0x0003, 0x0035, 8192}, {INT64_C(1380575043589615000), 0x0003, 0x0036, 5729}, {INT64_C(1380575043589615000), 0x0003, 0x0034, 0}, {INT64_C(1380575043589615000), 0x0003, 0x0030, 320}, {INT64_C(1380575043589615000), 0x0003, 0x0031, 128}, {INT64_C(1380575043589615000), 0x0000, 0x0002, 0}, {INT64_C(1380575043589615000), 0x0003, 0x0035, 8758}, {INT64_C(1380575043589615000), 0x0003, 0x0036, 4411}, {INT64_C(1380575043589615000), 0x0003, 0x0034, 0}, {INT64_C(1380575043589615000), 0x0003, 0x0030, 640}, {INT64_C(1380575043589615000), 0x0003, 0x0031, 256}, {INT64_C(1380575043589615000), 0x0000, 0x0002, 0}, {INT64_C(1380575043589615000), 0x0003, 0x0035, 5057}, {INT64_C(1380575043589615000), 0x0003, 0x0036, 800}, {INT64_C(1380575043589615000), 0x0003, 0x0034, 1}, {INT64_C(1380575043589615000), 0x0003, 0x0030, 512}, {INT64_C(1380575043589615000), 0x0003, 0x0031, 160}, {INT64_C(1380575043589615000), 0x0000, 0x0002, 0}, {INT64_C(1380575043589615000), 0x0000, 0x0000, 0}, {INT64_C(1380575043595634000), 0x0003, 0x0000, 7028}, {INT64_C(1380575043595634000), 0x0003, 0x0035, 7028}, {INT64_C(1380575043595634000), 0x0003, 0x0036, 6720}, {INT64_C(1380575043595634000), 0x0003, 0x0034, 1}, {INT64_C(1380575043595634000), 0x0003, 0x0030, 384}, {INT64_C(1380575043595634000), 0x0003, 0x0031, 160}, {INT64_C(1380575043595634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043595634000), 0x0003, 0x0035, 5216}, {INT64_C(1380575043595634000), 0x0003, 0x0036, 5710}, {INT64_C(1380575043595634000), 0x0003, 0x0034, 1}, {INT64_C(1380575043595634000), 0x0003, 0x0030, 512}, {INT64_C(1380575043595634000), 0x0003, 0x0031, 320}, {INT64_C(1380575043595634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043595634000), 0x0003, 0x0035, 8192}, {INT64_C(1380575043595634000), 0x0003, 0x0036, 5707}, {INT64_C(1380575043595634000), 0x0003, 0x0034, 0}, {INT64_C(1380575043595634000), 0x0003, 0x0030, 320}, {INT64_C(1380575043595634000), 0x0003, 0x0031, 128}, {INT64_C(1380575043595634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043595634000), 0x0003, 0x0035, 8752}, {INT64_C(1380575043595634000), 0x0003, 0x0036, 4395}, {INT64_C(1380575043595634000), 0x0003, 0x0034, 0}, {INT64_C(1380575043595634000), 0x0003, 0x0030, 480}, {INT64_C(1380575043595634000), 0x0003, 0x0031, 256}, {INT64_C(1380575043595634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043595634000), 0x0003, 0x0035, 5031}, {INT64_C(1380575043595634000), 0x0003, 0x0036, 800}, {INT64_C(1380575043595634000), 0x0003, 0x0034, 1}, {INT64_C(1380575043595634000), 0x0003, 0x0030, 512}, {INT64_C(1380575043595634000), 0x0003, 0x0031, 160}, {INT64_C(1380575043595634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043595634000), 0x0000, 0x0000, 0}, {INT64_C(1380575043609633000), 0x0003, 0x0000, 7015}, {INT64_C(1380575043609633000), 0x0003, 0x0035, 7015}, {INT64_C(1380575043609633000), 0x0003, 0x0036, 6720}, {INT64_C(1380575043609633000), 0x0003, 0x0034, 1}, {INT64_C(1380575043609633000), 0x0003, 0x0030, 384}, {INT64_C(1380575043609633000), 0x0003, 0x0031, 160}, {INT64_C(1380575043609633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043609633000), 0x0003, 0x0035, 5211}, {INT64_C(1380575043609633000), 0x0003, 0x0036, 5737}, {INT64_C(1380575043609633000), 0x0003, 0x0034, 1}, {INT64_C(1380575043609633000), 0x0003, 0x0030, 512}, {INT64_C(1380575043609633000), 0x0003, 0x0031, 480}, {INT64_C(1380575043609633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043609633000), 0x0003, 0x0035, 8192}, {INT64_C(1380575043609633000), 0x0003, 0x0036, 5861}, {INT64_C(1380575043609633000), 0x0003, 0x0034, 0}, {INT64_C(1380575043609633000), 0x0003, 0x0030, 480}, {INT64_C(1380575043609633000), 0x0003, 0x0031, 128}, {INT64_C(1380575043609633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043609633000), 0x0003, 0x0035, 8747}, {INT64_C(1380575043609633000), 0x0003, 0x0036, 4382}, {INT64_C(1380575043609633000), 0x0003, 0x0034, 0}, {INT64_C(1380575043609633000), 0x0003, 0x0030, 480}, {INT64_C(1380575043609633000), 0x0003, 0x0031, 256}, {INT64_C(1380575043609633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043609633000), 0x0000, 0x0000, 0}, {INT64_C(1380575043615633000), 0x0003, 0x0000, 7023}, {INT64_C(1380575043615633000), 0x0003, 0x0035, 7023}, {INT64_C(1380575043615633000), 0x0003, 0x0036, 6720}, {INT64_C(1380575043615633000), 0x0003, 0x0034, 1}, {INT64_C(1380575043615633000), 0x0003, 0x0030, 384}, {INT64_C(1380575043615633000), 0x0003, 0x0031, 160}, {INT64_C(1380575043615633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043615633000), 0x0003, 0x0035, 5212}, {INT64_C(1380575043615633000), 0x0003, 0x0036, 5730}, {INT64_C(1380575043615633000), 0x0003, 0x0034, 0}, {INT64_C(1380575043615633000), 0x0003, 0x0030, 480}, {INT64_C(1380575043615633000), 0x0003, 0x0031, 384}, {INT64_C(1380575043615633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043615633000), 0x0003, 0x0035, 8192}, {INT64_C(1380575043615633000), 0x0003, 0x0036, 5867}, {INT64_C(1380575043615633000), 0x0003, 0x0034, 0}, {INT64_C(1380575043615633000), 0x0003, 0x0030, 480}, {INT64_C(1380575043615633000), 0x0003, 0x0031, 128}, {INT64_C(1380575043615633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043615633000), 0x0003, 0x0035, 8739}, {INT64_C(1380575043615633000), 0x0003, 0x0036, 4337}, {INT64_C(1380575043615633000), 0x0003, 0x0034, 0}, {INT64_C(1380575043615633000), 0x0003, 0x0030, 640}, {INT64_C(1380575043615633000), 0x0003, 0x0031, 256}, {INT64_C(1380575043615633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043615633000), 0x0000, 0x0000, 0}, {INT64_C(1380575043627633000), 0x0003, 0x0000, 6979}, {INT64_C(1380575043627633000), 0x0003, 0x0035, 6979}, {INT64_C(1380575043627633000), 0x0003, 0x0036, 6720}, {INT64_C(1380575043627633000), 0x0003, 0x0034, 1}, {INT64_C(1380575043627633000), 0x0003, 0x0030, 256}, {INT64_C(1380575043627633000), 0x0003, 0x0031, 160}, {INT64_C(1380575043627633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043627633000), 0x0003, 0x0035, 8192}, {INT64_C(1380575043627633000), 0x0003, 0x0036, 5866}, {INT64_C(1380575043627633000), 0x0003, 0x0034, 0}, {INT64_C(1380575043627633000), 0x0003, 0x0030, 480}, {INT64_C(1380575043627633000), 0x0003, 0x0031, 128}, {INT64_C(1380575043627633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043627633000), 0x0003, 0x0035, 5206}, {INT64_C(1380575043627633000), 0x0003, 0x0036, 5691}, {INT64_C(1380575043627633000), 0x0003, 0x0034, 1}, {INT64_C(1380575043627633000), 0x0003, 0x0030, 512}, {INT64_C(1380575043627633000), 0x0003, 0x0031, 320}, {INT64_C(1380575043627633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043627633000), 0x0003, 0x0035, 8733}, {INT64_C(1380575043627633000), 0x0003, 0x0036, 4322}, {INT64_C(1380575043627633000), 0x0003, 0x0034, 0}, {INT64_C(1380575043627633000), 0x0003, 0x0030, 640}, {INT64_C(1380575043627633000), 0x0003, 0x0031, 256}, {INT64_C(1380575043627633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043627633000), 0x0000, 0x0000, 0}, {INT64_C(1380575043633632000), 0x0003, 0x0000, 6961}, {INT64_C(1380575043633632000), 0x0003, 0x0035, 6961}, {INT64_C(1380575043633632000), 0x0003, 0x0036, 6720}, {INT64_C(1380575043633632000), 0x0003, 0x0034, 1}, {INT64_C(1380575043633632000), 0x0003, 0x0030, 256}, {INT64_C(1380575043633632000), 0x0003, 0x0031, 160}, {INT64_C(1380575043633632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043633632000), 0x0003, 0x0035, 8135}, {INT64_C(1380575043633632000), 0x0003, 0x0036, 5860}, {INT64_C(1380575043633632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043633632000), 0x0003, 0x0030, 480}, {INT64_C(1380575043633632000), 0x0003, 0x0031, 256}, {INT64_C(1380575043633632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043633632000), 0x0003, 0x0035, 5188}, {INT64_C(1380575043633632000), 0x0003, 0x0036, 5651}, {INT64_C(1380575043633632000), 0x0003, 0x0034, 1}, {INT64_C(1380575043633632000), 0x0003, 0x0030, 384}, {INT64_C(1380575043633632000), 0x0003, 0x0031, 320}, {INT64_C(1380575043633632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043633632000), 0x0003, 0x0035, 8704}, {INT64_C(1380575043633632000), 0x0003, 0x0036, 4288}, {INT64_C(1380575043633632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043633632000), 0x0003, 0x0030, 480}, {INT64_C(1380575043633632000), 0x0003, 0x0031, 128}, {INT64_C(1380575043633632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043633632000), 0x0000, 0x0000, 0}, {INT64_C(1380575043645634000), 0x0003, 0x0000, 6865}, {INT64_C(1380575043645634000), 0x0003, 0x0001, 6560}, {INT64_C(1380575043645634000), 0x0003, 0x0035, 6865}, {INT64_C(1380575043645634000), 0x0003, 0x0036, 6560}, {INT64_C(1380575043645634000), 0x0003, 0x0034, 1}, {INT64_C(1380575043645634000), 0x0003, 0x0030, 256}, {INT64_C(1380575043645634000), 0x0003, 0x0031, 160}, {INT64_C(1380575043645634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043645634000), 0x0003, 0x0035, 6895}, {INT64_C(1380575043645634000), 0x0003, 0x0036, 5920}, {INT64_C(1380575043645634000), 0x0003, 0x0034, 1}, {INT64_C(1380575043645634000), 0x0003, 0x0030, 256}, {INT64_C(1380575043645634000), 0x0003, 0x0031, 160}, {INT64_C(1380575043645634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043645634000), 0x0003, 0x0035, 8125}, {INT64_C(1380575043645634000), 0x0003, 0x0036, 5920}, {INT64_C(1380575043645634000), 0x0003, 0x0034, 1}, {INT64_C(1380575043645634000), 0x0003, 0x0030, 256}, {INT64_C(1380575043645634000), 0x0003, 0x0031, 160}, {INT64_C(1380575043645634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043645634000), 0x0003, 0x0035, 5181}, {INT64_C(1380575043645634000), 0x0003, 0x0036, 5540}, {INT64_C(1380575043645634000), 0x0003, 0x0034, 1}, {INT64_C(1380575043645634000), 0x0003, 0x0030, 384}, {INT64_C(1380575043645634000), 0x0003, 0x0031, 320}, {INT64_C(1380575043645634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043645634000), 0x0003, 0x0035, 8099}, {INT64_C(1380575043645634000), 0x0003, 0x0036, 5564}, {INT64_C(1380575043645634000), 0x0003, 0x0034, 0}, {INT64_C(1380575043645634000), 0x0003, 0x0030, 320}, {INT64_C(1380575043645634000), 0x0003, 0x0031, 256}, {INT64_C(1380575043645634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043645634000), 0x0003, 0x0035, 8704}, {INT64_C(1380575043645634000), 0x0003, 0x0036, 4222}, {INT64_C(1380575043645634000), 0x0003, 0x0034, 0}, {INT64_C(1380575043645634000), 0x0003, 0x0030, 480}, {INT64_C(1380575043645634000), 0x0003, 0x0031, 128}, {INT64_C(1380575043645634000), 0x0000, 0x0002, 0}, {INT64_C(1380575043645634000), 0x0000, 0x0000, 0}, {INT64_C(1380575043665631000), 0x0003, 0x0000, 6851}, {INT64_C(1380575043665631000), 0x0003, 0x0035, 6851}, {INT64_C(1380575043665631000), 0x0003, 0x0036, 6560}, {INT64_C(1380575043665631000), 0x0003, 0x0034, 1}, {INT64_C(1380575043665631000), 0x0003, 0x0030, 256}, {INT64_C(1380575043665631000), 0x0003, 0x0031, 160}, {INT64_C(1380575043665631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043665631000), 0x0003, 0x0035, 5153}, {INT64_C(1380575043665631000), 0x0003, 0x0036, 5486}, {INT64_C(1380575043665631000), 0x0003, 0x0034, 1}, {INT64_C(1380575043665631000), 0x0003, 0x0030, 384}, {INT64_C(1380575043665631000), 0x0003, 0x0031, 320}, {INT64_C(1380575043665631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043665631000), 0x0003, 0x0035, 8064}, {INT64_C(1380575043665631000), 0x0003, 0x0036, 5581}, {INT64_C(1380575043665631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043665631000), 0x0003, 0x0030, 320}, {INT64_C(1380575043665631000), 0x0003, 0x0031, 128}, {INT64_C(1380575043665631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043665631000), 0x0003, 0x0035, 8654}, {INT64_C(1380575043665631000), 0x0003, 0x0036, 4155}, {INT64_C(1380575043665631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043665631000), 0x0003, 0x0030, 480}, {INT64_C(1380575043665631000), 0x0003, 0x0031, 256}, {INT64_C(1380575043665631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043665631000), 0x0000, 0x0000, 0}, {INT64_C(1380575043683632000), 0x0003, 0x0000, 6808}, {INT64_C(1380575043683632000), 0x0003, 0x0035, 6808}, {INT64_C(1380575043683632000), 0x0003, 0x0036, 6560}, {INT64_C(1380575043683632000), 0x0003, 0x0034, 1}, {INT64_C(1380575043683632000), 0x0003, 0x0030, 256}, {INT64_C(1380575043683632000), 0x0003, 0x0031, 160}, {INT64_C(1380575043683632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043683632000), 0x0003, 0x0035, 8064}, {INT64_C(1380575043683632000), 0x0003, 0x0036, 5813}, {INT64_C(1380575043683632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043683632000), 0x0003, 0x0030, 320}, {INT64_C(1380575043683632000), 0x0003, 0x0031, 128}, {INT64_C(1380575043683632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043683632000), 0x0003, 0x0035, 5133}, {INT64_C(1380575043683632000), 0x0003, 0x0036, 5355}, {INT64_C(1380575043683632000), 0x0003, 0x0034, 1}, {INT64_C(1380575043683632000), 0x0003, 0x0030, 384}, {INT64_C(1380575043683632000), 0x0003, 0x0031, 320}, {INT64_C(1380575043683632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043683632000), 0x0003, 0x0035, 8618}, {INT64_C(1380575043683632000), 0x0003, 0x0036, 4088}, {INT64_C(1380575043683632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043683632000), 0x0003, 0x0030, 320}, {INT64_C(1380575043683632000), 0x0003, 0x0031, 256}, {INT64_C(1380575043683632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043683632000), 0x0000, 0x0000, 0}, {INT64_C(1380575043701633000), 0x0003, 0x0000, 6725}, {INT64_C(1380575043701633000), 0x0003, 0x0001, 6400}, {INT64_C(1380575043701633000), 0x0003, 0x0035, 6725}, {INT64_C(1380575043701633000), 0x0003, 0x0036, 6400}, {INT64_C(1380575043701633000), 0x0003, 0x0034, 1}, {INT64_C(1380575043701633000), 0x0003, 0x0030, 256}, {INT64_C(1380575043701633000), 0x0003, 0x0031, 160}, {INT64_C(1380575043701633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043701633000), 0x0003, 0x0035, 8001}, {INT64_C(1380575043701633000), 0x0003, 0x0036, 5760}, {INT64_C(1380575043701633000), 0x0003, 0x0034, 1}, {INT64_C(1380575043701633000), 0x0003, 0x0030, 256}, {INT64_C(1380575043701633000), 0x0003, 0x0031, 160}, {INT64_C(1380575043701633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043701633000), 0x0003, 0x0035, 5078}, {INT64_C(1380575043701633000), 0x0003, 0x0036, 5303}, {INT64_C(1380575043701633000), 0x0003, 0x0034, 0}, {INT64_C(1380575043701633000), 0x0003, 0x0030, 320}, {INT64_C(1380575043701633000), 0x0003, 0x0031, 256}, {INT64_C(1380575043701633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043701633000), 0x0003, 0x0035, 7967}, {INT64_C(1380575043701633000), 0x0003, 0x0036, 5383}, {INT64_C(1380575043701633000), 0x0003, 0x0034, 0}, {INT64_C(1380575043701633000), 0x0003, 0x0030, 320}, {INT64_C(1380575043701633000), 0x0003, 0x0031, 256}, {INT64_C(1380575043701633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043701633000), 0x0003, 0x0035, 8576}, {INT64_C(1380575043701633000), 0x0003, 0x0036, 4022}, {INT64_C(1380575043701633000), 0x0003, 0x0034, 0}, {INT64_C(1380575043701633000), 0x0003, 0x0030, 320}, {INT64_C(1380575043701633000), 0x0003, 0x0031, 128}, {INT64_C(1380575043701633000), 0x0000, 0x0002, 0}, {INT64_C(1380575043701633000), 0x0000, 0x0000, 0}, {INT64_C(1380575043721631000), 0x0003, 0x0000, 6666}, {INT64_C(1380575043721631000), 0x0003, 0x0001, 6305}, {INT64_C(1380575043721631000), 0x0003, 0x0035, 6666}, {INT64_C(1380575043721631000), 0x0003, 0x0036, 6305}, {INT64_C(1380575043721631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043721631000), 0x0003, 0x0030, 320}, {INT64_C(1380575043721631000), 0x0003, 0x0031, 256}, {INT64_C(1380575043721631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043721631000), 0x0003, 0x0035, 5063}, {INT64_C(1380575043721631000), 0x0003, 0x0036, 5097}, {INT64_C(1380575043721631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043721631000), 0x0003, 0x0030, 320}, {INT64_C(1380575043721631000), 0x0003, 0x0031, 256}, {INT64_C(1380575043721631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043721631000), 0x0000, 0x0000, 0}, {INT64_C(1380575043739627000), 0x0003, 0x0000, 6588}, {INT64_C(1380575043739627000), 0x0003, 0x0001, 6240}, {INT64_C(1380575043739627000), 0x0003, 0x0035, 6588}, {INT64_C(1380575043739627000), 0x0003, 0x0036, 6240}, {INT64_C(1380575043739627000), 0x0003, 0x0034, 1}, {INT64_C(1380575043739627000), 0x0003, 0x0030, 256}, {INT64_C(1380575043739627000), 0x0003, 0x0031, 160}, {INT64_C(1380575043739627000), 0x0000, 0x0002, 0}, {INT64_C(1380575043739627000), 0x0003, 0x0035, 4975}, {INT64_C(1380575043739627000), 0x0003, 0x0036, 4967}, {INT64_C(1380575043739627000), 0x0003, 0x0034, 1}, {INT64_C(1380575043739627000), 0x0003, 0x0030, 384}, {INT64_C(1380575043739627000), 0x0003, 0x0031, 320}, {INT64_C(1380575043739627000), 0x0000, 0x0002, 0}, {INT64_C(1380575043739627000), 0x0003, 0x0035, 8448}, {INT64_C(1380575043739627000), 0x0003, 0x0036, 3855}, {INT64_C(1380575043739627000), 0x0003, 0x0034, 0}, {INT64_C(1380575043739627000), 0x0003, 0x0030, 320}, {INT64_C(1380575043739627000), 0x0003, 0x0031, 128}, {INT64_C(1380575043739627000), 0x0000, 0x0002, 0}, {INT64_C(1380575043739627000), 0x0000, 0x0000, 0}, {INT64_C(1380575043757630000), 0x0003, 0x0000, 7847}, {INT64_C(1380575043757630000), 0x0003, 0x0001, 5493}, {INT64_C(1380575043757630000), 0x0003, 0x0035, 7847}, {INT64_C(1380575043757630000), 0x0003, 0x0036, 5493}, {INT64_C(1380575043757630000), 0x0003, 0x0034, 0}, {INT64_C(1380575043757630000), 0x0003, 0x0030, 320}, {INT64_C(1380575043757630000), 0x0003, 0x0031, 256}, {INT64_C(1380575043757630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043757630000), 0x0003, 0x0035, 4982}, {INT64_C(1380575043757630000), 0x0003, 0x0036, 4825}, {INT64_C(1380575043757630000), 0x0003, 0x0034, 0}, {INT64_C(1380575043757630000), 0x0003, 0x0030, 480}, {INT64_C(1380575043757630000), 0x0003, 0x0031, 384}, {INT64_C(1380575043757630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043757630000), 0x0000, 0x0000, 0}, {INT64_C(1380575043777630000), 0x0003, 0x0000, 6450}, {INT64_C(1380575043777630000), 0x0003, 0x0001, 6001}, {INT64_C(1380575043777630000), 0x0003, 0x0035, 6450}, {INT64_C(1380575043777630000), 0x0003, 0x0036, 6001}, {INT64_C(1380575043777630000), 0x0003, 0x0034, 0}, {INT64_C(1380575043777630000), 0x0003, 0x0030, 320}, {INT64_C(1380575043777630000), 0x0003, 0x0031, 256}, {INT64_C(1380575043777630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043777630000), 0x0003, 0x0035, 8346}, {INT64_C(1380575043777630000), 0x0003, 0x0036, 5920}, {INT64_C(1380575043777630000), 0x0003, 0x0034, 1}, {INT64_C(1380575043777630000), 0x0003, 0x0030, 256}, {INT64_C(1380575043777630000), 0x0003, 0x0031, 160}, {INT64_C(1380575043777630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043777630000), 0x0003, 0x0035, 4958}, {INT64_C(1380575043777630000), 0x0003, 0x0036, 4720}, {INT64_C(1380575043777630000), 0x0003, 0x0034, 1}, {INT64_C(1380575043777630000), 0x0003, 0x0030, 384}, {INT64_C(1380575043777630000), 0x0003, 0x0031, 320}, {INT64_C(1380575043777630000), 0x0000, 0x0002, 0}, {INT64_C(1380575043777630000), 0x0000, 0x0000, 0}, {INT64_C(1380575043795628000), 0x0003, 0x0000, 6419}, {INT64_C(1380575043795628000), 0x0003, 0x0001, 5920}, {INT64_C(1380575043795628000), 0x0003, 0x0035, 6419}, {INT64_C(1380575043795628000), 0x0003, 0x0036, 5920}, {INT64_C(1380575043795628000), 0x0003, 0x0034, 1}, {INT64_C(1380575043795628000), 0x0003, 0x0030, 256}, {INT64_C(1380575043795628000), 0x0003, 0x0031, 160}, {INT64_C(1380575043795628000), 0x0000, 0x0002, 0}, {INT64_C(1380575043795628000), 0x0003, 0x0035, 7742}, {INT64_C(1380575043795628000), 0x0003, 0x0036, 5337}, {INT64_C(1380575043795628000), 0x0003, 0x0034, 0}, {INT64_C(1380575043795628000), 0x0003, 0x0030, 320}, {INT64_C(1380575043795628000), 0x0003, 0x0031, 256}, {INT64_C(1380575043795628000), 0x0000, 0x0002, 0}, {INT64_C(1380575043795628000), 0x0003, 0x0035, 4963}, {INT64_C(1380575043795628000), 0x0003, 0x0036, 4640}, {INT64_C(1380575043795628000), 0x0003, 0x0034, 1}, {INT64_C(1380575043795628000), 0x0003, 0x0030, 384}, {INT64_C(1380575043795628000), 0x0003, 0x0031, 160}, {INT64_C(1380575043795628000), 0x0000, 0x0002, 0}, {INT64_C(1380575043795628000), 0x0000, 0x0000, 0}, {INT64_C(1380575043815631000), 0x0003, 0x0000, 6335}, {INT64_C(1380575043815631000), 0x0003, 0x0001, 5814}, {INT64_C(1380575043815631000), 0x0003, 0x0035, 6335}, {INT64_C(1380575043815631000), 0x0003, 0x0036, 5814}, {INT64_C(1380575043815631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043815631000), 0x0003, 0x0030, 320}, {INT64_C(1380575043815631000), 0x0003, 0x0031, 256}, {INT64_C(1380575043815631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043815631000), 0x0003, 0x0035, 7701}, {INT64_C(1380575043815631000), 0x0003, 0x0036, 5280}, {INT64_C(1380575043815631000), 0x0003, 0x0034, 1}, {INT64_C(1380575043815631000), 0x0003, 0x0030, 256}, {INT64_C(1380575043815631000), 0x0003, 0x0031, 160}, {INT64_C(1380575043815631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043815631000), 0x0003, 0x0035, 4942}, {INT64_C(1380575043815631000), 0x0003, 0x0036, 4425}, {INT64_C(1380575043815631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043815631000), 0x0003, 0x0030, 640}, {INT64_C(1380575043815631000), 0x0003, 0x0031, 384}, {INT64_C(1380575043815631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043815631000), 0x0000, 0x0000, 0}, {INT64_C(1380575043833632000), 0x0003, 0x0000, 6305}, {INT64_C(1380575043833632000), 0x0003, 0x0001, 5678}, {INT64_C(1380575043833632000), 0x0003, 0x0035, 6305}, {INT64_C(1380575043833632000), 0x0003, 0x0036, 5678}, {INT64_C(1380575043833632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043833632000), 0x0003, 0x0030, 320}, {INT64_C(1380575043833632000), 0x0003, 0x0031, 256}, {INT64_C(1380575043833632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043833632000), 0x0003, 0x0035, 7680}, {INT64_C(1380575043833632000), 0x0003, 0x0036, 5710}, {INT64_C(1380575043833632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043833632000), 0x0003, 0x0030, 320}, {INT64_C(1380575043833632000), 0x0003, 0x0031, 128}, {INT64_C(1380575043833632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043833632000), 0x0003, 0x0035, 8254}, {INT64_C(1380575043833632000), 0x0003, 0x0036, 5640}, {INT64_C(1380575043833632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043833632000), 0x0003, 0x0030, 320}, {INT64_C(1380575043833632000), 0x0003, 0x0031, 256}, {INT64_C(1380575043833632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043833632000), 0x0003, 0x0035, 7680}, {INT64_C(1380575043833632000), 0x0003, 0x0036, 5167}, {INT64_C(1380575043833632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043833632000), 0x0003, 0x0030, 480}, {INT64_C(1380575043833632000), 0x0003, 0x0031, 128}, {INT64_C(1380575043833632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043833632000), 0x0003, 0x0035, 4945}, {INT64_C(1380575043833632000), 0x0003, 0x0036, 4293}, {INT64_C(1380575043833632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043833632000), 0x0003, 0x0030, 480}, {INT64_C(1380575043833632000), 0x0003, 0x0031, 384}, {INT64_C(1380575043833632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043833632000), 0x0000, 0x0000, 0}, {INT64_C(1380575043851632000), 0x0003, 0x0000, 6236}, {INT64_C(1380575043851632000), 0x0003, 0x0001, 5522}, {INT64_C(1380575043851632000), 0x0003, 0x0035, 6236}, {INT64_C(1380575043851632000), 0x0003, 0x0036, 5522}, {INT64_C(1380575043851632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043851632000), 0x0003, 0x0030, 640}, {INT64_C(1380575043851632000), 0x0003, 0x0031, 256}, {INT64_C(1380575043851632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043851632000), 0x0003, 0x0035, 8192}, {INT64_C(1380575043851632000), 0x0003, 0x0036, 5488}, {INT64_C(1380575043851632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043851632000), 0x0003, 0x0030, 480}, {INT64_C(1380575043851632000), 0x0003, 0x0031, 128}, {INT64_C(1380575043851632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043851632000), 0x0003, 0x0035, 7603}, {INT64_C(1380575043851632000), 0x0003, 0x0036, 5072}, {INT64_C(1380575043851632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043851632000), 0x0003, 0x0030, 480}, {INT64_C(1380575043851632000), 0x0003, 0x0031, 256}, {INT64_C(1380575043851632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043851632000), 0x0003, 0x0035, 4934}, {INT64_C(1380575043851632000), 0x0003, 0x0036, 4194}, {INT64_C(1380575043851632000), 0x0003, 0x0034, 0}, {INT64_C(1380575043851632000), 0x0003, 0x0030, 480}, {INT64_C(1380575043851632000), 0x0003, 0x0031, 256}, {INT64_C(1380575043851632000), 0x0000, 0x0002, 0}, {INT64_C(1380575043851632000), 0x0000, 0x0000, 0}, {INT64_C(1380575043871631000), 0x0003, 0x0000, 6215}, {INT64_C(1380575043871631000), 0x0003, 0x0001, 5449}, {INT64_C(1380575043871631000), 0x0003, 0x0035, 6215}, {INT64_C(1380575043871631000), 0x0003, 0x0036, 5449}, {INT64_C(1380575043871631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043871631000), 0x0003, 0x0030, 640}, {INT64_C(1380575043871631000), 0x0003, 0x0031, 256}, {INT64_C(1380575043871631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043871631000), 0x0003, 0x0035, 8192}, {INT64_C(1380575043871631000), 0x0003, 0x0036, 5499}, {INT64_C(1380575043871631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043871631000), 0x0003, 0x0030, 320}, {INT64_C(1380575043871631000), 0x0003, 0x0031, 128}, {INT64_C(1380575043871631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043871631000), 0x0003, 0x0035, 7556}, {INT64_C(1380575043871631000), 0x0003, 0x0036, 5013}, {INT64_C(1380575043871631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043871631000), 0x0003, 0x0030, 320}, {INT64_C(1380575043871631000), 0x0003, 0x0031, 256}, {INT64_C(1380575043871631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043871631000), 0x0003, 0x0035, 4948}, {INT64_C(1380575043871631000), 0x0003, 0x0036, 4090}, {INT64_C(1380575043871631000), 0x0003, 0x0034, 1}, {INT64_C(1380575043871631000), 0x0003, 0x0030, 384}, {INT64_C(1380575043871631000), 0x0003, 0x0031, 320}, {INT64_C(1380575043871631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043871631000), 0x0000, 0x0000, 0}, {INT64_C(1380575043889628000), 0x0003, 0x0000, 6197}, {INT64_C(1380575043889628000), 0x0003, 0x0001, 5324}, {INT64_C(1380575043889628000), 0x0003, 0x0035, 6197}, {INT64_C(1380575043889628000), 0x0003, 0x0036, 5324}, {INT64_C(1380575043889628000), 0x0003, 0x0034, 0}, {INT64_C(1380575043889628000), 0x0003, 0x0030, 800}, {INT64_C(1380575043889628000), 0x0003, 0x0031, 256}, {INT64_C(1380575043889628000), 0x0000, 0x0002, 0}, {INT64_C(1380575043889628000), 0x0003, 0x0035, 8064}, {INT64_C(1380575043889628000), 0x0003, 0x0036, 5430}, {INT64_C(1380575043889628000), 0x0003, 0x0034, 0}, {INT64_C(1380575043889628000), 0x0003, 0x0030, 320}, {INT64_C(1380575043889628000), 0x0003, 0x0031, 128}, {INT64_C(1380575043889628000), 0x0000, 0x0002, 0}, {INT64_C(1380575043889628000), 0x0003, 0x0035, 7552}, {INT64_C(1380575043889628000), 0x0003, 0x0036, 4877}, {INT64_C(1380575043889628000), 0x0003, 0x0034, 0}, {INT64_C(1380575043889628000), 0x0003, 0x0030, 480}, {INT64_C(1380575043889628000), 0x0003, 0x0031, 128}, {INT64_C(1380575043889628000), 0x0000, 0x0002, 0}, {INT64_C(1380575043889628000), 0x0003, 0x0035, 4954}, {INT64_C(1380575043889628000), 0x0003, 0x0036, 4015}, {INT64_C(1380575043889628000), 0x0003, 0x0034, 1}, {INT64_C(1380575043889628000), 0x0003, 0x0030, 384}, {INT64_C(1380575043889628000), 0x0003, 0x0031, 320}, {INT64_C(1380575043889628000), 0x0000, 0x0002, 0}, {INT64_C(1380575043889628000), 0x0003, 0x0035, 8074}, {INT64_C(1380575043889628000), 0x0003, 0x0036, 3360}, {INT64_C(1380575043889628000), 0x0003, 0x0034, 1}, {INT64_C(1380575043889628000), 0x0003, 0x0030, 256}, {INT64_C(1380575043889628000), 0x0003, 0x0031, 160}, {INT64_C(1380575043889628000), 0x0000, 0x0002, 0}, {INT64_C(1380575043889628000), 0x0000, 0x0000, 0}, {INT64_C(1380575043907629000), 0x0003, 0x0000, 6161}, {INT64_C(1380575043907629000), 0x0003, 0x0001, 5126}, {INT64_C(1380575043907629000), 0x0003, 0x0035, 6161}, {INT64_C(1380575043907629000), 0x0003, 0x0036, 5126}, {INT64_C(1380575043907629000), 0x0003, 0x0034, 0}, {INT64_C(1380575043907629000), 0x0003, 0x0030, 640}, {INT64_C(1380575043907629000), 0x0003, 0x0031, 256}, {INT64_C(1380575043907629000), 0x0000, 0x0002, 0}, {INT64_C(1380575043907629000), 0x0003, 0x0035, 7465}, {INT64_C(1380575043907629000), 0x0003, 0x0036, 4773}, {INT64_C(1380575043907629000), 0x0003, 0x0034, 0}, {INT64_C(1380575043907629000), 0x0003, 0x0030, 480}, {INT64_C(1380575043907629000), 0x0003, 0x0031, 256}, {INT64_C(1380575043907629000), 0x0000, 0x0002, 0}, {INT64_C(1380575043907629000), 0x0000, 0x0000, 0}, {INT64_C(1380575043927631000), 0x0003, 0x0000, 6097}, {INT64_C(1380575043927631000), 0x0003, 0x0001, 5019}, {INT64_C(1380575043927631000), 0x0003, 0x0035, 6097}, {INT64_C(1380575043927631000), 0x0003, 0x0036, 5019}, {INT64_C(1380575043927631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043927631000), 0x0003, 0x0030, 480}, {INT64_C(1380575043927631000), 0x0003, 0x0031, 256}, {INT64_C(1380575043927631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043927631000), 0x0003, 0x0035, 7420}, {INT64_C(1380575043927631000), 0x0003, 0x0036, 4666}, {INT64_C(1380575043927631000), 0x0003, 0x0034, 0}, {INT64_C(1380575043927631000), 0x0003, 0x0030, 320}, {INT64_C(1380575043927631000), 0x0003, 0x0031, 256}, {INT64_C(1380575043927631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043927631000), 0x0003, 0x0035, 4944}, {INT64_C(1380575043927631000), 0x0003, 0x0036, 3680}, {INT64_C(1380575043927631000), 0x0003, 0x0034, 1}, {INT64_C(1380575043927631000), 0x0003, 0x0030, 256}, {INT64_C(1380575043927631000), 0x0003, 0x0031, 160}, {INT64_C(1380575043927631000), 0x0000, 0x0002, 0}, {INT64_C(1380575043927631000), 0x0000, 0x0000, 0}, {INT64_C(1380575043945629000), 0x0003, 0x0000, 6065}, {INT64_C(1380575043945629000), 0x0003, 0x0001, 4857}, {INT64_C(1380575043945629000), 0x0003, 0x0035, 6065}, {INT64_C(1380575043945629000), 0x0003, 0x0036, 4857}, {INT64_C(1380575043945629000), 0x0003, 0x0034, 0}, {INT64_C(1380575043945629000), 0x0003, 0x0030, 800}, {INT64_C(1380575043945629000), 0x0003, 0x0031, 256}, {INT64_C(1380575043945629000), 0x0000, 0x0002, 0}, {INT64_C(1380575043945629000), 0x0003, 0x0035, 7323}, {INT64_C(1380575043945629000), 0x0003, 0x0036, 4451}, {INT64_C(1380575043945629000), 0x0003, 0x0034, 0}, {INT64_C(1380575043945629000), 0x0003, 0x0030, 480}, {INT64_C(1380575043945629000), 0x0003, 0x0031, 256}, {INT64_C(1380575043945629000), 0x0000, 0x0002, 0}, {INT64_C(1380575043945629000), 0x0000, 0x0000, 0}, {INT64_C(1380575043963628000), 0x0003, 0x0000, 6028}, {INT64_C(1380575043963628000), 0x0003, 0x0001, 4723}, {INT64_C(1380575043963628000), 0x0003, 0x0035, 6028}, {INT64_C(1380575043963628000), 0x0003, 0x0036, 4723}, {INT64_C(1380575043963628000), 0x0003, 0x0034, 0}, {INT64_C(1380575043963628000), 0x0003, 0x0030, 800}, {INT64_C(1380575043963628000), 0x0003, 0x0031, 256}, {INT64_C(1380575043963628000), 0x0000, 0x0002, 0}, {INT64_C(1380575043963628000), 0x0003, 0x0035, 7230}, {INT64_C(1380575043963628000), 0x0003, 0x0036, 4339}, {INT64_C(1380575043963628000), 0x0003, 0x0034, 0}, {INT64_C(1380575043963628000), 0x0003, 0x0030, 480}, {INT64_C(1380575043963628000), 0x0003, 0x0031, 256}, {INT64_C(1380575043963628000), 0x0000, 0x0002, 0}, {INT64_C(1380575043963628000), 0x0000, 0x0000, 0}, {INT64_C(1380575043983629000), 0x0003, 0x0000, 5948}, {INT64_C(1380575043983629000), 0x0003, 0x0001, 4544}, {INT64_C(1380575043983629000), 0x0003, 0x0035, 5948}, {INT64_C(1380575043983629000), 0x0003, 0x0036, 4544}, {INT64_C(1380575043983629000), 0x0003, 0x0034, 0}, {INT64_C(1380575043983629000), 0x0003, 0x0030, 480}, {INT64_C(1380575043983629000), 0x0003, 0x0031, 256}, {INT64_C(1380575043983629000), 0x0000, 0x0002, 0}, {INT64_C(1380575043983629000), 0x0003, 0x0035, 7168}, {INT64_C(1380575043983629000), 0x0003, 0x0036, 4199}, {INT64_C(1380575043983629000), 0x0003, 0x0034, 0}, {INT64_C(1380575043983629000), 0x0003, 0x0030, 480}, {INT64_C(1380575043983629000), 0x0003, 0x0031, 128}, {INT64_C(1380575043983629000), 0x0000, 0x0002, 0}, {INT64_C(1380575043983629000), 0x0000, 0x0000, 0}, {INT64_C(1380575044001588000), 0x0003, 0x0000, 5905}, {INT64_C(1380575044001588000), 0x0003, 0x0001, 4386}, {INT64_C(1380575044001588000), 0x0003, 0x0035, 5905}, {INT64_C(1380575044001588000), 0x0003, 0x0036, 4386}, {INT64_C(1380575044001588000), 0x0003, 0x0034, 0}, {INT64_C(1380575044001588000), 0x0003, 0x0030, 640}, {INT64_C(1380575044001588000), 0x0003, 0x0031, 256}, {INT64_C(1380575044001588000), 0x0000, 0x0002, 0}, {INT64_C(1380575044001588000), 0x0003, 0x0035, 7054}, {INT64_C(1380575044001588000), 0x0003, 0x0036, 4033}, {INT64_C(1380575044001588000), 0x0003, 0x0034, 0}, {INT64_C(1380575044001588000), 0x0003, 0x0030, 320}, {INT64_C(1380575044001588000), 0x0003, 0x0031, 256}, {INT64_C(1380575044001588000), 0x0000, 0x0002, 0}, {INT64_C(1380575044001588000), 0x0000, 0x0000, 0}, {INT64_C(1380575044019626000), 0x0003, 0x0000, 5825}, {INT64_C(1380575044019626000), 0x0003, 0x0001, 4220}, {INT64_C(1380575044019626000), 0x0003, 0x0035, 5825}, {INT64_C(1380575044019626000), 0x0003, 0x0036, 4220}, {INT64_C(1380575044019626000), 0x0003, 0x0034, 0}, {INT64_C(1380575044019626000), 0x0003, 0x0030, 480}, {INT64_C(1380575044019626000), 0x0003, 0x0031, 256}, {INT64_C(1380575044019626000), 0x0000, 0x0002, 0}, {INT64_C(1380575044019626000), 0x0000, 0x0000, 0}, {INT64_C(1380575044039627000), 0x0003, 0x0000, 5778}, {INT64_C(1380575044039627000), 0x0003, 0x0001, 4085}, {INT64_C(1380575044039627000), 0x0003, 0x0035, 5778}, {INT64_C(1380575044039627000), 0x0003, 0x0036, 4085}, {INT64_C(1380575044039627000), 0x0003, 0x0034, 0}, {INT64_C(1380575044039627000), 0x0003, 0x0030, 800}, {INT64_C(1380575044039627000), 0x0003, 0x0031, 256}, {INT64_C(1380575044039627000), 0x0000, 0x0002, 0}, {INT64_C(1380575044039627000), 0x0003, 0x0035, 6928}, {INT64_C(1380575044039627000), 0x0003, 0x0036, 3730}, {INT64_C(1380575044039627000), 0x0003, 0x0034, 0}, {INT64_C(1380575044039627000), 0x0003, 0x0030, 320}, {INT64_C(1380575044039627000), 0x0003, 0x0031, 256}, {INT64_C(1380575044039627000), 0x0000, 0x0002, 0}, {INT64_C(1380575044039627000), 0x0000, 0x0000, 0}, {INT64_C(1380575044057628000), 0x0003, 0x0000, 5691}, {INT64_C(1380575044057628000), 0x0003, 0x0001, 3923}, {INT64_C(1380575044057628000), 0x0003, 0x0035, 5691}, {INT64_C(1380575044057628000), 0x0003, 0x0036, 3923}, {INT64_C(1380575044057628000), 0x0003, 0x0034, 0}, {INT64_C(1380575044057628000), 0x0003, 0x0030, 480}, {INT64_C(1380575044057628000), 0x0003, 0x0031, 256}, {INT64_C(1380575044057628000), 0x0000, 0x0002, 0}, {INT64_C(1380575044057628000), 0x0003, 0x0035, 6840}, {INT64_C(1380575044057628000), 0x0003, 0x0036, 3680}, {INT64_C(1380575044057628000), 0x0003, 0x0034, 1}, {INT64_C(1380575044057628000), 0x0003, 0x0030, 256}, {INT64_C(1380575044057628000), 0x0003, 0x0031, 160}, {INT64_C(1380575044057628000), 0x0000, 0x0002, 0}, {INT64_C(1380575044057628000), 0x0000, 0x0000, 0}, {INT64_C(1380575044077627000), 0x0003, 0x0000, 5603}, {INT64_C(1380575044077627000), 0x0003, 0x0001, 3795}, {INT64_C(1380575044077627000), 0x0003, 0x0035, 5603}, {INT64_C(1380575044077627000), 0x0003, 0x0036, 3795}, {INT64_C(1380575044077627000), 0x0003, 0x0034, 0}, {INT64_C(1380575044077627000), 0x0003, 0x0030, 320}, {INT64_C(1380575044077627000), 0x0003, 0x0031, 256}, {INT64_C(1380575044077627000), 0x0000, 0x0002, 0}, {INT64_C(1380575044077627000), 0x0000, 0x0000, 0}, {INT64_C(1380575044169624000), 0x0001, 0x014d, 0}, {INT64_C(1380575044169624000), 0x0001, 0x014a, 0}, {INT64_C(1380575044169624000), 0x0000, 0x0000, 0}, {INT64_C(1380575044807625000), 0x0003, 0x0035, 1536}, {INT64_C(1380575044807625000), 0x0003, 0x0036, 2478}, {INT64_C(1380575044807625000), 0x0003, 0x0034, 0}, {INT64_C(1380575044807625000), 0x0003, 0x0030, 320}, {INT64_C(1380575044807625000), 0x0003, 0x0031, 128}, {INT64_C(1380575044807625000), 0x0000, 0x0002, 0}, {INT64_C(1380575044807625000), 0x0000, 0x0000, 0}, {INT64_C(1380575044813624000), 0x0003, 0x0000, 2922}, {INT64_C(1380575044813624000), 0x0003, 0x0001, 5026}, {INT64_C(1380575044813624000), 0x0003, 0x0035, 2922}, {INT64_C(1380575044813624000), 0x0003, 0x0036, 5026}, {INT64_C(1380575044813624000), 0x0003, 0x0034, 1}, {INT64_C(1380575044813624000), 0x0003, 0x0030, 384}, {INT64_C(1380575044813624000), 0x0003, 0x0031, 320}, {INT64_C(1380575044813624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044813624000), 0x0003, 0x0035, 2048}, {INT64_C(1380575044813624000), 0x0003, 0x0036, 4202}, {INT64_C(1380575044813624000), 0x0003, 0x0034, 0}, {INT64_C(1380575044813624000), 0x0003, 0x0030, 480}, {INT64_C(1380575044813624000), 0x0003, 0x0031, 128}, {INT64_C(1380575044813624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044813624000), 0x0003, 0x0035, 1624}, {INT64_C(1380575044813624000), 0x0003, 0x0036, 2469}, {INT64_C(1380575044813624000), 0x0003, 0x0034, 0}, {INT64_C(1380575044813624000), 0x0003, 0x0030, 320}, {INT64_C(1380575044813624000), 0x0003, 0x0031, 256}, {INT64_C(1380575044813624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044813624000), 0x0001, 0x014d, 1}, {INT64_C(1380575044813624000), 0x0001, 0x014a, 1}, {INT64_C(1380575044813624000), 0x0000, 0x0000, 0}, {INT64_C(1380575044825623000), 0x0003, 0x0000, 2964}, {INT64_C(1380575044825623000), 0x0003, 0x0001, 5029}, {INT64_C(1380575044825623000), 0x0003, 0x0035, 2964}, {INT64_C(1380575044825623000), 0x0003, 0x0036, 5029}, {INT64_C(1380575044825623000), 0x0003, 0x0034, 1}, {INT64_C(1380575044825623000), 0x0003, 0x0030, 384}, {INT64_C(1380575044825623000), 0x0003, 0x0031, 320}, {INT64_C(1380575044825623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044825623000), 0x0003, 0x0035, 2127}, {INT64_C(1380575044825623000), 0x0003, 0x0036, 4200}, {INT64_C(1380575044825623000), 0x0003, 0x0034, 0}, {INT64_C(1380575044825623000), 0x0003, 0x0030, 480}, {INT64_C(1380575044825623000), 0x0003, 0x0031, 256}, {INT64_C(1380575044825623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044825623000), 0x0003, 0x0035, 1664}, {INT64_C(1380575044825623000), 0x0003, 0x0036, 2465}, {INT64_C(1380575044825623000), 0x0003, 0x0034, 0}, {INT64_C(1380575044825623000), 0x0003, 0x0030, 320}, {INT64_C(1380575044825623000), 0x0003, 0x0031, 128}, {INT64_C(1380575044825623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044825623000), 0x0000, 0x0000, 0}, {INT64_C(1380575044831623000), 0x0003, 0x0000, 3014}, {INT64_C(1380575044831623000), 0x0003, 0x0001, 4990}, {INT64_C(1380575044831623000), 0x0003, 0x0035, 3014}, {INT64_C(1380575044831623000), 0x0003, 0x0036, 4990}, {INT64_C(1380575044831623000), 0x0003, 0x0034, 0}, {INT64_C(1380575044831623000), 0x0003, 0x0030, 320}, {INT64_C(1380575044831623000), 0x0003, 0x0031, 256}, {INT64_C(1380575044831623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044831623000), 0x0003, 0x0035, 2265}, {INT64_C(1380575044831623000), 0x0003, 0x0036, 4163}, {INT64_C(1380575044831623000), 0x0003, 0x0034, 0}, {INT64_C(1380575044831623000), 0x0003, 0x0030, 480}, {INT64_C(1380575044831623000), 0x0003, 0x0031, 256}, {INT64_C(1380575044831623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044831623000), 0x0003, 0x0035, 1792}, {INT64_C(1380575044831623000), 0x0003, 0x0036, 2467}, {INT64_C(1380575044831623000), 0x0003, 0x0034, 0}, {INT64_C(1380575044831623000), 0x0003, 0x0030, 320}, {INT64_C(1380575044831623000), 0x0003, 0x0031, 128}, {INT64_C(1380575044831623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044831623000), 0x0000, 0x0000, 0}, {INT64_C(1380575044843625000), 0x0003, 0x0000, 3034}, {INT64_C(1380575044843625000), 0x0003, 0x0001, 4965}, {INT64_C(1380575044843625000), 0x0003, 0x0035, 3034}, {INT64_C(1380575044843625000), 0x0003, 0x0036, 4965}, {INT64_C(1380575044843625000), 0x0003, 0x0034, 0}, {INT64_C(1380575044843625000), 0x0003, 0x0030, 480}, {INT64_C(1380575044843625000), 0x0003, 0x0031, 256}, {INT64_C(1380575044843625000), 0x0000, 0x0002, 0}, {INT64_C(1380575044843625000), 0x0003, 0x0035, 2304}, {INT64_C(1380575044843625000), 0x0003, 0x0036, 4119}, {INT64_C(1380575044843625000), 0x0003, 0x0034, 0}, {INT64_C(1380575044843625000), 0x0003, 0x0030, 480}, {INT64_C(1380575044843625000), 0x0003, 0x0031, 128}, {INT64_C(1380575044843625000), 0x0000, 0x0002, 0}, {INT64_C(1380575044843625000), 0x0003, 0x0035, 1920}, {INT64_C(1380575044843625000), 0x0003, 0x0036, 2437}, {INT64_C(1380575044843625000), 0x0003, 0x0034, 0}, {INT64_C(1380575044843625000), 0x0003, 0x0030, 320}, {INT64_C(1380575044843625000), 0x0003, 0x0031, 128}, {INT64_C(1380575044843625000), 0x0000, 0x0002, 0}, {INT64_C(1380575044843625000), 0x0000, 0x0000, 0}, {INT64_C(1380575044849623000), 0x0003, 0x0000, 3119}, {INT64_C(1380575044849623000), 0x0003, 0x0001, 4886}, {INT64_C(1380575044849623000), 0x0003, 0x0035, 3119}, {INT64_C(1380575044849623000), 0x0003, 0x0036, 4886}, {INT64_C(1380575044849623000), 0x0003, 0x0034, 0}, {INT64_C(1380575044849623000), 0x0003, 0x0030, 640}, {INT64_C(1380575044849623000), 0x0003, 0x0031, 256}, {INT64_C(1380575044849623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044849623000), 0x0003, 0x0035, 2497}, {INT64_C(1380575044849623000), 0x0003, 0x0036, 4078}, {INT64_C(1380575044849623000), 0x0003, 0x0034, 1}, {INT64_C(1380575044849623000), 0x0003, 0x0030, 384}, {INT64_C(1380575044849623000), 0x0003, 0x0031, 320}, {INT64_C(1380575044849623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044849623000), 0x0003, 0x0035, 2156}, {INT64_C(1380575044849623000), 0x0003, 0x0036, 2422}, {INT64_C(1380575044849623000), 0x0003, 0x0034, 1}, {INT64_C(1380575044849623000), 0x0003, 0x0030, 384}, {INT64_C(1380575044849623000), 0x0003, 0x0031, 320}, {INT64_C(1380575044849623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044849623000), 0x0000, 0x0000, 0}, {INT64_C(1380575044863624000), 0x0003, 0x0000, 3251}, {INT64_C(1380575044863624000), 0x0003, 0x0001, 4806}, {INT64_C(1380575044863624000), 0x0003, 0x0035, 3251}, {INT64_C(1380575044863624000), 0x0003, 0x0036, 4806}, {INT64_C(1380575044863624000), 0x0003, 0x0034, 0}, {INT64_C(1380575044863624000), 0x0003, 0x0030, 480}, {INT64_C(1380575044863624000), 0x0003, 0x0031, 256}, {INT64_C(1380575044863624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044863624000), 0x0003, 0x0035, 2635}, {INT64_C(1380575044863624000), 0x0003, 0x0036, 4051}, {INT64_C(1380575044863624000), 0x0003, 0x0034, 0}, {INT64_C(1380575044863624000), 0x0003, 0x0030, 320}, {INT64_C(1380575044863624000), 0x0003, 0x0031, 256}, {INT64_C(1380575044863624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044863624000), 0x0003, 0x0035, 2311}, {INT64_C(1380575044863624000), 0x0003, 0x0036, 2312}, {INT64_C(1380575044863624000), 0x0003, 0x0034, 1}, {INT64_C(1380575044863624000), 0x0003, 0x0030, 384}, {INT64_C(1380575044863624000), 0x0003, 0x0031, 320}, {INT64_C(1380575044863624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044863624000), 0x0000, 0x0000, 0}, {INT64_C(1380575044869622000), 0x0003, 0x0000, 3399}, {INT64_C(1380575044869622000), 0x0003, 0x0001, 4671}, {INT64_C(1380575044869622000), 0x0003, 0x0035, 3399}, {INT64_C(1380575044869622000), 0x0003, 0x0036, 4671}, {INT64_C(1380575044869622000), 0x0003, 0x0034, 0}, {INT64_C(1380575044869622000), 0x0003, 0x0030, 480}, {INT64_C(1380575044869622000), 0x0003, 0x0031, 256}, {INT64_C(1380575044869622000), 0x0000, 0x0002, 0}, {INT64_C(1380575044869622000), 0x0003, 0x0035, 2769}, {INT64_C(1380575044869622000), 0x0003, 0x0036, 3955}, {INT64_C(1380575044869622000), 0x0003, 0x0034, 0}, {INT64_C(1380575044869622000), 0x0003, 0x0030, 480}, {INT64_C(1380575044869622000), 0x0003, 0x0031, 256}, {INT64_C(1380575044869622000), 0x0000, 0x0002, 0}, {INT64_C(1380575044869622000), 0x0003, 0x0035, 2473}, {INT64_C(1380575044869622000), 0x0003, 0x0036, 2300}, {INT64_C(1380575044869622000), 0x0003, 0x0034, 1}, {INT64_C(1380575044869622000), 0x0003, 0x0030, 384}, {INT64_C(1380575044869622000), 0x0003, 0x0031, 320}, {INT64_C(1380575044869622000), 0x0000, 0x0002, 0}, {INT64_C(1380575044869622000), 0x0000, 0x0000, 0}, {INT64_C(1380575044881624000), 0x0003, 0x0000, 3589}, {INT64_C(1380575044881624000), 0x0003, 0x0001, 4580}, {INT64_C(1380575044881624000), 0x0003, 0x0035, 3589}, {INT64_C(1380575044881624000), 0x0003, 0x0036, 4580}, {INT64_C(1380575044881624000), 0x0003, 0x0034, 0}, {INT64_C(1380575044881624000), 0x0003, 0x0030, 640}, {INT64_C(1380575044881624000), 0x0003, 0x0031, 384}, {INT64_C(1380575044881624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044881624000), 0x0003, 0x0035, 2947}, {INT64_C(1380575044881624000), 0x0003, 0x0036, 3921}, {INT64_C(1380575044881624000), 0x0003, 0x0034, 0}, {INT64_C(1380575044881624000), 0x0003, 0x0030, 480}, {INT64_C(1380575044881624000), 0x0003, 0x0031, 384}, {INT64_C(1380575044881624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044881624000), 0x0003, 0x0035, 2619}, {INT64_C(1380575044881624000), 0x0003, 0x0036, 2285}, {INT64_C(1380575044881624000), 0x0003, 0x0034, 1}, {INT64_C(1380575044881624000), 0x0003, 0x0030, 384}, {INT64_C(1380575044881624000), 0x0003, 0x0031, 320}, {INT64_C(1380575044881624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044881624000), 0x0000, 0x0000, 0}, {INT64_C(1380575044887620000), 0x0003, 0x0000, 3778}, {INT64_C(1380575044887620000), 0x0003, 0x0001, 4523}, {INT64_C(1380575044887620000), 0x0003, 0x0035, 3778}, {INT64_C(1380575044887620000), 0x0003, 0x0036, 4523}, {INT64_C(1380575044887620000), 0x0003, 0x0034, 0}, {INT64_C(1380575044887620000), 0x0003, 0x0030, 480}, {INT64_C(1380575044887620000), 0x0003, 0x0031, 256}, {INT64_C(1380575044887620000), 0x0000, 0x0002, 0}, {INT64_C(1380575044887620000), 0x0003, 0x0035, 3072}, {INT64_C(1380575044887620000), 0x0003, 0x0036, 3859}, {INT64_C(1380575044887620000), 0x0003, 0x0034, 0}, {INT64_C(1380575044887620000), 0x0003, 0x0030, 480}, {INT64_C(1380575044887620000), 0x0003, 0x0031, 128}, {INT64_C(1380575044887620000), 0x0000, 0x0002, 0}, {INT64_C(1380575044887620000), 0x0003, 0x0035, 2790}, {INT64_C(1380575044887620000), 0x0003, 0x0036, 2240}, {INT64_C(1380575044887620000), 0x0003, 0x0034, 1}, {INT64_C(1380575044887620000), 0x0003, 0x0030, 384}, {INT64_C(1380575044887620000), 0x0003, 0x0031, 160}, {INT64_C(1380575044887620000), 0x0000, 0x0002, 0}, {INT64_C(1380575044887620000), 0x0000, 0x0000, 0}, {INT64_C(1380575044901622000), 0x0003, 0x0000, 3950}, {INT64_C(1380575044901622000), 0x0003, 0x0001, 4415}, {INT64_C(1380575044901622000), 0x0003, 0x0035, 3950}, {INT64_C(1380575044901622000), 0x0003, 0x0036, 4415}, {INT64_C(1380575044901622000), 0x0003, 0x0034, 0}, {INT64_C(1380575044901622000), 0x0003, 0x0030, 640}, {INT64_C(1380575044901622000), 0x0003, 0x0031, 256}, {INT64_C(1380575044901622000), 0x0000, 0x0002, 0}, {INT64_C(1380575044901622000), 0x0003, 0x0035, 3300}, {INT64_C(1380575044901622000), 0x0003, 0x0036, 3802}, {INT64_C(1380575044901622000), 0x0003, 0x0034, 0}, {INT64_C(1380575044901622000), 0x0003, 0x0030, 480}, {INT64_C(1380575044901622000), 0x0003, 0x0031, 256}, {INT64_C(1380575044901622000), 0x0000, 0x0002, 0}, {INT64_C(1380575044901622000), 0x0003, 0x0035, 2971}, {INT64_C(1380575044901622000), 0x0003, 0x0036, 2240}, {INT64_C(1380575044901622000), 0x0003, 0x0034, 1}, {INT64_C(1380575044901622000), 0x0003, 0x0030, 384}, {INT64_C(1380575044901622000), 0x0003, 0x0031, 160}, {INT64_C(1380575044901622000), 0x0000, 0x0002, 0}, {INT64_C(1380575044901622000), 0x0000, 0x0000, 0}, {INT64_C(1380575044919624000), 0x0003, 0x0000, 4157}, {INT64_C(1380575044919624000), 0x0003, 0x0001, 4318}, {INT64_C(1380575044919624000), 0x0003, 0x0035, 4157}, {INT64_C(1380575044919624000), 0x0003, 0x0036, 4318}, {INT64_C(1380575044919624000), 0x0003, 0x0034, 0}, {INT64_C(1380575044919624000), 0x0003, 0x0030, 480}, {INT64_C(1380575044919624000), 0x0003, 0x0031, 256}, {INT64_C(1380575044919624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044919624000), 0x0003, 0x0035, 3449}, {INT64_C(1380575044919624000), 0x0003, 0x0036, 3759}, {INT64_C(1380575044919624000), 0x0003, 0x0034, 0}, {INT64_C(1380575044919624000), 0x0003, 0x0030, 320}, {INT64_C(1380575044919624000), 0x0003, 0x0031, 256}, {INT64_C(1380575044919624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044919624000), 0x0003, 0x0035, 3147}, {INT64_C(1380575044919624000), 0x0003, 0x0036, 2240}, {INT64_C(1380575044919624000), 0x0003, 0x0034, 1}, {INT64_C(1380575044919624000), 0x0003, 0x0030, 256}, {INT64_C(1380575044919624000), 0x0003, 0x0031, 160}, {INT64_C(1380575044919624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044919624000), 0x0000, 0x0000, 0}, {INT64_C(1380575044937622000), 0x0003, 0x0000, 4352}, {INT64_C(1380575044937622000), 0x0003, 0x0001, 4238}, {INT64_C(1380575044937622000), 0x0003, 0x0035, 4352}, {INT64_C(1380575044937622000), 0x0003, 0x0036, 4238}, {INT64_C(1380575044937622000), 0x0003, 0x0034, 0}, {INT64_C(1380575044937622000), 0x0003, 0x0030, 640}, {INT64_C(1380575044937622000), 0x0003, 0x0031, 384}, {INT64_C(1380575044937622000), 0x0000, 0x0002, 0}, {INT64_C(1380575044937622000), 0x0003, 0x0035, 3676}, {INT64_C(1380575044937622000), 0x0003, 0x0036, 3734}, {INT64_C(1380575044937622000), 0x0003, 0x0034, 0}, {INT64_C(1380575044937622000), 0x0003, 0x0030, 320}, {INT64_C(1380575044937622000), 0x0003, 0x0031, 256}, {INT64_C(1380575044937622000), 0x0000, 0x0002, 0}, {INT64_C(1380575044937622000), 0x0003, 0x0035, 3353}, {INT64_C(1380575044937622000), 0x0003, 0x0036, 2080}, {INT64_C(1380575044937622000), 0x0003, 0x0034, 1}, {INT64_C(1380575044937622000), 0x0003, 0x0030, 384}, {INT64_C(1380575044937622000), 0x0003, 0x0031, 160}, {INT64_C(1380575044937622000), 0x0000, 0x0002, 0}, {INT64_C(1380575044937622000), 0x0000, 0x0000, 0}, {INT64_C(1380575044957624000), 0x0003, 0x0000, 4565}, {INT64_C(1380575044957624000), 0x0003, 0x0001, 4132}, {INT64_C(1380575044957624000), 0x0003, 0x0035, 4565}, {INT64_C(1380575044957624000), 0x0003, 0x0036, 4132}, {INT64_C(1380575044957624000), 0x0003, 0x0034, 0}, {INT64_C(1380575044957624000), 0x0003, 0x0030, 640}, {INT64_C(1380575044957624000), 0x0003, 0x0031, 256}, {INT64_C(1380575044957624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044957624000), 0x0003, 0x0035, 3907}, {INT64_C(1380575044957624000), 0x0003, 0x0036, 3692}, {INT64_C(1380575044957624000), 0x0003, 0x0034, 1}, {INT64_C(1380575044957624000), 0x0003, 0x0030, 384}, {INT64_C(1380575044957624000), 0x0003, 0x0031, 320}, {INT64_C(1380575044957624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044957624000), 0x0003, 0x0035, 3532}, {INT64_C(1380575044957624000), 0x0003, 0x0036, 2080}, {INT64_C(1380575044957624000), 0x0003, 0x0034, 1}, {INT64_C(1380575044957624000), 0x0003, 0x0030, 256}, {INT64_C(1380575044957624000), 0x0003, 0x0031, 160}, {INT64_C(1380575044957624000), 0x0000, 0x0002, 0}, {INT64_C(1380575044957624000), 0x0000, 0x0000, 0}, {INT64_C(1380575044975623000), 0x0003, 0x0000, 4774}, {INT64_C(1380575044975623000), 0x0003, 0x0001, 4042}, {INT64_C(1380575044975623000), 0x0003, 0x0035, 4774}, {INT64_C(1380575044975623000), 0x0003, 0x0036, 4042}, {INT64_C(1380575044975623000), 0x0003, 0x0034, 0}, {INT64_C(1380575044975623000), 0x0003, 0x0030, 320}, {INT64_C(1380575044975623000), 0x0003, 0x0031, 256}, {INT64_C(1380575044975623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044975623000), 0x0003, 0x0035, 4081}, {INT64_C(1380575044975623000), 0x0003, 0x0036, 3583}, {INT64_C(1380575044975623000), 0x0003, 0x0034, 0}, {INT64_C(1380575044975623000), 0x0003, 0x0030, 320}, {INT64_C(1380575044975623000), 0x0003, 0x0031, 256}, {INT64_C(1380575044975623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044975623000), 0x0003, 0x0035, 3754}, {INT64_C(1380575044975623000), 0x0003, 0x0036, 2080}, {INT64_C(1380575044975623000), 0x0003, 0x0034, 1}, {INT64_C(1380575044975623000), 0x0003, 0x0030, 256}, {INT64_C(1380575044975623000), 0x0003, 0x0031, 160}, {INT64_C(1380575044975623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044975623000), 0x0000, 0x0000, 0}, {INT64_C(1380575044993623000), 0x0003, 0x0000, 4944}, {INT64_C(1380575044993623000), 0x0003, 0x0001, 3890}, {INT64_C(1380575044993623000), 0x0003, 0x0035, 4944}, {INT64_C(1380575044993623000), 0x0003, 0x0036, 3890}, {INT64_C(1380575044993623000), 0x0003, 0x0034, 0}, {INT64_C(1380575044993623000), 0x0003, 0x0030, 800}, {INT64_C(1380575044993623000), 0x0003, 0x0031, 256}, {INT64_C(1380575044993623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044993623000), 0x0003, 0x0035, 4278}, {INT64_C(1380575044993623000), 0x0003, 0x0036, 3555}, {INT64_C(1380575044993623000), 0x0003, 0x0034, 1}, {INT64_C(1380575044993623000), 0x0003, 0x0030, 640}, {INT64_C(1380575044993623000), 0x0003, 0x0031, 320}, {INT64_C(1380575044993623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044993623000), 0x0003, 0x0035, 3930}, {INT64_C(1380575044993623000), 0x0003, 0x0036, 1920}, {INT64_C(1380575044993623000), 0x0003, 0x0034, 1}, {INT64_C(1380575044993623000), 0x0003, 0x0030, 256}, {INT64_C(1380575044993623000), 0x0003, 0x0031, 160}, {INT64_C(1380575044993623000), 0x0000, 0x0002, 0}, {INT64_C(1380575044993623000), 0x0000, 0x0000, 0}, {INT64_C(1380575045013623000), 0x0003, 0x0000, 5120}, {INT64_C(1380575045013623000), 0x0003, 0x0001, 3885}, {INT64_C(1380575045013623000), 0x0003, 0x0035, 5120}, {INT64_C(1380575045013623000), 0x0003, 0x0036, 3885}, {INT64_C(1380575045013623000), 0x0003, 0x0034, 0}, {INT64_C(1380575045013623000), 0x0003, 0x0030, 320}, {INT64_C(1380575045013623000), 0x0003, 0x0031, 128}, {INT64_C(1380575045013623000), 0x0000, 0x0002, 0}, {INT64_C(1380575045013623000), 0x0003, 0x0035, 4484}, {INT64_C(1380575045013623000), 0x0003, 0x0036, 3430}, {INT64_C(1380575045013623000), 0x0003, 0x0034, 1}, {INT64_C(1380575045013623000), 0x0003, 0x0030, 384}, {INT64_C(1380575045013623000), 0x0003, 0x0031, 320}, {INT64_C(1380575045013623000), 0x0000, 0x0002, 0}, {INT64_C(1380575045013623000), 0x0003, 0x0035, 4158}, {INT64_C(1380575045013623000), 0x0003, 0x0036, 1920}, {INT64_C(1380575045013623000), 0x0003, 0x0034, 1}, {INT64_C(1380575045013623000), 0x0003, 0x0030, 256}, {INT64_C(1380575045013623000), 0x0003, 0x0031, 160}, {INT64_C(1380575045013623000), 0x0000, 0x0002, 0}, {INT64_C(1380575045013623000), 0x0000, 0x0000, 0}, {INT64_C(1380575045031622000), 0x0003, 0x0000, 5325}, {INT64_C(1380575045031622000), 0x0003, 0x0001, 3736}, {INT64_C(1380575045031622000), 0x0003, 0x0035, 5325}, {INT64_C(1380575045031622000), 0x0003, 0x0036, 3736}, {INT64_C(1380575045031622000), 0x0003, 0x0034, 0}, {INT64_C(1380575045031622000), 0x0003, 0x0030, 480}, {INT64_C(1380575045031622000), 0x0003, 0x0031, 256}, {INT64_C(1380575045031622000), 0x0000, 0x0002, 0}, {INT64_C(1380575045031622000), 0x0003, 0x0035, 4677}, {INT64_C(1380575045031622000), 0x0003, 0x0036, 3403}, {INT64_C(1380575045031622000), 0x0003, 0x0034, 0}, {INT64_C(1380575045031622000), 0x0003, 0x0030, 320}, {INT64_C(1380575045031622000), 0x0003, 0x0031, 256}, {INT64_C(1380575045031622000), 0x0000, 0x0002, 0}, {INT64_C(1380575045031622000), 0x0003, 0x0035, 4384}, {INT64_C(1380575045031622000), 0x0003, 0x0036, 1920}, {INT64_C(1380575045031622000), 0x0003, 0x0034, 1}, {INT64_C(1380575045031622000), 0x0003, 0x0030, 256}, {INT64_C(1380575045031622000), 0x0003, 0x0031, 160}, {INT64_C(1380575045031622000), 0x0000, 0x0002, 0}, {INT64_C(1380575045031622000), 0x0000, 0x0000, 0}, {INT64_C(1380575045049620000), 0x0003, 0x0000, 5504}, {INT64_C(1380575045049620000), 0x0003, 0x0001, 3636}, {INT64_C(1380575045049620000), 0x0003, 0x0035, 5504}, {INT64_C(1380575045049620000), 0x0003, 0x0036, 3636}, {INT64_C(1380575045049620000), 0x0003, 0x0034, 0}, {INT64_C(1380575045049620000), 0x0003, 0x0030, 480}, {INT64_C(1380575045049620000), 0x0003, 0x0031, 128}, {INT64_C(1380575045049620000), 0x0000, 0x0002, 0}, {INT64_C(1380575045049620000), 0x0000, 0x0000, 0}, {INT64_C(1380575045143617000), 0x0001, 0x014d, 0}, {INT64_C(1380575045143617000), 0x0001, 0x014a, 0}, {INT64_C(1380575045143617000), 0x0000, 0x0000, 0}, {INT64_C(-1), 0x0000, 0x0000, 0} }; #endif // NTRIG_INPUT_EVENTS_H_ mir-0.1.8+14.04.20140411/benchmarks/android-input/CMakeLists.txt0000644000015301777760000000051112322054247024331 0ustar pbusernogroup00000000000000project(android-input-perf) set(SOURCES input_reader_perf.cpp ) include_directories( ${Mir_SOURCE_DIR}/include/test ${Mir_SOURCE_DIR}/include/platform ) add_executable(input-reader-perf ${SOURCES}) target_link_libraries( input-reader-perf android-input mir-test-doubles ) uses_android_input(input-reader-perf) mir-0.1.8+14.04.20140411/benchmarks/CMakeLists.txt0000644000015301777760000000050412322054223021550 0ustar pbusernogroup00000000000000include_directories(${MIR_3RD_PARTY_INCLUDE_DIRECTORIES}) include_directories(${MIR_ANDROID_INCLUDE_DIRECTORIES}) add_custom_target( benchmarks ) if (MIR_ENABLE_TESTS) add_subdirectory(android-input) endif () add_subdirectory(cpu) add_subdirectory(memory) add_dependencies(benchmarks cpu_benchmarks memory_benchmarks) mir-0.1.8+14.04.20140411/benchmarks/cpu/0000755000015301777760000000000012322054703017603 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/benchmarks/cpu/CMakeLists.txt0000644000015301777760000000235312322054223022343 0ustar pbusernogroup00000000000000find_program( VALGRIND_EXECUTABLE valgrind ) if(NOT VALGRIND_EXECUTABLE) message("valgrind not found, disabling cpu benchmarks") else() set(CPU_BENCHMARKS_SOCKET "/tmp/benchmarks.cpu.socket.mir") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/benchmark.sh.in ${CMAKE_CURRENT_BINARY_DIR}/benchmark.sh ) add_custom_target( cpu_benchmark_one_server_one_client "${CMAKE_CURRENT_BINARY_DIR}/benchmark.sh" 1 1000 one_server_one_client_results_for_client one_server_one_client_results_for_server ) add_custom_target( cpu_benchmark_one_server_multiple_clients "${CMAKE_CURRENT_BINARY_DIR}/benchmark.sh" 10 100 one_server_multiple_client_results_for_client one_server_multiple_client_results_for_server ) add_custom_target( cpu_benchmark_one_server_multiple_clients_heavy_load "${CMAKE_CURRENT_BINARY_DIR}/benchmark.sh" 20 100 one_server_multiple_client_heavy_load_results_for_client one_server_multiple_client_heavy_load_results_for_server ) add_custom_target( cpu_benchmarks DEPENDS cpu_benchmark_one_server_one_client cpu_benchmark_one_server_multiple_clients cpu_benchmark_one_server_multiple_clients_heavy_load ) endif() mir-0.1.8+14.04.20140411/benchmarks/cpu/benchmark.sh.in0000755000015301777760000000124612322054223022501 0ustar pbusernogroup00000000000000#!/bin/bash # Starting the server server_fn=@CMAKE_CURRENT_BINARY_DIR@/callgrind_$4 @VALGRIND_EXECUTABLE@ --tool=callgrind --callgrind-out-file=`echo $server_fn`.out @EXECUTABLE_OUTPUT_PATH@/mir -f @CPU_BENCHMARKS_SOCKET@ & server_pid=$! sleep 5 # Starting the clients fn=@CMAKE_CURRENT_BINARY_DIR@/callgrind_$3 seq 1 $1 | xargs -I {} -n 1 -P $1 @VALGRIND_EXECUTABLE@ --tool=callgrind --callgrind-out-file=`echo $fn`.out.{} @EXECUTABLE_OUTPUT_PATH@/mir_demo_client -f @CPU_BENCHMARKS_SOCKET@ -c $2 kill $server_pid # This is extremely ugly, but we need to introduce some latency to account # for the fact that we fire up multiple mir instances in rapid succession. sleep 5 mir-0.1.8+14.04.20140411/.clang-format0000644000015301777760000000261512322054223017253 0ustar pbusernogroup00000000000000Language: 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: true ColumnLimit: 120 ConstructorInitializerAllOnOneLineOrOnePerLine: false 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 mir-0.1.8+14.04.20140411/cmake/0000755000015301777760000000000012322054703015757 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/cmake/PrePush.cmake0000644000015301777760000001231212322054223020343 0ustar pbusernogroup00000000000000####################################################################### # A convenience target that carries out the following steps: # - Apply astyle to all source files of interest. # - Build & test in a chroot, comparable setup to CI/Autolanding # and ppa builders. Will fail if new files have not been added. # - Build & test for android. # # NOTE: This target is very sensitive to the availability of all # all required dependencies. For that, we prefer to fail the # target if deps are missing to make the problem very visible. # # TODO: # - Wire up the style-check target once we have reached a state # where trunk actually passes the style check. ####################################################################### add_custom_target( pre-push WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) ####################################################################### # Add target for running astyle with the correct options # ####################################################################### find_program(ASTYLE_EXECUTABLE astyle) if(NOT ASTYLE_EXECUTABLE) message(STATUS "Could NOT find astyle, pre-push is going to FAIL") endif() set( ASTYLE_OPTIONS ${ASTYLE_OPTIONS} --indent-switches --pad-header --unpad-paren --align-pointer=type ) add_custom_target( astyle find ${CMAKE_SOURCE_DIR}/examples -name *.h | xargs ${ASTYLE_EXECUTABLE} ${ASTYLE_OPTIONS} COMMAND find ${CMAKE_SOURCE_DIR}/include -name *.h | xargs ${ASTYLE_EXECUTABLE} COMMAND find ${CMAKE_SOURCE_DIR}/src -name *.h | xargs ${ASTYLE_EXECUTABLE} ${${ASTYLE_EXECUTABLE}_OPTIONS} COMMAND find ${CMAKE_SOURCE_DIR}/tests -name *.h | xargs ${ASTYLE_EXECUTABLE} ${${ASTYLE_EXECUTABLE}_OPTIONS} COMMAND find ${CMAKE_SOURCE_DIR}/tools -name *.h | xargs ${ASTYLE_EXECUTABLE} ${${ASTYLE_EXECUTABLE}_OPTIONS} COMMAND find ${CMAKE_SOURCE_DIR}/examples -name *.cpp | xargs ${ASTYLE_EXECUTABLE} ${${ASTYLE_EXECUTABLE}_OPTIONS} COMMAND find ${CMAKE_SOURCE_DIR}/include -name *.cpp | xargs ${ASTYLE_EXECUTABLE} ${${ASTYLE_EXECUTABLE}_OPTIONS} COMMAND find ${CMAKE_SOURCE_DIR}/src -name *.cpp | xargs ${ASTYLE_EXECUTABLE} ${${ASTYLE_EXECUTABLE}_OPTIONS} COMMAND find ${CMAKE_SOURCE_DIR}/tests -name *.cpp | xargs ${ASTYLE_EXECUTABLE} ${${ASTYLE_EXECUTABLE}_OPTIONS} COMMAND find ${CMAKE_SOURCE_DIR}/tools -name *.cpp | xargs ${ASTYLE_EXECUTABLE} ${${ASTYLE_EXECUTABLE}_OPTIONS} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} VERBATIM ) ####################################################################### # Add target for creating a source tarball with bzr export # ####################################################################### add_custom_target( pre-push-source-tarball COMMAND rm -rf pre-push-build-area COMMAND mkdir pre-push-build-area COMMAND bzr export --root mir-pre-push pre-push-build-area/mir_${MIR_VERSION_MAJOR}.${MIR_VERSION_MINOR}.${MIR_VERSION_PATCH}.orig.tar.bz2 ${CMAKE_SOURCE_DIR} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Preparing source tarball for pre-push build & test" ) ####################################################################### # Add target for extracting source tarball for pdebuild # ####################################################################### add_custom_target( extract-pre-push-tarball COMMAND tar -xf mir_${MIR_VERSION_MAJOR}.${MIR_VERSION_MINOR}.${MIR_VERSION_PATCH}.orig.tar.bz2 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/pre-push-build-area VERBATIM ) ####################################################################### # Builds & tests the last committed revision of the current branch # ####################################################################### find_program(PDEBUILD_EXECUTABLE pdebuild) if(NOT PDEBUILD_EXECUTABLE) message(STATUS "pdebuild NOT found, pre-push is going to FAIL") endif() add_custom_target( pdebuild COMMAND ${PDEBUILD_EXECUTABLE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/pre-push-build-area/mir-pre-push COMMENT "Building & testing in chroot'd environment" VERBATIM ) ####################################################################### # Builds & tests the last committed revision of the current branch # # for Android # ####################################################################### if(NOT DEFINED ENV{MIR_ANDROID_NDK_DIR}) message(STATUS "Env. variable MIR_ANDROID_NDK_DIR not set, pre-push is going to FAIL") endif() if(NOT DEFINED ENV{MIR_ANDROID_SDK_DIR}) message(STATUS "Env. variable MIR_ANDROID_SDK_DIR not set, pre-push is going to FAIL") endif() add_custom_target( android-build COMMAND ./cross-compile.sh android-build WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMENT "Building & testing for android" ) ####################################################################### # pdebuild: make tarball -> extract to build area -> pdebuild # # android-build: invoke cross-compile script # ####################################################################### add_dependencies(extract-pre-push-tarball pre-push-source-tarball) add_dependencies(pdebuild extract-pre-push-tarball) add_dependencies(pre-push pdebuild android-build) mir-0.1.8+14.04.20140411/cmake/FindLcov.cmake0000644000015301777760000000172012322054223020462 0ustar pbusernogroup00000000000000# - Find lcov # Will define: # # LCOV_EXECUTABLE - the lcov binary # GENHTML_EXECUTABLE - the genhtml executable # # Copyright (C) 2010 by Johannes Wienke # # 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 2, 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. # INCLUDE(FindPackageHandleStandardArgs) FIND_PROGRAM(LCOV_EXECUTABLE lcov) FIND_PROGRAM(GENHTML_EXECUTABLE genhtml) FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lcov DEFAULT_MSG LCOV_EXECUTABLE GENHTML_EXECUTABLE) # only visible in advanced view MARK_AS_ADVANCED(LCOV_EXECUTABLE GENHTML_EXECUTABLE) mir-0.1.8+14.04.20140411/cmake/Debian.cmake0000644000015301777760000000310012322054223020132 0ustar pbusernogroup00000000000000# Check if dpkg-buildflags is available and adjust cmake buildflags find_program(DPKG_BUILDFLAGS dpkg-buildflags) if (DPKG_BUILDFLAGS) message(STATUS "dpkg-buildflags available, adjusting compiler flags.") #dpkg-buildflags is available, adjust cmake buildflags now. execute_process( COMMAND ${DPKG_BUILDFLAGS} "--get" "CFLAGS" OUTPUT_VARIABLE DPKG_BUILDFLAGS_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE ) execute_process( COMMAND ${DPKG_BUILDFLAGS} "--get" "CPPFLAGS" OUTPUT_VARIABLE DPKG_BUILDFLAGS_CPPFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE ) execute_process( COMMAND ${DPKG_BUILDFLAGS} "--get" "CXXFLAGS" OUTPUT_VARIABLE DPKG_BUILDFLAGS_CXXFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE ) execute_process( COMMAND ${DPKG_BUILDFLAGS} "--get" "LDFLAGS" OUTPUT_VARIABLE DPKG_BUILDFLAGS_LDFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE ) message(STATUS "DPKG_BUILDFLAGS_CFLAGS: " ${DPKG_BUILDFLAGS_CFLAGS}) message(STATUS "DPKG_BUILDFLAGS_CPPFLAGS: " ${DPKG_BUILDFLAGS_CPPFLAGS}) message(STATUS "DPKG_BUILDFLAGS_CXXFLAGS: " ${DPKG_BUILDFLAGS_CXXFLAGS}) message(STATUS "DPKG_BUILDFLAGS_LDFLAGS: " ${DPKG_BUILDFLAGS_LDFLAGS}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${DPKG_BUILDFLAGS_CFLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${DPKG_BUILDFLAGS_CXXFLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${DPKG_BUILDFLAGS_LDFLAGS}") add_definitions("${DPKG_BUILDFLAGS_CPPFLAGS}") else() message(WARNING "Could not find dpkg-buildflags, not building with packaging setup C/C++/LD-Flags.") endif(DPKG_BUILDFLAGS)mir-0.1.8+14.04.20140411/cmake/EnableCoverageReport.cmake0000644000015301777760000001562112322054223023021 0ustar pbusernogroup00000000000000# - Creates a special coverage build type and target on GCC. # # Defines a function ENABLE_COVERAGE_REPORT which generates the coverage target # for selected targets. Optional arguments to this function are used to filter # unwanted results using globbing expressions. Moreover targets with tests for # the source code can be specified to trigger regenerating the report if the # test has changed # # ENABLE_COVERAGE_REPORT(TARGETS target... [FILTER filter...] [TESTS test targets...]) # # To generate a coverage report first build the project with # CMAKE_BUILD_TYPE=coverage, then call make test and afterwards make coverage. # # The coverage report is based on gcov. Depending on the availability of lcov # a HTML report will be generated and/or an XML report of gcovr is found. # The generated coverage target executes all found solutions. Special targets # exist to create e.g. only the xml report: coverage-xml. # # Copyright (C) 2010 by Johannes Wienke # # 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 2, 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. # INCLUDE(ParseArguments) FIND_PACKAGE(Lcov) FIND_PACKAGE(gcovr) FUNCTION(ENABLE_COVERAGE_REPORT) # argument parsing PARSE_ARGUMENTS(ARG "FILTER;TARGETS;TESTS" "" ${ARGN}) SET(COVERAGE_RAW_FILE "${CMAKE_BINARY_DIR}/coverage.raw.info") SET(COVERAGE_FILTERED_FILE "${CMAKE_BINARY_DIR}/coverage.info") SET(COVERAGE_REPORT_DIR "${CMAKE_BINARY_DIR}/coveragereport") SET(COVERAGE_XML_FILE "${CMAKE_BINARY_DIR}/coverage.xml") SET(COVERAGE_XML_COMMAND_FILE "${CMAKE_BINARY_DIR}/coverage-xml.cmake") # decide if there is any tool to create coverage data SET(TOOL_FOUND FALSE) IF(LCOV_FOUND OR GCOVR_FOUND) SET(TOOL_FOUND TRUE) ENDIF() IF(NOT TOOL_FOUND) MESSAGE(STATUS "Cannot enable coverage targets because neither lcov nor gcovr are found.") ENDIF() STRING(TOLOWER "${CMAKE_BUILD_TYPE}" COVERAGE_BUILD_TYPE) IF(CMAKE_COMPILER_IS_GNUCXX AND TOOL_FOUND AND "${COVERAGE_BUILD_TYPE}" MATCHES "coverage") MESSAGE(STATUS "Coverage support enabled for targets: ${ARG_TARGETS}") # create coverage build type SET(CMAKE_CXX_FLAGS_COVERAGE ${CMAKE_CXX_FLAGS_DEBUG} PARENT_SCOPE) SET(CMAKE_C_FLAGS_COVERAGE ${CMAKE_C_FLAGS_DEBUG} PARENT_SCOPE) SET(CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES} coverage PARENT_SCOPE) # instrument targets SET_TARGET_PROPERTIES(${ARG_TARGETS} PROPERTIES COMPILE_FLAGS --coverage LINK_FLAGS --coverage) # html report IF (LCOV_FOUND) MESSAGE(STATUS "Enabling HTML coverage report") # set up coverage target ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_RAW_FILE} COMMAND ${LCOV_EXECUTABLE} -c -d ${CMAKE_BINARY_DIR} -o ${COVERAGE_RAW_FILE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Collecting coverage data" DEPENDS ${ARG_TARGETS} ${ARG_TESTS} VERBATIM) # filter unwanted stuff LIST(LENGTH ARG_FILTER FILTER_LENGTH) IF(${FILTER_LENGTH} GREATER 0) SET(FILTER COMMAND ${LCOV_EXECUTABLE}) FOREACH(F ${ARG_FILTER}) SET(FILTER ${FILTER} -r ${COVERAGE_FILTERED_FILE} ${F}) ENDFOREACH() SET(FILTER ${FILTER} -o ${COVERAGE_FILTERED_FILE}) ELSE() SET(FILTER "") ENDIF() ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_FILTERED_FILE} COMMAND ${LCOV_EXECUTABLE} -e ${COVERAGE_RAW_FILE} "${CMAKE_SOURCE_DIR}*" -o ${COVERAGE_FILTERED_FILE} ${FILTER} DEPENDS ${COVERAGE_RAW_FILE} COMMENT "Filtering recorded coverage data for project-relevant entries" VERBATIM) ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_REPORT_DIR} COMMAND ${CMAKE_COMMAND} -E make_directory ${COVERAGE_REPORT_DIR} COMMAND ${GENHTML_EXECUTABLE} --legend --show-details -t "${PROJECT_NAME} test coverage" -o ${COVERAGE_REPORT_DIR} ${COVERAGE_FILTERED_FILE} DEPENDS ${COVERAGE_FILTERED_FILE} COMMENT "Generating HTML coverage report in ${COVERAGE_REPORT_DIR}" VERBATIM) ADD_CUSTOM_TARGET(coverage-html DEPENDS ${COVERAGE_REPORT_DIR}) ENDIF() # xml coverage report IF(GCOVR_FOUND) MESSAGE(STATUS "Enabling XML coverage report") # gcovr cannot write directly to a file so the execution needs to # be wrapped in a cmake file that generates the file output FILE(WRITE ${COVERAGE_XML_COMMAND_FILE} "SET(ENV{LANG} en)\n") FILE(APPEND ${COVERAGE_XML_COMMAND_FILE} "EXECUTE_PROCESS(COMMAND \"${GCOVR_EXECUTABLE}\" --exclude=3rd_party.* --exclude=tests.* --exclude=obj-.* --exclude=cmake.* --exclude=include.mir_test.* --exclude=include.mir_test_doubles.* --exclude=include.mir_test_framework.* -c \"${CMAKE_GCOV}\" -x -r \"${CMAKE_SOURCE_DIR}\" OUTPUT_FILE \"${COVERAGE_XML_FILE}\" WORKING_DIRECTORY \"${CMAKE_BINARY_DIR}\")\n") ADD_CUSTOM_COMMAND(OUTPUT ${COVERAGE_XML_FILE} COMMAND ${CMAKE_COMMAND} ARGS -P ${COVERAGE_XML_COMMAND_FILE} COMMENT "Generating coverage XML report" VERBATIM) ADD_CUSTOM_TARGET(coverage-xml DEPENDS ${COVERAGE_XML_FILE}) ENDIF() # provide a global coverage target executing both steps if available SET(GLOBAL_DEPENDS "") IF(LCOV_FOUND) LIST(APPEND GLOBAL_DEPENDS ${COVERAGE_REPORT_DIR}) ENDIF() IF(GCOVR_FOUND) LIST(APPEND GLOBAL_DEPENDS ${COVERAGE_XML_FILE}) ENDIF() IF(LCOV_FOUND OR GCOVR_FOUND) ADD_CUSTOM_TARGET(coverage DEPENDS ${GLOBAL_DEPENDS}) ENDIF() ENDIF() ENDFUNCTION() mir-0.1.8+14.04.20140411/cmake/MirCommon.cmake0000644000015301777760000001026212322054247020665 0ustar pbusernogroup00000000000000cmake_minimum_required (VERSION 2.6) # Create target to discover tests include(CMakeDependentOption) CMAKE_DEPENDENT_OPTION( DISABLE_GTEST_TEST_DISCOVERY "If set to ON, disables fancy test autodiscovery and switches back to classic add_test behavior" OFF "NOT MIR_IS_CROSS_COMPILING" ON) option( ENABLE_MEMCHECK_OPTION "If set to ON, enables automatic creation of memcheck targets" OFF ) if(ENABLE_MEMCHECK_OPTION) find_program( VALGRIND_EXECUTABLE valgrind) if(VALGRIND_EXECUTABLE) set(VALGRIND_ARGS "--error-exitcode=1" "--trace-children=yes" "--leak-check=full" "--show-leak-kinds=definite" "--errors-for-leak-kinds=definite") set(VALGRIND_ARGS ${VALGRIND_ARGS} "--suppressions=${CMAKE_SOURCE_DIR}/tools/valgrind_suppressions_generic") set(DISCOVER_FLAGS "--enable-memcheck") set(DISCOVER_FLAGS ${DISCOVER_FLAGS} "--suppressions=${CMAKE_SOURCE_DIR}/tools/valgrind_suppressions_generic") if (TARGET_ARCH STREQUAL "arm-linux-gnueabihf") set(VALGRIND_ARGS ${VALGRIND_ARGS} "--suppressions=${CMAKE_SOURCE_DIR}/tools/valgrind_suppressions_armhf") set(DISCOVER_FLAGS ${DISCOVER_FLAGS} "--suppressions=${CMAKE_SOURCE_DIR}/tools/valgrind_suppressions_armhf") endif() else(VALGRIND_EXECUTABLE) message("Not enabling memcheck as valgrind is missing on your system") endif(VALGRIND_EXECUTABLE) endif(ENABLE_MEMCHECK_OPTION) function (mir_discover_tests EXECUTABLE) if(DISABLE_GTEST_TEST_DISCOVERY) add_test(${EXECUTABLE} ${VALGRIND_EXECUTABLE} ${VALGRIND_ARGS} ${EXECUTABLE_OUTPUT_PATH}/${EXECUTABLE} "--gtest_filter=-*DeathTest.*") add_test(${EXECUTABLE}_death_tests ${EXECUTABLE_OUTPUT_PATH}/${EXECUTABLE} "--gtest_filter=*DeathTest.*") if (${ARGC} GREATER 1) set_property(TEST ${EXECUTABLE} PROPERTY ENVIRONMENT ${ARGN}) set_property(TEST ${EXECUTABLE}_death_tests PROPERTY ENVIRONMENT ${ARGN}) endif() else() set(CHECK_TEST_DISCOVERY_TARGET_NAME "check_discover_tests_in_${EXECUTABLE}") set(TEST_DISCOVERY_TARGET_NAME "discover_tests_in_${EXECUTABLE}") message(STATUS "Defining targets: ${CHECK_TEST_DISCOVERY_TARGET_NAME} and ${TEST_DISCOVERY_TARGET_NAME}") # These targets are always considered out-of-date, and are always run (at least for normal builds, except for make test/install). add_custom_target( ${CHECK_TEST_DISCOVERY_TARGET_NAME} ALL ${EXECUTABLE_OUTPUT_PATH}/${EXECUTABLE} --gtest_list_tests > /dev/null WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Check that discovering Tests in ${EXECUTABLE} works") if (${ARGC} GREATER 1) foreach (env ${ARGN}) list(APPEND EXTRA_ENV_FLAGS "--add-environment" "${env}") endforeach() endif() add_custom_target( ${TEST_DISCOVERY_TARGET_NAME} ALL ${EXECUTABLE_OUTPUT_PATH}/${EXECUTABLE} --gtest_list_tests | ${CMAKE_BINARY_DIR}/mir_gtest/mir_discover_gtest_tests --executable=${EXECUTABLE_OUTPUT_PATH}/${EXECUTABLE} ${DISCOVER_FLAGS} ${EXTRA_ENV_FLAGS} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Discovering Tests in ${EXECUTABLE}" VERBATIM) add_dependencies( ${CHECK_TEST_DISCOVERY_TARGET_NAME} ${EXECUTABLE}) add_dependencies( ${TEST_DISCOVERY_TARGET_NAME} ${CHECK_TEST_DISCOVERY_TARGET_NAME} ${EXECUTABLE} mir_discover_gtest_tests) endif() endfunction () function (mir_add_memcheck_test) if (ENABLE_MEMCHECK_OPTION) if(DISABLE_GTEST_TEST_DISCOVERY) add_custom_target( memcheck_test ALL ) ADD_TEST("memcheck-test" ${CMAKE_BINARY_DIR}/mir_gtest/fail_on_success.sh ${VALGRIND_EXECUTABLE} ${VALGRIND_ARGS} ${CMAKE_BINARY_DIR}/mir_gtest/mir_test_memory_error) add_dependencies( memcheck_test mir_test_memory_error ) else() add_custom_target( memcheck_test ALL ${CMAKE_BINARY_DIR}/mir_gtest/mir_discover_gtest_tests --executable=${CMAKE_BINARY_DIR}/mir_gtest/mir_test_memory_error --memcheck-test ${DISCOVER_FLAGS} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Adding memcheck test" VERBATIM) add_dependencies( memcheck_test mir_discover_gtest_tests mir_test_memory_error) endif() endif() endfunction() mir-0.1.8+14.04.20140411/cmake/FindLTTngUST.cmake0000644000015301777760000000244312322054223021146 0ustar pbusernogroup00000000000000# - Try to find LTTng-UST # Once done this will define # LTTNG_UST_FOUND - System has LTTng-UST # LTTNG_UST_INCLUDE_DIRS - The LTTng-UST include directories # LTTNG_UST_LIBRARIES - The libraries needed to use LTTng-UST find_package(PkgConfig) # pkgconfig is currently broken for LTTng-UST and urcu-bp #pkg_check_modules(PC_LTTNG_UST QUIET lttng-ust) #pkg_check_modules(PC_LIBURCU_BP QUIET liburcu-bp) find_path(LTTNG_UST_INCLUDE_DIR lttng/tracepoint.h HINTS ${PC_LTTNG_UST_INCLUDEDIR} ${PC_LTTNG_UST_INCLUDE_DIRS}) find_library(LTTNG_UST_LIBRARY lttng-ust HINTS ${PC_LTTNG_UST_LIBDIR} ${PC_LTTNG_UST_LIBRARY_DIRS}) find_library(LIBURCU_BP_LIBRARY urcu-bp HINTS ${PC_LIBURCU_BP_LIBDIR} ${PC_LIBURCU_BP_LIBRARY_DIRS}) set(LTTNG_UST_LIBRARIES ${LTTNG_UST_LIBRARY} ${LIBURCU_BP_LIBRARY} -ldl) set(LTTNG_UST_INCLUDE_DIRS ${LTTNG_UST_INCLUDE_DIR}) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LTTNG_UST_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(LTTNG_UST DEFAULT_MSG LTTNG_UST_LIBRARY LIBURCU_BP_LIBRARY LTTNG_UST_INCLUDE_DIR) mark_as_advanced(LTTNG_UST_INCLUDE_DIR LTTNG_UST_LIBRARY) mir-0.1.8+14.04.20140411/cmake/Doxygen.cmake0000644000015301777760000000206112322054223020372 0ustar pbusernogroup00000000000000# Check if doxygen is present and add 'make doc' target find_package(Doxygen) option( BUILD_DOXYGEN "Build Doxygen documentation as part of the default build" OFF ) if(DOXYGEN_FOUND AND (DOXYGEN_VERSION VERSION_GREATER "1.8")) message(STATUS "doxygen ${DOXYGEN_VERSION} (>= 1.8.0) available - enabling make target doc") EXECUTE_PROCESS(COMMAND "date" "-u" OUTPUT_VARIABLE DATE_TODAY) configure_file(doc/Doxyfile.in ${PROJECT_BINARY_DIR}/Doxyfile @ONLY IMMEDIATE) configure_file(doc/footer.html.in ${PROJECT_BINARY_DIR}/doc/footer.html @ONLY IMMEDIATE) configure_file(doc/extra.css ${PROJECT_BINARY_DIR}/doc/extra.css @ONLY IMMEDIATE) if (BUILD_DOXYGEN) set(ALL "ALL") endif() add_custom_target(doc ${ALL} COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_BINARY_DIR}/Doxyfile SOURCES ${PROJECT_BINARY_DIR}/Doxyfile DEPENDS guides) install(DIRECTORY ${CMAKE_BINARY_DIR}/doc/html DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/mir-doc/) endif() mir-0.1.8+14.04.20140411/cmake/FindGtest.cmake0000644000015301777760000000337212322054223020652 0ustar pbusernogroup00000000000000include(ExternalProject) include(FindPackageHandleStandardArgs) #gtest set(GTEST_INSTALL_DIR /usr/src/gmock/gtest/include) find_path(GTEST_INCLUDE_DIR gtest/gtest.h HINTS ${GTEST_INSTALL_DIR}) #gmock find_path(GMOCK_INSTALL_DIR gmock/CMakeLists.txt HINTS /usr/src) if(${GMOCK_INSTALL_DIR} STREQUAL "GMOCK_INSTALL_DIR-NOTFOUND") message(FATAL_ERROR "google-mock package not found") endif() set(GMOCK_INSTALL_DIR ${GMOCK_INSTALL_DIR}/gmock) find_path(GMOCK_INCLUDE_DIR gmock/gmock.h) set(GMOCK_PREFIX gmock) set(GMOCK_BINARY_DIR ${CMAKE_BINARY_DIR}/${GMOCK_PREFIX}/libs) set(GTEST_BINARY_DIR ${GMOCK_BINARY_DIR}/gtest) set(GTEST_CMAKE_ARGS "") if (${MIR_IS_CROSS_COMPILING}) set(GTEST_CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_MODULE_PATH}/LinuxCrossCompile.cmake) endif() ExternalProject_Add( GMock #where to build in source tree PREFIX ${GMOCK_PREFIX} #where the source is external to the project SOURCE_DIR ${GMOCK_INSTALL_DIR} #forward the compilers to the subproject so cross-arch builds work CMAKE_ARGS ${GTEST_CMAKE_ARGS} BINARY_DIR ${GMOCK_BINARY_DIR} #we don't need to install, so skip INSTALL_COMMAND "" ) set(GMOCK_LIBRARY ${GMOCK_BINARY_DIR}/libgmock.a) set(GMOCK_MAIN_LIBRARY ${GMOCK_BINARY_DIR}/libgmock_main.a) set(GMOCK_BOTH_LIBRARIES ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY}) set(GTEST_LIBRARY ${GTEST_BINARY_DIR}/libgtest.a) set(GTEST_MAIN_LIBRARY ${GTEST_BINARY_DIR}/libgtest_main.a) set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARY} ${GTEST_MAIN_LIBRARY}) set(GTEST_ALL_LIBRARIES ${GTEST_BOTH_LIBRARIES} ${GMOCK_BOTH_LIBRARIES}) find_package_handle_standard_args(GTest DEFAULT_MSG GMOCK_INCLUDE_DIR GTEST_INCLUDE_DIR) mir-0.1.8+14.04.20140411/cmake/Findgcovr.cmake0000644000015301777760000000170212322054223020677 0ustar pbusernogroup00000000000000# - Find gcovr scrip # Will define: # # GCOVR_EXECUTABLE - the gcovr script # # Uses: # # GCOVR_ROOT - root to search for the script # # Copyright (C) 2011 by Johannes Wienke # # 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 2, 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. # INCLUDE(FindPackageHandleStandardArgs) FIND_PROGRAM(GCOVR_EXECUTABLE gcovr HINTS ${GCOVR_ROOT} "${GCOVR_ROOT}/bin") FIND_PACKAGE_HANDLE_STANDARD_ARGS(gcovr DEFAULT_MSG GCOVR_EXECUTABLE) # only visible in advanced view MARK_AS_ADVANCED(GCOVR_EXECUTABLE) mir-0.1.8+14.04.20140411/cmake/FindGLESv2.cmake0000644000015301777760000000157312322054223020567 0ustar pbusernogroup00000000000000# - Try to find GLESv2 # Once done this will define # GLESv2_FOUND - System has GLESv2 # GLESv2_INCLUDE_DIRS - The GLESv2 include directories # GLESv2_LIBRARIES - The libraries needed to use GLESv2 find_package(PkgConfig) pkg_check_modules(PC_GLESv2 QUIET glesv2) find_path(GLESv2_INCLUDE_DIR GLES2/gl2.h HINTS ${PC_GLESv2_INCLUDEDIR} ${PC_GLESv2_INCLUDE_DIRS}) find_library(GLESv2_LIBRARY GLESv2 HINTS ${PC_GLESv2_LIBDIR} ${PC_GLESv2_LIBRARY_DIRS}) set(GLESv2_LIBRARIES ${GLESv2_LIBRARY}) set(GLESv2_INCLUDE_DIRS ${GLESv2_INCLUDE_DIR}) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set GLESv2_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(GLESv2 DEFAULT_MSG GLESv2_LIBRARY GLESv2_INCLUDE_DIR) mark_as_advanced(GLESv2_INCLUDE_DIR GLESv2_LIBRARY) mir-0.1.8+14.04.20140411/cmake/ParseArguments.cmake0000644000015301777760000000340612322054223021721 0ustar pbusernogroup00000000000000# Parse arguments passed to a function into several lists separated by # upper-case identifiers and options that do not have an associated list e.g.: # # SET(arguments # hello OPTION3 world # LIST3 foo bar # OPTION2 # LIST1 fuz baz # ) # PARSE_ARGUMENTS(ARG "LIST1;LIST2;LIST3" "OPTION1;OPTION2;OPTION3" ${arguments}) # # results in 7 distinct variables: # * ARG_DEFAULT_ARGS: hello;world # * ARG_LIST1: fuz;baz # * ARG_LIST2: # * ARG_LIST3: foo;bar # * ARG_OPTION1: FALSE # * ARG_OPTION2: TRUE # * ARG_OPTION3: TRUE # # taken from http://www.cmake.org/Wiki/CMakeMacroParseArguments MACRO(PARSE_ARGUMENTS prefix arg_names option_names) SET(DEFAULT_ARGS) FOREACH(arg_name ${arg_names}) SET(${prefix}_${arg_name}) ENDFOREACH(arg_name) FOREACH(option ${option_names}) SET(${prefix}_${option} FALSE) ENDFOREACH(option) SET(current_arg_name DEFAULT_ARGS) SET(current_arg_list) FOREACH(arg ${ARGN}) SET(larg_names ${arg_names}) LIST(FIND larg_names "${arg}" is_arg_name) IF (is_arg_name GREATER -1) SET(${prefix}_${current_arg_name} ${current_arg_list}) SET(current_arg_name ${arg}) SET(current_arg_list) ELSE (is_arg_name GREATER -1) SET(loption_names ${option_names}) LIST(FIND loption_names "${arg}" is_option) IF (is_option GREATER -1) SET(${prefix}_${arg} TRUE) ELSE (is_option GREATER -1) SET(current_arg_list ${current_arg_list} ${arg}) ENDIF (is_option GREATER -1) ENDIF (is_arg_name GREATER -1) ENDFOREACH(arg) SET(${prefix}_${current_arg_name} ${current_arg_list}) ENDMACRO(PARSE_ARGUMENTS) mir-0.1.8+14.04.20140411/cmake/LinuxCrossCompile.cmake0000644000015301777760000000315012322054223022377 0ustar pbusernogroup00000000000000set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_VERSION 1) set(MIR_IS_CROSS_COMPILING TRUE CACHE STRING "build is a cross compile") set(MIR_NDK_PATH $ENV{MIR_NDK_PATH} CACHE STRING "path of mir android bundle") set(MIR_ARM_EABI "arm-linux-gnueabihf") set(CMAKE_C_COMPILER /usr/bin/${MIR_ARM_EABI}-gcc) set(CMAKE_CXX_COMPILER /usr/bin/${MIR_ARM_EABI}-g++) # where to look to find dependencies in the target environment set(CMAKE_FIND_ROOT_PATH "${MIR_NDK_PATH}") #treat the chroot's includes as system includes include_directories(SYSTEM "${MIR_NDK_PATH}/usr/include" "${MIR_NDK_PATH}/usr/include/${MIR_ARM_EABI}") list(APPEND CMAKE_SYSTEM_INCLUDE_PATH "${MIR_NDK_PATH}/usr/include" "${MIR_NDK_PATH}/usr/include/${MIR_ARM_EABI}" ) # Add the chroot libraries as system libraries list(APPEND CMAKE_SYSTEM_LIBRARY_PATH "${MIR_NDK_PATH}/lib" "${MIR_NDK_PATH}/lib/${MIR_ARM_EABI}" "${MIR_NDK_PATH}/usr/lib" "${MIR_NDK_PATH}/usr/lib/${MIR_ARM_EABI}" ) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) set(CMAKE_EXECUTABLE_RUNTIME_C_FLAG "-Wl,-rpath-link,") set(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG "-Wl,-rpath-link,") set(CMAKE_INSTALL_RPATH "${MIR_NDK_PATH}/lib:${MIR_NDK_PATH}/lib/${MIR_ARM_EABI}:${MIR_NDK_PATH}/usr/lib:${MIR_NDK_PATH}/usr/lib/${MIR_ARM_EABI}") set(ENV{PKG_CONFIG_PATH} "${MIR_NDK_PATH}/usr/lib/pkgconfig:${MIR_NDK_PATH}/usr/lib/${MIR_ARM_EABI}/pkgconfig") set(ENV{PKG_CONFIG_SYSROOT_DIR} "${MIR_NDK_PATH}") #use only the cross compile system set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) mir-0.1.8+14.04.20140411/cmake/FindXKBCOMMON.cmake0000644000015301777760000000133612322054223021117 0ustar pbusernogroup00000000000000pkg_check_modules( PC_XKBCOMMON QUIET xkbcommon ) find_path(XKBCOMMON_INCLUDE_DIR xkbcommon/xkbcommon.h HINTS ${PC_XKBCOMMON_INCLUDEDIR} ${PC_XKBCOMMON_INCLUDE_DIRS}) find_library(XKBCOMMON_LIBRARY xkbcommon HINTS ${PC_XKBCOMMON_LIBDIR} ${PC_XKBCOMMON_LIBRARY_DIRS}) set(XKBCOMMON_LIBRARIES ${XKBCOMMON_LIBRARY}) set(XKBCOMMON_INCLUDE_DIRS ${XKBCOMMON_INCLUDE_DIR}) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set XKBCOMMON_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(XKBCOMMON DEFAULT_MSG XKBCOMMON_LIBRARY XKBCOMMON_INCLUDE_DIR) mark_as_advanced(XKBCOMMON_INCLUDE_DIR XKBCOMMON_LIBRARY) mir-0.1.8+14.04.20140411/cmake/FindEGL.cmake0000644000015301777760000000145312322054223020171 0ustar pbusernogroup00000000000000# - Try to find EGL # Once done this will define # EGL_FOUND - System has EGL # EGL_INCLUDE_DIRS - The EGL include directories # EGL_LIBRARIES - The libraries needed to use EGL find_package(PkgConfig) pkg_check_modules(PC_EGL QUIET egl) find_path(EGL_INCLUDE_DIR EGL/egl.h HINTS ${PC_EGL_INCLUDEDIR} ${PC_EGL_INCLUDE_DIRS}) find_library(EGL_LIBRARY EGL HINTS ${PC_EGL_LIBDIR} ${PC_EGL_LIBRARY_DIRS}) set(EGL_LIBRARIES ${EGL_LIBRARY}) set(EGL_INCLUDE_DIRS ${EGL_INCLUDE_DIR}) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set EGL_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(EGL DEFAULT_MSG EGL_LIBRARY EGL_INCLUDE_DIR) mark_as_advanced(EGL_INCLUDE_DIR EGL_LIBRARY) mir-0.1.8+14.04.20140411/cmake/FindLibHardware.cmake0000644000015301777760000000141412322054223021743 0ustar pbusernogroup00000000000000# Variables defined by this module: #message(${LIBHARDWARE_LIBRARY}) # LIBHARDWARE_FOUND # LIBHARDWARE_LIBRARIES # LIBHARDWARE_INCLUDE_DIRS INCLUDE(FindPackageHandleStandardArgs) find_package( PkgConfig ) pkg_check_modules(ANDROID_HEADERS REQUIRED android-headers) set(LIBHARDWARE_INCLUDE_DIRS ${ANDROID_HEADERS_INCLUDE_DIRS}) find_library(LIBHARDWARE_LIBRARY NAMES libhardware.so.2 libhardware.so ) set(LIBHARDWARE_LIBRARIES ${LIBHARDWARE_LIBRARY}) # handle the QUIETLY and REQUIRED arguments and set LIBHARDWARE_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(LIBHARDWARE DEFAULT_MSG LIBHARDWARE_LIBRARY) mark_as_advanced(LIBHARDWARE_INCLUDE_DIR LIBHARDWARE_LIBRARY ) mir-0.1.8+14.04.20140411/cmake/FindBoost.cmake0000644000015301777760000015377712322054223020671 0ustar pbusernogroup00000000000000# - Try to find Boost include dirs and libraries # Usage of this module as follows: # # NOTE: Take note of the Boost_ADDITIONAL_VERSIONS variable below. # Due to Boost naming conventions and limitations in CMake this find # module is NOT future safe with respect to Boost version numbers, # and may break. # # == Using Header-Only libraries from within Boost: == # # find_package( Boost 1.36.0 ) # if(Boost_FOUND) # include_directories(${Boost_INCLUDE_DIRS}) # add_executable(foo foo.cc) # endif() # # # == Using actual libraries from within Boost: == # # set(Boost_USE_STATIC_LIBS ON) # set(Boost_USE_MULTITHREADED ON) # set(Boost_USE_STATIC_RUNTIME OFF) # find_package( Boost 1.36.0 COMPONENTS date_time filesystem system ... ) # # if(Boost_FOUND) # include_directories(${Boost_INCLUDE_DIRS}) # add_executable(foo foo.cc) # target_link_libraries(foo ${Boost_LIBRARIES}) # endif() # # # The components list needs to contain actual names of boost libraries only, # such as "date_time" for "libboost_date_time". If you're using parts of # Boost that contain header files only (e.g. foreach) you do not need to # specify COMPONENTS. # # You should provide a minimum version number that should be used. If you provide this # version number and specify the REQUIRED attribute, this module will fail if it # can't find the specified or a later version. If you specify a version number this is # automatically put into the considered list of version numbers and thus doesn't need # to be specified in the Boost_ADDITIONAL_VERSIONS variable (see below). # # NOTE for Visual Studio Users: # Automatic linking is used on MSVC & Borland compilers by default when # #including things in Boost. It's important to note that setting # Boost_USE_STATIC_LIBS to OFF is NOT enough to get you dynamic linking, # should you need this feature. Automatic linking typically uses static # libraries with a few exceptions (Boost.Python is one). # # Please see the section below near Boost_LIB_DIAGNOSTIC_DEFINITIONS for # more details. Adding a TARGET_LINK_LIBRARIES() as shown in the example # above appears to cause VS to link dynamically if Boost_USE_STATIC_LIBS # gets set to OFF. It is suggested you avoid automatic linking since it # will make your application less portable. # # =========== The mess that is Boost_ADDITIONAL_VERSIONS (sorry?) ============ # # OK, so the Boost_ADDITIONAL_VERSIONS variable can be used to specify a list of # boost version numbers that should be taken into account when searching # for Boost. Unfortunately boost puts the version number into the # actual filename for the libraries, so this variable will certainly be needed # in the future when new Boost versions are released. # # Currently this module searches for the following version numbers: # 1.33, 1.33.0, 1.33.1, 1.34, 1.34.0, 1.34.1, 1.35, 1.35.0, 1.35.1, # 1.36, 1.36.0, 1.36.1, 1.37, 1.37.0, 1.38, 1.38.0, 1.39, 1.39.0, # 1.40, 1.40.0, 1.41, 1.41.0, 1.42, 1.42.0, 1.43, 1.43.0, 1.44, 1.44.0, # 1.45, 1.45.0, 1.46, 1.46.0, 1.46.1, 1.47, 1.47.0, 1.48, 1.48.0 # # NOTE: If you add a new major 1.x version in Boost_ADDITIONAL_VERSIONS you should # add both 1.x and 1.x.0 as shown above. Official Boost include directories # omit the 3rd version number from include paths if it is 0 although not all # binary Boost releases do so. # # set(Boost_ADDITIONAL_VERSIONS "1.78" "1.78.0" "1.79" "1.79.0") # # ===================================== ============= ======================== # # Variables used by this module, they can change the default behaviour and # need to be set before calling find_package: # # Boost_USE_MULTITHREADED Can be set to OFF to use the non-multithreaded # boost libraries. If not specified, defaults # to ON. # # Boost_USE_STATIC_LIBS Can be set to ON to force the use of the static # boost libraries. Defaults to OFF. # # Boost_NO_SYSTEM_PATHS Set to TRUE to suppress searching in system # paths (or other locations outside of BOOST_ROOT # or BOOST_INCLUDEDIR). Useful when specifying # BOOST_ROOT. Defaults to OFF. # [Since CMake 2.8.3] # # Boost_NO_BOOST_CMAKE Do not do a find_package call in config mode # before searching for a regular boost install. # This will avoid finding boost-cmake installs. # Defaults to OFF. # [Since CMake 2.8.6] # # Boost_USE_STATIC_RUNTIME If enabled, searches for boost libraries # linked against a static C++ standard library # ('s' ABI tag). This option should be set to # ON or OFF because the default behavior # if not specified is platform dependent # for backwards compatibility. # [Since CMake 2.8.3] # # Boost_USE_DEBUG_PYTHON If enabled, searches for boost libraries # compiled against a special debug build of # Python ('y' ABI tag). Defaults to OFF. # [Since CMake 2.8.3] # # Boost_USE_STLPORT If enabled, searches for boost libraries # compiled against the STLPort standard # library ('p' ABI tag). Defaults to OFF. # [Since CMake 2.8.3] # # Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS # If enabled, searches for boost libraries # compiled against the deprecated STLPort # "native iostreams" feature ('n' ABI tag). # Defaults to OFF. # [Since CMake 2.8.3] # # Other Variables used by this module which you may want to set. # # Boost_ADDITIONAL_VERSIONS A list of version numbers to use for searching # the boost include directory. Please see # the documentation above regarding this # annoying, but necessary variable :( # # Boost_DEBUG Set this to TRUE to enable debugging output # of FindBoost.cmake if you are having problems. # Please enable this before filing any bug # reports. # # Boost_DETAILED_FAILURE_MSG FindBoost doesn't output detailed information # about why it failed or how to fix the problem # unless this is set to TRUE or the REQUIRED # keyword is specified in find_package(). # [Since CMake 2.8.0] # # Boost_COMPILER Set this to the compiler suffix used by Boost # (e.g. "-gcc43") if FindBoost has problems finding # the proper Boost installation # # Boost_THREADAPI When building boost.thread, sometimes the name of the # library contains an additional "pthread" or "win32" # string known as the threadapi. This can happen when # compiling against pthreads on Windows or win32 threads # on Cygwin. You may specify this variable and if set # when FindBoost searches for the Boost threading library # it will first try to match the threadapi you specify. # For Example: libboost_thread_win32-mgw45-mt-1_43.a # might be found if you specified "win32" here before # falling back on libboost_thread-mgw45-mt-1_43.a. # [Since CMake 2.8.3] # # Boost_REALPATH Resolves symbolic links for discovered boost libraries # to assist with packaging. For example, instead of # Boost_SYSTEM_LIBRARY_RELEASE being resolved to # "/usr/lib/libboost_system.so" it would be # "/usr/lib/libboost_system.so.1.42.0" instead. # This does not affect linking and should not be # enabled unless the user needs this information. # [Since CMake 2.8.3] # # # These last three variables are available also as environment variables: # Also, note they are completely UPPERCASE, except Boost_DIR. # # Boost_DIR or The preferred installation prefix for searching for # BOOST_ROOT or BOOSTROOT Boost. Set this if the module has problems finding # the proper Boost installation. # # Note that Boost_DIR behaves exactly as _DIR # variables are documented to behave in find_package's # Config mode. That is, if it is set as a -D argument # to CMake, it must point to the location of the # BoostConfig.cmake or Boost-config.cmake file. If it # is set as an environment variable, it must point to # the root of the boost installation. BOOST_ROOT and # BOOSTROOT, on the other hand, will point to the root # in either case. # # To prevent falling back on the system paths, set # Boost_NO_SYSTEM_PATHS to true. # # To avoid finding boost-cmake installations, set # Boost_NO_BOOST_CMAKE to true. # # BOOST_INCLUDEDIR Set this to the include directory of Boost, if the # module has problems finding the proper Boost installation # # BOOST_LIBRARYDIR Set this to the lib directory of Boost, if the # module has problems finding the proper Boost installation # # Variables defined by this module: # # Boost_FOUND System has Boost, this means the include dir was # found, as well as all the libraries specified in # the COMPONENTS list. # # Boost_INCLUDE_DIRS Boost include directories: not cached # # Boost_INCLUDE_DIR This is almost the same as above, but this one is # cached and may be modified by advanced users # # Boost_LIBRARIES Link to these to use the Boost libraries that you # specified: not cached # # Boost_LIBRARY_DIRS The path to where the Boost library files are. # # Boost_VERSION The version number of the boost libraries that # have been found, same as in version.hpp from Boost # # Boost_LIB_VERSION The version number in filename form as # it's appended to the library filenames # # Boost_MAJOR_VERSION major version number of boost # Boost_MINOR_VERSION minor version number of boost # Boost_SUBMINOR_VERSION subminor version number of boost # # Boost_LIB_DIAGNOSTIC_DEFINITIONS [WIN32 Only] You can call # add_definitions(${Boost_LIB_DIAGNOSTIC_DEFINITIONS}) # to have diagnostic information about Boost's # automatic linking outputted during compilation time. # # For each component you specify in find_package(), the following (UPPER-CASE) # variables are set. You can use these variables if you would like to pick and # choose components for your targets instead of just using Boost_LIBRARIES. # # Boost_${COMPONENT}_FOUND True IF the Boost library "component" was found. # # Boost_${COMPONENT}_LIBRARY Contains the libraries for the specified Boost # "component" (includes debug and optimized keywords # when needed). #============================================================================= # Copyright 2006-2009 Kitware, Inc. # Copyright 2006-2008 Andreas Schneider # Copyright 2007 Wengo # Copyright 2007 Mike Jackson # Copyright 2008 Andreas Pakulat # Copyright 2008-2010 Philip Lowman # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) #------------------------------------------------------------------------------- # Before we go searching, check whether boost-cmake is avaialble, unless the # user specifically asked NOT to search for boost-cmake. # # If Boost_DIR is set, this behaves as any find_package call would. If not, # it looks at BOOST_ROOT and BOOSTROOT to find Boost. # if (NOT Boost_NO_BOOST_CMAKE) # If Boost_DIR is not set, look for BOOSTROOT and BOOST_ROOT as alternatives, # since these are more conventional for Boost. if ("$ENV{Boost_DIR}" STREQUAL "") if (NOT "$ENV{BOOST_ROOT}" STREQUAL "") set(ENV{Boost_DIR} $ENV{BOOST_ROOT}) elseif (NOT "$ENV{BOOSTROOT}" STREQUAL "") set(ENV{Boost_DIR} $ENV{BOOSTROOT}) endif() endif() # Do the same find_package call but look specifically for the CMake version. # Note that args are passed in the Boost_FIND_xxxxx variables, so there is no # need to delegate them to this find_package call. find_package(Boost QUIET NO_MODULE) # If we found boost-cmake, then we're done. Print out what we found. # Otherwise let the rest of the module try to find it. if (Boost_FOUND) message("Boost ${Boost_FIND_VERSION} found.") if (Boost_FIND_COMPONENTS) message("Found Boost components:") message(" ${Boost_FIND_COMPONENTS}") endif() return() endif() endif() #------------------------------------------------------------------------------- # FindBoost functions & macros # ############################################ # # Check the existence of the libraries. # ############################################ # This macro was taken directly from the FindQt4.cmake file that is included # with the CMake distribution. This is NOT my work. All work was done by the # original authors of the FindQt4.cmake file. Only minor modifications were # made to remove references to Qt and make this file more generally applicable # And ELSE/ENDIF pairs were removed for readability. ######################################################################### macro(_Boost_ADJUST_LIB_VARS basename) if(Boost_INCLUDE_DIR ) if(Boost_${basename}_LIBRARY_DEBUG AND Boost_${basename}_LIBRARY_RELEASE) # if the generator supports configuration types then set # optimized and debug libraries, or if the CMAKE_BUILD_TYPE has a value if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) set(Boost_${basename}_LIBRARY optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) else() # if there are no configuration types and CMAKE_BUILD_TYPE has no value # then just use the release libraries set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) endif() # FIXME: This probably should be set for both cases set(Boost_${basename}_LIBRARIES optimized ${Boost_${basename}_LIBRARY_RELEASE} debug ${Boost_${basename}_LIBRARY_DEBUG}) endif() # if only the release version was found, set the debug variable also to the release version if(Boost_${basename}_LIBRARY_RELEASE AND NOT Boost_${basename}_LIBRARY_DEBUG) set(Boost_${basename}_LIBRARY_DEBUG ${Boost_${basename}_LIBRARY_RELEASE}) set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE}) set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE}) endif() # if only the debug version was found, set the release variable also to the debug version if(Boost_${basename}_LIBRARY_DEBUG AND NOT Boost_${basename}_LIBRARY_RELEASE) set(Boost_${basename}_LIBRARY_RELEASE ${Boost_${basename}_LIBRARY_DEBUG}) set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_DEBUG}) set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_DEBUG}) endif() # If the debug & release library ends up being the same, omit the keywords if(${Boost_${basename}_LIBRARY_RELEASE} STREQUAL ${Boost_${basename}_LIBRARY_DEBUG}) set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY_RELEASE} ) set(Boost_${basename}_LIBRARIES ${Boost_${basename}_LIBRARY_RELEASE} ) endif() if(Boost_${basename}_LIBRARY) set(Boost_${basename}_LIBRARY ${Boost_${basename}_LIBRARY} CACHE FILEPATH "The Boost ${basename} library") # Remove superfluous "debug" / "optimized" keywords from # Boost_LIBRARY_DIRS foreach(_boost_my_lib ${Boost_${basename}_LIBRARY}) get_filename_component(_boost_my_lib_path "${_boost_my_lib}" PATH) list(APPEND Boost_LIBRARY_DIRS ${_boost_my_lib_path}) endforeach() list(REMOVE_DUPLICATES Boost_LIBRARY_DIRS) set(Boost_LIBRARY_DIRS ${Boost_LIBRARY_DIRS} CACHE FILEPATH "Boost library directory") set(Boost_${basename}_FOUND ON CACHE INTERNAL "Whether the Boost ${basename} library found") endif(Boost_${basename}_LIBRARY) endif(Boost_INCLUDE_DIR ) # Make variables changeble to the advanced user mark_as_advanced( Boost_${basename}_LIBRARY Boost_${basename}_LIBRARY_RELEASE Boost_${basename}_LIBRARY_DEBUG ) endmacro(_Boost_ADJUST_LIB_VARS) #------------------------------------------------------------------------------- # # Runs compiler with "-dumpversion" and parses major/minor # version with a regex. # function(_Boost_COMPILER_DUMPVERSION _OUTPUT_VERSION) exec_program(${CMAKE_CXX_COMPILER} ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion OUTPUT_VARIABLE _boost_COMPILER_VERSION ) string(REGEX REPLACE "([0-9])\\.([0-9])(\\.[0-9])?" "\\1\\2" _boost_COMPILER_VERSION ${_boost_COMPILER_VERSION}) set(${_OUTPUT_VERSION} ${_boost_COMPILER_VERSION} PARENT_SCOPE) endfunction() # # A convenience function for marking desired components # as found or not # function(_Boost_MARK_COMPONENTS_FOUND _yes_or_no) foreach(COMPONENT ${Boost_FIND_COMPONENTS}) string(TOUPPER ${COMPONENT} UPPERCOMPONENT) set(Boost_${UPPERCOMPONENT}_FOUND ${_yes_or_no} CACHE INTERNAL "Whether the Boost ${COMPONENT} library found" FORCE) endforeach() endfunction() # # Take a list of libraries with "thread" in it # and prepend duplicates with "thread_${Boost_THREADAPI}" # at the front of the list # function(_Boost_PREPEND_LIST_WITH_THREADAPI _output) set(_orig_libnames ${ARGN}) string(REPLACE "thread" "thread_${Boost_THREADAPI}" _threadapi_libnames "${_orig_libnames}") set(${_output} ${_threadapi_libnames} ${_orig_libnames} PARENT_SCOPE) endfunction() # # If a library is found, replace its cache entry with its REALPATH # function(_Boost_SWAP_WITH_REALPATH _library _docstring) if(${_library}) get_filename_component(_boost_filepathreal ${${_library}} REALPATH) unset(${_library} CACHE) set(${_library} ${_boost_filepathreal} CACHE FILEPATH "${_docstring}") endif() endfunction() function(_Boost_CHECK_SPELLING _var) if(${_var}) string(TOUPPER ${_var} _var_UC) message(FATAL_ERROR "ERROR: ${_var} is not the correct spelling. The proper spelling is ${_var_UC}.") endif() endfunction() # # End functions/macros # #------------------------------------------------------------------------------- if(NOT DEFINED Boost_USE_MULTITHREADED) set(Boost_USE_MULTITHREADED TRUE) endif() if(Boost_FIND_VERSION_EXACT) # The version may appear in a directory with or without the patch # level, even when the patch level is non-zero. set(_boost_TEST_VERSIONS "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}.${Boost_FIND_VERSION_PATCH}" "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") else(Boost_FIND_VERSION_EXACT) # The user has not requested an exact version. Among known # versions, find those that are acceptable to the user request. set(_Boost_KNOWN_VERSIONS ${Boost_ADDITIONAL_VERSIONS} "1.48.0" "1.48" "1.47.0" "1.47" "1.46.1" "1.46.0" "1.46" "1.45.0" "1.45" "1.44.0" "1.44" "1.43.0" "1.43" "1.42.0" "1.42" "1.41.0" "1.41" "1.40.0" "1.40" "1.39.0" "1.39" "1.38.0" "1.38" "1.37.0" "1.37" "1.36.1" "1.36.0" "1.36" "1.35.1" "1.35.0" "1.35" "1.34.1" "1.34.0" "1.34" "1.33.1" "1.33.0" "1.33") set(_boost_TEST_VERSIONS) if(Boost_FIND_VERSION) set(_Boost_FIND_VERSION_SHORT "${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") # Select acceptable versions. foreach(version ${_Boost_KNOWN_VERSIONS}) if(NOT "${version}" VERSION_LESS "${Boost_FIND_VERSION}") # This version is high enough. list(APPEND _boost_TEST_VERSIONS "${version}") elseif("${version}.99" VERSION_EQUAL "${_Boost_FIND_VERSION_SHORT}.99") # This version is a short-form for the requested version with # the patch level dropped. list(APPEND _boost_TEST_VERSIONS "${version}") endif() endforeach(version) else(Boost_FIND_VERSION) # Any version is acceptable. set(_boost_TEST_VERSIONS "${_Boost_KNOWN_VERSIONS}") endif(Boost_FIND_VERSION) endif(Boost_FIND_VERSION_EXACT) # The reason that we failed to find Boost. This will be set to a # user-friendly message when we fail to find some necessary piece of # Boost. set(Boost_ERROR_REASON) set( _boost_IN_CACHE TRUE) if(Boost_INCLUDE_DIR) # On versions < 1.35, remove the System library from the considered list # since it wasn't added until 1.35. if(Boost_VERSION AND Boost_FIND_COMPONENTS) if(Boost_VERSION LESS 103500) list(REMOVE_ITEM Boost_FIND_COMPONENTS system) endif() endif() foreach(COMPONENT ${Boost_FIND_COMPONENTS}) string(TOUPPER ${COMPONENT} COMPONENT) if(NOT Boost_${COMPONENT}_FOUND) set( _boost_IN_CACHE FALSE) endif(NOT Boost_${COMPONENT}_FOUND) endforeach(COMPONENT) else(Boost_INCLUDE_DIR) set( _boost_IN_CACHE FALSE) endif(Boost_INCLUDE_DIR) if(_boost_IN_CACHE) # in cache already set(Boost_FOUND TRUE) foreach(COMPONENT ${Boost_FIND_COMPONENTS}) string(TOUPPER ${COMPONENT} COMPONENT) _Boost_ADJUST_LIB_VARS( ${COMPONENT} ) set(Boost_LIBRARIES ${Boost_LIBRARIES} ${Boost_${COMPONENT}_LIBRARY}) endforeach(COMPONENT) set(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIR}) if(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") math(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000") math(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000") math(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100") endif(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "boost ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION} " "is already in the cache. To view debugging messages, please clear the cache.") endif() else(_boost_IN_CACHE) # Need to search for boost if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost not in cache") # Output some of their choices message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_USE_MULTITHREADED = ${Boost_USE_MULTITHREADED}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_USE_STATIC_LIBS = ${Boost_USE_STATIC_LIBS}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_USE_STATIC_RUNTIME = ${Boost_USE_STATIC_RUNTIME}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_ADDITIONAL_VERSIONS = ${Boost_ADDITIONAL_VERSIONS}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Boost_NO_SYSTEM_PATHS = ${Boost_NO_SYSTEM_PATHS}") endif() if(WIN32) # In windows, automatic linking is performed, so you do not have # to specify the libraries. If you are linking to a dynamic # runtime, then you can choose to link to either a static or a # dynamic Boost library, the default is to do a static link. You # can alter this for a specific library "whatever" by defining # BOOST_WHATEVER_DYN_LINK to force Boost library "whatever" to be # linked dynamically. Alternatively you can force all Boost # libraries to dynamic link by defining BOOST_ALL_DYN_LINK. # This feature can be disabled for Boost library "whatever" by # defining BOOST_WHATEVER_NO_LIB, or for all of Boost by defining # BOOST_ALL_NO_LIB. # If you want to observe which libraries are being linked against # then defining BOOST_LIB_DIAGNOSTIC will cause the auto-linking # code to emit a #pragma message each time a library is selected # for linking. set(Boost_LIB_DIAGNOSTIC_DEFINITIONS "-DBOOST_LIB_DIAGNOSTIC" CACHE STRING "Boost diagnostic define") endif(WIN32) set(_boost_INCLUDE_SEARCH_DIRS_SYSTEM C:/boost/include C:/boost "$ENV{ProgramFiles}/boost/include" "$ENV{ProgramFiles}/boost" /sw/local/include ) _Boost_CHECK_SPELLING(Boost_ROOT) _Boost_CHECK_SPELLING(Boost_LIBRARYDIR) _Boost_CHECK_SPELLING(Boost_INCLUDEDIR) # If BOOST_ROOT was defined in the environment, use it. if (NOT BOOST_ROOT AND NOT $ENV{Boost_DIR} STREQUAL "") set(BOOST_ROOT $ENV{Boost_DIR}) endif() # If BOOST_ROOT was defined in the environment, use it. if (NOT BOOST_ROOT AND NOT $ENV{BOOST_ROOT} STREQUAL "") set(BOOST_ROOT $ENV{BOOST_ROOT}) endif() # If BOOSTROOT was defined in the environment, use it. if (NOT BOOST_ROOT AND NOT $ENV{BOOSTROOT} STREQUAL "") set(BOOST_ROOT $ENV{BOOSTROOT}) endif() # If BOOST_INCLUDEDIR was defined in the environment, use it. if( NOT $ENV{BOOST_INCLUDEDIR} STREQUAL "" ) set(BOOST_INCLUDEDIR $ENV{BOOST_INCLUDEDIR}) endif() # If BOOST_LIBRARYDIR was defined in the environment, use it. if( NOT $ENV{BOOST_LIBRARYDIR} STREQUAL "" ) set(BOOST_LIBRARYDIR $ENV{BOOST_LIBRARYDIR}) endif() if( BOOST_ROOT ) file(TO_CMAKE_PATH ${BOOST_ROOT} BOOST_ROOT) endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Declared as CMake or Environmental Variables:") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " BOOST_ROOT = ${BOOST_ROOT}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " BOOST_INCLUDEDIR = ${BOOST_INCLUDEDIR}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " BOOST_LIBRARYDIR = ${BOOST_LIBRARYDIR}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_TEST_VERSIONS = ${_boost_TEST_VERSIONS}") endif() if( Boost_NO_SYSTEM_PATHS) set(_boost_FIND_OPTIONS NO_CMAKE_SYSTEM_PATH) else() set(_boost_INCLUDE_SEARCH_DIRS ${_boost_INCLUDE_SEARCH_DIRS_SYSTEM}) endif() if( BOOST_ROOT ) set(_boost_INCLUDE_SEARCH_DIRS ${BOOST_ROOT}/include ${BOOST_ROOT} ${_boost_INCLUDE_SEARCH_DIRS}) endif() # prepend BOOST_INCLUDEDIR to search path if specified if( BOOST_INCLUDEDIR ) file(TO_CMAKE_PATH ${BOOST_INCLUDEDIR} BOOST_INCLUDEDIR) set(_boost_INCLUDE_SEARCH_DIRS ${BOOST_INCLUDEDIR} ${_boost_INCLUDE_SEARCH_DIRS}) endif( BOOST_INCLUDEDIR ) # ------------------------------------------------------------------------ # Search for Boost include DIR # ------------------------------------------------------------------------ # Try to find Boost by stepping backwards through the Boost versions # we know about. if( NOT Boost_INCLUDE_DIR ) # Build a list of path suffixes for each version. set(_boost_PATH_SUFFIXES) foreach(_boost_VER ${_boost_TEST_VERSIONS}) # Add in a path suffix, based on the required version, ideally # we could read this from version.hpp, but for that to work we'd # need to know the include dir already set(_boost_BOOSTIFIED_VERSION) # Transform 1.35 => 1_35 and 1.36.0 => 1_36_0 if(_boost_VER MATCHES "[0-9]+\\.[0-9]+\\.[0-9]+") string(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1_\\2_\\3" _boost_BOOSTIFIED_VERSION ${_boost_VER}) elseif(_boost_VER MATCHES "[0-9]+\\.[0-9]+") string(REGEX REPLACE "([0-9]+)\\.([0-9]+)" "\\1_\\2" _boost_BOOSTIFIED_VERSION ${_boost_VER}) endif() list(APPEND _boost_PATH_SUFFIXES "boost-${_boost_BOOSTIFIED_VERSION}") list(APPEND _boost_PATH_SUFFIXES "boost_${_boost_BOOSTIFIED_VERSION}") endforeach(_boost_VER) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Include debugging info:") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " _boost_INCLUDE_SEARCH_DIRS = ${_boost_INCLUDE_SEARCH_DIRS}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " " _boost_PATH_SUFFIXES = ${_boost_PATH_SUFFIXES}") endif() # Look for a standard boost header file. find_path(Boost_INCLUDE_DIR NAMES boost/config.hpp HINTS ${_boost_INCLUDE_SEARCH_DIRS} PATH_SUFFIXES ${_boost_PATH_SUFFIXES} ${_boost_FIND_OPTIONS} ) endif( NOT Boost_INCLUDE_DIR ) # ------------------------------------------------------------------------ # Extract version information from version.hpp # ------------------------------------------------------------------------ if(Boost_INCLUDE_DIR) # Extract Boost_VERSION and Boost_LIB_VERSION from version.hpp # Read the whole file: # set(BOOST_VERSION 0) set(BOOST_LIB_VERSION "") file(READ "${Boost_INCLUDE_DIR}/boost/version.hpp" _boost_VERSION_HPP_CONTENTS) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "location of version.hpp: ${Boost_INCLUDE_DIR}/boost/version.hpp") endif() string(REGEX REPLACE ".*#define BOOST_VERSION ([0-9]+).*" "\\1" Boost_VERSION "${_boost_VERSION_HPP_CONTENTS}") string(REGEX REPLACE ".*#define BOOST_LIB_VERSION \"([0-9_]+)\".*" "\\1" Boost_LIB_VERSION "${_boost_VERSION_HPP_CONTENTS}") set(Boost_LIB_VERSION ${Boost_LIB_VERSION} CACHE INTERNAL "The library version string for boost libraries") set(Boost_VERSION ${Boost_VERSION} CACHE INTERNAL "The version number for boost libraries") if(NOT "${Boost_VERSION}" STREQUAL "0") math(EXPR Boost_MAJOR_VERSION "${Boost_VERSION} / 100000") math(EXPR Boost_MINOR_VERSION "${Boost_VERSION} / 100 % 1000") math(EXPR Boost_SUBMINOR_VERSION "${Boost_VERSION} % 100") set(Boost_ERROR_REASON "${Boost_ERROR_REASON}Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}\nBoost include path: ${Boost_INCLUDE_DIR}") endif(NOT "${Boost_VERSION}" STREQUAL "0") if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "version.hpp reveals boost " "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") endif() else(Boost_INCLUDE_DIR) set(Boost_ERROR_REASON "${Boost_ERROR_REASON}Unable to find the Boost header files. Please set BOOST_ROOT to the root directory containing Boost or BOOST_INCLUDEDIR to the directory containing Boost's headers.") endif(Boost_INCLUDE_DIR) # ------------------------------------------------------------------------ # Suffix initialization and compiler suffix detection. # ------------------------------------------------------------------------ # Setting some more suffixes for the library set(Boost_LIB_PREFIX "") if ( WIN32 AND Boost_USE_STATIC_LIBS AND NOT CYGWIN) set(Boost_LIB_PREFIX "lib") endif() if (Boost_COMPILER) set(_boost_COMPILER ${Boost_COMPILER}) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "using user-specified Boost_COMPILER = ${_boost_COMPILER}") endif() else(Boost_COMPILER) # Attempt to guess the compiler suffix # NOTE: this is not perfect yet, if you experience any issues # please report them and use the Boost_COMPILER variable # to work around the problems. if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" OR "${CMAKE_CXX_COMPILER}" MATCHES "icl" OR "${CMAKE_CXX_COMPILER}" MATCHES "icpc") if(WIN32) set (_boost_COMPILER "-iw") else() set (_boost_COMPILER "-il") endif() elseif (MSVC11) set(_boost_COMPILER "-vc110") elseif (MSVC10) set(_boost_COMPILER "-vc100") elseif (MSVC90) set(_boost_COMPILER "-vc90") elseif (MSVC80) set(_boost_COMPILER "-vc80") elseif (MSVC71) set(_boost_COMPILER "-vc71") elseif (MSVC70) # Good luck! set(_boost_COMPILER "-vc7") # yes, this is correct elseif (MSVC60) # Good luck! set(_boost_COMPILER "-vc6") # yes, this is correct elseif (BORLAND) set(_boost_COMPILER "-bcb") elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "SunPro") set(_boost_COMPILER "-sw") elseif (MINGW) if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34) set(_boost_COMPILER "-mgw") # no GCC version encoding prior to 1.34 else() _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION) set(_boost_COMPILER "-mgw${_boost_COMPILER_VERSION}") endif() elseif (UNIX) if (CMAKE_COMPILER_IS_GNUCXX) if(${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION} VERSION_LESS 1.34) set(_boost_COMPILER "-gcc") # no GCC version encoding prior to 1.34 else() _Boost_COMPILER_DUMPVERSION(_boost_COMPILER_VERSION) # Determine which version of GCC we have. if(APPLE) if(Boost_MINOR_VERSION) if(${Boost_MINOR_VERSION} GREATER 35) # In Boost 1.36.0 and newer, the mangled compiler name used # on Mac OS X/Darwin is "xgcc". set(_boost_COMPILER "-xgcc${_boost_COMPILER_VERSION}") else(${Boost_MINOR_VERSION} GREATER 35) # In Boost <= 1.35.0, there is no mangled compiler name for # the Mac OS X/Darwin version of GCC. set(_boost_COMPILER "") endif(${Boost_MINOR_VERSION} GREATER 35) else(Boost_MINOR_VERSION) # We don't know the Boost version, so assume it's # pre-1.36.0. set(_boost_COMPILER "") endif(Boost_MINOR_VERSION) else() set(_boost_COMPILER "-gcc${_boost_COMPILER_VERSION}") endif() endif() endif (CMAKE_COMPILER_IS_GNUCXX) endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "guessed _boost_COMPILER = ${_boost_COMPILER}") endif() endif(Boost_COMPILER) set (_boost_MULTITHREADED "-mt") if( NOT Boost_USE_MULTITHREADED ) set (_boost_MULTITHREADED "") endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_MULTITHREADED = ${_boost_MULTITHREADED}") endif() #====================== # Systematically build up the Boost ABI tag # http://boost.org/doc/libs/1_41_0/more/getting_started/windows.html#library-naming set( _boost_RELEASE_ABI_TAG "-") set( _boost_DEBUG_ABI_TAG "-") # Key Use this library when: # s linking statically to the C++ standard library and # compiler runtime support libraries. if(Boost_USE_STATIC_RUNTIME) set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}s") set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}s") endif() # g using debug versions of the standard and runtime # support libraries if(WIN32) if(MSVC OR "${CMAKE_CXX_COMPILER}" MATCHES "icl" OR "${CMAKE_CXX_COMPILER}" MATCHES "icpc") set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}g") endif() endif() # y using special debug build of python if(Boost_USE_DEBUG_PYTHON) set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}y") endif() # d using a debug version of your code set(_boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}d") # p using the STLport standard library rather than the # default one supplied with your compiler if(Boost_USE_STLPORT) set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}p") set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}p") endif() # n using the STLport deprecated "native iostreams" feature if(Boost_USE_STLPORT_DEPRECATED_NATIVE_IOSTREAMS) set( _boost_RELEASE_ABI_TAG "${_boost_RELEASE_ABI_TAG}n") set( _boost_DEBUG_ABI_TAG "${_boost_DEBUG_ABI_TAG}n") endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_RELEASE_ABI_TAG = ${_boost_RELEASE_ABI_TAG}") message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_DEBUG_ABI_TAG = ${_boost_DEBUG_ABI_TAG}") endif() # ------------------------------------------------------------------------ # Begin finding boost libraries # ------------------------------------------------------------------------ if(BOOST_ROOT) set(_boost_LIBRARY_SEARCH_DIRS_ALWAYS ${BOOST_ROOT}/lib ${BOOST_ROOT}/stage/lib) endif() set(_boost_LIBRARY_SEARCH_DIRS_ALWAYS ${_boost_LIBRARY_SEARCH_DIRS_ALWAYS} ${Boost_INCLUDE_DIR}/lib ${Boost_INCLUDE_DIR}/../lib ${Boost_INCLUDE_DIR}/stage/lib ) set(_boost_LIBRARY_SEARCH_DIRS_SYSTEM C:/boost/lib C:/boost "$ENV{ProgramFiles}/boost/boost_${Boost_MAJOR_VERSION}_${Boost_MINOR_VERSION}_${Boost_SUBMINOR_VERSION}/lib" "$ENV{ProgramFiles}/boost/boost_${Boost_MAJOR_VERSION}_${Boost_MINOR_VERSION}/lib" "$ENV{ProgramFiles}/boost/lib" "$ENV{ProgramFiles}/boost" /sw/local/lib ) set(_boost_LIBRARY_SEARCH_DIRS ${_boost_LIBRARY_SEARCH_DIRS_ALWAYS}) if( Boost_NO_SYSTEM_PATHS ) set(_boost_FIND_OPTIONS NO_CMAKE_SYSTEM_PATH) else() list(APPEND _boost_LIBRARY_SEARCH_DIRS ${_boost_LIBRARY_SEARCH_DIRS_SYSTEM}) endif() # prepend BOOST_LIBRARYDIR to search path if specified if( BOOST_LIBRARYDIR ) file(TO_CMAKE_PATH ${BOOST_LIBRARYDIR} BOOST_LIBRARYDIR) set(_boost_LIBRARY_SEARCH_DIRS ${BOOST_LIBRARYDIR} ${_boost_LIBRARY_SEARCH_DIRS}) endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "_boost_LIBRARY_SEARCH_DIRS = ${_boost_LIBRARY_SEARCH_DIRS}") endif() # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES if( Boost_USE_STATIC_LIBS ) set( _boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) if(WIN32) set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) else() set(CMAKE_FIND_LIBRARY_SUFFIXES .a ) endif() endif() # We want to use the tag inline below without risking double dashes if(_boost_RELEASE_ABI_TAG) if(${_boost_RELEASE_ABI_TAG} STREQUAL "-") set(_boost_RELEASE_ABI_TAG "") endif() endif() if(_boost_DEBUG_ABI_TAG) if(${_boost_DEBUG_ABI_TAG} STREQUAL "-") set(_boost_DEBUG_ABI_TAG "") endif() endif() # The previous behavior of FindBoost when Boost_USE_STATIC_LIBS was enabled # on WIN32 was to: # 1. Search for static libs compiled against a SHARED C++ standard runtime library (use if found) # 2. Search for static libs compiled against a STATIC C++ standard runtime library (use if found) # We maintain this behavior since changing it could break people's builds. # To disable the ambiguous behavior, the user need only # set Boost_USE_STATIC_RUNTIME either ON or OFF. set(_boost_STATIC_RUNTIME_WORKAROUND false) if(WIN32 AND Boost_USE_STATIC_LIBS) if(NOT DEFINED Boost_USE_STATIC_RUNTIME) set(_boost_STATIC_RUNTIME_WORKAROUND true) endif() endif() foreach(COMPONENT ${Boost_FIND_COMPONENTS}) string(TOUPPER ${COMPONENT} UPPERCOMPONENT) set( Boost_${UPPERCOMPONENT}_LIBRARY "Boost_${UPPERCOMPONENT}_LIBRARY-NOTFOUND" ) set( Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE-NOTFOUND" ) set( Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG-NOTFOUND") set( _boost_docstring_release "Boost ${COMPONENT} library (release)") set( _boost_docstring_debug "Boost ${COMPONENT} library (debug)") # # Find RELEASE libraries # set(_boost_RELEASE_NAMES ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_ABI_TAG} ${Boost_LIB_PREFIX}boost_${COMPONENT} ) if(_boost_STATIC_RUNTIME_WORKAROUND) set(_boost_RELEASE_STATIC_ABI_TAG "-s${_boost_RELEASE_ABI_TAG}") list(APPEND _boost_RELEASE_NAMES ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_RELEASE_STATIC_ABI_TAG} ) endif() if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_RELEASE_NAMES ${_boost_RELEASE_NAMES}) endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: ${_boost_RELEASE_NAMES}") endif() find_library(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE NAMES ${_boost_RELEASE_NAMES} PATHS ${_boost_LIBRARY_SEARCH_DIRS} ${_boost_FIND_OPTIONS} DOC "${_boost_docstring_release}" ) # # Find DEBUG libraries # set(_boost_DEBUG_NAMES ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_ABI_TAG} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED} ${Boost_LIB_PREFIX}boost_${COMPONENT} ) if(_boost_STATIC_RUNTIME_WORKAROUND) set(_boost_DEBUG_STATIC_ABI_TAG "-s${_boost_DEBUG_ABI_TAG}") list(APPEND _boost_DEBUG_NAMES ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_COMPILER}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG}-${Boost_LIB_VERSION} ${Boost_LIB_PREFIX}boost_${COMPONENT}${_boost_MULTITHREADED}${_boost_DEBUG_STATIC_ABI_TAG} ) endif() if(Boost_THREADAPI AND ${COMPONENT} STREQUAL "thread") _Boost_PREPEND_LIST_WITH_THREADAPI(_boost_DEBUG_NAMES ${_boost_DEBUG_NAMES}) endif() if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] " "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: ${_boost_DEBUG_NAMES}") endif() find_library(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG NAMES ${_boost_DEBUG_NAMES} HINTS ${_boost_LIBRARY_SEARCH_DIRS} ${_boost_FIND_OPTIONS} DOC "${_boost_docstring_debug}" ) if(Boost_REALPATH) _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_RELEASE "${_boost_docstring_release}") _Boost_SWAP_WITH_REALPATH(Boost_${UPPERCOMPONENT}_LIBRARY_DEBUG "${_boost_docstring_debug}" ) endif() _Boost_ADJUST_LIB_VARS(${UPPERCOMPONENT}) endforeach(COMPONENT) # Restore the original find library ordering if( Boost_USE_STATIC_LIBS ) set(CMAKE_FIND_LIBRARY_SUFFIXES ${_boost_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) endif() # ------------------------------------------------------------------------ # End finding boost libraries # ------------------------------------------------------------------------ set(Boost_INCLUDE_DIRS ${Boost_INCLUDE_DIR} ) set(Boost_FOUND FALSE) if(Boost_INCLUDE_DIR) set( Boost_FOUND TRUE ) # Check the version of Boost against the requested version. if (Boost_FIND_VERSION AND NOT Boost_FIND_VERSION_MINOR) message(SEND_ERROR "When requesting a specific version of Boost, you must provide at least the major and minor version numbers, e.g., 1.34") endif (Boost_FIND_VERSION AND NOT Boost_FIND_VERSION_MINOR) if(Boost_MAJOR_VERSION LESS "${Boost_FIND_VERSION_MAJOR}" ) set( Boost_FOUND FALSE ) set(_Boost_VERSION_AGE "old") elseif(Boost_MAJOR_VERSION EQUAL "${Boost_FIND_VERSION_MAJOR}" ) if(Boost_MINOR_VERSION LESS "${Boost_FIND_VERSION_MINOR}" ) set( Boost_FOUND FALSE ) set(_Boost_VERSION_AGE "old") elseif(Boost_MINOR_VERSION EQUAL "${Boost_FIND_VERSION_MINOR}" ) if( Boost_FIND_VERSION_PATCH AND Boost_SUBMINOR_VERSION LESS "${Boost_FIND_VERSION_PATCH}" ) set( Boost_FOUND FALSE ) set(_Boost_VERSION_AGE "old") endif( Boost_FIND_VERSION_PATCH AND Boost_SUBMINOR_VERSION LESS "${Boost_FIND_VERSION_PATCH}" ) endif( Boost_MINOR_VERSION LESS "${Boost_FIND_VERSION_MINOR}" ) endif( Boost_MAJOR_VERSION LESS "${Boost_FIND_VERSION_MAJOR}" ) if (NOT Boost_FOUND) _Boost_MARK_COMPONENTS_FOUND(OFF) endif() if (Boost_FOUND AND Boost_FIND_VERSION_EXACT) # If the user requested an exact version of Boost, check # that. We already know that the Boost version we have is >= the # requested version. set(_Boost_VERSION_AGE "new") # If the user didn't specify a patchlevel, it's 0. if (NOT Boost_FIND_VERSION_PATCH) set(Boost_FIND_VERSION_PATCH 0) endif (NOT Boost_FIND_VERSION_PATCH) # We'll set Boost_FOUND true again if we have an exact version match. set(Boost_FOUND FALSE) _Boost_MARK_COMPONENTS_FOUND(OFF) if(Boost_MAJOR_VERSION EQUAL "${Boost_FIND_VERSION_MAJOR}" ) if(Boost_MINOR_VERSION EQUAL "${Boost_FIND_VERSION_MINOR}" ) if(Boost_SUBMINOR_VERSION EQUAL "${Boost_FIND_VERSION_PATCH}" ) set( Boost_FOUND TRUE ) _Boost_MARK_COMPONENTS_FOUND(ON) endif(Boost_SUBMINOR_VERSION EQUAL "${Boost_FIND_VERSION_PATCH}" ) endif( Boost_MINOR_VERSION EQUAL "${Boost_FIND_VERSION_MINOR}" ) endif( Boost_MAJOR_VERSION EQUAL "${Boost_FIND_VERSION_MAJOR}" ) endif (Boost_FOUND AND Boost_FIND_VERSION_EXACT) if(NOT Boost_FOUND) # State that we found a version of Boost that is too new or too old. set(Boost_ERROR_REASON "${Boost_ERROR_REASON}\nDetected version of Boost is too ${_Boost_VERSION_AGE}. Requested version was ${Boost_FIND_VERSION_MAJOR}.${Boost_FIND_VERSION_MINOR}") if (Boost_FIND_VERSION_PATCH) set(Boost_ERROR_REASON "${Boost_ERROR_REASON}.${Boost_FIND_VERSION_PATCH}") endif (Boost_FIND_VERSION_PATCH) if (NOT Boost_FIND_VERSION_EXACT) set(Boost_ERROR_REASON "${Boost_ERROR_REASON} (or newer)") endif (NOT Boost_FIND_VERSION_EXACT) set(Boost_ERROR_REASON "${Boost_ERROR_REASON}.") endif (NOT Boost_FOUND) # Always check for missing components set(_boost_CHECKED_COMPONENT FALSE) set(_Boost_MISSING_COMPONENTS "") foreach(COMPONENT ${Boost_FIND_COMPONENTS}) string(TOUPPER ${COMPONENT} COMPONENT) set(_boost_CHECKED_COMPONENT TRUE) if(NOT Boost_${COMPONENT}_FOUND) string(TOLOWER ${COMPONENT} COMPONENT) list(APPEND _Boost_MISSING_COMPONENTS ${COMPONENT}) set( Boost_FOUND FALSE) endif() endforeach(COMPONENT) if(Boost_DEBUG) message(STATUS "[ ${CMAKE_CURRENT_LIST_FILE}:${CMAKE_CURRENT_LIST_LINE} ] Boost_FOUND = ${Boost_FOUND}") endif() if (_Boost_MISSING_COMPONENTS) # We were unable to find some libraries, so generate a sensible # error message that lists the libraries we were unable to find. set(Boost_ERROR_REASON "${Boost_ERROR_REASON}\nThe following Boost libraries could not be found:\n") foreach(COMPONENT ${_Boost_MISSING_COMPONENTS}) set(Boost_ERROR_REASON "${Boost_ERROR_REASON} boost_${COMPONENT}\n") endforeach(COMPONENT) list(LENGTH Boost_FIND_COMPONENTS Boost_NUM_COMPONENTS_WANTED) list(LENGTH _Boost_MISSING_COMPONENTS Boost_NUM_MISSING_COMPONENTS) if (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) set(Boost_ERROR_REASON "${Boost_ERROR_REASON}No Boost libraries were found. You may need to set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") else (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) set(Boost_ERROR_REASON "${Boost_ERROR_REASON}Some (but not all) of the required Boost libraries were found. You may need to install these additional Boost libraries. Alternatively, set BOOST_LIBRARYDIR to the directory containing Boost libraries or BOOST_ROOT to the location of Boost.") endif (${Boost_NUM_COMPONENTS_WANTED} EQUAL ${Boost_NUM_MISSING_COMPONENTS}) endif (_Boost_MISSING_COMPONENTS) if( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT ) # Compatibility Code for backwards compatibility with CMake # 2.4's FindBoost module. # Look for the boost library path. # Note that the user may not have installed any libraries # so it is quite possible the Boost_LIBRARY_PATH may not exist. set(_boost_LIB_DIR ${Boost_INCLUDE_DIR}) if("${_boost_LIB_DIR}" MATCHES "boost-[0-9]+") get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) endif() if("${_boost_LIB_DIR}" MATCHES "/include$") # Strip off the trailing "/include" in the path. get_filename_component(_boost_LIB_DIR ${_boost_LIB_DIR} PATH) endif() if(EXISTS "${_boost_LIB_DIR}/lib") set(_boost_LIB_DIR ${_boost_LIB_DIR}/lib) else() if(EXISTS "${_boost_LIB_DIR}/stage/lib") set(_boost_LIB_DIR ${_boost_LIB_DIR}/stage/lib) else() set(_boost_LIB_DIR "") endif() endif() if(_boost_LIB_DIR AND EXISTS "${_boost_LIB_DIR}") set(Boost_LIBRARY_DIRS ${_boost_LIB_DIR} CACHE FILEPATH "Boost library directory") endif() endif( NOT Boost_LIBRARY_DIRS AND NOT _boost_CHECKED_COMPONENT ) else(Boost_INCLUDE_DIR) set( Boost_FOUND FALSE) endif(Boost_INCLUDE_DIR) if(Boost_FOUND) if(NOT Boost_FIND_QUIETLY) message(STATUS "Boost version: ${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") if(Boost_FIND_COMPONENTS) message(STATUS "Found the following Boost libraries:") endif() endif(NOT Boost_FIND_QUIETLY) foreach( COMPONENT ${Boost_FIND_COMPONENTS} ) string( TOUPPER ${COMPONENT} UPPERCOMPONENT ) if( Boost_${UPPERCOMPONENT}_FOUND ) if(NOT Boost_FIND_QUIETLY) message (STATUS " ${COMPONENT}") endif(NOT Boost_FIND_QUIETLY) set(Boost_LIBRARIES ${Boost_LIBRARIES} ${Boost_${UPPERCOMPONENT}_LIBRARY}) if(${UPPERCOMPONENT} STREQUAL "THREAD" AND UNIX) find_package (Threads) set(Boost_LIBRARIES ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) endif(${UPPERCOMPONENT} STREQUAL "THREAD" AND UNIX) endif( Boost_${UPPERCOMPONENT}_FOUND ) endforeach(COMPONENT) else() if(Boost_FIND_REQUIRED) message(SEND_ERROR "Unable to find the requested Boost libraries.\n${Boost_ERROR_REASON}") else() if(NOT Boost_FIND_QUIETLY) # we opt not to automatically output Boost_ERROR_REASON here as # it could be quite lengthy and somewhat imposing in it's requests # Since Boost is not always a required dependency we'll leave this # up to the end-user. if(Boost_DEBUG OR Boost_DETAILED_FAILURE_MSG) message(STATUS "Could NOT find Boost\n${Boost_ERROR_REASON}") else() message(STATUS "Could NOT find Boost") endif() endif() endif(Boost_FIND_REQUIRED) endif() # show the Boost_INCLUDE_DIRS AND Boost_LIBRARIES variables only in the advanced view mark_as_advanced(Boost_INCLUDE_DIR Boost_INCLUDE_DIRS Boost_LIBRARY_DIRS ) endif(_boost_IN_CACHE) mir-0.1.8+14.04.20140411/cmake/FindGFlags.cmake0000644000015301777760000000064112322054223020723 0ustar pbusernogroup00000000000000if (GFlags_INCLUDE_DIR) # Already in cache, be silent set(GFlags_FIND_QUIETLY TRUE) endif () find_path(GFlags_INCLUDE_DIR gflags/gflags.h) find_library(GFlags_LIBRARY libgflags.so HINTS /usr/lib/arm-linux-gnueabihf/) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GFlags DEFAULT_MSG GFlags_LIBRARY GFlags_INCLUDE_DIR) mark_as_advanced(GFlags_LIBRARY GFlags_INCLUDE_DIR) mir-0.1.8+14.04.20140411/cmake/CMakeLists.txt0000644000015301777760000000002712322054223020513 0ustar pbusernogroup00000000000000add_subdirectory (src) mir-0.1.8+14.04.20140411/cmake/src/0000755000015301777760000000000012322054703016546 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/cmake/src/mir/0000755000015301777760000000000012322054703017335 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/cmake/src/mir/mir_test_memory_error.cpp0000644000015301777760000000015512322054223024466 0ustar pbusernogroup00000000000000#include int main() { auto x = new int{5}; delete x; std::cout << *x << std::endl; } mir-0.1.8+14.04.20140411/cmake/src/mir/fail_on_success.sh0000755000015301777760000000007512322054247023040 0ustar pbusernogroup00000000000000#!/bin/sh $@ if [ $? -eq 0 ] ; then exit 1; fi exit 0; mir-0.1.8+14.04.20140411/cmake/src/mir/mir_discover_gtest_tests.cpp0000644000015301777760000002152012322054247025161 0ustar pbusernogroup00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; namespace { enum DescriptorType { test_case, test_suite }; DescriptorType check_line_for_test_case_or_suite(const string& line) { if (line.find(" ") == 0) return test_case; return test_suite; } int get_output_width() { const int fd_out{fileno(stdout)}; const int max_width{65535}; int width{max_width}; if (isatty(fd_out)) { struct winsize w; if (ioctl(fd_out, TIOCGWINSZ, &w) != -1) width = w.ws_col; } return width; } string ordinary_cmd_line_pattern() { static const char* pattern = "ADD_TEST(\"%s.%s\" \"%s\" \"--gtest_filter=%s\")\n"; return pattern; } vector valgrind_cmd_patterns(vector const& suppressions) { vector patterns{ "valgrind", "--error-exitcode=1", "--trace-children=yes" }; for (auto const& sup : suppressions) patterns.push_back(std::string("--suppressions=") + sup); vector gtest_patterns{ "%s", "--gtest_death_test_use_fork", "--gtest_filter=%s" }; patterns.insert(patterns.end(), gtest_patterns.begin(), gtest_patterns.end()); return patterns; } string memcheck_cmd_line_pattern(vector const& suppressions) { stringstream ss; ss << "ADD_TEST(\"memcheck(%s.%s)\""; for (auto& s : valgrind_cmd_patterns(suppressions)) ss << " \"" << s << "\""; ss << ")" << endl; return ss.str(); } std::string elide_string_left(const std::string& in, std::size_t max_size) { assert(max_size >= 3); if (in.size() <= max_size) return in; std::string result(in.begin() + (in.size() - max_size), in.end()); *(result.begin()) = '.'; *(result.begin()+1) = '.'; *(result.begin()+2) = '.'; return result; } struct Configuration { Configuration() : executable(NULL), enable_memcheck(false), memcheck_test(false) { } const char* executable; bool enable_memcheck; bool memcheck_test; std::vector> extra_environment; std::vector suppressions; }; bool parse_configuration_from_cmd_line(int argc, char** argv, Configuration& config) { static struct option long_options[] = { {"executable", required_argument, 0, 0}, {"enable-memcheck", no_argument, 0, 0}, {"memcheck-test", no_argument, 0, 0}, {"add-environment", required_argument, 0, 0}, {"suppressions", required_argument, 0, 0}, {0, 0, 0, 0} }; while(1) { int option_index = -1; const char *optname = ""; int c = getopt_long( argc, argv, "e:m", long_options, &option_index); /* Detect the end of the options. */ if (c == -1) break; /* Detect an error in the passed options */ if (c == ':' || c == '?') return false; /* Check if we got a long option and get its name */ if (option_index != -1) optname = long_options[option_index].name; /* Handle options */ if (c == 'e' || !strcmp(optname, "executable")) config.executable = optarg; else if (c == 'm' || !strcmp(optname, "enable-memcheck")) config.enable_memcheck = true; else if (!strcmp(optname, "memcheck-test")) config.memcheck_test = true; else if (!strcmp(optname, "add-environment")) { char const* equal_pos = strchr(optarg, '='); if (!equal_pos) return false; config.extra_environment.push_back(std::make_pair(std::string(optarg, equal_pos - optarg), std::string(equal_pos + 1))); } else if (!strcmp(optname, "suppressions")) { config.suppressions.push_back(std::string(optarg)); } } return true; } string prepareMemcheckTestLine(string const& exe, vector const& suppressions) { stringstream ss; ss << "ADD_TEST(\"memcheck-test\" \"sh\" \"-c\" \""; for (auto& s : valgrind_cmd_patterns(suppressions)) ss << s << " "; ss << "; if [ $? != 0 ]; then exit 0; else exit 1; fi\")"; char cmd_line[1024] = ""; snprintf(cmd_line, sizeof(cmd_line), ss.str().c_str(), exe.c_str(), "*" ); return cmd_line; } void emitMemcheckTest(string const& exe, vector const& suppressions) { ifstream CTestTestfile("CTestTestfile.cmake", ifstream::in); bool need_memcheck_test = true; string line; string memcheckTestLine = prepareMemcheckTestLine(exe, suppressions); if (CTestTestfile.is_open()) { while (CTestTestfile.good()) { getline(CTestTestfile, line); if (line == memcheckTestLine) need_memcheck_test = false; } CTestTestfile.close(); } if (need_memcheck_test) { ofstream CTestTestfileW ("CTestTestfile.cmake", ofstream::app | ofstream::out); if (CTestTestfileW.is_open()) { CTestTestfileW << memcheckTestLine << endl; CTestTestfileW.close(); } } } } bool is_death_test(string const& test) { // precondition: test will match Foo.* // assumption: death tests will match FooDeathTest.* bool death_test = false; if (test.size() > strlen("DeathTest.*")) death_test = test.substr(test.size() - strlen("DeathTest.*"), strlen("DeathTest")) == "DeathTest"; return death_test; } int main (int argc, char **argv) { int output_width = get_output_width(); cin >> noskipws; Configuration config; if (!parse_configuration_from_cmd_line(argc, argv, config) || config.executable == NULL) { cout << "Usage: PATH_TO_TEST_BINARY --gtest_list_tests | " << basename(argv[0]) << " --executable PATH_TO_TEST_BINARY [--enable-memcheck]" << std::endl << " or " << std::endl << basename(argv[0]) << " --executable PATH_TO_MEMCHECK_BINARY --memcheck-test" << std::endl; return 1; } if (config.memcheck_test) { emitMemcheckTest(config.executable, config.suppressions); return 0; } set tests; string line; string current_test; while (getline (cin, line)) { switch(check_line_for_test_case_or_suite(line)) { case test_case: tests.insert(current_test + "*"); break; case test_suite: current_test = line; break; } } ofstream testfilecmake; char* executable_copy = strdup(config.executable); string test_suite(basename(executable_copy)); free(executable_copy); testfilecmake.open(string(test_suite + "_test.cmake").c_str(), ios::out | ios::trunc); if (testfilecmake.is_open()) { for (auto& env_pair : config.extra_environment) { testfilecmake << "SET( ENV{"<c_str()); if (testfilecmake.good()) { testfilecmake << cmd_line; } } testfilecmake.close(); } ifstream CTestTestfile("CTestTestfile.cmake", ifstream::in); bool need_include = true; line.clear(); string includeLine = string ("INCLUDE (") + test_suite + string ("_test.cmake)"); if (CTestTestfile.is_open()) { while (CTestTestfile.good()) { getline(CTestTestfile, line); if (line == includeLine) need_include = false; } CTestTestfile.close(); } if (need_include) { ofstream CTestTestfileW ("CTestTestfile.cmake", ofstream::app | ofstream::out); if (CTestTestfileW.is_open()) { CTestTestfileW << includeLine << endl; CTestTestfileW.close(); } } return 0; } mir-0.1.8+14.04.20140411/cmake/src/mir/CMakeLists.txt0000644000015301777760000000114212322054247022076 0ustar pbusernogroup00000000000000add_executable( mir_discover_gtest_tests EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/mir_discover_gtest_tests.cpp) set_target_properties( mir_discover_gtest_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/mir_gtest ) add_executable( mir_test_memory_error EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/mir_test_memory_error.cpp) set_target_properties( mir_test_memory_error PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/mir_gtest ) file(INSTALL ${CMAKE_CURRENT_SOURCE_DIR}/fail_on_success.sh DESTINATION ${CMAKE_BINARY_DIR}/mir_gtest USE_SOURCE_PERMISSIONS ) mir-0.1.8+14.04.20140411/cmake/src/CMakeLists.txt0000644000015301777760000000002712322054223021302 0ustar pbusernogroup00000000000000add_subdirectory (mir) mir-0.1.8+14.04.20140411/cmake/FindGLM.cmake0000644000015301777760000000046712322054223020205 0ustar pbusernogroup00000000000000# - Try to find GLM # Once done this will define # GLM_FOUND - System has GLM # GLM_INCLUDE_DIRS - The GLM include directories find_path(GLM_INCLUDE_DIR glm/glm.hpp) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GLM DEFAULT_MSG GLM_INCLUDE_DIR) mark_as_advanced(GLM_INCLUDE_DIR) mir-0.1.8+14.04.20140411/cmake/FindGLog.cmake0000644000015301777760000000061412322054223020410 0ustar pbusernogroup00000000000000if (GLog_INCLUDE_DIR) # Already in cache, be silent set(GLog_FIND_QUIETLY TRUE) endif () find_path(GLog_INCLUDE_DIR glog/logging.h) find_library(GLog_LIBRARY libglog.so HINTS /usr/lib/arm-linux-gnueabihf/) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GLog DEFAULT_MSG GLog_LIBRARY GLog_INCLUDE_DIR) mark_as_advanced(GLog_LIBRARY GLog_INCLUDE_DIR) mir-0.1.8+14.04.20140411/examples/0000755000015301777760000000000012322054703016515 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/examples/progressbar.c0000644000015301777760000002021512322054223021207 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Daniel van Vugt */ #include "mir_toolkit/mir_client_library.h" #include #include #include #include #define __USE_BSD 1 /* for usleep() */ #include /* sleep() */ #include #define BYTES_PER_PIXEL(f) ((f) == mir_pixel_format_bgr_888 ? 3 : 4) #define MIN(a, b) ((a) <= (b) ? (a) : (b)) typedef struct { uint8_t r, g, b, a; } Color; static const Color blue = {0, 0, 255, 255}; static const Color white = {255, 255, 255, 255}; static const Color *const foreground = &white; static const Color *const background = &blue; static volatile sig_atomic_t running = 1; static void shutdown(int signum) { if (running) { running = 0; printf("Signal %d received. Good night.\n", signum); } } static void blend(uint32_t *dest, uint32_t src, int alpha_shift) { uint8_t *d = (uint8_t*)dest; uint8_t *s = (uint8_t*)&src; uint32_t src_alpha = (uint32_t)(src >> alpha_shift) & 0xff; uint32_t dest_alpha = 0xff - src_alpha; int i; for (i = 0; i < 4; i++) { d[i] = (uint8_t) ( ( ((uint32_t)d[i] * dest_alpha) + ((uint32_t)s[i] * src_alpha) ) >> 8 /* Close enough, and faster than /255 */ ); } *dest |= (0xff << alpha_shift); /* Restore alpha 1.0 in the destination */ } static void put_pixels(void *where, int count, MirPixelFormat format, const Color *color) { uint32_t pixel = 0; int alpha_shift = -1; int n; /* * We are blending in software, so can pretend that * mir_pixel_format_abgr_8888 == mir_pixel_format_xbgr_8888 * mir_pixel_format_argb_8888 == mir_pixel_format_xrgb_8888 */ switch (format) { case mir_pixel_format_abgr_8888: case mir_pixel_format_xbgr_8888: alpha_shift = 24; pixel = (uint32_t)color->a << 24 | (uint32_t)color->b << 16 | (uint32_t)color->g << 8 | (uint32_t)color->r; break; case mir_pixel_format_argb_8888: case mir_pixel_format_xrgb_8888: alpha_shift = 24; pixel = (uint32_t)color->a << 24 | (uint32_t)color->r << 16 | (uint32_t)color->g << 8 | (uint32_t)color->b; break; case mir_pixel_format_bgr_888: for (n = 0; n < count; n++) { uint8_t *p = (uint8_t*)where + n * 3; p[0] = color->b; p[1] = color->g; p[2] = color->r; } count = 0; break; default: count = 0; break; } if (alpha_shift >= 0 && color->a < 255) { for (n = 0; n < count; n++) blend((uint32_t*)where + n, pixel, alpha_shift); } else { for (n = 0; n < count; n++) ((uint32_t*)where)[n] = pixel; } } static void clear_region(const MirGraphicsRegion *region, const Color *color) { int y; char *row = region->vaddr; for (y = 0; y < region->height; y++) { put_pixels(row, region->width, region->pixel_format, color); row += region->stride; } } static void draw_box(const MirGraphicsRegion *region, int x, int y, int size, const Color *color) { if (x >= 0 && y >= 0 && x+size < region->width && y+size < region->height) { int j; char *row = region->vaddr + (y * region->stride) + (x * BYTES_PER_PIXEL(region->pixel_format)); for (j = 0; j < size; j++) { put_pixels(row, size, region->pixel_format, color); row += region->stride; } } } static void copy_region(const MirGraphicsRegion *dest, const MirGraphicsRegion *src) { int height = MIN(src->height, dest->height); int width = MIN(src->width, dest->width); int y; const char *srcrow = src->vaddr; char *destrow = dest->vaddr; int copy = width * BYTES_PER_PIXEL(dest->pixel_format); for (y = 0; y < height; y++) { memcpy(destrow, srcrow, copy); srcrow += src->stride; destrow += dest->stride; } } static void redraw(MirSurface *surface, const MirGraphicsRegion *canvas) { MirGraphicsRegion backbuffer; mir_surface_get_graphics_region(surface, &backbuffer); clear_region(&backbuffer, background); copy_region(&backbuffer, canvas); mir_surface_swap_buffers_sync(surface); } int main(int argc, char *argv[]) { MirConnection *conn; MirSurfaceParameters parm; MirSurface *surf; MirGraphicsRegion canvas; unsigned int f; unsigned int const pf_size = 32; MirPixelFormat formats[pf_size]; unsigned int valid_formats; int sleep_usec = 50000; if (argc > 1) { int rate; if (sscanf(argv[1], "%d", &rate) == 1 && rate > 0) { sleep_usec = 1000000 / rate; } else { fprintf(stderr, "Usage: %s [repeat rate in Hz]\n" "Default repeat rate is %d\n", argv[0], 1000000 / sleep_usec); return 1; } } conn = mir_connect_sync(NULL, argv[0]); if (!mir_connection_is_valid(conn)) { fprintf(stderr, "Could not connect to a display server.\n"); return 1; } parm.buffer_usage = mir_buffer_usage_software; parm.output_id = mir_display_output_id_invalid; mir_connection_get_available_surface_formats(conn, formats, pf_size, &valid_formats); parm.pixel_format = mir_pixel_format_invalid; for (f = 0; f < valid_formats; f++) { if (BYTES_PER_PIXEL(formats[f]) == 4) { parm.pixel_format = formats[f]; break; } } if (parm.pixel_format == mir_pixel_format_invalid) { fprintf(stderr, "Could not find a fast 32-bit pixel format\n"); mir_connection_release(conn); return 1; } parm.name = "Progress Bars"; parm.width = 500; parm.height = 500; surf = mir_connection_create_surface_sync(conn, &parm); if (surf != NULL) { canvas.width = parm.width; canvas.height = parm.height; canvas.stride = canvas.width * BYTES_PER_PIXEL(parm.pixel_format); canvas.pixel_format = parm.pixel_format; canvas.vaddr = (char*)malloc(canvas.stride * canvas.height); if (canvas.vaddr != NULL) { int t = 0; signal(SIGINT, shutdown); signal(SIGTERM, shutdown); while (running) { static const int width = 8; static const int space = 1; const int grid = width + 2 * space; const int row = parm.width / grid; const int square = row * row; const int x = (t % row) * grid + space; const int y = (t / row) * grid + space; if (t % square == 0) clear_region(&canvas, background); t = (t + 1) % square; draw_box(&canvas, x, y, width, foreground); redraw(surf, &canvas); usleep(sleep_usec); } free(canvas.vaddr); } else { fprintf(stderr, "Failed to malloc canvas\n"); } mir_surface_release_sync(surf); } else { fprintf(stderr, "mir_connection_create_surface_sync failed\n"); } mir_connection_release(conn); return 0; } mir-0.1.8+14.04.20140411/examples/demo_input_filter.cpp0000644000015301777760000000615112322054223022731 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/run_mir.h" #include "mir/abnormal_exit.h" #include "mir/input/composite_event_filter.h" #include "server_configuration.h" #include #include namespace mi = mir::input; namespace { struct PrintingEventFilter : public mi::EventFilter { void print_motion_event(MirMotionEvent const& ev) { std::cout << "Motion Event time=" << ev.event_time << " pointer_count=" << ev.pointer_count << std::endl; for (size_t i = 0; i < ev.pointer_count; ++i) { std::cout << " " << " id=" << ev.pointer_coordinates[i].id << " pos=(" << ev.pointer_coordinates[i].x << ", " << ev.pointer_coordinates[i].y << ")" << std::endl; } std::cout << "----------------" << std::endl << std::endl; } bool handle(MirEvent const& ev) override { // TODO: Enhance printing if (ev.type == mir_event_type_key) { std::cout << "Handling key event (time, scancode, keycode): " << ev.key.event_time << " " << ev.key.scan_code << " " << ev.key.key_code << std::endl; } else if (ev.type == mir_event_type_motion) { print_motion_event(ev.motion); } return false; } }; struct DemoServerConfiguration : public mir::examples::ServerConfiguration { DemoServerConfiguration(int argc, char const* argv[]) : ServerConfiguration(argc, argv), event_filter(std::make_shared()) { } std::shared_ptr the_composite_event_filter() override { auto composite_filter = ServerConfiguration::the_composite_event_filter(); composite_filter->prepend(event_filter); return composite_filter; } std::shared_ptr const event_filter; }; } #include void my_write_to_log(int /*prio*/, char const* buffer) { printf("%s\n", buffer); } int main(int argc, char const* argv[]) try { DemoServerConfiguration config(argc, argv); mir::write_to_log = my_write_to_log; mir::run_mir(config, [](mir::DisplayServer&) {/* empty init */}); return 0; } catch (mir::AbnormalExit const& error) { std::cerr << error.what() << std::endl; return 1; } catch (std::exception const& error) { std::cerr << "ERROR: " << boost::diagnostic_information(error) << std::endl; return 1; } mir-0.1.8+14.04.20140411/examples/image_renderer.h0000644000015301777760000000257712322054223021646 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #ifndef MIR_TOOLS_IMAGE_RENDERER_H_ #define MIR_TOOLS_IMAGE_RENDERER_H_ #include "mir/geometry/size.h" #include #include namespace mir { namespace tools { class ImageRenderer { public: ImageRenderer(const uint8_t* pixel_data, mir::geometry::Size size, uint32_t bytes_per_pixel); void render(); private: class Resources { public: ~Resources(); void setup(); GLuint vertex_shader; GLuint fragment_shader; GLuint program; GLuint position_attr_loc; GLuint vertex_attribs_vbo; GLuint texture; }; Resources resources; }; } } #endif /* MIR_TOOLS_IMAGE_RENDERER_H_ */ mir-0.1.8+14.04.20140411/examples/scroll.cpp0000644000015301777760000001126612322054223020522 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "graphics.h" #include #include #include #include #include #include #include #include #include #include static char const *socket_file = NULL; static EGLDisplay disp; void create_and_run_scroll_surface(MirConnection *connection) { MirSurface *surface = 0; MirPixelFormat pixel_format; unsigned int valid_formats; mir_connection_get_available_surface_formats(connection, &pixel_format, 1, &valid_formats); MirSurfaceParameters const request_params = {__PRETTY_FUNCTION__, 640, 480, pixel_format, mir_buffer_usage_hardware, mir_display_output_id_invalid}; surface = mir_connection_create_surface_sync(connection, &request_params); assert(surface != NULL); assert(mir_surface_is_valid(surface)); assert(strcmp(mir_surface_get_error_message(surface), "") == 0); puts("Surface created"); /* egl setup */ int major, minor, n, rc; EGLContext context; EGLSurface egl_surface; EGLConfig egl_config; EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLNativeWindowType native_window = (EGLNativeWindowType) mir_surface_get_egl_native_window(surface); assert(native_window != (EGLNativeWindowType)NULL); rc = eglInitialize(disp, &major, &minor); assert(rc == EGL_TRUE); assert(major == 1); assert(minor == 4); rc = eglChooseConfig(disp, attribs, &egl_config, 1, &n); assert(rc == EGL_TRUE); assert(n == 1); egl_surface = eglCreateWindowSurface(disp, egl_config, native_window, NULL); assert(egl_surface != EGL_NO_SURFACE); context = eglCreateContext(disp, egl_config, EGL_NO_CONTEXT, context_attribs); assert(context != EGL_NO_CONTEXT); rc = eglMakeCurrent(disp, egl_surface, egl_surface, context); assert(rc == EGL_TRUE); mir::draw::glAnimationBasic gl_animation; gl_animation.init_gl(); for(;;) { gl_animation.render_gl(); rc = eglSwapBuffers(disp, egl_surface); assert(rc == EGL_TRUE); gl_animation.step(); } eglDestroySurface(disp, egl_surface); eglDestroyContext(disp, context); mir_surface_release_sync(surface); puts("Surface released"); } int main(int argc, char* argv[]) { MirConnection *connection = 0; unsigned num_windows = 1; int arg; opterr = 0; while ((arg = getopt (argc, argv, "hm:w:")) != -1) { switch (arg) { case 'm': socket_file = optarg; break; case 'w': num_windows = atoi(optarg); break; case '?': case 'h': default: puts(argv[0]); puts("Usage:"); puts(" -m "); puts(" -w :"); puts(" -h: this help text"); return -1; } } puts("Starting"); connection = mir_connect_sync(socket_file, __PRETTY_FUNCTION__); assert(connection != NULL); assert(mir_connection_is_valid(connection)); assert(strcmp(mir_connection_get_error_message(connection), "") == 0); puts("Connected"); EGLNativeDisplayType native_display = (EGLNativeDisplayType) mir_connection_get_egl_native_display(connection); disp = eglGetDisplay(native_display); assert(disp != EGL_NO_DISPLAY); if (num_windows == 1) { create_and_run_scroll_surface(connection); } else { for (unsigned i = 0; i < num_windows; i++) std::thread(create_and_run_scroll_surface, connection).detach(); for(;;) {} } eglTerminate(disp); mir_connection_release(connection); puts("Connection released"); return 0; } mir-0.1.8+14.04.20140411/examples/graphics_utils.cpp0000644000015301777760000001005112322054223022233 0ustar pbusernogroup00000000000000/* * 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 */ #include "graphics.h" #include "mir_image.h" #include #include namespace md=mir::draw; static const GLchar *vtex_shader_src = { "attribute vec4 vPosition;\n" "attribute vec4 uvCoord;\n" "varying vec2 texcoord;\n" "uniform float slide;\n" "void main() {\n" " gl_Position = vPosition;\n" " texcoord = uvCoord.xy + vec2(slide);\n" "}\n" }; static const GLchar *frag_shader_src = { "precision mediump float;\n" "uniform sampler2D tex;\n" "varying vec2 texcoord;\n" "void main() {\n" " gl_FragColor = texture2D(tex, texcoord);\n" "}\n" }; const GLint num_vertex = 4; GLfloat vertex_data[] = { -0.5f, -0.5f, 0.0f, 1.0f, -0.5f, 0.5f, 0.0f, 1.0f, 0.5f, -0.5f, 0.0f, 1.0f, 0.5f, 0.5f, 0.0f, 1.0f, }; GLfloat uv_data[] = { 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; md::glAnimationBasic::glAnimationBasic() : program(-1), vPositionAttr(-1), uvCoord(-1), slideUniform(-1), slide(0.0) { } int md::glAnimationBasic::texture_width() { return mir_image.width; } int md::glAnimationBasic::texture_height() { return mir_image.height; } void md::glAnimationBasic::init_gl() { glClearColor(0.0, 1.0, 0.0, 1.0); GLuint vtex_shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vtex_shader, 1, &vtex_shader_src, 0); glCompileShader(vtex_shader); GLuint frag_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(frag_shader, 1, &frag_shader_src, 0); glCompileShader(frag_shader); program = glCreateProgram(); glAttachShader(program, vtex_shader); glAttachShader(program, frag_shader); glLinkProgram(program); vPositionAttr = glGetAttribLocation(program, "vPosition"); glVertexAttribPointer(vPositionAttr, 4, GL_FLOAT, GL_FALSE, 0, vertex_data); uvCoord = glGetAttribLocation(program, "uvCoord"); glVertexAttribPointer(uvCoord, 4, GL_FLOAT, GL_FALSE, 0, uv_data); GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, mir_image.width, mir_image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, mir_image.pixel_data); slideUniform = glGetUniformLocation(program, "slide"); } void md::glAnimationBasic::render_gl() { glUseProgram(program); glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ); glUniform1fv(slideUniform, 1, &slide); glActiveTexture(GL_TEXTURE0); glEnableVertexAttribArray(vPositionAttr); glEnableVertexAttribArray(uvCoord); glDrawArrays(GL_TRIANGLE_STRIP, 0, num_vertex); glDisableVertexAttribArray(uvCoord); glDisableVertexAttribArray(vPositionAttr); } void md::glAnimationBasic::step() { typedef std::chrono::high_resolution_clock hr_clock; typedef std::chrono::duration seconds_double; auto elapsed = hr_clock::now().time_since_epoch(); auto elapsed_seconds = std::chrono::duration_cast(elapsed).count(); double i; /* slide increases 0.01 per 1/60s */ slide = modf(0.6 * elapsed_seconds, &i); } mir-0.1.8+14.04.20140411/examples/render_to_fb.cpp0000644000015301777760000000372212322054223021652 0ustar pbusernogroup00000000000000/* * 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 */ #include "graphics.h" #include "mir/default_server_configuration.h" #include "mir/graphics/display.h" #include "mir/graphics/display_buffer.h" #include "mir/report_exception.h" #include #include namespace mg=mir::graphics; namespace mo=mir::options; namespace { volatile std::sig_atomic_t running = true; void signal_handler(int /*signum*/) { running = false; } } int main(int argc, char const** argv) try { /* 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); mir::DefaultServerConfiguration conf{argc, argv}; auto display = conf.the_display(); mir::draw::glAnimationBasic gl_animation; display->for_each_display_buffer([&](mg::DisplayBuffer& buffer) { buffer.make_current(); gl_animation.init_gl(); }); while (running) { display->for_each_display_buffer([&](mg::DisplayBuffer& buffer) { buffer.make_current(); gl_animation.render_gl(); buffer.post_update(); }); gl_animation.step(); } return 0; } catch (...) { mir::report_exception(std::cerr); return 1; } mir-0.1.8+14.04.20140411/examples/pixel_format_selector.cpp0000644000015301777760000000403012322054223023604 0ustar pbusernogroup00000000000000/* * 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 */ #include "pixel_format_selector.h" #include "mir/graphics/display_configuration.h" #include "mir/graphics/pixel_format_utils.h" #include #include namespace mir { namespace examples { PixelFormatSelector::PixelFormatSelector(std::shared_ptr const& base_policy, bool with_alpha) : base_policy{base_policy}, with_alpha{with_alpha} {} void PixelFormatSelector::apply_to(graphics::DisplayConfiguration & conf) { base_policy->apply_to(conf); conf.for_each_output( [&](graphics::UserDisplayConfigurationOutput& conf_output) { if (!conf_output.connected || !conf_output.used) return; auto const& pos = find_if(conf_output.pixel_formats.begin(), conf_output.pixel_formats.end(), [&](MirPixelFormat format) -> bool { return graphics::contains_alpha(format) == with_alpha; } ); // keep the default settings if nothing was found if (pos == conf_output.pixel_formats.end()) return; conf_output.current_format = *pos; }); } } } mir-0.1.8+14.04.20140411/examples/basic_server_configuration.h0000644000015301777760000000230312322054223024257 0ustar pbusernogroup00000000000000/* * 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_EXAMPLES_BASIC_SERVER_CONFIGURATION_H_ #define MIR_EXAMPLES_BASIC_SERVER_CONFIGURATION_H_ #include "server_configuration.h" namespace mir { namespace examples { /** * \brief BasicServerConfiguration extends ServerConfiguration with the ability to launch a client application */ class BasicServerConfiguration : public ServerConfiguration { public: BasicServerConfiguration(int argc, char const** argv); void launch_client(); }; } } #endif /* MIR_EXAMPLES_BASIC_SERVER_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/examples/buffer_render_target.cpp0000644000015301777760000000607012322054223023377 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "buffer_render_target.h" #include "mir/graphics/buffer.h" #include #include namespace geom = mir::geometry; namespace mg = mir::graphics; namespace mt = mir::tools; mt::BufferRenderTarget::BufferRenderTarget(mg::Buffer& buffer) : buffer(buffer), old_fbo(), old_viewport() { /* * With the new lazy buffer allocation method, we may be executing inside * the compositor's GL context. So be careful to save and restore what * we change... */ glGetIntegerv(GL_VIEWPORT, old_viewport); glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo); resources.setup(buffer); } mt::BufferRenderTarget::~BufferRenderTarget() { glFinish(); glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]); } void mt::BufferRenderTarget::make_current() { geom::Size buf_size = buffer.size(); glBindFramebuffer(GL_FRAMEBUFFER, resources.fbo); glViewport(0, 0, buf_size.width.as_uint32_t(), buf_size.height.as_uint32_t()); } mt::BufferRenderTarget::Resources::~Resources() { if (color_tex != 0) glDeleteTextures(1, &color_tex); if (depth_rbo != 0) glDeleteRenderbuffers(1, &depth_rbo); if (fbo != 0) glDeleteFramebuffers(1, &fbo); } void mt::BufferRenderTarget::Resources::setup(mg::Buffer& buffer) { geom::Size buf_size = buffer.size(); if (fbo == 0) { glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); /* Set up color buffer... */ glGenTextures(1, &color_tex); glBindTexture(GL_TEXTURE_2D, color_tex); buffer.bind_to_texture(); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_tex, 0); /* and depth buffer */ glGenRenderbuffers(1, &depth_rbo); glBindRenderbuffer(GL_RENDERBUFFER, depth_rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, buf_size.width.as_uint32_t(), buf_size.height.as_uint32_t()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_rbo); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) throw std::runtime_error("Failed to create FBO for GBM buffer"); } } mir-0.1.8+14.04.20140411/examples/render_overlays.cpp0000644000015301777760000001326512322054247022436 0ustar pbusernogroup00000000000000/* * 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/default_server_configuration.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/graphic_buffer_allocator.h" #include "mir/graphics/buffer_properties.h" #include "mir/report_exception.h" #include "testdraw/graphics_region_factory.h" #include "testdraw/patterns.h" #include #include #include namespace mg=mir::graphics; namespace ml=mir::logging; namespace mo=mir::options; namespace geom=mir::geometry; namespace { volatile std::sig_atomic_t running = true; void signal_handler(int /*signum*/) { running = false; } 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)), region_factory(mir::test::draw::create_graphics_region_factory()), color{color}, last_tick{std::chrono::high_resolution_clock::now()} { } void update_green_channel() { char green_value = (color >> 8) & 0xFF; green_value += compute_update_value(); color &= 0xFFFF00FF; color |= (green_value << 8); mir::test::draw::DrawPatternSolid fill{color}; fill.draw(*region_factory->graphic_region_from_handle(*back_buffer->native_buffer_handle())); 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; std::shared_ptr region_factory; unsigned int color; std::chrono::time_point last_tick; }; class DemoRenderable : public mg::Renderable { public: DemoRenderable(std::shared_ptr const& client, geom::Rectangle rect) : client(client), position(rect) { } std::shared_ptr buffer(void const*) const override { return client->last_rendered(); } bool alpha_enabled() const override { return false; } 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; } bool visible() const override { return true; } int buffers_ready_for_compositor() const override { return 1; } private: std::shared_ptr const client; geom::Rectangle const position; glm::mat4 const trans; }; } int main(int argc, char const** argv) try { /* 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); mir::DefaultServerConfiguration conf{argc, argv}; auto platform = conf.the_graphics_platform(); auto display = platform->create_display( conf.the_display_configuration_policy(), conf.the_gl_config()); auto buffer_allocator = platform->create_buffer_allocator(conf.the_buffer_initializer()); mg::BufferProperties buffer_properties{ geom::Size{512, 512}, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware }; auto client1 = std::make_shared(*buffer_allocator, buffer_properties,0xFF0000FF); auto client2 = std::make_shared(*buffer_allocator, buffer_properties,0xFFFFFF00); std::list> renderlist { std::make_shared(client1, geom::Rectangle{{0,0} , {512, 512}}), std::make_shared(client2, geom::Rectangle{{80,80} , {592,592}}) }; while (running) { display->for_each_display_buffer([&](mg::DisplayBuffer& buffer) { buffer.make_current(); client1->update_green_channel(); client2->update_green_channel(); auto render_fn = [](mg::Renderable const&) {}; buffer.render_and_post_update(renderlist, render_fn); }); } return 0; } catch (...) { mir::report_exception(std::cerr); return 1; } mir-0.1.8+14.04.20140411/examples/basic_server_configuration.cpp0000644000015301777760000000342412322054223024617 0ustar pbusernogroup00000000000000/* * 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 */ #include "basic_server_configuration.h" #include "mir/options/default_configuration.h" #include "mir/abnormal_exit.h" #include "mir/frontend/connector.h" #include "mir/options/option.h" #include namespace { char const* const launch_child_opt = "launch-client"; } namespace mir { namespace examples { BasicServerConfiguration::BasicServerConfiguration(int argc, char const** argv) : ServerConfiguration([argc, argv] { auto result = std::make_shared(argc, argv); namespace po = boost::program_options; result->add_options() (launch_child_opt, po::value(), "system() command to launch client"); return result; }()) { } void BasicServerConfiguration::launch_client() { if (the_options()->is_set(launch_child_opt)) { char buffer[128] = {0}; sprintf(buffer, "fd://%d", the_connector()->client_socket_fd()); setenv("MIR_SOCKET", buffer, 1); auto ignore = std::system((the_options()->get(launch_child_opt) + "&").c_str()); (void)ignore; } } } } mir-0.1.8+14.04.20140411/examples/egltriangle.c0000644000015301777760000001006312322054223021153 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Daniel van Vugt */ #include "eglapp.h" #include #include #include static GLuint load_shader(const char *src, GLenum type) { GLuint shader = glCreateShader(type); if (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; } } return shader; } /* Colours from http://design.ubuntu.com/brand/colour-palette */ #define MID_AUBERGINE 0.368627451f, 0.152941176f, 0.31372549f #define ORANGE 0.866666667f, 0.282352941f, 0.141414141f int main(int argc, char *argv[]) { const char vshadersrc[] = "attribute vec4 vPosition; \n" "uniform float theta; \n" "void main() \n" "{ \n" " float c = cos(theta); \n" " float s = sin(theta); \n" " mat2 m; \n" " m[0] = vec2(c, s); \n" " m[1] = vec2(-s, c); \n" " vec2 p = m * vec2(vPosition); \n" " gl_Position = vec4(p, 0.0, 1.0); \n" "} \n"; const char fshadersrc[] = "precision mediump float; \n" "uniform vec4 col; \n" "void main() \n" "{ \n" " gl_FragColor = col; \n" "} \n"; const GLfloat vertices[] = { 0.0f, 1.0f, -1.0f,-0.866f, 1.0f,-0.866f, }; GLuint vshader, fshader, prog; GLint linked, col, vpos, theta; unsigned int width = 512, height = 512; GLfloat angle = 0.0f; if (!mir_eglapp_init(argc, argv, &width, &height)) return 1; vshader = load_shader(vshadersrc, GL_VERTEX_SHADER); assert(vshader); fshader = load_shader(fshadersrc, GL_FRAGMENT_SHADER); assert(fshader); prog = glCreateProgram(); assert(prog); glAttachShader(prog, vshader); glAttachShader(prog, fshader); glLinkProgram(prog); glGetProgramiv(prog, GL_LINK_STATUS, &linked); if (!linked) { GLchar log[1024]; glGetProgramInfoLog(prog, sizeof log - 1, NULL, log); log[sizeof log - 1] = '\0'; printf("Link failed: %s\n", log); return 2; } glClearColor(MID_AUBERGINE, mir_eglapp_background_opacity); glViewport(0, 0, width, height); glUseProgram(prog); vpos = glGetAttribLocation(prog, "vPosition"); col = glGetUniformLocation(prog, "col"); theta = glGetUniformLocation(prog, "theta"); glUniform4f(col, ORANGE, 1.0f); glVertexAttribPointer(vpos, 2, GL_FLOAT, GL_FALSE, 0, vertices); glEnableVertexAttribArray(0); while (mir_eglapp_running()) { glClear(GL_COLOR_BUFFER_BIT); glUniform1f(theta, angle); angle += 0.02f; glDrawArrays(GL_TRIANGLES, 0, 3); mir_eglapp_swap_buffers(); } mir_eglapp_shutdown(); return 0; } mir-0.1.8+14.04.20140411/examples/server_configuration.cpp0000644000015301777760000001366012322054223023461 0ustar pbusernogroup00000000000000/* * 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/graphics/display_configuration_policy.h" #include "mir/graphics/display_configuration.h" #include "mir/input/composite_event_filter.h" #include "mir/main_loop.h" #include #include #include namespace me = mir::examples; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace { char const* const display_config_opt = "display-config"; char const* const clone_opt_val = "clone"; char const* const sidebyside_opt_val = "sidebyside"; char const* const single_opt_val = "single"; class SideBySideDisplayConfigurationPolicy : public mg::DisplayConfigurationPolicy { public: void apply_to(mg::DisplayConfiguration& conf) { size_t const preferred_mode_index{0}; int max_x = 0; std::unordered_map available_outputs_for_card; conf.for_each_card( [&](mg::DisplayConfigurationCard const& card) { available_outputs_for_card[card.id] = card.max_simultaneous_outputs; }); conf.for_each_output( [&](mg::UserDisplayConfigurationOutput& conf_output) { if (conf_output.connected && conf_output.modes.size() > 0 && available_outputs_for_card[conf_output.card_id] > 0) { conf_output.used = true; conf_output.top_left = geom::Point{max_x, 0}; conf_output.current_mode_index = preferred_mode_index; conf_output.power_mode = mir_power_mode_on; conf_output.orientation = mir_orientation_normal; max_x += conf_output.modes[preferred_mode_index].size.width.as_int(); --available_outputs_for_card[conf_output.card_id]; } else { conf_output.used = false; conf_output.power_mode = mir_power_mode_off; } }); } }; class SingleDisplayConfigurationPolicy : public mg::DisplayConfigurationPolicy { public: void apply_to(mg::DisplayConfiguration& conf) { size_t const preferred_mode_index{0}; bool done{false}; conf.for_each_output( [&](mg::UserDisplayConfigurationOutput& conf_output) { if (!done && conf_output.connected && conf_output.modes.size() > 0) { conf_output.used = true; conf_output.top_left = geom::Point{0, 0}; conf_output.current_mode_index = preferred_mode_index; conf_output.power_mode = mir_power_mode_on; done = true; } else { conf_output.used = false; conf_output.power_mode = mir_power_mode_off; } }); } }; class QuitFilter : public mir::input::EventFilter { public: QuitFilter(std::shared_ptr const& main_loop) : main_loop{main_loop} { } bool handle(MirEvent const& event) override { if (event.type == mir_event_type_key && event.key.action == mir_key_action_down && (event.key.modifiers & mir_key_modifier_alt) && (event.key.modifiers & mir_key_modifier_ctrl) && event.key.scan_code == KEY_BACKSPACE) { main_loop->stop(); return true; } return false; } private: std::shared_ptr const main_loop; }; } me::ServerConfiguration::ServerConfiguration(std::shared_ptr const& configuration_options) : DefaultServerConfiguration(configuration_options) { namespace po = boost::program_options; configuration_options->add_options() (display_config_opt, po::value()->default_value(clone_opt_val), "Display configuration [{clone,sidebyside,single}]"); } 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(display_config_opt); if (display_config == sidebyside_opt_val) return std::make_shared(); else if (display_config == single_opt_val) return std::make_shared(); else return DefaultServerConfiguration::the_display_configuration_policy(); }); } std::shared_ptr me::ServerConfiguration::the_composite_event_filter() { if (!quit_filter) quit_filter = std::make_shared(the_main_loop()); auto composite_filter = DefaultServerConfiguration::the_composite_event_filter(); composite_filter->append(quit_filter); return composite_filter; } mir-0.1.8+14.04.20140411/examples/flicker.c0000644000015301777760000001201612322054223020275 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include #include #include #include #include #include #include #include static char const *socket_file = NULL; static void render_pattern(MirGraphicsRegion *region, uint32_t pf) { char *row = region->vaddr; int j; for (j = 0; j < region->height; j++) { int i; uint32_t *pixel = (uint32_t*)row; for (i = 0; i < region->width; i++) { pixel[i] = pf; } row += region->stride; } } static MirPixelFormat find_8888_format(MirPixelFormat *formats, unsigned int num_formats) { MirPixelFormat pf = mir_pixel_format_invalid; for (unsigned int i = 0; i < num_formats; ++i) { MirPixelFormat cur_pf = formats[i]; if (cur_pf == mir_pixel_format_abgr_8888 || cur_pf == mir_pixel_format_xbgr_8888 || cur_pf == mir_pixel_format_argb_8888 || cur_pf == mir_pixel_format_xrgb_8888) { pf = cur_pf; break; } } assert(pf != mir_pixel_format_invalid); return pf; } static void fill_pattern(uint32_t pattern[2], MirPixelFormat pf) { switch(pf) { case mir_pixel_format_abgr_8888: case mir_pixel_format_xbgr_8888: pattern[0] = 0xFF00FF00; pattern[1] = 0xFFFF0000; break; case mir_pixel_format_argb_8888: case mir_pixel_format_xrgb_8888: pattern[0] = 0xFF00FF00; pattern[1] = 0xFF0000FF; break; default: assert(0 && "Invalid pixel format"); }; } int main(int argc, char* argv[]) { MirConnection *connection = 0; MirSurface *surface = 0; int swapinterval = 1; int arg; opterr = 0; while ((arg = getopt (argc, argv, "qhnm:")) != -1) { switch (arg) { case 'm': socket_file = optarg; break; case 'n': swapinterval = 0; break; case 'q': { FILE *unused = freopen("/dev/null", "a", stdout); (void)unused; break; } case '?': case 'h': default: printf("Usage: %s []\n" " -m Connect to a specific Mir socket\n" " -h Show this help text\n" " -n Don't sync to vblank\n" " -q Quiet mode (no messages output)\n" , argv[0]); return -1; } } puts("Starting"); connection = mir_connect_sync(socket_file, __PRETTY_FUNCTION__); assert(connection != NULL); assert(mir_connection_is_valid(connection)); assert(strcmp(mir_connection_get_error_message(connection), "") == 0); puts("Connected"); unsigned int const num_formats = 32; MirPixelFormat pixel_formats[num_formats]; unsigned int valid_formats; mir_connection_get_available_surface_formats(connection, pixel_formats, num_formats, &valid_formats); MirPixelFormat pixel_format = find_8888_format(pixel_formats, valid_formats); MirSurfaceParameters const request_params = {__PRETTY_FUNCTION__, 640, 480, pixel_format, mir_buffer_usage_software, mir_display_output_id_invalid}; surface = mir_connection_create_surface_sync(connection, &request_params); assert(surface != NULL); assert(mir_surface_is_valid(surface)); assert(strcmp(mir_surface_get_error_message(surface), "") == 0); puts("Surface created"); mir_surface_set_swapinterval(surface, swapinterval); uint32_t pattern[2] = {0}; fill_pattern(pattern, pixel_format); time_t lasttime = 0; int lastcount = 0; int count = 0; MirGraphicsRegion graphics_region; int i=0; while (1) { mir_surface_get_graphics_region( surface, &graphics_region); i++; render_pattern(&graphics_region, pattern[i & 1]); mir_surface_swap_buffers_sync(surface); count++; time_t now = time(NULL); if (now != lasttime) { printf("%d FPS\n", count - lastcount); lasttime = now; lastcount = count; } } mir_surface_release_sync(surface); puts("Surface released"); mir_connection_release(connection); puts("Connection released"); return 0; } mir-0.1.8+14.04.20140411/examples/demo-shell/0000755000015301777760000000000012322054703020546 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/examples/demo-shell/demo_renderer.cpp0000644000015301777760000002531512322054247024075 0ustar pbusernogroup00000000000000/* * 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 */ #include "demo_renderer.h" #include #include using namespace mir; using namespace mir::examples; namespace { 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() { struct Texel { GLubyte r, g, b, a; }; int const width = 256; Texel image[width][width]; int cx = width / 2; int cy = width / 2; int radius_sqr = cx * cx; for (int y = 0; y < width; ++y) { for (int x = 0; x < width; ++x) { GLubyte lum = 128; GLubyte alpha = 255; // 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) alpha = 0; } // Set gradient if (y < cy) { float brighten = (1.0f - (static_cast(y) / cy)); if (x < cx) brighten *= std::sin(x * M_PI / width); lum += (255 - lum) * brighten; } image[y][x] = {lum, lum, lum, alpha}; } } 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, width, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); glGenerateMipmap(GL_TEXTURE_2D); // Antialiasing please return corner; } } // namespace DemoRenderer::DemoRenderer(geometry::Rectangle const& display_area) : GLRenderer(display_area) { shadow_corner_tex = generate_shadow_corner_texture(0.4f); titlebar_corner_tex = generate_frame_corner_texture(); } DemoRenderer::~DemoRenderer() { glDeleteTextures(1, &shadow_corner_tex); glDeleteTextures(1, &titlebar_corner_tex); } void DemoRenderer::begin() const { glClearColor(0.2f, 0.2f, 0.2f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); } void DemoRenderer::tessellate(std::vector& primitives, graphics::Renderable const& renderable, geometry::Size const& buf_size) const { GLRenderer::tessellate(primitives, renderable, buf_size); tessellate_shadow(primitives, renderable, 80.0f); tessellate_frame(primitives, renderable, 30.0f); } 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.type = GL_TRIANGLE_FAN; right_shadow.vertices.resize(4); 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.type = GL_TRIANGLE_FAN; left_shadow.vertices.resize(4); 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.type = GL_TRIANGLE_FAN; top_shadow.vertices.resize(4); 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.type = GL_TRIANGLE_FAN; bottom_shadow.vertices.resize(4); 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.type = GL_TRIANGLE_FAN; tr_shadow.vertices.resize(4); 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.type = GL_TRIANGLE_FAN; br_shadow.vertices.resize(4); 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.type = GL_TRIANGLE_FAN; bl_shadow.vertices.resize(4); 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.type = GL_TRIANGLE_FAN; tl_shadow.vertices.resize(4); 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}}; // Shadows always need blending... glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } void DemoRenderer::tessellate_frame(std::vector& primitives, graphics::Renderable const& renderable, float titlebar_height) 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 + 3); GLfloat htop = top - titlebar_height; GLfloat inleft = left + titlebar_height; // Square proportions for corners GLfloat inright = right - titlebar_height; 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.type = GL_TRIANGLE_FAN; top_left_corner.vertices.resize(4); 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.type = GL_TRIANGLE_FAN; top_right_corner.vertices.resize(4); 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.type = GL_TRIANGLE_FAN; titlebar.vertices.resize(4); 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}}; } mir-0.1.8+14.04.20140411/examples/demo-shell/fullscreen_placement_strategy.cpp0000644000015301777760000000273412322054223027371 0ustar pbusernogroup00000000000000/* * 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 */ #include "fullscreen_placement_strategy.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/shell/display_layout.h" #include "mir/geometry/rectangle.h" namespace me = mir::examples; namespace msh = mir::shell; me::FullscreenPlacementStrategy::FullscreenPlacementStrategy( std::shared_ptr const& display_layout) : display_layout(display_layout) { } msh::SurfaceCreationParameters me::FullscreenPlacementStrategy::place(msh::Session const& /* session */, msh::SurfaceCreationParameters const& request_parameters) { auto placed_parameters = request_parameters; geometry::Rectangle rect{request_parameters.top_left, request_parameters.size}; display_layout->size_to_output(rect); placed_parameters.size = rect.size; return placed_parameters; } mir-0.1.8+14.04.20140411/examples/demo-shell/window_manager.h0000644000015301777760000000401312322054223023713 0ustar pbusernogroup00000000000000/* * 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/geometry/displacement.h" #include "mir/geometry/size.h" #include namespace mir { namespace shell { class FocusController; } namespace graphics { class Display; } namespace compositor { class Compositor; } 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); 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; 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 }; } } // namespace mir #endif // MIR_EXAMPLES_WINDOW_MANAGER_H_ mir-0.1.8+14.04.20140411/examples/demo-shell/fullscreen_placement_strategy.h0000644000015301777760000000312712322054223027033 0ustar pbusernogroup00000000000000/* * 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_FULLSCREEN_PLACEMENT_STRATEGY_H_ #define MIR_EXAMPLES_FULLSCREEN_PLACEMENT_STRATEGY_H_ #include "mir/shell/placement_strategy.h" #include namespace mir { namespace shell { class DisplayLayout; } namespace examples { class FullscreenPlacementStrategy : public shell::PlacementStrategy { public: FullscreenPlacementStrategy(std::shared_ptr const& display_layout); ~FullscreenPlacementStrategy() = default; shell::SurfaceCreationParameters place(shell::Session const&, shell::SurfaceCreationParameters const& request_parameters); protected: FullscreenPlacementStrategy(FullscreenPlacementStrategy const&) = delete; FullscreenPlacementStrategy& operator=(FullscreenPlacementStrategy const&) = delete; private: std::shared_ptr const display_layout; }; } } // namespace mir #endif // MIR_EXAMPLES_FULLSCREEN_PLACEMENT_STRATEGY_H_ mir-0.1.8+14.04.20140411/examples/demo-shell/demo_shell.cpp0000644000015301777760000000756612322054223023400 0ustar pbusernogroup00000000000000/* * 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 */ /// \example demo_shell.cpp A simple mir shell #include "demo_renderer.h" #include "window_manager.h" #include "fullscreen_placement_strategy.h" #include "../server_configuration.h" #include "mir/options/default_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/renderer_factory.h" #include namespace me = mir::examples; namespace msh = mir::shell; namespace mg = mir::graphics; namespace mf = mir::frontend; namespace mi = mir::input; namespace mo = mir::options; namespace mir { namespace examples { class DemoRendererFactory : public compositor::RendererFactory { public: std::unique_ptr create_renderer_for( geometry::Rectangle const& rect) override { return std::unique_ptr(new DemoRenderer(rect)); } }; class DemoServerConfiguration : public mir::examples::ServerConfiguration { public: DemoServerConfiguration(int argc, char const* argv[], std::initializer_list> const& filter_list) : ServerConfiguration([argc, argv] { auto result = std::make_shared(argc, argv); namespace po = boost::program_options; result->add_options() ("fullscreen-surfaces", "Make all surfaces fullscreen"); return result; }()), filter_list(filter_list) { } std::shared_ptr the_shell_placement_strategy() override { return shell_placement_strategy( [this]() -> std::shared_ptr { if (the_options()->is_set("fullscreen-surfaces")) return std::make_shared(the_shell_display_layout()); else return DefaultServerConfiguration::the_shell_placement_strategy(); }); } std::shared_ptr the_composite_event_filter() override { auto composite_filter = ServerConfiguration::the_composite_event_filter(); for (auto const& filter : filter_list) composite_filter->append(filter); return composite_filter; } std::shared_ptr the_renderer_factory() override { return std::make_shared(); } private: std::vector> const filter_list; }; } } int main(int argc, char const* argv[]) try { auto wm = std::make_shared(); me::DemoServerConfiguration config(argc, argv, {wm}); 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()); }); return 0; } catch (...) { mir::report_exception(std::cerr); return 1; } mir-0.1.8+14.04.20140411/examples/demo-shell/CMakeLists.txt0000644000015301777760000000046212322054223023305 0ustar pbusernogroup00000000000000add_executable(mir_demo_server_shell demo_shell.cpp demo_renderer.cpp fullscreen_placement_strategy.cpp window_manager.cpp ../server_configuration.cpp ) target_link_libraries(mir_demo_server_shell mirserver ) install(TARGETS mir_demo_server_shell RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) mir-0.1.8+14.04.20140411/examples/demo-shell/demo_renderer.h0000644000015301777760000000325212322054247023536 0ustar pbusernogroup00000000000000/* * 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 "mir/compositor/gl_renderer.h" namespace mir { namespace examples { class DemoRenderer : public compositor::GLRenderer { public: DemoRenderer(geometry::Rectangle const& display_area); ~DemoRenderer(); void begin() const override; void tessellate(std::vector& primitives, graphics::Renderable const& renderable, geometry::Size const& buf_size) const override; 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) const; private: GLuint shadow_corner_tex; GLuint titlebar_corner_tex; }; } // namespace examples } // namespace mir #endif // MIR_EXAMPLES_DEMO_RENDERER_H_ mir-0.1.8+14.04.20140411/examples/demo-shell/window_manager.cpp0000644000015301777760000002406712322054223024261 0ustar pbusernogroup00000000000000/* * 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 "mir/shell/focus_controller.h" #include "mir/shell/session.h" #include "mir/shell/surface.h" #include "mir/graphics/display.h" #include "mir/graphics/display_configuration.h" #include "mir/compositor/compositor.h" #include #include // TODO remove this dependency #include #include #include namespace me = mir::examples; namespace msh = mir::shell; namespace mg = mir::graphics; namespace mc = mir::compositor; 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; } namespace { mir::geometry::Point average_pointer(MirMotionEvent const& motion) { using namespace mir; using namespace geometry; int x = 0, y = 0, count = static_cast(motion.pointer_count); for (int i = 0; i < count; i++) { x += motion.pointer_coordinates[i].x; y += motion.pointer_coordinates[i].y; } x /= count; y /= count; return Point{x, y}; } float measure_pinch(MirMotionEvent const& motion, mir::geometry::Displacement& dir) { int count = static_cast(motion.pointer_count); int max = 0; for (int i = 0; i < count; i++) { for (int j = 0; j < i; j++) { int dx = motion.pointer_coordinates[i].x - motion.pointer_coordinates[j].x; int dy = motion.pointer_coordinates[i].y - motion.pointer_coordinates[j].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 bool me::WindowManager::handle(MirEvent const& event) { // TODO: Fix android configuration and remove static hack ~racarr static bool display_off = false; assert(focus_controller); assert(display); assert(compositor); bool handled = false; if (event.key.type == mir_event_type_key && event.key.action == mir_key_action_down) { if (event.key.modifiers & mir_key_modifier_alt && event.key.scan_code == KEY_TAB) // TODO: Use keycode once we support keymapping on the server side { focus_controller->focus_next(); return true; } else if ((event.key.modifiers & mir_key_modifier_alt && event.key.scan_code == KEY_P) || (event.key.key_code == AKEYCODE_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 ((event.key.modifiers & mir_key_modifier_alt) && (event.key.modifiers & mir_key_modifier_ctrl)) { MirOrientation orientation = mir_orientation_normal; bool rotating = true; switch (event.key.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; } if (rotating) { compositor->stop(); auto conf = display->configuration(); conf->for_each_output( [&](mg::UserDisplayConfigurationOutput& output) -> void { output.orientation = orientation; } ); display->configure(*conf); compositor->start(); return true; } } } else if (event.type == mir_event_type_motion && focus_controller) { geometry::Point cursor = average_pointer(event.motion); // FIXME: https://bugs.launchpad.net/mir/+bug/1197108 MirMotionAction action = static_cast(event.motion.action & ~0xff00); std::shared_ptr app = focus_controller->focussed_application().lock(); int fingers = static_cast(event.motion.pointer_count); if (action == mir_motion_action_down || fingers > max_fingers) max_fingers = fingers; if (app) { // FIXME: We need to be able to select individual surfaces in // future and not just the "default" one. std::shared_ptr surf = app->default_surface(); if (surf && (event.motion.modifiers & mir_key_modifier_alt || fingers >= 3)) { geometry::Displacement pinch_dir; auto pinch_diam = measure_pinch(event.motion, pinch_dir); // Start of a gesture: When the latest finger/button goes down if (action == mir_motion_action_down || action == mir_motion_action_pointer_down) { click = cursor; handled = true; } else if (event.motion.action == mir_motion_action_move && max_fingers <= 3) // Avoid accidental movement { geometry::Displacement drag = cursor - old_cursor; if (event.motion.button_state == mir_motion_button_tertiary) { // Resize by mouse middle button int width = old_size.width.as_int() + drag.dx.as_int(); int height = old_size.height.as_int() + drag.dy.as_int(); if (width <= 0) width = 1; if (height <= 0) height = 1; surf->resize({width, height}); } else { // Move surface (by mouse or 3 fingers) 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; if (width <= 0) width = 1; if (height <= 0) height = 1; surf->resize({width, height}); } handled = true; } else if (action == mir_motion_action_scroll) { float alpha = surf->alpha(); alpha += 0.1f * event.motion.pointer_coordinates[0].vscroll; if (alpha < 0.0f) alpha = 0.0f; else if (alpha > 1.0f) alpha = 1.0f; surf->set_alpha(alpha); handled = true; } old_pos = surf->top_left(); old_size = surf->size(); old_pinch_diam = pinch_diam; old_cursor = cursor; } } if (max_fingers == 4 && action == mir_motion_action_up) { // Four fingers released geometry::Displacement dir = cursor - click; if (abs(dir.dx.as_int()) >= min_swipe_distance) { focus_controller->focus_next(); handled = true; } } } return handled; } mir-0.1.8+14.04.20140411/examples/demo_client_display_config.c0000644000015301777760000002563012322054223024220 0ustar pbusernogroup00000000000000/* * Client-side display configuration demo. * * 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 . * * Author: Alexandros Frantzis */ #include "eglapp.h" #include "mir_toolkit/mir_client_library.h" #include #include #include #include #include #include #include #include typedef enum { configuration_mode_unknown, configuration_mode_clone, configuration_mode_horizontal, configuration_mode_vertical, configuration_mode_single } ConfigurationMode; struct ClientContext { MirConnection *connection; ConfigurationMode mode; int mode_data; volatile sig_atomic_t running; volatile sig_atomic_t reconfigure; }; struct Card { uint32_t card_id; uint32_t available_outputs; }; struct Cards { size_t num_cards; struct Card *cards; }; static struct Cards *cards_create(struct MirDisplayConfiguration *conf) { struct Cards *cards = (struct Cards*) calloc(1, sizeof(struct Cards)); cards->num_cards = conf->num_cards; cards->cards = (struct Card*) calloc(cards->num_cards, sizeof(struct Card)); for (size_t i = 0; i < cards->num_cards; i++) { cards->cards[i].card_id = conf->cards[i].card_id; cards->cards[i].available_outputs = conf->cards[i].max_simultaneous_outputs; } return cards; } static void cards_free(struct Cards *cards) { free(cards->cards); free(cards); } static struct Card *cards_find_card(struct Cards *cards, uint32_t card_id) { for (size_t i = 0; i < cards->num_cards; i++) { if (cards->cards[i].card_id == card_id) return &cards->cards[i]; } fprintf(stderr, "Error: Couldn't find card with id: %u\n", card_id); abort(); } static void print_current_configuration(MirConnection *connection) { MirDisplayConfiguration *conf = mir_connection_create_display_config(connection); for (uint32_t i = 0; i < conf->num_outputs; i++) { MirDisplayOutput *output = &conf->outputs[i]; printf("Output id: %d connected: %d used: %d position_x: %d position_y: %d", output->output_id, output->connected, output->used, output->position_x, output->position_y); if (output->current_mode < output->num_modes) { MirDisplayMode *mode = &output->modes[output->current_mode]; printf(" mode: %dx%d@%.2f\n", mode->horizontal_resolution, mode->vertical_resolution, mode->refresh_rate); } else { printf("\n"); } } mir_display_config_destroy(conf); } static int apply_configuration(MirConnection *connection, MirDisplayConfiguration *conf) { MirWaitHandle* handle = mir_connection_apply_display_config(connection, conf); if (!handle) { printf("Failed to apply configuration, check that the configuration is valid.\n"); return 0; } mir_wait_for(handle); const char* error = mir_connection_get_error_message(connection); if (!strcmp(error, "")) { printf("Succeeded.\n"); return 1; } else { printf("Failed to apply configuration with error '%s'.\n", error); return 0; } } static void configure_display_clone(struct MirDisplayConfiguration *conf) { struct Cards *cards = cards_create(conf); for (uint32_t i = 0; i < conf->num_outputs; i++) { MirDisplayOutput *output = &conf->outputs[i]; struct Card *card = cards_find_card(cards, output->card_id); if (output->connected && output->num_modes > 0 && card->available_outputs > 0) { output->used = 1; output->current_mode = 0; output->position_x = 0; output->position_y = 0; --card->available_outputs; } } cards_free(cards); } static void configure_display_horizontal(struct MirDisplayConfiguration *conf) { struct Cards *cards = cards_create(conf); uint32_t max_x = 0; for (uint32_t i = 0; i < conf->num_outputs; i++) { MirDisplayOutput *output = &conf->outputs[i]; struct Card *card = cards_find_card(cards, output->card_id); if (output->connected && output->num_modes > 0 && card->available_outputs > 0) { output->used = 1; output->current_mode = 0; output->position_x = max_x; output->position_y = 0; max_x += output->modes[0].horizontal_resolution; --card->available_outputs; } } cards_free(cards); } static void configure_display_vertical(struct MirDisplayConfiguration *conf) { struct Cards *cards = cards_create(conf); uint32_t max_y = 0; for (uint32_t i = 0; i < conf->num_outputs; i++) { MirDisplayOutput *output = &conf->outputs[i]; struct Card *card = cards_find_card(cards, output->card_id); if (output->connected && output->num_modes > 0 && card->available_outputs > 0) { output->used = 1; output->current_mode = 0; output->position_x = 0; output->position_y = max_y; max_y += output->modes[0].vertical_resolution; --card->available_outputs; } } cards_free(cards); } static void configure_display_single(struct MirDisplayConfiguration *conf, int output_num) { uint32_t num_connected = 0; uint32_t output_to_enable = output_num; for (uint32_t i = 0; i < conf->num_outputs; i++) { MirDisplayOutput *output = &conf->outputs[i]; if (output->connected && output->num_modes > 0) ++num_connected; } if (output_to_enable > num_connected) output_to_enable = num_connected; for (uint32_t i = 0; i < conf->num_outputs; i++) { MirDisplayOutput *output = &conf->outputs[i]; if (output->connected && output->num_modes > 0) { output->used = (--output_to_enable == 0); output->current_mode = 0; output->position_x = 0; output->position_y = 0; } } } static void configure_display(struct ClientContext *context, ConfigurationMode mode, int mode_data) { MirDisplayConfiguration *conf = mir_connection_create_display_config(context->connection); if (mode == configuration_mode_clone) { configure_display_clone(conf); printf("Applying clone configuration: "); } else if (mode == configuration_mode_vertical) { configure_display_vertical(conf); printf("Applying vertical configuration: "); } else if (mode == configuration_mode_horizontal) { configure_display_horizontal(conf); printf("Applying horizontal configuration: "); } else if (mode == configuration_mode_single) { configure_display_single(conf, mode_data); printf("Applying single configuration for output %d: ", mode_data); } if (apply_configuration(context->connection, conf)) { context->mode = mode; context->mode_data = mode_data; } mir_display_config_destroy(conf); } static void display_change_callback(MirConnection *connection, void *context) { (void)context; printf("=== Display configuration changed === \n"); print_current_configuration(connection); struct ClientContext *ctx = (struct ClientContext*) context; ctx->reconfigure = 1; } static void event_callback( MirSurface* surface, MirEvent const* event, void* context) { (void)surface; struct ClientContext *ctx = (struct ClientContext*) context; if (event->type == mir_event_type_key && event->key.action == mir_key_action_up) { if (event->key.key_code == XKB_KEY_q) { ctx->running = 0; } else if (event->key.key_code == XKB_KEY_c) { configure_display(ctx, configuration_mode_clone, 0); } else if (event->key.key_code == XKB_KEY_h) { configure_display(ctx, configuration_mode_horizontal, 0); } else if (event->key.key_code == XKB_KEY_v) { configure_display(ctx, configuration_mode_vertical, 0); } else if (event->key.key_code >= XKB_KEY_1 && event->key.key_code <= XKB_KEY_9) { configure_display(ctx, configuration_mode_single, event->key.key_code - XKB_KEY_0); } else if (event->key.key_code == XKB_KEY_p) { print_current_configuration(ctx->connection); } } } int main(int argc, char *argv[]) { unsigned int width = 256, height = 256; if (!mir_eglapp_init(argc, argv, &width, &height)) { printf("A demo client that allows changing the display configuration. While the client\n" "has the focus, use the following keys to change and get information about the\n" "display configuration:\n" " c: clone outputs\n" " h: arrange outputs horizontally in the virtual space\n" " v: arrange outputs vertically in the virtual space\n" " 1-9: enable only the Nth connected output (in the order returned by the hardware)\n" " p: print current display configuration\n"); return 1; } MirConnection *connection = mir_eglapp_native_connection(); MirSurface *surface = mir_eglapp_native_surface(); struct ClientContext ctx = {connection, configuration_mode_unknown, 0, 1, 0}; mir_connection_set_display_config_change_callback( connection, display_change_callback, &ctx); struct MirEventDelegate ed = {event_callback, &ctx}; mir_surface_set_event_handler(surface, &ed); time_t start = time(NULL); while (ctx.running && mir_eglapp_running()) { time_t elapsed = time(NULL) - start; int mod = elapsed % 3; glClearColor(mod == 0 ? 1.0f : 0.0f, mod == 1 ? 1.0f : 0.0f, mod == 2 ? 1.0f : 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); mir_eglapp_swap_buffers(); if (ctx.reconfigure) { configure_display(&ctx, ctx.mode, ctx.mode_data); ctx.reconfigure = 0; } } mir_eglapp_shutdown(); return 0; } mir-0.1.8+14.04.20140411/examples/mir_image.h0000644000015301777760000014630112322054223020621 0ustar pbusernogroup00000000000000/* * 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 */ /* autogenerated from GIMP */ #ifndef MIR_DRAW_MIR_IMAGE_H_ #define MIR_DRAW_MIR_IMAGE_H_ static const struct { unsigned int width; unsigned int height; unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ unsigned char pixel_data[64 * 64 * 4 + 1]; } mir_image = { 64, 64, 4, "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377" "\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\34\34\34\377qqq\377\34\34\34\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377q" "qq\377\34\34\34\377\0\0\0\377\0\0\0\377\3\1\2\377\15\5\11\377\3\1\2\377\0" "\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34\34\34\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\10\10\10\377\35\35\35\377\10\10\10\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377" "\34\34\34\377\7\7\7\377\0\0\0\377\3\1\3\377!\20\32\377W2F\377!\20\32\377" "\3\1\3\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\7\7\7\377???\377\234\234\234\377???\377\7\7\7\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\1" "\1\1\377\0\0\0\377\3\1\3\377!\21\32\377zUi\377\303\252\267\377zUi\377!\21" "\32\377\3\1\3\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\10\10\10\377\35\35\35\377\10\10\10\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34\34\34\377" "\0\0\0\377\0\0\0\377\3\1\2\377\21\6\14\377\24\10\17\377\24\10\17\377\24\10" "\17\377\24\10\17\377\24\10\17\377\21\6\14\377\3\1\2\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\35\35\35\377\234\234\234\377\342\342\342\377" "\234\234\234\377\35\35\35\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377???\377\233\233\233\377???" "\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vj\377" "\332\311\322\377\367\362\365\377\332\311\322\377{Uj\377!\21\32\377\3\1\3" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\7\7\7\377???\377\234\234\234\377???\377\7\7\7\377\0\0\0\377\0\0\0\377\0" "\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\20\6\14\377" "V%?\377uB^\377yHc\377yHc\377yHc\377uB^\377V%@\377\21\6\14\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377???\377\234\234\234\377?" "??\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\35\35\35\377\234\234\234\377\342\342\342\377\234" "\234\234\377\35\35\35\377\0\0\0\377\0\0\0\377\3\1\3\377!\21\32\377{Vj\377" "\332\311\322\377\374\371\372\377\377\377\377\377\374\371\372\377\332\311" "\322\377{Uj\377!\21\32\377\3\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\35\35\35\377\234\234\234\377\342\342\342\377\234" "\234\234\377\35\35\35\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377" "\0\0\0\377\0\0\0\377\0\0\0\377\21\7\14\377d8P\377\303\246\266\377\344\326" "\336\377\351\334\344\377\350\334\343\377\331\305\320\377\210[t\377%\22\35" "\377\4\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\10\10\10" "\377\35\35\35\377\10\10\10\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377???\377\234\234" "\234\377???\377\7\7\7\377\0\0\0\377\3\1\3\377!\21\32\377{Uj\377\332\311\322" "\377\374\371\373\377\377\377\377\377\377\377\377\377\377\377\377\377\374" "\371\372\377\332\311\322\377{Uj\377!\21\32\377\3\1\3\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377???\377\234\234\234\377???\377" "\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377" "\0\0\0\377\0\0\0\377\4\1\3\377%\22\34\377\214ax\377\354\342\347\377\377\377" "\377\377\377\377\377\377\374\371\373\377\327\304\316\377i>U\377\21\7\14\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\10\10\10\377\35\35\35\377\10\10\10\377" "\0\0\0\377\0\0\0\377\16\5\12\377X3G\377\303\253\270\377\370\364\366\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\374\371\372\377\332\311\322\377{Uj\377!\21\32\377\3\1\3\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\10\10\10\377\35\35\35\377\10\10" "\10\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34\34" "\34\377\0\0\0\377\0\0\0\377\0\0\0\377\21\7\14\377i>V\377\327\304\316\377" "\374\371\373\377\377\377\377\377\377\377\377\377\350\334\343\377yIc\377\24" "\10\17\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0" "\377\0\0\0\377\0\0\0\377\3\1\3\377!\21\32\377{Vj\377\332\311\322\377\374" "\371\373\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\373\371\372\377\326\304\315\377h>U\377\21\7\14\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7" "\7\377\0\0\0\377\0\0\0\377\0\0\0\377\4\1\3\377%\22\35\377\214ax\377\354\342" "\350\377\377\377\377\377\377\377\377\377\354\342\350\377\214ax\377%\22\35" "\377\4\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7" "\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377" "\374\371\373\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\354\341\347\377\213ax\377%\23\35\377\4\2\3\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1" "\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\21\7\14\377i>V\377\327\304\316\377\374" "\371\373\377\377\377\377\377\374\371\373\377\327\304\316\377i>U\377\21\7" "\14\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7" "\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34" "\34\377qqq\377\34\34\34\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323" "\377\374\371\373\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\374\371\372\377\332\311\322\377{Vj\377!\21\32\377\3\1\3\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377" "\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377%\23\35\377\214ay\377\354\342\350\377" "\377\377\377\377\377\377\377\377\350\334\343\377yIc\377\24\10\17\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34\34\34\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34" "\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323" "\377\374\371\373\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\374\371\373\377\332\311\322\377{Vj\377\"\22\33\377\4\2\3\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34\34\34\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\7\7\7\377-#(\377pE\\\377\327\304\316\377\374\371\373\377" "\377\377\377\377\354\342\350\377\214ax\377%\22\35\377\4\1\3\377\0\0\0\377" "\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\1\1\1\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\374" "\371\373\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\374\371\372\377\332\311\322\377{Vk\377\"\22\33\377\4\2\3\377\0\0\0\377" "\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\3\1\2\377\15\5\12\377\3\1\2\377\0\0\0\377\0\0\0\377" "\34\34\34\377ust\377A.9\377\215ay\377\354\342\350\377\377\377\377\377\374" "\371\373\377\326\304\316\377i>U\377\21\7\14\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34" "\34\377\7\7\7\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\374\371\373" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374" "\371\373\377\332\311\323\377{Vk\377!\21\32\377\3\1\3\377\0\0\0\377\0\0\0" "\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377" "!\21\32\377W3G\377!\21\32\377\3\1\3\377\0\0\0\377\7\7\7\377\34\34\34\377" "\30\16\23\377i>V\377\327\304\316\377\374\371\373\377\377\377\377\377\354" "\342\347\377\213ax\377$\22\34\377\4\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34\34" "\34\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\374\371\373" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374" "\371\373\377\332\311\322\377{Vj\377\"\22\33\377\4\2\3\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vj\377" "\303\252\270\377{Uj\377\"\22\33\377\4\2\3\377\0\0\0\377\1\1\1\377\4\2\3\377" "%\22\35\377\214ax\377\354\342\350\377\377\377\377\377\373\371\372\377\326" "\304\315\377h>U\377\21\7\14\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7" "\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0" "\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\374\371\373" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374" "\371\372\377\332\311\322\377{Vk\377\"\22\33\377\4\2\3\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\3\1\3\377!\21\32\377{Vj\377\332\311\322\377\367" "\363\365\377\332\311\322\377{Vk\377\"\22\33\377\4\2\3\377\0\0\0\377\0\0\0" "\377\21\7\14\377i>V\377\327\304\316\377\370\364\366\377\361\347\354\377\345" "\326\336\377yHc\377\24\10\17\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377??" "?\377\233\233\233\377???\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\374" "\371\373\377\377\377\377\377\377\377\377\377\374\372\373\377\361\350\355" "\377\370\363\366\377\332\311\323\377{Vk\377\"\22\33\377\4\2\3\377\0\0\0\377" "\0\0\0\377\0\0\0\377\16\5\12\377X3G\377\303\253\270\377\370\364\366\377\377" "\377\377\377\374\371\373\377\332\311\323\377{Vk\377\"\22\33\377\4\2\3\377" "\0\0\0\377\4\1\3\377%\22\35\377\214`x\377\332\305\320\377\264\212\240\377" "\332\305\320\377\214`w\377%\22\34\377\4\1\3\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\35\35\35" "\377\234\234\234\377\342\342\342\377\234\234\234\377\35\35\35\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22" "\33\377{Vk\377\332\311\323\377\373\371\373\377\374\372\373\377\336\314\325" "\377\254\177\230\377\335\313\325\377\367\363\366\377\332\311\323\377{Vk\377" "\"\22\33\377\4\2\3\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vj\377\332" "\311\322\377\374\371\373\377\377\377\377\377\374\371\373\377\332\311\323" "\377{Vk\377\"\21\32\377\4\1\3\377\0\0\0\377\21\7\14\377i=U\377\304\247\266" "\377\254\177\227\377\331\305\320\377\322\275\310\377h>U\377\21\7\14\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7" "\7\7\377\0\0\0\377\7\7\7\377???\377\234\234\234\377???\377\7\7\7\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34" "\34\377\10\10\10\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\4\2\3\377%\23\35\377\214ay\377\354\342\347\377\360\350\354\377\254" "\177\230\377\203?d\377\231a\200\377\336\313\325\377\370\363\366\377\332\311" "\323\377{Vk\377\"\22\33\377\4\2\3\377\0\0\0\377\7\7\7\377\40\36\37\377)\31" "\"\377{Vk\377\332\311\323\377\374\371\373\377\377\377\377\377\373\371\373" "\377\326\304\316\377i>V\377\21\7\14\377\0\0\0\377\4\1\3\377%\22\35\377\210" "Zs\377\312\256\276\377\257\203\233\377\326\276\313\377yGb\377\24\10\17\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34" "\34\34\377\0\0\0\377\0\0\0\377\10\10\10\377\35\35\35\377\10\10\10\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377???\377" "\233\233\233\377???\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377" "\34\34\34\377\7\7\7\377\21\7\14\377i>V\377\326\304\316\377\370\363\366\377" "\336\313\325\377\231a\200\377~9_\377\231a\200\377\336\313\325\377\370\363" "\366\377\332\311\323\377{Vk\377\"\22\33\377\4\2\3\377\34\34\34\377rrr\377" "\40\36\37\377\"\22\33\377{Vk\377\332\311\323\377\374\371\373\377\377\377" "\377\377\354\342\350\377\214ay\377)\24\40\377\21\6\14\377\4\1\3\377\21\7" "\14\377i=U\377\303\247\266\377\253~\227\377\312\256\275\377\210Zs\377%\22" "\34\377\4\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34" "\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\35\35\35\377\234\234" "\234\377\342\342\342\377\234\234\234\377\35\35\35\377\0\0\0\377\0\0\0\377" "\0\0\0\377\34\34\34\377qqq\377\34\34\34\377\4\2\3\377\"\21\32\377{Vk\377" "\332\311\323\377\370\363\366\377\336\313\325\377\231a\177\377\1779_\377\231" "a\200\377\336\313\325\377\370\363\366\377\332\311\323\377{Vk\377!\21\32\377" "\12\10\11\377\34\34\34\377\7\7\7\377\4\2\3\377\"\22\33\377{Vk\377\332\311" "\323\377\374\371\373\377\373\371\373\377\332\312\323\377\210[t\377W%@\377" "\21\6\14\377\4\1\3\377%\22\35\377\210Zs\377\312\256\275\377\253~\226\377" "\303\247\266\377i=U\377\21\7\14\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7" "\7\377???\377\234\234\234\377???\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0" "\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk" "\377\332\311\323\377\367\363\365\377\335\313\324\377\231a\200\377\1779_\377" "\231a\200\377\336\313\325\377\370\363\366\377\332\311\322\377{Vj\377!\21" "\32\377\4\2\3\377\0\0\0\377\0\0\0\377\4\2\3\377%\23\35\377\214ay\377\354" "\342\350\377\374\371\373\377\355\342\350\377\331\305\320\377\210[t\377%\23" "\35\377\4\2\3\377\21\7\14\377i=U\377\303\247\266\377\253~\226\377\312\256" "\275\377\210[t\377)\24\40\377\21\6\14\377\3\1\2\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\10\10\10\377\35\35\35\377\10\10\10\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"" "\22\33\377{Vk\377\332\311\323\377\370\363\366\377\336\312\325\377\231a\200" "\377\1779_\377\231a\200\377\336\313\325\377\370\363\365\377\326\304\315\377" "h>U\377\21\7\14\377\0\0\0\377\0\0\0\377\0\0\0\377\21\7\14\377i>V\377\326" "\303\316\377\354\342\350\377\277\234\257\377\336\313\325\377\326\303\316" "\377{Vk\377\"\22\33\377\7\3\5\377%\22\35\377\210Zs\377\312\256\275\377\253" "~\227\377\307\254\273\377\210[t\377W%@\377\21\6\14\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377" "\"\22\33\377{Vk\377\332\311\323\377\370\363\366\377\336\313\325\377\231a" "\200\377\1779_\377\231a\200\377\336\312\325\377\350\333\342\377\213ax\377" "%\23\35\377\4\2\3\377\0\0\0\377\0\0\0\377\4\1\3\377\"\21\32\377{Vj\377\326" "\303\316\377\336\313\325\377\274\226\253\377\336\313\325\377\326\303\315" "\377{Vj\377&\23\36\377)\25\40\377\214`x\377\326\277\313\377\240m\210\377" "\326\277\314\377\331\304\320\377\210[t\377)\24\40\377\21\6\14\377\3\1\2\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7" "\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0" "\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\370\363\366\377\336\313" "\325\377\231a\200\377\1779_\377\231a\200\377\331\304\320\377\326\303\315" "\377{Vj\377\"\22\33\377\4\2\3\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377" "{Vj\377\326\303\315\377\336\313\325\377\274\226\253\377\336\313\325\377\326" "\304\315\377\214ay\377\214ax\377\326\303\315\377\325\277\313\377\216Pq\377" "\236h\205\377\351\334\343\377\332\311\322\377\210[t\377Z&C\377\35\13\25\377" "\3\1\2\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34" "\34\34\377qqq\377\34\34\34\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7" "\7\7\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\370\363\366" "\377\336\313\325\377\231a\200\377\1779_\377\231a\200\377\331\304\317\377" "\326\303\315\377{Vj\377\"\22\33\377\4\2\3\377\0\0\0\377\0\0\0\377\4\2\3\377" "\"\22\33\377{Vk\377\326\303\316\377\336\313\325\377\274\226\253\377\336\313" "\325\377\345\327\336\377\331\305\320\377\326\277\313\377\231a\177\377\177" "9_\377\232b\200\377\332\306\320\377\351\334\343\377\331\305\320\377\231e" "\202\377l>W\377%\22\35\377\20\6\14\377\3\1\2\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34\34\34\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34" "\34\377qqq\377\34\34\34\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk" "\377\332\311\323\377\370\363\366\377\336\313\325\377\231a\200\377~9_\377" "\231a\200\377\331\304\320\377\326\303\315\377{Vj\377\"\22\33\377\4\2\3\377" "\0\0\0\377\0\0\0\377\4\2\3\377&\23\35\377\211\\t\377\332\305\320\377\336" "\313\325\377\273\226\252\377\316\263\302\377\234f\203\377\212Jm\377~9^\377" "\231a\177\377\316\263\302\377\260\205\235\377\260\205\235\377\336\313\325" "\377\350\334\343\377\326\304\315\377\214ax\377i=U\377$\22\34\377\20\6\14" "\377\3\1\2\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377" "\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\3\1\2\377\15" "\5\11\377\12\10\11\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377" "\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\370\363\366\377\336\313\325" "\377\231a\177\377~9^\377\231a\200\377\331\304\320\377\326\303\315\377{Vj" "\377!\21\32\377\4\1\3\377\3\1\3\377\21\7\15\377(\24\37\377~Jf\377\260\204" "\233\377\351\334\343\377\316\264\302\377\225\\{\377{3Z\377{3Y\377\231a\177" "\377\331\305\317\377\351\334\342\377\351\334\343\377\336\313\326\377\274" "\226\253\377\336\313\325\377\351\334\343\377\350\334\342\377\326\304\315" "\377\214`w\377h=T\377!\21\32\377\3\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\3\1" "\3\377!\20\32\377W2F\377!\21\32\377\4\2\3\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\1\1\1\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\367\363" "\365\377\335\313\324\377\231a\177\377\1779_\377\231a\200\377\331\304\320" "\377\326\303\315\377{Vj\377&\23\36\377%\23\35\377i>V\377\214ax\377\322\276" "\312\377\332\305\320\377\326\277\314\377\231a\177\377\1779_\377\206Dh\377" "\215Oq\377\325\277\313\377\326\304\315\377\237z\216\377\326\304\316\377\350" "\334\342\377\336\313\325\377\260\205\235\377\260\205\234\377\342\320\332" "\377\370\363\366\377\354\342\347\377\326\304\315\377{Uj\377$\22\34\377\20" "\6\14\377\3\1\2\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\3\1\2\377\20\6\14\377$\22\34\377{Ui\377\303\252\267\377{Ui\377\"\22" "\33\377\4\2\3\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\4" "\2\3\377\"\22\33\377{Vk\377\332\311\323\377\370\363\365\377\335\312\324\377" "\231a\200\377\1779_\377\231a\200\377\331\304\320\377\326\303\315\377\214" "ay\377\214ay\377\326\304\316\377\350\334\342\377\331\305\320\377\235g\204" "\377\212Jm\377\1779_\377\231a\177\377\307\250\271\377\240l\210\377\331\304" "\320\377\237y\215\377K*<\377m?X\377\214ax\377\326\304\315\377\351\334\343" "\377\336\313\326\377\273\226\253\377\335\313\325\377\354\342\347\377\370" "\363\366\377\332\311\322\377\214`x\377i=U\377$\22\34\377\20\6\14\377\3\1" "\2\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\3\1\3\377!\21\32\377h=T\377\214`x\377" "\332\311\322\377\367\362\365\377\332\311\322\377{Vj\377!\21\32\377\3\1\3" "\377\0\0\0\377\34\34\34\377qqq\377\34\34\34\377\0\0\0\377\4\2\3\377%\23\35" "\377\215ay\377\354\342\350\377\373\370\372\377\336\313\325\377\231a\200\377" "\1779_\377\231a\200\377\331\305\320\377\350\334\342\377\354\342\347\377\370" "\364\366\377\335\313\325\377\231a\200\377{3Z\377{3Z\377\231a\200\377\335" "\312\325\377\351\334\343\377\260\204\233\377\331\305\320\377\326\303\316" "\377\177Wm\3773\30'\377)\24\40\377{Vk\377\332\311\322\377\370\363\366\377" "\342\320\332\377\260\204\234\377\260\204\234\377\341\320\332\377\370\363" "\366\377\354\342\347\377\326\304\315\377\214`w\377i=U\377$\22\34\377\20\6" "\14\377\3\1\2\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1" "\377\0\0\0\377\0\0\0\377\16\5\12\377X2G\377\277\245\263\377\350\334\342\377" "\374\371\373\377\377\377\377\377\374\371\373\377\332\311\322\377{Vj\377\"" "\22\33\377\4\2\3\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\4\1\3\377" "%\22\35\377\214ax\377\354\342\350\377\377\377\377\377\374\371\373\377\336" "\313\325\377\231a\200\377\1779_\377\231a\200\377\331\305\320\377\350\334" "\343\377\332\305\320\377\231a\200\377\1779_\377\212Jm\377\235g\204\377\331" "\305\320\377\354\342\347\377\370\364\366\377\341\321\331\377\273\226\252" "\377\335\313\324\377\322\276\311\377i>U\377\25\10\17\377\"\22\33\377{Vk\377" "\326\304\316\377\350\334\343\377\350\334\343\377\335\313\325\377\277\234" "\257\377\361\350\355\377\377\376\377\377\374\371\373\377\354\342\347\377" "\326\304\315\377\214`w\377i=U\377$\22\34\377\20\6\14\377\3\1\2\377\0\0\0" "\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\3\1\3\377!\21\32" "\377{Vj\377\332\311\322\377\374\371\372\377\377\377\377\377\377\377\377\377" "\374\371\372\377\332\311\322\377{Vj\377\"\21\32\377\4\2\3\377\1\1\1\377\0" "\0\0\377\0\0\0\377\16\5\12\377X3G\377\304\253\270\377\370\364\366\377\377" "\377\377\377\377\377\377\377\374\371\373\377\336\313\325\377\231a\200\377" "~9^\377\212Jm\377\215Oq\377\212Jm\377\1779_\377\231a\200\377\332\305\320" "\377\350\334\343\377\326\304\316\377\237z\216\377\333\312\323\377\370\363" "\366\377\335\313\325\377\257\204\234\377\331\305\320\377\214`x\377%\23\35" "\377\10\3\6\377\"\21\33\377i>U\377\214bx\377\332\312\322\377\370\363\366" "\377\360\350\355\377\374\372\373\377\377\377\377\377\377\377\377\377\377" "\377\377\377\374\371\373\377\354\342\347\377\326\304\315\377\210Zs\377V%" "?\377\20\6\14\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34\34\34\377\0" "\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\374\371\373" "\377\377\377\377\377\377\377\377\377\373\371\373\377\326\304\316\377i>V\377" "\21\7\14\377\0\0\0\377\0\0\0\377\0\0\0\377\4\1\3\377%\22\34\377\214ax\377" "\354\342\347\377\377\377\377\377\377\377\377\377\377\377\377\377\374\371" "\373\377\331\305\320\377\212Jl\377w-U\377w-U\377{3Z\377\231a\200\377\336" "\313\325\377\370\363\365\377\332\311\322\377{Wk\377:\37.\377\214ay\377\354" "\341\347\377\355\341\350\377\260\204\234\377\332\305\321\377\326\303\316" "\377{Vk\377\"\22\33\377\10\3\5\377\30\16\24\377A/9\377\202]r\377\332\311" "\323\377\374\371\373\377\377\377\377\377\377\377\377\377\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\374\371\372\377\331\305" "\317\377vB^\377\24\10\16\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7" "\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311" "\323\377\374\371\373\377\377\377\377\377\377\377\377\377\354\342\350\377" "\214ax\377%\22\35\377\4\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377\21\7\14\377" "i>V\377\326\304\316\377\373\371\373\377\377\377\377\377\377\377\377\377\374" "\371\373\377\331\305\320\377\212Jl\377{3Z\377\212Jm\377\235g\204\377\336" "\313\325\377\370\363\366\377\332\311\323\377{Vk\377\"\22\33\377\25\10\17" "\377i>V\377\326\304\316\377\367\363\365\377\336\313\325\377\260\205\234\377" "\351\334\343\377\331\311\322\377{Vk\377\"\22\33\377\40\35\37\377vst\377>" ".7\377{Wk\377\326\304\316\377\354\342\350\377\374\372\373\377\377\377\377" "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\350" "\334\343\377yHc\377\24\10\17\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377%\23\35\377\214" "ay\377\354\342\350\377\377\377\377\377\374\372\373\377\355\343\350\377\326" "\304\316\377{Vj\377\"\22\33\377\4\2\3\377\0\0\0\377\0\0\0\377\7\3\5\3776" "\35+\377\237y\216\377\360\350\354\377\374\371\373\377\355\342\350\377\332" "\305\320\377\231a\200\377~9^\377\231a\177\377\332\305\320\377\355\342\350" "\377\370\364\366\377\332\311\323\377{Vk\377\"\22\33\377\4\2\3\377\4\1\3\377" "\"\21\32\377{Vk\377\331\311\322\377\351\334\343\377\261\205\234\377\336\314" "\325\377\370\363\366\377\326\304\316\377i>V\377\30\16\23\377\34\34\34\377" "\13\10\12\377\"\22\33\377i>U\377\214ay\377\332\312\323\377\374\371\373\377" "\377\377\377\377\377\377\377\377\377\377\377\377\373\371\373\377\326\304" "\316\377i>U\377\21\7\14\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\21\7\14\377i>V\377" "\326\304\316\377\373\371\372\377\361\350\355\377\277\234\260\377\336\313" "\325\377\326\303\315\377{Vj\377\"\22\33\377\7\3\5\377\21\7\15\377%\23\35" "\377|Vk\377\332\311\323\377\370\363\366\377\336\313\325\377\235g\204\377" "\212Jm\377{3Z\377\206Dh\377\313\256\275\377\370\364\366\377\377\377\377\377" "\354\342\350\377\215ay\377%\23\35\377\4\2\3\377\0\0\0\377\0\0\0\377\4\2\3" "\377%\23\35\377\214ay\377\350\334\343\377\342\321\332\377\277\234\260\377" "\360\350\355\377\354\342\347\377\214ax\377%\23\35\377\4\2\3\377\0\0\0\377" "\3\1\3\377\21\7\15\377%\23\35\377{Vk\377\332\311\323\377\374\371\373\377" "\377\377\377\377\374\371\373\377\332\311\323\377{Vk\377\"\21\32\377\4\1\3" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\4\1\3\377\"\21\32\377{Vk\377\332\311\323\377" "\370\363\366\377\342\322\332\377\273\227\253\377\335\313\324\377\326\303" "\315\377{Vk\3776\36,\377i>V\377\214ax\377\332\311\322\377\367\363\365\377" "\335\312\325\377\231a\200\377{3Z\377{3Z\377\206Dh\377~8^\377\231a\177\377" "\336\313\325\377\373\371\372\377\354\342\350\377\215ay\377%\23\35\377\4\2" "\3\377\0\0\0\377\7\7\7\377\34\34\34\377\30\16\23\377i>V\377\326\304\316\377" "\370\364\366\377\361\351\355\377\374\372\373\377\374\371\373\377\332\311" "\322\377{Vj\377\"\22\33\377\4\2\3\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22" "\33\377{Vk\377\326\304\316\377\354\342\350\377\350\334\343\377\214ay\377" "%\23\35\377\4\2\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\4" "\2\3\377\"\22\33\377{Vk\377\332\311\323\377\370\363\366\377\342\322\332\377" "\274\226\252\377\336\313\325\377\326\304\316\377\237z\216\377\326\304\316" "\377\350\334\343\377\350\334\343\377\331\305\320\377\231a\200\377\1779_\377" "\212Jm\377\234f\204\377\313\255\275\377\231a\177\377\1779_\377\231a\200\377" "\336\313\325\377\370\363\366\377\332\311\323\377{Vk\377\"\21\32\377\4\2\3" "\377\34\34\34\377rrr\377\40\35\37\377&\23\35\377\214ax\377\354\342\350\377" "\377\377\377\377\377\377\377\377\377\377\377\377\374\371\372\377\332\311" "\322\377{Vj\377!\21\32\377\3\1\3\377\0\0\0\377\0\0\0\377\4\2\3\377\"\21\33" "\377i>U\377\213`x\377\277\245\264\377i=U\377\21\7\14\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377???\377\233\233\233" "\377???\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377" "{Vk\377\332\311\323\377\367\363\366\377\341\321\332\377\273\227\253\377\336" "\313\325\377\354\342\347\377\370\364\366\377\335\313\325\377\235g\204\377" "\212Jm\377~9^\377\231a\200\377\332\305\320\377\355\342\350\377\370\364\366" "\377\335\313\324\377\231a\200\377\1779_\377\231a\200\377\336\313\325\377" "\370\363\366\377\326\304\316\377i>V\377\21\7\14\377\7\7\7\377\34\34\34\377" "\7\7\7\377\21\7\14\377i>V\377\326\304\316\377\373\371\373\377\377\377\377" "\377\377\377\377\377\377\377\377\377\373\371\373\377\326\304\316\377h>U\377" "\21\7\14\377\0\0\0\377\0\0\0\377\0\0\0\377\3\1\3\377\21\7\15\377%\23\35\377" "W3G\377!\21\32\377\4\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\35\35\35\377\234\234\234\377\342\342\342\377\234\234\234" "\377\35\35\35\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22" "\33\377|Vk\377\332\312\323\377\370\363\366\377\342\321\332\377\273\226\252" "\377\335\313\325\377\332\305\320\377\231a\200\377{3Z\377{3Y\377\231a\177" "\377\336\313\325\377\374\371\373\377\374\372\373\377\354\342\350\377\350" "\334\343\377\331\305\320\377\231a\200\377\1779_\377\231a\200\377\336\312" "\325\377\350\334\343\377\214ay\377%\23\35\377\4\2\3\377\1\1\1\377\0\0\0\377" "\4\1\3\377\"\21\32\377{Vk\377\332\311\323\377\374\371\373\377\377\377\377" "\377\377\377\377\377\377\377\377\377\350\334\343\377}Ie\377!\15\30\377\3" "\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\3\1\2\377\15\5\12\377\3" "\1\2\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\7\7\7\377???\377\234\234\234\377???\377\7\7\7\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\7\3\5\3776\36+\377\237z\216\377\360\350" "\354\377\370\363\366\377\317\264\302\377\231a\200\377\212Jm\377\1779_\377" "\212Jm\377\235g\204\377\335\313\324\377\374\371\372\377\373\371\373\377\332" "\312\323\377\214ay\377\214ay\377\326\303\315\377\325\277\313\377\212Km\377" "|4[\377\235g\204\377\351\334\343\377\332\311\322\377{Vk\377\"\22\33\377\4" "\2\3\377\0\0\0\377\0\0\0\377\4\2\3\377%\23\35\377\214ay\377\354\342\350\377" "\374\371\373\377\354\342\350\377\350\334\343\377\322\276\311\377vB^\377F" "\32""2\377\15\5\11\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\10\10\10\377\35\35\35\377\10\10\10\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\3\1\3\377!\21\32\377|Vk\377" "\332\312\323\377\370\363\366\377\336\313\325\377\231a\177\377{3Z\377{3Z\377" "\231a\200\377\332\305\320\377\354\342\347\377\370\363\366\377\354\342\350" "\377\326\304\316\377{Vk\377&\23\36\377&\23\36\377{Vj\377\306\254\272\377" "\231a\177\377|4Z\377\213Km\377\332\305\320\377\370\363\366\377\332\311\323" "\377{Vk\377\"\22\33\377\4\2\3\377\0\0\0\377\0\0\0\377\21\7\14\377i>U\377" "\322\275\311\377\326\303\316\377\214ay\377yHc\377h=U\377%\22\34\377\20\6" "\14\377\3\1\2\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7" "\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\4\1\3\377\"\21\32\377{Vj\377\332\311\322\377\367" "\363\366\377\335\313\325\377\231a\200\377{3Z\377{3Z\377\231a\200\377\336" "\313\325\377\374\371\373\377\373\371\373\377\332\311\323\377\214ay\377i>" "U\377\"\21\33\377\4\2\3\377\4\2\3\377\"\22\33\377wPf\377\267\225\247\377" "\225[z\377\1779_\377\231a\200\377\336\313\325\377\370\363\366\377\332\311" "\323\377{Vk\377!\21\32\377\3\1\3\377\0\0\0\377\4\1\3\377\"\21\32\377h=U\377" "h=U\377%\23\35\377\24\10\17\377\21\7\15\377\3\1\3\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\7\7\7\377???\377\233\233\233\377???\377\7\7\7\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7" "\7\7\377\21\7\14\377i>U\377\326\304\315\377\370\363\365\377\336\313\325\377" "\231a\200\377\1779_\377\206Dh\377\216Pr\377\332\305\321\377\373\371\373\377" "\373\371\373\377\332\311\323\377{Vk\377%\23\35\377\21\7\15\377\4\2\3\377" "\1\1\1\377\0\0\0\377\4\2\3\377\"\22\33\377wPe\377\267\225\247\377\225[z\377" "\1779_\377\231a\200\377\336\313\325\377\370\363\366\377\326\304\316\377h" ">U\377\21\7\14\377\0\0\0\377\0\0\0\377\3\1\3\377\21\7\14\377\21\7\14\377" "\3\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\35\35\35\377\234\234\234\377\342\342\342\377\234\234\234\377\35" "\35\35\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34" "\34\34\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377" "qqq\377\34\34\34\377\25\11\17\377yIc\377\350\333\343\377\360\347\354\377" "\254\177\230\377\202?c\377\231a\177\377\313\256\276\377\254~\227\377\336" "\313\325\377\374\371\372\377\360\350\354\377\237y\215\3777\35+\377\10\3\5" "\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\4\2\3\377\"\22" "\33\377wPe\377\270\225\247\377\225[{\377\1779_\377\231a\200\377\336\312\325" "\377\350\334\342\377\213ax\377$\22\34\377\4\1\3\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34" "\34\377\7\7\7\377\0\0\0\377\7\7\7\377???\377\234\234\234\377???\377\7\7\7" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\37\35\36" "\377\27\15\23\377(\24\37\377\214ay\377\354\342\350\377\373\371\372\377\336" "\314\325\377\254\177\227\377\335\313\325\377\370\363\366\377\341\321\332" "\377\274\227\253\377\342\322\332\377\370\363\366\377\332\311\322\377{Vj\377" "\"\22\33\377\4\2\3\377\34\34\34\377qqq\377\34\34\34\377\0\0\0\377\0\0\0\377" "\4\2\3\377%\23\35\377\210[s\377\312\255\275\377\231a\177\377\1779_\377\231" "a\200\377\332\305\320\377\326\303\315\377{Uj\377!\21\32\377\3\1\3\377\0\0" "\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34" "\34\377qqq\377\34\34\34\377\0\0\0\377\0\0\0\377\10\10\10\377\35\35\35\377" "\10\10\10\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\4" "\2\3\377\"\21\32\377i=U\377\214`x\377\332\311\323\377\374\371\373\377\377" "\377\377\377\374\372\373\377\354\342\347\377\351\335\343\377\351\335\343" "\377\351\334\343\377\336\313\325\377\274\227\253\377\342\322\332\377\370" "\363\366\377\332\311\322\377{Vk\377\"\22\33\377\13\10\12\377\34\34\34\377" "\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\21\7\14\377i>U\377\322\275\310\377" "\331\304\320\377\231a\200\377\203?d\377\254\177\230\377\354\341\347\377\331" "\311\321\377{Vj\377\"\22\33\377\4\2\3\377\0\0\0\377\7\7\7\377\34\34\34\377" "\7\7\7\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377" "\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\3\1\3\377!\21\32\377{Uj\377\322\276\310\377\331\305\320" "\377\345\327\336\377\351\334\343\377\351\335\344\377\350\334\343\377\326" "\304\315\377\214ay\377zId\377\214ay\377\326\304\315\377\336\313\325\377\273" "\227\253\377\341\321\332\377\367\363\366\377\332\311\323\377{Vk\377\"\22" "\33\377\4\2\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\4\1\3\377\"\21" "\32\377{Vj\377\326\303\315\377\331\305\320\377\254\177\230\377\336\314\325" "\377\374\371\373\377\373\371\372\377\332\311\322\377{Vj\377\"\21\32\377\4" "\2\3\377\34\34\34\377qqq\377\34\34\34\377\0\0\0\377\0\0\0\377\0\0\0\377\1" "\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34\34" "\34\377\0\0\0\377\0\0\0\377\3\1\2\377\20\6\14\377$\22\34\377{Uj\377\325\303" "\315\377\326\303\315\377\214ax\377zIc\377yHc\377yHc\377yHc\377h=U\377%\23" "\35\377\25\10\17\377%\23\35\377{Vj\377\326\303\315\377\336\313\325\377\273" "\226\252\377\341\321\332\377\367\363\366\377\332\311\323\377{Vk\377\"\21" "\32\377\4\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22" "\33\377{Vj\377\326\304\315\377\354\342\350\377\374\372\373\377\377\377\377" "\377\377\377\377\377\373\371\373\377\326\304\316\377i>V\377\21\7\14\377\7" "\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0" "\0\377\3\1\3\377!\21\32\377h=T\377\214`w\377\326\303\315\377\325\303\315" "\377{Vj\377%\23\35\377\24\10\17\377\24\10\17\377\24\10\17\377\25\11\17\377" "\21\7\15\377\3\1\3\377\0\0\0\377\4\2\3\377\"\22\33\377{Vj\377\326\303\315" "\377\335\313\325\377\273\226\252\377\342\322\332\377\370\363\366\377\326" "\304\316\377i>V\377\21\7\14\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\322\377\374\371\372\377\377" "\377\377\377\377\377\377\377\377\377\377\377\354\342\350\377\214ay\377%\23" "\35\377\4\2\3\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\3\1\3\377\20" "\6\14\377$\22\34\377{Uj\377\322\276\310\377\331\304\317\377\322\276\310\377" "{Vj\377\"\22\33\377\4\2\3\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377" "\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vj\377\326" "\303\315\377\335\313\325\377\277\234\260\377\360\350\355\377\354\342\347" "\377\214ax\377%\22\35\377\4\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\374\371\373\377\377" "\377\377\377\377\377\377\377\374\371\373\377\332\311\323\377{Vk\377\"\22" "\33\377\4\2\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\3\1\3\377!\21\32\377h=T\377\214" "`w\377\326\303\315\377\326\303\315\377\214ax\377i>U\377\"\21\33\377\4\2\3" "\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34\34\34\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vj\377\326\304\315" "\377\355\342\350\377\374\372\373\377\374\371\373\377\332\311\322\377{Vj\377" "\"\22\33\377\4\2\3\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377" "\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\374\371\373\377\377\377\377" "\377\377\377\377\377\374\371\373\377\332\311\323\377{Vk\377\"\22\33\377\4" "\2\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7" "\7\7\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\16\5\12\377X2G\377\274\237\257\377\325\277\313" "\377\322\276\310\377{Vj\377%\23\35\377\21\7\15\377\3\1\3\377\0\0\0\377\0" "\0\0\377\1\1\1\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311" "\322\377\374\371\372\377\377\377\377\377\374\371\372\377\332\311\322\377" "{Vk\377\"\22\33\377\4\2\3\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377" "\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\374\371\373\377\377" "\377\377\377\377\377\377\377\374\371\373\377\332\311\323\377{Vk\377!\21\32" "\377\3\1\3\377\0\0\0\377\0\0\0\377\7\7\7\377???\377\233\233\233\377???\377" "\7\7\7\377\1\1\1\377\34\34\34\377qqq\377\34\34\34\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\4\1\3\377$\22\34\377vB]\377|Id\377h=U\377\"\21\33\377" "\4\2\3\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377" "\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\374\371\373" "\377\377\377\377\377\374\371\373\377\332\311\322\377{Vj\377\"\22\33\377\37" "\35\37\377rrr\377\34\34\34\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"" "\22\33\377{Vk\377\332\311\323\377\374\371\373\377\377\377\377\377\377\377" "\377\377\373\371\373\377\326\304\316\377h>U\377\21\7\14\377\0\0\0\377\0\0" "\0\377\35\35\35\377\234\234\234\377\342\342\342\377\234\234\234\377\35\35" "\35\377\1\1\1\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\20\6\14\377E\32""2\377!\15\30\377\21\7\15\377" "\3\1\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\34\34\34\377qqq\377\34" "\34\34\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311" "\323\377\374\371\373\377\377\377\377\377\370\364\366\377\303\253\270\377" "X3G\377\25\14\21\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377\374\371\373\377\377" "\377\377\377\377\377\377\377\354\342\347\377\213ax\377%\23\35\377\4\2\3\377" "\0\0\0\377\7\7\7\377???\377\234\234\234\377???\377\7\7\7\377\0\0\0\377\0" "\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\3\1\2\377\15\5\11\377\3\1\2\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\10\10\10\377\35\35\35\377\10\10\10\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323\377" "\367\363\366\377\332\311\322\377{Vj\377!\21\32\377\4\2\3\377\1\1\1\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377%\23" "\35\377\214ay\377\354\342\350\377\377\377\377\377\377\377\377\377\374\371" "\372\377\332\311\322\377{Vj\377!\21\32\377\3\1\3\377\0\0\0\377\10\10\10\377" "\35\35\35\377\10\10\10\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377" "\7\7\7\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377??" "?\377\234\234\234\377???\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\4\2\3\377\"\22\33\377{Vj\377\303\253\270\377{Vj\377\"\22\33\377\4" "\2\3\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0" "\0\377\0\0\0\377\0\0\0\377\21\7\14\377i>V\377\326\304\316\377\373\371\373" "\377\377\377\377\377\377\377\377\377\373\371\373\377\326\304\316\377h>U\377" "\21\7\14\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\10\10\10\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\34\34\34\377qqq\377\34\34\34\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\35\35\35\377\234\234\234\377\342\342\342\377\234" "\234\234\377\35\35\35\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\4\2\3\377!\21\32\377W3G\377!\21\32\377\4\2\3\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\10\10\10\377\35\35\35\377\10\10\10\377\0\0\0\377" "\0\0\0\377\4\1\3\377\"\21\32\377{Vk\377\332\311\323\377\374\371\373\377\377" "\377\377\377\377\377\377\377\350\334\343\377yHc\377\24\10\17\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377???\377\233\233" "\233\377???\377\7\7\7\377\0\0\0\377\0\0\0\377\7\7\7\377???\377\233\233\233" "\377???\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377\34\34\34\377" "\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377??" "?\377\234\234\234\377???\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\1\1\1\377\0\0\0\377\3\1\2\377\15\5\12\377\3\1\2\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377???\377\234\234\234\377???" "\377\7\7\7\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22\33\377{Vk\377\332\311\323" "\377\374\371\373\377\377\377\377\377\350\334\343\377yHc\377\24\10\17\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\35\35\35\377" "\234\234\234\377\342\342\342\377\234\234\234\377\35\35\35\377\0\0\0\377\0" "\0\0\377\35\35\35\377\234\234\234\377\342\342\342\377\234\234\234\377\35" "\35\35\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\10\10\10\377\35" "\35\35\377\10\10\10\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377" "\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\35\35\35\377\234\234\234\377\342\342\342\377" "\234\234\234\377\35\35\35\377\0\0\0\377\0\0\0\377\0\0\0\377\4\2\3\377\"\22" "\33\377{Vk\377\326\304\316\377\350\334\343\377\325\277\313\377vB^\377\24" "\10\16\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7" "\7\7\377???\377\234\234\234\377???\377\7\7\7\377\0\0\0\377\0\0\0\377\7\7" "\7\377???\377\234\234\234\377???\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\34\34\34\377qqq\377\34\34\34\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\7\7\7\377???\377" "\234\234\234\377???\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\4\2\3\377\"\21\33\377h=U\377yHc\377uB^\377V%?\377\21\6\14\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\10\10\10\377" "\35\35\35\377\10\10\10\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\10\10" "\10\377\35\35\35\377\10\10\10\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\7\7\7\377\34\34\34\377\7\7\7\377\0\0\0\377\0\0\0\377\0\0" "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\10\10" "\10\377\35\35\35\377\10\10\10\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" "\0\0\0\377\0\0\0\377\3\1\2\377\21\7\14\377\24\10\17\377\24\10\17\377\21\6" "\14\377\3\1\2\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" "\377\0\0\0\377\0\0\0\377\1\1\1\377\0\0\0\377\0\0\0\377", }; #endif /* MIR_DRAW_MIR_IMAGE_H_*/ mir-0.1.8+14.04.20140411/examples/translucent_server.cpp0000644000015301777760000000211112322054223023141 0ustar pbusernogroup00000000000000/* * 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 */ #include "translucent_server_configuration.h" #include "mir/report_exception.h" #include "mir/run_mir.h" #include int main(int argc, char const* argv[]) try { mir::examples::TranslucentServerConfiguration config(argc, argv); run_mir(config, [&](mir::DisplayServer&){ config.launch_client(); }); return 0; } catch (...) { mir::report_exception(std::cerr); return 1; } mir-0.1.8+14.04.20140411/examples/render_surfaces.cpp0000644000015301777760000004403612322054247022405 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/compositor/display_buffer_compositor_factory.h" #include "mir/server_status_listener.h" #include "mir/compositor/display_buffer_compositor.h" #include "mir/options/default_configuration.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "mir/frontend/connector.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/geometry/size.h" #include "mir/geometry/rectangles.h" #include "mir/graphics/buffer_initializer.h" #include "mir/graphics/cursor.h" #include "mir/graphics/display.h" #include "mir/graphics/display_buffer.h" #include "mir/graphics/gl_context.h" #include "mir/shell/surface_factory.h" #include "mir/scene/surface.h" #include "mir/scene/surface_coordinator.h" #include "mir/run_mir.h" #include "mir/report_exception.h" #include "mir/raii.h" #include "mir_image.h" #include "buffer_render_target.h" #include "image_renderer.h" #include "server_configuration.h" #define GLM_FORCE_RADIANS #include #include #include #include #include #include #include #include namespace mg = mir::graphics; namespace mc = mir::compositor; namespace ms = mir::scene; namespace mf = mir::frontend; namespace mo = mir::options; namespace msh = mir::shell; namespace mi = mir::input; namespace geom = mir::geometry; namespace mt = mir::tools; namespace me = mir::examples; ///\page render_surfaces-example render_surfaces.cpp: A simple program using the mir library. ///\tableofcontents ///render_surfaces shows the use of mir to render some moving surfaces ///\section main main() /// The main() function uses a RenderSurfacesServerConfiguration to initialize and run mir. /// \snippet render_surfaces.cpp main_tag ///\section RenderSurfacesServerConfiguration RenderSurfacesServerConfiguration /// The configuration stubs out client connectivity and input. /// \snippet render_surfaces.cpp RenderSurfacesServerConfiguration_stubs_tag /// it also provides a bespoke buffer initializer /// \snippet render_surfaces.cpp RenderResourcesBufferInitializer_tag /// and a bespoke display buffer compositor /// \snippet render_surfaces.cpp RenderSurfacesDisplayBufferCompositor_tag ///\section Utilities Utility classes /// For smooth animation we need to track time and move surfaces accordingly ///\subsection StopWatch StopWatch /// \snippet render_surfaces.cpp StopWatch_tag ///\subsection Moveable Moveable /// \snippet render_surfaces.cpp Moveable_tag ///\example render_surfaces.cpp A simple program using the mir library. namespace { std::atomic created{false}; bool input_is_on = false; std::weak_ptr cursor; static const uint32_t bg_color = 0x00000000; static const uint32_t fg_color = 0xffdd4814; static const float min_alpha = 0.3f; void update_cursor(uint32_t bg_color, uint32_t fg_color) { if (auto cursor = ::cursor.lock()) { static const int width = 64; static const int height = 64; std::vector image(height * width, bg_color); for (int i = 0; i != width-1; ++i) { if (i < 16) { image[0 * height + i] = fg_color; image[1 * height + i] = fg_color; image[i * height + 0] = fg_color; image[i * height + 1] = fg_color; } image[i * height + i] = fg_color; image[(i+1) * height + i] = fg_color; image[i * height + i + 1] = fg_color; } cursor->set_image(image.data(), geom::Size{width, height}); } } void animate_cursor() { if (!input_is_on) { if (auto cursor = ::cursor.lock()) { static int cursor_pos = 0; if (++cursor_pos == 300) { cursor_pos = 0; static const uint32_t fg_colors[3] = { fg_color, 0xffffffff, 0x3f000000 }; static int fg_color = 0; if (++fg_color == 3) fg_color = 0; update_cursor(bg_color, fg_colors[fg_color]); } cursor->move_to(geom::Point{cursor_pos, cursor_pos}); } } } char const* const surfaces_to_render = "surfaces-to-render"; char const* const display_cursor = "display-cursor"; ///\internal [StopWatch_tag] // tracks elapsed time - for animation. class StopWatch { public: StopWatch() : start(std::chrono::high_resolution_clock::now()), last(start), now(last) { } void stop() { now = std::chrono::high_resolution_clock::now(); } double elapsed_seconds_since_start() { auto elapsed = now - start; float elapsed_sec = std::chrono::duration_cast(elapsed).count() / 1000000.0f; return elapsed_sec; } double elapsed_seconds_since_last_restart() { auto elapsed = now - last; float elapsed_sec = std::chrono::duration_cast(elapsed).count() / 1000000.0f; return elapsed_sec; } void restart() { std::swap(last, now); } private: std::chrono::high_resolution_clock::time_point start; std::chrono::high_resolution_clock::time_point last; std::chrono::high_resolution_clock::time_point now; }; ///\internal [StopWatch_tag] ///\internal [Moveable_tag] // Adapter to support movement of surfaces. class Moveable { public: Moveable() {} Moveable(std::shared_ptr const& s, const geom::Size& display_size, float dx, float dy, const glm::vec3& rotation_axis, float alpha_offset) : surface(s), display_size(display_size), x{static_cast(s->top_left().x.as_uint32_t())}, y{static_cast(s->top_left().y.as_uint32_t())}, w{static_cast(s->size().width.as_uint32_t())}, h{static_cast(s->size().height.as_uint32_t())}, dx{dx}, dy{dy}, rotation_axis(rotation_axis), alpha_offset{alpha_offset} { } void step() { stop_watch.stop(); float elapsed_sec = stop_watch.elapsed_seconds_since_last_restart(); float total_elapsed_sec = stop_watch.elapsed_seconds_since_start(); stop_watch.restart(); bool should_update = true; float new_x = x + elapsed_sec * dx; float new_y = y + elapsed_sec * dy; if (new_x < 0.0 || new_x + w > display_size.width.as_uint32_t()) { dx = -dx; should_update = false; } if (new_y < 0.0 || new_y + h > display_size.height.as_uint32_t()) { dy = -dy; should_update = false; } if (should_update) { surface->move_to({new_x, new_y}); x = new_x; y = new_y; } glm::mat4 trans = glm::rotate(glm::mat4(1.0f), glm::radians(total_elapsed_sec * 120.0f), rotation_axis); surface->set_transformation(trans); float const alpha_amplitude = (1.0f - min_alpha) / 2.0f; surface->set_alpha(min_alpha + alpha_amplitude + alpha_amplitude * sin(alpha_offset + 2 * M_PI * total_elapsed_sec / 3.0)); } private: std::shared_ptr surface; geom::Size display_size; float x; float y; float w; float h; float dx; float dy; StopWatch stop_watch; glm::vec3 rotation_axis; float alpha_offset; }; ///\internal [Moveable_tag] ///\internal [RenderSurfacesServerConfiguration_tag] // Extend the default configuration to manage moveables. class RenderSurfacesServerConfiguration : public me::ServerConfiguration { public: RenderSurfacesServerConfiguration(int argc, char const** argv) : ServerConfiguration([argc, argv] { auto result = std::make_shared(argc, argv); namespace po = boost::program_options; result->add_options() (surfaces_to_render, po::value()->default_value(5), "Number of surfaces to render") (display_cursor, po::value()->default_value(false), "Display test cursor. (If input is disabled it gets animated.)"); return result; }()) { } ///\internal [RenderSurfacesServerConfiguration_stubs_tag] // Stub out server connectivity. std::shared_ptr the_connector() override { struct NullConnector : public mf::Connector { void start() {} void stop() {} int client_socket_fd() const override { return 0; } void remove_endpoint() const override { } }; return std::make_shared(); } ///\internal [RenderSurfacesServerConfiguration_stubs_tag] ///\internal [RenderResourcesBufferInitializer_tag] // Override for a bespoke buffer initializer std::shared_ptr the_buffer_initializer() override { class RenderResourcesBufferInitializer : public mg::BufferInitializer { public: RenderResourcesBufferInitializer(std::unique_ptr gl_context) : gl_context{std::move(gl_context)} { } void operator()(mg::Buffer& buffer) { auto using_gl_context = mir::raii::paired_calls( [this] { gl_context->make_current(); }, [this] { gl_context->release_current(); }); mt::ImageRenderer img_renderer{mir_image.pixel_data, geom::Size{mir_image.width, mir_image.height}, mir_image.bytes_per_pixel}; mt::BufferRenderTarget brt{buffer}; brt.make_current(); img_renderer.render(); } private: std::unique_ptr const gl_context; }; return std::make_shared(the_display()->create_gl_context()); } ///\internal [RenderResourcesBufferInitializer_tag] // Unless the compositor starts before we create the surfaces it won't respond to // the change notification that causes. std::shared_ptr the_server_status_listener() { struct ServerStatusListener : mir::ServerStatusListener { ServerStatusListener(std::function create_surfaces, std::shared_ptr wrapped) : create_surfaces(create_surfaces), wrapped(wrapped) {} virtual void paused() override { wrapped->paused(); } virtual void resumed() override { wrapped->resumed(); } virtual void started() override { wrapped->started(); create_surfaces(); create_surfaces = []{}; } std::function create_surfaces; std::shared_ptr const wrapped; }; return server_status_listener( [this]() { auto wrapped = ServerConfiguration::the_server_status_listener(); return std::make_shared([this] { create_surfaces(); }, wrapped); }); } ///\internal [RenderSurfacesDisplayBufferCompositor_tag] // Decorate the DefaultDisplayBufferCompositor in order to move surfaces. std::shared_ptr the_display_buffer_compositor_factory() override { class RenderSurfacesDisplayBufferCompositor : public mc::DisplayBufferCompositor { public: RenderSurfacesDisplayBufferCompositor( std::unique_ptr db_compositor, std::vector& moveables) : db_compositor{std::move(db_compositor)}, moveables(moveables), frames{0} { } bool composite() { while (!created) std::this_thread::yield(); animate_cursor(); stop_watch.stop(); if (stop_watch.elapsed_seconds_since_last_restart() >= 1) { std::cout << "FPS: " << frames << " Frame Time: " << 1.0 / frames << std::endl; frames = 0; stop_watch.restart(); } glClearColor(0.0, 1.0, 0.0, 1.0); db_compositor->composite(); for (auto& m : moveables) m.step(); frames++; return false; } private: std::unique_ptr const db_compositor; StopWatch stop_watch; std::vector& moveables; uint32_t frames; }; class RenderSurfacesDisplayBufferCompositorFactory : public mc::DisplayBufferCompositorFactory { public: RenderSurfacesDisplayBufferCompositorFactory( std::shared_ptr const& factory, std::vector& moveables) : factory{factory}, moveables(moveables) { } std::unique_ptr create_compositor_for(mg::DisplayBuffer& display_buffer) { auto compositor = factory->create_compositor_for(display_buffer); auto raw = new RenderSurfacesDisplayBufferCompositor( std::move(compositor), moveables); return std::unique_ptr(raw); } private: std::shared_ptr const factory; std::vector& moveables; }; return std::make_shared( me::ServerConfiguration::the_display_buffer_compositor_factory(), moveables); } ///\internal [RenderSurfacesDisplayBufferCompositor_tag] // New function to initialize moveables with surfaces void create_surfaces() { moveables.resize(the_options()->get(surfaces_to_render)); std::cout << "Rendering " << moveables.size() << " surfaces" << std::endl; auto const display = the_display(); auto const surface_coordinator = the_surface_coordinator(); /* TODO: Get proper configuration */ geom::Rectangles view_area; display->for_each_display_buffer([&view_area](mg::DisplayBuffer const& db) { view_area.add(db.view_area()); }); geom::Size const display_size{view_area.bounding_rectangle().size}; uint32_t const surface_side{300}; geom::Size const surface_size{surface_side, surface_side}; float const angular_step = 2.0 * M_PI / moveables.size(); float const w = display_size.width.as_uint32_t(); float const h = display_size.height.as_uint32_t(); auto const surface_pf = the_buffer_allocator()->supported_pixel_formats()[0]; int i = 0; for (auto& m : moveables) { auto const s = surface_coordinator->add_surface( msh::a_surface().of_size(surface_size) .of_pixel_format(surface_pf) .of_buffer_usage(mg::BufferUsage::hardware), {}); /* * We call swap_buffers() twice so that the surface is * considers the first buffer to be posted. * (TODO There must be a better way!) */ { mg::Buffer* buffer{nullptr}; auto const complete = [&](mg::Buffer* new_buf){ buffer = new_buf; }; s->swap_buffers(buffer, complete); s->swap_buffers(buffer, complete); } /* * Place each surface at a different starting location and give it a * different speed, rotation and alpha offset. */ uint32_t const x = w * (0.5 + 0.25 * cos(i * angular_step)) - surface_side / 2.0; uint32_t const y = h * (0.5 + 0.25 * sin(i * angular_step)) - surface_side / 2.0; s->move_to({x, y}); m = Moveable(s, display_size, cos(0.1f + i * M_PI / 6.0f) * w / 3.0f, sin(0.1f + i * M_PI / 6.0f) * h / 3.0f, glm::vec3{(i % 3 == 0) * 1.0f, (i % 3 == 1) * 1.0f, (i % 3 == 2) * 1.0f}, 2.0f * M_PI * cos(i)); ++i; } created = true; } bool input_is_on() { return the_options()->get(mo::enable_input_opt); } std::weak_ptr the_cursor() { if (the_options()->get(display_cursor)) { return the_display()->the_cursor(); } else { return {}; } } private: std::vector moveables; }; ///\internal [RenderSurfacesServerConfiguration_tag] } int main(int argc, char const** argv) try { ///\internal [main_tag] RenderSurfacesServerConfiguration conf{argc, argv}; mir::run_mir(conf, [&](mir::DisplayServer&) { cursor = conf.the_cursor(); input_is_on = conf.input_is_on(); }); ///\internal [main_tag] return 0; } catch (...) { mir::report_exception(std::cerr); return 1; } mir-0.1.8+14.04.20140411/examples/eglapp.c0000644000015301777760000002775512322054223020146 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Daniel van Vugt */ #include "eglapp.h" #include "mir_toolkit/mir_client_library.h" #include #include #include #include #include #include #include float mir_eglapp_background_opacity = 1.0f; static const char appname[] = "egldemo"; static MirConnection *connection; static MirSurface *surface; static EGLDisplay egldisplay; static EGLSurface eglsurface; static volatile sig_atomic_t running = 0; #define CHECK(_cond, _err) \ if (!(_cond)) \ { \ printf("%s\n", (_err)); \ return 0; \ } void mir_eglapp_shutdown(void) { eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglTerminate(egldisplay); mir_surface_release_sync(surface); surface = NULL; mir_connection_release(connection); connection = NULL; } static void shutdown(int signum) { if (running) { running = 0; printf("Signal %d received. Good night.\n", signum); } } mir_eglapp_bool mir_eglapp_running(void) { return running; } void mir_eglapp_swap_buffers(void) { static time_t lasttime = 0; static int lastcount = 0; static int count = 0; time_t now = time(NULL); time_t dtime; int dcount; EGLint width, height; if (!running) return; eglSwapBuffers(egldisplay, eglsurface); count++; dcount = count - lastcount; dtime = now - lasttime; if (dtime) { printf("%d FPS\n", dcount); lasttime = now; lastcount = count; } /* * Querying the surface (actually the current buffer) dimensions here is * the only truly safe way to be sure that the dimensions we think we * have are those of the buffer being rendered to. But this should be * improved in future; https://bugs.launchpad.net/mir/+bug/1194384 */ if (eglQuerySurface(egldisplay, eglsurface, EGL_WIDTH, &width) && eglQuerySurface(egldisplay, eglsurface, EGL_HEIGHT, &height)) { glViewport(0, 0, width, height); } } static void mir_eglapp_handle_event(MirSurface* surface, MirEvent const* ev, void* context) { (void) surface; (void) context; if (ev->type == mir_event_type_key && ev->key.key_code == XKB_KEY_q && ev->key.action == mir_key_action_up) { running = 0; } else if (ev->type == mir_event_type_resize) { /* * FIXME: https://bugs.launchpad.net/mir/+bug/1194384 * It is unsafe to set the width and height here because we're in a * different thread to that doing the rendering. So we either need * support for event queuing (directing them to another thread) or * full single-threaded callbacks. (LP: #1194384). */ printf("Resized to %dx%d\n", ev->resize.width, ev->resize.height); } } static const MirDisplayOutput *find_active_output( const MirDisplayConfiguration *conf) { const MirDisplayOutput *output = NULL; int d; for (d = 0; d < (int)conf->num_outputs; d++) { const MirDisplayOutput *out = conf->outputs + d; if (out->used && out->connected && out->num_modes && out->current_mode < out->num_modes) { output = out; break; } } return output; } mir_eglapp_bool mir_eglapp_init(int argc, char *argv[], unsigned int *width, unsigned int *height) { EGLint ctxattribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; MirSurfaceParameters surfaceparm = { "eglappsurface", 256, 256, mir_pixel_format_xbgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; MirEventDelegate delegate = { mir_eglapp_handle_event, NULL }; EGLConfig eglconfig; EGLint neglconfigs; EGLContext eglctx; EGLBoolean ok; EGLint swapinterval = 1; char *mir_socket = NULL; if (argc > 1) { int i; for (i = 1; i < argc; i++) { mir_eglapp_bool help = 0; const char *arg = argv[i]; if (arg[0] == '-') { switch (arg[1]) { case 'b': { float alpha = 1.0f; arg += 2; if (!arg[0] && i < argc-1) { i++; arg = argv[i]; } if (sscanf(arg, "%f", &alpha) == 1) { mir_eglapp_background_opacity = alpha; } else { printf("Invalid opacity value: %s\n", arg); help = 1; } } break; case 'n': swapinterval = 0; break; case 'o': { unsigned int output_id = 0; arg += 2; if (!arg[0] && i < argc-1) { i++; arg = argv[i]; } if (sscanf(arg, "%u", &output_id) == 1) { surfaceparm.output_id = output_id; } else { printf("Invalid output ID: %s\n", arg); help = 1; } } break; case 'f': *width = 0; *height = 0; break; case 's': { unsigned int w, h; arg += 2; if (!arg[0] && i < argc-1) { i++; arg = argv[i]; } if (sscanf(arg, "%ux%u", &w, &h) == 2) { *width = w; *height = h; } else { printf("Invalid size: %s\n", arg); help = 1; } } break; case 'm': mir_socket = argv[++i]; break; case 'q': { FILE *unused = freopen("/dev/null", "a", stdout); (void)unused; break; } case 'h': default: help = 1; break; } } else { help = 1; } if (help) { printf("Usage: %s []\n" " -b Background opacity (0.0 - 1.0)\n" " -h Show this help text\n" " -f Force full screen\n" " -o ID Force placement on output monitor ID\n" " -n Don't sync to vblank\n" " -m socket Mir server socket\n" " -s WIDTHxHEIGHT Force surface size\n" " -q Quiet mode (no messages output)\n" , argv[0]); return 0; } } } connection = mir_connect_sync(mir_socket, appname); CHECK(mir_connection_is_valid(connection), "Can't get connection"); /* eglapps are interested in the screen size, so use mir_connection_create_display_config */ MirDisplayConfiguration* display_config = mir_connection_create_display_config(connection); const MirDisplayOutput *output = find_active_output(display_config); if (output == NULL) { printf("No active outputs found.\n"); return 0; } const MirDisplayMode *mode = &output->modes[output->current_mode]; unsigned int format[mir_pixel_formats]; unsigned int nformats; mir_connection_get_available_surface_formats(connection, format, mir_pixel_formats, &nformats); surfaceparm.pixel_format = format[0]; for (unsigned int f = 0; f < nformats; f++) { const int opaque = (format[f] == mir_pixel_format_xbgr_8888 || format[f] == mir_pixel_format_xrgb_8888 || format[f] == mir_pixel_format_bgr_888); if ((mir_eglapp_background_opacity == 1.0f && opaque) || (mir_eglapp_background_opacity < 1.0f && !opaque)) { surfaceparm.pixel_format = format[f]; break; } } printf("Current active output is %dx%d %+d%+d\n", mode->horizontal_resolution, mode->vertical_resolution, output->position_x, output->position_y); surfaceparm.width = *width > 0 ? *width : mode->horizontal_resolution; surfaceparm.height = *height > 0 ? *height : mode->vertical_resolution; mir_display_config_destroy(display_config); printf("Server supports %d of %d surface pixel formats. Using format: %d\n", nformats, mir_pixel_formats, surfaceparm.pixel_format); unsigned int bpp = 8 * MIR_BYTES_PER_PIXEL(surfaceparm.pixel_format); EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, EGL_BUFFER_SIZE, bpp, EGL_NONE }; surface = mir_connection_create_surface_sync(connection, &surfaceparm); CHECK(mir_surface_is_valid(surface), "Can't create a surface"); mir_surface_set_event_handler(surface, &delegate); egldisplay = eglGetDisplay( mir_connection_get_egl_native_display(connection)); CHECK(egldisplay != EGL_NO_DISPLAY, "Can't eglGetDisplay"); ok = eglInitialize(egldisplay, NULL, NULL); CHECK(ok, "Can't eglInitialize"); ok = eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs); CHECK(ok, "Could not eglChooseConfig"); CHECK(neglconfigs > 0, "No EGL config available"); eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, (EGLNativeWindowType)mir_surface_get_egl_native_window(surface), NULL); CHECK(eglsurface != EGL_NO_SURFACE, "eglCreateWindowSurface failed"); 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"); signal(SIGINT, shutdown); signal(SIGTERM, shutdown); *width = surfaceparm.width; *height = surfaceparm.height; eglSwapInterval(egldisplay, swapinterval); running = 1; return 1; } struct MirConnection* mir_eglapp_native_connection() { return connection; } struct MirSurface* mir_eglapp_native_surface() { return surface; } mir-0.1.8+14.04.20140411/examples/server_configuration.h0000644000015301777760000000271612322054223023126 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/examples/demo-inprocess-surface-client/0000755000015301777760000000000012322054703024346 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/examples/demo-inprocess-surface-client/inprocess_egl_client.cpp0000644000015301777760000001063712322054223031250 0ustar pbusernogroup00000000000000/* * 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 */ #include "inprocess_egl_client.h" #include "example_egl_helper.h" #include "mir/main_loop.h" #include "mir/shell/focus_controller.h" #include "mir/frontend/surface.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/shell/session.h" #include "mir/frontend/session.h" #include "mir/frontend/shell.h" #include "mir/geometry/size.h" #include "mir/graphics/buffer_properties.h" #include "mir/graphics/platform.h" #include "mir/input/input_receiver_thread.h" #include "mir/input/input_platform.h" #include "mir/graphics/internal_client.h" #include "mir/graphics/internal_surface.h" #include "mir/frontend/event_sink.h" #include "graphics.h" #include #include #include #include #include #include namespace mf = mir::frontend; namespace msh = mir::shell; namespace mg = mir::graphics; namespace me = mir::examples; namespace mircv = mir::input::receiver; namespace geom = mir::geometry; me::InprocessEGLClient::InprocessEGLClient( std::shared_ptr const& graphics_platform, std::shared_ptr const& shell, std::shared_ptr const& focus_controller) : graphics_platform(graphics_platform), shell(shell), focus_controller(focus_controller), client_thread(std::mem_fn(&InprocessEGLClient::thread_loop), this), terminate(false) { } me::InprocessEGLClient::~InprocessEGLClient() { terminate = true; auto session = focus_controller->focussed_application().lock(); if (session) session->force_requests_to_complete(); client_thread.join(); } namespace { struct NullEventSink : mf::EventSink { void handle_event(MirEvent const& /*e*/) {} void handle_lifecycle_event(MirLifecycleState /*state*/) {} void handle_display_config_change(mg::DisplayConfiguration const& /*config*/) {} }; } void me::InprocessEGLClient::thread_loop() { geom::Size const surface_size{512, 512}; ///\internal [setup_tag] auto params = msh::a_surface().of_name("Inprocess EGL Demo") .of_size(surface_size) .of_buffer_usage(mg::BufferUsage::hardware) .of_pixel_format(mir_pixel_format_argb_8888); auto session = shell->open_session(getpid(), "Inprocess client", std::make_shared()); // TODO: Why do we get an ID? ~racarr auto surface = session->get_surface(shell->create_surface_for(session, params)); auto input_platform = mircv::InputPlatform::create(); input_thread = input_platform->create_input_thread( surface->client_input_fd(), std::bind(std::mem_fn(&me::InprocessEGLClient::handle_event), this, std::placeholders::_1)); input_thread->start(); auto internal_client = graphics_platform->create_internal_client(); auto internal_surface = as_internal_surface(surface); me::EGLHelper helper(internal_client->egl_native_display(), internal_client->egl_native_window(internal_surface)); auto rc = eglMakeCurrent(helper.the_display(), helper.the_surface(), helper.the_surface(), helper.the_context()); assert(rc == EGL_TRUE); mir::draw::glAnimationBasic gl_animation; gl_animation.init_gl(); ///\internal [setup_tag] ///\internal [loop_tag] while(!terminate) { gl_animation.render_gl(); rc = eglSwapBuffers(helper.the_display(), helper.the_surface()); assert(rc == EGL_TRUE); gl_animation.step(); } (void)rc; input_thread->stop(); ///\internal [loop_tag] } void me::InprocessEGLClient::handle_event(MirEvent *event) { if (event->type != mir_event_type_key) return; if (event->key.action != mir_key_action_down) return; if (event->key.key_code != XKB_KEY_Escape) return; terminate = true; } mir-0.1.8+14.04.20140411/examples/demo-inprocess-surface-client/example_egl_helper.h0000644000015301777760000000261012322054223030334 0ustar pbusernogroup00000000000000/* * 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_EGL_HELPER_H_ #define MIR_EXAMPLES_EGL_HELPER_H_ #include namespace mir { namespace examples { /// Simple helper class for managing an EGL rendering with a sensible default configuration. class EGLHelper { public: EGLHelper(EGLNativeDisplayType native_display, EGLNativeWindowType native_surface); virtual ~EGLHelper(); EGLDisplay the_display() const; EGLContext the_context() const; EGLSurface the_surface() const; protected: EGLHelper(EGLHelper const&) = delete; EGLHelper& operator=(EGLHelper const&) = delete; private: EGLDisplay display; EGLContext context; EGLSurface surface; }; } } // namespace mir #endif // MIR_EXAMPLES_EGL_HELPER_H_ mir-0.1.8+14.04.20140411/examples/demo-inprocess-surface-client/example_egl_helper.cpp0000644000015301777760000000422212322054223030670 0ustar pbusernogroup00000000000000/* * 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 */ #include "example_egl_helper.h" #include namespace me = mir::examples; me::EGLHelper::EGLHelper(EGLNativeDisplayType native_display, EGLNativeWindowType native_window) { display = eglGetDisplay(native_display); assert(display != EGL_NO_DISPLAY); int major, minor, rc; rc = eglInitialize(display, &major, &minor); assert(rc == EGL_TRUE); assert(major == 1); assert(minor == 4); EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLConfig egl_config; int n; rc = eglChooseConfig(display, attribs, &egl_config, 1, &n); assert(rc == EGL_TRUE); assert(n == 1); (void)rc; surface = eglCreateWindowSurface(display, egl_config, native_window, nullptr); assert(surface != EGL_NO_SURFACE); EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; context = eglCreateContext(display, egl_config, EGL_NO_CONTEXT, context_attribs); assert(surface != EGL_NO_CONTEXT); } me::EGLHelper::~EGLHelper() { eglDestroySurface(display, surface); eglDestroyContext(display, context); eglTerminate(display); } EGLDisplay me::EGLHelper::the_display() const { return display; } EGLContext me::EGLHelper::the_context() const { return context; } EGLSurface me::EGLHelper::the_surface() const { return surface; } mir-0.1.8+14.04.20140411/examples/demo-inprocess-surface-client/CMakeLists.txt0000644000015301777760000000045512322054223027107 0ustar pbusernogroup00000000000000include_directories(..) add_executable(mir_demo_standalone_inprocess_egl demo_inprocess_surface_client.cpp inprocess_egl_client.cpp example_egl_helper.cpp ../server_configuration.cpp ) target_link_libraries(mir_demo_standalone_inprocess_egl mirserver mirdraw ) # TODO Install this demo? mir-0.1.8+14.04.20140411/examples/demo-inprocess-surface-client/inprocess_egl_client.h0000644000015301777760000000407112322054223030710 0ustar pbusernogroup00000000000000/* * 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_INPROCESS_EGL_CLIENT_H_ #define MIR_EXAMPLES_INPROCESS_EGL_CLIENT_H_ #include "mir_toolkit/event.h" #include #include #include namespace mir { class MainLoop; namespace input { namespace receiver { class InputReceiverThread; } } namespace graphics { class Platform; } namespace shell { class FocusController; } namespace frontend { class Shell; } namespace examples { /// Encapsulation of a simple threaded client demonstrating inprocess EGL rendering class InprocessEGLClient { public: InprocessEGLClient( std::shared_ptr const& graphics_platform, std::shared_ptr const& shell, std::shared_ptr const& focus_controller); ~InprocessEGLClient(); protected: InprocessEGLClient(InprocessEGLClient const&) = delete; InprocessEGLClient& operator=(InprocessEGLClient const&) = delete; private: std::shared_ptr const graphics_platform; std::shared_ptr const shell; std::shared_ptr const focus_controller; std::thread client_thread; std::shared_ptr input_thread; void thread_loop(); void handle_event(MirEvent *event); std::atomic terminate; }; } } // namespace mir #endif // MIR_EXAMPLES_INPROCESS_EGL_CLIENT_H_ mir-0.1.8+14.04.20140411/examples/demo-inprocess-surface-client/demo_inprocess_surface_client.cpp0000644000015301777760000000360312322054223033130 0ustar pbusernogroup00000000000000/* * 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 */ #include "inprocess_egl_client.h" #include "mir/run_mir.h" #include "../server_configuration.h" #include "mir/report_exception.h" #include namespace me = mir::examples; ///\page demo_inprocess_egl demo_inprocess_egl.cpp: A simple use of egl in process ///\section main main /// The main() function uses a default configuration for Mir and sets up an InprocessEGLClient /// that accesses the graphics platform and surface factory. /// \snippet demo_inprocess_egl.cpp main_tag /// This InprocessEGLClient sets up a single surface /// \snippet inprocess_egl_client.cpp setup_tag /// And loops updating the surface /// \snippet inprocess_egl_client.cpp loop_tag int main(int argc, char const* argv[]) try { ///\internal [main_tag] me::ServerConfiguration config(argc, argv); std::shared_ptr client; mir::run_mir(config, [&config, &client](mir::DisplayServer&) { client = std::make_shared( config.the_graphics_platform(), config.the_frontend_shell(), config.the_focus_controller()); }); ///\internal [main_tag] return 0; } catch (...) { mir::report_exception(std::cerr); return 1; } mir-0.1.8+14.04.20140411/examples/buffer_render_target.h0000644000015301777760000000276512322054223023053 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #ifndef MIR_TOOLS_BUFFER_RENDER_TARGET_H_ #define MIR_TOOLS_BUFFER_RENDER_TARGET_H_ #include #include #include namespace mir { namespace graphics { class Buffer; } namespace tools { class BufferRenderTarget { public: BufferRenderTarget(mir::graphics::Buffer& buffer); ~BufferRenderTarget(); void make_current(); private: class Resources { public: Resources() : fbo{0}, color_tex{0}, depth_rbo{0} { } ~Resources(); void setup(mir::graphics::Buffer& buffer); GLuint fbo; GLuint color_tex; GLuint depth_rbo; }; Resources resources; mir::graphics::Buffer& buffer; GLint old_fbo; GLint old_viewport[4]; }; } } #endif /* MIR_TOOLS_BUFFER_RENDER_TARGET_H_ */ mir-0.1.8+14.04.20140411/examples/translucent_server_configuration.h0000644000015301777760000000245312322054223025546 0ustar pbusernogroup00000000000000/* * 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_EXAMPLES_TRANSLUCENT_SERVER_CONFIGURATION_H_ #define MIR_EXAMPLES_TRANSLUCENT_SERVER_CONFIGURATION_H_ #include "basic_server_configuration.h" namespace mir { namespace examples { /** * \brief TranslucentServerConfiguration extends BasicServerConfiguration with a different pixel format selection */ class TranslucentServerConfiguration : public BasicServerConfiguration { public: TranslucentServerConfiguration(int argc, char const** argv); std::shared_ptr the_display_configuration_policy(); }; } } #endif /* MIR_EXAMPLES_TRANSLUCENT_SERVER_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/examples/graphics.h0000644000015301777760000000210512322054223020461 0ustar pbusernogroup00000000000000/* * 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_DRAW_GRAPHICS #define MIR_DRAW_GRAPHICS #include namespace mir { namespace draw { class glAnimationBasic { public: glAnimationBasic(); void init_gl(); void render_gl(); void step(); int texture_width(); int texture_height(); private: GLuint program, vPositionAttr, uvCoord, slideUniform; float slide; }; } } #endif /* MIR_DRAW_GRAPHICS */ mir-0.1.8+14.04.20140411/examples/eglflash.c0000644000015301777760000000314612322054223020447 0ustar pbusernogroup00000000000000/* * Trivial GL demo; flashes the screen. Showing how simple life is with eglapp. * * 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 . * * Author: Daniel van Vugt */ #include "eglapp.h" #include #include #include int main(int argc, char *argv[]) { unsigned int width = 0, height = 0; if (!mir_eglapp_init(argc, argv, &width, &height)) return 1; /* This is probably the simplest GL you can do */ while (mir_eglapp_running()) { glClearColor(1.0f, 0.0f, 0.0f, mir_eglapp_background_opacity); glClear(GL_COLOR_BUFFER_BIT); mir_eglapp_swap_buffers(); sleep(1); glClearColor(0.0f, 1.0f, 0.0f, mir_eglapp_background_opacity); glClear(GL_COLOR_BUFFER_BIT); mir_eglapp_swap_buffers(); sleep(1); glClearColor(0.0f, 0.0f, 1.0f, mir_eglapp_background_opacity); glClear(GL_COLOR_BUFFER_BIT); mir_eglapp_swap_buffers(); sleep(1); } mir_eglapp_shutdown(); return 0; } mir-0.1.8+14.04.20140411/examples/pixel_format_selector.h0000644000015301777760000000270512322054223023260 0ustar pbusernogroup00000000000000/* * 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_EXAMPLES_SELECT_PIXEL_FORMAT_H #define MIR_EXAMPLES_SELECT_PIXEL_FORMAT_H #include "mir/graphics/display_configuration_policy.h" #include namespace mir { namespace examples { /** * \brief Example of a DisplayConfigurationPolicy that tries to find * an opaque or transparent pixel format, or falls back to the default * if not found. */ class PixelFormatSelector : public graphics::DisplayConfigurationPolicy { public: PixelFormatSelector(std::shared_ptr const& base_policy, bool with_alpha); virtual void apply_to(graphics::DisplayConfiguration& conf); private: std::shared_ptr const base_policy; bool const with_alpha; }; } } #endif mir-0.1.8+14.04.20140411/examples/translucent_server_configuration.cpp0000644000015301777760000000250612322054223026100 0ustar pbusernogroup00000000000000/* * 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 */ #include "translucent_server_configuration.h" #include "pixel_format_selector.h" namespace mir { namespace examples { TranslucentServerConfiguration::TranslucentServerConfiguration(int argc, char const** argv) : BasicServerConfiguration(argc, argv) { } std::shared_ptr TranslucentServerConfiguration::the_display_configuration_policy() { return display_configuration_policy( [this]() -> std::shared_ptr { return std::make_shared(BasicServerConfiguration::the_display_configuration_policy(), true); }); } } } mir-0.1.8+14.04.20140411/examples/CMakeLists.txt0000644000015301777760000001031312322054223021250 0ustar pbusernogroup00000000000000 #its a bit troubling that these need to be included for demo_input_filter include_directories(${MIR_3RD_PARTY_INCLUDE_DIRECTORIES}) include_directories(${MIR_ANDROID_INCLUDE_DIRECTORIES}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -fno-strict-aliasing -Wextra") add_library(eglapp STATIC eglapp.c ) target_link_libraries(eglapp mirclient ${EGL_LIBRARIES} ${GLESv2_LIBRARIES} ) add_executable(mir_demo_client_eglflash eglflash.c ) target_link_libraries(mir_demo_client_eglflash eglapp ) add_executable(mir_demo_client_egltriangle egltriangle.c ) target_link_libraries(mir_demo_client_egltriangle eglapp ) add_executable(mir_demo_client_eglplasma eglplasma.c ) target_link_libraries(mir_demo_client_eglplasma eglapp ) add_executable(mir_demo_client_basic basic.c ) target_link_libraries(mir_demo_client_basic mirclient mirprotobuf ${Boost_LIBRARIES} ${PROTOBUF_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) add_executable(mir_demo_client_multiwin multiwin.c) target_link_libraries(mir_demo_client_multiwin mirclient) add_executable(mir_demo_client_fingerpaint fingerpaint.c) target_link_libraries(mir_demo_client_fingerpaint mirclient) add_executable(mir_demo_client_progressbar progressbar.c) target_link_libraries(mir_demo_client_progressbar mirclient) add_executable(mir_demo_client_display_config demo_client_display_config.c) target_link_libraries(mir_demo_client_display_config eglapp) add_executable(mir_demo_client_flicker flicker.c ) target_link_libraries(mir_demo_client_flicker mirclient mirprotobuf ${Boost_LIBRARIES} ${PROTOBUF_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ) add_executable(mir_demo_client_scroll scroll.cpp ) target_link_libraries(mir_demo_client_scroll mirdraw mirclient mirprotobuf ${Boost_LIBRARIES} ${PROTOBUF_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${EGL_LIBRARIES} ${GLESv2_LIBRARIES} ) add_library(mirdraw STATIC graphics_utils.cpp) target_link_libraries(mirdraw ${GLESv2_LIBRARIES}) include_directories( ${PROJECT_SOURCE_DIR}/include/server ${PROJECT_SOURCE_DIR}/include/client ${PROJECT_SOURCE_DIR}/include/platform ${GLESv2_INCLUDE_DIRS} ) add_executable(mir_demo_standalone_render_to_fb render_to_fb.cpp ) target_link_libraries(mir_demo_standalone_render_to_fb mirserver mirlogging mirdraw ${Boost_LIBRARIES} ) add_executable(mir_demo_standalone_render_overlays render_overlays.cpp ) target_link_libraries(mir_demo_standalone_render_overlays mirserver mirlogging mirdraw mirtestdraw ) set(RENDER_SURFACES_SOURCES render_surfaces.cpp buffer_render_target.cpp image_renderer.cpp server_configuration.cpp ) add_executable(mir_demo_standalone_render_surfaces ${RENDER_SURFACES_SOURCES}) target_link_libraries(mir_demo_standalone_render_surfaces mirserver mirshell mirsharedgeometry ${Boost_LIBRARIES} ) add_executable(mir_demo_standalone_input_filter demo_input_filter.cpp server_configuration.cpp ) target_link_libraries(mir_demo_standalone_input_filter mirserver ) set (INSTALL_DEMOS mir_demo_client_basic mir_demo_client_flicker mir_demo_client_scroll mir_demo_client_eglflash mir_demo_client_egltriangle mir_demo_client_eglplasma mir_demo_client_fingerpaint mir_demo_client_multiwin mir_demo_client_display_config mir_demo_client_progressbar mir_demo_standalone_input_filter mir_demo_standalone_render_to_fb mir_demo_standalone_render_surfaces ) add_subdirectory(demo-inprocess-surface-client) add_subdirectory(demo-shell) install(TARGETS ${INSTALL_DEMOS} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) add_executable(mir_demo_server_basic basic_server.cpp basic_server_configuration.cpp server_configuration.cpp ) target_link_libraries(mir_demo_server_basic mirserver ${Boost_LIBRARIES} ) install(TARGETS mir_demo_server_basic RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) add_executable(mir_demo_server_translucent translucent_server.cpp translucent_server_configuration.cpp pixel_format_selector.cpp basic_server_configuration.cpp server_configuration.cpp ) target_link_libraries(mir_demo_server_translucent mirserver ${Boost_LIBRARIES} ) install(TARGETS mir_demo_server_translucent RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) mir-0.1.8+14.04.20140411/examples/eglplasma.c0000644000015301777760000001441712322054223020632 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Daniel van Vugt */ #include "eglapp.h" #include #include #include static GLuint load_shader(const char *src, GLenum type) { GLuint shader = glCreateShader(type); if (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; } } return shader; } /* Colours from http://design.ubuntu.com/brand/colour-palette */ #define DARK_AUBERGINE 0.17254902f, 0.0f, 0.117647059f #define MID_AUBERGINE 0.368627451f, 0.152941176f, 0.31372549f #define ORANGE 0.866666667f, 0.282352941f, 0.141414141f int main(int argc, char *argv[]) { const char vshadersrc[] = "attribute vec4 vPosition; \n" "varying vec2 texcoord; \n" "void main() \n" "{ \n" " gl_Position = vPosition; \n" " texcoord = vec2(vPosition) * vec2(0.5) + vec2(0.5); \n" "} \n"; const char fshadersrc[] = "precision mediump float; \n" "uniform float theta; \n" "varying vec2 texcoord; \n" "uniform vec3 low_color, high_color; \n" " \n" "vec3 gradient(float x) \n" "{ \n" " vec3 col; \n" " const vec3 white = vec3(1.0, 1.0, 1.0); \n" " if (x < 0.333) \n" " col = x * low_color / 0.333; \n" " else if (x < 0.666) \n" " col = (x - 0.333) * (high_color - low_color) / \n" " 0.333 + low_color; \n" " else \n" " col = (x - 0.666) * (white - high_color) / \n" " 0.333 + high_color; \n" " return col; \n" "} \n" " \n" "void main() \n" "{ \n" " const float pi2 = 6.283185308; \n" " float u = texcoord.x * pi2; \n" " float v = texcoord.y * pi2; \n" " float us = (cos(1.1 * u + 7.0 * theta) + \n" " cos(2.3 * v * cos(1.0 * theta)) + \n" " cos(0.3 * u * cos(3.0 * theta)) \n" " ) / 3.0; \n" " float vs = (cos(2.3 * v + 8.0 * theta) + \n" " cos(1.3 * u * cos(3.0 * theta)) + \n" " cos(1.7 * v * cos(2.0 * theta)) \n" " ) / 3.0; \n" " float x = (us * vs + 1.0) / 2.0; \n" " gl_FragColor = vec4(gradient(x), 1.0); \n" "} \n"; const GLfloat vertices[] = { -1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f,-1.0f, }; const float pi2 = 6.283185308f; GLuint vshader, fshader, prog; GLint linked, low_color, high_color, vpos, theta; unsigned int width = 0, height = 0; GLfloat angle = 0.0f; if (!mir_eglapp_init(argc, argv, &width, &height)) return 1; vshader = load_shader(vshadersrc, GL_VERTEX_SHADER); assert(vshader); fshader = load_shader(fshadersrc, GL_FRAGMENT_SHADER); assert(fshader); prog = glCreateProgram(); assert(prog); glAttachShader(prog, vshader); glAttachShader(prog, fshader); glLinkProgram(prog); glGetProgramiv(prog, GL_LINK_STATUS, &linked); if (!linked) { GLchar log[1024]; glGetProgramInfoLog(prog, sizeof log - 1, NULL, log); log[sizeof log - 1] = '\0'; printf("Link failed: %s\n", log); return 2; } glViewport(0, 0, width, height); glUseProgram(prog); vpos = glGetAttribLocation(prog, "vPosition"); low_color = glGetUniformLocation(prog, "low_color"); high_color = glGetUniformLocation(prog, "high_color"); theta = glGetUniformLocation(prog, "theta"); glUniform3f(low_color, DARK_AUBERGINE); glUniform3f(high_color, ORANGE); glVertexAttribPointer(vpos, 2, GL_FLOAT, GL_FALSE, 0, vertices); glEnableVertexAttribArray(0); while (mir_eglapp_running()) { glUniform1f(theta, angle); angle += 0.005f; if (angle > pi2) angle -= pi2; glDrawArrays(GL_TRIANGLE_FAN, 0, 4); mir_eglapp_swap_buffers(); } mir_eglapp_shutdown(); return 0; } mir-0.1.8+14.04.20140411/examples/eglapp.h0000644000015301777760000000241712322054223020137 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Daniel van Vugt */ #ifndef __EGLAPP_H__ #define __EGLAPP_H__ #ifdef __cplusplus extern "C" { #endif typedef int mir_eglapp_bool; struct MirConnection; struct MirSurface; extern float mir_eglapp_background_opacity; mir_eglapp_bool mir_eglapp_init(int argc, char *argv[], unsigned int *width, unsigned int *height); void mir_eglapp_swap_buffers(void); mir_eglapp_bool mir_eglapp_running(void); void mir_eglapp_shutdown(void); struct MirConnection* mir_eglapp_native_connection(); struct MirSurface* mir_eglapp_native_surface(); #ifdef __cplusplus } #endif #endif mir-0.1.8+14.04.20140411/examples/image_renderer.cpp0000644000015301777760000002003112322054223022162 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "image_renderer.h" // Unfortunately we have to ignore warnings/errors in 3rd party code. #pragma GCC diagnostic push #pragma GCC diagnostic warning "-Wall" #include #pragma GCC diagnostic pop #define GLM_FORCE_RADIANS #include #include #include #include #include namespace mt = mir::tools; namespace { const GLchar* vertex_shader_src = { "attribute vec3 position;\n" "varying vec2 v_texcoord;\n" "void main() {\n" " gl_Position = vec4(position, 1.0);\n" " v_texcoord = position.xy * 0.5 + 0.5;\n" "}\n" }; const GLchar* fragment_shader_src = { "precision mediump float;\n" "uniform sampler2D tex;\n" "varying vec2 v_texcoord;\n" "void main() {\n" " gl_FragColor = texture2D(tex, v_texcoord);\n" "}\n" }; glm::vec3 vertex_attribs[4] = { glm::vec3{-1.0f, 1.0f, 0.0f}, glm::vec3{-1.0f, -1.0f, 0.0f}, glm::vec3{1.0f, 1.0f, 0.0f}, glm::vec3{1.0f, -1.0f, 0.0f} }; typedef void(*MirGLGetObjectInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); typedef void(*MirGLGetObjectiv)(GLuint, GLenum, GLint *); void throw_with_object_log(MirGLGetObjectInfoLog getObjectInfoLog, MirGLGetObjectiv getObjectiv, std::string const & msg, GLuint object) { GLint object_log_length = 0; (*getObjectiv)(object, GL_INFO_LOG_LENGTH, &object_log_length); GLuint const object_log_buffer_length = object_log_length + 1; std::vector log_chars(object_log_buffer_length); (*getObjectInfoLog)(object, object_log_buffer_length, NULL, log_chars.data()); std::string object_info_err(msg + "\n"); object_info_err.append(log_chars.begin(), log_chars.end() - 1); BOOST_THROW_EXCEPTION(std::runtime_error(object_info_err)); } class GLState { public: GLState(GLint attrib_loc) : attrib_loc{attrib_loc} { glGetIntegerv(GL_CURRENT_PROGRAM, &program); glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture); glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &buffer); glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture_unit); if (attrib_loc >= 0) { glGetVertexAttribiv(attrib_loc, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &attrib_enabled); glGetVertexAttribiv(attrib_loc, GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib_size); glGetVertexAttribiv(attrib_loc, GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib_type); glGetVertexAttribiv(attrib_loc, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &attrib_normalized); glGetVertexAttribiv(attrib_loc, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib_stride); glGetVertexAttribPointerv(attrib_loc, GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib_pointer); } } GLState() : GLState{invalid_attrib_loc} {} ~GLState() { glUseProgram(program); glBindTexture(GL_TEXTURE_2D, texture); glBindBuffer(GL_ARRAY_BUFFER, buffer); glActiveTexture(active_texture_unit); if (attrib_loc >= 0) { glVertexAttribPointer(attrib_loc, attrib_size, attrib_type, attrib_normalized, attrib_stride, attrib_pointer); if (attrib_enabled) glEnableVertexAttribArray(attrib_loc); else glDisableVertexAttribArray(attrib_loc); } } private: static GLint const invalid_attrib_loc = -1; GLint program = 0; GLint texture = 0; GLint buffer = 0; GLint active_texture_unit = 0; GLint attrib_loc = invalid_attrib_loc; GLint attrib_enabled = 0; GLint attrib_size = 0; GLint attrib_type = 0; GLint attrib_normalized = 0; GLint attrib_stride = 0; GLvoid* attrib_pointer = nullptr; }; } mt::ImageRenderer::ImageRenderer(const uint8_t* pixel_data, mir::geometry::Size size, uint32_t bytes_per_pixel) { GLState gl_state; resources.setup(); /* Upload the texture */ glBindTexture(GL_TEXTURE_2D, resources.texture); GLenum format = (bytes_per_pixel == 3) ? GL_RGB : GL_RGBA; glTexImage2D(GL_TEXTURE_2D, 0, format, size.width.as_uint32_t(), size.height.as_uint32_t(), 0, format, GL_UNSIGNED_BYTE, pixel_data); } mt::ImageRenderer::Resources::~Resources() { if (vertex_shader) glDeleteShader(vertex_shader); if (fragment_shader) glDeleteShader(fragment_shader); if (program) glDeleteProgram(program); if (vertex_attribs_vbo) glDeleteBuffers(1, &vertex_attribs_vbo); if (texture) glDeleteTextures(1, &texture); } void mt::ImageRenderer::Resources::setup() { GLint param = 0; /* Create shaders and program */ vertex_shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex_shader, 1, &vertex_shader_src, 0); glCompileShader(vertex_shader); glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, ¶m); if (param == GL_FALSE) { throw_with_object_log(glGetShaderInfoLog, glGetShaderiv, "Failed to compile vertex shader:", vertex_shader); } fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment_shader, 1, &fragment_shader_src, 0); glCompileShader(fragment_shader); glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, ¶m); if (param == GL_FALSE) { throw_with_object_log(glGetShaderInfoLog, glGetShaderiv, "Failed to compile fragment shader:", fragment_shader); } program = glCreateProgram(); glAttachShader(program, vertex_shader); glAttachShader(program, fragment_shader); glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, ¶m); if (param == GL_FALSE) { throw_with_object_log(glGetProgramInfoLog, glGetProgramiv, "Failed to link shader program:", program); } glUseProgram(program); /* Set up program variables */ GLint tex_loc = glGetUniformLocation(program, "tex"); position_attr_loc = glGetAttribLocation(program, "position"); /* Create the texture */ glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glUniform1i(tex_loc, 0); /* Create VBO */ glGenBuffers(1, &vertex_attribs_vbo); glBindBuffer(GL_ARRAY_BUFFER, vertex_attribs_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_attribs), glm::value_ptr(vertex_attribs[0]), GL_STATIC_DRAW); } void mt::ImageRenderer::render() { GLState gl_state(resources.position_attr_loc); glUseProgram(resources.program); glActiveTexture(GL_TEXTURE0); /* Set up vertex attribute data */ glBindBuffer(GL_ARRAY_BUFFER, resources.vertex_attribs_vbo); glVertexAttribPointer(resources.position_attr_loc, 3, GL_FLOAT, GL_FALSE, 0, 0); glBindTexture(GL_TEXTURE_2D, resources.texture); /* Draw */ glEnableVertexAttribArray(resources.position_attr_loc); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } mir-0.1.8+14.04.20140411/examples/fingerpaint.c0000644000015301777760000002747112322054223021177 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Daniel van Vugt */ #include "mir_toolkit/mir_client_library.h" #include #include #include #include #include /* sleep() */ #include #define BYTES_PER_PIXEL(f) ((f) == mir_pixel_format_bgr_888 ? 3 : 4) #define MIN(a, b) ((a) <= (b) ? (a) : (b)) typedef struct { uint8_t r, g, b, a; } Color; static volatile sig_atomic_t running = 1; static void shutdown(int signum) { if (running) { running = 0; printf("Signal %d received. Good night.\n", signum); } } static void blend(uint32_t *dest, uint32_t src, int alpha_shift) { uint8_t *d = (uint8_t*)dest; uint8_t *s = (uint8_t*)&src; uint32_t src_alpha = (uint32_t)(src >> alpha_shift) & 0xff; uint32_t dest_alpha = 0xff - src_alpha; int i; for (i = 0; i < 4; i++) { d[i] = (uint8_t) ( ( ((uint32_t)d[i] * dest_alpha) + ((uint32_t)s[i] * src_alpha) ) >> 8 /* Close enough, and faster than /255 */ ); } *dest |= (0xff << alpha_shift); /* Restore alpha 1.0 in the destination */ } static void put_pixels(void *where, int count, MirPixelFormat format, const Color *color) { uint32_t pixel = 0; int alpha_shift = -1; int n; /* * We are blending in software, so can pretend that * mir_pixel_format_abgr_8888 == mir_pixel_format_xbgr_8888 * mir_pixel_format_argb_8888 == mir_pixel_format_xrgb_8888 */ switch (format) { case mir_pixel_format_abgr_8888: case mir_pixel_format_xbgr_8888: alpha_shift = 24; pixel = (uint32_t)color->a << 24 | (uint32_t)color->b << 16 | (uint32_t)color->g << 8 | (uint32_t)color->r; break; case mir_pixel_format_argb_8888: case mir_pixel_format_xrgb_8888: alpha_shift = 24; pixel = (uint32_t)color->a << 24 | (uint32_t)color->r << 16 | (uint32_t)color->g << 8 | (uint32_t)color->b; break; case mir_pixel_format_bgr_888: for (n = 0; n < count; n++) { uint8_t *p = (uint8_t*)where + n * 3; p[0] = color->b; p[1] = color->g; p[2] = color->r; } count = 0; break; default: count = 0; break; } if (alpha_shift >= 0) { for (n = 0; n < count; n++) blend((uint32_t*)where + n, pixel, alpha_shift); } else { for (n = 0; n < count; n++) ((uint32_t*)where)[n] = pixel; } } static void clear_region(const MirGraphicsRegion *region, const Color *color) { int y; char *row = region->vaddr; for (y = 0; y < region->height; y++) { put_pixels(row, region->width, region->pixel_format, color); row += region->stride; } } static void draw_box(const MirGraphicsRegion *region, int x, int y, int size, const Color *color) { if (x >= 0 && y >= 0 && x+size < region->width && y+size < region->height) { int j; char *row = region->vaddr + (y * region->stride) + (x * BYTES_PER_PIXEL(region->pixel_format)); for (j = 0; j < size; j++) { put_pixels(row, size, region->pixel_format, color); row += region->stride; } } } static void copy_region(const MirGraphicsRegion *dest, const MirGraphicsRegion *src) { int height = MIN(src->height, dest->height); int width = MIN(src->width, dest->width); int y; const char *srcrow = src->vaddr; char *destrow = dest->vaddr; int copy = width * BYTES_PER_PIXEL(dest->pixel_format); for (y = 0; y < height; y++) { memcpy(destrow, srcrow, copy); srcrow += src->stride; destrow += dest->stride; } } static void redraw(MirSurface *surface, const MirGraphicsRegion *canvas) { MirGraphicsRegion backbuffer; mir_surface_get_graphics_region(surface, &backbuffer); copy_region(&backbuffer, canvas); mir_surface_swap_buffers_sync(surface); } static void on_event(MirSurface *surface, const MirEvent *event, void *context) { MirGraphicsRegion *canvas = (MirGraphicsRegion*)context; static const Color color[] = { {0x80, 0xff, 0x00, 0xff}, {0x00, 0xff, 0x80, 0xff}, {0xff, 0x00, 0x80, 0xff}, {0xff, 0x80, 0x00, 0xff}, {0x00, 0x80, 0xff, 0xff}, {0x80, 0x00, 0xff, 0xff}, {0xff, 0xff, 0x00, 0xff}, {0x00, 0xff, 0xff, 0xff}, {0xff, 0x00, 0xff, 0xff}, {0xff, 0x00, 0x00, 0xff}, {0x00, 0xff, 0x00, 0xff}, {0x00, 0x00, 0xff, 0xff}, }; if (event->type == mir_event_type_motion) { static size_t base_color = 0; static size_t max_fingers = 0; static float max_pressure = 1.0f; // FIXME: https://bugs.launchpad.net/mir/+bug/1197108 MirMotionAction masked_action = event->motion.action & ~0xff00; if (masked_action == mir_motion_action_up) { base_color = (base_color + max_fingers) % (sizeof(color)/sizeof(color[0])); max_fingers = 0; } if (masked_action == mir_motion_action_move || masked_action == mir_motion_action_down) { size_t p; if (event->motion.pointer_count > max_fingers) max_fingers = event->motion.pointer_count; for (p = 0; p < event->motion.pointer_count; p++) { int x = event->motion.pointer_coordinates[p].x; int y = event->motion.pointer_coordinates[p].y; int radius = event->motion.pointer_coordinates[p].size * 50.0f + 1.0f; size_t c = (base_color + p) % (sizeof(color)/sizeof(color[0])); Color tone = color[c]; float pressure = event->motion.pointer_coordinates[p].pressure; if (pressure > max_pressure) max_pressure = pressure; pressure /= max_pressure; tone.a *= pressure; draw_box(canvas, x - radius, y - radius, 2*radius, &tone); } redraw(surface, canvas); } } else if (event->type == mir_event_type_resize) { /* FIXME: https://bugs.launchpad.net/mir/+bug/1194384 * mir_event_type_resize will arrive in a different thread to that of * mir_event_type_motion, so we cannot safely redraw from this thread. * Either the callbacks will need to become thread-safe, or we'd have * to employ some non-trivial event queuing and inter-thread signals, * which I think is beyond the scope of this example code. * * redraw(surface, canvas); */ } } static const MirDisplayOutput *find_active_output( const MirDisplayConfiguration *conf) { const MirDisplayOutput *output = NULL; int d; for (d = 0; d < (int)conf->num_outputs; d++) { const MirDisplayOutput *out = conf->outputs + d; if (out->used && out->connected && out->num_modes && out->current_mode < out->num_modes) { output = out; break; } } return output; } int main(int argc, char *argv[]) { static const Color background = {0x40, 0x40, 0x40, 0xff}; MirConnection *conn; MirSurfaceParameters parm; MirSurface *surf; MirGraphicsRegion canvas; MirEventDelegate delegate = {&on_event, &canvas}; unsigned int f; char *mir_socket = NULL; if (argc > 1) { int i; for (i = 1; i < argc; i++) { int help = 0; const char *arg = argv[i]; if (arg[0] == '-') { switch (arg[1]) { case 'm': mir_socket = argv[++i]; break; case 'h': default: help = 1; break; } } else { help = 1; } if (help) { printf("Usage: %s []\n" " -h Show this help text\n" " -m socket Mir server socket\n" , argv[0]); return 0; } } } conn = mir_connect_sync(mir_socket, argv[0]); if (!mir_connection_is_valid(conn)) { fprintf(stderr, "Could not connect to a display server.\n"); return 1; } MirDisplayConfiguration *display_config = mir_connection_create_display_config(conn); const MirDisplayOutput *dinfo = find_active_output(display_config); if (dinfo == NULL) { fprintf(stderr, "No active outputs found.\n"); mir_connection_release(conn); return 1; } parm.buffer_usage = mir_buffer_usage_software; parm.output_id = mir_display_output_id_invalid; unsigned int const pf_size = 32; MirPixelFormat formats[pf_size]; unsigned int valid_formats; mir_connection_get_available_surface_formats(conn, formats, pf_size, &valid_formats); parm.pixel_format = mir_pixel_format_invalid; for (f = 0; f < valid_formats; f++) { if (BYTES_PER_PIXEL(formats[f]) == 4) { parm.pixel_format = formats[f]; break; } } if (parm.pixel_format == mir_pixel_format_invalid) { fprintf(stderr, "Could not find a fast 32-bit pixel format\n"); mir_connection_release(conn); return 1; } parm.name = "Paint Canvas"; parm.width = dinfo->modes[dinfo->current_mode].horizontal_resolution; parm.height = dinfo->modes[dinfo->current_mode].vertical_resolution; mir_display_config_destroy(display_config); surf = mir_connection_create_surface_sync(conn, &parm); if (surf != NULL) { mir_surface_set_event_handler(surf, &delegate); canvas.width = parm.width; canvas.height = parm.height; canvas.stride = canvas.width * BYTES_PER_PIXEL(parm.pixel_format); canvas.pixel_format = parm.pixel_format; canvas.vaddr = (char*)malloc(canvas.stride * canvas.height); if (canvas.vaddr != NULL) { signal(SIGINT, shutdown); signal(SIGTERM, shutdown); clear_region(&canvas, &background); redraw(surf, &canvas); while (running) { sleep(1); /* Is there a better way yet? */ } /* Ensure canvas won't be used after it's freed */ mir_surface_set_event_handler(surf, NULL); free(canvas.vaddr); } else { fprintf(stderr, "Failed to malloc canvas\n"); } mir_surface_release_sync(surf); } else { fprintf(stderr, "mir_connection_create_surface_sync failed\n"); } mir_connection_release(conn); return 0; } mir-0.1.8+14.04.20140411/examples/basic_server.cpp0000644000015301777760000000207012322054223021664 0ustar pbusernogroup00000000000000/* * 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 */ #include "basic_server_configuration.h" #include "mir/report_exception.h" #include "mir/run_mir.h" #include int main(int argc, char const* argv[]) try { mir::examples::BasicServerConfiguration config(argc, argv); run_mir(config, [&](mir::DisplayServer&){ config.launch_client(); }); return 0; } catch (...) { mir::report_exception(std::cerr); return 1; } mir-0.1.8+14.04.20140411/examples/multiwin.c0000644000015301777760000001317112322054223020531 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Daniel van Vugt */ #include "mir_toolkit/mir_client_library.h" #include #include #include #include typedef struct { uint8_t r, g, b, a; } Color; typedef struct { MirSurface *surface; Color fill; } Window; static volatile sig_atomic_t running = 1; static void shutdown(int signum) { if (running) { running = 0; printf("Signal %d received. Good night.\n", signum); } } static void put_pixels(void *where, int count, MirPixelFormat format, const Color *color) { uint32_t pixel = 0; int n; switch (format) { case mir_pixel_format_abgr_8888: pixel = (uint32_t)color->a << 24 | (uint32_t)color->b << 16 | (uint32_t)color->g << 8 | (uint32_t)color->r; break; case mir_pixel_format_xbgr_8888: pixel = (uint32_t)color->b << 16 | (uint32_t)color->g << 8 | (uint32_t)color->r; break; case mir_pixel_format_argb_8888: pixel = (uint32_t)color->a << 24 | (uint32_t)color->r << 16 | (uint32_t)color->g << 8 | (uint32_t)color->b; break; case mir_pixel_format_xrgb_8888: pixel = (uint32_t)color->r << 16 | (uint32_t)color->g << 8 | (uint32_t)color->b; break; case mir_pixel_format_bgr_888: for (n = 0; n < count; n++) { uint8_t *p = (uint8_t*)where + n * 3; p[0] = color->b; p[1] = color->g; p[2] = color->r; } count = 0; break; default: count = 0; break; } for (n = 0; n < count; n++) ((uint32_t*)where)[n] = pixel; } static void clear_region(const MirGraphicsRegion *region, const Color *color) { int y; char *row = region->vaddr; for (y = 0; y < region->height; y++) { put_pixels(row, region->width, region->pixel_format, color); row += region->stride; } } static void draw_window(Window *win) { MirGraphicsRegion region; mir_surface_get_graphics_region(win->surface, ®ion); clear_region(®ion, &win->fill); mir_surface_swap_buffers_sync(win->surface); } static char const *socket_file = NULL; int main(int argc, char *argv[]) { MirConnection *conn; MirSurfaceParameters parm; Window win[3]; unsigned int f; int arg; opterr = 0; while ((arg = getopt (argc, argv, "hm:")) != -1) { switch (arg) { case 'm': socket_file = optarg; break; case '?': case 'h': default: puts(argv[0]); puts("Usage:"); puts(" -m "); puts(" -h: this help text"); return -1; } } conn = mir_connect_sync(socket_file, argv[0]); if (!mir_connection_is_valid(conn)) { fprintf(stderr, "Could not connect to a display server.\n"); return 1; } unsigned int const pf_size = 32; MirPixelFormat formats[pf_size]; unsigned int valid_formats; mir_connection_get_available_surface_formats(conn, formats, pf_size, &valid_formats); parm.buffer_usage = mir_buffer_usage_software; parm.output_id = mir_display_output_id_invalid; parm.pixel_format = mir_pixel_format_invalid; for (f = 0; f < valid_formats; f++) { if (formats[f] == mir_pixel_format_abgr_8888 || formats[f] == mir_pixel_format_argb_8888) { parm.pixel_format = formats[f]; break; } } if (parm.pixel_format == mir_pixel_format_invalid) { fprintf(stderr, "Could not find a fast 32-bit pixel format with " "alpha support. Blending won't work!.\n"); parm.pixel_format = formats[0]; } parm.name = "red"; parm.width = 225; parm.height = 225; win[0].surface = mir_connection_create_surface_sync(conn, &parm); win[0].fill.r = 0xff; win[0].fill.g = 0x00; win[0].fill.b = 0x00; win[0].fill.a = 0x50; parm.name = "green"; parm.width = 300; parm.height = 150; win[1].surface = mir_connection_create_surface_sync(conn, &parm); win[1].fill.r = 0x00; win[1].fill.g = 0xff; win[1].fill.b = 0x00; win[1].fill.a = 0x50; parm.name = "blue"; parm.width = 150; parm.height = 300; win[2].surface = mir_connection_create_surface_sync(conn, &parm); win[2].fill.r = 0x00; win[2].fill.g = 0x00; win[2].fill.b = 0xff; win[2].fill.a = 0x50; signal(SIGINT, shutdown); signal(SIGTERM, shutdown); while (running) { int w; for (w = 0; w < (int)(sizeof(win)/sizeof(win[0])); w++) draw_window(win + w); } mir_surface_release_sync(win[0].surface); mir_surface_release_sync(win[1].surface); mir_surface_release_sync(win[2].surface); mir_connection_release(conn); return 0; } mir-0.1.8+14.04.20140411/examples/README0000644000015301777760000000052312322054223017372 0ustar pbusernogroup00000000000000examples for mir clients. you should have package 'libmirclient-dev' installed you can compile with a command like: g++ -std=c++0x -o mir_demo_client_scroll `pkg-config --libs --cflags mirclient` demo_client_scroll.cpp graphics_utils.cpp gcc -o mir_demo_client_flicker `pkg-config --libs --cflags mirclient` demo_client_flicker.c mir-0.1.8+14.04.20140411/examples/basic.c0000644000015301777760000001765312322054223017753 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include #include #include #include #include ///\page basic.c basic.c: A simple mir client /// demo_client shows the use of mir API. /// This program opens a mir connection and creates a surface. ///\section demo_client demo_client() /// Opens a mir connection and creates a surface and advances the /// current buffer before closing the surface and connection. ///\subsection connect request and wait for connection handle /// \snippet basic.c connect_tag ///\subsection surface_create request and wait for surface handle /// \snippet basic.c surface_create_tag ///\subsection swap_buffers exchange the current buffer for a new one /// \snippet basic.c swap_buffers_tag ///\subsection surface_release We release our surface /// \snippet basic.c surface_release_tag ///\subsection connection_release We release our connection /// \snippet basic.c connection_release_tag ///\subsection get the raw, platform-specific buffer handle for the current buffer /// \snippet basic.c get_current_buffer_tag /// \example basic.c A simple mir client ///\section MirDemoState MirDemoState /// The handles needs to be accessible both to callbacks and to the control function. /// \snippet basic.c MirDemoState_tag ///\section Callbacks Callbacks /// This program opens a mir connection and creates a surface. The handles /// needs to be accessible both to callbacks and to the control function. /// \snippet basic.c Callback_tag ///\internal [MirDemoState_tag] // Utility structure for the state of a single surface session. typedef struct MirDemoState { MirConnection *connection; MirSurface *surface; } MirDemoState; ///\internal [MirDemoState_tag] ///\internal [Callback_tag] // Callback to update MirDemoState on connection static void connection_callback(MirConnection *new_connection, void *context) { ((MirDemoState*)context)->connection = new_connection; } // Callback to update MirDemoState on surface_create static void surface_create_callback(MirSurface *new_surface, void *context) { ((MirDemoState*)context)->surface = new_surface; } // Callback to update MirDemoState on swap_buffers static void surface_swap_buffers_callback(MirSurface* surface, void *context) { (void) surface; (void) context; } // Callback to update MirDemoState on surface_release static void surface_release_callback(MirSurface *old_surface, void *context) { (void)old_surface; ((MirDemoState*)context)->surface = 0; } ///\internal [Callback_tag] void demo_client(const char* server, int buffer_swap_count) { MirDemoState mcd; mcd.connection = 0; mcd.surface = 0; puts("Starting"); ///\internal [connect_tag] // Call mir_connect and wait for callback to complete. mir_wait_for(mir_connect(server, __PRETTY_FUNCTION__, connection_callback, &mcd)); puts("Connected"); ///\internal [connect_tag] // We expect a connection handle; // we expect it to be valid; and, // we don't expect an error description assert(mcd.connection != NULL); assert(mir_connection_is_valid(mcd.connection)); assert(strcmp(mir_connection_get_error_message(mcd.connection), "") == 0); // We can query information about the platform we're running on { MirPlatformPackage platform_package; platform_package.data_items = -1; platform_package.fd_items = -1; mir_connection_get_platform(mcd.connection, &platform_package); assert(0 <= platform_package.data_items); assert(0 <= platform_package.fd_items); } // Identify a supported pixel format MirPixelFormat pixel_format; unsigned int valid_formats; mir_connection_get_available_surface_formats(mcd.connection, &pixel_format, 1, &valid_formats); MirSurfaceParameters const request_params = {__PRETTY_FUNCTION__, 640, 480, pixel_format, mir_buffer_usage_hardware, mir_display_output_id_invalid}; ///\internal [surface_create_tag] // ...we create a surface using that format and wait for callback to complete. mir_wait_for(mir_connection_create_surface(mcd.connection, &request_params, surface_create_callback, &mcd)); puts("Surface created"); ///\internal [surface_create_tag] // We expect a surface handle; // we expect it to be valid; and, // we don't expect an error description assert(mcd.surface != NULL); assert(mir_surface_is_valid(mcd.surface)); assert(strcmp(mir_surface_get_error_message(mcd.surface), "") == 0); // We can query the surface parameters... { MirSurfaceParameters response_params; mir_surface_get_parameters(mcd.surface, &response_params); // ...and they should match the request assert(request_params.width == response_params.width); assert(request_params.height == response_params.height); assert(request_params.pixel_format == response_params.pixel_format); } // We can keep exchanging the current buffer for a new one for (int i = 0; i < buffer_swap_count; i++) { // We can query the current graphics buffer attributes { ///\internal [get_current_buffer_tag] MirNativeBuffer* buffer_package = NULL; mir_surface_get_current_buffer(mcd.surface, &buffer_package); assert(buffer_package != NULL); if (mir_platform_type_gbm == mir_surface_get_platform_type(mcd.surface)) { // Interpret buffer_package as MirBufferPackage } else if (mir_platform_type_android == mir_surface_get_platform_type(mcd.surface)) { // Interpret buffer_package as ANativeWindowBuffer } ///\internal [get_current_buffer_tag] // In a real application we'd render into the current buffer } ///\internal [swap_buffers_tag] mir_wait_for(mir_surface_swap_buffers(mcd.surface, surface_swap_buffers_callback, &mcd)); ///\internal [swap_buffers_tag] } ///\internal [surface_release_tag] // We should release our surface mir_wait_for(mir_surface_release(mcd.surface, surface_release_callback, &mcd)); puts("Surface released"); ///\internal [surface_release_tag] ///\internal [connection_release_tag] // We should release our connection mir_connection_release(mcd.connection); puts("Connection released"); ///\internal [connection_release_tag] } // The main() function deals with parsing arguments and defaults int main(int argc, char* argv[]) { // Some variables for holding command line options char const *server = NULL; int buffer_swap_count = 0; // Parse the command line { int arg; opterr = 0; while ((arg = getopt (argc, argv, "c:hm:")) != -1) { switch (arg) { case 'c': buffer_swap_count = atoi(optarg); break; case 'm': server = optarg; break; case '?': case 'h': default: puts(argv[0]); puts("Usage:"); puts(" -m "); puts(" -h: this help text"); return -1; } } } demo_client(server, buffer_swap_count); return 0; } mir-0.1.8+14.04.20140411/COPYING.GPL0000644000015301777760000010437412322054223016361 0ustar pbusernogroup00000000000000 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 . mir-0.1.8+14.04.20140411/tests/0000755000015301777760000000000012322054703016041 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/mir_test_doubles/0000755000015301777760000000000012322054703021404 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/mir_test_doubles/mock_egl.cpp0000644000015301777760000002530712322054223023674 0ustar pbusernogroup00000000000000/* * 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 * Kevin DuBois */ #include "mir_test_doubles/mock_egl.h" #include namespace mtd = mir::test::doubles; namespace { mtd::MockEGL* global_mock_egl = NULL; } EGLConfig configs[] = { (void*)3, (void*)4, (void*)8, (void*)14 }; EGLint config_size = 4; /* We prefix GL/EGL extensions with "extension_" so code under test has to get their function ptrs with eglGetProcAddress */ EGLImageKHR extension_eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); EGLBoolean extension_eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image); void extension_glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image); /* EGL{Surface,Display,Config,Context} are all opaque types, so we can put whatever we want in them for testing */ mtd::MockEGL::MockEGL() : fake_egl_display((EGLDisplay) 0x0530), fake_configs(configs), fake_configs_num(config_size), fake_egl_surface((EGLSurface) 0xa034), fake_egl_context((EGLContext) 0xbeef), fake_egl_image((EGLImageKHR) 0x1234), fake_visual_id(1) //HAL_PIXEL_FORMAT_RGBA on android { using namespace testing; assert(global_mock_egl == NULL && "Only one mock object per process is allowed"); global_mock_egl = this; ON_CALL(*this, eglGetDisplay(_)) .WillByDefault(Return(fake_egl_display)); ON_CALL(*this, eglInitialize(_,_,_)) .WillByDefault(DoAll( SetArgPointee<1>(1), SetArgPointee<2>(4), Return(EGL_TRUE))); ON_CALL(*this, eglBindApi(EGL_OPENGL_ES_API)) .WillByDefault(Return(EGL_TRUE)); ON_CALL(*this, eglGetConfigs(_,NULL, 0, _)) .WillByDefault(DoAll( SetArgPointee<3>(config_size), Return(EGL_TRUE))); ON_CALL(*this, eglGetConfigAttrib(_, _, EGL_NATIVE_VISUAL_ID, _)) .WillByDefault(DoAll( SetArgPointee<3>(fake_visual_id), Return(EGL_TRUE))); ON_CALL(*this, eglChooseConfig(_,_,_,_,_)) .WillByDefault(DoAll( SetArgPointee<2>(&fake_configs), SetArgPointee<4>(fake_configs_num), Return(EGL_TRUE))); ON_CALL(*this, eglCreateWindowSurface(_,_,_,_)) .WillByDefault(Return(fake_egl_surface)); ON_CALL(*this, eglCreatePbufferSurface(_,_,_)) .WillByDefault(Return(fake_egl_surface)); ON_CALL(*this, eglCreateContext(_,_,_,_)) .WillByDefault(Return(fake_egl_context)); ON_CALL(*this, eglMakeCurrent(_,_,_,_)) .WillByDefault(Return(EGL_TRUE)); ON_CALL(*this, eglSwapBuffers(_,_)) .WillByDefault(Return(EGL_TRUE)); ON_CALL(*this, eglGetCurrentDisplay()) .WillByDefault(Return(fake_egl_display)); ON_CALL(*this, eglCreateImageKHR(_,_,_,_,_)) .WillByDefault(Return(fake_egl_image)); typedef mtd::MockEGL::generic_function_pointer_t func_ptr_t; ON_CALL(*this, eglGetProcAddress(StrEq("eglCreateImageKHR"))) .WillByDefault(Return(reinterpret_cast(extension_eglCreateImageKHR))); ON_CALL(*this, eglGetProcAddress(StrEq("eglDestroyImageKHR"))) .WillByDefault(Return(reinterpret_cast(extension_eglDestroyImageKHR))); ON_CALL(*this, eglGetProcAddress(StrEq("glEGLImageTargetTexture2DOES"))) .WillByDefault(Return(reinterpret_cast(extension_glEGLImageTargetTexture2DOES))); } mtd::MockEGL::~MockEGL() { global_mock_egl = NULL; } #define CHECK_GLOBAL_MOCK(rettype) \ if (!global_mock_egl) \ { \ using namespace ::testing; \ ADD_FAILURE_AT(__FILE__,__LINE__); \ rettype type = (rettype) 0; \ return type; \ } #define CHECK_GLOBAL_VOID_MOCK() \ if (!global_mock_egl) \ { \ using namespace ::testing; \ ADD_FAILURE_AT(__FILE__,__LINE__); \ return; \ } EGLint eglGetError (void) { CHECK_GLOBAL_MOCK(EGLint) return global_mock_egl->eglGetError(); } EGLDisplay eglGetDisplay (NativeDisplayType display) { CHECK_GLOBAL_MOCK(EGLDisplay); return global_mock_egl->eglGetDisplay(display); } EGLBoolean eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglInitialize(dpy, major, minor); } EGLBoolean eglTerminate (EGLDisplay dpy) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglTerminate(dpy); } const char * eglQueryString (EGLDisplay dpy, EGLint name) { CHECK_GLOBAL_MOCK(const char *) return global_mock_egl->eglQueryString(dpy, name); } EGLBoolean eglBindAPI (EGLenum api) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglBindApi(api); } mtd::MockEGL::generic_function_pointer_t eglGetProcAddress (const char *name) { CHECK_GLOBAL_MOCK(mtd::MockEGL::generic_function_pointer_t) return global_mock_egl->eglGetProcAddress(name); } EGLBoolean eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglGetConfigs(dpy, configs, config_size, num_config); } EGLBoolean eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglChooseConfig(dpy, attrib_list, configs, config_size, num_config); } EGLBoolean eglGetConfigAttrib (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglGetConfigAttrib(dpy, config, attribute, value); } EGLSurface eglCreateWindowSurface (EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list) { CHECK_GLOBAL_MOCK(EGLSurface) return global_mock_egl->eglCreateWindowSurface(dpy, config, window, attrib_list); } EGLSurface eglCreatePixmapSurface (EGLDisplay dpy, EGLConfig config, NativePixmapType pixmap, const EGLint *attrib_list) { CHECK_GLOBAL_MOCK(EGLSurface) return global_mock_egl->eglCreatePixmapSurface(dpy, config, pixmap, attrib_list); } EGLSurface eglCreatePbufferSurface (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) { CHECK_GLOBAL_MOCK(EGLSurface) return global_mock_egl->eglCreatePbufferSurface(dpy, config, attrib_list); } EGLBoolean eglDestroySurface (EGLDisplay dpy, EGLSurface surface) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglDestroySurface(dpy, surface); } EGLBoolean eglQuerySurface (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglQuerySurface(dpy, surface, attribute, value); } /* EGL 1.1 render-to-texture APIs */ EGLBoolean eglSurfaceAttrib (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglSurfaceAttrib(dpy, surface, attribute, value); } EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglBindTexImage(dpy, surface, buffer); } EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglReleaseTexImage(dpy, surface, buffer); } /* EGL 1.1 swap control API */ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglSwapInterval(dpy, interval); } EGLContext eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list) { CHECK_GLOBAL_MOCK(EGLContext) return global_mock_egl->eglCreateContext(dpy, config, share_list, attrib_list); } EGLBoolean eglDestroyContext (EGLDisplay dpy, EGLContext ctx) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglDestroyContext(dpy, ctx); } EGLBoolean eglMakeCurrent (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglMakeCurrent(dpy, draw, read, ctx); } EGLContext eglGetCurrentContext (void) { CHECK_GLOBAL_MOCK(EGLContext) return global_mock_egl->eglGetCurrentContext(); } EGLSurface eglGetCurrentSurface (EGLint readdraw) { CHECK_GLOBAL_MOCK(EGLSurface) return global_mock_egl->eglGetCurrentSurface(readdraw); } EGLDisplay eglGetCurrentDisplay (void) { CHECK_GLOBAL_MOCK(EGLDisplay) return global_mock_egl->eglGetCurrentDisplay(); } EGLBoolean eglQueryContext (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglQueryContext(dpy, ctx, attribute, value); } EGLBoolean eglWaitGL (void) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglWaitGL(); } EGLBoolean eglWaitNative (EGLint engine) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglWaitNative(engine); } EGLBoolean eglSwapBuffers (EGLDisplay dpy, EGLSurface draw) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglSwapBuffers(dpy, draw); } EGLBoolean eglCopyBuffers (EGLDisplay dpy, EGLSurface surface, NativePixmapType target) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglCopyBuffers(dpy, surface, target); } /* extensions */ EGLImageKHR extension_eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) { CHECK_GLOBAL_MOCK(EGLImageKHR) return global_mock_egl->eglCreateImageKHR(dpy, ctx, target, buffer, attrib_list); } EGLBoolean extension_eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image) { CHECK_GLOBAL_MOCK(EGLBoolean) return global_mock_egl->eglDestroyImageKHR(dpy, image); } void extension_glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) { CHECK_GLOBAL_VOID_MOCK(); global_mock_egl->glEGLImageTargetTexture2DOES(target, image); } mir-0.1.8+14.04.20140411/tests/mir_test_doubles/test_protobuf_client.cpp0000644000015301777760000001602212322054223026343 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test/test_protobuf_client.h" #include "mir_test_doubles/mock_rpc_report.h" #include "src/client/connection_surface_map.h" #include "src/client/display_configuration.h" #include "src/client/lifecycle_control.h" #include "src/client/rpc/make_rpc_channel.h" #include "src/client/rpc/mir_basic_rpc_channel.h" #include namespace mtd = mir::test::doubles; mir::test::TestProtobufClient::TestProtobufClient( std::string socket_file, int timeout_ms) : rpc_report(std::make_shared>()), channel(mir::client::rpc::make_rpc_channel( socket_file, std::make_shared(), std::make_shared(), rpc_report, std::make_shared())), display_server(channel.get(), ::google::protobuf::Service::STUB_DOESNT_OWN_CHANNEL), maxwait(timeout_ms), connect_done_called(false), create_surface_called(false), next_buffer_called(false), release_surface_called(false), disconnect_done_called(false), drm_auth_magic_done_called(false), configure_display_done_called(false), tfd_done_called(false), connect_done_count(0), create_surface_done_count(0), disconnect_done_count(0) { surface_parameters.set_width(640); surface_parameters.set_height(480); surface_parameters.set_pixel_format(0); surface_parameters.set_buffer_usage(0); surface_parameters.set_output_id(mir_display_output_id_invalid); ON_CALL(*this, connect_done()) .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_connect_done)); ON_CALL(*this, create_surface_done()) .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_create_surface_done)); ON_CALL(*this, next_buffer_done()) .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_next_buffer_done)); ON_CALL(*this, release_surface_done()) .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_release_surface_done)); ON_CALL(*this, disconnect_done()) .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_disconnect_done)); ON_CALL(*this, drm_auth_magic_done()) .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_drm_auth_magic_done)); ON_CALL(*this, display_configure_done()) .WillByDefault(testing::Invoke(this, &TestProtobufClient::on_configure_display_done)); } void mir::test::TestProtobufClient::on_connect_done() { connect_done_called.store(true); auto old = connect_done_count.load(); while (!connect_done_count.compare_exchange_weak(old, old+1)); } void mir::test::TestProtobufClient::on_create_surface_done() { create_surface_called.store(true); auto old = create_surface_done_count.load(); while (!create_surface_done_count.compare_exchange_weak(old, old+1)); } void mir::test::TestProtobufClient::on_next_buffer_done() { next_buffer_called.store(true); } void mir::test::TestProtobufClient::on_release_surface_done() { release_surface_called.store(true); } void mir::test::TestProtobufClient::on_disconnect_done() { disconnect_done_called.store(true); auto old = disconnect_done_count.load(); while (!disconnect_done_count.compare_exchange_weak(old, old+1)); } void mir::test::TestProtobufClient::on_drm_auth_magic_done() { drm_auth_magic_done_called.store(true); } void mir::test::TestProtobufClient::on_configure_display_done() { configure_display_done_called.store(true); } void mir::test::TestProtobufClient::wait_for_configure_display_done() { for (int i = 0; !configure_display_done_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } configure_display_done_called.store(false); } void mir::test::TestProtobufClient::wait_for_connect_done() { for (int i = 0; !connect_done_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } connect_done_called.store(false); } void mir::test::TestProtobufClient::wait_for_create_surface() { for (int i = 0; !create_surface_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } create_surface_called.store(false); } void mir::test::TestProtobufClient::wait_for_next_buffer() { for (int i = 0; !next_buffer_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } next_buffer_called.store(false); } void mir::test::TestProtobufClient::wait_for_release_surface() { for (int i = 0; !release_surface_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } release_surface_called.store(false); } void mir::test::TestProtobufClient::wait_for_disconnect_done() { for (int i = 0; !disconnect_done_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } disconnect_done_called.store(false); } void mir::test::TestProtobufClient::wait_for_drm_auth_magic_done() { for (int i = 0; !drm_auth_magic_done_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } drm_auth_magic_done_called.store(false); } void mir::test::TestProtobufClient::wait_for_surface_count(int count) { for (int i = 0; count != create_surface_done_count.load() && i < 10000; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::yield(); } } void mir::test::TestProtobufClient::wait_for_disconnect_count(int count) { for (int i = 0; count != disconnect_done_count.load() && i < 10000; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::yield(); } } void mir::test::TestProtobufClient::tfd_done() { tfd_done_called.store(true); } void mir::test::TestProtobufClient::wait_for_tfd_done() { for (int i = 0; !tfd_done_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } tfd_done_called.store(false); } mir-0.1.8+14.04.20140411/tests/mir_test_doubles/mock_android_hw.cpp0000644000015301777760000000632712322054223025244 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_doubles/mock_android_hw.h" #include "mir_test_doubles/mock_hwc_composer_device_1.h" #include #include #include #include namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace { mtd::HardwareAccessMock* global_mock_android_hw = NULL; std::atomic open_count; } mtd::HardwareModuleStub::HardwareModuleStub(hw_device_t& device) : mock_hw_device(device) { gr_methods.open = hw_open; methods = &gr_methods; } int mtd::HardwareModuleStub::hw_open(const struct hw_module_t* module, const char*, struct hw_device_t** device) { auto self = static_cast(module); self->mock_hw_device.close = hw_close; *device = static_cast(&self->mock_hw_device); open_count++; return 0; } int mtd::HardwareModuleStub::hw_close(struct hw_device_t*) { open_count--; return 0; } mtd::FailingHardwareModuleStub::FailingHardwareModuleStub() { gr_methods.open = hw_open; methods = &gr_methods; } int mtd::FailingHardwareModuleStub::hw_open(const struct hw_module_t*, const char*, struct hw_device_t**) { return -1; } int mtd::FailingHardwareModuleStub::hw_close(struct hw_device_t*) { return 0; } mtd::HardwareAccessMock::HardwareAccessMock() { using namespace testing; assert(global_mock_android_hw == NULL && "Only one mock object per process is allowed"); global_mock_android_hw = this; mock_alloc_device = std::make_shared>(); mock_gralloc_module = std::make_shared(mock_alloc_device->common); mock_hwc_device = std::make_shared>(); mock_hwc_module = std::make_shared(mock_hwc_device->common); ON_CALL(*this, hw_get_module(StrEq(GRALLOC_HARDWARE_MODULE_ID),_)) .WillByDefault(DoAll(SetArgPointee<1>(mock_gralloc_module.get()), Return(0))); ON_CALL(*this, hw_get_module(StrEq(HWC_HARDWARE_MODULE_ID),_)) .WillByDefault(DoAll(SetArgPointee<1>(mock_hwc_module.get()), Return(0))); open_count.store(0); } bool mtd::HardwareAccessMock::open_count_matches_close() { return (open_count == 0); } mtd::HardwareAccessMock::~HardwareAccessMock() { global_mock_android_hw = NULL; } int hw_get_module(const char *id, const struct hw_module_t **module) { if (!global_mock_android_hw) { ADD_FAILURE_AT(__FILE__,__LINE__); \ return -1; } int rc = global_mock_android_hw->hw_get_module(id, module); return rc; } mir-0.1.8+14.04.20140411/tests/mir_test_doubles/test_protobuf_socket_server.cpp0000644000015301777760000000427012322054223027745 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test/test_protobuf_server.h" #include "mir_test_doubles/stub_ipc_factory.h" #include "mir_test_doubles/stub_session_authorizer.h" #include "mir/frontend/connector_report.h" #include "mir/frontend/protobuf_session_creator.h" #include "src/server/frontend/published_socket_connector.h" #include "src/server/report/null_report_factory.h" #include "src/server/report/null_report_factory.h" namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace mf = mir::frontend; namespace mr = mir::report; namespace { std::shared_ptr make_connector( std::string const& socket_name, std::shared_ptr const& factory, std::shared_ptr const& report) { return std::make_shared( socket_name, std::make_shared( factory, std::make_shared(), mr::null_message_processor_report()), 10, report); } } mt::TestProtobufServer::TestProtobufServer( std::string const& socket_name, const std::shared_ptr& tool) : TestProtobufServer(socket_name, tool, mr::null_connector_report()) { } mt::TestProtobufServer::TestProtobufServer( std::string const& socket_name, const std::shared_ptr& tool, std::shared_ptr const& report) : comm(make_connector(socket_name, std::make_shared(*tool), report)) { } mir-0.1.8+14.04.20140411/tests/mir_test_doubles/CMakeLists.txt0000644000015301777760000000244312322054223024144 0ustar pbusernogroup00000000000000include_directories( ${Boost_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ) set( TEST_UTILS_SRCS test_protobuf_client.cpp event_factory.cpp fake_event_hub.cpp fake_event_hub_input_configuration.cpp test_protobuf_socket_server.cpp ) set( MIR_TEST_DOUBLES_PLATFORM_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/mock_egl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mock_gl.cpp ) if (MIR_TEST_PLATFORM STREQUAL "mesa") include_directories(${DRM_INCLUDE_DIRS} ${GBM_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}) list(APPEND MIR_TEST_DOUBLES_PLATFORM_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/mock_drm.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mock_gbm.cpp ) elseif (MIR_TEST_PLATFORM STREQUAL "android") list(APPEND MIR_TEST_DOUBLES_PLATFORM_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/mock_android_hw.cpp ) endif() add_library( mir-test-doubles STATIC ${TEST_UTILS_SRCS}) uses_android_input(mir-test-doubles) target_link_libraries( mir-test-doubles mirserver 3rd_party ${PROTOBUF_LIBRARIES} ${Boost_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} # Link in pthread. ) add_library( mir-test-doubles-platform STATIC ${MIR_TEST_DOUBLES_PLATFORM_SRCS}) target_link_libraries( mir-test-doubles-platform -ldl ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} # Link in pthread. ) mir-0.1.8+14.04.20140411/tests/mir_test_doubles/event_factory.cpp0000644000015301777760000000521512322054223024760 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test/event_factory.h" namespace mis = mir::input::synthesis; mis::KeyParameters::KeyParameters() : device_id(0), scancode(0), action(mis::EventAction::Down) { } mis::KeyParameters& mis::KeyParameters::from_device(int new_device_id) { device_id = new_device_id; return *this; } mis::KeyParameters& mis::KeyParameters::of_scancode(int new_scancode) { scancode = new_scancode; return *this; } mis::KeyParameters& mis::KeyParameters::with_action(mis::EventAction new_action) { action = new_action; return *this; } mis::KeyParameters mis::a_key_down_event() { return mis::KeyParameters().with_action(mis::EventAction::Down); } mis::KeyParameters mis::a_key_up_event() { return mis::KeyParameters().with_action(mis::EventAction::Up); } mis::ButtonParameters::ButtonParameters() : device_id(0), button(0), action(mis::EventAction::Down) { } mis::ButtonParameters& mis::ButtonParameters::from_device(int new_device_id) { device_id = new_device_id; return *this; } mis::ButtonParameters& mis::ButtonParameters::of_button(int new_button) { button = new_button; return *this; } mis::ButtonParameters& mis::ButtonParameters::with_action(mis::EventAction new_action) { action = new_action; return *this; } mis::ButtonParameters mis::a_button_down_event() { return mis::ButtonParameters().with_action(mis::EventAction::Down); } mis::ButtonParameters mis::a_button_up_event() { return mis::ButtonParameters().with_action(mis::EventAction::Up); } mis::MotionParameters::MotionParameters() : device_id(0), rel_x(0), rel_y(0) { } mis::MotionParameters& mis::MotionParameters::from_device(int new_device_id) { device_id = new_device_id; return *this; } mis::MotionParameters& mis::MotionParameters::with_movement(int new_rel_x, int new_rel_y) { rel_x = new_rel_x; rel_y = new_rel_y; return *this; } mis::MotionParameters mis::a_motion_event() { return mis::MotionParameters(); } mir-0.1.8+14.04.20140411/tests/mir_test_doubles/fake_event_hub_input_configuration.cpp0000644000015301777760000000315112322054223031220 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test/fake_event_hub_input_configuration.h" #include "mir_test/fake_event_hub.h" namespace mi = mir::input; namespace mia = mi::android; namespace mtd = mir::test::doubles; mtd::FakeEventHubInputConfiguration::FakeEventHubInputConfiguration( std::shared_ptr const& event_filter, std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener, std::shared_ptr const& input_report) : DefaultInputConfiguration(event_filter, input_region, cursor_listener, input_report) { event_hub = new mia::FakeEventHub(); } mtd::FakeEventHubInputConfiguration::~FakeEventHubInputConfiguration() { } droidinput::sp mtd::FakeEventHubInputConfiguration::the_event_hub() { return event_hub; } mia::FakeEventHub* mtd::FakeEventHubInputConfiguration::the_fake_event_hub() { return event_hub.get(); } mir-0.1.8+14.04.20140411/tests/mir_test_doubles/mock_gl.cpp0000644000015301777760000002456512322054223023534 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_doubles/mock_gl.h" #include namespace mtd = mir::test::doubles; namespace { mtd::MockGL* global_mock_gl = NULL; } mtd::MockGL::MockGL() { using namespace testing; assert(global_mock_gl == NULL && "Only one mock object per process is allowed"); global_mock_gl = this; ON_CALL(*this, glCheckFramebufferStatus(_)) .WillByDefault(Return(GL_FRAMEBUFFER_COMPLETE)); } mtd::MockGL::~MockGL() { global_mock_gl = NULL; } #define CHECK_GLOBAL_VOID_MOCK() \ if (!global_mock_gl) \ { \ using namespace ::testing; \ ADD_FAILURE_AT(__FILE__,__LINE__); \ return; \ } #define CHECK_GLOBAL_MOCK(rettype) \ if (!global_mock_gl) \ { \ using namespace ::testing; \ ADD_FAILURE_AT(__FILE__,__LINE__); \ rettype type = (rettype) 0; \ return type; \ } GLenum glGetError() { CHECK_GLOBAL_MOCK(GLenum); return global_mock_gl->glGetError(); } const GLubyte* glGetString(GLenum name) { CHECK_GLOBAL_MOCK(const GLubyte*); return global_mock_gl->glGetString(name); } void glUseProgram(GLuint program) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glUseProgram (program); } void glClear (GLbitfield mask) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glClear(mask); } void glEnable(GLenum func) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glEnable (func); } void glDisable(GLenum func) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glDisable(func); } void glBlendFunc(GLenum src, GLenum dst) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glBlendFunc (src, dst); } void glActiveTexture(GLenum unit) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glActiveTexture (unit); } void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glUniformMatrix4fv(location, count, transpose, value); } void glUniform1f(GLint location, GLfloat x) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glUniform1f(location, x); } void glUniform2f(GLint location, GLfloat x, GLfloat y) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glUniform2f(location, x, y); } void glBindBuffer(GLenum buffer, GLuint name) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glBindBuffer(buffer, name); } void glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glVertexAttribPointer(indx, size, type, normalized, stride, ptr); } void glBindTexture(GLenum target, GLuint texture) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glBindTexture(target, texture); } void glEnableVertexAttribArray(GLuint index) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glEnableVertexAttribArray(index); } void glDisableVertexAttribArray(GLuint index) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glDisableVertexAttribArray(index); } void glDrawArrays(GLenum mode, GLint first, GLsizei count) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glDrawArrays(mode, first, count); } GLuint glCreateShader(GLenum type) { CHECK_GLOBAL_MOCK(GLuint); return global_mock_gl->glCreateShader(type); } void glDeleteShader(GLuint shader) { CHECK_GLOBAL_VOID_MOCK(); return global_mock_gl->glDeleteShader(shader); } /* This is the version of glShaderSource in Mesa < 9.0.1 */ void glShaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glShaderSource (shader, count, string, length); } /* This is the version of glShaderSource in Mesa >= 9.0.1 */ void glShaderSource(GLuint shader, GLsizei count, const GLchar* const* string, const GLint *length) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glShaderSource (shader, count, string, length); } void glCompileShader(GLuint shader) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glCompileShader(shader); } void glGetShaderiv(GLuint shader, GLenum pname, GLint *params) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glGetShaderiv(shader, pname, params); } void glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *infolog) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glGetShaderInfoLog(shader, bufsize, length, infolog); } GLuint glCreateProgram() { CHECK_GLOBAL_MOCK(GLuint); return global_mock_gl->glCreateProgram(); } void glDeleteProgram(GLuint program) { CHECK_GLOBAL_VOID_MOCK(); return global_mock_gl->glDeleteProgram(program); } void glAttachShader(GLuint program, GLuint shader) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glAttachShader(program, shader); } void glLinkProgram(GLuint program) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glLinkProgram(program); } GLint glGetUniformLocation(GLuint program, const GLchar *name) { CHECK_GLOBAL_MOCK(GLint); return global_mock_gl->glGetUniformLocation(program, name); } GLint glGetAttribLocation(GLuint program, const GLchar *name) { CHECK_GLOBAL_MOCK(GLint); return global_mock_gl->glGetAttribLocation(program, name); } void glTexParameteri(GLenum target, GLenum pname, GLint param) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glTexParameteri(target, pname, param); } void glGenTextures(GLsizei n, GLuint *textures) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glGenTextures(n, textures); } void glDeleteTextures(GLsizei n, const GLuint *textures) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glDeleteTextures(n, textures); } void glUniform1i(GLint location, GLint x) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glUniform1i(location, x); } void glGenBuffers(GLsizei n, GLuint *buffers) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glGenBuffers(n, buffers); } void glDeleteBuffers(GLsizei n, const GLuint *buffers) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glDeleteBuffers(n, buffers); } void glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glBufferData(target, size, data, usage); } void glGetProgramiv(GLuint program, GLenum pname, GLint *params) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glGetProgramiv(program, pname, params); } void glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei *length, GLchar *infolog) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glGetProgramInfoLog(program, bufsize, length, infolog); } void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); } void glGenFramebuffers(GLsizei n, GLuint *framebuffers) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glGenFramebuffers(n, framebuffers); } void glDeleteFramebuffers(GLsizei n, const GLuint * framebuffers) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glDeleteFramebuffers(n, framebuffers); } void glBindFramebuffer(GLenum target, GLuint framebuffer) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glBindFramebuffer(target, framebuffer); } void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glFramebufferTexture2D(target, attachment, textarget, texture, level); } GLenum glCheckFramebufferStatus(GLenum target) { CHECK_GLOBAL_MOCK(GLenum); return global_mock_gl->glCheckFramebufferStatus(target); } void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glReadPixels(x, y, width, height, format, type, pixels); } void glGetIntegerv(GLenum target, GLint* params) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glGetIntegerv(target, params); } void glBindRenderbuffer(GLenum target, GLuint renderbuffer) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glBindRenderbuffer(target, renderbuffer); } void glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); } void glGenRenderbuffers(GLsizei n, GLuint *renderbuffers) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glGenRenderbuffers(n, renderbuffers); } void glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glDeleteRenderbuffers(n, renderbuffers); } void glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glRenderbufferStorage(target, internalformat, width, height); } void glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glViewport(x, y, width, height); } void glFinish() { CHECK_GLOBAL_VOID_MOCK(); global_mock_gl->glFinish(); } mir-0.1.8+14.04.20140411/tests/mir_test_doubles/mock_drm.cpp0000644000015301777760000003032312322054223023701 0ustar pbusernogroup00000000000000/* * 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: * Alexandros Frantzis */ #include "mir_test_doubles/mock_drm.h" #include "mir/geometry/size.h" #include #include #include #include namespace mtd=mir::test::doubles; namespace geom = mir::geometry; namespace { mtd::MockDRM* global_mock = nullptr; } mtd::FakeDRMResources::FakeDRMResources() : pipe_fds{-1, -1} { /* Use the read end of a pipe as the fake DRM fd */ if (pipe(pipe_fds) < 0 || pipe_fds[0] < 0) throw std::runtime_error("Failed to create fake DRM fd"); /* Add some default resources */ uint32_t const invalid_id{0}; uint32_t const crtc0_id{10}; uint32_t const crtc1_id{11}; uint32_t const encoder0_id{20}; uint32_t const encoder1_id{21}; uint32_t const connector0_id{30}; uint32_t const connector1_id{31}; uint32_t const all_crtcs_mask{0x3}; modes.push_back(create_mode(1920, 1080, 138500, 2080, 1111, PreferredMode)); modes.push_back(create_mode(832, 624, 57284, 1152, 667, NormalMode)); connector_encoder_ids.push_back(encoder0_id); connector_encoder_ids.push_back(encoder1_id); add_crtc(crtc0_id, drmModeModeInfo()); add_crtc(crtc1_id, modes[1]); add_encoder(encoder0_id, invalid_id, all_crtcs_mask); add_encoder(encoder1_id, crtc1_id, all_crtcs_mask); add_connector(connector0_id, DRM_MODE_CONNECTOR_VGA, DRM_MODE_DISCONNECTED, invalid_id, modes_empty, connector_encoder_ids, geom::Size()); add_connector(connector1_id, DRM_MODE_CONNECTOR_DVID, DRM_MODE_CONNECTED, encoder1_id, modes, connector_encoder_ids, geom::Size{121, 144}); prepare(); } mtd::FakeDRMResources::~FakeDRMResources() { if (pipe_fds[0] >= 0) close(pipe_fds[0]); if (pipe_fds[1] >= 0) close(pipe_fds[1]); } int mtd::FakeDRMResources::fd() const { return pipe_fds[0]; } int mtd::FakeDRMResources::write_fd() const { return pipe_fds[1]; } drmModeRes* mtd::FakeDRMResources::resources_ptr() { return &resources; } void mtd::FakeDRMResources::prepare() { resources.count_crtcs = crtcs.size(); for (auto const& crtc: crtcs) crtc_ids.push_back(crtc.crtc_id); resources.crtcs = crtc_ids.data(); resources.count_encoders = encoders.size(); for (auto const& encoder: encoders) encoder_ids.push_back(encoder.encoder_id); resources.encoders = encoder_ids.data(); resources.count_connectors = connectors.size(); for (auto const& connector: connectors) connector_ids.push_back(connector.connector_id); resources.connectors = connector_ids.data(); } void mtd::FakeDRMResources::reset() { resources = drmModeRes(); crtcs.clear(); encoders.clear(); connectors.clear(); crtc_ids.clear(); encoder_ids.clear(); connector_ids.clear(); } void mtd::FakeDRMResources::add_crtc(uint32_t id, drmModeModeInfo mode) { drmModeCrtc crtc = drmModeCrtc(); crtc.crtc_id = id; crtc.mode = mode; crtcs.push_back(crtc); } void mtd::FakeDRMResources::add_encoder(uint32_t encoder_id, uint32_t crtc_id, uint32_t possible_crtcs_mask) { drmModeEncoder encoder = drmModeEncoder(); encoder.encoder_id = encoder_id; encoder.crtc_id = crtc_id; encoder.possible_crtcs = possible_crtcs_mask; encoders.push_back(encoder); } void mtd::FakeDRMResources::add_connector(uint32_t connector_id, uint32_t type, drmModeConnection connection, uint32_t encoder_id, std::vector& modes, std::vector& possible_encoder_ids, geom::Size const& physical_size) { drmModeConnector connector = drmModeConnector(); connector.connector_id = connector_id; connector.connector_type = type; connector.connection = connection; connector.encoder_id = encoder_id; connector.modes = modes.data(); connector.count_modes = modes.size(); connector.encoders = possible_encoder_ids.data(); connector.count_encoders = possible_encoder_ids.size(); connector.mmWidth = physical_size.width.as_uint32_t(); connector.mmHeight = physical_size.height.as_uint32_t(); connectors.push_back(connector); } drmModeCrtc* mtd::FakeDRMResources::find_crtc(uint32_t id) { for (auto& crtc : crtcs) { if (crtc.crtc_id == id) return &crtc; } return nullptr; } drmModeEncoder* mtd::FakeDRMResources::find_encoder(uint32_t id) { for (auto& encoder : encoders) { if (encoder.encoder_id == id) return &encoder; } return nullptr; } drmModeConnector* mtd::FakeDRMResources::find_connector(uint32_t id) { for (auto& connector : connectors) { if (connector.connector_id == id) return &connector; } return nullptr; } drmModeModeInfo mtd::FakeDRMResources::create_mode(uint16_t hdisplay, uint16_t vdisplay, uint32_t clock, uint16_t htotal, uint16_t vtotal, ModePreference preferred) { drmModeModeInfo mode = drmModeModeInfo(); mode.hdisplay = hdisplay; mode.vdisplay = vdisplay; mode.clock = clock; mode.htotal = htotal; mode.vtotal = vtotal; if (preferred) mode.type |= DRM_MODE_TYPE_PREFERRED; return mode; } mtd::MockDRM::MockDRM() { using namespace testing; assert(global_mock == NULL && "Only one mock object per process is allowed"); global_mock = this; ON_CALL(*this, open(_,_,_)) .WillByDefault(Return(fake_drm.fd())); ON_CALL(*this, drmOpen(_,_)) .WillByDefault(Return(fake_drm.fd())); ON_CALL(*this, drmModeGetResources(_)) .WillByDefault(Return(fake_drm.resources_ptr())); ON_CALL(*this, drmModeGetCrtc(_, _)) .WillByDefault(WithArgs<1>(Invoke(&fake_drm, &FakeDRMResources::find_crtc))); ON_CALL(*this, drmModeGetEncoder(_, _)) .WillByDefault(WithArgs<1>(Invoke(&fake_drm, &FakeDRMResources::find_encoder))); ON_CALL(*this, drmModeGetConnector(_, _)) .WillByDefault(WithArgs<1>(Invoke(&fake_drm, &FakeDRMResources::find_connector))); ON_CALL(*this, drmSetInterfaceVersion(_, _)) .WillByDefault(Return(0)); ON_CALL(*this, drmGetBusid(_)) .WillByDefault(WithoutArgs(Invoke([]{ return static_cast(malloc(10)); }))); } mtd::MockDRM::~MockDRM() noexcept { global_mock = nullptr; } int drmOpen(const char *name, const char *busid) { return global_mock->drmOpen(name, busid); } int drmClose(int fd) { return global_mock->drmClose(fd); } int drmIoctl(int fd, unsigned long request, void *arg) { return global_mock->drmIoctl(fd, request, arg); } drmModeResPtr drmModeGetResources(int fd) { return global_mock->drmModeGetResources(fd); } drmModeConnectorPtr drmModeGetConnector(int fd, uint32_t connectorId) { return global_mock->drmModeGetConnector(fd, connectorId); } drmModeEncoderPtr drmModeGetEncoder(int fd, uint32_t encoder_id) { return global_mock->drmModeGetEncoder(fd, encoder_id); } drmModeCrtcPtr drmModeGetCrtc(int fd, uint32_t crtcId) { return global_mock->drmModeGetCrtc(fd, crtcId); } int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId, uint32_t x, uint32_t y, uint32_t *connectors, int count, drmModeModeInfoPtr mode) { return global_mock->drmModeSetCrtc(fd, crtcId, bufferId, x, y, connectors, count, mode); } void drmModeFreeResources(drmModeResPtr ptr) { global_mock->drmModeFreeResources(ptr); } void drmModeFreeConnector(drmModeConnectorPtr ptr) { global_mock->drmModeFreeConnector(ptr); } void drmModeFreeEncoder(drmModeEncoderPtr ptr) { global_mock->drmModeFreeEncoder(ptr); } void drmModeFreeCrtc(drmModeCrtcPtr ptr) { global_mock->drmModeFreeCrtc(ptr); } int drmModeAddFB(int fd, uint32_t width, uint32_t height, uint8_t depth, uint8_t bpp, uint32_t pitch, uint32_t bo_handle, uint32_t *buf_id) { return global_mock->drmModeAddFB(fd, width, height, depth, bpp, pitch, bo_handle, buf_id); } int drmModeRmFB(int fd, uint32_t bufferId) { return global_mock->drmModeRmFB(fd, bufferId); } int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data) { return global_mock->drmModePageFlip(fd, crtc_id, fb_id, flags, user_data); } int drmHandleEvent(int fd, drmEventContextPtr evctx) { return global_mock->drmHandleEvent(fd, evctx); } int drmGetMagic(int fd, drm_magic_t *magic) { return global_mock->drmGetMagic(fd, magic); } int drmAuthMagic(int fd, drm_magic_t magic) { return global_mock->drmAuthMagic(fd, magic); } int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, int *prime_fd) { return global_mock->drmPrimeHandleToFD(fd, handle, flags, prime_fd); } int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle) { return global_mock->drmPrimeFDToHandle(fd, prime_fd, handle); } int drmSetMaster(int fd) { return global_mock->drmSetMaster(fd); } int drmDropMaster(int fd) { return global_mock->drmDropMaster(fd); } int drmModeSetCursor(int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height) { return global_mock->drmModeSetCursor(fd, crtcId, bo_handle, width, height); } int drmModeMoveCursor(int fd, uint32_t crtcId, int x, int y) { return global_mock->drmModeMoveCursor(fd, crtcId, x, y); } int drmSetInterfaceVersion(int fd, drmSetVersion* sv) { return global_mock->drmSetInterfaceVersion(fd, sv); } char* drmGetBusid(int fd) { return global_mock->drmGetBusid(fd); } // We need to wrap open as we sometimes open() the DRM device // We need to explicitly mark this as C because we don't match the // libc header; we only care about the three-parameter version extern "C" { int open(char const* path, int flags, mode_t mode) { char const* drm_prefix = "/dev/dri/"; if (!strncmp(path, drm_prefix, strlen(drm_prefix))) return global_mock->open(path, flags, mode); int (*real_open)(char const *path, int flags, mode_t mode); *(void **)(&real_open) = dlsym(RTLD_NEXT, "open"); return (*real_open)(path, flags, mode); } int open64(char const* path, int flags, mode_t mode) { char const* drm_prefix = "/dev/dri/"; if (!strncmp(path, drm_prefix, strlen(drm_prefix))) return global_mock->open(path, flags, mode); int (*real_open64)(char const *path, int flags, mode_t mode); *(void **)(&real_open64) = dlsym(RTLD_NEXT, "open64"); return (*real_open64)(path, flags, mode); } int __open(char const* path, int flags, mode_t mode) { char const* drm_prefix = "/dev/dri/"; if (!strncmp(path, drm_prefix, strlen(drm_prefix))) return global_mock->open(path, flags, mode); int (*real_open)(char const *path, int flags, mode_t mode); *(void **)(&real_open) = dlsym(RTLD_NEXT, "__open"); return (*real_open)(path, flags, mode); } int __open64(char const* path, int flags, mode_t mode) { char const* drm_prefix = "/dev/dri/"; if (!strncmp(path, drm_prefix, strlen(drm_prefix))) return global_mock->open(path, flags, mode); int (*real_open64)(char const *path, int flags, mode_t mode); *(void **)(&real_open64) = dlsym(RTLD_NEXT, "__open64"); return (*real_open64)(path, flags, mode); } } mir-0.1.8+14.04.20140411/tests/mir_test_doubles/mock_gbm.cpp0000644000015301777760000001101712322054223023663 0ustar pbusernogroup00000000000000/* * 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: * Alexandros Frantzis */ #include "mir_test_doubles/mock_gbm.h" #include namespace mtd=mir::test::doubles; namespace { mtd::MockGBM* global_mock = NULL; } mtd::FakeGBMResources::FakeGBMResources() : device(reinterpret_cast(0x12345678)), surface(reinterpret_cast(0x1234abcd)), bo(reinterpret_cast(0xabcdef12)) { bo_handle.u32 = 0x0987; } mtd::MockGBM::MockGBM() { using namespace testing; assert(global_mock == NULL && "Only one mock object per process is allowed"); global_mock = this; ON_CALL(*this, gbm_create_device(_)) .WillByDefault(Return(fake_gbm.device)); ON_CALL(*this, gbm_surface_create(fake_gbm.device,_,_,_,_)) .WillByDefault(Return(fake_gbm.surface)); ON_CALL(*this, gbm_surface_lock_front_buffer(fake_gbm.surface)) .WillByDefault(Return(fake_gbm.bo)); ON_CALL(*this, gbm_bo_create(fake_gbm.device,_,_,_,_)) .WillByDefault(Return(fake_gbm.bo)); ON_CALL(*this, gbm_bo_get_device(_)) .WillByDefault(Return(fake_gbm.device)); ON_CALL(*this, gbm_bo_get_handle(fake_gbm.bo)) .WillByDefault(Return(fake_gbm.bo_handle)); ON_CALL(*this, gbm_bo_set_user_data(_,_,_)) .WillByDefault(Invoke(this, &MockGBM::on_gbm_bo_set_user_data)); ON_CALL(*this, gbm_bo_write(_,_,_)) .WillByDefault(Return(0)); } mtd::MockGBM::~MockGBM() { // this is probably later than optimal, but at least ensures memory freed for (auto i = destroyers.begin(); i != destroyers.end(); ++i) (*i)(); global_mock = NULL; } struct gbm_device* gbm_create_device(int fd) { return global_mock->gbm_create_device(fd); } void gbm_device_destroy(struct gbm_device *gbm) { return global_mock->gbm_device_destroy(gbm); } int gbm_device_get_fd(struct gbm_device *gbm) { return global_mock->gbm_device_get_fd(gbm); } struct gbm_surface *gbm_surface_create(struct gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags) { return global_mock->gbm_surface_create(gbm, width, height, format, flags); } void gbm_surface_destroy(struct gbm_surface *surface) { return global_mock->gbm_surface_destroy(surface); } struct gbm_bo *gbm_surface_lock_front_buffer(struct gbm_surface *surface) { return global_mock->gbm_surface_lock_front_buffer(surface); } void gbm_surface_release_buffer(struct gbm_surface *surface, struct gbm_bo *bo) { global_mock->gbm_surface_release_buffer(surface, bo); } struct gbm_bo *gbm_bo_create(struct gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags) { return global_mock->gbm_bo_create(gbm, width, height, format,flags); } struct gbm_device *gbm_bo_get_device(struct gbm_bo *bo) { return global_mock->gbm_bo_get_device(bo); } uint32_t gbm_bo_get_width(struct gbm_bo *bo) { return global_mock->gbm_bo_get_width(bo); } uint32_t gbm_bo_get_height(struct gbm_bo *bo) { return global_mock->gbm_bo_get_height(bo); } uint32_t gbm_bo_get_stride(struct gbm_bo *bo) { return global_mock->gbm_bo_get_stride(bo); } uint32_t gbm_bo_get_format(struct gbm_bo *bo) { return global_mock->gbm_bo_get_format(bo); } union gbm_bo_handle gbm_bo_get_handle(struct gbm_bo *bo) { return global_mock->gbm_bo_get_handle(bo); } void gbm_bo_set_user_data(struct gbm_bo *bo, void *data, void (*destroy_user_data)(struct gbm_bo *, void *)) { global_mock->gbm_bo_set_user_data(bo, data, destroy_user_data); } void *gbm_bo_get_user_data(struct gbm_bo *bo) { return global_mock->gbm_bo_get_user_data(bo); } int gbm_bo_write(struct gbm_bo *bo, const void *buf, size_t count) { return global_mock->gbm_bo_write(bo, buf, count); } void gbm_bo_destroy(struct gbm_bo *bo) { return global_mock->gbm_bo_destroy(bo); } mir-0.1.8+14.04.20140411/tests/mir_test_doubles/fake_event_hub.cpp0000644000015301777760000004275012322054223025062 0ustar pbusernogroup00000000000000/* * Copyright (C) 2012-2013 Canonical Ltd. * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "mir_test/fake_event_hub.h" // from android-input #include #include #include #include using droidinput::AxisInfo; using droidinput::InputDeviceIdentifier; using droidinput::PropertyMap; using droidinput::Vector; using droidinput::String8; using droidinput::RawAbsoluteAxisInfo; using droidinput::RawEvent; using droidinput::sp; using droidinput::status_t; using droidinput::KeyCharacterMap; using droidinput::VirtualKeyDefinition; namespace mi = mir::input; namespace mis = mir::input::synthesis; using mir::input::android::FakeEventHub; using namespace android; namespace { // An arbitrary time value. const nsecs_t arbitrary_time = 1234; } // anonymous namespace FakeEventHub::FakeEventHub() { keymap.loadGenericMaps(); } FakeEventHub::~FakeEventHub() { } uint32_t FakeEventHub::getDeviceClasses(int32_t deviceId) const { if (deviceId == BuiltInKeyboardID) { return droidinput::INPUT_DEVICE_CLASS_KEYBOARD; } else if (deviceId == BuiltInCursorID) { return droidinput::INPUT_DEVICE_CLASS_CURSOR; } auto fake_device_iterator = device_from_id.find(deviceId); if (fake_device_iterator != device_from_id.end()) { return fake_device_iterator->second.classes; } else { return 0; } } InputDeviceIdentifier FakeEventHub::getDeviceIdentifier(int32_t deviceId) const { auto fake_device_iterator = device_from_id.find(deviceId); if (fake_device_iterator != device_from_id.end()) { return fake_device_iterator->second.identifier; } else { return InputDeviceIdentifier(); } } void FakeEventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { auto device_iterator = device_from_id.find(deviceId); if (device_iterator != device_from_id.end()) { *outConfiguration = device_iterator->second.configuration; } } status_t FakeEventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const { outAxisInfo->clear(); const FakeDevice* device = getDevice(deviceId); if (device) { ssize_t index = device->absoluteAxes.indexOfKey(axis); if (index >= 0) { *outAxisInfo = device->absoluteAxes.valueAt(index); return OK; } } return -1; } bool FakeEventHub::hasRelativeAxis(int32_t deviceId, int axis) const { const FakeDevice* device = getDevice(deviceId); if (device) { return device->relativeAxes.indexOfKey(axis) >= 0; } return false; } bool FakeEventHub::hasInputProperty(int32_t deviceId, int property) const { const FakeDevice* device = getDevice(deviceId); if (device) { auto property_iterator = device->input_properties.find(property); if (property_iterator != device->input_properties.end()) { return property_iterator->second; } else { return false; } } else { return false; } } status_t FakeEventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t* outKeycode, uint32_t* outFlags) const { const FakeDevice* device = getDevice(deviceId); if (device) { const KeyInfo* key = getKey(device, scanCode, usageCode); if (key) { if (outKeycode) { *outKeycode = key->keyCode; } if (outFlags) { *outFlags = key->flags; } return OK; } return NAME_NOT_FOUND; } else { keymap.keyLayoutMap->mapKey(scanCode, usageCode, outKeycode, outFlags); return droidinput::OK; } } const FakeEventHub::KeyInfo* FakeEventHub::getKey(const FakeDevice* device, int32_t scanCode, int32_t usageCode) const { if (usageCode) { ssize_t index = device->keysByUsageCode.indexOfKey(usageCode); if (index >= 0) { return &device->keysByUsageCode.valueAt(index); } } if (scanCode) { ssize_t index = device->keysByScanCode.indexOfKey(scanCode); if (index >= 0) { return &device->keysByScanCode.valueAt(index); } } return NULL; } status_t FakeEventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const { (void)deviceId; (void)scanCode; (void)outAxisInfo; return NAME_NOT_FOUND; } void FakeEventHub::setExcludedDevices(const Vector& devices) { excluded_devices = devices; } size_t FakeEventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { size_t num_events_obtained = 0; (void) timeoutMillis; { std::lock_guard lg(guard); for (size_t i = 0; i < bufferSize && events_available.size() > 0; ++i) { buffer[i] = events_available.front(); events_available.pop_front(); ++num_events_obtained; } } /* Yield to prevent spinning, which causes long test times under valgrind */ std::this_thread::yield(); return num_events_obtained; } int32_t FakeEventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { const FakeDevice* device = getDevice(deviceId); if (device) { ssize_t index = device->scanCodeStates.indexOfKey(scanCode); if (index >= 0) { return device->scanCodeStates.valueAt(index); } } return AKEY_STATE_UNKNOWN; } int32_t FakeEventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { const FakeDevice* device = getDevice(deviceId); if (device) { ssize_t index = device->keyCodeStates.indexOfKey(keyCode); if (index >= 0) { return device->keyCodeStates.valueAt(index); } } return AKEY_STATE_UNKNOWN; } int32_t FakeEventHub::getSwitchState(int32_t deviceId, int32_t sw) const { const FakeDevice* device = getDevice(deviceId); if (device) { ssize_t index = device->switchStates.indexOfKey(sw); if (index >= 0) { return device->switchStates.valueAt(index); } } return AKEY_STATE_UNKNOWN; } status_t FakeEventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const { const FakeDevice* device = getDevice(deviceId); if (device) { ssize_t index = device->absoluteAxisValue.indexOfKey(axis); if (index >= 0) { *outValue = device->absoluteAxisValue.valueAt(index); return OK; } } *outValue = 0; return -1; } bool FakeEventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { bool result = false; const FakeDevice* device = getDevice(deviceId); if (device) { for (size_t i = 0; i < numCodes; i++) { for (size_t j = 0; j < device->keysByScanCode.size(); j++) { if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) { outFlags[i] = 1; result = true; } } for (size_t j = 0; j < device->keysByUsageCode.size(); j++) { if (keyCodes[i] == device->keysByUsageCode.valueAt(j).keyCode) { outFlags[i] = 1; result = true; } } } } return result; } bool FakeEventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const { const FakeDevice* device = getDevice(deviceId); if (device) { ssize_t index = device->keysByScanCode.indexOfKey(scanCode); return index >= 0; } return false; } bool FakeEventHub::hasLed(int32_t deviceId, int32_t led) const { const FakeDevice* device = getDevice(deviceId); return device && device->leds.indexOfKey(led) >= 0; } void FakeEventHub::setLedState(int32_t deviceId, int32_t led, bool on) { FakeDevice* device = getDevice(deviceId); if (device) { ssize_t index = device->leds.indexOfKey(led); if (index >= 0) { device->leds.replaceValueAt(led, on); } } } void FakeEventHub::getVirtualKeyDefinitions(int32_t deviceId, Vector& outVirtualKeys) const { outVirtualKeys.clear(); const FakeDevice* device = getDevice(deviceId); if (device) { outVirtualKeys.appendVector(device->virtualKeys); } } sp FakeEventHub::getKeyCharacterMap(int32_t deviceId) const { (void)deviceId; return sp(); } bool FakeEventHub::setKeyboardLayoutOverlay(int32_t deviceId, const sp& map) { (void)deviceId; (void)map; return true; } void FakeEventHub::vibrate(int32_t deviceId, nsecs_t duration) { (void)deviceId; (void)duration; } void FakeEventHub::cancelVibrate(int32_t deviceId) { (void)deviceId; } void FakeEventHub::requestReopenDevices() { } void FakeEventHub::wake() { } void FakeEventHub::dump(droidinput::String8& dump) { (void)dump; } void FakeEventHub::monitor() { } void FakeEventHub::flush() { } void FakeEventHub::synthesize_builtin_keyboard_added() { RawEvent event; event.when = 0; event.deviceId = BuiltInKeyboardID; event.type = EventHubInterface::DEVICE_ADDED; std::lock_guard lg(guard); events_available.push_back(event); } void FakeEventHub::synthesize_builtin_cursor_added() { RawEvent event; event.when = 0; event.deviceId = BuiltInCursorID; event.type = EventHubInterface::DEVICE_ADDED; std::lock_guard lg(guard); events_available.push_back(event); } void FakeEventHub::synthesize_device_scan_complete() { RawEvent event; event.when = 0; event.type = EventHubInterface::FINISHED_DEVICE_SCAN; std::lock_guard lg(guard); events_available.push_back(event); } void FakeEventHub::synthesize_event(const mis::KeyParameters ¶meters) { RawEvent event; event.when = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); event.type = EV_KEY; event.code = parameters.scancode; if (parameters.device_id) event.deviceId = parameters.device_id; else event.deviceId = BuiltInKeyboardID; if (parameters.action == mis::EventAction::Down) event.value = 1; else event.value = 0; std::lock_guard lg(guard); events_available.push_back(event); } void FakeEventHub::synthesize_event(const mis::ButtonParameters ¶meters) { RawEvent event; event.when = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); event.type = EV_KEY; event.code = parameters.button; if (parameters.device_id) event.deviceId = parameters.device_id; else event.deviceId = BuiltInCursorID; if (parameters.action == mis::EventAction::Down) event.value = 1; else event.value = 0; std::lock_guard lg(guard); events_available.push_back(event); // Cursor button events require a sync as per droidinput::CursorInputMapper::process event.type = EV_SYN; event.code = SYN_REPORT; events_available.push_back(event); } void FakeEventHub::synthesize_event(const mis::MotionParameters ¶meters) { RawEvent event; event.when = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); event.type = EV_REL; if (parameters.device_id) event.deviceId = parameters.device_id; else event.deviceId = BuiltInCursorID; std::lock_guard lg(guard); event.code = REL_X; event.value = parameters.rel_x; events_available.push_back(event); event.code = REL_Y; event.value = parameters.rel_y; events_available.push_back(event); // Cursor motion events require a sync as per droidinput::CursorInputMapper::process event.type = EV_SYN; event.code = SYN_REPORT; events_available.push_back(event); } void FakeEventHub::synthesize_event(nsecs_t when, int32_t device_id, int32_t type, int32_t code, int32_t value) { RawEvent event; event.when = when; event.deviceId = device_id; event.type = type; event.code = code; event.value = value; { std::lock_guard lg(guard); events_available.push_back(event); } if (type == EV_ABS) { setAbsoluteAxisValue(device_id, code, value); } } void FakeEventHub::addDevice(int32_t deviceId, const std::string& name, uint32_t classes) { FakeDevice device; device.classes = classes; device.identifier.name = name; device_from_id.insert(std::pair(deviceId, device)); synthesize_event(arbitrary_time, deviceId, EventHubInterface::DEVICE_ADDED, 0, 0); } void FakeEventHub::removeDevice(int32_t device_id) { device_from_id.erase(device_id); synthesize_event(arbitrary_time, device_id, EventHubInterface::DEVICE_REMOVED, 0, 0); } void FakeEventHub::finishDeviceScan() { synthesize_event(arbitrary_time, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0); } void FakeEventHub::addConfigurationProperty(int32_t device_id, const std::string& key, const std::string& value) { FakeDevice& device = device_from_id.at(device_id); device.configuration.addProperty(key, value); } void FakeEventHub::addConfigurationMap(int32_t device_id, const PropertyMap* configuration) { FakeDevice& device = device_from_id.at(device_id); device.configuration.addAll(configuration); } void FakeEventHub::addAbsoluteAxis(int32_t device_id, int axis, int32_t minValue, int32_t maxValue, int flat, int fuzz, int resolution) { FakeDevice& device = device_from_id.at(device_id); RawAbsoluteAxisInfo info; info.valid = true; info.minValue = minValue; info.maxValue = maxValue; info.flat = flat; info.fuzz = fuzz; info.resolution = resolution; device.absoluteAxes.add(axis, info); } void FakeEventHub::addRelativeAxis(int32_t device_id, int32_t axis) { FakeDevice& device = device_from_id.at(device_id); device.relativeAxes.add(axis, true); } void FakeEventHub::setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state) { FakeDevice& device = device_from_id.at(deviceId); device.keyCodeStates.replaceValueFor(keyCode, state); } void FakeEventHub::setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state) { FakeDevice& device = device_from_id.at(deviceId); device.scanCodeStates.replaceValueFor(scanCode, state); } void FakeEventHub::setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state) { FakeDevice& device = device_from_id.at(deviceId); device.switchStates.replaceValueFor(switchCode, state); } void FakeEventHub::setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) { FakeDevice& device = device_from_id.at(deviceId); device.absoluteAxisValue.replaceValueFor(axis, value); } void FakeEventHub::addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t keyCode, uint32_t flags) { FakeDevice& device = device_from_id.at(deviceId); KeyInfo info; info.keyCode = keyCode; info.flags = flags; if (scanCode) { device.keysByScanCode.add(scanCode, info); } if (usageCode) { device.keysByUsageCode.add(usageCode, info); } } void FakeEventHub::addLed(int32_t deviceId, int32_t led, bool initialState) { FakeDevice& device = device_from_id.at(deviceId); device.leds.add(led, initialState); } bool FakeEventHub::getLedState(int32_t deviceId, int32_t led) { FakeDevice& device = device_from_id.at(deviceId); return device.leds.valueFor(led); } Vector& FakeEventHub::getExcludedDevices() { return excluded_devices; } void FakeEventHub::addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition) { FakeDevice& device = device_from_id.at(deviceId); device.virtualKeys.push(definition); } FakeEventHub::FakeDevice* FakeEventHub::getDevice(int32_t deviceId) { auto fake_device_iterator = device_from_id.find(deviceId); if (fake_device_iterator != device_from_id.end()) { return &(fake_device_iterator->second); } else { return nullptr; } } const FakeEventHub::FakeDevice* FakeEventHub::getDevice(int32_t deviceId) const { auto fake_device_iterator = device_from_id.find(deviceId); if (fake_device_iterator != device_from_id.end()) { return &(fake_device_iterator->second); } else { return nullptr; } } size_t FakeEventHub::eventsQueueSize() const { return events_available.size(); } mir-0.1.8+14.04.20140411/tests/mir-stress/0000755000015301777760000000000012322054703020151 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/mir-stress/CMakeLists.txt0000644000015301777760000000042312322054223022705 0ustar pbusernogroup00000000000000project(mir_stress) set(SOURCES src/client.cpp src/mir-stress.cpp src/results.cpp src/threading.cpp ) add_executable(mir_stress ${SOURCES}) target_link_libraries( mir_stress mirclient ) install( TARGETS mir_stress RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) mir-0.1.8+14.04.20140411/tests/mir-stress/src/0000755000015301777760000000000012322054703020740 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/mir-stress/src/mir-stress.cpp0000644000015301777760000000466212322054223023561 0ustar pbusernogroup00000000000000/* * 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: Thomi Richards */ #include "results.h" #include "threading.h" #include #include #include #include #include #include #include const std::string option_str("hn:t:p"); const std::string usage("Usage:\n" " -h: This help text.\n" " -n seconds Number of seconds to run. Default is 600 (10 minutes).\n" " -t threads Number of threads to create. Default is the number of cores\n" " on this machine.\n" ); int main(int argc, char **argv) { std::chrono::seconds duration_to_run(60 * 10); unsigned int num_threads = std::thread::hardware_concurrency(); int arg; opterr = 0; while ((arg = getopt(argc, argv, option_str.c_str())) != -1) { switch (arg) { case 'n': duration_to_run = std::chrono::seconds(std::atoi(optarg)); break; case 't': // TODO: limit to sensible values. num_threads = std::atoi(optarg); break; case '?': case 'h': default: std::cout << usage << std::endl; return -1; } } std::vector> futures; for (unsigned int i = 0; i < num_threads; i++) { std::cout << "Creating thread..." << std::endl; futures.push_back( std::async( std::launch::async, run_mir_test, duration_to_run ) ); } std::vector results; for (auto &t: futures) { results.push_back(t.get()); } bool success = true; for (auto &r: results) { std::cout << r.summary(); success &= r.success(); } return success ? 0 : 1; } mir-0.1.8+14.04.20140411/tests/mir-stress/src/results.cpp0000644000015301777760000000252712322054223023150 0ustar pbusernogroup00000000000000/* * 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: Thomi Richards */ #include "results.h" #include ThreadResults::ThreadResults(std::string thread_id) : thread_id_(thread_id) , tests_passed_(0) , tests_failed_(0) {} void ThreadResults::addTestResult(bool passed) { if (passed) ++tests_passed_; else ++tests_failed_; } std::string ThreadResults::summary() const { std::stringstream strstr; strstr << "Thread '" << thread_id_ << "' ran " << tests_passed_ + tests_failed_ << " tests, of which " << tests_passed_ << " passed and " << tests_failed_ << " failed." << std::endl; return strstr.str(); } bool ThreadResults::success() const { return tests_failed_ == 0; } mir-0.1.8+14.04.20140411/tests/mir-stress/src/results.h0000644000015301777760000000202612322054223022607 0ustar pbusernogroup00000000000000/* * 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: Thomi Richards */ #ifndef MIR_STRESS_TEST_RESULTS_H_ #define MIR_STRESS_TEST_RESULTS_H_ #include class ThreadResults { public: ThreadResults(std::string thread_id); void addTestResult(bool passed); std::string summary() const; bool success() const; private: std::string thread_id_; int tests_passed_; int tests_failed_; }; #endif mir-0.1.8+14.04.20140411/tests/mir-stress/src/threading.h0000644000015301777760000000166012322054223023056 0ustar pbusernogroup00000000000000/* * 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: Thomi Richards */ #ifndef MIR_STRESS_TEST_THREADING_H_ #define MIR_STRESS_TEST_THREADING_H_ #include class ThreadResults; // Run the mir test suite for some time, and return the results. ThreadResults run_mir_test(std::chrono::seconds for_seconds); #endif mir-0.1.8+14.04.20140411/tests/mir-stress/src/threading.cpp0000644000015301777760000000333012322054223023405 0ustar pbusernogroup00000000000000/* * 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: Thomi Richards */ #include "threading.h" #include "client.h" #include "results.h" #include #include #include std::string get_application_unique_name() { std::stringstream strstr; strstr << std::this_thread::get_id(); return strstr.str(); } ThreadResults run_mir_test(std::chrono::seconds for_seconds) { std::string thread_name(get_application_unique_name()); ThreadResults results(thread_name); auto start_time = std::chrono::steady_clock::now(); while (start_time + for_seconds > std::chrono::steady_clock::now()) { ClientStateMachine::Ptr p = ClientStateMachine::Create(); if (!p->connect(thread_name)) { results.addTestResult(false); } else { if (!p->create_surface()) { results.addTestResult(false); } else { p->release_surface(); } p->disconnect(); results.addTestResult(true); } } return results; } mir-0.1.8+14.04.20140411/tests/mir-stress/src/client.cpp0000644000015301777760000000561112322054223022722 0ustar pbusernogroup00000000000000/* * 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: Thomi Richards */ #include "client.h" #include "mir_toolkit/mir_client_library.h" #include #include #include #include ClientStateMachine::Ptr ClientStateMachine::Create() { // in the future we can extend this to return different // types of clients. Right now we only return an unaccelerated client. return std::make_shared(); } UnacceleratedClient::UnacceleratedClient() : connection_(nullptr) , surface_(nullptr) { } bool UnacceleratedClient::connect(std::string unique_name, const char* socket_file) { assert(connection_ == nullptr); connection_ = mir_connect_sync(socket_file, unique_name.c_str()); if (! connection_ || ! mir_connection_is_valid(connection_)) { const char* error_message = mir_connection_get_error_message(connection_); if (std::strcmp(error_message, "") != 0) { std::cout << "Could not connect to server, error is: " << error_message << std::endl; } return false; } return true; } bool UnacceleratedClient::create_surface() { auto display_configuration = mir_connection_create_display_config(connection_); if (display_configuration->num_outputs < 1) return false; MirDisplayOutput display_state = display_configuration->outputs[0]; if (display_state.num_output_formats < 1) return false; // TODO: instead of picking the first pixel format, pick a random one! MirPixelFormat const pixel_format = display_state.output_formats[0]; mir_display_config_destroy(display_configuration); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, pixel_format, mir_buffer_usage_software, mir_display_output_id_invalid }; surface_ = mir_connection_create_surface_sync(connection_, &request_params); return true; } void UnacceleratedClient::release_surface() { if (surface_ != nullptr) { mir_surface_release_sync(surface_); surface_ = nullptr; } } void UnacceleratedClient::disconnect() { if (connection_ != nullptr) { mir_connection_release(connection_); connection_ = nullptr; } } mir-0.1.8+14.04.20140411/tests/mir-stress/src/client.h0000644000015301777760000000314712322054223022371 0ustar pbusernogroup00000000000000/* * 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: Thomi Richards */ #ifndef MIR_STRESS_TEST_CLIENT_H_ #define MIR_STRESS_TEST_CLIENT_H_ #include /// A simple state machine that knows how to connect to a mir server, /// issue some devices, and exit cleanly. class ClientStateMachine { public: typedef std::shared_ptr Ptr; virtual ~ClientStateMachine() {}; static Ptr Create(); virtual bool connect(std::string unique_name, const char* socket_file=0) =0; virtual bool create_surface() =0; virtual void release_surface() =0; virtual void disconnect() =0; }; struct MirConnection; struct MirSurface; class UnacceleratedClient: public ClientStateMachine { public: UnacceleratedClient(); bool connect(std::string unique_name, const char* socket_file=0) override; bool create_surface() override; void release_surface() override; void disconnect() override; private: MirConnection* connection_; MirSurface* surface_; }; #endif mir-0.1.8+14.04.20140411/tests/client-language/0000755000015301777760000000000012322054703021100 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/client-language/c89.c0000644000015301777760000000172412322054223021650 0ustar pbusernogroup00000000000000/* * Stub client to be compiled with -std=c89, just to check we have correct * language compatibility in the client header(s). * * 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 * */ #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/mir_client_library_drm.h" #include "mir_toolkit/event.h" int main() { return 0; } mir-0.1.8+14.04.20140411/tests/client-language/CMakeLists.txt0000644000015301777760000000014312322054223023633 0ustar pbusernogroup00000000000000set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c89") add_executable(client-language-test-c89 c89.c ) mir-0.1.8+14.04.20140411/tests/mir_test/0000755000015301777760000000000012322054703017667 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/mir_test/display_config_matchers.cpp0000644000015301777760000002335012322054223025253 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test/display_config_matchers.h" #include "mir/graphics/display_configuration.h" #include "mir_protobuf.pb.h" #include "mir_toolkit/client_types.h" #include namespace mg = mir::graphics; namespace mp = mir::protobuf; namespace geom = mir::geometry; namespace mt = mir::test; namespace { class TestDisplayConfiguration : public mg::DisplayConfiguration { public: TestDisplayConfiguration(mp::DisplayConfiguration const& protobuf_config) { /* Cards */ for (int i = 0; i < protobuf_config.display_card_size(); i++) { auto const& protobuf_card = protobuf_config.display_card(i); mg::DisplayConfigurationCard display_card { mg::DisplayConfigurationCardId(protobuf_card.card_id()), protobuf_card.max_simultaneous_outputs(), }; cards.push_back(display_card); } /* Outputs */ for (int i = 0; i < protobuf_config.display_output_size(); i++) { auto const& protobuf_output = protobuf_config.display_output(i); mg::DisplayConfigurationOutput display_output { mg::DisplayConfigurationOutputId(protobuf_output.output_id()), mg::DisplayConfigurationCardId(protobuf_output.card_id()), static_cast(protobuf_output.type()), {}, {}, protobuf_output.preferred_mode(), geom::Size{protobuf_output.physical_width_mm(), protobuf_output.physical_height_mm()}, static_cast(protobuf_output.connected()), static_cast(protobuf_output.used()), geom::Point{protobuf_output.position_x(), protobuf_output.position_y()}, protobuf_output.current_mode(), static_cast(protobuf_output.current_format()), static_cast(protobuf_output.power_mode()), static_cast(protobuf_output.orientation()) }; /* Modes */ std::vector modes; for (int n = 0; n < protobuf_output.mode_size(); n++) { auto const& protobuf_mode = protobuf_output.mode(n); modes.push_back( { geom::Size{protobuf_mode.horizontal_resolution(), protobuf_mode.vertical_resolution()}, protobuf_mode.refresh_rate() }); } display_output.modes = modes; /* Pixel formats */ std::vector pixel_formats; for (int n = 0; n < protobuf_output.pixel_format_size(); n++) { pixel_formats.push_back( static_cast(protobuf_output.pixel_format(n))); } display_output.pixel_formats = pixel_formats; outputs.push_back(display_output); } } TestDisplayConfiguration(MirDisplayConfiguration const& client_config) { /* Cards */ for (size_t i = 0; i < client_config.num_cards; i++) { auto const& client_card = client_config.cards[i]; mg::DisplayConfigurationCard display_card { mg::DisplayConfigurationCardId(client_card.card_id), client_card.max_simultaneous_outputs, }; cards.push_back(display_card); } /* Outputs */ for (size_t i = 0; i < client_config.num_outputs; i++) { auto const& client_output = client_config.outputs[i]; mg::DisplayConfigurationOutput display_output { mg::DisplayConfigurationOutputId(client_output.output_id), mg::DisplayConfigurationCardId(client_output.card_id), static_cast(client_output.type), {}, {}, client_output.preferred_mode, geom::Size{client_output.physical_width_mm, client_output.physical_height_mm}, static_cast(client_output.connected), static_cast(client_output.used), geom::Point{client_output.position_x, client_output.position_y}, client_output.current_mode, client_output.current_format, static_cast(client_output.power_mode), static_cast(client_output.orientation) }; /* Modes */ std::vector modes; for (size_t n = 0; n < client_output.num_modes; n++) { auto const& client_mode = client_output.modes[n]; modes.push_back( { geom::Size{client_mode.horizontal_resolution, client_mode.vertical_resolution}, client_mode.refresh_rate }); } display_output.modes = modes; /* Pixel formats */ std::vector pixel_formats; for (size_t n = 0; n < client_output.num_output_formats; n++) { pixel_formats.push_back(client_output.output_formats[n]); } display_output.pixel_formats = pixel_formats; outputs.push_back(display_output); } } void for_each_card(std::function f) const override { for (auto const& card : cards) f(card); } void for_each_output(std::function f) const override { for (auto const& output : outputs) f(output); } void for_each_output(std::function f) override { for (auto& output : outputs) { mg::UserDisplayConfigurationOutput user(output); f(user); } } private: std::vector cards; std::vector outputs; }; } bool mt::compare_display_configurations(mg::DisplayConfiguration const& config1, mg::DisplayConfiguration const& config2) { bool result = true; /* cards */ std::vector cards1; std::vector cards2; config1.for_each_card( [&cards1](mg::DisplayConfigurationCard const& card) { cards1.push_back(card); }); config2.for_each_card( [&cards2](mg::DisplayConfigurationCard const& card) { cards2.push_back(card); }); if (cards1.size() == cards2.size()) { for (size_t i = 0; i < cards1.size(); i++) { if (cards1[i] != cards2[i]) { EXPECT_EQ(cards1[i], cards2[i]); result = false; } } } else { EXPECT_EQ(cards1.size(), cards2.size()); result = false; } /* Outputs */ std::vector outputs1; std::vector outputs2; config1.for_each_output( [&outputs1](mg::DisplayConfigurationOutput const& output) { outputs1.push_back(output); }); config2.for_each_output( [&outputs2](mg::DisplayConfigurationOutput const& output) { outputs2.push_back(output); }); if (outputs1.size() == outputs2.size()) { for (size_t i = 0; i < outputs1.size(); i++) { if (outputs1[i] != outputs2[i]) { EXPECT_EQ(outputs1[i], outputs2[i]); result = false; } } } else { EXPECT_EQ(outputs1.size(), outputs2.size()); result = false; } return result; } bool mt::compare_display_configurations(MirDisplayConfiguration const& client_config, mg::DisplayConfiguration const& display_config) { TestDisplayConfiguration config1{client_config}; return compare_display_configurations(config1, display_config); } bool mt::compare_display_configurations(mp::DisplayConfiguration const& protobuf_config, mg::DisplayConfiguration const& display_config) { TestDisplayConfiguration config1{protobuf_config}; return compare_display_configurations(config1, display_config); } bool mt::compare_display_configurations(MirDisplayConfiguration const& client_config, mp::DisplayConfiguration const& protobuf_config) { TestDisplayConfiguration config1{client_config}; TestDisplayConfiguration config2{protobuf_config}; return compare_display_configurations(config1, config2); } mir-0.1.8+14.04.20140411/tests/mir_test/CMakeLists.txt0000644000015301777760000000014612322054223022425 0ustar pbusernogroup00000000000000add_library( mir-test STATIC pipe.cpp display_config_matchers.cpp cross_process_action.cpp ) mir-0.1.8+14.04.20140411/tests/mir_test/pipe.cpp0000644000015301777760000000240412322054223021325 0ustar pbusernogroup00000000000000/* * 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 */ #include #include #include #include #include namespace mt = mir::test; mt::Pipe::Pipe() { if (pipe(pipefd)) { BOOST_THROW_EXCEPTION( boost::enable_error_info(std::runtime_error("Failed to create pipe")) << boost::errinfo_errno(errno)); } } mt::Pipe::~Pipe() { close(pipefd[0]); close(pipefd[1]); } int mt::Pipe::read_fd() const { return pipefd[0]; } int mt::Pipe::write_fd() const { return pipefd[1]; } mir-0.1.8+14.04.20140411/tests/mir_test/cross_process_action.cpp0000644000015301777760000000202512322054223024613 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test/cross_process_action.h" namespace mt = mir::test; void mt::CrossProcessAction::exec(std::function const& f) { start_sync.wait_for_signal_ready(); f(); finish_sync.signal_ready(); } void mt::CrossProcessAction::operator()() { start_sync.signal_ready(); finish_sync.wait_for_signal_ready(); } mir-0.1.8+14.04.20140411/tests/integration-tests/0000755000015301777760000000000012322054703021524 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/integration-tests/frontend/0000755000015301777760000000000012322054703023343 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/integration-tests/frontend/CMakeLists.txt0000644000015301777760000000026612322054223026104 0ustar pbusernogroup00000000000000list( APPEND INTEGRATION_TESTS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_application_mediator_report.cpp ) set( INTEGRATION_TESTS_SRCS ${INTEGRATION_TESTS_SRCS} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/integration-tests/frontend/test_application_mediator_report.cpp0000644000015301777760000003000112322054223032657 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "mir/frontend/session_mediator_report.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test/test_protobuf_client.h" #include #include namespace mf = mir::frontend; namespace mt = mir::test; namespace mtf = mir_test_framework; namespace { struct MockApplicationMediatorReport : mf::SessionMediatorReport { MockApplicationMediatorReport() { EXPECT_CALL(*this, session_connect_called(testing::_)). Times(testing::AtLeast(0)); EXPECT_CALL(*this, session_create_surface_called(testing::_)). Times(testing::AtLeast(0)); EXPECT_CALL(*this, session_next_buffer_called(testing::_)). Times(testing::AtLeast(0)); EXPECT_CALL(*this, session_release_surface_called(testing::_)). Times(testing::AtLeast(0)); EXPECT_CALL(*this, session_disconnect_called(testing::_)). Times(testing::AtLeast(0)); } MOCK_METHOD1(session_connect_called, void (std::string const&)); MOCK_METHOD1(session_create_surface_called, void (std::string const&)); MOCK_METHOD1(session_next_buffer_called, void (std::string const&)); MOCK_METHOD1(session_release_surface_called, void (std::string const&)); MOCK_METHOD1(session_disconnect_called, void (std::string const&)); void session_drm_auth_magic_called(const std::string&) override {}; void session_configure_surface_called(std::string const&) override {}; void session_configure_display_called(std::string const&) override {}; void session_error(const std::string&, const char*, const std::string&) override {}; }; const int rpc_timeout_ms{100000}; typedef BespokeDisplayServerTestFixture ApplicationMediatorReport; } TEST_F(ApplicationMediatorReport, session_connect_called) { struct Server : TestingServerConfiguration { std::shared_ptr the_application_mediator_report() { auto result = std::make_shared(); EXPECT_CALL(*result, session_connect_called(testing::_)). Times(1); return result; } } server_processing; launch_server_process(server_processing); struct Client: TestingClientConfiguration { void exec() { mt::TestProtobufClient client(mtf::test_socket_file(), rpc_timeout_ms); client.connect_parameters.set_application_name(__PRETTY_FUNCTION__); EXPECT_CALL(client, connect_done()). Times(testing::AtLeast(0)); client.display_server.connect( 0, &client.connect_parameters, &client.connection, google::protobuf::NewCallback(&client, &mt::TestProtobufClient::connect_done)); client.wait_for_connect_done(); } } client_process; launch_client_process(client_process); } TEST_F(ApplicationMediatorReport, session_create_surface_called) { struct Server : TestingServerConfiguration { std::shared_ptr the_application_mediator_report() { auto result = std::make_shared(); EXPECT_CALL(*result, session_create_surface_called(testing::_)). Times(1); return result; } } server_processing; launch_server_process(server_processing); struct Client: TestingClientConfiguration { void exec() { mt::TestProtobufClient client(mtf::test_socket_file(), rpc_timeout_ms); client.connect_parameters.set_application_name(__PRETTY_FUNCTION__); EXPECT_CALL(client, connect_done()). Times(testing::AtLeast(0)); EXPECT_CALL(client, create_surface_done()). Times(testing::AtLeast(0)); client.display_server.connect( 0, &client.connect_parameters, &client.connection, google::protobuf::NewCallback(&client, &mt::TestProtobufClient::connect_done)); client.wait_for_connect_done(); client.display_server.create_surface( 0, &client.surface_parameters, &client.surface, google::protobuf::NewCallback(&client, &mt::TestProtobufClient::create_surface_done)); client.wait_for_create_surface(); } } client_process; launch_client_process(client_process); } TEST_F(ApplicationMediatorReport, session_next_buffer_called) { struct Server : TestingServerConfiguration { std::shared_ptr the_application_mediator_report() { auto result = std::make_shared(); EXPECT_CALL(*result, session_next_buffer_called(testing::_)). Times(1); return result; } } server_processing; launch_server_process(server_processing); struct Client: TestingClientConfiguration { void exec() { mt::TestProtobufClient client(mtf::test_socket_file(), rpc_timeout_ms); client.connect_parameters.set_application_name(__PRETTY_FUNCTION__); EXPECT_CALL(client, connect_done()).Times(testing::AtLeast(0)); EXPECT_CALL(client, create_surface_done()).Times(testing::AtLeast(0)); EXPECT_CALL(client, next_buffer_done()).Times(testing::AtLeast(0)); client.display_server.connect( 0, &client.connect_parameters, &client.connection, google::protobuf::NewCallback(&client, &mt::TestProtobufClient::connect_done)); client.wait_for_connect_done(); client.display_server.create_surface( 0, &client.surface_parameters, &client.surface, google::protobuf::NewCallback(&client, &mt::TestProtobufClient::create_surface_done)); client.wait_for_create_surface(); client.display_server.next_buffer( 0, &client.surface.id(), client.surface.mutable_buffer(), google::protobuf::NewCallback(&client, &mt::TestProtobufClient::next_buffer_done)); client.wait_for_next_buffer(); } } client_process; launch_client_process(client_process); } TEST_F(ApplicationMediatorReport, session_release_surface_called) { struct Server : TestingServerConfiguration { std::shared_ptr the_application_mediator_report() { auto result = std::make_shared(); EXPECT_CALL(*result, session_release_surface_called(testing::_)). Times(1); return result; } } server_processing; launch_server_process(server_processing); struct Client: TestingClientConfiguration { void exec() { mt::TestProtobufClient client(mtf::test_socket_file(), rpc_timeout_ms); client.connect_parameters.set_application_name(__PRETTY_FUNCTION__); EXPECT_CALL(client, connect_done()).Times(testing::AtLeast(0)); EXPECT_CALL(client, create_surface_done()).Times(testing::AtLeast(0)); EXPECT_CALL(client, next_buffer_done()).Times(testing::AtLeast(0)); EXPECT_CALL(client, release_surface_done()).Times(testing::AtLeast(0)); client.display_server.connect( 0, &client.connect_parameters, &client.connection, google::protobuf::NewCallback(&client, &mt::TestProtobufClient::connect_done)); client.wait_for_connect_done(); client.display_server.create_surface( 0, &client.surface_parameters, &client.surface, google::protobuf::NewCallback(&client, &mt::TestProtobufClient::create_surface_done)); client.wait_for_create_surface(); client.display_server.next_buffer( 0, &client.surface.id(), client.surface.mutable_buffer(), google::protobuf::NewCallback(&client, &mt::TestProtobufClient::next_buffer_done)); client.wait_for_next_buffer(); client.display_server.release_surface( 0, &client.surface.id(), &client.ignored, google::protobuf::NewCallback(&client, &mt::TestProtobufClient::release_surface_done)); client.wait_for_release_surface(); } } client_process; launch_client_process(client_process); } TEST_F(ApplicationMediatorReport, session_disconnect_called) { struct Server : TestingServerConfiguration { std::shared_ptr the_application_mediator_report() { auto result = std::make_shared(); EXPECT_CALL(*result, session_disconnect_called(testing::_)). Times(1); return result; } } server_processing; launch_server_process(server_processing); struct Client: TestingClientConfiguration { void exec() { mt::TestProtobufClient client(mtf::test_socket_file(), rpc_timeout_ms); client.connect_parameters.set_application_name(__PRETTY_FUNCTION__); EXPECT_CALL(client, connect_done()).Times(testing::AtLeast(0)); EXPECT_CALL(client, create_surface_done()).Times(testing::AtLeast(0)); EXPECT_CALL(client, next_buffer_done()).Times(testing::AtLeast(0)); EXPECT_CALL(client, release_surface_done()).Times(testing::AtLeast(0)); EXPECT_CALL(client, disconnect_done()).Times(testing::AtLeast(0)); client.display_server.connect( 0, &client.connect_parameters, &client.connection, google::protobuf::NewCallback(&client, &mt::TestProtobufClient::connect_done)); client.wait_for_connect_done(); client.display_server.create_surface( 0, &client.surface_parameters, &client.surface, google::protobuf::NewCallback(&client, &mt::TestProtobufClient::create_surface_done)); client.wait_for_create_surface(); client.display_server.next_buffer( 0, &client.surface.id(), client.surface.mutable_buffer(), google::protobuf::NewCallback(&client, &mt::TestProtobufClient::next_buffer_done)); client.wait_for_next_buffer(); client.display_server.release_surface( 0, &client.surface.id(), &client.ignored, google::protobuf::NewCallback(&client, &mt::TestProtobufClient::release_surface_done)); client.wait_for_release_surface(); client.display_server.disconnect( 0, &client.ignored, &client.ignored, google::protobuf::NewCallback(&client, &mt::TestProtobufClient::disconnect_done)); client.wait_for_disconnect_done(); } } client_process; launch_client_process(client_process); } mir-0.1.8+14.04.20140411/tests/integration-tests/test_session.cpp0000644000015301777760000001417212322054223024754 0ustar pbusernogroup00000000000000/* * 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 "mir/default_server_configuration.h" #include "src/server/input/null_input_configuration.h" #include "mir/compositor/compositor.h" #include "src/server/scene/application_session.h" #include "src/server/scene/pixel_buffer.h" #include "mir/shell/placement_strategy.h" #include "mir/shell/surface.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/shell/null_session_listener.h" #include "mir/compositor/buffer_stream.h" #include "mir/compositor/renderer.h" #include "mir/compositor/renderer_factory.h" #include "mir/frontend/connector.h" #include "mir_test_doubles/stub_buffer_allocator.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/null_event_sink.h" #include "mir_test_doubles/stub_display_buffer.h" #include "mir_test_doubles/stub_renderer.h" #include namespace mc = mir::compositor; namespace mtd = mir::test::doubles; namespace ms = mir::scene; namespace msh = mir::shell; namespace mi = mir::input; namespace mf = mir::frontend; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace { struct TestServerConfiguration : public mir::DefaultServerConfiguration { TestServerConfiguration() : DefaultServerConfiguration(0, nullptr) {} std::shared_ptr the_input_configuration() override { if (!input_configuration) input_configuration = std::make_shared(); return input_configuration; } std::shared_ptr the_connector() override { struct NullConnector : public mf::Connector { void start() {} void stop() {} int client_socket_fd() const override { return 0; } void remove_endpoint() const override { } }; return std::make_shared(); } std::shared_ptr the_buffer_allocator() override { return buffer_allocator( [] { return std::make_shared(); }); } std::shared_ptr the_renderer_factory() override { struct StubRendererFactory : public mc::RendererFactory { std::unique_ptr create_renderer_for(geom::Rectangle const&) { auto raw = new mtd::StubRenderer{}; return std::unique_ptr(raw); } }; return std::make_shared(); } std::shared_ptr the_pixel_buffer() override { struct StubPixelBuffer : public ms::PixelBuffer { void fill_from(mg::Buffer&) {} void const* as_argb_8888() { return nullptr; } geom::Size size() const { return geom::Size(); } geom::Stride stride() const { return geom::Stride(); } }; return pixel_buffer( [] { return std::make_shared(); }); } std::shared_ptr the_display() override { struct StubDisplay : public mtd::NullDisplay { StubDisplay() : buffers{mtd::StubDisplayBuffer{geom::Rectangle{{0,0},{100,100}}}, mtd::StubDisplayBuffer{geom::Rectangle{{100,0},{100,100}}}, mtd::StubDisplayBuffer{geom::Rectangle{{0,100},{100,100}}}} { } void for_each_display_buffer(std::function const& f) { for (auto& db : buffers) f(db); } std::vector buffers; }; return display( []() { return std::make_shared(); }); } std::shared_ptr input_configuration; }; } TEST(ApplicationSession, stress_test_take_snapshot) { TestServerConfiguration conf; ms::ApplicationSession session{ conf.the_shell_surface_factory(), __LINE__, "stress", conf.the_snapshot_strategy(), std::make_shared(), std::make_shared() }; session.create_surface(msh::a_surface()); auto compositor = conf.the_compositor(); compositor->start(); session.default_surface()->allow_framedropping(true); std::thread client_thread{ [&session] { mg::Buffer* buffer{nullptr}; for (int i = 0; i < 500; ++i) { auto surface = session.default_surface(); surface->swap_buffers_blocking(buffer); std::this_thread::sleep_for(std::chrono::microseconds{50}); } }}; std::thread snapshot_thread{ [&session] { for (int i = 0; i < 500; ++i) { bool snapshot_taken1 = false; bool snapshot_taken2 = false; session.take_snapshot( [&](msh::Snapshot const&) { snapshot_taken1 = true; }); session.take_snapshot( [&](msh::Snapshot const&) { snapshot_taken2 = true; }); while (!snapshot_taken1 || !snapshot_taken2) std::this_thread::sleep_for(std::chrono::microseconds{50}); } }}; client_thread.join(); snapshot_thread.join(); compositor->stop(); } mir-0.1.8+14.04.20140411/tests/integration-tests/test_display_server_main_loop_events.cpp0000644000015301777760000005163412322054223031751 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/compositor/compositor.h" #include "mir/frontend/connector.h" #include "mir/graphics/display_configuration.h" #include "mir/graphics/display_configuration_policy.h" #include "mir/main_loop.h" #include "mir/display_changer.h" #include "mir/server_status_listener.h" #include "mir_test/pipe.h" #include "mir_test_framework/testing_server_configuration.h" #include "mir_test_doubles/mock_input_manager.h" #include "mir_test_doubles/mock_compositor.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/mock_server_status_listener.h" #include "mir/run_mir.h" #include #include #include #include #include #include #include namespace mi = mir::input; namespace mc = mir::compositor; namespace mg = mir::graphics; namespace mf = mir::frontend; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace mtf = mir_test_framework; namespace { class MockConnector : public mf::Connector { public: MOCK_METHOD0(start, void()); MOCK_METHOD0(stop, void()); /* * We don't have expectations for these, so use stubs * to silence gmock warnings. */ int client_socket_fd() const { return 0; } void remove_endpoint() const {} }; class MockDisplayChanger : public mir::DisplayChanger { public: MOCK_METHOD2(configure_for_hardware_change, void(std::shared_ptr const& conf, SystemStateHandling pause_resume_system)); }; class MockDisplay : public mtd::NullDisplay { public: MockDisplay(std::shared_ptr const& display, int pause_signal, int resume_signal, int fd) : display{display}, pause_signal{pause_signal}, resume_signal{resume_signal}, fd{fd}, pause_handler_invoked_{false}, resume_handler_invoked_{false}, conf_change_handler_invoked_{false} { } void for_each_display_buffer(std::function const& f) override { display->for_each_display_buffer(f); } std::unique_ptr configuration() const override { return std::unique_ptr( new mtd::NullDisplayConfiguration ); } MOCK_METHOD1(configure, void(mg::DisplayConfiguration const&)); void register_configuration_change_handler( mg::EventHandlerRegister& handlers, mg::DisplayConfigurationChangeHandler const& conf_change_handler) override { handlers.register_fd_handler( {fd}, [this,conf_change_handler](int fd) { char c; if (read(fd, &c, 1) == 1) { conf_change_handler(); conf_change_handler_invoked_ = true; } }); } void register_pause_resume_handlers( mg::EventHandlerRegister& handlers, mg::DisplayPauseHandler const& pause_handler, mg::DisplayResumeHandler const& resume_handler) override { handlers.register_signal_handler( {pause_signal}, [this,pause_handler](int) { pause_handler(); pause_handler_invoked_ = true; }); handlers.register_signal_handler( {resume_signal}, [this,resume_handler](int) { resume_handler(); resume_handler_invoked_ = true; }); } MOCK_METHOD0(pause, void()); MOCK_METHOD0(resume, void()); bool pause_handler_invoked() { return pause_handler_invoked_.exchange(false); } bool resume_handler_invoked() { return resume_handler_invoked_.exchange(false); } bool conf_change_handler_invoked() { return conf_change_handler_invoked_.exchange(false); } private: std::shared_ptr const display; int const pause_signal; int const resume_signal; int const fd; std::atomic pause_handler_invoked_; std::atomic resume_handler_invoked_; std::atomic conf_change_handler_invoked_; }; class ServerConfig : public mtf::TestingServerConfiguration { public: std::shared_ptr the_input_manager() override { if (!mock_input_manager) { mock_input_manager = std::make_shared(); EXPECT_CALL(*mock_input_manager, start()).Times(1); EXPECT_CALL(*mock_input_manager, stop()).Times(1); } return mock_input_manager; } std::shared_ptr the_compositor() override { if (!mock_compositor) { mock_compositor = std::make_shared(); EXPECT_CALL(*mock_compositor, start()).Times(1); EXPECT_CALL(*mock_compositor, stop()).Times(1); } return mock_compositor; } private: std::shared_ptr mock_input_manager; std::shared_ptr mock_compositor; }; class TestMainLoopServerConfig : public mtf::TestingServerConfiguration { public: TestMainLoopServerConfig() : pause_signal{SIGUSR1}, resume_signal{SIGUSR2} { } std::shared_ptr the_display() override { if (!mock_display) { auto display = mtf::TestingServerConfiguration::the_display(); mock_display = std::make_shared(display, pause_signal, resume_signal, p.read_fd()); } return mock_display; } std::shared_ptr the_compositor() override { if (!mock_compositor) mock_compositor = std::make_shared(); return mock_compositor; } std::shared_ptr the_connector() override { if (!mock_connector) mock_connector = std::make_shared(); return mock_connector; } std::shared_ptr the_input_manager() override { if (!mock_input_manager) mock_input_manager = std::make_shared(); return mock_input_manager; } std::shared_ptr the_display_changer() override { if (!mock_display_changer) mock_display_changer = std::make_shared(); return mock_display_changer; } std::shared_ptr the_mock_display() { the_display(); return mock_display; } std::shared_ptr the_mock_compositor() { the_compositor(); return mock_compositor; } std::shared_ptr the_mock_connector() { the_connector(); return mock_connector; } std::shared_ptr the_mock_input_manager() { the_input_manager(); return mock_input_manager; } std::shared_ptr the_mock_display_changer() { the_display_changer(); return mock_display_changer; } void emit_pause_event_and_wait_for_handler() { kill(getpid(), pause_signal); while (!mock_display->pause_handler_invoked()) std::this_thread::sleep_for(std::chrono::microseconds{500}); } void emit_resume_event_and_wait_for_handler() { kill(getpid(), resume_signal); while (!mock_display->resume_handler_invoked()) std::this_thread::sleep_for(std::chrono::microseconds{500}); } void emit_configuration_change_event_and_wait_for_handler() { if (write(p.write_fd(), "a", 1)) {} while (!mock_display->conf_change_handler_invoked()) std::this_thread::sleep_for(std::chrono::microseconds{500}); } private: std::shared_ptr mock_compositor; std::shared_ptr mock_display; std::shared_ptr mock_connector; std::shared_ptr mock_input_manager; std::shared_ptr mock_display_changer; mt::Pipe p; int const pause_signal; int const resume_signal; }; class TestServerStatusListenerConfig : public TestMainLoopServerConfig { public: std::shared_ptr the_server_status_listener() override { if (!mock_server_status_listener) mock_server_status_listener = std::make_shared(); return mock_server_status_listener; } std::shared_ptr the_mock_server_status_listener() { the_server_status_listener(); return mock_server_status_listener; } private: std::shared_ptr mock_server_status_listener; }; } TEST(DisplayServerMainLoopEvents, display_server_shuts_down_properly_on_sigint) { ServerConfig server_config; mir::run_mir(server_config, [](mir::DisplayServer&) { kill(getpid(), SIGINT); }); } TEST(DisplayServerMainLoopEvents, display_server_shuts_down_properly_on_sigterm) { ServerConfig server_config; mir::run_mir(server_config, [](mir::DisplayServer&) { kill(getpid(), SIGTERM); }); } TEST(DisplayServerMainLoopEvents, display_server_components_pause_and_resume) { using namespace testing; TestMainLoopServerConfig server_config; auto mock_compositor = server_config.the_mock_compositor(); auto mock_display = server_config.the_mock_display(); auto mock_connector = server_config.the_mock_connector(); auto mock_input_manager = server_config.the_mock_input_manager(); { InSequence s; /* Start */ EXPECT_CALL(*mock_connector, start()).Times(1); EXPECT_CALL(*mock_compositor, start()).Times(1); EXPECT_CALL(*mock_input_manager, start()).Times(1); /* Pause */ EXPECT_CALL(*mock_input_manager, stop()).Times(1); EXPECT_CALL(*mock_compositor, stop()).Times(1); EXPECT_CALL(*mock_connector, stop()).Times(1); EXPECT_CALL(*mock_display, pause()).Times(1); /* Resume */ EXPECT_CALL(*mock_display, resume()).Times(1); EXPECT_CALL(*mock_connector, start()).Times(1); EXPECT_CALL(*mock_input_manager, start()).Times(1); EXPECT_CALL(*mock_compositor, start()).Times(1); /* Stop */ EXPECT_CALL(*mock_input_manager, stop()).Times(1); EXPECT_CALL(*mock_compositor, stop()).Times(1); EXPECT_CALL(*mock_connector, stop()).Times(1); } mir::run_mir(server_config, [&server_config](mir::DisplayServer&) { std::thread t{ [&] { server_config.emit_pause_event_and_wait_for_handler(); server_config.emit_resume_event_and_wait_for_handler(); kill(getpid(), SIGTERM); }}; t.detach(); }); } TEST(DisplayServerMainLoopEvents, display_server_quits_when_paused) { using namespace testing; TestMainLoopServerConfig server_config; auto mock_compositor = server_config.the_mock_compositor(); auto mock_display = server_config.the_mock_display(); auto mock_connector = server_config.the_mock_connector(); auto mock_input_manager = server_config.the_mock_input_manager(); { InSequence s; /* Start */ EXPECT_CALL(*mock_connector, start()).Times(1); EXPECT_CALL(*mock_compositor, start()).Times(1); EXPECT_CALL(*mock_input_manager, start()).Times(1); /* Pause */ EXPECT_CALL(*mock_input_manager, stop()).Times(1); EXPECT_CALL(*mock_compositor, stop()).Times(1); EXPECT_CALL(*mock_connector, stop()).Times(1); EXPECT_CALL(*mock_display, pause()).Times(1); /* Stop */ EXPECT_CALL(*mock_input_manager, stop()).Times(1); EXPECT_CALL(*mock_compositor, stop()).Times(1); EXPECT_CALL(*mock_connector, stop()).Times(1); } mir::run_mir(server_config, [&server_config](mir::DisplayServer&) { std::thread t{ [&] { server_config.emit_pause_event_and_wait_for_handler(); kill(getpid(), SIGTERM); }}; t.detach(); }); } TEST(DisplayServerMainLoopEvents, display_server_attempts_to_continue_on_pause_failure) { using namespace testing; TestMainLoopServerConfig server_config; auto mock_compositor = server_config.the_mock_compositor(); auto mock_display = server_config.the_mock_display(); auto mock_connector = server_config.the_mock_connector(); auto mock_input_manager = server_config.the_mock_input_manager(); { InSequence s; /* Start */ EXPECT_CALL(*mock_connector, start()).Times(1); EXPECT_CALL(*mock_compositor, start()).Times(1); EXPECT_CALL(*mock_input_manager, start()).Times(1); /* Pause failure */ EXPECT_CALL(*mock_input_manager, stop()).Times(1); EXPECT_CALL(*mock_compositor, stop()).Times(1); EXPECT_CALL(*mock_connector, stop()).Times(1); EXPECT_CALL(*mock_display, pause()) .WillOnce(Throw(std::runtime_error(""))); /* Attempt to continue */ EXPECT_CALL(*mock_connector, start()).Times(1); EXPECT_CALL(*mock_compositor, start()).Times(1); EXPECT_CALL(*mock_input_manager, start()).Times(1); /* Stop */ EXPECT_CALL(*mock_input_manager, stop()).Times(1); EXPECT_CALL(*mock_compositor, stop()).Times(1); EXPECT_CALL(*mock_connector, stop()).Times(1); } mir::run_mir(server_config, [&server_config](mir::DisplayServer&) { std::thread t{ [&] { server_config.emit_pause_event_and_wait_for_handler(); kill(getpid(), SIGTERM); }}; t.detach(); }); } TEST(DisplayServerMainLoopEvents, display_server_handles_configuration_change) { using namespace testing; TestMainLoopServerConfig server_config; auto mock_compositor = server_config.the_mock_compositor(); auto mock_display = server_config.the_mock_display(); auto mock_connector = server_config.the_mock_connector(); auto mock_input_manager = server_config.the_mock_input_manager(); auto mock_display_changer = server_config.the_mock_display_changer(); { InSequence s; /* Start */ EXPECT_CALL(*mock_connector, start()).Times(1); EXPECT_CALL(*mock_compositor, start()).Times(1); EXPECT_CALL(*mock_input_manager, start()).Times(1); /* Configuration change event */ EXPECT_CALL(*mock_display_changer, configure_for_hardware_change(_, mir::DisplayChanger::PauseResumeSystem)) .Times(1); /* Stop */ EXPECT_CALL(*mock_input_manager, stop()).Times(1); EXPECT_CALL(*mock_compositor, stop()).Times(1); EXPECT_CALL(*mock_connector, stop()).Times(1); } mir::run_mir(server_config, [&](mir::DisplayServer&) { std::thread t{ [&] { server_config.emit_configuration_change_event_and_wait_for_handler(); kill(getpid(), SIGTERM); }}; t.detach(); }); } TEST(DisplayServerMainLoopEvents, postpones_configuration_when_paused) { using namespace testing; TestMainLoopServerConfig server_config; auto mock_compositor = server_config.the_mock_compositor(); auto mock_display = server_config.the_mock_display(); auto mock_connector = server_config.the_mock_connector(); auto mock_input_manager = server_config.the_mock_input_manager(); auto mock_display_changer = server_config.the_mock_display_changer(); { InSequence s; /* Start */ EXPECT_CALL(*mock_connector, start()).Times(1); EXPECT_CALL(*mock_compositor, start()).Times(1); EXPECT_CALL(*mock_input_manager, start()).Times(1); /* Pause event */ EXPECT_CALL(*mock_input_manager, stop()).Times(1); EXPECT_CALL(*mock_compositor, stop()).Times(1); EXPECT_CALL(*mock_connector, stop()).Times(1); EXPECT_CALL(*mock_display, pause()) .Times(1); /* Resume and reconfigure event */ EXPECT_CALL(*mock_display, resume()).Times(1); EXPECT_CALL(*mock_connector, start()).Times(1); EXPECT_CALL(*mock_display_changer, configure_for_hardware_change(_, mir::DisplayChanger::RetainSystemState)) .Times(1); EXPECT_CALL(*mock_input_manager, start()).Times(1); EXPECT_CALL(*mock_compositor, start()).Times(1); /* Stop */ EXPECT_CALL(*mock_input_manager, stop()).Times(1); EXPECT_CALL(*mock_compositor, stop()).Times(1); EXPECT_CALL(*mock_connector, stop()).Times(1); } mir::run_mir(server_config, [&](mir::DisplayServer&) { std::thread t{ [&] { server_config.emit_pause_event_and_wait_for_handler(); server_config.emit_configuration_change_event_and_wait_for_handler(); server_config.emit_resume_event_and_wait_for_handler(); kill(getpid(), SIGTERM); }}; t.detach(); }); } TEST(DisplayServerMainLoopEvents, server_status_listener) { using namespace testing; TestServerStatusListenerConfig server_config; auto mock_compositor = server_config.the_mock_compositor(); auto mock_display = server_config.the_mock_display(); auto mock_connector = server_config.the_mock_connector(); auto mock_input_manager = server_config.the_mock_input_manager(); auto mock_server_status_listener = server_config.the_mock_server_status_listener(); { InSequence s; /* "started" is emitted after all components have been started */ EXPECT_CALL(*mock_connector, start()).Times(1); EXPECT_CALL(*mock_compositor, start()).Times(1); EXPECT_CALL(*mock_input_manager, start()).Times(1); EXPECT_CALL(*mock_server_status_listener, started()).Times(1); /* "paused" is emitted after all components have been paused/stopped */ EXPECT_CALL(*mock_input_manager, stop()).Times(1); EXPECT_CALL(*mock_compositor, stop()).Times(1); EXPECT_CALL(*mock_connector, stop()).Times(1); EXPECT_CALL(*mock_display, pause()).Times(1); EXPECT_CALL(*mock_server_status_listener, paused()).Times(1); /* "resumed" is emitted after all components have been resumed/started */ EXPECT_CALL(*mock_display, resume()).Times(1); EXPECT_CALL(*mock_connector, start()).Times(1); EXPECT_CALL(*mock_input_manager, start()).Times(1); EXPECT_CALL(*mock_compositor, start()).Times(1); EXPECT_CALL(*mock_server_status_listener, resumed()).Times(1); /* Stop */ EXPECT_CALL(*mock_input_manager, stop()).Times(1); EXPECT_CALL(*mock_compositor, stop()).Times(1); EXPECT_CALL(*mock_connector, stop()).Times(1); } mir::run_mir(server_config, [&server_config](mir::DisplayServer&) { std::thread t{ [&] { server_config.emit_pause_event_and_wait_for_handler(); server_config.emit_resume_event_and_wait_for_handler(); kill(getpid(), SIGTERM); }}; t.detach(); }); } mir-0.1.8+14.04.20140411/tests/integration-tests/test_error_reporting.cpp0000644000015301777760000001630512322054223026513 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "src/server/frontend/protobuf_ipc_factory.h" #include "src/server/frontend/resource_cache.h" #include "mir/frontend/connector.h" #include "mir_protobuf.pb.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_doubles/stub_ipc_factory.h" #include #include #include #include #include #include "mir_test/gmock_fixes.h" namespace mc = mir::compositor; namespace mf = mir::frontend; namespace mg = mir::graphics; namespace mi = mir::input; namespace mtf = mir_test_framework; namespace mtd = mir::test::doubles; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); struct ErrorServer : mir::protobuf::DisplayServer { static std::string const test_exception_text; void create_surface( google::protobuf::RpcController*, const mir::protobuf::SurfaceParameters*, mir::protobuf::Surface*, google::protobuf::Closure*) { throw std::runtime_error(test_exception_text); } void release_surface( google::protobuf::RpcController*, const mir::protobuf::SurfaceId*, mir::protobuf::Void*, google::protobuf::Closure*) { throw std::runtime_error(test_exception_text); } void connect( ::google::protobuf::RpcController*, const ::mir::protobuf::ConnectParameters*, ::mir::protobuf::Connection*, ::google::protobuf::Closure*) { throw std::runtime_error(test_exception_text); } void disconnect( google::protobuf::RpcController*, const mir::protobuf::Void*, mir::protobuf::Void*, google::protobuf::Closure*) { throw std::runtime_error(test_exception_text); } void test_file_descriptors( google::protobuf::RpcController*, const mir::protobuf::Void*, mir::protobuf::Buffer*, google::protobuf::Closure*) { throw std::runtime_error(test_exception_text); } }; std::string const ErrorServer::test_exception_text{"test exception text"}; struct SurfaceSync { SurfaceSync() : surface(0) { } void surface_created(MirSurface * new_surface) { std::unique_lock lock(guard); surface = new_surface; wait_condition.notify_all(); } void surface_released(MirSurface * /*released_surface*/) { std::unique_lock lock(guard); surface = NULL; wait_condition.notify_all(); } void wait_for_surface_create() { std::unique_lock lock(guard); while (!surface) wait_condition.wait(lock); } void wait_for_surface_release() { std::unique_lock lock(guard); while (surface) wait_condition.wait(lock); } std::mutex guard; std::condition_variable wait_condition; MirSurface * surface; }; struct ClientConfigCommon : TestingClientConfiguration { ClientConfigCommon() : connection(NULL) { } static void connection_callback(MirConnection * connection, void * context) { ClientConfigCommon * config = reinterpret_cast(context); config->connected(connection); } void connected(MirConnection * new_connection) { std::unique_lock lock(guard); connection = new_connection; wait_condition.notify_all(); } void wait_for_connect() { std::unique_lock lock(guard); while (!connection) wait_condition.wait(lock); } std::mutex guard; std::condition_variable wait_condition; MirConnection * connection; static const int max_surface_count = 5; SurfaceSync ssync[max_surface_count]; }; const int ClientConfigCommon::max_surface_count; void create_surface_callback(MirSurface* surface, void * context) { SurfaceSync* config = reinterpret_cast(context); config->surface_created(surface); } void release_surface_callback(MirSurface* surface, void * context) { SurfaceSync* config = reinterpret_cast(context); config->surface_released(surface); } void wait_for_surface_create(SurfaceSync* context) { context->wait_for_surface_create(); } void wait_for_surface_release(SurfaceSync* context) { context->wait_for_surface_release(); } } using ErrorReporting = BespokeDisplayServerTestFixture; TEST_F(ErrorReporting, c_api_returns_error) { struct ServerConfig : TestingServerConfiguration { std::shared_ptr the_ipc_factory( std::shared_ptr const&, std::shared_ptr const&) override { static auto error_server = std::make_shared(); return std::make_shared(*error_server); } } server_config; launch_server_process(server_config); struct ClientConfig : ClientConfigCommon { void exec() { mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this); wait_for_connect(); ASSERT_TRUE(connection != NULL); EXPECT_FALSE(mir_connection_is_valid(connection)); EXPECT_TRUE(std::strstr(mir_connection_get_error_message(connection), ErrorServer::test_exception_text.c_str())); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_connection_create_surface(connection, &request_params, create_surface_callback, ssync); wait_for_surface_create(ssync); ASSERT_TRUE(ssync->surface != NULL); EXPECT_FALSE(mir_surface_is_valid(ssync->surface)); EXPECT_TRUE(std::strstr(mir_surface_get_error_message(ssync->surface), ErrorServer::test_exception_text.c_str())); EXPECT_NO_THROW({ MirSurfaceParameters response_params; mir_surface_get_parameters(ssync->surface, &response_params); }); mir_surface_release(ssync->surface, release_surface_callback, ssync); wait_for_surface_release(ssync); ASSERT_TRUE(ssync->surface == NULL); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } mir-0.1.8+14.04.20140411/tests/integration-tests/process/0000755000015301777760000000000012322054703023202 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/integration-tests/process/test_process.cpp0000644000015301777760000000745112322054223026427 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/process.h" #include #include #include namespace mtf = mir_test_framework; namespace mir { struct MainFunctionFactory { static void an_empty_main_function() { } static void an_infinitely_waiting_main_function() { std::mutex m; std::unique_lock ul(m); std::condition_variable cv; cv.wait(ul); } static void a_value_altering_main_function( int& value, int expected_value_after_increment) { value++; EXPECT_EQ( expected_value_after_increment, value); } }; struct ExitFunctionFactory { static int a_successful_exit_function() { return EXIT_SUCCESS; } static int a_failing_exit_function() { return EXIT_FAILURE; } static int a_gtest_exit_function() { return ::testing::Test::HasFailure() ? EXIT_FAILURE : EXIT_SUCCESS; } }; TEST(ProcessResult, a_default_result_never_succeeds) { mtf::Result r; EXPECT_FALSE(r.succeeded()); } TEST(ProcessResult, a_signalled_result_does_not_succeed) { mtf::Result r; r.reason = mtf::TerminationReason::child_terminated_by_signal; EXPECT_FALSE(r.succeeded()); } TEST(ProcessResult, a_normally_terminated_result_succeeds_only_with_exit_success) { mtf::Result r; r.reason = mtf::TerminationReason::child_terminated_normally; r.exit_code = EXIT_FAILURE; EXPECT_FALSE(r.succeeded()); r.exit_code = EXIT_SUCCESS; EXPECT_TRUE(r.succeeded()); } TEST(Process, a_main_fn_is_executed) { int value = 0; auto p = mtf::fork_and_run_in_a_different_process( std::bind( MainFunctionFactory::a_value_altering_main_function, value, 1), ExitFunctionFactory::a_gtest_exit_function); EXPECT_TRUE(p->wait_for_termination().succeeded()); } TEST(Process, a_successful_exit_function_succeeds) { auto p = mtf::fork_and_run_in_a_different_process( MainFunctionFactory::an_empty_main_function, ExitFunctionFactory::a_successful_exit_function); EXPECT_TRUE(p->wait_for_termination().succeeded()); } TEST(Process, a_failing_exit_function_does_not_succeed) { auto p = mtf::fork_and_run_in_a_different_process( MainFunctionFactory::an_empty_main_function, ExitFunctionFactory::a_failing_exit_function); EXPECT_FALSE(p->wait_for_termination().succeeded()); } TEST(Process, a_terminated_child_is_recognized_as_being_signalled) { auto p = mtf::fork_and_run_in_a_different_process( MainFunctionFactory::an_infinitely_waiting_main_function, ExitFunctionFactory::a_successful_exit_function); p->terminate(); EXPECT_TRUE(p->wait_for_termination().signalled()); } TEST(Process, a_killed_child_is_recognized_as_being_signalled) { auto p = mtf::fork_and_run_in_a_different_process( MainFunctionFactory::an_infinitely_waiting_main_function, ExitFunctionFactory::a_successful_exit_function); p->kill(); EXPECT_TRUE(p->wait_for_termination().signalled()); } } mir-0.1.8+14.04.20140411/tests/integration-tests/process/CMakeLists.txt0000644000015301777760000000023712322054223025741 0ustar pbusernogroup00000000000000list(APPEND INTEGRATION_TESTS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_process.cpp ) set( INTEGRATION_TESTS_SRCS ${INTEGRATION_TESTS_SRCS} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/integration-tests/test_server_client_types.cpp0000644000015301777760000000334312322054223027357 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/client_types.h" #include "mir/graphics/display_configuration.h" #include namespace mg = mir::graphics; #define EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(TYPE) \ EXPECT_EQ(static_cast(mir_display_output_type_##TYPE), \ mg::DisplayConfigurationOutputType::TYPE) TEST(ServerClientTypes, display_output_types_match) { EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(unknown); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(vga); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(dvid); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(dvia); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(composite); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(svideo); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(lvds); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(component); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(ninepindin); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(displayport); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(hdmia); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(hdmib); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(tv); EXPECT_DISPLAY_OUTPUT_TYPES_MATCH(edp); } mir-0.1.8+14.04.20140411/tests/integration-tests/test_surface_first_frame_sync.cpp0000644000015301777760000002421612322054223030336 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/geometry/rectangle.h" #include "mir/graphics/display_buffer.h" #include "mir/compositor/renderer.h" #include "mir/compositor/renderer_factory.h" #include "mir/compositor/compositor.h" #include "mir/compositor/display_buffer_compositor.h" #include "mir/compositor/display_buffer_compositor_factory.h" #include "mir/compositor/scene.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/stub_display_buffer.h" #include "mir_test_doubles/stub_renderer.h" #include "mir_toolkit/mir_client_library.h" #include #include #include #include #include namespace geom = mir::geometry; namespace mg = mir::graphics; namespace mc = mir::compositor; namespace ms = mir::scene; namespace mtf = mir_test_framework; namespace mtd = mir::test::doubles; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); class SynchronousCompositor : public mc::Compositor { public: SynchronousCompositor(std::shared_ptr const& display, std::shared_ptr const& scene, std::shared_ptr const& db_compositor_factory) : display{display}, scene{scene} { display->for_each_display_buffer( [this, &db_compositor_factory](mg::DisplayBuffer& display_buffer) { display_buffer_compositor_map[&display_buffer] = db_compositor_factory->create_compositor_for(display_buffer); }); } void start() { scene->set_change_callback([this]() { display->for_each_display_buffer([this](mg::DisplayBuffer& display_buffer) { display_buffer_compositor_map[&display_buffer]->composite(); }); }); } void stop() { scene->set_change_callback([]{}); } private: std::shared_ptr const display; std::shared_ptr const scene; std::unordered_map> display_buffer_compositor_map; }; class StubRenderer : public mtd::StubRenderer { public: StubRenderer(int render_operations_fd) : render_operations_fd{render_operations_fd} { } void render(mg::Renderable const&, mg::Buffer&) const override { while (write(render_operations_fd, "a", 1) != 1) continue; } private: int render_operations_fd; }; class StubDisplay : public mtd::NullDisplay { public: StubDisplay() : display_buffer{geom::Rectangle{geom::Point{}, geom::Size{1600,1600}}} { } void for_each_display_buffer(std::function const& f) override { f(display_buffer); } private: mtd::StubDisplayBuffer display_buffer; }; } using SurfaceFirstFrameSync = BespokeDisplayServerTestFixture; TEST_F(SurfaceFirstFrameSync, surface_not_rendered_until_buffer_is_pushed) { static std::string const surface_created{"surface_created_0950f3f9.tmp"}; static std::string const do_next_buffer{"do_next_buffer_0950f3f9.tmp"}; static std::string const next_buffer_done{"next_buffer_done_0950f3f9.tmp"}; static std::string const do_client_finish{"do_client_finish_0950f3f9.tmp"}; std::remove(surface_created.c_str()); std::remove(do_next_buffer.c_str()); std::remove(next_buffer_done.c_str()); std::remove(do_client_finish.c_str()); struct ServerConfig : TestingServerConfiguration { ServerConfig() { if (pipe(rendering_ops_pipe) != 0) { BOOST_THROW_EXCEPTION( std::runtime_error("Failed to create pipe")); } if (fcntl(rendering_ops_pipe[0], F_SETFL, O_NONBLOCK) != 0) { BOOST_THROW_EXCEPTION( std::runtime_error("Failed to make the read end of the pipe non-blocking")); } } ~ServerConfig() noexcept { if (rendering_ops_pipe[0] >= 0) close(rendering_ops_pipe[0]); if (rendering_ops_pipe[1] >= 0) close(rendering_ops_pipe[1]); } std::shared_ptr the_display() override { using namespace testing; if (!stub_display) stub_display = std::make_shared(); return stub_display; } std::shared_ptr the_renderer_factory() override { using namespace testing; struct StubRendererFactory : public mc::RendererFactory { StubRendererFactory(int ops_fd) : ops_fd{ops_fd} {} std::unique_ptr create_renderer_for(geom::Rectangle const&) { auto raw = new StubRenderer{ops_fd}; return std::unique_ptr(raw); } int ops_fd; }; if (!stub_renderer_factory) stub_renderer_factory = std::make_shared(rendering_ops_pipe[1]); return stub_renderer_factory; } std::shared_ptr the_compositor() override { using namespace testing; if (!sync_compositor) { sync_compositor = std::make_shared( the_display(), the_scene(), the_display_buffer_compositor_factory()); } return sync_compositor; } int num_of_executed_render_operations() { char c; int ops{0}; while (read(rendering_ops_pipe[0], &c, 1) == 1) ops++; return ops; } int rendering_ops_pipe[2]; std::shared_ptr stub_renderer_factory; std::shared_ptr stub_display; std::shared_ptr sync_compositor; } server_config; launch_server_process(server_config); struct ClientConfig : TestingClientConfiguration { ClientConfig(std::string const& surface_created, std::string const& do_next_buffer, std::string const& next_buffer_done, std::string const& do_client_finish) : surface_created{surface_created}, do_next_buffer{do_next_buffer}, next_buffer_done{next_buffer_done}, do_client_finish{do_client_finish} { } void exec() { auto connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ(mir_connection_get_error_message(connection), ""); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; auto surface = mir_connection_create_surface_sync(connection, &request_params); ASSERT_TRUE(surface != NULL); EXPECT_TRUE(mir_surface_is_valid(surface)); EXPECT_STREQ(mir_surface_get_error_message(surface), ""); set_flag(surface_created); wait_for(do_next_buffer); mir_surface_swap_buffers_sync(surface); set_flag(next_buffer_done); wait_for(do_client_finish); mir_surface_release_sync(surface); mir_connection_release(connection); } /* TODO: Extract this flag mechanism and make it reusable */ void set_flag(std::string const& flag_file) { close(open(flag_file.c_str(), O_CREAT, S_IWUSR | S_IRUSR)); } void wait_for(std::string const& flag_file) { int fd = -1; while ((fd = open(flag_file.c_str(), O_RDONLY, S_IWUSR | S_IRUSR)) == -1) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } close(fd); } std::string const surface_created; std::string const do_next_buffer; std::string const next_buffer_done; std::string const do_client_finish; } client_config{surface_created, do_next_buffer, next_buffer_done, do_client_finish}; launch_client_process(client_config); run_in_test_process([&] { client_config.wait_for(surface_created); /* * This test uses a synchronous compositor (instead of the default * multi-threaded one) to ensure we don't get a false negative * for this expectation. In the multi-threaded case this can * happen if the compositor doesn't get the chance to run at all * before we reach this point. */ EXPECT_EQ(0, server_config.num_of_executed_render_operations()); client_config.set_flag(do_next_buffer); client_config.wait_for(next_buffer_done); /* After submitting the buffer we should get some render operations */ while (server_config.num_of_executed_render_operations() == 0) std::this_thread::sleep_for(std::chrono::milliseconds(1)); client_config.set_flag(do_client_finish); }); } mir-0.1.8+14.04.20140411/tests/integration-tests/graphics/0000755000015301777760000000000012322054703023324 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/integration-tests/graphics/android/0000755000015301777760000000000012322054703024744 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/integration-tests/graphics/android/test_internal_client.cpp0000644000015301777760000001303212322054247031663 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/android_graphic_buffer_allocator.h" #include "src/platform/graphics/android/internal_client_window.h" #include "src/platform/graphics/android/interpreter_cache.h" #include "src/platform/graphics/android/internal_client.h" #include "src/server/compositor/buffer_stream_factory.h" #include "src/server/report/null_report_factory.h" #include "mir/graphics/buffer_initializer.h" #include "src/server/report/null_report_factory.h" #include "mir/graphics/android/mir_native_window.h" #include "mir/graphics/platform.h" #include "mir/graphics/internal_client.h" #include "mir/graphics/internal_surface.h" #include "src/server/scene/surface_stack.h" #include "src/server/scene/surface_controller.h" #include "mir/scene/scene_report.h" #include "src/server/scene/surface_allocator.h" #include "mir/scene/surface.h" #include "mir/scene/surface_event_source.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/frontend/surface_id.h" #include "mir/input/input_channel_factory.h" #include "mir/options/program_option.h" #include "mir_test_doubles/stub_input_registrar.h" #include "mir_test_doubles/null_surface_configurator.h" #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mc=mir::compositor; namespace geom=mir::geometry; namespace ms=mir::scene; namespace msh=mir::shell; namespace mf=mir::frontend; namespace mi=mir::input; namespace mtd=mir::test::doubles; namespace mr = mir::report; namespace mo=mir::options; namespace { class AndroidInternalClient : public ::testing::Test { protected: virtual void SetUp() { } }; struct StubInputFactory : public mi::InputChannelFactory { std::shared_ptr make_input_channel() { return std::shared_ptr(); } }; } TEST_F(AndroidInternalClient, internal_client_creation_and_use) { auto size = geom::Size{334, 122}; auto pf = mir_pixel_format_abgr_8888; msh::SurfaceCreationParameters params; params.name = std::string("test"); params.size = size; params.pixel_format = pf; params.buffer_usage = mg::BufferUsage::hardware; auto id = mf::SurfaceId{4458}; auto stub_input_factory = std::make_shared(); auto stub_input_registrar = std::make_shared(); auto null_buffer_initializer = std::make_shared(); auto allocator = std::make_shared(null_buffer_initializer); auto buffer_stream_factory = std::make_shared(allocator); auto scene_report = mr::null_scene_report(); auto surface_allocator = std::make_shared(buffer_stream_factory, stub_input_factory, std::make_shared(), scene_report); auto ss = std::make_shared(stub_input_registrar, scene_report); auto surface_controller = std::make_shared(surface_allocator, ss); auto const observer = std::make_shared(id, std::shared_ptr()); auto surface = surface_controller->add_surface(params, observer); surface->allow_framedropping(true); auto mir_surface = as_internal_surface(surface); auto options = std::shared_ptr(); auto report = mr::null_display_report(); auto internal_client = std::make_shared(); int major, minor, n; EGLContext egl_context; EGLSurface egl_surface; EGLConfig egl_config; EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; auto egl_display = eglGetDisplay(internal_client->egl_native_display()); int rc = eglInitialize(egl_display, &major, &minor); EXPECT_EQ(EGL_TRUE, rc); rc = eglChooseConfig(egl_display, attribs, &egl_config, 1, &n); EXPECT_EQ(EGL_TRUE, rc); egl_surface = eglCreateWindowSurface(egl_display, egl_config, internal_client->egl_native_window(mir_surface), NULL); EXPECT_NE(EGL_NO_SURFACE, egl_surface); egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attribs); EXPECT_NE(EGL_NO_CONTEXT, egl_context); rc = eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context); EXPECT_EQ(EGL_TRUE, rc); glClearColor(1.0f, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); rc = eglSwapBuffers(egl_display, egl_surface); EXPECT_EQ(EGL_TRUE, rc); eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(egl_display, egl_surface); eglDestroyContext(egl_display, egl_context); eglTerminate(egl_display); } mir-0.1.8+14.04.20140411/tests/integration-tests/graphics/android/test_display_integration.cpp0000644000015301777760000000642312322054247032567 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/buffer_initializer.h" #include "mir/graphics/display_buffer.h" #include "src/platform/graphics/android/android_display.h" #include "src/platform/graphics/android/resource_factory.h" #include "src/platform/graphics/android/android_graphic_buffer_allocator.h" #include "src/platform/graphics/android/output_builder.h" #include "src/server/report/null_report_factory.h" #include "examples/graphics.h" #include "mir_test_doubles/stub_gl_config.h" #include #include namespace mga=mir::graphics::android; namespace mg=mir::graphics; namespace geom=mir::geometry; namespace md=mir::draw; namespace mtd=mir::test::doubles; namespace { class AndroidDisplay : public ::testing::Test { protected: static void SetUpTestCase() { /* note: exynos5 hwc driver can sends sigterm to vsync thread when closing hwc. the server can handle this, but we need the test to as well */ original_sigterm_handler = signal(SIGTERM, [](int){}); /* note about fb_device: OMAP4 drivers seem to only be able to open fb once per process (repeated framebuffer_{open,close}() doesn't seem to work). once we figure out why, we can remove fb_device in the test fixture */ display_resource_factory = std::make_shared(false); } static void TearDownTestCase() { signal(SIGTERM, original_sigterm_handler); display_resource_factory.reset(); } md::glAnimationBasic gl_animation; static std::shared_ptr display_resource_factory; static void (*original_sigterm_handler)(int); }; void (*AndroidDisplay::original_sigterm_handler)(int); std::shared_ptr AndroidDisplay::display_resource_factory; } TEST_F(AndroidDisplay, display_can_post) { auto null_display_report = mir::report::null_display_report(); auto stub_gl_config = std::make_shared(); auto buffer_initializer = std::make_shared(); auto fb_allocator = std::make_shared(buffer_initializer); auto display_buffer_factory = std::make_shared( fb_allocator, display_resource_factory, null_display_report); mga::AndroidDisplay display{display_buffer_factory, stub_gl_config, null_display_report}; display.for_each_display_buffer([this](mg::DisplayBuffer& buffer) { buffer.make_current(); gl_animation.init_gl(); gl_animation.render_gl(); buffer.post_update(); gl_animation.render_gl(); buffer.post_update(); }); } mir-0.1.8+14.04.20140411/tests/integration-tests/graphics/android/test_buffer_integration.cpp0000644000015301777760000000751612322054223032371 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/android_graphic_buffer_allocator.h" #include "src/server/compositor/switching_bundle.h" #include "mir/graphics/buffer_initializer.h" #include "src/server/report/null_report_factory.h" #include "mir/graphics/android/native_buffer.h" #include "mir/graphics/buffer_properties.h" #include "testdraw/graphics_region_factory.h" #include "testdraw/patterns.h" #include namespace mc=mir::compositor; namespace geom=mir::geometry; namespace mga=mir::graphics::android; namespace mg=mir::graphics; namespace mtd=mir::test::draw; namespace { class AndroidBufferIntegration : public ::testing::Test { protected: virtual void SetUp() { size = geom::Size{334, 122}; pf = mir_pixel_format_abgr_8888; buffer_properties = mg::BufferProperties{size, pf, mg::BufferUsage::software}; null_buffer_initializer = std::make_shared(); graphics_region_factory = mtd::create_graphics_region_factory(); } std::shared_ptr null_buffer_initializer; geom::Size size; MirPixelFormat pf; mg::BufferProperties buffer_properties; std::shared_ptr graphics_region_factory; }; auto client_acquire_blocking(mc::SwitchingBundle& switching_bundle) -> mg::Buffer* { std::mutex mutex; std::condition_variable cv; bool done = false; mg::Buffer* result; switching_bundle.client_acquire( [&](mg::Buffer* new_buffer) { std::unique_lock lock(mutex); result = new_buffer; done = true; cv.notify_one(); }); std::unique_lock lock(mutex); cv.wait(lock, [&]{ return done; }); return result; } } TEST_F(AndroidBufferIntegration, allocator_can_create_sw_buffer) { using namespace testing; auto allocator = std::make_shared(null_buffer_initializer); mg::BufferProperties sw_properties{size, pf, mg::BufferUsage::software}; auto test_buffer = allocator->alloc_buffer(sw_properties); auto region = graphics_region_factory->graphic_region_from_handle( *test_buffer->native_buffer_handle()); mtd::DrawPatternSolid red_pattern(0xFF0000FF); red_pattern.draw(*region); EXPECT_TRUE(red_pattern.check(*region)); } TEST_F(AndroidBufferIntegration, allocator_can_create_hw_buffer) { using namespace testing; mg::BufferProperties hw_properties{size, pf, mg::BufferUsage::hardware}; auto allocator = std::make_shared(null_buffer_initializer); //TODO: kdub it is a bit trickier to test that a gpu can render... just check creation for now auto test_buffer = allocator->alloc_buffer(hw_properties); EXPECT_NE(nullptr, test_buffer); } TEST_F(AndroidBufferIntegration, swapper_creation_is_sane) { using namespace testing; auto allocator = std::make_shared(null_buffer_initializer); mc::SwitchingBundle swapper(2, allocator, buffer_properties); auto returned_buffer = client_acquire_blocking(swapper); EXPECT_NE(nullptr, returned_buffer); } mir-0.1.8+14.04.20140411/tests/integration-tests/graphics/android/CMakeLists.txt0000644000015301777760000000043712322054223027505 0ustar pbusernogroup00000000000000list( APPEND INTEGRATION_TESTS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_integration.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_display_integration.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_internal_client.cpp ) set( INTEGRATION_TESTS_SRCS ${INTEGRATION_TESTS_SRCS} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/integration-tests/graphics/mesa/0000755000015301777760000000000012322054703024251 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/integration-tests/graphics/mesa/test_buffer_integration.cpp0000644000015301777760000001471712322054247031705 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/graphics/buffer_basic.h" #include "mir/graphics/buffer_id.h" #include "mir/graphics/buffer_properties.h" #include "mir/graphics/buffer_initializer.h" #include "mir/options/configuration.h" #include "mir/options/option.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/stub_buffer_allocator.h" #include "mir_test_doubles/null_platform.h" #include "mir_test_doubles/stub_gl_config.h" #include "src/server/graphics/default_display_configuration_policy.h" #include "src/server/report/null_report_factory.h" #include "mir_test_framework/testing_server_configuration.h" #include #include #include namespace mc = mir::compositor; namespace geom = mir::geometry; namespace mg = mir::graphics; namespace mtf = mir_test_framework; namespace mtd = mir::test::doubles; namespace mr = mir::report; namespace mir { class StubBufferThread : public mtd::StubBuffer { public: StubBufferThread() : creation_thread_id{std::this_thread::get_id()} {} void bind_to_texture() { /* * If we are trying to bind the texture from a different thread from * the one used to create the buffer (i.e. a thread in which the * display is not supposed to be configured), force an EGL error to * make the tests happy. */ if (std::this_thread::get_id() != creation_thread_id) { eglInitialize(0, 0, 0); throw std::runtime_error("Binding to texture failed"); } } private: std::thread::id creation_thread_id; }; class StubGraphicBufferAllocator : public mtd::StubBufferAllocator { public: std::shared_ptr alloc_buffer(mg::BufferProperties const&) override { return std::make_shared(); } }; class StubGraphicPlatform : public mtd::NullPlatform { public: std::shared_ptr create_buffer_allocator( const std::shared_ptr& /*buffer_initializer*/) override { return std::make_shared(); } }; class MesaBufferIntegration : public ::testing::Test { protected: virtual void SetUp() { auto options = mtf::TestingServerConfiguration().the_options(); if (options->get("tests-use-real-graphics")) platform = mg::create_platform(options, mr::null_display_report()); else platform = std::make_shared(); auto conf_policy = std::make_shared(); display = platform->create_display( conf_policy, std::make_shared()); auto buffer_initializer = std::make_shared(); allocator = platform->create_buffer_allocator(buffer_initializer); size = geom::Size{100, 100}; pf = mir_pixel_format_abgr_8888; usage = mg::BufferUsage::hardware; buffer_properties = mg::BufferProperties{size, pf, usage}; } std::shared_ptr platform; std::shared_ptr display; std::shared_ptr allocator; geom::Size size; MirPixelFormat pf; mg::BufferUsage usage; mg::BufferProperties buffer_properties; }; struct BufferCreatorThread { BufferCreatorThread(const std::shared_ptr& allocator, mg::BufferProperties const& buffer_properties) : allocator{allocator}, buffer_properties{buffer_properties} { } void operator()() { using namespace testing; buffer = allocator->alloc_buffer(buffer_properties); } std::shared_ptr allocator; std::shared_ptr buffer; mg::BufferProperties buffer_properties; }; struct BufferDestructorThread { BufferDestructorThread(std::shared_ptr buffer) : buffer{std::move(buffer)} { } void operator()() { using namespace testing; buffer.reset(); ASSERT_EQ(EGL_SUCCESS, eglGetError()); } std::shared_ptr buffer; }; struct BufferTextureInstantiatorThread { BufferTextureInstantiatorThread(const std::shared_ptr& buffer) : buffer(buffer), exception_thrown(false) { } void operator()() { using namespace testing; try { buffer->bind_to_texture(); } catch(std::runtime_error const&) { exception_thrown = true; } ASSERT_NE(EGL_SUCCESS, eglGetError()); } const std::shared_ptr& buffer; bool exception_thrown; }; TEST_F(MesaBufferIntegration, buffer_creation_from_arbitrary_thread_works) { using namespace testing; EXPECT_NO_THROW({ BufferCreatorThread creator(allocator, buffer_properties); std::thread t{std::ref(creator)}; t.join(); ASSERT_TRUE(creator.buffer.get() != 0); }); } TEST_F(MesaBufferIntegration, buffer_destruction_from_arbitrary_thread_works) { using namespace testing; EXPECT_NO_THROW({ auto buffer = allocator->alloc_buffer(buffer_properties); buffer->bind_to_texture(); ASSERT_EQ(EGL_SUCCESS, eglGetError()); BufferDestructorThread destructor{std::move(buffer)}; std::thread t{std::ref(destructor)}; t.join(); }); } TEST_F(MesaBufferIntegration, buffer_lazy_texture_instantiation_from_arbitrary_thread_fails) { using namespace testing; EXPECT_NO_THROW({ auto buffer = allocator->alloc_buffer(buffer_properties); BufferTextureInstantiatorThread texture_instantiator{buffer}; std::thread t{std::ref(texture_instantiator)}; t.join(); ASSERT_TRUE(texture_instantiator.exception_thrown); }); } } mir-0.1.8+14.04.20140411/tests/integration-tests/graphics/mesa/CMakeLists.txt0000644000015301777760000000025612322054223027011 0ustar pbusernogroup00000000000000list( APPEND INTEGRATION_TESTS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_integration.cpp ) set( INTEGRATION_TESTS_SRCS ${INTEGRATION_TESTS_SRCS} PARENT_SCOPE ) mir-0.1.8+14.04.20140411/tests/integration-tests/test_drm_auth_magic.cpp0000644000015301777760000001220112322054223026223 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/graphics/display.h" #include "mir/graphics/drm_authenticator.h" #include "mir/graphics/platform_ipc_package.h" #include "mir/graphics/buffer_basic.h" #include #include #include "mir_test_doubles/stub_buffer_allocator.h" #include "mir_test_doubles/null_platform.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/mir_client_library_drm.h" #include #include namespace mg = mir::graphics; namespace mc = mir::compositor; namespace geom = mir::geometry; namespace mtf = mir_test_framework; namespace mtd = mir::test::doubles; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); class MockAuthenticatingPlatform : public mtd::NullPlatform, public mg::DRMAuthenticator { public: std::shared_ptr create_buffer_allocator( std::shared_ptr const& /*buffer_initializer*/) override { return std::make_shared(); } MOCK_METHOD1(drm_auth_magic, void(unsigned int)); }; void connection_callback(MirConnection* connection, void* context) { auto connection_ptr = static_cast(context); *connection_ptr = connection; } void drm_auth_magic_callback(int status, void* client_context) { auto status_ptr = static_cast(client_context); *status_ptr = status; } } TEST_F(BespokeDisplayServerTestFixture, client_drm_auth_magic_calls_platform) { unsigned int const magic{0x10111213}; struct ServerConfig : TestingServerConfiguration { std::shared_ptr the_graphics_platform() { using namespace testing; if (!platform) { platform = std::make_shared(); EXPECT_CALL(*platform, drm_auth_magic(magic)) .Times(1); } return platform; } std::shared_ptr platform; } server_config; launch_server_process(server_config); struct Client : TestingClientConfiguration { void exec() { MirConnection* connection{nullptr}; mir_wait_for(mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, &connection)); int const no_error{0}; int status{67}; ASSERT_TRUE(mir_connection_is_valid(connection)); mir_wait_for(mir_connection_drm_auth_magic(connection, magic, drm_auth_magic_callback, &status)); EXPECT_EQ(no_error, status); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } TEST_F(BespokeDisplayServerTestFixture, drm_auth_magic_platform_error_reaches_client) { unsigned int const magic{0x10111213}; static int const auth_magic_error{667}; struct ServerConfig : TestingServerConfiguration { std::shared_ptr the_graphics_platform() { using namespace testing; if (!platform) { platform = std::make_shared(); EXPECT_CALL(*platform, drm_auth_magic(magic)) .WillOnce(Throw(::boost::enable_error_info(std::exception()) << boost::errinfo_errno(auth_magic_error))); } return platform; } std::shared_ptr platform; } server_config; launch_server_process(server_config); struct Client : TestingClientConfiguration { void exec() { MirConnection* connection{nullptr}; mir_wait_for(mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, &connection)); int status{67}; mir_wait_for(mir_connection_drm_auth_magic(connection, magic, drm_auth_magic_callback, &status)); EXPECT_EQ(auth_magic_error, status); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } mir-0.1.8+14.04.20140411/tests/integration-tests/test_session_manager.cpp0000644000015301777760000001067612322054247026461 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/scene/session_manager.h" #include "mir/shell/session.h" #include "mir/shell/focus_setter.h" #include "src/server/scene/default_session_container.h" #include "mir/shell/null_session_listener.h" #include "mir/compositor/buffer_stream.h" #include "src/server/scene/basic_surface.h" #include "mir/shell/surface_creation_parameters.h" #include "mir_test/gmock_fixes.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_surface_factory.h" #include "mir_test_doubles/mock_focus_setter.h" #include "mir_test_doubles/null_snapshot_strategy.h" #include "mir_test_doubles/null_event_sink.h" #include "mir_test_doubles/null_session_event_sink.h" #include #include namespace mc = mir::compositor; namespace mf = mir::frontend; namespace msh = mir::shell; namespace ms = mir::scene; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace { struct TestSessionManagerAndFocusSelectionStrategy : public testing::Test { TestSessionManagerAndFocusSelectionStrategy() : session_manager( mt::fake_shared(surface_factory), mt::fake_shared(container), mt::fake_shared(focus_setter), std::make_shared(), std::make_shared(), mt::fake_shared(session_listener)) { } mtd::MockSurfaceFactory surface_factory; // TODO this isn't used as a mock ms::DefaultSessionContainer container; mtd::MockFocusSetter focus_setter; std::shared_ptr new_session; msh::NullSessionListener session_listener; ms::SessionManager session_manager; }; } TEST_F(TestSessionManagerAndFocusSelectionStrategy, cycle_focus) { using namespace ::testing; EXPECT_CALL(focus_setter, set_focus_to(_)).Times(3); auto session1 = session_manager.open_session(__LINE__, "Visual Basic Studio", std::make_shared()); auto session2 = session_manager.open_session(__LINE__, "Microsoft Access", std::make_shared()); auto session3 = session_manager.open_session(__LINE__, "WordPerfect", std::make_shared()); Mock::VerifyAndClearExpectations(&focus_setter); { InSequence seq; EXPECT_CALL(focus_setter, set_focus_to(Eq(session1))).Times(1); EXPECT_CALL(focus_setter, set_focus_to(Eq(session2))).Times(1); EXPECT_CALL(focus_setter, set_focus_to(Eq(session3))).Times(1); } session_manager.focus_next(); session_manager.focus_next(); session_manager.focus_next(); Mock::VerifyAndClearExpectations(&focus_setter); // Possible change of focus while sessions are closed on shutdown EXPECT_CALL(focus_setter, set_focus_to(_)).Times(AtLeast(0)); } TEST_F(TestSessionManagerAndFocusSelectionStrategy, closing_applications_transfers_focus) { using namespace ::testing; EXPECT_CALL(focus_setter, set_focus_to(_)).Times(3); auto session1 = session_manager.open_session(__LINE__, "Visual Basic Studio", std::make_shared()); auto session2 = session_manager.open_session(__LINE__, "Microsoft Access", std::make_shared()); auto session3 = session_manager.open_session(__LINE__, "WordPerfect", std::make_shared()); Mock::VerifyAndClearExpectations(&focus_setter); { InSequence seq; EXPECT_CALL(focus_setter, set_focus_to(Eq(session2))).Times(1); EXPECT_CALL(focus_setter, set_focus_to(Eq(session1))).Times(1); } session_manager.close_session(session3); session_manager.close_session(session2); Mock::VerifyAndClearExpectations(&focus_setter); // Possible change of focus while sessions are closed on shutdown EXPECT_CALL(focus_setter, set_focus_to(_)).Times(AtLeast(0)); } mir-0.1.8+14.04.20140411/tests/integration-tests/compositor/0000755000015301777760000000000012322054703023722 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/integration-tests/compositor/test_buffer_stream.cpp0000644000015301777760000002257212322054247030324 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/compositor/buffer_stream_surfaces.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "src/server/compositor/switching_bundle.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/stub_buffer_allocator.h" #include "multithread_harness.h" #include #include #include #include #include namespace mc = mir::compositor; namespace mg = mir::graphics; namespace mt = mir::testing; namespace mtd = mir::test::doubles; namespace geom = mir::geometry; namespace { struct BufferStreamSurfaces : mc::BufferStreamSurfaces { using mc::BufferStreamSurfaces::BufferStreamSurfaces; // Convenient function to allow tests to be written in linear style void swap_client_buffers_blocking(mg::Buffer*& buffer) { std::mutex mutex; std::condition_variable cv; bool done = false; swap_client_buffers(buffer, [&](mg::Buffer* new_buffer) { std::unique_lock lock(mutex); buffer = new_buffer; done = true; cv.notify_one(); }); std::unique_lock lock(mutex); cv.wait(lock, [&]{ return done; }); } }; struct BufferStreamTest : public ::testing::Test { BufferStreamTest() : nbuffers{3}, buffer_stream{create_bundle()} { } std::shared_ptr create_bundle() { auto allocator = std::make_shared(); mg::BufferProperties properties{geom::Size{380, 210}, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware}; return std::make_shared(nbuffers, allocator, properties); } const int nbuffers; BufferStreamSurfaces buffer_stream; }; } TEST_F(BufferStreamTest, gives_same_back_buffer_until_more_available) { mg::Buffer* client1{nullptr}; buffer_stream.swap_client_buffers_blocking(client1); auto client1_id = client1->id(); buffer_stream.swap_client_buffers_blocking(client1); auto comp1 = buffer_stream.lock_compositor_buffer(nullptr); auto comp2 = buffer_stream.lock_compositor_buffer(nullptr); EXPECT_EQ(comp1->id(), comp2->id()); EXPECT_EQ(comp1->id(), client1_id); comp1.reset(); buffer_stream.swap_client_buffers_blocking(client1); auto comp3 = buffer_stream.lock_compositor_buffer(nullptr); EXPECT_NE(client1_id, comp3->id()); comp2.reset(); auto comp3_id = comp3->id(); comp3.reset(); auto comp4 = buffer_stream.lock_compositor_buffer(nullptr); EXPECT_EQ(comp3_id, comp4->id()); } TEST_F(BufferStreamTest, gives_all_monitors_the_same_buffer) { mg::Buffer* client_buffer{nullptr}; for (int i = 0; i != nbuffers; i++) buffer_stream.swap_client_buffers_blocking(client_buffer); auto first_monitor = buffer_stream.lock_compositor_buffer(0); auto first_compositor_id = first_monitor->id(); first_monitor.reset(); for (int m = 1; m <= 10; m++) { const void *th = reinterpret_cast(m); auto monitor = buffer_stream.lock_compositor_buffer(th); ASSERT_EQ(first_compositor_id, monitor->id()); } } TEST_F(BufferStreamTest, gives_different_back_buffer_asap) { mg::Buffer* client_buffer{nullptr}; buffer_stream.swap_client_buffers_blocking(client_buffer); if (nbuffers > 1) { buffer_stream.swap_client_buffers_blocking(client_buffer); auto comp1 = buffer_stream.lock_compositor_buffer(nullptr); buffer_stream.swap_client_buffers_blocking(client_buffer); auto comp2 = buffer_stream.lock_compositor_buffer(nullptr); EXPECT_NE(comp1->id(), comp2->id()); comp1.reset(); comp2.reset(); } } TEST_F(BufferStreamTest, resize_affects_client_buffers_immediately) { auto old_size = buffer_stream.stream_size(); mg::Buffer* client{nullptr}; buffer_stream.swap_client_buffers_blocking(client); EXPECT_EQ(old_size, client->size()); geom::Size const new_size { old_size.width.as_int() * 2, old_size.height.as_int() * 3 }; buffer_stream.resize(new_size); EXPECT_EQ(new_size, buffer_stream.stream_size()); buffer_stream.swap_client_buffers_blocking(client); EXPECT_EQ(new_size, client->size()); buffer_stream.resize(old_size); EXPECT_EQ(old_size, buffer_stream.stream_size()); buffer_stream.swap_client_buffers_blocking(client); EXPECT_EQ(old_size, client->size()); } TEST_F(BufferStreamTest, compositor_gets_resized_buffers) { auto old_size = buffer_stream.stream_size(); mg::Buffer* client{nullptr}; buffer_stream.swap_client_buffers_blocking(client); geom::Size const new_size { old_size.width.as_int() * 2, old_size.height.as_int() * 3 }; buffer_stream.resize(new_size); EXPECT_EQ(new_size, buffer_stream.stream_size()); buffer_stream.swap_client_buffers_blocking(client); buffer_stream.swap_client_buffers_blocking(client); auto comp1 = buffer_stream.lock_compositor_buffer(nullptr); EXPECT_EQ(old_size, comp1->size()); comp1.reset(); auto comp2 = buffer_stream.lock_compositor_buffer(nullptr); EXPECT_EQ(new_size, comp2->size()); comp2.reset(); buffer_stream.swap_client_buffers_blocking(client); auto comp3 = buffer_stream.lock_compositor_buffer(nullptr); EXPECT_EQ(new_size, comp3->size()); comp3.reset(); buffer_stream.resize(old_size); EXPECT_EQ(old_size, buffer_stream.stream_size()); // No client frames "drawn" since resize(old_size), so compositor gets new_size buffer_stream.swap_client_buffers_blocking(client); auto comp4 = buffer_stream.lock_compositor_buffer(nullptr); EXPECT_EQ(new_size, comp4->size()); comp4.reset(); // Generate a new frame, which should be back to old_size now buffer_stream.swap_client_buffers_blocking(client); auto comp5 = buffer_stream.lock_compositor_buffer(nullptr); EXPECT_EQ(old_size, comp5->size()); comp5.reset(); } TEST_F(BufferStreamTest, can_get_partly_released_back_buffer) { mg::Buffer* client{nullptr}; buffer_stream.swap_client_buffers_blocking(client); buffer_stream.swap_client_buffers_blocking(client); int a, b, c; auto comp1 = buffer_stream.lock_compositor_buffer(&a); auto comp2 = buffer_stream.lock_compositor_buffer(&b); EXPECT_EQ(comp1->id(), comp2->id()); comp1.reset(); auto comp3 = buffer_stream.lock_compositor_buffer(&c); EXPECT_EQ(comp2->id(), comp3->id()); } namespace { void client_loop(int nframes, BufferStreamSurfaces& stream) { mg::Buffer* out_buffer{nullptr}; for (int f = 0; f < nframes; f++) { stream.swap_client_buffers_blocking(out_buffer); ASSERT_NE(nullptr, out_buffer); std::this_thread::yield(); } } void compositor_loop(mc::BufferStream &stream, std::atomic &done) { while (!done.load()) { auto comp1 = stream.lock_compositor_buffer(nullptr); ASSERT_NE(nullptr, comp1); // Also stress test getting a second compositor buffer before yielding auto comp2 = stream.lock_compositor_buffer(nullptr); ASSERT_NE(nullptr, comp2); std::this_thread::yield(); comp1.reset(); comp2.reset(); } } void snapshot_loop(mc::BufferStream &stream, std::atomic &done) { while (!done.load()) { auto out_region = stream.lock_snapshot_buffer(); ASSERT_NE(nullptr, out_region); std::this_thread::yield(); } } } TEST_F(BufferStreamTest, stress_test_distinct_buffers) { // More would be good, but armhf takes too long const int num_snapshotters{2}; const int num_frames{200}; std::atomic done; done = false; std::thread client(client_loop, num_frames, std::ref(buffer_stream)); std::thread compositor(compositor_loop, std::ref(buffer_stream), std::ref(done)); std::vector> snapshotters; for (unsigned int i = 0; i < num_snapshotters; i++) { snapshotters.push_back( std::make_shared(snapshot_loop, std::ref(buffer_stream), std::ref(done))); } client.join(); done = true; buffer_stream.force_requests_to_complete(); compositor.join(); for (auto &s : snapshotters) s->join(); } mir-0.1.8+14.04.20140411/tests/integration-tests/compositor/test_swapping_swappers.cpp0000644000015301777760000001216112322054247031245 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_doubles/stub_buffer_allocator.h" #include "multithread_harness.h" #include "src/server/compositor/switching_bundle.h" #include "src/server/compositor/buffer_stream_surfaces.h" #include "mir/graphics/graphic_buffer_allocator.h" #include #include #include #include #include #include namespace mc = mir::compositor; namespace mg = mir::graphics; namespace mt = mir::testing; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; namespace { struct SwapperSwappingStress : public ::testing::Test { void SetUp() { auto allocator = std::make_shared(); auto properties = mg::BufferProperties{geom::Size{380, 210}, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware}; switching_bundle = std::make_shared(3, allocator, properties); } std::shared_ptr switching_bundle; std::mutex acquire_mutex; // must live longer than our callback/lambda mg::Buffer* client_acquire_blocking( std::shared_ptr const& switching_bundle) { std::condition_variable cv; bool acquired = false; mg::Buffer* result; switching_bundle->client_acquire( [&](mg::Buffer* new_buffer) { std::unique_lock lock(acquire_mutex); result = new_buffer; acquired = true; cv.notify_one(); }); std::unique_lock lock(acquire_mutex); cv.wait(lock, [&]{ return acquired; }); return result; } }; } // namespace TEST_F(SwapperSwappingStress, swapper) { std::atomic_bool done(false); auto f = std::async(std::launch::async, [&] { for(auto i=0u; i < 400; i++) { auto b = client_acquire_blocking(switching_bundle); std::this_thread::yield(); switching_bundle->client_release(b); } done = true; }); auto g = std::async(std::launch::async, [&] { while (!done) { auto b = switching_bundle->compositor_acquire(0); std::this_thread::yield(); switching_bundle->compositor_release(b); } }); auto h = std::async(std::launch::async, [this] { for(auto i=0u; i < 100; i++) { switching_bundle->allow_framedropping(true); std::this_thread::yield(); switching_bundle->allow_framedropping(false); std::this_thread::yield(); } }); f.wait(); g.wait(); h.wait(); } TEST_F(SwapperSwappingStress, different_swapper_types) { std::atomic_bool done(false); auto f = std::async(std::launch::async, [&] { for(auto i=0u; i < 400; i++) { auto b = client_acquire_blocking(switching_bundle); std::this_thread::yield(); switching_bundle->client_release(b); } done = true; }); auto g = std::async(std::launch::async, [&] { while (!done) { auto b = switching_bundle->compositor_acquire(0); std::this_thread::yield(); switching_bundle->compositor_release(b); } }); auto h = std::async(std::launch::async, [this] { for(auto i=0u; i < 200; i++) { switching_bundle->allow_framedropping(true); std::this_thread::yield(); switching_bundle->allow_framedropping(false); std::this_thread::yield(); } }); f.wait(); g.wait(); h.wait(); } mir-0.1.8+14.04.20140411/tests/integration-tests/compositor/CMakeLists.txt0000644000015301777760000000042512322054223026460 0ustar pbusernogroup00000000000000list( APPEND INTEGRATION_TESTS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_swapping_swappers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_synchronizer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_stream.cpp ) set( INTEGRATION_TESTS_SRCS ${INTEGRATION_TESTS_SRCS} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/integration-tests/compositor/multithread_harness.h0000644000015301777760000000551512322054223030143 0ustar pbusernogroup00000000000000/* * 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_MULTITHREAD_HARNESS_H_ #define MIR_TEST_MULTITHREAD_HARNESS_H_ #include #include #include namespace mir { namespace testing { /* interface for main/controller thread to synchronize system */ class SynchronizerController { public: virtual ~SynchronizerController() {} virtual void ensure_child_is_waiting() = 0; virtual void activate_waiting_child() = 0; virtual void kill_thread() = 0; }; /* interface for spawned threads to interact with main thread */ class SynchronizerSpawned { public: virtual ~SynchronizerSpawned() {} virtual bool child_enter_wait() = 0; virtual bool child_check_wait_request() = 0; }; class Synchronizer : public SynchronizerController, public SynchronizerSpawned { public: Synchronizer () : paused(false), pause_request(false), kill(false) { }; ~Synchronizer () { }; void ensure_child_is_waiting() { std::unique_lock lk(sync_mutex); pause_request = true; while (!paused) { cv.wait(lk); } pause_request = false; }; void activate_waiting_child() { std::unique_lock lk(sync_mutex); paused = false; cv.notify_all(); }; bool child_enter_wait() { std::unique_lock lk(sync_mutex); paused = true; cv.notify_all(); while (paused) { cv.wait(lk); } return kill; }; bool child_check_wait_request() { std::unique_lock lk(sync_mutex); return pause_request; }; void kill_thread() { std::unique_lock lk(sync_mutex); kill = true; }; private: std::condition_variable cv; std::mutex sync_mutex; bool paused; bool pause_request; bool kill; }; } } #endif /* MIR_TEST_MULTITHREAD_HARNESS_ */ mir-0.1.8+14.04.20140411/tests/integration-tests/compositor/test_synchronizer.cpp0000644000015301777760000000435212322054223030223 0ustar pbusernogroup00000000000000/* * 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 */ #include "multithread_harness.h" #include namespace mt = mir::testing; namespace { void test_func(mt::SynchronizerSpawned* synchronizer, int* data) { *data = 1; synchronizer->child_enter_wait(); *data = 2; synchronizer->child_enter_wait(); } } TEST(Synchronizer, thread_stop_start) { int data = 0; mt::Synchronizer synchronizer; std::thread t1(test_func, &synchronizer, &data); synchronizer.ensure_child_is_waiting(); EXPECT_EQ(data, 1); synchronizer.activate_waiting_child(); synchronizer.ensure_child_is_waiting(); EXPECT_EQ(data, 2); synchronizer.activate_waiting_child(); t1.join(); } namespace { void test_func_pause (mt::SynchronizerSpawned* synchronizer, int* data) { bool wait_request; for(;;) { wait_request = synchronizer->child_check_wait_request(); *data = *data+1; if (wait_request) { if (synchronizer->child_enter_wait()) break; } std::this_thread::yield(); } } } TEST(Synchronizer, thread_pause_req) { int data = 0, old_data = 0; mt::Synchronizer synchronizer; std::thread t1(test_func_pause, &synchronizer, &data); synchronizer.ensure_child_is_waiting(); EXPECT_GT(data, old_data); old_data = data; synchronizer.activate_waiting_child(); synchronizer.ensure_child_is_waiting(); EXPECT_GT(data, old_data); synchronizer.activate_waiting_child(); synchronizer.ensure_child_is_waiting(); synchronizer.kill_thread(); synchronizer.activate_waiting_child(); t1.join(); } mir-0.1.8+14.04.20140411/tests/integration-tests/client/0000755000015301777760000000000012322054703023002 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/integration-tests/client/test_screencast.cpp0000644000015301777760000001373312322054223026703 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_protobuf.pb.h" #include "src/client/default_connection_configuration.h" #include "mir/frontend/connector.h" #include "mir_test/test_protobuf_server.h" #include "mir_test/stub_server_tool.h" #include "mir_test/pipe.h" #include #include #include #include #include namespace mcl = mir::client; namespace mt = mir::test; namespace { class WaitObject { public: void notify_ready() { std::unique_lock lock{mutex}; ready = true; cv.notify_all(); } void wait_until_ready() { std::unique_lock lock{mutex}; if (!cv.wait_for(lock, std::chrono::seconds{10}, [this] { return ready; })) { BOOST_THROW_EXCEPTION(std::runtime_error("WaitObject timed out")); } } private: std::mutex mutex; std::condition_variable cv; bool ready = false; }; struct StubScreencastServerTool : mt::StubServerTool { void create_screencast( google::protobuf::RpcController*, const mir::protobuf::ScreencastParameters*, mir::protobuf::Screencast* response, google::protobuf::Closure* done) override { response->mutable_buffer()->add_fd(pipe.read_fd()); done->Run(); } void screencast_buffer( ::google::protobuf::RpcController*, ::mir::protobuf::ScreencastId const*, ::mir::protobuf::Buffer* response, ::google::protobuf::Closure* done) override { response->add_fd(pipe.read_fd()); done->Run(); } mt::Pipe pipe; }; struct MirScreencastTest : public testing::Test { MirScreencastTest() : server_tool{std::make_shared()} { std::remove(test_socket); test_server = std::make_shared(test_socket, server_tool); test_server->comm->start(); rpc_channel = mcl::DefaultConnectionConfiguration{test_socket}.the_rpc_channel(); protobuf_server = std::make_shared(rpc_channel.get()); } char const* const test_socket = "./test_socket_screencast"; std::shared_ptr const server_tool; std::shared_ptr test_server; std::shared_ptr rpc_channel; std::shared_ptr protobuf_server; }; } TEST_F(MirScreencastTest, gets_buffer_fd_when_creating_screencast) { std::vector const cookie{'2','3','l','$'}; ASSERT_EQ(static_cast(cookie.size()), write(server_tool->pipe.write_fd(), cookie.data(), cookie.size())); mir::protobuf::ScreencastParameters protobuf_parameters; protobuf_parameters.set_width(0); protobuf_parameters.set_height(0); protobuf_parameters.mutable_region()->set_left(0); protobuf_parameters.mutable_region()->set_top(0); protobuf_parameters.mutable_region()->set_width(0); protobuf_parameters.mutable_region()->set_height(0); protobuf_parameters.set_pixel_format(0); mir::protobuf::Screencast protobuf_screencast; WaitObject wait_rpc; protobuf_server->create_screencast( nullptr, &protobuf_parameters, &protobuf_screencast, google::protobuf::NewCallback(&wait_rpc, &WaitObject::notify_ready)); wait_rpc.wait_until_ready(); ASSERT_EQ(1, protobuf_screencast.buffer().fd_size()); auto const read_fd = protobuf_screencast.buffer().fd(0); // The received FD should be different from the original pipe fd, // since we are sending it over our IPC mechanism, which for // the purposes of this test, lives in the same process. // TODO: Don't depend on IPC implementation details EXPECT_NE(read_fd, server_tool->pipe.read_fd()); std::vector received(cookie.size(), '\0'); EXPECT_EQ(static_cast(cookie.size()), read(read_fd, received.data(), received.size())); EXPECT_EQ(cookie, received); close(read_fd); } TEST_F(MirScreencastTest, gets_buffer_fd_when_getting_screencast_buffer) { std::vector const cookie{'X','%','q','S'}; ASSERT_EQ(static_cast(cookie.size()), write(server_tool->pipe.write_fd(), cookie.data(), cookie.size())); mir::protobuf::ScreencastId protobuf_screencast_id; protobuf_screencast_id.set_value(0); mir::protobuf::Buffer protobuf_buffer; WaitObject wait_rpc; protobuf_server->screencast_buffer( nullptr, &protobuf_screencast_id, &protobuf_buffer, google::protobuf::NewCallback(&wait_rpc, &WaitObject::notify_ready)); wait_rpc.wait_until_ready(); ASSERT_EQ(1, protobuf_buffer.fd_size()); auto const read_fd = protobuf_buffer.fd(0); // The received FD should be different from the original pipe fd, // since we are sending it over our IPC mechanism, which, for // the purposes of this test, lives in the same process. // TODO: Don't depend on IPC implementation details EXPECT_NE(read_fd, server_tool->pipe.read_fd()); std::vector received(cookie.size(), '\0'); EXPECT_EQ(static_cast(cookie.size()), read(read_fd, received.data(), received.size())); EXPECT_EQ(cookie, received); close(read_fd); } mir-0.1.8+14.04.20140411/tests/integration-tests/client/test_client_render.cpp0000644000015301777760000003541112322054223027363 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/process.h" #include "mir/graphics/buffer_properties.h" #include "mir/graphics/buffer_initializer.h" #include "src/platform/graphics/android/buffer.h" #include "mir/graphics/android/native_buffer.h" #include "src/platform/graphics/android/android_graphic_buffer_allocator.h" #include "mir_test_framework/cross_process_sync.h" #include "testdraw/graphics_region_factory.h" #include "testdraw/patterns.h" #include "mir_test/stub_server_tool.h" #include "mir_test/test_protobuf_server.h" #include "mir/frontend/connector.h" #include #include #include #include #include namespace mtf = mir_test_framework; namespace mt=mir::test; namespace mtd=mir::test::draw; namespace mga=mir::graphics::android; namespace mg=mir::graphics; namespace geom=mir::geometry; namespace { static int test_width = 300; static int test_height = 200; static uint32_t pattern0 [2][2] = {{0x12345678, 0x23456789}, {0x34567890, 0x45678901}}; static uint32_t pattern1 [2][2] = {{0xFFFFFFFF, 0xFFFF0000}, {0xFF00FF00, 0xFF0000FF}}; static mtd::DrawPatternCheckered<2,2> draw_pattern0(pattern0); static mtd::DrawPatternCheckered<2,2> draw_pattern1(pattern1); static const char socket_file[] = "./test_client_ipc_render_socket"; struct TestClient { static 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; } static MirSurface* create_mir_surface(MirConnection * connection, EGLDisplay display, EGLConfig config) { int visual_id; eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &visual_id); /* make surface */ MirSurfaceParameters surface_parameters; surface_parameters.name = "testsurface"; surface_parameters.width = test_width; surface_parameters.height = test_height; surface_parameters.pixel_format = select_format_for_visual_id(visual_id); return mir_connection_create_surface_sync(connection, &surface_parameters); } static int render_cpu_pattern(mtf::CrossProcessSync& process_sync, int num_frames) { process_sync.wait_for_signal_ready_for(); MirSurfaceParameters surface_parameters { "testsurface", test_width, test_height, mir_pixel_format_abgr_8888, mir_buffer_usage_software, mir_display_output_id_invalid }; auto connection = mir_connect_sync(socket_file, "test_renderer"); auto surface = mir_connection_create_surface_sync(connection, &surface_parameters); MirGraphicsRegion graphics_region; for(int i=0u; i < num_frames; i++) { mir_surface_get_graphics_region(surface, &graphics_region); if (i % 2) { draw_pattern1.draw(graphics_region); } else { draw_pattern0.draw(graphics_region); } mir_surface_swap_buffers_sync(surface); } mir_surface_release_sync(surface); mir_connection_release(connection); return 0; } //performs num_frames renders, in red, green, blue repeating pattern static int render_rgb_with_gl(mtf::CrossProcessSync& process_sync, int num_frames) { process_sync.wait_for_signal_ready_for(); auto connection = mir_connect_sync(socket_file, "test_renderer"); /* set up egl context */ int major, minor, n; 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); auto mir_surface = create_mir_surface(connection, egl_display, egl_config); auto native_window = static_cast( mir_surface_get_egl_native_window(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); for (auto i=0; i < num_frames; i++) { switch (i % 3) { case 0: //red glClearColor(1.0, 0.0, 0.0, 1.0); break; case 1: //green glClearColor(0.0, 1.0, 0.0, 1.0); break; case 2: //blue default: glClearColor(0.0, 0.0, 1.0, 1.0); break; } glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(egl_display, egl_surface); } mir_surface_release_sync(mir_surface); mir_connection_release(connection); return 0; } static int exit_function() { return EXIT_SUCCESS; } }; /* server code */ struct StubServerGenerator : public mt::StubServerTool { StubServerGenerator() { auto initializer = std::make_shared(); allocator = std::make_shared (initializer); auto size = geom::Size{test_width, test_height}; surface_pf = mir_pixel_format_abgr_8888; last_posted = allocator->alloc_buffer_platform(size, surface_pf, mga::BufferUsage::use_hardware); client_buffer = allocator->alloc_buffer_platform(size, surface_pf, mga::BufferUsage::use_hardware); } void create_surface(google::protobuf::RpcController* /*controller*/, const mir::protobuf::SurfaceParameters* request, mir::protobuf::Surface* response, google::protobuf::Closure* done) { response->mutable_id()->set_value(13); response->set_width(test_width); response->set_height(test_height); surface_pf = MirPixelFormat(request->pixel_format()); response->set_pixel_format(request->pixel_format()); response->mutable_buffer()->set_buffer_id(client_buffer->id().as_uint32_t()); auto buf = client_buffer->native_buffer_handle(); //note about the stride. Mir protocol sends stride in bytes, android uses stride in pixels response->mutable_buffer()->set_stride(client_buffer->stride().as_uint32_t()); auto const& size = client_buffer->size(); response->mutable_buffer()->set_width(size.width.as_int()); response->mutable_buffer()->set_height(size.height.as_int()); response->mutable_buffer()->set_fds_on_side_channel(1); native_handle_t const* native_handle = buf->handle(); for(auto i=0; inumFds; i++) response->mutable_buffer()->add_fd(native_handle->data[i]); for(auto i=0; i < native_handle->numInts; i++) response->mutable_buffer()->add_data(native_handle->data[native_handle->numFds+i]); std::unique_lock lock(guard); surface_name = request->surface_name(); wait_condition.notify_one(); done->Run(); } virtual void next_buffer( ::google::protobuf::RpcController* /*controller*/, ::mir::protobuf::SurfaceId const* /*request*/, ::mir::protobuf::Buffer* response, ::google::protobuf::Closure* done) { std::unique_lock lk(buffer_mutex); std::swap(last_posted, client_buffer); response->set_buffer_id(client_buffer->id().as_uint32_t()); auto buf = client_buffer->native_buffer_handle(); response->set_fds_on_side_channel(1); native_handle_t const* native_handle = buf->handle(); response->set_stride(client_buffer->stride().as_uint32_t()); auto const& size = client_buffer->size(); response->set_width(size.width.as_int()); response->set_height(size.height.as_int()); for(auto i=0; inumFds; i++) response->add_fd(native_handle->data[i]); for(auto i=0; inumInts; i++) response->add_data(native_handle->data[native_handle->numFds+i]); done->Run(); } uint32_t red_value_for_surface() { if ((surface_pf == mir_pixel_format_abgr_8888) || (surface_pf == mir_pixel_format_xbgr_8888)) return 0xFF0000FF; if ((surface_pf == mir_pixel_format_argb_8888) || (surface_pf == mir_pixel_format_xrgb_8888)) return 0xFFFF0000; return 0x0; } uint32_t green_value_for_surface() { return 0xFF00FF00; } std::shared_ptr second_to_last_posted_buffer() { std::unique_lock lk(buffer_mutex); return client_buffer; } std::shared_ptr last_posted_buffer() { std::unique_lock lk(buffer_mutex); return last_posted; } private: std::shared_ptr allocator; std::shared_ptr client_buffer; std::shared_ptr last_posted; std::mutex buffer_mutex; MirPixelFormat surface_pf; }; } struct TestClientIPCRender : public testing::Test { /* note: we fork here so that the loaded driver code does not fork */ static void SetUpTestCase() { render_single_client_process = mtf::fork_and_run_in_a_different_process( std::bind(TestClient::render_cpu_pattern, std::ref(sync1), 1), TestClient::exit_function); render_double_client_process = mtf::fork_and_run_in_a_different_process( std::bind(TestClient::render_cpu_pattern, std::ref(sync2), 2), TestClient::exit_function); render_accelerated_process = mtf::fork_and_run_in_a_different_process( std::bind(TestClient::render_rgb_with_gl, std::ref(sync3), 1), TestClient::exit_function); render_accelerated_process_double = mtf::fork_and_run_in_a_different_process( std::bind(TestClient::render_rgb_with_gl, std::ref(sync4), 2), TestClient::exit_function); } void SetUp() { buffer_converter = mtd::create_graphics_region_factory(); /* start a server */ mock_server = std::make_shared(); test_server = std::make_shared(socket_file, mock_server); test_server->comm->start(); } void TearDown() { test_server.reset(); std::remove(socket_file); } std::shared_ptr test_server; std::shared_ptr mock_server; std::shared_ptr buffer_converter; static std::shared_ptr render_single_client_process; static std::shared_ptr render_double_client_process; static std::shared_ptr render_accelerated_process; static std::shared_ptr render_accelerated_process_double; static mtf::CrossProcessSync sync1, sync2, sync3, sync4; }; mtf::CrossProcessSync TestClientIPCRender::sync1; std::shared_ptr TestClientIPCRender::render_single_client_process; mtf::CrossProcessSync TestClientIPCRender::sync2; std::shared_ptr TestClientIPCRender::render_double_client_process; mtf::CrossProcessSync TestClientIPCRender::sync3; std::shared_ptr TestClientIPCRender::render_accelerated_process; mtf::CrossProcessSync TestClientIPCRender::sync4; std::shared_ptr TestClientIPCRender::render_accelerated_process_double; TEST_F(TestClientIPCRender, test_render_single) { sync1.try_signal_ready_for(); /* wait for client to finish */ EXPECT_TRUE(render_single_client_process->wait_for_termination().succeeded()); /* check content */ auto buf = mock_server->last_posted_buffer(); auto region = buffer_converter->graphic_region_from_handle(*buf->native_buffer_handle()); EXPECT_TRUE(draw_pattern0.check(*region)); } TEST_F(TestClientIPCRender, test_render_double) { sync2.try_signal_ready_for(); /* wait for client to finish */ EXPECT_TRUE(render_double_client_process->wait_for_termination().succeeded()); auto buf0 = mock_server->second_to_last_posted_buffer(); auto region0 = buffer_converter->graphic_region_from_handle(*buf0->native_buffer_handle()); EXPECT_TRUE(draw_pattern0.check(*region0)); auto buf1 = mock_server->last_posted_buffer(); auto region1 = buffer_converter->graphic_region_from_handle(*buf1->native_buffer_handle()); EXPECT_TRUE(draw_pattern1.check(*region1)); } TEST_F(TestClientIPCRender, test_accelerated_render) { mtd::DrawPatternSolid red_pattern(0xFF0000FF); sync3.try_signal_ready_for(); /* wait for client to finish */ EXPECT_TRUE(render_accelerated_process->wait_for_termination().succeeded()); /* check content */ auto buf0 = mock_server->last_posted_buffer(); auto region0 = buffer_converter->graphic_region_from_handle(*buf0->native_buffer_handle()); EXPECT_TRUE(red_pattern.check(*region0)); } TEST_F(TestClientIPCRender, test_accelerated_render_double) { mtd::DrawPatternSolid red_pattern(0xFF0000FF); mtd::DrawPatternSolid green_pattern(0xFF00FF00); sync4.try_signal_ready_for(); /* wait for client to finish */ EXPECT_TRUE(render_accelerated_process_double->wait_for_termination().succeeded()); auto buf0 = mock_server->second_to_last_posted_buffer(); auto region0 = buffer_converter->graphic_region_from_handle(*buf0->native_buffer_handle()); EXPECT_TRUE(red_pattern.check(*region0)); auto buf1 = mock_server->last_posted_buffer(); auto region1 = buffer_converter->graphic_region_from_handle(*buf1->native_buffer_handle()); EXPECT_TRUE(green_pattern.check(*region1)); } mir-0.1.8+14.04.20140411/tests/integration-tests/client/CMakeLists.txt0000644000015301777760000000057312322054223025544 0ustar pbusernogroup00000000000000# TODO(tvoss): These tests are failing for me when run in an emulator if( MIR_TEST_PLATFORM STREQUAL "android") list( APPEND INTEGRATION_TESTS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_client_render.cpp ) endif() list( APPEND INTEGRATION_TESTS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_screencast.cpp ) set( INTEGRATION_TESTS_SRCS ${INTEGRATION_TESTS_SRCS} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/integration-tests/shell/0000755000015301777760000000000012322054703022633 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/integration-tests/shell/test_session_lifecycle_event.cpp0000644000015301777760000000560312322054223031302 0ustar pbusernogroup00000000000000/* * 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: Ricardo Mendoza */ #include "mir/shell/null_session_listener.h" #include "src/server/scene/application_session.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_toolkit/mir_client_library.h" #include #include #include #include #include namespace ms = mir::scene; namespace msh = mir::shell; namespace mtf = mir_test_framework; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); struct MockStateHandler { MOCK_METHOD1(state_changed, void (MirLifecycleState)); }; class StubSessionListener : public msh::NullSessionListener { void stopping(std::shared_ptr const& session) { std::shared_ptr app_session( std::static_pointer_cast(session) ); app_session->set_lifecycle_state(mir_lifecycle_state_will_suspend); } }; using LifecycleEventTest = BespokeDisplayServerTestFixture; TEST_F(LifecycleEventTest, lifecycle_event_test) { using namespace ::testing; struct ServerConfig : TestingServerConfiguration { std::shared_ptr the_shell_session_listener() override { return std::make_shared(); } } server_config; launch_server_process(server_config); struct ClientConfig : TestingClientConfiguration { static void lifecycle_callback(MirConnection* /*connection*/, MirLifecycleState state, void* context) { auto config = static_cast(context); config->handler->state_changed(state); } void exec() { handler = std::make_shared(); MirConnection* connection = mir_connect_sync(mir_test_socket, "testapp"); mir_connection_set_lifecycle_event_callback(connection, lifecycle_callback, this); EXPECT_CALL(*handler, state_changed(Eq(mir_lifecycle_state_will_suspend))).Times(1); mir_connection_release(connection); handler.reset(); } std::shared_ptr handler; } client_config; launch_client_process(client_config); } } mir-0.1.8+14.04.20140411/tests/integration-tests/shell/CMakeLists.txt0000644000015301777760000000026212322054223025370 0ustar pbusernogroup00000000000000list( APPEND INTEGRATION_TESTS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_session_lifecycle_event.cpp ) set( INTEGRATION_TESTS_SRCS ${INTEGRATION_TESTS_SRCS} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/integration-tests/input/0000755000015301777760000000000012322054703022663 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/integration-tests/input/android/0000755000015301777760000000000012322054703024303 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/integration-tests/input/android/test_android_input_manager.cpp0000644000015301777760000003216312322054223032401 0ustar pbusernogroup00000000000000/* * 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 * Daniel d'Andrada */ #include "mir/input/event_filter.h" #include "mir/input/input_targets.h" #include "mir/input/input_region.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/geometry/point.h" #include "mir/geometry/rectangle.h" #include "src/server/report/null_report_factory.h" #include "src/server/input/android/android_input_manager.h" #include "src/server/input/android/android_input_targeter.h" #include "src/server/input/android/android_input_registrar.h" #include "src/server/input/android/event_filter_dispatcher_policy.h" #include "mir_test/fake_shared.h" #include "mir_test/fake_event_hub.h" #include "mir_test/fake_event_hub_input_configuration.h" #include "mir_test_doubles/mock_event_filter.h" #include "mir_test_doubles/mock_input_surface.h" #include "mir_test_doubles/stub_input_channel.h" #include "mir_test/wait_condition.h" #include "mir_test/event_factory.h" #include "mir_test/event_matchers.h" #include #include #include #include #include #include #include namespace mi = mir::input; namespace mia = mir::input::android; namespace mis = mir::input::synthesis; namespace ms = mir::scene; namespace msh = mir::shell; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace mr = mir::report; using mtd::MockEventFilter; namespace { using namespace ::testing; static const std::shared_ptr null_cursor_listener{}; struct StubInputTargets : public mi::InputTargets { void for_each(std::function const&)> const&) { } }; struct StubInputRegion : public mi::InputRegion { geom::Rectangle bounding_rectangle() { return {geom::Point{}, geom::Size{1600, 1400}}; } void confine(geom::Point&) { } }; class AndroidInputManagerAndEventFilterDispatcherSetup : public testing::Test { public: AndroidInputManagerAndEventFilterDispatcherSetup() { event_filter = std::make_shared(); configuration = std::make_shared( event_filter, mt::fake_shared(input_region), null_cursor_listener, mr::null_input_report()); fake_event_hub = configuration->the_fake_event_hub(); input_manager = configuration->the_input_manager(); stub_targets = std::make_shared(); configuration->set_input_targets(stub_targets); input_manager->start(); } void TearDown() { input_manager->stop(); } protected: std::shared_ptr configuration; mia::FakeEventHub* fake_event_hub; std::shared_ptr input_manager; std::shared_ptr event_filter; StubInputRegion input_region; std::shared_ptr stub_targets; }; } TEST_F(AndroidInputManagerAndEventFilterDispatcherSetup, manager_dispatches_key_events_to_filter) { using namespace ::testing; mt::WaitCondition wait_condition; EXPECT_CALL( *event_filter, handle(mt::KeyDownEvent())) .Times(1) .WillOnce(mt::ReturnFalseAndWakeUp(&wait_condition)); fake_event_hub->synthesize_builtin_keyboard_added(); fake_event_hub->synthesize_device_scan_complete(); fake_event_hub->synthesize_event(mis::a_key_down_event() .of_scancode(KEY_ENTER)); wait_condition.wait_for_at_most_seconds(1); } TEST_F(AndroidInputManagerAndEventFilterDispatcherSetup, manager_dispatches_button_down_events_to_filter) { using namespace ::testing; mt::WaitCondition wait_condition; EXPECT_CALL( *event_filter, handle(mt::ButtonDownEvent())) .Times(1) .WillOnce(mt::ReturnFalseAndWakeUp(&wait_condition)); fake_event_hub->synthesize_builtin_cursor_added(); fake_event_hub->synthesize_device_scan_complete(); fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT)); wait_condition.wait_for_at_most_seconds(1); } TEST_F(AndroidInputManagerAndEventFilterDispatcherSetup, manager_dispatches_button_up_events_to_filter) { using namespace ::testing; mt::WaitCondition wait_condition; { InSequence seq; EXPECT_CALL( *event_filter, handle(mt::ButtonDownEvent())) .Times(1) .WillOnce(Return(false)); EXPECT_CALL( *event_filter, handle(mt::ButtonUpEvent())) .Times(1) .WillOnce(Return(false)); EXPECT_CALL( *event_filter, handle(mt::MotionEvent(0,0))) .Times(1) .WillOnce(mt::ReturnFalseAndWakeUp(&wait_condition)); } fake_event_hub->synthesize_builtin_cursor_added(); fake_event_hub->synthesize_device_scan_complete(); fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT)); fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT)); wait_condition.wait_for_at_most_seconds(1); } TEST_F(AndroidInputManagerAndEventFilterDispatcherSetup, manager_dispatches_motion_events_to_filter) { using namespace ::testing; mt::WaitCondition wait_condition; // We get absolute motion events since we have a pointer controller. { InSequence seq; EXPECT_CALL(*event_filter, handle(mt::MotionEvent(100, 100))) .WillOnce(Return(false)); EXPECT_CALL(*event_filter, handle(mt::MotionEvent(200, 100))) .WillOnce(mt::ReturnFalseAndWakeUp(&wait_condition)); } fake_event_hub->synthesize_builtin_cursor_added(); fake_event_hub->synthesize_device_scan_complete(); fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(100, 100)); fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(100, 0)); wait_condition.wait_for_at_most_seconds(1); } namespace { struct MockDispatcherPolicy : public mia::EventFilterDispatcherPolicy { MockDispatcherPolicy(std::shared_ptr const& filter) : EventFilterDispatcherPolicy(filter, false) { } MOCK_METHOD3(interceptKeyBeforeDispatching, nsecs_t(droidinput::sp const&, droidinput::KeyEvent const*, uint32_t)); }; struct TestingInputConfiguration : public mtd::FakeEventHubInputConfiguration { TestingInputConfiguration(std::shared_ptr const& filter, std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener, std::shared_ptr const& input_report) : FakeEventHubInputConfiguration({}, input_region, cursor_listener, input_report), dispatcher_policy(new MockDispatcherPolicy(filter)) { } droidinput::sp the_dispatcher_policy() { return dispatcher_policy; } droidinput::sp the_mock_dispatcher_policy() { return dispatcher_policy; } droidinput::sp dispatcher_policy; }; struct AndroidInputManagerDispatcherInterceptSetup : public testing::Test { AndroidInputManagerDispatcherInterceptSetup() { event_filter = std::make_shared(); configuration = std::make_shared( event_filter, mt::fake_shared(input_region), null_cursor_listener, mr::null_input_report()); fake_event_hub = configuration->the_fake_event_hub(); input_manager = configuration->the_input_manager(); input_registrar = configuration->the_input_registrar(); input_targeter = configuration->the_input_targeter(); dispatcher_policy = configuration->the_mock_dispatcher_policy(); stub_targets = std::make_shared(); configuration->set_input_targets(stub_targets); } ~AndroidInputManagerDispatcherInterceptSetup() { input_manager->stop(); } // TODO: It would be nice if it were possible to mock the interface between // droidinput::InputChannel and droidinput::InputDispatcher rather than use // valid fds to allow non-throwing construction of a real input channel. void SetUp() { input_manager->start(); } int test_fd() { int fds[2]; // Closed by droidinput InputChannel on shutdown socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds); return fds[0]; } std::shared_ptr event_filter; StubInputRegion input_region; std::shared_ptr configuration; mia::FakeEventHub* fake_event_hub; droidinput::sp dispatcher_policy; std::shared_ptr stub_targets; std::shared_ptr input_manager; std::shared_ptr input_registrar; std::shared_ptr input_targeter; }; MATCHER_P(WindowHandleWithInputFd, input_fd, "") { if (arg->getInputChannel()->getFd() == input_fd) return true; return false; } } TEST_F(AndroidInputManagerDispatcherInterceptSetup, server_input_fd_of_focused_channel_is_sent_unfiltered_key_events) { using namespace ::testing; mt::WaitCondition wait_condition; auto input_fd = test_fd(); mtd::StubInputChannel channel(input_fd); mtd::StubInputSurface surface; EXPECT_CALL(*event_filter, handle(_)).Times(1).WillOnce(Return(false)); // We return -1 here to skip publishing of the event (to an unconnected test socket!). EXPECT_CALL(*dispatcher_policy, interceptKeyBeforeDispatching(WindowHandleWithInputFd(input_fd), _, _)) .Times(1).WillOnce(DoAll(mt::WakeUp(&wait_condition), Return(-1))); input_registrar->input_channel_opened(mt::fake_shared(channel), mt::fake_shared(surface), mi::InputReceptionMode::normal); input_targeter->focus_changed(mt::fake_shared(channel)); fake_event_hub->synthesize_builtin_keyboard_added(); fake_event_hub->synthesize_device_scan_complete(); fake_event_hub->synthesize_event(mis::a_key_down_event() .of_scancode(KEY_ENTER)); wait_condition.wait_for_at_most_seconds(1); } TEST_F(AndroidInputManagerDispatcherInterceptSetup, changing_focus_changes_event_recipient) { using namespace ::testing; mt::WaitCondition wait1, wait2, wait3; mtd::StubInputSurface surface; auto input_fd_1 = test_fd(); mtd::StubInputChannel channel1(input_fd_1); auto input_fd_2 = test_fd(); mtd::StubInputChannel channel2(input_fd_2); input_registrar->input_channel_opened(mt::fake_shared(channel1), mt::fake_shared(surface), mi::InputReceptionMode::normal); input_registrar->input_channel_opened(mt::fake_shared(channel2), mt::fake_shared(surface), mi::InputReceptionMode::normal); EXPECT_CALL(*event_filter, handle(_)).Times(3).WillRepeatedly(Return(false)); { InSequence seq; EXPECT_CALL(*dispatcher_policy, interceptKeyBeforeDispatching(WindowHandleWithInputFd(input_fd_1), _, _)) .Times(1).WillOnce(DoAll(mt::WakeUp(&wait1), Return(-1))); EXPECT_CALL(*dispatcher_policy, interceptKeyBeforeDispatching(WindowHandleWithInputFd(input_fd_2), _, _)) .Times(1).WillOnce(DoAll(mt::WakeUp(&wait2), Return(-1))); EXPECT_CALL(*dispatcher_policy, interceptKeyBeforeDispatching(WindowHandleWithInputFd(input_fd_1), _, _)) .Times(1).WillOnce(DoAll(mt::WakeUp(&wait3), Return(-1))); } fake_event_hub->synthesize_builtin_keyboard_added(); fake_event_hub->synthesize_device_scan_complete(); input_targeter->focus_changed(mt::fake_shared(channel1)); fake_event_hub->synthesize_event(mis::a_key_down_event() .of_scancode(KEY_1)); wait1.wait_for_at_most_seconds(1); input_targeter->focus_changed(mt::fake_shared(channel2)); fake_event_hub->synthesize_event(mis::a_key_down_event() .of_scancode(KEY_2)); wait2.wait_for_at_most_seconds(1); input_targeter->focus_changed(mt::fake_shared(channel1)); fake_event_hub->synthesize_event(mis::a_key_down_event() .of_scancode(KEY_3)); wait3.wait_for_at_most_seconds(5); } mir-0.1.8+14.04.20140411/tests/integration-tests/input/android/CMakeLists.txt0000644000015301777760000000035712322054223027045 0ustar pbusernogroup00000000000000list( APPEND INTEGRATION_TESTS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_manager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_cursor_listener.cpp ) set( INTEGRATION_TESTS_SRCS ${INTEGRATION_TESTS_SRCS} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/integration-tests/input/android/test_android_cursor_listener.cpp0000644000015301777760000000776512322054223033004 0ustar pbusernogroup00000000000000/* * 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 * Daniel d'Andrada */ #include "src/server/input/android/android_input_manager.h" #include "src/server/report/null_report_factory.h" #include "mir/input/android/default_android_input_configuration.h" #include "mir/input/event_filter.h" #include "mir/input/cursor_listener.h" #include "mir/input/input_targets.h" #include "mir/input/input_region.h" #include "mir/geometry/rectangle.h" #include "mir_test/fake_shared.h" #include "mir_test/fake_event_hub.h" #include "mir_test/fake_event_hub_input_configuration.h" #include "mir_test_doubles/mock_event_filter.h" #include "mir_test/wait_condition.h" #include "mir_test/event_factory.h" #include #include #include namespace mi = mir::input; namespace mia = mir::input::android; namespace mis = mir::input::synthesis; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace mr = mir::report; using mtd::MockEventFilter; namespace { using namespace ::testing; struct StubInputTargets : public mi::InputTargets { void for_each(std::function const&)> const&) { } }; struct StubInputRegion : public mi::InputRegion { geom::Rectangle bounding_rectangle() { return {geom::Point{}, geom::Size{1024, 1024}}; } void confine(geom::Point&) { } }; struct MockCursorListener : public mi::CursorListener { MOCK_METHOD2(cursor_moved_to, void(float, float)); ~MockCursorListener() noexcept {} }; struct AndroidInputManagerAndCursorListenerSetup : public testing::Test { void SetUp() { event_filter = std::make_shared(); configuration = std::make_shared( event_filter, mt::fake_shared(input_region), mt::fake_shared(cursor_listener), mr::null_input_report()); fake_event_hub = configuration->the_fake_event_hub(); input_manager = configuration->the_input_manager(); stub_targets = std::make_shared(); configuration->set_input_targets(stub_targets); input_manager->start(); } void TearDown() { input_manager->stop(); } std::shared_ptr configuration; mia::FakeEventHub* fake_event_hub; std::shared_ptr event_filter; std::shared_ptr input_manager; MockCursorListener cursor_listener; std::shared_ptr stub_targets; StubInputRegion input_region; }; } TEST_F(AndroidInputManagerAndCursorListenerSetup, cursor_listener_receives_motion) { using namespace ::testing; auto wait_condition = std::make_shared(); static const float x = 100.f; static const float y = 100.f; EXPECT_CALL(cursor_listener, cursor_moved_to(x, y)).Times(1); // The stack doesn't like shutting down while events are still moving through EXPECT_CALL(*event_filter, handle(_)) .WillOnce(mt::ReturnFalseAndWakeUp(wait_condition)); fake_event_hub->synthesize_builtin_cursor_added(); fake_event_hub->synthesize_device_scan_complete(); fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(x, y)); wait_condition->wait_for_at_most_seconds(1); } mir-0.1.8+14.04.20140411/tests/integration-tests/input/test_nested_input.cpp0000644000015301777760000000747712322054223027143 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/input/nested_input_configuration.h" #include "src/server/input/nested_input_relay.h" #include "mir/input/input_region.h" #include "mir/input/cursor_listener.h" #include "mir/input/input_manager.h" #include "mir/input/input_targets.h" #include "src/server/report/null/input_report.h" #include "mir/geometry/rectangle.h" #include "mir/raii.h" #include "mir_test_doubles/mock_event_filter.h" #include "mir_test/fake_shared.h" #include #include namespace mi = mir::input; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace geom = mir::geometry; namespace { struct NullInputRegion : mi::InputRegion { geom::Rectangle bounding_rectangle() override { return geom::Rectangle(); } void confine(geom::Point& /*point*/) override { } }; struct NullCursorListener : mi::CursorListener { void cursor_moved_to(float, float) override {} }; struct NullInputTargets : mi::InputTargets { void for_each(std::function const&)> const& ) override { } }; MATCHER_P(MirKeyEventMatches, event, "") { return event->type == arg.type && event->key.device_id == arg.key.device_id && event->key.source_id == arg.key.source_id && event->key.action == arg.key.action && event->key.flags == arg.key.flags && event->key.modifiers == arg.key.modifiers && event->key.key_code == arg.key.key_code && event->key.scan_code == arg.key.scan_code && event->key.repeat_count == arg.key.repeat_count && event->key.down_time == arg.key.down_time && event->key.event_time == arg.key.event_time && event->key.is_system_key == arg.key.is_system_key; } } TEST(NestedInputTest, applies_event_filter_on_relayed_event) { using namespace testing; mi::NestedInputRelay nested_input_relay; mtd::MockEventFilter mock_event_filter; mi::NestedInputConfiguration input_conf{ mt::fake_shared(nested_input_relay), mt::fake_shared(mock_event_filter), std::make_shared(), std::make_shared(), std::make_shared()}; input_conf.set_input_targets(std::make_shared()); auto const input_manager = input_conf.the_input_manager(); auto const with_running_input_manager = mir::raii::paired_calls( [&] { input_manager->start(); }, [&] { input_manager->stop(); }); MirEvent e; memset(&e, 0, sizeof(MirEvent)); e.key.type = mir_event_type_key; e.key.device_id = 13; e.key.source_id = 10; e.key.action = mir_key_action_down; e.key.flags = static_cast(0); e.key.modifiers = 0; e.key.key_code = 81; e.key.scan_code = 176; e.key.repeat_count = 0; e.key.down_time = 1234; e.key.event_time = 12345; e.key.is_system_key = 0; EXPECT_CALL(mock_event_filter, handle(MirKeyEventMatches(&e))) .WillOnce(Return(true)); mi::EventFilter& nested_input_relay_as_filter = nested_input_relay; nested_input_relay_as_filter.handle(e); } mir-0.1.8+14.04.20140411/tests/integration-tests/input/test_configuring_input_manager.cpp0000644000015301777760000000324112322054223031646 0ustar pbusernogroup00000000000000/* * 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 * Daniel d'Andrada */ #include #include #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_doubles/mock_input_manager.h" namespace mi = mir::input; namespace mtd = mir::test::doubles; #include TEST_F(BespokeDisplayServerTestFixture, starting_display_server_starts_input_manager) { struct ServerConfig : TestingServerConfiguration { std::shared_ptr the_input_manager() override { if (!mock_input_manager.get()) { mock_input_manager = std::make_shared(); EXPECT_CALL(*mock_input_manager, start()).Times(1); EXPECT_CALL(*mock_input_manager, stop()).Times(1); } return mock_input_manager; } std::shared_ptr mock_input_manager; } server_config; launch_server_process(server_config); } mir-0.1.8+14.04.20140411/tests/integration-tests/input/CMakeLists.txt0000644000015301777760000000047212322054223025423 0ustar pbusernogroup00000000000000list( APPEND INTEGRATION_TESTS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_configuring_input_manager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_nested_input.cpp ) if(NOT MIR_TEST_PLATFORM STREQUAL "android") add_subdirectory(android) endif() set( INTEGRATION_TESTS_SRCS ${INTEGRATION_TESTS_SRCS} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/integration-tests/CMakeLists.txt0000644000015301777760000000333512322054223024265 0ustar pbusernogroup00000000000000include(CMakeDependentOption) include_directories(${CMAKE_SOURCE_DIR}) set( INTEGRATION_TESTS_SRCS test_surfaceloop.cpp test_error_reporting.cpp test_display_info.cpp test_display_server_main_loop_events.cpp test_surface_first_frame_sync.cpp test_swapinterval.cpp test_server_client_types.cpp test_session_manager.cpp test_session.cpp ) add_subdirectory(client/) add_subdirectory(compositor/) add_subdirectory(frontend/) add_subdirectory(shell/) add_subdirectory(process/) add_subdirectory(input/) if (MIR_TEST_PLATFORM STREQUAL "android") add_subdirectory(graphics/android) endif() if(MIR_TEST_PLATFORM STREQUAL "mesa") include_directories( ${DRM_INCLUDE_DIRS} ${GBM_INCLUDE_DIRS} ${EGL_INCLUDE_DIRS} ${GLESv2_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ) add_subdirectory(graphics/mesa) list(APPEND INTEGRATION_TESTS_SRCS test_drm_auth_magic.cpp) endif() link_directories(${LIBRARY_OUTPUT_PATH}) add_executable( mir_integration_tests ${INTEGRATION_TESTS_SRCS}) uses_android_input(mir_integration_tests) target_link_libraries( mir_integration_tests mir-test mir-test-framework mir-test-doubles mirserver mirplatformgraphics mirclient mirdraw mirtestdraw 3rd_party ${PROTOBUF_LIBRARIES} ${Boost_LIBRARIES} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} # Link in pthread. ) CMAKE_DEPENDENT_OPTION( MIR_RUN_INTEGRATION_TESTS "Run integration tests as part of default testing" ON "MIR_BUILD_INTEGRATION_TESTS" OFF) if (MIR_RUN_INTEGRATION_TESTS) mir_discover_tests(mir_integration_tests) endif (MIR_RUN_INTEGRATION_TESTS) install( TARGETS mir_integration_tests RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) mir-0.1.8+14.04.20140411/tests/integration-tests/test_display_info.cpp0000644000015301777760000001263212322054247025756 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/graphics/display.h" #include "mir/graphics/buffer.h" #include "mir/frontend/session_authorizer.h" #include "src/server/frontend/protobuf_ipc_factory.h" #include "src/server/frontend/resource_cache.h" #include "src/server/frontend/session_mediator.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_framework/cross_process_sync.h" #include "mir_test_doubles/stub_buffer_allocator.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/null_event_sink.h" #include "mir_test_doubles/null_display_changer.h" #include "mir_test_doubles/stub_display_buffer.h" #include "mir_test_doubles/null_platform.h" #include "mir_test/display_config_matchers.h" #include "mir_test_doubles/stub_display_configuration.h" #include "mir_test/fake_shared.h" #include "mir_toolkit/mir_client_library.h" #include #include #include #include namespace msh = mir::shell; namespace mg = mir::graphics; namespace mc = mir::compositor; namespace geom = mir::geometry; namespace mf = mir::frontend; namespace mtf = mir_test_framework; namespace mtd = mir::test::doubles; namespace mt = mir::test; namespace { class StubDisplay : public mtd::NullDisplay { public: StubDisplay() { } void for_each_display_buffer(std::function const& f) override { f(display_buffer); } private: mtd::NullDisplayBuffer display_buffer; }; class StubChanger : public mtd::NullDisplayChanger { public: std::shared_ptr active_configuration() override { return mt::fake_shared(stub_display_config); } static mtd::StubDisplayConfig stub_display_config; private: mtd::NullDisplayBuffer display_buffer; }; mtd::StubDisplayConfig StubChanger::stub_display_config{ 2, { mir_pixel_format_xrgb_8888 } }; char const* const mir_test_socket = mtf::test_socket_file().c_str(); class StubGraphicBufferAllocator : public mtd::StubBufferAllocator { public: std::vector supported_pixel_formats() override { return pixel_formats; } static std::vector const pixel_formats; }; std::vector const StubGraphicBufferAllocator::pixel_formats{ mir_pixel_format_argb_8888, mir_pixel_format_xbgr_8888, mir_pixel_format_bgr_888 }; class StubPlatform : public mtd::NullPlatform { public: std::shared_ptr create_buffer_allocator( std::shared_ptr const& /*buffer_initializer*/) override { return std::make_shared(); } std::shared_ptr create_display( std::shared_ptr const&, std::shared_ptr const&) override { if (!display) display = std::make_shared(); return display; } std::shared_ptr display; }; } using AvailableSurfaceFormatsTest = BespokeDisplayServerTestFixture; TEST_F(AvailableSurfaceFormatsTest, surface_pixel_formats_reach_client) { struct ServerConfig : TestingServerConfiguration { std::shared_ptr the_graphics_platform() override { using namespace testing; if (!platform) platform = std::make_shared(); return platform; } std::shared_ptr the_frontend_display_changer() override { if (!changer) changer = std::make_shared(); return changer; } std::shared_ptr changer; std::shared_ptr platform; } server_config; launch_server_process(server_config); struct Client : TestingClientConfiguration { void exec() { MirConnection* connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(mir_connection_is_valid(connection)); unsigned int const format_storage_size = 4; MirPixelFormat formats[format_storage_size]; unsigned int returned_format_size = 0; mir_connection_get_available_surface_formats(connection, formats, format_storage_size, &returned_format_size); ASSERT_EQ(StubGraphicBufferAllocator::pixel_formats.size(), returned_format_size); for (auto i=0u; i < returned_format_size; ++i) { EXPECT_EQ(StubGraphicBufferAllocator::pixel_formats[i], formats[i]) << "i=" << i; } mir_connection_release(connection); } } client_config; launch_client_process(client_config); } mir-0.1.8+14.04.20140411/tests/integration-tests/test_swapinterval.cpp0000644000015301777760000001631512322054247026017 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/geometry/rectangle.h" #include "mir/graphics/display.h" #include "mir/graphics/display_buffer.h" #include "mir/compositor/renderer.h" #include "mir/compositor/compositor.h" #include "mir/compositor/display_buffer_compositor.h" #include "mir/compositor/scene.h" #include "mir/compositor/buffer_stream.h" #include "mir/scene/buffer_stream_factory.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_toolkit/mir_client_library.h" #include #include #include #include namespace geom = mir::geometry; namespace mg = mir::graphics; namespace mc = mir::compositor; namespace mtf = mir_test_framework; namespace ms = mir::scene; namespace mtd = mir::test::doubles; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); class CountingBufferStream : public mc::BufferStream { public: CountingBufferStream(int render_operations_fd) : render_operations_fd(render_operations_fd) { } void swap_client_buffers(mg::Buffer*, std::function complete) override { complete(&stub_buffer); } std::shared_ptr lock_compositor_buffer(void const*) override { return std::make_shared(); } std::shared_ptr lock_snapshot_buffer() override { return std::make_shared(); } MirPixelFormat get_stream_pixel_format() override { return mir_pixel_format_abgr_8888; } geom::Size stream_size() override { return geom::Size{}; } void resize(geom::Size const&) override {} void force_requests_to_complete() override {} void allow_framedropping(bool) override { while (write(render_operations_fd, "a", 1) != 1) continue; } int buffers_ready_for_compositor() const override { return 1; } private: int render_operations_fd; mtd::StubBuffer stub_buffer; }; class StubStreamFactory : public ms::BufferStreamFactory { public: StubStreamFactory(int render_operations_fd) : render_operations_fd(render_operations_fd) { } std::shared_ptr create_buffer_stream(mg::BufferProperties const&) { return std::make_shared(render_operations_fd); } private: int render_operations_fd; }; } using SwapIntervalSignalTest = BespokeDisplayServerTestFixture; TEST_F(SwapIntervalSignalTest, swapinterval_test) { static std::string const swapinterval_set{"swapinterval_set_952f3f10.tmp"}; static std::string const do_client_finish{"do_client_finish_952f3f10.tmp"}; std::remove(swapinterval_set.c_str()); std::remove(do_client_finish.c_str()); struct ServerConfig : TestingServerConfiguration { ServerConfig() { if (pipe(rendering_ops_pipe) != 0) { BOOST_THROW_EXCEPTION( std::runtime_error("Failed to create pipe")); } if (fcntl(rendering_ops_pipe[0], F_SETFL, O_NONBLOCK) != 0) { BOOST_THROW_EXCEPTION( std::runtime_error("Failed to make the read end of the pipe non-blocking")); } } ~ServerConfig() { if (rendering_ops_pipe[0] >= 0) close(rendering_ops_pipe[0]); if (rendering_ops_pipe[1] >= 0) close(rendering_ops_pipe[1]); } std::shared_ptr the_buffer_stream_factory() override { if (!stub_stream_factory) stub_stream_factory = std::make_shared(rendering_ops_pipe[1]); return stub_stream_factory; } int num_of_swapinterval_devices() { char c; int ops{0}; while (read(rendering_ops_pipe[0], &c, 1) == 1) ops++; return ops; } int rendering_ops_pipe[2]; std::shared_ptr stub_stream_factory; } server_config; launch_server_process(server_config); struct ClientConfig : TestingClientConfiguration { ClientConfig(std::string const& swapinterval_set, std::string const& do_client_finish) : swapinterval_set{swapinterval_set}, do_client_finish{do_client_finish} { } static void surface_callback(MirSurface*, void*) { } void exec() { MirSurfaceParameters request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; MirConnection* connection = mir_connect_sync(mir_test_socket, "testapp"); MirSurface* surface = mir_connection_create_surface_sync(connection, &request_params); //1 is the default swapinterval EXPECT_EQ(1, mir_surface_get_swapinterval(surface)); mir_wait_for(mir_surface_set_swapinterval(surface, 0)); EXPECT_EQ(0, mir_surface_get_swapinterval(surface)); mir_wait_for(mir_surface_set_swapinterval(surface, 1)); EXPECT_EQ(1, mir_surface_get_swapinterval(surface)); //swapinterval 2 not supported EXPECT_EQ(NULL, mir_surface_set_swapinterval(surface, 2)); EXPECT_EQ(1, mir_surface_get_swapinterval(surface)); set_flag(swapinterval_set); wait_for(do_client_finish); mir_surface_release_sync(surface); mir_connection_release(connection); } /* TODO: Extract this flag mechanism and make it reusable */ void set_flag(std::string const& flag_file) { close(open(flag_file.c_str(), O_CREAT, S_IWUSR | S_IRUSR)); } void wait_for(std::string const& flag_file) { int fd = -1; while ((fd = open(flag_file.c_str(), O_RDONLY, S_IWUSR | S_IRUSR)) == -1) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } close(fd); } std::string const swapinterval_set; std::string const do_client_finish; } client_config{swapinterval_set, do_client_finish}; launch_client_process(client_config); run_in_test_process([&] { client_config.wait_for(swapinterval_set); EXPECT_EQ(2, server_config.num_of_swapinterval_devices()); client_config.set_flag(do_client_finish); }); } mir-0.1.8+14.04.20140411/tests/integration-tests/test_surfaceloop.cpp0000644000015301777760000003341112322054247025616 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/compositor/switching_bundle.h" #include "mir/graphics/buffer_properties.h" #include "mir/graphics/buffer_id.h" #include "mir/graphics/buffer_basic.h" #include "mir/graphics/display.h" #include "mir_toolkit/mir_client_library.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/stub_buffer_allocator.h" #include "mir_test_doubles/null_platform.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/stub_display_buffer.h" #include #include #include #include #include "mir_test/gmock_fixes.h" namespace mc = mir::compositor; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace mf = mir::frontend; namespace mtf = mir_test_framework; namespace mtd = mir::test::doubles; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); geom::Size const size{640, 480}; MirPixelFormat const format{mir_pixel_format_abgr_8888}; mg::BufferUsage const usage{mg::BufferUsage::hardware}; mg::BufferProperties const buffer_properties{size, format, usage}; class MockGraphicBufferAllocator : public mtd::StubBufferAllocator { public: MockGraphicBufferAllocator() { using testing::_; ON_CALL(*this, alloc_buffer(_)) .WillByDefault(testing::Invoke(this, &MockGraphicBufferAllocator::on_create_swapper)); } MOCK_METHOD1( alloc_buffer, std::shared_ptr (mg::BufferProperties const&)); std::shared_ptr on_create_swapper(mg::BufferProperties const&) { return std::make_shared(::buffer_properties); } ~MockGraphicBufferAllocator() noexcept {} }; } namespace mir { namespace { class StubDisplay : public mtd::NullDisplay { public: StubDisplay() : display_buffer{geom::Rectangle{geom::Point{0,0}, geom::Size{1600,1600}}} { } void for_each_display_buffer(std::function const& f) override { f(display_buffer); } private: mtd::StubDisplayBuffer display_buffer; }; struct SurfaceSync { SurfaceSync() : surface(0) { } void surface_created(MirSurface * new_surface) { std::unique_lock lock(guard); surface = new_surface; wait_condition.notify_all(); } void surface_released(MirSurface * /*released_surface*/) { std::unique_lock lock(guard); surface = NULL; wait_condition.notify_all(); } void wait_for_surface_create() { std::unique_lock lock(guard); while (!surface) wait_condition.wait(lock); } void wait_for_surface_release() { std::unique_lock lock(guard); while (surface) wait_condition.wait(lock); } std::mutex guard; std::condition_variable wait_condition; MirSurface * surface; }; struct ClientConfigCommon : TestingClientConfiguration { static const int max_surface_count = 5; SurfaceSync ssync[max_surface_count]; }; const int ClientConfigCommon::max_surface_count; } } using SurfaceLoop = BespokeDisplayServerTestFixture; using SurfaceLoopDefault = DefaultDisplayServerTestFixture; using mir::SurfaceSync; using mir::ClientConfigCommon; using mir::StubDisplay; namespace { void create_surface_callback(MirSurface* surface, void * context) { SurfaceSync* config = reinterpret_cast(context); config->surface_created(surface); } void release_surface_callback(MirSurface* surface, void * context) { SurfaceSync* config = reinterpret_cast(context); config->surface_released(surface); } void wait_for_surface_create(SurfaceSync* context) { context->wait_for_surface_create(); } void wait_for_surface_release(SurfaceSync* context) { context->wait_for_surface_release(); } } TEST_F(SurfaceLoopDefault, creating_a_client_surface_gets_surface_of_requested_size) { struct ClientConfig : TestingClientConfiguration { void exec() { auto const connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ(mir_connection_get_error_message(connection), ""); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; auto const surface = mir_connection_create_surface_sync(connection, &request_params); ASSERT_TRUE(surface != NULL); EXPECT_TRUE(mir_surface_is_valid(surface)); EXPECT_STREQ(mir_surface_get_error_message(surface), ""); MirSurfaceParameters response_params; mir_surface_get_parameters(surface, &response_params); EXPECT_EQ(request_params.width, response_params.width); EXPECT_EQ(request_params.height, response_params.height); EXPECT_EQ(request_params.pixel_format, response_params.pixel_format); EXPECT_EQ(request_params.buffer_usage, response_params.buffer_usage); mir_surface_release_sync(surface); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } namespace { /* * Need to declare outside method, because g++ 4.4 doesn't support local types * as template parameters (in std::make_shared()). */ struct ServerConfigAllocatesBuffersOnServer : TestingServerConfiguration { class StubPlatform : public mtd::NullPlatform { public: std::shared_ptr create_buffer_allocator( const std::shared_ptr& /*buffer_initializer*/) override { using testing::AtMost; auto buffer_allocator = std::make_shared>(); EXPECT_CALL(*buffer_allocator, alloc_buffer(buffer_properties)) .Times(AtMost(3)); return buffer_allocator; } std::shared_ptr create_display( std::shared_ptr const&, std::shared_ptr const&) override { return std::make_shared(); } }; std::shared_ptr the_graphics_platform() { if (!platform) platform = std::make_shared(); return platform; } std::shared_ptr platform; }; } TEST_F(SurfaceLoop, creating_a_client_surface_allocates_buffers_on_server) { ServerConfigAllocatesBuffersOnServer server_config; launch_server_process(server_config); struct ClientConfig : ClientConfigCommon { void exec() { auto connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ(mir_connection_get_error_message(connection), ""); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_connection_create_surface(connection, &request_params, create_surface_callback, ssync); wait_for_surface_create(ssync); ASSERT_TRUE(ssync->surface != NULL); EXPECT_TRUE(mir_surface_is_valid(ssync->surface)); EXPECT_STREQ(mir_surface_get_error_message(ssync->surface), ""); MirSurfaceParameters response_params; mir_surface_get_parameters(ssync->surface, &response_params); EXPECT_EQ(request_params.width, response_params.width); EXPECT_EQ(request_params.height, response_params.height); EXPECT_EQ(request_params.pixel_format, response_params.pixel_format); EXPECT_EQ(request_params.buffer_usage, response_params.buffer_usage); mir_surface_release(ssync->surface, release_surface_callback, ssync); wait_for_surface_release(ssync); ASSERT_TRUE(ssync->surface == NULL); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } namespace { struct BufferCounterConfig : TestingServerConfiguration { class CountingStubBuffer : public mtd::StubBuffer { public: CountingStubBuffer() { int created = buffers_created.load(); while (!buffers_created.compare_exchange_weak(created, created + 1)) std::this_thread::yield(); } ~CountingStubBuffer() { int destroyed = buffers_destroyed.load(); while (!buffers_destroyed.compare_exchange_weak(destroyed, destroyed + 1)) std::this_thread::yield(); } static std::atomic buffers_created; static std::atomic buffers_destroyed; }; class StubGraphicBufferAllocator : public mtd::StubBufferAllocator { public: std::shared_ptr alloc_buffer(mg::BufferProperties const&) override { return std::make_shared(); } }; class StubPlatform : public mtd::NullPlatform { public: std::shared_ptr create_buffer_allocator( const std::shared_ptr& /*buffer_initializer*/) override { return std::make_shared(); } std::shared_ptr create_display( std::shared_ptr const&, std::shared_ptr const&) override { return std::make_shared(); } }; std::shared_ptr the_graphics_platform() { if (!platform) platform = std::make_shared(); return platform; } std::shared_ptr platform; }; std::atomic BufferCounterConfig::CountingStubBuffer::buffers_created; std::atomic BufferCounterConfig::CountingStubBuffer::buffers_destroyed; } TEST_F(SurfaceLoop, all_created_buffers_are_destoyed) { struct ServerConfig : BufferCounterConfig { void on_exit() override { EXPECT_EQ(CountingStubBuffer::buffers_created.load(), CountingStubBuffer::buffers_destroyed.load()); } } server_config; launch_server_process(server_config); struct Client : ClientConfigCommon { void exec() override { auto connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; for (int i = 0; i != max_surface_count; ++i) mir_connection_create_surface(connection, &request_params, create_surface_callback, ssync+i); for (int i = 0; i != max_surface_count; ++i) wait_for_surface_create(ssync+i); for (int i = 0; i != max_surface_count; ++i) mir_surface_release(ssync[i].surface, release_surface_callback, ssync+i); for (int i = 0; i != max_surface_count; ++i) wait_for_surface_release(ssync+i); mir_connection_release(connection); } } client_creates_surfaces; launch_client_process(client_creates_surfaces); } TEST_F(SurfaceLoop, all_created_buffers_are_destoyed_if_client_disconnects_without_releasing_surfaces) { struct ServerConfig : BufferCounterConfig { void on_exit() override { EXPECT_EQ(CountingStubBuffer::buffers_created.load(), CountingStubBuffer::buffers_destroyed.load()); } } server_config; launch_server_process(server_config); struct Client : ClientConfigCommon { void exec() override { auto connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; for (int i = 0; i != max_surface_count; ++i) mir_connection_create_surface(connection, &request_params, create_surface_callback, ssync+i); for (int i = 0; i != max_surface_count; ++i) wait_for_surface_create(ssync+i); mir_connection_release(connection); } } client_creates_surfaces; launch_client_process(client_creates_surfaces); } mir-0.1.8+14.04.20140411/tests/unit-tests/0000755000015301777760000000000012322054703020160 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/0000755000015301777760000000000012322054703021777 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_protobuf_surface_apis.cpp0000644000015301777760000002012412322054223030122 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/frontend/connector.h" #include "src/server/frontend/resource_cache.h" #include "mir_protobuf.pb.h" #include "mir_test_doubles/stub_ipc_factory.h" #include "mir_test/stub_server_tool.h" #include "mir_test/test_protobuf_client.h" #include "mir_test/test_protobuf_server.h" #include #include #include #include #include namespace mf = mir::frontend; namespace mt = mir::test; namespace mir { namespace test { struct StubServerSurfaceCounter : public StubServerTool { int surface_count; StubServerSurfaceCounter() : surface_count(0) { } void create_surface(google::protobuf::RpcController* controller, const mir::protobuf::SurfaceParameters* request, mir::protobuf::Surface* response, google::protobuf::Closure* done) { { std::unique_lock lock(guard); ++surface_count; } StubServerTool::create_surface(controller, request, response, done); } void expect_surface_count(int expected_count) { std::unique_lock ul(guard); while (surface_count != expected_count) wait_condition.wait(ul); EXPECT_EQ(expected_count, surface_count); } }; } struct ProtobufSurfaceCounter : public ::testing::Test { void SetUp() { stub_server_tool = std::make_shared(); stub_server = std::make_shared("./test_socket", stub_server_tool); stub_server->comm->start(); stub_client = std::make_shared("./test_socket", 100); stub_client->connect_parameters.set_application_name(__PRETTY_FUNCTION__); } void TearDown() { stub_server.reset(); } std::shared_ptr stub_client; std::shared_ptr stub_server_tool; std::shared_ptr stub_server; }; TEST_F(ProtobufSurfaceCounter, server_creates_surface_on_create_surface_call) { EXPECT_CALL(*stub_client, create_surface_done()).Times(testing::AtLeast(1)); stub_client->display_server.create_surface( 0, &stub_client->surface_parameters, &stub_client->surface, google::protobuf::NewCallback(stub_client.get(), &mt::TestProtobufClient::create_surface_done)); stub_client->wait_for_create_surface(); stub_server_tool->expect_surface_count(1); } TEST_F(ProtobufSurfaceCounter, surface_count_is_zero_after_connection) { using namespace testing; EXPECT_CALL(*stub_client, connect_done()).Times(AtLeast(0)); stub_client->display_server.connect( 0, &stub_client->connect_parameters, &stub_client->connection, google::protobuf::NewCallback(stub_client.get(), &mt::TestProtobufClient::connect_done)); stub_client->wait_for_connect_done(); stub_server_tool->expect_surface_count(0); } TEST_F(ProtobufSurfaceCounter, each_create_surface_results_in_a_new_surface_being_created) { int const surface_count{5}; EXPECT_CALL(*stub_client, create_surface_done()).Times(surface_count); for (int i = 0; i != surface_count; ++i) { stub_client->display_server.create_surface( 0, &stub_client->surface_parameters, &stub_client->surface, google::protobuf::NewCallback(stub_client.get(), &mt::TestProtobufClient::create_surface_done)); stub_client->wait_for_create_surface(); } stub_server_tool->expect_surface_count(surface_count); } TEST_F(ProtobufSurfaceCounter, each_create_surface_results_in_a_new_surface_being_created_asynchronously) { int const surface_count{5}; EXPECT_CALL(*stub_client, create_surface_done()).Times(surface_count); for (int i = 0; i != surface_count; ++i) { stub_client->display_server.create_surface( 0, &stub_client->surface_parameters, &stub_client->surface, google::protobuf::NewCallback(stub_client.get(), &mt::TestProtobufClient::create_surface_done)); } stub_server_tool->expect_surface_count(surface_count); stub_client->wait_for_surface_count(surface_count); } /* start Multi test cases */ struct ProtobufSocketMultiClientCommunicator : public ::testing::Test { static int const number_of_clients = 10; void SetUp() { using namespace testing; stub_server_tool = std::make_shared(); stub_server = std::make_shared("./test_socket", stub_server_tool); stub_server->comm->start(); for(int i=0; i("./test_socket", 100); clients.push_back(client_tmp); } } void TearDown() { clients.clear(); stub_server.reset(); stub_server_tool.reset(); } std::vector> clients; std::shared_ptr stub_server_tool; std::shared_ptr stub_server; }; TEST_F(ProtobufSocketMultiClientCommunicator, multiple_clients_can_connect_create_surface_and_disconnect) { for (int i = 0; i != number_of_clients; ++i) { EXPECT_CALL(*clients[i], create_surface_done()).Times(1); clients[i]->display_server.create_surface( 0, &clients[i]->surface_parameters, &clients[i]->surface, google::protobuf::NewCallback(clients[i].get(), &mt::TestProtobufClient::create_surface_done)); clients[i]->wait_for_create_surface(); } stub_server_tool->expect_surface_count(number_of_clients); for (int i = 0; i != number_of_clients; ++i) { EXPECT_CALL(*clients[i], disconnect_done()).Times(1); clients[i]->display_server.disconnect( 0, &clients[i]->ignored, &clients[i]->ignored, google::protobuf::NewCallback(clients[i].get(), &mt::TestProtobufClient::disconnect_done)); clients[i]->wait_for_disconnect_done(); } stub_server_tool->expect_surface_count(number_of_clients); } TEST_F(ProtobufSocketMultiClientCommunicator, multiple_clients_can_connect_and_disconnect_asynchronously) { for (int i = 0; i != number_of_clients; ++i) { EXPECT_CALL(*clients[i], create_surface_done()).Times(1); clients[i]->display_server.create_surface( 0, &clients[i]->surface_parameters, &clients[i]->surface, google::protobuf::NewCallback(clients[i].get(), &mt::TestProtobufClient::create_surface_done)); } for (int i = 0; i != number_of_clients; ++i) { clients[i]->wait_for_create_surface(); } stub_server_tool->expect_surface_count(number_of_clients); for (int i = 0; i != number_of_clients; ++i) { EXPECT_CALL(*clients[i], disconnect_done()).Times(1); clients[i]->display_server.disconnect( 0, &clients[i]->ignored, &clients[i]->ignored, google::protobuf::NewCallback(clients[i].get(), &mt::TestProtobufClient::disconnect_done)); } for (int i = 0; i != number_of_clients; ++i) { clients[i]->wait_for_disconnect_done(); } stub_server_tool->expect_surface_count(number_of_clients); } } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_unauthorized_display_changer.cpp0000644000015301777760000000356412322054223031504 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/frontend/unauthorized_display_changer.h" #include "mir_test_doubles/mock_display_changer.h" #include "mir_test_doubles/null_display_configuration.h" #include "mir_test/fake_shared.h" #include #include namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace mf = mir::frontend; struct UnauthorizedDisplayChangerTest : public ::testing::Test { mtd::MockDisplayChanger underlying_changer; }; TEST_F(UnauthorizedDisplayChangerTest, change_attempt) { mtd::NullDisplayConfiguration conf; mf::UnauthorizedDisplayChanger changer(mt::fake_shared(underlying_changer)); EXPECT_THROW({ changer.configure(std::shared_ptr(), mt::fake_shared(conf)); }, std::runtime_error); } TEST_F(UnauthorizedDisplayChangerTest, access_config) { using namespace testing; mtd::NullDisplayConfiguration conf; EXPECT_CALL(underlying_changer, active_configuration()) .Times(1) .WillOnce(Return(mt::fake_shared(conf))); mf::UnauthorizedDisplayChanger changer(mt::fake_shared(underlying_changer)); auto returned_conf = changer.active_configuration(); EXPECT_EQ(&conf, returned_conf.get()); } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_client_buffer_tracker.cpp0000644000015301777760000000574612322054223030075 0ustar pbusernogroup00000000000000/* * 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: Christopher James Halse Rogers */ #include "../../src/server/frontend/client_buffer_tracker.h" #include "mir/graphics/buffer_id.h" #include namespace mf = mir::frontend; namespace mg = mir::graphics; TEST(ClientBufferTracker, just_added_buffer_is_known_by_client) { mf::ClientBufferTracker tracker(3); mg::BufferID const id{5}; tracker.add(id); EXPECT_TRUE(tracker.client_has(id)); } TEST(ClientBufferTracker, unadded_buffer_is_unknown_by_client) { mf::ClientBufferTracker tracker(3); tracker.add(mg::BufferID{5}); EXPECT_FALSE(tracker.client_has(mg::BufferID{6})); } TEST(ClientBufferTracker, tracks_sequence_of_buffers) { mf::ClientBufferTracker tracker(3); mg::BufferID const one{1}; mg::BufferID const two{2}; mg::BufferID const three{3}; mg::BufferID const four{4}; tracker.add(one); tracker.add(two); tracker.add(three); EXPECT_TRUE(tracker.client_has(one)); EXPECT_TRUE(tracker.client_has(two)); EXPECT_TRUE(tracker.client_has(three)); EXPECT_FALSE(tracker.client_has(four)); } TEST(ClientBufferTracker, old_buffers_expire_from_tracker) { mf::ClientBufferTracker tracker(3); mg::BufferID const one{1}; mg::BufferID const two{2}; mg::BufferID const three{3}; mg::BufferID const four{4}; tracker.add(one); tracker.add(two); tracker.add(three); ASSERT_TRUE(tracker.client_has(one)); ASSERT_TRUE(tracker.client_has(two)); ASSERT_TRUE(tracker.client_has(three)); tracker.add(two); tracker.add(three); tracker.add(four); EXPECT_FALSE(tracker.client_has(one)); EXPECT_TRUE(tracker.client_has(two)); EXPECT_TRUE(tracker.client_has(three)); EXPECT_TRUE(tracker.client_has(four)); } TEST(ClientBufferTracker, tracks_correct_number_of_buffers) { mg::BufferID ids[10]; for (unsigned int i = 0; i < 10; ++i) ids[i] = mg::BufferID{i}; for (unsigned int tracker_size = 2; tracker_size < 10; ++tracker_size) { mf::ClientBufferTracker tracker{tracker_size}; for (unsigned int i = 0; i < tracker_size; ++i) tracker.add(ids[i]); tracker.add(ids[tracker_size]); EXPECT_FALSE(tracker.client_has(ids[0])); for (unsigned int i = 1; i <= tracker_size; ++i) EXPECT_TRUE(tracker.client_has(ids[i])); } } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/stress_protobuf_communicator.cpp0000644000015301777760000002216612322054223030532 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/frontend/connector.h" #include "src/server/frontend/resource_cache.h" #include "mir_protobuf.pb.h" #include "mir_test_doubles/stub_ipc_factory.h" #include "mir_test/stub_server_tool.h" #include "mir_test/test_protobuf_server.h" #include "src/client/connection_surface_map.h" #include "src/client/display_configuration.h" #include "src/client/lifecycle_control.h" #include "src/client/rpc/null_rpc_report.h" #include "src/client/rpc/make_rpc_channel.h" #include "src/client/rpc/mir_basic_rpc_channel.h" #include #include #include #include #include #include #include namespace mf = mir::frontend; namespace mt = mir::test; namespace { struct StubProtobufClient { StubProtobufClient(std::string socket_file, int timeout_ms); std::shared_ptr rpc_report; std::shared_ptr channel; mir::protobuf::DisplayServer::Stub display_server; mir::protobuf::ConnectParameters connect_parameters; mir::protobuf::SurfaceParameters surface_parameters; mir::protobuf::Surface surface; mir::protobuf::Void ignored; mir::protobuf::Connection connection; void connect_done(); void create_surface_done(); void next_buffer_done(); void release_surface_done(); void disconnect_done(); void drm_auth_magic_done(); void wait_for_connect_done(); void wait_for_create_surface(); void wait_for_next_buffer(); void wait_for_release_surface(); void wait_for_disconnect_done(); void wait_for_drm_auth_magic_done(); void wait_for_surface_count(int count); void wait_for_disconnect_count(int count); void tfd_done(); void wait_for_tfd_done(); const int maxwait; std::atomic connect_done_called; std::atomic create_surface_called; std::atomic next_buffer_called; std::atomic release_surface_called; std::atomic disconnect_done_called; std::atomic drm_auth_magic_done_called; std::atomic tfd_done_called; std::atomic connect_done_count; std::atomic create_surface_done_count; std::atomic disconnect_done_count; }; } struct StressProtobufCommunicator : public ::testing::Test { static void SetUpTestCase() { stub_server_tool = std::make_shared(); stub_server = std::make_shared("./test_socket", stub_server_tool); stub_server->comm->start(); } void SetUp() { client = std::make_shared("./test_socket", 100); client->connect_parameters.set_application_name(__PRETTY_FUNCTION__); } void TearDown() { client.reset(); } static void TearDownTestCase() { stub_server.reset(); stub_server_tool.reset(); } std::shared_ptr client; static std::shared_ptr stub_server_tool; private: static std::shared_ptr stub_server; }; std::shared_ptr StressProtobufCommunicator::stub_server_tool; std::shared_ptr StressProtobufCommunicator::stub_server; TEST_F(StressProtobufCommunicator, DISABLED_stress_next_buffer) { client->display_server.create_surface( 0, &client->surface_parameters, &client->surface, google::protobuf::NewCallback(client.get(), &StubProtobufClient::create_surface_done)); client->wait_for_create_surface(); for (int i = 0; i != 100000; ++i) { client->display_server.next_buffer( 0, &client->surface.id(), client->surface.mutable_buffer(), google::protobuf::NewCallback(client.get(), &StubProtobufClient::next_buffer_done)); client->wait_for_next_buffer(); } client->display_server.disconnect( 0, &client->ignored, &client->ignored, google::protobuf::NewCallback(client.get(), &StubProtobufClient::disconnect_done)); client->wait_for_disconnect_done(); } StubProtobufClient::StubProtobufClient( std::string socket_file, int timeout_ms) : rpc_report(std::make_shared()), channel(mir::client::rpc::make_rpc_channel( socket_file, std::make_shared(), std::make_shared(), rpc_report, std::make_shared())), display_server(channel.get(), ::google::protobuf::Service::STUB_DOESNT_OWN_CHANNEL), maxwait(timeout_ms), connect_done_called(false), create_surface_called(false), next_buffer_called(false), release_surface_called(false), disconnect_done_called(false), tfd_done_called(false), connect_done_count(0), create_surface_done_count(0), disconnect_done_count(0) { surface_parameters.set_width(640); surface_parameters.set_height(480); surface_parameters.set_pixel_format(0); surface_parameters.set_buffer_usage(0); } void StubProtobufClient::connect_done() { connect_done_called.store(true); auto old = connect_done_count.load(); while (!connect_done_count.compare_exchange_weak(old, old+1)); } void StubProtobufClient::create_surface_done() { create_surface_called.store(true); auto old = create_surface_done_count.load(); while (!create_surface_done_count.compare_exchange_weak(old, old+1)); } void StubProtobufClient::next_buffer_done() { next_buffer_called.store(true); } void StubProtobufClient::release_surface_done() { release_surface_called.store(true); } void StubProtobufClient::disconnect_done() { disconnect_done_called.store(true); auto old = disconnect_done_count.load(); while (!disconnect_done_count.compare_exchange_weak(old, old+1)); } void StubProtobufClient::drm_auth_magic_done() { drm_auth_magic_done_called.store(true); } void StubProtobufClient::wait_for_connect_done() { for (int i = 0; !connect_done_called.load() && i < maxwait; ++i) { // TODO these sleeps and yields are silly (and in similar code around here) std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } connect_done_called.store(false); } void StubProtobufClient::wait_for_create_surface() { for (int i = 0; !create_surface_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } create_surface_called.store(false); } void StubProtobufClient::wait_for_next_buffer() { for (int i = 0; !next_buffer_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } next_buffer_called.store(false); } void StubProtobufClient::wait_for_release_surface() { for (int i = 0; !release_surface_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } release_surface_called.store(false); } void StubProtobufClient::wait_for_disconnect_done() { for (int i = 0; !disconnect_done_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } disconnect_done_called.store(false); } void StubProtobufClient::wait_for_drm_auth_magic_done() { for (int i = 0; !drm_auth_magic_done_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield(); } drm_auth_magic_done_called.store(false); } void StubProtobufClient::wait_for_surface_count(int count) { for (int i = 0; count != create_surface_done_count.load() && i < 10000; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::yield(); } } void StubProtobufClient::wait_for_disconnect_count(int count) { for (int i = 0; count != disconnect_done_count.load() && i < 10000; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::yield(); } } void StubProtobufClient::tfd_done() { tfd_done_called.store(true); } void StubProtobufClient::wait_for_tfd_done() { for (int i = 0; !tfd_done_called.load() && i < maxwait; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } tfd_done_called.store(false); } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_socket_session.cpp0000644000015301777760000001020612322054247026577 0ustar pbusernogroup00000000000000/* * 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 * Alan Griffiths */ #include "src/server/frontend/socket_session.h" #include "src/server/frontend/message_receiver.h" #include "mir/frontend/message_processor.h" #include "mir_test/fake_shared.h" #include "mir_protobuf_wire.pb.h" #include #include #include namespace mfd = mir::frontend::detail; namespace ba = boost::asio; namespace mt = mir::test; namespace { struct StubReceiver : public mfd::MessageReceiver { StubReceiver() : async_buffer{nullptr, 0} {} void async_receive_msg( std::function const& callback, boost::asio::mutable_buffers_1 const& buffer) override { async_buffer = buffer; callback_function = callback; } boost::system::error_code receive_msg(boost::asio::mutable_buffers_1 const& buffer) override { using namespace testing; if (ba::buffer_cast(buffer) == nullptr) throw std::runtime_error("StubReceiver::receive_msg got null buffer"); if (ba::buffer_size(buffer) != message.size()) throw std::runtime_error("StubReceiver::receive_msg buffer size not equal to message size"); memcpy(ba::buffer_cast(buffer), message.data(), ba::buffer_size(buffer)); return boost::system::error_code(); } size_t available_bytes() override { return message.size(); } void fake_receive_msg(char* buffer, size_t size) { using namespace testing; message.assign(buffer, buffer + size); ASSERT_NE(nullptr, callback_function); ASSERT_THAT(ba::buffer_cast(async_buffer), NotNull()); ASSERT_THAT(message.size(), Ge(ba::buffer_size(async_buffer))); memcpy(ba::buffer_cast(async_buffer), buffer, ba::buffer_size(async_buffer)); message.erase( message.begin(), message.begin() + ba::buffer_size(async_buffer)); boost::system::error_code code; callback_function(code, size); } private: std::function callback_function; boost::asio::mutable_buffers_1 async_buffer; std::vector message; MOCK_METHOD0(client_pid, pid_t()); }; struct MockProcessor : public mfd::MessageProcessor { MOCK_METHOD1(dispatch, bool(mfd::Invocation const& invocation)); }; } struct SocketSessionTest : public ::testing::Test { testing::NiceMock mock_processor; StubReceiver stub_receiver; }; TEST_F(SocketSessionTest, basic_msg_is_received_and_dispatched) { int const header_size = 2; char buffer[512]; mir::protobuf::wire::Invocation invocation; invocation.set_id(1); invocation.set_method_name(""); invocation.set_parameters(buffer, 0); invocation.set_protocol_version(1); auto const body_size = invocation.ByteSize(); using namespace testing; std::shared_ptr> null_sessions; mfd::SocketSession session(mt::fake_shared(stub_receiver), 0, null_sessions, mt::fake_shared(mock_processor)); EXPECT_CALL(mock_processor, dispatch(_)).Times(1).WillOnce(Return(true)); session.read_next_message(); buffer[0] = body_size / 0x100; buffer[1] = body_size % 0x100; invocation.SerializeToArray(buffer + header_size, sizeof buffer - header_size); stub_receiver.fake_receive_msg(buffer, header_size + body_size); } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_published_socket_connector.cpp0000644000015301777760000003372512322054223031152 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/frontend/connector.h" #include "src/server/report/null_report_factory.h" #include "src/server/frontend/resource_cache.h" #include "src/server/frontend/published_socket_connector.h" #include "mir/frontend/protobuf_session_creator.h" #include "mir/frontend/connector_report.h" #include "mir_protobuf.pb.h" #include "mir_test_doubles/stub_ipc_factory.h" #include "mir_test_doubles/stub_session_authorizer.h" #include "mir_test_doubles/mock_rpc_report.h" #include "mir_test/stub_server_tool.h" #include "mir_test/test_protobuf_client.h" #include "mir_test/test_protobuf_server.h" #include "mir_test_doubles/stub_ipc_factory.h" #include #include #include #include #include namespace mf = mir::frontend; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace mr = mir::report; namespace { const int timeout_ms = 60 * 1000; class MockConnectorReport : public mf::ConnectorReport { public: MockConnectorReport() { using namespace testing; EXPECT_CALL(*this, thread_start()).Times(AnyNumber()); EXPECT_CALL(*this, thread_end()).Times(AnyNumber()); EXPECT_CALL(*this, starting_threads(_)).Times(AnyNumber()); EXPECT_CALL(*this, stopping_threads(_)).Times(AnyNumber()); EXPECT_CALL(*this, creating_session_for(_)).Times(AnyNumber()); EXPECT_CALL(*this, creating_socket_pair(_, _)).Times(AnyNumber()); EXPECT_CALL(*this, listening_on(_)).Times(AnyNumber()); EXPECT_CALL(*this, error(_)).Times(AnyNumber()); } ~MockConnectorReport() noexcept {} MOCK_METHOD0(thread_start, void ()); MOCK_METHOD0(thread_end, void()); MOCK_METHOD1(starting_threads, void (int count)); MOCK_METHOD1(stopping_threads, void(int count)); MOCK_METHOD1(creating_session_for, void(int socket_handle)); MOCK_METHOD2(creating_socket_pair, void(int server_handle, int client_handle)); MOCK_METHOD1(listening_on, void(std::string const& endpoint)); MOCK_METHOD1(error, void (std::exception const& error)); }; } struct PublishedSocketConnector : public ::testing::Test { static const char* const test_socket; static void SetUpTestCase() { remove(test_socket); } void SetUp() { communicator_report = std::make_shared(); stub_server_tool = std::make_shared(); stub_server = std::make_shared( test_socket, stub_server_tool, communicator_report); stub_server->comm->start(); client = std::make_shared(test_socket, timeout_ms); client->connect_parameters.set_application_name(__PRETTY_FUNCTION__); } void TearDown() { client.reset(); stub_server->comm->stop(); stub_server.reset(); stub_server_tool.reset(); communicator_report.reset(); } static void TearDownTestCase() { } std::shared_ptr client; static std::shared_ptr communicator_report; static std::shared_ptr stub_server_tool; static std::shared_ptr stub_server; }; const char* const PublishedSocketConnector::test_socket = "./test_socket"; std::shared_ptr PublishedSocketConnector::stub_server_tool; std::shared_ptr PublishedSocketConnector::communicator_report; std::shared_ptr PublishedSocketConnector::stub_server; TEST_F(PublishedSocketConnector, create_surface_results_in_a_callback) { EXPECT_CALL(*client, create_surface_done()).Times(1); client->display_server.create_surface( 0, &client->surface_parameters, &client->surface, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); client->wait_for_create_surface(); } TEST_F(PublishedSocketConnector, connection_sets_app_name) { EXPECT_CALL(*client, connect_done()).Times(1); client->connect_parameters.set_application_name(__PRETTY_FUNCTION__); client->display_server.connect( 0, &client->connect_parameters, &client->connection, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::connect_done)); client->wait_for_connect_done(); EXPECT_EQ(__PRETTY_FUNCTION__, stub_server_tool->app_name); } TEST_F(PublishedSocketConnector, create_surface_sets_surface_name) { EXPECT_CALL(*client, connect_done()).Times(1); EXPECT_CALL(*client, create_surface_done()).Times(1); client->connect_parameters.set_application_name(__PRETTY_FUNCTION__); client->display_server.connect( 0, &client->connect_parameters, &client->connection, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::connect_done)); client->wait_for_connect_done(); client->surface_parameters.set_surface_name(__PRETTY_FUNCTION__); client->display_server.create_surface( 0, &client->surface_parameters, &client->surface, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); client->wait_for_create_surface(); EXPECT_EQ(__PRETTY_FUNCTION__, stub_server_tool->surface_name); } TEST_F(PublishedSocketConnector, create_surface_results_in_a_surface_being_created) { EXPECT_CALL(*client, create_surface_done()).Times(1); client->display_server.create_surface( 0, &client->surface_parameters, &client->surface, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); client->wait_for_create_surface(); } namespace { MATCHER_P(InvocationMethodEq, name, "") { return arg.method_name() == name; } } TEST_F(PublishedSocketConnector, double_disconnection_does_not_break) { using namespace testing; EXPECT_CALL(*client, create_surface_done()).Times(1); client->display_server.create_surface( 0, &client->surface_parameters, &client->surface, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); client->wait_for_create_surface(); EXPECT_CALL(*client, disconnect_done()).Times(1); client->display_server.disconnect( 0, &client->ignored, &client->ignored, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::disconnect_done)); client->wait_for_disconnect_done(); Mock::VerifyAndClearExpectations(client.get()); // There is a race between the server closing the socket and // the client sending the second "disconnect". // Usually[*] the server wins and the "disconnect" fails resulting // in an invocation_failed() report and an exception. // Occasionally, the client wins and the message is sent to dying socket. // [*] ON my desktop under valgrind "Usually" is ~49 times out of 50 EXPECT_CALL(*client->rpc_report, invocation_failed(InvocationMethodEq("disconnect"),_)).Times(AtMost(1)); EXPECT_CALL(*client, disconnect_done()).Times(1); try { client->display_server.disconnect( 0, &client->ignored, &client->ignored, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::disconnect_done)); // the write beat the socket closing } catch (std::runtime_error const& x) { // the socket closing beat the write EXPECT_THAT(x.what(), HasSubstr("Failed to send message to server:")); } client->wait_for_disconnect_done(); } TEST_F(PublishedSocketConnector, getting_and_advancing_buffers) { EXPECT_CALL(*client, create_surface_done()).Times(testing::AtLeast(0)); EXPECT_CALL(*client, disconnect_done()).Times(testing::AtLeast(0)); client->display_server.create_surface( 0, &client->surface_parameters, &client->surface, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); client->wait_for_create_surface(); EXPECT_TRUE(client->surface.has_buffer()); EXPECT_CALL(*client, next_buffer_done()).Times(8); for (int i = 0; i != 8; ++i) { client->display_server.next_buffer( 0, &client->surface.id(), client->surface.mutable_buffer(), google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::next_buffer_done)); client->wait_for_next_buffer(); EXPECT_TRUE(client->surface.has_buffer()); } client->display_server.disconnect( 0, &client->ignored, &client->ignored, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::disconnect_done)); client->wait_for_disconnect_done(); } TEST_F(PublishedSocketConnector, connect_create_surface_then_disconnect_a_session) { EXPECT_CALL(*client, create_surface_done()).Times(1); client->display_server.create_surface( 0, &client->surface_parameters, &client->surface, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); client->wait_for_create_surface(); EXPECT_CALL(*client, disconnect_done()).Times(1); client->display_server.disconnect( 0, &client->ignored, &client->ignored, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::disconnect_done)); client->wait_for_disconnect_done(); } TEST_F(PublishedSocketConnector, drm_auth_magic_is_processed_by_the_server) { mir::protobuf::DRMMagic magic; mir::protobuf::DRMAuthMagicStatus status; magic.set_magic(0x10111213); EXPECT_CALL(*client, drm_auth_magic_done()).Times(1); client->display_server.drm_auth_magic( 0, &magic, &status, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::drm_auth_magic_done)); client->wait_for_drm_auth_magic_done(); EXPECT_EQ(magic.magic(), stub_server_tool->drm_magic); } namespace { class MockForceRequests { public: MOCK_METHOD0(force_requests_to_complete, void()); }; } TEST_F(PublishedSocketConnector, disorderly_disconnection_handled) { using namespace testing; EXPECT_CALL(*client, create_surface_done()).Times(AnyNumber()); client->display_server.create_surface( 0, &client->surface_parameters, &client->surface, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); client->wait_for_create_surface(); std::mutex m; std::condition_variable cv; bool done = false; ON_CALL(*communicator_report, error(_)).WillByDefault(Invoke([&] (std::exception const&) { std::unique_lock lock(m); done = true; cv.notify_all(); })); EXPECT_CALL(*communicator_report, error(_)).Times(1); client.reset(); std::unique_lock lock(m); auto const deadline = std::chrono::steady_clock::now() + std::chrono::seconds(1); while (!done && cv.wait_until(lock, deadline) != std::cv_status::timeout); } TEST_F(PublishedSocketConnector, configure_display) { EXPECT_CALL(*client, display_configure_done()) .Times(1); client->display_server.configure_display( 0, &client->disp_config, &client->disp_config_response, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::display_configure_done)); client->wait_for_configure_display_done(); } TEST_F(PublishedSocketConnector, connection_using_socket_fd) { int const next_buffer_calls{8}; char buffer[128] = {0}; sprintf(buffer, "fd://%d", stub_server->comm->client_socket_fd()); auto client = std::make_shared(buffer, timeout_ms); client->connect_parameters.set_application_name(__PRETTY_FUNCTION__); EXPECT_CALL(*client, connect_done()).Times(1); client->display_server.connect( 0, &client->connect_parameters, &client->connection, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::connect_done)); EXPECT_CALL(*client, create_surface_done()).Times(testing::AtLeast(0)); EXPECT_CALL(*client, disconnect_done()).Times(testing::AtLeast(0)); client->display_server.create_surface( 0, &client->surface_parameters, &client->surface, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); client->wait_for_create_surface(); EXPECT_TRUE(client->surface.has_buffer()); EXPECT_CALL(*client, next_buffer_done()).Times(next_buffer_calls); for (int i = 0; i != next_buffer_calls; ++i) { client->display_server.next_buffer( 0, &client->surface.id(), client->surface.mutable_buffer(), google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::next_buffer_done)); client->wait_for_next_buffer(); EXPECT_TRUE(client->surface.has_buffer()); } client->display_server.disconnect( 0, &client->ignored, &client->ignored, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::disconnect_done)); client->wait_for_disconnect_done(); EXPECT_EQ(__PRETTY_FUNCTION__, stub_server_tool->app_name); } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_protobuf_reports_errors.cpp0000644000015301777760000001002712322054223030551 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/frontend/connector.h" #include "src/server/frontend/resource_cache.h" #include "mir_test/stub_server_tool.h" #include "mir_test/test_protobuf_server.h" #include "mir_test_doubles/stub_ipc_factory.h" #include "mir_test/test_protobuf_client.h" namespace mt = mir::test; namespace mir { namespace test { struct ErrorServer : StubServerTool { static std::string const test_exception_text; void create_surface( google::protobuf::RpcController*, const protobuf::SurfaceParameters*, protobuf::Surface*, google::protobuf::Closure*) { throw std::runtime_error(test_exception_text); } void release_surface( google::protobuf::RpcController*, const protobuf::SurfaceId*, protobuf::Void*, google::protobuf::Closure*) { throw std::runtime_error(test_exception_text); } void connect( ::google::protobuf::RpcController*, const ::mir::protobuf::ConnectParameters*, ::mir::protobuf::Connection*, ::google::protobuf::Closure*) { throw std::runtime_error(test_exception_text); } void disconnect( google::protobuf::RpcController*, const protobuf::Void*, protobuf::Void*, google::protobuf::Closure*) { throw std::runtime_error(test_exception_text); } void test_file_descriptors( google::protobuf::RpcController*, const protobuf::Void*, protobuf::Buffer*, google::protobuf::Closure*) { throw std::runtime_error(test_exception_text); } }; std::string const ErrorServer::test_exception_text{"test exception text"}; } } struct ProtobufErrorTestFixture : public ::testing::Test { void SetUp() { stub_services = std::make_shared(); server = std::make_shared("./test_error_fixture", stub_services); client = std::make_shared("./test_error_fixture", 100); server->comm->start(); } void TearDown() { server.reset(); } std::shared_ptr stub_services; std::shared_ptr server; std::shared_ptr client; }; TEST_F(ProtobufErrorTestFixture, connect_exception) { client->connect_parameters.set_application_name(__PRETTY_FUNCTION__); EXPECT_CALL(*client, connect_done()).Times(1); mir::protobuf::Connection result; client->display_server.connect( 0, &client->connect_parameters, &result, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::connect_done)); client->wait_for_connect_done(); ASSERT_TRUE(result.has_error()); EXPECT_NE(std::string::npos, result.error().find(stub_services->test_exception_text)); } TEST_F(ProtobufErrorTestFixture, create_surface_exception) { EXPECT_CALL(*client, create_surface_done()).Times(1); client->display_server.create_surface( 0, &client->surface_parameters, &client->surface, google::protobuf::NewCallback(client.get(), &mt::TestProtobufClient::create_surface_done)); client->wait_for_create_surface(); ASSERT_TRUE(client->surface.has_error()); EXPECT_NE(std::string::npos, client->surface.error().find(stub_services->test_exception_text)); } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_session_mediator.cpp0000644000015301777760000006074012322054247027123 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/compositor/buffer_stream.h" #include "src/server/frontend/session_mediator.h" #include "src/server/report/null_report_factory.h" #include "src/server/frontend/resource_cache.h" #include "src/server/scene/application_session.h" #include "mir/graphics/display.h" #include "mir/graphics/display_configuration.h" #include "mir/graphics/platform.h" #include "mir/graphics/platform_ipc_package.h" #include "src/server/scene/basic_surface.h" #include "mir_test_doubles/mock_display.h" #include "mir_test_doubles/mock_display_changer.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/null_event_sink.h" #include "mir_test_doubles/null_display_changer.h" #include "mir_test_doubles/mock_display.h" #include "mir_test_doubles/mock_shell.h" #include "mir_test_doubles/mock_frontend_surface.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/stub_session.h" #include "mir_test_doubles/stub_display_configuration.h" #include "mir_test_doubles/stub_buffer_allocator.h" #include "mir_test_doubles/null_screencast.h" #include "mir_test/display_config_matchers.h" #include "mir_test/fake_shared.h" #include "mir/frontend/event_sink.h" #include "mir/shell/surface.h" #include "gmock_set_arg.h" #include #include #include namespace mf = mir::frontend; namespace mg = mir::graphics; namespace mc = mir::compositor; namespace ms = mir::scene; namespace geom = mir::geometry; namespace mp = mir::protobuf; namespace msh = mir::shell; namespace mt = mir::test; namespace mtd = mt::doubles; namespace mr = mir::report; namespace { struct StubConfig : public mtd::NullDisplayConfiguration { StubConfig(std::shared_ptr const& conf) : outputs{conf, conf} { } virtual void for_each_output(std::function f) const override { for(auto const& disp : outputs) { f(*disp); } } std::vector> outputs; }; struct MockConfig : public mg::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)); }; } namespace { class StubbedSession : public mtd::StubSession { public: StubbedSession() : last_surface_id{1} { using namespace ::testing; mock_surface = std::make_shared(); mock_surfaces[mf::SurfaceId{1}] = mock_surface; mock_buffer = std::make_shared>(geom::Size(), geom::Stride(), MirPixelFormat()); EXPECT_CALL(*mock_surface, size()).Times(AnyNumber()).WillRepeatedly(Return(geom::Size())); EXPECT_CALL(*mock_surface, pixel_format()).Times(AnyNumber()).WillRepeatedly(Return(MirPixelFormat())); EXPECT_CALL(*mock_surface, swap_buffers(_, _)).Times(AnyNumber()) .WillRepeatedly(InvokeArgument<1>(mock_buffer.get())); EXPECT_CALL(*mock_surface, supports_input()).Times(AnyNumber()).WillRepeatedly(Return(true)); EXPECT_CALL(*mock_surface, client_input_fd()).Times(AnyNumber()).WillRepeatedly(Return(testing_client_input_fd)); } std::shared_ptr get_surface(mf::SurfaceId surface) const { return mock_surfaces.at(surface); } mf::SurfaceId create_surface(msh::SurfaceCreationParameters const& /* params */) override { using namespace ::testing; auto id = mf::SurfaceId{last_surface_id}; if (last_surface_id != 1) { mock_surfaces[id] = std::make_shared(); EXPECT_CALL(*mock_surfaces[id], size()).Times(AnyNumber()).WillRepeatedly(Return(geom::Size())); EXPECT_CALL(*mock_surfaces[id], pixel_format()).Times(AnyNumber()).WillRepeatedly(Return(MirPixelFormat())); EXPECT_CALL(*mock_surfaces[id], swap_buffers(_, _)).Times(AnyNumber()) .WillRepeatedly(InvokeArgument<1>(mock_buffer.get())); EXPECT_CALL(*mock_surfaces[id], supports_input()).Times(AnyNumber()).WillRepeatedly(Return(true)); EXPECT_CALL(*mock_surfaces[id], client_input_fd()).Times(AnyNumber()).WillRepeatedly(Return(testing_client_input_fd)); } last_surface_id++; return id; } void destroy_surface(mf::SurfaceId surface) override { mock_surfaces.erase(surface); } std::shared_ptr mock_surface; std::map> mock_surfaces; std::shared_ptr mock_buffer; static int const testing_client_input_fd; int last_surface_id; }; int const StubbedSession::testing_client_input_fd{11}; class MockGraphicBufferAllocator : public mtd::StubBufferAllocator { public: MockGraphicBufferAllocator() { ON_CALL(*this, supported_pixel_formats()) .WillByDefault(testing::Return(std::vector())); } MOCK_METHOD0(supported_pixel_formats, std::vector()); }; class MockPlatform : public mg::Platform { public: MockPlatform() { using namespace testing; ON_CALL(*this, create_buffer_allocator(_)) .WillByDefault(Return(std::shared_ptr())); ON_CALL(*this, create_display(_,_)) .WillByDefault(Return(std::make_shared())); ON_CALL(*this, get_ipc_package()) .WillByDefault(Return(std::make_shared())); } MOCK_METHOD1(create_buffer_allocator, std::shared_ptr(std::shared_ptr const&)); MOCK_METHOD2(create_display, std::shared_ptr( std::shared_ptr const&, std::shared_ptr const&)); MOCK_METHOD0(get_ipc_package, std::shared_ptr()); MOCK_METHOD0(create_internal_client, std::shared_ptr()); MOCK_CONST_METHOD2(fill_ipc_package, void(mg::BufferIPCPacker*, mg::Buffer const*)); MOCK_CONST_METHOD0(egl_native_display, EGLNativeDisplayType()); }; struct StubScreencast : mtd::NullScreencast { std::shared_ptr capture(mf::ScreencastSessionId) { return mt::fake_shared(stub_buffer); } mtd::StubBuffer stub_buffer; }; struct SessionMediatorTest : public ::testing::Test { SessionMediatorTest() : shell{std::make_shared>()}, graphics_platform{std::make_shared>()}, graphics_changer{std::make_shared()}, surface_pixel_formats{mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888}, report{mr::null_session_mediator_report()}, resource_cache{std::make_shared()}, stub_screencast{std::make_shared()}, mediator{__LINE__, shell, graphics_platform, graphics_changer, surface_pixel_formats, report, std::make_shared(), resource_cache, stub_screencast}, stubbed_session{std::make_shared()}, null_callback{google::protobuf::NewPermanentCallback(google::protobuf::DoNothing)} { using namespace ::testing; ON_CALL(*shell, open_session(_, _, _)).WillByDefault(Return(stubbed_session)); ON_CALL(*shell, create_surface_for(_, _)) .WillByDefault(WithArg<1>(Invoke(stubbed_session.get(), &StubbedSession::create_surface))); } std::shared_ptr> const shell; std::shared_ptr const graphics_platform; std::shared_ptr const graphics_changer; std::vector const surface_pixel_formats; std::shared_ptr const report; std::shared_ptr const resource_cache; std::shared_ptr const stub_screencast; mf::SessionMediator mediator; std::shared_ptr const stubbed_session; std::unique_ptr null_callback; }; } TEST_F(SessionMediatorTest, disconnect_releases_session) { using namespace ::testing; mp::ConnectParameters connect_parameters; mp::Connection connection; EXPECT_CALL(*shell, close_session(_)).Times(1); mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); mediator.disconnect(nullptr, nullptr, nullptr, null_callback.get()); } TEST_F(SessionMediatorTest, calling_methods_before_connect_throws) { EXPECT_THROW({ mp::SurfaceParameters request; mp::Surface response; mediator.create_surface(nullptr, &request, &response, null_callback.get()); }, std::logic_error); EXPECT_THROW({ mp::SurfaceId request; mp::Buffer response; mediator.next_buffer(nullptr, &request, &response, null_callback.get()); }, std::logic_error); EXPECT_THROW({ mp::SurfaceId request; mediator.release_surface(nullptr, &request, nullptr, null_callback.get()); }, std::logic_error); EXPECT_THROW({ mp::DRMMagic request; mp::DRMAuthMagicStatus response; mediator.drm_auth_magic(nullptr, &request, &response, null_callback.get()); }, std::logic_error); EXPECT_THROW({ mediator.disconnect(nullptr, nullptr, nullptr, null_callback.get()); }, std::logic_error); } TEST_F(SessionMediatorTest, calling_methods_after_connect_works) { mp::ConnectParameters connect_parameters; mp::Connection connection; mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); { mp::SurfaceParameters request; mp::Surface surface_response; mediator.create_surface(nullptr, &request, &surface_response, null_callback.get()); mp::SurfaceId surface = surface_response.id(); mp::Buffer buffer_response; mediator.next_buffer(nullptr, &surface, &buffer_response, null_callback.get()); mediator.release_surface(nullptr, &surface, nullptr, null_callback.get()); } mediator.disconnect(nullptr, nullptr, nullptr, null_callback.get()); } TEST_F(SessionMediatorTest, calling_methods_after_disconnect_throws) { mp::ConnectParameters connect_parameters; mp::Connection connection; mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); mediator.disconnect(nullptr, nullptr, nullptr, null_callback.get()); EXPECT_THROW({ mp::SurfaceParameters surface_parameters; mp::Surface surface; mediator.create_surface(nullptr, &surface_parameters, &surface, null_callback.get()); }, std::logic_error); EXPECT_THROW({ mp::SurfaceId request; mp::Buffer response; mediator.next_buffer(nullptr, &request, &response, null_callback.get()); }, std::logic_error); EXPECT_THROW({ mp::SurfaceId request; mediator.release_surface(nullptr, &request, nullptr, null_callback.get()); }, std::logic_error); EXPECT_THROW({ mp::DRMMagic request; mp::DRMAuthMagicStatus response; mediator.drm_auth_magic(nullptr, &request, &response, null_callback.get()); }, std::logic_error); EXPECT_THROW({ mediator.disconnect(nullptr, nullptr, nullptr, null_callback.get()); }, std::logic_error); } TEST_F(SessionMediatorTest, can_reconnect_after_disconnect) { mp::ConnectParameters connect_parameters; mp::Connection connection; mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); mediator.disconnect(nullptr, nullptr, nullptr, null_callback.get()); mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); } TEST_F(SessionMediatorTest, connect_packs_display_configuration) { using namespace testing; geom::Size sz{1022, 2411}; mtd::StubDisplayConfig config; auto mock_display = std::make_shared(); EXPECT_CALL(*mock_display, active_configuration()) .Times(1) .WillOnce(Return(mt::fake_shared(config))); mf::SessionMediator mediator( __LINE__, shell, graphics_platform, mock_display, surface_pixel_formats, report, std::make_shared(), resource_cache, std::make_shared()); mp::ConnectParameters connect_parameters; mp::Connection connection; connection.clear_platform(); connection.clear_display_info(); connection.clear_display_output(); connection.clear_display_configuration(); mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); EXPECT_THAT(connection.display_configuration(), mt::DisplayConfigMatches(std::cref(config))); } TEST_F(SessionMediatorTest, creating_surface_packs_response_with_input_fds) { mp::ConnectParameters connect_parameters; mp::Connection connection; mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); { mp::SurfaceParameters request; mp::Surface response; mediator.create_surface(nullptr, &request, &response, null_callback.get()); EXPECT_EQ(StubbedSession::testing_client_input_fd, response.fd(0)); } mediator.disconnect(nullptr, nullptr, nullptr, null_callback.get()); } TEST_F(SessionMediatorTest, no_input_channel_is_nonfatal) { mp::ConnectParameters connect_parameters; mp::Connection connection; EXPECT_CALL(*stubbed_session->mock_surface, supports_input()) .Times(1) .WillOnce(testing::Return(false)); EXPECT_CALL(*stubbed_session->mock_surface, client_input_fd()) .Times(0); mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); { mp::SurfaceParameters request; mp::Surface response; mediator.create_surface(nullptr, &request, &response, null_callback.get()); } mediator.disconnect(nullptr, nullptr, nullptr, null_callback.get()); } TEST_F(SessionMediatorTest, session_only_sends_needed_buffers) { using namespace testing; mp::ConnectParameters connect_parameters; mp::Connection connection; mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); { EXPECT_CALL(*stubbed_session->mock_buffer, id()) .WillOnce(Return(mg::BufferID{4})) .WillOnce(Return(mg::BufferID{4})) .WillOnce(Return(mg::BufferID{5})) .WillOnce(Return(mg::BufferID{5})) .WillOnce(Return(mg::BufferID{4})) .WillOnce(Return(mg::BufferID{4})) .WillOnce(Return(mg::BufferID{5})) .WillOnce(Return(mg::BufferID{5})); mp::Surface surface_response; mp::SurfaceId buffer_request; mp::Buffer buffer_response[3]; EXPECT_CALL(*graphics_platform, fill_ipc_package(_, stubbed_session->mock_buffer.get())) .Times(2); mp::SurfaceParameters surface_request; mediator.create_surface(nullptr, &surface_request, &surface_response, null_callback.get()); buffer_request = surface_response.id(); mediator.next_buffer(nullptr, &buffer_request, &buffer_response[0], null_callback.get()); mediator.next_buffer(nullptr, &buffer_request, &buffer_response[1], null_callback.get()); mediator.next_buffer(nullptr, &buffer_request, &buffer_response[2], null_callback.get()); } mediator.disconnect(nullptr, nullptr, nullptr, null_callback.get()); } TEST_F(SessionMediatorTest, session_with_multiple_surfaces_only_sends_needed_buffers) { using namespace testing; mp::ConnectParameters connect_parameters; mp::Connection connection; mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); { // AFAICS these values are stubs to set up the test condition, // the exact calls here are not a *requirement* on SessionMediator EXPECT_CALL(*stubbed_session->mock_buffer, id()) .WillOnce(Return(mg::BufferID{4})) .WillOnce(Return(mg::BufferID{4})) .WillOnce(Return(mg::BufferID{9})) .WillOnce(Return(mg::BufferID{9})) .WillOnce(Return(mg::BufferID{5})) .WillOnce(Return(mg::BufferID{5})) .WillOnce(Return(mg::BufferID{10})) .WillOnce(Return(mg::BufferID{10})) .WillOnce(Return(mg::BufferID{4})) .WillOnce(Return(mg::BufferID{4})) .WillOnce(Return(mg::BufferID{9})) .WillOnce(Return(mg::BufferID{9})) .WillOnce(Return(mg::BufferID{5})) .WillOnce(Return(mg::BufferID{5})) .WillOnce(Return(mg::BufferID{10})) .WillOnce(Return(mg::BufferID{10})); mp::Surface surface_response[2]; mp::SurfaceId buffer_request[2]; mp::Buffer buffer_response[6]; EXPECT_CALL(*graphics_platform, fill_ipc_package(_, stubbed_session->mock_buffer.get())) .Times(4); mp::SurfaceParameters surface_request; mediator.create_surface(nullptr, &surface_request, &surface_response[0], null_callback.get()); mediator.create_surface(nullptr, &surface_request, &surface_response[1], null_callback.get()); buffer_request[0] = surface_response[0].id(); buffer_request[1] = surface_response[1].id(); mediator.next_buffer(nullptr, &buffer_request[0], &buffer_response[0], null_callback.get()); mediator.next_buffer(nullptr, &buffer_request[1], &buffer_response[1], null_callback.get()); mediator.next_buffer(nullptr, &buffer_request[0], &buffer_response[2], null_callback.get()); mediator.next_buffer(nullptr, &buffer_request[1], &buffer_response[3], null_callback.get()); mediator.next_buffer(nullptr, &buffer_request[0], &buffer_response[4], null_callback.get()); mediator.next_buffer(nullptr, &buffer_request[1], &buffer_response[5], null_callback.get()); } mediator.disconnect(nullptr, nullptr, nullptr, null_callback.get()); } TEST_F(SessionMediatorTest, buffer_resource_for_surface_unaffected_by_other_surfaces) { using namespace testing; mtd::StubBuffer buffer; mp::ConnectParameters connect_parameters; mp::Connection connection; mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); mp::SurfaceParameters surface_request; mp::Surface surface_response; /* * Note that the surface created by the first create_surface() call is * the pre-created stubbed_session->mock_surface. Further create_surface() * invocations create new surfaces in stubbed_session->mock_surfaces[]. */ EXPECT_CALL(*stubbed_session->mock_surface, swap_buffers(_, _)) .WillOnce(InvokeArgument<1>(&buffer)); mediator.create_surface(nullptr, &surface_request, &surface_response, null_callback.get()); mp::SurfaceId our_surface{surface_response.id()}; Mock::VerifyAndClearExpectations(stubbed_session->mock_surface.get()); /* Creating a new surface should not affect our surfaces' buffers */ EXPECT_CALL(*stubbed_session->mock_surface, swap_buffers(_, _)).Times(0); mediator.create_surface(nullptr, &surface_request, &surface_response, null_callback.get()); mp::SurfaceId new_surface{surface_response.id()}; mp::Buffer buffer_response; /* Getting the next buffer of new surface should not affect our surfaces' buffers */ mediator.next_buffer(nullptr, &new_surface, &buffer_response, null_callback.get()); Mock::VerifyAndClearExpectations(stubbed_session->mock_surface.get()); /* Getting the next buffer of our surface should post the original */ EXPECT_CALL(*stubbed_session->mock_surface, swap_buffers(Eq(&buffer), _)).Times(1); mediator.next_buffer(nullptr, &our_surface, &buffer_response, null_callback.get()); mediator.disconnect(nullptr, nullptr, nullptr, null_callback.get()); } TEST_F(SessionMediatorTest, display_config_request) { using namespace testing; mp::ConnectParameters connect_parameters; mp::Connection connection; bool used0 = false, used1 = true; geom::Point pt0{44,22}, pt1{3,2}; size_t mode_index0 = 1, mode_index1 = 3; MirPixelFormat format0{mir_pixel_format_invalid}; MirPixelFormat format1{mir_pixel_format_argb_8888}; mg::DisplayConfigurationOutputId id0{6}, id1{3}; NiceMock mock_display_config; mtd::StubDisplayConfig stub_display_config; auto mock_display_selector = std::make_shared(); Sequence seq; EXPECT_CALL(*mock_display_selector, active_configuration()) .InSequence(seq) .WillOnce(Return(mt::fake_shared(mock_display_config))); EXPECT_CALL(*mock_display_selector, active_configuration()) .InSequence(seq) .WillOnce(Return(mt::fake_shared(mock_display_config))); EXPECT_CALL(*mock_display_selector, configure(_,_)) .InSequence(seq); EXPECT_CALL(*mock_display_selector, active_configuration()) .InSequence(seq) .WillOnce(Return(mt::fake_shared(stub_display_config))); mf::SessionMediator session_mediator{ __LINE__, shell, graphics_platform, mock_display_selector, surface_pixel_formats, report, std::make_shared(), resource_cache, std::make_shared()}; session_mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); mp::DisplayConfiguration configuration_response; mp::DisplayConfiguration configuration; auto disp0 = configuration.add_display_output(); disp0->set_output_id(id0.as_value()); disp0->set_used(used0); disp0->set_position_x(pt0.x.as_uint32_t()); disp0->set_position_y(pt0.y.as_uint32_t()); disp0->set_current_mode(mode_index0); disp0->set_current_format(format0); disp0->set_power_mode(static_cast(mir_power_mode_on)); disp0->set_orientation(mir_orientation_left); auto disp1 = configuration.add_display_output(); disp1->set_output_id(id1.as_value()); disp1->set_used(used1); disp1->set_position_x(pt1.x.as_uint32_t()); disp1->set_position_y(pt1.y.as_uint32_t()); disp1->set_current_mode(mode_index1); disp1->set_current_format(format1); disp1->set_power_mode(static_cast(mir_power_mode_off)); disp1->set_orientation(mir_orientation_inverted); session_mediator.configure_display(nullptr, &configuration, &configuration_response, null_callback.get()); EXPECT_THAT(configuration_response, mt::DisplayConfigMatches(std::cref(stub_display_config))); session_mediator.disconnect(nullptr, nullptr, nullptr, null_callback.get()); } TEST_F(SessionMediatorTest, fully_packs_buffer_for_create_screencast) { using namespace testing; mp::ScreencastParameters screencast_parameters; mp::Screencast screencast; auto const& stub_buffer = stub_screencast->stub_buffer; EXPECT_CALL(*graphics_platform, fill_ipc_package(_, &stub_buffer)); mediator.create_screencast(nullptr, &screencast_parameters, &screencast, null_callback.get()); EXPECT_EQ(stub_buffer.id().as_uint32_t(), screencast.buffer().buffer_id()); } TEST_F(SessionMediatorTest, partially_packs_buffer_for_screencast_buffer) { using namespace testing; mp::ScreencastId screencast_id; mp::Buffer protobuf_buffer; auto const& stub_buffer = stub_screencast->stub_buffer; EXPECT_CALL(*graphics_platform, fill_ipc_package(_, &stub_buffer)) .Times(0); mediator.screencast_buffer(nullptr, &screencast_id, &protobuf_buffer, null_callback.get()); EXPECT_EQ(stub_buffer.id().as_uint32_t(), protobuf_buffer.buffer_id()); } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_resource_cache.cpp0000644000015301777760000000433012322054223026511 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/frontend/resource_cache.h" #include #include #include #include namespace mir { namespace { struct TestResource { TestResource() { int count = instances.load(); while (!instances.compare_exchange_weak(count, count + 1)) std::this_thread::yield(); } ~TestResource() { int count = instances.load(); while (!instances.compare_exchange_weak(count, count - 1)) std::this_thread::yield(); } TestResource(TestResource const&) = delete; TestResource& operator=(TestResource const&) = delete; static std::atomic instances; }; std::atomic TestResource::instances; } } using mir::TestResource; namespace { struct ResourceCache : ::testing::Test { mir::frontend::ResourceCache cache; }; } TEST_F(ResourceCache, resources_are_saved) { int const a_few = 13; mir::protobuf::Void keys[a_few]; for (auto p = keys+0; p != keys+a_few; ++p) { auto sp = std::make_shared(); cache.save_resource(p, sp); } EXPECT_EQ(a_few, TestResource::instances.load()); } TEST_F(ResourceCache, resources_are_freed) { int const a_few = 13; mir::protobuf::Void keys[a_few]; for (auto p = keys+0; p != keys+a_few; ++p) { auto sp = std::make_shared(); cache.save_resource(p, sp); } for (auto p = keys+0; p != keys+a_few; ++p) { cache.free_resource(p); } EXPECT_EQ(0, TestResource::instances.load()); } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/CMakeLists.txt0000644000015301777760000000313612322054223024537 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_client_buffer_tracker.cpp ${CMAKE_CURRENT_SOURCE_DIR}/stress_protobuf_communicator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_published_socket_connector.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_protobuf_surface_apis.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_protobuf_reports_errors.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_protobuf_buffer_packer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_resource_cache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_session_mediator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_socket_session.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_event_sender.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_unauthorized_display_changer.cpp ) # TODO this test is a mess - something better is needed. # - it doesn't pass FDs between processes # - it doesn't test that the received FD can be used # - the code it tests [test_file_descriptors()] isn't part of the system proper # - it touches the filesystem # Really, it tests for a side-effect of passing an FD over a socket using libancillary. # So, we should write an integration level test that passes FDs between # processes and get rid of this test and test_file_descriptors() list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_protobuf_sends_fds.cpp ) if (MIR_TEST_PLATFORM STREQUAL "android") list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_session_mediator_android.cpp ) elseif (MIR_TEST_PLATFORM STREQUAL "mesa") list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_session_mediator_mesa.cpp ) endif() set( UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_session_mediator_android.cpp0000644000015301777760000000663412322054223030617 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/frontend/session_mediator_report.h" #include "src/server/frontend/session_mediator.h" #include "src/server/frontend/resource_cache.h" #include "src/server/scene/application_session.h" #include "src/server/report/null_report_factory.h" #include "mir/frontend/shell.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/graphics/display.h" #include "mir/graphics/platform.h" #include "mir/graphics/platform_ipc_package.h" #include "mir_test_doubles/null_display_changer.h" #include "mir_test_doubles/mock_session.h" #include "mir_test_doubles/stub_shell.h" #include "mir_test_doubles/null_platform.h" #include "mir_test_doubles/null_event_sink.h" #include "mir_test_doubles/stub_buffer_allocator.h" #include "mir_test_doubles/null_screencast.h" #include #include namespace mf = mir::frontend; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace mp = mir::protobuf; namespace msh = mir::shell; namespace mtd = mir::test::doubles; namespace mr = mir::report; namespace { struct SessionMediatorAndroidTest : public ::testing::Test { SessionMediatorAndroidTest() : shell{std::make_shared()}, graphics_platform{std::make_shared()}, display_changer{std::make_shared()}, surface_pixel_formats{mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888}, report{mr::null_session_mediator_report()}, resource_cache{std::make_shared()}, mediator{__LINE__, shell, graphics_platform, display_changer, surface_pixel_formats, report, std::make_shared(), resource_cache, std::make_shared()}, null_callback{google::protobuf::NewPermanentCallback(google::protobuf::DoNothing)} { } std::shared_ptr const shell; std::shared_ptr const graphics_platform; std::shared_ptr const display_changer; std::vector const surface_pixel_formats; std::shared_ptr const report; std::shared_ptr const resource_cache; mf::SessionMediator mediator; std::unique_ptr null_callback; }; } TEST_F(SessionMediatorAndroidTest, drm_auth_magic_throws) { mp::ConnectParameters connect_parameters; mp::Connection connection; mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); mp::DRMMagic magic; magic.set_magic(0x10111213); EXPECT_THROW({ mediator.drm_auth_magic(nullptr, &magic, nullptr, null_callback.get()); }, std::logic_error); } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_event_sender.cpp0000644000015301777760000000565612322054247026242 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/frontend/message_sender.h" #include "src/server/frontend/event_sender.h" #include "mir_test_doubles/stub_display_configuration.h" #include "mir_test/display_config_matchers.h" #include "mir_test/fake_shared.h" #include "mir_protobuf.pb.h" #include "mir_protobuf_wire.pb.h" #include #include namespace mt=mir::test; namespace mtd=mir::test::doubles; namespace mf=mir::frontend; namespace mfd=mf::detail; namespace geom=mir::geometry; namespace { struct MockMsgSender : public mfd::MessageSender { MOCK_METHOD3(send, void(char const*, size_t, mfd::FdSets const&)); }; } TEST(TestEventSender, display_send) { using namespace testing; mtd::StubDisplayConfig config; MockMsgSender mock_msg_sender; auto msg_validator = [&config](char const* data, size_t len){ mir::protobuf::wire::Result wire; wire.ParseFromArray(data, len); std::string str = wire.events(0); mir::protobuf::EventSequence seq; seq.ParseFromString(str); EXPECT_THAT(seq.display_configuration(), mt::DisplayConfigMatches(std::cref(config))); }; EXPECT_CALL(mock_msg_sender, send(_, _, _)) .Times(1) .WillOnce(WithArgs<0,1>(Invoke(msg_validator))); mfd::EventSender sender(mt::fake_shared(mock_msg_sender)); sender.handle_display_config_change(config); } TEST(TestEventSender, sends_noninput_events) { using namespace testing; auto msg_sender = std::make_shared(); mfd::EventSender event_sender(msg_sender); MirEvent event; memset(&event, 0, sizeof event); EXPECT_CALL(*msg_sender, send(_, _, _)) .Times(2); event.type = mir_event_type_surface; event_sender.handle_event(event); event.type = mir_event_type_resize; event_sender.handle_event(event); } TEST(TestEventSender, never_sends_input_events) { using namespace testing; auto msg_sender = std::make_shared(); mfd::EventSender event_sender(msg_sender); MirEvent event; memset(&event, 0, sizeof event); EXPECT_CALL(*msg_sender, send(_, _, _)) .Times(0); event.type = mir_event_type_key; event_sender.handle_event(event); event.type = mir_event_type_motion; event_sender.handle_event(event); } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_session_mediator_mesa.cpp0000644000015301777760000001146012322054223030115 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/frontend/session_mediator_report.h" #include "src/server/frontend/session_mediator.h" #include "src/server/frontend/resource_cache.h" #include "src/server/scene/application_session.h" #include "src/server/frontend/session_mediator.h" #include "src/server/report/null_report_factory.h" #include "mir/frontend/shell.h" #include "mir/graphics/display.h" #include "mir/graphics/drm_authenticator.h" #include "mir/frontend/event_sink.h" #include #include #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/null_event_sink.h" #include "mir_test_doubles/null_display_changer.h" #include "mir_test_doubles/null_platform.h" #include "mir_test_doubles/mock_session.h" #include "mir_test_doubles/stub_shell.h" #include "mir_test_doubles/null_screencast.h" #include #include namespace mf = mir::frontend; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace mp = mir::protobuf; namespace msh = mir::shell; namespace mtd = mir::test::doubles; namespace mr = mir::report; namespace { class MockAuthenticatingPlatform : public mtd::NullPlatform, public mg::DRMAuthenticator { public: std::shared_ptr create_buffer_allocator( const std::shared_ptr& /*buffer_initializer*/) override { return std::shared_ptr(); } MOCK_METHOD1(drm_auth_magic, void(unsigned int)); }; struct SessionMediatorMesaTest : public ::testing::Test { SessionMediatorMesaTest() : shell{std::make_shared()}, mock_platform{std::make_shared()}, display_changer{std::make_shared()}, surface_pixel_formats{mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888}, report{mr::null_session_mediator_report()}, resource_cache{std::make_shared()}, mediator{__LINE__, shell, mock_platform, display_changer, surface_pixel_formats, report, std::make_shared(), resource_cache, std::make_shared()}, null_callback{google::protobuf::NewPermanentCallback(google::protobuf::DoNothing)} { } std::shared_ptr const shell; std::shared_ptr const mock_platform; std::shared_ptr const display_changer; std::vector const surface_pixel_formats; std::shared_ptr const report; std::shared_ptr const resource_cache; mf::SessionMediator mediator; std::unique_ptr null_callback; }; } TEST_F(SessionMediatorMesaTest, drm_auth_magic_uses_drm_authenticator) { mp::ConnectParameters connect_parameters; mp::Connection connection; unsigned int const drm_magic{0x10111213}; int const no_error{0}; EXPECT_CALL(*mock_platform, drm_auth_magic(drm_magic)) .Times(1); mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); mp::DRMMagic magic; mp::DRMAuthMagicStatus status; magic.set_magic(drm_magic); mediator.drm_auth_magic(nullptr, &magic, &status, null_callback.get()); EXPECT_EQ(no_error, status.status_code()); } TEST_F(SessionMediatorMesaTest, drm_auth_magic_sets_status_code_on_error) { using namespace testing; mp::ConnectParameters connect_parameters; mp::Connection connection; unsigned int const drm_magic{0x10111213}; int const error_number{667}; EXPECT_CALL(*mock_platform, drm_auth_magic(drm_magic)) .WillOnce(Throw(::boost::enable_error_info(std::exception()) << boost::errinfo_errno(error_number))); mediator.connect(nullptr, &connect_parameters, &connection, null_callback.get()); mp::DRMMagic magic; mp::DRMAuthMagicStatus status; magic.set_magic(drm_magic); mediator.drm_auth_magic(nullptr, &magic, &status, null_callback.get()); EXPECT_EQ(error_number, status.status_code()); } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_protobuf_buffer_packer.cpp0000644000015301777760000000340112322054223030253 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/frontend/protobuf_buffer_packer.h" #include "mir_protobuf.pb.h" #include namespace mfd=mir::frontend::detail; namespace mp=mir::protobuf; namespace geom=mir::geometry; TEST(ProtobufBufferPacker, packing) { geom::Stride dummy_stride(4); mp::Buffer response; mfd::ProtobufBufferPacker packer(&response); int num_fd = 33, num_int = 44; for(auto i=0; i < num_fd; i++) packer.pack_fd(i); for(auto i=0; i < num_int; i++) packer.pack_data(i); packer.pack_stride(dummy_stride); packer.pack_flags(123); packer.pack_size(geom::Size{456, 789}); EXPECT_EQ(num_fd, response.fd_size()); EXPECT_EQ(num_int, response.data_size()); for (int i = 0; i < response.fd_size(); ++i) EXPECT_EQ(i, response.fd(i)); for (int i = 0; i < response.data_size(); ++i) EXPECT_EQ(i, response.data(i)); EXPECT_EQ(dummy_stride.as_uint32_t(), static_cast(response.stride())); EXPECT_EQ(123U, response.flags()); EXPECT_EQ(456, response.width()); EXPECT_EQ(789, response.height()); } mir-0.1.8+14.04.20140411/tests/unit-tests/frontend/test_protobuf_sends_fds.cpp0000644000015301777760000000750312322054223027434 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/frontend/connector.h" #include "src/server/frontend/resource_cache.h" #include "mir_protobuf.pb.h" #include "mir_test_doubles/stub_ipc_factory.h" #include "mir_test/stub_server_tool.h" #include "mir_test/test_protobuf_client.h" #include "mir_test/test_protobuf_server.h" #include #include #include #include #include #include namespace mf = mir::frontend; namespace mt = mir::test; namespace mir { namespace test { struct StubServerFd : public StubServerTool { static const int file_descriptors = 5; int file_descriptor[file_descriptors]; StubServerFd() { for (auto i = file_descriptor; i != file_descriptor+file_descriptors; ++i) *i = 0; } void test_file_descriptors(::google::protobuf::RpcController* , const ::mir::protobuf::Void* , ::mir::protobuf::Buffer* buffer, ::google::protobuf::Closure* done) { for (int i = 0; i != file_descriptors; ++i) { static char const test_file_fmt[] = "fd_test_file%d"; char test_file[sizeof test_file_fmt]; sprintf(test_file, test_file_fmt, i); remove(test_file); file_descriptor[i] = open(test_file, O_CREAT, S_IWUSR|S_IRUSR); buffer->add_fd(file_descriptor[i]); } done->Run(); } void close_files() { for (auto i = file_descriptor; i != file_descriptor+file_descriptors; ++i) close(*i), *i = 0; } }; const int StubServerFd::file_descriptors; } struct ProtobufSocketCommunicatorFD : public ::testing::Test { void SetUp() { stub_server_tool = std::make_shared(); stub_server = std::make_shared("./test_socket", stub_server_tool); stub_server->comm->start(); stub_client = std::make_shared("./test_socket", 500); stub_client->connect_parameters.set_application_name(__PRETTY_FUNCTION__); } void TearDown() { stub_server.reset(); } std::shared_ptr stub_client; std::shared_ptr stub_server_tool; private: std::shared_ptr stub_server; }; TEST_F(ProtobufSocketCommunicatorFD, test_file_descriptors) { mir::protobuf::Buffer fds; stub_client->display_server.test_file_descriptors(0, &stub_client->ignored, &fds, google::protobuf::NewCallback(stub_client.get(), &mt::TestProtobufClient::tfd_done)); stub_client->wait_for_tfd_done(); ASSERT_EQ(stub_server_tool->file_descriptors, fds.fd_size()); for (int i = 0; i != stub_server_tool->file_descriptors; ++i) { int const fd = fds.fd(i); EXPECT_NE(-1, fd); for (int j = 0; j != stub_server_tool->file_descriptors; ++j) { EXPECT_NE(stub_server_tool->file_descriptor[j], fd); } } stub_server_tool->close_files(); for (int i = 0; i != stub_server_tool->file_descriptors; ++i) close(fds.fd(i)); } } mir-0.1.8+14.04.20140411/tests/unit-tests/logging/0000755000015301777760000000000012322054703021606 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/logging/message_processor_report.cpp0000644000015301777760000001232512322054223027430 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/report/logging/message_processor_report.h" #include "mir/logging/logger.h" #include "mir_test/fake_shared.h" #include #include using namespace testing; namespace { class MockClock : public mir::time::Clock { public: MOCK_CONST_METHOD0(sample, mir::time::Timestamp()); ~MockClock() noexcept(true) {} }; class MockLogger : public mir::logging::Logger { public: MOCK_METHOD3(log, void(Severity severity, const std::string& message, const std::string& component)); ~MockLogger() noexcept(true) {} }; struct MessageProcessorReport : public Test { MockLogger logger; MockClock clock; mir::report::logging::MessageProcessorReport report; MessageProcessorReport() : report(mir::test::fake_shared(logger), mir::test::fake_shared(clock)) { EXPECT_CALL(logger, log( mir::logging::Logger::debug, _, "frontend::MessageProcessor")).Times(AnyNumber()); } }; } TEST_F(MessageProcessorReport, everything_fine) { mir::time::Timestamp a_time; EXPECT_CALL(clock, sample()).Times(2).WillRepeatedly(Return(a_time)); EXPECT_CALL(logger, log( mir::logging::Logger::informational, EndsWith(": a_function(), elapsed=0µs"), "frontend::MessageProcessor")).Times(1); report.received_invocation(this, 1, "a_function"); report.completed_invocation(this, 1, true); } TEST_F(MessageProcessorReport, slow_call) { mir::time::Timestamp a_time; mir::time::Timestamp another_time = a_time + std::chrono::microseconds(1234); EXPECT_CALL(clock, sample()).Times(2) .WillOnce(Return(a_time)).WillOnce(Return(another_time)); EXPECT_CALL(logger, log( mir::logging::Logger::informational, EndsWith("elapsed=1234µs"), "frontend::MessageProcessor")).Times(1); report.received_invocation(this, 1, __PRETTY_FUNCTION__); report.completed_invocation(this, 1, true); } TEST_F(MessageProcessorReport, reports_disconnect) { mir::time::Timestamp a_time; EXPECT_CALL(clock, sample()).Times(2).WillRepeatedly(Return(a_time)); EXPECT_CALL(logger, log( mir::logging::Logger::informational, HasSubstr("(disconnecting)"), "frontend::MessageProcessor")).Times(1); report.received_invocation(this, 1, __PRETTY_FUNCTION__); report.completed_invocation(this, 1, false); } TEST_F(MessageProcessorReport, reports_error_during_call) { const char* testError = "***Test error***"; mir::time::Timestamp a_time; EXPECT_CALL(clock, sample()).Times(2).WillRepeatedly(Return(a_time)); EXPECT_CALL(logger, log( mir::logging::Logger::informational, HasSubstr(testError), "frontend::MessageProcessor")).Times(1); report.received_invocation(this, 1, __PRETTY_FUNCTION__); report.exception_handled(this, 1, std::runtime_error(testError)); report.completed_invocation(this, 1, false); } TEST_F(MessageProcessorReport, reports_unknown_method) { EXPECT_CALL(clock, sample()).Times(0); EXPECT_CALL(logger, log( mir::logging::Logger::warning, HasSubstr("UNKNOWN method=\"unknown_function_name\""), "frontend::MessageProcessor")).Times(1); report.unknown_method(this, 1, "unknown_function_name"); } TEST_F(MessageProcessorReport, reports_error_deserializing_call) { const char* testError = "***Test error***"; EXPECT_CALL(logger, log( mir::logging::Logger::informational, HasSubstr(testError), "frontend::MessageProcessor")).Times(1); report.exception_handled(this, std::runtime_error(testError)); } TEST_F(MessageProcessorReport, logs_a_debug_message_when_invocation_starts) { mir::time::Timestamp a_time; EXPECT_CALL(clock, sample()).Times(AnyNumber()).WillRepeatedly(Return(a_time)); EXPECT_CALL(logger, log( mir::logging::Logger::informational, HasSubstr("Calls outstanding on exit:"), "frontend::MessageProcessor")).Times(AnyNumber()); EXPECT_CALL(logger, log( mir::logging::Logger::debug, _, "frontend::MessageProcessor")).Times(1); report.received_invocation(this, 1, __PRETTY_FUNCTION__); } TEST_F(MessageProcessorReport, logs_incomplete_calls_on_destruction) { mir::time::Timestamp a_time; EXPECT_CALL(clock, sample()).Times(AnyNumber()).WillRepeatedly(Return(a_time)); EXPECT_CALL(logger, log( mir::logging::Logger::informational, HasSubstr("Calls outstanding on exit:"), "frontend::MessageProcessor")).Times(1); report.received_invocation(this, 1, __PRETTY_FUNCTION__); } mir-0.1.8+14.04.20140411/tests/unit-tests/logging/CMakeLists.txt0000644000015301777760000000047712322054223024353 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/message_processor_report.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_legacy_input_report.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_display_report.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_compositor_report.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/logging/test_display_report.cpp0000644000015301777760000000717512322054223026420 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/report/logging/display_report.h" #include "mir/logging/logger.h" #include "mir_test_doubles/mock_egl.h" #include #include #include namespace ml = mir::logging; namespace mrl = mir::report::logging; namespace mtd = mir::test::doubles; namespace { class MockLogger : public ml::Logger { public: MOCK_METHOD3(log, void(Severity severity, const std::string& message, const std::string& component)); ~MockLogger() noexcept(true) {} }; struct DisplayReport : public testing::Test { DisplayReport() { } void SetUp() { logger = std::make_shared(); } std::shared_ptr logger; mtd::MockEGL mock_egl; }; char const* const component = "graphics"; #define STRMACRO(X) #X std::string egl_string_mapping [] = { STRMACRO(EGL_BUFFER_SIZE), STRMACRO(EGL_ALPHA_SIZE), STRMACRO(EGL_BLUE_SIZE), STRMACRO(EGL_GREEN_SIZE), STRMACRO(EGL_RED_SIZE), STRMACRO(EGL_DEPTH_SIZE), STRMACRO(EGL_STENCIL_SIZE), STRMACRO(EGL_CONFIG_CAVEAT), STRMACRO(EGL_CONFIG_ID), STRMACRO(EGL_LEVEL), STRMACRO(EGL_MAX_PBUFFER_HEIGHT), STRMACRO(EGL_MAX_PBUFFER_PIXELS), STRMACRO(EGL_MAX_PBUFFER_WIDTH), STRMACRO(EGL_NATIVE_RENDERABLE), STRMACRO(EGL_NATIVE_VISUAL_ID), STRMACRO(EGL_NATIVE_VISUAL_TYPE), STRMACRO(EGL_SAMPLES), STRMACRO(EGL_SAMPLE_BUFFERS), STRMACRO(EGL_SURFACE_TYPE), STRMACRO(EGL_TRANSPARENT_TYPE), STRMACRO(EGL_TRANSPARENT_BLUE_VALUE), STRMACRO(EGL_TRANSPARENT_GREEN_VALUE), STRMACRO(EGL_TRANSPARENT_RED_VALUE), STRMACRO(EGL_BIND_TO_TEXTURE_RGB), STRMACRO(EGL_BIND_TO_TEXTURE_RGBA), STRMACRO(EGL_MIN_SWAP_INTERVAL), STRMACRO(EGL_MAX_SWAP_INTERVAL), STRMACRO(EGL_LUMINANCE_SIZE), STRMACRO(EGL_ALPHA_MASK_SIZE), STRMACRO(EGL_COLOR_BUFFER_TYPE), STRMACRO(EGL_RENDERABLE_TYPE), STRMACRO(EGL_MATCH_NATIVE_PIXMAP), STRMACRO(EGL_CONFORMANT), STRMACRO(EGL_SLOW_CONFIG), STRMACRO(EGL_NON_CONFORMANT_CONFIG), STRMACRO(EGL_TRANSPARENT_RGB), STRMACRO(EGL_RGB_BUFFER), STRMACRO(EGL_LUMINANCE_BUFFER), STRMACRO(EGL_FRAMEBUFFER_TARGET_ANDROID) }; #undef STRMACRO } TEST_F(DisplayReport, eglconfig) { using namespace testing; EGLDisplay disp = reinterpret_cast(9); EGLConfig config = reinterpret_cast(8); int dummy_value = 7; EXPECT_CALL(mock_egl, eglGetConfigAttrib(disp, config,_,_)) .Times(AnyNumber()) .WillRepeatedly(DoAll(SetArgPointee<3>(dummy_value),Return(EGL_TRUE))); EXPECT_CALL(*logger, log( ml::Logger::informational, "Display EGL Configuration:", component)); for(auto &i : egl_string_mapping) { EXPECT_CALL(*logger, log( ml::Logger::informational, " [" + i + "] : " + std::to_string(dummy_value), component)); } mrl::DisplayReport report(logger); report.report_egl_configuration(disp, config); } mir-0.1.8+14.04.20140411/tests/unit-tests/logging/test_compositor_report.cpp0000644000015301777760000001154712322054223027147 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/report/logging/compositor_report.h" #include "mir/logging/logger.h" #include #include #include using namespace mir; using namespace std; namespace { class FakeClock : public time::Clock { public: void elapse(chrono::microseconds delta) { now += delta; } time::Timestamp sample() const { return now; } private: time::Timestamp now; }; class Recorder : public logging::Logger { public: void log(Severity, string const& message, string const&) { last = message; } string const& last_message() const { return last; } bool last_message_contains(char const* substr) { return last.find(substr) != string::npos; } bool scrape(float& fps, float& frame_time) const { return sscanf(last.c_str(), "Display %*s averaged %f FPS, %f ms/frame", &fps, &frame_time) == 2; } private: string last; }; } // namespace TEST(LoggingCompositorReport, calculates_accurate_stats) { /* * This test just verifies the important stats; FPS and frame time. * We don't need to validate all the numbers because maintaining low * coupling to log formats is more important. */ auto clock = make_shared(); auto recorder = make_shared(); const void* const display_id = nullptr; report::logging::CompositorReport report(recorder, clock); int target_fps = 60; for (int frame = 0; frame < target_fps*3; frame++) { report.began_frame(display_id); clock->elapse(chrono::microseconds(1000000 / target_fps)); report.finished_frame(false, display_id); } float measured_fps, measured_frame_time; ASSERT_TRUE(recorder->scrape(measured_fps, measured_frame_time)) << recorder->last_message(); EXPECT_LE(59.9f, measured_fps); EXPECT_GE(60.1f, measured_fps); EXPECT_LE(16.5f, measured_frame_time); EXPECT_GE(16.7f, measured_frame_time); clock->elapse(chrono::microseconds(5000000)); target_fps = 100; for (int frame = 0; frame < target_fps*3; frame++) { report.began_frame(display_id); clock->elapse(chrono::microseconds(1000000 / target_fps)); report.finished_frame(false, display_id); } ASSERT_TRUE(recorder->scrape(measured_fps, measured_frame_time)) << recorder->last_message(); EXPECT_FLOAT_EQ(100.0f, measured_fps); EXPECT_FLOAT_EQ(10.0f, measured_frame_time); } TEST(LoggingCompositorReport, survives_pause_resume) { auto clock = make_shared(); auto logger = make_shared(); const void* const before = "before"; const void* const after = "after"; report::logging::CompositorReport report(logger, clock); report.started(); report.began_frame(before); clock->elapse(chrono::microseconds(12345)); report.finished_frame(false, before); report.stopped(); clock->elapse(chrono::microseconds(12345678)); report.started(); report.began_frame(after); clock->elapse(chrono::microseconds(12345)); report.finished_frame(false, after); clock->elapse(chrono::microseconds(12345678)); report.began_frame(after); clock->elapse(chrono::microseconds(12345)); report.finished_frame(false, after); report.stopped(); } TEST(LoggingCompositorReport, reports_bypass_only_when_changed) { const void* const id = "My Screen"; auto clock = make_shared(); auto logger = make_shared(); report::logging::CompositorReport report(logger, clock); report.started(); report.began_frame(id); report.finished_frame(false, id); EXPECT_TRUE(logger->last_message_contains("bypass OFF")) << logger->last_message(); for (int f = 0; f < 3; ++f) { report.began_frame(id); report.finished_frame(false, id); clock->elapse(chrono::microseconds(12345678)); } EXPECT_FALSE(logger->last_message_contains("bypass ")) << logger->last_message(); report.began_frame(id); report.finished_frame(true, id); EXPECT_TRUE(logger->last_message_contains("bypass ON")) << logger->last_message(); report.stopped(); } mir-0.1.8+14.04.20140411/tests/unit-tests/logging/test_legacy_input_report.cpp0000644000015301777760000000547412322054223027436 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/report/legacy_input_report.h" #include "mir/logging/logger.h" #include #include "mir_test/fake_shared.h" #include #include namespace ml = mir::logging; namespace mri = mir::report::legacy_input; using testing::_; namespace { class MockLogger : public ml::Logger { public: MOCK_METHOD3(log, void(Severity severity, const std::string& message, const std::string& component)); ~MockLogger() noexcept(true) {} }; struct InputReport : public testing::Test { MockLogger logger; InputReport() { mri::initialize(mir::test::fake_shared(logger)); } }; char const* const component = "android-input"; char const* const LOG_TAG = "Foo"; } TEST_F(InputReport, debug_message) { // default minimum log priority is "informational". "debug" is lower than that. EXPECT_CALL(logger, log(_, _, _)).Times(0); ALOG(LOG_DEBUG, NULL, "Test function is %s", __PRETTY_FUNCTION__); } TEST_F(InputReport, unknown_message) { char const* const unknown = "Unknown message"; // default minimum log priority is "informational". "unknown" is lower than that. // Actually, I don't think this is even a valid priority. EXPECT_CALL(logger, log(_, _, _)).Times(0); ALOG(LOG_UNKNOWN, NULL, unknown); } TEST_F(InputReport, verbose_message) { char const* const verbose = "A very long story. (OK, I lied.)"; // default minimum log priority is "informational". "verbose" is lower than that. EXPECT_CALL(logger, log(_, _, _)).Times(0); ALOG(LOG_VERBOSE, NULL, verbose); } TEST_F(InputReport, info_message) { EXPECT_CALL(logger, log( ml::Logger::informational, "[Foo]Some informational message", component)); ALOGI("Some informational message"); } TEST_F(InputReport, warning_message) { EXPECT_CALL(logger, log( ml::Logger::warning, "[Foo]Warning!!!", component)); ALOGW("Warning!!!"); } TEST_F(InputReport, error_message) { EXPECT_CALL(logger, log( ml::Logger::error, "[Foo]An error occurred!", component)); ALOGE("An error occurred!"); } mir-0.1.8+14.04.20140411/tests/unit-tests/test_udev_wrapper.cpp0000644000015301777760000004101212322054223024421 0ustar pbusernogroup00000000000000/* * 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: Christopher James Halse Rogers */ #include "mir_test_framework/udev_environment.h" #include "mir/udev/wrapper.h" #include #include #include // At some point gnu libstdc++ will have a header that contains // actual functions. Until then, Boost to the rescue. #include #include #include #include namespace mtf=mir::mir_test_framework; namespace { bool KilledByInvalidMemoryAccess(int exit_status) { return testing::KilledBySignal(SIGSEGV)(exit_status) || testing::KilledBySignal(SIGBUS)(exit_status) || testing::KilledBySignal(SIGABRT)(exit_status) || // It seems that valgrind kills us with SIGKILL testing::KilledBySignal(SIGKILL)(exit_status); } class UdevWrapperTest : public ::testing::Test { public: mtf::UdevEnvironment udev_environment; }; } TEST_F(UdevWrapperTest, IteratesOverCorrectNumberOfDevices) { udev_environment.add_device("drm", "fakedev1", NULL, {}, {}); udev_environment.add_device("drm", "fakedev2", NULL, {}, {}); udev_environment.add_device("drm", "fakedev3", NULL, {}, {}); udev_environment.add_device("drm", "fakedev4", NULL, {}, {}); udev_environment.add_device("drm", "fakedev5", NULL, {}, {}); auto ctx = std::make_shared(); mir::udev::Enumerator enumerator(ctx); enumerator.scan_devices(); int device_count = 0; for (auto& device : enumerator) { // Silence unused variable warning static_cast(device); ++device_count; } ASSERT_EQ(device_count, 5); } TEST_F(UdevWrapperTest, EnumeratorMatchSubsystemIncludesCorrectDevices) { udev_environment.add_device("drm", "fakedrm1", NULL, {}, {}); udev_environment.add_device("scsi", "fakescsi1", NULL, {}, {}); udev_environment.add_device("drm", "fakedrm2", NULL, {}, {}); udev_environment.add_device("usb", "fakeusb1", NULL, {}, {}); udev_environment.add_device("usb", "fakeusb2", NULL, {}, {}); auto ctx = std::make_shared(); mir::udev::Enumerator devices(ctx); devices.match_subsystem("drm"); devices.scan_devices(); for (auto& device : devices) { ASSERT_STREQ("drm", device.subsystem()); } } TEST_F(UdevWrapperTest, UdevDeviceHasCorrectDevType) { auto sysfs_path = udev_environment.add_device("drm", "card0", NULL, {}, {"DEVTYPE", "drm_minor"}); mir::udev::Context ctx; auto dev = ctx.device_from_syspath(sysfs_path); ASSERT_STREQ("drm_minor", dev->devtype()); } TEST_F(UdevWrapperTest, UdevDeviceHasCorrectDevPath) { auto sysfs_path = udev_environment.add_device("drm", "card0", NULL, {}, {}); mir::udev::Context ctx; auto dev = ctx.device_from_syspath(sysfs_path); ASSERT_STREQ("/devices/card0", dev->devpath()); } TEST_F(UdevWrapperTest, UdevDeviceHasCorrectDevNode) { auto sysfs_path = udev_environment.add_device("drm", "card0", NULL, {}, {"DEVNAME", "/dev/dri/card0"}); mir::udev::Context ctx; auto dev = ctx.device_from_syspath(sysfs_path); ASSERT_STREQ("/dev/dri/card0", dev->devnode()); } TEST_F(UdevWrapperTest, UdevDeviceComparisonIsReflexive) { auto sysfs_path = udev_environment.add_device("drm", "card0", NULL, {}, {}); mir::udev::Context ctx; auto dev = ctx.device_from_syspath(sysfs_path); EXPECT_TRUE(*dev == *dev); } TEST_F(UdevWrapperTest, UdevDeviceComparisonIsSymmetric) { auto sysfs_path = udev_environment.add_device("drm", "card0", NULL, {}, {}); mir::udev::Context ctx; std::shared_ptr same_one = ctx.device_from_syspath(sysfs_path); std::shared_ptr same_two = ctx.device_from_syspath(sysfs_path); EXPECT_TRUE(*same_one == *same_two); EXPECT_TRUE(*same_two == *same_one); } TEST_F(UdevWrapperTest, UdevDeviceDifferentDevicesCompareFalse) { auto path_one = udev_environment.add_device("drm", "card0", NULL, {}, {}); auto path_two = udev_environment.add_device("drm", "card1", NULL, {}, {}); mir::udev::Context ctx; auto dev_one = ctx.device_from_syspath(path_one); auto dev_two = ctx.device_from_syspath(path_two); EXPECT_FALSE(*dev_one == *dev_two); EXPECT_FALSE(*dev_two == *dev_one); } TEST_F(UdevWrapperTest, UdevDeviceDifferentDevicesAreNotEqual) { auto path_one = udev_environment.add_device("drm", "card0", NULL, {}, {}); auto path_two = udev_environment.add_device("drm", "card1", NULL, {}, {}); mir::udev::Context ctx; auto dev_one = ctx.device_from_syspath(path_one); auto dev_two = ctx.device_from_syspath(path_two); EXPECT_TRUE(*dev_one != *dev_two); EXPECT_TRUE(*dev_two != *dev_one); } TEST_F(UdevWrapperTest, UdevDeviceSameDeviceIsNotNotEqual) { auto sysfs_path = udev_environment.add_device("drm", "card0", NULL, {}, {}); mir::udev::Context ctx; auto same_one = ctx.device_from_syspath(sysfs_path); auto same_two = ctx.device_from_syspath(sysfs_path); EXPECT_FALSE(*same_one != *same_two); EXPECT_FALSE(*same_two != *same_one); } TEST_F(UdevWrapperTest, EnumeratorMatchParentMatchesOnlyChildren) { auto card0_syspath = udev_environment.add_device("drm", "card0", NULL, {}, {}); udev_environment.add_device("usb", "fakeusb", NULL, {}, {}); udev_environment.add_device("drm", "card0-HDMI1", "/sys/devices/card0", {}, {}); udev_environment.add_device("drm", "card0-VGA1", "/sys/devices/card0", {}, {}); udev_environment.add_device("drm", "card0-LVDS1", "/sys/devices/card0", {}, {}); auto ctx = std::make_shared(); mir::udev::Enumerator devices(ctx); auto drm_device = ctx->device_from_syspath(card0_syspath); devices.match_parent(*drm_device); devices.scan_devices(); int child_count = 0; for (auto& device : devices) { EXPECT_STREQ("drm", device.subsystem()); ++child_count; } EXPECT_EQ(4, child_count); } TEST_F(UdevWrapperTest, EnumeratorThrowsLogicErrorIfIteratedBeforeScanned) { auto ctx = std::make_shared(); mir::udev::Enumerator devices(ctx); EXPECT_THROW({ devices.begin(); }, std::logic_error); } TEST_F(UdevWrapperTest, EnumeratorLogicErrorHasSensibleMessage) { auto ctx = std::make_shared(); mir::udev::Enumerator devices(ctx); std::string error_msg; try { devices.begin(); } catch (std::logic_error& e) { error_msg = e.what(); } EXPECT_STREQ("Attempted to iterate over udev devices without first scanning", error_msg.c_str()); } TEST_F(UdevWrapperTest, EnumeratorEnumeratesEmptyList) { auto ctx = std::make_shared(); mir::udev::Enumerator devices(ctx); devices.scan_devices(); for (auto& device : devices) ADD_FAILURE() << "Unexpected udev device: " << device.devpath(); } TEST_F(UdevWrapperTest, EnumeratorAddMatchSysnameIncludesCorrectDevices) { auto drm_sysfspath = udev_environment.add_device("drm", "card0", NULL, {}, {}); udev_environment.add_device("drm", "control64D", NULL, {}, {}); udev_environment.add_device("drm", "card0-LVDS1", drm_sysfspath.c_str(), {}, {}); udev_environment.add_device("drm", "card1", NULL, {}, {}); auto ctx = std::make_shared(); mir::udev::Enumerator devices(ctx); devices.match_sysname("card[0-9]"); devices.scan_devices(); for (auto& device : devices) { EXPECT_TRUE(boost::regex_match(device.devpath(), boost::regex(".*card[0-9].*"))) << "Unexpected device with devpath:" << device.devpath(); } } typedef UdevWrapperTest UdevWrapperDeathTest; TEST_F(UdevWrapperDeathTest, DereferencingEndReturnsInvalidObject) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; udev_environment.add_device("drm", "control64D", NULL, {}, {}); udev_environment.add_device("drm", "card1", NULL, {}, {}); mir::udev::Enumerator devices(std::make_shared()); devices.scan_devices(); EXPECT_EXIT((*devices.end()).subsystem(), KilledByInvalidMemoryAccess, ""); auto iter = devices.begin(); while(iter != devices.end()) { iter++; } EXPECT_EXIT((*iter).subsystem(), KilledByInvalidMemoryAccess, ""); } TEST_F(UdevWrapperTest, MemberDereferenceWorks) { udev_environment.add_device("drm", "control64D", NULL, {}, {}); udev_environment.add_device("drm", "card1", NULL, {}, {}); mir::udev::Enumerator devices(std::make_shared()); devices.scan_devices(); auto iter = devices.begin(); EXPECT_STREQ("drm", iter->subsystem()); EXPECT_STREQ("drm", iter->subsystem()); } TEST_F(UdevWrapperDeathTest, MemberDereferenceOfEndDies) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; udev_environment.add_device("drm", "control64D", NULL, {}, {}); udev_environment.add_device("drm", "card1", NULL, {}, {}); mir::udev::Enumerator devices(std::make_shared()); devices.scan_devices(); EXPECT_EXIT(devices.end()->subsystem(), KilledByInvalidMemoryAccess, ""); auto iter = devices.begin(); while(iter != devices.end()) { iter++; } EXPECT_EXIT(iter->subsystem(), KilledByInvalidMemoryAccess, ""); } TEST_F(UdevWrapperTest, UdevMonitorDoesNotTriggerBeforeEnabling) { mir::udev::Monitor monitor{mir::udev::Context()}; bool event_handler_called = false; udev_environment.add_device("drm", "control64D", NULL, {}, {}); monitor.process_events([&event_handler_called](mir::udev::Monitor::EventType, mir::udev::Device const&) {event_handler_called = true;}); EXPECT_FALSE(event_handler_called); } TEST_F(UdevWrapperTest, UdevMonitorTriggersAfterEnabling) { mir::udev::Monitor monitor{mir::udev::Context()}; bool event_handler_called = false; monitor.enable(); udev_environment.add_device("drm", "control64D", NULL, {}, {}); monitor.process_events([&event_handler_called](mir::udev::Monitor::EventType, mir::udev::Device const&) {event_handler_called = true;}); EXPECT_TRUE(event_handler_called); } TEST_F(UdevWrapperTest, UdevMonitorSendsRemoveEvent) { mir::udev::Monitor monitor{mir::udev::Context()}; bool remove_event_received = false; monitor.enable(); auto test_sysfspath = udev_environment.add_device("drm", "control64D", NULL, {}, {}); udev_environment.remove_device(test_sysfspath); monitor.process_events([&remove_event_received] (mir::udev::Monitor::EventType action, mir::udev::Device const&) { if (action == mir::udev::Monitor::EventType::REMOVED) remove_event_received = true; }); EXPECT_TRUE(remove_event_received); } TEST_F(UdevWrapperTest, UdevMonitorSendsChangedEvent) { mir::udev::Monitor monitor{mir::udev::Context()}; bool changed_event_received = false; monitor.enable(); auto test_sysfspath = udev_environment.add_device("drm", "control64D", NULL, {}, {}); udev_environment.emit_device_changed(test_sysfspath); monitor.process_events([&changed_event_received] (mir::udev::Monitor::EventType action, mir::udev::Device const&) { if (action == mir::udev::Monitor::EventType::CHANGED) changed_event_received = true; }); EXPECT_TRUE(changed_event_received); } TEST_F(UdevWrapperTest, UdevMonitorEventHasCorrectDeviceDetails) { mir::udev::Context ctx; mir::udev::Monitor monitor{mir::udev::Context()}; bool event_handler_called = false; monitor.enable(); auto sysfs_path = udev_environment.add_device("drm", "control64D", NULL, {}, {}); auto device = ctx.device_from_syspath(sysfs_path); monitor.process_events( [&event_handler_called, device](mir::udev::Monitor::EventType, mir::udev::Device const& dev) { event_handler_called = true; EXPECT_EQ(*device, dev); }); ASSERT_TRUE(event_handler_called); } TEST_F(UdevWrapperTest, UdevMonitorFdIsReadableWhenEventsAvailable) { mir::udev::Monitor monitor{mir::udev::Context()}; monitor.enable(); udev_environment.add_device("drm", "card0", NULL, {}, {}); struct pollfd fds; fds.fd = monitor.fd(); fds.events = POLLIN; ASSERT_GT(poll(&fds, 1, 0), 0); EXPECT_TRUE(fds.revents & POLLIN); } TEST_F(UdevWrapperTest, UdevMonitorFdIsUnreadableAfterProcessingEvents) { mir::udev::Monitor monitor{mir::udev::Context()}; monitor.enable(); udev_environment.add_device("drm", "card0", NULL, {}, {}); udev_environment.add_device("drm", "card1", NULL, {}, {}); udev_environment.add_device("usb", "mightymouse", NULL, {}, {}); struct pollfd fds; fds.fd = monitor.fd(); fds.events = POLLIN; ASSERT_GT(poll(&fds, 1, 0), 0); ASSERT_TRUE(fds.revents & POLLIN); monitor.process_events([](mir::udev::Monitor::EventType, mir::udev::Device const&){}); EXPECT_EQ(poll(&fds, 1, 0), 0); } TEST_F(UdevWrapperTest, UdevMonitorFiltersByPathAndType) { mir::udev::Context ctx; mir::udev::Monitor monitor{mir::udev::Context()}; bool event_received = false; monitor.filter_by_subsystem_and_type("drm", "drm_minor"); monitor.enable(); auto test_sysfspath = udev_environment.add_device("drm", "control64D", NULL, {}, {"DEVTYPE", "drm_minor"}); auto minor_device = ctx.device_from_syspath(test_sysfspath); udev_environment.add_device("drm", "card0-LVDS1", test_sysfspath.c_str(), {}, {}); udev_environment.add_device("usb", "mightymouse", NULL, {}, {}); monitor.process_events([&event_received, minor_device] (mir::udev::Monitor::EventType, mir::udev::Device const& dev) { EXPECT_EQ(dev, *minor_device); event_received = true; }); ASSERT_TRUE(event_received); } TEST_F(UdevWrapperTest, UdevMonitorFiltersAreAdditive) { mir::udev::Context ctx; mir::udev::Monitor monitor{mir::udev::Context()}; bool usb_event_received = false, drm_event_recieved = false; monitor.filter_by_subsystem_and_type("drm", "drm_minor"); monitor.filter_by_subsystem_and_type("usb", "hid"); monitor.enable(); auto drm_sysfspath = udev_environment.add_device("drm", "control64D", NULL, {}, {"DEVTYPE", "drm_minor"}); auto drm_device = ctx.device_from_syspath(drm_sysfspath); udev_environment.add_device("drm", "card0-LVDS1", drm_sysfspath.c_str(), {}, {}); auto usb_sysfspath = udev_environment.add_device("usb", "mightymouse", NULL, {}, {"DEVTYPE", "hid"}); auto usb_device = ctx.device_from_syspath(usb_sysfspath); monitor.process_events([&drm_event_recieved, drm_device, &usb_event_received, usb_device] (mir::udev::Monitor::EventType, mir::udev::Device const& dev) { if (dev == *drm_device) drm_event_recieved = true; if (dev == *usb_device) usb_event_received = true; }); EXPECT_TRUE(drm_event_recieved); EXPECT_TRUE(usb_event_received); } TEST_F(UdevWrapperTest, UdevMonitorFiltersApplyAfterEnable) { mir::udev::Context ctx; mir::udev::Monitor monitor{mir::udev::Context()}; bool event_received = false; monitor.enable(); monitor.filter_by_subsystem_and_type("drm", "drm_minor"); auto test_sysfspath = udev_environment.add_device("drm", "control64D", NULL, {}, {"DEVTYPE", "drm_minor"}); auto minor_device = ctx.device_from_syspath(test_sysfspath); udev_environment.add_device("drm", "card0-LVDS1", test_sysfspath.c_str(), {}, {}); udev_environment.add_device("usb", "mightymouse", NULL, {}, {}); monitor.process_events([&event_received, minor_device] (mir::udev::Monitor::EventType, mir::udev::Device const& dev) { EXPECT_EQ(dev, *minor_device); event_received = true; }); ASSERT_TRUE(event_received); } mir-0.1.8+14.04.20140411/tests/unit-tests/geometry/0000755000015301777760000000000012322054703022013 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/geometry/test-size.cpp0000644000015301777760000000235612322054223024451 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/geometry/size.h" #include #include namespace geom = mir::geometry; TEST(geometry, size) { using namespace geom; Size const size2x4{2, 4}; EXPECT_EQ(Width(2), size2x4.width); EXPECT_EQ(Height(4), size2x4.height); Size const copy = size2x4; EXPECT_EQ(Width(2), copy.width); EXPECT_EQ(Height(4), copy.height); EXPECT_EQ(size2x4, copy); Size const defaultValue; EXPECT_EQ(Width(0), defaultValue.width); EXPECT_EQ(Height(0), defaultValue.height); EXPECT_NE(size2x4, defaultValue); } mir-0.1.8+14.04.20140411/tests/unit-tests/geometry/test-rectangle.cpp0000644000015301777760000001363012322054223025440 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/geometry/rectangle.h" #include #include namespace geom = mir::geometry; TEST(geometry, rectangle) { using namespace geom; Point const x3y9{X(3), Y(9)}; Size const w2h4{2, 4}; Rectangle const rect{x3y9, w2h4}; EXPECT_EQ(x3y9, rect.top_left); EXPECT_EQ(w2h4, rect.size); Rectangle const copy = rect; EXPECT_EQ(x3y9, copy.top_left); EXPECT_EQ(w2h4, copy.size); EXPECT_EQ(rect, copy); Rectangle default_rect; EXPECT_EQ(Point(), default_rect.top_left); EXPECT_EQ(Size(), default_rect.size); EXPECT_NE(rect, default_rect); } TEST(geometry, rectangle_bottom_right) { using namespace testing; using namespace geom; Rectangle const rect{{0,0}, {1,1}}; Rectangle const rect_empty{{2,2}, {0,0}}; EXPECT_EQ(Point(1,1), rect.bottom_right()); EXPECT_EQ(Point(2,2), rect_empty.bottom_right()); } TEST(geometry, rectangle_contains_rectangle) { using namespace testing; using namespace geom; const int left = 3; const int top = 3; const int width = 3; const int height = 3; const Rectangle r{{left,top}, {width,height}}; const int right = left + width; const int bottom = top + height; // Test for _every_ rectangle contained in r for (int y = top; y <= bottom; y++) { for (int x = left; x <= right; x++) { const int max_height = bottom - y; const int max_width = right - x; for (int h = 0; h <= max_height; h++) { for (int w = 0; w <= max_width; w++) { EXPECT_TRUE(r.contains(Rectangle{{x,y}, {w,h}})); } } EXPECT_FALSE(r.contains(Rectangle{{x,y}, {max_width+1,max_height}})); EXPECT_FALSE(r.contains(Rectangle{{x,y}, {max_width,max_height+1}})); } } EXPECT_FALSE(r.contains(Rectangle{{2,2}, {5,5}})); EXPECT_FALSE(r.contains(Rectangle{{2,2}, {1,1}})); EXPECT_FALSE(r.contains(Rectangle{{-4,-3}, {10,10}})); EXPECT_FALSE(r.contains(Rectangle{{1,3}, {3,3}})); EXPECT_FALSE(r.contains(Rectangle{{3,1}, {3,3}})); EXPECT_FALSE(r.contains(Rectangle{{5,3}, {3,3}})); EXPECT_FALSE(r.contains(Rectangle{{3,5}, {3,3}})); EXPECT_FALSE(r.contains(Rectangle{{9,9}, {1,1}})); EXPECT_FALSE(r.contains(Rectangle{{-6,-7}, {3,4}})); } TEST(geometry, empty_rectangle_contains_point_only) { using namespace testing; using namespace geom; const int left = 3; const int top = 3; const Rectangle r{{left,top}, {0,0}}; EXPECT_TRUE(r.contains(Rectangle{{left,top}, {0,0}})); EXPECT_FALSE(r.contains(Rectangle{{left,top}, {1,0}})); EXPECT_FALSE(r.contains(Rectangle{{left,top}, {0,1}})); EXPECT_FALSE(r.contains(Rectangle{{left,top}, {1,1}})); EXPECT_FALSE(r.contains(Rectangle{{left-1,top}, {3,0}})); EXPECT_FALSE(r.contains(Rectangle{{left-1,top}, {0,0}})); EXPECT_FALSE(r.contains(Rectangle{{left,top+1}, {0,0}})); } TEST(geometry, elongated_empty_rectangle_contains_points_only) { using namespace testing; using namespace geom; const int left = 3; const int top = 3; const Rectangle r{{left,top}, {0,3}}; EXPECT_TRUE(r.contains(Rectangle{{left,top}, {0,0}})); EXPECT_TRUE(r.contains(Rectangle{{left,top+1}, {0,0}})); EXPECT_TRUE(r.contains(Rectangle{{left,top+2}, {0,0}})); EXPECT_TRUE(r.contains(Rectangle{{left,top+3}, {0,0}})); EXPECT_TRUE(r.contains(Rectangle{{left,top}, {0,1}})); EXPECT_TRUE(r.contains(Rectangle{{left,top+1}, {0,2}})); EXPECT_FALSE(r.contains(Rectangle{{left,top+4}, {0,0}})); EXPECT_FALSE(r.contains(Rectangle{{left,top}, {1,0}})); EXPECT_FALSE(r.contains(Rectangle{{left,top}, {1,1}})); EXPECT_FALSE(r.contains(Rectangle{{left-1,top}, {3,0}})); EXPECT_FALSE(r.contains(Rectangle{{left-1,top}, {0,0}})); } TEST(geometry, rectangle_contains_point) { using namespace testing; using namespace geom; Rectangle const rect{{0,0}, {1,1}}; Rectangle const rect_empty{{2,2}, {0,0}}; EXPECT_TRUE(rect.contains({0,0})); EXPECT_FALSE(rect.contains({0,1})); EXPECT_FALSE(rect.contains({1,0})); EXPECT_FALSE(rect.contains({1,1})); EXPECT_FALSE(rect_empty.contains({2,2})); } TEST(geometry, rectangle_overlaps) { using namespace testing; using namespace geom; Rectangle const rect1{{0,0}, {1,1}}; Rectangle const rect2{{1,1}, {1,1}}; Rectangle const rect3{{0,0}, {2,2}}; Rectangle const rect4{{-1,-1}, {2,2}}; Rectangle const rect_empty{{0,0}, {0,0}}; EXPECT_FALSE(rect_empty.overlaps(rect_empty)); EXPECT_FALSE(rect_empty.overlaps(rect1)); EXPECT_FALSE(rect_empty.overlaps(rect4)); EXPECT_FALSE(rect1.overlaps(rect2)); EXPECT_FALSE(rect2.overlaps(rect1)); EXPECT_FALSE(rect4.overlaps(rect2)); EXPECT_FALSE(rect2.overlaps(rect4)); EXPECT_TRUE(rect1.overlaps(rect1)); EXPECT_TRUE(rect4.overlaps(rect4)); EXPECT_TRUE(rect3.overlaps(rect1)); EXPECT_TRUE(rect1.overlaps(rect3)); EXPECT_TRUE(rect3.overlaps(rect2)); EXPECT_TRUE(rect2.overlaps(rect3)); EXPECT_TRUE(rect4.overlaps(rect1)); EXPECT_TRUE(rect1.overlaps(rect4)); EXPECT_TRUE(rect4.overlaps(rect3)); EXPECT_TRUE(rect3.overlaps(rect3)); } mir-0.1.8+14.04.20140411/tests/unit-tests/geometry/test-dimensions.cpp0000644000015301777760000000573712322054223025655 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/geometry/dimensions.h" #include #include namespace geom = mir::geometry; TEST(geometry, width) { geom::Width width0 {0}; geom::Width width42 {42}; EXPECT_EQ(uint32_t{0}, width0.as_uint32_t()); EXPECT_EQ(uint32_t{42}, width42.as_uint32_t()); EXPECT_EQ(width0, width0); EXPECT_NE(width0, width42); EXPECT_EQ(width42, width42); EXPECT_NE(width42, width0); } TEST(geometry, height) { geom::Height height0 {0}; geom::Height height42 {42}; EXPECT_EQ(uint32_t{0}, height0.as_uint32_t()); EXPECT_EQ(uint32_t{42}, height42.as_uint32_t()); EXPECT_EQ(height0, height0); EXPECT_NE(height0, height42); EXPECT_EQ(height42, height42); EXPECT_NE(height42, height0); } TEST(geometry, delta_arithmetic) { using namespace geom; DeltaX dx1{1}; DeltaY dy1{1}; DeltaX x2 = DeltaX(1) + dx1; EXPECT_EQ(DeltaX(2), x2); EXPECT_EQ(DeltaX(1), x2-dx1); } TEST(geometry, coordinates) { using namespace geom; X x1{1}; X x2{2}; DeltaX dx1{1}; EXPECT_EQ(X(2), x1 + dx1); EXPECT_EQ(X(1), x2 - dx1); Y y24{24}; Y y42{42}; DeltaY dx18{18}; EXPECT_EQ(dx18, y42 - y24); } TEST(geometry, conversions) { using namespace geom; Width w1{1}; DeltaX dx1{1}; EXPECT_EQ(w1, dim_cast(dx1)); EXPECT_EQ(dx1, dim_cast(w1)); EXPECT_NE(dx1, dim_cast(X())); } TEST(geometry, signed_dimensions) { using namespace geom; X const x0{0}; X const x2{2}; X const xn5{-5}; Y const y0{0}; Y const y3{3}; Y const yn6{-6}; Y const yn7{-7}; // Compare against zero to catch regressions of signed->unsigned that // wouldn't be caught using as_*int()... EXPECT_GT(x0, xn5); EXPECT_GT(y0, yn7); EXPECT_LT(xn5, x0); EXPECT_LT(xn5, x2); EXPECT_LT(yn7, yn6); EXPECT_LT(yn7, y0); EXPECT_LT(yn7, y3); EXPECT_LE(xn5, x0); EXPECT_LE(xn5, x2); EXPECT_LE(yn7, yn6); EXPECT_LE(yn7, y0); EXPECT_LE(yn7, y3); EXPECT_LE(yn7, yn7); EXPECT_GT(x0, xn5); EXPECT_GT(x2, xn5); EXPECT_GT(yn6, yn7); EXPECT_GT(y0, yn7); EXPECT_GT(y3, yn7); EXPECT_GE(x0, xn5); EXPECT_GE(x2, xn5); EXPECT_GE(yn6, yn7); EXPECT_GE(y0, yn7); EXPECT_GE(y3, yn7); EXPECT_GE(yn7, yn7); } mir-0.1.8+14.04.20140411/tests/unit-tests/geometry/test-length.cpp0000644000015301777760000000630412322054247024763 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/geometry/length.h" #include using namespace mir::geometry; TEST(Length, zero) { Length zero; EXPECT_EQ(0, zero.as(Length::micrometres)); EXPECT_EQ(0, zero.as(Length::millimetres)); EXPECT_EQ(0, zero.as(Length::centimetres)); EXPECT_EQ(0, zero.as(Length::inches)); EXPECT_EQ(zero, 0_mm); EXPECT_EQ(zero, 0.0_mm); EXPECT_EQ(zero, 0_cm); EXPECT_EQ(zero, 0.0_cm); EXPECT_EQ(zero, 0_in); EXPECT_EQ(zero, 0.0_in); } TEST(Length, millimetres) { Length one_mm(1, Length::millimetres); EXPECT_EQ(Length(1000, Length::micrometres), one_mm); EXPECT_EQ(1.0f, one_mm.as(Length::millimetres)); EXPECT_FLOAT_EQ(0.1f, one_mm.as(Length::centimetres)); EXPECT_FLOAT_EQ(0.039370079f, one_mm.as(Length::inches)); for (int n = 0; n < 10; ++n) { EXPECT_EQ(Length(1000*n, Length::micrometres), Length(n, Length::millimetres)); } } TEST(Length, centimetres) { Length one_cm(1, Length::centimetres); EXPECT_EQ(Length(10000, Length::micrometres), one_cm); EXPECT_EQ(Length(10, Length::millimetres), one_cm); EXPECT_EQ(1.0f, one_cm.as(Length::centimetres)); EXPECT_EQ(10.0f, one_cm.as(Length::millimetres)); EXPECT_FLOAT_EQ(0.39370079f, one_cm.as(Length::inches)); EXPECT_EQ(one_cm, 1_cm); EXPECT_EQ(one_cm, 1.0_cm); EXPECT_EQ(one_cm, 10_mm); EXPECT_EQ(one_cm, 10.0_mm); for (int n = 0; n < 10; ++n) { EXPECT_EQ(Length(10000*n, Length::micrometres), Length(n, Length::centimetres)); } } TEST(Length, inches) { Length one_in(1, Length::inches); EXPECT_EQ(Length(25400, Length::micrometres), one_in); EXPECT_FLOAT_EQ(2.54f, one_in.as(Length::centimetres)); EXPECT_EQ(one_in, 1.0_in); EXPECT_EQ(one_in, 2.54_cm); EXPECT_EQ(one_in, 25.4_mm); for (int n = 0; n < 10; ++n) { EXPECT_EQ(Length(25400*n, Length::micrometres), Length(n, Length::inches)); } } TEST(Length, DPI) { EXPECT_EQ(24, (0.25_in).as_pixels(96.0f)); EXPECT_FLOAT_EQ(3543.3070866f, (30_cm).as_pixels(300.0f)); EXPECT_EQ(123456, Length(123456, Length::inches).as_pixels(1.0f)); } TEST(Length, assign) { auto const a = 123.45_in; Length b; EXPECT_NE(a, b); EXPECT_EQ(0, b.as(Length::inches)); b = a; EXPECT_EQ(a, b); EXPECT_EQ(3135630, b.as(Length::micrometres)); } TEST(Length, copy) { auto const a = 123.45_in; Length b(a); EXPECT_EQ(a, b); EXPECT_EQ(3135630, b.as(Length::micrometres)); } mir-0.1.8+14.04.20140411/tests/unit-tests/geometry/test-displacement.cpp0000644000015301777760000000507612322054223026151 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/geometry/displacement.h" #include #include namespace geom = mir::geometry; TEST(geometry, displacement) { using namespace geom; Displacement disp; Displacement const dx2dy4{DeltaX{2}, DeltaY{4}}; EXPECT_EQ(DeltaX{0}, disp.dx); EXPECT_EQ(DeltaY{0}, disp.dy); EXPECT_EQ(DeltaX{2}, dx2dy4.dx); EXPECT_EQ(DeltaY{4}, dx2dy4.dy); EXPECT_EQ(disp, disp); EXPECT_NE(disp, dx2dy4); EXPECT_EQ(dx2dy4, dx2dy4); EXPECT_NE(dx2dy4, disp); } TEST(geometry, displacement_arithmetic) { using namespace geom; Displacement const dx2dy4{DeltaX{2}, DeltaY{4}}; Displacement const dx3dy9{DeltaX{3}, DeltaY{9}}; Displacement const expected_add{DeltaX{5}, DeltaY{13}}; Displacement const expected_sub{DeltaX{1}, DeltaY{5}}; Displacement const add = dx3dy9 + dx2dy4; Displacement const sub = dx3dy9 - dx2dy4; EXPECT_EQ(expected_add, add); EXPECT_EQ(expected_sub, sub); } TEST(geometry, displacement_point_arithmetic) { using namespace geom; Point const x2y4{X{2}, Y{4}}; Point const x3y9{X{3}, Y{9}}; Displacement const dx2dy4{DeltaX{2}, DeltaY{4}}; Displacement const dx7dy11{DeltaX{7}, DeltaY{11}}; Point const expected_pd_add{X{5}, Y{13}}; Point const expected_pd_sub{X{1}, Y{5}}; Point const expected_pd_sub2{X{-4}, Y{-2}}; Displacement const expected_pp_sub{DeltaX{1}, DeltaY{5}}; Displacement const expected_pp_sub2{DeltaX{-1}, DeltaY{-5}}; Point const pd_add = x3y9 + dx2dy4; Point const pd_sub = x3y9 - dx2dy4; Point const pd_sub2 = x3y9 - dx7dy11; Displacement const pp_sub = x3y9 - x2y4; Displacement const pp_sub2 = x2y4 - x3y9; EXPECT_EQ(expected_pd_add, pd_add); EXPECT_EQ(expected_pd_sub, pd_sub); EXPECT_EQ(expected_pd_sub2, pd_sub2); EXPECT_EQ(expected_pp_sub, pp_sub); EXPECT_EQ(expected_pp_sub2, pp_sub2); } mir-0.1.8+14.04.20140411/tests/unit-tests/geometry/CMakeLists.txt0000644000015301777760000000065212322054247024561 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test-dimensions.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-size.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-point.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-displacement.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-rectangle.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-rectangles.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-length.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/geometry/test-rectangles.cpp0000644000015301777760000001664512322054223025634 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/geometry/rectangles.h" #include #include #include namespace geom = mir::geometry; TEST(geometry, rectangles_empty) { using namespace geom; Rectangles const rectangles; EXPECT_EQ(0, std::distance(rectangles.begin(), rectangles.end())); EXPECT_EQ(0u, rectangles.size()); } TEST(geometry, rectangles_not_empty) { using namespace geom; std::vector const rectangles_vec = { {Point{1, 2}, Size{Width{10}, Height{11}}}, {Point{3, 4}, Size{Width{12}, Height{13}}}, {Point{5, 6}, Size{Width{14}, Height{15}}} }; Rectangles rectangles; for (auto const& rect : rectangles_vec) rectangles.add(rect); EXPECT_EQ(static_cast(rectangles_vec.size()), std::distance(rectangles.begin(), rectangles.end())); EXPECT_EQ(rectangles_vec.size(), rectangles.size()); std::vector rect_found(rectangles_vec.size(), false); for (auto const& rect : rectangles) { auto iter = std::find(rectangles.begin(), rectangles.end(), rect); ASSERT_NE(rectangles.end(), iter); auto index = std::distance(rectangles.begin(), iter); EXPECT_FALSE(rect_found[index]); rect_found[index] = true; } EXPECT_TRUE(std::all_of(rect_found.begin(), rect_found.end(), [](bool b){return b;})); } TEST(geometry, rectangles_clear) { using namespace geom; std::vector const rectangles_vec = { {Point{1, 2}, Size{Width{10}, Height{11}}}, {Point{3, 4}, Size{Width{12}, Height{13}}}, {Point{5, 6}, Size{Width{14}, Height{15}}} }; Rectangles rectangles; Rectangles const rectangles_empty; for (auto const& rect : rectangles_vec) rectangles.add(rect); EXPECT_NE(rectangles_empty, rectangles); rectangles.clear(); EXPECT_EQ(rectangles_empty, rectangles); } TEST(geometry, rectangles_bounding_rectangle) { using namespace geom; std::vector const rectangles_vec = { {Point{0, 0}, Size{Width{10}, Height{5}}}, {Point{2, 2}, Size{Width{4}, Height{1}}}, {Point{1, 1}, Size{Width{10}, Height{5}}}, {Point{-1, -2}, Size{Width{3}, Height{3}}}, {Point{-2, -3}, Size{Width{14}, Height{10}}}, {Point{-2, -3}, Size{Width{14}, Height{10}}} }; std::vector const expected_bounding_rectangles = { {Point{0, 0}, Size{Width{10}, Height{5}}}, {Point{0, 0}, Size{Width{10}, Height{5}}}, {Point{0, 0}, Size{Width{11}, Height{6}}}, {Point{-1, -2}, Size{Width{12}, Height{8}}}, {Point{-2, -3}, Size{Width{14}, Height{10}}}, {Point{-2, -3}, Size{Width{14}, Height{10}}} }; Rectangles rectangles; EXPECT_EQ(Rectangle(), rectangles.bounding_rectangle()); for (size_t i = 0; i < rectangles_vec.size(); i++) { rectangles.add(rectangles_vec[i]); EXPECT_EQ(expected_bounding_rectangles[i], rectangles.bounding_rectangle()) << "i=" << i; } } TEST(geometry, rectangles_equality) { using namespace geom; std::vector const rectangles_vec1 = { {Point{0, 0}, Size{Width{10}, Height{5}}}, {Point{2, 2}, Size{Width{4}, Height{1}}}, {Point{1, 1}, Size{Width{10}, Height{5}}}, {Point{-1, -2}, Size{Width{3}, Height{3}}}, {Point{-2, -3}, Size{Width{14}, Height{10}}}, {Point{-2, -3}, Size{Width{14}, Height{10}}} }; std::vector const rectangles_vec2 = { {Point{0, 0}, Size{Width{10}, Height{5}}}, {Point{1, 1}, Size{Width{10}, Height{5}}}, {Point{-1, -2}, Size{Width{3}, Height{3}}}, {Point{-2, -3}, Size{Width{14}, Height{10}}} }; std::vector reverse_rectangles_vec1{rectangles_vec1}; std::reverse(reverse_rectangles_vec1.begin(), reverse_rectangles_vec1.end()); Rectangles rectangles1; Rectangles rectangles2; Rectangles rectangles3; Rectangles rectangles_empty; for (auto const& rect : rectangles_vec1) rectangles1.add(rect); for (auto const& rect : rectangles_vec2) rectangles2.add(rect); for (auto const& rect : reverse_rectangles_vec1) rectangles3.add(rect); EXPECT_EQ(rectangles1, rectangles3); EXPECT_NE(rectangles1, rectangles2); EXPECT_NE(rectangles2, rectangles3); EXPECT_NE(rectangles1, rectangles_empty); } TEST(geometry, rectangles_copy_assign) { using namespace geom; std::vector const rectangles_vec = { {Point{0, 0}, Size{Width{10}, Height{5}}}, {Point{2, 2}, Size{Width{4}, Height{1}}}, {Point{0, 1}, Size{Width{10}, Height{5}}}, {Point{-1, -2}, Size{Width{3}, Height{3}}}, {Point{-5, -3}, Size{Width{14}, Height{10}}} }; Rectangles rectangles1; Rectangles rectangles2; for (auto const& rect : rectangles_vec) rectangles1.add(rect); rectangles2 = rectangles1; Rectangles const rectangles3{rectangles2}; EXPECT_EQ(rectangles1, rectangles2); EXPECT_EQ(rectangles1, rectangles3); EXPECT_EQ(rectangles2, rectangles3); EXPECT_EQ(rectangles1.bounding_rectangle(), rectangles2.bounding_rectangle()); EXPECT_EQ(rectangles1.bounding_rectangle(), rectangles3.bounding_rectangle()); EXPECT_EQ(rectangles2.bounding_rectangle(), rectangles3.bounding_rectangle()); } TEST(geometry, rectangles_confine) { using namespace geom; std::vector const rectangles_vec = { {geom::Point{0,0}, geom::Size{800,600}}, {geom::Point{0,600}, geom::Size{100,100}}, {geom::Point{800,0}, geom::Size{100,100}} }; std::vector> const point_tuples{ std::make_tuple(geom::Point{0,0}, geom::Point{0,0}), std::make_tuple(geom::Point{900,50}, geom::Point{899,50}), std::make_tuple(geom::Point{850,100}, geom::Point{850,99}), std::make_tuple(geom::Point{801,100}, geom::Point{801,99}), std::make_tuple(geom::Point{800,101}, geom::Point{799,101}), std::make_tuple(geom::Point{800,600}, geom::Point{799,599}), std::make_tuple(geom::Point{-1,700}, geom::Point{0,699}), std::make_tuple(geom::Point{-1,-1}, geom::Point{0,0}), std::make_tuple(geom::Point{-1,50}, geom::Point{0,50}), std::make_tuple(geom::Point{799,-1}, geom::Point{799,0}), std::make_tuple(geom::Point{800,-1}, geom::Point{800,0}) }; Rectangles rectangles; for (auto const& rect : rectangles_vec) rectangles.add(rect); for (auto const& t : point_tuples) { geom::Point confined_point{std::get<0>(t)}; geom::Point const expected_point{std::get<1>(t)}; rectangles.confine(confined_point); EXPECT_EQ(expected_point, confined_point); } } mir-0.1.8+14.04.20140411/tests/unit-tests/geometry/test-point.cpp0000644000015301777760000000261212322054223024623 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/geometry/point.h" #include #include namespace geom = mir::geometry; TEST(geometry, point) { using namespace geom; Point const pointx2y4{X(2), Y(4)}; EXPECT_EQ(X(2), pointx2y4.x); EXPECT_EQ(Y(4), pointx2y4.y); Point const copy = pointx2y4; EXPECT_EQ(X(2), copy.x); EXPECT_EQ(Y(4), copy.y); EXPECT_EQ(pointx2y4, copy); Point defaultValue; EXPECT_EQ(X(0), defaultValue.x); EXPECT_EQ(Y(0), defaultValue.y); EXPECT_NE(pointx2y4, defaultValue); } TEST(geometry, point_is_usable) { using namespace geom; int x = 0; int y = 1; auto p = Point{x, y}; EXPECT_EQ(X(x), p.x); EXPECT_EQ(Y(y), p.y); } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/0000755000015301777760000000000012322054703021255 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_the_session_container_implementation.cpp0000644000015301777760000000527312322054223032516 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/scene/application_session.h" #include "src/server/scene/default_session_container.h" #include "mir_test_doubles/stub_shell_session.h" #include #include #include namespace mf = mir::frontend; namespace ms = mir::scene; namespace msh = mir::shell; namespace mtd = mir::test::doubles; TEST(DefaultSessionContainer, for_each) { using namespace ::testing; ms::DefaultSessionContainer container; auto session1 = std::make_shared(); auto session2 = std::make_shared(); container.insert_session(session1); container.insert_session(session2); struct local { MOCK_METHOD1(see, void(std::shared_ptr const&)); void operator()(std::shared_ptr const& session) { see(session); } } functor; InSequence seq; EXPECT_CALL(functor, see(Eq(session1))); EXPECT_CALL(functor, see(Eq(session2))); container.for_each(std::ref(functor)); } TEST(DefaultSessionContainer, successor_of) { using namespace ::testing; ms::DefaultSessionContainer container; auto session1 = std::make_shared(); auto session2 = std::make_shared(); auto session3 = std::make_shared(); container.insert_session(session1); container.insert_session(session2); container.insert_session(session3); EXPECT_EQ(session2, container.successor_of(session1)); EXPECT_EQ(session3, container.successor_of(session2)); EXPECT_EQ(session1, container.successor_of(session3)); // Successor of no session is the last session. EXPECT_EQ(session3, container.successor_of(std::shared_ptr())); } TEST(DefaultSessionContainer, invalid_session_throw_behavior) { using namespace ::testing; ms::DefaultSessionContainer container; EXPECT_THROW({ container.remove_session(std::make_shared()); }, std::logic_error); } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_default_focus_mechanism.cpp0000644000015301777760000000763712322054247027707 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/scene/application_session.h" #include "src/server/shell/default_focus_mechanism.h" #include "mir/shell/session.h" #include "mir/shell/surface_creation_parameters.h" #include "src/server/scene/basic_surface.h" #include "mir/graphics/display_configuration.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_buffer_stream.h" #include "mir_test_doubles/mock_surface_factory.h" #include "mir_test_doubles/mock_shell_session.h" #include "mir_test_doubles/mock_surface.h" #include "mir_test_doubles/mock_surface_ranker.h" #include "mir_test_doubles/stub_input_targeter.h" #include "mir_test_doubles/mock_input_targeter.h" #include #include #include namespace mc = mir::compositor; namespace msh = mir::shell; namespace ms = mir::scene; namespace mf = mir::frontend; namespace mt = mir::test; namespace mtd = mir::test::doubles; TEST(DefaultFocusMechanism, mechanism_notifies_default_surface_of_focus_changes) { using namespace ::testing; NiceMock app1, app2; auto const mock_surface1 = std::make_shared>(); auto const mock_surface2 = std::make_shared>(); auto const surface_ranker = std::make_shared(); ON_CALL(app1, default_surface()).WillByDefault(Return(mock_surface1)); ON_CALL(app2, default_surface()).WillByDefault(Return(mock_surface2)); msh::DefaultFocusMechanism focus_mechanism( std::make_shared(), surface_ranker); InSequence seq; EXPECT_CALL(*mock_surface1, configure(mir_surface_attrib_focus, mir_surface_focused)).Times(1); EXPECT_CALL(*surface_ranker, raise(_)).Times(1); EXPECT_CALL(*mock_surface1, configure(mir_surface_attrib_focus, mir_surface_unfocused)).Times(1); EXPECT_CALL(*mock_surface2, configure(mir_surface_attrib_focus, mir_surface_focused)).Times(1); EXPECT_CALL(*surface_ranker, raise(_)).Times(1); focus_mechanism.set_focus_to(mt::fake_shared(app1)); focus_mechanism.set_focus_to(mt::fake_shared(app2)); } TEST(DefaultFocusMechanism, sets_input_focus) { using namespace ::testing; NiceMock app1; NiceMock mock_surface; auto const surface_ranker = std::make_shared(); { InSequence seq; EXPECT_CALL(app1, default_surface()).Times(1) .WillOnce(Return(mt::fake_shared(mock_surface))); EXPECT_CALL(app1, default_surface()).Times(1) .WillOnce(Return(std::shared_ptr())); } NiceMock targeter; msh::DefaultFocusMechanism focus_mechanism(mt::fake_shared(targeter), surface_ranker); { InSequence seq; EXPECT_CALL(mock_surface, take_input_focus(_)).Times(1); // When we have no default surface. EXPECT_CALL(targeter, focus_cleared()).Times(1); // When we have no session. EXPECT_CALL(targeter, focus_cleared()).Times(1); } EXPECT_CALL(*surface_ranker, raise(_)).Times(1); focus_mechanism.set_focus_to(mt::fake_shared(app1)); focus_mechanism.set_focus_to(mt::fake_shared(app1)); focus_mechanism.set_focus_to(std::shared_ptr()); } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_gl_pixel_buffer.cpp0000644000015301777760000001630212322054247026161 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/scene/gl_pixel_buffer.h" #include "mir/graphics/gl_context.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/mock_gl.h" #include #include #include namespace mg = mir::graphics; namespace geom = mir::geometry; namespace ms = mir::scene; namespace mtd = mir::test::doubles; namespace { struct MockGLContext : public mg::GLContext { ~MockGLContext() noexcept {} MOCK_CONST_METHOD0(make_current, void()); MOCK_CONST_METHOD0(release_current, void()); }; struct WrappingGLContext : public mg::GLContext { WrappingGLContext(mg::GLContext& wrapped) : wrapped(wrapped) { } ~WrappingGLContext() noexcept {} void make_current() const { wrapped.make_current(); } void release_current() const { wrapped.release_current(); } mg::GLContext& wrapped; }; class GLPixelBufferTest : public ::testing::Test { public: GLPixelBufferTest() : context{new WrappingGLContext{mock_context}} { using namespace testing; ON_CALL(mock_buffer, size()) .WillByDefault(Return(geom::Size{51, 71})); } testing::NiceMock mock_gl; testing::NiceMock mock_buffer; MockGLContext mock_context; std::unique_ptr context; }; ACTION(FillPixels) { auto const pixels = static_cast(arg6); size_t const width = arg2; size_t const height = arg3; for (uint32_t i = 0; i < width * height; ++i) { pixels[i] = i; } } ACTION(FillPixelsRGBA) { auto const pixels = static_cast(arg6); size_t const width = arg2; size_t const height = arg3; for (uint32_t i = 0; i < width * height; ++i) { pixels[i] = ((i << 16) & 0x00ff0000) | /* Move R to new position */ ((i) & 0x0000ff00) | /* G remains at same position */ ((i >> 16) & 0x000000ff) | /* Move B to new position */ ((i) & 0xff000000); /* A remains at same position */ } } } TEST_F(GLPixelBufferTest, returns_empty_if_not_initialized) { ms::GLPixelBuffer pixels{std::move(context)}; EXPECT_EQ(geom::Size(), pixels.size()); EXPECT_EQ(geom::Stride(), pixels.stride()); } TEST_F(GLPixelBufferTest, returns_data_from_bgra_buffer_texture) { using namespace testing; GLuint const tex{10}; GLuint const fbo{20}; uint32_t const width{mock_buffer.size().width.as_uint32_t()}; uint32_t const height{mock_buffer.size().height.as_uint32_t()}; { InSequence s; /* The GL context is made current */ EXPECT_CALL(mock_context, make_current()); /* The texture and framebuffer are prepared */ EXPECT_CALL(mock_gl, glGenTextures(_,_)) .WillOnce(SetArgPointee<1>(tex)); EXPECT_CALL(mock_gl, glBindTexture(_,tex)); EXPECT_CALL(mock_gl, glGenFramebuffers(_,_)) .WillOnce(SetArgPointee<1>(fbo)); EXPECT_CALL(mock_gl, glBindFramebuffer(_,fbo)); /* The buffer texture is read as BGRA */ EXPECT_CALL(mock_buffer, bind_to_texture()); EXPECT_CALL(mock_gl, glFramebufferTexture2D(_,_,_,tex,0)); EXPECT_CALL(mock_gl, glReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, _)) .WillOnce(FillPixels()); /* at destruction */ EXPECT_CALL(mock_context, make_current()); EXPECT_CALL(mock_gl, glDeleteTextures(_,_)); EXPECT_CALL(mock_gl, glDeleteFramebuffers(_,_)); } ms::GLPixelBuffer pixels{std::move(context)}; pixels.fill_from(mock_buffer); auto data = pixels.as_argb_8888(); EXPECT_EQ(mock_buffer.size(), pixels.size()); EXPECT_EQ(geom::Stride{width * 4}, pixels.stride()); /* Check that data has been properly y-flipped */ EXPECT_EQ(1, static_cast(data)[width * (height - 1) + 1]); EXPECT_EQ(width * (height / 2), static_cast(data)[width * (height / 2)]); EXPECT_EQ(width * (height - 1), static_cast(data)[0]); EXPECT_EQ(width - 1, static_cast(data)[width * height - 1]); } TEST_F(GLPixelBufferTest, returns_data_from_rgba_buffer_texture) { using namespace testing; GLuint const tex{10}; GLuint const fbo{20}; uint32_t const width{mock_buffer.size().width.as_uint32_t()}; uint32_t const height{mock_buffer.size().height.as_uint32_t()}; { InSequence s; /* The GL context is made current */ EXPECT_CALL(mock_context, make_current()); /* The texture and framebuffer are prepared */ EXPECT_CALL(mock_gl, glGenTextures(_,_)) .WillOnce(SetArgPointee<1>(tex)); EXPECT_CALL(mock_gl, glBindTexture(_,tex)); EXPECT_CALL(mock_gl, glGenFramebuffers(_,_)) .WillOnce(SetArgPointee<1>(fbo)); EXPECT_CALL(mock_gl, glBindFramebuffer(_,fbo)); /* Try to read the FBO as BGRA but fail */ EXPECT_CALL(mock_buffer, bind_to_texture()); EXPECT_CALL(mock_gl, glFramebufferTexture2D(_,_,_,tex,0)); EXPECT_CALL(mock_gl, glGetError()) .WillOnce(Return(GL_NO_ERROR)); EXPECT_CALL(mock_gl, glReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, _)); EXPECT_CALL(mock_gl, glGetError()) .WillOnce(Return(GL_INVALID_ENUM)); /* Read as RGBA */ EXPECT_CALL(mock_gl, glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, _)) .WillOnce(FillPixelsRGBA()); /* at destruction */ EXPECT_CALL(mock_context, make_current()); EXPECT_CALL(mock_gl, glDeleteTextures(_,_)); EXPECT_CALL(mock_gl, glDeleteFramebuffers(_,_)); } ms::GLPixelBuffer pixels{std::move(context)}; pixels.fill_from(mock_buffer); auto data = pixels.as_argb_8888(); EXPECT_EQ(mock_buffer.size(), pixels.size()); EXPECT_EQ(geom::Stride{width * 4}, pixels.stride()); /* Check that data has been properly y-flipped and converted to argb_8888 */ EXPECT_EQ(1, static_cast(data)[width * (height - 1) + 1]); EXPECT_EQ(width * (height / 2), static_cast(data)[width * (height / 2)]); EXPECT_EQ(width * (height - 1), static_cast(data)[0]); EXPECT_EQ(width - 1, static_cast(data)[width * height - 1]); } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_surface_impl.cpp0000644000015301777760000002623012322054247025477 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/scene/basic_surface.h" #include "mir/scene/surface_observer.h" #include "mir/scene/surface_event_source.h" #include "src/server/report/null_report_factory.h" #include "mir/frontend/event_sink.h" #include "mir/graphics/display_configuration.h" #include "mir_test_doubles/stub_buffer_stream.h" #include "mir_test_doubles/mock_buffer_stream.h" #include "mir_test_doubles/mock_input_targeter.h" #include "mir_test_doubles/null_event_sink.h" #include "mir_test_doubles/null_surface_configurator.h" #include "mir_test_doubles/mock_surface_configurator.h" #include "mir_test/fake_shared.h" #include "mir_test/event_matchers.h" #include #include #include #include namespace ms = mir::scene; namespace msh = mir::shell; namespace mf = mir::frontend; namespace mc = mir::compositor; namespace mg = mir::graphics; namespace mi = mir::input; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mt::doubles; namespace mr = mir::report; namespace { struct MockEventSink : public mf::EventSink { ~MockEventSink() noexcept(true) {} MOCK_METHOD1(handle_event, void(MirEvent const&)); MOCK_METHOD1(handle_lifecycle_event, void(MirLifecycleState)); MOCK_METHOD1(handle_display_config_change, void(mg::DisplayConfiguration const&)); }; typedef testing::NiceMock StubBufferStream; struct Surface : testing::Test { std::shared_ptr const buffer_stream; Surface() : buffer_stream(std::make_shared()), null_configurator(std::make_shared()) { using namespace testing; ON_CALL(*buffer_stream, stream_size()).WillByDefault(Return(geom::Size())); ON_CALL(*buffer_stream, get_stream_pixel_format()).WillByDefault(Return(mir_pixel_format_abgr_8888)); ON_CALL(*buffer_stream, swap_client_buffers(_, _)) .WillByDefault(InvokeArgument<1>(nullptr)); } mf::SurfaceId stub_id; std::shared_ptr null_configurator; std::shared_ptr const report = mr::null_scene_report(); }; } TEST_F(Surface, attributes) { using namespace testing; ms::BasicSurface surf( std::string("stub"), geom::Rectangle{{},{}}, false, buffer_stream, std::shared_ptr(), null_configurator, report); EXPECT_THROW({ surf.configure(static_cast(111), 222); }, std::logic_error); } TEST_F(Surface, types) { using namespace testing; ms::BasicSurface surf( std::string("stub"), geom::Rectangle{{},{}}, false, buffer_stream, std::shared_ptr(), null_configurator, report); EXPECT_EQ(mir_surface_type_normal, surf.type()); EXPECT_EQ(mir_surface_type_utility, surf.configure(mir_surface_attrib_type, mir_surface_type_utility)); EXPECT_EQ(mir_surface_type_utility, surf.type()); EXPECT_THROW({ surf.configure(mir_surface_attrib_type, 999); }, std::logic_error); EXPECT_THROW({ surf.configure(mir_surface_attrib_type, -1); }, std::logic_error); EXPECT_EQ(mir_surface_type_utility, surf.type()); EXPECT_EQ(mir_surface_type_dialog, surf.configure(mir_surface_attrib_type, mir_surface_type_dialog)); EXPECT_EQ(mir_surface_type_dialog, surf.type()); EXPECT_EQ(mir_surface_type_freestyle, surf.configure(mir_surface_attrib_type, mir_surface_type_freestyle)); EXPECT_EQ(mir_surface_type_freestyle, surf.type()); } TEST_F(Surface, states) { using namespace testing; ms::BasicSurface surf( std::string("stub"), geom::Rectangle{{},{}}, false, buffer_stream, std::shared_ptr(), null_configurator, report); EXPECT_EQ(mir_surface_state_restored, surf.state()); EXPECT_EQ(mir_surface_state_vertmaximized, surf.configure(mir_surface_attrib_state, mir_surface_state_vertmaximized)); EXPECT_EQ(mir_surface_state_vertmaximized, surf.state()); EXPECT_THROW({ surf.configure(mir_surface_attrib_state, 999); }, std::logic_error); EXPECT_THROW({ surf.configure(mir_surface_attrib_state, -1); }, std::logic_error); EXPECT_EQ(mir_surface_state_vertmaximized, surf.state()); EXPECT_EQ(mir_surface_state_minimized, surf.configure(mir_surface_attrib_state, mir_surface_state_minimized)); EXPECT_EQ(mir_surface_state_minimized, surf.state()); EXPECT_EQ(mir_surface_state_fullscreen, surf.configure(mir_surface_attrib_state, mir_surface_state_fullscreen)); EXPECT_EQ(mir_surface_state_fullscreen, surf.state()); } bool operator==(MirEvent const& a, MirEvent const& b) { // We will always fill unused bytes with zero, so memcmp is accurate... return !memcmp(&a, &b, sizeof(MirEvent)); } TEST_F(Surface, emits_resize_events) { using namespace testing; geom::Size const new_size{123, 456}; auto sink = std::make_shared(); auto const observer = std::make_shared(stub_id, sink); ms::BasicSurface surf( std::string("stub"), geom::Rectangle{{},{}}, false, buffer_stream, std::shared_ptr(), null_configurator, report); surf.add_observer(observer); MirEvent e; memset(&e, 0, sizeof e); e.type = mir_event_type_resize; e.resize.surface_id = stub_id.as_value(); e.resize.width = new_size.width.as_int(); e.resize.height = new_size.height.as_int(); EXPECT_CALL(*sink, handle_event(e)) .Times(1); surf.resize(new_size); EXPECT_EQ(new_size, surf.size()); } TEST_F(Surface, emits_resize_events_only_on_change) { using namespace testing; geom::Size const new_size{123, 456}; geom::Size const new_size2{789, 1011}; auto sink = std::make_shared(); auto const observer = std::make_shared(stub_id, sink); ms::BasicSurface surf( std::string("stub"), geom::Rectangle{{},{}}, false, buffer_stream, std::shared_ptr(), null_configurator, report); surf.add_observer(observer); MirEvent e; memset(&e, 0, sizeof e); e.type = mir_event_type_resize; e.resize.surface_id = stub_id.as_value(); e.resize.width = new_size.width.as_int(); e.resize.height = new_size.height.as_int(); EXPECT_CALL(*sink, handle_event(e)) .Times(1); MirEvent e2; memset(&e2, 0, sizeof e2); e2.type = mir_event_type_resize; e2.resize.surface_id = stub_id.as_value(); e2.resize.width = new_size2.width.as_int(); e2.resize.height = new_size2.height.as_int(); EXPECT_CALL(*sink, handle_event(e2)) .Times(1); surf.resize(new_size); EXPECT_EQ(new_size, surf.size()); surf.resize(new_size); EXPECT_EQ(new_size, surf.size()); surf.resize(new_size2); EXPECT_EQ(new_size2, surf.size()); surf.resize(new_size2); EXPECT_EQ(new_size2, surf.size()); } TEST_F(Surface, remembers_alpha) { ms::BasicSurface surf( std::string("stub"), geom::Rectangle{{},{}}, false, buffer_stream, std::shared_ptr(), null_configurator, report); EXPECT_FLOAT_EQ(1.0f, surf.alpha()); surf.set_alpha(0.5f); EXPECT_FLOAT_EQ(0.5f, surf.alpha()); surf.set_alpha(0.25f); EXPECT_FLOAT_EQ(0.25f, surf.alpha()); surf.set_alpha(0.0f); EXPECT_FLOAT_EQ(0.0f, surf.alpha()); surf.set_alpha(1.0f); EXPECT_FLOAT_EQ(1.0f, surf.alpha()); } TEST_F(Surface, sends_focus_notifications_when_focus_gained_and_lost) { using namespace testing; MockEventSink sink; { InSequence seq; EXPECT_CALL(sink, handle_event(mt::SurfaceEvent(mir_surface_attrib_focus, mir_surface_focused))) .Times(1); EXPECT_CALL(sink, handle_event(mt::SurfaceEvent(mir_surface_attrib_focus, mir_surface_unfocused))) .Times(1); } auto const observer = std::make_shared(stub_id, mt::fake_shared(sink)); ms::BasicSurface surf( std::string("stub"), geom::Rectangle{{},{}}, false, buffer_stream, std::shared_ptr(), null_configurator, report); surf.add_observer(observer); surf.configure(mir_surface_attrib_focus, mir_surface_focused); surf.configure(mir_surface_attrib_focus, mir_surface_unfocused); } TEST_F(Surface, configurator_selects_attribute_values) { using namespace testing; mtd::MockSurfaceConfigurator configurator; EXPECT_CALL(configurator, select_attribute_value(_, mir_surface_attrib_state, mir_surface_state_restored)).Times(1) .WillOnce(Return(mir_surface_state_minimized)); EXPECT_CALL(configurator, attribute_set(_, mir_surface_attrib_state, mir_surface_state_minimized)).Times(1); ms::BasicSurface surf( std::string("stub"), geom::Rectangle{{},{}}, false, buffer_stream, std::shared_ptr(), mt::fake_shared(configurator), report); EXPECT_EQ(mir_surface_state_minimized, surf.configure(mir_surface_attrib_state, mir_surface_state_restored)); } TEST_F(Surface, take_input_focus) { using namespace ::testing; ms::BasicSurface surf( std::string("stub"), geom::Rectangle{{},{}}, false, buffer_stream, std::shared_ptr(), null_configurator, report); mtd::MockInputTargeter targeter; EXPECT_CALL(targeter, focus_changed(_)).Times(1); surf.take_input_focus(mt::fake_shared(targeter)); } TEST_F(Surface, with_most_recent_buffer_do_uses_compositor_buffer) { auto stub_buffer_stream = std::make_shared(); ms::BasicSurface surf( std::string("stub"), geom::Rectangle{{},{}}, false, stub_buffer_stream, std::shared_ptr(), null_configurator, report); mg::Buffer* buf_ptr{nullptr}; surf.with_most_recent_buffer_do( [&](mg::Buffer& buffer) { buf_ptr = &buffer; }); EXPECT_EQ(stub_buffer_stream->stub_compositor_buffer.get(), buf_ptr); } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_surface.cpp0000644000015301777760000003715012322054247024461 0ustar pbusernogroup00000000000000/* * 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: Thomas Voss */ #include "src/server/scene/basic_surface.h" #include "src/server/report/null_report_factory.h" #include "mir/frontend/event_sink.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/scene/surface_configurator.h" #include "mir/scene/surface_event_source.h" #include "mir/input/input_channel.h" #include "mir_test_doubles/mock_buffer_stream.h" #include "mir_test_doubles/mock_input_surface.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test/fake_shared.h" #include "gmock_set_arg.h" #include #include #include namespace mf = mir::frontend; namespace ms = mir::scene; namespace msh = mir::shell; namespace mg = mir::graphics; namespace mi = mir::input; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mt::doubles; namespace mr = mir::report; namespace { struct MockInputChannel : public mi::InputChannel { MOCK_CONST_METHOD0(server_fd, int()); MOCK_CONST_METHOD0(client_fd, int()); }; } TEST(SurfaceCreationParametersTest, default_creation_parameters) { using namespace geom; msh::SurfaceCreationParameters params; geom::Point const default_point{geom::X{0}, geom::Y{0}}; EXPECT_EQ(std::string(), params.name); EXPECT_EQ(Width(0), params.size.width); EXPECT_EQ(Height(0), params.size.height); EXPECT_EQ(default_point, params.top_left); EXPECT_EQ(mg::BufferUsage::undefined, params.buffer_usage); EXPECT_EQ(mir_pixel_format_invalid, params.pixel_format); EXPECT_EQ(msh::a_surface(), params); } TEST(SurfaceCreationParametersTest, builder_mutators) { using namespace geom; Size const size{1024, 768}; mg::BufferUsage const usage{mg::BufferUsage::hardware}; MirPixelFormat const format{mir_pixel_format_abgr_8888}; std::string name{"surface"}; auto params = msh::a_surface().of_name(name) .of_size(size) .of_buffer_usage(usage) .of_pixel_format(format); EXPECT_EQ(name, params.name); EXPECT_EQ(size, params.size); EXPECT_EQ(usage, params.buffer_usage); EXPECT_EQ(format, params.pixel_format); } TEST(SurfaceCreationParametersTest, equality) { using namespace geom; Size const size{1024, 768}; mg::BufferUsage const usage{mg::BufferUsage::hardware}; MirPixelFormat const format{mir_pixel_format_abgr_8888}; auto params0 = msh::a_surface().of_name("surface") .of_size(size) .of_buffer_usage(usage) .of_pixel_format(format); auto params1 = msh::a_surface().of_name("surface") .of_size(size) .of_buffer_usage(usage) .of_pixel_format(format); EXPECT_EQ(params0, params1); EXPECT_EQ(params1, params0); } TEST(SurfaceCreationParametersTest, inequality) { using namespace geom; std::vector const sizes{{1024, 768}, {1025, 768}}; std::vector const usages{mg::BufferUsage::hardware, mg::BufferUsage::software}; std::vector const formats{mir_pixel_format_abgr_8888, mir_pixel_format_bgr_888}; std::vector params_vec; for (auto const& size : sizes) { for (auto const& usage : usages) { for (auto const& format : formats) { auto cur_params = msh::a_surface().of_name("surface0") .of_size(size) .of_buffer_usage(usage) .of_pixel_format(format); params_vec.push_back(cur_params); size_t cur_index = params_vec.size() - 1; /* * Compare the current SurfaceCreationParameters with all the previously * created ones. */ for (size_t i = 0; i < cur_index; i++) { EXPECT_NE(params_vec[i], params_vec[cur_index]) << "cur_index: " << cur_index << " i: " << i; EXPECT_NE(params_vec[cur_index], params_vec[i]) << "cur_index: " << cur_index << " i: " << i; } } } } } namespace { class StubEventSink : public mir::frontend::EventSink { public: void handle_event(MirEvent const&) override {} void handle_lifecycle_event(MirLifecycleState) override {} void handle_display_config_change(mir::graphics::DisplayConfiguration const&) override {} }; struct MockEventSink : StubEventSink { MOCK_METHOD1(handle_event, void(MirEvent const&)); }; struct StubSurfaceConfigurator : ms::SurfaceConfigurator { int select_attribute_value(ms::Surface const&, MirSurfaceAttrib, int) override { return 0; } void attribute_set(ms::Surface const&, MirSurfaceAttrib, int) override { } }; struct SurfaceCreation : public ::testing::Test { virtual void SetUp() { using namespace testing; notification_count = 0; change_notification = [this]() { notification_count++; }; surface_name = "test_surfaceA"; pf = mir_pixel_format_abgr_8888; size = geom::Size{43, 420}; rect = geom::Rectangle{geom::Point{geom::X{0}, geom::Y{0}}, size}; stride = geom::Stride{4 * size.width.as_uint32_t()}; mock_buffer_stream = std::make_shared>(); ON_CALL(*mock_buffer_stream, swap_client_buffers(_, _)) .WillByDefault(InvokeArgument<1>(&stub_buffer)); } std::string surface_name; std::shared_ptr> mock_buffer_stream; MirPixelFormat pf; geom::Stride stride; geom::Size size; geom::Rectangle rect; std::shared_ptr const report = mr::null_scene_report(); std::function change_notification; int notification_count; mtd::StubBuffer stub_buffer; std::shared_ptr const stub_configurator = std::make_shared(); }; } TEST_F(SurfaceCreation, test_surface_queries_stream_for_pf) { using namespace testing; ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); EXPECT_CALL(*mock_buffer_stream, get_stream_pixel_format()) .Times(1) .WillOnce(Return(pf)); auto ret_pf = surf.pixel_format(); EXPECT_EQ(ret_pf, pf); } TEST_F(SurfaceCreation, test_surface_gets_right_name) { ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); EXPECT_EQ(surface_name, surf.name()); } TEST_F(SurfaceCreation, test_surface_queries_state_for_size) { ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); EXPECT_EQ(size, surf.size()); } TEST_F(SurfaceCreation, test_surface_next_buffer) { using namespace testing; ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); mtd::StubBuffer graphics_resource; EXPECT_CALL(*mock_buffer_stream, swap_client_buffers(_, _)) .Times(1) .WillOnce(InvokeArgument<1>(&graphics_resource)); surf.swap_buffers( nullptr, [&graphics_resource](mg::Buffer* result){ EXPECT_THAT(result, Eq(&graphics_resource)); }); } TEST_F(SurfaceCreation, test_surface_gets_ipc_from_stream) { using namespace testing; mtd::StubBuffer stub_buffer; ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); EXPECT_CALL(*mock_buffer_stream, swap_client_buffers(_, _)) .Times(1) .WillOnce(InvokeArgument<1>(&stub_buffer)); surf.swap_buffers( nullptr, [&stub_buffer](mg::Buffer* result){ EXPECT_THAT(result, Eq(&stub_buffer)); }); } TEST_F(SurfaceCreation, test_surface_gets_top_left) { ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); auto ret_top_left = surf.top_left(); EXPECT_EQ(geom::Point(), ret_top_left); } TEST_F(SurfaceCreation, test_surface_move_to) { geom::Point p{55, 66}; ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); surf.move_to(p); EXPECT_EQ(p, surf.top_left()); } TEST_F(SurfaceCreation, resize_updates_stream_and_state) { using namespace testing; geom::Size const new_size{123, 456}; EXPECT_CALL(*mock_buffer_stream, resize(new_size)) .Times(1); auto const mock_event_sink = std::make_shared(); auto const observer = std::make_shared(mf::SurfaceId(), mock_event_sink); ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); surf.add_observer(observer); ASSERT_THAT(surf.size(), Ne(new_size)); EXPECT_CALL(*mock_event_sink, handle_event(_)).Times(1); surf.resize(new_size); EXPECT_THAT(surf.size(), Eq(new_size)); } TEST_F(SurfaceCreation, duplicate_resize_ignored) { using namespace testing; geom::Size const new_size{123, 456}; auto const mock_event_sink = std::make_shared(); auto const observer = std::make_shared(mf::SurfaceId(), mock_event_sink); ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); surf.add_observer(observer); ASSERT_THAT(surf.size(), Ne(new_size)); EXPECT_CALL(*mock_buffer_stream, resize(new_size)).Times(1); EXPECT_CALL(*mock_event_sink, handle_event(_)).Times(1); surf.resize(new_size); EXPECT_THAT(surf.size(), Eq(new_size)); Mock::VerifyAndClearExpectations(mock_buffer_stream.get()); Mock::VerifyAndClearExpectations(mock_event_sink.get()); EXPECT_CALL(*mock_buffer_stream, resize(_)).Times(0); EXPECT_CALL(*mock_event_sink, handle_event(_)).Times(0); surf.resize(new_size); EXPECT_THAT(surf.size(), Eq(new_size)); } TEST_F(SurfaceCreation, unsuccessful_resize_does_not_update_state) { using namespace testing; geom::Size const new_size{123, 456}; EXPECT_CALL(*mock_buffer_stream, resize(new_size)) .Times(1) .WillOnce(Throw(std::runtime_error("bad resize"))); ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); EXPECT_THROW({ surf.resize(new_size); }, std::runtime_error); EXPECT_EQ(size, surf.size()); } TEST_F(SurfaceCreation, impossible_resize_throws) { using namespace testing; geom::Size const bad_sizes[] = { {0, 123}, {456, 0}, {-1, -1}, {78, -10}, {0, 0} }; ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); EXPECT_CALL(*mock_buffer_stream, resize(size)) .Times(0); for (auto &size : bad_sizes) { EXPECT_THROW({ surf.resize(size); }, std::logic_error); } } TEST_F(SurfaceCreation, test_get_input_channel) { auto mock_channel = std::make_shared(); ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, mock_channel, stub_configurator, report); EXPECT_EQ(mock_channel, surf.input_channel()); } TEST_F(SurfaceCreation, test_surface_set_alpha) { using namespace testing; float alpha = 0.5f; ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); surf.set_alpha(alpha); EXPECT_FLOAT_EQ(alpha, surf.alpha()); } TEST_F(SurfaceCreation, test_surface_force_requests_to_complete) { using namespace testing; EXPECT_CALL(*mock_buffer_stream, force_requests_to_complete()).Times(Exactly(1)); ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); surf.force_requests_to_complete(); } TEST_F(SurfaceCreation, test_surface_allow_framedropping) { using namespace testing; EXPECT_CALL(*mock_buffer_stream, allow_framedropping(true)) .Times(1); ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); surf.allow_framedropping(true); } TEST_F(SurfaceCreation, test_surface_next_buffer_tells_state_on_first_frame) { ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); surf.on_change(change_notification); mg::Buffer* buffer{nullptr}; auto const complete = [&buffer](mg::Buffer* new_buffer){ buffer = new_buffer; }; surf.swap_buffers(buffer, complete); surf.swap_buffers(buffer, complete); surf.swap_buffers(buffer, complete); surf.swap_buffers(buffer, complete); EXPECT_EQ(3, notification_count); } TEST_F(SurfaceCreation, input_fds) { using namespace testing; ms::BasicSurface surf( surface_name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report); EXPECT_THROW({ surf.client_input_fd(); }, std::logic_error); MockInputChannel channel; int const client_fd = 13; EXPECT_CALL(channel, client_fd()).Times(1).WillOnce(Return(client_fd)); ms::BasicSurface input_surf( surface_name, rect, false, mock_buffer_stream,mt::fake_shared(channel), stub_configurator, report); EXPECT_EQ(client_fd, input_surf.client_input_fd()); } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_session_manager.cpp0000644000015301777760000002347112322054247026207 0ustar pbusernogroup00000000000000/* * 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: Thomas Voss */ #include "src/server/scene/session_manager.h" #include "mir/compositor/buffer_stream.h" #include "src/server/scene/default_session_container.h" #include "mir/scene/surface.h" #include "mir/shell/session.h" #include "mir/shell/session_listener.h" #include "mir/shell/null_session_listener.h" #include "mir/shell/surface_creation_parameters.h" #include "src/server/scene/session_event_sink.h" #include "src/server/scene/basic_surface.h" #include "src/server/report/null_report_factory.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_buffer_stream.h" #include "mir_test_doubles/mock_surface_factory.h" #include "mir_test_doubles/mock_focus_setter.h" #include "mir_test_doubles/mock_session_listener.h" #include "mir_test_doubles/stub_buffer_stream.h" #include "mir_test_doubles/null_snapshot_strategy.h" #include "mir_test_doubles/null_surface_configurator.h" #include "mir_test_doubles/null_session_event_sink.h" #include #include namespace mc = mir::compositor; namespace mf = mir::frontend; namespace mi = mir::input; namespace msh = mir::shell; namespace ms = mir::scene; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace { struct MockSessionContainer : public ms::SessionContainer { MOCK_METHOD1(insert_session, void(std::shared_ptr const&)); MOCK_METHOD1(remove_session, void(std::shared_ptr const&)); MOCK_CONST_METHOD1(successor_of, std::shared_ptr(std::shared_ptr const&)); MOCK_CONST_METHOD1(for_each, void(std::function const&)>)); MOCK_METHOD0(lock, void()); MOCK_METHOD0(unlock, void()); ~MockSessionContainer() noexcept {} }; struct MockSessionEventSink : public ms::SessionEventSink { MOCK_METHOD1(handle_focus_change, void(std::shared_ptr const& session)); MOCK_METHOD0(handle_no_focus, void()); MOCK_METHOD1(handle_session_stopping, void(std::shared_ptr const& session)); }; struct SessionManagerSetup : public testing::Test { SessionManagerSetup() : session_manager(mt::fake_shared(surface_factory), mt::fake_shared(container), mt::fake_shared(focus_setter), std::make_shared(), std::make_shared(), mt::fake_shared(session_listener)) { using namespace ::testing; ON_CALL(container, successor_of(_)).WillByDefault(Return((std::shared_ptr()))); } std::shared_ptr dummy_surface = std::make_shared( std::string("stub"), geom::Rectangle{{},{}}, false, std::make_shared(), std::shared_ptr(), std::shared_ptr(), mir::report::null_scene_report()); mtd::MockSurfaceFactory surface_factory; testing::NiceMock container; // Inelegant but some tests need a stub testing::NiceMock focus_setter; // Inelegant but some tests need a stub msh::NullSessionListener session_listener; ms::SessionManager session_manager; }; } TEST_F(SessionManagerSetup, open_and_close_session) { using namespace ::testing; EXPECT_CALL(container, insert_session(_)).Times(1); EXPECT_CALL(container, remove_session(_)).Times(1); EXPECT_CALL(focus_setter, set_focus_to(_)); EXPECT_CALL(focus_setter, set_focus_to(std::shared_ptr())).Times(1); auto session = session_manager.open_session(__LINE__, "Visual Basic Studio", std::shared_ptr()); session_manager.close_session(session); } TEST_F(SessionManagerSetup, closing_session_removes_surfaces) { using namespace ::testing; EXPECT_CALL(surface_factory, create_surface(_, _, _)).Times(1); ON_CALL(surface_factory, create_surface(_, _, _)).WillByDefault( Return(dummy_surface)); EXPECT_CALL(container, insert_session(_)).Times(1); EXPECT_CALL(container, remove_session(_)).Times(1); EXPECT_CALL(focus_setter, set_focus_to(_)).Times(1); EXPECT_CALL(focus_setter, set_focus_to(std::shared_ptr())).Times(1); auto session = session_manager.open_session(__LINE__, "Visual Basic Studio", std::shared_ptr()); session->create_surface(msh::a_surface().of_size(geom::Size{geom::Width{1024}, geom::Height{768}})); session_manager.close_session(session); } TEST_F(SessionManagerSetup, new_applications_receive_focus) { using namespace ::testing; std::shared_ptr new_session; EXPECT_CALL(container, insert_session(_)).Times(1); EXPECT_CALL(focus_setter, set_focus_to(_)).WillOnce(SaveArg<0>(&new_session)); auto session = session_manager.open_session(__LINE__, "Visual Basic Studio", std::shared_ptr()); EXPECT_EQ(session, new_session); } TEST_F(SessionManagerSetup, create_surface_for_session_forwards_and_then_focuses_session) { using namespace ::testing; ON_CALL(surface_factory, create_surface(_, _, _)).WillByDefault( Return(dummy_surface)); // Once for session creation and once for surface creation { InSequence seq; EXPECT_CALL(focus_setter, set_focus_to(_)).Times(1); // Session creation EXPECT_CALL(surface_factory, create_surface(_, _, _)).Times(1); EXPECT_CALL(focus_setter, set_focus_to(_)).Times(1); // Post Surface creation } auto session1 = session_manager.open_session(__LINE__, "Weather Report", std::shared_ptr()); session_manager.create_surface_for(session1, msh::a_surface()); } namespace { struct SessionManagerSessionListenerSetup : public testing::Test { SessionManagerSessionListenerSetup() : session_manager(mt::fake_shared(surface_factory), mt::fake_shared(container), mt::fake_shared(focus_setter), std::make_shared(), std::make_shared(), mt::fake_shared(session_listener)) { using namespace ::testing; ON_CALL(container, successor_of(_)).WillByDefault(Return((std::shared_ptr()))); } mtd::MockSurfaceFactory surface_factory; testing::NiceMock container; // Inelegant but some tests need a stub testing::NiceMock focus_setter; // Inelegant but some tests need a stub mtd::MockSessionListener session_listener; ms::SessionManager session_manager; }; } TEST_F(SessionManagerSessionListenerSetup, session_listener_is_notified_of_lifecycle_and_focus) { using namespace ::testing; EXPECT_CALL(session_listener, starting(_)).Times(1); EXPECT_CALL(session_listener, focused(_)).Times(1); EXPECT_CALL(session_listener, stopping(_)).Times(1); EXPECT_CALL(session_listener, unfocused()).Times(1); auto session = session_manager.open_session(__LINE__, "XPlane", std::shared_ptr()); session_manager.close_session(session); } namespace { struct SessionManagerSessionEventsSetup : public testing::Test { SessionManagerSessionEventsSetup() : session_manager(mt::fake_shared(surface_factory), mt::fake_shared(container), mt::fake_shared(focus_setter), std::make_shared(), mt::fake_shared(session_event_sink), std::make_shared()) { using namespace ::testing; ON_CALL(container, successor_of(_)).WillByDefault(Return((std::shared_ptr()))); } mtd::MockSurfaceFactory surface_factory; testing::NiceMock container; // Inelegant but some tests need a stub testing::NiceMock focus_setter; // Inelegant but some tests need a stub MockSessionEventSink session_event_sink; ms::SessionManager session_manager; }; } TEST_F(SessionManagerSessionEventsSetup, session_event_sink_is_notified_of_lifecycle_and_focus) { using namespace ::testing; EXPECT_CALL(session_event_sink, handle_focus_change(_)).Times(2); auto session = session_manager.open_session(__LINE__, "XPlane", std::shared_ptr()); auto session1 = session_manager.open_session(__LINE__, "Bla", std::shared_ptr()); Mock::VerifyAndClearExpectations(&session_event_sink); InSequence s; EXPECT_CALL(session_event_sink, handle_session_stopping(_)).Times(1); EXPECT_CALL(container, successor_of(_)). WillOnce(Return(std::dynamic_pointer_cast(session))); EXPECT_CALL(session_event_sink, handle_focus_change(_)).Times(1); EXPECT_CALL(session_event_sink, handle_session_stopping(_)).Times(1); EXPECT_CALL(container, successor_of(_)). WillOnce(Return(std::shared_ptr())); EXPECT_CALL(session_event_sink, handle_no_focus()).Times(1); session_manager.close_session(session1); session_manager.close_session(session); } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_surface_stack.cpp0000644000015301777760000003762312322054247025653 0ustar pbusernogroup00000000000000/* * 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: Thomas Voss */ #include "src/server/scene/surface_stack.h" #include "mir/graphics/buffer_properties.h" #include "mir/geometry/rectangle.h" #include "mir/shell/surface_creation_parameters.h" #include "src/server/report/null_report_factory.h" #include "src/server/scene/basic_surface.h" #include "mir/input/input_channel_factory.h" #include "mir_test_doubles/stub_input_registrar.h" #include "mir_test_doubles/stub_input_channel.h" #include "mir_test_doubles/mock_input_registrar.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/stub_buffer_stream.h" #include #include #include #include #include #include namespace mc = mir::compositor; namespace mg = mir::graphics; namespace ms = mir::scene; namespace msh = mir::shell; namespace mf = mir::frontend; namespace mi = mir::input; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace mr = mir::report; namespace { struct MockFilterForScene : public mc::FilterForScene { // Can not mock operator overload so need to forward MOCK_METHOD1(filter, bool(mg::Renderable const&)); bool operator()(mg::Renderable const& r) { return filter(r); } }; struct StubFilterForScene : public mc::FilterForScene { MOCK_METHOD1(filter, bool(mg::Renderable const&)); bool operator()(mg::Renderable const&) { return true; } }; struct MockOperatorForScene : public mc::OperatorForScene { MOCK_METHOD1(renderable_operator, void(mg::Renderable const&)); void operator()(mg::Renderable const& state) { renderable_operator(state); } }; struct StubOperatorForScene : public mc::OperatorForScene { void operator()(mg::Renderable const&) { } }; struct StubInputChannelFactory : public mi::InputChannelFactory { std::shared_ptr make_input_channel() { return std::make_shared(); } }; struct StubInputChannel : public mi::InputChannel { StubInputChannel(int server_fd, int client_fd) : s_fd(server_fd), c_fd(client_fd) { } int client_fd() const { return c_fd; } int server_fd() const { return s_fd; } int const s_fd; int const c_fd; }; class MockCallback { public: MOCK_METHOD0(call, void()); }; struct SurfaceStack : public ::testing::Test { void SetUp() { using namespace testing; default_params = msh::a_surface().of_size(geom::Size{geom::Width{1024}, geom::Height{768}}); stub_surface1 = std::make_shared( std::string("stub"), geom::Rectangle{{},{}}, false, std::make_shared(), std::shared_ptr(), std::shared_ptr(), report); stub_surface2 = std::make_shared( std::string("stub"), geom::Rectangle{{},{}}, false, std::make_shared(), std::shared_ptr(), std::shared_ptr(), report); stub_surface3 = std::make_shared( std::string("stub"), geom::Rectangle{{},{}}, false, std::make_shared(), std::shared_ptr(), std::shared_ptr(), report); } mtd::StubInputRegistrar input_registrar; msh::SurfaceCreationParameters default_params; std::shared_ptr stub_surface1; std::shared_ptr stub_surface2; std::shared_ptr stub_surface3; std::shared_ptr const report = mr::null_scene_report(); }; } TEST_F(SurfaceStack, owns_surface_from_add_to_remove) { using namespace testing; ms::SurfaceStack stack(mt::fake_shared(input_registrar), report); auto const use_count = stub_surface1.use_count(); stack.add_surface(stub_surface1, default_params.depth, default_params.input_mode); EXPECT_THAT(stub_surface1.use_count(), Gt(use_count)); stack.remove_surface(stub_surface1); EXPECT_THAT(stub_surface1.use_count(), Eq(use_count)); } TEST_F(SurfaceStack, surface_skips_surface_that_is_filtered_out) { using namespace ::testing; ms::SurfaceStack stack(mt::fake_shared(input_registrar), report); stack.add_surface(stub_surface1, default_params.depth, default_params.input_mode); stack.add_surface(stub_surface2, default_params.depth, default_params.input_mode); stack.add_surface(stub_surface3, default_params.depth, default_params.input_mode); MockFilterForScene filter; MockOperatorForScene renderable_operator; Sequence seq1, seq2; EXPECT_CALL(filter, filter(Ref(*stub_surface1))) .InSequence(seq1) .WillOnce(Return(true)); EXPECT_CALL(filter, filter(Ref(*stub_surface2))) .InSequence(seq1) .WillOnce(Return(false)); EXPECT_CALL(filter, filter(Ref(*stub_surface3))) .InSequence(seq1) .WillOnce(Return(true)); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface1))) .InSequence(seq2); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface3))) .InSequence(seq2); stack.for_each_if(filter, renderable_operator); } TEST_F(SurfaceStack, stacking_order) { using namespace ::testing; ms::SurfaceStack stack(mt::fake_shared(input_registrar), report); stack.add_surface(stub_surface1, default_params.depth, default_params.input_mode); stack.add_surface(stub_surface2, default_params.depth, default_params.input_mode); stack.add_surface(stub_surface3, default_params.depth, default_params.input_mode); StubFilterForScene filter; MockOperatorForScene renderable_operator; Sequence seq; EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface1))) .InSequence(seq); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface2))) .InSequence(seq); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface3))) .InSequence(seq); stack.for_each_if(filter, renderable_operator); } TEST_F(SurfaceStack, notify_on_create_and_destroy_surface) { using namespace ::testing; NiceMock mock_cb; EXPECT_CALL(mock_cb, call()) .Times(2); ms::SurfaceStack stack(mt::fake_shared(input_registrar), report); stack.set_change_callback(std::bind(&MockCallback::call, &mock_cb)); stack.add_surface(stub_surface1, default_params.depth, default_params.input_mode); stack.remove_surface(stub_surface1); } TEST_F(SurfaceStack, surfaces_are_emitted_by_layer) { using namespace ::testing; ms::SurfaceStack stack(mt::fake_shared(input_registrar), report); stack.add_surface(stub_surface1, ms::DepthId{0}, default_params.input_mode); stack.add_surface(stub_surface2, ms::DepthId{1}, default_params.input_mode); stack.add_surface(stub_surface3, ms::DepthId{0}, default_params.input_mode); StubFilterForScene filter; MockOperatorForScene renderable_operator; Sequence seq; EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface1))) .InSequence(seq); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface3))) .InSequence(seq); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface2))) .InSequence(seq); stack.for_each_if(filter, renderable_operator); } TEST_F(SurfaceStack, input_registrar_is_notified_of_surfaces) { using namespace ::testing; mtd::MockInputRegistrar registrar; ms::SurfaceStack stack(mt::fake_shared(registrar), report); Sequence seq; EXPECT_CALL(registrar, input_channel_opened(_,_,_)) .InSequence(seq); EXPECT_CALL(registrar, input_channel_closed(_)) .InSequence(seq); stack.add_surface(stub_surface1, default_params.depth, default_params.input_mode); stack.remove_surface(stub_surface1); } TEST_F(SurfaceStack, input_registrar_is_notified_of_input_monitor_scene) { using namespace ::testing; mtd::MockInputRegistrar registrar; ms::SurfaceStack stack(mt::fake_shared(registrar), report); Sequence seq; EXPECT_CALL(registrar, input_channel_opened(_,_,mi::InputReceptionMode::receives_all_input)) .InSequence(seq); EXPECT_CALL(registrar, input_channel_closed(_)) .InSequence(seq); stack.add_surface(stub_surface1, default_params.depth, mi::InputReceptionMode::receives_all_input); stack.remove_surface(stub_surface1); } TEST_F(SurfaceStack, raise_to_top_alters_render_ordering) { using namespace ::testing; ms::SurfaceStack stack(mt::fake_shared(input_registrar), report); stack.add_surface(stub_surface1, default_params.depth, default_params.input_mode); stack.add_surface(stub_surface2, default_params.depth, default_params.input_mode); stack.add_surface(stub_surface3, default_params.depth, default_params.input_mode); StubFilterForScene filter; MockOperatorForScene renderable_operator; Sequence seq; // After surface creation. EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface1))) .InSequence(seq); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface2))) .InSequence(seq); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface3))) .InSequence(seq); // After raising surface1 EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface2))) .InSequence(seq); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface3))) .InSequence(seq); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface1))) .InSequence(seq); stack.for_each_if(filter, renderable_operator); stack.raise(stub_surface1); stack.for_each_if(filter, renderable_operator); } TEST_F(SurfaceStack, depth_id_trumps_raise) { using namespace ::testing; ms::SurfaceStack stack(mt::fake_shared(input_registrar), report); stack.add_surface(stub_surface1, ms::DepthId{0}, default_params.input_mode); stack.add_surface(stub_surface2, ms::DepthId{0}, default_params.input_mode); stack.add_surface(stub_surface3, ms::DepthId{1}, default_params.input_mode); StubFilterForScene filter; MockOperatorForScene renderable_operator; Sequence seq; // After surface creation. EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface1))) .InSequence(seq); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface2))) .InSequence(seq); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface3))) .InSequence(seq); // After raising surface1 EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface2))) .InSequence(seq); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface1))) .InSequence(seq); EXPECT_CALL(renderable_operator, renderable_operator(Ref(*stub_surface3))) .InSequence(seq); stack.for_each_if(filter, renderable_operator); stack.raise(stub_surface1); stack.for_each_if(filter, renderable_operator); } TEST_F(SurfaceStack, raise_throw_behavior) { using namespace ::testing; ms::SurfaceStack stack(mt::fake_shared(input_registrar), report); std::shared_ptr null_surface{nullptr}; EXPECT_THROW({ stack.raise(null_surface); }, std::runtime_error); } namespace { struct UniqueOperatorForScene : public mc::OperatorForScene { UniqueOperatorForScene(const char *&owner) : owner(owner) { } void operator()(const mg::Renderable &) { ASSERT_STREQ("", owner); owner = "UniqueOperatorForScene"; std::this_thread::yield(); owner = ""; } const char *&owner; }; void tinker_scene(mc::Scene &scene, const char *&owner, const std::atomic_bool &done) { while (!done.load()) { std::this_thread::yield(); std::lock_guard lock(scene); ASSERT_STREQ("", owner); owner = "tinkerer"; std::this_thread::yield(); owner = ""; } } } TEST_F(SurfaceStack, is_locked_during_iteration) { using namespace ::testing; ms::SurfaceStack stack(mt::fake_shared(input_registrar), report); stack.add_surface(stub_surface1, default_params.depth, default_params.input_mode); stack.add_surface(stub_surface2, default_params.depth, default_params.input_mode); stack.add_surface(stub_surface3, default_params.depth, default_params.input_mode); const char *owner = ""; UniqueOperatorForScene op(owner); std::atomic_bool done(false); std::thread tinkerer(tinker_scene, std::ref(stack), std::ref(owner), std::ref(done)); for (int i = 0; i < 1000; i++) { stack.lock(); ASSERT_STREQ("", owner); owner = "main_before"; std::this_thread::yield(); owner = ""; stack.unlock(); MockFilterForScene filter; Sequence seq1; EXPECT_CALL(filter, filter(Ref(*stub_surface1))) .InSequence(seq1) .WillOnce(Return(true)); EXPECT_CALL(filter, filter(Ref(*stub_surface2))) .InSequence(seq1) .WillOnce(Return(false)); EXPECT_CALL(filter, filter(Ref(*stub_surface3))) .InSequence(seq1) .WillOnce(Return(true)); stack.for_each_if(filter, op); stack.lock(); ASSERT_STREQ("", owner); owner = "main_after"; std::this_thread::yield(); owner = ""; stack.unlock(); } done = true; tinkerer.join(); } TEST_F(SurfaceStack, is_recursively_lockable) { ms::SurfaceStack stack(mt::fake_shared(input_registrar), report); StubFilterForScene filter; StubOperatorForScene op; stack.lock(); stack.for_each_if(filter, op); stack.unlock(); stack.lock(); stack.lock(); stack.lock(); stack.unlock(); stack.unlock(); stack.unlock(); } TEST_F(SurfaceStack, generate_renderlist) { using namespace testing; size_t num_surfaces{3}; ms::SurfaceStack stack( mt::fake_shared(input_registrar), report); std::list> surfacelist; for(auto i = 0u; i < num_surfaces; i++) { auto const surface = std::make_shared( std::string("stub"), geom::Rectangle{geom::Point{3 * i, 4 * i},geom::Size{1 * i, 2 * i}}, true, std::make_shared(), std::shared_ptr(), std::shared_ptr(), report); surfacelist.emplace_back(surface); stack.add_surface(surface, default_params.depth, default_params.input_mode); } auto list = stack.generate_renderable_list(); ASSERT_THAT(list.size(), Eq(num_surfaces)); auto surface_it = surfacelist.begin(); for(auto& renderable : list) { EXPECT_THAT(renderable->screen_position(), Eq((*surface_it++)->screen_position())); } for(auto& surface : surfacelist) stack.remove_surface(surface); } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_broadcasting_session_event_sink.cpp0000644000015301777760000000536012322054223031451 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/scene/broadcasting_session_event_sink.h" #include "mir_test_doubles/stub_shell_session.h" #include "mir_test/fake_shared.h" #include namespace ms = mir::scene; namespace msh = mir::shell; namespace mtd = mir::test::doubles; namespace mt = mir::test; TEST(BroadcastingSessionEventSinkTest, emits_and_handles_focus_change) { mtd::StubShellSession session1; std::vector handler_called(3, nullptr); ms::BroadcastingSessionEventSink events; for (auto& h : handler_called) { events.register_focus_change_handler( [&h](std::shared_ptr const& session) { h = session.get(); }); } events.handle_focus_change(mt::fake_shared(session1)); for (unsigned int i = 0; i < handler_called.size(); i++) { EXPECT_EQ(&session1, handler_called[i]) << " i = " << i; } } TEST(BroadcastingSessionEventSinkTest, emits_and_handles_no_focus) { mtd::StubShellSession session1; std::vector handler_called(3, 0); ms::BroadcastingSessionEventSink events; for (auto& h : handler_called) { events.register_no_focus_handler( [&h] { h = 1; }); } events.handle_no_focus(); for (unsigned int i = 0; i < handler_called.size(); i++) { EXPECT_EQ(1, handler_called[i]) << " i = " << i; } } TEST(BroadcastingSessionEventSinkTest, emits_and_handles_session_stopping) { mtd::StubShellSession session1; std::vector handler_called(3, nullptr); ms::BroadcastingSessionEventSink events; for (auto& h : handler_called) { events.register_session_stopping_handler( [&h](std::shared_ptr const& session) { h = session.get(); }); } events.handle_session_stopping(mt::fake_shared(session1)); for (unsigned int i = 0; i < handler_called.size(); i++) { EXPECT_EQ(&session1, handler_called[i]) << " i = " << i; } } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_threaded_snapshot_strategy.cpp0000644000015301777760000000560012322054223030437 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/scene/threaded_snapshot_strategy.h" #include "src/server/scene/pixel_buffer.h" #include "mir/shell/surface_buffer_access.h" #include "mir/graphics/buffer.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test/fake_shared.h" #include #include #include #include #include namespace mg = mir::graphics; namespace ms = mir::scene; namespace msh = mir::shell; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace geom = mir::geometry; class StubSurfaceBufferAccess : public msh::SurfaceBufferAccess { public: ~StubSurfaceBufferAccess() noexcept {} void with_most_recent_buffer_do( std::function const& exec) { exec(buffer); } mtd::StubBuffer buffer; }; class MockPixelBuffer : public ms::PixelBuffer { public: ~MockPixelBuffer() noexcept {} MOCK_METHOD1(fill_from, void(mg::Buffer& buffer)); MOCK_METHOD0(as_argb_8888, void const*()); MOCK_CONST_METHOD0(size, geom::Size()); MOCK_CONST_METHOD0(stride, geom::Stride()); }; TEST(ThreadedSnapshotStrategyTest, takes_snapshot) { using namespace testing; void const* pixels{reinterpret_cast(0xabcd)}; geom::Size size{10, 11}; geom::Stride stride{123}; MockPixelBuffer pixel_buffer; StubSurfaceBufferAccess buffer_access; EXPECT_CALL(pixel_buffer, fill_from(Ref(buffer_access.buffer))); EXPECT_CALL(pixel_buffer, as_argb_8888()) .WillOnce(Return(pixels)); EXPECT_CALL(pixel_buffer, size()) .WillOnce(Return(size)); EXPECT_CALL(pixel_buffer, stride()) .WillOnce(Return(stride)); ms::ThreadedSnapshotStrategy strategy{mt::fake_shared(pixel_buffer)}; std::atomic snapshot_taken{false}; msh::Snapshot snapshot; strategy.take_snapshot_of( mt::fake_shared(buffer_access), [&](msh::Snapshot const& s) { snapshot = s; snapshot_taken = true; }); while (!snapshot_taken) std::this_thread::sleep_for(std::chrono::milliseconds{1}); EXPECT_EQ(size, snapshot.size); EXPECT_EQ(stride, snapshot.stride); EXPECT_EQ(pixels, snapshot.pixels); } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_surface_allocator.cpp0000644000015301777760000000435612322054223026515 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/scene/surface_allocator.h" #include "mir_test_doubles/mock_buffer_stream.h" #include #include namespace { struct MockBufferStreamFactory : public ms::BufferStreamFactory { MockBufferStreamFactory() { } MOCK_METHOD1(create_buffer_stream, std::shared_ptr(mc::BufferProperties const&)); }; struct MockInputChannelFactory : public mi::InputChannelFactory { MOCK_METHOD0(make_input_channel, std::shared_ptr()); }; struct SurfaceAllocator : public testing::Test; { void SetUp() { using namespace testing; default_size = geom::Size{geom::Width{9}, geom::Height{4}}; ON_CALL(mock_buffer_stream, stream_size()) .WillByDefault(Return(default_size)); ON_CALL(mock_stream_factory, create_buffer_stream(_)) .WillByDefault(Return(mt::fake_shared(mock_buffer_stream))); } geom::Size default_size; MockBufferStreamFactory mock_stream_factory; MockInputChannelFactory mock_input_factory; mtd::MockBufferStream mock_buffer_stream; }; } TEST_F(SurfaceStack, surface_creation) { msh::SurfaceCreationParameters const& params; EXPECT_CALL(buffer_stream_factory, create_buffer_stream(params)) .Times(1); EXPECT_CALL(mock_buffer_stream, stream_size()) .Times(1); EXPECT_CALL(mock_input_factory, make_input_channel()) .Times(1); ms::SurfaceAllocator allocator(mock_stream_factory, mock_input_factory); std::function cb; allocator.create_surface(params, cb); } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_global_event_sender.cpp0000644000015301777760000000425612322054223027025 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/scene/global_event_sender.h" #include "src/server/scene/session_container.h" #include "mir_test_doubles/mock_frontend_surface.h" #include "mir_test_doubles/mock_shell_session.h" #include "mir_test_doubles/stub_display_configuration.h" #include "mir_test/fake_shared.h" #include #include namespace mt=mir::test; namespace mtd=mir::test::doubles; namespace ms = mir::scene; namespace msh=mir::shell; namespace { class MockSessionStorage : public ms::SessionContainer { public: MOCK_METHOD1(insert_session, void(std::shared_ptr const&)); MOCK_METHOD1(remove_session, void(std::shared_ptr const&)); MOCK_CONST_METHOD1(for_each, void(std::function const&)>)); MOCK_CONST_METHOD1(successor_of, std::shared_ptr(std::shared_ptr const&)); }; } TEST(GlobalEventSender, sender) { using namespace testing; MockSessionStorage mock_storage; std::function const&)> called_fn; EXPECT_CALL(mock_storage, for_each(_)) .Times(1) .WillOnce(SaveArg<0>(&called_fn)); ms::GlobalEventSender g_sender(mt::fake_shared(mock_storage)); mtd::StubDisplayConfig stub_display_config; g_sender.handle_display_config_change(stub_display_config); auto mock_session = std::make_shared(); EXPECT_CALL(*mock_session, send_display_config(_)) .Times(1); called_fn(mock_session); } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_application_session.cpp0000644000015301777760000002625712322054247027105 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/scene/application_session.h" #include "mir/graphics/buffer.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/shell/null_session_listener.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_surface_factory.h" #include "mir_test_doubles/mock_surface.h" #include "mir_test_doubles/mock_session_listener.h" #include "mir_test_doubles/stub_display_configuration.h" #include "mir_test_doubles/null_snapshot_strategy.h" #include "mir_test_doubles/null_event_sink.h" #include "mir/shell/surface.h" #include #include namespace mc = mir::compositor; namespace mf = mir::frontend; namespace msh = mir::shell; namespace ms = mir::scene; namespace mi = mir::input; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace { static std::shared_ptr make_mock_surface() { return std::make_shared(); } class MockSnapshotStrategy : public ms::SnapshotStrategy { public: ~MockSnapshotStrategy() noexcept {} MOCK_METHOD2(take_snapshot_of, void(std::shared_ptr const&, msh::SnapshotCallback const&)); }; struct MockSnapshotCallback { void operator()(msh::Snapshot const& snapshot) { operator_call(snapshot); } MOCK_METHOD1(operator_call, void(msh::Snapshot const&)); }; MATCHER(IsNullSnapshot, "") { return arg.size == mir::geometry::Size{} && arg.stride == mir::geometry::Stride{} && arg.pixels == nullptr; } } TEST(ApplicationSession, create_and_destroy_surface) { using namespace ::testing; auto mock_surface = make_mock_surface(); mtd::NullEventSink sender; mtd::MockSurfaceFactory surface_factory; EXPECT_CALL(surface_factory, create_surface(_, _, _)) .WillOnce(Return(mock_surface)); mtd::MockSessionListener listener; EXPECT_CALL(listener, surface_created(_, _)) .Times(1); EXPECT_CALL(listener, destroying_surface(_, _)) .Times(1); ms::ApplicationSession session( mt::fake_shared(surface_factory), __LINE__, "Foo", std::make_shared(), mt::fake_shared(listener), mt::fake_shared(sender)); msh::SurfaceCreationParameters params; auto surf = session.create_surface(params); session.destroy_surface(surf); } TEST(ApplicationSession, listener_notified_of_surface_destruction_on_session_destruction) { using namespace ::testing; auto mock_surface = make_mock_surface(); mtd::NullEventSink sender; mtd::MockSurfaceFactory surface_factory; ON_CALL(surface_factory, create_surface(_,_,_)).WillByDefault(Return(mock_surface)); EXPECT_CALL(surface_factory, create_surface(_, _, _)); mtd::MockSessionListener listener; EXPECT_CALL(listener, surface_created(_, _)).Times(1); EXPECT_CALL(listener, destroying_surface(_, _)).Times(1); { ms::ApplicationSession session( mt::fake_shared(surface_factory), __LINE__, "Foo", std::make_shared(), mt::fake_shared(listener), mt::fake_shared(sender)); msh::SurfaceCreationParameters params; session.create_surface(params); } } TEST(ApplicationSession, default_surface_is_first_surface) { using namespace ::testing; mtd::NullEventSink sender; mtd::MockSurfaceFactory surface_factory; { InSequence seq; EXPECT_CALL(surface_factory, create_surface(_, _, _)).Times(1) .WillOnce(Return(make_mock_surface())); EXPECT_CALL(surface_factory, create_surface(_, _, _)).Times(1) .WillOnce(Return(make_mock_surface())); EXPECT_CALL(surface_factory, create_surface(_, _, _)).Times(1) .WillOnce(Return(make_mock_surface())); } ms::ApplicationSession app_session( mt::fake_shared(surface_factory), __LINE__, "Foo", std::make_shared(), std::make_shared(), mt::fake_shared(sender)); msh::SurfaceCreationParameters params; auto id1 = app_session.create_surface(params); auto id2 = app_session.create_surface(params); auto id3 = app_session.create_surface(params); auto default_surf = app_session.default_surface(); EXPECT_EQ(app_session.get_surface(id1), default_surf); app_session.destroy_surface(id1); default_surf = app_session.default_surface(); EXPECT_EQ(app_session.get_surface(id2), default_surf); app_session.destroy_surface(id2); default_surf = app_session.default_surface(); EXPECT_EQ(app_session.get_surface(id3), default_surf); app_session.destroy_surface(id3); } TEST(ApplicationSession, session_visbility_propagates_to_surfaces) { using namespace ::testing; mtd::NullEventSink sender; auto mock_surface = make_mock_surface(); mtd::MockSurfaceFactory surface_factory; ON_CALL(surface_factory, create_surface(_, _, _)).WillByDefault(Return(mock_surface)); ms::ApplicationSession app_session( mt::fake_shared(surface_factory), __LINE__, "Foo", std::make_shared(), std::make_shared(), mt::fake_shared(sender)); EXPECT_CALL(surface_factory, create_surface(_, _, _)); { InSequence seq; EXPECT_CALL(*mock_surface, hide()).Times(1); EXPECT_CALL(*mock_surface, show()).Times(1); } msh::SurfaceCreationParameters params; auto surf = app_session.create_surface(params); app_session.hide(); app_session.show(); app_session.destroy_surface(surf); } TEST(ApplicationSession, get_invalid_surface_throw_behavior) { using namespace ::testing; mtd::NullEventSink sender; mtd::MockSurfaceFactory surface_factory; ms::ApplicationSession app_session( mt::fake_shared(surface_factory), __LINE__, "Foo", std::make_shared(), std::make_shared(), mt::fake_shared(sender)); mf::SurfaceId invalid_surface_id(1); EXPECT_THROW({ app_session.get_surface(invalid_surface_id); }, std::runtime_error); } TEST(ApplicationSession, destroy_invalid_surface_throw_behavior) { using namespace ::testing; mtd::NullEventSink sender; mtd::MockSurfaceFactory surface_factory; ms::ApplicationSession app_session( mt::fake_shared(surface_factory), __LINE__, "Foo", std::make_shared(), std::make_shared(), mt::fake_shared(sender)); mf::SurfaceId invalid_surface_id(1); EXPECT_THROW({ app_session.destroy_surface(invalid_surface_id); }, std::runtime_error); } TEST(ApplicationSession, takes_snapshot_of_default_surface) { using namespace ::testing; mtd::MockSurfaceFactory surface_factory; mtd::NullEventSink sender; auto const default_surface = make_mock_surface(); auto const default_surface_buffer_access = std::static_pointer_cast(default_surface); auto const snapshot_strategy = std::make_shared(); EXPECT_CALL(surface_factory, create_surface(_,_,_)) .WillOnce(Return(default_surface)); EXPECT_CALL(*snapshot_strategy, take_snapshot_of(default_surface_buffer_access, _)); ms::ApplicationSession app_session( mt::fake_shared(surface_factory), __LINE__, "Foo", snapshot_strategy, std::make_shared(), mt::fake_shared(sender)); auto surface = app_session.create_surface(msh::SurfaceCreationParameters{}); app_session.take_snapshot(msh::SnapshotCallback()); app_session.destroy_surface(surface); } TEST(ApplicationSession, returns_null_snapshot_if_no_default_surface) { using namespace ::testing; mtd::NullEventSink sender; mtd::MockSurfaceFactory surface_factory; auto snapshot_strategy = std::make_shared(); MockSnapshotCallback mock_snapshot_callback; ms::ApplicationSession app_session( mt::fake_shared(surface_factory), __LINE__, "Foo", snapshot_strategy, std::make_shared(), mt::fake_shared(sender)); EXPECT_CALL(*snapshot_strategy, take_snapshot_of(_,_)).Times(0); EXPECT_CALL(mock_snapshot_callback, operator_call(IsNullSnapshot())); app_session.take_snapshot(std::ref(mock_snapshot_callback)); } namespace { class MockEventSink : public mf::EventSink { public: MOCK_METHOD1(handle_event, void(MirEvent const&)); MOCK_METHOD1(handle_lifecycle_event, void(MirLifecycleState)); MOCK_METHOD1(handle_display_config_change, void(mir::graphics::DisplayConfiguration const&)); }; } TEST(ApplicationSession, display_config_sender) { using namespace ::testing; mtd::StubDisplayConfig stub_config; mtd::MockSurfaceFactory surface_factory; MockEventSink sender; EXPECT_CALL(sender, handle_display_config_change(testing::Ref(stub_config))) .Times(1); ms::ApplicationSession app_session( mt::fake_shared(surface_factory), __LINE__, "Foo", std::make_shared(), std::make_shared(), mt::fake_shared(sender)); app_session.send_display_config(stub_config); } TEST(ApplicationSession, lifecycle_event_sender) { using namespace ::testing; MirLifecycleState exp_state = mir_lifecycle_state_will_suspend; mtd::MockSurfaceFactory surface_factory; MockEventSink sender; ms::ApplicationSession app_session( mt::fake_shared(surface_factory), __LINE__, "Foo", std::make_shared(), std::make_shared(), mt::fake_shared(sender)); EXPECT_CALL(sender, handle_lifecycle_event(exp_state)).Times(1); app_session.set_lifecycle_state(mir_lifecycle_state_will_suspend); } TEST(ApplicationSession, process_id) { using namespace ::testing; pid_t const pid{__LINE__}; mtd::MockSurfaceFactory surface_factory; MockEventSink sender; ms::ApplicationSession app_session( mt::fake_shared(surface_factory), pid, "Foo", std::make_shared(), std::make_shared(), mt::fake_shared(sender)); EXPECT_THAT(app_session.process_id(), Eq(pid)); } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_basic_surface.cpp0000644000015301777760000002313612322054247025621 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/scene/basic_surface.h" #include "mir/frontend/event_sink.h" #include "mir/geometry/rectangle.h" #include "mir/scene/surface_configurator.h" #include "mir_test_doubles/mock_buffer_stream.h" #include "mir_test/fake_shared.h" #include "src/server/report/null_report_factory.h" #include #include #include namespace mc = mir::compositor; namespace mf = mir::frontend; namespace mi = mir::input; namespace mr = mir::report; namespace ms = mir::scene; namespace msh = mir::shell; namespace mt = mir::test; namespace mtd = mt::doubles; namespace geom = mir::geometry; namespace { class MockCallback { public: MOCK_METHOD0(call, void()); }; class StubEventSink : public mir::frontend::EventSink { public: void handle_event(MirEvent const&) override {} void handle_lifecycle_event(MirLifecycleState) override {} void handle_display_config_change(mir::graphics::DisplayConfiguration const&) override {} }; struct StubSurfaceConfigurator : ms::SurfaceConfigurator { int select_attribute_value(ms::Surface const&, MirSurfaceAttrib, int) override { return 0; } void attribute_set(ms::Surface const&, MirSurfaceAttrib, int) override { } }; struct BasicSurfaceTest : public testing::Test { void SetUp() { name = std::string("aa"); top_left = geom::Point{geom::X{4}, geom::Y{7}}; size = geom::Size{5, 9}; rect = geom::Rectangle{top_left, size}; null_change_cb = []{}; mock_change_cb = std::bind(&MockCallback::call, &mock_callback); } std::string name; geom::Point top_left; geom::Size size; geom::Rectangle rect; testing::NiceMock mock_callback; std::function null_change_cb; std::function mock_change_cb; std::shared_ptr> mock_buffer_stream = std::make_shared>(); std::shared_ptr const stub_configurator = std::make_shared(); std::shared_ptr const report = mr::null_scene_report(); }; } TEST_F(BasicSurfaceTest, basics) { ms::BasicSurface surface{ name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report}; EXPECT_EQ(name, surface.name()); EXPECT_EQ(rect.size, surface.size()); EXPECT_EQ(rect.top_left, surface.top_left()); EXPECT_FALSE(surface.shaped()); } TEST_F(BasicSurfaceTest, update_top_left) { EXPECT_CALL(mock_callback, call()) .Times(1); ms::BasicSurface surface{ name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report}; surface.on_change(mock_change_cb); EXPECT_EQ(rect.top_left, surface.top_left()); auto new_top_left = geom::Point{geom::X{6}, geom::Y{10}}; surface.move_to(new_top_left); EXPECT_EQ(new_top_left, surface.top_left()); } TEST_F(BasicSurfaceTest, update_size) { geom::Size const new_size{34, 56}; EXPECT_CALL(mock_callback, call()) .Times(1); ms::BasicSurface surface{ name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report}; surface.on_change(mock_change_cb); EXPECT_EQ(rect.size, surface.size()); EXPECT_NE(new_size, surface.size()); auto old_transformation = surface.transformation(); surface.resize(new_size); EXPECT_EQ(new_size, surface.size()); // Size no longer affects transformation: EXPECT_EQ(old_transformation, surface.transformation()); } TEST_F(BasicSurfaceTest, test_surface_set_transformation_updates_transform) { EXPECT_CALL(mock_callback, call()) .Times(1); ms::BasicSurface surface{ name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report}; surface.on_change(mock_change_cb); auto original_transformation = surface.transformation(); glm::mat4 trans{0.1f, 0.5f, 0.9f, 1.3f, 0.2f, 0.6f, 1.0f, 1.4f, 0.3f, 0.7f, 1.1f, 1.5f, 0.4f, 0.8f, 1.2f, 1.6f}; surface.set_transformation(trans); auto got = surface.transformation(); EXPECT_NE(original_transformation, got); EXPECT_EQ(trans, got); } TEST_F(BasicSurfaceTest, test_surface_set_alpha_notifies_changes) { using namespace testing; EXPECT_CALL(mock_callback, call()) .Times(1); ms::BasicSurface surface{ name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report}; surface.on_change(mock_change_cb); float alpha = 0.5f; surface.set_alpha(0.5f); EXPECT_THAT(alpha, FloatEq(surface.alpha())); } TEST_F(BasicSurfaceTest, test_surface_is_opaque_by_default) { using namespace testing; ms::BasicSurface surface{ name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report}; EXPECT_THAT(1.0f, FloatEq(surface.alpha())); EXPECT_FALSE(surface.shaped()); } TEST_F(BasicSurfaceTest, test_surface_visibility) { ms::BasicSurface surface{ name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report}; //not visible by default EXPECT_FALSE(surface.visible()); surface.set_hidden(false); //not renderable if no first frame has been posted by client, regardless of hide state EXPECT_FALSE(surface.visible()); surface.set_hidden(true); EXPECT_FALSE(surface.visible()); surface.frame_posted(); EXPECT_FALSE(surface.visible()); surface.set_hidden(false); EXPECT_TRUE(surface.visible()); } TEST_F(BasicSurfaceTest, test_surface_hidden_notifies_changes) { using namespace testing; EXPECT_CALL(mock_callback, call()) .Times(1); ms::BasicSurface surface{ name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report}; surface.on_change(mock_change_cb); surface.set_hidden(true); } TEST_F(BasicSurfaceTest, test_surface_frame_posted_notifies_changes) { using namespace testing; EXPECT_CALL(mock_callback, call()) .Times(1); ms::BasicSurface surface{ name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report}; surface.on_change(mock_change_cb); surface.frame_posted(); } // a 1x1 window at (1,1) will get events at (1,1) TEST_F(BasicSurfaceTest, default_region_is_surface_rectangle) { geom::Point pt(1,1); geom::Size one_by_one{geom::Width{1}, geom::Height{1}}; ms::BasicSurface surface{ name, geom::Rectangle{pt, one_by_one}, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report}; surface.on_change(mock_change_cb); std::vector contained_pt { geom::Point{geom::X{1}, geom::Y{1}} }; for(auto x = 0; x <= 3; x++) { for(auto y = 0; y <= 3; y++) { auto test_pt = geom::Point{x, y}; auto contains = surface.contains(test_pt); if (std::find(contained_pt.begin(), contained_pt.end(), test_pt) != contained_pt.end()) { EXPECT_TRUE(contains); } else { EXPECT_FALSE(contains); } } } } TEST_F(BasicSurfaceTest, set_input_region) { std::vector const rectangles = { {{geom::X{0}, geom::Y{0}}, {geom::Width{1}, geom::Height{1}}}, //region0 {{geom::X{1}, geom::Y{1}}, {geom::Width{1}, geom::Height{1}}} //region1 }; ms::BasicSurface surface{ name, rect, false, mock_buffer_stream, std::shared_ptr(), stub_configurator, report}; surface.on_change(mock_change_cb); surface.set_input_region(rectangles); std::vector contained_pt { //region0 points geom::Point{geom::X{0}, geom::Y{0}}, //region1 points geom::Point{geom::X{1}, geom::Y{1}}, }; for(auto x = 0; x <= 3; x++) { for(auto y = 0; y <= 3; y++) { auto test_pt = geom::Point{x, y}; auto contains = surface.contains(test_pt); if (std::find(contained_pt.begin(), contained_pt.end(), test_pt) != contained_pt.end()) { EXPECT_TRUE(contains); } else { EXPECT_FALSE(contains); } } } } mir-0.1.8+14.04.20140411/tests/unit-tests/scene/CMakeLists.txt0000644000015301777760000000153512322054223024016 0ustar pbusernogroup00000000000000list( APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_application_session.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_broadcasting_session_event_sink.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_default_focus_mechanism.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_gl_pixel_buffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_global_event_sender.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_session_manager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_the_session_container_implementation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_threaded_snapshot_strategy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_surface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_surface_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_basic_surface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_surface_stack.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_surface_controller.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/scene/test_surface_controller.cpp0000644000015301777760000000576712322054247026735 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/scene/surface_controller.h" #include "src/server/scene/surface_stack_model.h" #include "mir/scene/surface_factory.h" #include "mir/shell/surface_creation_parameters.h" #include "mir_test_doubles/mock_surface.h" #include "mir_test/fake_shared.h" #include #include namespace mf = mir::frontend; namespace msh = mir::shell; namespace ms = mir::scene; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace { struct MockSurfaceAllocator : public ms::SurfaceFactory { MOCK_METHOD1(create_surface, std::shared_ptr( msh::SurfaceCreationParameters const&)); }; struct MockSurfaceStackModel : public ms::SurfaceStackModel { MOCK_METHOD3(add_surface, void( std::shared_ptr const&, ms::DepthId depth, mir::input::InputReceptionMode input_mode)); MOCK_METHOD1(remove_surface, void(std::weak_ptr const&)); MOCK_METHOD1(raise, void(std::weak_ptr const&)); }; } TEST(SurfaceController, add_and_remove_surface) { using namespace ::testing; mtd::MockSurface mock_surface; std::shared_ptr const expect_surface = mt::fake_shared(mock_surface); auto const surface = std::make_shared(); testing::NiceMock mock_surface_allocator; MockSurfaceStackModel model; ms::SurfaceController controller(mt::fake_shared(mock_surface_allocator), mt::fake_shared(model)); InSequence seq; EXPECT_CALL(mock_surface_allocator, create_surface(_)).Times(1).WillOnce(Return(expect_surface)); EXPECT_CALL(mock_surface, add_observer(_)).Times(1); EXPECT_CALL(model, add_surface(_,_,_)).Times(1); EXPECT_CALL(model, remove_surface(_)).Times(1); auto actual_surface = controller.add_surface(msh::a_surface(), std::shared_ptr()); EXPECT_THAT(actual_surface, Eq(expect_surface)); controller.remove_surface(actual_surface); } TEST(SurfaceController, raise_surface) { using namespace ::testing; testing::NiceMock mock_surface_allocator; MockSurfaceStackModel model; ms::SurfaceController controller(mt::fake_shared(mock_surface_allocator), mt::fake_shared(model)); EXPECT_CALL(model, raise(_)).Times(1); controller.raise(std::weak_ptr()); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/0000755000015301777760000000000012322054703021760 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/0000755000015301777760000000000012322054703023400 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_fb_simple_swapper.cpp0000644000015301777760000002112312322054223030640 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/framebuffers.h" #include "src/platform/graphics/android/graphic_buffer_allocator.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/mock_hwc_composer_device_1.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_fb_hal_device.h" #include #include #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mtd=mir::test::doubles; namespace geom=mir::geometry; namespace { struct MockGraphicBufferAllocator : public mga::GraphicBufferAllocator { MOCK_METHOD3(alloc_buffer_platform, std::shared_ptr( geom::Size, MirPixelFormat, mga::BufferUsage use)); }; static int const display_width = 180; static int const display_height = 1010101; class PostingFBBundleTest : public ::testing::Test { public: virtual void SetUp() { using namespace testing; fbnum = 2; format = HAL_PIXEL_FORMAT_RGBA_8888; buffer1 = std::make_shared(); buffer2 = std::make_shared(); buffer3 = std::make_shared(); mock_allocator = std::make_shared(); mock_hwc_device = std::make_shared>(); mock_fb_hal = std::make_shared(display_width, display_height, format, fbnum); EXPECT_CALL(*mock_allocator, alloc_buffer_platform(_,_,_)) .Times(AtLeast(0)) .WillOnce(Return(buffer1)) .WillOnce(Return(buffer2)) .WillRepeatedly(Return(buffer3)); } int format; int fbnum; std::shared_ptr mock_fb_hal; std::shared_ptr mock_allocator; std::shared_ptr buffer1; std::shared_ptr buffer2; std::shared_ptr buffer3; std::shared_ptr mock_hwc_device; testing::NiceMock mock_egl; }; static int display_attribute_handler(struct hwc_composer_device_1*, int, uint32_t, const uint32_t* attribute_list, int32_t* values) { int i = 0; while(attribute_list[i] != HWC_DISPLAY_NO_ATTRIBUTE) { switch(attribute_list[i]) { case HWC_DISPLAY_WIDTH: values[i] = display_width; break; case HWC_DISPLAY_HEIGHT: values[i] = display_height; break; default: break; } i++; } //the attribute list should be at least this long, as some qcom drivers always deref attribute_list[5] EXPECT_EQ(5, i); return 0; } } TEST_F(PostingFBBundleTest, hwc_fb_size_allocation) { using namespace testing; unsigned int hwc_configs = 0xA1; EXPECT_CALL(*mock_hwc_device, getDisplayConfigs_interface(mock_hwc_device.get(),HWC_DISPLAY_PRIMARY,_,Pointee(1))) .Times(1) .WillOnce(DoAll(SetArgPointee<2>(hwc_configs), Return(0))); EXPECT_CALL(*mock_hwc_device, getDisplayAttributes_interface(mock_hwc_device.get(), HWC_DISPLAY_PRIMARY, hwc_configs,_,_)) .Times(1) .WillOnce(Invoke(display_attribute_handler)); auto display_size = mir::geometry::Size{display_width, display_height}; EXPECT_CALL(*mock_allocator, alloc_buffer_platform(display_size, _, mga::BufferUsage::use_framebuffer_gles)) .Times(2) .WillRepeatedly(Return(nullptr)); mga::Framebuffers framebuffers(mock_allocator, mock_hwc_device); EXPECT_EQ(display_size, framebuffers.fb_size()); } TEST_F(PostingFBBundleTest, hwc_fb_format_selection) { using namespace testing; EGLint const expected_egl_config_attr [] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_FRAMEBUFFER_TARGET_ANDROID, EGL_TRUE, EGL_NONE }; int visual_id = HAL_PIXEL_FORMAT_BGRA_8888; EGLDisplay fake_display = reinterpret_cast(0x11235813); EGLConfig fake_egl_config = reinterpret_cast(0x44); Sequence seq; EXPECT_CALL(mock_egl, eglGetDisplay(EGL_DEFAULT_DISPLAY)) .InSequence(seq) .WillOnce(Return(fake_display)); EXPECT_CALL(mock_egl, eglInitialize(fake_display,_,_)) .InSequence(seq); EXPECT_CALL(mock_egl, eglChooseConfig(fake_display,mtd::AttrMatches(expected_egl_config_attr),_,1,_)) .InSequence(seq) .WillOnce(DoAll(SetArgPointee<2>(fake_egl_config), SetArgPointee<4>(1), Return(EGL_TRUE))); EXPECT_CALL(mock_egl, eglGetConfigAttrib(fake_display, fake_egl_config, EGL_NATIVE_VISUAL_ID, _)) .InSequence(seq) .WillOnce(DoAll(SetArgPointee<3>(visual_id), Return(EGL_TRUE))); EXPECT_CALL(mock_egl, eglTerminate(fake_display)) .InSequence(seq); mga::Framebuffers framebuffers(mock_allocator, mock_hwc_device); EXPECT_EQ(mir_pixel_format_argb_8888, framebuffers.fb_format()); } //apparently this can happen if the display is in the 'unplugged state' TEST_F(PostingFBBundleTest, test_hwc_device_display_config_failure_throws) { using namespace testing; EXPECT_CALL(*mock_hwc_device, getDisplayConfigs_interface(mock_hwc_device.get(),HWC_DISPLAY_PRIMARY,_,_)) .Times(1) .WillOnce(Return(-1)); EXPECT_THROW({ mga::Framebuffers framebuffers(mock_allocator, mock_hwc_device); }, std::runtime_error); } //not all hwc11 implementations give a hint about their framebuffer formats in their configuration. //prefer abgr_8888 if we can't figure things out TEST_F(PostingFBBundleTest, hwc_version_11_format_selection_failure) { using namespace testing; EGLDisplay fake_display = reinterpret_cast(0x11235813); Sequence seq; EXPECT_CALL(mock_egl, eglGetDisplay(EGL_DEFAULT_DISPLAY)) .InSequence(seq) .WillOnce(Return(fake_display)); EXPECT_CALL(mock_egl, eglInitialize(fake_display,_,_)) .InSequence(seq); EXPECT_CALL(mock_egl, eglChooseConfig(_,_,_,_,_)) .InSequence(seq) .WillOnce(DoAll(SetArgPointee<4>(0), Return(EGL_TRUE))); EXPECT_CALL(mock_egl, eglTerminate(fake_display)) .InSequence(seq); mga::Framebuffers framebuffers(mock_allocator, mock_hwc_device); EXPECT_EQ(mir_pixel_format_abgr_8888, framebuffers.fb_format()); } TEST_F(PostingFBBundleTest, bundle_from_fb) { using namespace testing; auto display_size = geom::Size{display_width, display_height}; EXPECT_CALL(*mock_allocator, alloc_buffer_platform(display_size, mir_pixel_format_abgr_8888, mga::BufferUsage::use_framebuffer_gles)) .Times(fbnum) .WillRepeatedly(Return(nullptr)); mga::Framebuffers framebuffers(mock_allocator, mock_fb_hal); EXPECT_EQ(display_size, framebuffers.fb_size()); EXPECT_EQ(mir_pixel_format_abgr_8888, framebuffers.fb_format()); } //some drivers incorrectly report 0 buffers available. if this is true, we should alloc 2, the minimum requirement TEST_F(PostingFBBundleTest, determine_fbnum_always_reports_2_minimum) { using namespace testing; auto slightly_malformed_fb_hal_mock = std::make_shared(display_width, display_height, format, 0); EXPECT_CALL(*mock_allocator, alloc_buffer_platform(_,_,_)) .Times(2) .WillRepeatedly(Return(nullptr)); mga::Framebuffers framebuffers(mock_allocator, slightly_malformed_fb_hal_mock); } TEST_F(PostingFBBundleTest, last_rendered_returns_valid) { mga::Framebuffers framebuffers(mock_allocator, mock_fb_hal); auto test_buffer = framebuffers.last_rendered_buffer(); EXPECT_TRUE((test_buffer == buffer1) || (test_buffer == buffer2)); auto first_buffer = framebuffers.buffer_for_render(); auto first_buffer_ptr = first_buffer.get(); EXPECT_NE(first_buffer, framebuffers.last_rendered_buffer()); first_buffer.reset(); EXPECT_EQ(first_buffer_ptr, framebuffers.last_rendered_buffer().get()); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_sync_fence.cpp0000644000015301777760000000655612322054223027270 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/android/sync_fence.h" #include "mir_test_doubles/mock_fence.h" #include #include #include #include #include namespace mga = mir::graphics::android; namespace mtd = mir::test::doubles; namespace { struct MockFileOps : public mga::SyncFileOps { MOCK_METHOD3(ioctl, int(int,int,void*)); MOCK_METHOD1(dup, int(int)); MOCK_METHOD1(close, int(int)); }; } class SyncSwTest : public ::testing::Test { protected: virtual void SetUp() { mock_fops = std::make_shared>(); } int dummy_fd = 3; int invalid_fd = -1; std::shared_ptr mock_fops; }; MATCHER_P(TimeoutMatches, value, std::string("timeout should be: " + testing::PrintToString(value))) { int* timeout = static_cast(arg); if (!timeout) return false; return value == *timeout; } MATCHER_P(MergeMatches, value, std::string("merge should be: " + testing::PrintToString(value))) { auto argument = static_cast(arg); return argument->fd2 == value.fd2; } TEST_F(SyncSwTest, sync_wait) { EXPECT_CALL(*mock_fops, ioctl(dummy_fd, SYNC_IOC_WAIT, TimeoutMatches(-1))) .Times(1); mga::SyncFence fence1(mock_fops, dummy_fd); fence1.wait(); //will not call ioctl mga::SyncFence fence2(mock_fops, invalid_fd); fence2.wait(); } namespace { struct IoctlSetter { IoctlSetter(int fd) : fd(fd) { } int merge_setter(int, int, void* data) { auto b = static_cast(data); b->fence = fd; return 0; } int fd; }; } TEST_F(SyncSwTest, sync_merge_with_valid_fd) { using namespace testing; int dummy_fd2 = 44; int out_fd = 88; IoctlSetter setter(out_fd); struct sync_merge_data expected_data_in { dummy_fd2, "name", 0 }; EXPECT_CALL(*mock_fops, ioctl(dummy_fd, SYNC_IOC_MERGE, MergeMatches(expected_data_in))) .Times(1) .WillOnce(Invoke(&setter, &IoctlSetter::merge_setter)); mga::SyncFence fence1(mock_fops, dummy_fd); fence1.merge_with(dummy_fd2); } TEST_F(SyncSwTest, sync_merge_with_invalid_fd) { using namespace testing; EXPECT_CALL(*mock_fops, ioctl(dummy_fd, SYNC_IOC_MERGE, _)) .Times(0); mga::SyncFence fence1(mock_fops, invalid_fd); fence1.merge_with(dummy_fd); } TEST_F(SyncSwTest, copy_dups_fd) { using namespace testing; int fd2 = dummy_fd + 1; EXPECT_CALL(*mock_fops, dup(dummy_fd)) .Times(1) .WillOnce(Return(fd2));; mga::SyncFence fence(mock_fops, dummy_fd); EXPECT_EQ(fd2, fence.copy_native_handle()); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_hwc_wrapper.cpp0000644000015301777760000001024212322054247027466 0ustar pbusernogroup00000000000000/* * 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 "src/platform/graphics/android/real_hwc_wrapper.h" #include "src/platform/graphics/android/hwc_logger.h" #include "mir_test_doubles/mock_hwc_composer_device_1.h" #include #include namespace mga=mir::graphics::android; namespace mtd=mir::test::doubles; namespace { struct MockHwcLogger : public mga::HwcLogger { MOCK_CONST_METHOD1(log_list_submitted_to_prepare, void(hwc_display_contents_1_t const&)); MOCK_CONST_METHOD1(log_prepare_done, void(hwc_display_contents_1_t const&)); MOCK_CONST_METHOD1(log_set_list, void(hwc_display_contents_1_t const&)); }; } struct HwcWrapper : public ::testing::Test { HwcWrapper() : mock_device(std::make_shared>()), mock_logger(std::make_shared>()), virtual_display{nullptr}, external_display{nullptr}, primary_display{nullptr} { } int display_saving_fn( struct hwc_composer_device_1*, size_t sz, hwc_display_contents_1_t** displays) { switch (sz) { case 3: virtual_display = displays[2]; case 2: external_display = displays[1]; case 1: primary_display = displays[0]; default: break; } return 0; } hwc_display_contents_1_t list; std::shared_ptr const mock_device; std::shared_ptr const mock_logger; hwc_display_contents_1_t *virtual_display; hwc_display_contents_1_t *external_display; hwc_display_contents_1_t *primary_display; }; TEST_F(HwcWrapper, submits_correct_prepare_parameters) { using namespace testing; Sequence seq; EXPECT_CALL(*mock_logger, log_list_submitted_to_prepare(Ref(list))) .InSequence(seq); EXPECT_CALL(*mock_device, prepare_interface(mock_device.get(), 1, _)) .InSequence(seq) .WillOnce(Invoke(this, &HwcWrapper::display_saving_fn)); EXPECT_CALL(*mock_logger, log_prepare_done(Ref(list))) .InSequence(seq); mga::RealHwcWrapper wrapper(mock_device, mock_logger); wrapper.prepare(list); EXPECT_EQ(&list, primary_display); EXPECT_EQ(nullptr, virtual_display); EXPECT_EQ(nullptr, external_display); } TEST_F(HwcWrapper, throws_on_prepare_failure) { using namespace testing; mga::RealHwcWrapper wrapper(mock_device, mock_logger); EXPECT_CALL(*mock_device, prepare_interface(mock_device.get(), _, _)) .Times(1) .WillOnce(Return(-1)); EXPECT_THROW({ wrapper.prepare(list); }, std::runtime_error); } TEST_F(HwcWrapper, submits_correct_set_parameters) { using namespace testing; Sequence seq; EXPECT_CALL(*mock_logger, log_set_list(Ref(list))) .InSequence(seq); EXPECT_CALL(*mock_device, set_interface(mock_device.get(), 1, _)) .InSequence(seq) .WillOnce(Invoke(this, &HwcWrapper::display_saving_fn)); mga::RealHwcWrapper wrapper(mock_device, mock_logger); wrapper.set(list); EXPECT_EQ(&list, primary_display); EXPECT_EQ(nullptr, virtual_display); EXPECT_EQ(nullptr, external_display); } TEST_F(HwcWrapper, throws_on_set_failure) { using namespace testing; mga::RealHwcWrapper wrapper(mock_device, mock_logger); EXPECT_CALL(*mock_device, set_interface(mock_device.get(), _, _)) .Times(1) .WillOnce(Return(-1)); EXPECT_THROW({ wrapper.set(list); }, std::runtime_error); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_internal_client.cpp0000644000015301777760000000362312322054223030316 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/internal_client.h" #include "mir/graphics/internal_surface.h" #include #include namespace geom=mir::geometry; namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace { class StubInternalSurface : public mg::InternalSurface { public: geom::Size size() const { return geom::Size(); } MirPixelFormat pixel_format() const { return MirPixelFormat(); } void swap_buffers(mg::Buffer*&) { } }; } TEST(InternalClient, native_display) { auto surface = std::make_shared(); mga::InternalClient client; EXPECT_EQ(EGL_DEFAULT_DISPLAY, client.egl_native_display()); } TEST(InternalClient, native_window) { auto surface = std::make_shared(); mga::InternalClient client; ANativeWindow* native_window = static_cast(client.egl_native_window(surface)); /* check for basic window sanity */ ASSERT_NE(nullptr, native_window); EXPECT_NE(nullptr, native_window->queueBuffer); EXPECT_NE(nullptr, native_window->dequeueBuffer); EXPECT_NE(nullptr, native_window->query); EXPECT_NE(nullptr, native_window->perform); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_fb_device.cpp0000644000015301777760000001143712322054223027054 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_doubles/mock_fb_hal_device.h" #include "mir_test_doubles/mock_buffer.h" #include "src/platform/graphics/android/fb_device.h" #include "mir_test_doubles/mock_framebuffer_bundle.h" #include "mir_test_doubles/mock_android_hw.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/stub_renderable.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include "mir_test_doubles/mock_render_function.h" #include "mir_test_doubles/mock_swapping_gl_context.h" #include #include namespace mg=mir::graphics; namespace mtd=mir::test::doubles; namespace mga=mir::graphics::android; namespace geom=mir::geometry; namespace mt=mir::test; struct FBDevice : public ::testing::Test { virtual void SetUp() { using namespace testing; width = 413; height = 516; fbnum = 4; format = HAL_PIXEL_FORMAT_RGBA_8888; fb_hal_mock = std::make_shared>(width, height, format, fbnum); mock_buffer = std::make_shared>(); native_buffer = std::make_shared(); ON_CALL(*mock_buffer, native_buffer_handle()) .WillByDefault(Return(native_buffer)); } unsigned int width, height, format, fbnum; std::shared_ptr fb_hal_mock; std::shared_ptr mock_buffer; std::shared_ptr native_buffer; mtd::HardwareAccessMock hw_access_mock; mtd::MockSwappingGLContext mock_context; }; TEST_F(FBDevice, render_overlays_via_gl) { auto renderable1 = std::make_shared(); auto renderable2 = std::make_shared(); std::list> renderlist { renderable1, renderable2 }; mtd::MockRenderFunction mock_call_counter; testing::Sequence seq; EXPECT_CALL(mock_call_counter, called(testing::Ref(*renderable1))) .InSequence(seq); EXPECT_CALL(mock_call_counter, called(testing::Ref(*renderable2))) .InSequence(seq); EXPECT_CALL(mock_context, swap_buffers()) .InSequence(seq); mga::FBDevice fbdev(fb_hal_mock); fbdev.render_gl_and_overlays(mock_context, renderlist, [&](mg::Renderable const& renderable) { mock_call_counter.called(renderable); }); } TEST_F(FBDevice, commits_frame_via_post) { using namespace testing; EXPECT_CALL(*fb_hal_mock, post_interface(fb_hal_mock.get(), native_buffer->handle())) .Times(2) .WillOnce(Return(-1)) .WillOnce(Return(0)); mga::FBDevice fbdev(fb_hal_mock); EXPECT_THROW({ fbdev.post(*mock_buffer); }, std::runtime_error); fbdev.post(*mock_buffer); } TEST_F(FBDevice, sets_swapinterval_1_on_start) { EXPECT_CALL(*fb_hal_mock, setSwapInterval_interface(fb_hal_mock.get(), 1)) .Times(1); mga::FBDevice fbdev(fb_hal_mock); } //not all fb devices provide a swap interval hook. make sure we don't explode if thats the case TEST_F(FBDevice, does_not_segfault_if_null_swapinterval_hook) { fb_hal_mock->setSwapInterval = nullptr; mga::FBDevice fbdev(fb_hal_mock); } TEST_F(FBDevice, does_not_accept_orientation_changes) { mga::FBDevice fbdev(fb_hal_mock); EXPECT_FALSE(fbdev.apply_orientation(mir_orientation_left)); } TEST_F(FBDevice, can_screen_on_off) { fb_hal_mock->setSwapInterval = nullptr; using namespace testing; //constructor turns on Sequence seq; EXPECT_CALL(*fb_hal_mock, enableScreen_interface(_,1)) .InSequence(seq); EXPECT_CALL(*fb_hal_mock, enableScreen_interface(_,0)) .InSequence(seq); EXPECT_CALL(*fb_hal_mock, enableScreen_interface(_,0)) .InSequence(seq); EXPECT_CALL(*fb_hal_mock, enableScreen_interface(_,0)) .InSequence(seq); EXPECT_CALL(*fb_hal_mock, enableScreen_interface(_,1)) .InSequence(seq); mga::FBDevice fbdev(fb_hal_mock); fbdev.mode(mir_power_mode_standby); fbdev.mode(mir_power_mode_suspend); fbdev.mode(mir_power_mode_off); fbdev.mode(mir_power_mode_on); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_buffer.cpp0000644000015301777760000000726512322054223026423 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/egl_extensions.h" #include "src/platform/graphics/android/buffer.h" #include "mir/graphics/android/sync_fence.h" #include "mir/graphics/android/native_buffer.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_fence.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include #include #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; namespace mt = mir::test; class AndroidGraphicBufferBasic : public ::testing::Test { protected: virtual void SetUp() { using namespace testing; mock_native_buffer = std::make_shared>(); anwb = mock_native_buffer->anwb(); anwb->width = 44; anwb->height = 45; anwb->stride = 46; anwb->format = HAL_PIXEL_FORMAT_RGBA_8888; default_use = mga::BufferUsage::use_hardware; pf = mir_pixel_format_abgr_8888; size = geom::Size{300, 200}; extensions = std::make_shared(); } ANativeWindowBuffer *anwb; testing::NiceMock mock_egl; std::shared_ptr mock_native_buffer; MirPixelFormat pf; geom::Size size; mga::BufferUsage default_use; std::shared_ptr extensions; }; TEST_F(AndroidGraphicBufferBasic, size_query_test) { using namespace testing; mga::Buffer buffer(mock_native_buffer, extensions); geom::Size expected_size{anwb->width, anwb->height}; EXPECT_EQ(expected_size, buffer.size()); } TEST_F(AndroidGraphicBufferBasic, format_query_test) { using namespace testing; mga::Buffer buffer(mock_native_buffer, extensions); EXPECT_EQ(mir_pixel_format_abgr_8888, buffer.pixel_format()); } TEST_F(AndroidGraphicBufferBasic, returns_native_buffer_times_two) { using namespace testing; int acquire_fake_fence_fd1 = 948; int acquire_fake_fence_fd2 = 954; EXPECT_CALL(*mock_native_buffer, update_fence(acquire_fake_fence_fd1)) .Times(1); EXPECT_CALL(*mock_native_buffer, update_fence(acquire_fake_fence_fd2)) .Times(1); mga::Buffer buffer(mock_native_buffer, extensions); { auto native_resource = buffer.native_buffer_handle(); EXPECT_EQ(mock_native_buffer, native_resource); native_resource->update_fence(acquire_fake_fence_fd1); } { auto native_resource = buffer.native_buffer_handle(); EXPECT_EQ(mock_native_buffer, native_resource); native_resource->update_fence(acquire_fake_fence_fd2); } } TEST_F(AndroidGraphicBufferBasic, queries_native_window_for_stride) { using namespace testing; geom::Stride expected_stride{anwb->stride * MIR_BYTES_PER_PIXEL(pf)}; mga::Buffer buffer(mock_native_buffer, extensions); EXPECT_EQ(expected_stride, buffer.stride()); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_internal_client_interpreter.cpp0000644000015301777760000000766012322054223032746 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/internal_client_window.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/mock_interpreter_resource_cache.h" #include "mir_test_doubles/mock_fence.h" #include "mir/graphics/internal_surface.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include "gmock_set_arg.h" #include #include namespace mg=mir::graphics; namespace mtd=mir::test::doubles; namespace mga=mir::graphics::android; namespace geom=mir::geometry; namespace { class MockInternalSurface : public mg::InternalSurface { public: MOCK_CONST_METHOD0(size, geom::Size()); MOCK_CONST_METHOD0(pixel_format, MirPixelFormat()); MOCK_METHOD1(swap_buffers, void(mg::Buffer*&)); }; struct InternalClientWindow : public ::testing::Test { void SetUp() { using namespace testing; sz = geom::Size{4, 23}; mock_surface = std::make_shared>(); stub_native_buffer = std::make_shared(); ON_CALL(*mock_surface, swap_buffers(_)) .WillByDefault(SetArg<0>(&mock_buffer)); ON_CALL(*mock_surface, pixel_format()) .WillByDefault(Return(mir_pixel_format_abgr_8888)); ON_CALL(mock_buffer, native_buffer_handle()) .WillByDefault(Return(stub_native_buffer)); } std::shared_ptr stub_native_buffer; std::shared_ptr mock_surface; mtd::MockBuffer mock_buffer; geom::Size sz; }; } TEST_F(InternalClientWindow, driver_requests_buffer) { using namespace testing; EXPECT_CALL(*mock_surface, swap_buffers(_)) .Times(1); EXPECT_CALL(mock_buffer, native_buffer_handle()) .Times(1); mga::InternalClientWindow interpreter(mock_surface); auto test_buffer = interpreter.driver_requests_buffer(); ASSERT_NE(nullptr, test_buffer); EXPECT_EQ(stub_native_buffer.get(), test_buffer); } TEST_F(InternalClientWindow, size_test) { using namespace testing; EXPECT_CALL(*mock_surface, size()) .Times(2) .WillOnce(Return(sz)) .WillOnce(Return(sz)); mga::InternalClientWindow interpreter(mock_surface); unsigned int rc_width = interpreter.driver_requests_info(NATIVE_WINDOW_WIDTH); unsigned int rc_height = interpreter.driver_requests_info(NATIVE_WINDOW_HEIGHT); EXPECT_EQ(sz.width.as_uint32_t(), rc_width); EXPECT_EQ(sz.height.as_uint32_t(), rc_height); } TEST_F(InternalClientWindow, driver_default_format) { using namespace testing; EXPECT_CALL(*mock_surface, pixel_format()) .Times(1); mga::InternalClientWindow interpreter(mock_surface); auto rc_format = interpreter.driver_requests_info(NATIVE_WINDOW_FORMAT); EXPECT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, rc_format); } TEST_F(InternalClientWindow, driver_sets_format) { using namespace testing; EXPECT_CALL(*mock_surface, pixel_format()) .Times(AtLeast(1)) .WillRepeatedly(Return(mir_pixel_format_abgr_8888)); mga::InternalClientWindow interpreter(mock_surface); interpreter.dispatch_driver_request_format(HAL_PIXEL_FORMAT_RGBA_8888); auto rc_format = interpreter.driver_requests_info(NATIVE_WINDOW_FORMAT); EXPECT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, rc_format); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/hwc_struct_helpers.cpp0000644000015301777760000000332012322054223030006 0ustar pbusernogroup00000000000000/* * 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 #include "hwc_struct_helpers.h" void PrintTo(const hwc_rect_t& rect, ::std::ostream* os) { *os << "( left: " << rect.left << ", top: " << rect.top << ", right " << rect.right << ", bottom: "<< rect.bottom << ")"; } void PrintTo(const hwc_layer_1& layer , ::std::ostream* os) { *os << "compositionType: " << layer.compositionType << std::endl << "\thints: " << layer.hints << std::endl << "\tflags: " << layer.flags << std::endl << "\thandle: " << layer.handle << std::endl << "\ttransform: " << layer.transform << std::endl << "\tblending: " << layer.blending << std::endl << "\tsourceCrop: "; PrintTo(layer.sourceCrop, os); *os << std::endl << "\tdisplayFrame:"; PrintTo(layer.displayFrame, os); *os << std::endl; *os << "\tvisibleRegionScreen.numRects: " << layer.visibleRegionScreen.numRects << std::endl << "\tacquireFenceFd: " << layer.acquireFenceFd << std::endl << "\treleaseFenceFd: " << layer.releaseFenceFd << std::endl; } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/hwc_struct_helpers.h0000644000015301777760000000652512322054247027473 0ustar pbusernogroup00000000000000/* * 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_HWC_STRUCT_HELPERS_H_ #define MIR_TEST_HWC_STRUCT_HELPERS_H_ #include #include void PrintTo(const hwc_rect_t& rect, ::std::ostream* os); void PrintTo(const hwc_layer_1& layer , ::std::ostream* os); MATCHER_P2(MatchesMember, value, str, std::string("layer's " + std::string(str) + " should be: " + testing::PrintToString(value))) { return arg == value; } MATCHER_P2(HWCRectMatchesRect, value, str, std::string("rectangle " + std::string(str) + " should be: " + testing::PrintToString(value))) { hwc_rect_t rect = arg; return ((rect.left == value.left) && (rect.top == value.top) && (rect.right == value.right) && (rect.bottom == value.bottom)); } MATCHER_P2(MatchesRect, value, str, std::string("rectangle " + std::string(str) + " should be: " + testing::PrintToString(value))) { return ((arg.left == value.left) && (arg.top == value.top) && (arg.right == value.right) && (arg.bottom == value.bottom)); } MATCHER_P(MatchesLayer, value, std::string(testing::PrintToString(value)) ) { EXPECT_THAT(arg.compositionType, MatchesMember(value.compositionType, "compositionType")); EXPECT_THAT(arg.hints, MatchesMember(value.hints, "hints")); EXPECT_THAT(arg.flags, MatchesMember(value.flags, "flags")); EXPECT_THAT(arg.handle, MatchesMember(value.handle, "handle")); EXPECT_THAT(arg.transform, MatchesMember(value.transform, "transform")); EXPECT_THAT(arg.blending, MatchesMember(value.blending, "blending")); EXPECT_THAT(arg.sourceCrop, MatchesRect(value.sourceCrop, "sourceCrop")); EXPECT_THAT(arg.displayFrame, MatchesRect(value.displayFrame, "displayFrame")); EXPECT_THAT(arg.visibleRegionScreen.numRects, MatchesMember(value.visibleRegionScreen.numRects, "visibleRegionScreen.numRects")); EXPECT_THAT(arg.acquireFenceFd, MatchesMember(value.acquireFenceFd, "acquireFenceFd")); EXPECT_THAT(arg.releaseFenceFd, MatchesMember(value.releaseFenceFd, "releaseFenceFd")); return !(::testing::Test::HasFailure()); } MATCHER_P(MatchesList, value, std::string("")) { EXPECT_EQ(arg.numHwLayers, value.size()); auto i = 0u; for(auto layer : value) { EXPECT_THAT(arg.hwLayers[i++], MatchesLayer(*layer)); if (::testing::Test::HasFailure()) return false; } return !(::testing::Test::HasFailure()); } MATCHER_P3(MatchesListWithEglFields, value, dpy, sur, std::string("")) { EXPECT_EQ(arg.dpy, dpy); EXPECT_EQ(arg.sur, sur); EXPECT_THAT(arg, MatchesList(value)); return !(::testing::Test::HasFailure()); } #endif /* MIR_TEST_HWC_STRUCT_HELPERS_H_ */ mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_android_buffer_allocator.cpp0000644000015301777760000001107312322054223032153 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "src/platform/graphics/android/android_graphic_buffer_allocator.h" #include "mir_test_doubles/mock_android_hw.h" #include "mir/graphics/buffer_initializer.h" #include "mir/graphics/buffer_properties.h" #include "mir_test_doubles/mock_buffer_initializer.h" #include "mir_test_doubles/mock_egl.h" #include #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; struct AndroidGraphicBufferAllocatorTest : public ::testing::Test { AndroidGraphicBufferAllocatorTest() : null_buffer_initializer{std::make_shared()} { } std::shared_ptr const null_buffer_initializer; testing::NiceMock hw_access_mock; testing::NiceMock mock_egl; }; TEST_F(AndroidGraphicBufferAllocatorTest, allocator_accesses_gralloc_module) { using namespace testing; EXPECT_CALL(hw_access_mock, hw_get_module(StrEq(GRALLOC_HARDWARE_MODULE_ID), _)) .Times(1); mga::AndroidGraphicBufferAllocator allocator(null_buffer_initializer); } TEST_F(AndroidGraphicBufferAllocatorTest, supported_pixel_formats_contain_common_formats) { mga::AndroidGraphicBufferAllocator allocator{null_buffer_initializer}; auto supported_pixel_formats = allocator.supported_pixel_formats(); auto abgr_8888_count = std::count(supported_pixel_formats.begin(), supported_pixel_formats.end(), mir_pixel_format_abgr_8888); auto xbgr_8888_count = std::count(supported_pixel_formats.begin(), supported_pixel_formats.end(), mir_pixel_format_xbgr_8888); auto bgr_888_count = std::count(supported_pixel_formats.begin(), supported_pixel_formats.end(), mir_pixel_format_bgr_888); EXPECT_EQ(1, abgr_8888_count); EXPECT_EQ(1, xbgr_8888_count); EXPECT_EQ(1, bgr_888_count); } TEST_F(AndroidGraphicBufferAllocatorTest, supported_pixel_formats_have_sane_default_in_first_position) { mga::AndroidGraphicBufferAllocator allocator{null_buffer_initializer}; auto supported_pixel_formats = allocator.supported_pixel_formats(); ASSERT_FALSE(supported_pixel_formats.empty()); EXPECT_EQ(mir_pixel_format_abgr_8888, supported_pixel_formats[0]); } TEST_F(AndroidGraphicBufferAllocatorTest, alloc_buffer_calls_initializer) { using namespace testing; auto buffer_initializer = std::make_shared(); mg::BufferProperties properties{geom::Size{2, 2}, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware}; mga::AndroidGraphicBufferAllocator allocator{buffer_initializer}; EXPECT_CALL(*buffer_initializer, operator_call(_)) .Times(1); allocator.alloc_buffer(properties); } TEST_F(AndroidGraphicBufferAllocatorTest, alloc_buffer_platform_calls_initializer) { using namespace testing; auto buffer_initializer = std::make_shared(); mga::AndroidGraphicBufferAllocator allocator{buffer_initializer}; auto size = geom::Size{2, 2}; auto pf = mir_pixel_format_abgr_8888; EXPECT_CALL(*buffer_initializer, operator_call(_)) .Times(1); allocator.alloc_buffer_platform(size, pf, mga::BufferUsage::use_hardware); } TEST_F(AndroidGraphicBufferAllocatorTest, buffer_usage_converter) { EXPECT_EQ(mga::BufferUsage::use_hardware, mga::AndroidGraphicBufferAllocator::convert_from_compositor_usage(mg::BufferUsage::hardware)); EXPECT_EQ(mga::BufferUsage::use_software, mga::AndroidGraphicBufferAllocator::convert_from_compositor_usage(mg::BufferUsage::software)); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_buffer_tex_bind.cpp0000644000015301777760000002755512322054223030303 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/buffer.h" #include "mir/graphics/egl_extensions.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_fence.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; class AndroidBufferBinding : public ::testing::Test { public: virtual void SetUp() { using namespace testing; mock_native_buffer = std::make_shared>(); size = geom::Size{300, 220}; pf = mir_pixel_format_abgr_8888; extensions = std::make_shared(); }; geom::Size size; MirPixelFormat pf; testing::NiceMock mock_egl; std::shared_ptr extensions; std::shared_ptr mock_native_buffer; }; TEST_F(AndroidBufferBinding, buffer_queries_for_display) { using namespace testing; EXPECT_CALL(mock_egl, eglGetCurrentDisplay()) .Times(Exactly(1)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_creates_image_on_first_bind) { using namespace testing; EXPECT_CALL(mock_egl, eglCreateImageKHR(_,_,_,_,_)) .Times(Exactly(1)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_only_makes_one_image_per_display) { using namespace testing; EXPECT_CALL(mock_egl, eglCreateImageKHR(_,_,_,_,_)) .Times(Exactly(1)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); buffer.bind_to_texture(); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_anwb_is_bound) { using namespace testing; ANativeWindowBuffer *stub_anwb = reinterpret_cast(0xdeed); EXPECT_CALL(*mock_native_buffer, anwb()) .Times(1) .WillOnce(Return(stub_anwb)); EXPECT_CALL(mock_egl, eglCreateImageKHR(_,_,_,stub_anwb,_)) .Times(Exactly(1)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_makes_new_image_with_new_display) { using namespace testing; EGLDisplay second_fake_display = reinterpret_cast(&second_fake_display); /* return 1st fake display */ EXPECT_CALL(mock_egl, eglCreateImageKHR(_,_,_,_,_)) .Times(Exactly(2)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); /* return 2nd fake display */ EXPECT_CALL(mock_egl, eglGetCurrentDisplay()) .Times(Exactly(1)) .WillOnce(Return(second_fake_display)); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_frees_images_it_makes) { using namespace testing; EGLDisplay second_fake_display = reinterpret_cast(&second_fake_display); EXPECT_CALL(mock_egl, eglDestroyImageKHR(_,_)) .Times(Exactly(2)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); EXPECT_CALL(mock_egl, eglGetCurrentDisplay()) .Times(Exactly(1)) .WillOnce(Return(second_fake_display)); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_frees_images_it_makes_with_proper_args) { using namespace testing; EGLDisplay first_fake_display = mock_egl.fake_egl_display; EGLImageKHR first_fake_egl_image = reinterpret_cast(&first_fake_egl_image); EGLDisplay second_fake_display = reinterpret_cast(&second_fake_display); EGLImageKHR second_fake_egl_image = reinterpret_cast(&second_fake_egl_image); /* actual expectations */ EXPECT_CALL(mock_egl, eglDestroyImageKHR(first_fake_display, first_fake_egl_image)) .Times(Exactly(1)); EXPECT_CALL(mock_egl, eglDestroyImageKHR(second_fake_display, second_fake_egl_image)) .Times(Exactly(1)); /* manipulate mock to return 1st set */ EXPECT_CALL(mock_egl, eglGetCurrentDisplay()) .Times(Exactly(1)) .WillOnce(Return(first_fake_display)); EXPECT_CALL(mock_egl, eglCreateImageKHR(_,_,_,_,_)) .Times(Exactly(1)) .WillOnce(Return((first_fake_egl_image))); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); /* manipulate mock to return 2nd set */ EXPECT_CALL(mock_egl, eglGetCurrentDisplay()) .Times(Exactly(1)) .WillOnce(Return(second_fake_display)); EXPECT_CALL(mock_egl, eglCreateImageKHR(_,_,_,_,_)) .Times(Exactly(1)) .WillOnce(Return((second_fake_egl_image))); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_uses_current_display) { using namespace testing; EGLDisplay fake_display = (EGLDisplay) 0x32298; EXPECT_CALL(mock_egl, eglGetCurrentDisplay()) .Times(Exactly(1)) .WillOnce(Return(fake_display)); EXPECT_CALL(mock_egl, eglCreateImageKHR(fake_display,_,_,_,_)) .Times(Exactly(1)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_specifies_no_context) { using namespace testing; EXPECT_CALL(mock_egl, eglCreateImageKHR(_, EGL_NO_CONTEXT,_,_,_)) .Times(Exactly(1)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_sets_egl_native_buffer_android) { using namespace testing; EXPECT_CALL(mock_egl, eglCreateImageKHR(_,_,EGL_NATIVE_BUFFER_ANDROID,_,_)) .Times(Exactly(1)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_sets_proper_attributes) { using namespace testing; const EGLint* attrs; EXPECT_CALL(mock_egl, eglCreateImageKHR(_,_,_,_,_)) .Times(Exactly(1)) .WillOnce(DoAll(SaveArg<4>(&attrs), Return(mock_egl.fake_egl_image))); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); /* note: this should not segfault. if it does, the attributes were set wrong */ EXPECT_EQ(attrs[0], EGL_IMAGE_PRESERVED_KHR); EXPECT_EQ(attrs[1], EGL_TRUE); EXPECT_EQ(attrs[2], EGL_NONE); } TEST_F(AndroidBufferBinding, buffer_destroys_correct_buffer_with_single_image) { using namespace testing; EGLImageKHR fake_egl_image = (EGLImageKHR) 0x84210; EXPECT_CALL(mock_egl, eglCreateImageKHR(mock_egl.fake_egl_display,_,_,_,_)) .Times(Exactly(1)) .WillOnce(Return((fake_egl_image))); EXPECT_CALL(mock_egl, eglDestroyImageKHR(mock_egl.fake_egl_display, fake_egl_image)) .Times(Exactly(1)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_image_creation_failure_does_not_save) { using namespace testing; EXPECT_CALL(mock_egl, eglCreateImageKHR(_,_,_,_,_)) .Times(Exactly(2)) .WillRepeatedly(Return((EGL_NO_IMAGE_KHR))); EXPECT_CALL(mock_egl, eglDestroyImageKHR(_,_)) .Times(Exactly(0)); mga::Buffer buffer(mock_native_buffer, extensions); EXPECT_THROW( { buffer.bind_to_texture(); }, std::runtime_error); EXPECT_THROW( { buffer.bind_to_texture(); }, std::runtime_error); } TEST_F(AndroidBufferBinding, buffer_image_creation_failure_throws) { using namespace testing; EXPECT_CALL(mock_egl, eglCreateImageKHR(_,_,_,_,_)) .Times(Exactly(1)) .WillRepeatedly(Return((EGL_NO_IMAGE_KHR))); mga::Buffer buffer(mock_native_buffer, extensions); EXPECT_THROW( { buffer.bind_to_texture(); }, std::runtime_error); } /* binding tests */ TEST_F(AndroidBufferBinding, buffer_calls_binding_extension) { using namespace testing; EXPECT_CALL(mock_egl, glEGLImageTargetTexture2DOES(_, _)) .Times(Exactly(1)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_calls_binding_extension_every_time) { using namespace testing; EXPECT_CALL(mock_egl, glEGLImageTargetTexture2DOES(_, _)) .Times(Exactly(3)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); buffer.bind_to_texture(); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_binding_specifies_gl_texture_2d) { using namespace testing; EXPECT_CALL(mock_egl, glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, _)) .Times(Exactly(1)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_binding_uses_right_image) { using namespace testing; EXPECT_CALL(mock_egl, glEGLImageTargetTexture2DOES(_, mock_egl.fake_egl_image)) .Times(Exactly(1)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, buffer_binding_uses_right_image_after_display_swap) { using namespace testing; EGLDisplay second_fake_display = reinterpret_cast(&second_fake_display); EGLImageKHR second_fake_egl_image = reinterpret_cast(&second_fake_egl_image); EXPECT_CALL(mock_egl, glEGLImageTargetTexture2DOES(_, _)) .Times(Exactly(1)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); EXPECT_CALL(mock_egl, glEGLImageTargetTexture2DOES(_, second_fake_egl_image)) .Times(Exactly(1)); EXPECT_CALL(mock_egl, eglGetCurrentDisplay()) .Times(Exactly(1)) .WillOnce(Return(second_fake_display)); EXPECT_CALL(mock_egl, eglCreateImageKHR(_,_,_,_,_)) .Times(Exactly(1)) .WillOnce(Return((second_fake_egl_image))); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, bind_to_texture_waits_on_fence) { using namespace testing; EXPECT_CALL(*mock_native_buffer, wait_for_content()) .Times(1); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); } TEST_F(AndroidBufferBinding, different_egl_contexts_displays_generate_new_eglimages) { using namespace testing; int d1 = 0, d2 = 0, c1 = 0, c2 = 0; EGLDisplay disp1 = reinterpret_cast(&d1); EGLDisplay disp2 = reinterpret_cast(&d2); EGLContext ctxt1 = reinterpret_cast(&c1); EGLContext ctxt2 = reinterpret_cast(&c2); EXPECT_CALL(mock_egl, eglGetCurrentDisplay()) .Times(3) .WillOnce(Return(disp1)) .WillOnce(Return(disp1)) .WillOnce(Return(disp2)); EXPECT_CALL(mock_egl, eglGetCurrentContext()) .Times(3) .WillOnce(Return(ctxt1)) .WillRepeatedly(Return(ctxt2)); EXPECT_CALL(mock_egl, eglCreateImageKHR(disp1,_,_,_,_)) .Times(2); EXPECT_CALL(mock_egl, eglCreateImageKHR(disp2,_,_,_,_)) .Times(1); EXPECT_CALL(mock_egl, eglDestroyImageKHR(_,_)) .Times(Exactly(3)); mga::Buffer buffer(mock_native_buffer, extensions); buffer.bind_to_texture(); buffer.bind_to_texture(); buffer.bind_to_texture(); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_hwc_logger.cpp0000644000015301777760000001217212322054247027271 0ustar pbusernogroup00000000000000/* * 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 "src/platform/graphics/android/hwc_formatted_logger.h" #include #include #include #include namespace mga=mir::graphics::android; namespace { struct HwcLogger : public ::testing::Test { HwcLogger() : num_layers{4}, display_list{std::shared_ptr( static_cast( ::operator new(sizeof(hwc_display_contents_1_t) + (num_layers * sizeof(hwc_layer_1_t)))))} { default_cout_buffer = std::cout.rdbuf(); std::cout.rdbuf(test_stream.rdbuf()); display_list->numHwLayers = num_layers; display_list->hwLayers[0].compositionType = HWC_OVERLAY; display_list->hwLayers[0].flags = 0; display_list->hwLayers[0].handle = &native_handle1; display_list->hwLayers[0].transform = HWC_TRANSFORM_ROT_90; display_list->hwLayers[0].blending = HWC_BLENDING_NONE; display_list->hwLayers[0].displayFrame = {1, 1, 2, 1}; display_list->hwLayers[0].sourceCrop = {3, 2, 5, 3}; display_list->hwLayers[1].compositionType = HWC_FRAMEBUFFER; display_list->hwLayers[1].flags = 0; display_list->hwLayers[1].handle = &native_handle2; display_list->hwLayers[1].transform = HWC_TRANSFORM_ROT_180; display_list->hwLayers[1].blending = HWC_BLENDING_PREMULT; display_list->hwLayers[1].displayFrame = {8, 5, 13, 8}; display_list->hwLayers[1].sourceCrop = {21, 13, 34, 21}; display_list->hwLayers[2].compositionType = HWC_FRAMEBUFFER; display_list->hwLayers[2].flags = HWC_SKIP_LAYER; display_list->hwLayers[2].handle = &native_handle3; display_list->hwLayers[2].transform = HWC_TRANSFORM_ROT_270; display_list->hwLayers[2].blending = HWC_BLENDING_COVERAGE; display_list->hwLayers[2].displayFrame = {55, 34, 89, 55}; display_list->hwLayers[2].sourceCrop = {144, 89, 233, 144}; display_list->hwLayers[3].compositionType = HWC_FRAMEBUFFER_TARGET; display_list->hwLayers[3].flags = 0; display_list->hwLayers[3].handle = &native_handle4; display_list->hwLayers[3].transform = 0; display_list->hwLayers[3].blending = HWC_BLENDING_NONE; display_list->hwLayers[3].displayFrame = {377, 233, 610, 337}; display_list->hwLayers[3].sourceCrop = {987, 610, 1597, 987}; }; virtual ~HwcLogger() { std::cout.rdbuf(default_cout_buffer); } decltype(std::cout.rdbuf()) default_cout_buffer; std::ostringstream test_stream; size_t const num_layers; std::shared_ptr const display_list; native_handle_t native_handle1; native_handle_t native_handle2; native_handle_t native_handle3; native_handle_t native_handle4; }; } TEST_F(HwcLogger, log_pre_prepare) { std::stringstream str; str << "before prepare():" << std::endl << " # | pos {l,t,r,b} | crop {l,t,r,b} | transform | blending | " << std::endl << " 0 | { 1, 1, 2, 1} | { 3, 2, 5, 3} | ROT_90 | NONE | " << std::endl << " 1 | { 8, 5, 13, 8} | { 21, 13, 34, 21} | ROT_180 | PREMULT | " << std::endl << " 2 | { 55, 34, 89, 55} | { 144, 89, 233, 144} | ROT_270 | COVERAGE | " << std::endl << " 3 | { 377, 233, 610, 337} | { 987, 610,1597, 987} | NONE | NONE | " << std::endl; mga::HwcFormattedLogger logger; logger.log_list_submitted_to_prepare(*display_list); EXPECT_EQ(str.str(), test_stream.str()); } TEST_F(HwcLogger, log_post_prepare) { std::stringstream str; str << "after prepare():" << std::endl << " # | Type | " << std::endl << " 0 | OVERLAY | " << std::endl << " 1 | GL_RENDER | " << std::endl << " 2 | FORCE_GL | " << std::endl << " 3 | FB_TARGET | " << std::endl; mga::HwcFormattedLogger logger; logger.log_prepare_done(*display_list); EXPECT_EQ(str.str(), test_stream.str()); } TEST_F(HwcLogger, log_set) { std::stringstream str; str << "set list():" << std::endl << " # | handle" << std::endl << " 0 | " << &native_handle1 << std::endl << " 1 | " << &native_handle2 << std::endl << " 2 | " << &native_handle3 << std::endl << " 3 | " << &native_handle4 << std::endl; mga::HwcFormattedLogger logger; logger.log_set_list(*display_list); EXPECT_EQ(str.str(), test_stream.str()); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_android_alloc_adaptor.cpp0000644000015301777760000001774112322054223031456 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/android_alloc_adaptor.h" #include "mir/graphics/android/native_buffer.h" #include "mir_test_doubles/mock_android_alloc_device.h" #include "mir_test_doubles/mock_alloc_adaptor.h" #include #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; class AdaptorICSTest : public ::testing::Test { public: AdaptorICSTest() : fb_usage_flags(GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB), hw_usage_flags(GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER), sw_usage_flags(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN) {} virtual void SetUp() { using namespace testing; mock_alloc_device = std::make_shared>(); alloc_adaptor = std::make_shared(mock_alloc_device); pf = mir_pixel_format_abgr_8888; size = geom::Size{300, 200}; usage = mga::BufferUsage::use_hardware; } std::shared_ptr mock_alloc_device; std::shared_ptr alloc_adaptor; MirPixelFormat pf; geom::Size size; mga::BufferUsage usage; int const fb_usage_flags; int const hw_usage_flags; int const sw_usage_flags; }; TEST_F(AdaptorICSTest, resource_type_test_fail_ret) { using namespace testing; EXPECT_CALL(*mock_alloc_device, alloc_interface(_,_,_,_,_,_,_)) .WillOnce(DoAll( SetArgPointee<5>(mock_alloc_device->buffer_handle), SetArgPointee<6>(size.width.as_uint32_t()*4), Return(-1))); EXPECT_THROW({ alloc_adaptor->alloc_buffer(size, pf, usage); }, std::runtime_error); } TEST_F(AdaptorICSTest, resource_type_test_fail_stride) { using namespace testing; EXPECT_CALL(*mock_alloc_device, alloc_interface(_,_,_,_,_,_,_)) .WillOnce(DoAll( SetArgPointee<5>(mock_alloc_device->buffer_handle), SetArgPointee<6>(0), Return(0))); EXPECT_THROW({ alloc_adaptor->alloc_buffer(size, pf, usage); }, std::runtime_error); } TEST_F(AdaptorICSTest, resource_type_test_fail_null_handle) { using namespace testing; EXPECT_CALL(*mock_alloc_device, alloc_interface(_,_,_,_,_,_,_)) .WillOnce(DoAll( SetArgPointee<5>(nullptr), SetArgPointee<6>(size.width.as_uint32_t()*4), Return(0))); EXPECT_THROW({ alloc_adaptor->alloc_buffer(size, pf, usage); }, std::runtime_error); } TEST_F(AdaptorICSTest, resource_type_test_proper_alloc_is_used) { using namespace testing; EXPECT_CALL(*mock_alloc_device, alloc_interface(mock_alloc_device.get(),_,_,_,_,_,_)); EXPECT_CALL(*mock_alloc_device, free_interface(mock_alloc_device.get(),_)); alloc_adaptor->alloc_buffer(size, pf, usage); } TEST_F(AdaptorICSTest, resource_type_test_deleter_deletes_correct_handle) { using namespace testing; EXPECT_CALL(*mock_alloc_device, alloc_interface(_,_,_,_,_,_,_)) .WillOnce(DoAll( SetArgPointee<5>(mock_alloc_device->buffer_handle), SetArgPointee<6>(size.width.as_uint32_t()*4), Return(0))); EXPECT_CALL(*mock_alloc_device, free_interface(_,mock_alloc_device->buffer_handle)); alloc_adaptor->alloc_buffer(size, pf, usage); } TEST_F(AdaptorICSTest, adaptor_gralloc_format_conversion_abgr8888) { using namespace testing; EXPECT_CALL(*mock_alloc_device, alloc_interface(_,_,_,HAL_PIXEL_FORMAT_RGBA_8888,_,_,_)); EXPECT_CALL(*mock_alloc_device, free_interface(_,_)); alloc_adaptor->alloc_buffer(size, pf, usage); } TEST_F(AdaptorICSTest, adaptor_gralloc_dimension_conversion) { using namespace testing; int w = size.width.as_uint32_t(); int h = size.height.as_uint32_t(); EXPECT_CALL(*mock_alloc_device, alloc_interface(_,w,h,_,_,_,_)); EXPECT_CALL(*mock_alloc_device, free_interface(_,_)); alloc_adaptor->alloc_buffer(size, pf, usage ); } TEST_F(AdaptorICSTest, adaptor_gralloc_hw_usage_conversion) { using namespace testing; EXPECT_CALL(*mock_alloc_device, alloc_interface(_,_,_,_,hw_usage_flags,_,_)); EXPECT_CALL(*mock_alloc_device, free_interface(_,_) ); alloc_adaptor->alloc_buffer(size, pf, usage ); } TEST_F(AdaptorICSTest, adaptor_gralloc_sw_usage_conversion) { using namespace testing; EXPECT_CALL(*mock_alloc_device, alloc_interface(_,_,_,_,sw_usage_flags,_,_)); EXPECT_CALL(*mock_alloc_device, free_interface(_,_)); alloc_adaptor->alloc_buffer(size, pf, mga::BufferUsage::use_software); } TEST_F(AdaptorICSTest, adaptor_gralloc_usage_conversion_fb_gles) { using namespace testing; EXPECT_CALL(*mock_alloc_device, alloc_interface(_,_,_,_,fb_usage_flags,_,_)); EXPECT_CALL(*mock_alloc_device, free_interface(_,_)); alloc_adaptor->alloc_buffer(size, pf, mga::BufferUsage::use_framebuffer_gles); } TEST_F(AdaptorICSTest, handle_size_is_correct) { auto native_handle = alloc_adaptor->alloc_buffer(size, pf, usage); auto anwb = native_handle->anwb(); EXPECT_EQ(static_cast(size.width.as_uint32_t()), anwb->width); EXPECT_EQ(static_cast(size.height.as_uint32_t()), anwb->height); EXPECT_EQ(static_cast(mock_alloc_device->fake_stride), anwb->stride); } TEST_F(AdaptorICSTest, handle_buffer_pf_is_converted_to_android_abgr_8888) { auto native_handle = alloc_adaptor->alloc_buffer(size, pf, usage); auto anwb = native_handle->anwb(); EXPECT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, anwb->format); } TEST_F(AdaptorICSTest, handle_buffer_pf_is_converted_to_android_xbgr_8888) { auto native_handle = alloc_adaptor->alloc_buffer(size, mir_pixel_format_xbgr_8888, usage); auto anwb = native_handle->anwb(); EXPECT_EQ(HAL_PIXEL_FORMAT_RGBX_8888, anwb->format); } TEST_F(AdaptorICSTest, handle_buffer_usage_is_converted_to_android_use_hw) { auto native_handle = alloc_adaptor->alloc_buffer(size, pf, usage); auto anwb = native_handle->anwb(); EXPECT_EQ(hw_usage_flags, anwb->usage); } TEST_F(AdaptorICSTest, handle_buffer_usage_is_converted_to_android_use_fb) { auto native_handle = alloc_adaptor->alloc_buffer(size, pf, mga::BufferUsage::use_framebuffer_gles); auto anwb = native_handle->anwb(); EXPECT_EQ(fb_usage_flags, anwb->usage); } TEST_F(AdaptorICSTest, handle_has_strong_reference_for_c_drivers) { auto native_handle = alloc_adaptor->alloc_buffer(size, pf, usage); auto anwb = native_handle->anwb(); ASSERT_NE(nullptr, anwb->common.incRef); ASSERT_NE(nullptr, anwb->common.decRef); anwb->common.incRef(&anwb->common); anwb->common.decRef(&anwb->common); } TEST_F(AdaptorICSTest, handle_has_right_magic) { int magic = ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r'); /* magic value shared by JB and ICS */ auto native_handle = alloc_adaptor->alloc_buffer(size, pf, usage); auto anwb = native_handle->anwb(); EXPECT_EQ(magic, anwb->common.magic); } TEST_F(AdaptorICSTest, handle_has_version) { int version = sizeof(ANativeWindowBuffer); /* version value shared by JB and ICS */ auto native_handle = alloc_adaptor->alloc_buffer(size, pf, usage); auto anwb = native_handle->anwb(); EXPECT_EQ(version, anwb->common.version); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_hwc_layers.cpp0000644000015301777760000002356012322054223027306 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/hwc_layerlist.h" #include "mir_test_doubles/mock_buffer.h" #include "hwc_struct_helpers.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include "mir_test_doubles/mock_renderable.h" #include "mir_test/fake_shared.h" #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mt=mir::test; namespace mtd=mir::test::doubles; namespace geom=mir::geometry; class HWCLayersTest : public ::testing::Test { public: virtual void SetUp() { using namespace testing; native_handle_1 = std::make_shared(buffer_size); ON_CALL(mock_buffer, size()) .WillByDefault(Return(buffer_size)); ON_CALL(mock_buffer, native_buffer_handle()) .WillByDefault(Return(native_handle_1)); list = std::shared_ptr( static_cast( ::operator new(sizeof(hwc_display_contents_1_t) + sizeof(hwc_layer_1_t)))); list_index = 0; hwc_layer = &list->hwLayers[list_index]; type = mga::LayerType::gl_rendered; reset_expected_layer(); } void reset_expected_layer() { memset(&expected_layer, 0, sizeof(expected_layer)); expected_layer.compositionType = HWC_FRAMEBUFFER; expected_layer.hints = 0; expected_layer.flags = 0; expected_layer.handle = nullptr; expected_layer.transform = 0; expected_layer.blending = HWC_BLENDING_NONE; expected_layer.sourceCrop = region; expected_layer.displayFrame = { screen_position.top_left.x.as_int(), screen_position.top_left.y.as_int(), screen_position.size.width.as_int(), screen_position.size.height.as_int()}; expected_layer.visibleRegionScreen = {1, ®ion}; expected_layer.acquireFenceFd = -1; expected_layer.releaseFenceFd = -1; } mga::LayerType type; geom::Size buffer_size{333, 444}; geom::Rectangle screen_position{{9,8},{245, 250}}; bool alpha_enabled{false}; std::shared_ptr native_handle_1; testing::NiceMock mock_buffer; std::shared_ptr list; hwc_layer_1_t* hwc_layer; size_t list_index; hwc_layer_1 expected_layer; hwc_rect_t region{0,0,0,0}; }; TEST_F(HWCLayersTest, check_if_layer_needs_gl_render) { mga::HWCLayer layer(list, list_index); hwc_layer->compositionType = HWC_OVERLAY; hwc_layer->flags = 0; EXPECT_FALSE(layer.needs_gl_render()); hwc_layer->compositionType = HWC_FRAMEBUFFER; hwc_layer->flags = HWC_SKIP_LAYER; EXPECT_TRUE(layer.needs_gl_render()); hwc_layer->compositionType = HWC_FRAMEBUFFER; hwc_layer->flags = 0; EXPECT_TRUE(layer.needs_gl_render()); } TEST_F(HWCLayersTest, move_layer_positions) { mga::HWCLayer layer(type, screen_position, false, list, list_index); mga::HWCLayer second_layer(std::move(layer)); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); } TEST_F(HWCLayersTest, change_layer_types) { expected_layer.compositionType = HWC_FRAMEBUFFER_TARGET; type = mga::LayerType::framebuffer_target; mga::HWCLayer layer(type, screen_position, alpha_enabled, list, list_index); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); EXPECT_THROW({ layer.set_layer_type(mga::LayerType::overlay); }, std::logic_error); expected_layer.compositionType = HWC_FRAMEBUFFER; layer.set_layer_type(mga::LayerType::gl_rendered); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); expected_layer.compositionType = HWC_FRAMEBUFFER; expected_layer.flags = HWC_SKIP_LAYER; layer.set_layer_type(mga::LayerType::skip); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); expected_layer.compositionType = HWC_FRAMEBUFFER; expected_layer.flags = 0; layer.set_layer_type(mga::LayerType::gl_rendered); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); } TEST_F(HWCLayersTest, apply_buffer_updates_to_framebuffer_layer) { EXPECT_CALL(*native_handle_1, copy_fence()) .Times(0); hwc_rect_t region = {0,0,buffer_size.width.as_int(), buffer_size.height.as_int()}; expected_layer.handle = native_handle_1->handle(); expected_layer.visibleRegionScreen = {1, ®ion}; expected_layer.sourceCrop = region; expected_layer.acquireFenceFd = -1; expected_layer.releaseFenceFd = -1; mga::HWCLayer layer(type, screen_position, alpha_enabled, list, list_index); layer.set_buffer(mock_buffer); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); } TEST_F(HWCLayersTest, apply_buffer_updates_to_overlay_layers) { int fake_fence = 552; hwc_rect_t region = {0,0,buffer_size.width.as_int(), buffer_size.height.as_int()}; expected_layer.compositionType = HWC_OVERLAY; expected_layer.handle = native_handle_1->handle(); expected_layer.visibleRegionScreen = {1, ®ion}; expected_layer.sourceCrop = region; expected_layer.acquireFenceFd = -1; expected_layer.releaseFenceFd = -1; mga::HWCLayer layer(type, screen_position, alpha_enabled, list, list_index); hwc_layer->compositionType = HWC_OVERLAY; layer.set_buffer(mock_buffer); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); //prepare_for_draw should set the fence //mir must reset releaseFenceFd to -1 hwc_layer->releaseFenceFd = fake_fence; EXPECT_CALL(*native_handle_1, copy_fence()) .Times(1) .WillOnce(testing::Return(fake_fence)); expected_layer.acquireFenceFd = fake_fence; layer.prepare_for_draw(); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); //multiple sequential updates to the same layer must not set the acquireFenceFds on the calls //after the first. hwc_layer->acquireFenceFd = -1; expected_layer.acquireFenceFd = -1; layer.set_buffer(mock_buffer); layer.prepare_for_draw(); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); } TEST_F(HWCLayersTest, apply_buffer_updates_to_fbtarget) { int fake_fence = 552; hwc_rect_t region = {0,0,buffer_size.width.as_int(), buffer_size.height.as_int()}; expected_layer.compositionType = HWC_FRAMEBUFFER_TARGET; expected_layer.handle = native_handle_1->handle(); expected_layer.visibleRegionScreen = {1, ®ion}; expected_layer.sourceCrop = region; expected_layer.acquireFenceFd = -1; expected_layer.releaseFenceFd = -1; mga::HWCLayer layer( mga::LayerType::framebuffer_target, screen_position, alpha_enabled, list, list_index); layer.set_buffer(mock_buffer); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); //mir must reset releaseFenceFd to -1 if hwc has changed it hwc_layer->releaseFenceFd = fake_fence; EXPECT_CALL(*native_handle_1, copy_fence()) .Times(1) .WillOnce(testing::Return(fake_fence)); expected_layer.acquireFenceFd = fake_fence; layer.prepare_for_draw(); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); //hwc will set this to -1 to acknowledge that its adopted this layer's fence. //multiple sequential updates to the same layer must not set the acquireFenceFds on the calls //after the first. hwc_layer->acquireFenceFd = -1; expected_layer.acquireFenceFd = -1; layer.set_buffer(mock_buffer); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); //TODO: we have to know if the fb target is needed or not. if it is not, we should not copy the fd. } TEST_F(HWCLayersTest, buffer_fence_updates) { int fake_fence = 552; EXPECT_CALL(*native_handle_1, update_fence(fake_fence)) .Times(1); type = mga::LayerType::framebuffer_target; mga::HWCLayer layer(type, screen_position, alpha_enabled, list, list_index); layer.set_buffer(mock_buffer); hwc_layer->releaseFenceFd = fake_fence; layer.update_fence_and_release_buffer(); } TEST_F(HWCLayersTest, check_layer_defaults_and_alpha) { using namespace testing; hwc_rect_t crop { 0,0, buffer_size.width.as_int(), buffer_size.height.as_int() }; hwc_rect_t screen_pos { screen_position.top_left.x.as_int(), screen_position.top_left.y.as_int(), screen_position.size.width.as_int(), screen_position.size.height.as_int() }; hwc_region_t visible_region {1, &screen_pos}; hwc_layer_1 expected_layer; expected_layer.compositionType = HWC_FRAMEBUFFER; expected_layer.hints = 0; expected_layer.flags = 0; expected_layer.handle = native_handle_1->handle(); expected_layer.transform = 0; expected_layer.blending = HWC_BLENDING_COVERAGE; expected_layer.sourceCrop = crop; expected_layer.displayFrame = screen_pos; expected_layer.visibleRegionScreen = visible_region; expected_layer.acquireFenceFd = -1; expected_layer.releaseFenceFd = -1; mga::HWCLayer layer(list, list_index); layer.set_render_parameters(screen_position, true); layer.set_buffer(mock_buffer); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); expected_layer.blending = HWC_BLENDING_NONE; layer.set_render_parameters(screen_position, false); EXPECT_THAT(*hwc_layer, MatchesLayer(expected_layer)); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_resource_factory.cpp0000644000015301777760000000607612322054247030535 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/resource_factory.h" #include "mir_test_doubles/mock_android_hw.h" #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mtd=mir::test::doubles; struct ResourceFactoryTest : public ::testing::Test { mtd::HardwareAccessMock hw_access_mock; bool const log_hwc{false}; }; TEST_F(ResourceFactoryTest, fb_native_creation_opens_and_closes_gralloc) { using namespace testing; EXPECT_CALL(hw_access_mock, hw_get_module(StrEq(GRALLOC_HARDWARE_MODULE_ID), _)) .Times(1); mga::ResourceFactory factory{log_hwc}; factory.create_fb_native_device(); EXPECT_TRUE(hw_access_mock.open_count_matches_close()); } TEST_F(ResourceFactoryTest, test_device_creation_throws_on_failure) { using namespace testing; mga::ResourceFactory factory{log_hwc}; /* failure because of rc */ EXPECT_CALL(hw_access_mock, hw_get_module(StrEq(GRALLOC_HARDWARE_MODULE_ID), _)) .Times(1) .WillOnce(Return(-1)); EXPECT_THROW({ factory.create_fb_native_device(); }, std::runtime_error); /* failure because of nullptr returned */ EXPECT_CALL(hw_access_mock, hw_get_module(StrEq(GRALLOC_HARDWARE_MODULE_ID), _)) .Times(1) .WillOnce(DoAll(SetArgPointee<1>(nullptr),Return(-1))); EXPECT_THROW({ factory.create_fb_native_device(); }, std::runtime_error); } TEST_F(ResourceFactoryTest, hwc_allocation) { using namespace testing; EXPECT_CALL(hw_access_mock, hw_get_module(StrEq(HWC_HARDWARE_MODULE_ID), _)) .Times(1); mga::ResourceFactory factory{log_hwc}; factory.create_hwc_native_device(); EXPECT_TRUE(hw_access_mock.open_count_matches_close()); } TEST_F(ResourceFactoryTest, hwc_allocation_failures) { using namespace testing; mtd::FailingHardwareModuleStub failing_hwc_module_stub; EXPECT_CALL(hw_access_mock, hw_get_module(StrEq(HWC_HARDWARE_MODULE_ID), _)) .Times(2) .WillOnce(Return(-1)) .WillOnce(DoAll(SetArgPointee<1>(&failing_hwc_module_stub), Return(0))); mga::ResourceFactory factory{log_hwc}; EXPECT_THROW({ factory.create_hwc_native_device(); }, std::runtime_error); EXPECT_THROW({ factory.create_hwc_native_device(); }, std::runtime_error); EXPECT_TRUE(hw_access_mock.open_count_matches_close()); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_hwc_common_device.cpp0000644000015301777760000002113612322054247030621 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/android/sync_fence.h" #include "src/platform/graphics/android/hwc_fb_device.h" #include "src/platform/graphics/android/hwc_device.h" #include "src/platform/graphics/android/hwc_wrapper.h" #include "src/platform/graphics/android/hwc_layerlist.h" #include "src/platform/graphics/android/hwc_vsync_coordinator.h" #include "mir_test_doubles/mock_hwc_composer_device_1.h" #include "mir_test_doubles/mock_hwc_vsync_coordinator.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_display_device.h" #include "mir_test_doubles/mock_fb_hal_device.h" #include #include #include #include #include namespace mga=mir::graphics::android; namespace mtd=mir::test::doubles; namespace geom=mir::geometry; namespace { class StubHWCWrapper : public mga::HwcWrapper { public: void prepare(hwc_display_contents_1_t&) const override { } void set(hwc_display_contents_1_t&) const override { } }; } template std::shared_ptr make_hwc_device( std::shared_ptr const& hwc_device, std::shared_ptr const& fb_device, std::shared_ptr const& coordinator); template <> std::shared_ptr make_hwc_device( std::shared_ptr const& hwc_device, std::shared_ptr const& fb_device, std::shared_ptr const& coordinator) { auto stub_wrapper = std::make_shared(); return std::make_shared(hwc_device, stub_wrapper, fb_device, coordinator); } template <> std::shared_ptr make_hwc_device( std::shared_ptr const& hwc_device, std::shared_ptr const&, std::shared_ptr const& coordinator) { auto file_ops = std::make_shared(); auto stub_wrapper = std::make_shared(); return std::make_shared(hwc_device, stub_wrapper, coordinator, file_ops); } template class HWCCommon : public ::testing::Test { protected: virtual void SetUp() { using namespace testing; mock_fbdev = std::make_shared(); mock_device = std::make_shared>(); mock_vsync = std::make_shared>(); } testing::NiceMock mock_egl; std::shared_ptr mock_vsync; std::shared_ptr mock_device; std::shared_ptr mock_fbdev; }; typedef ::testing::Types HWCDeviceTestTypes; TYPED_TEST_CASE(HWCCommon, HWCDeviceTestTypes); TYPED_TEST(HWCCommon, test_proc_registration) { using namespace testing; hwc_procs_t const* procs; EXPECT_CALL(*(this->mock_device), registerProcs_interface(this->mock_device.get(), _)) .Times(1) .WillOnce(SaveArg<1>(&procs)); auto device = make_hwc_device(this->mock_device, this->mock_fbdev, this->mock_vsync); EXPECT_NE(nullptr, procs->invalidate); EXPECT_NE(nullptr, procs->vsync); EXPECT_NE(nullptr, procs->hotplug); } TYPED_TEST(HWCCommon, test_vsync_activation_comes_after_proc_registration) { using namespace testing; InSequence sequence_enforcer; EXPECT_CALL(*this->mock_device, registerProcs_interface(this->mock_device.get(),_)) .Times(1); EXPECT_CALL(*this->mock_device, eventControl_interface(this->mock_device.get(), 0, HWC_EVENT_VSYNC, 1)) .Times(1) .WillOnce(Return(0)); auto device = make_hwc_device(this->mock_device, this->mock_fbdev, this->mock_vsync); testing::Mock::VerifyAndClearExpectations(this->mock_device.get()); } TYPED_TEST(HWCCommon, test_vsync_activation_failure_throws) { using namespace testing; EXPECT_CALL(*this->mock_device, eventControl_interface(this->mock_device.get(), 0, HWC_EVENT_VSYNC, _)) .WillRepeatedly(Return(-EINVAL)); auto device = make_hwc_device(this->mock_device, this->mock_fbdev, this->mock_vsync); EXPECT_THROW({ auto device = make_hwc_device(this->mock_device, this->mock_fbdev, this->mock_vsync); device->mode(mir_power_mode_off); }, std::runtime_error); } TYPED_TEST(HWCCommon, test_hwc_turns_on_display_after_proc_registration) { using namespace testing; InSequence sequence_enforcer; EXPECT_CALL(*this->mock_device, registerProcs_interface(this->mock_device.get(),_)) .Times(1); EXPECT_CALL(*this->mock_device, blank_interface(this->mock_device.get(), HWC_DISPLAY_PRIMARY, 0)) .Times(1); auto device = make_hwc_device(this->mock_device, this->mock_fbdev, this->mock_vsync); testing::Mock::VerifyAndClearExpectations(this->mock_device.get()); } TYPED_TEST(HWCCommon, test_hwc_throws_on_blanking_request_error) { using namespace testing; InSequence seq; EXPECT_CALL(*this->mock_device, blank_interface(this->mock_device.get(), HWC_DISPLAY_PRIMARY, 0)) .Times(1) .WillOnce(Return(0)); EXPECT_CALL(*this->mock_device, blank_interface(this->mock_device.get(), HWC_DISPLAY_PRIMARY, 1)) .Times(2) .WillOnce(Return(-1)) .WillOnce(Return(0)); auto device = make_hwc_device(this->mock_device, this->mock_fbdev, this->mock_vsync); EXPECT_THROW({ device->mode(mir_power_mode_off); }, std::runtime_error); } TYPED_TEST(HWCCommon, test_hwc_suspend_standby_throw) { using namespace testing; auto device = make_hwc_device(this->mock_device, this->mock_fbdev, this->mock_vsync); EXPECT_THROW({ device->mode(mir_power_mode_suspend); }, std::runtime_error); EXPECT_THROW({ device->mode(mir_power_mode_standby); }, std::runtime_error); } TYPED_TEST(HWCCommon, test_hwc_deactivates_vsync_on_blank) { using namespace testing; InSequence seq; EXPECT_CALL(*this->mock_device, blank_interface(this->mock_device.get(), HWC_DISPLAY_PRIMARY, 0)) .Times(1) .WillOnce(Return(0)); EXPECT_CALL(*this->mock_device, eventControl_interface(this->mock_device.get(), HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 1)) .Times(1); EXPECT_CALL(*this->mock_device, eventControl_interface(this->mock_device.get(), HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0)) .Times(1); EXPECT_CALL(*this->mock_device, blank_interface(this->mock_device.get(), HWC_DISPLAY_PRIMARY, 1)) .Times(1) .WillOnce(Return(0)); auto device = make_hwc_device(this->mock_device, this->mock_fbdev, this->mock_vsync); device->mode(mir_power_mode_off); } TYPED_TEST(HWCCommon, test_hwc_display_is_deactivated_on_destroy) { auto device = make_hwc_device(this->mock_device, this->mock_fbdev, this->mock_vsync); EXPECT_CALL(*this->mock_device, blank_interface(this->mock_device.get(), HWC_DISPLAY_PRIMARY, 1)) .Times(1); EXPECT_CALL(*this->mock_device, eventControl_interface(this->mock_device.get(), HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0)) .Times(1); device.reset(); } TYPED_TEST(HWCCommon, callback_calls_hwcvsync) { using namespace testing; hwc_procs_t const* procs; EXPECT_CALL(*this->mock_device, registerProcs_interface(this->mock_device.get(), _)) .Times(1) .WillOnce(SaveArg<1>(&procs)); auto device = make_hwc_device(this->mock_device, this->mock_fbdev, this->mock_vsync); EXPECT_CALL(*this->mock_vsync, notify_vsync()) .Times(1); procs->vsync(procs, 0, 0); } TYPED_TEST(HWCCommon, set_orientation) { auto device = make_hwc_device(this->mock_device, this->mock_fbdev, this->mock_vsync); EXPECT_FALSE(device->apply_orientation(mir_orientation_left)); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_android_fb.cpp0000644000015301777760000002413512322054247027242 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/display_buffer.h" #include "mir/graphics/display_configuration.h" #include "mir/logging/logger.h" #include "src/platform/graphics/android/android_display.h" #include "src/server/report/null_report_factory.h" #include "mir_test_doubles/mock_display_report.h" #include "mir_test_doubles/mock_display_device.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/stub_display_buffer.h" #include "mir_test_doubles/stub_display_builder.h" #include "mir_test_doubles/stub_gl_config.h" #include "mir_test_doubles/mock_gl_config.h" #include "mir/graphics/android/mir_native_window.h" #include "mir_test_doubles/stub_driver_interpreter.h" #include #include #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mtd=mir::test::doubles; namespace geom=mir::geometry; class AndroidDisplay : public ::testing::Test { public: AndroidDisplay() : dummy_display{mock_egl.fake_egl_display}, dummy_context{mock_egl.fake_egl_context}, dummy_config{mock_egl.fake_configs[0]}, null_display_report{mir::report::null_display_report()}, stub_db_factory{std::make_shared()}, stub_gl_config{std::make_shared()} { } protected: testing::NiceMock mock_egl; EGLDisplay const dummy_display; EGLContext const dummy_context; EGLConfig const dummy_config; std::shared_ptr const null_display_report; std::shared_ptr const stub_db_factory; std::shared_ptr const stub_gl_config; }; TEST_F(AndroidDisplay, creation_creates_egl_resources_properly) { using namespace testing; EGLSurface fake_surface = (EGLSurface) 0x715; EGLint const expected_pbuffer_attr[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; EGLint const expected_context_attr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; //on constrution EXPECT_CALL(mock_egl, eglGetDisplay(EGL_DEFAULT_DISPLAY)) .Times(1) .WillOnce(Return(dummy_display)); EXPECT_CALL(mock_egl, eglInitialize(dummy_display, _, _)) .Times(1) .WillOnce(DoAll(SetArgPointee<1>(1), SetArgPointee<2>(4), Return(EGL_TRUE))); EXPECT_CALL(mock_egl, eglCreateContext( dummy_display, _, EGL_NO_CONTEXT, mtd::AttrMatches(expected_context_attr))) .Times(1) .WillOnce(Return(dummy_context)); EXPECT_CALL(mock_egl, eglCreatePbufferSurface( dummy_display, _, mtd::AttrMatches(expected_pbuffer_attr))) .Times(1) .WillOnce(Return(fake_surface)); EXPECT_CALL(mock_egl, eglMakeCurrent(dummy_display, fake_surface, fake_surface, dummy_context)) .Times(1); //on destruction EXPECT_CALL(mock_egl, eglGetCurrentContext()) .Times(1) .WillOnce(Return(dummy_context)); EXPECT_CALL(mock_egl, eglMakeCurrent(dummy_display,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT)) .Times(1); EXPECT_CALL(mock_egl, eglDestroySurface(dummy_display, fake_surface)) .Times(1); EXPECT_CALL(mock_egl, eglDestroyContext(dummy_display, dummy_context)) .Times(1); EXPECT_CALL(mock_egl, eglTerminate(dummy_display)) .Times(1); mga::AndroidDisplay display(stub_db_factory, stub_gl_config, null_display_report); } TEST_F(AndroidDisplay, selects_usable_configuration) { using namespace testing; int const incorrect_visual_id = 2; int const correct_visual_id = 1; EGLint const num_cfgs = 45; EGLint const expected_cfg_attr [] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_DEPTH_SIZE, 0, EGL_STENCIL_SIZE, 0, EGL_NONE }; EGLConfig selected_config; EGLConfig cfgs[45]; for(auto i = 0; i < num_cfgs; i++) cfgs[i] = reinterpret_cast(i); int config_to_select_index = 37; EGLConfig correct_config = cfgs[config_to_select_index]; ON_CALL(mock_egl, eglGetConfigAttrib(_, _, EGL_NATIVE_VISUAL_ID, _)) .WillByDefault(DoAll(SetArgPointee<3>(incorrect_visual_id), Return(EGL_TRUE))); ON_CALL(mock_egl, eglGetConfigAttrib(dummy_display, correct_config, EGL_NATIVE_VISUAL_ID,_)) .WillByDefault(DoAll(SetArgPointee<3>(correct_visual_id), Return(EGL_TRUE))); ON_CALL(mock_egl, eglCreateContext(_,_,_,_)) .WillByDefault(DoAll(SaveArg<1>(&selected_config),Return(dummy_context))); auto config_filler = [&] (EGLDisplay, EGLint const*, EGLConfig* out_cfgs, EGLint, EGLint* out_num_cfgs) -> EGLBoolean { memcpy(out_cfgs, cfgs, sizeof(EGLConfig) * num_cfgs); *out_num_cfgs = num_cfgs; return EGL_TRUE; }; EXPECT_CALL(mock_egl, eglGetConfigs(dummy_display, NULL, 0, _)) .Times(1) .WillOnce(DoAll(SetArgPointee<3>(num_cfgs), Return(EGL_TRUE))); EXPECT_CALL(mock_egl, eglChooseConfig(dummy_display, mtd::AttrMatches(expected_cfg_attr),_,num_cfgs,_)) .Times(1) .WillOnce(Invoke(config_filler)); mga::AndroidDisplay display(stub_db_factory, stub_gl_config, null_display_report); EXPECT_EQ(correct_config, selected_config); } TEST_F(AndroidDisplay, respects_gl_config) { using namespace testing; auto const mock_gl_config = std::make_shared(); EGLint const depth_bits{24}; EGLint const stencil_bits{8}; EXPECT_CALL(*mock_gl_config, depth_buffer_bits()) .WillOnce(Return(depth_bits)); EXPECT_CALL(*mock_gl_config, stencil_buffer_bits()) .WillOnce(Return(stencil_bits)); EXPECT_CALL(mock_egl, eglChooseConfig( _, AllOf(mtd::EGLConfigContainsAttrib(EGL_DEPTH_SIZE, depth_bits), mtd::EGLConfigContainsAttrib(EGL_STENCIL_SIZE, stencil_bits)), _,_,_)); mga::AndroidDisplay display(stub_db_factory, mock_gl_config, null_display_report); } TEST_F(AndroidDisplay, logs_creation_events) { using namespace testing; auto const mock_display_report = std::make_shared(); EXPECT_CALL(*mock_display_report, report_successful_setup_of_native_resources()) .Times(1); EXPECT_CALL(*mock_display_report, report_egl_configuration(_,_)) .Times(1); EXPECT_CALL(*mock_display_report, report_successful_egl_make_current_on_construction()) .Times(1); EXPECT_CALL(*mock_display_report, report_successful_display_construction()) .Times(1); mga::AndroidDisplay display(stub_db_factory, stub_gl_config, mock_display_report); } TEST_F(AndroidDisplay, throws_on_eglMakeCurrent_failure) { using namespace testing; auto const mock_display_report = std::make_shared>(); EXPECT_CALL(*mock_display_report, report_successful_setup_of_native_resources()) .Times(1); EXPECT_CALL(mock_egl, eglMakeCurrent(dummy_display, _, _, _)) .Times(1) .WillOnce(Return(EGL_FALSE)); EXPECT_CALL(*mock_display_report, report_successful_egl_make_current_on_construction()) .Times(0); EXPECT_CALL(*mock_display_report, report_successful_display_construction()) .Times(0); EXPECT_THROW({ mga::AndroidDisplay display(stub_db_factory, stub_gl_config, mock_display_report); }, std::runtime_error); } TEST_F(AndroidDisplay, logs_error_because_of_surface_creation_failure) { using namespace testing; auto const mock_display_report = std::make_shared(); EXPECT_CALL(*mock_display_report, report_successful_setup_of_native_resources()) .Times(0); EXPECT_CALL(*mock_display_report, report_successful_egl_make_current_on_construction()) .Times(0); EXPECT_CALL(*mock_display_report, report_successful_display_construction()) .Times(0); EXPECT_CALL(mock_egl, eglCreatePbufferSurface(_,_,_)) .Times(1) .WillOnce(Return(EGL_NO_SURFACE)); EXPECT_THROW({ mga::AndroidDisplay display(stub_db_factory, stub_gl_config, mock_display_report); }, std::runtime_error); } TEST_F(AndroidDisplay, configures_display_buffer) { using namespace testing; mga::AndroidDisplay display(stub_db_factory, stub_gl_config, null_display_report); auto configuration = display.configuration(); configuration->for_each_output([&](mg::UserDisplayConfigurationOutput& output) { output.power_mode = mir_power_mode_on; }); display.configure(*configuration); configuration->for_each_output([&](mg::UserDisplayConfigurationOutput& output) { output.power_mode = mir_power_mode_standby; }); display.configure(*configuration); configuration->for_each_output([&](mg::UserDisplayConfigurationOutput& output) { output.power_mode = mir_power_mode_off; }); display.configure(*configuration); configuration->for_each_output([&](mg::UserDisplayConfigurationOutput& output) { output.power_mode = mir_power_mode_suspend; }); display.configure(*configuration); } //we only have single display and single mode on android for the time being TEST_F(AndroidDisplay, supports_one_output_configuration) { mga::AndroidDisplay display(stub_db_factory, stub_gl_config, null_display_report); auto config = display.configuration(); size_t num_configs = 0; config->for_each_output([&](mg::DisplayConfigurationOutput const&) { num_configs++; }); EXPECT_EQ(1u, num_configs); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_hwc_fb_device.cpp0000644000015301777760000001372612322054247027726 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/hwc_fb_device.h" #include "mir_test_doubles/mock_display_device.h" #include "mir_test_doubles/mock_hwc_composer_device_1.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include "mir_test_doubles/mock_hwc_vsync_coordinator.h" #include "mir_test_doubles/mock_framebuffer_bundle.h" #include "mir_test_doubles/mock_fb_hal_device.h" #include "mir_test_doubles/stub_renderable.h" #include "mir_test_doubles/mock_render_function.h" #include "mir_test_doubles/stub_swapping_gl_context.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_hwc_device_wrapper.h" #include "hwc_struct_helpers.h" #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mtd=mir::test::doubles; namespace geom=mir::geometry; class HwcFbDevice : public ::testing::Test { protected: virtual void SetUp() { using namespace testing; int width = 88; int height = 4; test_size = geom::Size{width, height}; int fbnum = 558; mock_hwc_device = std::make_shared>(); mock_fb_device = std::make_shared( width, height, HAL_PIXEL_FORMAT_RGBA_8888, fbnum); mock_vsync = std::make_shared>(); mock_buffer = std::make_shared>(); mock_hwc_device_wrapper = std::make_shared>(); hwc_rect_t empty_region = {0,0,0,0}; skip_layer.compositionType = HWC_FRAMEBUFFER; skip_layer.hints = 0; skip_layer.flags = HWC_SKIP_LAYER; skip_layer.handle = 0; skip_layer.transform = 0; skip_layer.blending = HWC_BLENDING_NONE; skip_layer.sourceCrop = empty_region; skip_layer.displayFrame = empty_region; skip_layer.visibleRegionScreen = {1, &empty_region}; skip_layer.acquireFenceFd = -1; skip_layer.releaseFenceFd = -1; } int fake_dpy = 0; int fake_sur = 0; EGLDisplay dpy{&fake_dpy}; EGLSurface sur{&fake_sur}; testing::NiceMock mock_egl; geom::Size test_size; std::shared_ptr mock_hwc_device; std::shared_ptr mock_fb_device; std::shared_ptr mock_vsync; std::shared_ptr mock_buffer; std::shared_ptr mock_hwc_device_wrapper; mtd::StubSwappingGLContext stub_context; hwc_layer_1_t skip_layer; }; TEST_F(HwcFbDevice, hwc10_render_gl_only) { using namespace testing; std::list expected_list{&skip_layer}; Sequence seq; EXPECT_CALL(*mock_hwc_device_wrapper, prepare(MatchesList(expected_list))) .InSequence(seq); EXPECT_CALL(mock_egl, eglGetCurrentDisplay()) .InSequence(seq) .WillOnce(Return(dpy)); EXPECT_CALL(mock_egl, eglGetCurrentSurface(EGL_DRAW)) .InSequence(seq) .WillOnce(Return(sur)); EXPECT_CALL(*mock_hwc_device_wrapper, set(MatchesListWithEglFields(expected_list, dpy, sur))) .InSequence(seq); mga::HwcFbDevice device(mock_hwc_device, mock_hwc_device_wrapper, mock_fb_device, mock_vsync); device.render_gl(stub_context); } TEST_F(HwcFbDevice, hwc10_prepare_with_renderables) { using namespace testing; std::list expected_list{&skip_layer}; auto renderable1 = std::make_shared(); auto renderable2 = std::make_shared(); std::list> renderlist { renderable1, renderable2 }; mtd::MockRenderFunction mock_call_counter; testing::Sequence seq; EXPECT_CALL(*mock_hwc_device_wrapper, prepare(MatchesList(expected_list))) .InSequence(seq); EXPECT_CALL(mock_call_counter, called(testing::Ref(*renderable1))) .InSequence(seq); EXPECT_CALL(mock_call_counter, called(testing::Ref(*renderable2))) .InSequence(seq); EXPECT_CALL(mock_egl, eglGetCurrentDisplay()) .InSequence(seq) .WillOnce(Return(dpy)); EXPECT_CALL(mock_egl, eglGetCurrentSurface(EGL_DRAW)) .InSequence(seq) .WillOnce(Return(sur)); EXPECT_CALL(*mock_hwc_device_wrapper, set(MatchesListWithEglFields(expected_list, dpy, sur))) .InSequence(seq); mga::HwcFbDevice device(mock_hwc_device, mock_hwc_device_wrapper, mock_fb_device, mock_vsync); device.render_gl_and_overlays(stub_context, renderlist, [&](mg::Renderable const& renderable) { mock_call_counter.called(renderable); }); } TEST_F(HwcFbDevice, hwc10_post) { using namespace testing; auto native_buffer = std::make_shared>(); Sequence seq; EXPECT_CALL(*mock_buffer, native_buffer_handle()) .InSequence(seq) .WillOnce(Return(native_buffer)); EXPECT_CALL(*mock_fb_device, post_interface(mock_fb_device.get(), &native_buffer->native_handle)) .InSequence(seq); EXPECT_CALL(*mock_vsync, wait_for_vsync()) .InSequence(seq); mga::HwcFbDevice device(mock_hwc_device, mock_hwc_device_wrapper, mock_fb_device, mock_vsync); device.post(*mock_buffer); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_hwc_display.cpp0000644000015301777760000003236212322054247027462 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/display_buffer.h" #include "src/platform/graphics/android/android_display.h" #include "src/platform/graphics/android/gl_context.h" #include "src/platform/graphics/android/android_format_conversion-inl.h" #include "mir_test_doubles/mock_display_device.h" #include "mir_test_doubles/mock_display_report.h" #include "mir_test_doubles/stub_renderable.h" #include "mir_test_doubles/mock_egl.h" #include "mir/graphics/android/mir_native_window.h" #include "mir_test_doubles/stub_driver_interpreter.h" #include "mir_test_doubles/stub_display_buffer.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/stub_gl_config.h" #include "mir_test_doubles/mock_framebuffer_bundle.h" #include namespace geom=mir::geometry; namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mtd=mir::test::doubles; class AndroidDisplayBuffer : public ::testing::Test { protected: virtual void SetUp() { stub_buffer = std::make_shared>(); mock_display_device = std::make_shared>(); native_window = std::make_shared(std::make_shared()); visual_id = 5; dummy_display = mock_egl.fake_egl_display; dummy_config = mock_egl.fake_configs[0]; dummy_context = mock_egl.fake_egl_context; testing::NiceMock report; mtd::StubGLConfig stub_gl_config; gl_context = std::make_shared( mga::to_mir_format(mock_egl.fake_visual_id), stub_gl_config, report); mock_fb_bundle = std::make_shared>(); ON_CALL(*mock_fb_bundle, fb_format()) .WillByDefault(testing::Return(mir_pixel_format_abgr_8888)); ON_CALL(*mock_fb_bundle, fb_size()) .WillByDefault(testing::Return(display_size)); } testing::NiceMock mock_egl; int visual_id; EGLConfig dummy_config; EGLDisplay dummy_display; EGLContext dummy_context; std::shared_ptr gl_context; std::shared_ptr stub_buffer; std::shared_ptr native_window; std::shared_ptr mock_display_device; std::shared_ptr mock_fb_bundle; geom::Size const display_size{433,232}; }; TEST_F(AndroidDisplayBuffer, can_post_update_with_gl_only) { using namespace testing; InSequence seq; EXPECT_CALL(*mock_display_device, render_gl(_)) .Times(Exactly(1)); EXPECT_CALL(*mock_fb_bundle, last_rendered_buffer()) .Times(1) .WillOnce(Return(stub_buffer)); EXPECT_CALL(*mock_display_device, post(Ref(*stub_buffer))) .Times(1); std::list> renderlist{}; mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); db.post_update(); } TEST_F(AndroidDisplayBuffer, performs_default_post_if_empty_list) { using namespace testing; mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); InSequence seq; EXPECT_CALL(*mock_display_device, render_gl(_)) .Times(1); EXPECT_CALL(*mock_fb_bundle, last_rendered_buffer()) .Times(1) .WillOnce(Return(stub_buffer)); EXPECT_CALL(*mock_display_device, post(Ref(*stub_buffer))) .Times(1); std::list> renderlist{}; auto render_fn = [] (mg::Renderable const&) {}; db.render_and_post_update(renderlist, render_fn); } TEST_F(AndroidDisplayBuffer, posts_overlay_list) { using namespace testing; std::list> renderlist{ std::make_shared(), std::make_shared()}; std::function render_fn; InSequence seq; EXPECT_CALL(*mock_display_device, render_gl_and_overlays(_, Ref(renderlist), Ref(render_fn))) .Times(1); EXPECT_CALL(*mock_fb_bundle, last_rendered_buffer()) .Times(1) .WillOnce(Return(stub_buffer)); EXPECT_CALL(*mock_display_device, post(Ref(*stub_buffer))) .Times(1); mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); db.render_and_post_update(renderlist, render_fn); } TEST_F(AndroidDisplayBuffer, defaults_to_normal_orientation) { mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); EXPECT_EQ(mir_orientation_normal, db.orientation()); } TEST_F(AndroidDisplayBuffer, orientation_is_passed_through) { mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); for (auto const& ori : {mir_orientation_normal, mir_orientation_left, mir_orientation_right, mir_orientation_inverted}) { auto config = db.configuration(); config.orientation = ori; db.configure(config); EXPECT_EQ(ori, db.orientation()); } } TEST_F(AndroidDisplayBuffer, rotation_transposes_dimensions) { using namespace testing; int const width = 123; int const height = 456; geom::Size const normal{width, height}; geom::Size const transposed{height, width}; EXPECT_CALL(*mock_fb_bundle, fb_size()) .WillRepeatedly(Return(normal)); mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); EXPECT_EQ(normal, db.view_area().size); auto config = db.configuration(); config.orientation = mir_orientation_right; db.configure(config); EXPECT_EQ(transposed, db.view_area().size); config.orientation = mir_orientation_inverted; db.configure(config); EXPECT_EQ(normal, db.view_area().size); config.orientation = mir_orientation_left; db.configure(config); EXPECT_EQ(transposed, db.view_area().size); } TEST_F(AndroidDisplayBuffer, reports_correct_size) { using namespace testing; mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); auto view_area = db.view_area(); geom::Point origin_pt{geom::X{0}, geom::Y{0}}; EXPECT_EQ(display_size, view_area.size); EXPECT_EQ(origin_pt, view_area.top_left); } TEST_F(AndroidDisplayBuffer, creates_egl_context_from_shared_context) { using namespace testing; EGLint const expected_attr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EXPECT_CALL(mock_egl, eglCreateContext( dummy_display, _, dummy_context, mtd::AttrMatches(expected_attr))) .Times(1) .WillOnce(Return(mock_egl.fake_egl_context)); EXPECT_CALL(mock_egl, eglCreateWindowSurface( dummy_display, _, native_window.get(), NULL)) .Times(1) .WillOnce(Return(mock_egl.fake_egl_surface)); EXPECT_CALL(mock_egl, eglDestroySurface(dummy_display, mock_egl.fake_egl_surface)) .Times(AtLeast(1)); EXPECT_CALL(mock_egl, eglDestroyContext(dummy_display, mock_egl.fake_egl_context)) .Times(AtLeast(1)); mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); testing::Mock::VerifyAndClearExpectations(&mock_egl); } TEST_F(AndroidDisplayBuffer, fails_on_egl_resource_creation) { using namespace testing; EXPECT_CALL(mock_egl, eglCreateContext(_,_,_,_)) .Times(2) .WillOnce(Return(EGL_NO_CONTEXT)) .WillOnce(Return(mock_egl.fake_egl_context)); EXPECT_CALL(mock_egl, eglCreateWindowSurface(_,_,_,_)) .Times(1) .WillOnce(Return(EGL_NO_SURFACE)); EXPECT_THROW( { mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); }, std::runtime_error); EXPECT_THROW( { mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); }, std::runtime_error); } TEST_F(AndroidDisplayBuffer, can_make_current) { using namespace testing; EGLContext fake_ctxt = reinterpret_cast(0x4422); EGLSurface fake_surf = reinterpret_cast(0x33984); EXPECT_CALL(mock_egl, eglCreateContext(_,_,_,_)) .Times(1) .WillOnce(Return(fake_ctxt)); EXPECT_CALL(mock_egl, eglCreateWindowSurface(_,_,_,_)) .Times(1) .WillOnce(Return(fake_surf)); EXPECT_CALL(mock_egl, eglMakeCurrent(dummy_display, fake_surf, fake_surf, fake_ctxt)) .Times(2) .WillOnce(Return(EGL_TRUE)) .WillOnce(Return(EGL_FALSE)); mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); db.make_current(); EXPECT_THROW( { db.make_current(); }, std::runtime_error); } TEST_F(AndroidDisplayBuffer, release_current) { using namespace testing; EXPECT_CALL(mock_egl, eglMakeCurrent(dummy_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) .Times(1); mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); db.release_current(); } TEST_F(AndroidDisplayBuffer, sets_display_power_mode_to_on_at_start) { using namespace testing; mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); auto config = db.configuration(); EXPECT_EQ(mir_power_mode_on, config.power_mode); } TEST_F(AndroidDisplayBuffer, changes_display_power_mode) { using namespace testing; mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); Sequence seq; EXPECT_CALL(*mock_display_device, mode(mir_power_mode_off)) .InSequence(seq); EXPECT_CALL(*mock_display_device, mode(mir_power_mode_on)) .InSequence(seq); auto config = db.configuration(); config.power_mode = mir_power_mode_off; db.configure(config); config = db.configuration(); config.power_mode = mir_power_mode_on; db.configure(config); } TEST_F(AndroidDisplayBuffer, disregards_double_display_power_mode_request) { using namespace testing; mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); EXPECT_CALL(*mock_display_device, mode(mir_power_mode_off)) .Times(1); auto config = db.configuration(); config.power_mode = mir_power_mode_off; db.configure(config); config.power_mode = mir_power_mode_suspend; db.configure(config); config.power_mode = mir_power_mode_standby; db.configure(config); } //configuration tests TEST_F(AndroidDisplayBuffer, display_orientation_supported) { using namespace testing; EXPECT_CALL(*mock_display_device, apply_orientation(mir_orientation_left)) .Times(1) .WillOnce(Return(true)); mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); auto config = db.configuration(); config.orientation = mir_orientation_left; db.configure(config); config = db.configuration(); EXPECT_EQ(mir_orientation_normal, config.orientation); } TEST_F(AndroidDisplayBuffer, display_orientation_not_supported) { using namespace testing; EXPECT_CALL(*mock_display_device, apply_orientation(mir_orientation_left)) .Times(1) .WillOnce(Return(false)); mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); auto config = db.configuration(); config.orientation = mir_orientation_left; db.configure(config); config = db.configuration(); EXPECT_EQ(mir_orientation_left, config.orientation); } TEST_F(AndroidDisplayBuffer, incorrect_display_configure_throws) { mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); auto config = db.configuration(); //error config.current_format = mir_pixel_format_invalid; EXPECT_THROW({ db.configure(config); }, std::runtime_error); } TEST_F(AndroidDisplayBuffer, android_display_configuration_info) { mga::DisplayBuffer db(mock_fb_bundle, mock_display_device, native_window, *gl_context); auto disp_conf = db.configuration(); ASSERT_EQ(1u, disp_conf.modes.size()); auto& disp_mode = disp_conf.modes[0]; EXPECT_EQ(display_size, disp_mode.size); EXPECT_EQ(mg::DisplayConfigurationOutputId{1}, disp_conf.id); EXPECT_EQ(mg::DisplayConfigurationCardId{0}, disp_conf.card_id); EXPECT_TRUE(disp_conf.connected); EXPECT_TRUE(disp_conf.used); auto origin = geom::Point{0,0}; EXPECT_EQ(origin, disp_conf.top_left); EXPECT_EQ(0, disp_conf.current_mode_index); //TODO fill refresh rate accordingly //TODO fill physical_size_mm fields accordingly; } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/CMakeLists.txt0000644000015301777760000000304612322054247026146 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/hwc_struct_helpers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_sync_fence.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_buffer_allocator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_tex_bind.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_fb.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_alloc_adaptor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_buffer_allocator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_hwc_device.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_hwc_fb_device.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_hwc_common_device.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_hwc_display.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_internal_client_interpreter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_internal_client.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_resource_factory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_fb_simple_swapper.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_fb_device.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_hwc_layers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_hwc_layerlist.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_hwc_logger.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_server_interpreter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_pixel_format.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_platform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_interpreter_buffer_cache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_external_refcount.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_output_builder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_hwc_wrapper.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_server_interpreter.cpp0000644000015301777760000001446412322054223031102 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/server_render_window.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/mock_fence.h" #include "mir_test_doubles/mock_interpreter_resource_cache.h" #include "mir_test_doubles/mock_framebuffer_bundle.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include #include #include namespace mt=mir::test; namespace mtd=mir::test::doubles; namespace geom=mir::geometry; namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace { struct ServerRenderWindowTest : public ::testing::Test { virtual void SetUp() { using namespace testing; mock_buffer1 = std::make_shared>(); mock_buffer2 = std::make_shared>(); mock_buffer3 = std::make_shared>(); mock_fb_bundle = std::make_shared>(); mock_cache = std::make_shared>(); ON_CALL(*mock_fb_bundle, fb_format()) .WillByDefault(Return(mir_pixel_format_abgr_8888)); } std::shared_ptr mock_buffer1; std::shared_ptr mock_buffer2; std::shared_ptr mock_buffer3; std::shared_ptr mock_cache; std::shared_ptr mock_fb_bundle; }; } TEST_F(ServerRenderWindowTest, driver_wants_a_buffer) { using namespace testing; mga::ServerRenderWindow render_window(mock_fb_bundle, mock_cache); auto stub_buffer = std::make_shared(); EXPECT_CALL(*mock_fb_bundle, buffer_for_render()) .Times(1) .WillOnce(Return(mock_buffer1)); EXPECT_CALL(*mock_buffer1, native_buffer_handle()) .Times(1) .WillOnce(Return(stub_buffer)); std::shared_ptr tmp = mock_buffer1; std::shared_ptr tmp2 = stub_buffer; EXPECT_CALL(*mock_cache, store_buffer(tmp, tmp2)) .Times(1); auto rc_buffer = render_window.driver_requests_buffer(); EXPECT_EQ(stub_buffer.get(), rc_buffer); } TEST_F(ServerRenderWindowTest, driver_is_done_with_a_buffer_properly) { using namespace testing; int fake_fence = 488; auto stub_buffer = std::make_shared(); mga::ServerRenderWindow render_window(mock_fb_bundle, mock_cache); EXPECT_CALL(*mock_fb_bundle, buffer_for_render()) .Times(1) .WillOnce(Return(mock_buffer1)); EXPECT_CALL(*mock_buffer1, native_buffer_handle()) .Times(1) .WillOnce(Return(stub_buffer)); render_window.driver_requests_buffer(); testing::Mock::VerifyAndClearExpectations(mock_fb_bundle.get()); std::shared_ptr buf1 = mock_buffer1; EXPECT_CALL(*mock_cache, update_native_fence(stub_buffer->anwb(), fake_fence)) .Times(1); EXPECT_CALL(*mock_cache, retrieve_buffer(stub_buffer->anwb())) .Times(1) .WillOnce(Return(mock_buffer1)); render_window.driver_returns_buffer(stub_buffer->anwb(), fake_fence); testing::Mock::VerifyAndClearExpectations(mock_fb_bundle.get()); } TEST_F(ServerRenderWindowTest, driver_inquires_about_format) { using namespace testing; EXPECT_CALL(*mock_fb_bundle, fb_format()) .Times(1) .WillOnce(Return(mir_pixel_format_abgr_8888)); mga::ServerRenderWindow render_window(mock_fb_bundle, mock_cache); EXPECT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, render_window.driver_requests_info(NATIVE_WINDOW_FORMAT)); } TEST_F(ServerRenderWindowTest, driver_inquires_about_format_after_format_set) { using namespace testing; mga::ServerRenderWindow render_window(mock_fb_bundle, mock_cache); render_window.dispatch_driver_request_format(HAL_PIXEL_FORMAT_RGBX_8888); auto rc_format = render_window.driver_requests_info(NATIVE_WINDOW_FORMAT); EXPECT_EQ(HAL_PIXEL_FORMAT_RGBX_8888, rc_format); } TEST_F(ServerRenderWindowTest, driver_inquires_about_size_without_having_been_set) { using namespace testing; geom::Size test_size{4, 5}; EXPECT_CALL(*mock_fb_bundle, fb_size()) .Times(4) .WillRepeatedly(Return(test_size)); mga::ServerRenderWindow render_window(mock_fb_bundle, mock_cache); unsigned int rc_width = render_window.driver_requests_info(NATIVE_WINDOW_DEFAULT_WIDTH); unsigned int rc_height = render_window.driver_requests_info(NATIVE_WINDOW_DEFAULT_HEIGHT); EXPECT_EQ(test_size.width.as_uint32_t(), rc_width); EXPECT_EQ(test_size.height.as_uint32_t(), rc_height); rc_width = render_window.driver_requests_info(NATIVE_WINDOW_WIDTH); rc_height = render_window.driver_requests_info(NATIVE_WINDOW_HEIGHT); EXPECT_EQ(test_size.width.as_uint32_t(), rc_width); EXPECT_EQ(test_size.height.as_uint32_t(), rc_height); } TEST_F(ServerRenderWindowTest, driver_inquires_about_transform) { using namespace testing; mga::ServerRenderWindow render_window(mock_fb_bundle, mock_cache); EXPECT_EQ(0, render_window.driver_requests_info(NATIVE_WINDOW_TRANSFORM_HINT)); } TEST_F(ServerRenderWindowTest, driver_unknown_inquiry) { using namespace testing; mga::ServerRenderWindow render_window(mock_fb_bundle, mock_cache); EXPECT_THROW({ render_window.driver_requests_info(NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND); }, std::runtime_error); } TEST_F(ServerRenderWindowTest, driver_swapinterval_request) { EXPECT_CALL(*mock_fb_bundle, wait_for_consumed_buffer(false)) .Times(1); mga::ServerRenderWindow render_window(mock_fb_bundle, mock_cache); render_window.sync_to_display(false); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_android_platform.cpp0000644000015301777760000001131212322054223030462 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/report/null_report_factory.h" #include "mir/graphics/native_platform.h" #include "mir/graphics/buffer_ipc_packer.h" #include "mir/options/program_option.h" #include "src/platform/graphics/android/android_platform.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/mock_android_hw.h" #include "mir_test_doubles/mock_buffer_packer.h" #include "mir_test_doubles/mock_display_report.h" #include "mir_test_doubles/stub_display_builder.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mt=mir::test; namespace mtd=mir::test::doubles; namespace mr=mir::report; namespace geom=mir::geometry; namespace mo=mir::options; class PlatformBufferIPCPackaging : public ::testing::Test { protected: virtual void SetUp() { using namespace testing; stub_display_builder = std::make_shared(); stub_display_report = mr::null_display_report(); stride = geom::Stride(300*4); num_ints = 43; num_fds = 55; auto handle_size = sizeof(native_handle_t) + (sizeof(int)*(num_ints + num_fds)); auto native_buffer_raw = (native_handle_t*) ::operator new(handle_size); native_buffer_handle = std::shared_ptr(native_buffer_raw); native_buffer_handle->numInts = num_ints; native_buffer_handle->numFds = num_fds; for(auto i=0u; i< (num_ints+num_fds); i++) { native_buffer_handle->data[i] = i; } native_buffer = std::make_shared(); mock_buffer = std::make_shared>(); ON_CALL(*native_buffer, handle()) .WillByDefault(Return(native_buffer_handle.get())); ON_CALL(*mock_buffer, native_buffer_handle()) .WillByDefault(Return(native_buffer)); ON_CALL(*mock_buffer, stride()) .WillByDefault(Return(stride)); } std::shared_ptr native_buffer; std::shared_ptr stub_display_builder; std::shared_ptr mock_buffer; std::shared_ptr native_buffer_handle; std::shared_ptr stub_display_report; geom::Stride stride; unsigned int num_ints, num_fds; }; /* ipc packaging tests */ TEST_F(PlatformBufferIPCPackaging, test_ipc_data_packed_correctly) { using namespace ::testing; mga::AndroidPlatform platform(stub_display_builder, stub_display_report); mtd::MockPacker mock_packer; int offset = 0; for(auto i=0u; idata[offset++])) .Times(1); } for(auto i=0u; idata[offset++])) .Times(1); } EXPECT_CALL(*mock_buffer, stride()) .WillOnce(Return(stride)); EXPECT_CALL(mock_packer, pack_stride(stride)) .Times(1); EXPECT_CALL(*mock_buffer, size()) .WillOnce(Return(mir::geometry::Size{123, 456})); EXPECT_CALL(mock_packer, pack_size(_)) .Times(1); platform.fill_ipc_package(&mock_packer, mock_buffer.get()); } TEST(AndroidGraphicsPlatform, egl_native_display_is_egl_default_display) { mga::AndroidPlatform platform( std::make_shared(), mr::null_display_report()); EXPECT_EQ(EGL_DEFAULT_DISPLAY, platform.egl_native_display()); } TEST(NestedPlatformCreation, doesnt_access_display_hardware) { using namespace testing; mtd::HardwareAccessMock hwaccess; mtd::MockDisplayReport stub_report; EXPECT_CALL(hwaccess, hw_get_module(StrEq(HWC_HARDWARE_MODULE_ID), _)) .Times(0); EXPECT_CALL(hwaccess, hw_get_module(StrEq(GRALLOC_HARDWARE_MODULE_ID), _)) .Times(AtMost(1)); auto platform = mg::create_native_platform(mt::fake_shared(stub_report)); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_output_builder.cpp0000644000015301777760000002124512322054247030220 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/output_builder.h" #include "src/platform/graphics/android/gl_context.h" #include "src/platform/graphics/android/android_format_conversion-inl.h" #include "src/platform/graphics/android/resource_factory.h" #include "src/platform/graphics/android/graphic_buffer_allocator.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/mock_buffer_packer.h" #include "mir_test_doubles/mock_display_report.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_android_hw.h" #include "mir_test_doubles/mock_fb_hal_device.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include "mir_test_doubles/stub_gl_config.h" #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mt=mir::test; namespace mtd=mir::test::doubles; namespace geom=mir::geometry; namespace { struct MockGraphicBufferAllocator : public mga::GraphicBufferAllocator { MockGraphicBufferAllocator() { using namespace testing; ON_CALL(*this, alloc_buffer_platform(_,_,_)) .WillByDefault(Return(nullptr)); } MOCK_METHOD3(alloc_buffer_platform, std::shared_ptr(geom::Size, MirPixelFormat, mga::BufferUsage)); }; struct MockResourceFactory: public mga::DisplayResourceFactory { ~MockResourceFactory() noexcept {} MockResourceFactory() { using namespace testing; ON_CALL(*this, create_hwc_native_device()).WillByDefault(Return(nullptr)); ON_CALL(*this, create_fb_native_device()).WillByDefault(Return(nullptr)); ON_CALL(*this, create_native_window(_)).WillByDefault(Return(nullptr)); ON_CALL(*this, create_fb_device(_)).WillByDefault(Return(nullptr)); ON_CALL(*this, create_hwc_device(_)).WillByDefault(Return(nullptr)); ON_CALL(*this, create_hwc_fb_device(_,_)).WillByDefault(Return(nullptr)); } MOCK_CONST_METHOD0(create_hwc_native_device, std::shared_ptr()); MOCK_CONST_METHOD0(create_fb_native_device, std::shared_ptr()); MOCK_CONST_METHOD1(create_native_window, std::shared_ptr(std::shared_ptr const&)); MOCK_CONST_METHOD1(create_fb_device, std::shared_ptr(std::shared_ptr const&)); MOCK_CONST_METHOD1(create_hwc_device, std::shared_ptr(std::shared_ptr const&)); MOCK_CONST_METHOD2(create_hwc_fb_device, std::shared_ptr( std::shared_ptr const&, std::shared_ptr const&)); }; class OutputBuilder : public ::testing::Test { public: void SetUp() { using namespace testing; mock_resource_factory = std::make_shared>(); ON_CALL(*mock_resource_factory, create_hwc_native_device()) .WillByDefault(Return(hw_access_mock.mock_hwc_device)); ON_CALL(*mock_resource_factory, create_fb_native_device()) .WillByDefault(Return(mt::fake_shared(fb_hal_mock))); } testing::NiceMock mock_egl; testing::NiceMock hw_access_mock; testing::NiceMock fb_hal_mock; std::shared_ptr mock_resource_factory; testing::NiceMock mock_display_report; testing::NiceMock mock_buffer_allocator; mtd::StubGLConfig stub_gl_config; mga::GLContext gl_context{ mga::to_mir_format(mock_egl.fake_visual_id), stub_gl_config, mock_display_report}; }; } TEST_F(OutputBuilder, hwc_version_10_success) { using namespace testing; hw_access_mock.mock_hwc_device->common.version = HWC_DEVICE_API_VERSION_1_0; EXPECT_CALL(*mock_resource_factory, create_hwc_native_device()) .Times(1); EXPECT_CALL(*mock_resource_factory, create_fb_native_device()) .Times(1); EXPECT_CALL(*mock_resource_factory, create_hwc_fb_device(_,_)) .Times(1); EXPECT_CALL(mock_display_report, report_hwc_composition_in_use(1,0)) .Times(1); EXPECT_CALL(*mock_resource_factory, create_native_window(_)) .Times(1); mga::OutputBuilder factory( mt::fake_shared(mock_buffer_allocator),mock_resource_factory, mt::fake_shared(mock_display_report)); factory.create_display_buffer(gl_context); } TEST_F(OutputBuilder, hwc_version_10_failure_uses_gpu) { using namespace testing; hw_access_mock.mock_hwc_device->common.version = HWC_DEVICE_API_VERSION_1_0; EXPECT_CALL(*mock_resource_factory, create_hwc_native_device()) .Times(1) .WillOnce(Throw(std::runtime_error(""))); EXPECT_CALL(*mock_resource_factory, create_fb_native_device()) .Times(1); EXPECT_CALL(*mock_resource_factory, create_fb_device(_)) .Times(1); EXPECT_CALL(mock_display_report, report_gpu_composition_in_use()) .Times(1); EXPECT_CALL(*mock_resource_factory, create_native_window(_)) .Times(1); mga::OutputBuilder factory( mt::fake_shared(mock_buffer_allocator),mock_resource_factory, mt::fake_shared(mock_display_report)); factory.create_display_buffer(gl_context); } TEST_F(OutputBuilder, hwc_version_11_success) { using namespace testing; hw_access_mock.mock_hwc_device->common.version = HWC_DEVICE_API_VERSION_1_1; EXPECT_CALL(*mock_resource_factory, create_hwc_native_device()) .Times(1); EXPECT_CALL(*mock_resource_factory, create_hwc_device(_)) .Times(1); EXPECT_CALL(mock_display_report, report_hwc_composition_in_use(1,1)) .Times(1); EXPECT_CALL(*mock_resource_factory, create_native_window(_)) .Times(1); mga::OutputBuilder factory( mt::fake_shared(mock_buffer_allocator),mock_resource_factory, mt::fake_shared(mock_display_report)); factory.create_display_buffer(gl_context); } TEST_F(OutputBuilder, hwc_version_11_hwc_failure) { using namespace testing; hw_access_mock.mock_hwc_device->common.version = HWC_DEVICE_API_VERSION_1_1; EXPECT_CALL(*mock_resource_factory, create_hwc_native_device()) .Times(1) .WillOnce(Throw(std::runtime_error(""))); EXPECT_CALL(*mock_resource_factory, create_fb_native_device()) .Times(1); EXPECT_CALL(*mock_resource_factory, create_fb_device(_)) .Times(1); EXPECT_CALL(mock_display_report, report_gpu_composition_in_use()) .Times(1); EXPECT_CALL(*mock_resource_factory, create_native_window(_)) .Times(1); mga::OutputBuilder factory( mt::fake_shared(mock_buffer_allocator),mock_resource_factory, mt::fake_shared(mock_display_report)); factory.create_display_buffer(gl_context); } TEST_F(OutputBuilder, hwc_version_11_hwc_and_fb_failure_fatal) { using namespace testing; hw_access_mock.mock_hwc_device->common.version = HWC_DEVICE_API_VERSION_1_1; EXPECT_CALL(*mock_resource_factory, create_hwc_native_device()) .Times(1) .WillOnce(Throw(std::runtime_error(""))); EXPECT_CALL(*mock_resource_factory, create_fb_native_device()) .Times(1) .WillOnce(Throw(std::runtime_error(""))); EXPECT_THROW({ mga::OutputBuilder factory( mt::fake_shared(mock_buffer_allocator),mock_resource_factory, mt::fake_shared(mock_display_report)); }, std::runtime_error); } TEST_F(OutputBuilder, hwc_version_12) { using namespace testing; hw_access_mock.mock_hwc_device->common.version = HWC_DEVICE_API_VERSION_1_2; EXPECT_CALL(*mock_resource_factory, create_hwc_native_device()) .Times(1); EXPECT_CALL(*mock_resource_factory, create_hwc_device(_)) .Times(1); EXPECT_CALL(mock_display_report, report_hwc_composition_in_use(1,2)) .Times(1); mga::OutputBuilder factory( mt::fake_shared(mock_buffer_allocator),mock_resource_factory, mt::fake_shared(mock_display_report)); factory.create_display_buffer(gl_context); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_external_refcount.cpp0000644000015301777760000000660112322054223030672 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/android/android_native_buffer.h" #include "mir_test_doubles/mock_fence.h" #include #include namespace mtd=mir::test::doubles; namespace mga=mir::graphics::android; TEST(AndroidRefcount, driver_hooks) { auto native_handle_resource = std::make_shared(); auto use_count_before = native_handle_resource.use_count(); ANativeWindowBuffer* driver_reference = nullptr; { auto tmp = new mga::RefCountedNativeBuffer(native_handle_resource); std::shared_ptr buffer(tmp, [](mga::RefCountedNativeBuffer* buffer) { buffer->mir_dereference(); }); driver_reference = buffer.get(); driver_reference->common.incRef(&driver_reference->common); //Mir loses its reference, driver still has a ref } EXPECT_EQ(use_count_before+1, native_handle_resource.use_count()); driver_reference->common.decRef(&driver_reference->common); EXPECT_EQ(use_count_before, native_handle_resource.use_count()); } TEST(AndroidRefcount, driver_hooks_mir_ref) { auto native_handle_resource = std::make_shared(); auto use_count_before = native_handle_resource.use_count(); { std::shared_ptr mir_reference; ANativeWindowBuffer* driver_reference = nullptr; { auto tmp = new mga::RefCountedNativeBuffer(native_handle_resource); mir_reference = std::shared_ptr(tmp, [](mga::RefCountedNativeBuffer* buffer) { buffer->mir_dereference(); }); driver_reference = tmp; driver_reference->common.incRef(&driver_reference->common); } //driver loses its reference driver_reference->common.decRef(&driver_reference->common); EXPECT_EQ(use_count_before+1, native_handle_resource.use_count()); } EXPECT_EQ(use_count_before, native_handle_resource.use_count()); } TEST(AndroidAndroidNativeBuffer, wait_for_fence) { auto fence = std::make_shared(); EXPECT_CALL(*fence, wait()) .Times(1); auto native_handle_resource = std::make_shared(); mga::AndroidNativeBuffer buffer(native_handle_resource, fence); buffer.wait_for_content(); } TEST(AndroidAndroidNativeBuffer, update_fence) { int fake_fd = 48484; auto fence = std::make_shared(); EXPECT_CALL(*fence, merge_with(fake_fd)) .Times(1); auto native_handle_resource = std::make_shared(); mga::AndroidNativeBuffer buffer(native_handle_resource, fence); buffer.update_fence(fake_fd); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_pixel_format.cpp0000644000015301777760000000341612322054223027635 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/android_format_conversion-inl.h" #include namespace mga=mir::graphics::android; TEST(PixelFormatConversion, conversion_to_android_test) { EXPECT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mga::to_android_format(mir_pixel_format_abgr_8888)); EXPECT_EQ(HAL_PIXEL_FORMAT_RGBX_8888, mga::to_android_format(mir_pixel_format_xbgr_8888)); EXPECT_EQ(HAL_PIXEL_FORMAT_BGRA_8888, mga::to_android_format(mir_pixel_format_argb_8888)); //note X to A conversion! EXPECT_EQ(HAL_PIXEL_FORMAT_BGRA_8888, mga::to_android_format(mir_pixel_format_xrgb_8888)); EXPECT_EQ(HAL_PIXEL_FORMAT_RGB_888, mga::to_android_format(mir_pixel_format_bgr_888)); } TEST(PixelFormatConversion, conversion_to_mir_test) { EXPECT_EQ(mir_pixel_format_abgr_8888, mga::to_mir_format(HAL_PIXEL_FORMAT_RGBA_8888)); EXPECT_EQ(mir_pixel_format_xbgr_8888, mga::to_mir_format(HAL_PIXEL_FORMAT_RGBX_8888)); EXPECT_EQ(mir_pixel_format_argb_8888, mga::to_mir_format(HAL_PIXEL_FORMAT_BGRA_8888)); EXPECT_EQ(mir_pixel_format_bgr_888, mga::to_mir_format(HAL_PIXEL_FORMAT_RGB_888)); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_hwc_device.cpp0000644000015301777760000004770112322054247027257 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/android/sync_fence.h" #include "src/platform/graphics/android/framebuffer_bundle.h" #include "src/platform/graphics/android/hwc_device.h" #include "src/platform/graphics/android/hwc_layerlist.h" #include "src/platform/graphics/android/gl_context.h" #include "mir_test_doubles/mock_hwc_composer_device_1.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/mock_hwc_vsync_coordinator.h" #include "mir_test_doubles/stub_renderable.h" #include "mir_test_doubles/mock_framebuffer_bundle.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/mock_hwc_device_wrapper.h" #include "mir_test/fake_shared.h" #include "hwc_struct_helpers.h" #include "mir_test_doubles/mock_render_function.h" #include "mir_test_doubles/mock_swapping_gl_context.h" #include "mir_test_doubles/stub_swapping_gl_context.h" #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mtd=mir::test::doubles; namespace geom=mir::geometry; namespace mt=mir::test; namespace { class StubRenderable : public mg::Renderable { public: StubRenderable(std::shared_ptr const& buffer, geom::Rectangle screen_pos) : buf(buffer), screen_pos(screen_pos) { } std::shared_ptr buffer(void const*) const override { return buf; } bool alpha_enabled() const { return false; } geom::Rectangle screen_position() const override { return screen_pos; } float alpha() const { return 1.0; } glm::mat4 transformation() const { static glm::mat4 matrix; return matrix; } bool visible() const { return true; } bool shaped() const { return true; } int buffers_ready_for_compositor() const override { return 1; } private: std::shared_ptr buf; geom::Rectangle screen_pos; }; struct MockFileOps : public mga::SyncFileOps { MOCK_METHOD3(ioctl, int(int,int,void*)); MOCK_METHOD1(dup, int(int)); MOCK_METHOD1(close, int(int)); }; } class HwcDevice : public ::testing::Test { protected: virtual void SetUp() { using namespace testing; mock_native_buffer = std::make_shared>(); mock_native_buffer->anwb()->width = buffer_size.width.as_int(); mock_native_buffer->anwb()->height = buffer_size.height.as_int(); mock_device = std::make_shared>(); mock_vsync = std::make_shared>(); mock_file_ops = std::make_shared(); ON_CALL(mock_buffer, size()) .WillByDefault(Return(buffer_size)); ON_CALL(mock_buffer, native_buffer_handle()) .WillByDefault(Return(mock_native_buffer)); empty_region = {0,0,0,0}; set_region = {0, 0, buffer_size.width.as_int(), buffer_size.height.as_int()}; screen_pos = { screen_position.top_left.x.as_int(), screen_position.top_left.y.as_int(), screen_position.size.width.as_int(), screen_position.size.height.as_int() }; comp_layer.compositionType = HWC_FRAMEBUFFER; comp_layer.hints = 0; comp_layer.flags = 0; comp_layer.handle = mock_native_buffer->handle(); comp_layer.transform = 0; comp_layer.blending = HWC_BLENDING_NONE; comp_layer.sourceCrop = set_region; comp_layer.displayFrame = screen_pos; comp_layer.visibleRegionScreen = {1, &set_region}; comp_layer.acquireFenceFd = -1; comp_layer.releaseFenceFd = -1; target_layer.compositionType = HWC_FRAMEBUFFER_TARGET; target_layer.hints = 0; target_layer.flags = 0; target_layer.handle = 0; target_layer.transform = 0; target_layer.blending = HWC_BLENDING_NONE; target_layer.sourceCrop = empty_region; target_layer.displayFrame = empty_region; target_layer.visibleRegionScreen = {1, &set_region}; target_layer.acquireFenceFd = -1; target_layer.releaseFenceFd = -1; skip_layer.compositionType = HWC_FRAMEBUFFER; skip_layer.hints = 0; skip_layer.flags = HWC_SKIP_LAYER; skip_layer.handle = 0; skip_layer.transform = 0; skip_layer.blending = HWC_BLENDING_NONE; skip_layer.sourceCrop = empty_region; skip_layer.displayFrame = empty_region; skip_layer.visibleRegionScreen = {1, &set_region}; skip_layer.acquireFenceFd = -1; skip_layer.releaseFenceFd = -1; set_skip_layer = skip_layer; set_skip_layer.handle = mock_native_buffer->handle(); set_skip_layer.sourceCrop = {0, 0, buffer_size.width.as_int(), buffer_size.height.as_int()}; set_skip_layer.displayFrame = {0, 0, buffer_size.width.as_int(), buffer_size.height.as_int()}; set_target_layer = target_layer; set_target_layer.handle = mock_native_buffer->handle(); set_target_layer.sourceCrop = {0, 0, buffer_size.width.as_int(), buffer_size.height.as_int()}; set_target_layer.displayFrame = {0, 0, buffer_size.width.as_int(), buffer_size.height.as_int()}; stub_renderable1 = std::make_shared( mt::fake_shared(mock_buffer), screen_position); stub_renderable2 = std::make_shared( mt::fake_shared(mock_buffer), screen_position); empty_prepare_fn = [] (hwc_display_contents_1_t&) {}; empty_render_fn = [] (mg::Renderable const&) {}; mock_hwc_device_wrapper = std::make_shared>(); } std::shared_ptr mock_file_ops; std::shared_ptr mock_vsync; std::shared_ptr mock_device; std::shared_ptr mock_native_buffer; EGLDisplay dpy; EGLSurface surf; hwc_rect_t screen_pos; hwc_rect_t empty_region; hwc_rect_t set_region; hwc_layer_1_t skip_layer; hwc_layer_1_t target_layer; hwc_layer_1_t set_skip_layer; hwc_layer_1_t set_target_layer; hwc_layer_1_t comp_layer; geom::Size buffer_size{333, 444}; geom::Rectangle screen_position{{9,8},{245, 250}}; std::shared_ptr stub_renderable1; std::shared_ptr stub_renderable2; std::shared_ptr mock_hwc_device_wrapper; std::function empty_prepare_fn; std::function empty_render_fn; testing::NiceMock mock_buffer; mtd::MockSwappingGLContext mock_context; mtd::StubSwappingGLContext stub_context; }; TEST_F(HwcDevice, prepares_a_skip_and_target_layer_by_default) { using namespace testing; std::list expected_list { &skip_layer, &target_layer }; EXPECT_CALL(*mock_hwc_device_wrapper, prepare(MatchesList(expected_list))) .Times(1); mga::HwcDevice device(mock_device, mock_hwc_device_wrapper, mock_vsync, mock_file_ops); device.render_gl(stub_context); } TEST_F(HwcDevice, calls_render_fn_and_swap_when_all_overlays_are_rejected) { using namespace testing; mtd::MockRenderFunction mock_render_fn; auto render_fn = [&](mg::Renderable const& renderable) { mock_render_fn.called(renderable); }; std::list> updated_list({ stub_renderable1, stub_renderable2 }); std::list expected_list { &comp_layer, &comp_layer, &target_layer }; Sequence seq; EXPECT_CALL(*mock_hwc_device_wrapper, prepare(MatchesList(expected_list))) .InSequence(seq) .WillOnce(Invoke([&](hwc_display_contents_1_t& contents) { ASSERT_EQ(contents.numHwLayers, 3); contents.hwLayers[0].compositionType = HWC_FRAMEBUFFER; contents.hwLayers[1].compositionType = HWC_FRAMEBUFFER; contents.hwLayers[2].compositionType = HWC_FRAMEBUFFER_TARGET; })); EXPECT_CALL(mock_render_fn, called(Ref(*stub_renderable1))) .InSequence(seq); EXPECT_CALL(mock_render_fn, called(Ref(*stub_renderable2))) .InSequence(seq); EXPECT_CALL(mock_context, swap_buffers()) .InSequence(seq); mga::HwcDevice device(mock_device, mock_hwc_device_wrapper, mock_vsync, mock_file_ops); device.render_gl_and_overlays(mock_context, updated_list, render_fn); } TEST_F(HwcDevice, calls_render_and_swap_when_some_overlays_are_rejected) { using namespace testing; mtd::MockRenderFunction mock_render_fn; auto render_fn = [&](mg::Renderable const& renderable) { mock_render_fn.called(renderable); }; std::list> updated_list({ stub_renderable1, stub_renderable2 }); std::list expected_list { &comp_layer, &comp_layer, &target_layer }; Sequence seq; EXPECT_CALL(*mock_hwc_device_wrapper, prepare(MatchesList(expected_list))) .InSequence(seq) .WillOnce(Invoke([&](hwc_display_contents_1_t& contents) { ASSERT_EQ(contents.numHwLayers, 3); contents.hwLayers[0].compositionType = HWC_OVERLAY; contents.hwLayers[1].compositionType = HWC_FRAMEBUFFER; contents.hwLayers[2].compositionType = HWC_FRAMEBUFFER_TARGET; })); EXPECT_CALL(mock_render_fn, called(Ref(*stub_renderable2))) .InSequence(seq); EXPECT_CALL(mock_context, swap_buffers()) .InSequence(seq); mga::HwcDevice device(mock_device, mock_hwc_device_wrapper, mock_vsync, mock_file_ops); device.render_gl_and_overlays(mock_context, updated_list, render_fn); } TEST_F(HwcDevice, does_not_call_render_or_swap_when_all_overlays_accepted) { using namespace testing; mtd::MockRenderFunction mock_render_fn; auto render_fn = [&](mg::Renderable const& renderable) { mock_render_fn.called(renderable); }; std::list> updated_list({ stub_renderable1, stub_renderable2 }); std::list expected_list { &comp_layer, &comp_layer, &target_layer }; EXPECT_CALL(*mock_hwc_device_wrapper, prepare(MatchesList(expected_list))) .Times(1) .WillOnce(Invoke([&](hwc_display_contents_1_t& contents) { ASSERT_EQ(contents.numHwLayers, 3); contents.hwLayers[0].compositionType = HWC_OVERLAY; contents.hwLayers[1].compositionType = HWC_OVERLAY; contents.hwLayers[2].compositionType = HWC_FRAMEBUFFER_TARGET; })); EXPECT_CALL(mock_render_fn, called(_)) .Times(0); EXPECT_CALL(mock_context, swap_buffers()) .Times(0); mga::HwcDevice device(mock_device, mock_hwc_device_wrapper, mock_vsync, mock_file_ops); device.render_gl_and_overlays(mock_context, updated_list, render_fn); } TEST_F(HwcDevice, resets_layers_when_prepare_gl_called) { using namespace testing; std::list expected_list1 { &comp_layer, &comp_layer, &target_layer }; std::list expected_list2 { &skip_layer, &target_layer }; Sequence seq; EXPECT_CALL(*mock_hwc_device_wrapper, prepare(MatchesList(expected_list1))) .InSequence(seq); EXPECT_CALL(*mock_hwc_device_wrapper, prepare(MatchesList(expected_list2))) .InSequence(seq); mga::HwcDevice device(mock_device, mock_hwc_device_wrapper, mock_vsync, mock_file_ops); std::list> updated_list({ stub_renderable1, stub_renderable2 }); device.render_gl_and_overlays(stub_context, updated_list, [](mg::Renderable const&){}); device.render_gl(stub_context); } TEST_F(HwcDevice, sets_and_updates_fences) { using namespace testing; int fb_release_fence = 94; int hwc_retire_fence = 74; auto set_fences_fn = [&](hwc_display_contents_1_t& contents) { ASSERT_EQ(contents.numHwLayers, 2); contents.hwLayers[1].releaseFenceFd = fb_release_fence; contents.retireFenceFd = hwc_retire_fence; }; std::list expected_list { &set_skip_layer, &set_target_layer }; Sequence seq; EXPECT_CALL(*mock_hwc_device_wrapper, set(MatchesList(expected_list))) .InSequence(seq) .WillOnce(Invoke(set_fences_fn)); EXPECT_CALL(*mock_native_buffer, update_fence(fb_release_fence)) .InSequence(seq); EXPECT_CALL(*mock_file_ops, close(hwc_retire_fence)) .InSequence(seq); mga::HwcDevice device(mock_device, mock_hwc_device_wrapper, mock_vsync, mock_file_ops); device.render_gl(stub_context); device.post(mock_buffer); } TEST_F(HwcDevice, sets_proper_list_with_overlays) { using namespace testing; int overlay_acquire_fence1 = 80; int overlay_acquire_fence2 = 81; int fb_acquire_fence = 82; int release_fence1 = 381; int release_fence2 = 382; int release_fence3 = 383; auto native_handle_1 = std::make_shared(); auto native_handle_2 = std::make_shared(); auto native_handle_3 = std::make_shared(); native_handle_1->anwb()->width = buffer_size.width.as_int(); native_handle_1->anwb()->height = buffer_size.height.as_int(); native_handle_2->anwb()->width = buffer_size.width.as_int(); native_handle_2->anwb()->height = buffer_size.height.as_int(); native_handle_3->anwb()->width = buffer_size.width.as_int(); native_handle_3->anwb()->height = buffer_size.height.as_int(); EXPECT_CALL(mock_buffer, native_buffer_handle()) .WillOnce(Return(native_handle_1)) .WillOnce(Return(native_handle_2)) .WillRepeatedly(Return(native_handle_3)); auto set_fences_fn = [&](hwc_display_contents_1_t& contents) { ASSERT_EQ(contents.numHwLayers, 3); contents.hwLayers[0].releaseFenceFd = release_fence1; contents.hwLayers[1].releaseFenceFd = release_fence2; contents.hwLayers[2].releaseFenceFd = release_fence3; contents.retireFenceFd = -1; }; /* set non-default renderlist */ std::list> updated_list({ stub_renderable1, stub_renderable1 }); hwc_layer_1_t comp_layer1, comp_layer2; comp_layer1.compositionType = HWC_OVERLAY; comp_layer1.hints = 0; comp_layer1.flags = 0; comp_layer1.handle = native_handle_1->handle(); comp_layer1.transform = 0; comp_layer1.blending = HWC_BLENDING_NONE; comp_layer1.sourceCrop = set_region; comp_layer1.displayFrame = screen_pos; comp_layer1.visibleRegionScreen = {1, &set_region}; comp_layer1.acquireFenceFd = overlay_acquire_fence1; comp_layer1.releaseFenceFd = -1; comp_layer2.compositionType = HWC_OVERLAY; comp_layer2.hints = 0; comp_layer2.flags = 0; comp_layer2.handle = native_handle_2->handle(); comp_layer2.transform = 0; comp_layer2.blending = HWC_BLENDING_NONE; comp_layer2.sourceCrop = set_region; comp_layer2.displayFrame = screen_pos; comp_layer2.visibleRegionScreen = {1, &set_region}; comp_layer2.acquireFenceFd = overlay_acquire_fence2; comp_layer2.releaseFenceFd = -1; set_target_layer.acquireFenceFd = fb_acquire_fence; set_target_layer.handle = native_handle_3->handle(); std::list expected_list { &comp_layer1, &comp_layer2, &set_target_layer }; mga::HwcDevice device(mock_device, mock_hwc_device_wrapper, mock_vsync, mock_file_ops); //all accepted Sequence seq; EXPECT_CALL(*mock_hwc_device_wrapper, prepare(_)) .InSequence(seq) .WillOnce(Invoke([&](hwc_display_contents_1_t& contents) { ASSERT_EQ(contents.numHwLayers, 3); contents.hwLayers[0].compositionType = HWC_OVERLAY; contents.hwLayers[1].compositionType = HWC_OVERLAY; contents.hwLayers[2].compositionType = HWC_FRAMEBUFFER_TARGET; })); //copy all fb fences for OVERLAY or FRAMEBUFFER_TARGET in preparation of set EXPECT_CALL(*native_handle_1, copy_fence()) .InSequence(seq) .WillOnce(Return(overlay_acquire_fence1)); EXPECT_CALL(*native_handle_2, copy_fence()) .InSequence(seq) .WillOnce(Return(overlay_acquire_fence2)); EXPECT_CALL(*native_handle_3, copy_fence()) .InSequence(seq) .WillOnce(Return(fb_acquire_fence)); //set EXPECT_CALL(*mock_hwc_device_wrapper, set(MatchesList(expected_list))) .InSequence(seq) .WillOnce(Invoke(set_fences_fn)); EXPECT_CALL(*native_handle_1, update_fence(release_fence1)) .InSequence(seq); EXPECT_CALL(*native_handle_2, update_fence(release_fence2)) .InSequence(seq); EXPECT_CALL(*native_handle_3, update_fence(release_fence3)) .InSequence(seq); device.render_gl_and_overlays(stub_context, updated_list, [](mg::Renderable const&){}); device.post(mock_buffer); } TEST_F(HwcDevice, discards_second_set_if_all_overlays_and_nothing_has_changed) { using namespace testing; std::list> updated_list({ stub_renderable1, stub_renderable2 }); mga::HwcDevice device(mock_device, mock_hwc_device_wrapper, mock_vsync, mock_file_ops); ON_CALL(*mock_hwc_device_wrapper, prepare(_)) .WillByDefault(Invoke([&](hwc_display_contents_1_t& contents) { ASSERT_EQ(contents.numHwLayers, 3); contents.hwLayers[0].compositionType = HWC_OVERLAY; contents.hwLayers[1].compositionType = HWC_OVERLAY; contents.hwLayers[2].compositionType = HWC_FRAMEBUFFER_TARGET; })); EXPECT_CALL(*mock_hwc_device_wrapper, set(_)) .Times(1); device.render_gl_and_overlays(stub_context, updated_list, [](mg::Renderable const&){}); device.post(mock_buffer); device.render_gl_and_overlays(stub_context, updated_list, [](mg::Renderable const&){}); device.post(mock_buffer); } TEST_F(HwcDevice, submits_every_time_if_at_least_one_layer_is_gl_rendered) { using namespace testing; std::list> updated_list({ stub_renderable1, stub_renderable2 }); mga::HwcDevice device(mock_device, mock_hwc_device_wrapper, mock_vsync, mock_file_ops); ON_CALL(*mock_hwc_device_wrapper, prepare(_)) .WillByDefault(Invoke([&](hwc_display_contents_1_t& contents) { ASSERT_EQ(contents.numHwLayers, 3); contents.hwLayers[0].compositionType = HWC_OVERLAY; contents.hwLayers[1].compositionType = HWC_FRAMEBUFFER; contents.hwLayers[2].compositionType = HWC_FRAMEBUFFER_TARGET; })); EXPECT_CALL(*mock_hwc_device_wrapper, set(_)) .Times(2); device.render_gl_and_overlays(stub_context, updated_list, [](mg::Renderable const&){}); device.post(mock_buffer); device.render_gl_and_overlays(stub_context, updated_list, [](mg::Renderable const&){}); device.post(mock_buffer); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_interpreter_buffer_cache.cpp0000644000015301777760000000730212322054223032161 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/android/interpreter_cache.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mtd=mir::test::doubles; struct InterpreterResourceTest : public ::testing::Test { void SetUp() { stub_buffer1 = std::make_shared(); stub_buffer2 = std::make_shared(); stub_buffer3 = std::make_shared(); native_buffer1 = std::make_shared>(); native_buffer2 = std::make_shared(); native_buffer3 = std::make_shared(); } std::shared_ptr stub_buffer1; std::shared_ptr stub_buffer2; std::shared_ptr stub_buffer3; std::shared_ptr native_buffer1; std::shared_ptr native_buffer2; std::shared_ptr native_buffer3; }; TEST_F(InterpreterResourceTest, deposit_buffer) { mga::InterpreterCache cache; cache.store_buffer(stub_buffer1, native_buffer1); auto test_buffer = cache.retrieve_buffer(native_buffer1->anwb()); EXPECT_EQ(stub_buffer1, test_buffer); } TEST_F(InterpreterResourceTest, deposit_many_buffers) { mga::InterpreterCache cache; cache.store_buffer(stub_buffer1, native_buffer1); cache.store_buffer(stub_buffer2, native_buffer2); cache.store_buffer(stub_buffer3, native_buffer3); EXPECT_EQ(stub_buffer3, cache.retrieve_buffer(native_buffer3->anwb())); EXPECT_EQ(stub_buffer1, cache.retrieve_buffer(native_buffer1->anwb())); EXPECT_EQ(stub_buffer2, cache.retrieve_buffer(native_buffer2->anwb())); } TEST_F(InterpreterResourceTest, deposit_buffer_has_ownership) { mga::InterpreterCache cache; auto native_use_count_before = native_buffer1.use_count(); auto use_count_before = stub_buffer1.use_count(); cache.store_buffer(stub_buffer1, native_buffer1); EXPECT_EQ(native_use_count_before+1, native_buffer1.use_count()); EXPECT_EQ(use_count_before+1, stub_buffer1.use_count()); cache.retrieve_buffer(native_buffer1->anwb()); EXPECT_EQ(native_use_count_before, native_buffer1.use_count()); EXPECT_EQ(use_count_before, stub_buffer1.use_count()); } TEST_F(InterpreterResourceTest, update_fence_for) { int fence_fd = 44; mga::InterpreterCache cache; EXPECT_CALL(*native_buffer1, update_fence(fence_fd)) .Times(1); cache.store_buffer(stub_buffer1, native_buffer1); cache.update_native_fence(native_buffer1->anwb(), fence_fd); EXPECT_THROW({ cache.update_native_fence(nullptr, fence_fd); }, std::runtime_error); } TEST_F(InterpreterResourceTest, retreive_buffer_with_bad_key_throws) { mga::InterpreterCache cache; EXPECT_THROW({ cache.retrieve_buffer(native_buffer1->anwb()); }, std::runtime_error); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/android/test_hwc_layerlist.cpp0000644000015301777760000000523612322054223030017 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_doubles/stub_renderable.h" #include "src/platform/graphics/android/hwc_layerlist.h" #include "hwc_struct_helpers.h" #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace mtd=mir::test::doubles; namespace { struct LayerListTest : public testing::Test { LayerListTest() : renderables{std::make_shared(), std::make_shared(), std::make_shared()} {} std::list> renderables; }; } TEST_F(LayerListTest, list_defaults) { mga::LayerList layerlist{{}, 0}; auto list = layerlist.native_list().lock(); EXPECT_EQ(-1, list->retireFenceFd); EXPECT_EQ(HWC_GEOMETRY_CHANGED, list->flags); EXPECT_NE(nullptr, list->dpy); EXPECT_NE(nullptr, list->sur); EXPECT_EQ(layerlist.begin(), layerlist.end()); EXPECT_EQ(layerlist.additional_layers_begin(), layerlist.end()); } TEST_F(LayerListTest, list_iterators) { size_t additional_layers = 2; mga::LayerList list(renderables, additional_layers); EXPECT_EQ(std::distance(list.begin(), list.end()), additional_layers + renderables.size()); EXPECT_EQ(std::distance(list.additional_layers_begin(), list.end()), additional_layers); EXPECT_EQ(std::distance(list.begin(), list.additional_layers_begin()), renderables.size()); mga::LayerList list2({}, additional_layers); EXPECT_EQ(std::distance(list2.begin(), list2.end()), additional_layers); EXPECT_EQ(std::distance(list2.additional_layers_begin(), list2.end()), additional_layers); EXPECT_EQ(std::distance(list2.begin(), list2.additional_layers_begin()), 0); mga::LayerList list3(renderables, 0); EXPECT_EQ(std::distance(list3.begin(), list3.end()), renderables.size()); EXPECT_EQ(std::distance(list3.additional_layers_begin(), list3.end()), 0); EXPECT_EQ(std::distance(list3.begin(), list3.additional_layers_begin()), renderables.size()); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/test_display.cpp0000644000015301777760000001471012322054247025176 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/display.h" #include "mir/graphics/display_configuration.h" #include "mir/graphics/gl_context.h" #include "mir/options/program_option.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_gl.h" #include "mir_test_doubles/stub_gl_config.h" #include "src/server/graphics/default_display_configuration_policy.h" #ifndef ANDROID #include "mir_test_doubles/mock_drm.h" #include "mir_test_doubles/mock_gbm.h" #include "mir_test_doubles/null_virtual_terminal.h" #include "src/platform/graphics/mesa/platform.h" #include "mir_test_framework/udev_environment.h" #else #include "src/platform/graphics/android/android_platform.h" #include "mir_test_doubles/mock_android_hw.h" #include "mir_test_doubles/mock_display_device.h" #endif #include "src/server/report/null_report_factory.h" #include #include namespace mg = mir::graphics; namespace mtd = mir::test::doubles; namespace mr = mir::report; #ifndef ANDROID namespace mtf = mir::mir_test_framework; #endif class DisplayTest : public ::testing::Test { public: DisplayTest() { using namespace testing; ON_CALL(mock_egl, eglChooseConfig(_,_,_,1,_)) .WillByDefault(DoAll(SetArgPointee<2>(mock_egl.fake_configs[0]), SetArgPointee<4>(1), Return(EGL_TRUE))); const char* egl_exts = "EGL_KHR_image EGL_KHR_image_base EGL_MESA_drm_image"; const char* gl_exts = "GL_OES_texture_npot GL_OES_EGL_image"; ON_CALL(mock_egl, eglQueryString(_,EGL_EXTENSIONS)) .WillByDefault(Return(egl_exts)); ON_CALL(mock_gl, glGetString(GL_EXTENSIONS)) .WillByDefault(Return(reinterpret_cast(gl_exts))); #ifndef ANDROID fake_devices.add_standard_device("standard-drm-devices"); #endif } std::shared_ptr create_display() { auto report = mr::null_display_report(); #ifdef ANDROID auto platform = mg::create_platform( std::make_shared(), report); #else auto platform = std::make_shared(report, std::make_shared()); #endif return platform->create_display( std::make_shared(), std::make_shared()); } ::testing::NiceMock mock_egl; ::testing::NiceMock mock_gl; #ifdef ANDROID ::testing::NiceMock hw_access_mock; #else ::testing::NiceMock mock_drm; ::testing::NiceMock mock_gbm; mtf::UdevEnvironment fake_devices; #endif }; namespace { class MockDisplayConfiguration : public mg::DisplayConfiguration { public: 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()); }; } TEST_F(DisplayTest, configure_disallows_invalid_configuration) { using namespace testing; auto display = create_display(); MockDisplayConfiguration config; EXPECT_CALL(config, valid()) .WillOnce(Return(false)); EXPECT_THROW({display->configure(config);}, std::logic_error); // Determining what counts as a valid configuration is a much trickier // platform-dependent exercise, so won't be tested here. } TEST_F(DisplayTest, gl_context_make_current_uses_shared_context) { using namespace testing; EGLContext const shared_context{reinterpret_cast(0x111)}; EGLContext const display_buffer_context{reinterpret_cast(0x222)}; EGLContext const new_context{reinterpret_cast(0x333)}; EXPECT_CALL(mock_egl, eglCreateContext(_,_,EGL_NO_CONTEXT,_)) .WillOnce(Return(shared_context)); EXPECT_CALL(mock_egl, eglCreateContext(_,_,shared_context,_)) .WillOnce(Return(display_buffer_context)); auto display = create_display(); Mock::VerifyAndClearExpectations(&mock_egl); { InSequence s; EXPECT_CALL(mock_egl, eglCreateContext(_,_,shared_context,_)) .WillOnce(Return(new_context)); EXPECT_CALL(mock_egl, eglMakeCurrent(_,_,_,new_context)); EXPECT_CALL(mock_egl, eglGetCurrentContext()) .WillOnce(Return(new_context)); EXPECT_CALL(mock_egl, eglMakeCurrent(_,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT)); auto gl_ctx = display->create_gl_context(); ASSERT_NE(nullptr, gl_ctx); gl_ctx->make_current(); } Mock::VerifyAndClearExpectations(&mock_egl); /* Possible display shutdown sequence, depending on the platform */ EXPECT_CALL(mock_egl, eglGetCurrentContext()) .Times(AtLeast(0)); EXPECT_CALL(mock_egl, eglMakeCurrent(_,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT)) .Times(AtLeast(0)); } TEST_F(DisplayTest, gl_context_releases_context) { using namespace testing; auto display = create_display(); { InSequence s; EXPECT_CALL(mock_egl, eglMakeCurrent(_,_,_,Ne(EGL_NO_CONTEXT))); EXPECT_CALL(mock_egl, eglMakeCurrent(_,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT)); auto gl_ctx = display->create_gl_context(); ASSERT_NE(nullptr, gl_ctx); gl_ctx->make_current(); gl_ctx->release_current(); Mock::VerifyAndClearExpectations(&mock_egl); } /* Possible display shutdown sequence, depending on the platform */ EXPECT_CALL(mock_egl, eglMakeCurrent(_,EGL_NO_SURFACE,EGL_NO_SURFACE,EGL_NO_CONTEXT)) .Times(AtLeast(0)); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/offscreen/0000755000015301777760000000000012322054703023732 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/offscreen/test_offscreen_display.cpp0000644000015301777760000001207612322054223031177 0ustar pbusernogroup00000000000000#include "mir/graphics/basic_platform.h" #include "mir/graphics/display_buffer.h" #include "src/server/graphics/offscreen/display.h" #include "src/server/graphics/default_display_configuration_policy.h" #include "src/server/report/null_report_factory.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_gl.h" #include #include #include namespace mg=mir::graphics; namespace mgo=mir::graphics::offscreen; namespace mtd=mir::test::doubles; namespace mr = mir::report; namespace { class StubBasicPlatform : public mg::BasicPlatform { public: StubBasicPlatform(EGLNativeDisplayType native_display) : native_display{native_display} { } EGLNativeDisplayType egl_native_display() const { return native_display; } private: EGLNativeDisplayType const native_display; }; class OffscreenDisplayTest : public ::testing::Test { public: OffscreenDisplayTest() { using namespace ::testing; ON_CALL(mock_egl, eglChooseConfig(_,_,_,1,_)) .WillByDefault(DoAll(SetArgPointee<2>(mock_egl.fake_configs[0]), SetArgPointee<4>(1), Return(EGL_TRUE))); const char* const egl_exts = "EGL_KHR_image EGL_KHR_image_base"; const char* const gl_exts = "GL_OES_EGL_image"; ON_CALL(mock_egl, eglQueryString(_,EGL_EXTENSIONS)) .WillByDefault(Return(egl_exts)); ON_CALL(mock_gl, glGetString(GL_EXTENSIONS)) .WillByDefault(Return(reinterpret_cast(gl_exts))); ON_CALL(mock_gl, glCheckFramebufferStatus(_)) .WillByDefault(Return(GL_FRAMEBUFFER_COMPLETE)); } ::testing::NiceMock mock_egl; ::testing::NiceMock mock_gl; }; } TEST_F(OffscreenDisplayTest, uses_basic_platform_egl_native_display) { using namespace ::testing; EGLNativeDisplayType const native_display{ reinterpret_cast(0x12345)}; InSequence s; EXPECT_CALL(mock_egl, eglGetDisplay(native_display)); EXPECT_CALL(mock_egl, eglInitialize(mock_egl.fake_egl_display, _, _)); EXPECT_CALL(mock_egl, eglTerminate(mock_egl.fake_egl_display)); mgo::Display display{ std::make_shared(native_display), std::make_shared(), mr::null_display_report()}; } TEST_F(OffscreenDisplayTest, orientation_normal) { using namespace ::testing; EGLNativeDisplayType const native_display{ reinterpret_cast(0x12345)}; mgo::Display display{ std::make_shared(native_display), std::make_shared(), mr::null_display_report()}; int count = 0; display.for_each_display_buffer( [&](mg::DisplayBuffer& db) { ++count; EXPECT_EQ(mir_orientation_normal, db.orientation()); }); EXPECT_TRUE(count); } TEST_F(OffscreenDisplayTest, makes_fbo_current_rendering_target) { using namespace ::testing; GLuint const fbo{66}; EGLNativeDisplayType const native_display{ reinterpret_cast(0x12345)}; /* Creates GL framebuffer objects */ EXPECT_CALL(mock_gl, glGenFramebuffers(1,_)) .Times(AtLeast(1)) .WillRepeatedly(SetArgPointee<1>(fbo)); mgo::Display display{ std::make_shared(native_display), std::make_shared(), mr::null_display_report()}; Mock::VerifyAndClearExpectations(&mock_gl); /* Binds the GL framebuffer objects */ display.for_each_display_buffer( [this](mg::DisplayBuffer& db) { EXPECT_CALL(mock_egl, eglMakeCurrent(_,_,_,Ne(EGL_NO_CONTEXT))); EXPECT_CALL(mock_gl, glBindFramebuffer(_,Ne(0))); db.make_current(); Mock::VerifyAndClearExpectations(&mock_egl); Mock::VerifyAndClearExpectations(&mock_gl); }); } TEST_F(OffscreenDisplayTest, restores_previous_state_on_fbo_setup_failure) { using namespace ::testing; GLuint const old_fbo{66}; GLuint const new_fbo{67}; EGLNativeDisplayType const native_display{ reinterpret_cast(0x12345)}; EXPECT_CALL(mock_gl, glGetIntegerv(GL_FRAMEBUFFER_BINDING, _)) .WillOnce(SetArgPointee<1>(old_fbo)); EXPECT_CALL(mock_gl, glGetIntegerv(GL_VIEWPORT, _)); InSequence s; EXPECT_CALL(mock_gl, glGenFramebuffers(1,_)) .WillOnce(SetArgPointee<1>(new_fbo)); EXPECT_CALL(mock_gl, glBindFramebuffer(_,new_fbo)); EXPECT_CALL(mock_gl, glCheckFramebufferStatus(_)) .WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)); EXPECT_CALL(mock_gl, glBindFramebuffer(_,old_fbo)); EXPECT_THROW({ mgo::Display display( std::make_shared(native_display), std::make_shared(), mr::null_display_report()); }, std::runtime_error); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/offscreen/CMakeLists.txt0000644000015301777760000000022412322054223026465 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_offscreen_display.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/test_buffer_properties.cpp0000644000015301777760000000606212322054223027251 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/graphics/buffer_properties.h" #include #include namespace mg = mir::graphics; namespace geom = mir::geometry; TEST(buffer_properties, default_create) { geom::Size size; MirPixelFormat pixel_format{mir_pixel_format_invalid}; mg::BufferUsage usage{mg::BufferUsage::undefined}; mg::BufferProperties prop; EXPECT_EQ(size, prop.size); EXPECT_EQ(pixel_format, prop.format); EXPECT_EQ(usage, prop.usage); } TEST(buffer_properties, custom_create) { geom::Size size{66, 166}; MirPixelFormat pixel_format{mir_pixel_format_abgr_8888}; mg::BufferUsage usage{mg::BufferUsage::hardware}; mg::BufferProperties prop{size, pixel_format, usage}; EXPECT_EQ(size, prop.size); EXPECT_EQ(pixel_format, prop.format); EXPECT_EQ(usage, prop.usage); } TEST(buffer_properties, equal_properties_test_equal) { geom::Size size{66, 166}; MirPixelFormat pixel_format{mir_pixel_format_abgr_8888}; mg::BufferUsage usage{mg::BufferUsage::hardware}; mg::BufferProperties prop0{size, pixel_format, usage}; mg::BufferProperties prop1{size, pixel_format, usage}; EXPECT_EQ(prop0, prop0); EXPECT_EQ(prop1, prop1); EXPECT_EQ(prop0, prop1); EXPECT_EQ(prop1, prop0); } TEST(buffer_properties, unequal_properties_test_unequal) { geom::Size size[2] = { {geom::Width{66}, geom::Height{166}}, {geom::Width{67}, geom::Height{166}} }; MirPixelFormat pixel_format[2] = { mir_pixel_format_abgr_8888, mir_pixel_format_bgr_888 }; mg::BufferUsage usage[2] = { mg::BufferUsage::hardware, mg::BufferUsage::software }; mg::BufferProperties prop000{size[0], pixel_format[0], usage[0]}; /* This approach doesn't really scale, but it's good enough for now */ for (int s = 0; s < 2; s++) { for (int p = 0; p < 2; p++) { for (int u = 0; u < 2; u++) { mg::BufferProperties prop{size[s], pixel_format[p], usage[u]}; if (s != 0 || p != 0 || u != 0) { EXPECT_NE(prop000, prop); EXPECT_NE(prop, prop000); } else { EXPECT_EQ(prop000, prop); EXPECT_EQ(prop, prop000); } } } } } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/egl_mock/0000755000015301777760000000000012322054703023540 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/egl_mock/egl_mock_test.cpp0000644000015301777760000000330512322054223027061 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_doubles/mock_egl.h" #include "gtest/gtest.h" namespace mtd = mir::test::doubles; TEST(EglMock, demo) { using namespace ::testing; mtd::MockEGL mock; EXPECT_CALL(mock, eglGetError()).Times(Exactly(1)); eglGetError(); } #define EGL_MOCK_TEST(test, egl_call, mock_egl_call) \ TEST(EglMock, test_##test) \ { \ using namespace ::testing; \ \ mtd::MockEGL mock; \ EXPECT_CALL(mock, mock_egl_call).Times(Exactly(1)); \ egl_call; \ } \ EGL_MOCK_TEST(eglGetError, eglGetError(), eglGetError()) EGL_MOCK_TEST(eglGetDisplay, eglGetDisplay(NULL), eglGetDisplay(NULL)) mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/egl_mock/CMakeLists.txt0000644000015301777760000000021412322054223026272 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/egl_mock_test.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/test_surfaceless_egl_context.cpp0000644000015301777760000001722612322054223030442 0ustar pbusernogroup00000000000000/* * 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: * Christopher James Halse Rogers */ #include "mir/graphics/surfaceless_egl_context.h" #include "mir_test_doubles/mock_egl.h" #include #include #include #include namespace mg = mir::graphics; namespace mtd = mir::test::doubles; class SurfacelessEGLContextTest : public ::testing::Test { public: EGLDisplay const fake_display{reinterpret_cast(0xfffaaafa)}; EGLSurface const fake_surface{reinterpret_cast(0xdeadbeef)}; EGLContext const fake_context{reinterpret_cast(0xfaafbaaf)}; protected: virtual void SetUp() { using namespace testing; ON_CALL(mock_egl, eglCreatePbufferSurface(_,_,_)) .WillByDefault(Return(fake_surface)); ON_CALL(mock_egl, eglCreateContext(_,_,_,_)) .WillByDefault(Return(fake_context)); ON_CALL(mock_egl, eglGetCurrentContext()) .WillByDefault(Return(EGL_NO_CONTEXT)); } testing::NiceMock mock_egl; }; namespace { MATCHER(ConfigAttribContainsPBufferFlag, "") { EGLint surface_type = 0; bool found_surface_type = false; std::list pretty_surface; for (int i = 0; arg[i] != EGL_NONE; ++i) { if (arg[i] == EGL_SURFACE_TYPE) { surface_type = arg[i+1]; found_surface_type = true; } } if (found_surface_type) { if (surface_type == EGL_DONT_CARE) { pretty_surface.push_back("EGL_DONT_CARE"); } else { if (surface_type & EGL_MULTISAMPLE_RESOLVE_BOX_BIT) { pretty_surface.push_back("EGL_MULTISAMPLE_RESOLVE_BOX_BIT"); } if (surface_type & EGL_PBUFFER_BIT) { pretty_surface.push_back("EGL_PBUFFER_BIT"); } if (surface_type & EGL_PIXMAP_BIT) { pretty_surface.push_back("EGL_PIXMAP_BIT"); } if (surface_type & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) { pretty_surface.push_back("EGL_SWAP_BEHAVIOR_PRESERVED_BIT"); } if (surface_type & EGL_VG_ALPHA_FORMAT_PRE_BIT) { pretty_surface.push_back("EGL_VG_ALPHA_FORMAT_PRE_BIT"); } if (surface_type & EGL_VG_COLORSPACE_LINEAR_BIT) { pretty_surface.push_back("EGL_VG_COLORSPACE_LINEAR_BIT"); } if (surface_type & EGL_WINDOW_BIT) { pretty_surface.push_back("EGL_WINDOW_BIT"); } } std::string pretty_result = pretty_surface.back(); pretty_surface.pop_back(); for (auto& pretty : pretty_surface) { pretty_result += " | " + pretty; } *result_listener << "surface type is "<< pretty_result; } else { *result_listener << "no surface type set"; } return found_surface_type && (surface_type != EGL_DONT_CARE) && (surface_type & EGL_PBUFFER_BIT); } } TEST_F(SurfacelessEGLContextTest, UsesPBufferContainingAttribsListByDefault) { using namespace testing; ON_CALL(mock_egl, eglQueryString(_,_)) .WillByDefault(Return("")); EXPECT_CALL(mock_egl, eglChooseConfig(_, ConfigAttribContainsPBufferFlag(), _,_,_)) .WillOnce(DoAll(SetArgPointee<4>(1), Return(EGL_TRUE))); mg::SurfacelessEGLContext ctx_noattrib(fake_display, EGL_NO_CONTEXT); } TEST_F(SurfacelessEGLContextTest, KeepsPBufferInAttribsList) { using namespace testing; const EGLint attribs_with_pbuffer[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT | EGL_WINDOW_BIT, EGL_NONE }; ON_CALL(mock_egl, eglQueryString(_,_)) .WillByDefault(Return("")); EXPECT_CALL(mock_egl, eglChooseConfig(_, ConfigAttribContainsPBufferFlag(), _,_,_)) .WillOnce(DoAll(SetArgPointee<4>(1), Return(EGL_TRUE))); mg::SurfacelessEGLContext ctx_attribs_with_pbuffer(fake_display, attribs_with_pbuffer, EGL_NO_CONTEXT); } TEST_F(SurfacelessEGLContextTest, AddsPBufferToAttribList) { using namespace testing; const EGLint attribs_without_surface_type[] = { EGL_ALPHA_SIZE, 8, EGL_CLIENT_APIS, EGL_OPENGL_ES2_BIT, EGL_NONE }; ON_CALL(mock_egl, eglQueryString(_,_)) .WillByDefault(Return("")); EXPECT_CALL(mock_egl, eglChooseConfig(_, ConfigAttribContainsPBufferFlag(), _,_,_)) .WillOnce(DoAll(SetArgPointee<4>(1), Return(EGL_TRUE))); mg::SurfacelessEGLContext ctx_attribs_without_surface_type(fake_display, attribs_without_surface_type, EGL_NO_CONTEXT); } TEST_F(SurfacelessEGLContextTest, AddsPBufferWhenNonPBufferSurfaceTypeRequested) { using namespace testing; const EGLint attribs_without_pbuffer[] = { EGL_SURFACE_TYPE, EGL_DONT_CARE, EGL_ALPHA_SIZE, 8, EGL_CLIENT_APIS, EGL_OPENGL_ES2_BIT, EGL_NONE }; ON_CALL(mock_egl, eglQueryString(_,_)) .WillByDefault(Return("")); EXPECT_CALL(mock_egl, eglChooseConfig(_, ConfigAttribContainsPBufferFlag(), _,_,_)) .WillOnce(DoAll(SetArgPointee<4>(1), Return(EGL_TRUE))); mg::SurfacelessEGLContext ctx_attribs_without_pbuffer(fake_display, attribs_without_pbuffer, EGL_NO_CONTEXT); } TEST_F(SurfacelessEGLContextTest, DoesNotRequestPBufferWithNoAttrib) { using namespace testing; ON_CALL(mock_egl, eglQueryString(_,_)) .WillByDefault(Return("EGL_KHR_surfaceless_context")); EXPECT_CALL(mock_egl, eglChooseConfig(_, Not(ConfigAttribContainsPBufferFlag()), _,_,_)) .WillOnce(DoAll(SetArgPointee<4>(1), Return(EGL_TRUE))); mg::SurfacelessEGLContext ctx_noattrib(fake_display, EGL_NO_CONTEXT); } TEST_F(SurfacelessEGLContextTest, DoesNotAddPBufferToAttribList) { using namespace testing; const EGLint attribs_without_surface_type[] = { EGL_ALPHA_SIZE, 8, EGL_CLIENT_APIS, EGL_OPENGL_ES2_BIT, EGL_NONE }; ON_CALL(mock_egl, eglQueryString(_,_)) .WillByDefault(Return("EGL_KHR_surfaceless_context")); EXPECT_CALL(mock_egl, eglChooseConfig(_, Not(ConfigAttribContainsPBufferFlag()), _,_,_)) .WillOnce(DoAll(SetArgPointee<4>(1), Return(EGL_TRUE))); mg::SurfacelessEGLContext ctx_attribs_without_surface_type(fake_display, attribs_without_surface_type, EGL_NO_CONTEXT); } TEST_F(SurfacelessEGLContextTest, DoesNotAddPBufferToSurfaceTypeRequest) { using namespace testing; const EGLint attribs_with_surface_type[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_ALPHA_SIZE, 8, EGL_CLIENT_APIS, EGL_OPENGL_ES2_BIT, EGL_NONE }; ON_CALL(mock_egl, eglQueryString(_,_)) .WillByDefault(Return("EGL_KHR_surfaceless_context")); EXPECT_CALL(mock_egl, eglChooseConfig(_, Not(ConfigAttribContainsPBufferFlag()), _,_,_)) .WillOnce(DoAll(SetArgPointee<4>(1), Return(EGL_TRUE))); mg::SurfacelessEGLContext ctx_attribs_with_surface_type(fake_display, attribs_with_surface_type, EGL_NO_CONTEXT); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/test_display_configuration.cpp0000644000015301777760000002042212322054223030114 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/display_configuration.h" #include namespace mg = mir::graphics; namespace geom = mir::geometry; namespace { mg::DisplayConfigurationOutput const tmpl_output { mg::DisplayConfigurationOutputId{3}, mg::DisplayConfigurationCardId{2}, mg::DisplayConfigurationOutputType::dvid, { mir_pixel_format_abgr_8888 }, { {geom::Size{10, 20}, 60.0}, {geom::Size{10, 20}, 59.0}, {geom::Size{15, 20}, 59.0} }, 0, geom::Size{10, 20}, true, true, geom::Point(), 2, mir_pixel_format_abgr_8888, mir_power_mode_on, mir_orientation_normal }; } TEST(DisplayConfiguration, same_cards_compare_equal) { mg::DisplayConfigurationCardId const id{1}; size_t const max_outputs{3}; mg::DisplayConfigurationCard const card1{id, max_outputs}; mg::DisplayConfigurationCard const card2 = card1; EXPECT_EQ(card1, card1); EXPECT_EQ(card1, card2); EXPECT_EQ(card2, card1); } TEST(DisplayConfiguration, different_cards_compare_unequal) { mg::DisplayConfigurationCardId const id1{1}; mg::DisplayConfigurationCardId const id2{2}; size_t const max_outputs1{3}; size_t const max_outputs2{4}; mg::DisplayConfigurationCard const card1{id1, max_outputs1}; mg::DisplayConfigurationCard const card2{id1, max_outputs2}; mg::DisplayConfigurationCard const card3{id2, max_outputs1}; EXPECT_NE(card1, card2); EXPECT_NE(card2, card1); EXPECT_NE(card2, card3); EXPECT_NE(card3, card2); EXPECT_NE(card1, card3); EXPECT_NE(card3, card1); } TEST(DisplayConfiguration, same_modes_compare_equal) { geom::Size const size{10, 20}; double const vrefresh{59.9}; mg::DisplayConfigurationMode const mode1{size, vrefresh}; mg::DisplayConfigurationMode const mode2 = mode1; EXPECT_EQ(mode1, mode1); EXPECT_EQ(mode1, mode2); EXPECT_EQ(mode2, mode1); } TEST(DisplayConfiguration, different_modes_compare_unequal) { geom::Size const size1{10, 20}; geom::Size const size2{10, 21}; double const vrefresh1{59.9}; double const vrefresh2{60.0}; mg::DisplayConfigurationMode const mode1{size1, vrefresh1}; mg::DisplayConfigurationMode const mode2{size1, vrefresh2}; mg::DisplayConfigurationMode const mode3{size2, vrefresh1}; EXPECT_NE(mode1, mode2); EXPECT_NE(mode2, mode1); EXPECT_NE(mode2, mode3); EXPECT_NE(mode3, mode2); EXPECT_NE(mode1, mode3); EXPECT_NE(mode3, mode1); } TEST(DisplayConfiguration, same_outputs_compare_equal) { mg::DisplayConfigurationOutput const output1 = tmpl_output; mg::DisplayConfigurationOutput output2 = tmpl_output; EXPECT_EQ(output1, output1); EXPECT_EQ(output1, output2); EXPECT_EQ(output2, output1); } TEST(DisplayConfiguration, outputs_with_different_ids_compare_unequal) { mg::DisplayConfigurationOutput const output1 = tmpl_output; mg::DisplayConfigurationOutput output2 = tmpl_output; mg::DisplayConfigurationOutput output3 = tmpl_output; output2.id = mg::DisplayConfigurationOutputId{15}; output3.card_id = mg::DisplayConfigurationCardId{12}; EXPECT_NE(output1, output2); EXPECT_NE(output2, output1); EXPECT_NE(output2, output3); EXPECT_NE(output3, output2); EXPECT_NE(output1, output3); EXPECT_NE(output3, output1); } TEST(DisplayConfiguration, outupts_with_different_modes_compare_unequal) { mg::DisplayConfigurationOutput const output1 = tmpl_output; mg::DisplayConfigurationOutput output2 = tmpl_output; mg::DisplayConfigurationOutput output3 = tmpl_output; std::vector const modes2 { {geom::Size{10, 20}, 60.0}, {geom::Size{10, 20}, 59.9}, {geom::Size{15, 20}, 59.0} }; std::vector const modes3 { {geom::Size{10, 20}, 60.0}, {geom::Size{10, 20}, 59.0} }; output2.modes = modes2; output3.modes = modes3; EXPECT_NE(output1, output2); EXPECT_NE(output2, output1); EXPECT_NE(output2, output3); EXPECT_NE(output3, output2); EXPECT_NE(output1, output3); EXPECT_NE(output3, output1); } TEST(DisplayConfiguration, outputs_with_different_physical_size_compare_unequal) { mg::DisplayConfigurationOutput const output1 = tmpl_output; mg::DisplayConfigurationOutput output2 = tmpl_output; geom::Size const physical_size2{11, 20}; output2.physical_size_mm = physical_size2; EXPECT_NE(output1, output2); EXPECT_NE(output2, output1); } TEST(DisplayConfiguration, outputs_with_different_connected_status_compare_unequal) { mg::DisplayConfigurationOutput const output1 = tmpl_output; mg::DisplayConfigurationOutput output2 = tmpl_output; output2.connected = false; EXPECT_NE(output1, output2); EXPECT_NE(output2, output1); } TEST(DisplayConfiguration, outputs_with_different_current_mode_index_compare_unequal) { mg::DisplayConfigurationOutput const output1 = tmpl_output; mg::DisplayConfigurationOutput output2 = tmpl_output; output2.current_mode_index = 0; EXPECT_NE(output1, output2); EXPECT_NE(output2, output1); } TEST(DisplayConfiguration, outputs_with_different_preferred_mode_index_compare_unequal) { mg::DisplayConfigurationOutput const output1 = tmpl_output; mg::DisplayConfigurationOutput output2 = tmpl_output; output2.preferred_mode_index = 1; EXPECT_NE(output1, output2); EXPECT_NE(output2, output1); } TEST(DisplayConfiguration, output_orientation_affects_equality) { mg::DisplayConfigurationOutput a = tmpl_output; mg::DisplayConfigurationOutput b = tmpl_output; EXPECT_EQ(a, b); EXPECT_EQ(b, a); a.orientation = mir_orientation_left; b.orientation = mir_orientation_inverted; EXPECT_NE(a, b); EXPECT_NE(b, a); } TEST(DisplayConfiguration, output_extents_uses_current_mode) { mg::DisplayConfigurationOutput out = tmpl_output; out.current_mode_index = 2; ASSERT_NE(out.modes[0], out.modes[2]); EXPECT_EQ(out.modes[out.current_mode_index].size, out.extents().size); } TEST(DisplayConfiguration, output_extents_rotates_with_orientation) { mg::DisplayConfigurationOutput out = tmpl_output; auto const& size = out.modes[out.current_mode_index].size; int w = size.width.as_int(); int h = size.height.as_int(); ASSERT_NE(w, h); geom::Rectangle normal{out.top_left, {w, h}}; geom::Rectangle swapped{out.top_left, {h, w}}; out.orientation = mir_orientation_normal; EXPECT_EQ(normal, out.extents()); out.orientation = mir_orientation_inverted; EXPECT_EQ(normal, out.extents()); out.orientation = mir_orientation_left; EXPECT_EQ(swapped, out.extents()); out.orientation = mir_orientation_right; EXPECT_EQ(swapped, out.extents()); } TEST(DisplayConfiguration, default_valid) { mg::DisplayConfigurationOutput out = tmpl_output; EXPECT_TRUE(out.valid()); } TEST(DisplayConfiguration, used_and_disconnected_invalid) { mg::DisplayConfigurationOutput out = tmpl_output; out.used = true; out.connected = false; EXPECT_FALSE(out.valid()); } TEST(DisplayConfiguration, unsupported_format_invalid) { mg::DisplayConfigurationOutput out = tmpl_output; out.current_format = mir_pixel_format_xbgr_8888; EXPECT_FALSE(out.valid()); } TEST(DisplayConfiguration, unsupported_current_mode_invalid) { mg::DisplayConfigurationOutput out = tmpl_output; out.current_mode_index = 123; EXPECT_FALSE(out.valid()); } TEST(DisplayConfiguration, unsupported_preferred_mode_invalid) { mg::DisplayConfigurationOutput out = tmpl_output; out.preferred_mode_index = 456; EXPECT_FALSE(out.valid()); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/test_egl_extensions.cpp0000644000015301777760000000434512322054223026554 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/egl_extensions.h" #include "mir_test_doubles/mock_egl.h" #include #include #include namespace mg = mir::graphics; namespace mtd = mir::test::doubles; class EGLExtensionsTest : public ::testing::Test { protected: virtual void SetUp() { } testing::NiceMock mock_egl; }; TEST_F(EGLExtensionsTest, constructor_throws_if_egl_image_not_supported) { using namespace testing; typedef mtd::MockEGL::generic_function_pointer_t func_ptr_t; ON_CALL(mock_egl, eglGetProcAddress(StrEq("eglCreateImageKHR"))) .WillByDefault(Return(reinterpret_cast(0))); ON_CALL(mock_egl, eglGetProcAddress(StrEq("eglDestroyImageKHR"))) .WillByDefault(Return(reinterpret_cast(0))); EXPECT_THROW({ mg::EGLExtensions extensions; }, std::runtime_error); } TEST_F(EGLExtensionsTest, constructor_throws_if_gl_oes_egl_image_not_supported) { using namespace testing; typedef mtd::MockEGL::generic_function_pointer_t func_ptr_t; ON_CALL(mock_egl, eglGetProcAddress(StrEq("glEGLImageTargetTexture2DOES"))) .WillByDefault(Return(reinterpret_cast(0))); EXPECT_THROW({ mg::EGLExtensions extensions; }, std::runtime_error); } TEST_F(EGLExtensionsTest, success_has_sane_function_hooks) { mg::EGLExtensions extensions; EXPECT_NE(nullptr, extensions.eglCreateImageKHR); EXPECT_NE(nullptr, extensions.eglDestroyImageKHR); EXPECT_NE(nullptr, extensions.glEGLImageTargetTexture2DOES); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/test_pixel_format_utils.cpp0000644000015301777760000001020012322054223027422 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/common.h" #include "mir/graphics/pixel_format_utils.h" #include #include using namespace mir::graphics; TEST(MirPixelFormatUtils, contains_alpha) { EXPECT_FALSE(contains_alpha(mir_pixel_format_xbgr_8888)); EXPECT_FALSE(contains_alpha(mir_pixel_format_bgr_888)); EXPECT_FALSE(contains_alpha(mir_pixel_format_xrgb_8888)); EXPECT_FALSE(contains_alpha(mir_pixel_format_xbgr_8888)); EXPECT_TRUE(contains_alpha(mir_pixel_format_argb_8888)); EXPECT_TRUE(contains_alpha(mir_pixel_format_abgr_8888)); EXPECT_FALSE(contains_alpha(mir_pixel_format_invalid)); EXPECT_FALSE(contains_alpha(mir_pixel_formats)); } TEST(MirPixelFormatUtils, red_channel_depths) { EXPECT_EQ(8, red_channel_depth(mir_pixel_format_xbgr_8888)); EXPECT_EQ(8, red_channel_depth(mir_pixel_format_bgr_888)); EXPECT_EQ(8, red_channel_depth(mir_pixel_format_xrgb_8888)); EXPECT_EQ(8, red_channel_depth(mir_pixel_format_xbgr_8888)); EXPECT_EQ(8, red_channel_depth(mir_pixel_format_argb_8888)); EXPECT_EQ(8, red_channel_depth(mir_pixel_format_abgr_8888)); EXPECT_EQ(0, red_channel_depth(mir_pixel_format_invalid)); EXPECT_EQ(0, red_channel_depth(mir_pixel_formats)); } TEST(MirPixelFormatUtils, blue_channel_depths) { EXPECT_EQ(8, blue_channel_depth(mir_pixel_format_xbgr_8888)); EXPECT_EQ(8, blue_channel_depth(mir_pixel_format_bgr_888)); EXPECT_EQ(8, blue_channel_depth(mir_pixel_format_xrgb_8888)); EXPECT_EQ(8, blue_channel_depth(mir_pixel_format_xbgr_8888)); EXPECT_EQ(8, blue_channel_depth(mir_pixel_format_argb_8888)); EXPECT_EQ(8, blue_channel_depth(mir_pixel_format_abgr_8888)); EXPECT_EQ(0, blue_channel_depth(mir_pixel_format_invalid)); EXPECT_EQ(0, blue_channel_depth(mir_pixel_formats)); } TEST(MirPixelFormatUtils, green_channel_depths) { EXPECT_EQ(8, green_channel_depth(mir_pixel_format_xbgr_8888)); EXPECT_EQ(8, green_channel_depth(mir_pixel_format_bgr_888)); EXPECT_EQ(8, green_channel_depth(mir_pixel_format_xrgb_8888)); EXPECT_EQ(8, green_channel_depth(mir_pixel_format_xbgr_8888)); EXPECT_EQ(8, green_channel_depth(mir_pixel_format_argb_8888)); EXPECT_EQ(8, green_channel_depth(mir_pixel_format_abgr_8888)); EXPECT_EQ(0, green_channel_depth(mir_pixel_format_invalid)); EXPECT_EQ(0, green_channel_depth(mir_pixel_formats)); } TEST(MirPixelFormatUtils, alpha_channel_depths) { EXPECT_EQ(0, alpha_channel_depth(mir_pixel_format_xbgr_8888)); EXPECT_EQ(0, alpha_channel_depth(mir_pixel_format_bgr_888)); EXPECT_EQ(0, alpha_channel_depth(mir_pixel_format_xrgb_8888)); EXPECT_EQ(0, alpha_channel_depth(mir_pixel_format_xbgr_8888)); EXPECT_EQ(8, alpha_channel_depth(mir_pixel_format_argb_8888)); EXPECT_EQ(8, alpha_channel_depth(mir_pixel_format_abgr_8888)); EXPECT_EQ(0, alpha_channel_depth(mir_pixel_format_invalid)); EXPECT_EQ(0, alpha_channel_depth(mir_pixel_formats)); } TEST(MirPixelFormatUtils, valid_mir_pixel_format) { EXPECT_TRUE(valid_pixel_format(mir_pixel_format_xbgr_8888)); EXPECT_TRUE(valid_pixel_format(mir_pixel_format_bgr_888)); EXPECT_TRUE(valid_pixel_format(mir_pixel_format_xrgb_8888)); EXPECT_TRUE(valid_pixel_format(mir_pixel_format_xbgr_8888)); EXPECT_TRUE(valid_pixel_format(mir_pixel_format_argb_8888)); EXPECT_TRUE(valid_pixel_format(mir_pixel_format_abgr_8888)); EXPECT_FALSE(valid_pixel_format(mir_pixel_format_invalid)); EXPECT_FALSE(valid_pixel_format(mir_pixel_formats)); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/test_buffer_id.cpp0000644000015301777760000000363312322054223025452 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/buffer_id.h" #include "mir_test_doubles/stub_buffer.h" #include #include namespace mg = mir::graphics; TEST(buffer_id, value_set ) { unsigned int id_as_int = 44; mg::BufferID id{id_as_int}; EXPECT_EQ(id_as_int, id.as_uint32_t()); } TEST(buffer_id, equality_testable) { unsigned int id_as_int0 = 44; unsigned int id_as_int1 = 41; mg::BufferID id0{id_as_int0}; mg::BufferID id1{id_as_int1}; EXPECT_EQ(id0, id0); EXPECT_EQ(id1, id1); EXPECT_NE(id0, id1); EXPECT_NE(id1, id0); } TEST(buffer_id, less_than_testable) { unsigned int id_as_int0 = 44; unsigned int id_as_int1 = 41; mg::BufferID id0{id_as_int0}; mg::BufferID id1{id_as_int1}; EXPECT_LT(id1, id0); } TEST(unique_generator, generate_unique) { using mir::test::doubles::StubBuffer; int const ids = 542; std::vector generated_ids; for (auto i=0; i < ids; i++) generated_ids.push_back(StubBuffer().id()); while (!generated_ids.empty()) { mg::BufferID test_id = generated_ids.back(); generated_ids.pop_back(); for (auto id : generated_ids) { EXPECT_NE(id, test_id); } } } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/0000755000015301777760000000000012322054703022705 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_real_kms_output.cpp0000644000015301777760000002137312322054223027670 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/mesa/real_kms_output.h" #include "src/platform/graphics/mesa/page_flipper.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_drm.h" #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace { class NullPageFlipper : public mgm::PageFlipper { public: bool schedule_flip(uint32_t,uint32_t) { return true; } void wait_for_flip(uint32_t) { } }; class MockPageFlipper : public mgm::PageFlipper { public: MOCK_METHOD2(schedule_flip, bool(uint32_t,uint32_t)); MOCK_METHOD1(wait_for_flip, void(uint32_t)); }; class RealKMSOutputTest : public ::testing::Test { public: RealKMSOutputTest() : invalid_id{0}, crtc_ids{10, 11}, encoder_ids{20, 21}, connector_ids{30, 21}, possible_encoder_ids1{encoder_ids[0]}, possible_encoder_ids2{encoder_ids[0], encoder_ids[1]} { } void setup_outputs_connected_crtc() { mtd::FakeDRMResources& resources(mock_drm.fake_drm); uint32_t const possible_crtcs_mask{0x1}; resources.reset(); resources.add_crtc(crtc_ids[0], drmModeModeInfo()); resources.add_encoder(encoder_ids[0], crtc_ids[0], possible_crtcs_mask); resources.add_connector(connector_ids[0], DRM_MODE_CONNECTOR_VGA, DRM_MODE_CONNECTED, encoder_ids[0], modes_empty, possible_encoder_ids1, geom::Size()); resources.prepare(); } void setup_outputs_no_connected_crtc() { mtd::FakeDRMResources& resources(mock_drm.fake_drm); uint32_t const possible_crtcs_mask1{0x1}; uint32_t const possible_crtcs_mask_all{0x3}; resources.reset(); resources.add_crtc(crtc_ids[0], drmModeModeInfo()); resources.add_crtc(crtc_ids[1], drmModeModeInfo()); resources.add_encoder(encoder_ids[0], crtc_ids[0], possible_crtcs_mask1); resources.add_encoder(encoder_ids[1], invalid_id, possible_crtcs_mask_all); resources.add_connector(connector_ids[0], DRM_MODE_CONNECTOR_Composite, DRM_MODE_CONNECTED, invalid_id, modes_empty, possible_encoder_ids2, geom::Size()); resources.add_connector(connector_ids[1], DRM_MODE_CONNECTOR_DVIA, DRM_MODE_CONNECTED, encoder_ids[0], modes_empty, possible_encoder_ids2, geom::Size()); resources.prepare(); } testing::NiceMock mock_drm; MockPageFlipper mock_page_flipper; NullPageFlipper null_page_flipper; std::vector modes_empty; uint32_t const invalid_id; std::vector const crtc_ids; std::vector const encoder_ids; std::vector const connector_ids; std::vector possible_encoder_ids1; std::vector possible_encoder_ids2; }; } TEST_F(RealKMSOutputTest, construction_queries_connector) { using namespace testing; setup_outputs_connected_crtc(); EXPECT_CALL(mock_drm, drmModeGetConnector(_,connector_ids[0])) .Times(1); mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0], mt::fake_shared(null_page_flipper)}; } TEST_F(RealKMSOutputTest, operations_use_existing_crtc) { using namespace testing; uint32_t const fb_id{67}; setup_outputs_connected_crtc(); { InSequence s; EXPECT_CALL(mock_drm, drmModeSetCrtc(_, crtc_ids[0], fb_id, _, _, Pointee(connector_ids[0]), _, _)) .Times(1); EXPECT_CALL(mock_page_flipper, schedule_flip(crtc_ids[0], fb_id)) .Times(1) .WillOnce(Return(true)); EXPECT_CALL(mock_page_flipper, wait_for_flip(crtc_ids[0])) .Times(1); EXPECT_CALL(mock_drm, drmModeSetCrtc(_, crtc_ids[0], Ne(fb_id), _, _, Pointee(connector_ids[0]), _, _)) .Times(1); } mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0], mt::fake_shared(mock_page_flipper)}; EXPECT_TRUE(output.set_crtc(fb_id)); EXPECT_TRUE(output.schedule_page_flip(fb_id)); output.wait_for_page_flip(); } TEST_F(RealKMSOutputTest, operations_use_possible_crtc) { using namespace testing; uint32_t const fb_id{67}; setup_outputs_no_connected_crtc(); { InSequence s; EXPECT_CALL(mock_drm, drmModeSetCrtc(_, crtc_ids[1], fb_id, _, _, Pointee(connector_ids[0]), _, _)) .Times(1); EXPECT_CALL(mock_page_flipper, schedule_flip(crtc_ids[1], fb_id)) .Times(1) .WillOnce(Return(true)); EXPECT_CALL(mock_page_flipper, wait_for_flip(crtc_ids[1])) .Times(1); EXPECT_CALL(mock_drm, drmModeSetCrtc(_, 0, 0, _, _, Pointee(connector_ids[0]), _, _)) .Times(1); } mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0], mt::fake_shared(mock_page_flipper)}; EXPECT_TRUE(output.set_crtc(fb_id)); EXPECT_TRUE(output.schedule_page_flip(fb_id)); output.wait_for_page_flip(); } TEST_F(RealKMSOutputTest, set_crtc_failure_is_handled_gracefully) { using namespace testing; uint32_t const fb_id{67}; setup_outputs_connected_crtc(); { InSequence s; EXPECT_CALL(mock_drm, drmModeSetCrtc(_, crtc_ids[0], fb_id, _, _, _, _, _)) .Times(1) .WillOnce(Return(1)); EXPECT_CALL(mock_page_flipper, schedule_flip(_, _)) .Times(0); EXPECT_CALL(mock_page_flipper, wait_for_flip(_)) .Times(0); EXPECT_CALL(mock_drm, drmModeSetCrtc(_, _, _, _, _, _, _, _)) .Times(0); } mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0], mt::fake_shared(mock_page_flipper)}; EXPECT_FALSE(output.set_crtc(fb_id)); EXPECT_THROW({ output.schedule_page_flip(fb_id); }, std::runtime_error); EXPECT_THROW({ output.wait_for_page_flip(); }, std::runtime_error); } TEST_F(RealKMSOutputTest, clear_crtc_gets_crtc_if_none_is_current) { using namespace testing; setup_outputs_connected_crtc(); mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0], mt::fake_shared(mock_page_flipper)}; EXPECT_CALL(mock_drm, drmModeSetCrtc(_, crtc_ids[0], 0, 0, 0, nullptr, 0, nullptr)) .Times(1) .WillOnce(Return(0)); output.clear_crtc(); } TEST_F(RealKMSOutputTest, clear_crtc_does_not_throw_if_no_crtc_is_found) { using namespace testing; mtd::FakeDRMResources& resources(mock_drm.fake_drm); uint32_t const possible_crtcs_mask_empty{0x0}; resources.reset(); resources.add_encoder(encoder_ids[0], invalid_id, possible_crtcs_mask_empty); resources.add_connector(connector_ids[0], DRM_MODE_CONNECTOR_VGA, DRM_MODE_CONNECTED, encoder_ids[0], modes_empty, possible_encoder_ids1, geom::Size()); resources.prepare(); mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0], mt::fake_shared(mock_page_flipper)}; EXPECT_CALL(mock_drm, drmModeSetCrtc(_, _, 0, 0, 0, nullptr, 0, nullptr)) .Times(0); output.clear_crtc(); } TEST_F(RealKMSOutputTest, clear_crtc_throws_if_drm_call_fails) { using namespace testing; setup_outputs_connected_crtc(); mgm::RealKMSOutput output{mock_drm.fake_drm.fd(), connector_ids[0], mt::fake_shared(mock_page_flipper)}; EXPECT_CALL(mock_drm, drmModeSetCrtc(_, crtc_ids[0], 0, 0, 0, nullptr, 0, nullptr)) .Times(1) .WillOnce(Return(-1)); EXPECT_THROW({ output.clear_crtc(); }, std::runtime_error); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_drm_helper.cpp0000644000015301777760000000330512322054223026567 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/mesa/display_helpers.h" #include "mir/udev/wrapper.h" #include "mir_test_framework/udev_environment.h" #include "mir_test_doubles/mock_drm.h" #include #include #include namespace mgm = mir::graphics::mesa; namespace mtf = mir::mir_test_framework; namespace mtd = mir::test::doubles; namespace { MATCHER_P(FlagSet, flag, "") { return (arg & flag); } class DRMHelperTest : public ::testing::Test { public: DRMHelperTest() { fake_devices.add_standard_device("standard-drm-devices"); } protected: ::testing::NiceMock mock_drm; mtf::UdevEnvironment fake_devices; }; } TEST_F(DRMHelperTest, closes_drm_fd_on_exec) { using namespace testing; EXPECT_CALL(mock_drm, open(_, FlagSet(O_CLOEXEC), _)); mgm::helpers::DRMHelper drm_helper; drm_helper.setup(std::make_shared()); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_display.cpp0000644000015301777760000006101212322054247026120 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include #include "src/platform/graphics/mesa/platform.h" #include "src/platform/graphics/mesa/display.h" #include "src/platform/graphics/mesa/virtual_terminal.h" #include "src/server/report/logging/display_report.h" #include "mir/logging/logger.h" #include "mir/graphics/display_buffer.h" #include "src/server/graphics/default_display_configuration_policy.h" #include "mir/asio_main_loop.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_gl.h" #include "src/server/report/null_report_factory.h" #include "mir_test_doubles/mock_display_report.h" #include "mir_test_doubles/null_virtual_terminal.h" #include "mir_test_doubles/stub_gl_config.h" #include "mir_test_doubles/mock_gl_config.h" #include "mir_test_doubles/mock_drm.h" #include "mir_test_doubles/mock_gbm.h" #include "mir_test_framework/udev_environment.h" #include "mir_test/fake_shared.h" #include #include #include #include #include #include #include namespace mg=mir::graphics; namespace mgm=mir::graphics::mesa; namespace ml=mir::logging; namespace mrl=mir::report::logging; namespace mtd=mir::test::doubles; namespace mtf=mir::mir_test_framework; namespace mr=mir::report; namespace { struct MockLogger : public ml::Logger { MOCK_METHOD3(log, void(ml::Logger::Severity, const std::string&, const std::string&)); ~MockLogger() noexcept(true) {} }; class MockVirtualTerminal : public mgm::VirtualTerminal { public: ~MockVirtualTerminal() noexcept(true) {} MOCK_METHOD0(set_graphics_mode, void()); MOCK_METHOD3(register_switch_handlers, void(mg::EventHandlerRegister&, std::function const&, std::function const&)); }; class MockEventRegister : public mg::EventHandlerRegister { public: MOCK_METHOD2(register_signal_handler, void(std::initializer_list, std::function const&)); MOCK_METHOD2(register_fd_handler, void(std::initializer_list, std::function const&)); }; class MesaDisplayTest : public ::testing::Test { public: MesaDisplayTest() : mock_report{std::make_shared>()}, null_report{mr::null_display_report()} { using namespace testing; ON_CALL(mock_egl, eglChooseConfig(_,_,_,1,_)) .WillByDefault(DoAll(SetArgPointee<2>(mock_egl.fake_configs[0]), SetArgPointee<4>(1), Return(EGL_TRUE))); const char* egl_exts = "EGL_KHR_image EGL_KHR_image_base EGL_MESA_drm_image"; const char* gl_exts = "GL_OES_texture_npot GL_OES_EGL_image"; ON_CALL(mock_egl, eglQueryString(_,EGL_EXTENSIONS)) .WillByDefault(Return(egl_exts)); ON_CALL(mock_gl, glGetString(GL_EXTENSIONS)) .WillByDefault(Return(reinterpret_cast(gl_exts))); /* * Silence uninteresting calls called when cleaning up resources in * the MockGBM destructor, and which are not handled by NiceMock<>. */ EXPECT_CALL(mock_gbm, gbm_bo_get_device(_)) .Times(AtLeast(0)); EXPECT_CALL(mock_gbm, gbm_device_get_fd(_)) .Times(AtLeast(0)); fake_devices.add_standard_device("standard-drm-devices"); } std::shared_ptr create_platform() { return std::make_shared( null_report, std::make_shared()); } std::shared_ptr create_display( std::shared_ptr const& platform) { return std::make_shared( platform, std::make_shared(), std::make_shared(), null_report); } void setup_post_update_expectations() { using namespace testing; EXPECT_CALL(mock_egl, eglSwapBuffers(mock_egl.fake_egl_display, mock_egl.fake_egl_surface)) .Times(Exactly(2)); EXPECT_CALL(mock_gbm, gbm_surface_lock_front_buffer(mock_gbm.fake_gbm.surface)) .Times(Exactly(2)) .WillOnce(Return(fake.bo1)) .WillOnce(Return(fake.bo2)); EXPECT_CALL(mock_gbm, gbm_bo_get_handle(fake.bo1)) .Times(Exactly(1)) .WillOnce(Return(fake.bo_handle1)); EXPECT_CALL(mock_gbm, gbm_bo_get_handle(fake.bo2)) .Times(Exactly(1)) .WillOnce(Return(fake.bo_handle2)); EXPECT_CALL(mock_drm, drmModeAddFB(mock_drm.fake_drm.fd(), _, _, _, _, _, fake.bo_handle1.u32, _)) .Times(Exactly(1)) .WillOnce(DoAll(SetArgPointee<7>(fake.fb_id1), Return(0))); EXPECT_CALL(mock_drm, drmModeAddFB(mock_drm.fake_drm.fd(), _, _, _, _, _, fake.bo_handle2.u32, _)) .Times(Exactly(1)) .WillOnce(DoAll(SetArgPointee<7>(fake.fb_id2), Return(0))); } uint32_t get_connected_connector_id() { auto drm_res = mock_drm.fake_drm.resources_ptr(); for (int i = 0; i < drm_res->count_connectors; i++) { auto connector = mock_drm.fake_drm.find_connector(drm_res->connectors[i]); if (connector->connection == DRM_MODE_CONNECTED) return connector->connector_id; } return 0; } uint32_t get_connected_crtc_id() { auto connector_id = get_connected_connector_id(); auto connector = mock_drm.fake_drm.find_connector(connector_id); if (connector) { auto encoder = mock_drm.fake_drm.find_encoder(connector->encoder_id); if (encoder) return encoder->crtc_id; } return 0; } struct FakeData { FakeData() : bo1{reinterpret_cast(0xabcd)}, bo2{reinterpret_cast(0xabce)}, fb_id1{66}, fb_id2{67}, crtc() { bo_handle1.u32 = 0x1234; bo_handle2.u32 = 0x1235; crtc.buffer_id = 88; crtc.crtc_id = 565; } gbm_bo* bo1; gbm_bo* bo2; uint32_t fb_id1; uint32_t fb_id2; gbm_bo_handle bo_handle1; gbm_bo_handle bo_handle2; drmModeCrtc crtc; } fake; ::testing::NiceMock mock_egl; ::testing::NiceMock mock_gl; ::testing::NiceMock mock_drm; ::testing::NiceMock mock_gbm; std::shared_ptr> const mock_report; std::shared_ptr const null_report; mtf::UdevEnvironment fake_devices; }; } TEST_F(MesaDisplayTest, create_display) { using namespace testing; auto const connector_id = get_connected_connector_id(); auto const crtc_id = get_connected_crtc_id(); /* To display a gbm surface, the MesaDisplay should... */ /* Create a gbm surface to use as the frame buffer */ EXPECT_CALL(mock_gbm, gbm_surface_create(mock_gbm.fake_gbm.device,_,_,_,_)) .Times(Exactly(1)); /* Create an EGL window surface backed by the gbm surface */ EXPECT_CALL(mock_egl, eglCreateWindowSurface(mock_egl.fake_egl_display, mock_egl.fake_configs[0], (EGLNativeWindowType)mock_gbm.fake_gbm.surface, _)) .Times(Exactly(1)); /* Swap the EGL window surface to bring the back buffer to the front */ EXPECT_CALL(mock_egl, eglSwapBuffers(mock_egl.fake_egl_display, mock_egl.fake_egl_surface)) .Times(Exactly(1)); /* Get the gbm_bo object corresponding to the front buffer */ EXPECT_CALL(mock_gbm, gbm_surface_lock_front_buffer(mock_gbm.fake_gbm.surface)) .Times(Exactly(1)) .WillOnce(Return(fake.bo1)); /* Get the DRM buffer handle associated with the gbm_bo */ EXPECT_CALL(mock_gbm, gbm_bo_get_handle(fake.bo1)) .Times(Exactly(1)) .WillOnce(Return(fake.bo_handle1)); /* Create a a DRM FB with the DRM buffer attached */ EXPECT_CALL(mock_drm, drmModeAddFB(mock_drm.fake_drm.fd(), _, _, _, _, _, fake.bo_handle1.u32, _)) .Times(Exactly(1)) .WillOnce(DoAll(SetArgPointee<7>(fake.fb_id1), Return(0))); /* Display the DRM FB (first expectation is for cleanup) */ EXPECT_CALL(mock_drm, drmModeSetCrtc(mock_drm.fake_drm.fd(), crtc_id, Ne(fake.fb_id1), _, _, Pointee(connector_id), _, _)) .Times(AtLeast(0)); EXPECT_CALL(mock_drm, drmModeSetCrtc(mock_drm.fake_drm.fd(), crtc_id, fake.fb_id1, _, _, Pointee(connector_id), _, _)) .Times(Exactly(1)) .WillOnce(Return(0)); auto display = create_display(create_platform()); } TEST_F(MesaDisplayTest, reset_crtc_on_destruction) { using namespace testing; auto const connector_id = get_connected_connector_id(); auto const crtc_id = get_connected_crtc_id(); uint32_t const fb_id{66}; /* Create DRM FBs */ EXPECT_CALL(mock_drm, drmModeAddFB(mock_drm.fake_drm.fd(), _, _, _, _, _, _, _)) .WillRepeatedly(DoAll(SetArgPointee<7>(fb_id), Return(0))); { InSequence s; /* crtc is set */ EXPECT_CALL(mock_drm, drmModeSetCrtc(mock_drm.fake_drm.fd(), crtc_id, fb_id, _, _, Pointee(connector_id), _, _)) .Times(AtLeast(1)); /* crtc is reset */ EXPECT_CALL(mock_drm, drmModeSetCrtc(mock_drm.fake_drm.fd(), crtc_id, Ne(fb_id), _, _, Pointee(connector_id), _, _)) .Times(1); } auto display = create_display(create_platform()); } TEST_F(MesaDisplayTest, create_display_drm_failure) { using namespace testing; EXPECT_CALL(mock_drm, open(_,_,_)) .Times(AtLeast(1)) .WillRepeatedly(Return(-1)); EXPECT_CALL(mock_drm, drmClose(_)) .Times(Exactly(0)); EXPECT_THROW( { auto display = create_display(create_platform()); }, std::runtime_error); } TEST_F(MesaDisplayTest, create_display_kms_failure) { using namespace testing; auto platform = create_platform(); Mock::VerifyAndClearExpectations(&mock_drm); EXPECT_CALL(mock_drm, drmModeGetResources(_)) .Times(Exactly(1)) .WillOnce(Return(reinterpret_cast(0))); EXPECT_CALL(mock_drm, drmModeFreeResources(_)) .Times(Exactly(0)); EXPECT_CALL(mock_drm, drmClose(_)) .Times(Exactly(1)); EXPECT_THROW({ auto display = create_display(platform); }, std::runtime_error) << "Expected that c'tor of mgm::Display throws"; } TEST_F(MesaDisplayTest, create_display_gbm_failure) { using namespace testing; EXPECT_CALL(mock_gbm, gbm_create_device(_)) .Times(Exactly(1)) .WillOnce(Return(reinterpret_cast(0))); EXPECT_CALL(mock_gbm, gbm_device_destroy(_)) .Times(Exactly(0)); EXPECT_CALL(mock_drm, drmClose(_)) .Times(Exactly(1)); EXPECT_THROW({ auto platform = create_platform(); }, std::runtime_error) << "Expected c'tor of Platform to throw an exception"; } namespace { ACTION_P(QueuePageFlipEvent, write_drm_fd) { EXPECT_EQ(1, write(write_drm_fd, "a", 1)); } ACTION_P(InvokePageFlipHandler, param) { int const dont_care{0}; char dummy; arg1->page_flip_handler(dont_care, dont_care, dont_care, dont_care, *param); ASSERT_EQ(1, read(arg0, &dummy, 1)); } } TEST_F(MesaDisplayTest, post_update) { using namespace testing; auto const crtc_id = get_connected_crtc_id(); void* user_data{nullptr}; setup_post_update_expectations(); { InSequence s; /* Flip the new FB */ EXPECT_CALL(mock_drm, drmModePageFlip(mock_drm.fake_drm.fd(), crtc_id, fake.fb_id2, _, _)) .Times(Exactly(1)) .WillOnce(DoAll(QueuePageFlipEvent(mock_drm.fake_drm.write_fd()), SaveArg<4>(&user_data), Return(0))); /* Handle the flip event */ EXPECT_CALL(mock_drm, drmHandleEvent(mock_drm.fake_drm.fd(), _)) .Times(0); /* Release last_flipped_bufobj (at destruction time) */ EXPECT_CALL(mock_gbm, gbm_surface_release_buffer(mock_gbm.fake_gbm.surface, fake.bo1)) .Times(Exactly(1)); /* Release scheduled_bufobj (at destruction time) */ EXPECT_CALL(mock_gbm, gbm_surface_release_buffer(mock_gbm.fake_gbm.surface, fake.bo2)) .Times(Exactly(1)); } auto display = create_display(create_platform()); display->for_each_display_buffer([](mg::DisplayBuffer& db) { db.post_update(); }); } TEST_F(MesaDisplayTest, post_update_flip_failure) { using namespace testing; auto const crtc_id = get_connected_crtc_id(); setup_post_update_expectations(); { InSequence s; /* New FB flip failure */ EXPECT_CALL(mock_drm, drmModePageFlip(mock_drm.fake_drm.fd(), crtc_id, fake.fb_id2, _, _)) .Times(Exactly(1)) .WillOnce(Return(-1)); /* Release failed bufobj */ EXPECT_CALL(mock_gbm, gbm_surface_release_buffer(mock_gbm.fake_gbm.surface, fake.bo2)) .Times(Exactly(1)); /* Release scheduled_bufobj (at destruction time) */ EXPECT_CALL(mock_gbm, gbm_surface_release_buffer(mock_gbm.fake_gbm.surface, fake.bo1)) .Times(Exactly(1)); } EXPECT_THROW( { auto display = create_display(create_platform()); display->for_each_display_buffer([](mg::DisplayBuffer& db) { db.post_update(); }); }, std::runtime_error); } TEST_F(MesaDisplayTest, successful_creation_of_display_reports_successful_setup_of_native_resources) { using namespace ::testing; EXPECT_CALL( *mock_report, report_successful_setup_of_native_resources()).Times(Exactly(1)); EXPECT_CALL( *mock_report, report_successful_egl_make_current_on_construction()).Times(Exactly(1)); EXPECT_CALL( *mock_report, report_successful_egl_buffer_swap_on_construction()).Times(Exactly(1)); EXPECT_CALL( *mock_report, report_successful_drm_mode_set_crtc_on_construction()).Times(Exactly(1)); EXPECT_CALL( *mock_report, report_successful_display_construction()).Times(Exactly(1)); EXPECT_CALL( *mock_report, report_egl_configuration(mock_egl.fake_egl_display,mock_egl.fake_configs[0])).Times(Exactly(1)); auto display = std::make_shared( create_platform(), std::make_shared(), std::make_shared(), mock_report); } TEST_F(MesaDisplayTest, outputs_correct_string_for_successful_setup_of_native_resources) { using namespace ::testing; auto logger = std::make_shared(); auto reporter = std::make_shared(logger); EXPECT_CALL( *logger, log(Eq(ml::Logger::informational), StrEq("Successfully setup native resources."), StrEq("graphics"))).Times(Exactly(1)); reporter->report_successful_setup_of_native_resources(); } TEST_F(MesaDisplayTest, outputs_correct_string_for_successful_egl_make_current_on_construction) { using namespace ::testing; auto logger = std::make_shared(); auto reporter = std::make_shared(logger); EXPECT_CALL( *logger, log(Eq(ml::Logger::informational), StrEq("Successfully made egl context current on construction."), StrEq("graphics"))).Times(Exactly(1)); reporter->report_successful_egl_make_current_on_construction(); } TEST_F(MesaDisplayTest, outputs_correct_string_for_successful_egl_buffer_swap_on_construction) { using namespace ::testing; auto logger = std::make_shared(); auto reporter = std::make_shared(logger); EXPECT_CALL( *logger, log(Eq(ml::Logger::informational), StrEq("Successfully performed egl buffer swap on construction."), StrEq("graphics"))).Times(Exactly(1)); reporter->report_successful_egl_buffer_swap_on_construction(); } TEST_F(MesaDisplayTest, outputs_correct_string_for_successful_drm_mode_set_crtc_on_construction) { using namespace ::testing; auto logger = std::make_shared(); auto reporter = std::make_shared(logger); EXPECT_CALL( *logger, log(Eq(ml::Logger::informational), StrEq("Successfully performed drm mode setup on construction."), StrEq("graphics"))).Times(Exactly(1)); reporter->report_successful_drm_mode_set_crtc_on_construction(); } TEST_F(MesaDisplayTest, constructor_throws_if_egl_mesa_drm_image_not_supported) { using namespace ::testing; const char* egl_exts = "EGL_KHR_image EGL_KHR_image_base"; EXPECT_CALL(mock_egl, eglQueryString(_,EGL_EXTENSIONS)) .WillOnce(Return(egl_exts)); EXPECT_THROW( { auto display = create_display(create_platform()); }, std::runtime_error); } TEST_F(MesaDisplayTest, constructor_throws_if_gl_oes_image_not_supported) { using namespace ::testing; const char* gl_exts = "GL_OES_texture_npot GL_OES_blend_func_separate"; EXPECT_CALL(mock_gl, glGetString(GL_EXTENSIONS)) .WillOnce(Return(reinterpret_cast(gl_exts))); EXPECT_THROW( { auto display = create_display(create_platform()); }, std::runtime_error); } TEST_F(MesaDisplayTest, for_each_display_buffer_calls_callback) { using namespace ::testing; auto display = create_display(create_platform()); int callback_count{0}; display->for_each_display_buffer([&](mg::DisplayBuffer&) { callback_count++; }); EXPECT_NE(0, callback_count); } TEST_F(MesaDisplayTest, constructor_sets_vt_graphics_mode) { using namespace testing; auto mock_vt = std::make_shared(); EXPECT_CALL(*mock_vt, set_graphics_mode()) .Times(1); auto platform = std::make_shared(null_report, mock_vt); auto display = create_display(platform); } TEST_F(MesaDisplayTest, pause_drops_drm_master) { using namespace testing; EXPECT_CALL(mock_drm, drmDropMaster(mock_drm.fake_drm.fd())) .Times(1); auto display = create_display(create_platform()); display->pause(); } TEST_F(MesaDisplayTest, resume_sets_drm_master) { using namespace testing; EXPECT_CALL(mock_drm, drmSetMaster(mock_drm.fake_drm.fd())) .Times(1); auto display = create_display(create_platform()); display->resume(); } TEST_F(MesaDisplayTest, set_or_drop_drm_master_failure_throws_and_reports_error) { using namespace testing; EXPECT_CALL(mock_drm, drmDropMaster(_)) .WillOnce(SetErrnoAndReturn(EACCES, -EACCES)); EXPECT_CALL(mock_drm, drmSetMaster(_)) .WillOnce(SetErrnoAndReturn(EPERM, -EPERM)); EXPECT_CALL(*mock_report, report_drm_master_failure(EACCES)); EXPECT_CALL(*mock_report, report_drm_master_failure(EPERM)); auto platform = std::make_shared( mock_report, std::make_shared()); auto display = std::make_shared( platform, std::make_shared(), std::make_shared(), mock_report); EXPECT_THROW({ display->pause(); }, std::runtime_error); EXPECT_THROW({ display->resume(); }, std::runtime_error); } TEST_F(MesaDisplayTest, configuration_change_registers_video_devices_handler) { using namespace testing; auto display = create_display(create_platform()); MockEventRegister mock_register; EXPECT_CALL(mock_register, register_fd_handler(_,_)); display->register_configuration_change_handler(mock_register, []{}); } TEST_F(MesaDisplayTest, drm_device_change_event_triggers_handler) { using namespace testing; auto display = create_display(create_platform()); mir::AsioMainLoop ml; std::condition_variable done; int const device_add_count{1}; int const device_change_count{10}; int const expected_call_count{device_add_count + device_change_count}; int call_count{0}; std::mutex m; display->register_configuration_change_handler( ml, [&call_count, &ml, &done, &m]() { std::unique_lock lock(m); if (++call_count == expected_call_count) { ml.stop(); done.notify_all(); } }); std::thread t{ [this] { auto const syspath = fake_devices.add_device("drm", "card2", NULL, {}, {"DEVTYPE", "drm_minor"}); for (int i = 0; i != device_change_count; ++i) { // sleeping between calls to fake_devices hides race conditions std::this_thread::sleep_for(std::chrono::microseconds{500}); fake_devices.emit_device_changed(syspath); } }}; std::thread watchdog{ [this, &done, &m, &ml, &call_count] { std::unique_lock lock(m); if (!done.wait_for(lock, std::chrono::seconds{1}, [&call_count]() { return call_count == expected_call_count; })) ml.stop(); } }; ml.run(); t.join(); watchdog.join(); EXPECT_EQ(expected_call_count, call_count); } TEST_F(MesaDisplayTest, respects_gl_config) { using namespace testing; mtd::MockGLConfig mock_gl_config; EGLint const depth_bits{24}; EGLint const stencil_bits{8}; EXPECT_CALL(mock_gl_config, depth_buffer_bits()) .Times(AtLeast(1)) .WillRepeatedly(Return(depth_bits)); EXPECT_CALL(mock_gl_config, stencil_buffer_bits()) .Times(AtLeast(1)) .WillRepeatedly(Return(stencil_bits)); EXPECT_CALL(mock_egl, eglChooseConfig( _, AllOf(mtd::EGLConfigContainsAttrib(EGL_DEPTH_SIZE, depth_bits), mtd::EGLConfigContainsAttrib(EGL_STENCIL_SIZE, stencil_bits)), _,_,_)) .Times(AtLeast(1)) .WillRepeatedly(DoAll(SetArgPointee<2>(mock_egl.fake_configs[0]), SetArgPointee<4>(1), Return(EGL_TRUE))); mgm::Display display{ create_platform(), std::make_shared(), mir::test::fake_shared(mock_gl_config), null_report}; } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_gbm_buffer.cpp0000644000015301777760000001536112322054223026551 0ustar pbusernogroup00000000000000/* * 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: Christopher James Halse Rogers */ #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_gl.h" #include "mir_test_doubles/mock_drm.h" #include "mir_test_doubles/mock_gbm.h" #include "mir_test_framework/udev_environment.h" #include "src/platform/graphics/mesa/platform.h" #include "src/platform/graphics/mesa/gbm_buffer.h" #include "src/platform/graphics/mesa/buffer_allocator.h" #include "mir/graphics/buffer_initializer.h" #include "mir/graphics/buffer_properties.h" #include "mir_test_doubles/null_virtual_terminal.h" #include "src/server/report/null_report_factory.h" #include #include #include #include #include namespace mg=mir::graphics; namespace mgm=mir::graphics::mesa; namespace geom=mir::geometry; namespace mtd=mir::test::doubles; namespace mr=mir::report; namespace mtf=mir::mir_test_framework; class GBMBufferTest : public ::testing::Test { protected: virtual void SetUp() { using namespace testing; fake_devices.add_standard_device("standard-drm-devices"); size = geom::Size{300, 200}; pf = mir_pixel_format_argb_8888; stride = geom::Stride{4 * size.width.as_uint32_t()}; usage = mg::BufferUsage::hardware; buffer_properties = mg::BufferProperties{size, pf, usage}; ON_CALL(mock_gbm, gbm_bo_get_width(_)) .WillByDefault(Return(size.width.as_uint32_t())); ON_CALL(mock_gbm, gbm_bo_get_height(_)) .WillByDefault(Return(size.height.as_uint32_t())); ON_CALL(mock_gbm, gbm_bo_get_format(_)) .WillByDefault(Return(GBM_BO_FORMAT_ARGB8888)); ON_CALL(mock_gbm, gbm_bo_get_stride(_)) .WillByDefault(Return(stride.as_uint32_t())); platform = std::make_shared( mr::null_display_report(), std::make_shared()); null_init = std::make_shared(); allocator.reset(new mgm::BufferAllocator(platform->gbm.device, null_init)); } ::testing::NiceMock mock_drm; ::testing::NiceMock mock_gbm; ::testing::NiceMock mock_egl; ::testing::NiceMock mock_gl; std::shared_ptr platform; std::shared_ptr null_init; std::unique_ptr allocator; // Defaults MirPixelFormat pf; geom::Size size; geom::Stride stride; mg::BufferUsage usage; mg::BufferProperties buffer_properties; mtf::UdevEnvironment fake_devices; }; TEST_F(GBMBufferTest, dimensions_test) { using namespace testing; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,_)); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)); auto buffer = allocator->alloc_buffer(buffer_properties); ASSERT_EQ(size, buffer->size()); } TEST_F(GBMBufferTest, buffer_has_expected_pixel_format) { using namespace testing; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,_)); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)); auto buffer(allocator->alloc_buffer(buffer_properties)); ASSERT_EQ(pf, buffer->pixel_format()); } TEST_F(GBMBufferTest, stride_has_sane_value) { using namespace testing; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,_)); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)); // RGBA 8888 cannot take less than 4 bytes // TODO: is there a *maximum* sane value for stride? geom::Stride minimum(size.width.as_uint32_t() * 4); auto buffer(allocator->alloc_buffer(buffer_properties)); ASSERT_LE(minimum, buffer->stride()); } TEST_F(GBMBufferTest, buffer_native_handle_has_correct_size) { using namespace testing; auto buffer = allocator->alloc_buffer(buffer_properties); auto native_handle = buffer->native_buffer_handle(); EXPECT_EQ(1, native_handle->fd_items); EXPECT_EQ(0, native_handle->data_items); } MATCHER_P(GEMFlinkHandleIs, value, "") { auto flink = reinterpret_cast(arg); return flink->handle == value; } ACTION_P(SetGEMFlinkName, value) { auto flink = reinterpret_cast(arg2); flink->name = value; } TEST_F(GBMBufferTest, buffer_native_handle_contains_correct_data) { using namespace testing; uint32_t prime_fd{0x77}; gbm_bo_handle mock_handle; mock_handle.u32 = 0xdeadbeef; EXPECT_CALL(mock_gbm, gbm_bo_get_handle(_)) .Times(Exactly(1)) .WillOnce(Return(mock_handle)); EXPECT_CALL(mock_drm, drmPrimeHandleToFD(_,mock_handle.u32,_,_)) .Times(Exactly(1)) .WillOnce(DoAll(SetArgPointee<3>(prime_fd), Return(0))); auto buffer = allocator->alloc_buffer(buffer_properties); auto handle = buffer->native_buffer_handle(); EXPECT_EQ(prime_fd, static_cast(handle->fd[0])); EXPECT_EQ(stride.as_uint32_t(), static_cast(handle->stride)); } TEST_F(GBMBufferTest, buffer_creation_throws_on_prime_fd_failure) { using namespace testing; EXPECT_CALL(mock_drm, drmPrimeHandleToFD(_,_,_,_)) .Times(Exactly(1)) .WillOnce(Return(-1)); EXPECT_THROW({ auto buffer = allocator->alloc_buffer(buffer_properties); }, std::runtime_error); } TEST_F(GBMBufferTest, bind_to_texture_egl_image_creation_failed) { using namespace testing; ON_CALL(mock_egl, eglCreateImageKHR(_,_,_,_,_)) .WillByDefault(Return(EGL_NO_IMAGE_KHR)); EXPECT_THROW({ auto buffer = allocator->alloc_buffer(buffer_properties); buffer->bind_to_texture(); }, std::runtime_error); } TEST_F(GBMBufferTest, bind_to_texture_uses_egl_image) { using namespace testing; { InSequence seq; EXPECT_CALL(mock_egl, eglCreateImageKHR(_,_,_,_,_)) .Times(Exactly(1)); EXPECT_CALL(mock_egl, glEGLImageTargetTexture2DOES(_,mock_egl.fake_egl_image)) .Times(Exactly(1)); EXPECT_CALL(mock_egl, eglDestroyImageKHR(_,mock_egl.fake_egl_image)) .Times(Exactly(1)); } EXPECT_NO_THROW({ auto buffer = allocator->alloc_buffer(buffer_properties); buffer->bind_to_texture(); }); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_internal_client.cpp0000644000015301777760000000414512322054223027623 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/mesa/internal_client.h" #include "mir/graphics/internal_surface.h" #include "mir_toolkit/mesa/native_display.h" #include "src/platform/graphics/mesa/internal_native_surface.h" #include namespace geom=mir::geometry; namespace mg = mir::graphics; namespace mgm=mir::graphics::mesa; namespace { class StubInternalSurface : public mg::InternalSurface { public: geom::Size size() const { return geom::Size(); } MirPixelFormat pixel_format() const { return MirPixelFormat(); } void swap_buffers(mg::Buffer*&) { } }; } TEST(InternalClient, native_display_sanity) { auto stub_display = std::make_shared(); mgm::InternalClient client(stub_display); auto native_display = client.egl_native_display(); EXPECT_EQ(reinterpret_cast(stub_display.get()), native_display); } TEST(InternalClient, native_surface_sanity) { auto stub_display = std::make_shared(); mgm::InternalClient client(stub_display); auto stub_window = std::make_shared(); auto native_window = reinterpret_cast(client.egl_native_window(stub_window)); ASSERT_NE(nullptr, native_window->surface_advance_buffer); ASSERT_NE(nullptr, native_window->surface_get_parameters); ASSERT_NE(nullptr, native_window->surface_set_swapinterval); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_linux_virtual_terminal.cpp0000644000015301777760000005117612322054223031257 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/mesa/linux_virtual_terminal.h" #include "src/server/report/null_report_factory.h" #include "mir/main_loop.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_display_report.h" #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace mr = mir::report; namespace { class MockVTFileOperations : public mgm::VTFileOperations { public: ~MockVTFileOperations() noexcept {} MOCK_METHOD2(open, int(char const*, int)); MOCK_METHOD1(close, int(int)); MOCK_METHOD3(ioctl, int(int, int, int)); MOCK_METHOD3(ioctl, int(int, int, void*)); MOCK_METHOD3(tcsetattr, int(int, int, const struct termios*)); MOCK_METHOD2(tcgetattr, int(int, struct termios*)); }; class MockPosixProcessOperations : public mgm::PosixProcessOperations { public: ~MockPosixProcessOperations() = default; MOCK_CONST_METHOD0(getpid, pid_t()); MOCK_CONST_METHOD0(getppid, pid_t()); MOCK_CONST_METHOD1(getpgid, pid_t(pid_t)); MOCK_CONST_METHOD1(getsid, pid_t(pid_t)); MOCK_METHOD2(setpgid, int(pid_t, pid_t)); MOCK_METHOD0(setsid, pid_t()); }; // The default return values are appropriate, so // Add a typedef to aid clarity. typedef testing::NiceMock StubPosixProcessOperations; class MockMainLoop : public mir::MainLoop { public: ~MockMainLoop() noexcept {} void run() {} void stop() {} MOCK_METHOD2(register_signal_handler, void(std::initializer_list, std::function const&)); MOCK_METHOD2(register_fd_handler, void(std::initializer_list, std::function const&)); }; ACTION_TEMPLATE(SetIoctlPointee, HAS_1_TEMPLATE_PARAMS(typename, T), AND_1_VALUE_PARAMS(param)) { *static_cast(arg2) = param; } ACTION_TEMPLATE(SetTcAttrPointee, HAS_1_TEMPLATE_PARAMS(typename, T), AND_1_VALUE_PARAMS(param)) { *static_cast(arg1) = param; } MATCHER_P(ModeUsesSignal, sig, "") { auto vtm = static_cast(arg); return vtm->mode == VT_PROCESS && vtm->relsig == sig && vtm->acqsig == sig; } MATCHER_P(VTModeMatches, mode, "") { auto vtm = static_cast(arg); return vtm->mode == mode.mode && vtm->waitv == mode.waitv && vtm->relsig == mode.relsig && vtm->acqsig == mode.acqsig && vtm->frsig == mode.frsig; } } class LinuxVirtualTerminalTest : public ::testing::Test { public: LinuxVirtualTerminalTest() : fake_vt_fd{5}, fake_kd_mode{KD_TEXT}, fake_vt_mode_auto{VT_AUTO, 0, 0, 0, 0}, fake_vt_mode_process{VT_PROCESS, 0, SIGUSR1, SIGUSR2, 0}, fake_kb_mode{K_RAW}, fake_tc_attr() { } void set_up_expectations_for_current_vt_search(int vt_num) { using namespace testing; int const tmp_fd1{3}; int const tmp_fd2{4}; vt_stat vts = vt_stat(); vts.v_active = vt_num; EXPECT_CALL(mock_fops, open(StrEq("/dev/tty"), _)) .WillOnce(Return(tmp_fd1)); EXPECT_CALL(mock_fops, ioctl(tmp_fd1, VT_GETSTATE, An())) .WillOnce(Return(-1)); EXPECT_CALL(mock_fops, close(tmp_fd1)) .WillOnce(Return(0)); EXPECT_CALL(mock_fops, open(StrEq("/dev/tty0"), _)) .WillOnce(Return(tmp_fd2)); EXPECT_CALL(mock_fops, ioctl(tmp_fd2, VT_GETSTATE, An())) .WillOnce(DoAll(SetIoctlPointee(vts), Return(0))); EXPECT_CALL(mock_fops, close(tmp_fd2)) .WillOnce(Return(0)); } void set_up_expectations_for_vt_setup(int vt_num, bool activate) { set_up_expectations_for_vt_setup(vt_num, activate, fake_vt_mode_auto); } void set_up_expectations_for_vt_setup(int vt_num, bool activate, vt_mode const& vtm) { using namespace testing; std::stringstream ss; ss << "/dev/tty" << vt_num; EXPECT_CALL(mock_fops, open(StrEq(ss.str()), _)) .WillOnce(Return(fake_vt_fd)); if (activate) { EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, VT_ACTIVATE, vt_num)) .WillOnce(Return(0)); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, VT_WAITACTIVE, vt_num)) .WillOnce(Return(0)); } EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, KDGETMODE, An())) .WillOnce(DoAll(SetIoctlPointee(fake_kd_mode), Return(0))); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, VT_GETMODE, An())) .WillOnce(DoAll(SetIoctlPointee(vtm), Return(0))); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, KDGKBMODE, An())) .WillOnce(DoAll(SetIoctlPointee(fake_kb_mode), Return(0))); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, KDSKBMODE, K_OFF)) .WillOnce(Return(0)); EXPECT_CALL(mock_fops, tcgetattr(fake_vt_fd, An())) .WillOnce(DoAll(SetTcAttrPointee(fake_tc_attr), Return(0))); EXPECT_CALL(mock_fops, tcsetattr(fake_vt_fd, TCSANOW, An())) .WillOnce(Return(0)); } void set_up_expectations_for_switch_handler(int sig) { using namespace testing; EXPECT_CALL(mock_main_loop, register_signal_handler(ElementsAre(sig), _)) .WillOnce(SaveArg<1>(&sig_handler)); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, VT_SETMODE, MatcherCast(ModeUsesSignal(sig)))); } void set_up_expectations_for_vt_teardown() { set_up_expectations_for_vt_teardown(fake_vt_mode_auto); } void set_up_expectations_for_vt_teardown(vt_mode const& vt_mode) { using namespace testing; EXPECT_CALL(mock_fops, tcsetattr(fake_vt_fd, TCSANOW, An())) .WillOnce(Return(0)); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, KDSKBMODE, fake_kb_mode)) .WillOnce(Return(0)); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, KDSETMODE, fake_kd_mode)) .WillOnce(Return(0)); if (vt_mode.mode == VT_AUTO) { EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, VT_SETMODE, Matcher(VTModeMatches(vt_mode)))) .WillOnce(Return(0)); } else { EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, VT_SETMODE, An())) .Times(0); } EXPECT_CALL(mock_fops, close(fake_vt_fd)) .WillOnce(Return(0)); } int const fake_vt_fd; int const fake_kd_mode; vt_mode const fake_vt_mode_auto; vt_mode const fake_vt_mode_process; int const fake_kb_mode; struct termios fake_tc_attr; std::function sig_handler; MockVTFileOperations mock_fops; MockMainLoop mock_main_loop; }; TEST_F(LinuxVirtualTerminalTest, use_provided_vt) { using namespace testing; int const vt_num{7}; InSequence s; set_up_expectations_for_vt_setup(vt_num, true); set_up_expectations_for_vt_teardown(); auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr(new StubPosixProcessOperations()); auto null_report = mr::null_display_report(); mgm::LinuxVirtualTerminal vt{fops, std::move(pops), vt_num, null_report}; } TEST_F(LinuxVirtualTerminalTest, sets_up_current_vt) { using namespace testing; int const vt_num{7}; InSequence s; set_up_expectations_for_current_vt_search(vt_num); set_up_expectations_for_vt_setup(vt_num, false); set_up_expectations_for_vt_teardown(); auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr(new StubPosixProcessOperations()); auto null_report = mr::null_display_report(); mgm::LinuxVirtualTerminal vt{fops, std::move(pops), 0, null_report}; } TEST_F(LinuxVirtualTerminalTest, failure_to_find_current_vt_throws) { using namespace testing; int const tmp_fd1{3}; InSequence s; EXPECT_CALL(mock_fops, open(StrEq("/dev/tty"), _)) .WillOnce(Return(tmp_fd1)); EXPECT_CALL(mock_fops, ioctl(tmp_fd1, VT_GETSTATE, An())) .WillOnce(Return(-1)); EXPECT_CALL(mock_fops, close(tmp_fd1)) .WillOnce(Return(0)); EXPECT_CALL(mock_fops, open(StrEq("/dev/tty0"), _)) .WillOnce(Return(-1)) .WillOnce(Return(-1)); auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr(new StubPosixProcessOperations()); auto null_report = mr::null_display_report(); EXPECT_THROW({ mgm::LinuxVirtualTerminal vt(fops, std::move(pops), 0, null_report); }, std::runtime_error); } TEST_F(LinuxVirtualTerminalTest, does_not_restore_vt_mode_if_vt_process) { using namespace testing; int const vt_num{7}; InSequence s; set_up_expectations_for_current_vt_search(vt_num); set_up_expectations_for_vt_setup(vt_num, false, fake_vt_mode_process); set_up_expectations_for_vt_teardown(fake_vt_mode_process); auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr(new StubPosixProcessOperations()); auto null_report = mr::null_display_report(); mgm::LinuxVirtualTerminal vt(fops, std::move(pops), 0, null_report); } TEST_F(LinuxVirtualTerminalTest, sets_graphics_mode) { using namespace testing; int const vt_num{7}; InSequence s; set_up_expectations_for_current_vt_search(vt_num); set_up_expectations_for_vt_setup(vt_num, false); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, KDSETMODE, KD_GRAPHICS)) .WillOnce(Return(0)); set_up_expectations_for_vt_teardown(); auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr(new StubPosixProcessOperations()); auto null_report = mr::null_display_report(); mgm::LinuxVirtualTerminal vt(fops, std::move(pops), 0, null_report); vt.set_graphics_mode(); } TEST_F(LinuxVirtualTerminalTest, failure_to_set_graphics_mode_throws) { using namespace testing; int const vt_num{7}; InSequence s; set_up_expectations_for_current_vt_search(vt_num); set_up_expectations_for_vt_setup(vt_num, false); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, KDSETMODE, KD_GRAPHICS)) .WillOnce(Return(-1)); set_up_expectations_for_vt_teardown(); auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr(new StubPosixProcessOperations()); auto null_report = mr::null_display_report(); mgm::LinuxVirtualTerminal vt(fops, std::move(pops), 0, null_report); EXPECT_THROW({ vt.set_graphics_mode(); }, std::runtime_error); } TEST_F(LinuxVirtualTerminalTest, uses_sigusr1_for_switch_handling) { using namespace testing; int const vt_num{7}; InSequence s; set_up_expectations_for_current_vt_search(vt_num); set_up_expectations_for_vt_setup(vt_num, false); set_up_expectations_for_switch_handler(SIGUSR1); set_up_expectations_for_vt_teardown(); auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr(new StubPosixProcessOperations()); auto null_report = mr::null_display_report(); mgm::LinuxVirtualTerminal vt(fops, std::move(pops), 0, null_report); auto null_handler = [] { return true; }; vt.register_switch_handlers(mock_main_loop, null_handler, null_handler); } TEST_F(LinuxVirtualTerminalTest, allows_vt_switch_on_switch_away_handler_success) { using namespace testing; int const vt_num{7}; int const allow_switch{1}; InSequence s; set_up_expectations_for_current_vt_search(vt_num); set_up_expectations_for_vt_setup(vt_num, false); set_up_expectations_for_switch_handler(SIGUSR1); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, VT_RELDISP, allow_switch)); set_up_expectations_for_vt_teardown(); auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr(new StubPosixProcessOperations()); auto null_report = mr::null_display_report(); mgm::LinuxVirtualTerminal vt(fops, std::move(pops), 0, null_report); auto succeeding_handler = [] { return true; }; vt.register_switch_handlers(mock_main_loop, succeeding_handler, succeeding_handler); /* Fake a VT switch away request */ sig_handler(SIGUSR1); } TEST_F(LinuxVirtualTerminalTest, disallows_vt_switch_on_switch_away_handler_failure) { using namespace testing; int const vt_num{7}; int const disallow_switch{0}; mtd::MockDisplayReport mock_report; InSequence s; set_up_expectations_for_current_vt_search(vt_num); set_up_expectations_for_vt_setup(vt_num, false); set_up_expectations_for_switch_handler(SIGUSR1); /* First switch away attempt */ EXPECT_CALL(mock_report, report_vt_switch_away_failure()); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, VT_RELDISP, MatcherCast(disallow_switch))); /* Second switch away attempt */ EXPECT_CALL(mock_report, report_vt_switch_away_failure()); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, VT_RELDISP, MatcherCast(disallow_switch))); set_up_expectations_for_vt_teardown(); auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr(new StubPosixProcessOperations()); mgm::LinuxVirtualTerminal vt(fops, std::move(pops), 0, mt::fake_shared(mock_report)); auto failing_handler = [] { return false; }; vt.register_switch_handlers(mock_main_loop, failing_handler, failing_handler); /* Fake a VT switch away request */ sig_handler(SIGUSR1); /* Fake another VT switch away request */ sig_handler(SIGUSR1); } TEST_F(LinuxVirtualTerminalTest, reports_failed_vt_switch_back_attempt) { using namespace testing; int const vt_num{7}; int const allow_switch{1}; mtd::MockDisplayReport mock_report; InSequence s; set_up_expectations_for_current_vt_search(vt_num); set_up_expectations_for_vt_setup(vt_num, false); set_up_expectations_for_switch_handler(SIGUSR1); /* Switch away */ EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, VT_RELDISP, allow_switch)); /* Switch back */ EXPECT_CALL(mock_report, report_vt_switch_back_failure()); EXPECT_CALL(mock_fops, ioctl(fake_vt_fd, VT_RELDISP, VT_ACKACQ)); set_up_expectations_for_vt_teardown(); auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr(new StubPosixProcessOperations()); mgm::LinuxVirtualTerminal vt(fops, std::move(pops), 0, mt::fake_shared(mock_report)); auto succeeding_handler = [] { return true; }; auto failing_handler = [] { return false; }; vt.register_switch_handlers(mock_main_loop, succeeding_handler, failing_handler); /* Fake a VT switch away request */ sig_handler(SIGUSR1); /* Fake a VT switch back request */ sig_handler(SIGUSR1); } TEST_F(LinuxVirtualTerminalTest, does_not_try_to_reaquire_session_leader) { using namespace testing; int const vt_num{7}; InSequence s; auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr>(new NiceMock()); auto null_report = mr::null_display_report(); pid_t const mockpid{1234}; ON_CALL(*pops, getpid()).WillByDefault(Return(mockpid)); ON_CALL(*pops, getsid(Eq(0))).WillByDefault(Return(mockpid)); ON_CALL(*pops, getsid(Eq(mockpid))).WillByDefault(Return(mockpid)); EXPECT_CALL(*pops, setpgid(_,_)).Times(0); EXPECT_CALL(*pops, setsid()).Times(0); set_up_expectations_for_vt_setup(vt_num, true); set_up_expectations_for_vt_teardown(); mgm::LinuxVirtualTerminal vt{fops, std::move(pops), vt_num, null_report}; } TEST_F(LinuxVirtualTerminalTest, relinquishes_group_leader_before_claiming_session_leader) { using namespace testing; int const vt_num{7}; InSequence s; auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr>(new NiceMock()); auto null_report = mr::null_display_report(); pid_t const mockpid{1234}; pid_t const mock_parent_pid{4567}; ON_CALL(*pops, getpid()).WillByDefault(Return(mockpid)); ON_CALL(*pops, getpgid(Eq(0))).WillByDefault(Return(mockpid)); ON_CALL(*pops, getpgid(Eq(mockpid))).WillByDefault(Return(mockpid)); ON_CALL(*pops, getpgid(Eq(mock_parent_pid))).WillByDefault(Return(mock_parent_pid)); ON_CALL(*pops, getppid()).WillByDefault(Return(mock_parent_pid)); ON_CALL(*pops, getsid(Eq(0))).WillByDefault(Return(1)); ON_CALL(*pops, getsid(Eq(mockpid))).WillByDefault(Return(1)); EXPECT_CALL(*pops, setpgid(Eq(0), Eq(mock_parent_pid))) .Times(1) .WillOnce(Return(0)); EXPECT_CALL(*pops, setsid()) .Times(1) .WillOnce(Return(0)); set_up_expectations_for_vt_setup(vt_num, true); set_up_expectations_for_vt_teardown(); mgm::LinuxVirtualTerminal vt{fops, std::move(pops), vt_num, null_report}; } TEST_F(LinuxVirtualTerminalTest, exception_if_setting_process_group_fails) { using namespace testing; int const vt_num{7}; InSequence s; auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr>(new NiceMock()); auto null_report = mr::null_display_report(); pid_t const mockpid{1234}; pid_t const mock_parent_pid{4567}; ON_CALL(*pops, getpid()).WillByDefault(Return(mockpid)); ON_CALL(*pops, getpgid(Eq(0))).WillByDefault(Return(mockpid)); ON_CALL(*pops, getpgid(Eq(mockpid))).WillByDefault(Return(mockpid)); ON_CALL(*pops, getpgid(Eq(mock_parent_pid))).WillByDefault(Return(mock_parent_pid)); ON_CALL(*pops, getppid()).WillByDefault(Return(mock_parent_pid)); ON_CALL(*pops, getsid(Eq(0))).WillByDefault(Return(1)); ON_CALL(*pops, getsid(Eq(mockpid))).WillByDefault(Return(1)); EXPECT_CALL(*pops, setpgid(Eq(0), Eq(mock_parent_pid))) .Times(1) .WillOnce(Return(-1)); EXPECT_THROW({ mgm::LinuxVirtualTerminal vt(fops, std::move(pops), vt_num, null_report); }, std::runtime_error); } TEST_F(LinuxVirtualTerminalTest, exception_if_becoming_session_leader_fails) { using namespace testing; int const vt_num{7}; InSequence s; auto fops = mt::fake_shared(mock_fops); auto pops = std::unique_ptr>(new NiceMock()); auto null_report = mr::null_display_report(); pid_t const mockpid{1234}; pid_t const mock_parent_pid{4567}; ON_CALL(*pops, getpid()).WillByDefault(Return(mockpid)); ON_CALL(*pops, getpgid(Eq(0))).WillByDefault(Return(mockpid)); ON_CALL(*pops, getpgid(Eq(mockpid))).WillByDefault(Return(mockpid)); ON_CALL(*pops, getpgid(Eq(mock_parent_pid))).WillByDefault(Return(mock_parent_pid)); ON_CALL(*pops, getppid()).WillByDefault(Return(mock_parent_pid)); ON_CALL(*pops, getsid(Eq(0))).WillByDefault(Return(1)); ON_CALL(*pops, getsid(Eq(mockpid))).WillByDefault(Return(1)); EXPECT_CALL(*pops, setpgid(Eq(0), Eq(mock_parent_pid))) .Times(1) .WillOnce(Return(0)); EXPECT_CALL(*pops, setsid()) .Times(1) .WillOnce(Return(-1)); EXPECT_THROW({ mgm::LinuxVirtualTerminal vt(fops, std::move(pops), vt_num, null_report); }, std::runtime_error); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_platform.cpp0000644000015301777760000002151312322054223026273 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/graphics/platform_ipc_package.h" #include "mir/graphics/drm_authenticator.h" #include "src/platform/graphics/mesa/platform.h" #include "src/platform/graphics/mesa/internal_client.h" #include "mir_test_doubles/null_virtual_terminal.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/mock_buffer_packer.h" #include "src/server/report/null_report_factory.h" #include #include "mir_test_framework/udev_environment.h" #include "mir_test/pipe.h" #include "mir_test_doubles/mock_drm.h" #include "mir_test_doubles/mock_gbm.h" #include #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace mtd = mir::test::doubles; namespace mtf = mir::mir_test_framework; namespace mr = mir::report; namespace { class MesaGraphicsPlatform : public ::testing::Test { public: void SetUp() { ::testing::Mock::VerifyAndClearExpectations(&mock_drm); ::testing::Mock::VerifyAndClearExpectations(&mock_gbm); fake_devices.add_standard_device("standard-drm-devices"); } std::shared_ptr create_platform() { return std::make_shared( mr::null_display_report(), std::make_shared()); } ::testing::NiceMock mock_drm; ::testing::NiceMock mock_gbm; mtf::UdevEnvironment fake_devices; }; } TEST_F(MesaGraphicsPlatform, get_ipc_package) { using namespace testing; mir::test::Pipe auth_pipe; int const auth_fd{auth_pipe.read_fd()}; /* First time for master DRM fd, second for authenticated fd */ EXPECT_CALL(mock_drm, open(_,_,_)) .WillOnce(Return(mock_drm.fake_drm.fd())); EXPECT_CALL(mock_drm, drmOpen(_,_)) .WillOnce(Return(auth_fd)); /* Expect proper authorization */ EXPECT_CALL(mock_drm, drmGetMagic(auth_fd,_)); EXPECT_CALL(mock_drm, drmAuthMagic(mock_drm.fake_drm.fd(),_)); EXPECT_CALL(mock_drm, drmClose(mock_drm.fake_drm.fd())); /* Expect authenticated fd to be closed when package is destroyed */ EXPECT_CALL(mock_drm, drmClose(auth_fd)); EXPECT_NO_THROW ( auto platform = create_platform(); auto pkg = platform->get_ipc_package(); ASSERT_TRUE(pkg.get()); ASSERT_EQ(std::vector::size_type{1}, pkg->ipc_fds.size()); ASSERT_EQ(auth_fd, pkg->ipc_fds[0]); ); } TEST_F(MesaGraphicsPlatform, a_failure_while_creating_a_platform_results_in_an_error) { using namespace ::testing; EXPECT_CALL(mock_drm, open(_,_,_)) .WillRepeatedly(Return(-1)); try { auto platform = create_platform(); } catch(...) { return; } FAIL() << "Expected an exception to be thrown."; } TEST_F(MesaGraphicsPlatform, fails_if_no_resources) { using namespace ::testing; EXPECT_CALL(mock_drm, drmModeGetResources(_)) .Times(Exactly(1)) .WillOnce(Return(reinterpret_cast(0))); EXPECT_CALL(mock_drm, drmModeFreeResources(_)) .Times(Exactly(0)); EXPECT_THROW({ auto platform = create_platform(); }, std::runtime_error) << "Expected that c'tor of Platform throws"; } /* ipc packaging tests */ TEST_F(MesaGraphicsPlatform, test_ipc_data_packed_correctly) { mtd::MockBuffer mock_buffer; mir::geometry::Stride dummy_stride(4390); auto native_handle = std::make_shared(); native_handle->data_items = 4; native_handle->fd_items = 2; for(auto i=0; ifd[i] = i; native_handle->data[i] = i; } EXPECT_CALL(mock_buffer, native_buffer_handle()) .WillOnce(testing::Return(native_handle)); EXPECT_CALL(mock_buffer, stride()) .WillOnce(testing::Return(mir::geometry::Stride{dummy_stride})); EXPECT_CALL(mock_buffer, size()) .WillOnce(testing::Return(mir::geometry::Size{123, 456})); auto platform = create_platform(); mtd::MockPacker mock_packer; for(auto i=0; i < native_handle->fd_items; i++) { EXPECT_CALL(mock_packer, pack_fd(native_handle->fd[i])) .Times(1); } for(auto i=0; i < native_handle->data_items; i++) { EXPECT_CALL(mock_packer, pack_data(native_handle->data[i])) .Times(1); } EXPECT_CALL(mock_packer, pack_stride(dummy_stride)) .Times(1); EXPECT_CALL(mock_packer, pack_flags(testing::_)) .Times(1); EXPECT_CALL(mock_packer, pack_size(testing::_)) .Times(1); platform->fill_ipc_package(&mock_packer, &mock_buffer); } TEST_F(MesaGraphicsPlatform, drm_auth_magic_calls_drm_function_correctly) { using namespace testing; unsigned int const magic{0x10111213}; EXPECT_CALL(mock_drm, drmAuthMagic(mock_drm.fake_drm.fd(),magic)) .WillOnce(Return(0)); auto platform = create_platform(); auto authenticator = std::dynamic_pointer_cast(platform); authenticator->drm_auth_magic(magic); } TEST_F(MesaGraphicsPlatform, drm_auth_magic_throws_if_drm_function_fails) { using namespace testing; unsigned int const magic{0x10111213}; EXPECT_CALL(mock_drm, drmAuthMagic(mock_drm.fake_drm.fd(),magic)) .WillOnce(Return(-1)); auto platform = create_platform(); auto authenticator = std::dynamic_pointer_cast(platform); EXPECT_THROW({ authenticator->drm_auth_magic(magic); }, std::runtime_error); } TEST_F(MesaGraphicsPlatform, platform_provides_validation_of_display_for_internal_clients) { MirMesaEGLNativeDisplay* native_display = nullptr; EXPECT_EQ(MIR_MESA_FALSE, mgm::mir_server_mesa_egl_native_display_is_valid(native_display)); { auto platform = create_platform(); auto client = platform->create_internal_client(); native_display = reinterpret_cast(client->egl_native_display()); EXPECT_EQ(MIR_MESA_TRUE, mgm::mir_server_mesa_egl_native_display_is_valid(native_display)); } EXPECT_EQ(MIR_MESA_FALSE, mgm::mir_server_mesa_egl_native_display_is_valid(native_display)); } TEST_F(MesaGraphicsPlatform, egl_native_display_is_gbm_device) { auto platform = create_platform(); EXPECT_EQ(mock_gbm.fake_gbm.device, platform->egl_native_display()); } namespace { class ConcurrentCallDetector { public: ConcurrentCallDetector() : threads_in_call{0}, detected_concurrent_calls_{false} { } void call() { if (threads_in_call.fetch_add(1) > 0) detected_concurrent_calls_ = true; std::this_thread::sleep_for(std::chrono::milliseconds{1}); --threads_in_call; } bool detected_concurrent_calls() { return detected_concurrent_calls_; } private: std::atomic threads_in_call; std::atomic detected_concurrent_calls_; }; } /* * This test is not 100% reliable in theory (we are trying to recreate a race * condition after all!), but it can only produce false successes, not false * failures, so it's safe to use. In practice it is reliable enough: I get a * 100% failure rate for this test (1000 out of 1000 repetitions) when testing * without the fix for the race condition we are testing for. */ TEST_F(MesaGraphicsPlatform, drm_close_not_called_concurrently_on_ipc_package_destruction) { using namespace testing; unsigned int const num_threads{10}; unsigned int const num_iterations{10}; ConcurrentCallDetector detector; ON_CALL(mock_drm, drmClose(_)) .WillByDefault(DoAll(InvokeWithoutArgs(&detector, &ConcurrentCallDetector::call), Return(0))); auto platform = create_platform(); std::vector threads; for (unsigned int i = 0; i < num_threads; i++) { threads.push_back(std::thread{ [platform] { for (unsigned int i = 0; i < num_iterations; i++) { platform->get_ipc_package(); } }}); } for (auto& t : threads) t.join(); EXPECT_FALSE(detector.detected_concurrent_calls()); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_buffer_allocator.cpp0000644000015301777760000002366212322054223027767 0ustar pbusernogroup00000000000000/* * 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: Christopher James Halse Rogers */ #include "src/platform/graphics/mesa/platform.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "src/platform/graphics/mesa/buffer_allocator.h" #include "mir/graphics/buffer_properties.h" #include "mir_test_doubles/mock_drm.h" #include "mir_test_doubles/mock_gbm.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_gl.h" #include "mir_test_doubles/mock_buffer_initializer.h" #include "mir_test_doubles/null_virtual_terminal.h" #include "mir_test_framework/udev_environment.h" #include "src/server/report/null_report_factory.h" #include #include #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; namespace mr = mir::report; namespace mtf = mir::mir_test_framework; class MesaBufferAllocatorTest : public ::testing::Test { protected: virtual void SetUp() { using namespace testing; unsetenv("MIR_BYPASS"); fake_devices.add_standard_device("standard-drm-devices"); size = geom::Size{300, 200}; pf = mir_pixel_format_argb_8888; usage = mg::BufferUsage::hardware; buffer_properties = mg::BufferProperties{size, pf, usage}; ON_CALL(mock_gbm, gbm_bo_get_handle(_)) .WillByDefault(Return(mock_gbm.fake_gbm.bo_handle)); platform = std::make_shared( mr::null_display_report(), std::make_shared()); mock_buffer_initializer = std::make_shared>(); allocator.reset(new mgm::BufferAllocator(platform->gbm.device, mock_buffer_initializer)); } // Defaults geom::Size size; MirPixelFormat pf; mg::BufferUsage usage; mg::BufferProperties buffer_properties; ::testing::NiceMock mock_drm; ::testing::NiceMock mock_gbm; ::testing::NiceMock mock_egl; ::testing::NiceMock mock_gl; std::shared_ptr platform; std::shared_ptr> mock_buffer_initializer; std::unique_ptr allocator; mtf::UdevEnvironment fake_devices; }; TEST_F(MesaBufferAllocatorTest, allocator_returns_non_null_buffer) { using namespace testing; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,_)); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)); EXPECT_TRUE(allocator->alloc_buffer(buffer_properties).get() != NULL); } TEST_F(MesaBufferAllocatorTest, large_hardware_buffers_bypass) { using namespace testing; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,_)); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)); const mg::BufferProperties properties(geom::Size{1280, 800}, mir_pixel_format_argb_8888, mg::BufferUsage::hardware); auto buf = allocator->alloc_buffer(properties); ASSERT_TRUE(buf.get() != NULL); EXPECT_TRUE(buf->can_bypass()); } TEST_F(MesaBufferAllocatorTest, small_buffers_dont_bypass) { using namespace testing; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,_)); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)); const mg::BufferProperties properties(geom::Size{100, 100}, mir_pixel_format_argb_8888, mg::BufferUsage::hardware); auto buf = allocator->alloc_buffer(properties); ASSERT_TRUE(buf.get() != NULL); EXPECT_FALSE(buf->can_bypass()); } TEST_F(MesaBufferAllocatorTest, software_buffers_dont_bypass) { using namespace testing; const mg::BufferProperties properties(geom::Size{1920, 1200}, mir_pixel_format_argb_8888, mg::BufferUsage::software); auto buf = allocator->alloc_buffer(properties); ASSERT_TRUE(buf.get() != NULL); EXPECT_FALSE(buf->can_bypass()); } TEST_F(MesaBufferAllocatorTest, bypass_disables_via_environment) { using namespace testing; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,_)); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)); const mg::BufferProperties properties(geom::Size{1280, 800}, mir_pixel_format_argb_8888, mg::BufferUsage::hardware); setenv("MIR_BYPASS", "0", 1); mgm::BufferAllocator alloc(platform->gbm.device, mock_buffer_initializer); auto buf = alloc.alloc_buffer(properties); ASSERT_TRUE(buf.get() != NULL); EXPECT_FALSE(buf->can_bypass()); unsetenv("MIR_BYPASS"); } TEST_F(MesaBufferAllocatorTest, correct_buffer_format_translation_argb_8888) { using namespace testing; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,GBM_FORMAT_ARGB8888,_)); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)); allocator->alloc_buffer(mg::BufferProperties{size, mir_pixel_format_argb_8888, usage}); } TEST_F(MesaBufferAllocatorTest, correct_buffer_format_translation_xrgb_8888) { using namespace testing; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,GBM_FORMAT_XRGB8888,_)); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)); allocator->alloc_buffer(mg::BufferProperties{size, mir_pixel_format_xrgb_8888, usage}); } MATCHER_P(has_flag_set, flag, "") { return arg & flag; } TEST_F(MesaBufferAllocatorTest, creates_hardware_rendering_buffer) { using namespace testing; mg::BufferProperties properties{size, pf, mg::BufferUsage::hardware}; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,has_flag_set(GBM_BO_USE_RENDERING))); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)); allocator->alloc_buffer(properties); } TEST_F(MesaBufferAllocatorTest, creates_software_rendering_buffer) { using namespace testing; mg::BufferProperties properties{size, pf, mg::BufferUsage::software}; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,_)).Times(0); allocator->alloc_buffer(properties); } TEST_F(MesaBufferAllocatorTest, creates_hardware_rendering_buffer_for_undefined_usage) { using namespace testing; mg::BufferProperties properties{size, pf, mg::BufferUsage::undefined}; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,has_flag_set(GBM_BO_USE_RENDERING))); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)); allocator->alloc_buffer(properties); } TEST_F(MesaBufferAllocatorTest, requests_correct_buffer_dimensions) { using namespace testing; EXPECT_CALL(mock_gbm, gbm_bo_create(_,size.width.as_uint32_t(),size.height.as_uint32_t(),_,_)); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)); allocator->alloc_buffer(buffer_properties); } TEST_F(MesaBufferAllocatorTest, correct_buffer_handle_is_destroyed) { using namespace testing; gbm_bo* bo{reinterpret_cast(0xabcd)}; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,_)) .WillOnce(Return(bo)); EXPECT_CALL(mock_gbm, gbm_bo_destroy(bo)); allocator->alloc_buffer(buffer_properties); } TEST_F(MesaBufferAllocatorTest, buffer_initializer_is_called) { using namespace testing; EXPECT_CALL(*mock_buffer_initializer, operator_call(_)) .Times(1); allocator->alloc_buffer(buffer_properties); } TEST_F(MesaBufferAllocatorTest, null_buffer_initializer_does_not_crash) { using namespace testing; auto null_buffer_initializer = std::make_shared(); allocator.reset(new mgm::BufferAllocator(platform->gbm.device, null_buffer_initializer)); EXPECT_NO_THROW({ allocator->alloc_buffer(buffer_properties); }); } TEST_F(MesaBufferAllocatorTest, throws_on_buffer_creation_failure) { using namespace testing; EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,_)) .WillOnce(Return(reinterpret_cast(0))); EXPECT_CALL(mock_gbm, gbm_bo_destroy(_)) .Times(0); EXPECT_THROW({ allocator->alloc_buffer(buffer_properties); }, std::runtime_error); } TEST_F(MesaBufferAllocatorTest, supported_pixel_formats_contain_common_formats) { auto supported_pixel_formats = allocator->supported_pixel_formats(); auto argb_8888_count = std::count(supported_pixel_formats.begin(), supported_pixel_formats.end(), mir_pixel_format_argb_8888); auto xrgb_8888_count = std::count(supported_pixel_formats.begin(), supported_pixel_formats.end(), mir_pixel_format_xrgb_8888); EXPECT_EQ(1, argb_8888_count); EXPECT_EQ(1, xrgb_8888_count); } TEST_F(MesaBufferAllocatorTest, supported_pixel_formats_have_sane_default_in_first_position) { auto supported_pixel_formats = allocator->supported_pixel_formats(); ASSERT_FALSE(supported_pixel_formats.empty()); EXPECT_EQ(mir_pixel_format_argb_8888, supported_pixel_formats[0]); } TEST_F(MesaBufferAllocatorTest, alloc_with_unsupported_pixel_format_throws) { using namespace testing; /* We shouldn't try to create a buffer with an unsupported format */ EXPECT_CALL(mock_gbm, gbm_bo_create(_,_,_,_,_)).Times(0); EXPECT_THROW({ allocator->alloc_buffer(mg::BufferProperties{size, mir_pixel_format_abgr_8888, usage}); }, std::runtime_error); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_internal_native_surface.cpp0000644000015301777760000001034512322054247031350 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/mesa/internal_native_surface.h" #include "mir/graphics/platform.h" #include "mir/graphics/platform_ipc_package.h" #include "mir/graphics/internal_surface.h" #include "mir_toolkit/mesa/native_display.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_frontend_surface.h" #include "mir_test_doubles/mock_buffer.h" #include "gmock_set_arg.h" #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mt::doubles; namespace { class MockInternalSurface : public mg::InternalSurface { public: MOCK_CONST_METHOD0(size, geom::Size()); MOCK_CONST_METHOD0(pixel_format, MirPixelFormat()); MOCK_METHOD1(swap_buffers, void(mg::Buffer*&)); }; struct InternalNativeSurface : public testing::Test { void SetUp() { using namespace ::testing; mock_surface = std::make_shared(); } std::shared_ptr mock_surface; }; MATCHER_P(ParametersHaveSize, size, "") { if (static_cast(arg.width) != size.width.as_uint32_t()) return false; if (static_cast(arg.height) != size.height.as_uint32_t()) return false; return true; } } TEST_F(InternalNativeSurface, surface_advance_buffer_packaging) { using namespace ::testing; mtd::MockBuffer buffer; auto test_buffer_package = std::make_shared(); test_buffer_package->data_items = 2; test_buffer_package->data[0] = 1; test_buffer_package->data[1] = 2; test_buffer_package->fd_items = 2; test_buffer_package->fd[0] = 3; test_buffer_package->fd[1] = 4; test_buffer_package->stride = 77; mgm::InternalNativeSurface native_surface(mock_surface); EXPECT_CALL(buffer, native_buffer_handle()) .WillOnce(Return(test_buffer_package)); EXPECT_CALL(*mock_surface, swap_buffers(_)) .Times(1) .WillOnce(SetArg<0>(&buffer)); MirBufferPackage buffer_package; memset(&buffer_package, 0, sizeof(MirBufferPackage)); native_surface.surface_advance_buffer(&native_surface, &buffer_package); EXPECT_EQ(test_buffer_package->data_items, buffer_package.data_items); EXPECT_EQ(test_buffer_package->data[0], buffer_package.data[0]); EXPECT_EQ(test_buffer_package->data[1], buffer_package.data[1]); EXPECT_EQ(test_buffer_package->fd_items, buffer_package.fd_items); EXPECT_EQ(test_buffer_package->fd[0], buffer_package.fd[0]); EXPECT_EQ(test_buffer_package->fd[1], buffer_package.fd[1]); EXPECT_EQ(test_buffer_package->stride, buffer_package.stride); } TEST_F(InternalNativeSurface, surface_get_parameters) { using namespace ::testing; geom::Size const test_surface_size{17, 29}; MirPixelFormat const test_pixel_format = mir_pixel_format_xrgb_8888; EXPECT_CALL(*mock_surface, size()) .Times(1) .WillOnce(Return(test_surface_size)); EXPECT_CALL(*mock_surface, pixel_format()) .Times(1) .WillOnce(Return(test_pixel_format)); mgm::InternalNativeSurface native_surface(mock_surface); MirSurfaceParameters parameters; memset(¶meters, 0, sizeof(MirSurfaceParameters)); native_surface.surface_get_parameters(&native_surface, ¶meters); EXPECT_THAT(parameters, ParametersHaveSize(test_surface_size)); EXPECT_EQ(parameters.pixel_format, mir_pixel_format_xrgb_8888); // TODO: What to do about buffer usage besides hardware? ~racarr EXPECT_EQ(parameters.buffer_usage, mir_buffer_usage_hardware); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_kms_page_flipper.cpp0000644000015301777760000003743512322054223027770 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/mesa/kms_page_flipper.h" #include "mir_test_doubles/mock_drm.h" #include "mir_test_doubles/mock_display_report.h" #include "src/server/report/null_report_factory.h" #include "mir_test/fake_shared.h" #include #include #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace { class KMSPageFlipperTest : public ::testing::Test { public: KMSPageFlipperTest() : page_flipper{mock_drm.fake_drm.fd()} { } testing::NiceMock mock_drm; mgm::KMSPageFlipper page_flipper; }; ACTION_P(InvokePageFlipHandler, param) { int const dont_care{0}; char dummy; arg1->page_flip_handler(dont_care, dont_care, dont_care, dont_care, *param); ASSERT_EQ(1, read(arg0, &dummy, 1)); } } TEST_F(KMSPageFlipperTest, schedule_flip_calls_drm_page_flip) { using namespace testing; uint32_t const crtc_id{10}; uint32_t const fb_id{101}; EXPECT_CALL(mock_drm, drmModePageFlip(mock_drm.fake_drm.fd(), crtc_id, fb_id, _, _)) .Times(1); page_flipper.schedule_flip(crtc_id, fb_id); } TEST_F(KMSPageFlipperTest, double_schedule_flip_throws) { using namespace testing; uint32_t const crtc_id{10}; uint32_t const fb_id{101}; EXPECT_CALL(mock_drm, drmModePageFlip(mock_drm.fake_drm.fd(), crtc_id, fb_id, _, _)) .Times(1); page_flipper.schedule_flip(crtc_id, fb_id); EXPECT_THROW({ page_flipper.schedule_flip(crtc_id, fb_id); }, std::logic_error); } TEST_F(KMSPageFlipperTest, wait_for_flip_handles_drm_event) { using namespace testing; uint32_t const crtc_id{10}; uint32_t const fb_id{101}; void* user_data{nullptr}; EXPECT_CALL(mock_drm, drmModePageFlip(mock_drm.fake_drm.fd(), crtc_id, fb_id, _, _)) .Times(1) .WillOnce(DoAll(SaveArg<4>(&user_data), Return(0))); EXPECT_CALL(mock_drm, drmHandleEvent(mock_drm.fake_drm.fd(), _)) .Times(1) .WillOnce(DoAll(InvokePageFlipHandler(&user_data), Return(0))); page_flipper.schedule_flip(crtc_id, fb_id); /* Fake a DRM event */ EXPECT_EQ(1, write(mock_drm.fake_drm.write_fd(), "a", 1)); page_flipper.wait_for_flip(crtc_id); } TEST_F(KMSPageFlipperTest, wait_for_non_scheduled_page_flip_doesnt_block) { using namespace testing; uint32_t const crtc_id{10}; EXPECT_CALL(mock_drm, drmModePageFlip(_, _, _, _, _)) .Times(0); EXPECT_CALL(mock_drm, drmHandleEvent(_, _)) .Times(0); page_flipper.wait_for_flip(crtc_id); } TEST_F(KMSPageFlipperTest, failure_in_wait_for_flip_throws) { using namespace testing; uint32_t const crtc_id{10}; uint32_t const fb_id{101}; void* user_data{nullptr}; EXPECT_CALL(mock_drm, drmModePageFlip(mock_drm.fake_drm.fd(), crtc_id, fb_id, _, _)) .Times(1) .WillOnce(DoAll(SaveArg<4>(&user_data), Return(0))); EXPECT_CALL(mock_drm, drmHandleEvent(_, _)) .Times(0); page_flipper.schedule_flip(crtc_id, fb_id); /* Cause a failure in wait_for_flip */ close(mock_drm.fake_drm.fd()); EXPECT_THROW({ page_flipper.wait_for_flip(crtc_id); }, std::runtime_error); } TEST_F(KMSPageFlipperTest, wait_for_flips_interleaved) { using namespace testing; uint32_t const fb_id{101}; std::vector const crtc_ids{10, 11, 12}; std::vector user_data{nullptr, nullptr, nullptr}; EXPECT_CALL(mock_drm, drmModePageFlip(mock_drm.fake_drm.fd(), _, fb_id, _, _)) .Times(3) .WillOnce(DoAll(SaveArg<4>(&user_data[0]), Return(0))) .WillOnce(DoAll(SaveArg<4>(&user_data[1]), Return(0))) .WillOnce(DoAll(SaveArg<4>(&user_data[2]), Return(0))); EXPECT_CALL(mock_drm, drmHandleEvent(mock_drm.fake_drm.fd(), _)) .Times(3) .WillOnce(DoAll(InvokePageFlipHandler(&user_data[1]), Return(0))) .WillOnce(DoAll(InvokePageFlipHandler(&user_data[2]), Return(0))) .WillOnce(DoAll(InvokePageFlipHandler(&user_data[0]), Return(0))); for (auto crtc_id : crtc_ids) page_flipper.schedule_flip(crtc_id, fb_id); /* Fake 3 DRM events */ EXPECT_EQ(3, write(mock_drm.fake_drm.write_fd(), "abc", 3)); for (auto crtc_id : crtc_ids) page_flipper.wait_for_flip(crtc_id); } namespace { class PageFlippingFunctor { public: PageFlippingFunctor(mgm::KMSPageFlipper& page_flipper, uint32_t crtc_id) : page_flipper(page_flipper), crtc_id{crtc_id}, done{false}, num_page_flips{0}, num_waits{0} { } void operator()() { while (!done) { page_flipper.schedule_flip(crtc_id, 0); num_page_flips++; std::this_thread::sleep_for(std::chrono::milliseconds{1}); page_flipper.wait_for_flip(crtc_id); num_waits++; } } int page_flip_count() { return num_page_flips; } int wait_count() { return num_waits; } void stop() { done = true; } private: mgm::KMSPageFlipper& page_flipper; uint32_t const crtc_id; std::atomic done; std::atomic num_page_flips; std::atomic num_waits; }; } TEST_F(KMSPageFlipperTest, threads_switch_worker) { using namespace testing; size_t const worker_index{0}; size_t const other_index{1}; std::vector const crtc_ids{10, 11}; std::vector user_data{nullptr, nullptr}; std::vector> page_flipping_functors; std::vector page_flipping_threads; std::thread::id tid; EXPECT_CALL(mock_drm, drmModePageFlip(mock_drm.fake_drm.fd(), _, _, _, _)) .Times(2) .WillOnce(DoAll(SaveArg<4>(&user_data[worker_index]), Return(0))) .WillOnce(DoAll(SaveArg<4>(&user_data[other_index]), Return(0))); /* * The first event releases the original worker, hence we expect that * then the other thread will become the worker. */ EXPECT_CALL(mock_drm, drmHandleEvent(mock_drm.fake_drm.fd(), _)) .Times(2) .WillOnce(DoAll(InvokePageFlipHandler(&user_data[worker_index]), Return(0))) .WillOnce(DoAll(InvokePageFlipHandler(&user_data[other_index]), Return(0))); /* Start the page-flipping threads */ for (auto crtc_id : crtc_ids) { auto pf = std::unique_ptr(new PageFlippingFunctor{page_flipper, crtc_id}); page_flipping_functors.push_back(std::move(pf)); page_flipping_threads.push_back(std::thread{std::ref(*page_flipping_functors.back())}); /* Wait for page-flip request and tell flipper to stop after this iteration */ while (page_flipping_functors.back()->page_flip_count() == 0) std::this_thread::sleep_for(std::chrono::milliseconds{1}); page_flipping_functors.back()->stop(); /* Wait until the (first) thread has become the worker */ while (tid == std::thread::id()) { std::this_thread::sleep_for(std::chrono::milliseconds{1}); tid = page_flipper.debug_get_worker_tid(); } } EXPECT_EQ(page_flipping_threads[worker_index].get_id(), tid); /* Fake a DRM event */ EXPECT_EQ(1, write(mock_drm.fake_drm.write_fd(), "a", 1)); page_flipping_threads[worker_index].join(); /* Wait for the worker to switch */ while (tid != page_flipping_threads[other_index].get_id()) { std::this_thread::sleep_for(std::chrono::milliseconds{1}); tid = page_flipper.debug_get_worker_tid(); } /* Fake another DRM event to unblock the remaining thread */ EXPECT_EQ(1, write(mock_drm.fake_drm.write_fd(), "a", 1)); page_flipping_threads[other_index].join(); } TEST_F(KMSPageFlipperTest, threads_worker_notifies_non_worker) { using namespace testing; size_t const worker_index{0}; size_t const other_index{1}; std::vector const crtc_ids{10, 11}; std::vector user_data{nullptr, nullptr}; std::vector> page_flipping_functors; std::vector page_flipping_threads; std::thread::id tid; EXPECT_CALL(mock_drm, drmModePageFlip(mock_drm.fake_drm.fd(), _, _, _, _)) .Times(2) .WillOnce(DoAll(SaveArg<4>(&user_data[worker_index]), Return(0))) .WillOnce(DoAll(SaveArg<4>(&user_data[other_index]), Return(0))); /* * The first event releases the non-worker thread, hence we expect that * original worker not change. */ EXPECT_CALL(mock_drm, drmHandleEvent(mock_drm.fake_drm.fd(), _)) .Times(2) .WillOnce(DoAll(InvokePageFlipHandler(&user_data[other_index]), Return(0))) .WillOnce(DoAll(InvokePageFlipHandler(&user_data[worker_index]), Return(0))); /* Start the page-flipping threads */ for (auto crtc_id : crtc_ids) { auto pf = std::unique_ptr(new PageFlippingFunctor{page_flipper, crtc_id}); page_flipping_functors.push_back(std::move(pf)); page_flipping_threads.push_back(std::thread{std::ref(*page_flipping_functors.back())}); /* Wait for page-flip request and tell flipper to stop after this iteration */ while (page_flipping_functors.back()->page_flip_count() == 0) std::this_thread::sleep_for(std::chrono::milliseconds{1}); page_flipping_functors.back()->stop(); /* Wait until the (first) thread has become the worker */ while (tid == std::thread::id()) { std::this_thread::sleep_for(std::chrono::milliseconds{1}); tid = page_flipper.debug_get_worker_tid(); } } EXPECT_EQ(page_flipping_threads[worker_index].get_id(), tid); /* Fake a DRM event */ EXPECT_EQ(1, write(mock_drm.fake_drm.write_fd(), "a", 1)); /* Wait for the non-worker thread to exit */ page_flipping_threads[other_index].join(); /* Check that the worker hasn't changed */ EXPECT_EQ(page_flipping_threads[worker_index].get_id(), page_flipper.debug_get_worker_tid()); /* Fake another DRM event to unblock the remaining thread */ EXPECT_EQ(1, write(mock_drm.fake_drm.write_fd(), "a", 1)); page_flipping_threads[worker_index].join(); } namespace { class PageFlipCounter { public: void add_flip(uint32_t crtc_id, void* user_data) { std::lock_guard lock{data_mutex}; data.push_back({CountType::flip, crtc_id}); pending_flips.insert(user_data); } void add_handle_event(uint32_t crtc_id) { std::lock_guard lock{data_mutex}; data.push_back({CountType::handle_event, crtc_id}); } int count_flips() { std::lock_guard lock{data_mutex}; return std::count_if(begin(data), end(data), [](CountElement& e) -> bool { return e.type == CountType::flip; }); } int count_handle_events() { std::lock_guard lock{data_mutex}; return std::count_if(begin(data), end(data), [](CountElement& e) -> bool { return e.type == CountType::handle_event; }); } bool no_consecutive_flips_for_same_crtc_id() { std::lock_guard lock{data_mutex}; std::unordered_set pending_crtc_ids; for (auto& e : data) { if (e.type == CountType::flip) { if (pending_crtc_ids.find(e.crtc_id) != pending_crtc_ids.end()) return false; pending_crtc_ids.insert(e.crtc_id); } else if (e.type == CountType::handle_event) { if (pending_crtc_ids.find(e.crtc_id) == pending_crtc_ids.end()) return false; pending_crtc_ids.erase(e.crtc_id); } } return true; } void* get_pending_flip_data() { std::lock_guard lock{data_mutex}; auto iter = pending_flips.begin(); if (iter == pending_flips.end()) { return 0; } else { auto d = *iter; pending_flips.erase(iter); return d; } } private: enum class CountType {flip, handle_event}; struct CountElement { CountType type; uint32_t crtc_id; }; std::vector data; std::unordered_set pending_flips; std::mutex data_mutex; }; ACTION_P(InvokePageFlipHandlerWithPendingData, counter) { int const dont_care{0}; int const drm_fd{arg0}; char dummy; auto user_data = static_cast(counter->get_pending_flip_data()); uint32_t const crtc_id{user_data->crtc_id}; /* Remove the event from the drm event queue */ ASSERT_EQ(1, read(drm_fd, &dummy, 1)); /* Call the page flip handler */ arg1->page_flip_handler(dont_care, dont_care, dont_care, dont_care, user_data); /* Record this call */ counter->add_handle_event(crtc_id); } ACTION_P2(AddPageFlipEvent, counter, write_drm_fd) { uint32_t const crtc_id{arg0}; void* const user_data{arg1}; /* Record this call */ counter->add_flip(crtc_id, user_data); /* Add an event to the drm event queue */ EXPECT_EQ(1, write(write_drm_fd, "a", 1)); } } TEST_F(KMSPageFlipperTest, threads_concurrent_page_flips_dont_deadlock) { using namespace testing; std::vector const crtc_ids{10, 11, 12}; std::vector> page_flipping_functors; std::vector page_flipping_threads; PageFlipCounter counter; EXPECT_CALL(mock_drm, drmModePageFlip(mock_drm.fake_drm.fd(), _, _, _, _)) .WillRepeatedly(DoAll(WithArgs<1,4>(AddPageFlipEvent(&counter, mock_drm.fake_drm.write_fd())), Return(0))); EXPECT_CALL(mock_drm, drmHandleEvent(mock_drm.fake_drm.fd(), _)) .WillRepeatedly(DoAll(InvokePageFlipHandlerWithPendingData(&counter), Return(0))); /* Set up threads */ for (auto crtc_id : crtc_ids) { auto pf = std::unique_ptr(new PageFlippingFunctor{page_flipper, crtc_id}); page_flipping_functors.push_back(std::move(pf)); page_flipping_threads.push_back(std::thread{std::ref(*page_flipping_functors.back())}); } /* Wait for at least min_flips page-flips to be processed */ int const min_flips{100}; while (counter.count_flips() < min_flips) std::this_thread::sleep_for(std::chrono::milliseconds{1}); /* Tell the flippers to stop and wait for them to finish */ for (auto& pf : page_flipping_functors) pf->stop(); for (auto& pf_thread : page_flipping_threads) pf_thread.join(); /* Sanity checks */ EXPECT_EQ(counter.count_flips(), counter.count_handle_events()); EXPECT_TRUE(counter.no_consecutive_flips_for_same_crtc_id()); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_display_configuration.cpp0000644000015301777760000004322612322054247031056 0ustar pbusernogroup00000000000000/* * 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 */ #include #include "mir/graphics/display_configuration.h" #include "mir/graphics/display.h" #include "src/server/graphics/default_display_configuration_policy.h" #include "src/platform/graphics/mesa/platform.h" #include "src/platform/graphics/mesa/kms_display_configuration.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_gl.h" #include "src/server/report/null_report_factory.h" #include "mir_test_doubles/null_virtual_terminal.h" #include "mir_test_doubles/stub_gl_config.h" #include "mir_test_framework/udev_environment.h" #include "mir_test_doubles/mock_drm.h" #include "mir_test_doubles/mock_gbm.h" #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace geom = mir::geometry; namespace mr = mir::report; namespace mtd = mir::test::doubles; namespace mtf = mir::mir_test_framework; namespace { mg::DisplayConfigurationMode conf_mode_from_drm_mode(drmModeModeInfo const& mode) { geom::Size const size{mode.hdisplay, mode.vdisplay}; double vrefresh_hz{0.0}; /* Calculate vertical refresh rate from DRM mode information */ if (mode.htotal != 0.0 && mode.vtotal != 0.0) { vrefresh_hz = mode.clock * 1000.0 / (mode.htotal * mode.vtotal); vrefresh_hz = round(vrefresh_hz * 10.0) / 10.0; } return mg::DisplayConfigurationMode{size, vrefresh_hz}; } class MesaDisplayConfigurationTest : public ::testing::Test { public: MesaDisplayConfigurationTest() { using namespace testing; /* Needed for display start-up */ ON_CALL(mock_egl, eglChooseConfig(_,_,_,1,_)) .WillByDefault(DoAll(SetArgPointee<2>(mock_egl.fake_configs[0]), SetArgPointee<4>(1), Return(EGL_TRUE))); const char* egl_exts = "EGL_KHR_image EGL_KHR_image_base EGL_MESA_drm_image"; const char* gl_exts = "GL_OES_texture_npot GL_OES_EGL_image"; ON_CALL(mock_egl, eglQueryString(_,EGL_EXTENSIONS)) .WillByDefault(Return(egl_exts)); ON_CALL(mock_gl, glGetString(GL_EXTENSIONS)) .WillByDefault(Return(reinterpret_cast(gl_exts))); setup_sample_modes(); fake_devices.add_standard_device("standard-drm-devices"); } std::shared_ptr create_platform() { return std::make_shared( mr::null_display_report(), std::make_shared()); } std::shared_ptr create_display( std::shared_ptr const& platform) { return platform->create_display( std::make_shared(), std::make_shared()); } void setup_sample_modes() { using fake = mtd::FakeDRMResources; /* Add DRM modes */ modes0.push_back(fake::create_mode(1920, 1080, 138500, 2080, 1111, fake::NormalMode)); modes0.push_back(fake::create_mode(1920, 1080, 148500, 2200, 1125, fake::PreferredMode)); modes0.push_back(fake::create_mode(1680, 1050, 119000, 1840, 1080, fake::NormalMode)); modes0.push_back(fake::create_mode(832, 624, 57284, 1152, 667, fake::NormalMode)); /* Add the DisplayConfiguration modes corresponding to the DRM modes */ for (auto const& mode : modes0) conf_modes0.push_back(conf_mode_from_drm_mode(mode)); } ::testing::NiceMock mock_egl; ::testing::NiceMock mock_gl; ::testing::NiceMock mock_drm; ::testing::NiceMock mock_gbm; std::vector modes0; std::vector conf_modes0; std::vector modes_empty; mtf::UdevEnvironment fake_devices; }; } TEST_F(MesaDisplayConfigurationTest, configuration_is_read_correctly) { using namespace ::testing; /* Set up DRM resources */ uint32_t const invalid_id{0}; uint32_t const crtc0_id{10}; uint32_t const encoder0_id{20}; uint32_t const encoder1_id{21}; uint32_t const connector0_id{30}; uint32_t const connector1_id{31}; uint32_t const connector2_id{32}; geom::Size const connector0_physical_size_mm{480, 270}; geom::Size const connector1_physical_size_mm{}; geom::Size const connector2_physical_size_mm{}; std::vector possible_encoder_ids_empty; uint32_t const possible_crtcs_mask_empty{0}; size_t const max_simultaneous_outputs{1}; mtd::FakeDRMResources& resources(mock_drm.fake_drm); resources.reset(); resources.add_crtc(crtc0_id, modes0[1]); resources.add_encoder(encoder0_id, crtc0_id, possible_crtcs_mask_empty); resources.add_encoder(encoder1_id, invalid_id, possible_crtcs_mask_empty); resources.add_connector(connector0_id, DRM_MODE_CONNECTOR_HDMIA, DRM_MODE_CONNECTED, encoder0_id, modes0, possible_encoder_ids_empty, connector0_physical_size_mm); resources.add_connector(connector1_id, DRM_MODE_CONNECTOR_Unknown, DRM_MODE_DISCONNECTED, invalid_id, modes_empty, possible_encoder_ids_empty, connector1_physical_size_mm); resources.add_connector(connector2_id, DRM_MODE_CONNECTOR_eDP, DRM_MODE_DISCONNECTED, encoder1_id, modes_empty, possible_encoder_ids_empty, connector2_physical_size_mm); resources.prepare(); /* Expected results */ std::vector const expected_cards = { { mg::DisplayConfigurationCardId{0}, max_simultaneous_outputs } }; std::vector const expected_outputs = { { mg::DisplayConfigurationOutputId{connector0_id}, mg::DisplayConfigurationCardId{0}, mg::DisplayConfigurationOutputType::hdmia, {}, conf_modes0, 1, connector0_physical_size_mm, true, true, geom::Point(), 1, mir_pixel_format_invalid, mir_power_mode_on, mir_orientation_normal }, { mg::DisplayConfigurationOutputId{connector1_id}, mg::DisplayConfigurationCardId{0}, mg::DisplayConfigurationOutputType::unknown, {}, std::vector(), std::numeric_limits::max(), connector1_physical_size_mm, false, false, geom::Point(), std::numeric_limits::max(), mir_pixel_format_invalid, mir_power_mode_on, mir_orientation_normal }, { mg::DisplayConfigurationOutputId{connector2_id}, mg::DisplayConfigurationCardId{0}, mg::DisplayConfigurationOutputType::edp, {}, std::vector(), std::numeric_limits::max(), connector2_physical_size_mm, false, false, geom::Point(), std::numeric_limits::max(), mir_pixel_format_invalid, mir_power_mode_on, mir_orientation_normal } }; /* Test body */ auto display = create_display(create_platform()); auto conf = display->configuration(); size_t card_count{0}; conf->for_each_card([&](mg::DisplayConfigurationCard const& card) { ASSERT_LT(card_count, expected_cards.size()); EXPECT_EQ(expected_cards[card_count], card) << "card_count: " << card_count; ++card_count; }); size_t output_count{0}; conf->for_each_output([&](mg::DisplayConfigurationOutput const& output) { ASSERT_LT(output_count, expected_outputs.size()); EXPECT_EQ(expected_outputs[output_count], output) << "output_count: " << output_count; ++output_count; }); EXPECT_EQ(expected_outputs.size(), output_count); } TEST_F(MesaDisplayConfigurationTest, get_kms_connector_id_returns_correct_id) { uint32_t const crtc0_id{10}; uint32_t const encoder0_id{20}; uint32_t const possible_crtcs_mask_empty{0}; std::vector const connector_ids{30, 31}; std::vector encoder_ids{20}; /* Set up DRM resources */ mtd::FakeDRMResources& resources(mock_drm.fake_drm); resources.reset(); resources.add_crtc(crtc0_id, modes0[1]); resources.add_encoder(encoder0_id, crtc0_id, possible_crtcs_mask_empty); for (auto id : connector_ids) { resources.add_connector(id, DRM_MODE_CONNECTOR_DVID, DRM_MODE_CONNECTED, encoder0_id, modes0, encoder_ids, geom::Size()); } resources.prepare(); /* Test body */ auto display = create_display(create_platform()); std::shared_ptr conf = display->configuration(); auto const& kms_conf = std::static_pointer_cast(conf); size_t output_count{0}; conf->for_each_output([&](mg::DisplayConfigurationOutput const& output) { ASSERT_LT(output_count, connector_ids.size()); EXPECT_EQ(connector_ids[output_count], kms_conf->get_kms_connector_id(output.id)); ++output_count; }); } TEST_F(MesaDisplayConfigurationTest, get_kms_connector_id_throws_on_invalid_id) { uint32_t const crtc0_id{10}; uint32_t const encoder0_id{20}; uint32_t const possible_crtcs_mask_empty{0}; std::vector const connector_ids{30, 31}; std::vector encoder_ids{20}; /* Set up DRM resources */ mtd::FakeDRMResources& resources(mock_drm.fake_drm); resources.reset(); resources.add_crtc(crtc0_id, modes0[1]); resources.add_encoder(encoder0_id, crtc0_id, possible_crtcs_mask_empty); for (auto id : connector_ids) { resources.add_connector(id, DRM_MODE_CONNECTOR_VGA, DRM_MODE_CONNECTED, encoder0_id, modes0, encoder_ids, geom::Size()); } resources.prepare(); /* Test body */ auto display = create_display(create_platform()); std::shared_ptr conf = display->configuration(); auto const& kms_conf = std::static_pointer_cast(conf); EXPECT_THROW({ kms_conf->get_kms_connector_id(mg::DisplayConfigurationOutputId{29}); }, std::runtime_error); EXPECT_THROW({ kms_conf->get_kms_connector_id(mg::DisplayConfigurationOutputId{32}); }, std::runtime_error); } TEST_F(MesaDisplayConfigurationTest, returns_updated_configuration) { using namespace ::testing; uint32_t const invalid_id{0}; std::vector const crtc_ids{10, 11}; std::vector const encoder_ids{20, 21}; std::vector const connector_ids{30, 31}; std::vector const connector_physical_sizes_mm_before{ {480, 270}, {} }; std::vector const connector_physical_sizes_mm_after{ {}, {512, 642} }; std::vector possible_encoder_ids_empty; uint32_t const possible_crtcs_mask_empty{0}; size_t const max_simultaneous_outputs{1}; /* Expected results */ std::vector const expected_cards = { { mg::DisplayConfigurationCardId{0}, max_simultaneous_outputs } }; std::vector const expected_outputs_before = { { mg::DisplayConfigurationOutputId(connector_ids[0]), mg::DisplayConfigurationCardId{0}, mg::DisplayConfigurationOutputType::composite, {}, conf_modes0, 1, connector_physical_sizes_mm_before[0], true, true, geom::Point(), 1, mir_pixel_format_invalid, mir_power_mode_on, mir_orientation_normal }, { mg::DisplayConfigurationOutputId(connector_ids[1]), mg::DisplayConfigurationCardId{0}, mg::DisplayConfigurationOutputType::vga, {}, std::vector(), std::numeric_limits::max(), connector_physical_sizes_mm_before[1], false, false, geom::Point(), std::numeric_limits::max(), mir_pixel_format_invalid, mir_power_mode_on, mir_orientation_normal }, }; std::vector const expected_outputs_after = { { mg::DisplayConfigurationOutputId(connector_ids[0]), mg::DisplayConfigurationCardId{0}, mg::DisplayConfigurationOutputType::composite, {}, std::vector(), std::numeric_limits::max(), connector_physical_sizes_mm_after[0], false, true, geom::Point(), std::numeric_limits::max(), mir_pixel_format_invalid, mir_power_mode_on, mir_orientation_normal }, { mg::DisplayConfigurationOutputId(connector_ids[1]), mg::DisplayConfigurationCardId{0}, mg::DisplayConfigurationOutputType::vga, {}, conf_modes0, 1, connector_physical_sizes_mm_after[1], true, false, geom::Point(), 1, mir_pixel_format_invalid, mir_power_mode_on, mir_orientation_normal }, }; /* Set up DRM resources and check */ mtd::FakeDRMResources& resources(mock_drm.fake_drm); resources.reset(); resources.add_crtc(crtc_ids[0], modes0[1]); resources.add_encoder(encoder_ids[0], crtc_ids[0], possible_crtcs_mask_empty); resources.add_encoder(encoder_ids[1], invalid_id, possible_crtcs_mask_empty); resources.add_connector(connector_ids[0], DRM_MODE_CONNECTOR_Composite, DRM_MODE_CONNECTED, encoder_ids[0], modes0, possible_encoder_ids_empty, connector_physical_sizes_mm_before[0]); resources.add_connector(connector_ids[1], DRM_MODE_CONNECTOR_VGA, DRM_MODE_DISCONNECTED, invalid_id, modes_empty, possible_encoder_ids_empty, connector_physical_sizes_mm_before[1]); resources.prepare(); auto display = create_display(create_platform()); auto conf = display->configuration(); size_t card_count{0}; conf->for_each_card([&](mg::DisplayConfigurationCard const& card) { ASSERT_LT(card_count, expected_cards.size()); EXPECT_EQ(expected_cards[card_count], card) << "card_count: " << card_count; ++card_count; }); size_t output_count{0}; conf->for_each_output([&](mg::DisplayConfigurationOutput const& output) { ASSERT_LT(output_count, expected_outputs_before.size()); EXPECT_EQ(expected_outputs_before[output_count], output) << "output_count: " << output_count; ++output_count; }); EXPECT_EQ(expected_outputs_before.size(), output_count); /* Reset DRM resources and check again */ resources.reset(); resources.add_crtc(crtc_ids[1], modes0[1]); resources.add_encoder(encoder_ids[0], invalid_id, possible_crtcs_mask_empty); resources.add_encoder(encoder_ids[1], crtc_ids[1], possible_crtcs_mask_empty); resources.add_connector(connector_ids[0], DRM_MODE_CONNECTOR_Composite, DRM_MODE_DISCONNECTED, invalid_id, modes_empty, possible_encoder_ids_empty, connector_physical_sizes_mm_after[0]); resources.add_connector(connector_ids[1], DRM_MODE_CONNECTOR_VGA, DRM_MODE_CONNECTED, encoder_ids[1], modes0, possible_encoder_ids_empty, connector_physical_sizes_mm_after[1]); resources.prepare(); conf = display->configuration(); card_count = 0; conf->for_each_card([&](mg::DisplayConfigurationCard const& card) { ASSERT_LT(card_count, expected_cards.size()); EXPECT_EQ(expected_cards[card_count], card) << "card_count: " << card_count; ++card_count; }); output_count = 0; conf->for_each_output([&](mg::DisplayConfigurationOutput const& output) { ASSERT_LT(output_count, expected_outputs_after.size()); EXPECT_EQ(expected_outputs_after[output_count], output) << "output_count: " << output_count; ++output_count; }); EXPECT_EQ(expected_outputs_after.size(), output_count); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_native_platform.cpp0000644000015301777760000001034612322054223027643 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/nested_context.h" #include "src/platform/graphics/mesa/native_platform.h" #include "mir/graphics/buffer_properties.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_drm.h" #include "mir_test_doubles/mock_gbm.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/mock_buffer_packer.h" #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace geom = mir::geometry; namespace { struct MockNestedContext : public mg::NestedContext { MOCK_METHOD0(platform_fd_items, std::vector()); MOCK_METHOD1(drm_auth_magic, void(int)); MOCK_METHOD1(drm_set_gbm_device, void(struct gbm_device*)); }; class StubBuffer : public mtd::StubBuffer { public: StubBuffer() : mtd::StubBuffer{ mg::BufferProperties{ geom::Size{123, 456}, mir_pixel_format_abgr_8888, mg::BufferUsage::software}, geom::Stride{4390}}, native_buffer{std::make_shared()} { native_buffer->data_items = 4; native_buffer->fd_items = 2; for(auto i = 0; i < native_buffer->data_items; i++) native_buffer->data[i] = i; for(auto i = 0; i < native_buffer->fd_items; i++) native_buffer->fd[i] = i; native_buffer->width = buf_size.width.as_int(); native_buffer->height = buf_size.height.as_int(); native_buffer->flags = 0x66; native_buffer->stride = buf_stride.as_int(); } std::shared_ptr native_buffer_handle() const override { return native_buffer; } private: std::shared_ptr native_buffer; }; class MesaNativePlatformTest : public ::testing::Test { public: MesaNativePlatformTest() { using namespace testing; ON_CALL(mock_nested_context, platform_fd_items()) .WillByDefault(Return(std::vector{mock_drm.fake_drm.fd()})); } protected: ::testing::NiceMock mock_drm; ::testing::NiceMock mock_gbm; ::testing::NiceMock mock_nested_context; }; } TEST_F(MesaNativePlatformTest, auth_magic_is_delegated_to_nested_context) { using namespace testing; mgm::NativePlatform native; EXPECT_CALL(mock_nested_context, drm_auth_magic(_)); native.initialize(mt::fake_shared(mock_nested_context)); native.get_ipc_package(); } TEST_F(MesaNativePlatformTest, sets_gbm_device_during_initialization) { using namespace testing; mgm::NativePlatform native; EXPECT_CALL(mock_nested_context, drm_set_gbm_device(mock_gbm.fake_gbm.device)); native.initialize(mt::fake_shared(mock_nested_context)); } TEST_F(MesaNativePlatformTest, packs_buffer_ipc_package_correctly) { using namespace testing; StubBuffer const stub_buffer; mtd::MockPacker mock_packer; auto const native_buffer = stub_buffer.native_buffer_handle(); for(auto i = 0; i < native_buffer->fd_items; i++) EXPECT_CALL(mock_packer, pack_fd(native_buffer->fd[i])); for(auto i = 0; i < native_buffer->data_items; i++) EXPECT_CALL(mock_packer, pack_data(native_buffer->data[i])); EXPECT_CALL(mock_packer, pack_stride(stub_buffer.stride())); EXPECT_CALL(mock_packer, pack_flags(native_buffer->flags)); EXPECT_CALL(mock_packer, pack_size(stub_buffer.size())); mgm::NativePlatform native; native.fill_ipc_package(&mock_packer, &stub_buffer); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_anonymous_shm_file.cpp0000644000015301777760000001453612322054223030354 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/mesa/anonymous_shm_file.h" #include #include #include #include #include #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace { class TemporaryEnvironmentValue { public: TemporaryEnvironmentValue(char const* name, char const* value) : name{name}, has_old_value{getenv(name) != nullptr}, old_value{has_old_value ? getenv(name) : ""} { if (value) setenv(name, value, overwrite); else unsetenv(name); } ~TemporaryEnvironmentValue() { if (has_old_value) setenv(name.c_str(), old_value.c_str(), overwrite); else unsetenv(name.c_str()); } private: static int const overwrite = 1; std::string const name; bool const has_old_value; std::string const old_value; }; class TemporaryDirectory { public: TemporaryDirectory() { char tmpl[] = "/tmp/mir-test-dir-XXXXXX"; if (mkdtemp(tmpl) == nullptr) { BOOST_THROW_EXCEPTION( std::runtime_error("Couldn't create temporary test directory")); } path_ = tmpl; } ~TemporaryDirectory() { rmdir(path()); } char const* path() const { return path_.c_str(); } private: std::string path_; }; class PathWatcher { public: PathWatcher(const char* path) : inotify_fd{inotify_init1(IN_NONBLOCK)}, watch_fd{inotify_add_watch(inotify_fd, path, IN_CREATE | IN_DELETE)} { /* TODO: RAII fd */ if (inotify_fd < 0) { BOOST_THROW_EXCEPTION( std::runtime_error("Couldn't create inotify fd")); } if (watch_fd < 0) { close(inotify_fd); BOOST_THROW_EXCEPTION( std::runtime_error("Couldn't create watch fd")); } } ~PathWatcher() { inotify_rm_watch(inotify_fd, watch_fd); close(inotify_fd); } void process_events() const { while (process_events_step()) continue; } MOCK_CONST_METHOD1(file_created, void(char const*)); MOCK_CONST_METHOD1(file_deleted, void(char const*)); private: bool process_events_step() const { size_t const max_path_size = 1024; size_t const buffer_size = sizeof(struct inotify_event) + max_path_size; uint8_t buffer[buffer_size]; auto nread = read(inotify_fd, buffer, buffer_size); if (nread < 0) { if (errno == EWOULDBLOCK) { return false; } else { BOOST_THROW_EXCEPTION( std::runtime_error("Couldn't read from inotify fd")); } } ssize_t i = 0; while (i < nread) { auto event = reinterpret_cast(&buffer[i]); if (event->len) { if (event->mask & IN_CREATE) { file_created(event->name); } if (event->mask & IN_DELETE) { file_deleted(event->name); } } i += sizeof(struct inotify_event) + event->len; } return true; } int const inotify_fd; int const watch_fd; }; } TEST(AnonymousShmFile, is_created_and_deleted_in_xdg_runtime_dir) { using namespace testing; TemporaryDirectory const temp_dir; TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()}; PathWatcher const path_watcher{temp_dir.path()}; size_t const file_size{100}; InSequence s; EXPECT_CALL(path_watcher, file_created(StartsWith("mir-buffer-"))); EXPECT_CALL(path_watcher, file_deleted(StartsWith("mir-buffer-"))); mgm::AnonymousShmFile shm_file{file_size}; path_watcher.process_events(); } TEST(AnonymousShmFile, is_created_and_deleted_in_tmp_dir) { using namespace testing; TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", nullptr}; PathWatcher const path_watcher{"/tmp"}; size_t const file_size{100}; InSequence s; EXPECT_CALL(path_watcher, file_created(StartsWith("mir-buffer-"))); EXPECT_CALL(path_watcher, file_deleted(StartsWith("mir-buffer-"))); mgm::AnonymousShmFile shm_file{file_size}; path_watcher.process_events(); } TEST(AnonymousShmFile, has_correct_size) { using namespace testing; TemporaryDirectory const temp_dir; TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()}; size_t const file_size{100}; mgm::AnonymousShmFile shm_file{file_size}; struct stat stat; fstat(shm_file.fd(), &stat); EXPECT_EQ(static_cast(file_size), stat.st_size); } TEST(AnonymousShmFile, writing_to_base_ptr_writes_to_file) { using namespace testing; TemporaryDirectory const temp_dir; TemporaryEnvironmentValue const env{"XDG_RUNTIME_DIR", temp_dir.path()}; size_t const file_size{100}; mgm::AnonymousShmFile shm_file{file_size}; auto base_ptr = reinterpret_cast(shm_file.base_ptr()); for (size_t i = 0; i < file_size; i++) { base_ptr[i] = i; } std::vector buffer(file_size); EXPECT_EQ(static_cast(file_size), read(shm_file.fd(), buffer.data(), file_size)); for (size_t i = 0; i < file_size; i++) { EXPECT_EQ(base_ptr[i], buffer[i]) << "i=" << i; } } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_internal_native_display.cpp0000644000015301777760000000461212322054247031365 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/mesa/internal_native_display.h" #include "mir/graphics/platform.h" #include "mir/graphics/platform_ipc_package.h" #include "mir_toolkit/mesa/native_display.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_buffer.h" #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mt::doubles; namespace { struct InternalNativeDisplay : public testing::Test { void SetUp() { using namespace ::testing; platform_package = std::make_shared(); platform_package->ipc_data = {1, 2}; platform_package->ipc_fds = {2, 3}; } std::shared_ptr platform_package; }; MATCHER_P(PackageMatches, package, "") { if (arg.data_items != static_cast(package->ipc_data.size())) return false; for (uint i = 0; i < package->ipc_data.size(); i++) { if (arg.data[i] != package->ipc_data[i]) return false; } if (arg.fd_items != static_cast(package->ipc_fds.size())) return false; for (uint i = 0; i < package->ipc_fds.size(); i++) { if (arg.fd[i] != package->ipc_fds[i]) return false; } return true; } } TEST_F(InternalNativeDisplay, display_get_platform_matches_construction_platform) { using namespace ::testing; mgm::InternalNativeDisplay native_display(platform_package); MirPlatformPackage test_package; memset(&test_package, 0, sizeof(MirPlatformPackage)); native_display.display_get_platform(&native_display, &test_package); EXPECT_THAT(test_package, PackageMatches(platform_package)); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/internal_client.h0000644000015301777760000000000012322054223026213 0ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_shm_buffer.cpp0000644000015301777760000000605212322054223026570 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/mesa/shm_buffer.h" #include "src/platform/graphics/mesa/shm_file.h" #include "mir_test_doubles/mock_gl.h" #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace mtd = mir::test::doubles; namespace geom = mir::geometry; namespace { struct StubShmFile : public mgm::ShmFile { void* base_ptr() const { return fake_mapping; } int fd() const { return fake_fd; } void* const fake_mapping = reinterpret_cast(0x12345678); int const fake_fd = 17; }; struct ShmBufferTest : public testing::Test { ShmBufferTest() : size{150,340}, pixel_format{mir_pixel_format_bgr_888}, stub_shm_file{std::make_shared()}, shm_buffer{stub_shm_file, size, pixel_format} { } geom::Size const size; MirPixelFormat const pixel_format; std::shared_ptr const stub_shm_file; mgm::ShmBuffer shm_buffer; testing::NiceMock mock_gl; }; } TEST_F(ShmBufferTest, has_correct_properties) { size_t const bytes_per_pixel = MIR_BYTES_PER_PIXEL(pixel_format); size_t const expected_stride{bytes_per_pixel * size.width.as_uint32_t()}; EXPECT_EQ(size, shm_buffer.size()); EXPECT_EQ(geom::Stride{expected_stride}, shm_buffer.stride()); EXPECT_EQ(pixel_format, shm_buffer.pixel_format()); } TEST_F(ShmBufferTest, native_buffer_contains_correct_data) { size_t const bytes_per_pixel = MIR_BYTES_PER_PIXEL(pixel_format); size_t const expected_stride{bytes_per_pixel * size.width.as_uint32_t()}; auto native_buffer = shm_buffer.native_buffer_handle(); EXPECT_EQ(1, native_buffer->fd_items); EXPECT_EQ(stub_shm_file->fake_fd, native_buffer->fd[0]); EXPECT_EQ(size.width.as_int(), native_buffer->width); EXPECT_EQ(size.height.as_int(), native_buffer->height); EXPECT_EQ(expected_stride, static_cast(native_buffer->stride)); } TEST_F(ShmBufferTest, cannot_be_used_for_bypass) { EXPECT_FALSE(shm_buffer.can_bypass()); } TEST_F(ShmBufferTest, uploads_pixels_to_texture) { using namespace testing; EXPECT_CALL(mock_gl, glTexImage2D(GL_TEXTURE_2D, 0, _, size.width.as_int(), size.height.as_int(), 0, _, _, stub_shm_file->fake_mapping)); shm_buffer.bind_to_texture(); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/CMakeLists.txt0000644000015301777760000000217312322054223025445 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_platform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_gbm_buffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_allocator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_display.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_display_buffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_display_multi_monitor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_display_configuration.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_internal_client.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_real_kms_output.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_kms_page_flipper.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_linux_virtual_terminal.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_internal_native_display.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_internal_native_surface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_overlapping_output_grouping.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_cursor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_native_platform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_anonymous_shm_file.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_shm_buffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_drm_helper.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/mock_kms_output.h0000644000015301777760000000304212322054223026275 0ustar pbusernogroup00000000000000/* * 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 MOCK_KMS_OUTPUT_H_ #define MOCK_KMS_OUTPUT_H_ #include "src/platform/graphics/mesa/kms_output.h" #include namespace mir { namespace test { struct MockKMSOutput : public graphics::mesa::KMSOutput { MOCK_METHOD0(reset, void()); MOCK_METHOD2(configure, void(geometry::Displacement, size_t)); MOCK_CONST_METHOD0(size, geometry::Size()); MOCK_METHOD1(set_crtc, bool(uint32_t)); MOCK_METHOD0(clear_crtc, void()); MOCK_METHOD1(schedule_page_flip, bool(uint32_t)); MOCK_METHOD0(wait_for_page_flip, void()); MOCK_METHOD1(set_cursor, void(gbm_bo*)); MOCK_METHOD1(move_cursor, void(geometry::Point)); MOCK_METHOD0(clear_cursor, void()); MOCK_CONST_METHOD0(has_cursor, bool()); MOCK_METHOD1(set_power_mode, void(MirPowerMode)); }; } // namespace test } // namespace mir #endif // MOCK_KMS_OUTPUT_H_ mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_overlapping_output_grouping.cpp0000644000015301777760000002056312322054223032333 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/overlapping_output_grouping.h" #include "mir/graphics/display_configuration.h" #include "mir/geometry/rectangle.h" #include "mir/geometry/rectangles.h" #include #include #include namespace mg = mir::graphics; namespace geom = mir::geometry; namespace { class StubDisplayConfiguration : public mg::DisplayConfiguration { public: struct OutputInfo { geom::Rectangle rect; bool connected; bool used; MirOrientation orientation; }; StubDisplayConfiguration(std::vector const& info) : outputs{info} { } void for_each_card(std::function f) const { mg::DisplayConfigurationCard card { mg::DisplayConfigurationCardId{1}, outputs.size() }; f(card); } void for_each_output(std::function f) const { size_t i = 1; for (auto const& info : outputs) { std::vector modes(i); modes[i - 1] = {info.rect.size, 59.9}; mg::DisplayConfigurationOutput output { mg::DisplayConfigurationOutputId(i), mg::DisplayConfigurationCardId{1}, mg::DisplayConfigurationOutputType::svideo, {}, modes, i - 1, {100, 100}, info.connected, info.used, info.rect.top_left, i - 1, mir_pixel_format_invalid, mir_power_mode_on, info.orientation }; f(output); i++; } } void for_each_output(std::function) override { } std::vector outputs; }; class OverlappingOutputGroupingTest : public testing::Test { public: void check_groupings(std::vector const& info, std::vector const& expected_groups) { StubDisplayConfiguration conf{info}; mg::OverlappingOutputGrouping grouping{conf}; std::vector> grouping_results; grouping.for_each_group( [&](mg::OverlappingOutputGroup const& group) { std::vector outputs; group.for_each_output([&](mg::DisplayConfigurationOutput const& output) { outputs.push_back(output); }); grouping_results.push_back(outputs); }); auto expected_groups_copy = expected_groups; EXPECT_EQ(expected_groups.size(), grouping_results.size()); for (auto const& v : grouping_results) { geom::Rectangles rects; for (auto const& output : v) rects.add(output.extents()); auto iter = std::find(expected_groups_copy.begin(), expected_groups_copy.end(), rects); EXPECT_TRUE(iter != expected_groups_copy.end()) << "Failed to find " << rects; expected_groups_copy.erase(iter); } } }; } TEST_F(OverlappingOutputGroupingTest, ignores_invalid_outputs) { std::vector info { {{{0,0}, {100, 100}}, false, false, mir_orientation_normal}, {{{0,0}, {100, 100}}, true, false, mir_orientation_normal}, {{{0,0}, {100, 100}}, false, true, mir_orientation_normal} }; std::vector expected_groups; check_groupings(info, expected_groups); } TEST_F(OverlappingOutputGroupingTest, distinct_outputs) { std::vector info { {{{0,0}, {100, 100}}, true, true, mir_orientation_normal}, {{{100,0}, {100, 100}}, true, true, mir_orientation_normal}, {{{0,100}, {100, 100}}, true, true, mir_orientation_normal} }; std::vector expected_groups { geom::Rectangles{{{0,0}, {100, 100}}}, geom::Rectangles{{{100,0}, {100, 100}}}, geom::Rectangles{{{0,100}, {100, 100}}}, }; check_groupings(info, expected_groups); } TEST_F(OverlappingOutputGroupingTest, rotated_output) { std::vector info { {{{0,0}, {100,200}}, true, true, mir_orientation_left}, }; std::vector expected_groups { geom::Rectangles{{{0,0}, {200,100}}}, }; check_groupings(info, expected_groups); } TEST_F(OverlappingOutputGroupingTest, rotated_outputs) { std::vector info { {{{0,0}, {100,200}}, true, true, mir_orientation_normal}, {{{1000,0}, {300,400}}, true, true, mir_orientation_left}, {{{2000,0}, {500,600}}, true, true, mir_orientation_right}, {{{3000,0}, {700,800}}, true, true, mir_orientation_inverted}, }; std::vector expected_groups { geom::Rectangles{{{0,0}, {100,200}}}, geom::Rectangles{{{1000,0}, {400,300}}}, geom::Rectangles{{{2000,0}, {600,500}}}, geom::Rectangles{{{3000,0}, {700,800}}}, }; check_groupings(info, expected_groups); } TEST_F(OverlappingOutputGroupingTest, rotation_creates_overlap) { std::vector info { {{{0,0}, {100,200}}, true, true, mir_orientation_left}, {{{100,0}, {100,200}}, true, true, mir_orientation_left}, }; std::vector expected_groups { geom::Rectangles{ {{0,0}, {200,100}}, {{100,0}, {200,100}} } }; check_groupings(info, expected_groups); } TEST_F(OverlappingOutputGroupingTest, different_orientation_prevents_grouping) { std::vector info { {{{0,0}, {100,200}}, true, true, mir_orientation_left}, {{{100,0}, {100,200}}, true, true, mir_orientation_normal}, }; std::vector expected_groups { geom::Rectangles{ {{0,0}, {200,100}} }, geom::Rectangles{ {{100,0}, {100,200}} }, }; check_groupings(info, expected_groups); } TEST_F(OverlappingOutputGroupingTest, overlapping_outputs) { std::vector info { {{{0,0}, {100, 100}}, true, true, mir_orientation_normal}, {{{0,0}, {50, 50}}, true, true, mir_orientation_normal}, {{{100,0}, {100, 100}}, true, true, mir_orientation_normal}, {{{101,0}, {100, 100}}, true, true, mir_orientation_normal} }; std::vector expected_groups { geom::Rectangles { {{0,0}, {100, 100}}, {{0,0}, {50, 50}} }, geom::Rectangles { {{100,0}, {100, 100}}, {{101,0}, {100, 100}} } }; check_groupings(info, expected_groups); } TEST_F(OverlappingOutputGroupingTest, multiply_overlapping_outputs) { std::vector info { {{{0,0}, {100, 100}}, true, true, mir_orientation_normal}, {{{150,150}, {50, 50}}, true, true, mir_orientation_normal}, {{{90,90}, {85, 85}}, true, true, mir_orientation_normal}, {{{50,50}, {100, 100}}, true, true, mir_orientation_normal} }; std::vector expected_groups { geom::Rectangles { {{0,0}, {100, 100}}, {{150,150}, {50, 50}}, {{90,90}, {85, 85}}, {{50,50}, {100, 100}} }, }; check_groupings(info, expected_groups); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_cursor.cpp0000644000015301777760000003175412322054223025774 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/mesa/cursor.h" #include "src/platform/graphics/mesa/kms_output.h" #include "src/platform/graphics/mesa/kms_output_container.h" #include "src/platform/graphics/mesa/kms_display_configuration.h" #include "mir_test_doubles/mock_gbm.h" #include "mir_test/fake_shared.h" #include "mock_kms_output.h" #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; using mir::test::MockKMSOutput; namespace { struct StubKMSOutputContainer : public mgm::KMSOutputContainer { StubKMSOutputContainer() : outputs{ {10, std::make_shared>()}, {11, std::make_shared>()}, {12, std::make_shared>()}} { } std::shared_ptr get_kms_output_for(uint32_t connector_id) { return outputs[connector_id]; } void for_each_output(std::function functor) const { for (auto const& pair : outputs) functor(*pair.second); } void verify_and_clear_expectations() { for (auto const& pair : outputs) ::testing::Mock::VerifyAndClearExpectations(pair.second.get()); } std::unordered_map>> outputs; }; struct StubKMSDisplayConfiguration : public mgm::KMSDisplayConfiguration { StubKMSDisplayConfiguration() : card_id{1} { outputs.push_back( { mg::DisplayConfigurationOutputId{10}, card_id, mg::DisplayConfigurationOutputType::vga, {}, { {geom::Size{10, 20}, 59.9}, {geom::Size{200, 100}, 59.9}, }, 1, geom::Size{324, 642}, true, true, geom::Point{0, 0}, 1, mir_pixel_format_invalid, mir_power_mode_on, mir_orientation_normal }); outputs.push_back( { mg::DisplayConfigurationOutputId{11}, card_id, mg::DisplayConfigurationOutputType::vga, {}, { {geom::Size{200, 200}, 59.9}, {geom::Size{100, 200}, 59.9}, }, 0, geom::Size{566, 111}, true, true, geom::Point{100, 50}, 0, mir_pixel_format_invalid, mir_power_mode_on, mir_orientation_normal }); outputs.push_back( { mg::DisplayConfigurationOutputId{12}, card_id, mg::DisplayConfigurationOutputType::vga, {}, { {geom::Size{800, 200}, 59.9}, {geom::Size{100, 200}, 59.9}, }, 0, geom::Size{800, 200}, true, true, geom::Point{666, 0}, 0, mir_pixel_format_invalid, mir_power_mode_on, mir_orientation_right }); } void for_each_card(std::function f) const override { f({card_id, outputs.size()}); } void for_each_output(std::function f) const override { for (auto const& output : outputs) f(output); } void for_each_output(std::function f) override { for (auto& output : outputs) { mg::UserDisplayConfigurationOutput user(output); f(user); } } uint32_t get_kms_connector_id(mg::DisplayConfigurationOutputId id) const override { return id.as_value(); } size_t get_kms_mode_index(mg::DisplayConfigurationOutputId, size_t conf_mode_index) const override { return conf_mode_index; } void update() { } void set_orentation_of_output(mg::DisplayConfigurationOutputId id, MirOrientation orientation) { auto output = std::find_if(outputs.begin(), outputs.end(), [id] (mg::DisplayConfigurationOutput const& output) -> bool {return output.id == id;}); if (output != outputs.end()) { output->orientation = orientation; } } mg::DisplayConfigurationCardId card_id; std::vector outputs; }; struct StubCurrentConfiguration : public mgm::CurrentConfiguration { void with_current_configuration_do( std::function const& exec) { exec(conf); } StubKMSDisplayConfiguration conf; }; struct MesaCursorTest : public ::testing::Test { MesaCursorTest() : cursor{mock_gbm.fake_gbm.device, output_container, mir::test::fake_shared(current_configuration)} { } StubCurrentConfiguration current_configuration; testing::NiceMock mock_gbm; StubKMSOutputContainer output_container; mgm::Cursor cursor; }; } TEST_F(MesaCursorTest, creates_cursor_bo_image) { size_t const cursor_side{64}; EXPECT_CALL(mock_gbm, gbm_bo_create(mock_gbm.fake_gbm.device, cursor_side, cursor_side, GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE)); mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container, std::make_shared()}; } TEST_F(MesaCursorTest, set_cursor_writes_to_bo) { using namespace testing; void* const image{reinterpret_cast(0x5678)}; size_t const cursor_side{64}; geom::Size const cursor_size{cursor_side, cursor_side}; size_t const cursor_size_bytes{cursor_side * cursor_side * sizeof(uint32_t)}; EXPECT_CALL(mock_gbm, gbm_bo_write(mock_gbm.fake_gbm.bo, image, cursor_size_bytes)); cursor.set_image(image, cursor_size); } TEST_F(MesaCursorTest, set_cursor_throws_on_incorrect_size) { using namespace testing; void* const image{reinterpret_cast(0x5678)}; size_t const cursor_side{48}; geom::Size const cursor_size{cursor_side, cursor_side}; EXPECT_THROW( cursor.set_image(image, cursor_size); , std::logic_error); } TEST_F(MesaCursorTest, forces_cursor_state_on_construction) { using namespace testing; EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{0,0})); EXPECT_CALL(*output_container.outputs[10], set_cursor(_)); EXPECT_CALL(*output_container.outputs[11], clear_cursor()); EXPECT_CALL(*output_container.outputs[12], clear_cursor()); /* No checking of existing cursor state */ EXPECT_CALL(*output_container.outputs[10], has_cursor()).Times(0); EXPECT_CALL(*output_container.outputs[11], has_cursor()).Times(0); EXPECT_CALL(*output_container.outputs[12], has_cursor()).Times(0); mgm::Cursor cursor_tmp{mock_gbm.fake_gbm.device, output_container, std::make_shared()}; output_container.verify_and_clear_expectations(); } TEST_F(MesaCursorTest, move_to_sets_clears_cursor_if_needed) { using namespace testing; EXPECT_CALL(*output_container.outputs[10], has_cursor()) .WillOnce(Return(false)); EXPECT_CALL(*output_container.outputs[10], set_cursor(_)); EXPECT_CALL(*output_container.outputs[11], has_cursor()) .WillOnce(Return(true)); EXPECT_CALL(*output_container.outputs[11], clear_cursor()); cursor.move_to({10, 10}); output_container.verify_and_clear_expectations(); } TEST_F(MesaCursorTest, move_to_doesnt_set_clear_cursor_if_not_needed) { using namespace testing; EXPECT_CALL(*output_container.outputs[10], has_cursor()) .WillOnce(Return(true)); EXPECT_CALL(*output_container.outputs[10], set_cursor(_)) .Times(0); EXPECT_CALL(*output_container.outputs[11], has_cursor()) .WillOnce(Return(false)); EXPECT_CALL(*output_container.outputs[11], clear_cursor()) .Times(0); cursor.move_to({10, 10}); output_container.verify_and_clear_expectations(); } TEST_F(MesaCursorTest, move_to_moves_cursor_to_right_output) { using namespace testing; EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{10,10})); EXPECT_CALL(*output_container.outputs[11], move_cursor(_)) .Times(0); cursor.move_to({10, 10}); output_container.verify_and_clear_expectations(); EXPECT_CALL(*output_container.outputs[10], move_cursor(_)) .Times(0); EXPECT_CALL(*output_container.outputs[11], move_cursor(geom::Point{50,100})); cursor.move_to({150, 150}); output_container.verify_and_clear_expectations(); EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{150,75})); EXPECT_CALL(*output_container.outputs[11], move_cursor(geom::Point{50,25})); cursor.move_to({150, 75}); output_container.verify_and_clear_expectations(); EXPECT_CALL(*output_container.outputs[10], move_cursor(_)) .Times(0); EXPECT_CALL(*output_container.outputs[11], move_cursor(_)) .Times(0); cursor.move_to({-1, -1}); output_container.verify_and_clear_expectations(); } TEST_F(MesaCursorTest, shows_at_last_known_position) { using namespace testing; EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{150,75})); EXPECT_CALL(*output_container.outputs[11], move_cursor(geom::Point{50,25})); cursor.move_to({150, 75}); output_container.verify_and_clear_expectations(); EXPECT_CALL(*output_container.outputs[10], move_cursor(geom::Point{150,75})); EXPECT_CALL(*output_container.outputs[11], move_cursor(geom::Point{50,25})); cursor.show_at_last_known_position(); output_container.verify_and_clear_expectations(); } TEST_F(MesaCursorTest, moves_properly_to_and_inside_left_rotated_output) { using namespace testing; current_configuration.conf.set_orentation_of_output(mg::DisplayConfigurationOutputId{12}, mir_orientation_left); EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{112,100})); EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{150,96})); cursor.move_to({766, 112}); cursor.move_to({770, 150}); output_container.verify_and_clear_expectations(); } TEST_F(MesaCursorTest, moves_properly_to_and_inside_right_rotated_output) { using namespace testing; current_configuration.conf.set_orentation_of_output(mg::DisplayConfigurationOutputId{12}, mir_orientation_right); EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{688,100})); EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{650,104})); cursor.move_to({766, 112}); cursor.move_to({770, 150}); output_container.verify_and_clear_expectations(); } TEST_F(MesaCursorTest, moves_properly_to_and_inside_inverted_output) { using namespace testing; current_configuration.conf.set_orentation_of_output(mg::DisplayConfigurationOutputId{12}, mir_orientation_inverted); EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{700,88})); EXPECT_CALL(*output_container.outputs[12], move_cursor(geom::Point{696,50})); cursor.move_to({766, 112}); cursor.move_to({770, 150}); output_container.verify_and_clear_expectations(); } TEST_F(MesaCursorTest, hides_cursor_in_all_outputs) { using namespace testing; EXPECT_CALL(*output_container.outputs[10], clear_cursor()); EXPECT_CALL(*output_container.outputs[11], clear_cursor()); EXPECT_CALL(*output_container.outputs[12], clear_cursor()); cursor.hide(); output_container.verify_and_clear_expectations(); } TEST_F(MesaCursorTest, clears_cursor_on_exit) { using namespace testing; EXPECT_CALL(*output_container.outputs[10], clear_cursor()); EXPECT_CALL(*output_container.outputs[11], clear_cursor()); EXPECT_CALL(*output_container.outputs[12], clear_cursor()); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_display_buffer.cpp0000644000015301777760000002147612322054247027463 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/platform/graphics/mesa/platform.h" #include "src/platform/graphics/mesa/display_buffer.h" #include "src/server/report/null_report_factory.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_gl.h" #include "mir_test_doubles/null_platform.h" #include "mir_test_doubles/null_virtual_terminal.h" #include "mir_test_doubles/mock_drm.h" #include "mir_test_doubles/mock_gbm.h" #include "mir_test_doubles/stub_gl_config.h" #include "mir_test_framework/udev_environment.h" #include "mock_kms_output.h" #include #include #include using namespace testing; using namespace mir; using namespace std; using namespace mir::test; using namespace mir::test::doubles; using namespace mir::mir_test_framework; using namespace mir::graphics; using mir::report::null_display_report; class MesaDisplayBufferTest : public Test { public: MesaDisplayBufferTest() { ON_CALL(mock_egl, eglChooseConfig(_,_,_,1,_)) .WillByDefault(DoAll(SetArgPointee<2>(mock_egl.fake_configs[0]), SetArgPointee<4>(1), Return(EGL_TRUE))); ON_CALL(mock_egl, eglQueryString(_,EGL_EXTENSIONS)) .WillByDefault(Return("EGL_KHR_image " "EGL_KHR_image_base " "EGL_MESA_drm_image")); ON_CALL(mock_gl, glGetString(GL_EXTENSIONS)) .WillByDefault(Return(reinterpret_cast( "GL_OES_texture_npot " "GL_OES_EGL_image"))); fake_bo = reinterpret_cast(123); ON_CALL(mock_gbm, gbm_surface_lock_front_buffer(_)) .WillByDefault(Return(fake_bo)); fake_handle.u32 = 123; ON_CALL(mock_gbm, gbm_bo_get_handle(_)) .WillByDefault(Return(fake_handle)); ON_CALL(mock_gbm, gbm_bo_get_stride(_)) .WillByDefault(Return(456)); fake_devices.add_standard_device("standard-drm-devices"); mock_kms_output = std::make_shared>(); ON_CALL(*mock_kms_output, set_crtc(_)) .WillByDefault(Return(true)); ON_CALL(*mock_kms_output, schedule_page_flip(_)) .WillByDefault(Return(true)); } // The platform has an implicit dependency on mock_gbm etc so must be // reconstructed locally to ensure its lifetime is shorter than mock_gbm. shared_ptr create_platform() { return make_shared( null_display_report(), make_shared()); } protected: NiceMock mock_gbm; NiceMock mock_egl; NiceMock mock_gl; NiceMock mock_drm; gbm_bo* fake_bo; gbm_bo_handle fake_handle; UdevEnvironment fake_devices; std::shared_ptr mock_kms_output; StubGLConfig gl_config; }; TEST_F(MesaDisplayBufferTest, unrotated_view_area_is_untouched) { geometry::Rectangle const area{{12,34}, {56,78}}; graphics::mesa::DisplayBuffer db( create_platform(), null_display_report(), {}, nullptr, area, mir_orientation_normal, gl_config, mock_egl.fake_egl_context); EXPECT_EQ(area, db.view_area()); } TEST_F(MesaDisplayBufferTest, normal_orientation_can_bypass) { geometry::Rectangle const area{{12,34}, {56,78}}; graphics::mesa::DisplayBuffer db( create_platform(), null_display_report(), {}, nullptr, area, mir_orientation_normal, gl_config, mock_egl.fake_egl_context); EXPECT_TRUE(db.can_bypass()); } TEST_F(MesaDisplayBufferTest, rotated_cannot_bypass) { geometry::Rectangle const area{{12,34}, {56,78}}; graphics::mesa::DisplayBuffer db( create_platform(), null_display_report(), {}, nullptr, area, mir_orientation_right, gl_config, mock_egl.fake_egl_context); EXPECT_FALSE(db.can_bypass()); } TEST_F(MesaDisplayBufferTest, orientation_not_implemented_internally) { geometry::Rectangle const area{{12,34}, {56,78}}; graphics::mesa::DisplayBuffer db( create_platform(), null_display_report(), {}, nullptr, area, mir_orientation_left, gl_config, mock_egl.fake_egl_context); EXPECT_EQ(mir_orientation_left, db.orientation()); } TEST_F(MesaDisplayBufferTest, normal_rotation_constructs_normal_fb) { int const width = 56; int const height = 78; geometry::Rectangle const area{{12,34}, {width,height}}; EXPECT_CALL(mock_gbm, gbm_bo_get_user_data(_)) .WillOnce(Return((void*)0)); EXPECT_CALL(mock_drm, drmModeAddFB(_, width, height, _, _, _, _, _)) .Times(1); graphics::mesa::DisplayBuffer db( create_platform(), null_display_report(), {}, nullptr, area, mir_orientation_normal, gl_config, mock_egl.fake_egl_context); } TEST_F(MesaDisplayBufferTest, left_rotation_constructs_transposed_fb) { int const width = 56; int const height = 78; geometry::Rectangle const area{{12,34}, {width,height}}; EXPECT_CALL(mock_gbm, gbm_bo_get_user_data(_)) .WillOnce(Return((void*)0)); EXPECT_CALL(mock_drm, drmModeAddFB(_, height, width, _, _, _, _, _)) .Times(1); graphics::mesa::DisplayBuffer db( create_platform(), null_display_report(), {}, nullptr, area, mir_orientation_left, gl_config, mock_egl.fake_egl_context); } TEST_F(MesaDisplayBufferTest, inverted_rotation_constructs_normal_fb) { int const width = 56; int const height = 78; geometry::Rectangle const area{{12,34}, {width,height}}; EXPECT_CALL(mock_gbm, gbm_bo_get_user_data(_)) .WillOnce(Return((void*)0)); EXPECT_CALL(mock_drm, drmModeAddFB(_, width, height, _, _, _, _, _)) .Times(1); graphics::mesa::DisplayBuffer db( create_platform(), null_display_report(), {}, nullptr, area, mir_orientation_inverted, gl_config, mock_egl.fake_egl_context); } TEST_F(MesaDisplayBufferTest, right_rotation_constructs_transposed_fb) { int const width = 56; int const height = 78; geometry::Rectangle const area{{12,34}, {width,height}}; EXPECT_CALL(mock_gbm, gbm_bo_get_user_data(_)) .WillOnce(Return((void*)0)); EXPECT_CALL(mock_drm, drmModeAddFB(_, height, width, _, _, _, _, _)) .Times(1); graphics::mesa::DisplayBuffer db( create_platform(), null_display_report(), {}, nullptr, area, mir_orientation_right, gl_config, mock_egl.fake_egl_context); } TEST_F(MesaDisplayBufferTest, first_post_flips_but_no_wait) { geometry::Rectangle const area{{12,34}, {56,78}}; EXPECT_CALL(*mock_kms_output, schedule_page_flip(_)) .Times(1); EXPECT_CALL(*mock_kms_output, wait_for_page_flip()) .Times(0); graphics::mesa::DisplayBuffer db( create_platform(), null_display_report(), {mock_kms_output}, nullptr, area, mir_orientation_normal, gl_config, mock_egl.fake_egl_context); db.post_update(); } TEST_F(MesaDisplayBufferTest, waits_for_page_flip_on_second_post) { geometry::Rectangle const area{{12,34}, {56,78}}; InSequence seq; EXPECT_CALL(*mock_kms_output, wait_for_page_flip()) .Times(0); EXPECT_CALL(*mock_kms_output, schedule_page_flip(_)) .Times(1); EXPECT_CALL(*mock_kms_output, wait_for_page_flip()) .Times(1); EXPECT_CALL(*mock_kms_output, schedule_page_flip(_)) .Times(1); EXPECT_CALL(*mock_kms_output, wait_for_page_flip()) .Times(0); graphics::mesa::DisplayBuffer db( create_platform(), null_display_report(), {mock_kms_output}, nullptr, area, mir_orientation_normal, gl_config, mock_egl.fake_egl_context); db.post_update(); db.post_update(); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/mesa/test_display_multi_monitor.cpp0000644000015301777760000004442212322054247031107 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/display.h" #include "mir/graphics/display_buffer.h" #include "mir/graphics/display_configuration.h" #include "src/platform/graphics/mesa/platform.h" #include "src/server/report/null_report_factory.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_gl.h" #include "mir/graphics/display_configuration_policy.h" #include "mir_test_doubles/null_virtual_terminal.h" #include "mir_test_doubles/stub_gl_config.h" #include "mir_test_framework/udev_environment.h" #include "mir_test_doubles/mock_drm.h" #include "mir_test_doubles/mock_gbm.h" #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; namespace mtf = mir::mir_test_framework; namespace mr = mir::report; namespace { class ClonedDisplayConfigurationPolicy : public mg::DisplayConfigurationPolicy { public: void apply_to(mg::DisplayConfiguration& conf) { conf.for_each_output( [&](mg::UserDisplayConfigurationOutput& conf_output) { if (conf_output.connected && conf_output.modes.size() > 0) { conf_output.used = true; conf_output.top_left = geom::Point{0, 0}; conf_output.current_mode_index = conf_output.preferred_mode_index; conf_output.power_mode = mir_power_mode_on; } else { conf_output.used = false; conf_output.power_mode = mir_power_mode_off; } }); } }; class SideBySideDisplayConfigurationPolicy : public mg::DisplayConfigurationPolicy { public: void apply_to(mg::DisplayConfiguration& conf) { int max_x = 0; conf.for_each_output( [&](mg::UserDisplayConfigurationOutput& conf_output) { if (conf_output.connected && conf_output.modes.size() > 0) { conf_output.used = true; conf_output.top_left = geom::Point{max_x, 0}; conf_output.current_mode_index = conf_output.preferred_mode_index; conf_output.power_mode = mir_power_mode_on; conf_output.orientation = mir_orientation_normal; max_x += conf_output.modes[conf_output.preferred_mode_index].size.width.as_int(); } else { conf_output.used = false; conf_output.power_mode = mir_power_mode_off; } }); } }; class MesaDisplayMultiMonitorTest : public ::testing::Test { public: MesaDisplayMultiMonitorTest() { using namespace testing; /* Needed for display start-up */ ON_CALL(mock_egl, eglChooseConfig(_,_,_,1,_)) .WillByDefault(DoAll(SetArgPointee<2>(mock_egl.fake_configs[0]), SetArgPointee<4>(1), Return(EGL_TRUE))); const char* egl_exts = "EGL_KHR_image EGL_KHR_image_base EGL_MESA_drm_image"; const char* gl_exts = "GL_OES_texture_npot GL_OES_EGL_image"; ON_CALL(mock_egl, eglQueryString(_,EGL_EXTENSIONS)) .WillByDefault(Return(egl_exts)); ON_CALL(mock_gl, glGetString(GL_EXTENSIONS)) .WillByDefault(Return(reinterpret_cast(gl_exts))); /* * Silence uninteresting calls called when cleaning up resources in * the MockGBM destructor, and which are not handled by NiceMock<>. */ EXPECT_CALL(mock_gbm, gbm_bo_get_device(_)) .Times(AtLeast(0)); EXPECT_CALL(mock_gbm, gbm_device_get_fd(_)) .Times(AtLeast(0)); fake_devices.add_standard_device("standard-drm-devices"); } std::shared_ptr create_platform() { return std::make_shared( mr::null_display_report(), std::make_shared()); } std::shared_ptr create_display_cloned( std::shared_ptr const& platform) { return platform->create_display( std::make_shared(), std::make_shared()); } std::shared_ptr create_display_side_by_side( std::shared_ptr const& platform) { return platform->create_display( std::make_shared(), std::make_shared()); } void setup_outputs(int connected, int disconnected) { using fake = mtd::FakeDRMResources; mtd::FakeDRMResources& resources(mock_drm.fake_drm); modes0.clear(); modes0.push_back(fake::create_mode(1920, 1080, 138500, 2080, 1111, fake::NormalMode)); modes0.push_back(fake::create_mode(1920, 1080, 148500, 2200, 1125, fake::PreferredMode)); modes0.push_back(fake::create_mode(1680, 1050, 119000, 1840, 1080, fake::NormalMode)); modes0.push_back(fake::create_mode(832, 624, 57284, 1152, 667, fake::NormalMode)); geom::Size const connector_physical_size_mm{1597, 987}; resources.reset(); uint32_t const crtc_base_id{10}; uint32_t const encoder_base_id{20}; uint32_t const connector_base_id{30}; for (int i = 0; i < connected; i++) { uint32_t const crtc_id{crtc_base_id + i}; uint32_t const encoder_id{encoder_base_id + i}; uint32_t const all_crtcs_mask{0xff}; crtc_ids.push_back(crtc_id); resources.add_crtc(crtc_id, drmModeModeInfo()); encoder_ids.push_back(encoder_id); resources.add_encoder(encoder_id, crtc_id, all_crtcs_mask); } for (int i = 0; i < connected; i++) { uint32_t const connector_id{connector_base_id + i}; connector_ids.push_back(connector_id); resources.add_connector(connector_id, DRM_MODE_CONNECTOR_VGA, DRM_MODE_CONNECTED, encoder_ids[i], modes0, encoder_ids, connector_physical_size_mm); } for (int i = 0; i < disconnected; i++) { uint32_t const connector_id{connector_base_id + connected + i}; connector_ids.push_back(connector_id); resources.add_connector(connector_id, DRM_MODE_CONNECTOR_VGA, DRM_MODE_DISCONNECTED, 0, modes_empty, encoder_ids, geom::Size{}); } resources.prepare(); } testing::NiceMock mock_egl; testing::NiceMock mock_gl; testing::NiceMock mock_drm; testing::NiceMock mock_gbm; std::vector modes0; std::vector modes_empty; std::vector crtc_ids; std::vector encoder_ids; std::vector connector_ids; mtf::UdevEnvironment fake_devices; }; } TEST_F(MesaDisplayMultiMonitorTest, create_display_sets_all_connected_crtcs) { using namespace testing; int const num_connected_outputs{3}; int const num_disconnected_outputs{2}; uint32_t const fb_id{66}; setup_outputs(num_connected_outputs, num_disconnected_outputs); /* Create DRM FBs */ EXPECT_CALL(mock_drm, drmModeAddFB(mock_drm.fake_drm.fd(), _, _, _, _, _, _, _)) .WillRepeatedly(DoAll(SetArgPointee<7>(fb_id), Return(0))); ExpectationSet crtc_setups; /* All crtcs are set */ for (int i = 0; i < num_connected_outputs; i++) { crtc_setups += EXPECT_CALL(mock_drm, drmModeSetCrtc(mock_drm.fake_drm.fd(), crtc_ids[i], fb_id, _, _, Pointee(connector_ids[i]), _, _)) .Times(AtLeast(1)); } /* All crtcs are restored at teardown */ for (int i = 0; i < num_connected_outputs; i++) { EXPECT_CALL(mock_drm, drmModeSetCrtc(mock_drm.fake_drm.fd(), crtc_ids[i], Ne(fb_id), _, _, Pointee(connector_ids[i]), _, _)) .Times(1) .After(crtc_setups); } auto display = create_display_cloned(create_platform()); } TEST_F(MesaDisplayMultiMonitorTest, create_display_creates_shared_egl_contexts) { using namespace testing; int const num_connected_outputs{3}; int const num_disconnected_outputs{2}; EGLContext const shared_context{reinterpret_cast(0x77)}; setup_outputs(num_connected_outputs, num_disconnected_outputs); /* Will create only one shared context */ EXPECT_CALL(mock_egl, eglCreateContext(_, _, EGL_NO_CONTEXT, _)) .WillOnce(Return(shared_context)); /* Will use the shared context when creating other contexts */ EXPECT_CALL(mock_egl, eglCreateContext(_, _, shared_context, _)) .Times(AtLeast(1)); { InSequence s; /* Contexts are made current to initialize DisplayBuffers */ EXPECT_CALL(mock_egl, eglMakeCurrent(_,_,_,Ne(shared_context))) .Times(AtLeast(1)); /* The shared context is made current finally */ EXPECT_CALL(mock_egl, eglMakeCurrent(_,_,_,shared_context)) .Times(1); } auto display = create_display_cloned(create_platform()); } namespace { ACTION_P(InvokePageFlipHandler, param) { int const dont_care{0}; char dummy; arg1->page_flip_handler(dont_care, dont_care, dont_care, dont_care, *param); ASSERT_EQ(1, read(arg0, &dummy, 1)); } } TEST_F(MesaDisplayMultiMonitorTest, post_update_flips_all_connected_crtcs) { using namespace testing; int const num_connected_outputs{3}; int const num_disconnected_outputs{2}; uint32_t const fb_id{66}; std::vector user_data(num_connected_outputs, nullptr); setup_outputs(num_connected_outputs, num_disconnected_outputs); /* Create DRM FBs */ EXPECT_CALL(mock_drm, drmModeAddFB(mock_drm.fake_drm.fd(), _, _, _, _, _, _, _)) .WillRepeatedly(DoAll(SetArgPointee<7>(fb_id), Return(0))); /* All crtcs are flipped */ for (int i = 0; i < num_connected_outputs; i++) { EXPECT_CALL(mock_drm, drmModePageFlip(mock_drm.fake_drm.fd(), crtc_ids[i], fb_id, _, _)) .Times(2) .WillRepeatedly(DoAll(SaveArg<4>(&user_data[i]), Return(0))); /* Emit fake DRM page-flip events */ EXPECT_EQ(1, write(mock_drm.fake_drm.write_fd(), "a", 1)); } /* Handle the events properly */ EXPECT_CALL(mock_drm, drmHandleEvent(mock_drm.fake_drm.fd(), _)) .Times(num_connected_outputs) .WillOnce(DoAll(InvokePageFlipHandler(&user_data[0]), Return(0))) .WillOnce(DoAll(InvokePageFlipHandler(&user_data[1]), Return(0))) .WillOnce(DoAll(InvokePageFlipHandler(&user_data[2]), Return(0))); auto display = create_display_cloned(create_platform()); /* First frame: Page flips are scheduled, but not waited for */ display->for_each_display_buffer([](mg::DisplayBuffer& buffer) { buffer.post_update(); }); /* Second frame: Previous page flips finish (drmHandleEvent) and new ones are scheduled */ display->for_each_display_buffer([](mg::DisplayBuffer& buffer) { buffer.post_update(); }); } namespace { struct FBIDContainer { FBIDContainer(uint32_t base_fb_id) : last_fb_id{base_fb_id} {} int add_fb(int, uint32_t, uint32_t, uint8_t, uint8_t, uint32_t, uint32_t, uint32_t *buf_id) { *buf_id = last_fb_id; fb_ids.insert(last_fb_id); ++last_fb_id; return 0; } bool check_fb_id(uint32_t i) { if (fb_ids.find(i) != fb_ids.end()) { fb_ids.erase(i); return true; } return false; } std::unordered_set fb_ids; uint32_t last_fb_id; }; MATCHER_P(IsValidFB, fb_id_container, "") { return fb_id_container->check_fb_id(arg); } } TEST_F(MesaDisplayMultiMonitorTest, create_display_uses_different_drm_fbs_for_side_by_side) { using namespace testing; int const num_connected_outputs{3}; int const num_disconnected_outputs{2}; uint32_t const base_fb_id{66}; FBIDContainer fb_id_container{base_fb_id}; setup_outputs(num_connected_outputs, num_disconnected_outputs); /* Create DRM FBs */ EXPECT_CALL(mock_drm, drmModeAddFB(mock_drm.fake_drm.fd(), _, _, _, _, _, _, _)) .Times(num_connected_outputs) .WillRepeatedly(Invoke(&fb_id_container, &FBIDContainer::add_fb)); ExpectationSet crtc_setups; /* All crtcs are set */ for (int i = 0; i < num_connected_outputs; i++) { crtc_setups += EXPECT_CALL(mock_drm, drmModeSetCrtc(mock_drm.fake_drm.fd(), crtc_ids[i], IsValidFB(&fb_id_container), _, _, Pointee(connector_ids[i]), _, _)) .Times(AtLeast(1)); } /* All crtcs are restored at teardown */ for (int i = 0; i < num_connected_outputs; i++) { EXPECT_CALL(mock_drm, drmModeSetCrtc(mock_drm.fake_drm.fd(), crtc_ids[i], 0, _, _, Pointee(connector_ids[i]), _, _)) .Times(1) .After(crtc_setups); } auto display = create_display_side_by_side(create_platform()); } TEST_F(MesaDisplayMultiMonitorTest, configure_clears_unused_connected_outputs) { using namespace testing; int const num_connected_outputs{3}; int const num_disconnected_outputs{2}; setup_outputs(num_connected_outputs, num_disconnected_outputs); auto display = create_display_cloned(create_platform()); Mock::VerifyAndClearExpectations(&mock_drm); /* All unused connected outputs are cleared */ for (int i = 0; i < num_connected_outputs; i++) { EXPECT_CALL(mock_drm, drmModeSetCursor(mock_drm.fake_drm.fd(), crtc_ids[i], 0, 0, 0)) .Times(1); EXPECT_CALL(mock_drm, drmModeSetCrtc(mock_drm.fake_drm.fd(), crtc_ids[i], 0, 0, 0, nullptr, 0, nullptr)) .Times(1); } /* Set all outputs to unused */ auto conf = display->configuration(); conf->for_each_output( [&](mg::UserDisplayConfigurationOutput& output) { output.used = false; output.current_mode_index = output.preferred_mode_index; output.current_format = mir_pixel_format_xrgb_8888; output.power_mode = mir_power_mode_on; }); display->configure(*conf); Mock::VerifyAndClearExpectations(&mock_drm); /* All crtcs are restored at teardown */ for (int i = 0; i < num_connected_outputs; i++) { EXPECT_CALL(mock_drm, drmModeSetCrtc(mock_drm.fake_drm.fd(), crtc_ids[i], 0, _, _, Pointee(connector_ids[i]), _, _)) .Times(1); } } TEST_F(MesaDisplayMultiMonitorTest, resume_clears_unused_connected_outputs) { using namespace testing; int const num_connected_outputs{3}; int const num_disconnected_outputs{2}; setup_outputs(num_connected_outputs, num_disconnected_outputs); auto display = create_display_cloned(create_platform()); /* Set all outputs to unused */ auto conf = display->configuration(); conf->for_each_output( [&](mg::UserDisplayConfigurationOutput& output) { output.used = false; output.current_mode_index = output.preferred_mode_index; output.current_format = mir_pixel_format_xrgb_8888; output.power_mode = mir_power_mode_on; }); display->configure(*conf); display->pause(); Mock::VerifyAndClearExpectations(&mock_drm); /* All unused connected outputs are cleared */ for (int i = 0; i < num_connected_outputs; i++) { EXPECT_CALL(mock_drm, drmModeSetCrtc(mock_drm.fake_drm.fd(), crtc_ids[i], 0, 0, 0, nullptr, 0, nullptr)) .Times(1); } display->resume(); Mock::VerifyAndClearExpectations(&mock_drm); /* All crtcs are restored at teardown */ for (int i = 0; i < num_connected_outputs; i++) { EXPECT_CALL(mock_drm, drmModeSetCrtc(mock_drm.fake_drm.fd(), crtc_ids[i], 0, _, _, Pointee(connector_ids[i]), _, _)) .Times(1); } } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/test_graphics_platform.cpp0000644000015301777760000001022612322054223027225 0ustar pbusernogroup00000000000000/* * 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 Guest * Kevin DuBois */ #include "mir/graphics/platform.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "mir/graphics/buffer_properties.h" #include "mir_test_doubles/mock_egl.h" #include "mir_test_doubles/mock_gl.h" #ifndef ANDROID #include "mir_test_doubles/mock_drm.h" #include "mir_test_doubles/mock_gbm.h" #include "mir_test_doubles/null_virtual_terminal.h" #include "src/platform/graphics/mesa/platform.h" #include "mir_test_framework/udev_environment.h" #else #include "mir_test_doubles/mock_android_hw.h" #endif #include "mir/graphics/buffer_initializer.h" #include "mir/logging/dumb_console_logger.h" #include "mir/options/program_option.h" #include "src/server/report/null_report_factory.h" #include namespace mg = mir::graphics; namespace ml = mir::logging; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; namespace mr = mir::report; namespace mo = mir::options; #ifndef ANDROID namespace mtf = mir::mir_test_framework; #endif class GraphicsPlatform : public ::testing::Test { public: GraphicsPlatform() : logger(std::make_shared()) { using namespace testing; buffer_initializer = std::make_shared(); #ifndef ANDROID ON_CALL(mock_gbm, gbm_bo_get_width(_)) .WillByDefault(Return(320)); ON_CALL(mock_gbm, gbm_bo_get_height(_)) .WillByDefault(Return(240)); ON_CALL(mock_gbm, gbm_bo_get_format(_)) .WillByDefault(Return(GBM_FORMAT_ARGB8888)); fake_devices.add_standard_device("standard-drm-devices"); #endif } std::shared_ptr create_platform() { #ifdef ANDROID return mg::create_platform(std::make_shared(), mr::null_display_report()); #else return std::make_shared( mr::null_display_report(), std::make_shared()); #endif } std::shared_ptr logger; std::shared_ptr buffer_initializer; ::testing::NiceMock mock_egl; ::testing::NiceMock mock_gl; #ifdef ANDROID ::testing::NiceMock hw_access_mock; #else ::testing::NiceMock mock_drm; ::testing::NiceMock mock_gbm; mtf::UdevEnvironment fake_devices; #endif }; TEST_F(GraphicsPlatform, buffer_allocator_creation) { using namespace testing; EXPECT_NO_THROW ( auto platform = create_platform(); auto allocator = platform->create_buffer_allocator(buffer_initializer); EXPECT_TRUE(allocator.get()); ); } TEST_F(GraphicsPlatform, buffer_creation) { auto platform = create_platform(); auto allocator = platform->create_buffer_allocator(buffer_initializer); auto supported_pixel_formats = allocator->supported_pixel_formats(); ASSERT_NE(0u, supported_pixel_formats.size()); geom::Size size{320, 240}; MirPixelFormat const pf{supported_pixel_formats[0]}; mg::BufferUsage usage{mg::BufferUsage::hardware}; mg::BufferProperties buffer_properties{size, pf, usage}; auto buffer = allocator->alloc_buffer(buffer_properties); ASSERT_TRUE(buffer.get() != NULL); EXPECT_EQ(buffer->size(), size); EXPECT_EQ(buffer->pixel_format(), pf ); } TEST_F(GraphicsPlatform, get_ipc_package) { auto platform = create_platform(); auto pkg = platform->get_ipc_package(); ASSERT_TRUE(pkg.get() != NULL); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/CMakeLists.txt0000644000015301777760000000154012322054223024515 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_graphics_platform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_display_configuration.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_egl_extensions.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_display.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_default_display_configuration_policy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_id.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_properties.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_pixel_format_utils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_surfaceless_egl_context.cpp ) add_subdirectory(nested/) add_subdirectory(offscreen/) add_subdirectory(egl_mock/) if (MIR_TEST_PLATFORM STREQUAL "android") add_subdirectory(android/) endif() if (MIR_TEST_PLATFORM STREQUAL "mesa") add_subdirectory(mesa/) endif() set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/test_default_display_configuration_policy.cpp0000644000015301777760000002002112322054223033172 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/graphics/default_display_configuration_policy.h" #include "mir/graphics/display_configuration.h" #include #include using namespace mir::graphics; using namespace mir::geometry; namespace { class MockDisplayConfiguration : public DisplayConfiguration { public: MockDisplayConfiguration(MockDisplayConfiguration && m) : max_simultaneous_outputs{m.max_simultaneous_outputs}, outputs{std::move(m.outputs)} { } MockDisplayConfiguration(size_t max_simultaneous_outputs, std::vector && config) : max_simultaneous_outputs{max_simultaneous_outputs}, outputs{config} { if (max_simultaneous_outputs == max_simultaneous_outputs_all) max_simultaneous_outputs = outputs.size(); } MockDisplayConfiguration(std::vector && config) : MockDisplayConfiguration(max_simultaneous_outputs_all, std::move(config)) { } void for_each_card(std::function f) const { f({DisplayConfigurationCardId{1}, max_simultaneous_outputs}); } void for_each_output(std::function f) const override { for (auto const& output : outputs) f(output); } void for_each_output(std::function f) { for (auto& output : outputs) { UserDisplayConfigurationOutput user(output); f(user); } } static const size_t max_simultaneous_outputs_all{std::numeric_limits::max()}; private: size_t max_simultaneous_outputs; std::vector outputs; }; } DisplayConfigurationOutput default_output(DisplayConfigurationOutputId id) { return { id, DisplayConfigurationCardId{1}, DisplayConfigurationOutputType::vga, {mir_pixel_format_abgr_8888}, { {Size{523, 555}, 60.0} }, 0, Size{324, 642}, true, false, Point{X{123}, Y{343}}, 0, mir_pixel_format_abgr_8888, mir_power_mode_on, mir_orientation_normal }; } DisplayConfigurationOutput connected_with_modes() { DisplayConfigurationOutput output = default_output(DisplayConfigurationOutputId{10}) ; output.modes = { {Size{123, 111}, 59.9}, {Size{123, 111}, 59.9}, {Size{123, 111}, 59.9} }; output.preferred_mode_index = 2; output.current_mode_index = 1; return output; } DisplayConfigurationOutput connected_without_modes() { DisplayConfigurationOutput output = default_output(DisplayConfigurationOutputId{11}); output.pixel_formats = {}; output.modes = {}; output.current_format = mir_pixel_format_invalid; output.current_mode_index = std::numeric_limits::max(); return output; } DisplayConfigurationOutput connected_with_single_mode() { return default_output(DisplayConfigurationOutputId{12}); } DisplayConfigurationOutput not_connected() { DisplayConfigurationOutput output = default_output(DisplayConfigurationOutputId{13}); output.connected = false; output.current_mode_index = 1; return output; } DisplayConfigurationOutput connected_with_rgba_and_xrgb() { DisplayConfigurationOutput output = default_output(DisplayConfigurationOutputId{14}); output.pixel_formats = {mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888}; return output; } DisplayConfigurationOutput connected_with_xrgb_bgr() { DisplayConfigurationOutput output = default_output(DisplayConfigurationOutputId{15}); output.pixel_formats = {mir_pixel_format_xrgb_8888, mir_pixel_format_bgr_888}; output.current_format = mir_pixel_format_bgr_888; return output; } MockDisplayConfiguration create_default_configuration(size_t max_outputs = MockDisplayConfiguration::max_simultaneous_outputs_all) { return MockDisplayConfiguration { max_outputs, { connected_with_modes(), connected_without_modes(), connected_with_single_mode(), not_connected(), } }; } TEST(DefaultDisplayConfigurationPolicyTest, uses_all_connected_valid_outputs) { using namespace ::testing; DefaultDisplayConfigurationPolicy policy; MockDisplayConfiguration conf{create_default_configuration()}; policy.apply_to(conf); conf.for_each_output([&conf](DisplayConfigurationOutput const& output) { if (output.connected && output.modes.size() > 0) { EXPECT_TRUE(output.used); EXPECT_EQ(Point(), output.top_left); EXPECT_EQ(output.preferred_mode_index, output.current_mode_index); } else { EXPECT_FALSE(output.used); } }); } TEST(DefaultDisplayConfigurationPolicyTest, default_policy_is_power_mode_on) { using namespace ::testing; DefaultDisplayConfigurationPolicy policy; MockDisplayConfiguration conf{create_default_configuration()}; policy.apply_to(conf); conf.for_each_output([](DisplayConfigurationOutput const& output) { EXPECT_EQ(mir_power_mode_on, output.power_mode); }); } TEST(DefaultDisplayConfigurationPolicyTest, default_orientation_is_normal) { using namespace ::testing; DefaultDisplayConfigurationPolicy policy; MockDisplayConfiguration conf{create_default_configuration()}; conf.for_each_output([&conf](DisplayConfigurationOutput const& output) { EXPECT_EQ(mir_orientation_normal, output.orientation); }); } TEST(DefaultDisplayConfigurationPolicyTest, does_not_enable_more_outputs_than_supported) { using namespace ::testing; size_t const max_simultaneous_outputs{1}; DefaultDisplayConfigurationPolicy policy; MockDisplayConfiguration conf{create_default_configuration(max_simultaneous_outputs)}; policy.apply_to(conf); size_t used_count{0}; conf.for_each_output([&used_count](DisplayConfigurationOutput const& output) { if (output.used) ++used_count; }); EXPECT_GE(max_simultaneous_outputs, used_count); } TEST(DefaultDisplayConfigurationPolicyTest, prefer_opaque_over_alpha) { using namespace ::testing; DefaultDisplayConfigurationPolicy policy; MockDisplayConfiguration pick_xrgb{ { connected_with_rgba_and_xrgb() } }; policy.apply_to(pick_xrgb); pick_xrgb.for_each_output([](DisplayConfigurationOutput const& output) { EXPECT_EQ(mir_pixel_format_xrgb_8888, output.current_format); }); } TEST(DefaultDisplayConfigurationPolicyTest, preserve_opaque_selection) { using namespace ::testing; DefaultDisplayConfigurationPolicy policy; MockDisplayConfiguration keep_bgr{ { connected_with_xrgb_bgr() } }; policy.apply_to(keep_bgr); keep_bgr.for_each_output([](DisplayConfigurationOutput const& output) { EXPECT_EQ(mir_pixel_format_bgr_888, output.current_format); }); } TEST(DefaultDisplayConfigurationPolicyTest, accept_transparency_when_only_option) { using namespace ::testing; DefaultDisplayConfigurationPolicy policy; MockDisplayConfiguration pick_rgba{ { default_output(DisplayConfigurationOutputId{15}) } }; policy.apply_to(pick_rgba); pick_rgba.for_each_output([](DisplayConfigurationOutput const& output) { EXPECT_EQ(mir_pixel_format_abgr_8888, output.current_format); }); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/nested/0000755000015301777760000000000012322054703023242 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/nested/test_nested_display.cpp0000644000015301777760000000166312322054247030025 0ustar pbusernogroup00000000000000/* * 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 */ #include /* * TODO: Improve testability of NestedDisplay, so we can have proper unit tests. * In particular we need a way to fake interactions with the client library. */ TEST(NestedDisplay, DISABLED_respects_gl_config) { } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/nested/CMakeLists.txt0000644000015301777760000000041312322054247026003 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_nested_display_configuration.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_nested_platform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_nested_display.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/nested/test_nested_display_configuration.cpp0000644000015301777760000002611412322054223032744 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/graphics/nested/nested_display_configuration.h" #include #include #include namespace mg = mir::graphics; namespace mgn = mir::graphics::nested; namespace geom = mir::geometry; using namespace testing; namespace { uint32_t const default_num_modes = 0; MirDisplayMode* const default_modes = nullptr; uint32_t const default_preferred_mode = 0; uint32_t const default_current_mode = 0; uint32_t const default_num_output_formats = 0; MirPixelFormat* const default_output_formats = nullptr; MirPixelFormat const default_current_output_format = mir_pixel_format_abgr_8888; uint32_t const default_card_id = 1; uint32_t const second_card_id = 2; uint32_t const default_output_id = 0; uint32_t const second_output_id = 1; uint32_t const third_output_id = 2; auto const default_type = MirDisplayOutputType(0); int32_t const default_position_x = 0; int32_t const default_position_y = 0; uint32_t const default_connected = 0; uint32_t const default_used = 0; uint32_t const default_physical_width_mm = 0; uint32_t const default_physical_height_mm = 0; struct NestedDisplayConfiguration : public ::testing::Test { template MirDisplayConfiguration* build_test_config( MirDisplayOutput const (&outputs)[NoOfOutputs], MirDisplayCard const (&cards)[NoOfCards]) { auto out_tmp = new MirDisplayOutput[NoOfOutputs]; std::copy(outputs, outputs+NoOfOutputs, out_tmp); auto card_tmp = new MirDisplayCard[NoOfCards]; std::copy(cards, cards+NoOfCards, card_tmp); return new MirDisplayConfiguration{ NoOfOutputs, out_tmp, NoOfCards, card_tmp }; } template void init_output( MirDisplayOutput* output, MirDisplayMode const (&modes)[NoOfModes], MirPixelFormat const (&formats)[NoOfFormats]) { auto mode_tmp = new MirDisplayMode[NoOfModes]; std::copy(modes, modes+NoOfModes, mode_tmp); auto format_tmp = new MirPixelFormat[NoOfFormats]; std::copy(formats, formats+NoOfFormats, format_tmp); output->num_modes = NoOfModes; output->modes = mode_tmp; output->preferred_mode = 0; output->current_mode = 0; output->num_output_formats = NoOfFormats; output->output_formats = format_tmp; output->current_format = NoOfFormats > 0 ? formats[0] : mir_pixel_format_invalid; } template void init_outputs( MirDisplayOutput (&outputs)[NoOfOutputs], MirDisplayMode const (&modes)[NoOfModes], MirPixelFormat const (&formats)[NoOfFormats]) { for(auto output = outputs; output != outputs+NoOfOutputs; ++output) init_output(output, modes, formats); } MirDisplayConfiguration* build_trivial_configuration() { static MirDisplayCard const cards[] {{default_card_id,1}}; static MirDisplayMode const modes[] = {{ 1080, 1920, 4.33f }}; static MirPixelFormat const formats[] = { mir_pixel_format_abgr_8888 }; MirDisplayOutput outputs[] {{ default_num_modes, default_modes, default_preferred_mode, default_current_mode, default_num_output_formats, default_output_formats, default_current_output_format, default_card_id, default_output_id, default_type, default_position_x, default_position_y, default_connected, default_used, default_physical_width_mm, default_physical_height_mm, mir_power_mode_on, mir_orientation_normal }}; init_output(outputs, modes, formats); return build_test_config(outputs, cards); } MirDisplayConfiguration* build_non_trivial_configuration() { static MirDisplayCard const cards[] { {default_card_id,1}, {second_card_id,2}}; static MirDisplayMode const modes[] = { { 1080, 1920, 4.33f }, { 1080, 1920, 1.11f }}; static MirPixelFormat const formats[] = { mir_pixel_format_abgr_8888, mir_pixel_format_xbgr_8888, mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888, mir_pixel_format_bgr_888}; MirDisplayOutput outputs[] { { default_num_modes, default_modes, default_preferred_mode, default_current_mode, default_num_output_formats, default_output_formats, default_current_output_format, default_card_id, default_output_id, default_type, default_position_x, default_position_y, default_connected, default_used, default_physical_width_mm, default_physical_height_mm, mir_power_mode_on, mir_orientation_normal }, { default_num_modes, default_modes, default_preferred_mode, default_current_mode, default_num_output_formats, default_output_formats, default_current_output_format, second_card_id, second_output_id, default_type, default_position_x, default_position_y, default_connected, default_used, default_physical_width_mm, default_physical_height_mm, mir_power_mode_on, mir_orientation_normal }, { default_num_modes, default_modes, default_preferred_mode, default_current_mode, default_num_output_formats, default_output_formats, default_current_output_format, second_card_id, third_output_id, default_type, default_position_x, default_position_y, default_connected, default_used, default_physical_width_mm, default_physical_height_mm, mir_power_mode_on, mir_orientation_normal }, }; init_outputs(outputs, modes, formats); return build_test_config(outputs, cards); } }; struct MockCardVisitor { MOCK_CONST_METHOD1(f, void(mg::DisplayConfigurationCard const&)); }; struct MockOutputVisitor { MOCK_CONST_METHOD1(f, void(mg::DisplayConfigurationOutput const&)); }; } TEST_F(NestedDisplayConfiguration, empty_configuration_is_read_correctly) { auto empty_configuration = new MirDisplayConfiguration{ 0, nullptr, 0, nullptr }; mgn::NestedDisplayConfiguration config(empty_configuration); config.for_each_card([](mg::DisplayConfigurationCard const&) { FAIL(); }); config.for_each_output([](mg::DisplayConfigurationOutput const&) { FAIL(); }); } TEST_F(NestedDisplayConfiguration, trivial_configuration_has_one_card) { mgn::NestedDisplayConfiguration config(build_trivial_configuration()); MockCardVisitor cv; EXPECT_CALL(cv, f(_)).Times(Exactly(1)); config.for_each_card([&cv](mg::DisplayConfigurationCard const& card) { cv.f(card); }); } TEST_F(NestedDisplayConfiguration, trivial_configuration_has_one_output) { mgn::NestedDisplayConfiguration config(build_trivial_configuration()); MockOutputVisitor ov; EXPECT_CALL(ov, f(_)).Times(Exactly(1)); config.for_each_output([&ov](mg::DisplayConfigurationOutput const& output) { ov.f(output); }); } TEST_F(NestedDisplayConfiguration, trivial_configuration_can_be_configured) { geom::Point const new_top_left{10,20}; mgn::NestedDisplayConfiguration config(build_trivial_configuration()); config.for_each_output([&](mg::UserDisplayConfigurationOutput& output) { output.used = true; output.top_left = new_top_left; }); MockOutputVisitor ov; EXPECT_CALL(ov, f(_)).Times(Exactly(1)); config.for_each_output([&](mg::DisplayConfigurationOutput const& output) { ov.f(output); EXPECT_EQ(true, output.used); EXPECT_EQ(new_top_left, output.top_left); EXPECT_EQ(0, output.current_mode_index); EXPECT_EQ(default_current_output_format, output.current_format); }); } // Validation tests once stood here. They've now been replaced by more // portable validation logic which can be found in: // TEST(DisplayConfiguration, ... TEST_F(NestedDisplayConfiguration, non_trivial_configuration_has_two_cards) { mgn::NestedDisplayConfiguration config(build_non_trivial_configuration()); MockCardVisitor cv; EXPECT_CALL(cv, f(_)).Times(Exactly(2)); config.for_each_card([&cv](mg::DisplayConfigurationCard const& card) { cv.f(card); }); } TEST_F(NestedDisplayConfiguration, non_trivial_configuration_has_three_outputs) { mgn::NestedDisplayConfiguration config(build_non_trivial_configuration()); MockOutputVisitor ov; EXPECT_CALL(ov, f(_)).Times(Exactly(3)); config.for_each_output([&ov](mg::DisplayConfigurationOutput const& output) { ov.f(output); }); } TEST_F(NestedDisplayConfiguration, non_trivial_configuration_can_be_configured) { mg::DisplayConfigurationOutputId const id(second_output_id); geom::Point const top_left{100,200}; mgn::NestedDisplayConfiguration config(build_non_trivial_configuration()); config.for_each_output([&](mg::UserDisplayConfigurationOutput& output) { if (output.id == id) { output.used = true; output.top_left = top_left; output.current_mode_index = 1; output.current_format = mir_pixel_format_argb_8888; } }); MockOutputVisitor ov; EXPECT_CALL(ov, f(_)).Times(Exactly(3)); config.for_each_output([&](mg::DisplayConfigurationOutput const& output) { ov.f(output); if (output.id == id) { EXPECT_EQ(true, output.used); EXPECT_EQ(top_left, output.top_left); EXPECT_EQ(1, output.current_mode_index); EXPECT_EQ(mir_pixel_format_argb_8888, output.current_format); } }); } mir-0.1.8+14.04.20140411/tests/unit-tests/graphics/nested/test_nested_platform.cpp0000644000015301777760000000173612322054223030177 0ustar pbusernogroup00000000000000/* * 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 */ #include /* * TODO: Improve testability of NestedPlatform, so we can have proper unit tests. * In particular we need a way to fake interactions with the client library. */ TEST(NestedGraphicsPlatform, DISABLED_egl_native_display_is_mir_connection_native_display) { } mir-0.1.8+14.04.20140411/tests/unit-tests/options/0000755000015301777760000000000012322054703021653 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/options/test_program_option.cpp0000644000015301777760000001357112322054223026461 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/options/program_option.h" #include #include #include #include #include namespace bpo = boost::program_options; namespace { struct ProgramOption : testing::Test { ProgramOption() : desc("Options") { desc.add_options() ("file,f", bpo::value(), "") ("flag-yes", bpo::value(), "flag \"yes\"") ("flag-true", bpo::value(), "flag \"true\"") ("flag-no", bpo::value(), "flag \"no\"") ("flag-false", bpo::value(), "flag \"false\"") ("count,c", bpo::value(), "count") ("defaulted,d", bpo::value()->default_value(666), "defaulted") ("help,h", "this help text"); } bpo::options_description desc; }; } TEST_F(ProgramOption, parse_device_line_long) { mir::options::ProgramOption po; const int argc = 3; char const* argv[argc] = { __PRETTY_FUNCTION__, "--file", "test_file" }; po.parse_arguments(desc, argc, argv); EXPECT_EQ("test_file", po.get("file", "default")); EXPECT_EQ("default", po.get("garbage", "default")); EXPECT_TRUE(po.is_set("file")); EXPECT_FALSE(po.is_set("garbage")); } TEST_F(ProgramOption, parse_device_line_short) { mir::options::ProgramOption po; const int argc = 3; char const* argv[argc] = { __PRETTY_FUNCTION__, "-f", "test_file" }; po.parse_arguments(desc, argc, argv); EXPECT_EQ("test_file", po.get("file", "default")); EXPECT_EQ("default", po.get("garbage", "default")); EXPECT_TRUE(po.is_set("file")); EXPECT_FALSE(po.is_set("garbage")); } TEST_F(ProgramOption, parse_device_yes_no) { mir::options::ProgramOption po; const int argc = 9; char const* argv[argc] = { __PRETTY_FUNCTION__, "--flag-yes", "yes", "--flag-true", "true", "--flag-no", "no", "--flag-false", "false" }; po.parse_arguments(desc, argc, argv); EXPECT_TRUE(po.get("flag-yes", false)); EXPECT_TRUE(po.get("flag-true", false)); EXPECT_FALSE(po.get("flag-no", true)); EXPECT_FALSE(po.get("flag-false", true)); EXPECT_FALSE(po.get("flag-default", false)); EXPECT_TRUE(po.get("flag-default", true)); } TEST_F(ProgramOption, parse_device_line_help) { mir::options::ProgramOption po; const int argc = 2; char const* argv[argc] = { __PRETTY_FUNCTION__, "--help" }; po.parse_arguments(desc, argc, argv); EXPECT_TRUE(po.is_set("help")); } TEST_F(ProgramOption, matches_compound_name_lookup) { using testing::Eq; mir::options::ProgramOption po; const int argc = 8; char const* argv[argc] = { __PRETTY_FUNCTION__, "--help", "--flag-yes", "yes", "-f", "test_file", "-c", "27" }; po.parse_arguments(desc, argc, argv); EXPECT_THAT(po.is_set("help,h"), Eq(true)); EXPECT_THAT(po.get("flag-yes,y", false), Eq(true)); EXPECT_THAT(po.get("file,f", "default"), Eq("test_file")); EXPECT_THAT(po.get("count,c", 42), Eq(27)); } TEST_F(ProgramOption, defaulted_values_are_available) { using testing::Eq; mir::options::ProgramOption po; const int argc = 1; char const* argv[argc] = { __PRETTY_FUNCTION__ }; po.parse_arguments(desc, argc, argv); EXPECT_THAT(po.is_set("defaulted"), Eq(true)); EXPECT_THAT(po.get("defaulted", 3), Eq(666)); } TEST_F(ProgramOption, test_boost_any_overload) { using testing::Eq; mir::options::ProgramOption po; const int argc = 8; char const* argv[argc] = { __PRETTY_FUNCTION__, "--help", "--flag-yes", "yes", "-f", "test_file", "-c", "27" }; po.parse_arguments(desc, argc, argv); EXPECT_THAT(po.is_set("help,h"), Eq(true)); EXPECT_THAT(po.get("flag-yes,y"), Eq(true)); EXPECT_THAT(po.get("file,f"), Eq("test_file")); EXPECT_THAT(po.get("count,c"), Eq(27)); EXPECT_THAT(po.get("defaulted"), Eq(666)); auto const error_result = po.get("garbage"); EXPECT_THAT(error_result.empty(), Eq(true)); EXPECT_THROW(boost::any_cast(error_result), std::bad_cast); EXPECT_THROW(po.get("flag-yes,y"), std::bad_cast); } TEST(ProgramOptionEnv, parse_environment) { // Env variables should be uppercase and "_" delimited char const* name = "some-key"; char const* key = "SOME_KEY"; char const* value = "test_value"; auto const env = std::string(__PRETTY_FUNCTION__) + key; setenv(env.c_str(), value, true); bpo::options_description desc; desc.add_options() (name, bpo::value()); mir::options::ProgramOption po; po.parse_environment(desc, __PRETTY_FUNCTION__); EXPECT_EQ(value, po.get(name, "default")); EXPECT_EQ("default", po.get("garbage", "default")); EXPECT_TRUE(po.is_set(name)); EXPECT_FALSE(po.is_set("garbage")); } // TODO need to parse something TEST(ProgramOptionFile, parse_files) { bpo::options_description desc("Config file options"); mir::options::ProgramOption po; po.parse_file(desc, "test.config"); } mir-0.1.8+14.04.20140411/tests/unit-tests/options/CMakeLists.txt0000644000015301777760000000022712322054223024411 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_program_option.cpp ) set( UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/0000755000015301777760000000000012322054703022356 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/test_occlusion.cpp0000644000015301777760000001432512322054247026127 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/geometry/rectangle.h" #include "src/server/compositor/occlusion.h" #include "mir_test_doubles/fake_renderable.h" #include #include using namespace testing; using namespace mir::geometry; using namespace mir::compositor; namespace mg = mir::graphics; namespace mtd = mir::test::doubles; struct OcclusionFilterTest : public Test { OcclusionFilterTest() { monitor_rect.top_left = {0, 0}; monitor_rect.size = {1920, 1200}; } Rectangle monitor_rect; }; TEST_F(OcclusionFilterTest, single_window_not_occluded) { auto window = std::make_shared(12, 34, 56, 78); mg::RenderableList list{window}; filter_occlusions_from(list, monitor_rect); ASSERT_EQ(1u, list.size()); EXPECT_EQ(window, list.front()); } TEST_F(OcclusionFilterTest, partially_offscreen_still_visible) { // Regression test for LP: #1301115 auto left = std::make_shared(-10, 10, 100, 100); auto right = std::make_shared(1900, 10, 100, 100); auto top = std::make_shared(500, -1, 100, 100); auto bottom = std::make_shared(200, 1000, 100, 1000); mg::RenderableList list{left, right, top, bottom}; filter_occlusions_from(list, monitor_rect); EXPECT_EQ(4u, list.size()); } TEST_F(OcclusionFilterTest, smaller_window_occluded) { auto top = std::make_shared(10, 10, 10, 10); auto bottom = std::make_shared(12, 12, 5, 5); mg::RenderableList list{bottom, top}; filter_occlusions_from(list, monitor_rect); ASSERT_EQ(1u, list.size()); EXPECT_EQ(top, list.front()); } TEST_F(OcclusionFilterTest, translucent_window_occludes_nothing) { auto top = std::make_shared(10, 10, 10, 10, 0.5f); auto bottom = std::make_shared(12, 12, 5, 5, 1.0f); mg::RenderableList list{bottom, top}; filter_occlusions_from(list, monitor_rect); ASSERT_EQ(2u, list.size()); EXPECT_EQ(bottom, list.front()); EXPECT_EQ(top, list.back()); } TEST_F(OcclusionFilterTest, hidden_window_is_self_occluded) { auto window = std::make_shared(10, 10, 10, 10, 1.0f, true, false); mg::RenderableList list{window}; filter_occlusions_from(list, monitor_rect); EXPECT_EQ(0u, list.size()); } TEST_F(OcclusionFilterTest, hidden_window_occludes_nothing) { auto top = std::make_shared(10, 10, 10, 10, 1.0f, true, false); auto bottom = std::make_shared(12, 12, 5, 5); mg::RenderableList list{bottom, top}; filter_occlusions_from(list, monitor_rect); ASSERT_EQ(1u, list.size()); EXPECT_EQ(bottom, list.front()); } TEST_F(OcclusionFilterTest, shaped_window_occludes_nothing) { auto top = std::make_shared(10, 10, 10, 10, 1.0f, false, true); auto bottom = std::make_shared(12, 12, 5, 5); mg::RenderableList list{bottom, top}; filter_occlusions_from(list, monitor_rect); ASSERT_EQ(2u, list.size()); EXPECT_EQ(bottom, list.front()); EXPECT_EQ(top, list.back()); } TEST_F(OcclusionFilterTest, identical_window_occluded) { auto top = std::make_shared(10, 10, 10, 10); auto bottom = std::make_shared(10, 10, 10, 10); mg::RenderableList list{bottom, top}; filter_occlusions_from(list, monitor_rect); ASSERT_EQ(1u, list.size()); EXPECT_EQ(top, list.front()); } TEST_F(OcclusionFilterTest, larger_window_never_occluded) { auto top = std::make_shared(10, 10, 10, 10); auto bottom = std::make_shared(9, 9, 12, 12); mg::RenderableList list{bottom, top}; filter_occlusions_from(list, monitor_rect); ASSERT_EQ(2u, list.size()); EXPECT_EQ(bottom, list.front()); EXPECT_EQ(top, list.back()); } TEST_F(OcclusionFilterTest, cascaded_windows_never_occluded) { mg::RenderableList list; unsigned int const num_windows{10u}; for (auto x = 0u; x < num_windows; x++) list.push_back(std::make_shared(x, x, 200, 100)); filter_occlusions_from(list, monitor_rect); EXPECT_EQ(num_windows, list.size()); } TEST_F(OcclusionFilterTest, some_occluded_and_some_not) { auto window0 = std::make_shared(10, 20, 400, 300); auto window1 = std::make_shared(10, 20, 5, 5); auto window2 = std::make_shared(100, 100, 20, 20); auto window3 = std::make_shared(200, 200, 50, 50); auto window4 = std::make_shared(500, 600, 34, 56); auto window5 = std::make_shared(200, 200, 1000, 1000); mg::RenderableList list{ window5, //not occluded window4, //not occluded window3, //occluded window2, //occluded window1, //occluded window0 //not occluded }; filter_occlusions_from(list, monitor_rect); auto expected_size = 3u; ASSERT_EQ(expected_size, list.size()); auto it = list.begin(); for(auto count = 0u; count < expected_size; count++) { switch (count) { case 0u: EXPECT_EQ(window5, *it); break; case 1u: EXPECT_EQ(window4, *it); break; case 2u: EXPECT_EQ(window0, *it); break; default: FAIL(); break; } it++; } } mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/test_multi_threaded_compositor.cpp0000644000015301777760000004271412322054247031404 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/compositor/multi_threaded_compositor.h" #include "mir/compositor/display_buffer_compositor.h" #include "mir/compositor/scene.h" #include "mir/compositor/display_buffer_compositor_factory.h" #include "src/server/report/null_report_factory.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/null_display_buffer.h" #include "mir_test_doubles/mock_display_buffer.h" #include "mir_test_doubles/mock_compositor_report.h" #include "mir_test_doubles/mock_scene.h" #include #include #include #include #include #include #include namespace mc = mir::compositor; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; namespace mr = mir::report; namespace { class StubDisplay : public mtd::NullDisplay { public: StubDisplay(unsigned int nbuffers) : buffers{nbuffers} {} void for_each_display_buffer(std::function const& f) override { for (auto& db : buffers) f(db); } private: std::vector buffers; }; class StubDisplayWithMockBuffers : public mtd::NullDisplay { public: StubDisplayWithMockBuffers(unsigned int nbuffers) : buffers{nbuffers} {} void for_each_display_buffer(std::function const& f) { for (auto& db : buffers) f(db); } void for_each_mock_buffer(std::function const& f) { for (auto& db : buffers) f(db); } private: std::vector> buffers; }; class StubScene : public mc::Scene { public: StubScene() : callback{[]{}} {} mg::RenderableList generate_renderable_list() const { return mg::RenderableList{}; } void for_each_if(mc::FilterForScene&, mc::OperatorForScene&) { } void set_change_callback(std::function const& f) { std::lock_guard lock{callback_mutex}; assert(f); callback = f; } void emit_change_event() { { std::lock_guard lock{callback_mutex}; callback(); } /* Reduce run-time under valgrind */ std::this_thread::yield(); } void lock() {} void unlock() {} private: std::function callback; std::mutex callback_mutex; }; class RecordingDisplayBufferCompositor : public mc::DisplayBufferCompositor { public: RecordingDisplayBufferCompositor(std::function const& mark_render_buffer) : mark_render_buffer{mark_render_buffer} { } bool composite() { mark_render_buffer(); /* Reduce run-time under valgrind */ std::this_thread::yield(); return false; } private: std::function const mark_render_buffer; }; class RecordingDisplayBufferCompositorFactory : public mc::DisplayBufferCompositorFactory { public: std::unique_ptr create_compositor_for(mg::DisplayBuffer& display_buffer) { auto raw = new RecordingDisplayBufferCompositor{ [&display_buffer,this]() { mark_render_buffer(display_buffer); }}; return std::unique_ptr(raw); } void mark_render_buffer(mg::DisplayBuffer& display_buffer) { std::lock_guard lk{m}; if (records.find(&display_buffer) == records.end()) records[&display_buffer] = Record(0, std::unordered_set()); ++records[&display_buffer].first; records[&display_buffer].second.insert(std::this_thread::get_id()); } bool enough_records_gathered(unsigned int nbuffers) { static unsigned int const min_record_count{1000}; std::lock_guard lk{m}; if (records.size() < nbuffers) return false; for (auto const& e : records) { Record const& r = e.second; if (r.first < min_record_count) return false; } return true; } bool each_buffer_rendered_in_single_thread() { for (auto const& e : records) { Record const& r = e.second; if (r.second.size() != 1) return false; } return true; } bool buffers_rendered_in_different_threads() { std::unordered_set seen; seen.insert(std::this_thread::get_id()); for (auto const& e : records) { Record const& r = e.second; auto iter = r.second.begin(); if (seen.find(*iter) != seen.end()) return false; seen.insert(*iter); } return true; } bool check_record_count_for_each_buffer( unsigned int nbuffers, unsigned int min, unsigned int max = ~0u) { std::lock_guard lk{m}; if (records.size() < nbuffers) return (min == 0 && max == 0); for (auto const& e : records) { Record const& r = e.second; if (r.first < min || r.first > max) return false; } return true; } private: std::mutex m; typedef std::pair> Record; std::unordered_map records; }; class SurfaceUpdatingDisplayBufferCompositor : public mc::DisplayBufferCompositor { public: SurfaceUpdatingDisplayBufferCompositor(std::function const& fake_surface_update) : fake_surface_update{fake_surface_update} { } bool composite() { fake_surface_update(); /* Reduce run-time under valgrind */ std::this_thread::yield(); return false; } private: std::function const fake_surface_update; }; class SurfaceUpdatingDisplayBufferCompositorFactory : public mc::DisplayBufferCompositorFactory { public: SurfaceUpdatingDisplayBufferCompositorFactory(std::shared_ptr const& scene) : scene{scene}, render_count{0} { } std::unique_ptr create_compositor_for(mg::DisplayBuffer&) { auto raw = new SurfaceUpdatingDisplayBufferCompositor{[this]{fake_surface_update();}}; return std::unique_ptr(raw); } void fake_surface_update() { scene->emit_change_event(); ++render_count; } bool enough_renders_happened() { unsigned int const enough_renders{1000}; return render_count > enough_renders; } private: std::shared_ptr const scene; unsigned int render_count; }; class NullDisplayBufferCompositorFactory : public mc::DisplayBufferCompositorFactory { public: std::unique_ptr create_compositor_for(mg::DisplayBuffer&) { struct NullDisplayBufferCompositor : mc::DisplayBufferCompositor { bool composite() { return false; } }; auto raw = new NullDisplayBufferCompositor{}; return std::unique_ptr(raw); } }; auto const null_report = mr::null_compositor_report(); unsigned int const composites_per_update{1}; } TEST(MultiThreadedCompositor, compositing_happens_in_different_threads) { using namespace testing; unsigned int const nbuffers{3}; auto display = std::make_shared(nbuffers); auto scene = std::make_shared(); auto db_compositor_factory = std::make_shared(); mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, true}; compositor.start(); while (!db_compositor_factory->enough_records_gathered(nbuffers)) scene->emit_change_event(); compositor.stop(); EXPECT_TRUE(db_compositor_factory->each_buffer_rendered_in_single_thread()); EXPECT_TRUE(db_compositor_factory->buffers_rendered_in_different_threads()); } TEST(MultiThreadedCompositor, reports_in_the_right_places) { using namespace testing; auto display = std::make_shared(1); auto scene = std::make_shared(); auto db_compositor_factory = std::make_shared(); auto mock_report = std::make_shared(); mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, mock_report, true}; EXPECT_CALL(*mock_report, started()) .Times(1); display->for_each_mock_buffer([](mtd::MockDisplayBuffer& mock_buf) { EXPECT_CALL(mock_buf, make_current()).Times(1); EXPECT_CALL(mock_buf, view_area()) .WillOnce(Return(geom::Rectangle())); }); EXPECT_CALL(*mock_report, added_display(_,_,_,_,_)) .Times(1); EXPECT_CALL(*mock_report, scheduled()) .Times(2); display->for_each_mock_buffer([](mtd::MockDisplayBuffer& mock_buf) { EXPECT_CALL(mock_buf, release_current()).Times(1); }); EXPECT_CALL(*mock_report, stopped()) .Times(AtLeast(1)); compositor.start(); scene->emit_change_event(); while (!db_compositor_factory->check_record_count_for_each_buffer(1, composites_per_update)) std::this_thread::yield(); compositor.stop(); } /* * It's difficult to test that a render won't happen, without some further * introspective capabilities that would complicate the code. This test will * catch a problem if it occurs, but can't ensure that a problem, even if * present, will occur in a determinstic manner. * * Nonetheless, the test is useful since it's very likely to fail if a problem * is present (and don't forget that it's usually run multiple times per day). */ TEST(MultiThreadedCompositor, composites_only_on_demand) { using namespace testing; unsigned int const nbuffers = 3; auto display = std::make_shared(nbuffers); auto scene = std::make_shared(); auto db_compositor_factory = std::make_shared(); mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, true}; // Verify we're actually starting at zero frames EXPECT_TRUE(db_compositor_factory->check_record_count_for_each_buffer(nbuffers, 0, 0)); compositor.start(); // Initial render: initial_composites frames should be composited at least while (!db_compositor_factory->check_record_count_for_each_buffer(nbuffers, composites_per_update)) std::this_thread::sleep_for(std::chrono::milliseconds(10)); // Now we have initial_composites redraws, pause for a while std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // ... and make sure the number is still only 3 EXPECT_TRUE(db_compositor_factory->check_record_count_for_each_buffer(nbuffers, composites_per_update, composites_per_update)); // Trigger more surface changes scene->emit_change_event(); // Display buffers should be forced to render another 3, so that's 6 while (!db_compositor_factory->check_record_count_for_each_buffer(nbuffers, 2*composites_per_update)) std::this_thread::sleep_for(std::chrono::milliseconds(10)); // Now pause without any further surface changes std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // Verify we never triggered more than 2*initial_composites compositions EXPECT_TRUE(db_compositor_factory->check_record_count_for_each_buffer(nbuffers, 2*composites_per_update, 2*composites_per_update)); compositor.stop(); // Pause the compositor so we don't race // Now trigger many surfaces changes close together for (int i = 0; i < 10; i++) scene->emit_change_event(); compositor.start(); // Display buffers should be forced to render another 3, so that's 9 while (!db_compositor_factory->check_record_count_for_each_buffer(nbuffers, 3*composites_per_update)) std::this_thread::sleep_for(std::chrono::milliseconds(10)); // Now pause without any further surface changes std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // Verify we never triggered more than 9 compositions EXPECT_TRUE(db_compositor_factory->check_record_count_for_each_buffer(nbuffers, 3*composites_per_update, 3*composites_per_update)); compositor.stop(); } TEST(MultiThreadedCompositor, when_no_initial_composite_is_needed_there_is_none) { using namespace testing; unsigned int const nbuffers = 3; auto display = std::make_shared(nbuffers); auto scene = std::make_shared(); auto db_compositor_factory = std::make_shared(); mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, false}; // Verify we're actually starting at zero frames ASSERT_TRUE(db_compositor_factory->check_record_count_for_each_buffer(nbuffers, 0, 0)); compositor.start(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Verify we're still at zero frames EXPECT_TRUE(db_compositor_factory->check_record_count_for_each_buffer(nbuffers, 0, 0)); compositor.stop(); } TEST(MultiThreadedCompositor, when_no_initial_composite_is_needed_we_still_composite_on_restart) { using namespace testing; unsigned int const nbuffers = 3; auto display = std::make_shared(nbuffers); auto scene = std::make_shared(); auto db_compositor_factory = std::make_shared(); mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, false}; compositor.start(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Verify we're actually starting at zero frames ASSERT_TRUE(db_compositor_factory->check_record_count_for_each_buffer(nbuffers, 0, 0)); compositor.stop(); compositor.start(); for (int countdown = 100; countdown != 0 && !db_compositor_factory->check_record_count_for_each_buffer(nbuffers, composites_per_update, composites_per_update); --countdown) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); } // Verify we composited the expected frame EXPECT_TRUE(db_compositor_factory->check_record_count_for_each_buffer(nbuffers, composites_per_update, composites_per_update)); compositor.stop(); } TEST(MultiThreadedCompositor, surface_update_from_render_doesnt_deadlock) { using namespace testing; unsigned int const nbuffers{3}; auto display = std::make_shared(nbuffers); auto scene = std::make_shared(); auto db_compositor_factory = std::make_shared(scene); mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, true}; compositor.start(); while (!db_compositor_factory->enough_renders_happened()) std::this_thread::sleep_for(std::chrono::milliseconds(10)); compositor.stop(); } TEST(MultiThreadedCompositor, makes_and_releases_display_buffer_current_target) { using namespace testing; unsigned int const nbuffers{3}; auto display = std::make_shared(nbuffers); auto scene = std::make_shared(); auto db_compositor_factory = std::make_shared(); mc::MultiThreadedCompositor compositor{display, scene, db_compositor_factory, null_report, true}; display->for_each_mock_buffer([](mtd::MockDisplayBuffer& mock_buf) { EXPECT_CALL(mock_buf, view_area()) .WillOnce(Return(geom::Rectangle())); EXPECT_CALL(mock_buf, make_current()).Times(1); EXPECT_CALL(mock_buf, release_current()).Times(1); }); compositor.start(); compositor.stop(); } TEST(MultiThreadedCompositor, double_start_or_stop_ignored) { unsigned int const nbuffers{3}; auto display = std::make_shared(nbuffers); auto mock_scene = std::make_shared(); auto db_compositor_factory = std::make_shared(); auto mock_report = std::make_shared>(); EXPECT_CALL(*mock_report, started()) .Times(1); EXPECT_CALL(*mock_report, stopped()) .Times(1); EXPECT_CALL(*mock_scene, set_change_callback(testing::_)) .Times(2); mc::MultiThreadedCompositor compositor{display, mock_scene, db_compositor_factory, mock_report, true}; compositor.start(); compositor.start(); compositor.stop(); compositor.stop(); } mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/test_buffer_stream.cpp0000644000015301777760000001246412322054223026751 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/compositor/buffer_stream_surfaces.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/mock_buffer_bundle.h" #include "mir_test/gmock_fixes.h" #include #include #include namespace mc = mir::compositor; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; class BufferStreamTest : public ::testing::Test { protected: BufferStreamTest() { mock_buffer = std::make_shared(); mock_bundle = std::make_shared(); // Two of the tests care about this, the rest should not... EXPECT_CALL(*mock_bundle, force_requests_to_complete()) .Times(::testing::AnyNumber()); } std::shared_ptr mock_buffer; std::shared_ptr mock_bundle; }; TEST_F(BufferStreamTest, size_query) { geom::Size size{4, 5}; mg::BufferProperties properties {size, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware}; EXPECT_CALL(*mock_bundle, properties()) .Times(1) .WillOnce(testing::Return(properties)); mc::BufferStreamSurfaces buffer_stream(mock_bundle); auto returned_size = buffer_stream.stream_size(); EXPECT_EQ(size, returned_size); } TEST_F(BufferStreamTest, pixel_format_query) { MirPixelFormat format{mir_pixel_format_abgr_8888}; mg::BufferProperties properties {geom::Size{4, 5}, format, mg::BufferUsage::hardware}; EXPECT_CALL(*mock_bundle, properties()) .Times(1) .WillOnce(testing::Return(properties)); mc::BufferStreamSurfaces buffer_stream(mock_bundle); auto returned_pf = buffer_stream.get_stream_pixel_format(); EXPECT_EQ(format, returned_pf); } TEST_F(BufferStreamTest, force_requests_to_complete) { EXPECT_CALL(*mock_bundle, force_requests_to_complete()) .Times(2); // Once explcit, once on destruction mc::BufferStreamSurfaces buffer_stream(mock_bundle); buffer_stream.force_requests_to_complete(); } TEST_F(BufferStreamTest, requests_are_completed_before_destruction) { EXPECT_CALL(*mock_bundle, force_requests_to_complete()) .Times(1); mc::BufferStreamSurfaces buffer_stream(mock_bundle); } TEST_F(BufferStreamTest, get_buffer_for_compositor_handles_resources) { using namespace testing; EXPECT_CALL(*mock_bundle, compositor_acquire(_)) .Times(1) .WillOnce(Return(mock_buffer)); EXPECT_CALL(*mock_bundle, compositor_release(_)) .Times(1); mc::BufferStreamSurfaces buffer_stream(mock_bundle); buffer_stream.lock_compositor_buffer(0); } TEST_F(BufferStreamTest, get_buffer_for_compositor_can_lock) { using namespace testing; EXPECT_CALL(*mock_bundle, compositor_acquire(_)) .Times(1) .WillOnce(Return(mock_buffer)); EXPECT_CALL(*mock_bundle, compositor_release(_)) .Times(1); mc::BufferStreamSurfaces buffer_stream(mock_bundle); buffer_stream.lock_compositor_buffer(0); } TEST_F(BufferStreamTest, get_buffer_for_client_releases_resources) { std::mutex mutex; std::condition_variable cv; mg::Buffer* buffer{nullptr}; bool done = false; auto const callback = [&](mg::Buffer* new_buffer) { std::unique_lock lock(mutex); buffer = new_buffer; done = true; cv.notify_one(); }; using namespace testing; mc::BufferStreamSurfaces buffer_stream(mock_bundle); InSequence seq; EXPECT_CALL(*mock_bundle, client_acquire(_)) .Times(1) .WillOnce(InvokeArgument<0>(mock_buffer.get())); EXPECT_CALL(*mock_bundle, client_release(_)) .Times(1); EXPECT_CALL(*mock_bundle, client_acquire(_)) .Times(1) .WillOnce(InvokeArgument<0>(mock_buffer.get())); buffer_stream.swap_client_buffers(buffer, callback); { std::unique_lock lock(mutex); cv.wait(lock, [&]{ return done; }); } done = false; buffer_stream.swap_client_buffers(buffer, callback); { std::unique_lock lock(mutex); cv.wait(lock, [&]{ return done; }); } } TEST_F(BufferStreamTest, allow_framedropping_device) { EXPECT_CALL(*mock_bundle, allow_framedropping(true)) .Times(1); mc::BufferStreamSurfaces buffer_stream(mock_bundle); buffer_stream.allow_framedropping(true); } TEST_F(BufferStreamTest, resizes_bundle) { geom::Size const new_size{66, 77}; EXPECT_CALL(*mock_bundle, resize(new_size)) .Times(1); mc::BufferStreamSurfaces buffer_stream(mock_bundle); buffer_stream.resize(new_size); } mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/test_temporary_buffers.cpp0000644000015301777760000001026412322054223027657 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/compositor/temporary_buffers.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/mock_buffer_bundle.h" #include #include namespace mtd=mir::test::doubles; namespace mg = mir::graphics; namespace mc=mir::compositor; namespace geom=mir::geometry; namespace { class TemporaryTestBuffer : public mc::TemporaryBuffer { public: TemporaryTestBuffer(const std::shared_ptr& buf) : TemporaryBuffer(buf) { } }; class TemporaryBuffersTest : public ::testing::Test { public: TemporaryBuffersTest() : buffer_size{1024, 768}, buffer_stride{1024}, buffer_pixel_format{mir_pixel_format_abgr_8888}, mock_buffer{std::make_shared>( buffer_size, buffer_stride, buffer_pixel_format)}, mock_bundle{std::make_shared>()} { using namespace testing; ON_CALL(*mock_bundle, client_acquire(_)) .WillByDefault(InvokeArgument<0>(mock_buffer.get())); ON_CALL(*mock_bundle, compositor_acquire(_)) .WillByDefault(Return(mock_buffer)); } geom::Size const buffer_size; geom::Stride const buffer_stride; MirPixelFormat const buffer_pixel_format; std::shared_ptr const mock_buffer; std::shared_ptr mock_bundle; }; } TEST_F(TemporaryBuffersTest, compositor_buffer_acquires_and_releases) { using namespace testing; EXPECT_CALL(*mock_bundle, compositor_acquire(_)) .WillOnce(Return(mock_buffer)); EXPECT_CALL(*mock_bundle, compositor_release(_)) .Times(1); mc::TemporaryCompositorBuffer proxy_buffer(mock_bundle, 0); } TEST_F(TemporaryBuffersTest, snapshot_buffer_acquires_and_releases) { using namespace testing; EXPECT_CALL(*mock_bundle, snapshot_acquire()) .WillOnce(Return(mock_buffer)); EXPECT_CALL(*mock_bundle, snapshot_release(_)) .Times(1); mc::TemporarySnapshotBuffer proxy_buffer(mock_bundle); } TEST_F(TemporaryBuffersTest, base_test_size) { TemporaryTestBuffer proxy_buffer(mock_buffer); EXPECT_CALL(*mock_buffer, size()) .Times(1); geom::Size size; size = proxy_buffer.size(); EXPECT_EQ(buffer_size, size); } TEST_F(TemporaryBuffersTest, base_test_stride) { TemporaryTestBuffer proxy_buffer(mock_buffer); EXPECT_CALL(*mock_buffer, stride()) .Times(1); geom::Stride stride; stride = proxy_buffer.stride(); EXPECT_EQ(buffer_stride, stride); } TEST_F(TemporaryBuffersTest, base_test_pixel_format) { TemporaryTestBuffer proxy_buffer(mock_buffer); EXPECT_CALL(*mock_buffer, pixel_format()) .Times(1); MirPixelFormat pixel_format; pixel_format = proxy_buffer.pixel_format(); EXPECT_EQ(buffer_pixel_format, pixel_format); } TEST_F(TemporaryBuffersTest, base_bind_to_texture) { TemporaryTestBuffer proxy_buffer(mock_buffer); EXPECT_CALL(*mock_buffer, bind_to_texture()) .Times(1); proxy_buffer.bind_to_texture(); } TEST_F(TemporaryBuffersTest, base_test_id) { TemporaryTestBuffer proxy_buffer(mock_buffer); EXPECT_CALL(*mock_buffer, id()) .Times(1); proxy_buffer.id(); } TEST_F(TemporaryBuffersTest, base_test_native_buffer_handle) { TemporaryTestBuffer proxy_buffer(mock_buffer); EXPECT_CALL(*mock_buffer, native_buffer_handle()) .Times(1); proxy_buffer.native_buffer_handle(); } mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/test_screencast_display_buffer.cpp0000644000015301777760000001325712322054223031336 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/compositor/screencast_display_buffer.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/mock_gl.h" #include "mir_test_doubles/stub_renderable.h" #include #include namespace mc = mir::compositor; namespace mtd = mir::test::doubles; namespace geom = mir::geometry; namespace mg = mir::graphics; namespace { struct MockRenderFunctor { void operator()(mg::Renderable const& r) { operator_call(&r); } MOCK_METHOD1(operator_call, void(mg::Renderable const*)); }; struct ScreencastDisplayBufferTest : testing::Test { testing::NiceMock mock_gl; }; } TEST_F(ScreencastDisplayBufferTest, cleans_up_gl_resources) { using namespace testing; GLuint const texture{11}; GLuint const renderbuffer{12}; GLuint const framebuffer{13}; EXPECT_CALL(mock_gl, glGenTextures(1,_)) .WillOnce(SetArgPointee<1>(texture)); EXPECT_CALL(mock_gl, glGenRenderbuffers(1,_)) .WillOnce(SetArgPointee<1>(renderbuffer)); EXPECT_CALL(mock_gl, glGenFramebuffers(1,_)) .WillOnce(SetArgPointee<1>(framebuffer)); EXPECT_CALL(mock_gl, glDeleteTextures(1,Pointee(texture))); EXPECT_CALL(mock_gl, glDeleteRenderbuffers(1,Pointee(renderbuffer))); EXPECT_CALL(mock_gl, glDeleteFramebuffers(1,Pointee(framebuffer))); geom::Rectangle const rect{{100,100}, {800,600}}; mtd::StubBuffer stub_buffer; mc::ScreencastDisplayBuffer db{rect, stub_buffer}; } TEST_F(ScreencastDisplayBufferTest, cleans_up_gl_resources_on_construction_failure) { using namespace testing; GLuint const texture{11}; GLuint const renderbuffer{12}; GLuint const framebuffer{13}; EXPECT_CALL(mock_gl, glGenTextures(1,_)) .WillOnce(SetArgPointee<1>(texture)); EXPECT_CALL(mock_gl, glGenRenderbuffers(1,_)) .WillOnce(SetArgPointee<1>(renderbuffer)); EXPECT_CALL(mock_gl, glGenFramebuffers(1,_)) .WillOnce(SetArgPointee<1>(framebuffer)); EXPECT_CALL(mock_gl, glCheckFramebufferStatus(_)) .WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)); EXPECT_CALL(mock_gl, glDeleteTextures(1,Pointee(texture))); EXPECT_CALL(mock_gl, glDeleteRenderbuffers(1,Pointee(renderbuffer))); EXPECT_CALL(mock_gl, glDeleteFramebuffers(1,Pointee(framebuffer))); geom::Rectangle const rect{{100,100}, {800,600}}; mtd::StubBuffer stub_buffer; EXPECT_THROW({ mc::ScreencastDisplayBuffer db(rect, stub_buffer); }, std::runtime_error); } TEST_F(ScreencastDisplayBufferTest, sets_render_buffer_size_to_supplied_buffer_size) { using namespace testing; geom::Rectangle const rect{{100,100}, {800,600}}; testing::NiceMock mock_buffer{ rect.size, geom::Stride{100}, mir_pixel_format_xbgr_8888}; /* Set the buffer as rendering target */ EXPECT_CALL(mock_gl, glRenderbufferStorage(_, _, mock_buffer.size().width.as_int(), mock_buffer.size().height.as_int())); mc::ScreencastDisplayBuffer db{rect, mock_buffer}; } TEST_F(ScreencastDisplayBufferTest, renders_to_supplied_buffer) { using namespace testing; geom::Rectangle const rect{{100,100}, {800,600}}; testing::NiceMock mock_buffer{ rect.size, geom::Stride{100}, mir_pixel_format_xbgr_8888}; InSequence s; /* Set the buffer as rendering target */ EXPECT_CALL(mock_buffer, bind_to_texture()); EXPECT_CALL(mock_gl, glViewport(0, 0, mock_buffer.size().width.as_int(), mock_buffer.size().height.as_int())); /* Restore previous viewport on exit */ EXPECT_CALL(mock_gl, glViewport(0, 0, 0, 0)); mc::ScreencastDisplayBuffer db{rect, mock_buffer}; db.make_current(); } TEST_F(ScreencastDisplayBufferTest, forces_rendering_to_complete_on_post_update) { using namespace testing; geom::Rectangle const rect{{100,100}, {800,600}}; mtd::StubBuffer stub_buffer; mc::ScreencastDisplayBuffer db{rect, stub_buffer}; Mock::VerifyAndClearExpectations(&mock_gl); EXPECT_CALL(mock_gl, glFinish()); db.post_update(); } TEST_F(ScreencastDisplayBufferTest, renders_renderables_on_render_and_post_update) { using namespace testing; geom::Rectangle const rect{{100,100}, {800,600}}; mtd::StubBuffer stub_buffer; std::list> renderables{ std::make_shared(), std::make_shared(), std::make_shared()}; mc::ScreencastDisplayBuffer db{rect, stub_buffer}; Mock::VerifyAndClearExpectations(&mock_gl); MockRenderFunctor mock_render_functor; InSequence s; for (auto const& renderable : renderables) EXPECT_CALL(mock_render_functor, operator_call(renderable.get())); EXPECT_CALL(mock_gl, glFinish()); db.render_and_post_update(renderables, std::ref(mock_render_functor)); } mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/test_rendering_operator.cpp0000644000015301777760000000540012322054247030013 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/compositor/rendering_operator.h" #include "mir/geometry/rectangle.h" #include "mir_test_doubles/mock_renderer.h" #include "mir_test_doubles/mock_buffer_stream.h" #include "mir_test_doubles/mock_renderable.h" #include "mir_test_doubles/stub_buffer.h" #include #include namespace mc = mir::compositor; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; namespace mg = mir::graphics; TEST(RenderingOperator, render_operator_saves_resources) { using namespace testing; mtd::MockRenderer mock_renderer; mtd::MockRenderable mock_renderable; auto stub_buffer0 = std::make_shared(); auto stub_buffer1 = std::make_shared(); auto stub_buffer2 = std::make_shared(); EXPECT_CALL(mock_renderable, buffer(_)) .Times(3) .WillOnce(Return(stub_buffer0)) .WillOnce(Return(stub_buffer1)) .WillOnce(Return(stub_buffer2)); Sequence seq; EXPECT_CALL(mock_renderer, render(Ref(mock_renderable), Ref(*stub_buffer0))) .InSequence(seq); EXPECT_CALL(mock_renderer, render(Ref(mock_renderable), Ref(*stub_buffer1))) .InSequence(seq); EXPECT_CALL(mock_renderer, render(Ref(mock_renderable), Ref(*stub_buffer2))) .InSequence(seq); auto use_count_before0 = stub_buffer0.use_count(); auto use_count_before1 = stub_buffer1.use_count(); auto use_count_before2 = stub_buffer2.use_count(); { mc::RenderingOperator rendering_operator(mock_renderer); rendering_operator(mock_renderable); rendering_operator(mock_renderable); rendering_operator(mock_renderable); EXPECT_EQ(use_count_before0 + 1, stub_buffer0.use_count()); EXPECT_EQ(use_count_before1 + 1, stub_buffer1.use_count()); EXPECT_EQ(use_count_before2 + 1, stub_buffer2.use_count()); } EXPECT_EQ(use_count_before0, stub_buffer0.use_count()); EXPECT_EQ(use_count_before1, stub_buffer1.use_count()); EXPECT_EQ(use_count_before2, stub_buffer2.use_count()); } mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/test_compositing_screencast.cpp0000644000015301777760000002246712322054223030676 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/compositor/compositing_screencast.h" #include "mir/compositor/display_buffer_compositor_factory.h" #include "mir/compositor/display_buffer_compositor.h" #include "mir/graphics/display_buffer.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "mir/geometry/rectangle.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/stub_display_configuration.h" #include "mir_test_doubles/stub_buffer_allocator.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/mock_gl.h" #include "mir_test/fake_shared.h" #include #include #include #include namespace mc = mir::compositor; namespace mg = mir::graphics; namespace mf = mir::frontend; namespace mtd = mir::test::doubles; namespace mt = mir::test; namespace geom = mir::geometry; namespace { class StubDisplay : public mtd::NullDisplay { public: StubDisplay() : connected_used_outputs{{connected,!used}, {connected,used}}, stub_config{connected_used_outputs} { } std::unique_ptr configuration() const override { return std::unique_ptr{ new mtd::StubDisplayConfig{connected_used_outputs}}; } mg::DisplayConfigurationOutput const& output_with(mg::DisplayConfigurationOutputId id) { for (auto const& output : stub_config.outputs) { if (output.id == id) return output; } BOOST_THROW_EXCEPTION(std::logic_error("Can't find stub output")); } private: std::vector> const connected_used_outputs; mtd::StubDisplayConfig const stub_config; static bool const connected; static bool const used; }; bool const StubDisplay::connected{true}; bool const StubDisplay::used{true}; class NullDisplayBufferCompositorFactory : public mc::DisplayBufferCompositorFactory { public: std::unique_ptr create_compositor_for(mg::DisplayBuffer&) { struct NullDisplayBufferCompositor : mc::DisplayBufferCompositor { bool composite() { return false; } }; auto raw = new NullDisplayBufferCompositor{}; return std::unique_ptr(raw); } }; struct MockDisplayBufferCompositor : mc::DisplayBufferCompositor { MOCK_METHOD0(composite, bool()); }; class WrappingDisplayBufferCompositor : public mc::DisplayBufferCompositor { public: WrappingDisplayBufferCompositor(mc::DisplayBufferCompositor& comp) : comp(comp) { } bool composite() { return comp.composite(); } private: mc::DisplayBufferCompositor& comp; }; struct MockBufferAllocator : mg::GraphicBufferAllocator { MOCK_METHOD1(alloc_buffer, std::shared_ptr(mg::BufferProperties const&)); MOCK_METHOD0(supported_pixel_formats, std::vector()); }; struct MockDisplayBufferCompositorFactory : mc::DisplayBufferCompositorFactory { std::unique_ptr create_compositor_for(mg::DisplayBuffer& db) { create_compositor_mock(db); return std::unique_ptr( new WrappingDisplayBufferCompositor{mock_db_compositor}); } MockDisplayBufferCompositor mock_db_compositor; MOCK_METHOD1(create_compositor_mock, void(mg::DisplayBuffer&)); }; MATCHER_P(DisplayBufferCoversArea, output_extents, "") { return arg.view_area() == output_extents; } MATCHER_P(BufferPropertiesMatchOutput, output, "") { return arg.size == output.extents().size; } MATCHER_P(BufferPropertiesMatchSize, size, "") { return arg.size == size; } struct CompositingScreencastTest : testing::Test { CompositingScreencastTest() : screencast{mt::fake_shared(stub_display), mt::fake_shared(stub_buffer_allocator), mt::fake_shared(stub_db_compositor_factory)}, default_size{1, 1}, default_region{{0, 0}, {1, 1}}, default_pixel_format{mir_pixel_format_xbgr_8888} { } testing::NiceMock mock_gl; StubDisplay stub_display; mtd::StubBufferAllocator stub_buffer_allocator; NullDisplayBufferCompositorFactory stub_db_compositor_factory; mc::CompositingScreencast screencast; geom::Size const default_size; geom::Rectangle const default_region; MirPixelFormat default_pixel_format; }; } TEST_F(CompositingScreencastTest, produces_different_session_ids) { std::unordered_set session_ids; for (int i = 0; i != 10; ++i) { auto session_id = screencast.create_session(default_region, default_size, default_pixel_format); ASSERT_TRUE(session_ids.find(session_id) == session_ids.end()) << "session_id: " << session_id << " iter: " << i; session_ids.insert(session_id); } } TEST_F(CompositingScreencastTest, throws_on_creation_with_invalid_params) { std::unordered_set session_ids; geom::Size invalid_size{0, 0}; geom::Rectangle invalid_region{{0, 0}, {0, 0}}; EXPECT_THROW(screencast.create_session(invalid_region, default_size, default_pixel_format), std::runtime_error); EXPECT_THROW(screencast.create_session(default_region, invalid_size, default_pixel_format), std::runtime_error); EXPECT_THROW(screencast.create_session(default_region, default_size, mir_pixel_format_invalid), std::runtime_error); } TEST_F(CompositingScreencastTest, throws_on_capture_with_invalid_session_id) { mf::ScreencastSessionId const invalid_session_id{10}; EXPECT_THROW(screencast.capture(invalid_session_id), std::logic_error); } TEST_F(CompositingScreencastTest, throws_on_capture_with_destroyed_session_id) { auto session_id = screencast.create_session(default_region, default_size, default_pixel_format); screencast.destroy_session(session_id); EXPECT_THROW(screencast.capture(session_id), std::logic_error); } TEST_F(CompositingScreencastTest, captures_by_compositing_with_provided_region) { using namespace testing; MockDisplayBufferCompositorFactory mock_db_compositor_factory; InSequence s; EXPECT_CALL(mock_db_compositor_factory, create_compositor_mock(DisplayBufferCoversArea(default_region))); EXPECT_CALL(mock_db_compositor_factory.mock_db_compositor, composite()); mc::CompositingScreencast screencast_local{ mt::fake_shared(stub_display), mt::fake_shared(stub_buffer_allocator), mt::fake_shared(mock_db_compositor_factory)}; auto session_id = screencast_local.create_session(default_region, default_size, default_pixel_format); screencast_local.capture(session_id); } TEST_F(CompositingScreencastTest, allocates_and_uses_buffer_with_provided_size) { using namespace testing; MockBufferAllocator mock_buffer_allocator; mtd::StubBuffer stub_buffer; InSequence s; EXPECT_CALL(mock_buffer_allocator, alloc_buffer(BufferPropertiesMatchSize(default_size))) .WillOnce(Return(mt::fake_shared(stub_buffer))); mc::CompositingScreencast screencast_local{ mt::fake_shared(stub_display), mt::fake_shared(mock_buffer_allocator), mt::fake_shared(stub_db_compositor_factory)}; auto session_id = screencast_local.create_session(default_region, default_size, default_pixel_format); auto buffer = screencast_local.capture(session_id); ASSERT_EQ(&stub_buffer, buffer.get()); } TEST_F(CompositingScreencastTest, uses_one_buffer_per_session) { using namespace testing; MockBufferAllocator mock_buffer_allocator; mtd::StubBuffer stub_buffer1; mtd::StubBuffer stub_buffer2; EXPECT_CALL(mock_buffer_allocator, alloc_buffer(_)) .WillOnce(Return(mt::fake_shared(stub_buffer1))) .WillOnce(Return(mt::fake_shared(stub_buffer2))); mc::CompositingScreencast screencast_local{ mt::fake_shared(stub_display), mt::fake_shared(mock_buffer_allocator), mt::fake_shared(stub_db_compositor_factory)}; auto session_id1 = screencast_local.create_session(default_region, default_size, default_pixel_format); auto buffer1 = screencast_local.capture(session_id1); ASSERT_EQ(&stub_buffer1, buffer1.get()); buffer1 = screencast_local.capture(session_id1); ASSERT_EQ(&stub_buffer1, buffer1.get()); auto session_id2 = screencast_local.create_session(default_region, default_size, default_pixel_format); auto buffer2 = screencast_local.capture(session_id2); ASSERT_EQ(&stub_buffer2, buffer2.get()); buffer2 = screencast_local.capture(session_id2); ASSERT_EQ(&stub_buffer2, buffer2.get()); } mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/test_default_display_buffer_compositor.cpp0000644000015301777760000004254612322054247033117 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/compositor/default_display_buffer_compositor.h" #include "mir/compositor/display_buffer_compositor.h" #include "src/server/report/null_report_factory.h" #include "mir/compositor/scene.h" #include "mir/compositor/renderer.h" #include "mir/geometry/rectangle.h" #include "mir_test_doubles/mock_renderer.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_display_buffer.h" #include "mir_test_doubles/mock_renderable.h" #include "mir_test_doubles/fake_renderable.h" #include "mir_test_doubles/stub_display_buffer.h" #include "mir_test_doubles/mock_buffer.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/mock_compositor_report.h" #include "mir_test_doubles/mock_scene.h" #include #include namespace mg = mir::graphics; namespace mc = mir::compositor; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace mr = mir::report; namespace { struct FakeScene : mc::Scene { FakeScene(mg::RenderableList& renderlist) : renderlist{renderlist} { } mg::RenderableList generate_renderable_list() const { return renderlist; } // Ugly...should we use delegation? void for_each_if(mc::FilterForScene& filter, mc::OperatorForScene& renderable_operator) { for (auto it = renderlist.begin(); it != renderlist.end(); it++) { mg::Renderable &info = **it; if (filter(info)) renderable_operator(info); } } void set_change_callback(std::function const&) {} void change(mg::RenderableList const& new_renderlist) { renderlist = new_renderlist; } void lock() {} void unlock() {} mg::RenderableList renderlist; }; struct DefaultDisplayBufferCompositor : public testing::Test { DefaultDisplayBufferCompositor() : small(std::make_shared(10, 20, 30, 40)), big(std::make_shared(5, 10, 100, 200)), fullscreen(std::make_shared(0, 0, 1366, 768)) { using namespace testing; ON_CALL(display_buffer, orientation()) .WillByDefault(Return(mir_orientation_normal)); ON_CALL(display_buffer, view_area()) .WillByDefault(Return(screen)); ON_CALL(display_buffer, can_bypass()) .WillByDefault(Return(false)); } testing::NiceMock mock_renderer; geom::Rectangle screen{{0, 0}, {1366, 768}}; testing::NiceMock display_buffer; std::shared_ptr small; std::shared_ptr big; std::shared_ptr fullscreen; }; } TEST_F(DefaultDisplayBufferCompositor, render) { using namespace testing; mtd::MockScene scene; EXPECT_CALL(mock_renderer, render(_,_)) .Times(0); EXPECT_CALL(display_buffer, view_area()) .Times(AtLeast(1)); EXPECT_CALL(display_buffer, make_current()) .Times(1); EXPECT_CALL(scene, generate_renderable_list()) .Times(1); EXPECT_CALL(scene, for_each_if(_,_)) .Times(1); EXPECT_CALL(display_buffer, post_update()) .Times(1); mc::DefaultDisplayBufferCompositor compositor( display_buffer, mt::fake_shared(scene), mt::fake_shared(mock_renderer), mr::null_compositor_report()); compositor.composite(); } TEST_F(DefaultDisplayBufferCompositor, skips_scene_that_should_not_be_rendered) { using namespace testing; mtd::StubDisplayBuffer display_buffer{geom::Rectangle{{0,0},{14,14}}}; auto mock_renderable1 = std::make_shared>(); auto mock_renderable2 = std::make_shared>(); auto mock_renderable3 = std::make_shared>(); auto buf = std::make_shared(); EXPECT_CALL(*mock_renderable1, buffer(_)) .WillOnce(Return(buf)); EXPECT_CALL(*mock_renderable2, buffer(_)) .Times(0); EXPECT_CALL(*mock_renderable3, buffer(_)) .WillOnce(Return(buf)); glm::mat4 simple; EXPECT_CALL(*mock_renderable1, transformation()) .WillOnce(Return(simple)); EXPECT_CALL(*mock_renderable2, transformation()) .WillOnce(Return(simple)); EXPECT_CALL(*mock_renderable3, transformation()) .WillOnce(Return(simple)); EXPECT_CALL(*mock_renderable1, visible()) .WillRepeatedly(Return(true)); EXPECT_CALL(*mock_renderable2, visible()) .WillRepeatedly(Return(false)); EXPECT_CALL(*mock_renderable3, visible()) .WillRepeatedly(Return(true)); EXPECT_CALL(*mock_renderable1, alpha()) .WillOnce(Return(1.0f)); EXPECT_CALL(*mock_renderable3, alpha()) .WillOnce(Return(1.0f)); EXPECT_CALL(*mock_renderable1, shaped()) .WillOnce(Return(false)); EXPECT_CALL(*mock_renderable3, shaped()) .WillOnce(Return(false)); EXPECT_CALL(*mock_renderable1, screen_position()) .WillRepeatedly(Return(geom::Rectangle{{1,2}, {3,4}})); EXPECT_CALL(*mock_renderable2, screen_position()) .WillRepeatedly(Return(geom::Rectangle{{1,2}, {3,4}})); EXPECT_CALL(*mock_renderable3, screen_position()) .WillRepeatedly(Return(geom::Rectangle{{5,6}, {7,8}})); mg::RenderableList list{ mock_renderable1, mock_renderable2, mock_renderable3 }; FakeScene scene(list); EXPECT_CALL(mock_renderer, render(Ref(*mock_renderable1),_)) .Times(1); EXPECT_CALL(mock_renderer, render(Ref(*mock_renderable2),_)) .Times(0); EXPECT_CALL(mock_renderer, render(Ref(*mock_renderable3),_)) .Times(1); mc::DefaultDisplayBufferCompositor compositor( display_buffer, mt::fake_shared(scene), mt::fake_shared(mock_renderer), mr::null_compositor_report()); compositor.composite(); } TEST_F(DefaultDisplayBufferCompositor, bypass_skips_composition) { using namespace testing; ON_CALL(display_buffer, can_bypass()) .WillByDefault(Return(true)); mg::RenderableList list{ small, fullscreen }; FakeScene scene(list); EXPECT_CALL(mock_renderer, suspend()) .Times(1); EXPECT_CALL(mock_renderer, begin()) .Times(0); EXPECT_CALL(mock_renderer, render(Ref(*small),_)) .Times(0); EXPECT_CALL(mock_renderer, render(Ref(*fullscreen),_)) .Times(0); EXPECT_CALL(mock_renderer, end()) .Times(0); auto compositor_buffer = std::make_shared(); fullscreen->set_buffer(compositor_buffer); EXPECT_CALL(*compositor_buffer, can_bypass()) .WillOnce(Return(true)); auto report = std::make_shared(); EXPECT_CALL(*report, began_frame(_)); EXPECT_CALL(*report, finished_frame(true,_)); mc::DefaultDisplayBufferCompositor compositor( display_buffer, mt::fake_shared(scene), mt::fake_shared(mock_renderer), report); compositor.composite(); } TEST_F(DefaultDisplayBufferCompositor, calls_renderer_in_sequence) { using namespace testing; mg::RenderableList list{ big, small }; FakeScene scene(list); Sequence render_seq; EXPECT_CALL(mock_renderer, suspend()) .Times(0); EXPECT_CALL(display_buffer, make_current()) .InSequence(render_seq); EXPECT_CALL(display_buffer, orientation()) .InSequence(render_seq) .WillOnce(Return(mir_orientation_normal)); EXPECT_CALL(mock_renderer, set_rotation(_)) .InSequence(render_seq); EXPECT_CALL(mock_renderer, begin()) .InSequence(render_seq); EXPECT_CALL(mock_renderer, render(Ref(*big),_)) .InSequence(render_seq); EXPECT_CALL(mock_renderer, render(Ref(*small),_)) .InSequence(render_seq); EXPECT_CALL(mock_renderer, end()) .InSequence(render_seq); EXPECT_CALL(display_buffer, post_update()) .InSequence(render_seq); mc::DefaultDisplayBufferCompositor compositor( display_buffer, mt::fake_shared(scene), mt::fake_shared(mock_renderer), mr::null_compositor_report()); compositor.composite(); } TEST_F(DefaultDisplayBufferCompositor, obscured_fullscreen_does_not_bypass) { using namespace testing; ON_CALL(display_buffer, can_bypass()) .WillByDefault(Return(true)); mg::RenderableList list{ fullscreen, small }; FakeScene scene(list); auto report = std::make_shared(); InSequence seq; EXPECT_CALL(*report, began_frame(_)) .Times(1); EXPECT_CALL(display_buffer, make_current()) .Times(1); EXPECT_CALL(mock_renderer, render(Ref(*fullscreen),_)) .Times(1); EXPECT_CALL(mock_renderer, render(Ref(*small),_)) .Times(1); EXPECT_CALL(display_buffer, post_update()) .Times(1); EXPECT_CALL(*report, finished_frame(false,_)) .Times(1); mc::DefaultDisplayBufferCompositor compositor( display_buffer, mt::fake_shared(scene), mt::fake_shared(mock_renderer), report); compositor.composite(); } TEST_F(DefaultDisplayBufferCompositor, platform_does_not_support_bypass) { using namespace testing; mg::RenderableList list{ small, //obscured fullscreen }; FakeScene scene(list); EXPECT_CALL(display_buffer, view_area()) .WillRepeatedly(Return(screen)); EXPECT_CALL(display_buffer, make_current()) .Times(1); EXPECT_CALL(display_buffer, orientation()) .WillOnce(Return(mir_orientation_normal)); EXPECT_CALL(display_buffer, post_update()) .Times(1); EXPECT_CALL(display_buffer, can_bypass()) .WillRepeatedly(Return(false)); EXPECT_CALL(mock_renderer, render(Ref(*small),_)) .Times(0); // zero due to occlusion detection EXPECT_CALL(mock_renderer, render(Ref(*fullscreen),_)) .Times(1); mc::DefaultDisplayBufferCompositor compositor( display_buffer, mt::fake_shared(scene), mt::fake_shared(mock_renderer), mr::null_compositor_report()); compositor.composite(); } TEST_F(DefaultDisplayBufferCompositor, bypass_aborted_for_incompatible_buffers) { using namespace testing; EXPECT_CALL(display_buffer, view_area()) .WillRepeatedly(Return(screen)); EXPECT_CALL(display_buffer, make_current()) .Times(1); EXPECT_CALL(display_buffer, orientation()) .WillOnce(Return(mir_orientation_normal)); EXPECT_CALL(display_buffer, post_update()) .Times(1); EXPECT_CALL(display_buffer, can_bypass()) .WillRepeatedly(Return(true)); mg::RenderableList list{ small, //obscured fullscreen }; FakeScene scene(list); EXPECT_CALL(mock_renderer, render(Ref(*small),_)) .Times(0); // zero due to occlusion detection EXPECT_CALL(mock_renderer, render(Ref(*fullscreen),_)) .Times(1); auto nonbypassable = std::make_shared(); fullscreen->set_buffer(nonbypassable); EXPECT_CALL(*nonbypassable, can_bypass()) .WillRepeatedly(Return(false)); mc::DefaultDisplayBufferCompositor compositor( display_buffer, mt::fake_shared(scene), mt::fake_shared(mock_renderer), mr::null_compositor_report()); compositor.composite(); } TEST_F(DefaultDisplayBufferCompositor, bypass_toggles_seamlessly) { using namespace testing; auto compositor_buffer = std::make_shared(); fullscreen->set_buffer(compositor_buffer); ON_CALL(display_buffer, can_bypass()) .WillByDefault(Return(true)); ON_CALL(display_buffer, view_area()) .WillByDefault(Return(screen)); ON_CALL(display_buffer, orientation()) .WillByDefault(Return(mir_orientation_normal)); ON_CALL(*compositor_buffer, can_bypass()) .WillByDefault(Return(true)); Sequence seq; // Frame 1: small window over fullscreen = no bypass EXPECT_CALL(display_buffer, make_current()) .InSequence(seq); EXPECT_CALL(display_buffer, orientation()) .InSequence(seq); EXPECT_CALL(mock_renderer, set_rotation(mir_orientation_normal)) .InSequence(seq); EXPECT_CALL(mock_renderer, begin()) .InSequence(seq); EXPECT_CALL(mock_renderer, render(Ref(*fullscreen),_)) .InSequence(seq); EXPECT_CALL(mock_renderer, render(Ref(*small),_)) .InSequence(seq); EXPECT_CALL(display_buffer, post_update()) .InSequence(seq); // Frame 2: fullscreen over small window = bypass //we should be testing that post_buffer is called, not just that //we check the bits on the compositor buffer EXPECT_CALL(*compositor_buffer, can_bypass()) .InSequence(seq); // Frame 3: only a small window = no bypass EXPECT_CALL(display_buffer, make_current()) .InSequence(seq); EXPECT_CALL(display_buffer, orientation()) .InSequence(seq); EXPECT_CALL(mock_renderer, set_rotation(mir_orientation_normal)) .InSequence(seq); EXPECT_CALL(mock_renderer, begin()) .InSequence(seq); EXPECT_CALL(mock_renderer, render(Ref(*small),_)) .InSequence(seq); EXPECT_CALL(display_buffer, post_update()) .InSequence(seq); mg::RenderableList first_list { fullscreen, small }; mg::RenderableList second_list { small, fullscreen }; mg::RenderableList third_list { small }; FakeScene scene(first_list); mc::DefaultDisplayBufferCompositor compositor( display_buffer, mt::fake_shared(scene), mt::fake_shared(mock_renderer), mr::null_compositor_report()); compositor.composite(); scene.change(second_list); compositor.composite(); scene.change(third_list); compositor.composite(); } TEST_F(DefaultDisplayBufferCompositor, occluded_surfaces_are_not_rendered) { using namespace testing; EXPECT_CALL(display_buffer, view_area()) .WillRepeatedly(Return(screen)); EXPECT_CALL(display_buffer, orientation()) .WillOnce(Return(mir_orientation_normal)); EXPECT_CALL(display_buffer, can_bypass()) .WillRepeatedly(Return(false)); auto window0 = std::make_shared(99, 99, 2, 2); auto window1 = std::make_shared(10, 10, 20, 20); auto window2 = std::make_shared(0,0,100,100); auto window3 = std::make_shared(0,0,100,100); auto window4 = std::make_shared(0,0,500,500, 1.0f, true, false, true); mg::RenderableList list({ window0, //not occluded window1, //occluded window2, //occluded window3, //not occluded window4 //invisible }); FakeScene scene(list); Sequence seq; EXPECT_CALL(display_buffer, make_current()) .InSequence(seq); EXPECT_CALL(mock_renderer, render(Ref(*window0),_)) .InSequence(seq); EXPECT_CALL(mock_renderer, render(Ref(*window3),_)) .InSequence(seq); EXPECT_CALL(display_buffer, post_update()) .InSequence(seq); mc::DefaultDisplayBufferCompositor compositor( display_buffer, mt::fake_shared(scene), mt::fake_shared(mock_renderer), mr::null_compositor_report()); compositor.composite(); } //test associated with lp:1290306, 1293896, 1294048, 1294051, 1294053 TEST_F(DefaultDisplayBufferCompositor, decides_whether_to_recomposite_before_rendering) { using namespace testing; ON_CALL(display_buffer, view_area()) .WillByDefault(Return(screen)); ON_CALL(display_buffer, orientation()) .WillByDefault(Return(mir_orientation_normal)); ON_CALL(display_buffer, can_bypass()) .WillByDefault(Return(false)); auto mock_renderable = std::make_shared>(); ON_CALL(*mock_renderable, screen_position()) .WillByDefault(Return(geom::Rectangle{{0,0},{200,200}})); //check for how many buffers should come before accessing the buffers. Sequence seq; EXPECT_CALL(*mock_renderable, buffers_ready_for_compositor()) .InSequence(seq) .WillOnce(Return(2)); EXPECT_CALL(*mock_renderable, buffer(_)) .InSequence(seq); EXPECT_CALL(*mock_renderable, buffers_ready_for_compositor()) .InSequence(seq) .WillOnce(Return(1)); EXPECT_CALL(*mock_renderable, buffer(_)) .InSequence(seq); mg::RenderableList list({mock_renderable}); FakeScene scene(list); mc::DefaultDisplayBufferCompositor compositor( display_buffer, mt::fake_shared(scene), mt::fake_shared(mock_renderer), mr::null_compositor_report()); EXPECT_TRUE(compositor.composite()); EXPECT_FALSE(compositor.composite()); } mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/test_switching_bundle.cpp0000644000015301777760000007043412322054247027464 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/compositor/switching_bundle.h" #include "mir_test_doubles/stub_buffer_allocator.h" #include "mir_test_doubles/stub_buffer.h" #include #include #include #include #include namespace geom=mir::geometry; namespace mtd=mir::test::doubles; namespace mc=mir::compositor; namespace mg = mir::graphics; using namespace testing; namespace { struct SwitchingBundleTest : public ::testing::Test { void SetUp() { allocator = std::make_shared(); basic_properties = { geom::Size{3, 4}, mir_pixel_format_abgr_8888, mg::BufferUsage::hardware }; } std::shared_ptr allocator; mg::BufferProperties basic_properties; }; auto client_acquire_blocking(mc::SwitchingBundle& switching_bundle) -> mg::Buffer* { std::mutex mutex; std::condition_variable cv; bool done = false; mg::Buffer* result; switching_bundle.client_acquire( [&](mg::Buffer* new_buffer) { std::unique_lock lock(mutex); result = new_buffer; done = true; cv.notify_one(); }); std::unique_lock lock(mutex); cv.wait(lock, [&]{ return done; }); return result; } } TEST_F(SwitchingBundleTest, sync_swapper_by_default) { mg::BufferProperties properties{geom::Size{7, 8}, mir_pixel_format_argb_8888, mg::BufferUsage::software}; for (int nbuffers = mc::SwitchingBundle::min_buffers; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, properties); EXPECT_FALSE(bundle.framedropping_allowed()); EXPECT_EQ(properties, bundle.properties()); } } TEST_F(SwitchingBundleTest, invalid_nbuffers) { EXPECT_THROW( mc::SwitchingBundle a(0, allocator, basic_properties), std::logic_error ); EXPECT_THROW( mc::SwitchingBundle b(-1, allocator, basic_properties), std::logic_error ); EXPECT_THROW( mc::SwitchingBundle c(-123, allocator, basic_properties), std::logic_error ); EXPECT_THROW( mc::SwitchingBundle d(10, allocator, basic_properties), std::logic_error ); } TEST_F(SwitchingBundleTest, client_acquire_basic) { for (int nbuffers = mc::SwitchingBundle::min_buffers; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); auto buffer = client_acquire_blocking(bundle); bundle.client_release(buffer); } } namespace { void composite_thread(mc::SwitchingBundle &bundle, mg::BufferID &composited) { auto buffer = bundle.compositor_acquire(nullptr); composited = buffer->id(); bundle.compositor_release(buffer); } } TEST_F(SwitchingBundleTest, is_really_synchronous) { for (int nbuffers = mc::SwitchingBundle::min_buffers; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); mg::BufferID prev_id, prev_prev_id; ASSERT_FALSE(bundle.framedropping_allowed()); for (int i = 0; i < 20; i++) { auto client1 = client_acquire_blocking(bundle); mg::BufferID expect_id = client1->id(), composited_id; bundle.client_release(client1); std::thread compositor(composite_thread, std::ref(bundle), std::ref(composited_id)); compositor.join(); ASSERT_EQ(expect_id, composited_id); if (i >= 2 && nbuffers == 2) ASSERT_EQ(composited_id, prev_prev_id); prev_prev_id = prev_id; prev_id = composited_id; auto second_monitor = bundle.compositor_acquire(this); ASSERT_EQ(composited_id, second_monitor->id()); bundle.compositor_release(second_monitor); } } } TEST_F(SwitchingBundleTest, framedropping_clients_never_block) { for (int nbuffers = 2; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); bundle.allow_framedropping(true); mg::BufferID last_client_id; for (int i = 0; i < 10; i++) { for (int j = 0; j < 100; j++) { auto client = client_acquire_blocking(bundle); last_client_id = client->id(); bundle.client_release(client); } // Flush the pipeline of previously ready buffers for (int k = 0; k < nbuffers-1; k++) { bundle.compositor_release(bundle.compositor_acquire(nullptr)); } auto compositor = bundle.compositor_acquire(nullptr); ASSERT_EQ(last_client_id, compositor->id()); bundle.compositor_release(compositor); } } } TEST_F(SwitchingBundleTest, clients_dont_recycle_startup_buffer) { // Regression test for LP: #1210042 mc::SwitchingBundle bundle(3, allocator, basic_properties); auto client1 = client_acquire_blocking(bundle); auto client1_id = client1->id(); bundle.client_release(client1); auto client2 = client_acquire_blocking(bundle); bundle.client_release(client2); auto compositor = bundle.compositor_acquire(nullptr); EXPECT_EQ(client1_id, compositor->id()); bundle.compositor_release(compositor); } TEST_F(SwitchingBundleTest, out_of_order_client_release) { for (int nbuffers = 2; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); auto client1 = client_acquire_blocking(bundle); auto client2 = client_acquire_blocking(bundle); EXPECT_THROW( bundle.client_release(client2), std::logic_error ); bundle.client_release(client1); EXPECT_THROW( bundle.client_release(client1), std::logic_error ); } } TEST_F(SwitchingBundleTest, compositor_acquire_basic) { for (int nbuffers = mc::SwitchingBundle::min_buffers; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); auto client = client_acquire_blocking(bundle); auto client_id = client->id(); bundle.client_release(client); auto compositor = bundle.compositor_acquire(nullptr); ASSERT_EQ(client_id, compositor->id()); bundle.compositor_release(compositor); } } TEST_F(SwitchingBundleTest, multimonitor_frame_sync) { for (int nbuffers = mc::SwitchingBundle::min_buffers; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); auto client = client_acquire_blocking(bundle); auto client_id = client->id(); bundle.client_release(client); for (int monitor = 0; monitor < 10; monitor++) { void const* user_id = reinterpret_cast(monitor); auto compositor = bundle.compositor_acquire(user_id); ASSERT_EQ(client_id, compositor->id()); bundle.compositor_release(compositor); } } } TEST_F(SwitchingBundleTest, frames_in_order) { int const nbuffers = 3; mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); mg::Buffer* clients[nbuffers]; for (auto& client : clients) { client = client_acquire_blocking(bundle); bundle.client_release(client); } for (int frame = 0; frame < nbuffers; ++frame) { if (frame > 0) ASSERT_NE(clients[frame-1]->id(), clients[frame]->id()); auto compositor = bundle.compositor_acquire(nullptr); ASSERT_EQ(clients[frame]->id(), compositor->id()); bundle.compositor_release(compositor); } } TEST_F(SwitchingBundleTest, compositor_acquire_never_blocks) { for (int nbuffers = mc::SwitchingBundle::min_buffers; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); const int N = 100; bundle.force_requests_to_complete(); std::shared_ptr buf[N]; for (int i = 0; i < N; i++) buf[i] = bundle.compositor_acquire(nullptr); for (int i = 0; i < N; i++) bundle.compositor_release(buf[i]); } } TEST_F(SwitchingBundleTest, compositor_acquire_recycles_latest_ready_buffer) { for (int nbuffers = mc::SwitchingBundle::min_buffers; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); mg::BufferID client_id; for (int i = 0; i < 20; i++) { if (i % 10 == 0) { auto client = client_acquire_blocking(bundle); client_id = client->id(); bundle.client_release(client); } for (int monitor_id = 0; monitor_id < 10; monitor_id++) { void const* user_id = reinterpret_cast(monitor_id); auto compositor = bundle.compositor_acquire(user_id); ASSERT_EQ(client_id, compositor->id()); bundle.compositor_release(compositor); } } } } TEST_F(SwitchingBundleTest, compositor_release_verifies_parameter) { for (int nbuffers = 2; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); auto client = client_acquire_blocking(bundle); bundle.client_release(client); auto compositor1 = bundle.compositor_acquire(nullptr); bundle.compositor_release(compositor1); EXPECT_THROW( bundle.compositor_release(compositor1), std::logic_error ); } } /* Regression test for LP#1270964 In the original bug, SwitchingBundle::last_consumed would be used without ever being set in the compositor_acquire() call, thus its initial value of zero would wrongly be used and lead to the wrong buffer being given to the compositor */ TEST_F(SwitchingBundleTest, compositor_client_interleaved) { int nbuffers = 3; mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); mg::Buffer* client_buffer = nullptr; std::shared_ptr compositor_buffer = nullptr; client_buffer = client_acquire_blocking(bundle); mg::BufferID first_ready_buffer_id = client_buffer->id(); bundle.client_release(client_buffer); client_buffer = client_acquire_blocking(bundle); // in the original bug, compositor would be given the wrong buffer here compositor_buffer = bundle.compositor_acquire(0); ASSERT_EQ(first_ready_buffer_id, compositor_buffer->id()); // Clean up bundle.client_release(client_buffer); bundle.compositor_release(compositor_buffer); compositor_buffer.reset(); } TEST_F(SwitchingBundleTest, overlapping_compositors_get_different_frames) { // This test simulates bypass behaviour for (int nbuffers = 2; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); std::shared_ptr compositor[2]; bundle.client_release(client_acquire_blocking(bundle)); compositor[0] = bundle.compositor_acquire(nullptr); bundle.client_release(client_acquire_blocking(bundle)); compositor[1] = bundle.compositor_acquire(nullptr); for (int i = 0; i < 20; i++) { // Two compositors acquired, and they're always different... ASSERT_NE(compositor[0]->id(), compositor[1]->id()); // One of the compositors (the oldest one) gets a new buffer... int oldest = i & 1; bundle.compositor_release(compositor[oldest]); bundle.client_release(client_acquire_blocking(bundle)); compositor[oldest] = bundle.compositor_acquire(nullptr); } bundle.compositor_release(compositor[0]); bundle.compositor_release(compositor[1]); } } TEST_F(SwitchingBundleTest, snapshot_acquire_basic) { for (int nbuffers = mc::SwitchingBundle::min_buffers; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); auto compositor = bundle.compositor_acquire(nullptr); auto snapshot = bundle.snapshot_acquire(); EXPECT_EQ(snapshot->id(), compositor->id()); bundle.compositor_release(compositor); bundle.snapshot_release(snapshot); } } TEST_F(SwitchingBundleTest, snapshot_acquire_never_blocks) { for (int nbuffers = mc::SwitchingBundle::min_buffers; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); const int N = 100; std::shared_ptr buf[N]; for (int i = 0; i < N; i++) buf[i] = bundle.snapshot_acquire(); for (int i = 0; i < N; i++) bundle.snapshot_release(buf[i]); } } TEST_F(SwitchingBundleTest, snapshot_release_verifies_parameter) { for (int nbuffers = 2; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); auto compositor = bundle.compositor_acquire(nullptr); EXPECT_THROW( bundle.snapshot_release(compositor), std::logic_error ); auto client = client_acquire_blocking(bundle); auto snapshot = bundle.snapshot_acquire(); EXPECT_EQ(compositor->id(), snapshot->id()); EXPECT_NE(client->id(), snapshot->id()); bundle.snapshot_release(snapshot); EXPECT_THROW( bundle.snapshot_release(snapshot), std::logic_error ); } } namespace { void compositor_thread(mc::SwitchingBundle &bundle, std::atomic &done) { while (!done) { bundle.compositor_release(bundle.compositor_acquire(nullptr)); std::this_thread::yield(); } } void snapshot_thread(mc::SwitchingBundle &bundle, std::atomic &done) { while (!done) { bundle.snapshot_release(bundle.snapshot_acquire()); std::this_thread::yield(); } } void client_thread(mc::SwitchingBundle &bundle, int nframes) { for (int i = 0; i < nframes; i++) { bundle.client_release(client_acquire_blocking(bundle)); std::this_thread::yield(); } } void switching_client_thread(mc::SwitchingBundle &bundle, int nframes) { for (int i = 0; i < nframes; i += 10) { bundle.allow_framedropping(false); for (int j = 0; j < 5; j++) bundle.client_release(client_acquire_blocking(bundle)); std::this_thread::yield(); bundle.allow_framedropping(true); for (int j = 0; j < 5; j++) bundle.client_release(client_acquire_blocking(bundle)); std::this_thread::yield(); } } } TEST_F(SwitchingBundleTest, stress) { for (int nbuffers = 2; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); std::atomic done; done = false; std::thread compositor(compositor_thread, std::ref(bundle), std::ref(done)); std::thread snapshotter1(snapshot_thread, std::ref(bundle), std::ref(done)); std::thread snapshotter2(snapshot_thread, std::ref(bundle), std::ref(done)); bundle.allow_framedropping(false); std::thread client1(client_thread, std::ref(bundle), 1000); client1.join(); bundle.allow_framedropping(true); std::thread client2(client_thread, std::ref(bundle), 1000); client2.join(); std::thread client3(switching_client_thread, std::ref(bundle), 1000); client3.join(); done = true; compositor.join(); snapshotter1.join(); snapshotter2.join(); } } // FIXME (enabling this optimization breaks timing tests) TEST_F(SwitchingBundleTest, DISABLED_synchronous_clients_only_get_two_real_buffers) { /* * You might ask for more buffers, but we should only allocate two * unique ones while it makes sense to do so. Buffers are big things and * should be allocated sparingly... */ for (int nbuffers = mc::SwitchingBundle::min_buffers; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); bundle.allow_framedropping(false); const int nframes = 100; mg::BufferID prev_id, prev_prev_id; std::thread client(client_thread, std::ref(bundle), nframes); for (int frame = 0; frame < nframes; frame++) { auto compositor = bundle.compositor_acquire(nullptr); auto compositor_id = compositor->id(); bundle.compositor_release(compositor); if (frame >= 2) ASSERT_EQ(prev_prev_id, compositor_id); prev_prev_id = prev_id; prev_id = compositor_id; } client.join(); } } TEST_F(SwitchingBundleTest, bypass_clients_get_more_than_two_buffers) { for (int nbuffers = 3; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); std::shared_ptr compositor[2]; bundle.client_release(client_acquire_blocking(bundle)); compositor[0] = bundle.compositor_acquire(nullptr); bundle.client_release(client_acquire_blocking(bundle)); compositor[1] = bundle.compositor_acquire(nullptr); for (int i = 0; i < 20; i++) { // Two compositors acquired, and they're always different... ASSERT_NE(compositor[0]->id(), compositor[1]->id()); auto client = client_acquire_blocking(bundle); ASSERT_NE(compositor[0]->id(), client->id()); ASSERT_NE(compositor[1]->id(), client->id()); bundle.client_release(client); // One of the compositors (the oldest one) gets a new buffer... int oldest = i & 1; bundle.compositor_release(compositor[oldest]); compositor[oldest] = bundle.compositor_acquire(nullptr); } bundle.compositor_release(compositor[0]); bundle.compositor_release(compositor[1]); } } TEST_F(SwitchingBundleTest, framedropping_clients_get_all_buffers) { for (int nbuffers = 2; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); bundle.allow_framedropping(true); const int nframes = 100; mg::BufferID expect[mc::SwitchingBundle::max_buffers]; mg::Buffer* buf[mc::SwitchingBundle::max_buffers]; for (int b = 0; b < nbuffers; b++) { buf[b] = client_acquire_blocking(bundle); expect[b] = buf[b]->id(); for (int p = 0; p < b; p++) ASSERT_NE(expect[p], expect[b]); } for (int b = 0; b < nbuffers; b++) bundle.client_release(buf[b]); for (int frame = 0; frame < nframes; frame++) { auto client = client_acquire_blocking(bundle); ASSERT_EQ(expect[frame % nbuffers], client->id()); bundle.client_release(client); } } } TEST_F(SwitchingBundleTest, waiting_clients_unblock_on_shutdown) { for (int nbuffers = 2; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); bundle.allow_framedropping(false); std::thread client(client_thread, std::ref(bundle), nbuffers); /* * Tecnhically we would like to distinguish between final shutdown * and temporary shutdown (VT switch). The former should permanently * unblock clients. The latter only temporarily unblock clients. * But that requires interface changes all over the place... */ bundle.force_requests_to_complete(); client.join(); } } TEST_F(SwitchingBundleTest, waiting_clients_unblock_on_vt_switch_not_permanent) { // Regression test for LP: #1207226 for (int nbuffers = 2; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); bundle.allow_framedropping(false); std::thread client(client_thread, std::ref(bundle), nbuffers); bundle.force_requests_to_complete(); client.join(); EXPECT_FALSE(bundle.framedropping_allowed()); } } TEST_F(SwitchingBundleTest, client_framerate_matches_compositor) { for (int nbuffers = 2; nbuffers <= 3; nbuffers++) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); unsigned long client_frames = 0; const unsigned long compose_frames = 20; bundle.allow_framedropping(false); std::atomic done(false); std::thread monitor1([&] { for (unsigned long frame = 0; frame != compose_frames+3; frame++) { std::this_thread::sleep_for(std::chrono::milliseconds(10)); auto buf = bundle.compositor_acquire(this); bundle.compositor_release(buf); if (frame == compose_frames) { // Tell the "client" to stop after compose_frames, but // don't stop rendering immediately to avoid blocking // if we rendered any twice done.store(true); } } }); bundle.client_release(client_acquire_blocking(bundle)); while (!done.load()) { bundle.client_release(client_acquire_blocking(bundle)); client_frames++; } monitor1.join(); // Roughly compose_frames == client_frames within 50% ASSERT_GT(client_frames, compose_frames / 2); ASSERT_LT(client_frames, compose_frames * 3 / 2); } } TEST_F(SwitchingBundleTest, slow_client_framerate_matches_compositor) { // Regression test LP: #1241369 / LP: #1241371 for (int nbuffers = 2; nbuffers <= 3; nbuffers++) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); unsigned long client_frames = 0; const unsigned long compose_frames = 100; const auto frame_time = std::chrono::milliseconds(16); bundle.allow_framedropping(false); std::atomic done(false); std::mutex sync; std::thread monitor1([&] { for (unsigned long frame = 0; frame != compose_frames+3; frame++) { std::this_thread::sleep_for(frame_time); sync.lock(); auto buf = bundle.compositor_acquire(this); bundle.compositor_release(buf); sync.unlock(); if (frame == compose_frames) { // Tell the "client" to stop after compose_frames, but // don't stop rendering immediately to avoid blocking // if we rendered any twice done.store(true); } } }); bundle.client_release(client_acquire_blocking(bundle)); while (!done.load()) { sync.lock(); sync.unlock(); auto buf = client_acquire_blocking(bundle); std::this_thread::sleep_for(frame_time); bundle.client_release(buf); client_frames++; } monitor1.join(); // Roughly compose_frames == client_frames within 20% ASSERT_GT(client_frames, compose_frames * 0.8f); ASSERT_LT(client_frames, compose_frames * 1.2f); } } TEST_F(SwitchingBundleTest, resize_affects_client_acquires_immediately) { for (int nbuffers = mc::SwitchingBundle::min_buffers; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); for (int width = 1; width < 100; ++width) { const geom::Size expect_size{width, width * 2}; for (int subframe = 0; subframe < 3; ++subframe) { bundle.resize(expect_size); auto client = client_acquire_blocking(bundle); ASSERT_EQ(expect_size, client->size()); bundle.client_release(client); auto compositor = bundle.compositor_acquire(nullptr); ASSERT_EQ(expect_size, compositor->size()); bundle.compositor_release(compositor); } } } } TEST_F(SwitchingBundleTest, compositor_acquires_resized_frames) { for (int nbuffers = mc::SwitchingBundle::min_buffers; nbuffers <= mc::SwitchingBundle::max_buffers; ++nbuffers) { mc::SwitchingBundle bundle(nbuffers, allocator, basic_properties); mg::BufferID history[5]; const int width0 = 123; const int height0 = 456; const int dx = 2; const int dy = -3; int width = width0; int height = height0; for (int produce = 0; produce < nbuffers; ++produce) { geom::Size new_size{width, height}; width += dx; height += dy; bundle.resize(new_size); auto client = client_acquire_blocking(bundle); history[produce] = client->id(); ASSERT_EQ(new_size, client->size()); bundle.client_release(client); } width = width0; height = height0; for (int consume = 0; consume < nbuffers; ++consume) { geom::Size expect_size{width, height}; width += dx; height += dy; auto compositor = bundle.compositor_acquire(nullptr); // Verify the compositor gets resized buffers, eventually ASSERT_EQ(expect_size, compositor->size()); // Verify the compositor gets buffers with *contents*, ie. that // they have not been resized prematurely and are empty. ASSERT_EQ(history[consume], compositor->id()); bundle.compositor_release(compositor); } // Verify the final buffer size sticks const geom::Size final_size{width - dx, height - dy}; for (int unchanging = 0; unchanging < 100; ++unchanging) { auto compositor = bundle.compositor_acquire(nullptr); ASSERT_EQ(final_size, compositor->size()); bundle.compositor_release(compositor); } } } mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/CMakeLists.txt0000644000015301777760000000132512322054223025114 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_default_display_buffer_compositor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_buffer_stream.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_temporary_buffers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_rendering_operator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_multi_threaded_compositor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_switching_bundle.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_gl_renderer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_bypass.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_occlusion.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_screencast_display_buffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_compositing_screencast.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/test_bypass.cpp0000644000015301777760000002365312322054223025430 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/compositor/bypass.h" #include "mir_test_doubles/mock_display_buffer.h" #include "mir_test_doubles/fake_renderable.h" #include #include using namespace testing; using namespace mir::geometry; using namespace mir::compositor; using namespace mir::test::doubles; struct BypassFilterTest : public Test { BypassFilterTest() { monitor_rect[0].top_left = {0, 0}; monitor_rect[0].size = {1920, 1200}; EXPECT_CALL(display_buffer[0], view_area()) .WillRepeatedly(Return(monitor_rect[0])); monitor_rect[1].top_left = {1920, 0}; monitor_rect[1].size = {1920, 1200}; EXPECT_CALL(display_buffer[1], view_area()) .WillRepeatedly(Return(monitor_rect[1])); } Rectangle monitor_rect[2]; MockDisplayBuffer display_buffer[2]; }; TEST_F(BypassFilterTest, nothing_matches_nothing) { BypassFilter filter(display_buffer[0]); BypassMatch match; EXPECT_FALSE(filter.fullscreen_on_top()); EXPECT_FALSE(match.topmost_fullscreen()); } TEST_F(BypassFilterTest, small_window_not_bypassed) { BypassFilter filter(display_buffer[0]); FakeRenderable win(12, 34, 56, 78); EXPECT_FALSE(filter(win)); EXPECT_FALSE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, single_fullscreen_window_bypassed) { BypassFilter filter(display_buffer[0]); FakeRenderable win(0, 0, 1920, 1200); EXPECT_TRUE(filter(win)); EXPECT_TRUE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, translucent_fullscreen_window_not_bypassed) { BypassFilter filter(display_buffer[0]); FakeRenderable win(0, 0, 1920, 1200, 0.5f); EXPECT_FALSE(filter(win)); EXPECT_FALSE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, hidden_fullscreen_window_not_bypassed) { BypassFilter filter(display_buffer[0]); FakeRenderable win(0, 0, 1920, 1200, 1.0f, true, false); EXPECT_FALSE(filter(win)); EXPECT_FALSE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, unposted_fullscreen_window_not_bypassed) { BypassFilter filter(display_buffer[0]); FakeRenderable win(0, 0, 1920, 1200, 1.0f, true, true, false); EXPECT_FALSE(filter(win)); EXPECT_FALSE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, shaped_fullscreen_window_not_bypassed) { BypassFilter filter(display_buffer[0]); FakeRenderable win(0, 0, 1920, 1200, 1.0f, false); EXPECT_FALSE(filter(win)); EXPECT_FALSE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, offset_fullscreen_window_not_bypassed) { BypassFilter filter(display_buffer[0]); FakeRenderable win(10, 50, 1920, 1200); EXPECT_FALSE(filter(win)); EXPECT_FALSE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, obscured_fullscreen_window_not_bypassed) { BypassFilter filter(display_buffer[0]); FakeRenderable fs(0, 0, 1920, 1200); FakeRenderable small(20, 30, 40, 50); EXPECT_TRUE(filter(fs)); EXPECT_FALSE(filter(small)); EXPECT_FALSE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, translucently_obscured_fullscreen_window_not_bypassed) { // Regression test for LP: #1266385 BypassFilter filter(display_buffer[0]); FakeRenderable fs(0, 0, 1920, 1200); FakeRenderable small(20, 30, 40, 50, 0.5f); EXPECT_TRUE(filter(fs)); EXPECT_FALSE(filter(small)); EXPECT_FALSE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, unobscured_fullscreen_window_bypassed) { BypassFilter filter(display_buffer[0]); FakeRenderable fs(0, 0, 1920, 1200); FakeRenderable small(20, 30, 40, 50); EXPECT_FALSE(filter(small)); EXPECT_TRUE(filter(fs)); EXPECT_TRUE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, unobscured_fullscreen_alpha_window_not_bypassed) { BypassFilter filter(display_buffer[0]); FakeRenderable fs(0, 0, 1920, 1200, 0.9f); FakeRenderable small(20, 30, 40, 50); EXPECT_FALSE(filter(small)); EXPECT_FALSE(filter(fs)); EXPECT_FALSE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, many_fullscreen_windows_only_bypass_top) { BypassFilter filter(display_buffer[0]); FakeRenderable a(0, 0, 1920, 1200); EXPECT_TRUE(filter(a)); EXPECT_TRUE(filter.fullscreen_on_top()); FakeRenderable b(1, 2, 3, 4); EXPECT_FALSE(filter(b)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable c(0, 0, 1920, 1200); EXPECT_TRUE(filter(c)); EXPECT_TRUE(filter.fullscreen_on_top()); FakeRenderable d(5, 6, 7, 8); EXPECT_FALSE(filter(d)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable e(0, 0, 1920, 1200); EXPECT_TRUE(filter(e)); EXPECT_TRUE(filter.fullscreen_on_top()); FakeRenderable f(9, 10, 11, 12); EXPECT_FALSE(filter(f)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable g(0, 0, 1920, 1200); EXPECT_TRUE(filter(g)); EXPECT_TRUE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, many_fullscreen_windows_only_bypass_top_rectangular) { BypassFilter filter(display_buffer[0]); FakeRenderable a(0, 0, 1920, 1200, 1.0f, false); EXPECT_FALSE(filter(a)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable b(1, 2, 3, 4); EXPECT_FALSE(filter(b)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable c(0, 0, 1920, 1200); EXPECT_TRUE(filter(c)); EXPECT_TRUE(filter.fullscreen_on_top()); FakeRenderable d(5, 6, 7, 8); EXPECT_FALSE(filter(d)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable e(0, 0, 1920, 1200, 1.0f, true); EXPECT_TRUE(filter(e)); EXPECT_TRUE(filter.fullscreen_on_top()); FakeRenderable f(9, 10, 11, 12); EXPECT_FALSE(filter(f)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable g(0, 0, 1920, 1200, 0.5f, false); EXPECT_FALSE(filter(g)); EXPECT_FALSE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, many_fullscreen_windows_only_bypass_top_visible_posted) { BypassFilter filter(display_buffer[0]); FakeRenderable a(0, 0, 1920, 1200, 1.0f, false); EXPECT_FALSE(filter(a)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable b(1, 2, 3, 4); EXPECT_FALSE(filter(b)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable c(0, 0, 1920, 1200); EXPECT_TRUE(filter(c)); EXPECT_TRUE(filter.fullscreen_on_top()); FakeRenderable d(5, 6, 7, 8); EXPECT_FALSE(filter(d)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable e(0, 0, 1920, 1200, 1.0f, true, false, true); EXPECT_FALSE(filter(e)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable f(0, 0, 1920, 1200, 1.0f, true, true, false); EXPECT_FALSE(filter(f)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable g(9, 10, 11, 12); EXPECT_FALSE(filter(g)); EXPECT_FALSE(filter.fullscreen_on_top()); FakeRenderable h(0, 0, 1920, 1200, 1.0f, true, true, true); EXPECT_TRUE(filter(h)); EXPECT_TRUE(filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, multimonitor_one_bypassed) { BypassFilter left(display_buffer[0]); BypassFilter right(display_buffer[1]); FakeRenderable fs(1920, 0, 1920, 1200); FakeRenderable small(20, 30, 40, 50); EXPECT_FALSE(left(small)); EXPECT_FALSE(left.fullscreen_on_top()); EXPECT_FALSE(left(fs)); EXPECT_FALSE(left.fullscreen_on_top()); EXPECT_FALSE(right(small)); EXPECT_FALSE(right.fullscreen_on_top()); EXPECT_TRUE(right(fs)); EXPECT_TRUE(right.fullscreen_on_top()); EXPECT_FALSE(right(small)); EXPECT_TRUE(right.fullscreen_on_top()); } TEST_F(BypassFilterTest, dual_bypass) { BypassFilter left_filter(display_buffer[0]); BypassFilter right_filter(display_buffer[1]); FakeRenderable left_win(0, 0, 1920, 1200); FakeRenderable right_win(1920, 0, 1920, 1200); EXPECT_TRUE(left_filter(left_win)); EXPECT_TRUE(left_filter.fullscreen_on_top()); EXPECT_FALSE(left_filter(right_win)); EXPECT_TRUE(left_filter.fullscreen_on_top()); EXPECT_FALSE(right_filter(left_win)); EXPECT_FALSE(right_filter.fullscreen_on_top()); EXPECT_TRUE(right_filter(right_win)); EXPECT_TRUE(right_filter.fullscreen_on_top()); } TEST_F(BypassFilterTest, multimonitor_oversized_no_bypass) { BypassFilter left_filter(display_buffer[0]); BypassFilter right_filter(display_buffer[1]); FakeRenderable big_win(0, 0, 3840, 1200); EXPECT_FALSE(left_filter(big_win)); EXPECT_FALSE(left_filter.fullscreen_on_top()); EXPECT_FALSE(right_filter(big_win)); EXPECT_FALSE(right_filter.fullscreen_on_top()); } TEST(BypassMatchTest, defaults_to_null) { BypassMatch match; EXPECT_EQ(nullptr, match.topmost_fullscreen()); } TEST(BypassMatchTest, returns_one) { BypassMatch match; FakeRenderable win(1, 2, 3, 4); EXPECT_EQ(nullptr, match.topmost_fullscreen()); match(win); EXPECT_EQ(&win, match.topmost_fullscreen()); } TEST(BypassMatchTest, returns_latest) { BypassMatch match; FakeRenderable a(1, 2, 3, 4), b(5, 6, 7, 8), c(9, 10, 11, 12); EXPECT_EQ(nullptr, match.topmost_fullscreen()); match(a); EXPECT_EQ(&a, match.topmost_fullscreen()); match(b); EXPECT_EQ(&b, match.topmost_fullscreen()); match(c); EXPECT_EQ(&c, match.topmost_fullscreen()); EXPECT_EQ(&c, match.topmost_fullscreen()); EXPECT_EQ(&c, match.topmost_fullscreen()); } mir-0.1.8+14.04.20140411/tests/unit-tests/compositor/test_gl_renderer.cpp0000644000015301777760000004317012322054247026421 0ustar pbusernogroup00000000000000/* * 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: Sam Spilsbury */ #include #include #include #include #include #include #include #include "mir/compositor/renderer.h" #include "src/server/compositor/gl_renderer_factory.h" #include #include #include #include #include #include using testing::SetArgPointee; using testing::InSequence; using testing::Return; using testing::ReturnRef; using testing::Pointee; using testing::AnyNumber; using testing::AtLeast; using testing::_; namespace mt=mir::test; namespace mtd=mir::test::doubles; namespace mc=mir::compositor; namespace mg=mir::graphics; namespace { const GLint stub_v_shader = 1; const GLint stub_f_shader = 2; const GLint stub_program = 1; const GLuint stub_texture = 1; const GLint transform_uniform_location = 1; const GLint alpha_uniform_location = 2; const GLint position_attr_location = 3; const GLint texcoord_attr_location = 4; const GLint screen_to_gl_coords_uniform_location = 5; const GLint tex_uniform_location = 6; const GLint display_transform_uniform_location = 7; const GLint centre_uniform_location = 8; const std::string stub_info_log = "something failed!"; const size_t stub_info_log_length = stub_info_log.size(); void ExpectShaderCompileFailure(const GLint shader, mtd::MockGL &mock_gl) { EXPECT_CALL(mock_gl, glGetShaderiv(shader, GL_COMPILE_STATUS, _)) .WillOnce(SetArgPointee<2>(GL_FALSE)); } void ExpectShaderCompileSuccess(const GLint shader, mtd::MockGL &mock_gl) { EXPECT_CALL(mock_gl, glGetShaderiv(shader, GL_COMPILE_STATUS, _)) .WillOnce(SetArgPointee<2>(GL_TRUE)); } void SetUpMockVertexShader(mtd::MockGL &mock_gl, const std::function &shader_compile_expectation) { /* Vertex Shader */ EXPECT_CALL(mock_gl, glCreateShader(GL_VERTEX_SHADER)) .WillOnce(Return(stub_v_shader)); EXPECT_CALL(mock_gl, glShaderSource(stub_v_shader, 1, _, 0)); EXPECT_CALL(mock_gl, glCompileShader(stub_v_shader)); shader_compile_expectation(stub_v_shader, mock_gl); } void SetUpMockFragmentShader(mtd::MockGL &mock_gl, const std::function &shader_compile_expectation) { /* Fragment Shader */ EXPECT_CALL(mock_gl, glCreateShader(GL_FRAGMENT_SHADER)) .WillOnce(Return(stub_f_shader)); EXPECT_CALL(mock_gl, glShaderSource(stub_f_shader, 1, _, 0)); EXPECT_CALL(mock_gl, glCompileShader(stub_f_shader)); shader_compile_expectation(stub_f_shader, mock_gl); } void ExpectProgramLinkFailure(const GLint program, mtd::MockGL &mock_gl) { EXPECT_CALL(mock_gl, glGetProgramiv(program, GL_LINK_STATUS, _)) .WillOnce(SetArgPointee<2>(GL_FALSE)); } void ExpectProgramLinkSuccess(const GLint program, mtd::MockGL &mock_gl) { EXPECT_CALL(mock_gl, glGetProgramiv(program, GL_LINK_STATUS, _)) .WillOnce(SetArgPointee<2>(GL_TRUE)); } void SetUpMockGraphicsProgram(mtd::MockGL &mock_gl, const std::function &program_link_expectation) { /* Graphics Program */ EXPECT_CALL(mock_gl, glCreateProgram()) .WillOnce(Return(stub_program)); EXPECT_CALL(mock_gl, glAttachShader(stub_program, stub_v_shader)); EXPECT_CALL(mock_gl, glAttachShader(stub_program, stub_f_shader)); EXPECT_CALL(mock_gl, glLinkProgram(stub_program)); program_link_expectation(stub_program, mock_gl); } void SetUpMockProgramData(mtd::MockGL &mock_gl) { /* Uniforms and Attributes */ EXPECT_CALL(mock_gl, glUseProgram(stub_program)); EXPECT_CALL(mock_gl, glGetUniformLocation(stub_program, _)) .WillOnce(Return(tex_uniform_location)); EXPECT_CALL(mock_gl, glGetUniformLocation(stub_program, _)) .WillOnce(Return(display_transform_uniform_location)); EXPECT_CALL(mock_gl, glGetUniformLocation(stub_program, _)) .WillOnce(Return(transform_uniform_location)); EXPECT_CALL(mock_gl, glGetUniformLocation(stub_program, _)) .WillOnce(Return(alpha_uniform_location)); EXPECT_CALL(mock_gl, glGetAttribLocation(stub_program, _)) .WillOnce(Return(position_attr_location)); EXPECT_CALL(mock_gl, glGetAttribLocation(stub_program, _)) .WillOnce(Return(texcoord_attr_location)); EXPECT_CALL(mock_gl, glGetUniformLocation(stub_program, _)) .WillOnce(Return(centre_uniform_location)); } class GLRendererSetupProcess : public testing::Test { public: mtd::MockGL mock_gl; mc::GLRendererFactory gl_renderer_factory; mir::geometry::Rectangle display_area; }; ACTION_P2(CopyString, str, len) { memcpy(arg3, str, len); arg3[len] = '\0'; } ACTION_P(ReturnByConstReference, cref) { return cref; } MATCHER_P(NthCharacterIsNul, n, "specified character is the nul-byte") { return arg[n] == '\0'; } TEST_F(GLRendererSetupProcess, vertex_shader_compiler_failure_recovers_and_throws) { using namespace std::placeholders; SetUpMockVertexShader(mock_gl, std::bind(ExpectShaderCompileFailure, _1, _2)); EXPECT_CALL(mock_gl, glGetShaderiv(stub_v_shader, GL_INFO_LOG_LENGTH, _)) .WillOnce(SetArgPointee<2>(stub_info_log_length)); EXPECT_CALL(mock_gl, glGetShaderInfoLog(stub_v_shader, stub_info_log_length, _, NthCharacterIsNul(stub_info_log_length))) .WillOnce(CopyString(stub_info_log.c_str(), stub_info_log.size())); EXPECT_THROW({ auto r = gl_renderer_factory.create_renderer_for(display_area); }, std::runtime_error); } TEST_F(GLRendererSetupProcess, fragment_shader_compiler_failure_recovers_and_throw) { using namespace std::placeholders; SetUpMockVertexShader(mock_gl, std::bind(ExpectShaderCompileSuccess, _1, _2)); SetUpMockFragmentShader(mock_gl, std::bind(ExpectShaderCompileFailure, _1, _2)); EXPECT_CALL(mock_gl, glGetShaderiv(stub_f_shader, GL_INFO_LOG_LENGTH, _)) .WillOnce(SetArgPointee<2>(stub_info_log_length)); EXPECT_CALL(mock_gl, glGetShaderInfoLog(stub_f_shader, stub_info_log_length, _, NthCharacterIsNul(stub_info_log_length))) .WillOnce(CopyString(stub_info_log.c_str(), stub_info_log.size())); EXPECT_THROW({ auto r = gl_renderer_factory.create_renderer_for(display_area); }, std::runtime_error); } TEST_F(GLRendererSetupProcess, graphics_program_linker_failure_recovers_and_throw) { using namespace std::placeholders; SetUpMockVertexShader(mock_gl, std::bind(ExpectShaderCompileSuccess, _1, _2)); SetUpMockFragmentShader(mock_gl, std::bind(ExpectShaderCompileSuccess, _1, _2)); SetUpMockGraphicsProgram(mock_gl, std::bind(ExpectProgramLinkFailure, _1, _2)); EXPECT_CALL(mock_gl, glGetProgramiv(stub_program, GL_INFO_LOG_LENGTH, _)) .WillOnce(SetArgPointee<2>(stub_info_log_length)); EXPECT_CALL(mock_gl, glGetProgramInfoLog(stub_program, stub_info_log_length, _, NthCharacterIsNul(stub_info_log_length))) .WillOnce(CopyString(stub_info_log.c_str(), stub_info_log.size())); EXPECT_THROW({ auto r = gl_renderer_factory.create_renderer_for(display_area); }, std::runtime_error); } class GLRenderer : public testing::Test { public: GLRenderer() { using namespace std::placeholders; // Silence warnings about "uninteresting" calls that we truly aren't // interested in (for most test cases)... EXPECT_CALL(mock_gl, glClear(_)).Times(AnyNumber()); EXPECT_CALL(mock_gl, glUseProgram(_)).Times(AnyNumber()); EXPECT_CALL(mock_gl, glActiveTexture(_)).Times(AnyNumber()); EXPECT_CALL(mock_gl, glUniformMatrix4fv(_, _, GL_FALSE, _)) .Times(AtLeast(1)); EXPECT_CALL(mock_gl, glUniform1f(_, _)).Times(AnyNumber()); EXPECT_CALL(mock_gl, glUniform2f(_, _, _)).Times(AnyNumber()); EXPECT_CALL(mock_gl, glBindBuffer(_, _)).Times(AnyNumber()); EXPECT_CALL(mock_gl, glVertexAttribPointer(_, _, _, _, _, _)) .Times(AnyNumber()); EXPECT_CALL(mock_gl, glEnableVertexAttribArray(_)).Times(AnyNumber()); EXPECT_CALL(mock_gl, glDrawArrays(_, _, _)).Times(AnyNumber()); EXPECT_CALL(mock_gl, glDisableVertexAttribArray(_)).Times(AnyNumber()); EXPECT_CALL(renderable, shaped()).WillRepeatedly(Return(false)); EXPECT_CALL(renderable, alpha()).WillRepeatedly(Return(1.0f)); EXPECT_CALL(renderable, transformation()).WillRepeatedly(Return(trans)); EXPECT_CALL(renderable, screen_position()) .WillRepeatedly(Return(mir::geometry::Rectangle{{1,2},{3,4}})); EXPECT_CALL(mock_gl, glDisable(_)).Times(AnyNumber()); InSequence s; SetUpMockVertexShader(mock_gl, std::bind(ExpectShaderCompileSuccess, _1, _2)); SetUpMockFragmentShader(mock_gl, std::bind(ExpectShaderCompileSuccess, _1, _2)); SetUpMockGraphicsProgram(mock_gl, std::bind(ExpectProgramLinkSuccess, _1,_2)); SetUpMockProgramData(mock_gl); EXPECT_CALL(mock_gl, glUniform1i(tex_uniform_location, 0)); EXPECT_CALL(mock_gl, glGetUniformLocation(stub_program, _)) .WillOnce(Return(screen_to_gl_coords_uniform_location)); mc::GLRendererFactory gl_renderer_factory; display_area = {{1, 2}, {3, 4}}; renderer = gl_renderer_factory.create_renderer_for(display_area); EXPECT_CALL(mock_gl, glDeleteShader(stub_v_shader)); EXPECT_CALL(mock_gl, glDeleteShader(stub_f_shader)); EXPECT_CALL(mock_gl, glDeleteProgram(stub_program)); } mtd::MockGL mock_gl; mir::geometry::Rectangle display_area; std::unique_ptr renderer; glm::mat4 trans; mtd::MockRenderable renderable; }; } TEST_F(GLRenderer, TestSetUpRenderContextBeforeRendering) { using namespace std::placeholders; mtd::MockBuffer mock_buffer; InSequence seq; EXPECT_CALL(mock_gl, glClear(_)); EXPECT_CALL(mock_gl, glUseProgram(stub_program)); EXPECT_CALL(renderable, shaped()) .WillOnce(Return(true)); EXPECT_CALL(mock_gl, glEnable(GL_BLEND)); EXPECT_CALL(mock_gl, glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); EXPECT_CALL(mock_gl, glActiveTexture(GL_TEXTURE0)); EXPECT_CALL(mock_gl, glUniform2f(centre_uniform_location, _, _)); EXPECT_CALL(renderable, transformation()) .WillOnce(Return(trans)); EXPECT_CALL(mock_gl, glUniformMatrix4fv(transform_uniform_location, 1, GL_FALSE, _)); EXPECT_CALL(renderable, alpha()) .WillOnce(Return(0.0f)); EXPECT_CALL(mock_gl, glUniform1f(alpha_uniform_location, _)); EXPECT_CALL(mock_buffer, id()) .WillOnce(Return(mg::BufferID(123))); EXPECT_CALL(mock_gl, glGenTextures(1, _)) .WillOnce(SetArgPointee<1>(stub_texture)); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_gl, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _)); EXPECT_CALL(mock_gl, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _)); EXPECT_CALL(mock_gl, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _)); EXPECT_CALL(mock_gl, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _)); EXPECT_CALL(mock_buffer, bind_to_texture()); EXPECT_CALL(mock_gl, glEnableVertexAttribArray(position_attr_location)); EXPECT_CALL(mock_gl, glEnableVertexAttribArray(texcoord_attr_location)); EXPECT_CALL(mock_buffer, size()) .WillOnce(Return(mir::geometry::Size{123, 456})); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_gl, glVertexAttribPointer(position_attr_location, 3, GL_FLOAT, GL_FALSE, _, _)); EXPECT_CALL(mock_gl, glVertexAttribPointer(texcoord_attr_location, 2, GL_FLOAT, GL_FALSE, _, _)); EXPECT_CALL(mock_gl, glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)); EXPECT_CALL(mock_gl, glDisableVertexAttribArray(texcoord_attr_location)); EXPECT_CALL(mock_gl, glDisableVertexAttribArray(position_attr_location)); EXPECT_CALL(mock_gl, glClear(_)); EXPECT_CALL(mock_gl, glDeleteTextures(1, Pointee(stub_texture))); renderer->begin(); renderer->render(renderable, mock_buffer); renderer->end(); // Clear the cache to ensure tests are not sensitive to execution order renderer->begin(); renderer->end(); } TEST_F(GLRenderer, disables_blending_for_rgbx_surfaces) { mtd::MockBuffer mock_buffer; InSequence seq; EXPECT_CALL(renderable, shaped()) .WillOnce(Return(false)); EXPECT_CALL(mock_gl, glDisable(GL_BLEND)); EXPECT_CALL(mock_buffer, id()) .WillOnce(Return(mg::BufferID(123))); EXPECT_CALL(mock_gl, glGenTextures(1, _)) .WillOnce(SetArgPointee<1>(stub_texture)); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_gl, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _)); EXPECT_CALL(mock_gl, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _)); EXPECT_CALL(mock_gl, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _)); EXPECT_CALL(mock_gl, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _)); EXPECT_CALL(mock_buffer, bind_to_texture()); EXPECT_CALL(mock_buffer, size()) .WillOnce(Return(mir::geometry::Size{123, 456})); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_gl, glDeleteTextures(1, Pointee(stub_texture))); renderer->begin(); renderer->render(renderable, mock_buffer); renderer->end(); // Clear the cache to ensure tests are not sensitive to execution order renderer->begin(); renderer->end(); } TEST_F(GLRenderer, caches_and_uploads_texture_only_on_buffer_changes) { mtd::MockBuffer mock_buffer; EXPECT_CALL(mock_buffer, size()) .WillRepeatedly(Return(mir::geometry::Size{123, 456})); InSequence seq; // First render() - texture generated and uploaded EXPECT_CALL(mock_buffer, id()) .WillOnce(Return(mg::BufferID(123))); EXPECT_CALL(mock_gl, glGenTextures(1, _)) .WillOnce(SetArgPointee<1>(stub_texture)); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_gl, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, _)); EXPECT_CALL(mock_gl, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, _)); EXPECT_CALL(mock_gl, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, _)); EXPECT_CALL(mock_gl, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _)); EXPECT_CALL(mock_buffer, bind_to_texture()); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_gl, glDeleteTextures(_, _)) .Times(0); // Second render() - texture found in cache and not re-uploaded EXPECT_CALL(mock_buffer, id()) .WillOnce(Return(mg::BufferID(123))); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_gl, glDeleteTextures(_, _)) .Times(0); // Third render() - texture found in cache but refreshed with new buffer EXPECT_CALL(mock_buffer, id()) .WillOnce(Return(mg::BufferID(456))); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_buffer, bind_to_texture()); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_gl, glDeleteTextures(1, Pointee(stub_texture))) .Times(0); // Forth render() - stale texture reuploaded following bypass EXPECT_CALL(mock_buffer, id()) .WillOnce(Return(mg::BufferID(456))); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_buffer, bind_to_texture()); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_gl, glDeleteTextures(1, Pointee(stub_texture))) .Times(0); // Fifth render() - texture found in cache and not re-uploaded EXPECT_CALL(mock_buffer, id()) .WillOnce(Return(mg::BufferID(456))); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_gl, glBindTexture(GL_TEXTURE_2D, stub_texture)); EXPECT_CALL(mock_gl, glDeleteTextures(_, _)) .Times(0); EXPECT_CALL(mock_gl, glDeleteTextures(1, Pointee(stub_texture))); renderer->begin(); renderer->render(renderable, mock_buffer); renderer->end(); renderer->begin(); renderer->render(renderable, mock_buffer); renderer->end(); renderer->begin(); renderer->render(renderable, mock_buffer); renderer->end(); renderer->suspend(); renderer->begin(); renderer->render(renderable, mock_buffer); renderer->end(); renderer->begin(); renderer->render(renderable, mock_buffer); renderer->end(); // Clear the cache to ensure tests are not sensitive to execution order renderer->begin(); renderer->end(); } mir-0.1.8+14.04.20140411/tests/unit-tests/input_recordings/0000755000015301777760000000000012322054703023536 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/input_recordings/quanta_touchscreen/0000755000015301777760000000000012322054703027431 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/input_recordings/quanta_touchscreen/device.prop0000644000015301777760000000147712322054223031600 0ustar pbusernogroup00000000000000N: QUANTA OpticalTouchScreen (Virtual Test Device) I: 0003 0408 3001 0110 P: 00 00 00 00 00 00 00 00 B: 00 0b 00 00 00 00 00 00 00 B: 01 00 00 00 00 00 00 00 00 B: 01 00 00 00 00 00 00 00 00 B: 01 00 00 00 00 00 00 00 00 B: 01 00 00 00 00 00 00 00 00 B: 01 00 00 00 00 00 00 00 00 B: 01 00 04 00 00 00 00 00 00 B: 01 00 00 00 00 00 00 00 00 B: 01 00 00 00 00 00 00 00 00 B: 01 00 00 00 00 00 00 00 00 B: 01 00 00 00 00 00 00 00 00 B: 01 00 00 00 00 00 00 00 00 B: 01 00 00 00 00 00 00 00 00 B: 02 00 00 00 00 00 00 00 00 B: 03 03 00 00 00 00 80 60 02 B: 04 00 00 00 00 00 00 00 00 B: 05 00 00 00 00 00 00 00 00 B: 11 00 00 00 00 00 00 00 00 B: 12 00 00 00 00 00 00 00 00 B: 15 00 00 00 00 00 00 00 00 B: 15 00 00 00 00 00 00 00 00 A: 00 0 1920 0 0 A: 01 0 1080 0 0 A: 2f 0 9 0 0 A: 35 0 1920 0 0 A: 36 0 1080 0 0 A: 39 0 65535 0 0 mir-0.1.8+14.04.20140411/tests/unit-tests/client/0000755000015301777760000000000012322054703021436 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/client/test_mir_connection.cpp0000644000015301777760000005137512322054247026225 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "mir/geometry/rectangle.h" #include "src/client/client_platform.h" #include "src/client/client_platform_factory.h" #include "src/client/mir_connection.h" #include "src/client/default_connection_configuration.h" #include "src/client/rpc/mir_basic_rpc_channel.h" #include "src/client/display_configuration.h" #include "src/client/mir_surface.h" #include "src/client/client_buffer_factory.h" #include "src/server/frontend/resource_cache.h" /* needed by test_server.h */ #include "mir_test/test_protobuf_server.h" #include "mir_test/stub_server_tool.h" #include "mir_protobuf.pb.h" #include #include #include namespace mcl = mir::client; namespace mp = mir::protobuf; namespace geom = mir::geometry; namespace { struct MockRpcChannel : public mir::client::rpc::MirBasicRpcChannel { void CallMethod(const google::protobuf::MethodDescriptor* method, google::protobuf::RpcController*, const google::protobuf::Message* parameters, google::protobuf::Message* response, google::protobuf::Closure* complete) { if (method->name() == "drm_auth_magic") { drm_auth_magic(static_cast(parameters)); } else if (method->name() == "connect") { static_cast(response)->clear_error(); connect(static_cast(parameters), static_cast(response)); } else if (method->name() == "configure_display") { configure_display_sent(static_cast(parameters)); } complete->Run(); } MOCK_METHOD1(drm_auth_magic, void(const mp::DRMMagic*)); MOCK_METHOD2(connect, void(mp::ConnectParameters const*,mp::Connection*)); MOCK_METHOD1(configure_display_sent, void(mp::DisplayConfiguration const*)); }; struct StubClientBufferFactory : public mcl::ClientBufferFactory { std::shared_ptr create_buffer(std::shared_ptr const& /* package */, geom::Size /*size*/, MirPixelFormat /*pf*/) override { return std::shared_ptr(); } }; struct MockClientPlatform : public mcl::ClientPlatform { MockClientPlatform() { using namespace testing; auto native_display = std::make_shared(); *native_display = reinterpret_cast(0x0); ON_CALL(*this, create_egl_native_display()) .WillByDefault(Return(native_display)); ON_CALL(*this, create_buffer_factory()) .WillByDefault(Return(std::make_shared())); ON_CALL(*this, create_egl_native_window(_)) .WillByDefault(Return(std::shared_ptr())); } MOCK_CONST_METHOD1(convert_native_buffer, MirNativeBuffer*(mir::graphics::NativeBuffer*)); MOCK_CONST_METHOD0(platform_type, MirPlatformType()); MOCK_METHOD0(create_buffer_factory, std::shared_ptr()); MOCK_METHOD1(create_egl_native_window, std::shared_ptr(mcl::ClientSurface*)); MOCK_METHOD0(create_egl_native_display, std::shared_ptr()); }; struct StubClientPlatformFactory : public mcl::ClientPlatformFactory { StubClientPlatformFactory(std::shared_ptr const& platform) : platform{platform} { } std::shared_ptr create_client_platform(mcl::ClientContext*) { return platform; } std::shared_ptr platform; }; void connected_callback(MirConnection* /*connection*/, void * /*client_context*/) { } void drm_auth_magic_callback(int status, void* client_context) { auto status_ptr = static_cast(client_context); *status_ptr = status; } class TestConnectionConfiguration : public mcl::DefaultConnectionConfiguration { public: TestConnectionConfiguration( std::shared_ptr const& platform, std::shared_ptr const& channel) : DefaultConnectionConfiguration(""), disp_config(std::make_shared()), platform{platform}, channel{channel} { } std::shared_ptr<::google::protobuf::RpcChannel> the_rpc_channel() override { return channel; } std::shared_ptr the_client_platform_factory() override { return std::make_shared(platform); } std::shared_ptr the_display_configuration() override { return disp_config; } private: std::shared_ptr disp_config; std::shared_ptr const platform; std::shared_ptr const channel; }; } struct MirConnectionTest : public testing::Test { MirConnectionTest() : mock_platform{std::make_shared>()}, mock_channel{std::make_shared>()}, conf{mock_platform, mock_channel}, connection{std::make_shared(conf)} { } std::shared_ptr> const mock_platform; std::shared_ptr> const mock_channel; TestConnectionConfiguration conf; std::shared_ptr const connection; }; TEST_F(MirConnectionTest, returns_correct_egl_native_display) { using namespace testing; EGLNativeDisplayType native_display_raw = reinterpret_cast(0xabcdef); auto native_display = std::make_shared(); *native_display = native_display_raw; EXPECT_CALL(*mock_platform, create_egl_native_display()) .WillOnce(Return(native_display)); MirWaitHandle* wait_handle = connection->connect("MirClientSurfaceTest", connected_callback, 0); wait_handle->wait_for_all(); EGLNativeDisplayType connection_native_display = connection->egl_native_display(); ASSERT_EQ(native_display_raw, connection_native_display); } MATCHER_P(has_drm_magic, magic, "") { return arg->magic() == magic; } TEST_F(MirConnectionTest, client_drm_auth_magic_calls_server_drm_auth_magic) { using namespace testing; unsigned int const drm_magic{0x10111213}; EXPECT_CALL(*mock_channel, drm_auth_magic(has_drm_magic(drm_magic))) .Times(1); MirWaitHandle* wait_handle = connection->connect("MirClientSurfaceTest", connected_callback, 0); wait_handle->wait_for_all(); int const no_error{0}; int status{67}; wait_handle = connection->drm_auth_magic(drm_magic, drm_auth_magic_callback, &status); wait_handle->wait_for_all(); EXPECT_EQ(no_error, status); } namespace { std::vector const supported_output_formats{ mir_pixel_format_abgr_8888, mir_pixel_format_xbgr_8888 }; unsigned int const number_of_outputs = 4; geom::Rectangle rects[number_of_outputs] = { geom::Rectangle{geom::Point(1,2), geom::Size(14,15)}, geom::Rectangle{geom::Point(3,4), geom::Size(12,13)}, geom::Rectangle{geom::Point(5,6), geom::Size(10,11)}, geom::Rectangle{geom::Point(7,8), geom::Size(9,10)}, }; void fill_display_configuration(mp::ConnectParameters const*, mp::Connection* response) { auto protobuf_config = response->mutable_display_configuration(); for (auto i = 0u; i < number_of_outputs; i++) { auto output = protobuf_config->add_display_output(); output->set_output_id(i); auto const& rect = rects[i]; output->set_position_x(rect.top_left.x.as_uint32_t()); output->set_position_y(rect.top_left.y.as_uint32_t()); auto mode = output->add_mode(); mode->set_horizontal_resolution(rect.size.width.as_uint32_t()); mode->set_vertical_resolution(rect.size.height.as_uint32_t()); for (auto pf : supported_output_formats) output->add_pixel_format(static_cast(pf)); } } std::vector const supported_surface_formats{ mir_pixel_format_argb_8888, mir_pixel_format_bgr_888 }; void fill_surface_pixel_formats(mp::ConnectParameters const*, mp::Connection* response) { for (auto pf : supported_surface_formats) response->add_surface_pixel_format(static_cast(pf)); } } TEST_F(MirConnectionTest, populates_display_output_correctly_on_startup) { using namespace testing; EXPECT_CALL(*mock_channel, connect(_,_)) .WillOnce(Invoke(fill_display_configuration)); MirWaitHandle* wait_handle = connection->connect("MirClientSurfaceTest", connected_callback, 0); wait_handle->wait_for_all(); auto configuration = connection->create_copy_of_display_config(); ASSERT_EQ(number_of_outputs, configuration->num_outputs); for(auto i=0u; i < number_of_outputs; i++) { auto output = configuration->outputs[i]; auto rect = rects[i]; ASSERT_EQ(1u, output.num_modes); ASSERT_NE(nullptr, output.modes); EXPECT_EQ(rect.size.width.as_uint32_t(), output.modes[0].horizontal_resolution); EXPECT_EQ(rect.size.height.as_uint32_t(), output.modes[0].vertical_resolution); EXPECT_EQ(output.position_x, static_cast(rect.top_left.x.as_uint32_t())); EXPECT_EQ(output.position_y, static_cast(rect.top_left.y.as_uint32_t())); ASSERT_EQ(supported_output_formats.size(), static_cast(output.num_output_formats)); for (size_t i = 0; i < supported_output_formats.size(); ++i) { EXPECT_EQ(supported_output_formats[i], output.output_formats[i]); } } mcl::delete_config_storage(configuration); } TEST_F(MirConnectionTest, user_tries_to_configure_incorrectly) { using namespace testing; EXPECT_CALL(*mock_channel, connect(_,_)) .WillOnce(Invoke(fill_display_configuration)); MirWaitHandle* wait_handle = connection->connect("MirClientSurfaceTest", connected_callback, 0); wait_handle->wait_for_all(); auto configuration = connection->create_copy_of_display_config(); EXPECT_GT(configuration->num_outputs, 0u); auto proper_num_outputs = configuration->num_outputs; auto proper_outputs = configuration->outputs; auto proper_output_id = configuration->outputs[0].output_id; //user lies about num_outputs configuration->num_outputs = 0; EXPECT_EQ(nullptr, connection->configure_display(configuration)); configuration->num_outputs = proper_num_outputs + 1; EXPECT_EQ(nullptr, connection->configure_display(configuration)); configuration->num_outputs = proper_num_outputs; //user sends nullptr for outputs configuration->outputs = nullptr; EXPECT_EQ(nullptr, connection->configure_display(configuration)); configuration->outputs = proper_outputs; //user makes up own id configuration->outputs[0].output_id = 4944949; EXPECT_EQ(nullptr, connection->configure_display(configuration)); configuration->outputs[0].output_id = proper_output_id; //user tries to set nonsense mode on a connected output configuration->outputs[0].current_mode++; configuration->outputs[0].connected = 1; EXPECT_EQ(nullptr, connection->configure_display(configuration)); mcl::delete_config_storage(configuration); } TEST_F(MirConnectionTest, display_configuration_validation_succeeds_for_invalid_mode_in_disconnected_output) { using namespace testing; EXPECT_CALL(*mock_channel, connect(_,_)) .WillOnce(Invoke(fill_display_configuration)); MirWaitHandle* wait_handle = connection->connect("MirClientSurfaceTest", connected_callback, 0); wait_handle->wait_for_all(); auto configuration = connection->create_copy_of_display_config(); EXPECT_GT(configuration->num_outputs, 0u); configuration->outputs[0].current_mode++; configuration->outputs[0].connected = 0; EXPECT_NE(nullptr, connection->configure_display(configuration)); mcl::delete_config_storage(configuration); } TEST_F(MirConnectionTest, display_configuration_validation_uses_updated_configuration) { using namespace testing; EXPECT_CALL(*mock_channel, connect(_,_)) .WillOnce(Invoke(fill_display_configuration)); MirWaitHandle* wait_handle = connection->connect("MirClientSurfaceTest", connected_callback, 0); wait_handle->wait_for_all(); auto old_configuration = connection->create_copy_of_display_config(); /* Update the configuration */ uint32_t const output1_id{11}; uint32_t const output2_id{12}; mp::DisplayConfiguration protobuf_config; auto output1 = protobuf_config.add_display_output(); output1->set_output_id(output1_id); auto output2 = protobuf_config.add_display_output(); output2->set_output_id(output2_id); auto display_config = conf.the_display_configuration(); display_config->set_configuration(protobuf_config); /* Check that the old config cannot be validated */ EXPECT_EQ(nullptr, connection->configure_display(old_configuration)); /* Check that the new config can be validated */ auto configuration = connection->create_copy_of_display_config(); EXPECT_NE(nullptr, connection->configure_display(configuration)); mcl::delete_config_storage(old_configuration); mcl::delete_config_storage(configuration); } TEST_F(MirConnectionTest, populates_pfs_correctly) { using namespace testing; EXPECT_CALL(*mock_channel, connect(_,_)) .WillOnce(Invoke(fill_surface_pixel_formats)); MirWaitHandle* wait_handle = connection->connect("MirClientSurfaceTest", connected_callback, 0); wait_handle->wait_for_all(); unsigned int const formats_size = 5; unsigned int valid_formats = 0; MirPixelFormat formats[formats_size]; connection->available_surface_formats(&formats[0], formats_size, valid_formats); ASSERT_EQ(supported_surface_formats.size(), valid_formats); for (auto i=0u; i < valid_formats; i++) { EXPECT_EQ(supported_surface_formats[i], formats[i]) << "i=" << i; } } TEST_F(MirConnectionTest, valid_display_configure_sent) { using namespace testing; EXPECT_CALL(*mock_channel, connect(_,_)) .WillOnce(Invoke(fill_display_configuration)); MirDisplayOutput output; output.output_id = 0; output.current_mode = 0; output.current_format = mir_pixel_format_xbgr_8888; output.used = 0; output.position_x = 4; output.position_y = 6; output.connected = 0; MirDisplayConfiguration user_config{1, &output, 0, nullptr}; auto verify_display_change = [&](mp::DisplayConfiguration const* config) { ASSERT_NE(nullptr, config); ASSERT_EQ(1, config->display_output_size()); auto const& disp1 = config->display_output(0); EXPECT_TRUE(disp1.has_output_id()); EXPECT_EQ(output.output_id, disp1.output_id()); EXPECT_TRUE(disp1.has_used()); EXPECT_EQ(output.used, disp1.used()); EXPECT_TRUE(disp1.has_current_mode()); EXPECT_EQ(output.current_mode, disp1.current_mode()); EXPECT_TRUE(disp1.has_current_format()); EXPECT_EQ(output.current_format, disp1.current_format()); EXPECT_TRUE(disp1.has_position_x()); EXPECT_EQ(output.position_x, disp1.position_x()); EXPECT_TRUE(disp1.has_position_y()); EXPECT_EQ(output.position_y, disp1.position_y()); }; EXPECT_CALL(*mock_channel, configure_display_sent(_)) .Times(1) .WillOnce(Invoke(verify_display_change)); MirWaitHandle* wait_handle = connection->connect("MirClientSurfaceTest", connected_callback, 0); wait_handle->wait_for_all(); auto config_wait_handle = connection->configure_display(&user_config); config_wait_handle->wait_for_all(); } static MirSurface *surface; static void surface_callback(MirSurface* surf, void*) { surface = surf; } static bool unfocused_received; static void surface_event_callback(MirSurface *, MirEvent const *ev, void *) { if (ev->type == mir_event_type_surface && ev->surface.attrib == mir_surface_attrib_focus && ev->surface.value == mir_surface_unfocused) unfocused_received = true; } TEST_F(MirConnectionTest, focused_window_synthesises_unfocus_event_on_release) { using namespace testing; MirSurfaceParameters params; params.name = __PRETTY_FUNCTION__; MirEventDelegate const event_delegate = { &surface_event_callback, nullptr }; unfocused_received = false; MirWaitHandle *wait_handle = connection->connect("MirClientSurfaceTest", &connected_callback, nullptr); wait_handle->wait_for_all(); wait_handle = connection->create_surface(params, &surface_callback, nullptr); wait_handle->wait_for_all(); MirEvent focus_event; focus_event.type = mir_event_type_surface; focus_event.surface.id = surface->id(); focus_event.surface.attrib = mir_surface_attrib_focus; focus_event.surface.value = mir_surface_focused; surface->handle_event(focus_event); surface->set_event_handler(&event_delegate); wait_handle = connection->release_surface(surface, &surface_callback, nullptr); wait_handle->wait_for_all(); wait_handle = connection->disconnect(); wait_handle->wait_for_all(); EXPECT_TRUE(unfocused_received); } TEST_F(MirConnectionTest, unfocused_window_does_not_synthesise_unfocus_event_on_release) { using namespace testing; MirSurfaceParameters params; params.name = __PRETTY_FUNCTION__; MirEventDelegate const event_delegate = { &surface_event_callback, nullptr }; unfocused_received = false; MirWaitHandle *wait_handle = connection->connect("MirClientSurfaceTest", &connected_callback, nullptr); wait_handle->wait_for_all(); wait_handle = connection->create_surface(params, &surface_callback, nullptr); wait_handle->wait_for_all(); MirEvent focus_event; focus_event.type = mir_event_type_surface; focus_event.surface.id = surface->id(); focus_event.surface.attrib = mir_surface_attrib_focus; focus_event.surface.value = mir_surface_unfocused; surface->handle_event(focus_event); surface->set_event_handler(&event_delegate); wait_handle = connection->release_surface(surface, &surface_callback, nullptr); wait_handle->wait_for_all(); wait_handle = connection->disconnect(); wait_handle->wait_for_all(); EXPECT_FALSE(unfocused_received); } namespace { ACTION_P(FillPlatformDataWith, sample_data) { for (auto d : sample_data) arg1->mutable_platform()->add_data(d); } } TEST_F(MirConnectionTest, sets_extra_platform_data) { using namespace testing; std::vector const initial_data{0x66, 0x67, 0x68}; std::vector const extra_data{0x11, 0x12, 0x13}; EXPECT_CALL(*mock_channel, connect(_,_)) .WillOnce(FillPlatformDataWith(initial_data)); MirWaitHandle *wait_handle = connection->connect("MirClientSurfaceTest", &connected_callback, nullptr); wait_handle->wait_for_all(); MirPlatformPackage pkg; /* Check initial data */ connection->populate(pkg); EXPECT_EQ(initial_data.size(), static_cast(pkg.data_items)); for (size_t i = 0; i < initial_data.size(); i++) EXPECT_EQ(initial_data[i], pkg.data[i]) << " i=" << i; /* Check initial data plus extra data*/ connection->set_extra_platform_data(extra_data); connection->populate(pkg); EXPECT_EQ(initial_data.size() + extra_data.size(), static_cast(pkg.data_items)); for (size_t i = 0; i < initial_data.size(); i++) EXPECT_EQ(initial_data[i], pkg.data[i]) << " i=" << i; for (size_t i = 0; i < extra_data.size(); i++) EXPECT_EQ(extra_data[i], pkg.data[i + initial_data.size()]) << " i=" << i; } mir-0.1.8+14.04.20140411/tests/unit-tests/client/android/0000755000015301777760000000000012322054703023056 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/client/android/test_client_android_registrar.cpp0000644000015301777760000002542312322054223031664 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/client/android/android_client_buffer.h" #include "src/client/android/android_registrar_gralloc.h" #include "mir_test_doubles/mock_android_alloc_device.h" #include "mir_test/fake_shared.h" #include #include #include #include #include #include namespace mcl=mir::client; namespace mcla=mir::client::android; namespace geom=mir::geometry; class ICSRegistrarInterface { public: virtual ~ICSRegistrarInterface() {} virtual int registerBuffer_interface(struct gralloc_module_t const* module, buffer_handle_t handle) const = 0; virtual int unregisterBuffer_interface(struct gralloc_module_t const* module, buffer_handle_t handle) const = 0; virtual int lock_interface(struct gralloc_module_t const* module, buffer_handle_t handle, int usage, int l, int t, int w, int h, void** vaddr) const = 0; virtual int unlock_interface(struct gralloc_module_t const* module, buffer_handle_t handle) const = 0; }; class MockRegistrarDevice : public ICSRegistrarInterface, public gralloc_module_t { public: MockRegistrarDevice() { registerBuffer = hook_registerBuffer; unregisterBuffer = hook_unregisterBuffer; lock = hook_lock; unlock = hook_unlock; } MOCK_CONST_METHOD2(registerBuffer_interface, int (struct gralloc_module_t const*, buffer_handle_t)); MOCK_CONST_METHOD2(unregisterBuffer_interface, int (struct gralloc_module_t const*, buffer_handle_t)); MOCK_CONST_METHOD8(lock_interface, int(struct gralloc_module_t const*, buffer_handle_t, int, int, int, int, int, void**)); MOCK_CONST_METHOD2(unlock_interface, int(struct gralloc_module_t const* module, buffer_handle_t handle)); static int hook_registerBuffer(struct gralloc_module_t const* module, buffer_handle_t handle) { const MockRegistrarDevice *registrar = static_cast(module); return registrar->registerBuffer_interface(module, handle); } static int hook_unregisterBuffer(struct gralloc_module_t const* module, buffer_handle_t handle) { const MockRegistrarDevice *registrar = static_cast(module); return registrar->unregisterBuffer_interface(module, handle); } static int hook_lock(struct gralloc_module_t const* module, buffer_handle_t handle, int usage, int l, int t, int w, int h, void** vaddr) { const MockRegistrarDevice *registrar = static_cast(module); return registrar->lock_interface(module, handle, usage, l, t, w, h, vaddr); } static int hook_unlock(struct gralloc_module_t const* module, buffer_handle_t handle) { const MockRegistrarDevice *registrar = static_cast(module); return registrar->unlock_interface(module, handle); } }; typedef ::testing::NiceMock StubRegistrarDevice; class ClientAndroidRegistrarTest : public ::testing::Test { protected: virtual void SetUp() { using namespace testing; mock_module = std::make_shared>(); width = 41; height = 43; top = 0; left = 1; auto t = geom::X(top); auto l = geom::Y(left); auto pt = geom::Point{t,l}; rect = geom::Rectangle{ pt, {width, height}}; package = std::make_shared(); package->fd_items = 4; package->data_items = 21; for(auto i=0; i < package->fd_items; i++) package->fd[i] = (i*4); for(auto i=0; i < package->data_items; i++) package->fd[i] = (i*3); } geom::Rectangle rect; uint32_t width, height, top, left; std::shared_ptr package; std::shared_ptr mock_module; }; TEST_F(ClientAndroidRegistrarTest, client_buffer_converts_package) { mcla::AndroidRegistrarGralloc registrar(mock_module); auto handle = registrar.register_buffer(package); ASSERT_NE(nullptr, handle); ASSERT_EQ(package->fd_items, handle->numFds); ASSERT_EQ(package->data_items, handle->numInts); for(auto i = 0; i < package->fd_items; i++) EXPECT_EQ(package->fd[i], handle->data[i]); for(auto i = 0; i < package->data_items; i++) EXPECT_EQ(package->data[i], handle->data[i + package->fd_items]); } TEST_F(ClientAndroidRegistrarTest, client_sets_correct_version) { mcla::AndroidRegistrarGralloc registrar(mock_module); auto handle = registrar.register_buffer(package); EXPECT_EQ(handle->version, static_cast(sizeof(native_handle_t))); } TEST_F(ClientAndroidRegistrarTest, registrar_registers_using_module) { using namespace testing; native_handle_t const* handle1 = nullptr; native_handle_t const* handle2 = nullptr; EXPECT_CALL(*mock_module, registerBuffer_interface(mock_module.get(),_)) .Times(1) .WillOnce(DoAll(SaveArg<1>(&handle1), Return(0))); EXPECT_CALL(*mock_module, unregisterBuffer_interface(mock_module.get(),_)) .Times(1) .WillOnce(DoAll(SaveArg<1>(&handle2), Return(0))); mcla::AndroidRegistrarGralloc registrar(mock_module); { auto handle = registrar.register_buffer(package); EXPECT_EQ(handle1, handle.get()); } EXPECT_EQ(handle1, handle2); } TEST_F(ClientAndroidRegistrarTest, registrar_frees_fds) { using namespace testing; StubRegistrarDevice stub_module; auto package = std::make_shared(); package->data_items = 0; package->fd_items = 2; int ret = pipe(static_cast(package->fd)); { mcla::AndroidRegistrarGralloc registrar(mir::test::fake_shared(stub_module)); auto handle = registrar.register_buffer(package); } EXPECT_EQ(0, ret); EXPECT_EQ(-1, fcntl(package->fd[0], F_GETFD)); EXPECT_EQ(-1, fcntl(package->fd[1], F_GETFD)); } TEST_F(ClientAndroidRegistrarTest, register_failure) { using namespace testing; EXPECT_CALL(*mock_module, registerBuffer_interface(_, _)) .Times(1) .WillOnce(Return(-1)); EXPECT_CALL(*mock_module, unregisterBuffer_interface(_,_)) .Times(0); mcla::AndroidRegistrarGralloc registrar(mock_module); EXPECT_THROW({ registrar.register_buffer(package); }, std::runtime_error); } class AndroidSoftwareRegionTest : public ::testing::Test { protected: virtual void SetUp() { using namespace testing; mock_module = std::make_shared>(); width = 41; height = 43; top = 0; left = 1; auto t = geom::X(top); auto l = geom::Y(left); auto pt = geom::Point{t,l}; rect = geom::Rectangle{ pt, {width, height}}; fake_package = std::make_shared(); } geom::Rectangle rect; uint32_t width, height, top, left; std::shared_ptr fake_package; std::shared_ptr mock_module; }; TEST_F(AndroidSoftwareRegionTest, region_is_cleaned_up_correctly) { using namespace testing; mcla::AndroidRegistrarGralloc registrar(mock_module); const gralloc_module_t *gralloc_dev_alloc, *gralloc_dev_freed; const native_handle_t *handle_alloc, *handle_freed; EXPECT_CALL(*mock_module, lock_interface(_,_,_,_,_,_,_,_)) .Times(1) .WillOnce(DoAll( SaveArg<0>(&gralloc_dev_alloc), SaveArg<1>(&handle_alloc), Return(0))); EXPECT_CALL(*mock_module, unlock_interface(_,_)) .Times(1) .WillOnce(DoAll( SaveArg<0>(&gralloc_dev_freed), SaveArg<1>(&handle_freed), Return(0))); registrar.secure_for_cpu(fake_package, rect); EXPECT_EQ(gralloc_dev_freed, gralloc_dev_alloc); EXPECT_EQ(handle_alloc, handle_freed); } TEST_F(AndroidSoftwareRegionTest, region_lock_usage_set_correctly) { using namespace testing; mcla::AndroidRegistrarGralloc registrar(mock_module); int usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; EXPECT_CALL(*mock_module, lock_interface(_,_,usage,_,_,_,_,_)) .Times(1); registrar.secure_for_cpu(fake_package, rect); } TEST_F(AndroidSoftwareRegionTest, region_locks_from_top_corner) { using namespace testing; mcla::AndroidRegistrarGralloc registrar(mock_module); EXPECT_CALL(*mock_module, lock_interface(_,_,_,top,_,_,_,_)) .Times(1); registrar.secure_for_cpu(fake_package, rect); } TEST_F(AndroidSoftwareRegionTest, region_locks_from_left_corner) { using namespace testing; mcla::AndroidRegistrarGralloc registrar(mock_module); EXPECT_CALL(*mock_module, lock_interface(_,_,_,_,left,_,_,_)) .Times(1); registrar.secure_for_cpu(fake_package, rect); } TEST_F(AndroidSoftwareRegionTest, region_locks_with_right_width) { using namespace testing; mcla::AndroidRegistrarGralloc registrar(mock_module); EXPECT_CALL(*mock_module, lock_interface(_,_,_,_,_,width,_,_)) .Times(1); registrar.secure_for_cpu(fake_package, rect); } TEST_F(AndroidSoftwareRegionTest, region_locks_with_right_height) { using namespace testing; mcla::AndroidRegistrarGralloc registrar(mock_module); EXPECT_CALL(*mock_module, lock_interface(_,_,_,_,_,_,height,_)) .Times(1); registrar.secure_for_cpu(fake_package, rect); } TEST_F(AndroidSoftwareRegionTest, lock_failure) { using namespace testing; EXPECT_CALL(*mock_module, lock_interface(_,_,_,_,_,_,_,_)) .Times(1) .WillOnce(Return(-1)); mcla::AndroidRegistrarGralloc registrar(mock_module); EXPECT_THROW({ registrar.secure_for_cpu(fake_package, rect); }, std::runtime_error); } /* unlock is called in destructor. should not throw */ TEST_F(AndroidSoftwareRegionTest, unlock_failure) { using namespace testing; EXPECT_CALL(*mock_module, unlock_interface(_,_)) .Times(1) .WillOnce(Return(-1)); mcla::AndroidRegistrarGralloc registrar(mock_module); auto region = registrar.secure_for_cpu(fake_package, rect); EXPECT_NO_THROW({ region.reset(); }); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/android/test_android_native_window.cpp0000644000015301777760000002425312322054223031201 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/android/mir_native_window.h" #include "mir/graphics/android/android_driver_interpreter.h" #include "src/client/mir_client_surface.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include "mir_test_doubles/mock_fence.h" #include #include #include namespace mga=mir::graphics::android; namespace mtd=mir::test::doubles; namespace { class MockAndroidDriverInterpreter : public mga::AndroidDriverInterpreter { public: MockAndroidDriverInterpreter() : buffer(std::make_shared()) { using namespace testing; ON_CALL(*this, driver_requests_buffer()) .WillByDefault(Return(buffer.get())); } MOCK_METHOD0(driver_requests_buffer, mir::graphics::NativeBuffer*()); MOCK_METHOD2(driver_returns_buffer, void(ANativeWindowBuffer*, int)); MOCK_METHOD1(dispatch_driver_request_format, void(int)); MOCK_CONST_METHOD1(driver_requests_info, int(int)); MOCK_METHOD1(sync_to_display, void(bool)); std::shared_ptr buffer; }; } class AndroidNativeWindowTest : public ::testing::Test { protected: virtual void SetUp() { using namespace testing; mock_driver_interpreter = std::make_shared>(); } std::shared_ptr mock_driver_interpreter; }; TEST_F(AndroidNativeWindowTest, native_window_swapinterval) { using namespace testing; std::shared_ptr window = std::make_shared(mock_driver_interpreter); ASSERT_NE(nullptr, window->setSwapInterval); EXPECT_CALL(*mock_driver_interpreter, sync_to_display(true)) .Times(1); window->setSwapInterval(window.get(), 1); Mock::VerifyAndClearExpectations(window.get()); EXPECT_CALL(*mock_driver_interpreter, sync_to_display(true)) .Times(1); window->setSwapInterval(window.get(), 2); Mock::VerifyAndClearExpectations(window.get()); EXPECT_CALL(*mock_driver_interpreter, sync_to_display(false)) .Times(1); window->setSwapInterval(window.get(), 0); } /* Query hook tests */ TEST_F(AndroidNativeWindowTest, native_window_query_hook) { using namespace testing; int returned_width, width = 271828; std::shared_ptr window = std::make_shared(mock_driver_interpreter); ASSERT_NE(nullptr, window->query); EXPECT_CALL(*mock_driver_interpreter, driver_requests_info(NATIVE_WINDOW_WIDTH)) .Times(1) .WillOnce(Return(width)); window->query(window.get(), NATIVE_WINDOW_WIDTH ,&returned_width); EXPECT_EQ(width, returned_width); } /* perform hook tests */ TEST_F(AndroidNativeWindowTest, native_window_perform_hook_callable) { int format = 4; std::shared_ptr window = std::make_shared(mock_driver_interpreter); EXPECT_CALL(*mock_driver_interpreter, dispatch_driver_request_format(format)) .Times(1); ASSERT_NE(nullptr, window->perform); window->perform(window.get(), NATIVE_WINDOW_SET_BUFFERS_FORMAT, format); } /* setSwapInterval hook tests */ TEST_F(AndroidNativeWindowTest, native_window_setswapinterval_hook_callable) { int swap = 2; std::shared_ptr window = std::make_shared(mock_driver_interpreter); ASSERT_NE(nullptr, window->setSwapInterval); window->setSwapInterval(window.get(), swap); } /* dequeue hook tests */ TEST_F(AndroidNativeWindowTest, native_window_dequeue_hook_callable) { ANativeWindowBuffer* returned_buffer; int fence_fd; std::shared_ptr window = std::make_shared(mock_driver_interpreter); ASSERT_NE(nullptr, window->dequeueBuffer); window->dequeueBuffer(window.get(), &returned_buffer, &fence_fd); } TEST_F(AndroidNativeWindowTest, native_window_dequeue_returns_right_buffer) { using namespace testing; int fake_fd = 4948; auto mock_buffer = std::make_shared>(); EXPECT_CALL(*mock_buffer, copy_fence()) .Times(1) .WillOnce(Return(fake_fd)); EXPECT_CALL(*mock_driver_interpreter, driver_requests_buffer()) .Times(1) .WillOnce(Return(mock_buffer.get())); std::shared_ptr window = std::make_shared(mock_driver_interpreter); int fence_fd; ANativeWindowBuffer* returned_buffer; window->dequeueBuffer(window.get(), &returned_buffer, &fence_fd); EXPECT_EQ(mock_buffer->anwb(), returned_buffer); EXPECT_EQ(fake_fd, fence_fd); } TEST_F(AndroidNativeWindowTest, native_window_dequeue_deprecated_hook_callable) { ANativeWindowBuffer* tmp; std::shared_ptr window = std::make_shared(mock_driver_interpreter); ASSERT_NE(nullptr, window->dequeueBuffer_DEPRECATED); window->dequeueBuffer_DEPRECATED(window.get(), &tmp); } TEST_F(AndroidNativeWindowTest, native_window_dequeue_deprecated_returns_right_buffer) { using namespace testing; ANativeWindowBuffer* returned_buffer; auto mock_buffer = std::make_shared>(); std::shared_ptr window = std::make_shared(mock_driver_interpreter); EXPECT_CALL(*mock_driver_interpreter, driver_requests_buffer()) .Times(1) .WillOnce(Return(mock_buffer.get())); EXPECT_CALL(*mock_buffer, wait_for_content()) .Times(1); EXPECT_CALL(*mock_buffer, copy_fence()) .Times(0); window->dequeueBuffer_DEPRECATED(window.get(), &returned_buffer); EXPECT_EQ(mock_buffer->anwb(), returned_buffer); } /* queue hook tests */ TEST_F(AndroidNativeWindowTest, native_window_queue_hook_callable) { ANativeWindowBuffer* tmp = nullptr; std::shared_ptr window = std::make_shared(mock_driver_interpreter); ASSERT_NE(nullptr, window->queueBuffer); window->queueBuffer(window.get(), tmp, -1); } TEST_F(AndroidNativeWindowTest, native_window_queue_passes_buffer_back) { using namespace testing; ANativeWindowBuffer buffer; int fence_fd = 33; std::shared_ptr window = std::make_shared(mock_driver_interpreter); EXPECT_CALL(*mock_driver_interpreter, driver_returns_buffer(&buffer, fence_fd)) .Times(1); window->queueBuffer(window.get(), &buffer, fence_fd); } TEST_F(AndroidNativeWindowTest, native_window_queue_deprecated_hook_callable) { ANativeWindowBuffer* tmp = nullptr; std::shared_ptr window = std::make_shared(mock_driver_interpreter); ASSERT_NE(nullptr, window->queueBuffer_DEPRECATED); window->queueBuffer_DEPRECATED(window.get(), tmp); } TEST_F(AndroidNativeWindowTest, native_window_queue_deprecated_passes_buffer_back) { using namespace testing; ANativeWindowBuffer buffer; std::shared_ptr window = std::make_shared(mock_driver_interpreter); EXPECT_CALL(*mock_driver_interpreter, driver_returns_buffer(&buffer,_)) .Times(1); window->queueBuffer_DEPRECATED(window.get(), &buffer); } /* cancel hook tests */ TEST_F(AndroidNativeWindowTest, native_window_cancel_hooks_callable) { ANativeWindowBuffer* tmp = nullptr; std::shared_ptr window = std::make_shared(mock_driver_interpreter); ASSERT_NE(nullptr, window->cancelBuffer_DEPRECATED); ASSERT_NE(nullptr, window->cancelBuffer); window->cancelBuffer_DEPRECATED(window.get(), tmp); window->cancelBuffer(window.get(), tmp, -1); } /* lock hook tests */ TEST_F(AndroidNativeWindowTest, native_window_lock_hook_callable) { ANativeWindowBuffer* tmp = 0x0; std::shared_ptr window = std::make_shared(mock_driver_interpreter); ASSERT_NE(nullptr, window->lockBuffer_DEPRECATED); window->lockBuffer_DEPRECATED(window.get(), tmp); } TEST_F(AndroidNativeWindowTest, native_window_incref_hook_callable) { std::shared_ptr window = std::make_shared(mock_driver_interpreter); ASSERT_NE(nullptr, window->common.incRef); window->common.incRef(NULL); } TEST_F(AndroidNativeWindowTest, native_window_decref_hook_callable) { std::shared_ptr window = std::make_shared(mock_driver_interpreter); ASSERT_NE(nullptr, window->common.decRef); window->common.decRef(NULL); } TEST_F(AndroidNativeWindowTest, native_window_dequeue_deprecated_has_proper_rc) { ANativeWindowBuffer* tmp; std::shared_ptr window = std::make_shared(mock_driver_interpreter); auto ret = window->dequeueBuffer_DEPRECATED(window.get(), &tmp); EXPECT_EQ(0, ret); } TEST_F(AndroidNativeWindowTest, native_window_dequeue_has_proper_rc) { ANativeWindowBuffer* tmp; int fencefd; std::shared_ptr window = std::make_shared(mock_driver_interpreter); auto ret = window->dequeueBuffer(window.get(), &tmp, &fencefd); EXPECT_EQ(0, ret); } TEST_F(AndroidNativeWindowTest, native_window_cancel_hook_behavior) { using namespace testing; ANativeWindowBuffer buffer; int fence_fd = 33; EXPECT_CALL(*mock_driver_interpreter, driver_returns_buffer(&buffer, _)) .Times(1); std::shared_ptr window = std::make_shared(mock_driver_interpreter); auto rc = window->cancelBuffer(window.get(), &buffer, fence_fd); EXPECT_EQ(0, rc); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/android/test_client_android_buffer.cpp0000644000015301777760000001320112322054223031122 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_doubles/mock_android_registrar.h" #include "src/client/android/android_client_buffer.h" #include "mir_toolkit/mir_client_library.h" #include #include #include #include #include namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace mcl = mir::client; namespace mcla = mir::client::android; namespace geom = mir::geometry; class ClientAndroidBufferTest : public ::testing::Test { protected: virtual void SetUp() { using namespace testing; height = geom::Height(124); width = geom::Width(248); size = geom::Size{width, height}; stride = geom::Stride{66}; pf = mir_pixel_format_abgr_8888; mock_android_registrar = std::make_shared>(); package = std::make_shared(); } std::shared_ptr package; geom::Size size; geom::Height height; geom::Width width; geom::Stride stride; MirPixelFormat pf; std::shared_ptr buffer; std::shared_ptr mock_android_registrar; }; TEST_F(ClientAndroidBufferTest, buffer_returns_width_without_modifying) { mcla::AndroidClientBuffer buffer(mock_android_registrar, package, size, pf, stride); EXPECT_EQ(size, buffer.size()); } TEST_F(ClientAndroidBufferTest, buffer_returns_pf_without_modifying) { mcla::AndroidClientBuffer buffer(mock_android_registrar, package, size, pf, stride); EXPECT_EQ(pf, buffer.pixel_format()); } TEST_F(ClientAndroidBufferTest, buffer_returns_correct_stride) { mcla::AndroidClientBuffer buffer(mock_android_registrar, package, size, pf, stride); EXPECT_EQ(stride, buffer.stride()); } TEST_F(ClientAndroidBufferTest, buffer_uses_registrar_for_secure) { using namespace testing; mcla::AndroidClientBuffer buffer(mock_android_registrar, package, size, pf, stride); std::shared_ptr empty_char = std::make_shared(); EXPECT_CALL(*mock_android_registrar, secure_for_cpu(_,_)) .Times(1) .WillOnce(Return(empty_char)); buffer.secure_for_cpu_write(); } TEST_F(ClientAndroidBufferTest, buffer_uses_right_handle_to_secure) { using namespace testing; geom::Point point{0, 0}; geom::Size size{width, height}; geom::Rectangle rect{point, size}; std::shared_ptr tmp = package; EXPECT_CALL(*mock_android_registrar, secure_for_cpu(tmp,rect)) .Times(1) .WillOnce(Return(std::shared_ptr())); mcla::AndroidClientBuffer buffer(mock_android_registrar, package, size, pf, stride); auto region = buffer.secure_for_cpu_write(); } TEST_F(ClientAndroidBufferTest, buffer_packs_memory_region_with_right_vaddr) { using namespace testing; std::shared_ptr empty_char = std::make_shared(); EXPECT_CALL(*mock_android_registrar, secure_for_cpu(_,_)) .Times(1) .WillOnce(Return(empty_char)); mcla::AndroidClientBuffer buffer(mock_android_registrar, package, size, pf, stride); auto region = buffer.secure_for_cpu_write(); EXPECT_EQ(empty_char, region->vaddr); } TEST_F(ClientAndroidBufferTest, buffer_packs_memory_region_with_correct_buffer_dimensions) { using namespace testing; EXPECT_CALL(*mock_android_registrar, secure_for_cpu(_,_)) .Times(1) .WillOnce(Return(std::shared_ptr())); mcla::AndroidClientBuffer buffer(mock_android_registrar, package, size, pf, stride); auto region = buffer.secure_for_cpu_write(); EXPECT_EQ(width, region->width); EXPECT_EQ(height, region->height); EXPECT_EQ(stride, region->stride); EXPECT_EQ(pf, region->format); } TEST_F(ClientAndroidBufferTest, buffer_packs_anativewindowbuffer_info) { int correct_usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER; int32_t const expected_stride_in_pixels = static_cast(stride.as_uint32_t() / MIR_BYTES_PER_PIXEL(pf)); mcla::AndroidClientBuffer buffer(mock_android_registrar, package, size, pf, stride); auto native_handle = buffer.native_buffer_handle(); ASSERT_NE(nullptr, native_handle); auto anwb = native_handle->anwb(); ASSERT_NE(nullptr, anwb); EXPECT_EQ(package.get(), anwb->handle); EXPECT_EQ(width.as_uint32_t(), static_cast(anwb->width)); EXPECT_EQ(height.as_uint32_t(), static_cast(anwb->height)); EXPECT_EQ(correct_usage, anwb->usage); EXPECT_EQ(expected_stride_in_pixels, anwb->stride); } TEST_F(ClientAndroidBufferTest, buffer_packs_anativewindowbuffer_refcounters_set) { mcla::AndroidClientBuffer buffer(mock_android_registrar, package, size, pf, stride); auto native_handle = buffer.native_buffer_handle(); auto anwb = native_handle->anwb(); ASSERT_NE(nullptr, anwb); ASSERT_NE(nullptr, anwb->common.incRef); ASSERT_NE(nullptr, anwb->common.decRef); anwb->common.incRef(&anwb->common); anwb->common.decRef(&anwb->common); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/android/test_client_surface_interpreter.cpp0000644000015301777760000001743712322054223032243 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/android/native_buffer.h" #include "src/client/mir_client_surface.h" #include "src/client/client_buffer.h" #include "src/client/android/client_surface_interpreter.h" #include "mir_test_doubles/mock_android_native_buffer.h" #include "mir_test/fake_shared.h" #include #include #include namespace mcl=mir::client; namespace mcla=mir::client::android; namespace mga=mir::graphics::android; namespace geom=mir::geometry; namespace mt=mir::test; namespace mtd=mir::test::doubles; struct MockClientBuffer : public mcl::ClientBuffer { MockClientBuffer() { using namespace testing; buffer = std::make_shared(); ON_CALL(*this, native_buffer_handle()) .WillByDefault(Return(buffer)); } ~MockClientBuffer() noexcept {} MOCK_METHOD0(secure_for_cpu_write, std::shared_ptr()); MOCK_CONST_METHOD0(size, geom::Size()); MOCK_CONST_METHOD0(stride, geom::Stride()); MOCK_CONST_METHOD0(pixel_format, MirPixelFormat()); MOCK_CONST_METHOD0(age, uint32_t()); MOCK_METHOD0(mark_as_submitted, void()); MOCK_METHOD0(increment_age, void()); MOCK_CONST_METHOD0(native_buffer_handle, std::shared_ptr()); std::shared_ptr buffer; native_handle_t handle; }; struct MockMirSurface : public mcl::ClientSurface { MockMirSurface(MirSurfaceParameters params) : params(params) { using namespace testing; ON_CALL(*this, get_parameters()) .WillByDefault(Return(params)); ON_CALL(*this, get_current_buffer()) .WillByDefault(Return( std::make_shared>())); } MOCK_CONST_METHOD0(get_parameters, MirSurfaceParameters()); MOCK_METHOD0(get_current_buffer, std::shared_ptr()); MOCK_METHOD0(request_and_wait_for_next_buffer, void()); MOCK_METHOD2(request_and_wait_for_configure, void(MirSurfaceAttrib, int)); MirSurfaceParameters params; }; class AndroidInterpreterTest : public ::testing::Test { protected: virtual void SetUp() { using namespace testing; surf_params.width = 530; surf_params.height = 715; surf_params.pixel_format = mir_pixel_format_abgr_8888; mock_client_buffer = std::make_shared>(); } MirSurfaceParameters surf_params; std::shared_ptr mock_client_buffer; }; TEST_F(AndroidInterpreterTest, native_window_dequeue_calls_surface_get_current) { using namespace testing; testing::NiceMock mock_surface{surf_params}; mcla::ClientSurfaceInterpreter interpreter(mock_surface); EXPECT_CALL(mock_surface, get_current_buffer()) .Times(1) .WillOnce(Return(mock_client_buffer)); interpreter.driver_requests_buffer(); } TEST_F(AndroidInterpreterTest, native_window_dequeue_gets_native_handle_from_returned_buffer) { using namespace testing; auto buffer = std::make_shared(); testing::NiceMock mock_surface{surf_params}; mcla::ClientSurfaceInterpreter interpreter(mock_surface); EXPECT_CALL(*mock_client_buffer, native_buffer_handle()) .Times(1) .WillOnce(Return(buffer)); EXPECT_CALL(mock_surface, get_current_buffer()) .Times(1) .WillOnce(Return(mock_client_buffer)); auto returned_buffer = interpreter.driver_requests_buffer(); EXPECT_EQ(buffer.get(), returned_buffer); } TEST_F(AndroidInterpreterTest, native_window_queue_advances_buffer) { using namespace testing; ANativeWindowBuffer buffer; testing::NiceMock mock_surface{surf_params}; mcla::ClientSurfaceInterpreter interpreter(mock_surface); EXPECT_CALL(mock_surface, request_and_wait_for_next_buffer()) .Times(1); interpreter.driver_returns_buffer(&buffer, -1); } /* format is an int that is set by the driver. these are not the HAL_PIXEL_FORMATS in android */ TEST_F(AndroidInterpreterTest, native_window_perform_remembers_format) { int format = 945; testing::NiceMock mock_surface{surf_params}; mcla::ClientSurfaceInterpreter interpreter(mock_surface); interpreter.dispatch_driver_request_format(format); auto tmp_format = interpreter.driver_requests_info(NATIVE_WINDOW_FORMAT); EXPECT_EQ(format, tmp_format); } TEST_F(AndroidInterpreterTest, native_window_hint_query_hook) { testing::NiceMock mock_surface{surf_params}; mcla::ClientSurfaceInterpreter interpreter(mock_surface); /* transform hint is a bitmask of a few options for rotation/flipping buffer. a value of zero is no transform */ int transform_hint_zero = 0; auto transform = interpreter.driver_requests_info(NATIVE_WINDOW_TRANSFORM_HINT); EXPECT_EQ(transform_hint_zero, transform); } TEST_F(AndroidInterpreterTest, native_window_default_width_query_hook) { testing::NiceMock mock_surface{surf_params}; mcla::ClientSurfaceInterpreter interpreter(mock_surface); auto default_width = interpreter.driver_requests_info(NATIVE_WINDOW_DEFAULT_WIDTH); EXPECT_EQ(surf_params.width, default_width); } TEST_F(AndroidInterpreterTest, native_window_default_height_query_hook) { testing::NiceMock mock_surface{surf_params}; mcla::ClientSurfaceInterpreter interpreter(mock_surface); auto default_height = interpreter.driver_requests_info(NATIVE_WINDOW_DEFAULT_HEIGHT); EXPECT_EQ(surf_params.height, default_height); } TEST_F(AndroidInterpreterTest, native_window_width_query_hook) { testing::NiceMock mock_surface{surf_params}; mcla::ClientSurfaceInterpreter interpreter(mock_surface); auto width = interpreter.driver_requests_info(NATIVE_WINDOW_WIDTH); EXPECT_EQ(surf_params.width, width); } TEST_F(AndroidInterpreterTest, native_window_height_query_hook) { testing::NiceMock mock_surface{surf_params}; mcla::ClientSurfaceInterpreter interpreter(mock_surface); auto height = interpreter.driver_requests_info(NATIVE_WINDOW_HEIGHT); EXPECT_EQ(surf_params.height, height); } /* this is query key is a bit confusing from the system/window.h description. what it means is the minimum number of buffers that the server reserves for its own use in steady state. The drivers consider 'steady state' to begin after the first call to queueBuffer. So, for instance, if a driver requires 3 buffers to run at steady state, and the server needs to keep 2 buffers on hand at all time, the driver might dequeue 5 buffers, then cancel those 5 buffers. After the first call to queueBuffer however, the client may never own more than the number it has reserved (in this case, 3 buffers) */ TEST_F(AndroidInterpreterTest, native_window_minimum_undequeued_query_hook) { testing::NiceMock mock_surface{surf_params}; mcla::ClientSurfaceInterpreter interpreter(mock_surface); auto num_buffers = interpreter.driver_requests_info(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS); EXPECT_EQ(2, num_buffers); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/android/test_android_client_platform.cpp0000644000015301777760000000360712322054223031506 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "src/client/client_platform.h" #include "src/client/android/client_platform_factory.h" #include "mir_test_doubles/mock_client_context.h" #include "mir_test_doubles/mock_client_surface.h" #include #include namespace mcl = mir::client; namespace mt = mir::test; namespace mtd = mt::doubles; TEST(AndroidClientPlatformTest, egl_native_display_is_egl_default_display) { mtd::MockClientContext context; mcl::android::ClientPlatformFactory factory; mtd::MockClientSurface surface; auto platform = factory.create_client_platform(&context); auto mock_client_surface = std::make_shared(); auto native_display = platform->create_egl_native_display(); EXPECT_EQ(EGL_DEFAULT_DISPLAY, *native_display); } TEST(AndroidClientPlatformTest, egl_native_window_is_set) { mtd::MockClientContext context; mcl::android::ClientPlatformFactory factory; mtd::MockClientSurface surface; auto platform = factory.create_client_platform(&context); auto mock_client_surface = std::make_shared(); auto egl_native_window = platform->create_egl_native_window(&surface); EXPECT_NE(nullptr, egl_native_window); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/android/CMakeLists.txt0000644000015301777760000000214312322054223025613 0ustar pbusernogroup00000000000000# 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 list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_client_android_buffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_client_android_registrar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_native_window.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_client_platform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_client_surface_interpreter.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/client/test_client_buffer_depository.cpp0000644000015301777760000003145112322054223030272 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "src/client/client_buffer_depository.h" #include "src/client/client_buffer_factory.h" #include "src/client/aging_buffer.h" #include "mir_toolkit/common.h" #include "mir/geometry/size.h" #include #include namespace geom=mir::geometry; namespace mcl=mir::client; struct MockBuffer : public mcl::AgingBuffer { MockBuffer() { using namespace testing; ON_CALL(*this, mark_as_submitted()) .WillByDefault(Invoke([this](){this->AgingBuffer::mark_as_submitted();})); // By default we expect all buffers to be destroyed. EXPECT_CALL(*this, Destroy()).Times(1); } MOCK_METHOD0(Destroy, void()); virtual ~MockBuffer() noexcept { Destroy(); } MOCK_METHOD0(mark_as_submitted, void()); MOCK_METHOD0(secure_for_cpu_write, std::shared_ptr()); MOCK_CONST_METHOD0(size, geom::Size()); MOCK_CONST_METHOD0(stride, geom::Stride()); MOCK_CONST_METHOD0(pixel_format, MirPixelFormat()); MOCK_CONST_METHOD0(native_buffer_handle, std::shared_ptr()); }; struct MockClientBufferFactory : public mcl::ClientBufferFactory { MockClientBufferFactory() { using namespace testing; // Some tests, quite reasonably, rely on create_buffer returning a different buffer each time // Handle this by first updating our "buffer" temporary, then returning-by-pointee. ON_CALL(*this, create_buffer(_,_,_)) .WillByDefault(DoAll(InvokeWithoutArgs([this]() {this->buffer = std::make_shared>();}), ReturnPointee(&buffer))); } MOCK_METHOD3(create_buffer, std::shared_ptr(std::shared_ptr const&, geom::Size, MirPixelFormat)); std::shared_ptr buffer; }; struct MirBufferDepositoryTest : public testing::Test { void SetUp() { width = geom::Width(12); height =geom::Height(14); pf = mir_pixel_format_abgr_8888; size = geom::Size{width, height}; package = std::make_shared(); mock_factory = std::make_shared>(); } geom::Width width; geom::Height height; MirPixelFormat pf; geom::Size size; std::shared_ptr package; std::shared_ptr mock_factory; }; MATCHER_P(SizeMatches, value, "") { return value == arg; } TEST_F(MirBufferDepositoryTest, depository_sets_width_and_height) { using namespace testing; mcl::ClientBufferDepository depository{mock_factory, 3}; EXPECT_CALL(*mock_factory, create_buffer(_,size,pf)) .Times(1); depository.deposit_package(package, 8, size, pf); } TEST_F(MirBufferDepositoryTest, depository_new_deposit_changes_current_buffer) { using namespace testing; auto package2 = std::make_shared(); mcl::ClientBufferDepository depository{mock_factory, 3}; depository.deposit_package(package, 8, size, pf); auto buffer1 = depository.current_buffer(); depository.deposit_package(package2, 9, size, pf); auto buffer2 = depository.current_buffer(); EXPECT_NE(buffer1, buffer2); } TEST_F(MirBufferDepositoryTest, depository_sets_buffer_age_to_zero_for_new_buffer) { using namespace testing; mcl::ClientBufferDepository depository{mock_factory, 3}; depository.deposit_package(package, 1, size, pf); auto buffer1 = depository.current_buffer(); EXPECT_EQ(0u, buffer1->age()); } TEST_F(MirBufferDepositoryTest, just_sumbitted_buffer_has_age_1) { using namespace testing; mcl::ClientBufferDepository depository{mock_factory, 3}; auto package2 = std::make_shared(); depository.deposit_package(package, 1, size, pf); auto buffer1 = depository.current_buffer(); ASSERT_EQ(0u, buffer1->age()); // Deposit new package, implicitly marking previous buffer as submitted depository.deposit_package(package2, 2, size, pf); EXPECT_EQ(1u, buffer1->age()); } TEST_F(MirBufferDepositoryTest, submitting_buffer_ages_other_buffers) { using namespace testing; mcl::ClientBufferDepository depository{mock_factory, 3}; depository.deposit_package(package, 1, size, pf); auto buffer1 = depository.current_buffer(); EXPECT_EQ(0u, buffer1->age()); auto package2 = std::make_shared(); depository.deposit_package(package2, 2, size, pf); auto buffer2 = depository.current_buffer(); EXPECT_EQ(1u, buffer1->age()); EXPECT_EQ(0u, buffer2->age()); auto package3 = std::make_shared(); depository.deposit_package(package3, 3, size, pf); auto buffer3 = depository.current_buffer(); EXPECT_EQ(2u, buffer1->age()); EXPECT_EQ(1u, buffer2->age()); EXPECT_EQ(0u, buffer3->age()); } TEST_F(MirBufferDepositoryTest, double_buffering_reaches_steady_state_age) { using namespace testing; mcl::ClientBufferDepository depository{mock_factory, 3}; depository.deposit_package(package, 1, size, pf); auto buffer1 = depository.current_buffer(); EXPECT_EQ(0u, buffer1->age()); auto package2 = std::make_shared(); depository.deposit_package(package2, 2, size, pf); auto buffer2 = depository.current_buffer(); EXPECT_EQ(1u, buffer1->age()); EXPECT_EQ(0u, buffer2->age()); depository.deposit_package(package, 1, size, pf); EXPECT_EQ(2u, buffer1->age()); EXPECT_EQ(1u, buffer2->age()); depository.deposit_package(package2, 2, size, pf); EXPECT_EQ(1u, buffer1->age()); EXPECT_EQ(2u, buffer2->age()); } TEST_F(MirBufferDepositoryTest, triple_buffering_reaches_steady_state_age) { using namespace testing; mcl::ClientBufferDepository depository{mock_factory, 3}; depository.deposit_package(package, 1, size, pf); auto buffer1 = depository.current_buffer(); auto package2 = std::make_shared(); depository.deposit_package(package2, 2, size, pf); auto buffer2 = depository.current_buffer(); auto package3 = std::make_shared(); depository.deposit_package(package3, 3, size, pf); auto buffer3 = depository.current_buffer(); EXPECT_EQ(2u, buffer1->age()); EXPECT_EQ(1u, buffer2->age()); EXPECT_EQ(0u, buffer3->age()); depository.deposit_package(package, 1, size, pf); EXPECT_EQ(3u, buffer1->age()); EXPECT_EQ(2u, buffer2->age()); EXPECT_EQ(1u, buffer3->age()); depository.deposit_package(package2, 2, size, pf); EXPECT_EQ(1u, buffer1->age()); EXPECT_EQ(3u, buffer2->age()); EXPECT_EQ(2u, buffer3->age()); depository.deposit_package(package3, 3, size, pf); EXPECT_EQ(2u, buffer1->age()); EXPECT_EQ(1u, buffer2->age()); EXPECT_EQ(3u, buffer3->age()); } TEST_F(MirBufferDepositoryTest, depository_destroys_old_buffers) { using namespace testing; const int num_buffers = 3; mcl::ClientBufferDepository depository{mock_factory, num_buffers}; const int num_packages = 4; std::shared_ptr packages[num_packages]; depository.deposit_package(packages[0], 1, size, pf); // Raw pointer so we don't influence the buffer's life-cycle MockBuffer *first_buffer = static_cast(depository.current_buffer().get()); // We expect this to not be destroyed before we deposit the fourth buffer. bool buffer_destroyed = false; ON_CALL(*first_buffer, Destroy()).WillByDefault(Invoke([&buffer_destroyed] () {buffer_destroyed = true;})); depository.deposit_package(packages[1], 2, size, pf); depository.deposit_package(packages[2], 3, size, pf); // We've deposited three different buffers now; the fourth should trigger the destruction // of the first buffer. ASSERT_FALSE(buffer_destroyed); depository.deposit_package(packages[3], 4, size, pf); // Explicitly verify that the buffer has been destroyed here, before the depository goes out of scope // and its destructor cleans everything up. EXPECT_TRUE(buffer_destroyed); } TEST_F(MirBufferDepositoryTest, depositing_packages_implicitly_submits_current_buffer) { using namespace testing; const int num_buffers = 3; mcl::ClientBufferDepository depository{mock_factory, num_buffers}; auto package1 = std::make_shared(); auto package2 = std::make_shared(); depository.deposit_package(package1, 1, size, pf); EXPECT_CALL(*static_cast(depository.current_buffer().get()), mark_as_submitted()); depository.deposit_package(package2, 2, size, pf); } TEST_F(MirBufferDepositoryTest, depository_respects_max_buffer_parameter) { using namespace testing; std::shared_ptr depository; std::shared_ptr packages[10]; bool buffer_destroyed[10]; for (int num_buffers = 2; num_buffers < 10; ++num_buffers) { depository = std::make_shared(mock_factory, num_buffers); // Reset destroyed tracking; resetting the depository will have destroyed all the buffers for (bool& destroyed_flag : buffer_destroyed) destroyed_flag = false; int i; for (i = 0; i < num_buffers ; ++i) { MockBuffer *buffer; depository->deposit_package(packages[i], i + 1, size, pf); buffer = static_cast(depository->current_buffer().get()); ON_CALL(*buffer, Destroy()).WillByDefault(Invoke([&buffer_destroyed, i] () {buffer_destroyed[i] = true;})); } // Next deposit should destroy first buffer ASSERT_FALSE(buffer_destroyed[0]); depository->deposit_package(packages[i], i+1, size, pf); EXPECT_TRUE(buffer_destroyed[0]); // Verify none of the other buffers have been destroyed for (i = 1; i < num_buffers; ++i) EXPECT_FALSE(buffer_destroyed[i]); } } TEST_F(MirBufferDepositoryTest, depository_caches_recently_seen_buffer) { using namespace testing; mcl::ClientBufferDepository depository{mock_factory, 3}; auto package1 = std::make_shared(); auto package2 = std::make_shared(); EXPECT_CALL(*mock_factory, create_buffer(_,_,_)) .Times(1); depository.deposit_package(package1, 8, size, pf); depository.deposit_package(package1, 8, size, pf); depository.deposit_package(package1, 8, size, pf); } TEST_F(MirBufferDepositoryTest, depository_creates_new_buffer_for_different_id) { using namespace testing; mcl::ClientBufferDepository depository{mock_factory, 3}; auto package1 = std::make_shared(); auto package2 = std::make_shared(); EXPECT_CALL(*mock_factory, create_buffer(_,_,_)) .Times(2); depository.deposit_package(package1, 8, size, pf); depository.deposit_package(package2, 9, size, pf); } TEST_F(MirBufferDepositoryTest, depository_keeps_last_2_buffers_regardless_of_age) { using namespace testing; mcl::ClientBufferDepository depository{mock_factory, 2}; EXPECT_CALL(*mock_factory, create_buffer(_,_,_)).Times(2); depository.deposit_package(package, 8, size, pf); depository.deposit_package(package, 9, size, pf); depository.deposit_package(package, 9, size, pf); depository.deposit_package(package, 9, size, pf); depository.deposit_package(package, 8, size, pf); } TEST_F(MirBufferDepositoryTest, depository_keeps_last_3_buffers_regardless_of_age) { using namespace testing; mcl::ClientBufferDepository depository{mock_factory, 3}; EXPECT_CALL(*mock_factory, create_buffer(_,_,_)).Times(3); depository.deposit_package(package, 8, size, pf); depository.deposit_package(package, 9, size, pf); depository.deposit_package(package, 10, size, pf); depository.deposit_package(package, 9, size, pf); depository.deposit_package(package, 10, size, pf); depository.deposit_package(package, 9, size, pf); depository.deposit_package(package, 10, size, pf); depository.deposit_package(package, 8, size, pf); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/test_aging_buffer.cpp0000644000015301777760000000421512322054223025616 0ustar pbusernogroup00000000000000/* * 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: Christopher James Halse Rogers */ #include "src/client/aging_buffer.h" #include #include namespace mcl = mir::client; namespace geom = mir::geometry; namespace mir { namespace test { struct MyAgingBuffer : public mcl::AgingBuffer { std::shared_ptr secure_for_cpu_write() { exit(1); } geom::Size size() const { exit(1); } geom::Stride stride() const { exit(1); } MirPixelFormat pixel_format() const { exit(1); } std::shared_ptr native_buffer_handle() const { exit(1); } }; TEST(MirClientAgingBufferTest, buffer_age_starts_at_zero) { using namespace testing; MyAgingBuffer buffer; EXPECT_EQ(0u, buffer.age()); } TEST(MirClientAgingBufferTest, buffer_age_set_to_one_on_submit) { using namespace testing; MyAgingBuffer buffer; buffer.mark_as_submitted(); EXPECT_EQ(1u, buffer.age()); } TEST(MirClientAgingBufferTest, buffer_age_increases_on_increment) { using namespace testing; MyAgingBuffer buffer; buffer.mark_as_submitted(); for (uint32_t age = 2; age < 10; ++age) { buffer.increment_age(); EXPECT_EQ(age, buffer.age()); } } TEST(MirClientAgingBufferTest, incrementing_age_has_no_effect_for_unsubmitted_buffer) { using namespace testing; MyAgingBuffer buffer; buffer.increment_age(); EXPECT_EQ(0u, buffer.age()); } } } mir-0.1.8+14.04.20140411/tests/unit-tests/client/test_android_client_buffer_factory.cpp0000644000015301777760000000434212322054223031237 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "src/client/android/android_client_buffer_factory.h" #include "src/client/android/android_client_buffer.h" #include "mir_test_doubles/mock_android_registrar.h" #include namespace geom = mir::geometry; namespace mcla = mir::client::android; namespace mt = mir::test; namespace mtd = mir::test::doubles; struct MirBufferFactoryTest : public testing::Test { void SetUp() { width = geom::Width(12); height =geom::Height(14); size = geom::Size{width, height}; pf = mir_pixel_format_abgr_8888; mock_registrar = std::make_shared(); package1 = std::make_shared(); package1->width = width.as_int(); package1->height = height.as_int(); } geom::Width width; geom::Height height; MirPixelFormat pf; geom::Size size; std::shared_ptr mock_registrar; std::shared_ptr package1; }; TEST_F(MirBufferFactoryTest, factory_sets_width_and_height) { using namespace testing; mcla::AndroidClientBufferFactory buffer_factory(mock_registrar); EXPECT_CALL(*mock_registrar, register_buffer(_)) .Times(1); EXPECT_CALL(*mock_registrar, unregister_buffer(_)) .Times(1); auto buffer = buffer_factory.create_buffer(package1, size, pf); EXPECT_EQ(package1->width, buffer->size().width.as_int()); EXPECT_EQ(package1->height, buffer->size().height.as_int()); EXPECT_EQ(buffer->pixel_format(), pf); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/test_client.cpp0000644000015301777760000000271412322054223024460 0ustar pbusernogroup00000000000000/* * 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: Christopher James Halse Rogers */ #include "mir_toolkit/mir_client_library.h" #include #include #include TEST(MirClientTest, mir_connection_is_valid_handles_invalid_pointers) { using namespace testing; MirConnection *null_pointer = NULL; double stack_variable; MirConnection *not_a_mir_connection_on_the_stack = reinterpret_cast(&stack_variable); auto heap_variable = std::make_shared(); MirConnection *not_a_mir_connection_on_the_heap = reinterpret_cast(heap_variable.get()); ASSERT_FALSE(mir_connection_is_valid(null_pointer)); ASSERT_FALSE(mir_connection_is_valid(not_a_mir_connection_on_the_stack)); ASSERT_FALSE(mir_connection_is_valid(not_a_mir_connection_on_the_heap)); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/test_mir_screencast.cpp0000644000015301777760000004167512322054223026214 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/client/mir_screencast.h" #include "src/client/client_buffer_factory.h" #include "src/client/client_platform.h" #include "mir_test_doubles/null_client_buffer.h" #include #include #include namespace mcl = mir::client; namespace mp = mir::protobuf; namespace mtd = mir::test::doubles; namespace google { namespace protobuf { class RpcController; } } namespace { struct MockProtobufServer : mir::protobuf::DisplayServer { MOCK_METHOD4(create_screencast, void(google::protobuf::RpcController* /*controller*/, mp::ScreencastParameters const* /*request*/, mp::Screencast* /*response*/, google::protobuf::Closure* /*done*/)); MOCK_METHOD4(release_screencast, void(google::protobuf::RpcController* /*controller*/, mp::ScreencastId const* /*request*/, mp::Void* /*response*/, google::protobuf::Closure* /*done*/)); MOCK_METHOD4(screencast_buffer, void(google::protobuf::RpcController* /*controller*/, mp::ScreencastId const* /*request*/, mp::Buffer* /*response*/, google::protobuf::Closure* /*done*/)); }; class StubProtobufServer : public mir::protobuf::DisplayServer { public: void create_screencast( google::protobuf::RpcController* /*controller*/, mp::ScreencastParameters const* /*request*/, mp::Screencast* response, google::protobuf::Closure* done) override { if (server_thread.joinable()) server_thread.join(); server_thread = std::thread{ [response, done, this] { response->clear_error(); done->Run(); }}; } void release_screencast( google::protobuf::RpcController* /*controller*/, mp::ScreencastId const* /*request*/, mp::Void* /*response*/, google::protobuf::Closure* done) override { if (server_thread.joinable()) server_thread.join(); server_thread = std::thread{[done, this] { done->Run(); }}; } void screencast_buffer( google::protobuf::RpcController* /*controller*/, mp::ScreencastId const* /*request*/, mp::Buffer* /*response*/, google::protobuf::Closure* done) override { if (server_thread.joinable()) server_thread.join(); server_thread = std::thread{[done, this] { done->Run(); }}; } ~StubProtobufServer() { if (server_thread.joinable()) server_thread.join(); } private: std::thread server_thread; }; struct StubEGLNativeWindowFactory : mcl::EGLNativeWindowFactory { std::shared_ptr create_egl_native_window(mcl::ClientSurface*) { return std::make_shared(egl_native_window); } static EGLNativeWindowType egl_native_window; }; EGLNativeWindowType StubEGLNativeWindowFactory::egl_native_window{ reinterpret_cast(&StubEGLNativeWindowFactory::egl_native_window)}; class StubClientBufferFactory : public mcl::ClientBufferFactory { std::shared_ptr create_buffer( std::shared_ptr const& /*package*/, mir::geometry::Size /*size*/, MirPixelFormat /*pf*/) { return std::make_shared(); } }; struct MockClientBufferFactory : mcl::ClientBufferFactory { MOCK_METHOD3(create_buffer, std::shared_ptr( std::shared_ptr const& /*package*/, mir::geometry::Size /*size*/, MirPixelFormat /*pf*/)); }; MATCHER_P(WithOutputId, value, "") { return arg->output_id() == value; } MATCHER_P3(WithParams, region, size, pixel_format, "") { return arg->width() == size.width.as_uint32_t() && arg->height() == size.height.as_uint32_t() && arg->region().left() == region.top_left.x.as_int() && arg->region().top() == region.top_left.y.as_int() && arg->region().width() == region.size.width.as_uint32_t() && arg->region().height() == region.size.height.as_uint32_t() && arg->pixel_format() == pixel_format; } MATCHER_P(WithScreencastId, value, "") { return arg->value() == value; } ACTION_P(SetCreateScreencastId, screencast_id) { arg2->clear_error(); arg2->mutable_screencast_id()->set_value(screencast_id); } ACTION_P(SetCreateBufferId, buffer_id) { arg2->mutable_buffer()->set_buffer_id(buffer_id); } ACTION_P(SetBufferId, buffer_id) { arg2->set_buffer_id(buffer_id); } ACTION_P(SetCreateBufferFromPackage, package) { arg2->clear_error(); auto buffer = arg2->mutable_buffer(); for (int i = 0; i != package.data_items; ++i) { buffer->add_data(package.data[i]); } for (int i = 0; i != package.fd_items; ++i) { buffer->add_fd(package.fd[i]); } buffer->set_stride(package.stride); } ACTION(SetCreateError) { arg2->set_error("Test error"); } ACTION(RunClosure) { arg3->Run(); } MATCHER_P(BufferPackageSharedPtrMatches, package, "") { if (package.data_items != arg->data_items) return false; if (package.fd_items != arg->fd_items) return false; if (memcmp(package.data, arg->data, sizeof(package.data[0]) * package.data_items)) return false; if (package.stride != arg->stride) return false; return true; } struct MockCallback { MOCK_METHOD2(call, void(void*, void*)); }; void mock_callback_func(MirScreencast* screencast, void* context) { auto mock_cb = static_cast(context); mock_cb->call(screencast, context); } void null_callback_func(MirScreencast*, void*) { } class MirScreencastTest : public testing::Test { public: MirScreencastTest() : default_size{1, 1}, default_region{{0, 0}, {1, 1}}, default_pixel_format{mir_pixel_format_xbgr_8888}, stub_egl_native_window_factory{std::make_shared()}, stub_client_buffer_factory{std::make_shared()}, mock_client_buffer_factory{std::make_shared()} { } testing::NiceMock mock_server; StubProtobufServer stub_server; mir::geometry::Size default_size; mir::geometry::Rectangle default_region; MirPixelFormat default_pixel_format; std::shared_ptr const stub_egl_native_window_factory; std::shared_ptr const stub_client_buffer_factory; std::shared_ptr const mock_client_buffer_factory; }; } TEST_F(MirScreencastTest, creates_screencast_on_construction) { using namespace testing; EXPECT_CALL(mock_server, create_screencast(_,WithParams(default_region, default_size, default_pixel_format),_,_)) .WillOnce(RunClosure()); MirScreencast screencast{ default_region, default_size, default_pixel_format, mock_server, stub_egl_native_window_factory, stub_client_buffer_factory, null_callback_func, nullptr}; } TEST_F(MirScreencastTest, releases_screencast_on_release) { using namespace testing; uint32_t const screencast_id{77}; InSequence seq; EXPECT_CALL(mock_server, create_screencast(_,WithParams(default_region, default_size, default_pixel_format),_,_)) .WillOnce(DoAll(SetCreateScreencastId(screencast_id), RunClosure())); EXPECT_CALL(mock_server, release_screencast(_,WithScreencastId(screencast_id),_,_)) .WillOnce(RunClosure()); MirScreencast screencast{ default_region, default_size, default_pixel_format, mock_server, stub_egl_native_window_factory, stub_client_buffer_factory, null_callback_func, nullptr}; screencast.release(null_callback_func, nullptr); } TEST_F(MirScreencastTest, requests_screencast_buffer_on_next_buffer) { using namespace testing; uint32_t const screencast_id{77}; InSequence seq; EXPECT_CALL(mock_server, create_screencast(_,WithParams(default_region, default_size, default_pixel_format),_,_)) .WillOnce(DoAll(SetCreateScreencastId(screencast_id), RunClosure())); EXPECT_CALL(mock_server, screencast_buffer(_,WithScreencastId(screencast_id),_,_)) .WillOnce(RunClosure()); MirScreencast screencast{ default_region, default_size, default_pixel_format, mock_server, stub_egl_native_window_factory, stub_client_buffer_factory, null_callback_func, nullptr}; screencast.next_buffer(null_callback_func, nullptr); } TEST_F(MirScreencastTest, executes_callback_on_creation) { using namespace testing; MockCallback mock_cb; EXPECT_CALL(mock_cb, call(_, &mock_cb)); MirScreencast screencast{ default_region, default_size, default_pixel_format, stub_server, stub_egl_native_window_factory, stub_client_buffer_factory, mock_callback_func, &mock_cb}; screencast.creation_wait_handle()->wait_for_all(); } TEST_F(MirScreencastTest, executes_callback_on_release) { using namespace testing; MirScreencast screencast{ default_region, default_size, default_pixel_format, stub_server, stub_egl_native_window_factory, stub_client_buffer_factory, null_callback_func, nullptr}; screencast.creation_wait_handle()->wait_for_all(); MockCallback mock_cb; EXPECT_CALL(mock_cb, call(&screencast, &mock_cb)); auto wh = screencast.release(mock_callback_func, &mock_cb); wh->wait_for_all(); } TEST_F(MirScreencastTest, executes_callback_on_next_buffer) { using namespace testing; MirScreencast screencast{ default_region, default_size, default_pixel_format, stub_server, stub_egl_native_window_factory, stub_client_buffer_factory, null_callback_func, nullptr}; screencast.creation_wait_handle()->wait_for_all(); MockCallback mock_cb; EXPECT_CALL(mock_cb, call(&screencast, &mock_cb)); auto wh = screencast.next_buffer(mock_callback_func, &mock_cb); wh->wait_for_all(); } TEST_F(MirScreencastTest, construction_throws_on_invalid_params) { mir::geometry::Size const invalid_size{0, 0}; mir::geometry::Rectangle const invalid_region{{0, 0}, {0, 0}}; EXPECT_THROW({ MirScreencast screencast( default_region, invalid_size, default_pixel_format, stub_server, stub_egl_native_window_factory, stub_client_buffer_factory, null_callback_func, nullptr); }, std::runtime_error); EXPECT_THROW({ MirScreencast screencast( invalid_region, default_size, default_pixel_format, stub_server, stub_egl_native_window_factory, stub_client_buffer_factory, null_callback_func, nullptr); }, std::runtime_error); EXPECT_THROW({ MirScreencast screencast( default_region, default_size, mir_pixel_format_invalid, stub_server, stub_egl_native_window_factory, stub_client_buffer_factory, null_callback_func, nullptr); }, std::runtime_error); } TEST_F(MirScreencastTest, returns_correct_surface_parameters) { MirScreencast screencast{ default_region, default_size, default_pixel_format, stub_server, stub_egl_native_window_factory, stub_client_buffer_factory, null_callback_func, nullptr}; screencast.creation_wait_handle()->wait_for_all(); auto params = screencast.get_parameters(); EXPECT_STREQ("", params.name); EXPECT_EQ(default_size.width.as_int(), params.width); EXPECT_EQ(default_size.height.as_int(), params.height); EXPECT_EQ(default_pixel_format, params.pixel_format); EXPECT_EQ(mir_buffer_usage_hardware, params.buffer_usage); EXPECT_EQ(mir_display_output_id_invalid, params.output_id); } TEST_F(MirScreencastTest, uses_buffer_message_from_server) { using namespace testing; auto const client_buffer1 = std::make_shared(); MirBufferPackage buffer_package; buffer_package.fd_items = 1; buffer_package.fd[0] = 16; buffer_package.data_items = 2; buffer_package.data[0] = 100; buffer_package.data[1] = 234; buffer_package.stride = 768; EXPECT_CALL(mock_server, create_screencast(_,WithParams(default_region, default_size, default_pixel_format),_,_)) .WillOnce(DoAll(SetCreateBufferFromPackage(buffer_package), RunClosure())); EXPECT_CALL(*mock_client_buffer_factory, create_buffer(BufferPackageSharedPtrMatches(buffer_package),_,_)) .WillOnce(Return(client_buffer1)); MirScreencast screencast{ default_region, default_size, default_pixel_format, mock_server, stub_egl_native_window_factory, mock_client_buffer_factory, null_callback_func, nullptr}; screencast.creation_wait_handle()->wait_for_all(); } TEST_F(MirScreencastTest, returns_current_client_buffer) { using namespace testing; uint32_t const screencast_id = 88; int const buffer_id1 = 5; int const buffer_id2 = 6; auto const client_buffer1 = std::make_shared(); auto const client_buffer2 = std::make_shared(); EXPECT_CALL(mock_server, create_screencast(_,WithParams(default_region, default_size, default_pixel_format),_,_)) .WillOnce(DoAll(SetCreateBufferId(buffer_id1), SetCreateScreencastId(screencast_id), RunClosure())); EXPECT_CALL(mock_server, screencast_buffer(_,WithScreencastId(screencast_id),_,_)) .WillOnce(DoAll(SetBufferId(buffer_id2), RunClosure())); EXPECT_CALL(*mock_client_buffer_factory, create_buffer(_,_,_)) .WillOnce(Return(client_buffer1)) .WillOnce(Return(client_buffer2)); MirScreencast screencast{ default_region, default_size, default_pixel_format, mock_server, stub_egl_native_window_factory, mock_client_buffer_factory, null_callback_func, nullptr}; screencast.creation_wait_handle()->wait_for_all(); EXPECT_EQ(client_buffer1, screencast.get_current_buffer()); auto wh = screencast.next_buffer(null_callback_func, nullptr); wh->wait_for_all(); EXPECT_EQ(client_buffer2, screencast.get_current_buffer()); } TEST_F(MirScreencastTest, gets_egl_native_window) { using namespace testing; MirScreencast screencast{ default_region, default_size, default_pixel_format, stub_server, stub_egl_native_window_factory, stub_client_buffer_factory, null_callback_func, nullptr}; screencast.creation_wait_handle()->wait_for_all(); auto egl_native_window = screencast.egl_native_window(); EXPECT_EQ(StubEGLNativeWindowFactory::egl_native_window, egl_native_window); } TEST_F(MirScreencastTest, is_invalid_if_server_create_screencast_fails) { using namespace testing; EXPECT_CALL(mock_server, create_screencast(_,_,_,_)) .WillOnce(DoAll(SetCreateError(), RunClosure())); MirScreencast screencast{ default_region, default_size, default_pixel_format, mock_server, stub_egl_native_window_factory, stub_client_buffer_factory, null_callback_func, nullptr}; screencast.creation_wait_handle()->wait_for_all(); EXPECT_FALSE(screencast.valid()); } TEST_F(MirScreencastTest, calls_callback_on_creation_failure) { using namespace testing; MockCallback mock_cb; EXPECT_CALL(mock_server, create_screencast(_,_,_,_)) .WillOnce(DoAll(SetCreateError(), RunClosure())); EXPECT_CALL(mock_cb, call(_,&mock_cb)); MirScreencast screencast{ default_region, default_size, default_pixel_format, mock_server, stub_egl_native_window_factory, stub_client_buffer_factory, mock_callback_func, &mock_cb}; screencast.creation_wait_handle()->wait_for_all(); EXPECT_FALSE(screencast.valid()); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/test_client_display_conf.cpp0000644000015301777760000000505712322054223027215 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/client/display_configuration.h" #include "mir_test/display_config_matchers.h" #include "gtest/gtest.h" namespace mp = mir::protobuf; namespace mcl = mir::client; namespace mt = mir::test; namespace { void fill(mp::DisplayCard* out) { out->set_card_id(7); out->set_max_simultaneous_outputs(3); } void fill(mp::DisplayOutput* out) { out->add_pixel_format(4); out->set_current_format(45); auto mode = out->add_mode(); mode->set_horizontal_resolution(4); mode->set_vertical_resolution(558); mode->set_refresh_rate(4.33f); out->set_current_mode(0); out->set_position_x(5); out->set_position_y(6); out->set_card_id(7); out->set_output_id(8); out->set_connected(1); out->set_used(1); out->set_physical_width_mm(11); out->set_physical_height_mm(12); out->set_orientation(90); } } TEST(TestDisplayConfiguration, configuration_storage) { mp::DisplayConfiguration protobuf_config; fill(protobuf_config.add_display_output()); fill(protobuf_config.add_display_output()); fill(protobuf_config.add_display_card()); fill(protobuf_config.add_display_card()); fill(protobuf_config.add_display_card()); mcl::DisplayConfiguration internal_config; internal_config.update_configuration(protobuf_config); MirDisplayConfiguration *info; info = internal_config.copy_to_client(); EXPECT_THAT(*info, mt::DisplayConfigMatches(protobuf_config)); mcl::delete_config_storage(info); int called_count = 0u; internal_config.set_display_change_handler([&]() { called_count++; }); mp::DisplayConfiguration new_result; fill(new_result.add_display_output()); internal_config.update_configuration(new_result); info = internal_config.copy_to_client(); EXPECT_THAT(*info, mt::DisplayConfigMatches(new_result)); EXPECT_EQ(1u, called_count); mcl::delete_config_storage(info); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/test_client_mir_surface.cpp0000644000015301777760000005727012322054223027046 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_protobuf.pb.h" #include "mir_toolkit/mir_client_library.h" #include "src/client/client_buffer.h" #include "src/client/client_buffer_factory.h" #include "src/client/client_platform.h" #include "src/client/client_platform_factory.h" #include "src/client/mir_surface.h" #include "src/client/mir_connection.h" #include "src/client/default_connection_configuration.h" #include "src/client/rpc/null_rpc_report.h" #include "src/client/rpc/make_rpc_channel.h" #include "src/client/rpc/mir_basic_rpc_channel.h" #include "src/server/frontend/resource_cache.h" #include "mir/frontend/connector.h" #include "mir/input/input_platform.h" #include "mir/input/input_receiver_thread.h" #include "mir_test/test_protobuf_server.h" #include "mir_test/stub_server_tool.h" #include "mir_test/test_protobuf_client.h" #include "mir_test/gmock_fixes.h" #include "mir_test/fake_shared.h" #include #include #include #include namespace mcl = mir::client; namespace mircv = mir::input::receiver; namespace mp = mir::protobuf; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace mir { namespace test { struct MockServerPackageGenerator : public StubServerTool { MockServerPackageGenerator() : server_package(), global_buffer_id(0) { width_sent = 891; height_sent = 458; pf_sent = mir_pixel_format_abgr_8888; stride_sent = 66; input_fd = open("/dev/null", O_APPEND); } ~MockServerPackageGenerator() { close(input_fd); for (int i = 0; i < server_package.fd_items; i++) close(server_package.fd[i]); } void create_surface(google::protobuf::RpcController*, const mir::protobuf::SurfaceParameters* request, mir::protobuf::Surface* response, google::protobuf::Closure* done) { create_surface_response(response); surface_name = request->surface_name(); done->Run(); } void next_buffer( ::google::protobuf::RpcController* /*controller*/, ::mir::protobuf::SurfaceId const* /*request*/, ::mir::protobuf::Buffer* response, ::google::protobuf::Closure* done) { create_buffer_response(response); done->Run(); } /* helpers */ void generate_unique_buffer() { global_buffer_id++; for (int i = 0; i < server_package.fd_items; i++) close(server_package.fd[i]); int num_fd = 2, num_data = 8; for (auto i=0; iset_buffer_id(global_buffer_id); /* assemble buffers */ response->set_fds_on_side_channel(server_package.fd_items); for (int i=0; i< server_package.data_items; i++) { response->add_data(server_package.data[i]); } for (int i=0; i< server_package.fd_items; i++) { response->add_fd(server_package.fd[i]); } response->set_stride(server_package.stride); response->set_width(server_package.width); response->set_height(server_package.height); } void create_surface_response(mir::protobuf::Surface* response) { response->set_fds_on_side_channel(1); response->mutable_id()->set_value(2); response->set_width(width_sent); response->set_height(height_sent); response->set_pixel_format(pf_sent); response->add_fd(input_fd); create_buffer_response(response->mutable_buffer()); } }; struct MockBuffer : public mcl::ClientBuffer { MockBuffer() { } ~MockBuffer() noexcept { } MOCK_METHOD0(secure_for_cpu_write, std::shared_ptr()); MOCK_CONST_METHOD0(size, geom::Size()); MOCK_CONST_METHOD0(stride, geom::Stride()); MOCK_CONST_METHOD0(pixel_format, MirPixelFormat()); MOCK_CONST_METHOD0(age, uint32_t()); MOCK_METHOD0(increment_age, void()); MOCK_METHOD0(mark_as_submitted, void()); MOCK_CONST_METHOD0(native_buffer_handle, std::shared_ptr()); }; struct MockClientBufferFactory : public mcl::ClientBufferFactory { MockClientBufferFactory() { using namespace testing; emptybuffer=std::make_shared>(); ON_CALL(*this, create_buffer(_,_,_)) .WillByDefault(DoAll(SaveArg<0>(¤t_package), InvokeWithoutArgs([this] () {this->current_buffer = std::make_shared>();}), ReturnPointee(¤t_buffer))); } MOCK_METHOD3(create_buffer, std::shared_ptr(std::shared_ptr const&, geom::Size, MirPixelFormat)); std::shared_ptr current_package; std::shared_ptr current_buffer; std::shared_ptr emptybuffer; }; struct StubClientPlatform : public mcl::ClientPlatform { MirPlatformType platform_type() const { return mir_platform_type_android; } std::shared_ptr create_buffer_factory() { return std::shared_ptr(); } std::shared_ptr create_egl_native_window(mcl::ClientSurface* /*surface*/) { return std::shared_ptr(); } std::shared_ptr create_egl_native_display() { return std::shared_ptr(); } MirNativeBuffer* convert_native_buffer(mir::graphics::NativeBuffer*) const { return nullptr; } }; struct StubClientPlatformFactory : public mcl::ClientPlatformFactory { std::shared_ptr create_client_platform(mcl::ClientContext* /*context*/) { return std::make_shared(); } }; struct StubClientInputPlatform : public mircv::InputPlatform { std::shared_ptr create_input_thread(int /* fd */, std::function const& /* callback */) { return std::shared_ptr(); } }; struct MockClientInputPlatform : public mircv::InputPlatform { MOCK_METHOD2(create_input_thread, std::shared_ptr(int, std::function const&)); }; struct MockInputReceiverThread : public mircv::InputReceiverThread { MOCK_METHOD0(start, void()); MOCK_METHOD0(stop, void()); MOCK_METHOD0(join, void()); }; class TestConnectionConfiguration : public mcl::DefaultConnectionConfiguration { public: TestConnectionConfiguration() : DefaultConnectionConfiguration("./test_socket_surface") { } std::shared_ptr the_rpc_report() override { return std::make_shared(); } std::shared_ptr the_client_platform_factory() override { return std::make_shared(); } }; } } namespace mt = mir::test; void connected_callback(MirConnection* /*connection*/, void * /*client_context*/) { } struct CallBack { void msg() {} }; struct MirClientSurfaceTest : public testing::Test { void SetUp() { // In case an earlier test left a stray file std::remove("./test_socket_surface"); mock_server_tool = std::make_shared(); test_server = std::make_shared("./test_socket_surface", mock_server_tool); test_server->comm->start(); mock_buffer_factory = std::make_shared>(); input_platform = std::make_shared(); params = MirSurfaceParameters{"test", 33, 45, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid}; /* connect dummy server */ connect_parameters.set_application_name("test"); /* connect client */ mt::TestConnectionConfiguration conf; connection = std::make_shared(conf); MirWaitHandle* wait_handle = connection->connect("MirClientSurfaceTest", connected_callback, 0); wait_handle->wait_for_all(); client_comm_channel = std::make_shared( conf.the_rpc_channel().get()); } void TearDown() { test_server.reset(); } std::shared_ptr connection; MirSurfaceParameters params; std::shared_ptr mock_buffer_factory; std::shared_ptr input_platform; mir::protobuf::Connection response; mir::protobuf::ConnectParameters connect_parameters; std::shared_ptr test_server; std::shared_ptr client_tools; std::shared_ptr mock_server_tool; CallBack callback; std::shared_ptr client_comm_channel; }; void empty_callback(MirSurface*, void*) { } TEST_F(MirClientSurfaceTest, client_buffer_created_on_surface_creation) { using namespace testing; EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)) .Times(1); auto surface = std::make_shared (connection.get(), *client_comm_channel, mock_buffer_factory, input_platform, params, &empty_callback, nullptr); auto wait_handle = surface->get_create_wait_handle(); wait_handle->wait_for_all(); } namespace { void empty_surface_callback(MirSurface*, void*) {} } TEST_F(MirClientSurfaceTest, client_buffer_created_on_next_buffer) { using namespace testing; EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)) .Times(1); auto surface = std::make_shared (connection.get(), *client_comm_channel, mock_buffer_factory, input_platform, params, &empty_callback, nullptr); auto wait_handle = surface->get_create_wait_handle(); wait_handle->wait_for_all(); EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)) .Times(1); auto buffer_wait_handle = surface->next_buffer(&empty_surface_callback, nullptr); buffer_wait_handle->wait_for_all(); } MATCHER_P(BufferPackageMatches, package, "") { // Can't simply use memcmp() on the whole struct because age is not sent over the wire if (package.data_items != arg.data_items) return false; // Note we can not compare the fd's directly as they may change when being sent over the wire. if (package.fd_items != arg.fd_items) return false; if (memcmp(package.data, arg.data, sizeof(package.data[0]) * package.data_items)) return false; if (package.stride != arg.stride) return false; return true; } TEST_F(MirClientSurfaceTest, client_buffer_uses_ipc_message_from_server_on_create) { using namespace testing; std::shared_ptr submitted_package; EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)) .Times(1) .WillOnce(DoAll(SaveArg<0>(&submitted_package), Return(mock_buffer_factory->emptybuffer))); auto surface = std::make_shared (connection.get(), *client_comm_channel, mock_buffer_factory, input_platform, params, &empty_callback, nullptr); auto wait_handle = surface->get_create_wait_handle(); wait_handle->wait_for_all(); /* check for same contents */ EXPECT_THAT(*submitted_package, BufferPackageMatches(mock_server_tool->server_package)); } TEST_F(MirClientSurfaceTest, message_width_used_in_buffer_creation ) { using namespace testing; geom::Size sz; std::shared_ptr submitted_package; EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)) .Times(1) .WillOnce(DoAll(SaveArg<1>(&sz), Return(mock_buffer_factory->emptybuffer))); auto surface = std::make_shared (connection.get(), *client_comm_channel, mock_buffer_factory, input_platform, params, &empty_callback, nullptr); auto wait_handle = surface->get_create_wait_handle(); wait_handle->wait_for_all(); EXPECT_EQ(sz.width.as_uint32_t(), (unsigned int) mock_server_tool->width_sent); } TEST_F(MirClientSurfaceTest, message_height_used_in_buffer_creation ) { using namespace testing; geom::Size sz; std::shared_ptr submitted_package; EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)) .Times(1) .WillOnce(DoAll(SaveArg<1>(&sz), Return(mock_buffer_factory->emptybuffer))); auto surface = std::make_shared (connection.get(), *client_comm_channel, mock_buffer_factory, input_platform, params, &empty_callback, nullptr); auto wait_handle = surface->get_create_wait_handle(); wait_handle->wait_for_all(); EXPECT_EQ(sz.height.as_uint32_t(), (unsigned int) mock_server_tool->height_sent); } TEST_F(MirClientSurfaceTest, message_pf_used_in_buffer_creation ) { using namespace testing; MirPixelFormat pf; std::shared_ptr submitted_package; EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)) .Times(1) .WillOnce(DoAll(SaveArg<2>(&pf), Return(mock_buffer_factory->emptybuffer))); auto surface = std::make_shared (connection.get(), *client_comm_channel, mock_buffer_factory, input_platform, params, &empty_callback, nullptr); auto wait_handle = surface->get_create_wait_handle(); wait_handle->wait_for_all(); EXPECT_EQ(pf, mir_pixel_format_abgr_8888); } namespace { static void null_event_callback(MirSurface*, MirEvent const*, void*) { } } TEST_F(MirClientSurfaceTest, input_fd_used_to_create_input_thread_when_delegate_specified) { using namespace ::testing; auto mock_input_platform = std::make_shared(); auto mock_input_thread = std::make_shared>(); MirEventDelegate delegate = {null_event_callback, nullptr}; EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)).Times(2); EXPECT_CALL(*mock_input_platform, create_input_thread(_, _)).Times(1) .WillOnce(Return(mock_input_thread)); EXPECT_CALL(*mock_input_thread, start()).Times(1); EXPECT_CALL(*mock_input_thread, stop()).Times(1); { auto surface = std::make_shared (connection.get(), *client_comm_channel, mock_buffer_factory, mock_input_platform, params, &empty_callback, nullptr); auto wait_handle = surface->get_create_wait_handle(); wait_handle->wait_for_all(); surface->set_event_handler(&delegate); } { // This surface should not trigger a call to the input platform as no input delegate is specified. auto surface = std::make_shared (connection.get(), *client_comm_channel, mock_buffer_factory, mock_input_platform, params, &empty_callback, nullptr); auto wait_handle = surface->get_create_wait_handle(); wait_handle->wait_for_all(); } } TEST_F(MirClientSurfaceTest, get_buffer_returns_last_received_buffer_package) { using namespace testing; EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)) .Times(1); auto surface = std::make_shared (connection.get(), *client_comm_channel, mock_buffer_factory, input_platform, params, &empty_callback, nullptr); auto wait_handle = surface->get_create_wait_handle(); wait_handle->wait_for_all(); Mock::VerifyAndClearExpectations(mock_buffer_factory.get()); EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)) .Times(1); auto buffer_wait_handle = surface->next_buffer(&empty_surface_callback, nullptr); buffer_wait_handle->wait_for_all(); Mock::VerifyAndClearExpectations(mock_buffer_factory.get()); } TEST_F(MirClientSurfaceTest, surface_resizes_with_latest_buffer) { using namespace testing; EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)) .Times(1); auto surface = std::make_shared (connection.get(), *client_comm_channel, mock_buffer_factory, input_platform, params, &empty_callback, nullptr); auto wait_handle = surface->get_create_wait_handle(); wait_handle->wait_for_all(); Mock::VerifyAndClearExpectations(mock_buffer_factory.get()); EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)) .Times(2); auto buffer_wait_handle = surface->next_buffer(&empty_surface_callback, nullptr); buffer_wait_handle->wait_for_all(); int new_width = mock_server_tool->width_sent += 12; int new_height = mock_server_tool->height_sent -= 34; auto const& before = surface->get_parameters(); EXPECT_NE(new_width, before.width); EXPECT_NE(new_height, before.height); buffer_wait_handle = surface->next_buffer(&empty_surface_callback, nullptr); buffer_wait_handle->wait_for_all(); auto const& after = surface->get_parameters(); EXPECT_EQ(new_width, after.width); EXPECT_EQ(new_height, after.height); Mock::VerifyAndClearExpectations(mock_buffer_factory.get()); } TEST_F(MirClientSurfaceTest, default_surface_type) { using namespace testing; using namespace mir::protobuf; EXPECT_CALL(*mock_buffer_factory, create_buffer(_,_,_)) .Times(1); auto surface = std::make_shared (connection.get(), *client_comm_channel, mock_buffer_factory, input_platform, params, &empty_callback, nullptr); surface->get_create_wait_handle()->wait_for_all(); EXPECT_EQ(mir_surface_type_normal, surface->attrib(mir_surface_attrib_type)); } TEST_F(MirClientSurfaceTest, default_surface_state) { auto surface = std::make_shared (connection.get(), *client_comm_channel, mock_buffer_factory, input_platform, params, &empty_callback, nullptr); surface->get_create_wait_handle()->wait_for_all(); // Test the default cached state value. It is always unknown until we // get a real answer from the server. EXPECT_EQ(mir_surface_state_unknown, surface->attrib(mir_surface_attrib_state)); } namespace { struct StubBuffer : public mcl::ClientBuffer { StubBuffer(geom::Size size, geom::Stride stride, MirPixelFormat pf) : size_{size}, stride_{stride}, pf_{pf} { } std::shared_ptr secure_for_cpu_write() { auto raw = new mcl::MemoryRegion{size_.width, size_.height, stride_, pf_, nullptr}; return std::shared_ptr(raw); } geom::Size size() const { return size_; } geom::Stride stride() const { return stride_; } MirPixelFormat pixel_format() const { return pf_; } uint32_t age() const { return 0; } void increment_age() {} void mark_as_submitted() {} std::shared_ptr native_buffer_handle() const { return std::shared_ptr(); } geom::Size size_; geom::Stride stride_; MirPixelFormat pf_; }; struct StubClientBufferFactory : public mcl::ClientBufferFactory { std::shared_ptr create_buffer( std::shared_ptr const& package, geom::Size size, MirPixelFormat pf) { return std::make_shared(size, geom::Stride{package->stride}, pf); } }; } TEST_F(MirClientSurfaceTest, get_cpu_region_returns_correct_data) { using namespace testing; struct TestDataEntry { int width; int height; int stride; MirPixelFormat pf; }; std::vector test_data{ {100, 200, 300, mir_pixel_format_argb_8888}, {101, 201, 301, mir_pixel_format_xrgb_8888}, {102, 202, 302, mir_pixel_format_bgr_888} }; auto stub_buffer_factory = std::make_shared(); for (auto& td : test_data) { mock_server_tool->width_sent = td.width; mock_server_tool->height_sent = td.height; mock_server_tool->stride_sent = td.stride; mock_server_tool->pf_sent = td.pf; auto surface = std::make_shared(connection.get(), *client_comm_channel, stub_buffer_factory, input_platform, params, &empty_callback, nullptr); auto wait_handle = surface->get_create_wait_handle(); wait_handle->wait_for_all(); MirGraphicsRegion region; surface->get_cpu_region(region); EXPECT_EQ(mock_server_tool->width_sent, region.width); EXPECT_EQ(mock_server_tool->height_sent, region.height); EXPECT_EQ(mock_server_tool->stride_sent, region.stride); EXPECT_EQ(mock_server_tool->pf_sent, region.pixel_format); } } mir-0.1.8+14.04.20140411/tests/unit-tests/client/mesa/0000755000015301777760000000000012322054703022363 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/client/mesa/test_client_buffer.cpp0000644000015301777760000001320412322054223026732 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "src/client/mesa/client_buffer.h" #include "src/client/mesa/client_buffer_factory.h" #include "src/client/mesa/buffer_file_ops.h" #include #include #include #include namespace geom=mir::geometry; namespace mclg=mir::client::mesa; namespace { class MockBufferFileOps : public mclg::BufferFileOps { public: MOCK_CONST_METHOD1(close, int(int fd)); MOCK_CONST_METHOD3(map, void*(int fd, off_t offset, size_t size)); MOCK_CONST_METHOD2(unmap, void(void* addr, size_t size)); }; struct MesaClientBufferTest : public testing::Test { void SetUp() { width = geom::Width(12); height =geom::Height(14); stride = geom::Stride(66); pf = mir_pixel_format_abgr_8888; size = geom::Size{width, height}; buffer_file_ops = std::make_shared>(); package = std::make_shared(); package->fd[0] = 167; package->fd_items = 1; package->stride = stride.as_uint32_t(); package->width = width.as_int(); package->height = height.as_int(); package_copy = std::make_shared(*package.get()); } geom::Width width; geom::Height height; geom::Stride stride; MirPixelFormat pf; geom::Size size; std::shared_ptr> buffer_file_ops; std::shared_ptr package; std::shared_ptr package_copy; }; } TEST_F(MesaClientBufferTest, width_and_height) { using namespace testing; mclg::ClientBuffer buffer(buffer_file_ops, package, size, pf); EXPECT_EQ(buffer.size().height, height); EXPECT_EQ(buffer.size().width, width); EXPECT_EQ(buffer.pixel_format(), pf); } TEST_F(MesaClientBufferTest, buffer_returns_correct_stride) { using namespace testing; mclg::ClientBuffer buffer(buffer_file_ops, package, size, pf); EXPECT_EQ(buffer.stride(), stride); } TEST_F(MesaClientBufferTest, buffer_returns_set_package) { using namespace testing; mclg::ClientBuffer buffer(buffer_file_ops, package, size, pf); auto package_return = buffer.native_buffer_handle(); EXPECT_EQ(package_return->data_items, package_copy->data_items); EXPECT_EQ(package_return->fd_items, package_copy->fd_items); EXPECT_EQ(package_return->stride, package_copy->stride); for (auto i=0; idata[i], package_copy->data[i]); for (auto i=0; ifd[i], package_copy->fd[i]); } TEST_F(MesaClientBufferTest, secure_for_cpu_write_maps_buffer_fd) { using namespace testing; void *map_addr{reinterpret_cast(0xabcdef)}; EXPECT_CALL(*buffer_file_ops, map(package->fd[0],_,_)) .WillOnce(Return(map_addr)); EXPECT_CALL(*buffer_file_ops, unmap(map_addr,_)) .Times(1); EXPECT_CALL(*buffer_file_ops, close(package->fd[0])) .Times(1); mclg::ClientBuffer buffer(buffer_file_ops, package, size, pf); auto mem_region = buffer.secure_for_cpu_write(); ASSERT_EQ(map_addr, mem_region->vaddr.get()); ASSERT_EQ(width, mem_region->width); ASSERT_EQ(height, mem_region->height); ASSERT_EQ(stride, mem_region->stride); ASSERT_EQ(pf, mem_region->format); } TEST_F(MesaClientBufferTest, secure_for_cpu_write_throws_on_map_failure) { using namespace testing; EXPECT_CALL(*buffer_file_ops, map(package->fd[0],_,_)) .WillOnce(Return(MAP_FAILED)); EXPECT_CALL(*buffer_file_ops, unmap(_,_)) .Times(0); EXPECT_CALL(*buffer_file_ops, close(package->fd[0])) .Times(1); mclg::ClientBuffer buffer(buffer_file_ops, package, size, pf); EXPECT_THROW({ auto mem_region = buffer.secure_for_cpu_write(); }, std::runtime_error); } TEST_F(MesaClientBufferTest, buffer_fd_closed_on_buffer_destruction) { using namespace testing; EXPECT_CALL(*buffer_file_ops, close(package->fd[0])) .Times(1); mclg::ClientBuffer buffer(buffer_file_ops, package, size, pf); } TEST_F(MesaClientBufferTest, factory_gets_size_from_package) { using namespace testing; mclg::ClientBufferFactory factory(buffer_file_ops); geom::Size unused_size{0, 0}; auto buffer = factory.create_buffer(package, unused_size, pf); auto const& buf_size = buffer->size(); EXPECT_EQ(package->width, buf_size.width.as_int()); EXPECT_EQ(package->height, buf_size.height.as_int()); EXPECT_NE(unused_size, buf_size); } TEST_F(MesaClientBufferTest, creation_with_invalid_buffer_package_throws) { using namespace testing; mclg::ClientBufferFactory factory(buffer_file_ops); auto const invalid_package = std::make_shared(); package->fd_items = 0; geom::Size const unused_size{0, 0}; EXPECT_THROW({ factory.create_buffer(invalid_package, unused_size, pf); }, std::runtime_error); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/mesa/test_mesa_native_display_container.cpp0000644000015301777760000000356112322054223032212 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/client/mesa/mesa_native_display_container.h" #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/mesa/native_display.h" #include #include #include namespace mclg = mir::client::mesa; namespace { struct MesaNativeDisplayContainerSetup : public testing::Test { MesaNativeDisplayContainerSetup() : container(std::make_shared()), connection(nullptr) { } std::shared_ptr const container; MirConnection* connection; }; } TEST_F(MesaNativeDisplayContainerSetup, valid_displays_come_from_factory) { using namespace ::testing; auto display = container->create(connection); EXPECT_TRUE(container->validate(display)); MirEGLNativeDisplayType invalid_native_display; EXPECT_FALSE(container->validate(&invalid_native_display)); } TEST_F(MesaNativeDisplayContainerSetup, releasing_displays_invalidates_address) { using namespace ::testing; auto display = container->create(connection); EXPECT_TRUE(container->validate(display)); container->release(display); EXPECT_FALSE(container->validate(display)); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/mesa/CMakeLists.txt0000644000015301777760000000201712322054223025120 0ustar pbusernogroup00000000000000# 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 list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_client_buffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_client_platform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_mesa_native_display_container.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_native_surface.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/client/mesa/test_native_surface.cpp0000644000015301777760000001113212322054223027117 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/client/mesa/native_surface.h" #include "src/client/client_buffer.h" #include "mir_test_doubles/mock_client_surface.h" #include #include namespace mtd=mir::test::doubles; namespace mcl=mir::client; namespace mcl=mir::client; namespace mclg=mir::client::mesa; namespace geom=mir::geometry; namespace { struct MockClientBuffer : public mcl::ClientBuffer { MockClientBuffer() { ON_CALL(*this, native_buffer_handle()) .WillByDefault(testing::Return(std::make_shared())); } ~MockClientBuffer() noexcept {} MOCK_METHOD0(secure_for_cpu_write, std::shared_ptr()); MOCK_CONST_METHOD0(size, geom::Size()); MOCK_CONST_METHOD0(stride, geom::Stride()); MOCK_CONST_METHOD0(pixel_format, MirPixelFormat()); MOCK_CONST_METHOD0(age, uint32_t()); MOCK_METHOD0(mark_as_submitted, void()); MOCK_METHOD0(increment_age, void()); MOCK_CONST_METHOD0(native_buffer_handle, std::shared_ptr()); }; } class MesaClientNativeSurfaceTest : public ::testing::Test { public: virtual void SetUp() { using namespace testing; surf_params.width = 530; surf_params.height = 715; surf_params.pixel_format = mir_pixel_format_abgr_8888; ON_CALL(mock_surface, get_parameters()) .WillByDefault(Return(surf_params)); ON_CALL(mock_surface, get_current_buffer()) .WillByDefault(Return( std::make_shared>())); } MirSurfaceParameters surf_params; testing::NiceMock mock_surface; }; TEST_F(MesaClientNativeSurfaceTest, basic_parameters) { mclg::NativeSurface interpreter(mock_surface); MirSurfaceParameters params; interpreter.surface_get_parameters(&interpreter, ¶ms); EXPECT_EQ(surf_params.width, params.width); EXPECT_EQ(surf_params.height, params.height); EXPECT_EQ(surf_params.pixel_format, params.pixel_format); } TEST_F(MesaClientNativeSurfaceTest, first_advance_skips_request) { // Verify the workaround for LP: #1281938 is functioning, until it's // fixed in Mesa and we can remove it from Mir. using namespace testing; MirBufferPackage buffer_package; EXPECT_CALL(mock_surface, request_and_wait_for_next_buffer()) .Times(0); EXPECT_CALL(mock_surface, get_current_buffer()) .Times(1); mclg::NativeSurface interpreter(mock_surface); interpreter.surface_advance_buffer(&interpreter, &buffer_package); } TEST_F(MesaClientNativeSurfaceTest, basic_advance) { using namespace testing; MirBufferPackage buffer_package; InSequence seq; EXPECT_CALL(mock_surface, get_current_buffer()) .Times(1); EXPECT_CALL(mock_surface, request_and_wait_for_next_buffer()) .Times(1); EXPECT_CALL(mock_surface, get_current_buffer()) .Times(1); mclg::NativeSurface interpreter(mock_surface); interpreter.surface_advance_buffer(&interpreter, &buffer_package); interpreter.surface_advance_buffer(&interpreter, &buffer_package); } TEST_F(MesaClientNativeSurfaceTest, swapinterval_request) { using namespace testing; Sequence seq; EXPECT_CALL(mock_surface, request_and_wait_for_configure(mir_surface_attrib_swapinterval,0)) .InSequence(seq); EXPECT_CALL(mock_surface, request_and_wait_for_configure(mir_surface_attrib_swapinterval,1)) .InSequence(seq); mclg::NativeSurface interpreter(mock_surface); interpreter.set_swapinterval(0); interpreter.set_swapinterval(1); } TEST_F(MesaClientNativeSurfaceTest, swapinterval_unsupported_request) { mclg::NativeSurface interpreter(mock_surface); EXPECT_EQ(MIR_MESA_FALSE, interpreter.set_swapinterval(-1)); EXPECT_EQ(MIR_MESA_TRUE, interpreter.set_swapinterval(0)); EXPECT_EQ(MIR_MESA_TRUE, interpreter.set_swapinterval(1)); EXPECT_EQ(MIR_MESA_FALSE, interpreter.set_swapinterval(2)); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/mesa/test_client_platform.cpp0000644000015301777760000000335212322054223027310 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "src/client/client_platform.h" #include "src/client/mesa/client_platform_factory.h" #include "src/client/mesa/mesa_native_display_container.h" #include "mir_test_doubles/mock_client_context.h" #include "mir_test_doubles/mock_client_surface.h" #include "mir_toolkit/mesa/native_display.h" #include namespace mcl = mir::client; namespace mclm = mir::client::mesa; namespace mt = mir::test; namespace mtd = mir::test::doubles; TEST(MesaClientPlatformTest, egl_native_display_is_valid_until_released) { mtd::MockClientContext context; mclm::ClientPlatformFactory factory; auto platform = factory.create_client_platform(&context); MirMesaEGLNativeDisplay* nd; { std::shared_ptr native_display = platform->create_egl_native_display(); nd = reinterpret_cast(*native_display); EXPECT_EQ(MIR_MESA_TRUE, mclm::mir_client_mesa_egl_native_display_is_valid(nd)); } EXPECT_EQ(MIR_MESA_FALSE, mclm::mir_client_mesa_egl_native_display_is_valid(nd)); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/input/0000755000015301777760000000000012322054703022575 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/client/input/test_android_input_receiver_thread.cpp0000644000015301777760000001052312322054223032410 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/shared/input/android/android_input_receiver_thread.h" #include "src/shared/input/android/android_input_receiver.h" #include "mir/input/null_input_receiver_report.h" #include "mir_toolkit/mir_client_library.h" #include #include #include #include #include namespace mircv = mir::input::receiver; namespace mircva = mircv::android; namespace { struct MockEventHandler { MOCK_METHOD1(handle_event, void(MirEvent*)); }; struct MockInputReceiver : public mircva::InputReceiver { MockInputReceiver(int fd) : InputReceiver(fd, std::make_shared()) { } MOCK_METHOD1(next_event, bool(MirEvent &)); }; struct AndroidInputReceiverThreadSetup : public testing::Test { AndroidInputReceiverThreadSetup() { test_receiver_fd = open("/dev/null", O_APPEND); input_receiver = std::make_shared(test_receiver_fd); } virtual ~AndroidInputReceiverThreadSetup() { close(test_receiver_fd); } int test_receiver_fd; std::shared_ptr input_receiver; }; ACTION_P(StopThread, thread) { thread->stop(); // thread->join(); } } TEST_F(AndroidInputReceiverThreadSetup, reads_events_until_stopped) { using namespace ::testing; mircva::InputReceiverThread input_thread(input_receiver, std::function()); { InSequence seq; EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(Return(false)); EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(Return(false)); EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(DoAll(StopThread(&input_thread), Return(false))); } input_thread.start(); input_thread.join(); } TEST_F(AndroidInputReceiverThreadSetup, receives_and_dispatches_available_events_when_ready) { using namespace ::testing; MockEventHandler mock_handler; struct InputDelegate { InputDelegate(MockEventHandler& handler) : handler(handler) {} void operator()(MirEvent* ev) { handler.handle_event(ev); } MockEventHandler &handler; } input_delegate(mock_handler); mircva::InputReceiverThread input_thread(input_receiver, input_delegate); { InSequence seq; EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(Return(true)); EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(Return(false)); EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(DoAll(StopThread(&input_thread), Return(true))); } EXPECT_CALL(mock_handler, handle_event(_)).Times(2); input_thread.start(); input_thread.join(); } TEST_F(AndroidInputReceiverThreadSetup, input_callback_invoked_from_thread) { using namespace ::testing; MockEventHandler mock_handler; std::atomic handled; handled = false; struct InputDelegate { InputDelegate(std::atomic &handled) : handled(handled) {} void operator()(MirEvent* /*ev*/) { handled = true; } std::atomic &handled; } input_delegate(handled); mircva::InputReceiverThread input_thread(input_receiver, input_delegate); { InSequence seq; EXPECT_CALL(*input_receiver, next_event(_)).Times(1).WillOnce(DoAll(StopThread(&input_thread), Return(true))); } input_thread.start(); // We would block forever here were delivery not threaded. // Yield to improve the run-time under valgrind. while (handled == false) std::this_thread::yield(); input_thread.join(); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/input/test_xkb_mapper.cpp0000644000015301777760000000525612322054223026475 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/input/xkb_mapper.h" #include #include #include #include namespace mircv = mir::input::receiver; namespace { static int map_key(mircv::XKBMapper &mapper, MirKeyAction action, int scan_code) { MirKeyEvent ev; ev.action = action; ev.scan_code = scan_code; ev.repeat_count = 0; mapper.update_state_and_map_event(ev); return ev.key_code; } static int map_repeated_key(mircv::XKBMapper &mapper, MirKeyAction action, int scan_code) { MirKeyEvent ev; ev.action = action; ev.scan_code = scan_code; ev.repeat_count = 1; mapper.update_state_and_map_event(ev); return ev.key_code; } } TEST(XKBMapper, maps_generic_us_english_keys) { mircv::XKBMapper mapper; EXPECT_EQ(XKB_KEY_4, map_key(mapper, mir_key_action_down, KEY_4)); EXPECT_EQ(XKB_KEY_Shift_L, map_key(mapper, mir_key_action_down, KEY_LEFTSHIFT)); EXPECT_EQ(XKB_KEY_dollar, map_key(mapper, mir_key_action_down, KEY_4)); EXPECT_EQ(XKB_KEY_dollar, map_key(mapper, mir_key_action_up, KEY_4)); EXPECT_EQ(XKB_KEY_Shift_L, map_key(mapper, mir_key_action_up, KEY_LEFTSHIFT)); EXPECT_EQ(XKB_KEY_4, map_key(mapper, mir_key_action_down, KEY_4)); } TEST(XKBMapper, key_action_multiple_does_not_update_modifier_state) { mircv::XKBMapper mapper; EXPECT_EQ(XKB_KEY_Shift_R, map_key(mapper, mir_key_action_multiple, KEY_RIGHTSHIFT)); EXPECT_EQ(XKB_KEY_7, map_key(mapper, mir_key_action_down, KEY_7)); } TEST(XKBMapper, key_repeats_do_not_recurse_modifier_state) { mircv::XKBMapper mapper; EXPECT_EQ(XKB_KEY_Shift_R, map_key(mapper, mir_key_action_down, KEY_RIGHTSHIFT)); EXPECT_EQ(XKB_KEY_Shift_R, map_repeated_key(mapper, mir_key_action_down, KEY_RIGHTSHIFT)); EXPECT_EQ(XKB_KEY_ampersand, map_key(mapper, mir_key_action_down, KEY_7)); EXPECT_EQ(XKB_KEY_Shift_R, map_key(mapper, mir_key_action_up, KEY_RIGHTSHIFT)); EXPECT_EQ(XKB_KEY_7, map_key(mapper, mir_key_action_down, KEY_7)); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/input/CMakeLists.txt0000644000015301777760000000042612322054223025334 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_receiver_thread.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_receiver.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_xkb_mapper.cpp ) set( UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/client/input/test_android_input_receiver.cpp0000644000015301777760000001374712322054223031074 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/shared/input/android/android_input_receiver.h" #include "mir/input/null_input_receiver_report.h" #include "mir_toolkit/event.h" #include #include #include #include #include namespace mircv = mir::input::receiver; namespace mircva = mircv::android; namespace droidinput = android; namespace { class TestingInputProducer { public: TestingInputProducer(int fd) : input_publisher(std::make_shared(new droidinput::InputChannel("", fd))), incrementing_seq_id(1), // Sequence id must be > 0 or publisher will reject testing_key_event_scan_code(13) { } // The input publisher does not care about event semantics so we only highlight // a few fields for transport verification void produce_a_key_event() { input_publisher->publishKeyEvent( incrementing_seq_id, filler_device_id, 0 /* source */, 0 /* action */, 0 /* flags */, 0 /* key_code */, testing_key_event_scan_code, 0 /* meta_state */, 0 /* repeat_count */, 0 /* down_time */, 0 /* event_time */); } void produce_a_motion_event() { droidinput::PointerProperties filler_pointer_properties; droidinput::PointerCoords filler_pointer_coordinates; memset(&filler_pointer_properties, 0, sizeof(droidinput::PointerProperties)); memset(&filler_pointer_coordinates, 0, sizeof(droidinput::PointerCoords)); input_publisher->publishMotionEvent( incrementing_seq_id, filler_device_id, 0 /* source */, motion_event_action_flags, 0 /* flags */, 0 /* edge_flags */, 0 /* meta_state */, 0 /* button_state */, 0 /* x_offset */, 0 /* y_offset */, 0 /* x_precision */, 0 /* y_precision */, 0 /* down_time */, 0 /* event_time */, default_pointer_count, &filler_pointer_properties, &filler_pointer_coordinates); } bool must_receive_handled_signal() { uint32_t seq; bool handled; auto status = input_publisher->receiveFinishedSignal(&seq, &handled); return (status == droidinput::OK) && handled; } std::shared_ptr input_publisher; int incrementing_seq_id; int32_t testing_key_event_scan_code; // Some default values // device_id must be > 0 or input publisher will reject static const int32_t filler_device_id = 1; // event_action_move is necessary to engage batching behavior static const int32_t motion_event_action_flags = mir_motion_action_move; // We have to have at least 1 pointer or the publisher will fail to marshal a motion event static const int32_t default_pointer_count = 1; }; class AndroidInputReceiverSetup : public testing::Test { public: AndroidInputReceiverSetup() { auto status = droidinput::InputChannel::openInputFdPair(server_fd, client_fd); EXPECT_EQ(droidinput::OK, status); } ~AndroidInputReceiverSetup() { close(server_fd); close(client_fd); } void flush_channels() { fsync(server_fd); fsync(client_fd); } int server_fd, client_fd; static std::chrono::milliseconds const next_event_timeout; }; std::chrono::milliseconds const AndroidInputReceiverSetup::next_event_timeout(1000); } TEST_F(AndroidInputReceiverSetup, receiever_takes_channel_fd) { mircva::InputReceiver receiver(client_fd, std::make_shared()); EXPECT_EQ(client_fd, receiver.fd()); } TEST_F(AndroidInputReceiverSetup, receiver_receives_key_events) { mircva::InputReceiver receiver(client_fd, std::make_shared()); TestingInputProducer producer(server_fd); producer.produce_a_key_event(); flush_channels(); MirEvent ev; EXPECT_EQ(true, receiver.next_event(next_event_timeout, ev)); EXPECT_EQ(mir_event_type_key, ev.type); EXPECT_EQ(producer.testing_key_event_scan_code, ev.key.scan_code); } TEST_F(AndroidInputReceiverSetup, receiver_handles_events) { mircva::InputReceiver receiver(client_fd, std::make_shared()); TestingInputProducer producer(server_fd); producer.produce_a_key_event(); flush_channels(); MirEvent ev; EXPECT_EQ(true, receiver.next_event(next_event_timeout, ev)); flush_channels(); EXPECT_TRUE (producer.must_receive_handled_signal()); } TEST_F(AndroidInputReceiverSetup, receiver_consumes_batched_motion_events) { mircva::InputReceiver receiver(client_fd, std::make_shared()); TestingInputProducer producer(server_fd); // Produce 3 motion events before client handles any. producer.produce_a_motion_event(); producer.produce_a_motion_event(); producer.produce_a_motion_event(); flush_channels(); MirEvent ev; // Handle all three events as a batched event EXPECT_TRUE(receiver.next_event(next_event_timeout, ev)); // Now there should be no events EXPECT_FALSE(receiver.next_event(std::chrono::milliseconds(1), ev)); // Minimal timeout needed for valgrind } mir-0.1.8+14.04.20140411/tests/unit-tests/client/CMakeLists.txt0000644000015301777760000000143712322054223024200 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_aging_buffer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_client.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_client_buffer_depository.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_client_platform.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_client_mir_surface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_mir_connection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_wait_handle.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_client_display_conf.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_mir_screencast.cpp ) if(MIR_TEST_PLATFORM STREQUAL "android") add_subdirectory("android") endif() if(MIR_TEST_PLATFORM STREQUAL "mesa") add_subdirectory("mesa") endif() if (NOT MIR_DISABLE_INPUT) add_subdirectory("input") endif() set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/client/test_client_platform.cpp0000644000015301777760000000476712322054223026376 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/client/client_platform.h" #include "src/client/mir_client_surface.h" #include "mir_test_doubles/mock_client_context.h" #include "mir_test_doubles/mock_client_surface.h" #ifdef ANDROID #include "mir_test_doubles/mock_android_hw.h" #include "src/client/android/client_platform_factory.h" #else #include "src/client/mesa/client_platform_factory.h" #endif #include #include namespace mcl=mir::client; namespace mtd = mir::test::doubles; struct ClientPlatformTest : public ::testing::Test { mtd::MockClientContext context; #ifdef ANDROID testing::NiceMock hw_access_mock; mcl::android::ClientPlatformFactory factory; #else mcl::mesa::ClientPlatformFactory factory; #endif }; TEST_F(ClientPlatformTest, platform_name) { auto platform = factory.create_client_platform(&context); #ifdef ANDROID auto type = mir_platform_type_android; #else auto type = mir_platform_type_gbm; #endif EXPECT_EQ(type, platform->platform_type()); } TEST_F(ClientPlatformTest, platform_creates) { auto platform = factory.create_client_platform(&context); auto buffer_factory = platform->create_buffer_factory(); EXPECT_NE(buffer_factory.get(), (mcl::ClientBufferFactory*) NULL); } TEST_F(ClientPlatformTest, platform_creates_native_window) { auto platform = factory.create_client_platform(&context); auto mock_client_surface = std::make_shared(); auto native_window = platform->create_egl_native_window(mock_client_surface.get()); EXPECT_NE(*native_window, (EGLNativeWindowType) NULL); } TEST_F(ClientPlatformTest, platform_creates_egl_native_display) { auto platform = factory.create_client_platform(&context); auto native_display = platform->create_egl_native_display(); EXPECT_NE(nullptr, native_display.get()); } mir-0.1.8+14.04.20140411/tests/unit-tests/client/test_wait_handle.cpp0000644000015301777760000000674112322054223025465 0ustar pbusernogroup00000000000000/* * 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 */ #include #include #include "src/client/mir_wait_handle.h" TEST(WaitHandle, symmetric_synchronous) { MirWaitHandle w; for (int i = 0; i < 100; i++) { w.result_received(); w.wait_for_all(); } EXPECT_TRUE(true); // Failure would be hanging in the above loop } TEST(WaitHandle, asymmetric_synchronous) { MirWaitHandle w; for (int i = 1; i <= 100; i++) { for (int j = 1; j <= i; j++) w.result_received(); w.wait_for_all(); } EXPECT_TRUE(true); // Failure would be hanging in the above loop } namespace { int symmetric_result = 0; void symmetric_thread(MirWaitHandle *in, MirWaitHandle *out, int max) { for (int i = 1; i <= max; i++) { in->wait_for_all(); symmetric_result = i; out->result_received(); } } } TEST(WaitHandle, symmetric_asynchronous) { const int max = 100; MirWaitHandle in, out; std::thread t(symmetric_thread, &in, &out, max); for (int i = 1; i <= max; i++) { in.result_received(); out.wait_for_all(); ASSERT_EQ(symmetric_result, i); } t.join(); } namespace { int asymmetric_result = 0; void asymmetric_thread(MirWaitHandle *in, MirWaitHandle *out, int max) { for (int i = 1; i <= max; i++) { in->wait_for_all(); asymmetric_result = i; for (int j = 1; j <= i; j++) out->result_received(); } } } TEST(WaitHandle, asymmetric_asynchronous) { const int max = 100; MirWaitHandle in, out; std::thread t(asymmetric_thread, &in, &out, max); for (int i = 1; i <= max; i++) { in.result_received(); for (int j = 1; j <= i; j++) out.expect_result(); out.wait_for_all(); ASSERT_EQ(asymmetric_result, i); } t.join(); } namespace { void crowded_thread(MirWaitHandle *w, int max) { for (int i = 0; i < max; i++) { /* * This doesn't work with wait_for_all, because waiters will * race and the winner would gobble up all the results, leaving * the other waiters hanging forever. So we have wait_for_one() * to allow many threads to safely wait on the same handle and * guarantee that they will all get the number of results they * expect. */ w->wait_for_one(); } } } TEST(WaitHandle, many_waiters) { const int max = 100; MirWaitHandle w; std::thread a(crowded_thread, &w, max); std::thread b(crowded_thread, &w, max); std::thread c(crowded_thread, &w, max); for (int n = 0; n < max * 3; n++) w.result_received(); a.join(); b.join(); c.join(); } mir-0.1.8+14.04.20140411/tests/unit-tests/shell/0000755000015301777760000000000012322054703021267 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/shell/test_consuming_placement_strategy.cpp0000644000015301777760000000553612322054223031014 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_doubles/mock_display_layout.h" #include "mir_test_doubles/stub_shell_session.h" #include "src/server/shell/consuming_placement_strategy.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/geometry/rectangle.h" #include #include namespace msh = mir::shell; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; namespace { struct ConsumingPlacementStrategySetup : public testing::Test { void SetUp() { using namespace ::testing; display_layout = std::make_shared(); } std::shared_ptr display_layout; mtd::StubShellSession session; }; } TEST_F(ConsumingPlacementStrategySetup, parameters_with_no_geometry_are_made_fullscreen) { using namespace ::testing; msh::SurfaceCreationParameters input_params; geom::Rectangle rect{input_params.top_left, input_params.size}; EXPECT_CALL(*display_layout, size_to_output(rect)).Times(1); msh::ConsumingPlacementStrategy placement_strategy(display_layout); placement_strategy.place(session, input_params); } TEST_F(ConsumingPlacementStrategySetup, parameters_with_geometry_are_clipped) { using namespace ::testing; msh::SurfaceCreationParameters input_params; input_params.size = geom::Size{100, 200}; geom::Rectangle rect{input_params.top_left, input_params.size}; EXPECT_CALL(*display_layout, clip_to_output(rect)).Times(1); msh::ConsumingPlacementStrategy placement_strategy(display_layout); placement_strategy.place(session, input_params); } TEST_F(ConsumingPlacementStrategySetup, parameters_with_output_id_are_placed_in_output) { using namespace ::testing; msh::SurfaceCreationParameters input_params; input_params.size = geom::Size{100, 200}; input_params.output_id = mir::graphics::DisplayConfigurationOutputId{1}; geom::Rectangle rect{input_params.top_left, input_params.size}; EXPECT_CALL(*display_layout, place_in_output(input_params.output_id, rect)) .Times(1); msh::ConsumingPlacementStrategy placement_strategy(display_layout); placement_strategy.place(session, input_params); } mir-0.1.8+14.04.20140411/tests/unit-tests/shell/test_mediating_display_changer.cpp0000644000015301777760000002701412322054223030210 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/shell/mediating_display_changer.h" #include "src/server/shell/session_container.h" #include "mir/graphics/display_configuration_policy.h" #include "src/server/shell/broadcasting_session_event_sink.h" #include "mir_test_doubles/mock_display.h" #include "mir_test_doubles/mock_compositor.h" #include "mir_test_doubles/null_display_configuration.h" #include "mir_test_doubles/stub_display_configuration.h" #include "mir_test_doubles/mock_shell_session.h" #include "mir_test_doubles/stub_shell_session.h" #include "mir_test/fake_shared.h" #include "mir_test/display_config_matchers.h" #include #include namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace mf = mir::frontend; namespace msh = mir::shell; namespace mg = mir::graphics; class MockDisplayConfigurationPolicy : public mg::DisplayConfigurationPolicy { public: ~MockDisplayConfigurationPolicy() noexcept {} MOCK_METHOD1(apply_to, void(mg::DisplayConfiguration&)); }; class StubSessionContainer : public msh::SessionContainer { public: void insert_session(std::shared_ptr const& session) { sessions.push_back(session); } void remove_session(std::shared_ptr const&) { } void for_each(std::function const&)> f) const { for (auto const& session : sessions) f(session); } private: std::vector> sessions; }; struct MediatingDisplayChangerTest : public ::testing::Test { MediatingDisplayChangerTest() { using namespace testing; ON_CALL(mock_display, configuration()) .WillByDefault(Return(mt::fake_shared(base_config))); changer = std::make_shared( mt::fake_shared(mock_display), mt::fake_shared(mock_compositor), mt::fake_shared(mock_conf_policy), mt::fake_shared(stub_session_container), mt::fake_shared(session_event_sink)); } testing::NiceMock mock_display; testing::NiceMock mock_compositor; testing::NiceMock mock_conf_policy; StubSessionContainer stub_session_container; msh::BroadcastingSessionEventSink session_event_sink; mtd::StubDisplayConfig base_config; std::shared_ptr changer; }; TEST_F(MediatingDisplayChangerTest, returns_active_configuration_from_display) { using namespace testing; mtd::NullDisplayConfiguration conf; EXPECT_CALL(mock_display, configuration()) .Times(1) .WillOnce(Return(mt::fake_shared(conf))); auto returned_conf = changer->active_configuration(); EXPECT_EQ(&conf, returned_conf.get()); } TEST_F(MediatingDisplayChangerTest, pauses_system_when_applying_new_configuration_for_focused_session) { using namespace testing; mtd::NullDisplayConfiguration conf; auto session = std::make_shared(); InSequence s; EXPECT_CALL(mock_compositor, stop()); EXPECT_CALL(mock_display, configure(Ref(conf))); EXPECT_CALL(mock_compositor, start()); session_event_sink.handle_focus_change(session); changer->configure(session, mt::fake_shared(conf)); } TEST_F(MediatingDisplayChangerTest, doesnt_apply_config_for_unfocused_session) { using namespace testing; mtd::NullDisplayConfiguration conf; EXPECT_CALL(mock_compositor, stop()).Times(0); EXPECT_CALL(mock_display, configure(Ref(conf))).Times(0); EXPECT_CALL(mock_compositor, start()).Times(0); changer->configure(std::make_shared(), mt::fake_shared(conf)); } TEST_F(MediatingDisplayChangerTest, handles_hardware_change_properly_when_pausing_system) { using namespace testing; mtd::NullDisplayConfiguration conf; InSequence s; EXPECT_CALL(mock_conf_policy, apply_to(Ref(conf))); EXPECT_CALL(mock_compositor, stop()); EXPECT_CALL(mock_display, configure(Ref(conf))); EXPECT_CALL(mock_compositor, start()); changer->configure_for_hardware_change(mt::fake_shared(conf), mir::DisplayChanger::PauseResumeSystem); } TEST_F(MediatingDisplayChangerTest, handles_hardware_change_properly_when_retaining_system_state) { using namespace testing; mtd::NullDisplayConfiguration conf; EXPECT_CALL(mock_compositor, stop()).Times(0); EXPECT_CALL(mock_compositor, start()).Times(0); InSequence s; EXPECT_CALL(mock_conf_policy, apply_to(Ref(conf))); EXPECT_CALL(mock_display, configure(Ref(conf))); changer->configure_for_hardware_change(mt::fake_shared(conf), mir::DisplayChanger::RetainSystemState); } TEST_F(MediatingDisplayChangerTest, hardware_change_doesnt_apply_base_config_if_per_session_config_is_active) { using namespace testing; auto conf = std::make_shared(); auto session1 = std::make_shared(); stub_session_container.insert_session(session1); changer->configure(session1, conf); session_event_sink.handle_focus_change(session1); Mock::VerifyAndClearExpectations(&mock_compositor); Mock::VerifyAndClearExpectations(&mock_display); InSequence s; EXPECT_CALL(mock_compositor, stop()).Times(0); EXPECT_CALL(mock_display, configure(_)).Times(0); EXPECT_CALL(mock_compositor, start()).Times(0); changer->configure_for_hardware_change(conf, mir::DisplayChanger::PauseResumeSystem); } TEST_F(MediatingDisplayChangerTest, notifies_all_sessions_on_hardware_config_change) { using namespace testing; mtd::NullDisplayConfiguration conf; mtd::MockShellSession mock_session1; mtd::MockShellSession mock_session2; stub_session_container.insert_session(mt::fake_shared(mock_session1)); stub_session_container.insert_session(mt::fake_shared(mock_session2)); EXPECT_CALL(mock_session1, send_display_config(_)); EXPECT_CALL(mock_session2, send_display_config(_)); changer->configure_for_hardware_change(mt::fake_shared(conf), mir::DisplayChanger::PauseResumeSystem); } TEST_F(MediatingDisplayChangerTest, focusing_a_session_with_attached_config_applies_config) { using namespace testing; auto conf = std::make_shared(); auto session1 = std::make_shared(); stub_session_container.insert_session(session1); changer->configure(session1, conf); InSequence s; EXPECT_CALL(mock_compositor, stop()); EXPECT_CALL(mock_display, configure(Ref(*conf))); EXPECT_CALL(mock_compositor, start()); session_event_sink.handle_focus_change(session1); } TEST_F(MediatingDisplayChangerTest, focusing_a_session_without_attached_config_applies_base_config) { using namespace testing; auto conf = std::make_shared(); auto session1 = std::make_shared(); auto session2 = std::make_shared(); stub_session_container.insert_session(session1); changer->configure(session1, conf); session_event_sink.handle_focus_change(session1); Mock::VerifyAndClearExpectations(&mock_compositor); Mock::VerifyAndClearExpectations(&mock_display); InSequence s; EXPECT_CALL(mock_compositor, stop()); EXPECT_CALL(mock_display, configure(mt::DisplayConfigMatches(std::cref(base_config)))); EXPECT_CALL(mock_compositor, start()); session_event_sink.handle_focus_change(session2); } TEST_F(MediatingDisplayChangerTest, losing_focus_applies_base_config) { using namespace testing; auto conf = std::make_shared(); auto session1 = std::make_shared(); stub_session_container.insert_session(session1); changer->configure(session1, conf); session_event_sink.handle_focus_change(session1); Mock::VerifyAndClearExpectations(&mock_compositor); Mock::VerifyAndClearExpectations(&mock_display); InSequence s; EXPECT_CALL(mock_compositor, stop()); EXPECT_CALL(mock_display, configure(mt::DisplayConfigMatches(std::cref(base_config)))); EXPECT_CALL(mock_compositor, start()); session_event_sink.handle_no_focus(); } TEST_F(MediatingDisplayChangerTest, base_config_is_not_applied_if_already_active) { using namespace testing; auto conf = std::make_shared(); auto session1 = std::make_shared(); auto session2 = std::make_shared(); EXPECT_CALL(mock_compositor, stop()).Times(0); EXPECT_CALL(mock_display, configure(_)).Times(0); EXPECT_CALL(mock_compositor, start()).Times(0); stub_session_container.insert_session(session1); stub_session_container.insert_session(session2); session_event_sink.handle_focus_change(session1); session_event_sink.handle_focus_change(session2); session_event_sink.handle_no_focus(); } TEST_F(MediatingDisplayChangerTest, hardware_change_invalidates_session_configs) { using namespace testing; auto conf = std::make_shared(); auto session1 = std::make_shared(); stub_session_container.insert_session(session1); changer->configure(session1, conf); changer->configure_for_hardware_change(conf, mir::DisplayChanger::PauseResumeSystem); Mock::VerifyAndClearExpectations(&mock_compositor); Mock::VerifyAndClearExpectations(&mock_display); /* * Session1 had a config, but it should have been invalidated by the hardware * change, so expect no reconfiguration. */ EXPECT_CALL(mock_compositor, stop()).Times(0); EXPECT_CALL(mock_display, configure(_)).Times(0); EXPECT_CALL(mock_compositor, start()).Times(0); session_event_sink.handle_focus_change(session1); } TEST_F(MediatingDisplayChangerTest, session_stopping_invalidates_session_config) { using namespace testing; auto conf = std::make_shared(); auto session1 = std::make_shared(); stub_session_container.insert_session(session1); changer->configure(session1, conf); session_event_sink.handle_session_stopping(session1); Mock::VerifyAndClearExpectations(&mock_compositor); Mock::VerifyAndClearExpectations(&mock_display); /* * Session1 had a config, but it should have been invalidated by the * session stopping event, so expect no reconfiguration. */ EXPECT_CALL(mock_compositor, stop()).Times(0); EXPECT_CALL(mock_display, configure(_)).Times(0); EXPECT_CALL(mock_compositor, start()).Times(0); session_event_sink.handle_focus_change(session1); } mir-0.1.8+14.04.20140411/tests/unit-tests/shell/test_graphics_display_layout.cpp0000644000015301777760000001505312322054223027755 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/shell/graphics_display_layout.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/stub_display_configuration.h" #include "mir_test_doubles/stub_display_buffer.h" #include #include #include namespace msh = mir::shell; namespace mg = mir::graphics; namespace mtd = mir::test::doubles; namespace geom = mir::geometry; namespace { class StubDisplay : public mtd::NullDisplay { public: StubDisplay() : rects{{{0,0}, {800,600}}, {{0,600}, {100,100}}, {{800,0}, {100,100}}} { for (auto const& rect : rects) { display_buffers.push_back( std::make_shared(rect)); } } void for_each_display_buffer(std::function const& f) override { for (auto& db : display_buffers) f(*db); } std::unique_ptr configuration() const override { return std::unique_ptr( new mtd::StubDisplayConfig(rects) ); } private: std::vector const rects; std::vector> display_buffers; }; } TEST(GraphicsDisplayLayoutTest, clips_correctly) { auto stub_display = std::make_shared(); msh::GraphicsDisplayLayout display_layout{stub_display}; std::vector> rect_tuples{ std::make_tuple( geom::Rectangle{geom::Point{0,0}, geom::Size{800,600}}, geom::Rectangle{geom::Point{0,0}, geom::Size{800,600}}), std::make_tuple( geom::Rectangle{geom::Point{750,50}, geom::Size{100,100}}, geom::Rectangle{geom::Point{750,50}, geom::Size{50,100}}), std::make_tuple( geom::Rectangle{geom::Point{899,99}, geom::Size{100,100}}, geom::Rectangle{geom::Point{899,99}, geom::Size{1,1}}), std::make_tuple( geom::Rectangle{geom::Point{-1,-1}, geom::Size{100,100}}, geom::Rectangle{geom::Point{-1,-1}, geom::Size{0,0}}) }; for (auto const& t : rect_tuples) { auto clipped_rect = std::get<0>(t); auto const expected_rect = std::get<1>(t); display_layout.clip_to_output(clipped_rect); EXPECT_EQ(expected_rect, clipped_rect); } } TEST(GraphicsDisplayLayoutTest, makes_fullscreen_in_correct_screen) { auto stub_display = std::make_shared(); msh::GraphicsDisplayLayout display_layout{stub_display}; std::vector> rect_tuples{ std::make_tuple( geom::Rectangle{geom::Point{0,0}, geom::Size{800,600}}, geom::Rectangle{geom::Point{0,0}, geom::Size{800,600}}), std::make_tuple( geom::Rectangle{geom::Point{750,50}, geom::Size{150,130}}, geom::Rectangle{geom::Point{0,0}, geom::Size{800,600}}), std::make_tuple( geom::Rectangle{geom::Point{899,99}, geom::Size{30,40}}, geom::Rectangle{geom::Point{800,0}, geom::Size{100,100}}), std::make_tuple( geom::Rectangle{geom::Point{-1,-1}, geom::Size{100,100}}, geom::Rectangle{geom::Point{0,0}, geom::Size{0,0}}) }; for (auto const& t : rect_tuples) { auto fullscreen_rect = std::get<0>(t); auto const expected_rect = std::get<1>(t); display_layout.size_to_output(fullscreen_rect); EXPECT_EQ(expected_rect, fullscreen_rect); } } TEST(GraphicsDisplayLayoutTest, place_in_output_places_in_correct_output) { auto stub_display = std::make_shared(); msh::GraphicsDisplayLayout display_layout{stub_display}; std::vector> rect_tuples { std::make_tuple( mg::DisplayConfigurationOutputId{1}, geom::Rectangle{{0,0}, {800,600}}, geom::Rectangle{{0,0}, {800,600}}), std::make_tuple( mg::DisplayConfigurationOutputId{1}, geom::Rectangle{{750,50}, {800,600}}, geom::Rectangle{{0,0}, {800,600}}), std::make_tuple( mg::DisplayConfigurationOutputId{2}, geom::Rectangle{{899,99}, {100,100}}, geom::Rectangle{{0,600}, {100,100}}), std::make_tuple( mg::DisplayConfigurationOutputId{3}, geom::Rectangle{{-1,-1}, {100,100}}, geom::Rectangle{{800,0}, {100,100}}) }; for (auto const& t : rect_tuples) { auto const output_id = std::get<0>(t); auto submitted_rect = std::get<1>(t); auto const expected_rect = std::get<2>(t); display_layout.place_in_output(output_id, submitted_rect); EXPECT_EQ(expected_rect, submitted_rect); } } TEST(GraphicsDisplayLayoutTest, place_in_output_throws_on_non_fullscreen_request) { auto stub_display = std::make_shared(); msh::GraphicsDisplayLayout display_layout{stub_display}; std::vector> rect_tuples { std::make_tuple( mg::DisplayConfigurationOutputId{1}, geom::Rectangle{{0,0}, {801,600}}), std::make_tuple( mg::DisplayConfigurationOutputId{1}, geom::Rectangle{{750,50}, {800,599}}), std::make_tuple( mg::DisplayConfigurationOutputId{2}, geom::Rectangle{{899,99}, {1,1}}), std::make_tuple( mg::DisplayConfigurationOutputId{3}, geom::Rectangle{{-1,-1}, {0,0}}), }; for (auto const& t : rect_tuples) { auto const output_id = std::get<0>(t); auto submitted_rect = std::get<1>(t); EXPECT_THROW({ display_layout.place_in_output(output_id, submitted_rect); }, std::runtime_error); } } mir-0.1.8+14.04.20140411/tests/unit-tests/shell/CMakeLists.txt0000644000015301777760000000044612322054223024030 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_consuming_placement_strategy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_organising_surface_factory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_graphics_display_layout.cpp ) set( UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/shell/test_organising_surface_factory.cpp0000644000015301777760000000712412322054247030440 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/shell/organising_surface_factory.h" #include "mir/shell/placement_strategy.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/shell/session.h" #include "mir/scene/surface.h" #include "mir/scene/surface_event_source.h" #include "mir/scene/surface_coordinator.h" #include "mir_test_doubles/stub_shell_session.h" #include "mir_test_doubles/null_event_sink.h" #include #include namespace mf = mir::frontend; namespace ms = mir::scene; namespace msh = mir::shell; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; namespace { struct MockSurfaceCoordinator : public ms::SurfaceCoordinator { MOCK_METHOD2(add_surface, std::shared_ptr( msh::SurfaceCreationParameters const&, std::shared_ptr const&)); void remove_surface(std::weak_ptr const& /*surface*/) override {} void raise(std::weak_ptr const& /*surface*/) override {} }; struct MockPlacementStrategy : public msh::PlacementStrategy { MOCK_METHOD2(place, msh::SurfaceCreationParameters(msh::Session const&, msh::SurfaceCreationParameters const&)); }; struct OrganisingSurfaceFactorySetup : public testing::Test { void SetUp() { using namespace ::testing; ON_CALL(*surface_coordinator, add_surface(_, _)).WillByDefault(Return(null_surface)); } std::shared_ptr null_surface; std::shared_ptr surface_coordinator = std::make_shared(); std::shared_ptr const observer = std::make_shared(mf::SurfaceId(), std::make_shared()); std::shared_ptr placement_strategy = std::make_shared(); }; } // namespace TEST_F(OrganisingSurfaceFactorySetup, offers_create_surface_parameters_to_placement_strategy) { using namespace ::testing; msh::OrganisingSurfaceFactory factory(surface_coordinator, placement_strategy); mtd::StubShellSession session; EXPECT_CALL(*surface_coordinator, add_surface(_, _)).Times(1); auto params = msh::a_surface(); EXPECT_CALL(*placement_strategy, place(Ref(session), Ref(params))).Times(1) .WillOnce(Return(msh::a_surface())); factory.create_surface(&session, params, observer); } TEST_F(OrganisingSurfaceFactorySetup, forwards_create_surface_parameters_from_placement_strategy_to_underlying_factory) { using namespace ::testing; msh::OrganisingSurfaceFactory factory(surface_coordinator, placement_strategy); auto params = msh::a_surface(); auto placed_params = params; placed_params.size.width = geom::Width{100}; EXPECT_CALL(*placement_strategy, place(_, Ref(params))).Times(1) .WillOnce(Return(placed_params)); EXPECT_CALL(*surface_coordinator, add_surface(placed_params, _)); factory.create_surface(nullptr, params, observer); } mir-0.1.8+14.04.20140411/tests/unit-tests/shared_library_test.cpp0000644000015301777760000000656712322054223024730 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/shared_library.h" #include #include #include namespace { class HasSubstring { public: HasSubstring(char const* substring) : substring(substring) {} friend::testing::AssertionResult operator,(std::string const& target, HasSubstring const& match) { if (std::string::npos != target.find(match.substring)) return ::testing::AssertionSuccess(); else return ::testing::AssertionFailure() << "The target:\n\"" << target << "\"\n" "Does not contain:\n\"" << match.substring << "\""; } private: char const* const substring; HasSubstring(HasSubstring const&) = delete; HasSubstring& operator=(HasSubstring const&) = delete; }; #define EXPECT_THAT(target, condition) EXPECT_TRUE((target, condition)) char const* const nonexistent_library = "nonexistent_library"; char const* const existing_library = "libmirplatformgraphics.so"; char const* const nonexistent_function = "nonexistent_library"; char const* const existing_function = "create_platform"; } TEST(SharedLibrary, load_nonexistent_library_fails) { EXPECT_THROW({ mir::SharedLibrary nonexistent(nonexistent_library); }, std::runtime_error); } TEST(SharedLibrary, load_nonexistent_library_fails_with_useful_info) { try { mir::SharedLibrary nonexistent(nonexistent_library); } catch (std::exception const& error) { auto info = boost::diagnostic_information(error); EXPECT_THAT(info, HasSubstring("cannot open shared object")) << "What went wrong"; EXPECT_THAT(info, HasSubstring(nonexistent_library)) << "Name of library"; } } TEST(SharedLibrary, load_valid_library_works) { mir::SharedLibrary existing(existing_library); } TEST(SharedLibrary, load_nonexistent_function_fails) { mir::SharedLibrary existing(existing_library); EXPECT_THROW({ existing.load_function(nonexistent_function); }, std::runtime_error); } TEST(SharedLibrary, load_nonexistent_function_fails_with_useful_info) { mir::SharedLibrary existing(existing_library); try { existing.load_function(nonexistent_function); } catch (std::exception const& error) { auto info = boost::diagnostic_information(error); EXPECT_THAT(info, HasSubstring("undefined symbol")) << "What went wrong"; EXPECT_THAT(info, HasSubstring(existing_library)) << "Name of library"; EXPECT_THAT(info, HasSubstring(nonexistent_function)) << "Name of function"; } } TEST(SharedLibrary, load_valid_function_works) { mir::SharedLibrary existing(existing_library); existing.load_function(existing_function); } mir-0.1.8+14.04.20140411/tests/unit-tests/test_gmock_fixes.cpp0000644000015301777760000000223312322054223024216 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test/gmock_fixes.h" #include #include TEST(GMock, return_by_move) { struct Interface { virtual ~Interface() = default; virtual std::unique_ptr function() const = 0; }; struct MockImplementation : Interface { MOCK_CONST_METHOD0(function, std::unique_ptr()); ~MockImplementation() noexcept {} }; MockImplementation mi; EXPECT_CALL(mi, function()); mi.function(); } mir-0.1.8+14.04.20140411/tests/unit-tests/draw/0000755000015301777760000000000012322054703021115 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/draw/test_draw_patterns.cpp0000644000015301777760000001024212322054223025531 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "testdraw/patterns.h" #include #include namespace mtd=mir::test::draw; class DrawPatternsTest : public ::testing::Test { protected: DrawPatternsTest() : stride_color(0x77) {} virtual void SetUp() { test_region.pixel_format = mir_pixel_format_abgr_8888; bytes_pp = 4; test_region.width = 100; /* misaligned stride to tease out stride problems */ test_region.stride = (test_region.width * bytes_pp) + 2; test_region.height = 50; auto region_size = sizeof(char) * bytes_pp * test_region.height * test_region.stride; region = std::shared_ptr(static_cast(::operator new(region_size))); test_region.vaddr = region.get(); uint32_t colors[2][2] = {{0x12345678, 0x23456789}, {0x34567890, 0x45678901}}; memcpy(pattern_colors, colors, sizeof(uint32_t)*4); write_stride_region(); } virtual void TearDown() { EXPECT_TRUE(check_stride_region_unaltered()); } MirGraphicsRegion test_region; uint32_t pattern_colors [2][2]; int bytes_pp; std::shared_ptr region; private: /* check that no pattern writes or checks the stride region */ void write_stride_region() { for(auto i = 0; i < test_region.height; i++) { for(auto j = test_region.width * bytes_pp; j < test_region.stride; j++) { test_region.vaddr[ (i * test_region.stride) + j ] = stride_color; } } } bool check_stride_region_unaltered() { for(auto i=0; i < test_region.height; i++) { for(auto j=test_region.width * bytes_pp; j < test_region.stride; j++) { if(test_region.vaddr[ ((i * test_region.stride) + j) ] != stride_color) { return false; } } } return true; } const char stride_color; }; TEST_F(DrawPatternsTest, solid_color_unaccelerated) { mtd::DrawPatternSolid pattern(0x43214321); pattern.draw(test_region); EXPECT_TRUE(pattern.check(test_region)); } TEST_F(DrawPatternsTest, solid_color_unaccelerated_error) { mtd::DrawPatternSolid pattern(0x43214321); pattern.draw(test_region); test_region.vaddr[0]++; EXPECT_FALSE(pattern.check(test_region)); } TEST_F(DrawPatternsTest, solid_bad_pixel_formats) { test_region.pixel_format = mir_pixel_format_xbgr_8888; mtd::DrawPatternSolid pattern(0x43214321); EXPECT_THROW({ pattern.draw(test_region); }, std::runtime_error); EXPECT_THROW({ pattern.check(test_region); }, std::runtime_error); } TEST_F(DrawPatternsTest, checkered_pattern) { mtd::DrawPatternCheckered<2,2> pattern(pattern_colors); pattern.draw(test_region); EXPECT_TRUE(pattern.check(test_region)); } TEST_F(DrawPatternsTest, checkered_pattern_error) { mtd::DrawPatternCheckered<2,2> pattern(pattern_colors); pattern.draw(test_region); test_region.vaddr[0]++; EXPECT_FALSE(pattern.check(test_region)); } TEST_F(DrawPatternsTest, checkered_bad_pixel_formats) { test_region.pixel_format = mir_pixel_format_xbgr_8888; mtd::DrawPatternCheckered<2,2> pattern(pattern_colors); EXPECT_THROW({ pattern.draw(test_region); }, std::runtime_error); EXPECT_THROW({ pattern.check(test_region); }, std::runtime_error); } mir-0.1.8+14.04.20140411/tests/unit-tests/draw/CMakeLists.txt0000644000015301777760000000021712322054223023652 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_draw_patterns.cpp ) set(UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/input/0000755000015301777760000000000012322054703021317 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/0000755000015301777760000000000012322054703022737 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/test_android_input_target_enumerator.cpp0000644000015301777760000000662412322054223033155 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/input/android/android_input_target_enumerator.h" #include "mir/input/input_channel.h" #include "mir/input/input_targets.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/stub_input_channel.h" #include "mir_test_doubles/stub_input_handles.h" #include "mir_test_doubles/mock_window_handle_repository.h" #include #include #include #include #include #include namespace mi = mir::input; namespace mia = mir::input::android; namespace mt = mir::test; namespace mtd = mir::test::doubles; namespace { struct StubInputTargets : public mi::InputTargets { StubInputTargets(std::initializer_list> const& target_list) : targets(target_list.begin(), target_list.end()) { } void for_each(std::function const&)> const& callback) override { for (auto target : targets) callback(target); } std::vector> targets; }; } TEST(AndroidInputTargetEnumerator, enumerates_registered_handles_for_surfaces) { using namespace ::testing; std::shared_ptr t1, t2; t1 = std::make_shared(); t2 = std::make_shared(); mtd::MockWindowHandleRepository repository; droidinput::sp stub_window_handle1 = new mtd::StubWindowHandle; droidinput::sp stub_window_handle2 = new mtd::StubWindowHandle; StubInputTargets targets({t1, t2}); Sequence seq2; EXPECT_CALL(repository, handle_for_channel( std::const_pointer_cast(t1))) .InSequence(seq2) .WillOnce(Return(stub_window_handle1)); EXPECT_CALL(repository, handle_for_channel( std::const_pointer_cast(t2))) .InSequence(seq2) .WillOnce(Return(stub_window_handle2)); struct MockTargetObserver { MOCK_METHOD1(see, void(droidinput::sp const&)); } observer; Sequence seq; EXPECT_CALL(observer, see(stub_window_handle1)) .InSequence(seq); EXPECT_CALL(observer, see(stub_window_handle2)) .InSequence(seq); // The InputTargetEnumerator only holds a weak reference to the targets so we need to hold a shared pointer. auto shared_targets = mt::fake_shared(targets); auto shared_handles = mt::fake_shared(repository); mia::InputTargetEnumerator enumerator(shared_targets, shared_handles); enumerator.for_each([&](droidinput::sp const& handle) { observer.see(handle); }); } ././@LongLink0000000000000000000000000000014600000000000011216 Lustar 00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/test_event_filter_input_dispatcher_policy.cppmir-0.1.8+14.04.20140411/tests/unit-tests/input/android/test_event_filter_input_dispatcher_policy.cp0000644000015301777760000000444412322054223034017 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/input/event_filter.h" #include "src/server/input/android/event_filter_dispatcher_policy.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_event_filter.h" #include #include #include namespace mi = mir::input; namespace mia = mi::android; namespace mt = mir::test; namespace mtd = mir::test::doubles; TEST(EventFilterDispatcherPolicy, offers_key_events_to_filter) { using namespace ::testing; droidinput::KeyEvent ev; mtd::MockEventFilter filter; mia::EventFilterDispatcherPolicy policy(mt::fake_shared(filter), true); uint32_t policy_flags; EXPECT_CALL(filter, handle(_)).Times(1).WillOnce(Return(false)); // The policy filters ALL key events before queuing policy.interceptKeyBeforeQueueing(&ev, policy_flags); // If the event is unfiltered we will allow it to pass to applications EXPECT_TRUE(policy_flags & droidinput::POLICY_FLAG_PASS_TO_USER); // Android uses alternate notation...the policy returns true if the event was NOT handled (e.g. the EventFilter // returns false) EXPECT_TRUE(policy.filterInputEvent(&ev, 0)); } TEST(EventFilterDispatcherPolicy, motion_events_are_allowed_to_pass_to_clients) { using namespace ::testing; mtd::MockEventFilter filter; mia::EventFilterDispatcherPolicy policy(mt::fake_shared(filter), true); uint32_t policy_flags; policy.interceptMotionBeforeQueueing(0, policy_flags); // All motion events are allowed. Of course they could later be removed by the input filter. EXPECT_TRUE(policy_flags & droidinput::POLICY_FLAG_PASS_TO_USER); } mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/test_android_input_manager.cpp0000644000015301777760000001334012322054223031031 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/input/android/android_input_manager.h" #include "src/server/input/android/android_input_thread.h" #include "src/server/input/android/android_input_constants.h" #include "src/server/input/android/android_input_channel.h" #include "mir/input/input_channel.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_input_dispatcher.h" #include "mir_test_doubles/stub_input_channel.h" #include #include #include #include #include namespace droidinput = android; namespace mi = mir::input; namespace mia = mir::input::android; namespace mt = mir::test; namespace mtd = mt::doubles; // Mock objects namespace { struct MockEventHub : public droidinput::EventHubInterface { MOCK_CONST_METHOD1(getDeviceClasses, uint32_t(int32_t)); MOCK_CONST_METHOD1(getDeviceIdentifier, droidinput::InputDeviceIdentifier(int32_t)); MOCK_CONST_METHOD2(getConfiguration, void(int32_t, droidinput::PropertyMap*)); MOCK_CONST_METHOD3(getAbsoluteAxisInfo, droidinput::status_t(int32_t, int, droidinput::RawAbsoluteAxisInfo*)); MOCK_CONST_METHOD2(hasRelativeAxis, bool(int32_t, int)); MOCK_CONST_METHOD2(hasInputProperty, bool(int32_t, int)); MOCK_CONST_METHOD5(mapKey, droidinput::status_t(int32_t, int32_t, int32_t, int32_t*, uint32_t*)); MOCK_CONST_METHOD3(mapAxis, droidinput::status_t(int32_t, int32_t, droidinput::AxisInfo*)); MOCK_METHOD1(setExcludedDevices, void(droidinput::Vector const&)); MOCK_METHOD3(getEvents, size_t(int, droidinput::RawEvent*, size_t)); MOCK_CONST_METHOD2(getScanCodeState, int32_t(int32_t, int32_t)); MOCK_CONST_METHOD2(getKeyCodeState, int32_t(int32_t, int32_t)); MOCK_CONST_METHOD2(getSwitchState, int32_t(int32_t, int32_t)); MOCK_CONST_METHOD3(getAbsoluteAxisValue, droidinput::status_t(int32_t, int32_t, int32_t*)); MOCK_CONST_METHOD4(markSupportedKeyCodes, bool(int32_t, size_t, int32_t const*, uint8_t*)); MOCK_CONST_METHOD2(hasScanCode, bool(int32_t, int32_t)); MOCK_CONST_METHOD2(hasLed, bool(int32_t, int32_t)); MOCK_METHOD3(setLedState, void(int32_t, int32_t, bool)); MOCK_CONST_METHOD2(getVirtualKeyDefinitions, void(int32_t, droidinput::Vector&)); MOCK_CONST_METHOD1(getKeyCharacterMap, droidinput::sp(int32_t)); MOCK_METHOD2(setKeyboardLayoutOverlay, bool(int32_t, const droidinput::sp&)); MOCK_METHOD2(vibrate, void(int32_t, nsecs_t)); MOCK_METHOD1(cancelVibrate, void(int32_t)); MOCK_METHOD0(requestReopenDevices, void()); MOCK_METHOD0(wake, void()); MOCK_METHOD1(dump, void(droidinput::String8&)); MOCK_METHOD0(monitor, void()); MOCK_METHOD0(flush, void()); }; struct MockInputThread : public mia::InputThread { MOCK_METHOD0(start, void()); MOCK_METHOD0(request_stop, void()); MOCK_METHOD0(join, void()); }; } // Test fixture namespace { struct AndroidInputManagerSetup : public testing::Test { AndroidInputManagerSetup() { using namespace ::testing; event_hub = new MockEventHub(); dispatcher = new mtd::MockInputDispatcher(); dispatcher_thread = std::make_shared(); reader_thread = std::make_shared(); } droidinput::sp event_hub; droidinput::sp dispatcher; std::shared_ptr dispatcher_thread; std::shared_ptr reader_thread; }; } TEST_F(AndroidInputManagerSetup, start_and_stop) { using namespace ::testing; ExpectationSet dispatcher_setup; ExpectationSet reader_setup; dispatcher_setup += EXPECT_CALL(*dispatcher, setInputDispatchMode(mia::DispatchEnabled, mia::DispatchUnfrozen)) .Times(1); dispatcher_setup += EXPECT_CALL(*dispatcher, setInputFilterEnabled(true)).Times(1); reader_setup += EXPECT_CALL(*event_hub, flush()).Times(1); EXPECT_CALL(*reader_thread, start()) .Times(1) .After(reader_setup); EXPECT_CALL(*dispatcher_thread, start()) .Times(1) .After(dispatcher_setup); { InSequence seq; EXPECT_CALL(*dispatcher_thread, request_stop()); EXPECT_CALL(*dispatcher, setInputDispatchMode(mia::DispatchDisabled, mia::DispatchFrozen)).Times(1); EXPECT_CALL(*dispatcher_thread, join()); EXPECT_CALL(*reader_thread, request_stop()); EXPECT_CALL(*event_hub, wake()); EXPECT_CALL(*reader_thread, join()); } mia::InputManager manager(event_hub, dispatcher, reader_thread, dispatcher_thread); manager.start(); manager.stop(); } TEST_F(AndroidInputManagerSetup, manager_returns_input_channel_with_fds) { mia::InputManager manager(event_hub, dispatcher, reader_thread, dispatcher_thread); auto package = manager.make_input_channel(); EXPECT_NE(nullptr, std::dynamic_pointer_cast(package)); } mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/test_android_input_lexicon.cpp0000644000015301777760000002621512322054223031065 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/input/android/android_input_lexicon.h" #include "mir_toolkit/event.h" #include #include #include namespace mi = mir::input; namespace mia = mir::input::android; TEST(AndroidInputLexicon, translates_key_events) { using namespace ::testing; auto android_key_ev = new android::KeyEvent(); const int32_t device_id = 1; const int32_t source_id = 2; const int32_t action = 3; const int32_t flags = 4; const int32_t key_code = 5; const int32_t scan_code = 6; const int32_t meta_state = 7; const int32_t repeat_count = 8; const nsecs_t down_time = 9; const nsecs_t event_time = 10; android_key_ev->initialize(device_id, source_id, action, flags, key_code, scan_code, meta_state, repeat_count, down_time, event_time); MirEvent mir_ev; mia::Lexicon::translate(android_key_ev, mir_ev); // Common event properties EXPECT_EQ(device_id, mir_ev.key.device_id); EXPECT_EQ(source_id, mir_ev.key.source_id); EXPECT_EQ(action, mir_ev.key.action); EXPECT_EQ(flags, mir_ev.key.flags); EXPECT_EQ((unsigned int)meta_state, mir_ev.key.modifiers); auto mir_key_ev = &mir_ev.key; // Key event specific properties EXPECT_EQ(mir_ev.type, mir_event_type_key); EXPECT_EQ(mir_key_ev->key_code, key_code); EXPECT_EQ(mir_key_ev->scan_code, scan_code); EXPECT_EQ(mir_key_ev->repeat_count, repeat_count); EXPECT_EQ(mir_key_ev->down_time, down_time); EXPECT_EQ(mir_key_ev->event_time, event_time); // What is this flag and where does it come from? EXPECT_EQ(mir_key_ev->is_system_key, false); delete android_key_ev; } TEST(AndroidInputLexicon, translates_single_pointer_motion_events) { using namespace ::testing; auto android_motion_ev = new android::MotionEvent; // Common event properties const int32_t device_id = 1; const int32_t source_id = 2; const int32_t action = 3; const int32_t flags = 4; const int32_t edge_flags = 5; const int32_t meta_state = 6; const int32_t button_state = 7; const float x_offset = 8; const float y_offset = 9; const float x_precision = 10; const float y_precision = 11; const nsecs_t down_time = 12; const nsecs_t event_time = 13; const size_t pointer_count = 1; // Pointer specific properties (i.e. per touch) const int pointer_id = 1; droidinput::PointerProperties pointer_properties; pointer_properties.id = pointer_id; droidinput::PointerCoords pointer_coords; pointer_coords.clear(); const float x_axis = 100.0; const float y_axis = 200.0; const float touch_minor = 300.0; const float touch_major = 400.0; const float size = 500.0; const float pressure = 600.0; const float orientation = 700.0; const float vscroll = 800.0; const float hscroll = 900.0; const MirMotionToolType tool_type = mir_motion_tool_type_mouse; pointer_coords.setAxisValue(AMOTION_EVENT_AXIS_X, x_axis); pointer_coords.setAxisValue(AMOTION_EVENT_AXIS_Y, y_axis); pointer_coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touch_major); pointer_coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touch_minor); pointer_coords.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); pointer_coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); pointer_coords.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); pointer_coords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointer_coords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); pointer_properties.toolType = tool_type; android_motion_ev->initialize(device_id, source_id, action, flags, edge_flags, meta_state, button_state, x_offset, y_offset, x_precision, y_precision, down_time, event_time, pointer_count, &pointer_properties, &pointer_coords); MirEvent mir_ev; mia::Lexicon::translate(android_motion_ev, mir_ev); // Common event properties EXPECT_EQ(device_id, mir_ev.motion.device_id); EXPECT_EQ(source_id, mir_ev.motion.source_id); EXPECT_EQ(action, mir_ev.motion.action); EXPECT_EQ(flags, mir_ev.motion.flags); EXPECT_EQ((unsigned int)meta_state, mir_ev.motion.modifiers); // Motion event specific properties EXPECT_EQ(mir_ev.type, mir_event_type_motion); auto mir_motion_ev = &mir_ev.motion; EXPECT_EQ(mir_motion_ev->edge_flags, edge_flags); EXPECT_EQ(mir_motion_ev->button_state, button_state); EXPECT_EQ(mir_motion_ev->x_offset, x_offset); EXPECT_EQ(mir_motion_ev->y_offset, y_offset); EXPECT_EQ(mir_motion_ev->x_precision, x_precision); EXPECT_EQ(mir_motion_ev->y_precision, y_precision); EXPECT_EQ(mir_motion_ev->down_time, down_time); EXPECT_EQ(mir_motion_ev->event_time, event_time); EXPECT_EQ(mir_motion_ev->pointer_count, pointer_count); auto mir_pointer_coords = &mir_motion_ev->pointer_coordinates[0]; EXPECT_EQ(mir_pointer_coords->id, pointer_id); // Notice these two coordinates are offset by x/y offset EXPECT_EQ(mir_pointer_coords->x, x_axis + x_offset); EXPECT_EQ(mir_pointer_coords->y, y_axis + y_offset); EXPECT_EQ(mir_pointer_coords->raw_x, x_axis); EXPECT_EQ(mir_pointer_coords->raw_y, y_axis); EXPECT_EQ(mir_pointer_coords->touch_major, touch_major); EXPECT_EQ(mir_pointer_coords->touch_minor, touch_minor); EXPECT_EQ(mir_pointer_coords->size, size); EXPECT_EQ(mir_pointer_coords->pressure, pressure); EXPECT_EQ(mir_pointer_coords->orientation, orientation); EXPECT_EQ(mir_pointer_coords->vscroll, vscroll); EXPECT_EQ(mir_pointer_coords->hscroll, hscroll); EXPECT_EQ(mir_pointer_coords->tool_type, tool_type); delete android_motion_ev; } TEST(AndroidInputLexicon, translates_multi_pointer_motion_events) { using namespace ::testing; auto android_motion_ev = new android::MotionEvent; // Common event properties const int32_t device_id = 1; const int32_t source_id = 2; const int32_t action = 3 | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); const int32_t flags = 4; const int32_t edge_flags = 5; const int32_t meta_state = 6; const int32_t button_state = 7; const float x_offset = 8; const float y_offset = 9; const float x_precision = 10; const float y_precision = 11; const nsecs_t down_time = 12; const nsecs_t event_time = 13; const size_t pointer_count = 2; const int pointer_id[2] = {1, 2}; droidinput::PointerProperties pointer_properties[2]; droidinput::PointerCoords pointer_coords[2]; pointer_coords[0].clear(); pointer_coords[1].clear(); const float x_axis[2] = {100.0, 1000.0}; const float y_axis[2] = {200.0, 2000.0}; const float touch_minor[2] = {300.0, 3000.0}; const float touch_major[2] = {400.0, 4000.0}; const float size[2] = {500.0, 5000.0}; const float pressure[2] = {600.0, 6000.0}; const float orientation[2] = {700.0, 7000.0}; const float vscroll[2] = {800.0, 8000.0}; const float hscroll[2] = {900.0, 9000.0}; const MirMotionToolType tool_types[2] = {mir_motion_tool_type_mouse, mir_motion_tool_type_finger}; for (size_t p = 0; p < pointer_count; p++) { pointer_properties[p].id = pointer_id[p]; pointer_coords[p].setAxisValue(AMOTION_EVENT_AXIS_X, x_axis[p]); pointer_coords[p].setAxisValue(AMOTION_EVENT_AXIS_Y, y_axis[p]); pointer_coords[p].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touch_major[p]); pointer_coords[p].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touch_minor[p]); pointer_coords[p].setAxisValue(AMOTION_EVENT_AXIS_SIZE, size[p]); pointer_coords[p].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure[p]); pointer_coords[p].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation[p]); pointer_coords[p].setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll[p]); pointer_coords[p].setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll[p]); pointer_properties[p].toolType = tool_types[p]; } android_motion_ev->initialize(device_id, source_id, action, flags, edge_flags, meta_state, button_state, x_offset, y_offset, x_precision, y_precision, down_time, event_time, pointer_count, pointer_properties, pointer_coords); MirEvent mir_ev; mia::Lexicon::translate(android_motion_ev, mir_ev); // Common event properties EXPECT_EQ(device_id, mir_ev.motion.device_id); EXPECT_EQ(source_id, mir_ev.motion.source_id); EXPECT_EQ(action, mir_ev.motion.action); EXPECT_EQ(flags, mir_ev.motion.flags); EXPECT_EQ((unsigned int)meta_state, mir_ev.motion.modifiers); // Motion event specific properties EXPECT_EQ(mir_ev.type, mir_event_type_motion); auto mir_motion_ev = &mir_ev.motion; EXPECT_EQ(mir_motion_ev->edge_flags, edge_flags); EXPECT_EQ(mir_motion_ev->button_state, button_state); EXPECT_EQ(mir_motion_ev->x_offset, x_offset); EXPECT_EQ(mir_motion_ev->y_offset, y_offset); EXPECT_EQ(mir_motion_ev->x_precision, x_precision); EXPECT_EQ(mir_motion_ev->y_precision, y_precision); EXPECT_EQ(mir_motion_ev->down_time, down_time); EXPECT_EQ(mir_motion_ev->event_time, event_time); EXPECT_EQ(mir_motion_ev->pointer_count, pointer_count); auto pointer = &mir_motion_ev->pointer_coordinates[0]; for (size_t p = 0; p < pointer_count; p++) { EXPECT_EQ(pointer[p].id, pointer_id[p]); EXPECT_EQ(pointer[p].x, x_axis[p] + x_offset); EXPECT_EQ(pointer[p].y, y_axis[p] + y_offset); EXPECT_EQ(pointer[p].raw_x, x_axis[p]); EXPECT_EQ(pointer[p].raw_y, y_axis[p]); EXPECT_EQ(pointer[p].touch_major, touch_major[p]); EXPECT_EQ(pointer[p].touch_minor, touch_minor[p]); EXPECT_EQ(pointer[p].size, size[p]); EXPECT_EQ(pointer[p].pressure, pressure[p]); EXPECT_EQ(pointer[p].orientation, orientation[p]); EXPECT_EQ(pointer[p].vscroll, vscroll[p]); EXPECT_EQ(pointer[p].hscroll, hscroll[p]); EXPECT_EQ(pointer[p].tool_type, tool_types[p]); } delete android_motion_ev; } mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/test_android_input_window_handle.cpp0000644000015301777760000000775412322054247032263 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/input/android/android_input_window_handle.h" #include "mir/frontend/surface.h" #include "mir/geometry/size.h" #include "mir/input/input_channel.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_input_surface.h" #include "mir/raii.h" #include #include #include #include namespace mi = mir::input; namespace mia = mi::android; namespace mf = mir::frontend; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mt::doubles; namespace { struct StubInputApplicationHandle : public droidinput::InputApplicationHandle { bool updateInfo() { return true; } }; struct MockInputChannel : public mi::InputChannel { MOCK_CONST_METHOD0(client_fd, int()); MOCK_CONST_METHOD0(server_fd, int()); }; } TEST(AndroidInputWindowHandle, update_info_uses_geometry_and_channel_from_surface) { using namespace ::testing; geom::Size const default_surface_size{256, 256}; geom::Point const default_surface_top_left = geom::Point{geom::X{10}, geom::Y{10}}; std::string const testing_surface_name = "Test"; int testing_server_fd; auto fd_wrapper = mir::raii::paired_calls([&testing_server_fd]() { // We need a real open fd, as InputWindowHandle's constructor will fcntl() it, and // InputWindowHandle's destructor will close() it. char *filename = strdup("/tmp/mir_unit_test_XXXXXX"); testing_server_fd = mkstemp(filename); // We don't actually need the file to exist after this test. unlink(filename); free(filename); }, [&testing_server_fd]() { if (testing_server_fd > 0) close(testing_server_fd); }); MockInputChannel mock_channel; mtd::MockInputSurface mock_surface; EXPECT_CALL(mock_channel, server_fd()) .Times(1) .WillOnce(Return(testing_server_fd)); // For now since we are just doing keyboard input we only need surface size, // for touch/pointer events we will need a position EXPECT_CALL(mock_surface, size()) .Times(1) .WillOnce(Return(default_surface_size)); EXPECT_CALL(mock_surface, top_left()) .Times(1) .WillOnce(Return(default_surface_top_left)); EXPECT_CALL(mock_surface, name()) .Times(1) .WillOnce(Return(testing_surface_name)); mia::InputWindowHandle handle(new StubInputApplicationHandle(), mt::fake_shared(mock_channel), mt::fake_shared(mock_surface)); auto info = handle.getInfo(); EXPECT_EQ(droidinput::String8(testing_surface_name.c_str()), info->name); EXPECT_EQ(testing_server_fd, info->inputChannel->getFd()); EXPECT_EQ(default_surface_top_left.x.as_uint32_t(), (uint32_t)(info->frameLeft)); EXPECT_EQ(default_surface_top_left.y.as_uint32_t(), (uint32_t)(info->frameTop)); EXPECT_EQ(default_surface_size.height.as_uint32_t(), (uint32_t)(info->frameRight - info->frameLeft)); EXPECT_EQ(default_surface_size.height.as_uint32_t(), (uint32_t)(info->frameBottom - info->frameTop)); EXPECT_EQ(info->frameLeft, info->touchableRegionLeft); EXPECT_EQ(info->frameTop, info->touchableRegionTop); EXPECT_EQ(info->frameRight, info->touchableRegionRight); EXPECT_EQ(info->frameBottom, info->touchableRegionBottom); } mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/CMakeLists.txt0000644000015301777760000000150012322054223025470 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_event_filter_input_dispatcher_policy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_pointer_controller.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_lexicon.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_reader_policy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_manager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_communication_package.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_application_handle.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_window_handle.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_targeter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_target_enumerator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_android_input_registrar.cpp ) set( UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/test_android_communication_package.cpp0000644000015301777760000000255212322054223032523 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/input/android/android_input_channel.h" #include #include #include #include namespace droidinput = android; namespace mia = mir::input::android; TEST(AndroidInputChannel, packages_own_valid_fds) { int server_fd, client_fd; { mia::AndroidInputChannel package; server_fd = package.server_fd(); client_fd = package.client_fd(); EXPECT_LE(0, server_fd); EXPECT_LE(0, client_fd); EXPECT_EQ(fcntl(server_fd, F_GETFD), 0); EXPECT_EQ(fcntl(client_fd, F_GETFD), 0); } EXPECT_LT(fcntl(server_fd, F_GETFD), 0); EXPECT_LT(fcntl(client_fd, F_GETFD), 0); } mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/test_android_input_reader_policy.cpp0000644000015301777760000000510712322054223032242 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_doubles/mock_input_region.h" #include "mir_test/fake_shared.h" #include "src/server/input/android/android_input_reader_policy.h" #include "mir/geometry/rectangle.h" #include #include namespace mi = mir::input; namespace mia = mi::android; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mir::test::doubles; static geom::Rectangle const default_view_area = geom::Rectangle{geom::Point(), geom::Size{1600, 1400}}; namespace { using namespace::testing; class AndroidInputReaderPolicySetup : public testing::Test { public: void SetUp() { reader_policy = std::make_shared( mt::fake_shared(input_region), std::shared_ptr()); ON_CALL(input_region, bounding_rectangle()).WillByDefault(Return(default_view_area)); } mtd::MockInputRegion input_region; std::shared_ptr reader_policy; }; } TEST_F(AndroidInputReaderPolicySetup, configuration_has_display_info_filled_from_view_area) { static int32_t const testing_display_id = 0; static bool const testing_display_is_external = false; EXPECT_CALL(input_region, bounding_rectangle()).Times(1); droidinput::InputReaderConfiguration configuration; reader_policy->getReaderConfiguration(&configuration); int32_t configured_height, configured_width, configured_orientation; bool configuration_has_display_info = configuration.getDisplayInfo( testing_display_id, testing_display_is_external, &configured_width, &configured_height, &configured_orientation); ASSERT_TRUE(configuration_has_display_info); EXPECT_EQ(default_view_area.size.width.as_uint32_t(), (uint32_t)configured_width); EXPECT_EQ(default_view_area.size.height.as_uint32_t(), (uint32_t)configured_height); } mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/test_android_pointer_controller.cpp0000644000015301777760000000736312322054223032133 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/input/android/android_pointer_controller.h" #include "mir_test_doubles/mock_input_region.h" #include "mir_test/event_factory.h" #include "mir_test/fake_shared.h" #include #include #include namespace mi = mir::input; namespace mia = mi::android; namespace mis = mi::synthesis; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mir::test::doubles; static const geom::Rectangle default_view_area = geom::Rectangle{geom::Point(), geom::Size{1600, 1400}}; namespace { class AndroidPointerControllerSetup : public testing::Test { public: void SetUp() { controller = std::make_shared(mt::fake_shared(input_region)); } protected: mtd::MockInputRegion input_region; std::shared_ptr controller; }; } TEST_F(AndroidPointerControllerSetup, button_state_is_saved) { using namespace ::testing; controller->setButtonState(AKEY_STATE_DOWN); EXPECT_EQ(controller->getButtonState(), AKEY_STATE_DOWN); } TEST_F(AndroidPointerControllerSetup, position_is_saved) { using namespace ::testing; static const float stored_x = 100; static const float stored_y = 200; geom::Point stored{stored_x, stored_y}; EXPECT_CALL(input_region, confine(stored)); controller->setPosition(stored_x, stored_y); float saved_x, saved_y; controller->getPosition(&saved_x, &saved_y); EXPECT_EQ(stored_x, saved_x); EXPECT_EQ(stored_y, saved_y); } TEST_F(AndroidPointerControllerSetup, move_updates_position) { using namespace ::testing; static const float start_x = 100; static const float start_y = 100; static const float dx = 100; static const float dy = 50; geom::Point start{start_x, start_y}; geom::Point moved{start_x + dx, start_y + dy}; EXPECT_CALL(input_region, confine(start)); EXPECT_CALL(input_region, confine(moved)); controller->setPosition(start_x, start_y); controller->move(dx, dy); float final_x, final_y; controller->getPosition(&final_x, &final_y); EXPECT_EQ(start_x + dx, final_x); EXPECT_EQ(start_y + dy, final_y); } TEST_F(AndroidPointerControllerSetup, returns_bounds_of_view_area) { using namespace ::testing; EXPECT_CALL(input_region, bounding_rectangle()) .WillOnce(Return(default_view_area)); float controller_min_x, controller_min_y, controller_max_x, controller_max_y; controller->getBounds(&controller_min_x, &controller_min_y, &controller_max_x, &controller_max_y); const float area_min_x = default_view_area.top_left.x.as_float(); const float area_min_y = default_view_area.top_left.x.as_float(); const float area_max_x = default_view_area.size.width.as_float(); const float area_max_y = default_view_area.size.height.as_float(); EXPECT_EQ(controller_min_x, area_min_x); EXPECT_EQ(controller_min_y, area_min_y); EXPECT_EQ(controller_max_x, area_max_x); EXPECT_EQ(controller_max_y, area_max_y); } mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/test_android_input_targeter.cpp0000644000015301777760000000654712322054223031247 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/input/android/android_input_targeter.h" #include "src/server/input/android/android_input_registrar.h" #include "src/server/input/android/android_window_handle_repository.h" #include "mir/input/input_channel.h" #include "mir_test_doubles/mock_input_dispatcher.h" #include "mir_test_doubles/stub_input_channel.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/stub_input_channel.h" #include "mir_test_doubles/stub_input_handles.h" #include "mir_test_doubles/mock_window_handle_repository.h" #include #include #include #include #include #include #include namespace mi = mir::input; namespace mia = mi::android; namespace mt = mir::test; namespace mtd = mt::doubles; TEST(AndroidInputTargeterSetup, on_focus_cleared) { using namespace ::testing; droidinput::sp dispatcher = new mtd::MockInputDispatcher; EXPECT_CALL(*dispatcher, setKeyboardFocus(droidinput::sp(0))) .Times(1); mtd::MockWindowHandleRepository repository; mia::InputTargeter targeter(dispatcher, mt::fake_shared(repository)); targeter.focus_cleared(); } TEST(AndroidInputTargeterSetup, on_focus_changed) { using namespace ::testing; std::shared_ptr stub_channel = std::make_shared(); mtd::MockWindowHandleRepository repository; droidinput::sp dispatcher = new mtd::MockInputDispatcher; droidinput::sp stub_window_handle = new mtd::StubWindowHandle; EXPECT_CALL(*dispatcher, setKeyboardFocus(stub_window_handle)) .Times(1); EXPECT_CALL(repository, handle_for_channel(stub_channel)) .Times(1) .WillOnce(Return(stub_window_handle)); mia::InputTargeter targeter(dispatcher, mt::fake_shared(repository)); targeter.focus_changed(stub_channel); } TEST(AndroidInputTargeterSetup, on_focus_changed_throw_behavior) { using namespace ::testing; droidinput::sp dispatcher = new mtd::MockInputDispatcher; mtd::MockWindowHandleRepository repository; mia::InputTargeter targeter(dispatcher, mt::fake_shared(repository)); std::shared_ptr stub_channel = std::make_shared(); EXPECT_CALL(repository, handle_for_channel(stub_channel)) .Times(1) .WillOnce(Return(droidinput::sp())); EXPECT_THROW({ // We can't focus channels which never opened targeter.focus_changed(stub_channel); }, std::logic_error); } mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/test_android_input_registrar.cpp0000644000015301777760000001051312322054247031426 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/input/surface.h" #include "src/server/input/android/android_input_registrar.h" #include "mir_test_doubles/mock_input_dispatcher.h" #include "mir_test_doubles/stub_input_channel.h" #include "mir_test/fake_shared.h" #include #include #include #include #include namespace mi = mir::input; namespace mia = mi::android; namespace ms = mir::scene; namespace mt = mir::test; namespace mtd = mt::doubles; namespace geom = mir::geometry; namespace { // TODO: It would be nice if it were possible to mock the interface between // droidinput::InputChannel and droidinput::InputDispatcher rather than use // valid fds to allow non-throwing construction of a real input channel. struct AndroidInputRegistrarFdSetup : public testing::Test { void SetUp() override { test_input_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); dispatcher = new mtd::MockInputDispatcher(); } void TearDown() override { close(test_input_fd); } int test_input_fd; droidinput::sp dispatcher; }; struct StubInputSurface : public mi::Surface { geom::Point top_left() const { return geom::Point(); } geom::Size size() const { return geom::Size(); } std::string name() const { return {}; } bool contains(geom::Point const&) const { return true; } }; MATCHER_P(WindowHandleFor, channel, "") { if (arg->getInputChannel()->getFd() != channel->server_fd()) return false; return true; } } TEST_F(AndroidInputRegistrarFdSetup, input_channel_opened_behavior) { using namespace ::testing; auto channel = std::make_shared(test_input_fd); auto surface = std::make_shared(); EXPECT_CALL(*dispatcher, registerInputChannel(_, WindowHandleFor(channel), _)).Times(1) .WillOnce(Return(droidinput::OK)); mia::InputRegistrar registrar(dispatcher); registrar.input_channel_opened(channel, surface, mi::InputReceptionMode::normal); EXPECT_THROW({ // We can't open a surface twice registrar.input_channel_opened(channel, surface, mi::InputReceptionMode::normal); }, std::logic_error); } TEST_F(AndroidInputRegistrarFdSetup, input_channel_closed_behavior) { using namespace ::testing; auto channel = std::make_shared(test_input_fd); auto surface = std::make_shared(); EXPECT_CALL(*dispatcher, registerInputChannel(_, WindowHandleFor(channel), _)).Times(1) .WillOnce(Return(droidinput::OK)); EXPECT_CALL(*dispatcher, unregisterInputChannel(_)).Times(1); mia::InputRegistrar registrar(dispatcher); EXPECT_THROW({ // We can't close a surface which hasn't been opened registrar.input_channel_closed(channel); }, std::logic_error); registrar.input_channel_opened(channel, surface, mi::InputReceptionMode::normal); registrar.input_channel_closed(channel); EXPECT_THROW({ // Nor can we close a surface twice registrar.input_channel_closed(channel); }, std::logic_error); } TEST_F(AndroidInputRegistrarFdSetup, monitor_flag_is_passed_to_dispatcher) { using namespace ::testing; auto channel = std::make_shared(test_input_fd); auto surface = std::make_shared(); EXPECT_CALL(*dispatcher, registerInputChannel(_, _, true)).Times(1) .WillOnce(Return(droidinput::OK)); mia::InputRegistrar registrar(dispatcher); registrar.input_channel_opened(channel, surface, mi::InputReceptionMode::receives_all_input); } mir-0.1.8+14.04.20140411/tests/unit-tests/input/android/test_android_input_application_handle.cpp0000644000015301777760000000322412322054247033243 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/input/android/android_input_application_handle.h" #include "mir/input/input_channel.h" #include "mir_test_doubles/mock_input_surface.h" #include #include #include namespace mi = mir::input; namespace mia = mi::android; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; TEST(AndroidInputApplicationHandle, takes_name_from_surface_and_specifies_max_timeout) { using namespace ::testing; std::string testing_surface_name = "Cats"; auto surface_info = std::make_shared(); EXPECT_CALL(*surface_info, name()) .Times(2) .WillRepeatedly(Return(testing_surface_name)); mia::InputApplicationHandle application_handle(surface_info); EXPECT_TRUE(application_handle.updateInfo()); auto info = application_handle.getInfo(); EXPECT_EQ(INT_MAX, info->dispatchingTimeout); EXPECT_EQ(droidinput::String8(testing_surface_name.c_str()), info->name); } mir-0.1.8+14.04.20140411/tests/unit-tests/input/test_event_filter_chain.cpp0000644000015301777760000000577012322054223026720 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/input/event_filter_chain.h" #include "mir_test_doubles/mock_event_filter.h" #include #include #include namespace mi = mir::input; namespace mtd = mir::test::doubles; TEST(EventFilterChain, offers_events_to_filters) { using namespace ::testing; auto filter = std::make_shared(); MirEvent ev; mi::EventFilterChain filter_chain{filter, filter}; // Filter will pass the event on twice EXPECT_CALL(*filter, handle(_)).Times(2).WillRepeatedly(Return(false)); // So the filter chain should also reject the event EXPECT_FALSE(filter_chain.handle(ev)); } TEST(EventFilterChain, prepends_appends_filters) { using namespace ::testing; auto filter1 = std::make_shared(); auto filter2 = std::make_shared(); auto filter3 = std::make_shared(); MirEvent ev; mi::EventFilterChain filter_chain{filter2}; filter_chain.append(filter3); filter_chain.prepend(filter1); { InSequence s; EXPECT_CALL(*filter1, handle(_)).WillOnce(Return(false)); EXPECT_CALL(*filter2, handle(_)).WillOnce(Return(false)); EXPECT_CALL(*filter3, handle(_)).WillOnce(Return(false)); } // So the filter chain should also reject the event EXPECT_FALSE(filter_chain.handle(ev)); } TEST(EventFilterChain, accepting_event_halts_emission) { using namespace ::testing; auto filter = std::make_shared(); MirEvent ev; mi::EventFilterChain filter_chain{filter, filter, filter}; // First filter will reject, second will accept, third one should not be asked. { InSequence seq; EXPECT_CALL(*filter, handle(_)).Times(1).WillOnce(Return(false)); EXPECT_CALL(*filter, handle(_)).Times(1).WillOnce(Return(true)); } // So the chain should accept EXPECT_TRUE(filter_chain.handle(ev)); } TEST(EventFilterChain, does_not_own_event_filters) { using namespace ::testing; auto filter = std::make_shared(); MirEvent ev; mi::EventFilterChain filter_chain{filter}; EXPECT_CALL(*filter, handle(_)).Times(1).WillOnce(Return(true)); EXPECT_TRUE(filter_chain.handle(ev)); filter.reset(); EXPECT_FALSE(filter_chain.handle(ev)); } mir-0.1.8+14.04.20140411/tests/unit-tests/input/test_display_input_region.cpp0000644000015301777760000000635112322054223027313 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/input/display_input_region.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/stub_display_buffer.h" #include #include #include namespace mi = mir::input; namespace mg = mir::graphics; namespace mtd = mir::test::doubles; namespace geom = mir::geometry; namespace { class StubDisplay : public mtd::NullDisplay { public: StubDisplay() : display_buffers{ mtd::StubDisplayBuffer{geom::Rectangle{geom::Point{0,0}, geom::Size{800,600}}}, mtd::StubDisplayBuffer{geom::Rectangle{geom::Point{0,600}, geom::Size{100,100}}}, mtd::StubDisplayBuffer{geom::Rectangle{geom::Point{800,0}, geom::Size{100,100}}}} { } void for_each_display_buffer(std::function const& f) override { for (auto& db : display_buffers) f(db); } private: std::vector display_buffers; }; } TEST(DisplayInputRegionTest, returns_correct_bounding_rectangle) { geom::Rectangle const expected_bounding_rect{geom::Point{0,0}, geom::Size{900,700}}; auto stub_display = std::make_shared(); mi::DisplayInputRegion input_region{stub_display}; auto rect = input_region.bounding_rectangle(); EXPECT_EQ(expected_bounding_rect, rect); } TEST(DisplayInputRegionTest, confines_point_to_closest_valid_position) { auto stub_display = std::make_shared(); mi::DisplayInputRegion input_region{stub_display}; std::vector> point_tuples{ std::make_tuple(geom::Point{0,0}, geom::Point{0,0}), std::make_tuple(geom::Point{900,50}, geom::Point{899,50}), std::make_tuple(geom::Point{850,100}, geom::Point{850,99}), std::make_tuple(geom::Point{801,100}, geom::Point{801,99}), std::make_tuple(geom::Point{800,101}, geom::Point{799,101}), std::make_tuple(geom::Point{800,600}, geom::Point{799,599}), std::make_tuple(geom::Point{-1,700}, geom::Point{0,699}), std::make_tuple(geom::Point{-1,-1}, geom::Point{0,0}), std::make_tuple(geom::Point{-1,50}, geom::Point{0,50}), std::make_tuple(geom::Point{799,-1}, geom::Point{799,0}), std::make_tuple(geom::Point{800,-1}, geom::Point{800,0}) }; for (auto const& t : point_tuples) { geom::Point confined_point{std::get<0>(t)}; geom::Point const expected_point{std::get<1>(t)}; input_region.confine(confined_point); EXPECT_EQ(expected_point, confined_point); } } mir-0.1.8+14.04.20140411/tests/unit-tests/input/CMakeLists.txt0000644000015301777760000000036212322054223024055 0ustar pbusernogroup00000000000000add_subdirectory(android) list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/test_event_filter_chain.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_display_input_region.cpp ) set( UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/unit-tests/CMakeLists.txt0000644000015301777760000000335212322054247022726 0ustar pbusernogroup00000000000000include(CMakeDependentOption) add_definitions(-DTEST_RECORDINGS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/input_recordings/") include_directories(${DRM_INCLUDE_DIRS} ${GBM_INCLUDE_DIRS} ${UMOCKDEV_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}) set( UNIT_TEST_SOURCES test_gmock_fixes.cpp test_asio_main_loop.cpp shared_library_test.cpp test_raii.cpp test_udev_wrapper.cpp ) add_subdirectory(options/) add_subdirectory(client/) add_subdirectory(compositor/) add_subdirectory(frontend/) add_subdirectory(logging/) add_subdirectory(shell/) add_subdirectory(geometry/) add_subdirectory(graphics/) add_subdirectory(input/) add_subdirectory(android_input/) add_subdirectory(scene/) add_subdirectory(draw/) link_directories(${LIBRARY_OUTPUT_PATH}) add_executable(mir_unit_tests ${UNIT_TEST_SOURCES}) uses_android_input(mir_unit_tests) target_link_libraries( mir_unit_tests mirclient mirserver mirplatformgraphics mirclientplatform mirdraw mirtestdraw mirlogging mir-test mir-test-doubles mir-test-doubles-platform mir-test-framework 3rd_party ${PROTOBUF_LIBRARIES} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${Boost_LIBRARIES} ${UMOCKDEV_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} # Link in pthread. ) # Umockdev uses glib, which uses the deprecated "register" allocation specifier set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dregister=") CMAKE_DEPENDENT_OPTION( MIR_RUN_UNIT_TESTS "Run unit tests as part of default testing" ON "MIR_BUILD_UNIT_TESTS" OFF) if (MIR_RUN_UNIT_TESTS) mir_discover_tests(mir_unit_tests LD_PRELOAD=libumockdev-preload.so.0 G_SLICE=always-malloc G_DEBUG=gc-friendly) endif (MIR_RUN_UNIT_TESTS) install( TARGETS mir_unit_tests RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) mir-0.1.8+14.04.20140411/tests/unit-tests/test_raii.cpp0000644000015301777760000001127012322054223022645 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/raii.h" #include #include namespace { struct RaiiTest : public ::testing::Test { RaiiTest(); ~RaiiTest(); MOCK_METHOD0(create_void, void()); MOCK_METHOD0(destroy_void, void()); MOCK_METHOD0(create_ptr, RaiiTest*()); MOCK_METHOD1(destroy_ptr, void (RaiiTest*)); MOCK_METHOD0(test_call, void()); }; RaiiTest* self = nullptr; RaiiTest::RaiiTest() { self = this; } RaiiTest::~RaiiTest() { self = nullptr; } void create_void() { return self->create_void(); } void destroy_void() { self->destroy_void(); } RaiiTest* create_ptr() { return self->create_ptr(); } void destroy_ptr(RaiiTest* p) { self->destroy_ptr(p); } } using namespace testing; TEST_F(RaiiTest, free_create_free_destroy_ptr) { InSequence seq; EXPECT_CALL(*this, create_ptr()).Times(1).WillRepeatedly(Return(this)); EXPECT_CALL(*this, test_call()).Times(1); EXPECT_CALL(*this, destroy_ptr(this)).Times(1); auto const raii = mir::raii::paired_calls( ::create_ptr, ::destroy_ptr); raii->test_call(); EXPECT_EQ(this, raii.get()); } TEST_F(RaiiTest, lambda_create_free_destroy_ptr) { InSequence seq; EXPECT_CALL(*this, create_ptr()).Times(1).WillRepeatedly(Return(this)); EXPECT_CALL(*this, test_call()).Times(1); EXPECT_CALL(*this, destroy_ptr(this)).Times(1); auto const raii = mir::raii::paired_calls( [this] { return create_ptr(); }, ::destroy_ptr); raii->test_call(); EXPECT_EQ(this, raii.get()); } TEST_F(RaiiTest, free_create_lambda_destroy_ptr) { InSequence seq; EXPECT_CALL(*this, create_ptr()).Times(1).WillRepeatedly(Return(this)); EXPECT_CALL(*this, test_call()).Times(1); EXPECT_CALL(*this, destroy_ptr(this)).Times(1); auto const raii = mir::raii::paired_calls( ::create_ptr, [this] (RaiiTest*p){ ::destroy_ptr(p); }); raii->test_call(); EXPECT_EQ(this, raii.get()); } TEST_F(RaiiTest, lambda_create_lambda_destroy_ptr) { InSequence seq; EXPECT_CALL(*this, create_ptr()).Times(1).WillRepeatedly(Return(this)); EXPECT_CALL(*this, test_call()).Times(1); EXPECT_CALL(*this, destroy_ptr(this)).Times(1); auto const raii = mir::raii::paired_calls( [this] { return create_ptr(); }, [this] (RaiiTest*p){ destroy_ptr(p); }); raii->test_call(); EXPECT_EQ(this, raii.get()); } TEST_F(RaiiTest, free_create_free_destroy_void) { EXPECT_CALL(*this, create_void()).Times(1); auto const raii = mir::raii::paired_calls( ::create_void, ::destroy_void); Mock::VerifyAndClearExpectations(this); EXPECT_CALL(*this, destroy_void()).Times(1); } TEST_F(RaiiTest, lambda_create_free_destroy_void) { InSequence seq; EXPECT_CALL(*this, create_void()).Times(1); EXPECT_CALL(*this, destroy_void()).Times(1); auto const raii = mir::raii::paired_calls( [this] { return create_void(); }, ::destroy_void); } TEST_F(RaiiTest, free_create_lambda_destroy_void) { InSequence seq; EXPECT_CALL(*this, create_void()).Times(1); EXPECT_CALL(*this, destroy_void()).Times(1); auto const raii = mir::raii::paired_calls( ::create_void, [this] (){ destroy_void(); }); } TEST_F(RaiiTest, lambda_create_lambda_destroy_void) { InSequence seq; EXPECT_CALL(*this, create_void()).Times(1); EXPECT_CALL(*this, destroy_void()).Times(1); auto const raii = mir::raii::paired_calls( [this] { return create_void(); }, [this] (){ destroy_void(); }); } TEST_F(RaiiTest, deleter_for_free_destroy_ptr) { EXPECT_CALL(*this, destroy_ptr(this)).Times(1); auto const raii = mir::raii::deleter_for( static_cast(this), ::destroy_ptr); EXPECT_EQ(this, raii.get()); } TEST_F(RaiiTest, deleter_for_lambda_destroy_ptr) { EXPECT_CALL(*this, destroy_ptr(this)).Times(1); auto const raii = mir::raii::deleter_for( static_cast(this), [this] (RaiiTest*p){ destroy_ptr(p); }); EXPECT_EQ(this, raii.get()); } mir-0.1.8+14.04.20140411/tests/unit-tests/test_asio_main_loop.cpp0000644000015301777760000001776212322054223024725 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/asio_main_loop.h" #include "mir_test/pipe.h" #include #include #include #include #include namespace mt = mir::test; TEST(AsioMainLoopTest, signal_handled) { int const signum{SIGUSR1}; int handled_signum{0}; mir::AsioMainLoop ml; ml.register_signal_handler( {signum}, [&handled_signum, &ml](int sig) { handled_signum = sig; ml.stop(); }); kill(getpid(), signum); ml.run(); ASSERT_EQ(signum, handled_signum); } TEST(AsioMainLoopTest, multiple_signals_handled) { std::vector const signals{SIGUSR1, SIGUSR2}; size_t const num_signals_to_send{10}; std::vector handled_signals; std::atomic num_handled_signals{0}; mir::AsioMainLoop ml; ml.register_signal_handler( {signals[0], signals[1]}, [&handled_signals, &num_handled_signals](int sig) { handled_signals.push_back(sig); ++num_handled_signals; }); std::thread signal_sending_thread( [&ml, num_signals_to_send, &signals, &num_handled_signals] { for (size_t i = 0; i < num_signals_to_send; i++) { kill(getpid(), signals[i % signals.size()]); while (num_handled_signals <= i) std::this_thread::yield(); } ml.stop(); }); ml.run(); signal_sending_thread.join(); ASSERT_EQ(num_signals_to_send, handled_signals.size()); for (size_t i = 0; i < num_signals_to_send; i++) ASSERT_EQ(signals[i % signals.size()], handled_signals[i]) << " index " << i; } TEST(AsioMainLoopTest, all_registered_handlers_are_called) { int const signum{SIGUSR1}; std::vector handled_signum{0,0,0}; mir::AsioMainLoop ml; ml.register_signal_handler( {signum}, [&handled_signum, &ml](int sig) { handled_signum[0] = sig; if (handled_signum[0] != 0 && handled_signum[1] != 0 && handled_signum[2] != 0) { ml.stop(); } }); ml.register_signal_handler( {signum}, [&handled_signum, &ml](int sig) { handled_signum[1] = sig; if (handled_signum[0] != 0 && handled_signum[1] != 0 && handled_signum[2] != 0) { ml.stop(); } }); ml.register_signal_handler( {signum}, [&handled_signum, &ml](int sig) { handled_signum[2] = sig; if (handled_signum[0] != 0 && handled_signum[1] != 0 && handled_signum[2] != 0) { ml.stop(); } }); kill(getpid(), signum); ml.run(); ASSERT_EQ(signum, handled_signum[0]); ASSERT_EQ(signum, handled_signum[1]); ASSERT_EQ(signum, handled_signum[2]); } TEST(AsioMainLoopTest, fd_data_handled) { mt::Pipe p; char const data_to_write{'a'}; int handled_fd{0}; char data_read{0}; mir::AsioMainLoop ml; ml.register_fd_handler( {p.read_fd()}, [&handled_fd, &data_read, &ml](int fd) { handled_fd = fd; EXPECT_EQ(1, read(fd, &data_read, 1)); ml.stop(); }); EXPECT_EQ(1, write(p.write_fd(), &data_to_write, 1)); ml.run(); EXPECT_EQ(data_to_write, data_read); } TEST(AsioMainLoopTest, multiple_fds_with_single_handler_handled) { std::vector const pipes(2); size_t const num_elems_to_send{10}; std::vector handled_fds; std::vector elems_read; std::atomic num_handled_fds{0}; mir::AsioMainLoop ml; ml.register_fd_handler( {pipes[0].read_fd(), pipes[1].read_fd()}, [&handled_fds, &elems_read, &num_handled_fds](int fd) { handled_fds.push_back(fd); size_t i; EXPECT_EQ(static_cast(sizeof(i)), read(fd, &i, sizeof(i))); elems_read.push_back(i); ++num_handled_fds; }); std::thread fd_writing_thread{ [&ml, num_elems_to_send, &pipes, &num_handled_fds] { for (size_t i = 0; i < num_elems_to_send; i++) { EXPECT_EQ(static_cast(sizeof(i)), write(pipes[i % pipes.size()].write_fd(), &i, sizeof(i))); while (num_handled_fds <= i) std::this_thread::yield(); } ml.stop(); }}; ml.run(); fd_writing_thread.join(); ASSERT_EQ(num_elems_to_send, handled_fds.size()); ASSERT_EQ(num_elems_to_send, elems_read.size()); for (size_t i = 0; i < num_elems_to_send; i++) { EXPECT_EQ(pipes[i % pipes.size()].read_fd(), handled_fds[i]) << " index " << i; EXPECT_EQ(i, elems_read[i]) << " index " << i; } } TEST(AsioMainLoopTest, multiple_fd_handlers_are_called) { std::vector const pipes(3); std::vector const elems_to_send{10,11,12}; std::vector handled_fds{0,0,0}; std::vector elems_read{0,0,0}; mir::AsioMainLoop ml; ml.register_fd_handler( {pipes[0].read_fd()}, [&handled_fds, &elems_read, &ml](int fd) { EXPECT_EQ(static_cast(sizeof(elems_read[0])), read(fd, &elems_read[0], sizeof(elems_read[0]))); handled_fds[0] = fd; if (handled_fds[0] != 0 && handled_fds[1] != 0 && handled_fds[2] != 0) { ml.stop(); } }); ml.register_fd_handler( {pipes[1].read_fd()}, [&handled_fds, &elems_read, &ml](int fd) { EXPECT_EQ(static_cast(sizeof(elems_read[1])), read(fd, &elems_read[1], sizeof(elems_read[1]))); handled_fds[1] = fd; if (handled_fds[0] != 0 && handled_fds[1] != 0 && handled_fds[2] != 0) { ml.stop(); } }); ml.register_fd_handler( {pipes[2].read_fd()}, [&handled_fds, &elems_read, &ml](int fd) { EXPECT_EQ(static_cast(sizeof(elems_read[2])), read(fd, &elems_read[2], sizeof(elems_read[2]))); handled_fds[2] = fd; if (handled_fds[0] != 0 && handled_fds[1] != 0 && handled_fds[2] != 0) { ml.stop(); } }); EXPECT_EQ(static_cast(sizeof(elems_to_send[0])), write(pipes[0].write_fd(), &elems_to_send[0], sizeof(elems_to_send[0]))); EXPECT_EQ(static_cast(sizeof(elems_to_send[1])), write(pipes[1].write_fd(), &elems_to_send[1], sizeof(elems_to_send[1]))); EXPECT_EQ(static_cast(sizeof(elems_to_send[2])), write(pipes[2].write_fd(), &elems_to_send[2], sizeof(elems_to_send[2]))); ml.run(); EXPECT_EQ(pipes[0].read_fd(), handled_fds[0]); EXPECT_EQ(pipes[1].read_fd(), handled_fds[1]); EXPECT_EQ(pipes[2].read_fd(), handled_fds[2]); EXPECT_EQ(elems_to_send[0], elems_read[0]); EXPECT_EQ(elems_to_send[1], elems_read[1]); EXPECT_EQ(elems_to_send[2], elems_read[2]); } mir-0.1.8+14.04.20140411/tests/unit-tests/android_input/0000755000015301777760000000000012322054703023017 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/unit-tests/android_input/input_reader.cpp0000644000015301777760000064440412322054223026215 0ustar pbusernogroup00000000000000/* * Copyright (C) 2013 Canonical Ltd. * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "mir/logging/logger.h" #include "mir/report/legacy_input_report.h" #include "mir_test/fake_event_hub.h" namespace ml = mir::logging; using std::string; using mir::input::android::FakeEventHub; namespace { class TestLogger : public ml::Logger { public: void log(Severity severity, const string& message, const string& component) override { (void)severity; (void)message; (void)component; } }; } namespace android { // An arbitrary time value. static const nsecs_t ARBITRARY_TIME = 1234; // Arbitrary display properties. static const int32_t DISPLAY_ID = 0; static const int32_t DISPLAY_WIDTH = 480; static const int32_t DISPLAY_HEIGHT = 800; // Error tolerance for floating point assertions. static const float EPSILON = 0.001f; template static inline T min(T a, T b) { return a < b ? a : b; } static inline float avg(float x, float y) { return (x + y) / 2; } // --- FakePointerController --- class FakePointerController : public PointerControllerInterface { bool mHaveBounds; float mMinX, mMinY, mMaxX, mMaxY; float mX, mY; int32_t mButtonState; protected: virtual ~FakePointerController() { } public: FakePointerController() : mHaveBounds(false), mMinX(0), mMinY(0), mMaxX(0), mMaxY(0), mX(0), mY(0), mButtonState(0) { } void setBounds(float minX, float minY, float maxX, float maxY) { mHaveBounds = true; mMinX = minX; mMinY = minY; mMaxX = maxX; mMaxY = maxY; } virtual void setPosition(float x, float y) { mX = x; mY = y; } virtual void setButtonState(int32_t buttonState) { mButtonState = buttonState; } virtual int32_t getButtonState() const { return mButtonState; } virtual void getPosition(float* outX, float* outY) const { *outX = mX; *outY = mY; } private: virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const { *outMinX = mMinX; *outMinY = mMinY; *outMaxX = mMaxX; *outMaxY = mMaxY; return mHaveBounds; } virtual void move(float deltaX, float deltaY) { mX += deltaX; if (mX < mMinX) mX = mMinX; if (mX > mMaxX) mX = mMaxX; mY += deltaY; if (mY < mMinY) mY = mMinY; if (mY > mMaxY) mY = mMaxY; } void fade(Transition /*transition*/) override {} void unfade(Transition /*transition*/) override {} void setPresentation(Presentation /*presentation*/) override {} void setSpots(const PointerCoords* /*spotCoords*/, uint32_t /*spotCount*/) override {} void clearSpots() override {} }; // --- FakeInputReaderPolicy --- class FakeInputReaderPolicy : public InputReaderPolicyInterface { InputReaderConfiguration mConfig; KeyedVector > mPointerControllers; Vector mInputDevices; protected: virtual ~FakeInputReaderPolicy() { } public: FakeInputReaderPolicy() { } void setDisplayInfo(int32_t displayId, int32_t width, int32_t height, int32_t orientation) { // Set the size of both the internal and external display at the same time. mConfig.setDisplayInfo(displayId, false /*external*/, width, height, orientation); mConfig.setDisplayInfo(displayId, true /*external*/, width, height, orientation); } void addExcludedDeviceName(const String8& deviceName) { mConfig.excludedDeviceNames.push(deviceName); } void setPointerController(int32_t deviceId, const sp& controller) { mPointerControllers.add(deviceId, controller); } const InputReaderConfiguration* getReaderConfiguration() const { return &mConfig; } const Vector& getInputDevices() const { return mInputDevices; } private: virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) { *outConfig = mConfig; } virtual sp obtainPointerController(int32_t deviceId) { return mPointerControllers.valueFor(deviceId); } virtual void notifyInputDevicesChanged(const Vector& inputDevices) { mInputDevices = inputDevices; } sp getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) override { (void) inputDeviceDescriptor; return NULL; } String8 getDeviceAlias(const InputDeviceIdentifier& identifier) override { (void)identifier; return String8(); } }; // --- FakeInputListener --- class FakeInputListener : public InputListenerInterface { private: List mNotifyConfigurationChangedArgsQueue; List mNotifyDeviceResetArgsQueue; List mNotifyKeyArgsQueue; List mNotifyMotionArgsQueue; List mNotifySwitchArgsQueue; protected: virtual ~FakeInputListener() { } public: FakeInputListener() { } void assertNotifyConfigurationChangedWasCalled( NotifyConfigurationChangedArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyConfigurationChangedArgsQueue.empty()) << "Expected notifyConfigurationChanged() to have been called."; if (outEventArgs) { *outEventArgs = *mNotifyConfigurationChangedArgsQueue.begin(); } mNotifyConfigurationChangedArgsQueue.erase(mNotifyConfigurationChangedArgsQueue.begin()); } void assertNotifyDeviceResetWasCalled( NotifyDeviceResetArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty()) << "Expected notifyDeviceReset() to have been called."; if (outEventArgs) { *outEventArgs = *mNotifyDeviceResetArgsQueue.begin(); } mNotifyDeviceResetArgsQueue.erase(mNotifyDeviceResetArgsQueue.begin()); } void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyKeyArgsQueue.empty()) << "Expected notifyKey() to have been called."; if (outEventArgs) { *outEventArgs = *mNotifyKeyArgsQueue.begin(); } mNotifyKeyArgsQueue.erase(mNotifyKeyArgsQueue.begin()); } void assertNotifyKeyWasNotCalled() { ASSERT_TRUE(mNotifyKeyArgsQueue.empty()) << "Expected notifyKey() to not have been called."; } void assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifyMotionArgsQueue.empty()) << "Expected notifyMotion() to have been called."; if (outEventArgs) { *outEventArgs = *mNotifyMotionArgsQueue.begin(); } mNotifyMotionArgsQueue.erase(mNotifyMotionArgsQueue.begin()); } void assertNotifyMotionWasNotCalled() { ASSERT_TRUE(mNotifyMotionArgsQueue.empty()) << "Expected notifyMotion() to not have been called."; } void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = NULL) { ASSERT_FALSE(mNotifySwitchArgsQueue.empty()) << "Expected notifySwitch() to have been called."; if (outEventArgs) { *outEventArgs = *mNotifySwitchArgsQueue.begin(); } mNotifySwitchArgsQueue.erase(mNotifySwitchArgsQueue.begin()); } private: virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { mNotifyConfigurationChangedArgsQueue.push_back(*args); } virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) { mNotifyDeviceResetArgsQueue.push_back(*args); } virtual void notifyKey(const NotifyKeyArgs* args) { mNotifyKeyArgsQueue.push_back(*args); } virtual void notifyMotion(const NotifyMotionArgs* args) { mNotifyMotionArgsQueue.push_back(*args); } virtual void notifySwitch(const NotifySwitchArgs* args) { mNotifySwitchArgsQueue.push_back(*args); } }; // --- FakeInputReaderContext --- class FakeInputReaderContext : public InputReaderContext { sp mEventHub; sp mPolicy; sp mListener; int32_t mGlobalMetaState; bool mUpdateGlobalMetaStateWasCalled; int32_t mGeneration; public: FakeInputReaderContext(const sp& eventHub, const sp& policy, const sp& listener) : mEventHub(eventHub), mPolicy(policy), mListener(listener), mGlobalMetaState(0) { } virtual ~FakeInputReaderContext() { } void assertUpdateGlobalMetaStateWasCalled() { ASSERT_TRUE(mUpdateGlobalMetaStateWasCalled) << "Expected updateGlobalMetaState() to have been called."; mUpdateGlobalMetaStateWasCalled = false; } void setGlobalMetaState(int32_t state) { mGlobalMetaState = state; } private: virtual void updateGlobalMetaState() { mUpdateGlobalMetaStateWasCalled = true; } virtual int32_t getGlobalMetaState() { return mGlobalMetaState; } virtual EventHubInterface* getEventHub() { return mEventHub.get(); } virtual InputReaderPolicyInterface* getPolicy() { return mPolicy.get(); } virtual InputListenerInterface* getListener() { return mListener.get(); } void disableVirtualKeysUntil(nsecs_t /*time*/) override {} bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode) override { (void) now; (void) device; (void) keyCode; (void) scanCode; return false; } void fadePointer() override {} void requestTimeoutAtTime(nsecs_t /*when*/) override {} int32_t bumpGeneration() override { return ++mGeneration; } }; // --- FakeInputMapper --- class FakeInputMapper : public InputMapper { uint32_t mSources; int32_t mKeyboardType; int32_t mMetaState; KeyedVector mKeyCodeStates; KeyedVector mScanCodeStates; KeyedVector mSwitchStates; Vector mSupportedKeyCodes; RawEvent mLastEvent; bool mConfigureWasCalled; bool mResetWasCalled; bool mProcessWasCalled; public: FakeInputMapper(InputDevice* device, uint32_t sources) : InputMapper(device), mSources(sources), mKeyboardType(AINPUT_KEYBOARD_TYPE_NONE), mMetaState(0), mConfigureWasCalled(false), mResetWasCalled(false), mProcessWasCalled(false) { } virtual ~FakeInputMapper() { } void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } void setMetaState(int32_t metaState) { mMetaState = metaState; } void assertConfigureWasCalled() { ASSERT_TRUE(mConfigureWasCalled) << "Expected configure() to have been called."; mConfigureWasCalled = false; } void assertResetWasCalled() { ASSERT_TRUE(mResetWasCalled) << "Expected reset() to have been called."; mResetWasCalled = false; } void assertProcessWasCalled(RawEvent* outLastEvent = NULL) { ASSERT_TRUE(mProcessWasCalled) << "Expected process() to have been called."; if (outLastEvent) { *outLastEvent = mLastEvent; } mProcessWasCalled = false; } void setKeyCodeState(int32_t keyCode, int32_t state) { mKeyCodeStates.replaceValueFor(keyCode, state); } void setScanCodeState(int32_t scanCode, int32_t state) { mScanCodeStates.replaceValueFor(scanCode, state); } void setSwitchState(int32_t switchCode, int32_t state) { mSwitchStates.replaceValueFor(switchCode, state); } void addSupportedKeyCode(int32_t keyCode) { mSupportedKeyCodes.add(keyCode); } private: virtual uint32_t getSources() { return mSources; } virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) { InputMapper::populateDeviceInfo(deviceInfo); if (mKeyboardType != AINPUT_KEYBOARD_TYPE_NONE) { deviceInfo->setKeyboardType(mKeyboardType); } } void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) override { (void)when; (void)config; (void)changes; mConfigureWasCalled = true; } void reset(nsecs_t when) override { (void)when; mResetWasCalled = true; } void process(const RawEvent* rawEvent) override { mLastEvent = *rawEvent; mProcessWasCalled = true; } int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override { (void)sourceMask; ssize_t index = mKeyCodeStates.indexOfKey(keyCode); return index >= 0 ? mKeyCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; } int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override { (void)sourceMask; ssize_t index = mScanCodeStates.indexOfKey(scanCode); return index >= 0 ? mScanCodeStates.valueAt(index) : AKEY_STATE_UNKNOWN; } int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode) override { (void)sourceMask; ssize_t index = mSwitchStates.indexOfKey(switchCode); return index >= 0 ? mSwitchStates.valueAt(index) : AKEY_STATE_UNKNOWN; } bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) override { (void)sourceMask; bool result = false; for (size_t i = 0; i < numCodes; i++) { for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) { if (keyCodes[i] == mSupportedKeyCodes[j]) { outFlags[i] = 1; result = true; } } } return result; } int32_t getMetaState() override { return mMetaState; } }; // --- InstrumentedInputReader --- class InstrumentedInputReader : public InputReader { InputDevice* mNextDevice; public: InstrumentedInputReader(const sp& eventHub, const sp& policy, const sp& listener) : InputReader(eventHub, policy, listener), mNextDevice(NULL) { } virtual ~InstrumentedInputReader() { if (mNextDevice) { delete mNextDevice; } } void setNextDevice(InputDevice* device) { mNextDevice = device; } InputDevice* newDevice(int32_t deviceId, const String8& name, uint32_t classes) { InputDeviceIdentifier identifier; identifier.name = name; int32_t generation = deviceId + 1; return new InputDevice(&mContext, deviceId, generation, identifier, classes); } protected: virtual InputDevice* createDeviceLocked(int32_t deviceId, const InputDeviceIdentifier& identifier, uint32_t classes) { if (mNextDevice) { InputDevice* device = mNextDevice; mNextDevice = NULL; return device; } return InputReader::createDeviceLocked(deviceId, identifier, classes); } friend class InputReaderTest; }; // --- InputReaderTest --- class InputReaderTest : public testing::Test { protected: sp mFakeListener; sp mFakePolicy; sp mFakeEventHub; sp mReader; virtual void SetUp() { mir::report::legacy_input::initialize(std::make_shared()); mFakeEventHub = new FakeEventHub(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = new FakeInputListener(); mReader = new InstrumentedInputReader(mFakeEventHub, mFakePolicy, mFakeListener); } virtual void TearDown() { mReader.clear(); mFakeListener.clear(); mFakePolicy.clear(); mFakeEventHub.clear(); } void addDevice(int32_t deviceId, const String8& name, uint32_t classes, const PropertyMap* configuration) { mFakeEventHub->addDevice(deviceId, name, classes); if (configuration) { mFakeEventHub->addConfigurationMap(deviceId, configuration); } mFakeEventHub->finishDeviceScan(); mReader->loopOnce(); mReader->loopOnce(); ASSERT_EQ(size_t(0), mFakeEventHub->eventsQueueSize()) << "Expected the event queue to be empty (fully consumed)."; } FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId, const String8& name, uint32_t classes, uint32_t sources, const PropertyMap* configuration) { InputDevice* device = mReader->newDevice(deviceId, name, classes); FakeInputMapper* mapper = new FakeInputMapper(device, sources); device->addMapper(mapper); mReader->setNextDevice(device); addDevice(deviceId, name, classes, configuration); return mapper; } }; TEST_F(InputReaderTest, GetInputDevices) { ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("keyboard"), INPUT_DEVICE_CLASS_KEYBOARD, NULL)); ASSERT_NO_FATAL_FAILURE(addDevice(3, String8("ignored"), 0, NULL)); // no classes so device will be ignored Vector inputDevices; mReader->getInputDevices(inputDevices); ASSERT_EQ(1U, inputDevices.size()); ASSERT_EQ(2, inputDevices[0].getId()); ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str()); ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType()); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources()); ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size()); // Should also have received a notification describing the new input devices. inputDevices = mFakePolicy->getInputDevices(); ASSERT_EQ(1U, inputDevices.size()); ASSERT_EQ(2, inputDevices[0].getId()); ASSERT_STREQ("keyboard", inputDevices[0].getIdentifier().name.c_str()); ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC, inputDevices[0].getKeyboardType()); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, inputDevices[0].getSources()); ASSERT_EQ(size_t(0), inputDevices[0].getMotionRanges().size()); } TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(0, AINPUT_SOURCE_ANY, AKEYCODE_A)) << "Should return unknown when the device id is >= 0 but unknown."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(1, AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return unknown when the device id is valid but the sources are not supported by the device."; ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(-1, AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; ASSERT_EQ(AKEY_STATE_DOWN, mReader->getKeyCodeState(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; } TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN); ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(0, AINPUT_SOURCE_ANY, KEY_A)) << "Should return unknown when the device id is >= 0 but unknown."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(1, AINPUT_SOURCE_TRACKBALL, KEY_A)) << "Should return unknown when the device id is valid but the sources are not supported by the device."; ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A)) << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(-1, AINPUT_SOURCE_TRACKBALL, KEY_A)) << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; ASSERT_EQ(AKEY_STATE_DOWN, mReader->getScanCodeState(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, KEY_A)) << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; } TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN); ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(0, AINPUT_SOURCE_ANY, SW_LID)) << "Should return unknown when the device id is >= 0 but unknown."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(1, AINPUT_SOURCE_TRACKBALL, SW_LID)) << "Should return unknown when the device id is valid but the sources are not supported by the device."; ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID)) << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(-1, AINPUT_SOURCE_TRACKBALL, SW_LID)) << "Should return unknown when the device id is < 0 but the sources are not supported by any device."; ASSERT_EQ(AKEY_STATE_DOWN, mReader->getSwitchState(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, SW_LID)) << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; } TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mapper->addSupportedKeyCode(AKEYCODE_A); mapper->addSupportedKeyCode(AKEYCODE_B); const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; uint8_t flags[4] = { 0, 0, 0, 1 }; ASSERT_FALSE(mReader->hasKeys(0, AINPUT_SOURCE_ANY, 4, keyCodes, flags)) << "Should return false when device id is >= 0 but unknown."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; ASSERT_FALSE(mReader->hasKeys(1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) << "Should return false when device id is valid but the sources are not supported by the device."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; ASSERT_TRUE(mReader->hasKeys(1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) << "Should return value provided by mapper when device id is valid and the device supports some of the sources."; ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); flags[3] = 1; ASSERT_FALSE(mReader->hasKeys(-1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) << "Should return false when the device id is < 0 but the sources are not supported by any device."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; ASSERT_TRUE(mReader->hasKeys(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); } TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) { addDevice(2, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD, NULL); NotifyConfigurationChangedArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(&args)); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); } TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) { FakeInputMapper* mapper = NULL; ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, String8("fake"), INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL)); mFakeEventHub->synthesize_event(0, 1, EV_KEY, KEY_A, 1); mReader->loopOnce(); EXPECT_EQ(size_t(0), mFakeEventHub->eventsQueueSize()); RawEvent event; ASSERT_NO_FATAL_FAILURE(mapper->assertProcessWasCalled(&event)); ASSERT_EQ(0, event.when); ASSERT_EQ(1, event.deviceId); ASSERT_EQ(EV_KEY, event.type); ASSERT_EQ(KEY_A, event.code); ASSERT_EQ(1, event.value); } // --- InputDeviceTest --- class InputDeviceTest : public testing::Test { protected: static const char* DEVICE_NAME; static const int32_t DEVICE_ID; static const int32_t DEVICE_GENERATION; static const uint32_t DEVICE_CLASSES; sp mFakeEventHub; sp mFakePolicy; sp mFakeListener; FakeInputReaderContext* mFakeContext; InputDevice* mDevice; virtual void SetUp() { mir::report::legacy_input::initialize(std::make_shared()); mFakeEventHub = new FakeEventHub(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = new FakeInputListener(); mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener); mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0); InputDeviceIdentifier identifier; identifier.name = DEVICE_NAME; mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, identifier, DEVICE_CLASSES); } virtual void TearDown() { delete mDevice; delete mFakeContext; mFakeListener.clear(); mFakePolicy.clear(); mFakeEventHub.clear(); } }; const char* InputDeviceTest::DEVICE_NAME = "device"; const int32_t InputDeviceTest::DEVICE_ID = 2; const int32_t InputDeviceTest::DEVICE_GENERATION = 2; const uint32_t InputDeviceTest::DEVICE_CLASSES = INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_JOYSTICK; TEST_F(InputDeviceTest, ImmutableProperties) { ASSERT_EQ(DEVICE_ID, mDevice->getId()); ASSERT_STREQ(DEVICE_NAME, mDevice->getName().c_str()); ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses()); } TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { // Configuration. InputReaderConfiguration config; mDevice->configure(ARBITRARY_TIME, &config, 0); // Reset. mDevice->reset(ARBITRARY_TIME); NotifyDeviceResetArgs resetArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); ASSERT_EQ(DEVICE_ID, resetArgs.deviceId); // Metadata. ASSERT_TRUE(mDevice->isIgnored()); ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mDevice->getSources()); InputDeviceInfo info; mDevice->getDeviceInfo(&info); ASSERT_EQ(DEVICE_ID, info.getId()); ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.c_str()); ASSERT_EQ(AINPUT_KEYBOARD_TYPE_NONE, info.getKeyboardType()); ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, info.getSources()); // State queries. ASSERT_EQ(0, mDevice->getMetaState()); ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_KEYBOARD, 0)) << "Ignored device should return unknown key code state."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getScanCodeState(AINPUT_SOURCE_KEYBOARD, 0)) << "Ignored device should return unknown scan code state."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 0)) << "Ignored device should return unknown switch state."; const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; uint8_t flags[2] = { 0, 1 }; ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 2, keyCodes, flags)) << "Ignored device should never mark any key codes."; ASSERT_EQ(0, flags[0]) << "Flag for unsupported key should be unchanged."; ASSERT_EQ(1, flags[1]) << "Flag for unsupported key should be unchanged."; } TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) { // Configuration. mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8("key"), String8("value")); FakeInputMapper* mapper1 = new FakeInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD); mapper1->setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC); mapper1->setMetaState(AMETA_ALT_ON); mapper1->addSupportedKeyCode(AKEYCODE_A); mapper1->addSupportedKeyCode(AKEYCODE_B); mapper1->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN); mapper1->setKeyCodeState(AKEYCODE_B, AKEY_STATE_UP); mapper1->setScanCodeState(2, AKEY_STATE_DOWN); mapper1->setScanCodeState(3, AKEY_STATE_UP); mapper1->setSwitchState(4, AKEY_STATE_DOWN); mDevice->addMapper(mapper1); FakeInputMapper* mapper2 = new FakeInputMapper(mDevice, AINPUT_SOURCE_TOUCHSCREEN); mapper2->setMetaState(AMETA_SHIFT_ON); mDevice->addMapper(mapper2); InputReaderConfiguration config; mDevice->configure(ARBITRARY_TIME, &config, 0); String8 propertyValue; ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue)) << "Device should have read configuration during configuration phase."; ASSERT_STREQ("value", propertyValue.c_str()); ASSERT_NO_FATAL_FAILURE(mapper1->assertConfigureWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2->assertConfigureWasCalled()); // Reset mDevice->reset(ARBITRARY_TIME); ASSERT_NO_FATAL_FAILURE(mapper1->assertResetWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2->assertResetWasCalled()); NotifyDeviceResetArgs resetArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); ASSERT_EQ(ARBITRARY_TIME, resetArgs.eventTime); ASSERT_EQ(DEVICE_ID, resetArgs.deviceId); // Metadata. ASSERT_FALSE(mDevice->isIgnored()); ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), mDevice->getSources()); InputDeviceInfo info; mDevice->getDeviceInfo(&info); ASSERT_EQ(DEVICE_ID, info.getId()); ASSERT_STREQ(DEVICE_NAME, info.getIdentifier().name.c_str()); ASSERT_EQ(AINPUT_KEYBOARD_TYPE_ALPHABETIC, info.getKeyboardType()); ASSERT_EQ(uint32_t(AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TOUCHSCREEN), info.getSources()); // State queries. ASSERT_EQ(AMETA_ALT_ON | AMETA_SHIFT_ON, mDevice->getMetaState()) << "Should query mappers and combine meta states."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return unknown key code state when source not supported."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getScanCodeState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return unknown scan code state when source not supported."; ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_TRACKBALL, AKEYCODE_A)) << "Should return unknown switch state when source not supported."; ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getKeyCodeState(AINPUT_SOURCE_KEYBOARD, AKEYCODE_A)) << "Should query mapper when source is supported."; ASSERT_EQ(AKEY_STATE_UP, mDevice->getScanCodeState(AINPUT_SOURCE_KEYBOARD, 3)) << "Should query mapper when source is supported."; ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 4)) << "Should query mapper when source is supported."; const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; uint8_t flags[4] = { 0, 0, 0, 1 }; ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) << "Should do nothing when source is unsupported."; ASSERT_EQ(0, flags[0]) << "Flag should be unchanged when source is unsupported."; ASSERT_EQ(0, flags[1]) << "Flag should be unchanged when source is unsupported."; ASSERT_EQ(0, flags[2]) << "Flag should be unchanged when source is unsupported."; ASSERT_EQ(1, flags[3]) << "Flag should be unchanged when source is unsupported."; ASSERT_TRUE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 4, keyCodes, flags)) << "Should query mapper when source is supported."; ASSERT_EQ(1, flags[0]) << "Flag for supported key should be set."; ASSERT_EQ(1, flags[1]) << "Flag for supported key should be set."; ASSERT_EQ(0, flags[2]) << "Flag for unsupported key should be unchanged."; ASSERT_EQ(1, flags[3]) << "Flag for unsupported key should be unchanged."; // Event handling. RawEvent event; event.type = EV_KEY; // some arbitrary event type and code event.code = KEY_A; mDevice->process(&event, 1); ASSERT_NO_FATAL_FAILURE(mapper1->assertProcessWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled()); } // --- InputMapperTest --- class InputMapperTest : public testing::Test { protected: static const char* DEVICE_NAME; static const int32_t DEVICE_ID; static const int32_t DEVICE_GENERATION; static const uint32_t DEVICE_CLASSES; sp mFakeEventHub; sp mFakePolicy; sp mFakeListener; FakeInputReaderContext* mFakeContext; InputDevice* mDevice; virtual void SetUp() { mir::report::legacy_input::initialize(std::make_shared()); mFakeEventHub = new FakeEventHub(); mFakePolicy = new FakeInputReaderPolicy(); mFakeListener = new FakeInputListener(); mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener); InputDeviceIdentifier identifier; identifier.name = DEVICE_NAME; mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION, identifier, DEVICE_CLASSES); mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0); } virtual void TearDown() { delete mDevice; delete mFakeContext; mFakeListener.clear(); mFakePolicy.clear(); mFakeEventHub.clear(); } void addConfigurationProperty(const char* key, const char* value) { mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8(key), String8(value)); } void addMapperAndConfigure(InputMapper* mapper) { mDevice->addMapper(mapper); mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0); mDevice->reset(ARBITRARY_TIME); } void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height, int32_t orientation) { mFakePolicy->setDisplayInfo(displayId, width, height, orientation); mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), InputReaderConfiguration::CHANGE_DISPLAY_INFO); } static void process(InputMapper* mapper, nsecs_t when, int32_t deviceId, int32_t type, int32_t code, int32_t value) { RawEvent event; event.when = when; event.deviceId = deviceId; event.type = type; event.code = code; event.value = value; mapper->process(&event); } static void assertMotionRange(const InputDeviceInfo& info, int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) { const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source); ASSERT_TRUE(range != NULL) << "Axis: " << axis << " Source: " << source; ASSERT_EQ(axis, range->axis) << "Axis: " << axis << " Source: " << source; ASSERT_EQ(source, range->source) << "Axis: " << axis << " Source: " << source; ASSERT_NEAR(min, range->min, EPSILON) << "Axis: " << axis << " Source: " << source; ASSERT_NEAR(max, range->max, EPSILON) << "Axis: " << axis << " Source: " << source; ASSERT_NEAR(flat, range->flat, EPSILON) << "Axis: " << axis << " Source: " << source; ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Axis: " << axis << " Source: " << source; } static void assertPointerCoords(const PointerCoords& coords, float x, float y, float pressure, float size, float touchMajor, float touchMinor, float toolMajor, float toolMinor, float orientation, float distance) { ASSERT_NEAR(x, coords.getAxisValue(AMOTION_EVENT_AXIS_X), 1); ASSERT_NEAR(y, coords.getAxisValue(AMOTION_EVENT_AXIS_Y), 1); ASSERT_NEAR(pressure, coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), EPSILON); ASSERT_NEAR(size, coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE), EPSILON); ASSERT_NEAR(touchMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), 1); ASSERT_NEAR(touchMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), 1); ASSERT_NEAR(toolMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), 1); ASSERT_NEAR(toolMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), 1); ASSERT_NEAR(orientation, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), EPSILON); ASSERT_NEAR(distance, coords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), EPSILON); } static void assertPosition(const sp& controller, float x, float y) { float actualX, actualY; controller->getPosition(&actualX, &actualY); ASSERT_NEAR(x, actualX, 1); ASSERT_NEAR(y, actualY, 1); } }; const char* InputMapperTest::DEVICE_NAME = "device"; const int32_t InputMapperTest::DEVICE_ID = 2; const int32_t InputMapperTest::DEVICE_GENERATION = 2; const uint32_t InputMapperTest::DEVICE_CLASSES = 0; // not needed for current tests // --- SwitchInputMapperTest --- class SwitchInputMapperTest : public InputMapperTest { protected: }; TEST_F(SwitchInputMapperTest, GetSources) { SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); addMapperAndConfigure(mapper); ASSERT_EQ(uint32_t(AINPUT_SOURCE_SWITCH), mapper->getSources()); } TEST_F(SwitchInputMapperTest, GetSwitchState) { SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); addMapperAndConfigure(mapper); mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 1); ASSERT_EQ(1, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); mFakeEventHub->setSwitchState(DEVICE_ID, SW_LID, 0); ASSERT_EQ(0, mapper->getSwitchState(AINPUT_SOURCE_ANY, SW_LID)); } TEST_F(SwitchInputMapperTest, Process) { SwitchInputMapper* mapper = new SwitchInputMapper(mDevice); addMapperAndConfigure(mapper); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SW, SW_LID, 1); NotifySwitchArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifySwitchWasCalled(&args)); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(SW_LID, args.switchCode); ASSERT_EQ(1, args.switchValue); ASSERT_EQ(uint32_t(0), args.policyFlags); } // --- KeyboardInputMapperTest --- class KeyboardInputMapperTest : public InputMapperTest { protected: void testDPadKeyRotation(KeyboardInputMapper* mapper, int32_t originalScanCode, int32_t rotatedKeyCode); }; void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper, int32_t originalScanCode, int32_t rotatedKeyCode) { NotifyKeyArgs args; process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(originalScanCode, args.scanCode); ASSERT_EQ(rotatedKeyCode, args.keyCode); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, originalScanCode, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(originalScanCode, args.scanCode); ASSERT_EQ(rotatedKeyCode, args.keyCode); } TEST_F(KeyboardInputMapperTest, GetSources) { KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, mapper->getSources()); } TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) { const int32_t USAGE_A = 0x070004; const int32_t USAGE_UNKNOWN = 0x07ffff; mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); mFakeEventHub->addKey(DEVICE_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE); KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); // Key down by scan code. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_HOME, 1); NotifyKeyArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(AKEYCODE_HOME, args.keyCode); ASSERT_EQ(KEY_HOME, args.scanCode); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Key up by scan code. process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, KEY_HOME, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(AKEYCODE_HOME, args.keyCode); ASSERT_EQ(KEY_HOME, args.scanCode); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Key down by usage code. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_MSC, MSC_SCAN, USAGE_A); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, 0, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(AKEYCODE_A, args.keyCode); ASSERT_EQ(0, args.scanCode); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Key up by usage code. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_MSC, MSC_SCAN, USAGE_A); process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, 0, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(AKEYCODE_A, args.keyCode); ASSERT_EQ(0, args.scanCode); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); ASSERT_EQ(POLICY_FLAG_WAKE, args.policyFlags); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Key down with unknown scan code or usage code. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_MSC, MSC_SCAN, USAGE_UNKNOWN); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UNKNOWN, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(0, args.keyCode); ASSERT_EQ(KEY_UNKNOWN, args.scanCode); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); ASSERT_EQ(0U, args.policyFlags); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Key up with unknown scan code or usage code. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_MSC, MSC_SCAN, USAGE_UNKNOWN); process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, KEY_UNKNOWN, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(0, args.keyCode); ASSERT_EQ(KEY_UNKNOWN, args.scanCode); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags); ASSERT_EQ(0U, args.policyFlags); ASSERT_EQ(ARBITRARY_TIME, args.downTime); } TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) { mFakeEventHub->addKey(DEVICE_ID, KEY_LEFTSHIFT, 0, AKEYCODE_SHIFT_LEFT, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0); KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); // Initial metastate. ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); // Metakey down. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_LEFTSHIFT, 1); NotifyKeyArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); // Key down. process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, KEY_A, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); // Key up. process(mapper, ARBITRARY_TIME + 2, DEVICE_ID, EV_KEY, KEY_A, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, mapper->getMetaState()); // Metakey up. process(mapper, ARBITRARY_TIME + 3, DEVICE_ID, EV_KEY, KEY_LEFTSHIFT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AMETA_NONE, args.metaState); ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled()); } TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateDPad) { mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT)); } TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) { mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0); KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addConfigurationProperty("keyboard.orientationAware", "1"); addMapperAndConfigure(mapper); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT)); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_LEFT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_UP)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_RIGHT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_DOWN)); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_DOWN)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_LEFT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_UP)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_RIGHT)); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_RIGHT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_DOWN)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_LEFT)); ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_UP)); // Special case: if orientation changes while key is down, we still emit the same keycode // in the key up as we did in the key down. NotifyKeyArgs args; setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(KEY_UP, args.scanCode); ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(KEY_UP, args.scanCode); ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode); } TEST_F(KeyboardInputMapperTest, GetKeyCodeState) { KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 1); ASSERT_EQ(1, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); mFakeEventHub->setKeyCodeState(DEVICE_ID, AKEYCODE_A, 0); ASSERT_EQ(0, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); } TEST_F(KeyboardInputMapperTest, GetScanCodeState) { KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 1); ASSERT_EQ(1, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); mFakeEventHub->setScanCodeState(DEVICE_ID, KEY_A, 0); ASSERT_EQ(0, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); } TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) { KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); mFakeEventHub->addKey(DEVICE_ID, KEY_A, 0, AKEYCODE_A, 0); const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; uint8_t flags[2] = { 0, 0 }; ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags)); ASSERT_TRUE(flags[0]); ASSERT_FALSE(flags[1]); } TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds) { mFakeEventHub->addLed(DEVICE_ID, LED_CAPSL, true /*initially on*/); mFakeEventHub->addLed(DEVICE_ID, LED_NUML, false /*initially off*/); mFakeEventHub->addLed(DEVICE_ID, LED_SCROLLL, false /*initially off*/); mFakeEventHub->addKey(DEVICE_ID, KEY_CAPSLOCK, 0, AKEYCODE_CAPS_LOCK, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_NUMLOCK, 0, AKEYCODE_NUM_LOCK, 0); mFakeEventHub->addKey(DEVICE_ID, KEY_SCROLLLOCK, 0, AKEYCODE_SCROLL_LOCK, 0); KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC); addMapperAndConfigure(mapper); // Initialization should have turned all of the lights off. ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); // Toggle caps lock on. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_CAPSLOCK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_CAPSLOCK, 0); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_CAPS_LOCK_ON, mapper->getMetaState()); // Toggle num lock on. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_NUMLOCK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_NUMLOCK, 0); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON, mapper->getMetaState()); // Toggle caps lock off. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_CAPSLOCK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_CAPSLOCK, 0); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_NUM_LOCK_ON, mapper->getMetaState()); // Toggle scroll lock on. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_SCROLLLOCK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_SCROLLLOCK, 0); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON, mapper->getMetaState()); // Toggle num lock off. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_NUMLOCK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_NUMLOCK, 0); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_TRUE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_SCROLL_LOCK_ON, mapper->getMetaState()); // Toggle scroll lock off. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_SCROLLLOCK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_SCROLLLOCK, 0); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_CAPSL)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_NUML)); ASSERT_FALSE(mFakeEventHub->getLedState(DEVICE_ID, LED_SCROLLL)); ASSERT_EQ(AMETA_NONE, mapper->getMetaState()); } // --- CursorInputMapperTest --- class CursorInputMapperTest : public InputMapperTest { protected: static const int32_t TRACKBALL_MOVEMENT_THRESHOLD; sp mFakePointerController; virtual void SetUp() { InputMapperTest::SetUp(); mFakePointerController = new FakePointerController(); mFakePolicy->setPointerController(DEVICE_ID, mFakePointerController); } void testMotionRotation(CursorInputMapper* mapper, int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY); }; const int32_t CursorInputMapperTest::TRACKBALL_MOVEMENT_THRESHOLD = 6; void CursorInputMapperTest::testMotionRotation(CursorInputMapper* mapper, int32_t originalX, int32_t originalY, int32_t rotatedX, int32_t rotatedY) { NotifyMotionArgs args; process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, originalX); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, originalY); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], float(rotatedX) / TRACKBALL_MOVEMENT_THRESHOLD, float(rotatedY) / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, WhenModeIsPointer_GetSources_ReturnsMouse) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources()); } TEST_F(CursorInputMapperTest, WhenModeIsNavigation_GetSources_ReturnsTrackball) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper->getSources()); } TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeFromPointerController) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); addMapperAndConfigure(mapper); InputDeviceInfo info; mapper->populateDeviceInfo(&info); // Initially there may not be a valid motion range. ASSERT_EQ(NULL, info.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_MOUSE)); ASSERT_EQ(NULL, info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_MOUSE)); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f)); // When the bounds are set, then there should be a valid motion range. mFakePointerController->setBounds(1, 2, 800 - 1, 480 - 1); InputDeviceInfo info2; mapper->populateDeviceInfo(&info2); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_MOUSE, 1, 800 - 1, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_MOUSE, 2, 480 - 1, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, WhenModeIsNavigation_PopulateDeviceInfo_ReturnsScaledRange) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); InputDeviceInfo info; mapper->populateDeviceInfo(&info); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TRACKBALL, -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD)); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TRACKBALL, -1.0f, 1.0f, 0.0f, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD)); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info, AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_TRACKBALL, 0.0f, 1.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyMotionArgs args; // Button press. // Mostly testing non x/y behavior here so we don't need to check again elsewhere. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, args.source); ASSERT_EQ(uint32_t(0), args.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(0, args.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, args.buttonState); ASSERT_EQ(0, args.edgeFlags); ASSERT_EQ(uint32_t(1), args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Button release. Should have same down time. process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_KEY, BTN_MOUSE, 0); process(mapper, ARBITRARY_TIME + 1, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(ARBITRARY_TIME + 1, args.eventTime); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, args.source); ASSERT_EQ(uint32_t(0), args.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); ASSERT_EQ(0, args.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(0, args.buttonState); ASSERT_EQ(0, args.edgeFlags); ASSERT_EQ(uint32_t(1), args.pointerCount); ASSERT_EQ(0, args.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, args.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.xPrecision); ASSERT_EQ(TRACKBALL_MOVEMENT_THRESHOLD, args.yPrecision); ASSERT_EQ(ARBITRARY_TIME, args.downTime); } TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentXYUpdates) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); NotifyMotionArgs args; // Motion in X but not Y. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); // Motion in Y but not X. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, -2); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); NotifyMotionArgs args; // Button press. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); // Button release. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); NotifyMotionArgs args; // Combined X, Y and Button. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, -2); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, -2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); // Move X, Y a bit while pressed. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 2); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 2.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f / TRACKBALL_MOVEMENT_THRESHOLD, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); // Release Button. process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MOUSE, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); } TEST_F(CursorInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addMapperAndConfigure(mapper); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); } TEST_F(CursorInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "navigation"); addConfigurationProperty("cursor.orientationAware", "1"); addMapperAndConfigure(mapper); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1)); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_90); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, -1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, 1)); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_180); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, -1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, 1, -1)); setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_270); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, -1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, -1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 0, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, -1, 1, 1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, -1, 1, 0)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, -1, 1, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 0, 0, -1)); ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, -1)); } TEST_F(CursorInputMapperTest, Process_ShouldHandleAllButtons) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); addMapperAndConfigure(mapper); mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); mFakePointerController->setPosition(100, 200); mFakePointerController->setButtonState(0); NotifyMotionArgs motionArgs; NotifyKeyArgs keyArgs; // press BTN_LEFT, release BTN_LEFT process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_LEFT, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, mFakePointerController->getButtonState()); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_LEFT, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_RIGHT, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MIDDLE, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState()); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_RIGHT, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_MIDDLE, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); // press BTN_BACK, release BTN_BACK process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_BACK, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_BACK, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); // press BTN_SIDE, release BTN_SIDE process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_SIDE, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_SIDE, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); // press BTN_FORWARD, release BTN_FORWARD process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_FORWARD, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_FORWARD, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); // press BTN_EXTRA, release BTN_EXTRA process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_EXTRA, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_EXTRA, 0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, mFakePointerController->getButtonState()); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 100.0f, 200.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); } TEST_F(CursorInputMapperTest, Process_WhenModeIsPointer_ShouldMoveThePointerAround) { CursorInputMapper* mapper = new CursorInputMapper(mDevice); addConfigurationProperty("cursor.mode", "pointer"); addMapperAndConfigure(mapper); mFakePointerController->setBounds(0, 0, 800 - 1, 480 - 1); mFakePointerController->setPosition(100, 200); mFakePointerController->setButtonState(0); NotifyMotionArgs args; process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_X, 10); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_REL, REL_Y, 20); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], 110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f)); } // --- TouchInputMapperTest --- class TouchInputMapperTest : public InputMapperTest { protected: static const int32_t RAW_X_MIN; static const int32_t RAW_X_MAX; static const int32_t RAW_Y_MIN; static const int32_t RAW_Y_MAX; static const int32_t RAW_TOUCH_MIN; static const int32_t RAW_TOUCH_MAX; static const int32_t RAW_TOOL_MIN; static const int32_t RAW_TOOL_MAX; static const int32_t RAW_PRESSURE_MIN; static const int32_t RAW_PRESSURE_MAX; static const int32_t RAW_ORIENTATION_MIN; static const int32_t RAW_ORIENTATION_MAX; static const int32_t RAW_DISTANCE_MIN; static const int32_t RAW_DISTANCE_MAX; static const int32_t RAW_TILT_MIN; static const int32_t RAW_TILT_MAX; static const int32_t RAW_ID_MIN; static const int32_t RAW_ID_MAX; static const int32_t RAW_SLOT_MIN; static const int32_t RAW_SLOT_MAX; static const float X_PRECISION; static const float Y_PRECISION; static const float GEOMETRIC_SCALE; static const VirtualKeyDefinition VIRTUAL_KEYS[2]; enum Axes { POSITION = 1 << 0, TOUCH = 1 << 1, TOOL = 1 << 2, PRESSURE = 1 << 3, ORIENTATION = 1 << 4, MINOR = 1 << 5, ID = 1 << 6, DISTANCE = 1 << 7, TILT = 1 << 8, SLOT = 1 << 9, TOOL_TYPE = 1 << 10, }; void prepareDisplay(int32_t orientation); void prepareVirtualKeys(); int32_t toRawX(float displayX); int32_t toRawY(float displayY); float toDisplayX(int32_t rawX); float toDisplayY(int32_t rawY); }; const int32_t TouchInputMapperTest::RAW_X_MIN = 25; const int32_t TouchInputMapperTest::RAW_X_MAX = 1019; const int32_t TouchInputMapperTest::RAW_Y_MIN = 30; const int32_t TouchInputMapperTest::RAW_Y_MAX = 1009; const int32_t TouchInputMapperTest::RAW_TOUCH_MIN = 0; const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31; const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0; const int32_t TouchInputMapperTest::RAW_TOOL_MAX = 15; const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = RAW_TOUCH_MIN; const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = RAW_TOUCH_MAX; const int32_t TouchInputMapperTest::RAW_ORIENTATION_MIN = -7; const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7; const int32_t TouchInputMapperTest::RAW_DISTANCE_MIN = 0; const int32_t TouchInputMapperTest::RAW_DISTANCE_MAX = 7; const int32_t TouchInputMapperTest::RAW_TILT_MIN = 0; const int32_t TouchInputMapperTest::RAW_TILT_MAX = 150; const int32_t TouchInputMapperTest::RAW_ID_MIN = 0; const int32_t TouchInputMapperTest::RAW_ID_MAX = 9; const int32_t TouchInputMapperTest::RAW_SLOT_MIN = 0; const int32_t TouchInputMapperTest::RAW_SLOT_MAX = 9; const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH; const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT; const float TouchInputMapperTest::GEOMETRIC_SCALE = avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN + 1), float(DISPLAY_HEIGHT) / (RAW_Y_MAX - RAW_Y_MIN + 1)); const VirtualKeyDefinition TouchInputMapperTest::VIRTUAL_KEYS[2] = { { KEY_HOME, 60, DISPLAY_HEIGHT + 15, 20, 20 }, { KEY_MENU, DISPLAY_HEIGHT - 60, DISPLAY_WIDTH + 15, 20, 20 }, }; void TouchInputMapperTest::prepareDisplay(int32_t orientation) { setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, orientation); } void TouchInputMapperTest::prepareVirtualKeys() { mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[0]); mFakeEventHub->addVirtualKeyDefinition(DEVICE_ID, VIRTUAL_KEYS[1]); mFakeEventHub->addKey(DEVICE_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE); mFakeEventHub->addKey(DEVICE_ID, KEY_MENU, 0, AKEYCODE_MENU, POLICY_FLAG_WAKE); } int32_t TouchInputMapperTest::toRawX(float displayX) { return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH + RAW_X_MIN); } int32_t TouchInputMapperTest::toRawY(float displayY) { return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN); } float TouchInputMapperTest::toDisplayX(int32_t rawX) { return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN + 1); } float TouchInputMapperTest::toDisplayY(int32_t rawY) { return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN + 1); } // --- SingleTouchInputMapperTest --- class SingleTouchInputMapperTest : public TouchInputMapperTest { protected: void prepareButtons(); void prepareAxes(int axes); void processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y); void processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y); void processUp(SingleTouchInputMapper* mappery); void processPressure(SingleTouchInputMapper* mapper, int32_t pressure); void processToolMajor(SingleTouchInputMapper* mapper, int32_t toolMajor); void processDistance(SingleTouchInputMapper* mapper, int32_t distance); void processTilt(SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY); void processKey(SingleTouchInputMapper* mapper, int32_t code, int32_t value); void processSync(SingleTouchInputMapper* mapper); }; void SingleTouchInputMapperTest::prepareButtons() { mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); } void SingleTouchInputMapperTest::prepareAxes(int axes) { if (axes & POSITION) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_X, RAW_X_MIN, RAW_X_MAX, 0, 0); mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0); } if (axes & PRESSURE) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_PRESSURE, RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0); } if (axes & TOOL) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TOOL_WIDTH, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); } if (axes & DISTANCE) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_DISTANCE, RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0); } if (axes & TILT) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_X, RAW_TILT_MIN, RAW_TILT_MAX, 0, 0); mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_TILT_Y, RAW_TILT_MIN, RAW_TILT_MAX, 0, 0); } } void SingleTouchInputMapperTest::processDown(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 1); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, x); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, y); } void SingleTouchInputMapperTest::processMove(SingleTouchInputMapper* mapper, int32_t x, int32_t y) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, x); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, y); } void SingleTouchInputMapperTest::processUp(SingleTouchInputMapper* mapper) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 0); } void SingleTouchInputMapperTest::processPressure( SingleTouchInputMapper* mapper, int32_t pressure) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_PRESSURE, pressure); } void SingleTouchInputMapperTest::processToolMajor( SingleTouchInputMapper* mapper, int32_t toolMajor) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TOOL_WIDTH, toolMajor); } void SingleTouchInputMapperTest::processDistance( SingleTouchInputMapper* mapper, int32_t distance) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_DISTANCE, distance); } void SingleTouchInputMapperTest::processTilt( SingleTouchInputMapper* mapper, int32_t tiltX, int32_t tiltY) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TILT_X, tiltX); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_TILT_Y, tiltY); } void SingleTouchInputMapperTest::processKey( SingleTouchInputMapper* mapper, int32_t code, int32_t value) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, code, value); } void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNotACursor_ReturnsPointer) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareButtons(); prepareAxes(POSITION); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper->getSources()); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndIsACursor_ReturnsTouchPad) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_X); mFakeEventHub->addRelativeAxis(DEVICE_ID, REL_Y); prepareButtons(); prepareAxes(POSITION); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchPad_ReturnsTouchPad) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareButtons(); prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchPad"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources()); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); prepareButtons(); prepareAxes(POSITION); addConfigurationProperty("touch.deviceType", "touchScreen"); addMapperAndConfigure(mapper); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources()); } TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); // Unknown key. ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_A)); // Virtual key is down. int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); processDown(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); // Virtual key is up. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); ASSERT_EQ(AKEY_STATE_UP, mapper->getKeyCodeState(AINPUT_SOURCE_ANY, AKEYCODE_HOME)); } TEST_F(SingleTouchInputMapperTest, GetScanCodeState) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); // Unknown key. ASSERT_EQ(AKEY_STATE_UNKNOWN, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_A)); // Virtual key is down. int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); processDown(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); ASSERT_EQ(AKEY_STATE_VIRTUAL, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); // Virtual key is up. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled()); ASSERT_EQ(AKEY_STATE_UP, mapper->getScanCodeState(AINPUT_SOURCE_ANY, KEY_HOME)); } TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); const int32_t keys[2] = { AKEYCODE_HOME, AKEYCODE_A }; uint8_t flags[2] = { 0, 0 }; ASSERT_TRUE(mapper->markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags)); ASSERT_TRUE(flags[0]); ASSERT_FALSE(flags[1]); } TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyKeyArgs args; // Press virtual key. int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); processDown(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); ASSERT_EQ(AKEYCODE_HOME, args.keyCode); ASSERT_EQ(KEY_HOME, args.scanCode); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Release virtual key. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args)); ASSERT_EQ(ARBITRARY_TIME, args.eventTime); ASSERT_EQ(DEVICE_ID, args.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source); ASSERT_EQ(POLICY_FLAG_VIRTUAL, args.policyFlags); ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, args.flags); ASSERT_EQ(AKEYCODE_HOME, args.keyCode); ASSERT_EQ(KEY_HOME, args.scanCode); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, args.metaState); ASSERT_EQ(ARBITRARY_TIME, args.downTime); // Should not have sent any motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); } TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyKeyArgs keyArgs; // Press virtual key. int32_t x = toRawX(VIRTUAL_KEYS[0].centerX); int32_t y = toRawY(VIRTUAL_KEYS[0].centerY); processDown(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(ARBITRARY_TIME, keyArgs.eventTime); ASSERT_EQ(DEVICE_ID, keyArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyArgs.source); ASSERT_EQ(POLICY_FLAG_VIRTUAL, keyArgs.policyFlags); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY, keyArgs.flags); ASSERT_EQ(AKEYCODE_HOME, keyArgs.keyCode); ASSERT_EQ(KEY_HOME, keyArgs.scanCode); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, keyArgs.metaState); ASSERT_EQ(ARBITRARY_TIME, keyArgs.downTime); // Move out of bounds. This should generate a cancel and a pointer down since we moved // into the display area. y -= 100; processMove(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(ARBITRARY_TIME, keyArgs.eventTime); ASSERT_EQ(DEVICE_ID, keyArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, keyArgs.source); ASSERT_EQ(POLICY_FLAG_VIRTUAL, keyArgs.policyFlags); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY | AKEY_EVENT_FLAG_CANCELED, keyArgs.flags); ASSERT_EQ(AKEYCODE_HOME, keyArgs.keyCode); ASSERT_EQ(KEY_HOME, keyArgs.scanCode); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, keyArgs.metaState); ASSERT_EQ(ARBITRARY_TIME, keyArgs.downTime); NotifyMotionArgs motionArgs; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_GE(motionArgs.pointerProperties[0].id, 0); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); int32_t touchId = motionArgs.pointerProperties[0].id; // Keep moving out of bounds. Should generate a pointer move. y -= 50; processMove(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(touchId, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Release out of bounds. Should generate a pointer up. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(touchId, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Should not have sent any more keys or motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyMotionArgs motionArgs; // Initially go down out of bounds. int32_t x = -10; int32_t y = -10; processDown(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); // Move into the display area. Should generate a pointer down. x = 50; y = 75; processMove(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_GE(motionArgs.pointerProperties[0].id, 0); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); int32_t touchId = motionArgs.pointerProperties[0].id; // Release. Should generate a pointer up. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(touchId, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Should not have sent any more keys or motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyMotionArgs motionArgs; // Down. int32_t x = 100; int32_t y = 125; processDown(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_GE(motionArgs.pointerProperties[0].id, 0); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); int32_t touchId = motionArgs.pointerProperties[0].id; // Move. x += 50; y += 75; processMove(mapper, x, y); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(touchId, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Up. processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(touchId, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x), toDisplayY(y), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Should not have sent any more keys or motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareButtons(); prepareAxes(POSITION); addConfigurationProperty("touch.orientationAware", "0"); addMapperAndConfigure(mapper); NotifyMotionArgs args; // Rotation 90. prepareDisplay(DISPLAY_ORIENTATION_90); processDown(mapper, toRawX(50), toRawY(75)); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); } TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareButtons(); prepareAxes(POSITION); addMapperAndConfigure(mapper); NotifyMotionArgs args; // Rotation 0. prepareDisplay(DISPLAY_ORIENTATION_0); processDown(mapper, toRawX(50), toRawY(75)); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); // Rotation 90. prepareDisplay(DISPLAY_ORIENTATION_90); processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50)); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); // Rotation 180. prepareDisplay(DISPLAY_ORIENTATION_180); processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); // Rotation 270. prepareDisplay(DISPLAY_ORIENTATION_270); processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled()); } TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE | TOOL | DISTANCE | TILT); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; int32_t rawY = 200; int32_t rawPressure = 10; int32_t rawToolMajor = 12; int32_t rawDistance = 2; int32_t rawTiltX = 30; int32_t rawTiltY = 110; float x = toDisplayX(rawX); float y = toDisplayY(rawY); float pressure = float(rawPressure) / RAW_PRESSURE_MAX; float size = float(rawToolMajor) / RAW_TOOL_MAX; float tool = float(rawToolMajor) * GEOMETRIC_SCALE; float distance = float(rawDistance); float tiltCenter = (RAW_TILT_MAX + RAW_TILT_MIN) * 0.5f; float tiltScale = M_PI / 180; float tiltXAngle = (rawTiltX - tiltCenter) * tiltScale; float tiltYAngle = (rawTiltY - tiltCenter) * tiltScale; float orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); float tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); processDown(mapper, rawX, rawY); processPressure(mapper, rawPressure); processToolMajor(mapper, rawToolMajor); processDistance(mapper, rawDistance); processTilt(mapper, rawTiltX, rawTiltY); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, pressure, size, tool, tool, tool, tool, orientation, distance)); ASSERT_EQ(tilt, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_TILT)); } TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllButtons) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; NotifyKeyArgs keyArgs; processDown(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); // press BTN_LEFT, release BTN_LEFT processKey(mapper, BTN_LEFT, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState); processKey(mapper, BTN_LEFT, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE processKey(mapper, BTN_RIGHT, 1); processKey(mapper, BTN_MIDDLE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); processKey(mapper, BTN_RIGHT, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_MIDDLE, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // press BTN_BACK, release BTN_BACK processKey(mapper, BTN_BACK, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_BACK, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); // press BTN_SIDE, release BTN_SIDE processKey(mapper, BTN_SIDE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_SIDE, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); // press BTN_FORWARD, release BTN_FORWARD processKey(mapper, BTN_FORWARD, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_FORWARD, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); // press BTN_EXTRA, release BTN_EXTRA processKey(mapper, BTN_EXTRA, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_EXTRA, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); // press BTN_STYLUS, release BTN_STYLUS processKey(mapper, BTN_STYLUS, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY, motionArgs.buttonState); processKey(mapper, BTN_STYLUS, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // press BTN_STYLUS2, release BTN_STYLUS2 processKey(mapper, BTN_STYLUS2, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); processKey(mapper, BTN_STYLUS2, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // release touch processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); } TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; // default tool type is finger processDown(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // eraser processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); // stylus processKey(mapper, BTN_TOOL_RUBBER, 0); processKey(mapper, BTN_TOOL_PEN, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // brush processKey(mapper, BTN_TOOL_PEN, 0); processKey(mapper, BTN_TOOL_BRUSH, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // pencil processKey(mapper, BTN_TOOL_BRUSH, 0); processKey(mapper, BTN_TOOL_PENCIL, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // airbrush processKey(mapper, BTN_TOOL_PENCIL, 0); processKey(mapper, BTN_TOOL_AIRBRUSH, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // mouse processKey(mapper, BTN_TOOL_AIRBRUSH, 0); processKey(mapper, BTN_TOOL_MOUSE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); // lens processKey(mapper, BTN_TOOL_MOUSE, 0); processKey(mapper, BTN_TOOL_LENS, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); // double-tap processKey(mapper, BTN_TOOL_LENS, 0); processKey(mapper, BTN_TOOL_DOUBLETAP, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // triple-tap processKey(mapper, BTN_TOOL_DOUBLETAP, 0); processKey(mapper, BTN_TOOL_TRIPLETAP, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // quad-tap processKey(mapper, BTN_TOOL_TRIPLETAP, 0); processKey(mapper, BTN_TOOL_QUADTAP, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // finger processKey(mapper, BTN_TOOL_QUADTAP, 0); processKey(mapper, BTN_TOOL_FINGER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // stylus trumps finger processKey(mapper, BTN_TOOL_PEN, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // eraser trumps stylus processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); // mouse trumps eraser processKey(mapper, BTN_TOOL_MOUSE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); // back to default tool type processKey(mapper, BTN_TOOL_MOUSE, 0); processKey(mapper, BTN_TOOL_RUBBER, 0); processKey(mapper, BTN_TOOL_PEN, 0); processKey(mapper, BTN_TOOL_FINGER, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); } TEST_F(SingleTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION); mFakeEventHub->addKey(DEVICE_ID, BTN_TOOL_FINGER, 0, AKEYCODE_UNKNOWN, 0); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; // initially hovering because BTN_TOUCH not sent yet, pressure defaults to 0 processKey(mapper, BTN_TOOL_FINGER, 1); processMove(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); // move a little processMove(mapper, 150, 250); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // down when BTN_TOUCH is pressed, pressure defaults to 1 processKey(mapper, BTN_TOUCH, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); // up when BTN_TOUCH is released, hover restored processKey(mapper, BTN_TOUCH, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // exit hover when pointer goes away processKey(mapper, BTN_TOOL_FINGER, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } TEST_F(SingleTouchInputMapperTest, Process_WhenAbsPressureIsPresent_HoversIfItsValueIsZero) { SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareButtons(); prepareAxes(POSITION | PRESSURE); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; // initially hovering because pressure is 0 processDown(mapper, 100, 200); processPressure(mapper, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); // move a little processMove(mapper, 150, 250); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // down when pressure is non-zero processPressure(mapper, RAW_PRESSURE_MAX); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); // up when pressure becomes 0, hover restored processPressure(mapper, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // exit hover when pointer goes away processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } // --- MultiTouchInputMapperTest --- class MultiTouchInputMapperTest : public TouchInputMapperTest { protected: void prepareAxes(int axes); void processPosition(MultiTouchInputMapper* mapper, int32_t x, int32_t y); void processTouchMajor(MultiTouchInputMapper* mapper, int32_t touchMajor); void processTouchMinor(MultiTouchInputMapper* mapper, int32_t touchMinor); void processToolMajor(MultiTouchInputMapper* mapper, int32_t toolMajor); void processToolMinor(MultiTouchInputMapper* mapper, int32_t toolMinor); void processOrientation(MultiTouchInputMapper* mapper, int32_t orientation); void processPressure(MultiTouchInputMapper* mapper, int32_t pressure); void processDistance(MultiTouchInputMapper* mapper, int32_t distance); void processId(MultiTouchInputMapper* mapper, int32_t id); void processSlot(MultiTouchInputMapper* mapper, int32_t slot); void processToolType(MultiTouchInputMapper* mapper, int32_t toolType); void processKey(MultiTouchInputMapper* mapper, int32_t code, int32_t value); void processMTSync(MultiTouchInputMapper* mapper); void processSync(MultiTouchInputMapper* mapper); const char *inputSourceToStr(uint32_t source) const; }; void MultiTouchInputMapperTest::prepareAxes(int axes) { if (axes & POSITION) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, 0, 0); mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, 0, 0); } if (axes & TOUCH) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0); if (axes & MINOR) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX, 0, 0); } } if (axes & TOOL) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX, 0, 0); if (axes & MINOR) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MAX, RAW_TOOL_MAX, 0, 0); } } if (axes & ORIENTATION) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_ORIENTATION, RAW_ORIENTATION_MIN, RAW_ORIENTATION_MAX, 0, 0); } if (axes & PRESSURE) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_PRESSURE, RAW_PRESSURE_MIN, RAW_PRESSURE_MAX, 0, 0); } if (axes & DISTANCE) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_DISTANCE, RAW_DISTANCE_MIN, RAW_DISTANCE_MAX, 0, 0); } if (axes & ID) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TRACKING_ID, RAW_ID_MIN, RAW_ID_MAX, 0, 0); } if (axes & SLOT) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_SLOT, RAW_SLOT_MIN, RAW_SLOT_MAX, 0, 0); mFakeEventHub->setAbsoluteAxisValue(DEVICE_ID, ABS_MT_SLOT, 0); } if (axes & TOOL_TYPE) { mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0); } } void MultiTouchInputMapperTest::processPosition( MultiTouchInputMapper* mapper, int32_t x, int32_t y) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_X, x); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_Y, y); } void MultiTouchInputMapperTest::processTouchMajor( MultiTouchInputMapper* mapper, int32_t touchMajor) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MAJOR, touchMajor); } void MultiTouchInputMapperTest::processTouchMinor( MultiTouchInputMapper* mapper, int32_t touchMinor) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MINOR, touchMinor); } void MultiTouchInputMapperTest::processToolMajor( MultiTouchInputMapper* mapper, int32_t toolMajor) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_WIDTH_MAJOR, toolMajor); } void MultiTouchInputMapperTest::processToolMinor( MultiTouchInputMapper* mapper, int32_t toolMinor) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_WIDTH_MINOR, toolMinor); } void MultiTouchInputMapperTest::processOrientation( MultiTouchInputMapper* mapper, int32_t orientation) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_ORIENTATION, orientation); } void MultiTouchInputMapperTest::processPressure( MultiTouchInputMapper* mapper, int32_t pressure) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_PRESSURE, pressure); } void MultiTouchInputMapperTest::processDistance( MultiTouchInputMapper* mapper, int32_t distance) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_DISTANCE, distance); } void MultiTouchInputMapperTest::processId( MultiTouchInputMapper* mapper, int32_t id) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TRACKING_ID, id); } void MultiTouchInputMapperTest::processSlot( MultiTouchInputMapper* mapper, int32_t slot) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_SLOT, slot); } void MultiTouchInputMapperTest::processToolType( MultiTouchInputMapper* mapper, int32_t toolType) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOOL_TYPE, toolType); } void MultiTouchInputMapperTest::processKey( MultiTouchInputMapper* mapper, int32_t code, int32_t value) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, code, value); } void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper* mapper) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_MT_REPORT, 0); } void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper* mapper) { process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0); } const char *MultiTouchInputMapperTest::inputSourceToStr(uint32_t source) const { switch (source) { case AINPUT_SOURCE_UNKNOWN: return "AINPUT_SOURCE_UNKNOWN"; case AINPUT_SOURCE_KEYBOARD: return "AINPUT_SOURCE_KEYBOARD"; case AINPUT_SOURCE_DPAD: return "AINPUT_SOURCE_DPAD"; case AINPUT_SOURCE_GAMEPAD: return "AINPUT_SOURCE_GAMEPAD"; case AINPUT_SOURCE_TOUCHSCREEN: return "AINPUT_SOURCE_TOUCHSCREEN"; case AINPUT_SOURCE_MOUSE: return "AINPUT_SOURCE_MOUSE"; case AINPUT_SOURCE_STYLUS: return "AINPUT_SOURCE_STYLUS"; case AINPUT_SOURCE_TRACKBALL: return "AINPUT_SOURCE_TRACKBALL"; case AINPUT_SOURCE_TOUCHPAD: return "AINPUT_SOURCE_TOUCHPAD"; case AINPUT_SOURCE_JOYSTICK: return "AINPUT_SOURCE_JOYSTICK"; case AINPUT_SOURCE_ANY: return "AINPUT_SOURCE_ANY"; default: return "No matching enum value!"; } } TEST_F(MultiTouchInputMapperTest, DISABLED_Process_NormalMultiTouchGesture_WithoutTrackingIds) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyMotionArgs motionArgs; // Two fingers down at once. int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; processPosition(mapper, x1, y1); processMTSync(mapper); processPosition(mapper, x2, y2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source) << "motionArgs.source=" << inputSourceToStr(motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_GE(motionArgs.pointerProperties[0].id, 0); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); int32_t touchId1 = motionArgs.pointerProperties[0].id; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(touchId1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_GT(motionArgs.pointerProperties[1].id, touchId1); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); int32_t touchId2 = motionArgs.pointerProperties[1].id; // Move. x1 += 10; y1 += 15; x2 += 5; y2 -= 10; processPosition(mapper, x1, y1); processMTSync(mapper); processPosition(mapper, x2, y2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(touchId1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(touchId2, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // First finger up. x2 += 15; y2 -= 20; processPosition(mapper, x2, y2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(touchId1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(touchId2, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(touchId2, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Move. x2 += 20; y2 -= 25; processPosition(mapper, x2, y2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(touchId2, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // New finger down. int32_t x3 = 700, y3 = 300; processPosition(mapper, x2, y2); processMTSync(mapper); processPosition(mapper, x3, y3); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(touchId2, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_GT(motionArgs.pointerProperties[1].id, touchId2); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); int32_t touchId3 = motionArgs.pointerProperties[1].id; // Second finger up. x3 += 30; y3 -= 20; processPosition(mapper, x3, y3); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(touchId2, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(touchId3, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(touchId3, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Last finger up. processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(ARBITRARY_TIME, motionArgs.eventTime); ASSERT_EQ(DEVICE_ID, motionArgs.deviceId); ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, motionArgs.source); ASSERT_EQ(uint32_t(0), motionArgs.policyFlags); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.flags); ASSERT_EQ(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON, motionArgs.metaState); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(0, motionArgs.edgeFlags); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(touchId3, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NEAR(X_PRECISION, motionArgs.xPrecision, EPSILON); ASSERT_NEAR(Y_PRECISION, motionArgs.yPrecision, EPSILON); ASSERT_EQ(ARBITRARY_TIME, motionArgs.downTime); // Should not have sent any more keys or motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyMotionArgs motionArgs; // Two fingers down at once. int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; processPosition(mapper, x1, y1); processId(mapper, 1); processMTSync(mapper); processPosition(mapper, x2, y2); processId(mapper, 2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // Move. x1 += 10; y1 += 15; x2 += 5; y2 -= 10; processPosition(mapper, x1, y1); processId(mapper, 1); processMTSync(mapper); processPosition(mapper, x2, y2); processId(mapper, 2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // First finger up. x2 += 15; y2 -= 20; processPosition(mapper, x2, y2); processId(mapper, 2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // Move. x2 += 20; y2 -= 25; processPosition(mapper, x2, y2); processId(mapper, 2); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // New finger down. int32_t x3 = 700, y3 = 300; processPosition(mapper, x2, y2); processId(mapper, 2); processMTSync(mapper); processPosition(mapper, x3, y3); processId(mapper, 3); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); // <<<<<<<<< BOOOOOOOOOOOOOOMMMM!!!!! ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(2, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); // Second finger up. x3 += 30; y3 -= 20; processPosition(mapper, x3, y3); processId(mapper, 3); processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_EQ(2, motionArgs.pointerProperties[1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(2, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); // Last finger up. processMTSync(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(2, motionArgs.pointerProperties[0].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); // Should not have sent any more keys or motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithSlots) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT); prepareVirtualKeys(); addMapperAndConfigure(mapper); mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON); NotifyMotionArgs motionArgs; // Two fingers down at once. int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500; processPosition(mapper, x1, y1); processId(mapper, 1); processSlot(mapper, 1); processPosition(mapper, x2, y2); processId(mapper, 2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); size_t index1 = 0; ASSERT_EQ(0, motionArgs.pointerProperties[index1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index1].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index1], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN, motionArgs.action & AMOTION_EVENT_ACTION_MASK); size_t index2 = motionArgs.action >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; ASSERT_LT(index2, motionArgs.pointerCount); index1 = index2 == 0 ? 1 : 0; ASSERT_EQ(0, motionArgs.pointerProperties[index1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index1].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[index2].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index2].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index1], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index2], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // Move. x1 += 10; y1 += 15; x2 += 5; y2 -= 10; processSlot(mapper, 0); processPosition(mapper, x1, y1); processSlot(mapper, 1); processPosition(mapper, x2, y2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[index1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index1].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[index2].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index2].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index1], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index2], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // First finger up. x2 += 15; y2 -= 20; processSlot(mapper, 0); processId(mapper, -1); processSlot(mapper, 1); processPosition(mapper, x2, y2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ((int32_t)(AMOTION_EVENT_ACTION_POINTER_UP | (index1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT)), motionArgs.action); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(0, motionArgs.pointerProperties[index1].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index1].toolType); ASSERT_EQ(1, motionArgs.pointerProperties[index2].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index2].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index1], toDisplayX(x1), toDisplayY(y1), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index2], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); index2 = 0; ASSERT_EQ(1, motionArgs.pointerProperties[index2].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index2].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index2], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // Move. x2 += 20; y2 -= 25; processPosition(mapper, x2, y2); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); ASSERT_EQ(1, motionArgs.pointerProperties[index2].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index2].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index2], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); // New finger down. int32_t x3 = 700, y3 = 300; processPosition(mapper, x2, y2); processSlot(mapper, 0); processId(mapper, 3); processPosition(mapper, x3, y3); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN, motionArgs.action & AMOTION_EVENT_ACTION_MASK); size_t index3 = motionArgs.action >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; ASSERT_LT(index3, motionArgs.pointerCount); index2 = index3 == 0 ? 1 : 0; ASSERT_EQ(1, motionArgs.pointerProperties[index2].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index2].toolType); ASSERT_EQ(2, motionArgs.pointerProperties[index3].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index3].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index2], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index3], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); // Second finger up. x3 += 30; y3 -= 20; processSlot(mapper, 1); processId(mapper, -1); processSlot(mapper, 0); processPosition(mapper, x3, y3); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(size_t(2), motionArgs.pointerCount); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP, motionArgs.action & AMOTION_EVENT_ACTION_MASK); index2 = motionArgs.action >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; ASSERT_LT(index2, motionArgs.pointerCount); index3 = index2 == 0 ? 1 : 0; ASSERT_EQ(1, motionArgs.pointerProperties[index2].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index2].toolType); ASSERT_EQ(2, motionArgs.pointerProperties[index3].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index3].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index2], toDisplayX(x2), toDisplayY(y2), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index3], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); index3 = 0; ASSERT_EQ(2, motionArgs.pointerProperties[index3].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index3].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index3], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); // Last finger up. processId(mapper, -1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(size_t(1), motionArgs.pointerCount); index3 = 0; ASSERT_EQ(2, motionArgs.pointerProperties[index3].id); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[index3].toolType); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[index3], toDisplayX(x3), toDisplayY(y3), 1, 0, 0, 0, 0, 0, 0, 0)); // Should not have sent any more keys or motions. ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasNotCalled()); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); } TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR | DISTANCE); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; int32_t rawY = 200; int32_t rawTouchMajor = 7; int32_t rawTouchMinor = 6; int32_t rawToolMajor = 9; int32_t rawToolMinor = 8; int32_t rawPressure = 11; int32_t rawDistance = 0; int32_t rawOrientation = 3; int32_t id = 5; float x = toDisplayX(rawX); float y = toDisplayY(rawY); float pressure = float(rawPressure) / RAW_PRESSURE_MAX; float size = avg(rawTouchMajor, rawTouchMinor) / RAW_TOUCH_MAX; float toolMajor = float(rawToolMajor) * GEOMETRIC_SCALE; float toolMinor = float(rawToolMinor) * GEOMETRIC_SCALE; float touchMajor = float(rawTouchMajor) * GEOMETRIC_SCALE; float touchMinor = float(rawTouchMinor) * GEOMETRIC_SCALE; float orientation = float(rawOrientation) / RAW_ORIENTATION_MAX * M_PI_2; float distance = float(rawDistance); processPosition(mapper, rawX, rawY); processTouchMajor(mapper, rawTouchMajor); processTouchMinor(mapper, rawTouchMinor); processToolMajor(mapper, rawToolMajor); processToolMinor(mapper, rawToolMinor); processPressure(mapper, rawPressure); processOrientation(mapper, rawOrientation); processDistance(mapper, rawDistance); processId(mapper, id); processMTSync(mapper); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(0, args.pointerProperties[0].id); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, pressure, size, touchMajor, touchMinor, toolMajor, toolMinor, orientation, distance)); } TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | TOUCH | TOOL | MINOR); addConfigurationProperty("touch.size.calibration", "geometric"); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; int32_t rawY = 200; int32_t rawTouchMajor = 140; int32_t rawTouchMinor = 120; int32_t rawToolMajor = 180; int32_t rawToolMinor = 160; float x = toDisplayX(rawX); float y = toDisplayY(rawY); float size = avg(rawTouchMajor, rawTouchMinor) / RAW_TOUCH_MAX; float toolMajor = float(rawToolMajor) * GEOMETRIC_SCALE; float toolMinor = float(rawToolMinor) * GEOMETRIC_SCALE; float touchMajor = float(rawTouchMajor) * GEOMETRIC_SCALE; float touchMinor = float(rawTouchMinor) * GEOMETRIC_SCALE; processPosition(mapper, rawX, rawY); processTouchMajor(mapper, rawTouchMajor); processTouchMinor(mapper, rawTouchMinor); processToolMajor(mapper, rawToolMajor); processToolMinor(mapper, rawToolMinor); processMTSync(mapper); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, 1.0f, size, touchMajor, touchMinor, toolMajor, toolMinor, 0, 0)); } TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_SummedLinearCalibration) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | TOUCH | TOOL); addConfigurationProperty("touch.size.calibration", "diameter"); addConfigurationProperty("touch.size.scale", "10"); addConfigurationProperty("touch.size.bias", "160"); addConfigurationProperty("touch.size.isSummed", "1"); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. // Note: We only provide a single common touch/tool value because the device is assumed // not to emit separate values for each pointer (isSummed = 1). int32_t rawX = 100; int32_t rawY = 200; int32_t rawX2 = 150; int32_t rawY2 = 250; int32_t rawTouchMajor = 5; int32_t rawToolMajor = 8; float x = toDisplayX(rawX); float y = toDisplayY(rawY); float x2 = toDisplayX(rawX2); float y2 = toDisplayY(rawY2); float size = float(rawTouchMajor) / 2 / RAW_TOUCH_MAX; float touch = float(rawTouchMajor) / 2 * 10.0f + 160.0f; float tool = float(rawToolMajor) / 2 * 10.0f + 160.0f; processPosition(mapper, rawX, rawY); processTouchMajor(mapper, rawTouchMajor); processToolMajor(mapper, rawToolMajor); processMTSync(mapper); processPosition(mapper, rawX2, rawY2); processTouchMajor(mapper, rawTouchMajor); processToolMajor(mapper, rawToolMajor); processMTSync(mapper); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), args.action); ASSERT_EQ(size_t(2), args.pointerCount); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, 1.0f, size, touch, touch, tool, tool, 0, 0)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[1], x2, y2, 1.0f, size, touch, touch, tool, tool, 0, 0)); } TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_AreaCalibration) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | TOUCH | TOOL); addConfigurationProperty("touch.size.calibration", "area"); addConfigurationProperty("touch.size.scale", "43"); addConfigurationProperty("touch.size.bias", "3"); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; int32_t rawY = 200; int32_t rawTouchMajor = 5; int32_t rawToolMajor = 8; float x = toDisplayX(rawX); float y = toDisplayY(rawY); float size = float(rawTouchMajor) / RAW_TOUCH_MAX; float touch = sqrtf(rawTouchMajor) * 43.0f + 3.0f; float tool = sqrtf(rawToolMajor) * 43.0f + 3.0f; processPosition(mapper, rawX, rawY); processTouchMajor(mapper, rawTouchMajor); processToolMajor(mapper, rawToolMajor); processMTSync(mapper); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, 1.0f, size, touch, touch, tool, tool, 0, 0)); } TEST_F(MultiTouchInputMapperTest, Process_PressureAxis_AmplitudeCalibration) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | PRESSURE); addConfigurationProperty("touch.pressure.calibration", "amplitude"); addConfigurationProperty("touch.pressure.scale", "0.01"); addMapperAndConfigure(mapper); // These calculations are based on the input device calibration documentation. int32_t rawX = 100; int32_t rawY = 200; int32_t rawPressure = 60; float x = toDisplayX(rawX); float y = toDisplayY(rawY); float pressure = float(rawPressure) * 0.01f; processPosition(mapper, rawX, rawY); processPressure(mapper, rawPressure); processMTSync(mapper); processSync(mapper); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0], x, y, pressure, 0, 0, 0, 0, 0, 0, 0)); } TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllButtons) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; NotifyKeyArgs keyArgs; processId(mapper, 1); processPosition(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); // press BTN_LEFT, release BTN_LEFT processKey(mapper, BTN_LEFT, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_PRIMARY, motionArgs.buttonState); processKey(mapper, BTN_LEFT, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // press BTN_RIGHT + BTN_MIDDLE, release BTN_RIGHT, release BTN_MIDDLE processKey(mapper, BTN_RIGHT, 1); processKey(mapper, BTN_MIDDLE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); processKey(mapper, BTN_RIGHT, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_MIDDLE, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // press BTN_BACK, release BTN_BACK processKey(mapper, BTN_BACK, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_BACK, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); // press BTN_SIDE, release BTN_SIDE processKey(mapper, BTN_SIDE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_BACK, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_SIDE, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_BACK, keyArgs.keyCode); // press BTN_FORWARD, release BTN_FORWARD processKey(mapper, BTN_FORWARD, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_FORWARD, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); // press BTN_EXTRA, release BTN_EXTRA processKey(mapper, BTN_EXTRA, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_BUTTON_FORWARD, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); processKey(mapper, BTN_EXTRA, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&keyArgs)); ASSERT_EQ(AKEY_EVENT_ACTION_UP, keyArgs.action); ASSERT_EQ(AKEYCODE_FORWARD, keyArgs.keyCode); // press BTN_STYLUS, release BTN_STYLUS processKey(mapper, BTN_STYLUS, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_SECONDARY, motionArgs.buttonState); processKey(mapper, BTN_STYLUS, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // press BTN_STYLUS2, release BTN_STYLUS2 processKey(mapper, BTN_STYLUS2, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_BUTTON_TERTIARY, motionArgs.buttonState); processKey(mapper, BTN_STYLUS2, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(0, motionArgs.buttonState); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); // release touch processId(mapper, -1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_EQ(0, motionArgs.buttonState); } TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT | TOOL_TYPE); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; // default tool type is finger processId(mapper, 1); processPosition(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // eraser processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); // stylus processKey(mapper, BTN_TOOL_RUBBER, 0); processKey(mapper, BTN_TOOL_PEN, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // brush processKey(mapper, BTN_TOOL_PEN, 0); processKey(mapper, BTN_TOOL_BRUSH, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // pencil processKey(mapper, BTN_TOOL_BRUSH, 0); processKey(mapper, BTN_TOOL_PENCIL, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // airbrush processKey(mapper, BTN_TOOL_PENCIL, 0); processKey(mapper, BTN_TOOL_AIRBRUSH, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // mouse processKey(mapper, BTN_TOOL_AIRBRUSH, 0); processKey(mapper, BTN_TOOL_MOUSE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); // lens processKey(mapper, BTN_TOOL_MOUSE, 0); processKey(mapper, BTN_TOOL_LENS, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); // double-tap processKey(mapper, BTN_TOOL_LENS, 0); processKey(mapper, BTN_TOOL_DOUBLETAP, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // triple-tap processKey(mapper, BTN_TOOL_DOUBLETAP, 0); processKey(mapper, BTN_TOOL_TRIPLETAP, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // quad-tap processKey(mapper, BTN_TOOL_TRIPLETAP, 0); processKey(mapper, BTN_TOOL_QUADTAP, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // finger processKey(mapper, BTN_TOOL_QUADTAP, 0); processKey(mapper, BTN_TOOL_FINGER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // stylus trumps finger processKey(mapper, BTN_TOOL_PEN, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // eraser trumps stylus processKey(mapper, BTN_TOOL_RUBBER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_ERASER, motionArgs.pointerProperties[0].toolType); // mouse trumps eraser processKey(mapper, BTN_TOOL_MOUSE, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); // MT tool type trumps BTN tool types: MT_TOOL_FINGER processToolType(mapper, MT_TOOL_FINGER); // this is the first time we send MT_TOOL_TYPE processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); // MT tool type trumps BTN tool types: MT_TOOL_PEN processToolType(mapper, MT_TOOL_PEN); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_STYLUS, motionArgs.pointerProperties[0].toolType); // back to default tool type processToolType(mapper, -1); // use a deliberately undefined tool type, for testing processKey(mapper, BTN_TOOL_MOUSE, 0); processKey(mapper, BTN_TOOL_RUBBER, 0); processKey(mapper, BTN_TOOL_PEN, 0); processKey(mapper, BTN_TOOL_FINGER, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); } TEST_F(MultiTouchInputMapperTest, Process_WhenBtnTouchPresent_HoversIfItsValueIsZero) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT); mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; // initially hovering because BTN_TOUCH not sent yet, pressure defaults to 0 processId(mapper, 1); processPosition(mapper, 100, 200); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); // move a little processPosition(mapper, 150, 250); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // down when BTN_TOUCH is pressed, pressure defaults to 1 processKey(mapper, BTN_TOUCH, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); // up when BTN_TOUCH is released, hover restored processKey(mapper, BTN_TOUCH, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // exit hover when pointer goes away processId(mapper, -1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } TEST_F(MultiTouchInputMapperTest, Process_WhenAbsMTPressureIsPresent_HoversIfItsValueIsZero) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); prepareDisplay(DISPLAY_ORIENTATION_0); prepareAxes(POSITION | ID | SLOT | PRESSURE); addMapperAndConfigure(mapper); NotifyMotionArgs motionArgs; // initially hovering because pressure is 0 processId(mapper, 1); processPosition(mapper, 100, 200); processPressure(mapper, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(100), toDisplayY(200), 0, 0, 0, 0, 0, 0, 0, 0)); // move a little processPosition(mapper, 150, 250); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // down when pressure becomes non-zero processPressure(mapper, RAW_PRESSURE_MAX); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); // up when pressure becomes 0, hover restored processPressure(mapper, 0); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 1, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_ENTER, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); // exit hover when pointer goes away processId(mapper, -1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_EXIT, motionArgs.action); ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0)); } /* Just checks that no crash occurs, as it used to before a bug got fixed. NB: Data taken from an actual run on a laptop with a N-Trig touchscreen. */ TEST_F(MultiTouchInputMapperTest, Process_QuickTwoFingerTap_WithoutTrackingIds) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); addConfigurationProperty("device.internal", "1"); setDisplayInfoAndReconfigure(DISPLAY_ID, 1024, 768, DISPLAY_ORIENTATION_0); mFakeEventHub->addKey(DEVICE_ID, BTN_TOUCH, 0, AKEYCODE_UNKNOWN, 0); mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_X, 0, 9600, 0, 0, 28); mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_POSITION_Y, 0, 7200, 0, 0, 37); mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MAJOR, 0, 9600, 0, 0, 50); mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_TOUCH_MINOR, 0, 7200, 0, 0, 37); mFakeEventHub->addAbsoluteAxis(DEVICE_ID, ABS_MT_ORIENTATION, 0, 1, 0, 0, 0); addMapperAndConfigure(mapper); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_X, 0x0000176d); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_Y, 0x00000ca8); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_ORIENTATION, 0x00000000); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MAJOR, 0x00000140); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MINOR, 0x00000100); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_MT_REPORT, 0x00000000); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0x00000000); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_X, 0x00001663); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_Y, 0x00000f8e); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_X, 0x00001663); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_Y, 0x00000f8e); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_ORIENTATION, 0x00000000); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MAJOR, 0x000001e0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MINOR, 0x00000100); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_MT_REPORT, 0x00000000); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_X, 0x00001786); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_Y, 0x00000c80); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_ORIENTATION, 0x00000001); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MAJOR, 0x00000180); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TOUCH_MINOR, 0x000000a0); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_MT_REPORT, 0x00000000); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOOL_DOUBLETAP, 0x00000001); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, BTN_TOUCH, 0x00000001); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0x00000000); } // Regression test for LP#1238417: // https://bugs.launchpad.net/mir/+bug/1238417 // // Don't assume that ABS_MT_PRESSURE is 0 if you haven't heard from it yet. Instead, // the pressure axis should be considered as absent. // If a touch point has always the same positive, non-zero, pressure, that value // will be informed only once, on its first event. But if mir wasn't running at // that time, it would consider the pressure to be zero and therefore the point to be // hovering, which is wrong. TEST_F(MultiTouchInputMapperTest, Process_IgnorePressureAxisIfValueUnknown) { MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice); addConfigurationProperty("touch.deviceType", "touchScreen"); addConfigurationProperty("device.internal", "1"); setDisplayInfoAndReconfigure(DISPLAY_ID, 1024, 768, DISPLAY_ORIENTATION_0); prepareAxes(POSITION | PRESSURE | ID); addMapperAndConfigure(mapper); // Note that there's no ABS_MT_PRESSURE process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_TRACKING_ID, 0x00000018); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_X, 500); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_ABS, ABS_MT_POSITION_Y, 300); process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_SYN, SYN_REPORT, 0x00000000); NotifyMotionArgs args; ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); // Would be AMOTION_EVENT_ACTION_HOVER_ENTER if pressure value was assumed to be 0 (zero), // which is de default value when the accumulator is cleared. ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); } } // namespace android mir-0.1.8+14.04.20140411/tests/unit-tests/android_input/test_eventhub.cpp0000644000015301777760000001077312322054247026415 0ustar pbusernogroup00000000000000/* * 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 */ #include #include "src/server/report/null_report_factory.h" #include #include "mir_test_framework/udev_environment.h" #include #include namespace mi = mir::input; class EventHubDeviceEnumerationTest : public ::testing::TestWithParam { // Don't actually need any shared state at the moment }; TEST_P(EventHubDeviceEnumerationTest, ScansOnConstruction) { mir::mir_test_framework::UdevEnvironment env; env.add_standard_device(GetParam()); auto hub = android::sp{new android::EventHub{mir::report::null_input_report()}}; android::RawEvent buffer[10]; memset(buffer, 0, sizeof(buffer)); auto num_events = hub->getEvents(0, buffer, 10); EXPECT_EQ(static_cast(3), num_events); EXPECT_EQ(android::EventHub::DEVICE_ADDED, buffer[0].type); EXPECT_EQ(android::VIRTUAL_KEYBOARD_ID, buffer[0].deviceId); EXPECT_EQ(android::EventHub::DEVICE_ADDED, buffer[1].type); EXPECT_EQ(1, buffer[1].deviceId); EXPECT_EQ(android::EventHub::FINISHED_DEVICE_SCAN, buffer[2].type); } TEST_P(EventHubDeviceEnumerationTest, GeneratesDeviceAddedOnHotplug) { mir::mir_test_framework::UdevEnvironment env; auto hub = android::sp{new android::EventHub{mir::report::null_input_report()}}; android::RawEvent buffer[10]; memset(buffer, 0, sizeof(buffer)); auto num_events = hub->getEvents(0, buffer, 10); EXPECT_EQ(static_cast(2), num_events); EXPECT_EQ(android::EventHub::DEVICE_ADDED, buffer[0].type); EXPECT_EQ(android::VIRTUAL_KEYBOARD_ID, buffer[0].deviceId); EXPECT_EQ(android::EventHub::FINISHED_DEVICE_SCAN, buffer[1].type); env.add_standard_device(GetParam()); memset(buffer, 0, sizeof(buffer)); num_events = hub->getEvents(0, buffer, 10); EXPECT_EQ(static_cast(2), num_events); EXPECT_EQ(android::EventHub::DEVICE_ADDED, buffer[0].type); EXPECT_EQ(1, buffer[0].deviceId); EXPECT_EQ(android::EventHub::FINISHED_DEVICE_SCAN, buffer[1].type); } TEST_P(EventHubDeviceEnumerationTest, GeneratesDeviceRemovedOnHotunplug) { mir::mir_test_framework::UdevEnvironment env; env.add_standard_device(GetParam()); auto hub = android::sp{new android::EventHub{mir::report::null_input_report()}}; android::RawEvent buffer[10]; // Flush out initial events. auto num_events = hub->getEvents(0, buffer, 10); mir::udev::Enumerator devices{std::make_shared()}; devices.scan_devices(); for (auto& device : devices) { /* * Remove just the device providing dev/input/event* * If we remove more, it's possible that we'll remove the parent of the * /dev/input device, and umockdev will not generate a remove event * in that case. */ if (device.devnode() && (std::string(device.devnode()).find("input/event") != std::string::npos)) { env.remove_device((std::string("/sys") + device.devpath()).c_str()); } } memset(buffer, 0, sizeof(buffer)); num_events = hub->getEvents(0, buffer, 10); EXPECT_EQ(static_cast(2), num_events); EXPECT_EQ(android::EventHub::DEVICE_REMOVED, buffer[0].type); EXPECT_EQ(1, buffer[0].deviceId); EXPECT_EQ(android::EventHub::FINISHED_DEVICE_SCAN, buffer[1].type); } INSTANTIATE_TEST_CASE_P(VariousDevices, EventHubDeviceEnumerationTest, ::testing::Values(std::string("synaptics-touchpad"), std::string("usb-keyboard"), std::string("usb-mouse"), std::string("laptop-keyboard"), std::string("bluetooth-magic-trackpad"))); mir-0.1.8+14.04.20140411/tests/unit-tests/android_input/sha1.cpp0000644000015301777760000000355512322054223024364 0ustar pbusernogroup00000000000000/* * 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 */ #include "EventHub.h" #include #include using namespace android; namespace { char const* const test_text = R"(Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus luctus, nulla in iaculis scelerisque, ipsum elit varius neque, nec dapibus magna ligula vitae sem. Aenean auctor porttitor augue, vitae molestie eros tristique id. Nullam eget nibh nisi, a laoreet dolor. Pellentesque nulla neque, ultrices nec mollis eget, venenatis ac diam. Phasellus egestas ultrices facilisis. Cras a nulla at purus facilisis varius. Fusce posuere cursus libero sed pellentesque. In fringilla nibh ut sapien fermentum gravida. Nam ipsum mauris, euismod non malesuada eu, posuere ac neque. Cras volutpat, lacus in ultricies auctor, est neque gravida ante, quis cursus ante nisl vitae massa. Fusce facilisis elementum ante non vestibulum. In id ullamcorper nunc. Vivamus quis blandit turpis. Nullam nec metus massa. Cras ultrices molestie eleifend. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.)"; } TEST(AndroidSha1, test) { EXPECT_STREQ("aa74e4cdc9b384c5e30df0d3ea3cd1121a854ef7", c_str(detail::sha1(String8(test_text)))); } mir-0.1.8+14.04.20140411/tests/unit-tests/android_input/string8.cpp0000644000015301777760000000233412322054223025120 0ustar pbusernogroup00000000000000/* * 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 */ #include #include #include using namespace android; TEST(AndroidString8, appendFormat) { String8 string; EXPECT_STREQ("", c_str(string)); appendFormat(string, "%s", "Hello"); EXPECT_STREQ("Hello", c_str(string)); u_char digits = 0x12; appendFormat(string, "%02x", digits); EXPECT_STREQ("Hello12", c_str(string)); } TEST(AndroidString8, formatString8) { auto string = formatString8("Hello %s #%02x", "world", 0x42); EXPECT_STREQ("Hello world #42", c_str(string)); } mir-0.1.8+14.04.20140411/tests/unit-tests/android_input/sorted_vector.cpp0000644000015301777760000001250012322054223026400 0ustar pbusernogroup00000000000000/* * 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 */ #include #include #include namespace { struct AndroidInputSortedVector : public ::testing::Test { android::SortedVector test_vector; void SetUp() { test_vector.clear(); } }; } TEST_F(AndroidInputSortedVector, empty_vector_isEmpty) { EXPECT_TRUE(test_vector.isEmpty()); } TEST_F(AndroidInputSortedVector, non_empty_vector_not_isEmpty) { test_vector.add(1); EXPECT_FALSE(test_vector.isEmpty()); } TEST_F(AndroidInputSortedVector, items_found_at_expected_indexes) { test_vector.add(3); test_vector.add(1); test_vector.add(2); test_vector.add(0); EXPECT_EQ(0, test_vector.indexOf(0)); EXPECT_EQ(1, test_vector.indexOf(1)); EXPECT_EQ(2, test_vector.indexOf(2)); EXPECT_EQ(3, test_vector.indexOf(3)); EXPECT_EQ(android::NAME_NOT_FOUND, test_vector.indexOf(4)); } TEST_F(AndroidInputSortedVector, duplicate_adds_create_single_entry) { test_vector.add(3); test_vector.add(1); test_vector.add(2); test_vector.add(0); test_vector.add(3); test_vector.add(1); test_vector.add(2); test_vector.add(0); EXPECT_EQ(0, test_vector.indexOf(0)); EXPECT_EQ(1, test_vector.indexOf(1)); EXPECT_EQ(2, test_vector.indexOf(2)); EXPECT_EQ(3, test_vector.indexOf(3)); EXPECT_EQ(4u, test_vector.size()); EXPECT_EQ(android::NAME_NOT_FOUND, test_vector.indexOf(4)); } TEST_F(AndroidInputSortedVector, adds_returns_correct_index) { EXPECT_EQ(0, test_vector.add(3)); EXPECT_EQ(0, test_vector.add(1)); EXPECT_EQ(1, test_vector.add(2)); EXPECT_EQ(0, test_vector.add(0)); EXPECT_EQ(3, test_vector.add(3)); EXPECT_EQ(1, test_vector.add(1)); EXPECT_EQ(2, test_vector.add(2)); EXPECT_EQ(0, test_vector.add(0)); } TEST_F(AndroidInputSortedVector, missing_items_are_not_found) { test_vector.add(3); test_vector.add(1); test_vector.add(2); test_vector.add(0); EXPECT_EQ(android::NAME_NOT_FOUND, test_vector.indexOf(4)); } TEST_F(AndroidInputSortedVector, index_gets_expected_items) { test_vector.add(30); test_vector.add(10); test_vector.add(20); test_vector.add(00); EXPECT_EQ(00, test_vector.itemAt(0)); EXPECT_EQ(10, test_vector.itemAt(1)); EXPECT_EQ(20, test_vector.itemAt(2)); EXPECT_EQ(30, test_vector.itemAt(3)); } TEST_F(AndroidInputSortedVector, edit_changes_item) { test_vector.add(30); test_vector.add(10); test_vector.add(20); test_vector.add(00); ASSERT_EQ(10, test_vector.itemAt(1)); test_vector.editItemAt(1) = 12; EXPECT_EQ(12, test_vector.itemAt(1)); } TEST_F(AndroidInputSortedVector, removed_items_are_not_found) { test_vector.add(3); test_vector.add(1); test_vector.add(2); test_vector.add(0); auto const old_index = test_vector.remove(1); EXPECT_EQ(1, old_index); EXPECT_EQ(android::NAME_NOT_FOUND, test_vector.indexOf(1)); } TEST_F(AndroidInputSortedVector, remove_unknown_items_is_noop) { test_vector.add(3); test_vector.add(2); test_vector.add(0); EXPECT_EQ(android::NAME_NOT_FOUND, test_vector.remove(1)); EXPECT_EQ(3u, test_vector.size()); } TEST_F(AndroidInputSortedVector, item_at_removed_index_are_not_found) { test_vector.add(30); test_vector.add(10); test_vector.add(20); test_vector.add(00); ASSERT_EQ(10, test_vector.itemAt(1)); auto const old_index = test_vector.removeItemsAt(1); EXPECT_EQ(1, old_index); EXPECT_EQ(android::NAME_NOT_FOUND, test_vector.indexOf(10)); } TEST_F(AndroidInputSortedVector, count_items_at_removed_index_are_not_found) { test_vector.add(30); test_vector.add(10); test_vector.add(20); test_vector.add(00); ASSERT_EQ(10, test_vector.itemAt(1)); auto const old_index = test_vector.removeItemsAt(1, 2); EXPECT_EQ(1, old_index); EXPECT_EQ(android::NAME_NOT_FOUND, test_vector.indexOf(10)); EXPECT_EQ(android::NAME_NOT_FOUND, test_vector.indexOf(20)); EXPECT_NE(android::NAME_NOT_FOUND, test_vector.indexOf(00)); EXPECT_NE(android::NAME_NOT_FOUND, test_vector.indexOf(30)); } // Android utils use ALOG_ASSERT - which tends to bomb the program TEST_F(AndroidInputSortedVector, remove_beyond_end_fails) { test_vector.add(30); test_vector.add(10); test_vector.add(20); test_vector.add(00); EXPECT_EQ(android::BAD_VALUE, test_vector.removeItemsAt(4, 1)); EXPECT_EQ(android::BAD_VALUE, test_vector.removeItemsAt(3, 2)); EXPECT_EQ(android::BAD_VALUE, test_vector.removeItemsAt(2, 3)); EXPECT_EQ(android::BAD_VALUE, test_vector.removeItemsAt(1, 4)); EXPECT_EQ(android::BAD_VALUE, test_vector.removeItemsAt(0, 5)); EXPECT_EQ(4u, test_vector.size()); } mir-0.1.8+14.04.20140411/tests/unit-tests/android_input/property_map.cpp0000644000015301777760000000636512322054223026253 0ustar pbusernogroup00000000000000/* * 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 */ #include #include #include #include using namespace android; namespace { static char const* test_file = "AndroidInputPropertyMap.ini"; struct AndroidInputPropertyMap : public ::testing::Test { PropertyMap* test_map; static void SetUpTestCase() { ASSERT_TRUE(std::ofstream(test_file) << "test.string=a_string\n" "#test.bool.true=true\n" "test.bool.true=1\n" "test.bool.false=0\n" "#test.bool.true=true\n" "# a comment\n" "#test.int.ignored=1\n" "test.int_32=123\n" "test.float=0.5\n"); } void SetUp() { ASSERT_EQ(NO_ERROR, PropertyMap::load(String8(test_file), &test_map)); } void TearDown() { delete test_map; } }; } TEST_F(AndroidInputPropertyMap, test_map_created) { EXPECT_TRUE(test_map); } TEST_F(AndroidInputPropertyMap, test_map_has_a_string) { String8 result; EXPECT_TRUE(test_map->tryGetProperty(String8("test.string"), result)); EXPECT_EQ(String8("a_string"), result); } TEST_F(AndroidInputPropertyMap, test_map_has_an_int32_t) { int32_t result; EXPECT_TRUE(test_map->tryGetProperty(String8("test.int_32"), result)); EXPECT_EQ(123, result); } TEST_F(AndroidInputPropertyMap, test_map_has_bools_true_and_false) { bool result{}; EXPECT_TRUE(test_map->tryGetProperty(String8("test.bool.true"), result)); EXPECT_TRUE(result); EXPECT_TRUE(test_map->tryGetProperty(String8("test.bool.false"), result)); EXPECT_FALSE(result); } TEST_F(AndroidInputPropertyMap, test_map_has_a_float) { float result; EXPECT_TRUE(test_map->tryGetProperty(String8("test.float"), result)); EXPECT_EQ(0.5, result); } TEST_F(AndroidInputPropertyMap, test_map_fails_to_get_unknown_string) { String8 result; EXPECT_FALSE(test_map->tryGetProperty(String8("unknown"), result)); } TEST_F(AndroidInputPropertyMap, test_map_fails_to_get_unknown_bool) { bool result{}; EXPECT_FALSE(test_map->tryGetProperty(String8("unknown"), result)); } TEST_F(AndroidInputPropertyMap, test_map_fails_to_get_unknown_int32_t) { int32_t result; EXPECT_FALSE(test_map->tryGetProperty(String8("unknown"), result)); } TEST_F(AndroidInputPropertyMap, test_map_fails_to_get_unknown_float) { float result; EXPECT_FALSE(test_map->tryGetProperty(String8("unknown"), result)); } TEST_F(AndroidInputPropertyMap, test_map_ignores_comment) { int32_t result; EXPECT_FALSE(test_map->tryGetProperty(String8("test.int.ignored"), result)); } mir-0.1.8+14.04.20140411/tests/unit-tests/android_input/int_set.cpp0000644000015301777760000000600612322054223025167 0ustar pbusernogroup00000000000000/* * 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 d'Andrada */ // Need a different implementation of IntSet with ANDROID_INPUT_INTSET_TEST // defined. It will fall under test::android namespace instead of in android // to avoid clashing with the production IntSet from libmirserver #define ANDROID_INPUT_INTSET_TEST #include #include int test::android::IntSet::constructionCount; int test::android::IntSet::destructionCount; #include #include #include using std::vector; using std::string; namespace { struct AndroidInputIntSet : public ::testing::Test { void SetUp() { } }; } TEST_F(AndroidInputIntSet, difference) { IntSet a = {1, 2, 3, 6}; IntSet b = { 2, 3, 4, 5}; IntSet c = a - b; IntSet expected_c = {1, 6}; EXPECT_EQ(expected_c, c); } TEST_F(AndroidInputIntSet, intersection) { IntSet a = {1, 2, 3}; IntSet b = { 2, 3, 4, 5}; IntSet c = a & b; IntSet expected_c = {2, 3}; EXPECT_EQ(expected_c, c); } TEST_F(AndroidInputIntSet, first) { IntSet a = {4, 2, 1, 3}; EXPECT_EQ(1, a.first()); } TEST_F(AndroidInputIntSet, remove_set) { IntSet a = {1, 2, 3, 4}; IntSet b = { 2, 3, 5}; a.remove(b); IntSet expected_a = {1, 4}; EXPECT_EQ(expected_a, a); } TEST_F(AndroidInputIntSet, index_of) { IntSet a = {5, 6, 10, 15}; EXPECT_EQ(1u, a.indexOf(6)); EXPECT_EQ(2u, a.indexOf(10)); } TEST_F(AndroidInputIntSet, for_each) { IntSet a = {5, 6, 10, 15}; std::vector expected_values = {5, 6, 10, 15}; std::vector actual_values; a.forEach([&](int32_t value) { actual_values.push_back(value); }); EXPECT_EQ(expected_values, actual_values); } TEST_F(AndroidInputIntSet, to_string) { IntSet a = {1, 2, 3}; string expected_str = "1, 2, 3"; EXPECT_EQ(expected_str, a.toString()); } TEST_F(AndroidInputIntSet, unnecessary_constructions) { IntSet a = {1, 2, 3, 6}; IntSet b = { 2, 3, 4, 5}; IntSet::constructionCount = 0; IntSet::destructionCount = 0; { IntSet c = a - b; } EXPECT_EQ(1, IntSet::constructionCount); EXPECT_EQ(1, IntSet::destructionCount); IntSet::constructionCount = 0; IntSet::destructionCount = 0; { IntSet c = a & b; } EXPECT_EQ(1, IntSet::constructionCount); EXPECT_EQ(1, IntSet::destructionCount); } mir-0.1.8+14.04.20140411/tests/unit-tests/android_input/CMakeLists.txt0000644000015301777760000000063212322054247025563 0ustar pbusernogroup00000000000000list(APPEND UNIT_TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/input_reader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/int_set.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sorted_vector.cpp ${CMAKE_CURRENT_SOURCE_DIR}/property_map.cpp ${CMAKE_CURRENT_SOURCE_DIR}/string8.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sha1.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_eventhub.cpp ) set( UNIT_TEST_SOURCES ${UNIT_TEST_SOURCES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/tests/CMakeLists.txt0000644000015301777760000000313012322054247020601 0ustar pbusernogroup00000000000000pkg_check_modules(UMOCKDEV REQUIRED umockdev-1.0>=0.6) if (NOT UMOCKDEV_FOUND) message(FATAL_ERROR "Umockdev not found, cannot build without disabling tests (via MIR_ENABLE_TESTS).") endif() include_directories(${MIR_3RD_PARTY_INCLUDE_DIRECTORIES}) include_directories(${MIR_ANDROID_INCLUDE_DIRECTORIES}) if ("${CMAKE_CXX_COMPILER}" MATCHES "clang") # Avoid clang complaints about poor quality gmock/gtest headers set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=null-dereference") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=overloaded-virtual") endif() if (MIR_TEST_PLATFORM STREQUAL "android") #avoid complaints about poor quality android headers include_directories(SYSTEM ${LIBHARDWARE_INCLUDE_DIRS}) add_definitions(-DANDROID) endif() include_directories( ${PROJECT_SOURCE_DIR}/include/platform ${PROJECT_SOURCE_DIR}/include/server ${PROJECT_SOURCE_DIR}/include/client ${PROJECT_SOURCE_DIR}/include/test) option(MIR_BUILD_ACCEPTANCE_TESTS "Build acceptance tests" ON) option(MIR_BUILD_INTEGRATION_TESTS "Build integration tests" ON) option(MIR_BUILD_UNIT_TESTS "Build unit tests" ON) if (MIR_BUILD_ACCEPTANCE_TESTS) add_subdirectory(acceptance-tests/) endif (MIR_BUILD_ACCEPTANCE_TESTS) if (MIR_BUILD_INTEGRATION_TESTS) add_subdirectory(integration-tests/) endif (MIR_BUILD_INTEGRATION_TESTS) if (MIR_BUILD_UNIT_TESTS) add_subdirectory(unit-tests/) endif (MIR_BUILD_UNIT_TESTS) add_subdirectory(mir_test/) add_subdirectory(mir_test_framework/) add_subdirectory(mir_test_doubles/) add_subdirectory(client-language/) add_subdirectory(mir-stress/) mir_add_memcheck_test() mir-0.1.8+14.04.20140411/tests/mir_test_framework/0000755000015301777760000000000012322054703021744 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/mir_test_framework/testing_process_manager.cpp0000644000015301777760000001337612322054223027364 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/client_types.h" #include "mir_test_framework/testing_process_manager.h" #include "mir_test_framework/detect_server.h" #include "mir_test_framework/using_stub_client_platform.h" #include "src/client/mir_connection.h" #include "mir/run_mir.h" #include #include #include #include namespace mo = mir::options; namespace mc = mir::compositor; namespace mtf = mir_test_framework; mtf::TestingProcessManager::TestingProcessManager() : is_test_process(true), server_process_was_started(false) { // In case an earlier test left a stray file std::remove(test_socket_file().c_str()); } mtf::TestingProcessManager::~TestingProcessManager() { } void mtf::TestingProcessManager::launch_server_process(TestingServerConfiguration& config) { pid_t pid = fork(); if (pid < 0) { throw std::runtime_error("Failed to fork process"); } if (pid == 0) { using namespace mir; is_test_process = false; // We're in the server process, so create a display server SCOPED_TRACE("Server"); mir::run_mir(config, [&](mir::DisplayServer&) { config.exec(); }); config.on_exit(); } else { server_process = std::shared_ptr(new Process(pid)); config.wait_for_server_start(); server_process_was_started = true; } } void mtf::TestingProcessManager::launch_client_process(TestingClientConfiguration& config, mo::Option const& test_options) { if (!is_test_process) { return; // We're not in the test process, so just return gracefully } // We're in the test process, so make sure we started a service ASSERT_TRUE(server_process_was_started); pid_t pid = fork(); if (pid < 0) { throw std::runtime_error("Failed to fork process"); } if (pid == 0) { is_test_process = false; // Need to avoid terminating server or other clients server_process->detach(); for(auto client = clients.begin(); client != clients.end(); ++client) { (*client)->detach(); } clients.clear(); server_process.reset(); SCOPED_TRACE("Client"); if (!config.use_real_graphics(test_options)) { mtf::UsingStubClientPlatform p; config.exec(); } else { config.exec(); } exit(::testing::Test::HasFailure() ? EXIT_FAILURE : EXIT_SUCCESS); } else { clients.push_back(std::shared_ptr(new Process(pid))); } } void mtf::TestingProcessManager::tear_down_clients() { if (is_test_process) { for(auto client = clients.begin(); client != clients.end(); ++client) { auto result((*client)->wait_for_termination()); EXPECT_TRUE(result.succeeded()) << "client terminate error=" << result; } clients.clear(); } else { // Exiting here in the child processes causes "memory leaks", // however, not exiting allows the client processes to continue // executing tests (which spawn further child processes) // with worse results. exit(::testing::Test::HasFailure() ? EXIT_FAILURE : EXIT_SUCCESS); } } mtf::Result mtf::TestingProcessManager::shutdown_server_process() { Result result; if (server_process) { server_process->terminate(); result = server_process->wait_for_termination(); server_process.reset(); return result; } else { result.reason = TerminationReason::child_terminated_normally; result.exit_code = EXIT_SUCCESS; } return result; } mtf::Result mtf::TestingProcessManager::wait_for_shutdown_server_process() { Result result; if (server_process) { result = server_process->wait_for_termination(); server_process.reset(); return result; } else { result.reason = TerminationReason::child_terminated_normally; result.exit_code = EXIT_SUCCESS; } return result; } void mtf::TestingProcessManager::terminate_client_processes() { if (is_test_process) { for(auto client : clients) { client->terminate(); } } } void mtf::TestingProcessManager::kill_client_processes() { if (is_test_process) { for(auto client : clients) { client->kill(); } clients.clear(); } } void mtf::TestingProcessManager::run_in_test_process(std::function const& run_code) { if (is_test_process) run_code(); } void mtf::TestingProcessManager::tear_down_server() { if (is_test_process) { ASSERT_TRUE(clients.empty()) << "Clients should be stopped before server"; // We're in the test process, so make sure we started a service ASSERT_TRUE(server_process_was_started); auto const& result = shutdown_server_process(); EXPECT_TRUE(result.succeeded()) << result; } } void mtf::TestingProcessManager::tear_down_all() { tear_down_clients(); tear_down_server(); } mir-0.1.8+14.04.20140411/tests/mir_test_framework/in_process_server.cpp0000644000015301777760000000514712322054223026206 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/in_process_server.h" #include "mir/default_server_configuration.h" #include "mir/display_server.h" #include "mir/frontend/connector.h" #include "mir/run_mir.h" #include #include #include namespace mtf = mir_test_framework; namespace { char const* const env_no_file = "MIR_SERVER_NO_FILE"; } mtf::InProcessServer::InProcessServer() : old_env(getenv(env_no_file)) { if (!old_env) setenv(env_no_file, "", true); } void mtf::InProcessServer::SetUp() { display_server = start_mir_server(); ASSERT_TRUE(display_server); } std::string mtf::InProcessServer::new_connection() { char connect_string[64] = {0}; sprintf(connect_string, "fd://%d", server_config().the_connector()->client_socket_fd()); return connect_string; } void mtf::InProcessServer::TearDown() { ASSERT_TRUE(display_server) << "Did you override SetUp() and forget to call mtf::InProcessServer::SetUp()?"; display_server->stop(); } mtf::InProcessServer::~InProcessServer() { if (server_thread.joinable()) server_thread.join(); if (!old_env) unsetenv(env_no_file); } mir::DisplayServer* mtf::InProcessServer::start_mir_server() { std::mutex mutex; std::condition_variable cv; mir::DisplayServer* result{nullptr}; server_thread = std::thread([&] { try { mir::run_mir(server_config(), [&](mir::DisplayServer& ds) { std::unique_lock lock(mutex); result = &ds; cv.notify_one(); }); } catch (std::exception const& e) { FAIL() << e.what(); } }); using namespace std::chrono; auto const time_limit = system_clock::now() + seconds(2); std::unique_lock lock(mutex); while (!result && time_limit > system_clock::now()) cv.wait_until(lock, time_limit); return result; } mir-0.1.8+14.04.20140411/tests/mir_test_framework/testing_server_options.cpp0000644000015301777760000000541712322054223027272 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/testing_server_configuration.h" #include "mir/server_status_listener.h" #include #include namespace mtf = mir_test_framework; mtf::TestingServerConfiguration::TestingServerConfiguration() : using_server_started_sync(false) { } void mtf::TestingServerConfiguration::exec() { } void mtf::TestingServerConfiguration::on_start() { } void mtf::TestingServerConfiguration::on_exit() { } std::string mtf::TestingServerConfiguration::the_socket_file() const { return test_socket_file(); } std::shared_ptr mtf::TestingServerConfiguration::the_server_status_listener() { struct TestingServerStatusListener : public mir::ServerStatusListener { TestingServerStatusListener(CrossProcessSync const& sync, std::function const& on_start) : server_started_sync{sync}, on_start{on_start} { } void paused() {} void resumed() {} void started() { server_started_sync.try_signal_ready_for(); on_start(); } CrossProcessSync server_started_sync; std::function const on_start; }; return server_status_listener( [this] { using_server_started_sync = true; return std::make_shared( server_started_sync, [this] { on_start(); }); }); } void mtf::TestingServerConfiguration::wait_for_server_start() { auto listener = the_server_status_listener(); if (!using_server_started_sync) { BOOST_THROW_EXCEPTION( std::runtime_error( "Not using cross process sync mechanism for server startup detection." "Did you override the_server_status_listener() in the test?")); } server_started_sync.wait_for_signal_ready_for(); } std::string const& mtf::test_socket_file() { static const std::string socket_file{"./mir_socket_test"}; return socket_file; } mir-0.1.8+14.04.20140411/tests/mir_test_framework/process.cpp0000644000015301777760000001331112322054223024122 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/process.h" #include #include #include #include #include #include #include #include #include namespace mtf = mir_test_framework; namespace { struct SignalNumberErrorInfoTag {}; typedef boost::error_info errinfo_signum; struct ProcessIdErrorInfoTag {}; typedef boost::error_info errinfo_pid; void signal_process(pid_t pid, int signum) { if (::kill(pid, signum) != 0) { BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error("Failed to kill process.")) << errinfo_pid(pid) << errinfo_signum(signum) << boost::errinfo_errno(errno)); } } } mtf::Result::Result() : reason(TerminationReason::unknown) , exit_code(EXIT_FAILURE) , signal(_NSIG+1) { } bool mtf::Result::succeeded() const { return reason == TerminationReason::child_terminated_normally && exit_code == EXIT_SUCCESS; } bool mtf::Result::signalled() const { return reason == TerminationReason::child_terminated_by_signal; } mtf::Process::Process(pid_t pid) : pid(pid) , terminated(false) , detached(false) { assert(pid > 0); } mtf::Process::~Process() { if (!detached && !terminated) { try { terminate(); wait_for_termination(); } catch (std::exception const &) { // Ignore a failure to signal the process. } } } mtf::Result mtf::Process::wait_for_termination(const std::chrono::milliseconds& timeout) { Result result; int status; if (!detached) { auto tp = std::chrono::steady_clock::now() + timeout; int rc = -1; while (true) { if ((rc = ::waitpid(pid, &status, WNOHANG)) == pid) { if (WIFEXITED(status)) { terminated = true; result.reason = TerminationReason::child_terminated_normally; result.exit_code = WEXITSTATUS(status); break; } else if (WIFSIGNALED(status)) { terminated = true; result.reason = TerminationReason::child_terminated_by_signal; result.signal = WTERMSIG(status); break; } } else if (rc == 0) { if (std::chrono::steady_clock::now() < tp) { std::this_thread::yield(); continue; } else { BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error("Timeout while waiting for child to change state")) << errinfo_pid(pid)); } } else break; } } return result; } void mtf::Process::kill() { if (!detached) signal_process(pid, SIGKILL); } void mtf::Process::terminate() { if (!detached) signal_process(pid, SIGTERM); } void mtf::Process::stop() { if (!detached) signal_process(pid, SIGSTOP); } void mtf::Process::cont() { if (!detached) signal_process(pid, SIGCONT); } void mtf::Process::detach() { detached = true; } namespace { std::ostream& print_reason(std::ostream & out, mtf::TerminationReason reason) { switch (reason) { case mtf::TerminationReason::unknown: out << "unknown"; break; case mtf::TerminationReason::child_terminated_normally: out << "child_terminated_normally"; break; case mtf::TerminationReason::child_terminated_by_signal: out << "child_terminated_by_signal"; break; case mtf::TerminationReason::child_terminated_with_core_dump: out << "child_terminated_with_core_dump"; break; case mtf::TerminationReason::child_stopped_by_signal: out << "child_stopped_by_signal"; break; case mtf::TerminationReason::child_resumed_by_signal: out << "child_resumed_by_signal"; break; } return out; } std::ostream& print_signal(std::ostream& out, int signal) { out << "signal(" << signal << ")"; return out; } std::ostream& print_exit_code(std::ostream& out, int exit_code) { if (exit_code == EXIT_SUCCESS) { out << "success"; } else { out << "failure(" << exit_code << ')'; } return out; } } std::ostream& mtf::operator<<(std::ostream& out, const mtf::Result& result) { out << "process::Result("; print_reason(out, result.reason); out << ", "; if (result.signalled()) { print_signal(out, result.signal); out << ", "; } if (result.reason == TerminationReason::child_terminated_normally) { print_exit_code(out, result.exit_code); } return out << ')'; } mir-0.1.8+14.04.20140411/tests/mir_test_framework/testing_client_options.cpp0000644000015301777760000000706412322054223027242 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/testing_client_configuration.h" #include "mir_test_framework/stub_client_connection_configuration.h" #include "mir/options/program_option.h" #include "src/client/default_connection_configuration.h" #include "src/client/client_platform_factory.h" #include "src/client/client_buffer_factory.h" #include "src/client/client_buffer.h" #include "src/client/client_platform.h" #include "src/client/mir_connection.h" namespace mcl = mir::client; namespace mtf=mir_test_framework; namespace geom = mir::geometry; namespace { class StubClientBuffer : public mcl::ClientBuffer { std::shared_ptr secure_for_cpu_write() { return nullptr; } geom::Size size() const { return geom::Size{}; } geom::Stride stride() const { return geom::Stride{}; } MirPixelFormat pixel_format() const { return mir_pixel_format_abgr_8888; } uint32_t age() const { return 0; } void increment_age() { } void mark_as_submitted() { } std::shared_ptr native_buffer_handle() const { return nullptr; } }; struct StubClientBufferFactory : public mcl::ClientBufferFactory { std::shared_ptr create_buffer(std::shared_ptr const&, geom::Size, MirPixelFormat) { return std::make_shared(); } }; struct StubClientPlatform : public mcl::ClientPlatform { MirPlatformType platform_type() const { return mir_platform_type_gbm; } std::shared_ptr create_buffer_factory() { return std::make_shared(); } std::shared_ptr create_egl_native_window(mcl::ClientSurface*) { auto fake_window = reinterpret_cast(0x12345678lu); return std::make_shared(fake_window); } std::shared_ptr create_egl_native_display() { auto fake_display = reinterpret_cast(0x12345678lu); return std::make_shared(fake_display); } MirNativeBuffer* convert_native_buffer(mir::graphics::NativeBuffer*) const { return nullptr; } }; struct StubClientPlatformFactory : public mcl::ClientPlatformFactory { std::shared_ptr create_client_platform(mcl::ClientContext*) { return std::make_shared(); } }; } mtf::StubConnectionConfiguration::StubConnectionConfiguration(std::string const& socket_file) : DefaultConnectionConfiguration(socket_file) { } std::shared_ptr mtf::StubConnectionConfiguration::the_client_platform_factory() { return std::make_shared(); } mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_recordings/0000755000015301777760000000000012322054703025126 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_recordings/usb-mouse.umockdev0000644000015301777760000002025312322054247030611 0ustar pbusernogroup00000000000000P: /devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3:1.0/input/input23/event13 N: input/event13 S: input/by-id/usb-Logitech_USB_Optical_Mouse-event-mouse S: input/by-path/pci-0000:00:14.0-usb-0:3:1.0-event-mouse E: DEVLINKS=/dev/input/by-id/usb-Logitech_USB_Optical_Mouse-event-mouse /dev/input/by-path/pci-0000:00:14.0-usb-0:3:1.0-event-mouse E: DEVNAME=/dev/input/event13 E: ID_BUS=usb E: ID_INPUT=1 E: ID_INPUT_MOUSE=1 E: ID_MODEL=USB_Optical_Mouse E: ID_MODEL_ENC=USB\x20Optical\x20Mouse E: ID_MODEL_ID=c018 E: ID_PATH=pci-0000:00:14.0-usb-0:3:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_3_1_0 E: ID_REVISION=4301 E: ID_SERIAL=Logitech_USB_Optical_Mouse E: ID_TYPE=hid E: ID_USB_DRIVER=usbhid E: ID_USB_INTERFACES=:030102: E: ID_USB_INTERFACE_NUM=00 E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: MAJOR=13 E: MINOR=77 E: SUBSYSTEM=input A: dev=13:77 L: device=../../input23 P: /devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3:1.0/input/input23 E: EV=17 E: ID_BUS=usb E: ID_FOR_SEAT=input-pci-0000_00_14_0-usb-0_3_1_0 E: ID_INPUT=1 E: ID_INPUT_MOUSE=1 E: ID_MODEL=USB_Optical_Mouse E: ID_MODEL_ENC=USB\x20Optical\x20Mouse E: ID_MODEL_ID=c018 E: ID_PATH=pci-0000:00:14.0-usb-0:3:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_3_1_0 E: ID_REVISION=4301 E: ID_SERIAL=Logitech_USB_Optical_Mouse E: ID_TYPE=hid E: ID_USB_DRIVER=usbhid E: ID_USB_INTERFACES=:030102: E: ID_USB_INTERFACE_NUM=00 E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_ID=046d E: KEY=70000 0 0 0 0 E: MODALIAS=input:b0003v046DpC018e0111-e0,1,2,4,k110,111,112,r0,1,8,am4,lsfw E: MSC=10 E: NAME="Logitech USB Optical Mouse" E: PHYS="usb-0000:00:14.0-3/input0" E: PRODUCT=3/46d/c018/111 E: PROP=0 E: REL=103 E: SUBSYSTEM=input E: TAGS=:seat: E: UNIQ="" L: device=../../../3-3:1.0 A: modalias=input:b0003v046DpC018e0111-e0,1,2,4,k110,111,112,r0,1,8,am4,lsfw A: name=Logitech USB Optical Mouse A: phys=usb-0000:00:14.0-3/input0 A: properties=0 A: uniq= P: /devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3:1.0 E: DEVTYPE=usb_interface E: DRIVER=usbhid E: ID_MODEL_FROM_DATABASE=Optical Wheel Mouse E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. E: INTERFACE=3/1/2 E: MODALIAS=usb:v046DpC018d4301dc00dsc00dp00ic03isc01ip02in00 E: PRODUCT=46d/c018/4301 E: SUBSYSTEM=usb E: TYPE=0/0/0 A: bAlternateSetting= 0 A: bInterfaceClass=03 A: bInterfaceNumber=00 A: bInterfaceProtocol=02 A: bInterfaceSubClass=01 A: bNumEndpoints=01 L: driver=../../../../../../bus/usb/drivers/usbhid A: modalias=usb:v046DpC018d4301dc00dsc00dp00ic03isc01ip02in00 A: supports_autosuspend=1 P: /devices/pci0000:00/0000:00:14.0/usb3/3-3 N: bus/usb/003/015=12010002000000086D0418C001430102000109022200010100A0320904000001030102000921110100012234000705810305000A E: BUSNUM=003 E: DEVNAME=/dev/bus/usb/003/015 E: DEVNUM=015 E: DEVTYPE=usb_device E: DRIVER=usb E: ID_BUS=usb E: ID_MODEL=USB_Optical_Mouse E: ID_MODEL_ENC=USB\x20Optical\x20Mouse E: ID_MODEL_FROM_DATABASE=Optical Wheel Mouse E: ID_MODEL_ID=c018 E: ID_REVISION=4301 E: ID_SERIAL=Logitech_USB_Optical_Mouse E: ID_USB_INTERFACES=:030102: E: ID_VENDOR=Logitech E: ID_VENDOR_ENC=Logitech E: ID_VENDOR_FROM_DATABASE=Logitech, Inc. E: ID_VENDOR_ID=046d E: MAJOR=189 E: MINOR=270 E: PRODUCT=46d/c018/4301 E: SUBSYSTEM=usb E: TYPE=0/0/0 E: UPOWER_VENDOR=Logitech, Inc. A: authorized=1 A: avoid_reset_quirk=0 A: bConfigurationValue=1 A: bDeviceClass=00 A: bDeviceProtocol=00 A: bDeviceSubClass=00 A: bMaxPacketSize0=8 A: bMaxPower=100mA A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=4301 A: bmAttributes=a0 A: busnum=3 A: configuration= H: descriptors=12010002000000086D0418C001430102000109022200010100A0320904000001030102000921110100012234000705810305000A A: dev=189:270 A: devnum=15 A: devpath=3 L: driver=../../../../../bus/usb/drivers/usb A: idProduct=c018 A: idVendor=046d A: ltm_capable=no A: manufacturer=Logitech A: maxchild=0 L: port=../3-0:1.0/port3 A: product=USB Optical Mouse A: quirks=0x0 A: removable=removable A: speed=1.5 A: urbnum=167 A: version= 2.00 P: /devices/pci0000:00/0000:00:14.0/usb3 N: bus/usb/003/001=12010002090001406B1D020013030302010109021900010100E0000904000001090000000705810304000C E: BUSNUM=003 E: DEVNAME=/dev/bus/usb/003/001 E: DEVNUM=001 E: DEVTYPE=usb_device E: DRIVER=usb E: ID_BUS=usb E: ID_FOR_SEAT=usb-pci-0000_00_14_0 E: ID_MODEL=xHCI_Host_Controller E: ID_MODEL_ENC=xHCI\x20Host\x20Controller E: ID_MODEL_FROM_DATABASE=2.0 root hub E: ID_MODEL_ID=0002 E: ID_PATH=pci-0000:00:14.0 E: ID_PATH_TAG=pci-0000_00_14_0 E: ID_REVISION=0313 E: ID_SERIAL=Linux_3.13.0-8-generic_xhci_hcd_xHCI_Host_Controller_0000:00:14.0 E: ID_SERIAL_SHORT=0000:00:14.0 E: ID_USB_INTERFACES=:090000: E: ID_VENDOR=Linux_3.13.0-8-generic_xhci_hcd E: ID_VENDOR_ENC=Linux\x203.13.0-8-generic\x20xhci_hcd E: ID_VENDOR_FROM_DATABASE=Linux Foundation E: ID_VENDOR_ID=1d6b E: MAJOR=189 E: MINOR=256 E: PRODUCT=1d6b/2/313 E: SUBSYSTEM=usb E: TAGS=:seat: E: TYPE=9/0/1 A: authorized=1 A: authorized_default=1 A: avoid_reset_quirk=0 A: bConfigurationValue=1 A: bDeviceClass=09 A: bDeviceProtocol=01 A: bDeviceSubClass=00 A: bMaxPacketSize0=64 A: bMaxPower=0mA A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0313 A: bmAttributes=e0 A: busnum=3 A: configuration= H: descriptors=12010002090001406B1D020013030302010109021900010100E0000904000001090000000705810304000C A: dev=189:256 A: devnum=1 A: devpath=0 L: driver=../../../../bus/usb/drivers/usb A: idProduct=0002 A: idVendor=1d6b A: ltm_capable=no A: manufacturer=Linux 3.13.0-8-generic xhci_hcd A: maxchild=14 A: product=xHCI Host Controller A: quirks=0x0 A: removable=unknown A: serial=0000:00:14.0 A: speed=480 A: urbnum=225 A: version= 2.00 P: /devices/pci0000:00/0000:00:14.0 E: DRIVER=xhci_hcd E: ID_MODEL_FROM_DATABASE=Lynx Point USB xHCI Host Controller E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller E: ID_VENDOR_FROM_DATABASE=Intel Corporation E: MODALIAS=pci:v00008086d00008C31sv00001558sd00007410bc0Csc03i30 E: PCI_CLASS=C0330 E: PCI_ID=8086:8C31 E: PCI_SLOT_NAME=0000:00:14.0 E: PCI_SUBSYS_ID=1558:7410 E: SUBSYSTEM=pci A: broken_parity_status=0 A: class=0x0c0330 H: config=8680318C060490020430030C000000000400E2F700000000000000000000000000000000000000000000000058151074000000007000000000000000FF010000FD01368089C60F8000000000000000009F6E8807000000000000000000000000302000000000000000000000000000000180C2C108000000000000000000000005008700F802E0FE000000000000000000000000000000000000000000000000400100000000000000000000000000000F000100000000000000000000000000030420C0030C3000030C300000000000FF3F0000FF3F00003F0000003F000000A0000000D03C000000000000D8D8D8080000000000000000B10F050800000000 A: consistent_dma_mask_bits=64 A: d3cold_allowed=1 A: device=0x8c31 A: dma_mask_bits=64 L: driver=../../../bus/pci/drivers/xhci_hcd A: enabled=1 A: irq=42 A: local_cpulist=0-7 A: local_cpus=00000000,00000000,00000000,00000000,00000000,00000000,00000000,000000ff A: modalias=pci:v00008086d00008C31sv00001558sd00007410bc0Csc03i30 A: msi_bus= A: numa_node=-1 A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 9 9 2112 9\nxHCI ring segments 34 34 4096 34\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 3 32 128 1\nbuffer-32 0 0 32 0 A: resource=0x00000000f7e20000 0x00000000f7e2ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000 A: subsystem_device=0x7410 A: subsystem_vendor=0x1558 A: vendor=0x8086 mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_recordings/laptop-keyboard.umockdev0000644000015301777760000000377312322054247031777 0ustar pbusernogroup00000000000000P: /devices/platform/i8042/serio0/input/input4/event4 N: input/event4 S: input/by-path/platform-i8042-serio-0-event-kbd E: DEVLINKS=/dev/input/by-path/platform-i8042-serio-0-event-kbd E: DEVNAME=/dev/input/event4 E: ID_INPUT=1 E: ID_INPUT_KEY=1 E: ID_INPUT_KEYBOARD=1 E: ID_PATH=platform-i8042-serio-0 E: ID_PATH_TAG=platform-i8042-serio-0 E: ID_SERIAL=noserial E: MAJOR=13 E: MINOR=68 E: SUBSYSTEM=input E: XKBLAYOUT=us E: XKBMODEL=pc105 E: XKBOPTIONS=compose:menu,ctrl:nocaps E: XKBVARIANT=dvorak A: dev=13:68 L: device=../../input4 P: /devices/platform/i8042/serio0/input/input4 E: EV=120013 E: ID_FOR_SEAT=input-platform-i8042-serio-0 E: ID_INPUT=1 E: ID_INPUT_KEY=1 E: ID_INPUT_KEYBOARD=1 E: ID_PATH=platform-i8042-serio-0 E: ID_PATH_TAG=platform-i8042-serio-0 E: ID_SERIAL=noserial E: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe E: LED=7 E: MODALIAS=input:b0011v0001p0001eAB83-e0,1,4,11,14,k71,72,73,74,75,76,77,79,7A,7B,7C,7D,7E,7F,80,8C,8E,8F,9B,9C,9D,9E,9F,A3,A4,A5,A6,AC,AD,B7,B8,B9,D9,E2,ram4,l0,1,2,sfw E: MSC=10 E: NAME="AT Translated Set 2 keyboard" E: PHYS="isa0060/serio0/input0" E: PRODUCT=11/1/1/ab83 E: PROP=0 E: SUBSYSTEM=input E: TAGS=:seat: L: device=../../../serio0 A: modalias=input:b0011v0001p0001eAB83-e0,1,4,11,14,k71,72,73,74,75,76,77,79,7A,7B,7C,7D,7E,7F,80,8C,8E,8F,9B,9C,9D,9E,9F,A3,A4,A5,A6,AC,AD,B7,B8,B9,D9,E2,ram4,l0,1,2,sfw A: name=AT Translated Set 2 keyboard A: phys=isa0060/serio0/input0 A: properties=0 A: uniq= P: /devices/platform/i8042/serio0 E: DRIVER=atkbd E: MODALIAS=serio:ty06pr00id00ex00 E: SERIO_EXTRA=00 E: SERIO_ID=00 E: SERIO_PROTO=00 E: SERIO_TYPE=06 E: SUBSYSTEM=serio A: bind_mode=auto A: description=i8042 KBD port L: driver=../../../../bus/serio/drivers/atkbd A: err_count=0 A: extra=0 A: force_release=369-370 A: modalias=serio:ty06pr00id00ex00 A: scroll=0 A: set=2 A: softraw=1 A: softrepeat=0 P: /devices/platform/i8042 E: DRIVER=i8042 E: MODALIAS=platform:i8042 E: SUBSYSTEM=platform L: driver=../../../bus/platform/drivers/i8042 A: modalias=platform:i8042 mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_recordings/bluetooth-magic-trackpad.ioctl0000644000015301777760000000315612322054247033044 0ustar pbusernogroup00000000000000@DEV /dev/input/event13 EVIOCGNAME(0) 24 4170706C6520576972656C65737320547261636B70616400003C6F4488EC284430A3960100000000B08601F81A7F000080018F071B7F000000000000000000000000000000000000C0298F071B7F00 EVIOCGVERSION 0 01000100 EVIOCGID 0 0500AC050E036001 EVIOCGPHYS(0) 18 62383A37363A33663A37383A65623A373600636B70616400003C6F4488EC284430A3960100000000B08601F81A7F000080018F071B7F000000000000000000000000000000000000C0298F071B7F00 EVIOCGUNIQ(0) 18 64383A61323A35653A66383A37303A643600636B70616400003C6F4488EC284430A3960100000000B08601F81A7F000080018F071B7F000000000000000000000000000000000000C0298F071B7F00 EVIOCGBIT(1) 96 0000000000000000000000000000000000000000000000000000000000000000000001000000000020E5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EVIOCGBIT(3) 8 0300000000807302 EVIOCGBIT(2) 2 0000 EVIOCGBIT(5) 2 0000 EVIOCGBIT(17) 2 0000 EVIOCGBIT(21) 16 00000000000000000000000000000000 EVIOCGPROP(0) 4 05000000 EVIOCGABS(53) 0 00000000A3F4FFFF5F0C000004000000000000002E000000 EVIOCGABS(54) 0 0000000068F6FFFF050A000004000000000000002D000000 EVIOCGABS(48) 0 0000000000000000FC030000040000000000000000000000 EVIOCGABS(49) 0 0000000000000000FC030000040000000000000000000000 EVIOCGABS(52) 0 00000000E1FFFFFF20000000010000000000000000000000 EVIOCGABS(57) 0 0000000000000000FFFF0000000000000000000000000000 EVIOCGABS(47) 0 04000000000000000F000000000000000000000000000000 EVIOCGKEY(0) 96 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_recordings/laptop-keyboard.ioctl0000644000015301777760000000144512322054247031266 0ustar pbusernogroup00000000000000@DEV /dev/input/event4 EVIOCGNAME(0) 29 4154205472616E736C61746564205365742032206B6579626F61726400E9B73A300372020000000000CB0170ED7F000080E1C47FED7F000000000000000000000000000000000000C009C57FED7F00 EVIOCGVERSION 0 01000100 EVIOCGID 0 11000100010083AB EVIOCGPHYS(0) 22 697361303036302F736572696F302F696E707574300079626F61726400E9B73A300372020000000000CB0170ED7F000080E1C47FED7F000000000000000000000000000000000000C009C57FED7F00 EVIOCGBIT(1) 96 FEFFFFFFFFFFFFFFFFFFEFFFDFFFFFFE01D000F878308003000000020400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EVIOCGBIT(3) 8 0000000000000000 EVIOCGBIT(2) 2 0000 EVIOCGBIT(5) 2 0000 EVIOCGBIT(17) 2 0700 EVIOCGBIT(21) 16 00000000000000000000000000000000 EVIOCGPROP(0) 4 00000000 mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_recordings/synaptics-touchpad.umockdev0000644000015301777760000000331012322054247032507 0ustar pbusernogroup00000000000000P: /devices/platform/i8042/serio2/input/input11/event12 N: input/event12 S: input/by-path/platform-i8042-serio-2-event-mouse E: DEVLINKS=/dev/input/by-path/platform-i8042-serio-2-event-mouse E: DEVNAME=/dev/input/event12 E: ID_INPUT=1 E: ID_INPUT_TOUCHPAD=1 E: ID_PATH=platform-i8042-serio-2 E: ID_PATH_TAG=platform-i8042-serio-2 E: ID_SERIAL=noserial E: MAJOR=13 E: MINOR=76 E: SUBSYSTEM=input A: dev=13:76 L: device=../../input11 P: /devices/platform/i8042/serio2/input/input11 E: ABS=660800011000003 E: EV=b E: ID_FOR_SEAT=input-platform-i8042-serio-2 E: ID_INPUT=1 E: ID_INPUT_TOUCHPAD=1 E: ID_PATH=platform-i8042-serio-2 E: ID_PATH_TAG=platform-i8042-serio-2 E: ID_SERIAL=noserial E: KEY=e520 10000 0 0 0 0 E: MODALIAS=input:b0011v0002p0007e01B1-e0,1,3,k110,145,148,14A,14D,14E,14F,ra0,1,18,1C,2F,35,36,39,3A,mlsfw E: NAME="SynPS/2 Synaptics TouchPad" E: PHYS="isa0060/serio2/input0" E: PRODUCT=11/2/7/1b1 E: PROP=5 E: SUBSYSTEM=input E: TAGS=:seat: L: device=../../../serio2 A: modalias=input:b0011v0002p0007e01B1-e0,1,3,k110,145,148,14A,14D,14E,14F,ra0,1,18,1C,2F,35,36,39,3A,mlsfw A: name=SynPS/2 Synaptics TouchPad A: phys=isa0060/serio2/input0 A: properties=5 A: uniq= P: /devices/platform/i8042/serio2 E: DRIVER=psmouse E: MODALIAS=serio:ty01pr00id00ex00 E: SERIO_EXTRA=00 E: SERIO_ID=00 E: SERIO_PROTO=00 E: SERIO_TYPE=01 E: SUBSYSTEM=serio A: bind_mode=auto A: description=i8042 AUX1 port L: driver=../../../../bus/serio/drivers/psmouse A: modalias=serio:ty01pr00id00ex00 A: protocol=SynPS/2 A: rate=80 A: resetafter=5 A: resolution=200 A: resync_time=0 P: /devices/platform/i8042 E: DRIVER=i8042 E: MODALIAS=platform:i8042 E: SUBSYSTEM=platform L: driver=../../../bus/platform/drivers/i8042 A: modalias=platform:i8042 mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_recordings/usb-mouse.ioctl0000644000015301777760000000224612322054247030110 0ustar pbusernogroup00000000000000@DEV /dev/input/event13 EVIOCGNAME(0) 27 4C6F67697465636820555342204F70746963616C204D6F757365006C29CED7F73013430200000000C0200014ED7F000080D1FF1BED7F000000000000000000000000000000000000C0F9FF1BED7F00 EVIOCGVERSION 0 01000100 EVIOCGID 0 03006D0418C01101 EVIOCGPHYS(0) 26 7573622D303030303A30303A31342E302D332F696E7075743000006C29CED7F73013430200000000C0200014ED7F000080D1FF1BED7F000000000000000000000000000000000000C0F9FF1BED7F00 EVIOCGUNIQ(0) 1 0073622D303030303A30303A31342E302D332F696E7075743000006C29CED7F73013430200000000C0200014ED7F000080D1FF1BED7F000000000000000000000000000000000000C0F9FF1BED7F00 EVIOCGBIT(1) 96 000000000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EVIOCGBIT(3) 8 0000000000000000 EVIOCGBIT(2) 2 0301 EVIOCGBIT(5) 2 0000 EVIOCGBIT(17) 2 0000 EVIOCGBIT(21) 16 00000000000000000000000000000000 EVIOCGPROP(0) 4 00000000 EVIOCGKEY(0) 96 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_recordings/usb-keyboard.umockdev0000644000015301777760000002117212322054247031262 0ustar pbusernogroup00000000000000P: /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/input/input24/event14 N: input/event14 S: input/by-id/usb-Fujitsu_Siemens_Computers_GmbH_FSC_KB_USB-event-kbd S: input/by-path/pci-0000:00:14.0-usb-0:2:1.0-event-kbd E: DEVLINKS=/dev/input/by-id/usb-Fujitsu_Siemens_Computers_GmbH_FSC_KB_USB-event-kbd /dev/input/by-path/pci-0000:00:14.0-usb-0:2:1.0-event-kbd E: DEVNAME=/dev/input/event14 E: ID_BUS=usb E: ID_INPUT=1 E: ID_INPUT_KEY=1 E: ID_INPUT_KEYBOARD=1 E: ID_MODEL=FSC_KB_USB E: ID_MODEL_ENC=FSC\x20KB\x20USB E: ID_MODEL_ID=1004 E: ID_PATH=pci-0000:00:14.0-usb-0:2:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_2_1_0 E: ID_REVISION=0001 E: ID_SERIAL=Fujitsu_Siemens_Computers_GmbH_FSC_KB_USB E: ID_TYPE=hid E: ID_USB_DRIVER=usbhid E: ID_USB_INTERFACES=:030101:030000: E: ID_USB_INTERFACE_NUM=00 E: ID_VENDOR=Fujitsu_Siemens_Computers_GmbH E: ID_VENDOR_ENC=Fujitsu\x20Siemens\x20Computers\x20GmbH E: ID_VENDOR_ID=0bf8 E: MAJOR=13 E: MINOR=78 E: SUBSYSTEM=input E: XKBLAYOUT=us E: XKBMODEL=pc105 E: XKBOPTIONS=compose:menu,ctrl:nocaps E: XKBVARIANT=dvorak A: dev=13:78 L: device=../../input24 P: /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/input/input24 E: EV=120013 E: ID_BUS=usb E: ID_FOR_SEAT=input-pci-0000_00_14_0-usb-0_2_1_0 E: ID_INPUT=1 E: ID_INPUT_KEY=1 E: ID_INPUT_KEYBOARD=1 E: ID_MODEL=FSC_KB_USB E: ID_MODEL_ENC=FSC\x20KB\x20USB E: ID_MODEL_ID=1004 E: ID_PATH=pci-0000:00:14.0-usb-0:2:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_2_1_0 E: ID_REVISION=0001 E: ID_SERIAL=Fujitsu_Siemens_Computers_GmbH_FSC_KB_USB E: ID_TYPE=hid E: ID_USB_DRIVER=usbhid E: ID_USB_INTERFACES=:030101:030000: E: ID_USB_INTERFACE_NUM=00 E: ID_VENDOR=Fujitsu_Siemens_Computers_GmbH E: ID_VENDOR_ENC=Fujitsu\x20Siemens\x20Computers\x20GmbH E: ID_VENDOR_ID=0bf8 E: KEY=e080ffdf01cfffff fffffffffffffffe E: LED=1f E: MODALIAS=input:b0003v0BF8p1004e0110-e0,1,4,11,14,k77,7D,7E,7F,ram4,l0,1,2,3,4,sfw E: MSC=10 E: NAME="Fujitsu Siemens Computers GmbH FSC KB USB" E: PHYS="usb-0000:00:14.0-2/input0" E: PRODUCT=3/bf8/1004/110 E: PROP=0 E: SUBSYSTEM=input E: TAGS=:seat: E: UNIQ="" L: device=../../../3-2:1.0 A: modalias=input:b0003v0BF8p1004e0110-e0,1,4,11,14,k77,7D,7E,7F,ram4,l0,1,2,3,4,sfw A: name=Fujitsu Siemens Computers GmbH FSC KB USB A: phys=usb-0000:00:14.0-2/input0 A: properties=0 A: uniq= P: /devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0 E: DEVTYPE=usb_interface E: DRIVER=usbhid E: ID_VENDOR_FROM_DATABASE=Fujitsu Siemens Computers E: INTERFACE=3/1/1 E: MODALIAS=usb:v0BF8p1004d0001dc00dsc00dp00ic03isc01ip01in00 E: PRODUCT=bf8/1004/1 E: SUBSYSTEM=usb E: TYPE=0/0/0 A: bAlternateSetting= 0 A: bInterfaceClass=03 A: bInterfaceNumber=00 A: bInterfaceProtocol=01 A: bInterfaceSubClass=01 A: bNumEndpoints=01 L: driver=../../../../../../bus/usb/drivers/usbhid A: interface=HID KEYBOARD (v2.0 rf) A: modalias=usb:v0BF8p1004d0001dc00dsc00dp00ic03isc01ip01in00 A: supports_autosuspend=1 P: /devices/pci0000:00/0000:00:14.0/usb3/3-2 N: bus/usb/003/016=1201100100000008F80B041001000102000109023B00020102A032090400000103010103092110010001223F000705810308000A090401000103000000092110010001225100070582030200A0 E: BUSNUM=003 E: DEVNAME=/dev/bus/usb/003/016 E: DEVNUM=016 E: DEVTYPE=usb_device E: DRIVER=usb E: ID_BUS=usb E: ID_MODEL=FSC_KB_USB E: ID_MODEL_ENC=FSC\x20KB\x20USB E: ID_MODEL_ID=1004 E: ID_REVISION=0001 E: ID_SERIAL=Fujitsu_Siemens_Computers_GmbH_FSC_KB_USB E: ID_USB_INTERFACES=:030101:030000: E: ID_VENDOR=Fujitsu_Siemens_Computers_GmbH E: ID_VENDOR_ENC=Fujitsu\x20Siemens\x20Computers\x20GmbH E: ID_VENDOR_FROM_DATABASE=Fujitsu Siemens Computers E: ID_VENDOR_ID=0bf8 E: MAJOR=189 E: MINOR=271 E: PRODUCT=bf8/1004/1 E: SUBSYSTEM=usb E: TYPE=0/0/0 A: authorized=1 A: avoid_reset_quirk=0 A: bConfigurationValue=1 A: bDeviceClass=00 A: bDeviceProtocol=00 A: bDeviceSubClass=00 A: bMaxPacketSize0=8 A: bMaxPower=100mA A: bNumConfigurations=1 A: bNumInterfaces= 2 A: bcdDevice=0001 A: bmAttributes=a0 A: busnum=3 A: configuration=FSC KB USB H: descriptors=1201100100000008F80B041001000102000109023B00020102A032090400000103010103092110010001223F000705810308000A090401000103000000092110010001225100070582030200A0 A: dev=189:271 A: devnum=16 A: devpath=2 L: driver=../../../../../bus/usb/drivers/usb A: idProduct=1004 A: idVendor=0bf8 A: ltm_capable=no A: manufacturer=Fujitsu Siemens Computers GmbH A: maxchild=0 L: port=../3-0:1.0/port2 A: product=FSC KB USB A: quirks=0x0 A: removable=removable A: speed=1.5 A: urbnum=136 A: version= 1.10 P: /devices/pci0000:00/0000:00:14.0/usb3 N: bus/usb/003/001=12010002090001406B1D020013030302010109021900010100E0000904000001090000000705810304000C E: BUSNUM=003 E: DEVNAME=/dev/bus/usb/003/001 E: DEVNUM=001 E: DEVTYPE=usb_device E: DRIVER=usb E: ID_BUS=usb E: ID_FOR_SEAT=usb-pci-0000_00_14_0 E: ID_MODEL=xHCI_Host_Controller E: ID_MODEL_ENC=xHCI\x20Host\x20Controller E: ID_MODEL_FROM_DATABASE=2.0 root hub E: ID_MODEL_ID=0002 E: ID_PATH=pci-0000:00:14.0 E: ID_PATH_TAG=pci-0000_00_14_0 E: ID_REVISION=0313 E: ID_SERIAL=Linux_3.13.0-8-generic_xhci_hcd_xHCI_Host_Controller_0000:00:14.0 E: ID_SERIAL_SHORT=0000:00:14.0 E: ID_USB_INTERFACES=:090000: E: ID_VENDOR=Linux_3.13.0-8-generic_xhci_hcd E: ID_VENDOR_ENC=Linux\x203.13.0-8-generic\x20xhci_hcd E: ID_VENDOR_FROM_DATABASE=Linux Foundation E: ID_VENDOR_ID=1d6b E: MAJOR=189 E: MINOR=256 E: PRODUCT=1d6b/2/313 E: SUBSYSTEM=usb E: TAGS=:seat: E: TYPE=9/0/1 A: authorized=1 A: authorized_default=1 A: avoid_reset_quirk=0 A: bConfigurationValue=1 A: bDeviceClass=09 A: bDeviceProtocol=01 A: bDeviceSubClass=00 A: bMaxPacketSize0=64 A: bMaxPower=0mA A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0313 A: bmAttributes=e0 A: busnum=3 A: configuration= H: descriptors=12010002090001406B1D020013030302010109021900010100E0000904000001090000000705810304000C A: dev=189:256 A: devnum=1 A: devpath=0 L: driver=../../../../bus/usb/drivers/usb A: idProduct=0002 A: idVendor=1d6b A: ltm_capable=no A: manufacturer=Linux 3.13.0-8-generic xhci_hcd A: maxchild=14 A: product=xHCI Host Controller A: quirks=0x0 A: removable=unknown A: serial=0000:00:14.0 A: speed=480 A: urbnum=236 A: version= 2.00 P: /devices/pci0000:00/0000:00:14.0 E: DRIVER=xhci_hcd E: ID_MODEL_FROM_DATABASE=Lynx Point USB xHCI Host Controller E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller E: ID_VENDOR_FROM_DATABASE=Intel Corporation E: MODALIAS=pci:v00008086d00008C31sv00001558sd00007410bc0Csc03i30 E: PCI_CLASS=C0330 E: PCI_ID=8086:8C31 E: PCI_SLOT_NAME=0000:00:14.0 E: PCI_SUBSYS_ID=1558:7410 E: SUBSYSTEM=pci A: broken_parity_status=0 A: class=0x0c0330 H: config=8680318C060490020430030C000000000400E2F700000000000000000000000000000000000000000000000058151074000000007000000000000000FF010000FD01368089C60F8000000000000000009F6E8807000000000000000000000000302000000000000000000000000000000180C2C108000000000000000000000005008700F802E0FE000000000000000000000000000000000000000000000000400100000000000000000000000000000F000100000000000000000000000000030420C0030C3000030C300000000000FF3F0000FF3F00003F0000003F000000A0000000D03C000000000000D8D8D8080000000000000000B10F050800000000 A: consistent_dma_mask_bits=64 A: d3cold_allowed=1 A: device=0x8c31 A: dma_mask_bits=64 L: driver=../../../bus/pci/drivers/xhci_hcd A: enabled=1 A: irq=42 A: local_cpulist=0-7 A: local_cpus=00000000,00000000,00000000,00000000,00000000,00000000,00000000,000000ff A: modalias=pci:v00008086d00008C31sv00001558sd00007410bc0Csc03i30 A: msi_bus= A: numa_node=-1 A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 11 11 2112 11\nxHCI ring segments 40 40 4096 40\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 9 32 128 1\nbuffer-32 0 0 32 0 A: resource=0x00000000f7e20000 0x00000000f7e2ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000 A: subsystem_device=0x7410 A: subsystem_vendor=0x1558 A: vendor=0x8086 mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_recordings/usb-keyboard.ioctl0000644000015301777760000000172512322054247030561 0ustar pbusernogroup00000000000000@DEV /dev/input/event14 EVIOCGNAME(0) 42 46756A69747375205369656D656E7320436F6D70757465727320476D624820465343204B42205553420000C0837F000080D1FFC7837F000000000000000000000000000000000000C0F9FFC7837F00 EVIOCGVERSION 0 01000100 EVIOCGID 0 0300F80B04101001 EVIOCGPHYS(0) 26 7573622D303030303A30303A31342E302D322F696E7075743000476D624820465343204B42205553420000C0837F000080D1FFC7837F000000000000000000000000000000000000C0F9FFC7837F00 EVIOCGUNIQ(0) 1 0073622D303030303A30303A31342E302D322F696E7075743000476D624820465343204B42205553420000C0837F000080D1FFC7837F000000000000000000000000000000000000C0F9FFC7837F00 EVIOCGBIT(1) 96 FEFFFFFFFFFFFFFFFFFFCF01DFFF80E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EVIOCGBIT(3) 8 0000000000000000 EVIOCGBIT(2) 2 0000 EVIOCGBIT(5) 2 0000 EVIOCGBIT(17) 2 1F00 EVIOCGBIT(21) 16 00000000000000000000000000000000 EVIOCGPROP(0) 4 00000000 mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_recordings/bluetooth-magic-trackpad.umockdev0000644000015301777760000002030212322054247033537 0ustar pbusernogroup00000000000000P: /devices/pci0000:00/0000:00:14.0/usb3/3-4/3-4:1.0/bluetooth/hci0/hci0:21/input20/event13 N: input/event13 E: DEVNAME=/dev/input/event13 E: ID_INPUT=1 E: ID_INPUT_TOUCHPAD=1 E: MAJOR=13 E: MINOR=77 E: SUBSYSTEM=input A: dev=13:77 L: device=../../input20 P: /devices/pci0000:00/0000:00:14.0/usb3/3-4/3-4:1.0/bluetooth/hci0/hci0:21/input20 E: ABS=273800000000003 E: EV=10001b E: ID_FOR_SEAT=input-pci-0000_00_14_0-usb-0_4_1_0 E: ID_INPUT=1 E: ID_INPUT_TOUCHPAD=1 E: ID_PATH=pci-0000:00:14.0-usb-0:4:1.0 E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_4_1_0 E: KEY=e520 10000 0 0 0 0 E: MODALIAS=input:b0005v05ACp030Ee0160-e0,1,3,4,14,k110,145,148,14A,14D,14E,14F,ra0,1,2F,30,31,34,35,36,39,m4,lsfw E: MSC=10 E: NAME="Apple Wireless Trackpad" E: PHYS="b8:76:3f:78:eb:76" E: PRODUCT=5/5ac/30e/160 E: PROP=5 E: SUBSYSTEM=input E: TAGS=:seat: E: UNIQ="d8:a2:5e:f8:70:d6" L: device=../../hci0:21 A: modalias=input:b0005v05ACp030Ee0160-e0,1,3,4,14,k110,145,148,14A,14D,14E,14F,ra0,1,2F,30,31,34,35,36,39,m4,lsfw A: name=Apple Wireless Trackpad A: phys=b8:76:3f:78:eb:76 A: properties=5 A: uniq=d8:a2:5e:f8:70:d6 P: /devices/pci0000:00/0000:00:14.0/usb3/3-4/3-4:1.0/bluetooth/hci0/hci0:21 E: DEVTYPE=link E: SUBSYSTEM=bluetooth A: address=d8:a2:5e:f8:70:d6 L: device=../../hci0 A: type=ACL P: /devices/pci0000:00/0000:00:14.0/usb3/3-4/3-4:1.0/bluetooth/hci0 E: DEVTYPE=host E: SUBSYSTEM=bluetooth A: address=b8:76:3f:78:eb:76 L: device=../../../3-4:1.0 A: name=ubuntu-0 A: type=BR/EDR P: /devices/pci0000:00/0000:00:14.0/usb3/3-4/3-4:1.0 E: DEVTYPE=usb_interface E: DRIVER=btusb E: ID_USB_CLASS_FROM_DATABASE=Wireless E: ID_USB_PROTOCOL_FROM_DATABASE=Bluetooth E: ID_USB_SUBCLASS_FROM_DATABASE=Radio Frequency E: ID_VENDOR_FROM_DATABASE=Atheros Communications, Inc. E: INTERFACE=224/1/1 E: MODALIAS=usb:v0CF3p3004d0002dcE0dsc01dp01icE0isc01ip01in00 E: PRODUCT=cf3/3004/2 E: SUBSYSTEM=usb E: TYPE=224/1/1 A: bAlternateSetting= 0 A: bInterfaceClass=e0 A: bInterfaceNumber=00 A: bInterfaceProtocol=01 A: bInterfaceSubClass=01 A: bNumEndpoints=03 L: driver=../../../../../../bus/usb/drivers/btusb A: modalias=usb:v0CF3p3004d0002dcE0dsc01dp01icE0isc01ip01in00 A: supports_autosuspend=1 P: /devices/pci0000:00/0000:00:14.0/usb3/3-4 N: bus/usb/003/003=12011001E0010140F30C04300200010203010902B100020104E0320904000003E00101000705810310000107058202400001070502024000010904010002E001010007058301000001070503010000010904010102E001010007058301090001070503010900010904010202E001010007058301110001070503011100010904010302E001010007058301190001070503011900010904010402E001010007058301210001070503012100010904010502E00101000705830131000107050301310001 E: BUSNUM=003 E: DEVNAME=/dev/bus/usb/003/003 E: DEVNUM=003 E: DEVTYPE=usb_device E: DRIVER=usb E: ID_BUS=usb E: ID_MODEL=3004 E: ID_MODEL_ENC=3004 E: ID_MODEL_ID=3004 E: ID_REVISION=0002 E: ID_SERIAL=0cf3_3004 E: ID_USB_INTERFACES=:e00101: E: ID_VENDOR=0cf3 E: ID_VENDOR_ENC=0cf3 E: ID_VENDOR_FROM_DATABASE=Atheros Communications, Inc. E: ID_VENDOR_ID=0cf3 E: MAJOR=189 E: MINOR=258 E: PRODUCT=cf3/3004/2 E: SUBSYSTEM=usb E: TYPE=224/1/1 A: authorized=1 A: avoid_reset_quirk=0 A: bConfigurationValue=1 A: bDeviceClass=e0 A: bDeviceProtocol=01 A: bDeviceSubClass=01 A: bMaxPacketSize0=64 A: bMaxPower=100mA A: bNumConfigurations=1 A: bNumInterfaces= 2 A: bcdDevice=0002 A: bmAttributes=e0 A: busnum=3 A: configuration= H: descriptors=12011001E0010140F30C04300200010203010902B100020104E0320904000003E00101000705810310000107058202400001070502024000010904010002E001010007058301000001070503010000010904010102E001010007058301090001070503010900010904010202E001010007058301110001070503011100010904010302E001010007058301190001070503011900010904010402E001010007058301210001070503012100010904010502E00101000705830131000107050301310001 A: dev=189:258 A: devnum=3 A: devpath=4 L: driver=../../../../../bus/usb/drivers/usb A: idProduct=3004 A: idVendor=0cf3 A: ltm_capable=no A: maxchild=0 L: port=../3-0:1.0/port4 A: quirks=0x0 A: removable=removable A: speed=12 A: urbnum=2662 A: version= 1.10 P: /devices/pci0000:00/0000:00:14.0/usb3 N: bus/usb/003/001=12010002090001406B1D020013030302010109021900010100E0000904000001090000000705810304000C E: BUSNUM=003 E: DEVNAME=/dev/bus/usb/003/001 E: DEVNUM=001 E: DEVTYPE=usb_device E: DRIVER=usb E: ID_BUS=usb E: ID_FOR_SEAT=usb-pci-0000_00_14_0 E: ID_MODEL=xHCI_Host_Controller E: ID_MODEL_ENC=xHCI\x20Host\x20Controller E: ID_MODEL_FROM_DATABASE=2.0 root hub E: ID_MODEL_ID=0002 E: ID_PATH=pci-0000:00:14.0 E: ID_PATH_TAG=pci-0000_00_14_0 E: ID_REVISION=0313 E: ID_SERIAL=Linux_3.13.0-8-generic_xhci_hcd_xHCI_Host_Controller_0000:00:14.0 E: ID_SERIAL_SHORT=0000:00:14.0 E: ID_USB_INTERFACES=:090000: E: ID_VENDOR=Linux_3.13.0-8-generic_xhci_hcd E: ID_VENDOR_ENC=Linux\x203.13.0-8-generic\x20xhci_hcd E: ID_VENDOR_FROM_DATABASE=Linux Foundation E: ID_VENDOR_ID=1d6b E: MAJOR=189 E: MINOR=256 E: PRODUCT=1d6b/2/313 E: SUBSYSTEM=usb E: TAGS=:seat: E: TYPE=9/0/1 A: authorized=1 A: authorized_default=1 A: avoid_reset_quirk=0 A: bConfigurationValue=1 A: bDeviceClass=09 A: bDeviceProtocol=01 A: bDeviceSubClass=00 A: bMaxPacketSize0=64 A: bMaxPower=0mA A: bNumConfigurations=1 A: bNumInterfaces= 1 A: bcdDevice=0313 A: bmAttributes=e0 A: busnum=3 A: configuration= H: descriptors=12010002090001406B1D020013030302010109021900010100E0000904000001090000000705810304000C A: dev=189:256 A: devnum=1 A: devpath=0 L: driver=../../../../bus/usb/drivers/usb A: idProduct=0002 A: idVendor=1d6b A: ltm_capable=no A: manufacturer=Linux 3.13.0-8-generic xhci_hcd A: maxchild=14 A: product=xHCI Host Controller A: quirks=0x0 A: removable=unknown A: serial=0000:00:14.0 A: speed=480 A: urbnum=178 A: version= 2.00 P: /devices/pci0000:00/0000:00:14.0 E: DRIVER=xhci_hcd E: ID_MODEL_FROM_DATABASE=Lynx Point USB xHCI Host Controller E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller E: ID_VENDOR_FROM_DATABASE=Intel Corporation E: MODALIAS=pci:v00008086d00008C31sv00001558sd00007410bc0Csc03i30 E: PCI_CLASS=C0330 E: PCI_ID=8086:8C31 E: PCI_SLOT_NAME=0000:00:14.0 E: PCI_SUBSYS_ID=1558:7410 E: SUBSYSTEM=pci A: broken_parity_status=0 A: class=0x0c0330 H: config=8680318C060490020430030C000000000400E2F700000000000000000000000000000000000000000000000058151074000000007000000000000000FF010000FD01368089C60F8000000000000000009F6E8807000000000000000000000000302000000000000000000000000000000180C2C108000000000000000000000005008700F802E0FE000000000000000000000000000000000000000000000000400100000000000000000000000000000F000100000000000000000000000000030420C0030C3000030C300000000000FF3F0000FF3F00003F0000003F000000A0000000D03C000000000000D8D8D8080000000000000000B10F050800000000 A: consistent_dma_mask_bits=64 A: d3cold_allowed=1 A: device=0x8c31 A: dma_mask_bits=64 L: driver=../../../bus/pci/drivers/xhci_hcd A: enabled=1 A: irq=42 A: local_cpulist=0-7 A: local_cpus=00000000,00000000,00000000,00000000,00000000,00000000,00000000,000000ff A: modalias=pci:v00008086d00008C31sv00001558sd00007410bc0Csc03i30 A: msi_bus= A: numa_node=-1 A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 7 7 2112 7\nxHCI ring segments 40 40 4096 40\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0 A: resource=0x00000000f7e20000 0x00000000f7e2ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000 A: subsystem_device=0x7410 A: subsystem_vendor=0x1558 A: vendor=0x8086 mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_recordings/standard-drm-devices.umockdev0000644000015301777760000001650012322054223032664 0ustar pbusernogroup00000000000000P: /devices/pci0000:00/0000:00:02.0/drm/card1/card1-HDMI-A-1 E: SUBSYSTEM=drm A: dpms=On H: edid=00FFFFFFFFFFFF0010AC16F04C574B300415010380342078EA1EC5AE4F34B1260E5054A54B008180A940D100714F0101010101010101283C80A070B023403020360006442100001A000000FF00483339304D31314A304B574C0A000000FC0044454C4C2055323431300A2020000000FD00384C1E5111000A202020202020013E020329F15090050403020716011F121314201511062309070767030C001000382D83010000E3050301023A801871382D40582C450006442100001E011D8018711C1620582C250006442100009E011D007251D01E206E28550006442100001E8C0AD08A20E02D10103E960006442100001800000000000000000000000000003E A: enabled=enabled A: modes=1920x1200\n1920x1080\n1920x1080\n1920x1080\n1920x1080i\n1920x1080i\n1600x1200\n1280x1024\n1280x1024\n1152x864\n1280x720\n1280x720\n1440x576i\n1024x768\n1024x768\n1440x480i\n800x600\n800x600\n720x576\n720x480\n640x480\n640x480\n640x480\n720x400 A: status=connected P: /devices/pci0000:00/0000:00:02.0/drm/card1 N: dri/card1 E: DEVNAME=/dev/dri/card1 E: DEVTYPE=drm_minor E: ID_FOR_SEAT=drm-pci-0000_00_02_0 E: ID_PATH=pci-0000:00:02.0 E: ID_PATH_TAG=pci-0000_00_02_0 E: MAJOR=226 E: MINOR=1 E: SUBSYSTEM=drm E: TAGS=:seat:uaccess: A: dev=226:1 A: gt_RP0_freq_mhz=1200 A: gt_RP1_freq_mhz=650 A: gt_RPn_freq_mhz=650 A: gt_cur_freq_mhz=1200 A: gt_max_freq_mhz=1200 A: gt_min_freq_mhz=650 P: /devices/pci0000:00/0000:00:02.0 E: DRIVER=i915 E: ID_MODEL_FROM_DATABASE=2nd Generation Core Processor Family Integrated Graphics Controller E: ID_PCI_CLASS_FROM_DATABASE=Display controller E: ID_PCI_INTERFACE_FROM_DATABASE=VGA controller E: ID_PCI_SUBCLASS_FROM_DATABASE=VGA compatible controller E: ID_VENDOR_FROM_DATABASE=Intel Corporation E: MODALIAS=pci:v00008086d00000116sv00001028sd000004C1bc03sc00i00 E: PCI_CLASS=30000 E: PCI_ID=8086:0116 E: PCI_SLOT_NAME=0000:00:02.0 E: PCI_SUBSYS_ID=1028:04C1 E: SUBSYSTEM=pci A: boot_vga=1 A: broken_parity_status=0 A: class=0x030000 H: config=86801601070490000900000300000000040000E0000000000C0000D0000000000150000000000000000000002810C1040000000090000000000000000B010000 A: consistent_dma_mask_bits=40 A: d3cold_allowed=1 A: device=0x0116 A: dma_mask_bits=40 A: irq=50 A: local_cpulist=0-3 A: local_cpus=00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f A: modalias=pci:v00008086d00000116sv00001028sd000004C1bc03sc00i00 A: msi_bus= A: numa_node=-1 A: resource=0x00000000e0000000 0x00000000e03fffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x00000000d0000000 0x00000000dfffffff 0x000000000014220c\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000005000 0x000000000000503f 0x0000000000040101\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000002\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000 A: subsystem_device=0x04c1 A: subsystem_vendor=0x1028 A: vendor=0x8086 P: /devices/pci0000:00/0000:00:01.0/0000:01:00.0/drm/card0 N: dri/card0 E: DEVNAME=/dev/dri/card0 E: DEVTYPE=drm_minor E: ID_FOR_SEAT=drm-pci-0000_01_00_0 E: ID_PATH=pci-0000:01:00.0 E: ID_PATH_TAG=pci-0000_01_00_0 E: MAJOR=226 E: MINOR=0 E: PRIMARY_DEVICE_FOR_DISPLAY=1 E: SUBSYSTEM=drm E: TAGS=:seat:uaccess: A: dev=226:0 P: /devices/pci0000:00/0000:00:01.0/0000:01:00.0 E: DRIVER=radeon E: ID_MODEL_FROM_DATABASE=Whistler [Radeon HD 6600M/6700M/7600M Series] E: ID_PCI_CLASS_FROM_DATABASE=Display controller E: ID_PCI_INTERFACE_FROM_DATABASE=VGA controller E: ID_PCI_SUBCLASS_FROM_DATABASE=VGA compatible controller E: ID_VENDOR_FROM_DATABASE=Advanced Micro Devices, Inc. [AMD/ATI] E: MODALIAS=pci:v00001002d00006741sv00001028sd000004C1bc03sc00i00 E: PCI_CLASS=30000 E: PCI_ID=1002:6741 E: PCI_SLOT_NAME=0000:01:00.0 E: PCI_SUBSYS_ID=1028:04C1 E: SUBSYSTEM=pci A: boot_vga=0 A: broken_parity_status=0 A: class=0x030000 H: config=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF A: consistent_dma_mask_bits=40 A: d3cold_allowed=1 A: device=0x6741 A: dma_mask_bits=40 A: irq=49 A: local_cpulist=0-3 A: local_cpus=00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f A: modalias=pci:v00001002d00006741sv00001028sd000004C1bc03sc00i00 A: msi_bus= A: numa_node=-1 A: power_method=profile A: power_profile=default A: resource=0x00000000c0000000 0x00000000cfffffff 0x000000000014220c\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x00000000e1700000 0x00000000e171ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000004000 0x00000000000040ff 0x0000000000040101\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x00000000e1720000 0x00000000e173ffff 0x000000000004e200\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000 A: subsystem_device=0x04c1 A: subsystem_vendor=0x1028 A: vendor=0x1002 P: /devices/pci0000:00/0000:00:01.0 E: DRIVER=pcieport E: ID_MODEL_FROM_DATABASE=Xeon E3-1200/2nd Generation Core Processor Family PCI Express Root Port E: ID_PCI_CLASS_FROM_DATABASE=Bridge E: ID_PCI_INTERFACE_FROM_DATABASE=Normal decode E: ID_PCI_SUBCLASS_FROM_DATABASE=PCI bridge E: ID_VENDOR_FROM_DATABASE=Intel Corporation E: MODALIAS=pci:v00008086d00000101sv00008086sd00002010bc06sc04i00 E: PCI_CLASS=60400 E: PCI_ID=8086:0101 E: PCI_SLOT_NAME=0000:00:01.0 E: PCI_SUBSYS_ID=8086:2010 E: SUBSYSTEM=pci A: broken_parity_status=0 A: class=0x060400 H: config=868001010704100009000406100081000000000000000000000101004040000070E170E101C0F1CF00000000000000000000000088000000000000000B010000 A: consistent_dma_mask_bits=32 A: d3cold_allowed=0 A: device=0x0101 A: dma_mask_bits=32 A: irq=40 A: local_cpulist=0-3 A: local_cpus=00000000,00000000,00000000,00000000,00000000,00000000,00000000,0000000f A: modalias=pci:v00008086d00000101sv00008086sd00002010bc06sc04i00 A: msi_bus=1 A: numa_node=-1 A: resource=0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000004000 0x0000000000004fff 0x0000000000000100\n0x00000000e1700000 0x00000000e17fffff 0x0000000000000200\n0x00000000c0000000 0x00000000cfffffff 0x0000000000102201\n0x0000000000000000 0x0000000000000000 0x0000000000000000 A: subsystem_device=0x2010 A: subsystem_vendor=0x8086 A: vendor=0x8086 mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_recordings/synaptics-touchpad.ioctl0000644000015301777760000000522512322054247032013 0ustar pbusernogroup00000000000000@DEV /dev/input/event12 EVIOCGNAME(0) 27 53796E50532F322053796E61707469637320546F756368506164000000000000200B0050157F0000C895BE6B157F0000C0080050157F0000C0F4275D157F0000F03FD30100000000F523476D157F00 EVIOCGVERSION 0 01000100 EVIOCGID 0 110002000700B101 EVIOCGPHYS(0) 22 697361303036302F736572696F322F696E707574300068506164000000000000200B0050157F0000C895BE6B157F0000C0080050157F0000C0F4275D157F0000F03FD30100000000F523476D157F00 EVIOCGBIT(1) 96 0000000000000000000000000000000000000000000000000000000000000000000001000000000020E5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EVIOCGBIT(3) 8 0300001100806006 EVIOCGBIT(2) 2 0000 EVIOCGBIT(5) 2 0000 EVIOCGBIT(17) 2 0000 EVIOCGBIT(21) 16 00000000000000000000000000000000 EVIOCGPROP(0) 4 05000000 EVIOCGABS(53) 0 00000000C00500003016000008000000000000002E000000 EVIOCGABS(54) 0 00000000800500007812000008000000000000003E000000 EVIOCGABS(58) 0 0000000000000000FF000000000000000000000000000000 EVIOCGABS(57) 0 0000000000000000FFFF0000000000000000000000000000 EVIOCGABS(47) 0 000000000000000001000000000000000000000000000000 EVIOCGKEY(0) 96 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EVIOCGNAME(0) 27 53796E50532F322053796E61707469637320546F756368506164000000000000200B00A8A37F0000C8A59DC6A37F0000C00800A8A37F0000C00407B8A37F0000F0DF950100000000F53326C8A37F00 EVIOCGPHYS(0) 22 697361303036302F736572696F322F696E707574300068506164000000000000200B00A8A37F0000C8A59DC6A37F0000C00800A8A37F0000C00407B8A37F0000F0DF950100000000F53326C8A37F00 EVIOCGNAME(0) 18 48444120496E74656C20504348204D6963007574300068506164000000000000200B00CC1C7F0000C81563E91C7F0000C00800CC1C7F0000C074CCDA1C7F0000307F170200000000F5A3EBEA1C7F00 EVIOCGID 0 0000000000000000 EVIOCGPHYS(0) 5 414C5341006E74656C20504348204D6963007574300068506164000000000000200B00CC1C7F0000C81563E91C7F0000C00800CC1C7F0000C074CCDA1C7F0000307F170200000000F5A3EBEA1C7F00 EVIOCGBIT(1) 96 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 EVIOCGBIT(3) 8 0000000000000000 EVIOCGBIT(5) 2 1000 EVIOCGPROP(0) 4 00000000 EVIOCGNAME(0) 27 53796E50532F322053796E61707469637320546F756368506164000000000000200B00E8217F0000C885F704227F0000C00800E8217F0000C0E460F6217F0000303FF40100000000F5138006227F00 EVIOCGPHYS(0) 22 697361303036302F736572696F322F696E707574300068506164000000000000200B00E8217F0000C885F704227F0000C00800E8217F0000C0E460F6217F0000303FF40100000000F5138006227F00 mir-0.1.8+14.04.20140411/tests/mir_test_framework/CMakeLists.txt0000644000015301777760000000252712322054247024515 0ustar pbusernogroup00000000000000include_directories( ${Boost_INCLUDE_DIRS} ${GLESv2_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${UMOCKDEV_INCLUDE_DIRS} ) set( TEST_FRAMEWORK_SRCS cross_process_sync.cpp in_process_server.cpp testing_server_options.cpp input_testing_server_options.cpp input_testing_client_configuration.cpp stubbed_server_configuration.cpp testing_process_manager.cpp testing_client_options.cpp display_server_test_fixture.cpp process.cpp using_stub_client_platform.cpp udev_environment.cpp declarative_placement_strategy.cpp ) list(APPEND TEST_FRAMEWORK_SRCS socket_detect_server.cpp ) # Umockdev uses glib, which uses the deprecated "register" storage qualifier set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Dregister=") add_library( mir-test-framework STATIC ${TEST_FRAMEWORK_SRCS}) uses_android_input(mir-test-framework) target_link_libraries( mir-test-framework mirserver mirclient 3rd_party ${PROTOBUF_LIBRARIES} ${Boost_LIBRARIES} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${UMOCKDEV_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} # Link in pthread. ) add_custom_command(TARGET mir-test-framework POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/udev_recordings ${CMAKE_BINARY_DIR}/bin/udev_recordings COMMENT "Copying umockdev recordings to build dir..." ) mir-0.1.8+14.04.20140411/tests/mir_test_framework/display_server_test_fixture.cpp0000644000015301777760000000647412322054223030320 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_framework/testing_client_configuration.h" #include "src/client/mir_connection.h" namespace mc = mir::compositor; namespace mtf = mir_test_framework; mtf::TestingProcessManager mir_test_framework::DefaultDisplayServerTestFixture::process_manager; mtf::TestingServerConfiguration mir_test_framework::DefaultDisplayServerTestFixture::default_parameters; void DefaultDisplayServerTestFixture::launch_client_process(TestingClientConfiguration& config) { process_manager.launch_client_process(config, *default_parameters.the_options()); } void DefaultDisplayServerTestFixture::SetUpTestCase() { process_manager.launch_server_process(default_parameters); } void DefaultDisplayServerTestFixture::TearDown() { process_manager.tear_down_clients(); } void DefaultDisplayServerTestFixture::TearDownTestCase() { process_manager.tear_down_server(); } DefaultDisplayServerTestFixture::DefaultDisplayServerTestFixture() { } DefaultDisplayServerTestFixture::~DefaultDisplayServerTestFixture() {} void BespokeDisplayServerTestFixture::launch_server_process(TestingServerConfiguration& functor) { test_options = functor.the_options(); process_manager.launch_server_process(functor); } void BespokeDisplayServerTestFixture::launch_client_process(TestingClientConfiguration& config) { process_manager.launch_client_process(config, *test_options); } bool BespokeDisplayServerTestFixture::shutdown_server_process() { // TODO fix problem and remove this frig. // problem: sometimes the server exits normally with status // EXIT_SUCCESS but the test process sees TerminationReason::unknown auto const& result = process_manager.shutdown_server_process(); return result.succeeded() || result.reason == TerminationReason::unknown; } mtf::Result BespokeDisplayServerTestFixture::wait_for_shutdown_server_process() { return process_manager.wait_for_shutdown_server_process(); } void BespokeDisplayServerTestFixture::terminate_client_processes() { process_manager.terminate_client_processes(); } void BespokeDisplayServerTestFixture::kill_client_processes() { process_manager.kill_client_processes(); } void BespokeDisplayServerTestFixture::run_in_test_process( std::function const& run_code) { process_manager.run_in_test_process(run_code); } void BespokeDisplayServerTestFixture::SetUp() { } void BespokeDisplayServerTestFixture::TearDown() { process_manager.tear_down_all(); } BespokeDisplayServerTestFixture::BespokeDisplayServerTestFixture() : process_manager() { } BespokeDisplayServerTestFixture::~BespokeDisplayServerTestFixture() {} mir-0.1.8+14.04.20140411/tests/mir_test_framework/declarative_placement_strategy.cpp0000644000015301777760000000356112322054247030715 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/shell/surface_creation_parameters.h" #include "mir_test_framework/declarative_placement_strategy.h" namespace msh = mir::shell; namespace mtf = mir_test_framework; mtf::DeclarativePlacementStrategy::DeclarativePlacementStrategy( std::shared_ptr const& default_strategy, SurfaceGeometries const& positions, SurfaceDepths const& depths) : default_strategy(default_strategy), surface_geometries_by_name(positions), surface_depths_by_name(depths) { } msh::SurfaceCreationParameters mtf::DeclarativePlacementStrategy::place(msh::Session const& session, msh::SurfaceCreationParameters const& request_parameters) { auto placed = default_strategy->place(session, request_parameters); auto const& name = request_parameters.name; if (surface_geometries_by_name.find(name) != surface_geometries_by_name.end()) { auto const& geometry = surface_geometries_by_name[name]; placed.top_left = geometry.top_left; placed.size = geometry.size; } if (surface_depths_by_name.find(name) != surface_depths_by_name.end()) { placed.depth = surface_depths_by_name[name]; } return placed; } mir-0.1.8+14.04.20140411/tests/mir_test_framework/input_testing_client_configuration.cpp0000644000015301777760000000517412322054223031635 0ustar pbusernogroup00000000000000/* * 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 n */ #include "mir_test_framework/input_testing_client_configuration.h" #include "mir_test_framework/testing_process_manager.h" #include "mir_toolkit/mir_client_library.h" #include namespace mt = mir::test; namespace mtf = mir_test_framework; mtf::InputTestingClientConfiguration::InputTestingClientConfiguration( std::string const& client_name, mtf::CrossProcessSync const& input_cb_setup_fence) : client_name(client_name), input_cb_setup_fence(input_cb_setup_fence) { } namespace { void handle_input(MirSurface* /* surface */, MirEvent const* ev, void* context) { if (ev->type == mir_event_type_surface) return; auto handler = static_cast(context); handler->handle_input(ev); } } void mtf::InputTestingClientConfiguration::exec() { mt::WaitCondition events_received; MockInputHandler handler; expect_input(handler, events_received); auto connection = mir_connect_sync( mtf::test_socket_file().c_str(), client_name.c_str()); ASSERT_TRUE(connection != NULL); MirSurfaceParameters const request_params = { client_name.c_str(), surface_width, surface_height, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; auto surface = mir_connection_create_surface_sync(connection, &request_params); MirEventDelegate const event_delegate = { handle_input, &handler }; // Set this in the callback, not main thread to avoid missing test events mir_surface_set_event_handler(surface, &event_delegate); try { input_cb_setup_fence.try_signal_ready_for(); } catch (const std::runtime_error& e) { std::cout << e.what() << std::endl; } events_received.wait_for_at_most_seconds(60); mir_surface_release_sync(surface); mir_connection_release(connection); } mir-0.1.8+14.04.20140411/tests/mir_test_framework/udev_environment.cpp0000644000015301777760000001037612322054247026051 0ustar pbusernogroup00000000000000/* * 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: * Christopher James Halse Rogers */ #include "mir_test_framework/udev_environment.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace mtf = mir::mir_test_framework; namespace { std::string binary_path() { char buf[1024]; auto tmp = readlink("/proc/self/exe", buf, sizeof buf); if (tmp < 0) BOOST_THROW_EXCEPTION(boost::enable_error_info( std::runtime_error("Failed to find our executable path")) << boost::errinfo_errno(errno)); if (tmp > static_cast(sizeof(buf) - 1)) BOOST_THROW_EXCEPTION(std::runtime_error("Path to executable is too long!")); buf[tmp] = '\0'; return dirname(buf); } } mtf::UdevEnvironment::UdevEnvironment() : recordings_path(binary_path() + "/udev_recordings") { testbed = umockdev_testbed_new(); } mtf::UdevEnvironment::~UdevEnvironment() noexcept { g_object_unref(testbed); } std::string mtf::UdevEnvironment::add_device(char const* subsystem, char const* name, char const* parent, std::initializer_list attributes, std::initializer_list properties) { std::vector attrib(attributes); std::vector props(properties); attrib.push_back(nullptr); props.push_back(nullptr); gchar* syspath = umockdev_testbed_add_devicev(testbed, subsystem, name, parent, const_cast(attrib.data()), const_cast(props.data())); if (syspath == nullptr) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create mock udev device")); std::string retval(syspath); g_free(syspath); return retval; } void mtf::UdevEnvironment::remove_device(std::string const& device_path) { umockdev_testbed_uevent(testbed, device_path.c_str(), "remove"); umockdev_testbed_remove_device(testbed, device_path.c_str()); } void mtf::UdevEnvironment::emit_device_changed(std::string const& device_path) { umockdev_testbed_uevent(testbed, device_path.c_str(), "change"); } void mtf::UdevEnvironment::add_standard_device(std::string const& name) { auto descriptor_filename = recordings_path + "/" + name + ".umockdev"; GError* err = nullptr; if (!umockdev_testbed_add_from_file(testbed, descriptor_filename.c_str(), &err)) { BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Failed to create mock udev device: ") + err->message)); } auto ioctls_filename = recordings_path + "/" + name + ".ioctl"; struct stat sb; if (stat(ioctls_filename.c_str(), &sb) == 0) { if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) { if (!umockdev_testbed_load_ioctl(testbed, NULL, ioctls_filename.c_str(), &err)) { BOOST_THROW_EXCEPTION(std::runtime_error(std::string("Failed to load ioctl recording: ") + err->message)); } } } } mir-0.1.8+14.04.20140411/tests/mir_test_framework/input_testing_server_options.cpp0000644000015301777760000000470212322054223030505 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/input_testing_server_configuration.h" #include "mir/input/input_channel.h" #include "mir/scene/input_registrar.h" #include "mir/input/surface.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/frontend/shell.h" #include "mir/frontend/session.h" #include "mir/input/composite_event_filter.h" #include "mir_test/fake_event_hub.h" #include "mir_test/fake_event_hub_input_configuration.h" #include #include #include namespace mtf = mir_test_framework; namespace mf = mir::frontend; namespace mg = mir::graphics; namespace mi = mir::input; namespace mia = mi::android; namespace geom = mir::geometry; namespace mtd = mir::test::doubles; mtf::InputTestingServerConfiguration::InputTestingServerConfiguration() { } void mtf::InputTestingServerConfiguration::exec() { input_injection_thread = std::thread(std::mem_fn(&mtf::InputTestingServerConfiguration::inject_input), this); } void mtf::InputTestingServerConfiguration::on_exit() { input_injection_thread.join(); } std::shared_ptr mtf::InputTestingServerConfiguration::the_input_configuration() { if (!input_configuration) { std::shared_ptr null_cursor_listener{nullptr}; input_configuration = std::make_shared( the_composite_event_filter(), the_input_region(), null_cursor_listener, the_input_report()); fake_event_hub = input_configuration->the_fake_event_hub(); fake_event_hub->synthesize_builtin_keyboard_added(); fake_event_hub->synthesize_builtin_cursor_added(); fake_event_hub->synthesize_device_scan_complete(); } return input_configuration; } mir-0.1.8+14.04.20140411/tests/mir_test_framework/using_stub_client_platform.cpp0000644000015301777760000000412112322054247030075 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/using_stub_client_platform.h" #include "mir_test_framework/stub_client_connection_configuration.h" #include "src/client/mir_wait_handle.h" #include "src/client/mir_connection.h" #include "src/client/api_impl.h" namespace mtf = mir_test_framework; namespace { MirWaitHandle* mir_connect_override( char const *socket_file, char const *app_name, mir_connected_callback callback, void *context) { mtf::StubConnectionConfiguration conf(socket_file); auto connection = new MirConnection(conf); return connection->connect(app_name, callback, context); } void mir_connection_release_override(MirConnection *connection) { try { auto wait_handle = connection->disconnect(); wait_handle->wait_for_all(); } catch (std::exception const&) { // Really, we want try/finally, but that's not C++11 delete connection; throw; } delete connection; } } mtf::UsingStubClientPlatform::UsingStubClientPlatform() : prev_mir_connect_impl{mir_connect_impl}, prev_mir_connection_release_impl{mir_connection_release_impl} { mir_connect_impl = mir_connect_override; mir_connection_release_impl = mir_connection_release_override; } mtf::UsingStubClientPlatform::~UsingStubClientPlatform() { mir_connect_impl = prev_mir_connect_impl; mir_connection_release_impl = prev_mir_connection_release_impl; } mir-0.1.8+14.04.20140411/tests/mir_test_framework/stubbed_server_configuration.cpp0000644000015301777760000002111412322054247030417 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/stubbed_server_configuration.h" #include "mir/options/default_configuration.h" #include "mir/geometry/rectangle.h" #include "mir/graphics/buffer_ipc_packer.h" #include "mir/input/input_channel.h" #include "mir/input/input_manager.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/null_display_configuration.h" #include "mir_test_doubles/null_platform.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/stub_buffer_allocator.h" #include "mir_test_doubles/stub_display_buffer.h" #include "mir_test_doubles/stub_renderer.h" #ifdef ANDROID #include "mir_test_doubles/mock_android_native_buffer.h" #endif #include "mir/compositor/renderer.h" #include "mir/compositor/renderer_factory.h" #include "src/server/input/null_input_configuration.h" #include #include #include #include #include namespace geom = mir::geometry; namespace mc = mir::compositor; namespace mg = mir::graphics; namespace mi = mir::input; namespace mo = mir::options; namespace mtd = mir::test::doubles; namespace mtf = mir_test_framework; namespace { char const* dummy[] = {0}; int argc = 0; char const** argv = dummy; class StubFDBuffer : public mtd::StubBuffer { public: StubFDBuffer(mg::BufferProperties const& properties) : StubBuffer(properties), properties{properties} { fd = open("/dev/zero", O_RDONLY); if (fd < 0) BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to open dummy fd")) << boost::errinfo_errno(errno)); } std::shared_ptr native_buffer_handle() const override { #ifndef ANDROID auto native_buffer = std::make_shared(); native_buffer->data_items = 1; native_buffer->data[0] = 0xDEADBEEF; native_buffer->fd_items = 1; native_buffer->fd[0] = fd; native_buffer->width = properties.size.width.as_int(); native_buffer->height = properties.size.height.as_int(); native_buffer->flags = 0; if (properties.size.width.as_int() >= 800 && properties.size.height.as_int() >= 600 && properties.usage == mg::BufferUsage::hardware) { native_buffer->flags |= mir_buffer_flag_can_scanout; } #else auto native_buffer = std::make_shared(); auto anwb = native_buffer->anwb(); anwb->width = properties.size.width.as_int(); anwb->height = properties.size.width.as_int(); #endif return native_buffer; } ~StubFDBuffer() noexcept { close(fd); } private: int fd; const mg::BufferProperties properties; }; class StubGraphicBufferAllocator : public mtd::StubBufferAllocator { public: std::shared_ptr alloc_buffer(mg::BufferProperties const& properties) override { return std::make_shared(properties); } }; class StubDisplayConfiguration : public mtd::NullDisplayConfiguration { public: StubDisplayConfiguration(geom::Rectangle const& rect) : modes{mg::DisplayConfigurationMode{rect.size, 1.0f}} { } void for_each_output(std::function f) const override { mg::DisplayConfigurationOutput dummy_output_config{ mg::DisplayConfigurationOutputId{1}, mg::DisplayConfigurationCardId{0}, mg::DisplayConfigurationOutputType::vga, std::vector{mir_pixel_format_abgr_8888}, modes, 0, geom::Size{}, true, true, geom::Point{0,0}, 0, mir_pixel_format_abgr_8888, mir_power_mode_on, mir_orientation_normal}; f(dummy_output_config); } private: std::vector modes; }; class StubDisplay : public mtd::NullDisplay { public: StubDisplay() : rect{geom::Point{0,0}, geom::Size{1600,1600}}, display_buffer(rect) { } void for_each_display_buffer(std::function const& f) override { f(display_buffer); } std::unique_ptr configuration() const override { return std::unique_ptr( new StubDisplayConfiguration(rect) ); } private: geom::Rectangle rect; mtd::StubDisplayBuffer display_buffer; }; class StubGraphicPlatform : public mtd::NullPlatform { std::shared_ptr create_buffer_allocator( const std::shared_ptr& /*buffer_initializer*/) override { return std::make_shared(); } void fill_ipc_package(mg::BufferIPCPacker* packer, mg::Buffer const* buffer) const override { #ifndef ANDROID auto native_handle = buffer->native_buffer_handle(); for(auto i=0; idata_items; i++) { packer->pack_data(native_handle->data[i]); } for(auto i=0; ifd_items; i++) { packer->pack_fd(native_handle->fd[i]); } packer->pack_flags(native_handle->flags); #endif packer->pack_stride(buffer->stride()); packer->pack_size(buffer->size()); } std::shared_ptr create_display( std::shared_ptr const&, std::shared_ptr const&) override { return std::make_shared(); } }; class StubRendererFactory : public mc::RendererFactory { public: std::unique_ptr create_renderer_for(geom::Rectangle const&) { return std::unique_ptr(new mtd::StubRenderer()); } }; struct StubInputChannel : public mi::InputChannel { int client_fd() const { return 0; } int server_fd() const { return 0; } }; class StubInputManager : public mi::InputManager { public: void start() {} void stop() {} std::shared_ptr make_input_channel() { return std::make_shared(); } }; } mtf::StubbedServerConfiguration::StubbedServerConfiguration() : DefaultServerConfiguration([] { auto result = std::make_shared(::argc, ::argv); namespace po = boost::program_options; result->add_options() ("tests-use-real-graphics", po::value()->default_value(false), "Use real graphics in tests.") ("tests-use-real-input", po::value()->default_value(false), "Use real input in tests."); return result; }()) { } std::shared_ptr mtf::StubbedServerConfiguration::the_graphics_platform() { if (!graphics_platform) { graphics_platform = std::make_shared(); } return graphics_platform; } std::shared_ptr mtf::StubbedServerConfiguration::the_renderer_factory() { auto options = the_options(); if (options->get("tests-use-real-graphics")) return DefaultServerConfiguration::the_renderer_factory(); else return renderer_factory( [&]() { return std::make_shared(); }); } std::shared_ptr mtf::StubbedServerConfiguration::the_input_configuration() { auto options = the_options(); if (options->get("tests-use-real-input")) return DefaultServerConfiguration::the_input_configuration(); else return std::make_shared(); } int main(int argc, char** argv) { ::argc = std::remove_if( argv, argv+argc, [](char const* arg) { return !strncmp(arg, "--gtest_", 8); }) - argv; ::argv = const_cast(argv); ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } mir-0.1.8+14.04.20140411/tests/mir_test_framework/socket_detect_server.cpp0000644000015301777760000000252712322054223026661 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/detect_server.h" #include #include #include #include #include #include bool mir_test_framework::detect_server( std::string const& socket_file, std::chrono::milliseconds const& timeout) { auto limit = std::chrono::steady_clock::now() + timeout; bool error = false; struct stat file_status; do { if (error) { std::this_thread::sleep_for(std::chrono::milliseconds(0)); } error = stat(socket_file.c_str(), &file_status); } while (error && std::chrono::steady_clock::now() < limit); return !error; } mir-0.1.8+14.04.20140411/tests/mir_test_framework/cross_process_sync.cpp0000644000015301777760000001033112322054223026366 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/cross_process_sync.h" #include #include #include namespace mtf = mir_test_framework; namespace { const int read_fd = 0; const int write_fd = 1; struct UnexpectedValueErrorInfoTag {}; typedef boost::error_info errinfo_unexpected_value; } mtf::CrossProcessSync::CrossProcessSync() : counter(0) { if (::pipe(fds) < 0) { BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error("Failed to create pipe")) << boost::errinfo_errno(errno)); } } mtf::CrossProcessSync::CrossProcessSync(const CrossProcessSync& rhs) : counter(rhs.counter) { fds[0] = ::dup(rhs.fds[0]); fds[1] = ::dup(rhs.fds[1]); } mtf::CrossProcessSync::~CrossProcessSync() noexcept { ::close(fds[0]); ::close(fds[1]); } mtf::CrossProcessSync& mtf::CrossProcessSync::operator=(const mtf::CrossProcessSync& rhs) { ::close(fds[0]); ::close(fds[1]); fds[0] = ::dup(rhs.fds[0]); fds[1] = ::dup(rhs.fds[1]); counter = rhs.counter; return *this; } void mtf::CrossProcessSync::try_signal_ready_for() { try_signal_ready_for(std::chrono::minutes(2)); } void mtf::CrossProcessSync::try_signal_ready_for(const std::chrono::milliseconds& duration) { static const short empty_revents = 0; pollfd poll_fd[1] = { { fds[write_fd], POLLOUT, empty_revents } }; int rc = -1; if ((rc = ::poll(poll_fd, 1, duration.count())) < 0) { BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error("Error while polling pipe to become writable")) << boost::errinfo_errno(errno)); } else if (rc == 0) { throw std::runtime_error("Poll on writefd for pipe timed out"); } int value = 1; if (sizeof(value) != write(fds[write_fd], std::addressof(value), sizeof(value))) { BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error("Error while writing to pipe")) << boost::errinfo_errno(errno)); } } unsigned int mtf::CrossProcessSync::wait_for_signal_ready_for() { return wait_for_signal_ready_for(std::chrono::minutes(2)); } unsigned int mtf::CrossProcessSync::wait_for_signal_ready_for(const std::chrono::milliseconds& duration) { static const short empty_revents = 0; pollfd poll_fd[1] = { { fds[read_fd], POLLIN, empty_revents } }; int rc = -1; if ((rc = ::poll(poll_fd, 1, duration.count())) < 0) { BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error("Error while polling pipe to become readable")) << boost::errinfo_errno(errno)); } else if (rc == 0) { BOOST_THROW_EXCEPTION(std::runtime_error("Poll on readfd for pipe timed out")); } int value; if (sizeof(value) != read(fds[read_fd], std::addressof(value), sizeof(value))) { BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error("Error while reading from pipe")) << boost::errinfo_errno(errno)); } if (value != 1) { BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error("Read an unexpected value from pipe")) << errinfo_unexpected_value(value)); } counter += value; return counter; } void mtf::CrossProcessSync::signal_ready() { try_signal_ready_for(std::chrono::milliseconds{-1}); } unsigned int mtf::CrossProcessSync::wait_for_signal_ready() { return wait_for_signal_ready_for(std::chrono::milliseconds{-1}); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/0000755000015301777760000000000012322054703021267 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_client_input.cpp0000644000015301777760000006354612322054247025550 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/display.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/shell/placement_strategy.h" #include "mir/shell/surface_factory.h" #include "mir/shell/surface.h" #include "src/server/scene/session_container.h" #include "mir/shell/session.h" #include "src/server/scene/surface_controller.h" #include "src/server/scene/surface_stack_model.h" #include "src/server/input/android/android_input_manager.h" #include "src/server/input/android/android_input_targeter.h" #include "mir_toolkit/mir_client_library.h" #include "mir_test/fake_shared.h" #include "mir_test/fake_event_hub.h" #include "mir_test/event_factory.h" #include "mir_test/wait_condition.h" #include "mir_test/client_event_matchers.h" #include "mir_test_framework/cross_process_sync.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_framework/input_testing_server_configuration.h" #include "mir_test_framework/input_testing_client_configuration.h" #include "mir_test_framework/declarative_placement_strategy.h" #include #include #include #include #include #include namespace mi = mir::input; namespace mia = mi::android; namespace mis = mi::synthesis; namespace mf = mir::frontend; namespace msh = mir::shell; namespace ms = mir::scene; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace mt = mir::test; namespace mtd = mt::doubles; namespace mtf = mir_test_framework; namespace { std::shared_ptr make_event_producing_server(mtf::CrossProcessSync const& client_ready_fence, int number_of_clients, std::function const& produce_events, mtf::SurfaceGeometries const& client_geometries, mtf::SurfaceDepths const& client_depths) { struct ServerConfiguration : mtf::InputTestingServerConfiguration { mtf::CrossProcessSync input_cb_setup_fence; int const number_of_clients; std::function const produce_events; mtf::SurfaceGeometries const client_geometries; mtf::SurfaceDepths const client_depths; ServerConfiguration(mtf::CrossProcessSync const& input_cb_setup_fence, int number_of_clients, std::function const& produce_events, mtf::SurfaceGeometries const& client_geometries, mtf::SurfaceDepths const& client_depths) : input_cb_setup_fence(input_cb_setup_fence), number_of_clients(number_of_clients), produce_events(produce_events), client_geometries(client_geometries), client_depths(client_depths) { } std::shared_ptr the_shell_placement_strategy() override { return std::make_shared( InputTestingServerConfiguration::the_shell_placement_strategy(), client_geometries, client_depths); } void inject_input() { for (int i = 1; i < number_of_clients + 1; i++) EXPECT_EQ(i, input_cb_setup_fence.wait_for_signal_ready_for()); produce_events(*this); } }; return std::make_shared(client_ready_fence, number_of_clients, produce_events, client_geometries, client_depths); } std::shared_ptr make_event_producing_server(mtf::CrossProcessSync const& client_ready_fence, int number_of_clients, std::function const& produce_events) { return make_event_producing_server(client_ready_fence, number_of_clients, produce_events, mtf::SurfaceGeometries(), mtf::SurfaceDepths()); } std::shared_ptr make_event_expecting_client(std::string const& client_name, mtf::CrossProcessSync const& client_ready_fence, std::function const& expect_input) { struct EventReceivingClient : mtf::InputTestingClientConfiguration { std::function const expect_cb; EventReceivingClient(std::string const& client_name, mtf::CrossProcessSync const& client_ready_fence, std::function const& expect_cb) : InputTestingClientConfiguration(client_name, client_ready_fence), expect_cb(expect_cb) { } void expect_input(MockInputHandler &handler, mt::WaitCondition& events_received) override { expect_cb(handler, events_received); } }; return std::make_shared(client_name, client_ready_fence, expect_input); } std::shared_ptr make_event_expecting_client(mtf::CrossProcessSync const& client_ready_fence, std::function const& expect_input) { return make_event_expecting_client("input-test-client", client_ready_fence, expect_input); } } using TestClientInput = BespokeDisplayServerTestFixture; using MockHandler = mtf::InputTestingClientConfiguration::MockInputHandler; TEST_F(TestClientInput, clients_receive_key_input) { using namespace ::testing; static std::string const test_client_name = "1"; mtf::CrossProcessSync fence; auto server_config = make_event_producing_server(fence, 1, [&](mtf::InputTestingServerConfiguration& server) { int const num_events_produced = 3; for (int i = 0; i < num_events_produced; i++) server.fake_event_hub->synthesize_event(mis::a_key_down_event() .of_scancode(KEY_ENTER)); }); launch_server_process(*server_config); auto client_config = make_event_expecting_client(fence, [&](MockHandler& handler, mt::WaitCondition& events_received) { using namespace ::testing; InSequence seq; EXPECT_CALL(handler, handle_input(mt::KeyDownEvent())).Times(2); EXPECT_CALL(handler, handle_input(mt::KeyDownEvent())).Times(1) .WillOnce(mt::WakeUp(&events_received)); }); launch_client_process(*client_config); } TEST_F(TestClientInput, clients_receive_us_english_mapped_keys) { using namespace ::testing; static std::string const test_client_name = "1"; mtf::CrossProcessSync fence; auto server_config = make_event_producing_server(fence, 1, [&](mtf::InputTestingServerConfiguration& server) { server.fake_event_hub->synthesize_event(mis::a_key_down_event() .of_scancode(KEY_LEFTSHIFT)); server.fake_event_hub->synthesize_event(mis::a_key_down_event() .of_scancode(KEY_4)); }); launch_server_process(*server_config); auto client_config = make_event_expecting_client(fence, [&](MockHandler& handler, mt::WaitCondition& events_received) { using namespace ::testing; InSequence seq; EXPECT_CALL(handler, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_Shift_L)))).Times(1); EXPECT_CALL(handler, handle_input(AllOf(mt::KeyDownEvent(), mt::KeyOfSymbol(XKB_KEY_dollar)))).Times(1) .WillOnce(mt::WakeUp(&events_received)); }); launch_client_process(*client_config); } TEST_F(TestClientInput, clients_receive_motion_inside_window) { using namespace ::testing; static std::string const test_client_name = "1"; mtf::CrossProcessSync fence; auto server_config = make_event_producing_server(fence, 1, [&](mtf::InputTestingServerConfiguration& server) { server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(mtf::InputTestingClientConfiguration::surface_width - 1, mtf::InputTestingClientConfiguration::surface_height - 1)); server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(2,2)); }); launch_server_process(*server_config); auto client_config = make_event_expecting_client(fence, [&](MockHandler& handler, mt::WaitCondition& events_received) { using namespace ::testing; InSequence seq; // We should see the cursor enter EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(1); EXPECT_CALL(handler, handle_input( mt::MotionEventWithPosition(mtf::InputTestingClientConfiguration::surface_width - 1, mtf::InputTestingClientConfiguration::surface_height - 1))).Times(1) .WillOnce(mt::WakeUp(&events_received)); // But we should not receive an event for the second movement outside of our surface! }); launch_client_process(*client_config); } TEST_F(TestClientInput, clients_receive_button_events_inside_window) { using namespace ::testing; static std::string const test_client_name = "1"; mtf::CrossProcessSync fence; auto server_config = make_event_producing_server(fence, 1, [&](mtf::InputTestingServerConfiguration& server) { server.fake_event_hub->synthesize_event(mis::a_button_down_event() .of_button(BTN_LEFT).with_action(mis::EventAction::Down)); }); launch_server_process(*server_config); auto client_config = make_event_expecting_client(fence, [&](MockHandler& handler, mt::WaitCondition& events_received) { using namespace ::testing; InSequence seq; // The cursor starts at (0, 0). EXPECT_CALL(handler, handle_input(mt::ButtonDownEvent(0, 0))).Times(1) .WillOnce(mt::WakeUp(&events_received)); }); launch_client_process(*client_config); } TEST_F(TestClientInput, multiple_clients_receive_motion_inside_windows) { using namespace ::testing; static int const screen_width = 1000; static int const screen_height = 800; static int const client_height = screen_height/2; static int const client_width = screen_width/2; static std::string const test_client_1 = "1"; static std::string const test_client_2 = "2"; mtf::CrossProcessSync fence; static mtf::SurfaceGeometries positions; positions[test_client_1] = geom::Rectangle{geom::Point{0, 0}, geom::Size{client_width, client_height}}; positions[test_client_2] = geom::Rectangle{geom::Point{screen_width/2, screen_height/2}, geom::Size{client_width, client_height}}; auto server_config = make_event_producing_server(fence, 2, [&](mtf::InputTestingServerConfiguration& server) { // In the bounds of the first surface server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2-1, screen_height/2-1)); // In the bounds of the second surface server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2, screen_height/2)); }, positions, mtf::SurfaceDepths()); launch_server_process(*server_config); auto client_1 = make_event_expecting_client(test_client_1, fence, [&](MockHandler& handler, mt::WaitCondition& events_received) { InSequence seq; EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(1); EXPECT_CALL(handler, handle_input(mt::MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1); EXPECT_CALL(handler, handle_input(mt::HoverExitEvent())).Times(1) .WillOnce(mt::WakeUp(&events_received)); }); auto client_2 = make_event_expecting_client(test_client_2, fence, [&](MockHandler& handler, mt::WaitCondition& events_received) { InSequence seq; EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(1); EXPECT_CALL(handler, handle_input(mt::MotionEventWithPosition(client_width - 1, client_height - 1))).Times(1) .WillOnce(mt::WakeUp(&events_received)); }); launch_client_process(*client_1); launch_client_process(*client_2); } namespace { struct RegionApplyingSurfaceFactory : public msh::SurfaceFactory { RegionApplyingSurfaceFactory(std::shared_ptr real_factory, std::initializer_list const& input_rectangles) : underlying_factory(real_factory), input_rectangles(input_rectangles) { } std::shared_ptr create_surface( msh::Session* session, msh::SurfaceCreationParameters const& params, std::shared_ptr const& observer) override { auto surface = underlying_factory->create_surface(session, params, observer); surface->set_input_region(input_rectangles); return surface; } void destroy_surface(std::shared_ptr const& surface) override { underlying_factory->destroy_surface(surface); } std::shared_ptr const underlying_factory; std::vector const input_rectangles; }; } TEST_F(TestClientInput, clients_do_not_receive_motion_outside_input_region) { using namespace ::testing; static std::string const test_client_name = "1"; mtf::CrossProcessSync fence; static int const screen_width = 100; static int const screen_height = 100; static geom::Rectangle const screen_geometry{geom::Point{0, 0}, geom::Size{screen_width, screen_height}}; static std::initializer_list client_input_regions = { {geom::Point{0, 0}, {screen_width-80, screen_height}}, {geom::Point{screen_width-20, 0}, {screen_width-80, screen_height}} }; struct ServerConfiguration : mtf::InputTestingServerConfiguration { mtf::CrossProcessSync input_cb_setup_fence; ServerConfiguration(const mtf::CrossProcessSync& input_cb_setup_fence) : input_cb_setup_fence(input_cb_setup_fence) { } std::shared_ptr the_shell_placement_strategy() override { static mtf::SurfaceGeometries positions; positions[test_client_name] = screen_geometry; return std::make_shared( InputTestingServerConfiguration::the_shell_placement_strategy(), positions, mtf::SurfaceDepths()); } std::shared_ptr the_shell_surface_factory() override { return std::make_shared(InputTestingServerConfiguration::the_shell_surface_factory(), client_input_regions); } void inject_input() override { input_cb_setup_fence.wait_for_signal_ready_for(); // First we will move the cursor in to the input region on the left side of the window. We should see a click here fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 1)); fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down)); fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT)); // Now in to the dead zone in the center of the window. We should not see a click here. fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(49, 49)); fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down)); fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT)); // Now in to the right edge of the window, in the right input region. Again we should see a click fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(49, 49)); fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down)); fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT)); } } server_config{fence}; launch_server_process(server_config); auto client_config = make_event_expecting_client(test_client_name, fence, [&](MockHandler& handler, mt::WaitCondition& events_received) { EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(AnyNumber()); EXPECT_CALL(handler, handle_input(mt::HoverExitEvent())).Times(AnyNumber()); EXPECT_CALL(handler, handle_input(mt::MovementEvent())).Times(AnyNumber()); { // We should see two of the three button pairs. InSequence seq; EXPECT_CALL(handler, handle_input(mt::ButtonDownEvent(1, 1))).Times(1); EXPECT_CALL(handler, handle_input(mt::ButtonUpEvent(1, 1))).Times(1); EXPECT_CALL(handler, handle_input(mt::ButtonDownEvent(99, 99))).Times(1); EXPECT_CALL(handler, handle_input(mt::ButtonUpEvent(99, 99))).Times(1) .WillOnce(mt::WakeUp(&events_received)); } }); launch_client_process(*client_config); } TEST_F(TestClientInput, scene_obscure_motion_events_by_stacking) { using namespace ::testing; static std::string const test_client_name_1 = "1"; static std::string const test_client_name_2 = "2"; mtf::CrossProcessSync fence; static int const screen_width = 100; static int const screen_height = 100; static geom::Rectangle const screen_geometry{geom::Point{0, 0}, geom::Size{screen_width, screen_height}}; static mtf::SurfaceGeometries positions; positions[test_client_name_1] = screen_geometry; auto smaller_geometry = screen_geometry; smaller_geometry.size.width = geom::Width{screen_width/2}; positions[test_client_name_2] = smaller_geometry; static mtf::SurfaceDepths depths; depths[test_client_name_1] = ms::DepthId{0}; depths[test_client_name_2] = ms::DepthId{1}; auto server_config = make_event_producing_server(fence, 2, [&](mtf::InputTestingServerConfiguration& server) { // First we will move the cursor in to the region where client 2 obscures client 1 server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1, 1)); server.fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down)); server.fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT)); // Now we move to the unobscured region of client 1 server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(50, 0)); server.fake_event_hub->synthesize_event(mis::a_button_down_event().of_button(BTN_LEFT).with_action(mis::EventAction::Down)); server.fake_event_hub->synthesize_event(mis::a_button_up_event().of_button(BTN_LEFT)); }, positions, depths); launch_server_process(*server_config); auto client_config_1 = make_event_expecting_client(test_client_name_1, fence, [&](MockHandler& handler, mt::WaitCondition& events_received) { EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(AnyNumber()); EXPECT_CALL(handler, handle_input(mt::HoverExitEvent())).Times(AnyNumber()); EXPECT_CALL(handler, handle_input(mt::MovementEvent())).Times(AnyNumber()); { // We should only see one button event sequence. InSequence seq; EXPECT_CALL(handler, handle_input(mt::ButtonDownEvent(51, 1))).Times(1); EXPECT_CALL(handler, handle_input(mt::ButtonUpEvent(51, 1))).Times(1) .WillOnce(mt::WakeUp(&events_received)); } }); auto client_config_2 = make_event_expecting_client(test_client_name_2, fence, [&](MockHandler& handler, mt::WaitCondition& events_received) { EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(AnyNumber()); EXPECT_CALL(handler, handle_input(mt::HoverExitEvent())).Times(AnyNumber()); EXPECT_CALL(handler, handle_input(mt::MovementEvent())).Times(AnyNumber()); { // Likewise we should only see one button sequence. InSequence seq; EXPECT_CALL(handler, handle_input(mt::ButtonDownEvent(1, 1))).Times(1); EXPECT_CALL(handler, handle_input(mt::ButtonUpEvent(1, 1))).Times(1) .WillOnce(mt::WakeUp(&events_received)); } }); launch_client_process(*client_config_1); launch_client_process(*client_config_2); } namespace { ACTION_P(SignalFence, fence) { fence->try_signal_ready_for(); } } TEST_F(TestClientInput, hidden_clients_do_not_receive_pointer_events) { using namespace ::testing; static std::string const test_client_name = "1"; static std::string const test_client_2_name = "2"; mtf::CrossProcessSync fence, first_client_ready_fence, second_client_done_fence; static mtf::SurfaceDepths depths; depths[test_client_name] = ms::DepthId{0}; depths[test_client_2_name] = ms::DepthId{1}; auto server_config = make_event_producing_server(fence, 2, [&](mtf::InputTestingServerConfiguration& server) { // We send one event and then hide the surface on top before sending the next. // So we expect each of the two surfaces to receive one even server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1)); // We use a fence to ensure we do not hide the client // before event dispatch occurs second_client_done_fence.wait_for_signal_ready_for(); server.the_session_container()->for_each([&](std::shared_ptr const& session) -> void { if (session->name() == test_client_2_name) session->hide(); }); server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(1,1)); }, mtf::SurfaceGeometries(), depths); launch_server_process(*server_config); auto client_config_1 = make_event_expecting_client(test_client_name, fence, [&](MockHandler& handler, mt::WaitCondition& events_received) { EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(AnyNumber()); EXPECT_CALL(handler, handle_input(mt::HoverExitEvent())).Times(AnyNumber()); EXPECT_CALL(handler, handle_input(mt::MotionEventWithPosition(2, 2))).Times(1) .WillOnce(mt::WakeUp(&events_received)); }); auto client_config_2 = make_event_expecting_client(test_client_2_name, fence, [&](MockHandler& handler, mt::WaitCondition& events_received) { EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(AnyNumber()); EXPECT_CALL(handler, handle_input(mt::HoverExitEvent())).Times(AnyNumber()); EXPECT_CALL(handler, handle_input(mt::MotionEventWithPosition(1, 1))).Times(1) .WillOnce(DoAll(SignalFence(&second_client_done_fence), mt::WakeUp(&events_received))); }); launch_client_process(*client_config_1); launch_client_process(*client_config_2); } TEST_F(TestClientInput, clients_receive_motion_within_co_ordinate_system_of_window) { using namespace ::testing; static int const screen_width = 1000; static int const screen_height = 800; static int const client_height = screen_height/2; static int const client_width = screen_width/2; static std::string const test_client = "tc"; mtf::CrossProcessSync fence; static mtf::SurfaceGeometries positions; positions[test_client] = geom::Rectangle{geom::Point{screen_width/2, screen_height/2}, geom::Size{client_width, client_height}}; auto server_config = make_event_producing_server(fence, 1, [&](mtf::InputTestingServerConfiguration& server) { server.the_session_container()->for_each([&](std::shared_ptr const& session) -> void { session->default_surface()->move_to(geom::Point{screen_width/2-40, screen_height/2-80}); }); server.fake_event_hub->synthesize_event(mis::a_motion_event().with_movement(screen_width/2+40, screen_height/2+90)); }, positions, mtf::SurfaceDepths()); launch_server_process(*server_config); auto client = make_event_expecting_client(test_client, fence, [&](MockHandler& handler, mt::WaitCondition& events_received) { InSequence seq; EXPECT_CALL(handler, handle_input(mt::HoverEnterEvent())).Times(1); EXPECT_CALL(handler, handle_input(mt::MotionEventWithPosition(80, 170))).Times(AnyNumber()) .WillOnce(mt::WakeUp(&events_received)); }); launch_client_process(*client); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_focus_selection.cpp0000644000015301777760000001040612322054223026214 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "src/server/scene/session_container.h" #include "src/server/shell/consuming_placement_strategy.h" #include "src/server/shell/organising_surface_factory.h" #include "src/server/scene/session_manager.h" #include "mir/graphics/display.h" #include "mir/shell/input_targeter.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_doubles/mock_focus_setter.h" #include "mir_test_doubles/mock_input_targeter.h" #include #include namespace mf = mir::frontend; namespace msh = mir::shell; namespace mi = mir::input; namespace mt = mir::test; namespace mtd = mt::doubles; namespace mt = mir::test; namespace mtf = mir_test_framework; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); } namespace { struct SurfaceCreatingClient : mtf::TestingClientConfiguration { void exec() { connection = mir_connect_sync( mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; surface = mir_connection_create_surface_sync(connection, &request_params); mir_connection_release(connection); } MirConnection* connection; MirSurface* surface; }; } namespace { MATCHER(NonNullSession, "") { return arg != std::shared_ptr(); } } TEST_F(BespokeDisplayServerTestFixture, sessions_creating_surface_receive_focus) { struct ServerConfig : TestingServerConfiguration { std::shared_ptr the_shell_focus_setter() override { return shell_focus_setter( [] { using namespace ::testing; auto focus_setter = std::make_shared(); { InSequence seq; // Once on application registration and once on surface creation EXPECT_CALL(*focus_setter, set_focus_to(NonNullSession())).Times(2); // Focus is cleared when the session is closed EXPECT_CALL(*focus_setter, set_focus_to(_)).Times(1); } // TODO: Counterexample ~racarr return focus_setter; }); } } server_config; launch_server_process(server_config); SurfaceCreatingClient client; launch_client_process(client); } TEST_F(BespokeDisplayServerTestFixture, surfaces_receive_input_focus_when_created) { struct ServerConfig : TestingServerConfiguration { std::shared_ptr targeter; bool expected; ServerConfig() : targeter(std::make_shared()), expected(false) { } std::shared_ptr the_input_targeter() override { using namespace ::testing; if (!expected) { EXPECT_CALL(*targeter, focus_cleared()).Times(AtLeast(0)); { InSequence seq; EXPECT_CALL(*targeter, focus_changed(_)).Times(1); expected = true; } } return targeter; } } server_config; launch_server_process(server_config); SurfaceCreatingClient client; launch_client_process(client); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_client_library_drm.cpp0000644000015301777760000000364312322054223026701 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/display_server_test_fixture.h" #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/mir_client_library_drm.h" #include namespace mtf = mir_test_framework; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); } using MirClientLibraryDrmTest = DefaultDisplayServerTestFixture; TEST_F(MirClientLibraryDrmTest, sets_gbm_device_in_platform_data) { struct ClientConfig : TestingClientConfiguration { void exec() { auto connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection); EXPECT_TRUE(mir_connection_is_valid(connection)); struct gbm_device* dev = reinterpret_cast(connection); mir_connection_drm_set_gbm_device(connection, dev); MirPlatformPackage pkg; mir_connection_get_platform(connection, &pkg); EXPECT_EQ(sizeof(dev) / sizeof(int), static_cast(pkg.data_items)); EXPECT_EQ(dev, *reinterpret_cast(&pkg.data[0])); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_client_screencast.cpp0000644000015301777760000002166712322054247026541 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_screencast.h" #include "mir_toolkit/mir_client_library.h" #include "mir_test_framework/stubbed_server_configuration.h" #include "mir_test_framework/in_process_server.h" #include "mir_test_framework/using_stub_client_platform.h" #include "mir_test_doubles/null_display_changer.h" #include "mir_test_doubles/stub_display_configuration.h" #include "mir_test_doubles/stub_buffer.h" #include "mir_test_doubles/mock_screencast.h" #include "mir_test_doubles/stub_session_authorizer.h" #include "mir_test/fake_shared.h" #include #include namespace mtf = mir_test_framework; namespace mtd = mir::test::doubles; namespace mg = mir::graphics; namespace mf = mir::frontend; namespace mt = mir::test; namespace geom = mir::geometry; namespace { class StubChanger : public mtd::NullDisplayChanger { public: StubChanger() : stub_display_config{{{connected, !used}, {connected, used}}} { } std::shared_ptr active_configuration() override { return mt::fake_shared(stub_display_config); } mtd::StubDisplayConfig stub_display_config; private: static bool const connected; static bool const used; }; bool const StubChanger::connected{true}; bool const StubChanger::used{true}; struct StubServerConfig : mir_test_framework::StubbedServerConfiguration { std::shared_ptr the_frontend_display_changer() override { return mt::fake_shared(stub_changer); } std::shared_ptr the_screencast() override { return mt::fake_shared(mock_screencast); } StubChanger stub_changer; mtd::MockScreencast mock_screencast; }; class MirScreencastTest : public mir_test_framework::InProcessServer { public: mir::DefaultServerConfiguration& server_config() override { return server_config_; } mtd::MockScreencast& mock_screencast() { return server_config_.mock_screencast; } StubServerConfig server_config_; mtf::UsingStubClientPlatform using_stub_client_platform; MirScreencastParameters default_screencast_params { {0, 0, 1, 1}, 1, 1, mir_pixel_format_abgr_8888}; }; } TEST_F(MirScreencastTest, creation_with_invalid_connection_fails) { using namespace testing; auto screencast = mir_connection_create_screencast_sync(nullptr, &default_screencast_params); ASSERT_EQ(nullptr, screencast); } TEST_F(MirScreencastTest, contacts_server_screencast_for_create_and_release) { using namespace testing; auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); ASSERT_TRUE(mir_connection_is_valid(connection)); mf::ScreencastSessionId const screencast_session_id{99}; InSequence seq; EXPECT_CALL(mock_screencast(), create_session(_, _, _)) .WillOnce(Return(screencast_session_id)); EXPECT_CALL(mock_screencast(), capture(screencast_session_id)) .WillOnce(Return(std::make_shared())); EXPECT_CALL(mock_screencast(), destroy_session(screencast_session_id)); auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params); ASSERT_NE(nullptr, screencast); mir_screencast_release_sync(screencast); mir_connection_release(connection); } TEST_F(MirScreencastTest, contacts_server_screencast_with_provided_params) { using namespace testing; auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); ASSERT_TRUE(mir_connection_is_valid(connection)); mf::ScreencastSessionId const screencast_session_id{99}; geom::Size const size{default_screencast_params.width, default_screencast_params.height}; geom::Rectangle const region { {default_screencast_params.region.left, default_screencast_params.region.top}, {default_screencast_params.region.width, default_screencast_params.region.height}}; MirPixelFormat pixel_format {default_screencast_params.pixel_format}; InSequence seq; EXPECT_CALL(mock_screencast(), create_session(region, size, pixel_format)) .WillOnce(Return(screencast_session_id)); EXPECT_CALL(mock_screencast(), capture(_)) .WillOnce(Return(std::make_shared())); EXPECT_CALL(mock_screencast(), destroy_session(_)); auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params); ASSERT_NE(nullptr, screencast); mir_screencast_release_sync(screencast); mir_connection_release(connection); } TEST_F(MirScreencastTest, creation_with_invalid_params_fails) { using namespace testing; auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); ASSERT_TRUE(mir_connection_is_valid(connection)); MirScreencastParameters params = default_screencast_params; params.width = params.height = 0; auto screencast = mir_connection_create_screencast_sync(connection, ¶ms); ASSERT_EQ(nullptr, screencast); params = default_screencast_params; params.region.width = params.region.height = 0; screencast = mir_connection_create_screencast_sync(connection, ¶ms); ASSERT_EQ(nullptr, screencast); params = default_screencast_params; params.pixel_format = mir_pixel_format_invalid; screencast = mir_connection_create_screencast_sync(connection, ¶ms); ASSERT_EQ(nullptr, screencast); mir_connection_release(connection); } TEST_F(MirScreencastTest, gets_valid_egl_native_window) { using namespace testing; auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); ASSERT_TRUE(mir_connection_is_valid(connection)); mf::ScreencastSessionId const screencast_session_id{99}; InSequence seq; EXPECT_CALL(mock_screencast(), create_session(_, _, _)) .WillOnce(Return(screencast_session_id)); EXPECT_CALL(mock_screencast(), capture(_)) .WillOnce(Return(std::make_shared())); EXPECT_CALL(mock_screencast(), destroy_session(_)); auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params); ASSERT_NE(nullptr, screencast); auto egl_native_window = mir_screencast_egl_native_window(screencast); EXPECT_NE(MirEGLNativeWindowType(), egl_native_window); mir_screencast_release_sync(screencast); mir_connection_release(connection); } TEST_F(MirScreencastTest, fails_on_client_when_server_request_fails) { using namespace testing; auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); ASSERT_TRUE(mir_connection_is_valid(connection)); EXPECT_CALL(mock_screencast(), create_session(_, _, _)) .WillOnce(Throw(std::runtime_error(""))); auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params); ASSERT_EQ(nullptr, screencast); mir_connection_release(connection); } namespace { struct MockSessionAuthorizer : public mtd::StubSessionAuthorizer { MOCK_METHOD1(screencast_is_allowed, bool(pid_t)); }; struct MockAuthorizerServerConfig : mir_test_framework::StubbedServerConfiguration { std::shared_ptr the_session_authorizer() override { return mt::fake_shared(mock_authorizer); } MockSessionAuthorizer mock_authorizer; }; class UnauthorizedMirScreencastTest : public mir_test_framework::InProcessServer { public: mir::DefaultServerConfiguration& server_config() override { return server_config_; } MockSessionAuthorizer& mock_authorizer() { return server_config_.mock_authorizer; } MockAuthorizerServerConfig server_config_; mtf::UsingStubClientPlatform using_stub_client_platform; MirScreencastParameters default_screencast_params { {0, 0, 1, 1}, 1, 1, mir_pixel_format_abgr_8888}; }; } TEST_F(UnauthorizedMirScreencastTest, fails_to_create_screencast) { using namespace testing; EXPECT_CALL(mock_authorizer(), screencast_is_allowed(_)) .WillOnce(Return(false)); auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); ASSERT_TRUE(mir_connection_is_valid(connection)); auto screencast = mir_connection_create_screencast_sync(connection, &default_screencast_params); ASSERT_EQ(nullptr, screencast); mir_connection_release(connection); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_surfaces_with_output_id.cpp0000644000015301777760000002421412322054247030002 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "mir/compositor/scene.h" #include "mir/geometry/rectangle.h" #include "mir/graphics/renderable.h" #include "mir_test_doubles/stub_buffer_allocator.h" #include "mir_test_doubles/stub_display_buffer.h" #include "mir_test_doubles/stub_display_configuration.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/null_platform.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test/cross_process_action.h" #include #include #include #include namespace mt = mir::test; namespace mtf = mir_test_framework; namespace mc = mir::compositor; namespace geom = mir::geometry; namespace mg = mir::graphics; namespace mtd = mir::test::doubles; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); class StubDisplay : public mtd::NullDisplay { public: StubDisplay(std::vector const& rects) : rects{rects} { for (auto const& rect : rects) { display_buffers.push_back( std::make_shared(rect)); } } void for_each_display_buffer(std::function const& f) override { for (auto& db : display_buffers) f(*db); } std::unique_ptr configuration() const override { return std::unique_ptr( new mtd::StubDisplayConfig(rects) ); } private: std::vector const rects; std::vector> display_buffers; }; class StubPlatform : public mtd::NullPlatform { public: std::shared_ptr create_buffer_allocator( const std::shared_ptr& /*buffer_initializer*/) override { return std::make_shared(); } std::shared_ptr create_display( std::shared_ptr const&, std::shared_ptr const&) override { return std::make_shared(display_rects()); } std::vector display_rects() { return {{{0,0}, {800,600}}, {{800,600}, {200,400}}}; } }; struct RectangleCompare { bool operator()(geom::Rectangle const& rect1, geom::Rectangle const& rect2) { int x1 = rect1.top_left.x.as_int(); int y1 = rect1.top_left.y.as_int(); int w1 = rect1.size.width.as_int(); int h1 = rect1.size.height.as_int(); int x2 = rect2.top_left.x.as_int(); int y2 = rect2.top_left.y.as_int(); int w2 = rect2.size.width.as_int(); int h2 = rect2.size.height.as_int(); return std::tie(x1,y1,w1,h1) < std::tie(x2,y2,w2,h2); } }; void null_surface_callback(MirSurface*, void*) { } } using SurfacesWithOutputId = BespokeDisplayServerTestFixture; TEST_F(SurfacesWithOutputId, fullscreen_surfaces_are_placed_at_top_left_of_correct_output) { mt::CrossProcessAction client_connect_and_create_surface; mt::CrossProcessAction client_release_surface_and_disconnect; mt::CrossProcessAction verify_scene; struct ServerConfig : TestingServerConfiguration { ServerConfig(mt::CrossProcessAction verify_scene) : verify_scene{verify_scene} { } std::shared_ptr the_graphics_platform() override { if (!graphics_platform) graphics_platform = std::make_shared(); return graphics_platform; } void exec() override { verification_thread = std::thread([this](){ verify_scene.exec([this] { auto scene = the_scene(); struct VerificationFilter : public mc::FilterForScene { bool operator()(mg::Renderable const& rend) { rects.push_back(rend.screen_position()); return false; } std::vector rects; } filter; struct NullOperator : public mc::OperatorForScene { void operator()(mg::Renderable const&) {} } null_operator; scene->for_each_if(filter, null_operator); auto display_rects = graphics_platform->display_rects(); std::sort(display_rects.begin(), display_rects.end(), RectangleCompare()); std::sort(filter.rects.begin(), filter.rects.end(), RectangleCompare()); EXPECT_EQ(display_rects, filter.rects); }); }); } void on_exit() override { verification_thread.join(); } std::shared_ptr graphics_platform; std::thread verification_thread; mt::CrossProcessAction verify_scene; } server_config{verify_scene}; launch_server_process(server_config); struct ClientConfig : TestingClientConfiguration { ClientConfig(mt::CrossProcessAction const& connect_and_create_surface, mt::CrossProcessAction const& release_surface_and_disconnect) : connect_and_create_surface{connect_and_create_surface}, release_surface_and_disconnect{release_surface_and_disconnect} { } void exec() { MirConnection* connection; std::vector surfaces; connect_and_create_surface.exec([&] { connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(mir_connection_is_valid(connection)); auto config = mir_connection_create_display_config(connection); ASSERT_TRUE(config != NULL); for (uint32_t n = 0; n < config->num_outputs; ++n) { auto const& output = config->outputs[n]; auto const& mode = output.modes[output.current_mode]; MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, static_cast(mode.horizontal_resolution), static_cast(mode.vertical_resolution), mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, output.output_id }; surfaces.push_back( mir_connection_create_surface_sync(connection, &request_params)); } mir_display_config_destroy(config); }); release_surface_and_disconnect.exec([&] { for (auto surface : surfaces) mir_surface_release_sync(surface); mir_connection_release(connection); }); } mt::CrossProcessAction connect_and_create_surface; mt::CrossProcessAction release_surface_and_disconnect; } client_config{client_connect_and_create_surface, client_release_surface_and_disconnect}; launch_client_process(client_config); run_in_test_process([&] { client_connect_and_create_surface(); verify_scene(); client_release_surface_and_disconnect(); }); } TEST_F(SurfacesWithOutputId, non_fullscreen_surfaces_are_not_accepted) { mt::CrossProcessAction client_connect_and_create_scene; mt::CrossProcessAction client_disconnect; struct ServerConfig : TestingServerConfiguration { std::shared_ptr the_graphics_platform() override { if (!graphics_platform) graphics_platform = std::make_shared(); return graphics_platform; } std::shared_ptr graphics_platform; } server_config; launch_server_process(server_config); struct ClientConfig : TestingClientConfiguration { void exec() { auto connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(mir_connection_is_valid(connection)); auto config = mir_connection_create_display_config(connection); ASSERT_TRUE(config != NULL); for (uint32_t n = 0; n < config->num_outputs; ++n) { auto const& output = config->outputs[n]; auto const& mode = output.modes[output.current_mode]; MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, static_cast(mode.horizontal_resolution) - 1, static_cast(mode.vertical_resolution) + 1, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, output.output_id }; auto surface = mir_connection_create_surface_sync(connection, &request_params); EXPECT_FALSE(mir_surface_is_valid(surface)); mir_surface_release(surface, &null_surface_callback, nullptr); } mir_display_config_destroy(config); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_server_startup.cpp0000644000015301777760000000310512322054223026116 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_framework/detect_server.h" #include #include #include namespace mf = mir::frontend; namespace mc = mir::compositor; namespace mtf = mir_test_framework; namespace mir { TEST_F(BespokeDisplayServerTestFixture, server_announces_itself_on_startup) { ASSERT_FALSE(mtf::detect_server(mtf::test_socket_file(), std::chrono::milliseconds(0))); TestingServerConfiguration server_config; launch_server_process(server_config); struct ClientConfig : TestingClientConfiguration { void exec() { EXPECT_TRUE(mtf::detect_server(mtf::test_socket_file(), std::chrono::milliseconds(100))); } } client_config; launch_client_process(client_config); } } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_server_disconnect.cpp0000644000015301777760000001262012322054247026555 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_framework/cross_process_sync.h" #include "mir_test/cross_process_action.h" #include #include #include namespace mtf = mir_test_framework; namespace mt = mir::test; using ServerDisconnect = mtf::BespokeDisplayServerTestFixture; namespace { struct MockEventHandler { MOCK_METHOD1(handle, void(MirLifecycleState transition)); static void handle(MirConnection*, MirLifecycleState transition, void* event_handler) { static_cast(event_handler)->handle(transition); } }; struct MyTestingClientConfiguration : mtf::TestingClientConfiguration { void exec() override { static MirSurfaceParameters const params = { __PRETTY_FUNCTION__, 33, 45, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; MockEventHandler mock_event_handler; auto connection = mir_connect_sync(mtf::test_socket_file().c_str() , __PRETTY_FUNCTION__); mir_connection_set_lifecycle_event_callback(connection, &MockEventHandler::handle, &mock_event_handler); auto surface = mir_connection_create_surface_sync(connection, ¶ms); std::atomic signalled(false); EXPECT_CALL(mock_event_handler, handle(mir_lifecycle_connection_lost)).Times(1). WillOnce(testing::InvokeWithoutArgs([&] { signalled.store(true); })); sync.signal_ready(); using clock = std::chrono::high_resolution_clock; auto time_limit = clock::now() + std::chrono::seconds(2); while (!signalled.load() && clock::now() < time_limit) { mir_surface_swap_buffers_sync(surface); } mir_surface_release_sync(surface); mir_connection_release(connection); } mtf::CrossProcessSync sync; }; struct DisconnectingTestingClientConfiguration : mtf::TestingClientConfiguration { void exec() override { MirConnection* connection{nullptr}; connect.exec([&] { connection = mir_connect_sync(mtf::test_socket_file().c_str() , __PRETTY_FUNCTION__); EXPECT_TRUE(mir_connection_is_valid(connection)); /* * Set a null callback to avoid killing the process * (default callback raises SIGTERM). */ mir_connection_set_lifecycle_event_callback(connection, null_lifecycle_callback, nullptr); }); create_surface.exec([&] { MirSurfaceParameters const parameters = { __PRETTY_FUNCTION__, 1, 1, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_connection_create_surface_sync(connection, ¶meters); }); configure_display.exec([&] { auto config = mir_connection_create_display_config(connection); mir_wait_for(mir_connection_apply_display_config(connection, config)); mir_display_config_destroy(config); }); disconnect.exec([&] { mir_connection_release(connection); }); } static void null_lifecycle_callback(MirConnection*, MirLifecycleState, void*) { } mt::CrossProcessAction connect; mt::CrossProcessAction create_surface; mt::CrossProcessAction configure_display; mt::CrossProcessAction disconnect; }; } TEST_F(ServerDisconnect, client_detects_server_shutdown) { TestingServerConfiguration server_config; launch_server_process(server_config); MyTestingClientConfiguration client_config; launch_client_process(client_config); run_in_test_process([this, &client_config] { client_config.sync.wait_for_signal_ready_for(); shutdown_server_process(); }); } TEST_F(ServerDisconnect, client_can_call_connection_functions_after_connection_break_is_detected) { TestingServerConfiguration server_config; launch_server_process(server_config); DisconnectingTestingClientConfiguration client_config; launch_client_process(client_config); run_in_test_process([this, &client_config] { client_config.connect(); shutdown_server_process(); /* While trying to create a surface the connection break will be detected */ client_config.create_surface(); /* Trying to configure the display shouldn't block */ client_config.configure_display(); /* Trying to disconnect at this point shouldn't block */ client_config.disconnect(); }); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_nested_mir.cpp0000644000015301777760000002244212322054223025164 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/frontend/session_mediator_report.h" #include "mir/display_server.h" #include "mir/run_mir.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_doubles/mock_gl.h" #include "mir_test_doubles/mock_egl.h" #ifndef ANDROID #include "mir_test_doubles/mock_gbm.h" #endif #include #include namespace mf = mir::frontend; namespace mtf = mir_test_framework; using namespace testing; namespace { struct MockSessionMediatorReport : mf::SessionMediatorReport { MockSessionMediatorReport() { EXPECT_CALL(*this, session_connect_called(_)).Times(AnyNumber()); EXPECT_CALL(*this, session_disconnect_called(_)).Times(AnyNumber()); // These are not needed for the 1st test, but they will be soon EXPECT_CALL(*this, session_create_surface_called(_)).Times(AnyNumber()); EXPECT_CALL(*this, session_release_surface_called(_)).Times(AnyNumber()); EXPECT_CALL(*this, session_next_buffer_called(_)).Times(AnyNumber()); } MOCK_METHOD1(session_connect_called, void (std::string const&)); MOCK_METHOD1(session_create_surface_called, void (std::string const&)); MOCK_METHOD1(session_next_buffer_called, void (std::string const&)); MOCK_METHOD1(session_release_surface_called, void (std::string const&)); MOCK_METHOD1(session_disconnect_called, void (std::string const&)); void session_drm_auth_magic_called(const std::string&) override {}; void session_configure_surface_called(std::string const&) override {}; void session_configure_display_called(std::string const&) override {}; void session_error(const std::string&, const char*, const std::string&) override {}; }; struct HostServerConfiguration : public mtf::TestingServerConfiguration { virtual std::shared_ptr the_session_mediator_report() { if (!mock_session_mediator_report) mock_session_mediator_report = std::make_shared(); return mock_session_mediator_report; } std::shared_ptr mock_session_mediator_report; }; struct FakeCommandLine { static int const argc = 6; char const* argv[argc]; FakeCommandLine(std::string const& host_socket) { char const** to = argv; for(auto from : { "--file", "NestedServer", "--host-socket", host_socket.c_str(), "--enable-input", "off"}) { *to++ = from; } EXPECT_THAT(to - argv, Eq(argc)); // Check the array size matches parameter list } }; struct NestedServerConfiguration : FakeCommandLine, public mir::DefaultServerConfiguration { NestedServerConfiguration(std::string const& host_socket) : FakeCommandLine(host_socket), DefaultServerConfiguration(FakeCommandLine::argc, FakeCommandLine::argv) { } }; struct NestedMockEGL : mir::test::doubles::MockEGL { NestedMockEGL() { { InSequence init_before_terminate; EXPECT_CALL(*this, eglGetDisplay(_)).Times(1); EXPECT_CALL(*this, eglInitialize(_, _, _)).Times(1).WillRepeatedly( DoAll(WithArgs<1, 2>(Invoke(this, &NestedMockEGL::egl_initialize)), Return(EGL_TRUE))); EXPECT_CALL(*this, eglChooseConfig(_, _, _, _, _)).Times(AnyNumber()).WillRepeatedly( DoAll(WithArgs<2, 4>(Invoke(this, &NestedMockEGL::egl_choose_config)), Return(EGL_TRUE))); EXPECT_CALL(*this, eglTerminate(_)).Times(1); } EXPECT_CALL(*this, eglCreateWindowSurface(_, _, _, _)).Times(AnyNumber()); EXPECT_CALL(*this, eglMakeCurrent(_, _, _, _)).Times(AnyNumber()); EXPECT_CALL(*this, eglDestroySurface(_, _)).Times(AnyNumber()); EXPECT_CALL(*this, eglGetProcAddress(StrEq("eglCreateImageKHR"))).Times(AnyNumber()); EXPECT_CALL(*this, eglGetProcAddress(StrEq("eglDestroyImageKHR"))).Times(AnyNumber()); EXPECT_CALL(*this, eglGetProcAddress(StrEq("glEGLImageTargetTexture2DOES"))).Times(AnyNumber()); { InSequence context_lifecycle; EXPECT_CALL(*this, eglCreateContext(_, _, _, _)).Times(AnyNumber()).WillRepeatedly(Return((EGLContext)this)); EXPECT_CALL(*this, eglDestroyContext(_, _)).Times(AnyNumber()).WillRepeatedly(Return(EGL_TRUE)); } } private: void egl_initialize(EGLint* major, EGLint* minor) { *major = 1; *minor = 4; } void egl_choose_config(EGLConfig* config, EGLint* num_config) { *config = this; *num_config = 1; } }; struct NestedMockPlatform #ifndef ANDROID : mir::test::doubles::MockGBM #endif { NestedMockPlatform() { #ifndef ANDROID InSequence gbm_device_lifecycle; EXPECT_CALL(*this, gbm_create_device(_)).Times(1); EXPECT_CALL(*this, gbm_device_destroy(_)).Times(1); #endif } }; struct NestedMockGL : NiceMock { NestedMockGL() {} }; template struct ClientConfig : mtf::TestingClientConfiguration { ClientConfig(std::string const& host_socket) : host_socket(host_socket) {} std::string const host_socket; void exec() override { try { NestedMockPlatform mock_gbm; NestedMockEGL mock_egl; NestedMockGL mock_gl; NestedServerConfiguration nested_config(host_socket); mir::run_mir(nested_config, [](mir::DisplayServer& server){server.stop();}); // TODO - remove FAIL() as we should exit (NB we need logic to cause exit). FAIL(); } catch (std::exception const& x) { // TODO - this is only temporary until NestedPlatform is implemented. EXPECT_THAT(x.what(), HasSubstr("Platform::create_buffer_allocator is not implemented yet!")); } } }; } using TestNestedMir = mtf::BespokeDisplayServerTestFixture; // TODO resolve problems running "nested" tests on android and running nested on MESA #ifdef ANDROID #define DISABLED_ON_ANDROID_AND_MESA(name) DISABLED_##name #else #define DISABLED_ON_ANDROID_AND_MESA(name) DISABLED_##name #endif TEST_F(TestNestedMir, DISABLED_ON_ANDROID_AND_MESA(nested_platform_connects_and_disconnects)) { struct MyHostServerConfiguration : HostServerConfiguration { void exec() override { InSequence seq; EXPECT_CALL(*mock_session_mediator_report, session_connect_called(_)).Times(1); EXPECT_CALL(*mock_session_mediator_report, session_disconnect_called(_)).Times(1); } }; MyHostServerConfiguration host_config; ClientConfig client_config(host_config.the_socket_file()); launch_server_process(host_config); launch_client_process(client_config); } ////////////////////////////////////////////////////////////////// // TODO the following tests were used in investigating lifetime issues. // TODO they may not have much long term value, but decide that later TEST(DisplayLeak, on_exit_display_objects_should_be_destroyed) { struct MyServerConfiguration : mtf::TestingServerConfiguration { std::shared_ptr the_display() override { auto const& temp = mtf::TestingServerConfiguration::the_display(); my_display = temp; return temp; } std::weak_ptr my_display; }; MyServerConfiguration host_config; mir::run_mir(host_config, [](mir::DisplayServer& server){server.stop();}); EXPECT_FALSE(host_config.my_display.lock()) << "after run_mir() exits the display should be released"; } TEST_F(TestNestedMir, DISABLED_ON_ANDROID_AND_MESA(on_exit_display_objects_should_be_destroyed)) { struct MyNestedServerConfiguration : NestedServerConfiguration { // TODO clang says "error: inheriting constructors are not supported" // using NestedServerConfiguration::NestedServerConfiguration; MyNestedServerConfiguration(std::string const& host_socket) : NestedServerConfiguration(host_socket) {} std::shared_ptr the_display() override { auto const& temp = NestedServerConfiguration::the_display(); my_display = temp; return temp; } ~MyNestedServerConfiguration() { EXPECT_FALSE(my_display.lock()) << "after run_mir() exits the display should be released"; } std::weak_ptr my_display; }; HostServerConfiguration host_config; ClientConfig client_config(host_config.the_socket_file()); launch_server_process(host_config); launch_client_process(client_config); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_client_authorization.cpp0000644000015301777760000001641412322054247027301 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/frontend/session_authorizer.h" #include #include "mir_test/fake_shared.h" #include "mir_test_framework/display_server_test_fixture.h" #include #include #include #include #include #include #include namespace mf = mir::frontend; namespace mt = mir::test; namespace mtf = mir_test_framework; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); } namespace { struct ConnectingClient : TestingClientConfiguration { MirConnection *connection; void exec() { connection = mir_connect_sync( mir_test_socket, __PRETTY_FUNCTION__); mir_connection_release(connection); } }; struct ClientPidTestFixture : BespokeDisplayServerTestFixture { ClientPidTestFixture() { shared_region = static_cast( mmap(NULL, sizeof(SharedRegion), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, 0, 0)); sem_init(&shared_region->client_pid_set, 1, 0); shared_region->client_pid = 0; } struct SharedRegion { sem_t client_pid_set; pid_t client_pid; pid_t get_client_process_pid() { static time_t const timeout_seconds = 60; struct timespec abs_timeout = { time(NULL) + timeout_seconds, 0 }; sem_timedwait(&client_pid_set, &abs_timeout); return client_pid; } void post_client_process_pid(pid_t pid) { client_pid = pid; sem_post(&client_pid_set); } }; SharedRegion* shared_region; }; struct MockSessionAuthorizer : public mf::SessionAuthorizer { MOCK_METHOD1(connection_is_allowed, bool(pid_t)); MOCK_METHOD1(configure_display_is_allowed, bool(pid_t)); MOCK_METHOD1(screencast_is_allowed, bool(pid_t)); }; } TEST_F(ClientPidTestFixture, session_authorizer_receives_pid_of_connecting_clients) { mtf::CrossProcessSync connect_sync; struct ServerConfiguration : TestingServerConfiguration { ServerConfiguration(ClientPidTestFixture::SharedRegion *shared_region, mtf::CrossProcessSync const& connect_sync) : shared_region(shared_region), connect_sync(connect_sync) { } void on_start() override { using namespace ::testing; pid_t client_pid = shared_region->get_client_process_pid(); EXPECT_CALL(mock_authorizer, connection_is_allowed(client_pid)).Times(1) .WillOnce(Return(true)); EXPECT_CALL(mock_authorizer, configure_display_is_allowed(client_pid)).Times(1) .WillOnce(Return(false)); EXPECT_CALL(mock_authorizer, screencast_is_allowed(client_pid)).Times(1) .WillOnce(Return(false)); connect_sync.try_signal_ready_for(); } std::shared_ptr the_session_authorizer() override { return mt::fake_shared(mock_authorizer); } ClientPidTestFixture::SharedRegion* shared_region; MockSessionAuthorizer mock_authorizer; mtf::CrossProcessSync connect_sync; } server_config(shared_region, connect_sync); launch_server_process(server_config); struct ClientConfiguration : ConnectingClient { ClientConfiguration(ClientPidTestFixture::SharedRegion *shared_region, mtf::CrossProcessSync const& connect_sync) : shared_region(shared_region), connect_sync(connect_sync) { } void exec() override { pid_t client_pid = getpid(); shared_region->post_client_process_pid(client_pid); connect_sync.wait_for_signal_ready_for(); ConnectingClient::exec(); } ClientPidTestFixture::SharedRegion* shared_region; mtf::CrossProcessSync connect_sync; } client_config(shared_region, connect_sync); launch_client_process(client_config); } // TODO this test exposes a race condition when the client processes both an error // TODO from connect and the socket being dropped. RAOF is doing some rework that // TODO should fix this a side effect. It should be re-enabled when that is done. TEST_F(ClientPidTestFixture, DISABLED_authorizer_may_prevent_connection_of_clients) { using namespace ::testing; struct ServerConfiguration : TestingServerConfiguration { ServerConfiguration(ClientPidTestFixture::SharedRegion *shared_region) : shared_region(shared_region) { } void exec() override { using namespace ::testing; pid_t client_pid = shared_region->get_client_process_pid(); EXPECT_CALL(mock_authorizer, connection_is_allowed(client_pid)).Times(1) .WillOnce(Return(false)); } std::shared_ptr the_session_authorizer() override { return mt::fake_shared(mock_authorizer); } ClientPidTestFixture::SharedRegion* shared_region; MockSessionAuthorizer mock_authorizer; } server_config(shared_region); launch_server_process(server_config); struct ClientConfiguration : ConnectingClient { ClientConfiguration(ClientPidTestFixture::SharedRegion *shared_region) : shared_region(shared_region) { } void exec() override { pid_t client_pid = getpid(); shared_region->post_client_process_pid(client_pid); connection = mir_connect_sync( mir_test_socket, __PRETTY_FUNCTION__); MirSurfaceParameters const parameters = { __PRETTY_FUNCTION__, 1, 1, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_connection_create_surface_sync(connection, ¶meters); EXPECT_GT(strlen(mir_connection_get_error_message(connection)), static_cast(0)); mir_connection_release(connection); } //we are testing the connect function itself, without getting to the // point where drivers are used, so force using production config bool use_real_graphics(mir::options::Option const&) override { return true; } ClientPidTestFixture::SharedRegion* shared_region; } client_config(shared_region); launch_client_process(client_config); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_server_shutdown.cpp0000644000015301777760000003165612322054223026303 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "mir/compositor/renderer.h" #include "mir/compositor/renderer_factory.h" #include "mir/input/composite_event_filter.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test/fake_event_hub_input_configuration.h" #include "mir_test_framework/cross_process_sync.h" #include "mir_test_doubles/stub_renderer.h" #include #include #include #include namespace mc = mir::compositor; namespace mg = mir::graphics; namespace mi = mir::input; namespace mia = mir::input::android; namespace mtf = mir_test_framework; namespace mtd = mir::test::doubles; namespace ms = mir::scene; namespace geom = mir::geometry; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); class StubRendererFactory : public mc::RendererFactory { public: std::unique_ptr create_renderer_for(geom::Rectangle const&) { return std::unique_ptr(new mtd::StubRenderer()); } }; void null_surface_callback(MirSurface*, void*) { } class Flag { public: explicit Flag(std::string const& flag_file) : flag_file{flag_file} { std::remove(flag_file.c_str()); } void set() { close(open(flag_file.c_str(), O_CREAT, S_IWUSR | S_IRUSR)); } bool is_set() { int fd = -1; if ((fd = open(flag_file.c_str(), O_RDONLY, S_IWUSR | S_IRUSR)) != -1) { close(fd); return true; } return false; } void wait() { while (!is_set()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); } private: std::string const flag_file; }; } using ServerShutdown = BespokeDisplayServerTestFixture; TEST_F(ServerShutdown, server_can_shut_down_when_clients_are_blocked) { Flag next_buffer_done1{"next_buffer_done1_c5d49978.tmp"}; Flag next_buffer_done2{"next_buffer_done2_c5d49978.tmp"}; Flag next_buffer_done3{"next_buffer_done3_c5d49978.tmp"}; Flag server_done{"server_done_c5d49978.tmp"}; struct ServerConfig : TestingServerConfiguration { std::shared_ptr the_renderer_factory() override { return renderer_factory([] { return std::make_shared(); }); } } server_config; launch_server_process(server_config); struct ClientConfig : TestingClientConfiguration { ClientConfig(Flag& next_buffer_done, Flag& server_done) : next_buffer_done(next_buffer_done), server_done(server_done) { } void exec() { MirConnection* connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; MirSurface* surf = mir_connection_create_surface_sync(connection, &request_params); /* Ask for the first buffer (should succeed) */ mir_surface_swap_buffers_sync(surf); /* Ask for the first second buffer (should block) */ mir_surface_swap_buffers(surf, null_surface_callback, nullptr); next_buffer_done.set(); server_done.wait(); /* * TODO: Releasing the connection to a shut down server blocks * the client. We should handle unexpected server shutdown more * gracefully on the client side. * * mir_connection_release(connection); */ } Flag& next_buffer_done; Flag& server_done; }; ClientConfig client_config1{next_buffer_done1, server_done}; ClientConfig client_config2{next_buffer_done2, server_done}; ClientConfig client_config3{next_buffer_done3, server_done}; launch_client_process(client_config1); launch_client_process(client_config2); launch_client_process(client_config3); run_in_test_process([&] { /* Wait until the clients are blocked on getting the second buffer */ next_buffer_done1.wait(); next_buffer_done2.wait(); next_buffer_done3.wait(); /* Shutting down the server should not block */ shutdown_server_process(); /* Notify the clients that we are done (we only need to set the flag once) */ server_done.set(); }); } TEST_F(ServerShutdown, server_releases_resources_on_shutdown_with_connected_clients) { Flag surface_created1{"surface_created1_7e9c69fc.tmp"}; Flag surface_created2{"surface_created2_7e9c69fc.tmp"}; Flag surface_created3{"surface_created3_7e9c69fc.tmp"}; Flag server_done{"server_done_7e9c69fc.tmp"}; Flag resources_freed_success{"resources_free_success_7e9c69fc.tmp"}; Flag resources_freed_failure{"resources_free_failure_7e9c69fc.tmp"}; /* Use the real input manager, but with a fake event hub */ struct ServerConfig : TestingServerConfiguration { std::shared_ptr the_input_configuration() override { if (!input_configuration) { input_configuration = std::make_shared( the_composite_event_filter(), the_input_region(), std::shared_ptr(), the_input_report()); } return input_configuration; } std::shared_ptr the_input_manager() override { return DefaultServerConfiguration::the_input_manager(); } std::shared_ptr the_input_targeter() override { return DefaultServerConfiguration::the_input_targeter(); } std::shared_ptr the_input_registrar() override { return DefaultServerConfiguration::the_input_registrar(); } std::shared_ptr input_configuration; }; auto server_config = std::make_shared(); launch_server_process(*server_config); struct ClientConfig : TestingClientConfiguration { ClientConfig(Flag& surface_created, Flag& server_done) : surface_created(surface_created), server_done(server_done) { } void exec() { MirConnection* connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_connection_create_surface_sync(connection, &request_params); surface_created.set(); server_done.wait(); } Flag& surface_created; Flag& server_done; }; ClientConfig client_config1{surface_created1, server_done}; ClientConfig client_config2{surface_created2, server_done}; ClientConfig client_config3{surface_created3, server_done}; launch_client_process(client_config1); launch_client_process(client_config2); launch_client_process(client_config3); run_in_test_process([&] { /* Wait until the clients have created a surface */ surface_created1.wait(); surface_created2.wait(); surface_created3.wait(); /* Shut down the server */ shutdown_server_process(); /* Wait until we have checked the resources in the server process */ while (!resources_freed_failure.is_set() && !resources_freed_success.is_set()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); /* Fail if the resources have not been freed */ if (resources_freed_failure.is_set()) ADD_FAILURE(); /* Notify the clients that we are done (we only need to set the flag once) */ server_done.set(); }); /* * Check that all resources are freed after destroying the server config. * Note that these checks are run multiple times: in the server process, * in each of the client processes and in the test process. We only care about * the results in the server process (in the other cases the checks will * succeed anyway, since we are not using the config object). */ std::weak_ptr display = server_config->the_display(); std::weak_ptr compositor = server_config->the_compositor(); std::weak_ptr connector = server_config->the_connector(); std::weak_ptr input_manager = server_config->the_input_manager(); server_config.reset(); EXPECT_EQ(0, display.use_count()); EXPECT_EQ(0, compositor.use_count()); EXPECT_EQ(0, connector.use_count()); EXPECT_EQ(0, input_manager.use_count()); if (display.use_count() != 0 || compositor.use_count() != 0 || connector.use_count() != 0 || input_manager.use_count() != 0) { resources_freed_failure.set(); } else { resources_freed_success.set(); } } namespace { bool file_exists(std::string const& filename) { struct stat statbuf; return 0 == stat(filename.c_str(), &statbuf); } } TEST_F(ServerShutdown, server_removes_endpoint_on_normal_exit) { using ServerConfig = TestingServerConfiguration; ServerConfig server_config; launch_server_process(server_config); run_in_test_process([&] { ASSERT_TRUE(file_exists(server_config.the_socket_file())); shutdown_server_process(); EXPECT_FALSE(file_exists(server_config.the_socket_file())); }); } TEST_F(ServerShutdown, server_removes_endpoint_on_abort) { struct ServerConfig : TestingServerConfiguration { void on_start() override { sync.wait_for_signal_ready_for(); abort(); } mtf::CrossProcessSync sync; }; ServerConfig server_config; launch_server_process(server_config); run_in_test_process([&] { ASSERT_TRUE(file_exists(server_config.the_socket_file())); server_config.sync.signal_ready(); auto result = wait_for_shutdown_server_process(); EXPECT_EQ(mtf::TerminationReason::child_terminated_by_signal, result.reason); // Under valgrind the server process is reported as being terminated // by SIGKILL because of multithreading madness. // TODO: Investigate if we can do better than this workaround EXPECT_TRUE(result.signal == SIGABRT || result.signal == SIGKILL); EXPECT_FALSE(file_exists(server_config.the_socket_file())); }); } struct OnSignal : ServerShutdown, ::testing::WithParamInterface {}; TEST_P(OnSignal, removes_endpoint_on_signal) { struct ServerConfig : TestingServerConfiguration { void on_start() override { sync.wait_for_signal_ready_for(); raise(sig); } ServerConfig(int sig) : sig(sig) {} int const sig; mtf::CrossProcessSync sync; }; ServerConfig server_config(GetParam()); launch_server_process(server_config); run_in_test_process([&] { ASSERT_TRUE(file_exists(server_config.the_socket_file())); server_config.sync.signal_ready(); auto result = wait_for_shutdown_server_process(); EXPECT_EQ(mtf::TerminationReason::child_terminated_by_signal, result.reason); // Under valgrind the server process is reported as being terminated // by SIGKILL because of multithreading madness // TODO: Investigate if we can do better than this workaround EXPECT_TRUE(result.signal == GetParam() || result.signal == SIGKILL); EXPECT_FALSE(file_exists(server_config.the_socket_file())); }); } INSTANTIATE_TEST_CASE_P(ServerShutdown, OnSignal, ::testing::Values(SIGQUIT, SIGABRT, SIGFPE, SIGSEGV, SIGBUS)); mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_shell_control_of_surface_configuration.cpp0000644000015301777760000001216512322054247033034 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/scene/surface_configurator.h" #include "mir/scene/surface.h" #include "mir_test/fake_shared.h" #include "mir_test_doubles/mock_surface_configurator.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_toolkit/mir_client_library.h" #include #include namespace ms = mir::scene; namespace mt = mir::test; namespace mtd = mt::doubles; namespace mtf = mir_test_framework; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); } namespace { struct SurfaceCreatingClient : public mtf::TestingClientConfiguration { void exec() override { connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ(mir_connection_get_error_message(connection), ""); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; surface = mir_connection_create_surface_sync(connection, &request_params); } MirConnection* connection; MirSurface* surface; }; } TEST_F(BespokeDisplayServerTestFixture, the_shell_surface_configurator_is_notified_of_attribute_changes) { struct ServerConfiguration : TestingServerConfiguration { std::shared_ptr the_surface_configurator() override { return mt::fake_shared(mock_configurator); } void exec() override { using namespace ::testing; EXPECT_CALL(mock_configurator, select_attribute_value(_, mir_surface_attrib_focus, _)).Times(AnyNumber()); EXPECT_CALL(mock_configurator, attribute_set(_, mir_surface_attrib_focus, _)).Times(AnyNumber()); ON_CALL(mock_configurator, select_attribute_value(_, _, _)).WillByDefault(Return(mir_surface_type_freestyle)); EXPECT_CALL(mock_configurator, select_attribute_value(_, mir_surface_attrib_type, Eq(mir_surface_type_freestyle))).Times(1); EXPECT_CALL(mock_configurator, attribute_set(_, mir_surface_attrib_type, Eq(mir_surface_type_freestyle))).Times(1); } mtd::MockSurfaceConfigurator mock_configurator; } server_config; launch_server_process(server_config); struct ClientConfiguration : SurfaceCreatingClient { void exec() override { SurfaceCreatingClient::exec(); mir_wait_for(mir_surface_set_type(surface, mir_surface_type_freestyle)); EXPECT_EQ(mir_surface_type_freestyle, mir_surface_get_type(surface)); } } client_config; launch_client_process(client_config); } TEST_F(BespokeDisplayServerTestFixture, the_shell_surface_configurator_may_interfere_with_attribute_changes) { struct ServerConfiguration : TestingServerConfiguration { std::shared_ptr the_surface_configurator() override { return mt::fake_shared(mock_configurator); } void exec() override { using namespace ::testing; EXPECT_CALL(mock_configurator, select_attribute_value(_, mir_surface_attrib_focus, _)).Times(AnyNumber()); EXPECT_CALL(mock_configurator, attribute_set(_, mir_surface_attrib_focus, _)).Times(AnyNumber()); EXPECT_CALL(mock_configurator, select_attribute_value(_, mir_surface_attrib_type, Eq(mir_surface_type_freestyle))).Times(1) .WillOnce(Return(mir_surface_type_normal)); EXPECT_CALL(mock_configurator, attribute_set(_, mir_surface_attrib_type, Eq(mir_surface_type_normal))).Times(1); } mtd::MockSurfaceConfigurator mock_configurator; } server_config; launch_server_process(server_config); struct ClientConfiguration : SurfaceCreatingClient { void exec() override { SurfaceCreatingClient::exec(); mir_wait_for(mir_surface_set_type(surface, mir_surface_type_freestyle)); EXPECT_EQ(mir_surface_type_normal, mir_surface_get_type(surface)); } } client_config; launch_client_process(client_config); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_protobuf.cpp0000644000015301777760000002307012322054247024677 0ustar pbusernogroup00000000000000/* * 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 */ #include "test_protobuf.pb.h" #include "mir_toolkit/mir_client_library.h" #include "mir/client/private.h" #include "mir/frontend/protobuf_message_sender.h" #include "mir/frontend/protobuf_session_creator.h" #include "mir/frontend/template_protobuf_message_processor.h" #include "mir_test_framework/stubbed_server_configuration.h" #include "mir_test_framework/in_process_server.h" #include #include #include namespace mf = mir::frontend; namespace mfd = mir::frontend::detail; /*************************************************************************/ /*************************************************************************/ /* Note that the functionality demonstrated here relies on "detail" and */ /* is not guaranteed to be supported in future. */ /*************************************************************************/ /*************************************************************************/ namespace { struct DemoMirServer : mir::protobuf::MirServer { MOCK_CONST_METHOD1(on_call, std::string(std::string)); DemoMirServer() { using namespace testing; ON_CALL(*this, on_call(_)).WillByDefault(Return("ok")); } void function( ::google::protobuf::RpcController* , ::mir::protobuf::Parameters const* parameters, ::mir::protobuf::Result* response, ::google::protobuf::Closure* done) { response->set_value(on_call(parameters->name())); done->Run(); } }; // using a global for easy access from tests and DemoMessageProcessor::dispatch() DemoMirServer* demo_mir_server; struct DemoMessageProcessor : mfd::MessageProcessor { DemoMessageProcessor( std::shared_ptr const& sender, std::shared_ptr const& wrapped) : sender(sender), wrapped(wrapped) {} bool dispatch(mfd::Invocation const& invocation) { if ("function" == invocation.method_name()) { mfd::invoke( this, demo_mir_server, &DemoMirServer::function, invocation); return true; } return wrapped->dispatch(invocation); } void send_response(::google::protobuf::uint32 id, ::google::protobuf::Message* response) { sender->send_response(id, response, {}); } std::shared_ptr const sender; std::shared_ptr const wrapped; }; struct DemoSessionCreator : mf::ProtobufSessionCreator { using ProtobufSessionCreator::ProtobufSessionCreator; MOCK_CONST_METHOD3(create_processor, std::shared_ptr( std::shared_ptr const& sender, std::shared_ptr const& display_server, std::shared_ptr const& report)); std::shared_ptr create_wrapped_processor( std::shared_ptr const& sender, std::shared_ptr const& display_server, std::shared_ptr const& report) const { auto const wrapped = mf::ProtobufSessionCreator::create_processor( sender, display_server, report); return std::make_shared(sender, wrapped); } std::shared_ptr create_unwrapped_processor( std::shared_ptr const& sender, std::shared_ptr const& display_server, std::shared_ptr const& report) const { return mf::ProtobufSessionCreator::create_processor( sender, display_server, report); } }; struct DemoServerConfiguration : mir_test_framework::StubbedServerConfiguration { std::shared_ptr the_session_creator() override { return session_creator([this] { return std::make_shared( the_ipc_factory(the_frontend_shell(), the_buffer_allocator()), the_session_authorizer(), the_message_processor_report()); }); } }; struct DemoPrivateProtobuf : mir_test_framework::InProcessServer { mir::DefaultServerConfiguration& server_config() override { return my_server_config; } DemoServerConfiguration my_server_config; std::shared_ptr demo_session_creator; void SetUp() { ::demo_mir_server = &demo_mir_server; mir_test_framework::InProcessServer::SetUp(); demo_session_creator = std::dynamic_pointer_cast(my_server_config.the_session_creator()); using namespace testing; ASSERT_THAT(demo_session_creator, NotNull()); ON_CALL(*demo_session_creator, create_processor(_, _, _)) .WillByDefault(Invoke(demo_session_creator.get(), &DemoSessionCreator::create_unwrapped_processor)); } testing::NiceMock demo_mir_server; }; void callback(std::atomic* called_back) { called_back->store(true); } char const* const nothing_returned = "Nothing returned"; } TEST_F(DemoPrivateProtobuf, client_calls_server) { using namespace testing; EXPECT_CALL(*demo_session_creator, create_processor(_, _, _)); auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); ASSERT_TRUE(mir_connection_is_valid(connection)); auto const rpc_channel = mir::client::the_rpc_channel(connection); using namespace mir::protobuf; using namespace google::protobuf; MirServer::Stub server(rpc_channel.get()); Parameters parameters; parameters.set_name(__PRETTY_FUNCTION__); Result result; result.set_error(nothing_returned); std::atomic called_back{false}; // Note: // As the default server won't recognise this call it drops the connection // resulting in a callback when the connection drops (but result being unchanged) server.function( nullptr, ¶meters, &result, NewCallback(&callback, &called_back)); // FIXME - This test is somehow racy. If I add: // EXPECT_TRUE(false) << connection; // then I can get mir_connection_release to generate an exception during // disconnect() internally, sometimes. Although that exception is caught // internally by the client library so we don't see it here. mir_connection_release(connection); EXPECT_TRUE(called_back); EXPECT_THAT(result.error(), Eq(nothing_returned)); } TEST_F(DemoPrivateProtobuf, wrapping_message_processor) { using namespace testing; EXPECT_CALL(*demo_session_creator, create_processor(_, _, _)) .Times(1) .WillOnce(Invoke(demo_session_creator.get(), &DemoSessionCreator::create_wrapped_processor)); auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); mir_connection_release(connection); } TEST_F(DemoPrivateProtobuf, server_receives_function_call) { using namespace testing; EXPECT_CALL(*demo_session_creator, create_processor(_, _, _)) .WillRepeatedly(Invoke(demo_session_creator.get(), &DemoSessionCreator::create_wrapped_processor)); auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); ASSERT_TRUE(mir_connection_is_valid(connection)); auto const rpc_channel = mir::client::the_rpc_channel(connection); using namespace mir::protobuf; using namespace google::protobuf; MirServer::Stub server(rpc_channel.get()); Parameters parameters; Result result; parameters.set_name(__PRETTY_FUNCTION__); EXPECT_CALL(demo_mir_server, on_call(__PRETTY_FUNCTION__)).Times(1); server.function(nullptr, ¶meters, &result, NewCallback([]{})); mir_connection_release(connection); } TEST_F(DemoPrivateProtobuf, client_receives_result) { using namespace testing; EXPECT_CALL(*demo_session_creator, create_processor(_, _, _)) .WillRepeatedly(Invoke(demo_session_creator.get(), &DemoSessionCreator::create_wrapped_processor)); EXPECT_CALL(demo_mir_server, on_call(_)).WillRepeatedly(Return(__PRETTY_FUNCTION__)); auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); ASSERT_TRUE(mir_connection_is_valid(connection)); auto const rpc_channel = mir::client::the_rpc_channel(connection); using namespace mir::protobuf; using namespace google::protobuf; MirServer::Stub server(rpc_channel.get()); Parameters parameters; Result result; parameters.set_name(__PRETTY_FUNCTION__); server.function(nullptr, ¶meters, &result, NewCallback([]{})); mir_connection_release(connection); EXPECT_THAT(result.has_error(), Eq(false)); EXPECT_THAT(result.value(), Eq(__PRETTY_FUNCTION__)); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_display_configuration.cpp0000644000015301777760000006166712322054247027451 0ustar pbusernogroup00000000000000/* * 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 * Kevin DuBois */ #include "mir/frontend/session_authorizer.h" #include "mir/graphics/event_handler_register.h" #include "src/server/scene/global_event_sender.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_framework/cross_process_sync.h" #include "mir_test_doubles/null_platform.h" #include "mir_test_doubles/null_display.h" #include "mir_test_doubles/null_display_changer.h" #include "mir_test_doubles/null_display_buffer.h" #include "mir_test_doubles/null_platform.h" #include "mir_test/display_config_matchers.h" #include "mir_test_doubles/stub_display_configuration.h" #include "mir_test_doubles/stub_buffer_allocator.h" #include "mir_test_doubles/stub_session_authorizer.h" #include "mir_test/fake_shared.h" #include "mir_test/pipe.h" #include "mir_test/cross_process_action.h" #include "mir_toolkit/mir_client_library.h" #include #include #include #include namespace mg = mir::graphics; namespace geom = mir::geometry; namespace mf = mir::frontend; namespace mtf = mir_test_framework; namespace mtd = mir::test::doubles; namespace mt = mir::test; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); class StubChanger : public mtd::NullDisplayChanger { public: std::shared_ptr active_configuration() override { return mt::fake_shared(stub_display_config); } static mtd::StubDisplayConfig stub_display_config; private: mtd::NullDisplayBuffer display_buffer; }; mtd::StubDisplayConfig StubChanger::stub_display_config; mtd::StubDisplayConfig changed_stub_display_config{1}; class MockDisplay : public mtd::NullDisplay { public: MockDisplay() : config{std::make_shared()}, handler_called{false} { } void for_each_display_buffer(std::function const& f) override { f(display_buffer); } std::unique_ptr configuration() const override { return std::unique_ptr( new mtd::StubDisplayConfig(*config) ); } void register_configuration_change_handler( mg::EventHandlerRegister& handlers, mg::DisplayConfigurationChangeHandler const& handler) override { handlers.register_fd_handler( {p.read_fd()}, [this, handler](int fd) { char c; if (read(fd, &c, 1) == 1) { handler(); handler_called = true; } }); } MOCK_METHOD1(configure, void(mg::DisplayConfiguration const&)); void emit_configuration_change_event( std::shared_ptr const& new_config) { config = new_config; if (write(p.write_fd(), "a", 1)) {} } void wait_for_configuration_change_handler() { while (!handler_called) std::this_thread::sleep_for(std::chrono::milliseconds{1}); } private: std::shared_ptr config; mtd::NullDisplayBuffer display_buffer; mt::Pipe p; std::atomic handler_called; }; class StubPlatform : public mtd::NullPlatform { public: std::shared_ptr create_buffer_allocator( std::shared_ptr const& /*buffer_initializer*/) override { return std::make_shared(); } std::shared_ptr create_display( std::shared_ptr const&, std::shared_ptr const&) override { return mt::fake_shared(mock_display); } testing::NiceMock mock_display; }; } using DisplayConfigurationTest = BespokeDisplayServerTestFixture; TEST_F(DisplayConfigurationTest, display_configuration_reaches_client) { struct ServerConfig : TestingServerConfiguration { std::shared_ptr the_frontend_display_changer() override { if (!changer) changer = std::make_shared(); return changer; } std::shared_ptr changer; } server_config; launch_server_process(server_config); struct Client : TestingClientConfiguration { void exec() { auto connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); auto configuration = mir_connection_create_display_config(connection); EXPECT_THAT(*configuration, mt::DisplayConfigMatches(std::cref(StubChanger::stub_display_config))); mir_display_config_destroy(configuration); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } TEST_F(DisplayConfigurationTest, hw_display_change_notification_reaches_all_clients) { mtf::CrossProcessSync client_ready_fence; mtf::CrossProcessSync unsubscribed_client_ready_fence; mtf::CrossProcessSync unsubscribed_check_fence; mtf::CrossProcessSync send_event_fence; mtf::CrossProcessSync events_all_sent; struct ServerConfig : TestingServerConfiguration { ServerConfig(mtf::CrossProcessSync const& send_event_fence, mtf::CrossProcessSync const& events_sent) : send_event_fence(send_event_fence), events_sent(events_sent) { } std::shared_ptr the_graphics_platform() override { using namespace testing; if (!platform) platform = std::make_shared(); return platform; } void exec() override { change_thread = std::thread([this](){ send_event_fence.wait_for_signal_ready(); platform->mock_display.emit_configuration_change_event( mt::fake_shared(changed_stub_display_config)); events_sent.signal_ready(); }); } void on_exit() override { change_thread.join(); } mtf::CrossProcessSync send_event_fence; mtf::CrossProcessSync events_sent; std::thread change_thread; std::shared_ptr platform; } server_config(send_event_fence, events_all_sent); struct SubscribedClient : TestingClientConfiguration { SubscribedClient(mtf::CrossProcessSync const& client_ready_fence) : client_ready_fence{client_ready_fence}, callback_called{false} { } static void change_handler(MirConnection* connection, void* context) { auto configuration = mir_connection_create_display_config(connection); EXPECT_THAT(*configuration, mt::DisplayConfigMatches(std::cref(changed_stub_display_config))); mir_display_config_destroy(configuration); auto client_config = static_cast(context); client_config->callback_called = true; } void exec() { MirConnection* connection = mir_connect_sync(mir_test_socket, "notifier"); mir_connection_set_display_config_change_callback(connection, &change_handler, this); client_ready_fence.signal_ready(); while (!callback_called) std::this_thread::sleep_for(std::chrono::microseconds{500}); mir_connection_release(connection); } mtf::CrossProcessSync client_ready_fence; std::atomic callback_called; } client_config(client_ready_fence); struct UnsubscribedClient : TestingClientConfiguration { UnsubscribedClient(mtf::CrossProcessSync const& client_ready_fence, mtf::CrossProcessSync const& client_check_fence) : client_ready_fence{client_ready_fence}, client_check_fence{client_check_fence} { } void exec() { MirConnection* connection = mir_connect_sync(mir_test_socket, "notifier"); client_ready_fence.signal_ready(); //wait for display change signal sent client_check_fence.wait_for_signal_ready(); //at this point, the message has gone out on the wire. since we're emulating a client //that is passively subscribed, we will just wait for the display configuration to change //and then will check the new config. auto configuration = mir_connection_create_display_config(connection); while(configuration->num_outputs != changed_stub_display_config.outputs.size()) { mir_display_config_destroy(configuration); std::this_thread::sleep_for(std::chrono::microseconds(500)); configuration = mir_connection_create_display_config(connection); } EXPECT_THAT(*configuration, mt::DisplayConfigMatches(std::cref(changed_stub_display_config))); mir_display_config_destroy(configuration); mir_connection_release(connection); } mtf::CrossProcessSync client_ready_fence; mtf::CrossProcessSync client_check_fence; } unsubscribed_client_config(unsubscribed_client_ready_fence, unsubscribed_check_fence); launch_server_process(server_config); launch_client_process(client_config); launch_client_process(unsubscribed_client_config); run_in_test_process([&] { client_ready_fence.wait_for_signal_ready(); unsubscribed_client_ready_fence.wait_for_signal_ready(); send_event_fence.signal_ready(); events_all_sent.wait_for_signal_ready(); unsubscribed_check_fence.signal_ready(); }); } TEST_F(DisplayConfigurationTest, display_change_request_for_unauthorized_client_fails) { struct ServerConfig : TestingServerConfiguration { std::shared_ptr the_session_authorizer() override { class StubAuthorizer : public mtd::StubSessionAuthorizer { bool configure_display_is_allowed(pid_t) override { return false; } }; if (!authorizer) authorizer = std::make_shared(); return authorizer; } std::shared_ptr authorizer; } server_config; launch_server_process(server_config); struct Client : TestingClientConfiguration { void exec() { auto connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); auto configuration = mir_connection_create_display_config(connection); mir_wait_for(mir_connection_apply_display_config(connection, configuration)); EXPECT_THAT(mir_connection_get_error_message(connection), testing::HasSubstr("not authorized to apply display configurations")); mir_display_config_destroy(configuration); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } namespace { struct DisplayClient : TestingClientConfiguration { DisplayClient(mt::CrossProcessAction const& connect, mt::CrossProcessAction const& apply_config, mt::CrossProcessAction const& disconnect) : connect{connect}, apply_config{apply_config}, disconnect{disconnect} { } void exec() { MirConnection* connection; connect.exec([&] { connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); }); apply_config.exec([&] { auto configuration = mir_connection_create_display_config(connection); mir_wait_for(mir_connection_apply_display_config(connection, configuration)); EXPECT_STREQ("", mir_connection_get_error_message(connection)); mir_display_config_destroy(configuration); }); disconnect.exec([&] { mir_connection_release(connection); }); } mt::CrossProcessAction connect; mt::CrossProcessAction apply_config; mt::CrossProcessAction disconnect; }; struct SimpleClient : TestingClientConfiguration { SimpleClient(mt::CrossProcessAction const& connect, mt::CrossProcessAction const& disconnect) : connect{connect}, disconnect{disconnect} { } void exec() { MirConnection* connection; connect.exec([&] { connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); }); disconnect.exec([&] { mir_connection_release(connection); }); } mt::CrossProcessAction connect; mt::CrossProcessAction disconnect; }; } TEST_F(DisplayConfigurationTest, changing_config_for_focused_client_configures_display) { mt::CrossProcessAction display_client_connect; mt::CrossProcessAction display_client_apply_config; mt::CrossProcessAction display_client_disconnect; mt::CrossProcessAction verify_connection_expectations; mt::CrossProcessAction verify_apply_config_expectations; struct ServerConfig : TestingServerConfiguration { ServerConfig(mt::CrossProcessAction const& verify_connection_expectations, mt::CrossProcessAction const& verify_apply_config_expectations) : verify_connection_expectations{verify_connection_expectations}, verify_apply_config_expectations{verify_apply_config_expectations} { } std::shared_ptr the_graphics_platform() override { using namespace testing; if (!platform) { platform = std::make_shared(); EXPECT_CALL(platform->mock_display, configure(_)).Times(0); } return platform; } void exec() override { t = std::thread([this](){ verify_connection_expectations.exec([&] { testing::Mock::VerifyAndClearExpectations(&platform->mock_display); EXPECT_CALL(platform->mock_display, configure(testing::_)).Times(1); }); verify_apply_config_expectations.exec([&] { testing::Mock::VerifyAndClearExpectations(&platform->mock_display); }); }); } void on_exit() override { t.join(); } std::shared_ptr platform; std::thread t; mt::CrossProcessAction verify_connection_expectations; mt::CrossProcessAction verify_apply_config_expectations; } server_config{verify_connection_expectations, verify_apply_config_expectations}; launch_server_process(server_config); DisplayClient display_client_config{display_client_connect, display_client_apply_config, display_client_disconnect}; launch_client_process(display_client_config); run_in_test_process([&] { display_client_connect(); verify_connection_expectations(); display_client_apply_config(); verify_apply_config_expectations(); display_client_disconnect(); }); } TEST_F(DisplayConfigurationTest, focusing_client_with_display_config_configures_display) { mt::CrossProcessAction display_client_connect; mt::CrossProcessAction display_client_apply_config; mt::CrossProcessAction display_client_disconnect; mt::CrossProcessAction simple_client_connect; mt::CrossProcessAction simple_client_disconnect; mt::CrossProcessAction verify_apply_config_expectations; mt::CrossProcessAction verify_focus_change_expectations; struct ServerConfig : TestingServerConfiguration { ServerConfig(mt::CrossProcessAction const& verify_apply_config_expectations, mt::CrossProcessAction const& verify_focus_change_expectations) : verify_apply_config_expectations{verify_apply_config_expectations}, verify_focus_change_expectations{verify_focus_change_expectations} { } std::shared_ptr the_graphics_platform() override { using namespace testing; if (!platform) { platform = std::make_shared(); EXPECT_CALL(platform->mock_display, configure(_)).Times(0); } return platform; } void exec() override { t = std::thread([this](){ verify_apply_config_expectations.exec([&] { testing::Mock::VerifyAndClearExpectations(&platform->mock_display); EXPECT_CALL(platform->mock_display, configure(testing::_)).Times(1); }); verify_focus_change_expectations.exec([&] { testing::Mock::VerifyAndClearExpectations(&platform->mock_display); }); }); } void on_exit() override { t.join(); } std::shared_ptr platform; std::thread t; mt::CrossProcessAction verify_apply_config_expectations; mt::CrossProcessAction verify_focus_change_expectations; } server_config{verify_apply_config_expectations, verify_focus_change_expectations}; launch_server_process(server_config); DisplayClient display_client_config{display_client_connect, display_client_apply_config, display_client_disconnect}; SimpleClient simple_client_config{simple_client_connect, simple_client_disconnect}; launch_client_process(display_client_config); launch_client_process(simple_client_config); run_in_test_process([&] { display_client_connect(); /* Connect the simple client. After this the simple client should have the focus. */ simple_client_connect(); /* Apply the display config while not focused */ display_client_apply_config(); verify_apply_config_expectations(); /* * Shut down the simple client. After this the focus should have changed to the * display client and its configuration should have been applied. */ simple_client_disconnect(); verify_focus_change_expectations(); display_client_disconnect(); }); } TEST_F(DisplayConfigurationTest, changing_focus_from_client_with_config_to_client_without_config_configures_display) { mt::CrossProcessAction display_client_connect; mt::CrossProcessAction display_client_apply_config; mt::CrossProcessAction display_client_disconnect; mt::CrossProcessAction simple_client_connect; mt::CrossProcessAction simple_client_disconnect; mt::CrossProcessAction verify_apply_config_expectations; mt::CrossProcessAction verify_focus_change_expectations; struct ServerConfig : TestingServerConfiguration { ServerConfig(mt::CrossProcessAction const& verify_apply_config_expectations, mt::CrossProcessAction const& verify_focus_change_expectations) : verify_apply_config_expectations{verify_apply_config_expectations}, verify_focus_change_expectations{verify_focus_change_expectations} { } std::shared_ptr the_graphics_platform() override { using namespace testing; if (!platform) { platform = std::make_shared(); EXPECT_CALL(platform->mock_display, configure(_)).Times(1); } return platform; } void exec() override { t = std::thread([this](){ verify_apply_config_expectations.exec([&] { testing::Mock::VerifyAndClearExpectations(&platform->mock_display); EXPECT_CALL(platform->mock_display, configure(testing::_)).Times(1); }); verify_focus_change_expectations.exec([&] { testing::Mock::VerifyAndClearExpectations(&platform->mock_display); }); }); } void on_exit() override { t.join(); } std::shared_ptr platform; std::thread t; mt::CrossProcessAction verify_apply_config_expectations; mt::CrossProcessAction verify_focus_change_expectations; } server_config{verify_apply_config_expectations, verify_focus_change_expectations}; launch_server_process(server_config); DisplayClient display_client_config{display_client_connect, display_client_apply_config, display_client_disconnect}; SimpleClient simple_client_config{simple_client_connect, simple_client_disconnect}; launch_client_process(display_client_config); launch_client_process(simple_client_config); run_in_test_process([&] { /* Connect the simple client. */ simple_client_connect(); /* Connect the display config client and apply a display config. */ display_client_connect(); display_client_apply_config(); verify_apply_config_expectations(); /* * Shut down the display client. After this the focus should have changed to the * simple client and the base configuration should have been applied. */ display_client_disconnect(); verify_focus_change_expectations(); simple_client_disconnect(); }); } TEST_F(DisplayConfigurationTest, hw_display_change_doesnt_apply_base_config_if_per_session_config_is_active) { mt::CrossProcessAction display_client_connect; mt::CrossProcessAction display_client_apply_config; mt::CrossProcessAction display_client_disconnect; mt::CrossProcessAction verify_hw_config_change_expectations; struct ServerConfig : TestingServerConfiguration { ServerConfig(mt::CrossProcessAction const& verify_hw_config_change_expectations) : verify_hw_config_change_expectations{verify_hw_config_change_expectations} { } std::shared_ptr the_graphics_platform() override { if (!platform) platform = std::make_shared(); return platform; } void exec() override { t = std::thread([this](){ verify_hw_config_change_expectations.exec([&] { using namespace testing; Mock::VerifyAndClearExpectations(&platform->mock_display); /* * A client with a per-session config is active, the base configuration * shouldn't be applied. */ EXPECT_CALL(platform->mock_display, configure(_)).Times(0); platform->mock_display.emit_configuration_change_event( mt::fake_shared(changed_stub_display_config)); platform->mock_display.wait_for_configuration_change_handler(); Mock::VerifyAndClearExpectations(&platform->mock_display); }); }); } void on_exit() override { t.join(); } std::shared_ptr platform; std::thread t; mt::CrossProcessAction verify_hw_config_change_expectations; } server_config{verify_hw_config_change_expectations}; DisplayClient display_client_config{display_client_connect, display_client_apply_config, display_client_disconnect}; launch_server_process(server_config); launch_client_process(display_client_config); run_in_test_process([&] { display_client_connect(); display_client_apply_config(); verify_hw_config_change_expectations(); display_client_disconnect(); }); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_protobuf.proto0000644000015301777760000000040412322054223025246 0ustar pbusernogroup00000000000000option cc_generic_services = true; package mir.protobuf; message Parameters { required string name = 1; } message Result { optional string error = 127; optional string value = 1; } service MirServer { rpc function(Parameters) returns (Result); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/CMakeLists.txt0000644000015301777760000000314312322054223024025 0ustar pbusernogroup00000000000000include(CMakeDependentOption) include_directories( ${CMAKE_SOURCE_DIR} ${PROTOBUF_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) protobuf_generate_cpp( GENERATED_PROTOBUF_SRCS GENERATED_PROTOBUF_HDRS test_protobuf.proto ) set( SOURCES test_client_library.cpp test_surfaceloop.cpp test_test_framework.cpp test_focus_selection.cpp test_server_shutdown.cpp test_client_focus_notification.cpp test_client_authorization.cpp test_shell_control_of_surface_configuration.cpp test_nested_mir.cpp test_display_configuration.cpp test_surfaces_with_output_id.cpp test_server_disconnect.cpp test_client_library_drm.cpp test_protobuf.cpp test_client_screencast.cpp ${GENERATED_PROTOBUF_SRCS} ${GENERATED_PROTOBUF_HDRS} ) list(APPEND SOURCES test_client_input.cpp) list(APPEND SOURCES test_server_startup.cpp ) add_executable( mir_acceptance_tests ${SOURCES} ) uses_android_input(mir_acceptance_tests) target_link_libraries( mir_acceptance_tests mirserver mirclient mirplatform mir-test mir-test-framework mir-test-doubles mir-test-doubles-platform 3rd_party ${PROTOBUF_LIBRARIES} ${Boost_LIBRARIES} ${GTEST_BOTH_LIBRARIES} ${GMOCK_LIBRARY} ${GMOCK_MAIN_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} # Link in pthread. ) CMAKE_DEPENDENT_OPTION( MIR_RUN_ACCEPTANCE_TESTS "Run acceptance tests as part of default testing" ON "MIR_BUILD_ACCEPTANCE_TESTS" OFF) if (MIR_RUN_ACCEPTANCE_TESTS) mir_discover_tests(mir_acceptance_tests) endif (MIR_RUN_ACCEPTANCE_TESTS) install( TARGETS mir_acceptance_tests RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_client_library.cpp0000644000015301777760000011420312322054223026032 0ustar pbusernogroup00000000000000/* * 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 Guest */ #include "mir_test_framework/display_server_test_fixture.h" #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/mir_client_library_debug.h" #include "src/client/client_buffer.h" #include "mir/frontend/connector.h" #include "mir_protobuf.pb.h" #ifdef ANDROID /* * MirNativeBuffer for Android is defined opaquely, but we now depend on * it having width and height fields, for all platforms. So need definition... */ #include // for ANativeWindowBuffer AKA MirNativeBuffer #endif #include #include #include #include #include #include #include #include namespace mf = mir::frontend; namespace mc = mir::compositor; namespace mcl = mir::client; namespace mtf = mir_test_framework; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); } namespace mir { namespace { struct ClientConfigCommon : TestingClientConfiguration { ClientConfigCommon() : connection(0) , surface(0), buffers(0) { } static void connection_callback(MirConnection * connection, void * context) { ClientConfigCommon * config = reinterpret_cast(context); config->connection = connection; } static void create_surface_callback(MirSurface * surface, void * context) { ClientConfigCommon * config = reinterpret_cast(context); config->surface_created(surface); } static void next_buffer_callback(MirSurface * surface, void * context) { ClientConfigCommon * config = reinterpret_cast(context); config->next_buffer(surface); } static void release_surface_callback(MirSurface * surface, void * context) { ClientConfigCommon * config = reinterpret_cast(context); config->surface_released(surface); } virtual void connected(MirConnection * new_connection) { connection = new_connection; } virtual void surface_created(MirSurface * new_surface) { surface = new_surface; } virtual void next_buffer(MirSurface*) { ++buffers; } virtual void surface_released(MirSurface * /*released_surface*/) { surface = NULL; } MirConnection* connection; MirSurface* surface; int buffers; }; } TEST_F(DefaultDisplayServerTestFixture, client_library_connects_and_disconnects) { struct ClientConfig : ClientConfigCommon { void exec() { MirWaitHandle* wh = mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this); EXPECT_TRUE(wh != NULL); mir_wait_for(wh); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ(mir_connection_get_error_message(connection), ""); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, synchronous_connection) { struct ClientConfig : ClientConfigCommon { void exec() { connection = NULL; connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ(mir_connection_get_error_message(connection), ""); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, client_library_creates_surface) { struct ClientConfig : ClientConfigCommon { void exec() { mir_wait_for(mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this)); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ(mir_connection_get_error_message(connection), ""); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_wait_for(mir_connection_create_surface(connection, &request_params, create_surface_callback, this)); ASSERT_TRUE(surface != NULL); EXPECT_TRUE(mir_surface_is_valid(surface)); EXPECT_STREQ(mir_surface_get_error_message(surface), ""); MirSurfaceParameters response_params; mir_surface_get_parameters(surface, &response_params); EXPECT_EQ(request_params.width, response_params.width); EXPECT_EQ(request_params.height, response_params.height); EXPECT_EQ(request_params.pixel_format, response_params.pixel_format); EXPECT_EQ(request_params.buffer_usage, response_params.buffer_usage); mir_wait_for(mir_surface_release( surface, release_surface_callback, this)); ASSERT_TRUE(surface == NULL); surface = mir_connection_create_surface_sync(connection, &request_params); ASSERT_TRUE(surface != NULL); EXPECT_TRUE(mir_surface_is_valid(surface)); EXPECT_STREQ(mir_surface_get_error_message(surface), ""); mir_surface_get_parameters(surface, &response_params); EXPECT_EQ(request_params.width, response_params.width); EXPECT_EQ(request_params.height, response_params.height); EXPECT_EQ(request_params.pixel_format, response_params.pixel_format); EXPECT_EQ(request_params.buffer_usage, response_params.buffer_usage); mir_surface_release_sync(surface); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, surface_types) { struct ClientConfig : ClientConfigCommon { void exec() { mir_wait_for(mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this)); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ(mir_connection_get_error_message(connection), ""); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_wait_for(mir_connection_create_surface(connection, &request_params, create_surface_callback, this)); ASSERT_TRUE(surface != NULL); EXPECT_TRUE(mir_surface_is_valid(surface)); EXPECT_STREQ(mir_surface_get_error_message(surface), ""); EXPECT_EQ(mir_surface_type_normal, mir_surface_get_type(surface)); mir_wait_for(mir_surface_set_type(surface, mir_surface_type_freestyle)); EXPECT_EQ(mir_surface_type_freestyle, mir_surface_get_type(surface)); mir_wait_for(mir_surface_set_type(surface, static_cast(999))); EXPECT_EQ(mir_surface_type_freestyle, mir_surface_get_type(surface)); mir_wait_for(mir_surface_set_type(surface, mir_surface_type_dialog)); EXPECT_EQ(mir_surface_type_dialog, mir_surface_get_type(surface)); mir_wait_for(mir_surface_set_type(surface, static_cast(888))); EXPECT_EQ(mir_surface_type_dialog, mir_surface_get_type(surface)); // Stress-test synchronization logic with some flooding for (int i = 0; i < 100; i++) { mir_surface_set_type(surface, mir_surface_type_normal); mir_surface_set_type(surface, mir_surface_type_utility); mir_surface_set_type(surface, mir_surface_type_dialog); mir_surface_set_type(surface, mir_surface_type_overlay); mir_surface_set_type(surface, mir_surface_type_freestyle); mir_wait_for(mir_surface_set_type(surface, mir_surface_type_popover)); ASSERT_EQ(mir_surface_type_popover, mir_surface_get_type(surface)); } mir_wait_for(mir_surface_release(surface, release_surface_callback, this)); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, client_can_set_surface_state) { struct ClientConfig : ClientConfigCommon { void exec() { connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ(mir_connection_get_error_message(connection), ""); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; surface = mir_connection_create_surface_sync(connection, &request_params); ASSERT_TRUE(surface != NULL); EXPECT_TRUE(mir_surface_is_valid(surface)); EXPECT_STREQ(mir_surface_get_error_message(surface), ""); EXPECT_EQ(mir_surface_state_restored, mir_surface_get_state(surface)); mir_wait_for(mir_surface_set_state(surface, mir_surface_state_fullscreen)); EXPECT_EQ(mir_surface_state_fullscreen, mir_surface_get_state(surface)); mir_wait_for(mir_surface_set_state(surface, static_cast(999))); EXPECT_EQ(mir_surface_state_fullscreen, mir_surface_get_state(surface)); mir_wait_for(mir_surface_set_state(surface, mir_surface_state_minimized)); EXPECT_EQ(mir_surface_state_minimized, mir_surface_get_state(surface)); mir_wait_for(mir_surface_set_state(surface, static_cast(888))); EXPECT_EQ(mir_surface_state_minimized, mir_surface_get_state(surface)); // Stress-test synchronization logic with some flooding for (int i = 0; i < 100; i++) { mir_surface_set_state(surface, mir_surface_state_maximized); mir_surface_set_state(surface, mir_surface_state_restored); mir_wait_for(mir_surface_set_state(surface, mir_surface_state_fullscreen)); ASSERT_EQ(mir_surface_state_fullscreen, mir_surface_get_state(surface)); } mir_surface_release_sync(surface); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, client_receives_surface_state_events) { struct ClientConfig : ClientConfigCommon { static void event_callback(MirSurface* surface, MirEvent const* event, void* ctx) { ClientConfig* self = static_cast(ctx); self->last_event = *event; self->last_event_surface = surface; } void exec() { connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); ASSERT_TRUE(mir_connection_is_valid(connection)); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; memset(&last_event, 0, sizeof last_event); last_event_surface = nullptr; MirEventDelegate delegate{&event_callback, this}; MirSurface* other_surface = mir_connection_create_surface_sync(connection, &request_params); ASSERT_TRUE(other_surface != NULL); ASSERT_TRUE(mir_surface_is_valid(other_surface)); mir_surface_set_event_handler(other_surface, nullptr); surface = mir_connection_create_surface_sync(connection, &request_params); ASSERT_TRUE(surface != NULL); ASSERT_TRUE(mir_surface_is_valid(surface)); mir_surface_set_event_handler(surface, &delegate); int surface_id = mir_debug_surface_id(surface); mir_wait_for(mir_surface_set_state(surface, mir_surface_state_fullscreen)); mir_wait_for(mir_surface_set_state(other_surface, mir_surface_state_minimized)); EXPECT_EQ(surface, last_event_surface); EXPECT_EQ(mir_event_type_surface, last_event.type); EXPECT_EQ(surface_id, last_event.surface.id); EXPECT_EQ(mir_surface_attrib_state, last_event.surface.attrib); EXPECT_EQ(mir_surface_state_fullscreen, last_event.surface.value); mir_wait_for(mir_surface_set_state(surface, static_cast(999))); EXPECT_EQ(surface, last_event_surface); EXPECT_EQ(mir_event_type_surface, last_event.type); EXPECT_EQ(surface_id, last_event.surface.id); EXPECT_EQ(mir_surface_attrib_state, last_event.surface.attrib); EXPECT_EQ(mir_surface_state_fullscreen, last_event.surface.value); memset(&last_event, 0, sizeof last_event); last_event_surface = nullptr; mir_wait_for(mir_surface_set_state(surface, mir_surface_state_minimized)); EXPECT_EQ(surface, last_event_surface); EXPECT_EQ(mir_event_type_surface, last_event.type); EXPECT_EQ(surface_id, last_event.surface.id); EXPECT_EQ(mir_surface_attrib_state, last_event.surface.attrib); EXPECT_EQ(mir_surface_state_minimized, last_event.surface.value); memset(&last_event, 0, sizeof last_event); last_event_surface = nullptr; mir_wait_for(mir_surface_set_state(surface, static_cast(777))); mir_wait_for(mir_surface_set_state(other_surface, mir_surface_state_maximized)); EXPECT_EQ(0, last_event_surface); EXPECT_EQ(0, last_event.type); EXPECT_EQ(0, last_event.surface.id); EXPECT_EQ(0, last_event.surface.attrib); EXPECT_EQ(0, last_event.surface.value); mir_surface_release_sync(surface); mir_surface_release_sync(other_surface); mir_connection_release(connection); } MirEvent last_event; MirSurface* last_event_surface; } client_config; launch_client_process(client_config); } #ifndef ANDROID TEST_F(DefaultDisplayServerTestFixture, surface_scanout_flag_toggles) { struct ClientConfig : ClientConfigCommon { void exec() { connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ(mir_connection_get_error_message(connection), ""); MirSurfaceParameters parm = { __PRETTY_FUNCTION__, 1280, 1024, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; surface = mir_connection_create_surface_sync(connection, &parm); ASSERT_TRUE(mir_surface_is_valid(surface)); MirNativeBuffer *native; mir_surface_get_current_buffer(surface, &native); EXPECT_TRUE(native->flags & mir_buffer_flag_can_scanout); mir_surface_swap_buffers_sync(surface); EXPECT_TRUE(native->flags & mir_buffer_flag_can_scanout); mir_surface_release_sync(surface); parm.width = 100; parm.height = 100; surface = mir_connection_create_surface_sync(connection, &parm); ASSERT_TRUE(mir_surface_is_valid(surface)); mir_surface_get_current_buffer(surface, &native); EXPECT_FALSE(native->flags & mir_buffer_flag_can_scanout); mir_surface_swap_buffers_sync(surface); EXPECT_FALSE(native->flags & mir_buffer_flag_can_scanout); mir_surface_release_sync(surface); parm.width = 800; parm.height = 600; parm.buffer_usage = mir_buffer_usage_software; surface = mir_connection_create_surface_sync(connection, &parm); ASSERT_TRUE(mir_surface_is_valid(surface)); mir_surface_get_current_buffer(surface, &native); EXPECT_FALSE(native->flags & mir_buffer_flag_can_scanout); mir_surface_swap_buffers_sync(surface); EXPECT_FALSE(native->flags & mir_buffer_flag_can_scanout); mir_surface_release_sync(surface); parm.buffer_usage = mir_buffer_usage_hardware; surface = mir_connection_create_surface_sync(connection, &parm); ASSERT_TRUE(mir_surface_is_valid(surface)); mir_surface_get_current_buffer(surface, &native); EXPECT_TRUE(native->flags & mir_buffer_flag_can_scanout); mir_surface_swap_buffers_sync(surface); EXPECT_TRUE(native->flags & mir_buffer_flag_can_scanout); mir_surface_release_sync(surface); mir_connection_release(connection); } // this test relies on gbm drivers, use real graphics always bool use_real_graphics(mir::options::Option const&) override { return true; } } client_config; launch_client_process(client_config); } #endif #ifdef ANDROID // Mir's Android test infrastructure isn't quite ready for this yet. TEST_F(DefaultDisplayServerTestFixture, DISABLED_client_gets_buffer_dimensions) #else TEST_F(DefaultDisplayServerTestFixture, client_gets_buffer_dimensions) #endif { struct ClientConfig : ClientConfigCommon { void exec() { connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); ASSERT_TRUE(mir_connection_is_valid(connection)); MirSurfaceParameters parm = { __PRETTY_FUNCTION__, 0, 0, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; struct {int width, height;} const sizes[] = { {12, 34}, {56, 78}, {90, 21}, }; for (auto const& size : sizes) { parm.width = size.width; parm.height = size.height; surface = mir_connection_create_surface_sync(connection, &parm); ASSERT_TRUE(surface != NULL); ASSERT_TRUE(mir_surface_is_valid(surface)); MirNativeBuffer *native = NULL; mir_surface_get_current_buffer(surface, &native); ASSERT_TRUE(native != NULL); EXPECT_EQ(parm.width, native->width); EXPECT_EQ(parm.height, native->height); mir_surface_swap_buffers_sync(surface); mir_surface_get_current_buffer(surface, &native); ASSERT_TRUE(native != NULL); EXPECT_EQ(parm.width, native->width); EXPECT_EQ(parm.height, native->height); mir_surface_release_sync(surface); } mir_connection_release(connection); } bool use_real_graphics(mir::options::Option const&) override { return true; } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, client_library_creates_multiple_surfaces) { int const n_surfaces = 13; struct ClientConfig : ClientConfigCommon { ClientConfig(int n_surfaces) : n_surfaces(n_surfaces) { } void surface_created(MirSurface * new_surface) { surfaces.insert(new_surface); } void surface_released(MirSurface * surface) { surfaces.erase(surface); } MirSurface * any_surface() { return *surfaces.begin(); } size_t current_surface_count() { return surfaces.size(); } void exec() { mir_wait_for(mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this)); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ(mir_connection_get_error_message(connection), ""); for (int i = 0; i != n_surfaces; ++i) { old_surface_count = current_surface_count(); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_wait_for(mir_connection_create_surface(connection, &request_params, create_surface_callback, this)); ASSERT_EQ(old_surface_count + 1, current_surface_count()); } for (int i = 0; i != n_surfaces; ++i) { old_surface_count = current_surface_count(); ASSERT_NE(old_surface_count, 0u); MirSurface * surface = any_surface(); mir_wait_for(mir_surface_release( surface, release_surface_callback, this)); ASSERT_EQ(old_surface_count - 1, current_surface_count()); } mir_connection_release(connection); } int n_surfaces; std::set surfaces; size_t old_surface_count; } client_config(n_surfaces); launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, client_library_accesses_and_advances_buffers) { struct ClientConfig : ClientConfigCommon { void exec() { mir_wait_for(mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this)); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ("", mir_connection_get_error_message(connection)); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_wait_for(mir_connection_create_surface(connection, &request_params, create_surface_callback, this)); ASSERT_TRUE(surface != NULL); buffers = 0; mir_wait_for(mir_surface_swap_buffers(surface, next_buffer_callback, this)); EXPECT_EQ(buffers, 1); mir_wait_for(mir_surface_release( surface, release_surface_callback, this)); ASSERT_TRUE(surface == NULL); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, fully_synchronous_client) { struct ClientConfig : ClientConfigCommon { void exec() { connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ("", mir_connection_get_error_message(connection)); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_software, mir_display_output_id_invalid }; surface = mir_connection_create_surface_sync(connection, &request_params); ASSERT_TRUE(surface != NULL); EXPECT_TRUE(mir_surface_is_valid(surface)); EXPECT_STREQ(mir_surface_get_error_message(surface), ""); mir_surface_swap_buffers_sync(surface); EXPECT_TRUE(mir_surface_is_valid(surface)); EXPECT_STREQ(mir_surface_get_error_message(surface), ""); mir_surface_release_sync(surface); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ("", mir_connection_get_error_message(connection)); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, highly_threaded_client) { struct ClientConfig : ClientConfigCommon { static void nosey_thread(MirSurface *surf) { for (int i = 0; i < 10; i++) { mir_wait_for_one(mir_surface_set_state(surf, mir_surface_state_maximized)); mir_wait_for_one(mir_surface_set_type(surf, mir_surface_type_normal)); mir_wait_for_one(mir_surface_set_state(surf, mir_surface_state_restored)); mir_wait_for_one(mir_surface_set_type(surf, mir_surface_type_utility)); mir_wait_for_one(mir_surface_set_state(surf, mir_surface_state_fullscreen)); mir_wait_for_one(mir_surface_set_type(surf, mir_surface_type_dialog)); mir_wait_for_one(mir_surface_set_state(surf, mir_surface_state_minimized)); } } void exec() { connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ("", mir_connection_get_error_message(connection)); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_software, mir_display_output_id_invalid }; surface = mir_connection_create_surface_sync(connection, &request_params); ASSERT_TRUE(surface != NULL); EXPECT_TRUE(mir_surface_is_valid(surface)); EXPECT_STREQ(mir_surface_get_error_message(surface), ""); std::thread a(nosey_thread, surface); std::thread b(nosey_thread, surface); std::thread c(nosey_thread, surface); a.join(); b.join(); c.join(); EXPECT_EQ(mir_surface_type_dialog, mir_surface_get_type(surface)); EXPECT_EQ(mir_surface_state_minimized, mir_surface_get_state(surface)); mir_surface_release_sync(surface); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ("", mir_connection_get_error_message(connection)); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, client_library_accesses_platform_package) { struct ClientConfig : ClientConfigCommon { void exec() { mir_wait_for(mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this)); ASSERT_TRUE(connection != NULL); MirPlatformPackage platform_package; platform_package.data_items = -1; platform_package.fd_items = -1; mir_connection_get_platform(connection, &platform_package); EXPECT_GE(0, platform_package.data_items); EXPECT_GE(0, platform_package.fd_items); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, client_library_accesses_display_info) { struct ClientConfig : ClientConfigCommon { void exec() { mir_wait_for(mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this)); ASSERT_TRUE(connection != NULL); auto configuration = mir_connection_create_display_config(connection); ASSERT_NE(nullptr, configuration); ASSERT_GT(configuration->num_outputs, 0u); ASSERT_NE(nullptr, configuration->outputs); for (auto i=0u; i < configuration->num_outputs; i++) { MirDisplayOutput* disp = &configuration->outputs[i]; ASSERT_NE(nullptr, disp); EXPECT_GE(disp->num_modes, disp->current_mode); EXPECT_GE(disp->num_output_formats, disp->current_format); } mir_display_config_destroy(configuration); mir_connection_release(connection); } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, connect_errors_handled) { struct ClientConfig : ClientConfigCommon { void exec() { mir_wait_for(mir_connect("garbage", __PRETTY_FUNCTION__, connection_callback, this)); ASSERT_TRUE(connection != NULL); char const* error = mir_connection_get_error_message(connection); if (std::strcmp("connect: No such file or directory", error) && std::strcmp("Can't find MIR server", error) && std::strcmp("Failed to connect to server socket", error)) { FAIL() << error; } } //we are testing the connect function itself, without getting to the // point where drivers are used, so force using production config bool use_real_graphics(mir::options::Option const&) override { return true; } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, connect_errors_dont_blow_up) { struct ClientConfig : ClientConfigCommon { void exec() { mir_wait_for(mir_connect("garbage", __PRETTY_FUNCTION__, connection_callback, this)); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_wait_for(mir_connection_create_surface(connection, &request_params, create_surface_callback, this)); // TODO surface_create needs to fail safe too. After that is done we should add the following: // TODO mir_wait_for(mir_surface_swap_buffers(surface, next_buffer_callback, this)); // TODO mir_wait_for(mir_surface_release( surface, release_surface_callback, this)); mir_connection_release(connection); } //we are testing the connect function itself, without getting to the // point where drivers are used, so force using production config bool use_real_graphics(mir::options::Option const&) override { return true; } } client_config; launch_client_process(client_config); } bool signalled; static void SIGIO_handler(int /*signo*/) { signalled = true; } TEST_F(DefaultDisplayServerTestFixture, ClientLibraryThreadsHandleNoSignals) { struct ClientConfig : ClientConfigCommon { void exec() { signalled = false; sigset_t sigset; sigemptyset(&sigset); struct sigaction act; act.sa_handler = &SIGIO_handler; act.sa_mask = sigset; act.sa_flags = 0; act.sa_restorer = nullptr; if (sigaction(SIGIO, &act, NULL)) FAIL() << "Failed to set SIGIO action"; MirConnection* conn = NULL; conn = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); sigaddset(&sigset, SIGIO); pthread_sigmask(SIG_BLOCK, &sigset, NULL); // SIGIO should be blocked if (kill(getpid(), SIGIO)) FAIL() << "Failed to send SIGIO signal"; // Make a roundtrip to the server to ensure the SIGIO has time to be handled MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_software, mir_display_output_id_invalid }; surface = mir_connection_create_surface_sync(conn, &request_params); mir_connection_release(conn); EXPECT_FALSE(signalled); } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, ClientLibraryDoesNotInterfereWithClientSignalHandling) { struct ClientConfig : ClientConfigCommon { void exec() { signalled = false; sigset_t sigset; sigemptyset(&sigset); struct sigaction act; act.sa_handler = &SIGIO_handler; act.sa_mask = sigset; act.sa_flags = 0; act.sa_restorer = nullptr; if (sigaction(SIGIO, &act, NULL)) FAIL() << "Failed to set SIGIO action"; MirConnection* conn = NULL; conn = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); // We should receieve SIGIO if (kill(getpid(), SIGIO)) FAIL() << "Failed to send SIGIO signal"; mir_connection_release(conn); EXPECT_TRUE(signalled); } } client_config; launch_client_process(client_config); } TEST_F(DefaultDisplayServerTestFixture, MultiSurfaceClientTracksBufferFdsCorrectly) { struct ClientConfig : ClientConfigCommon { void exec() { mir_wait_for(mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this)); ASSERT_TRUE(connection != NULL); EXPECT_TRUE(mir_connection_is_valid(connection)); EXPECT_STREQ("", mir_connection_get_error_message(connection)); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; surf_one = mir_connection_create_surface_sync(connection, &request_params); surf_two = mir_connection_create_surface_sync(connection, &request_params); ASSERT_TRUE(surf_one != NULL); ASSERT_TRUE(surf_two != NULL); buffers = 0; while (buffers < 1024) { mir_surface_swap_buffers_sync(surf_one); mir_surface_swap_buffers_sync(surf_two); buffers++; } /* We should not have any stray fds hanging around. Test this by trying to open a new one */ int canary_fd; canary_fd = open("/dev/null", O_RDONLY); ASSERT_TRUE(canary_fd > 0) << "Failed to open canary file descriptor: "<< strerror(errno); EXPECT_TRUE(canary_fd < 1024); close(canary_fd); mir_wait_for(mir_surface_release(surf_one, release_surface_callback, this)); mir_wait_for(mir_surface_release(surf_two, release_surface_callback, this)); ASSERT_TRUE(surf_one == NULL); ASSERT_TRUE(surf_two == NULL); mir_connection_release(connection); } virtual void surface_released (MirSurface* surf) { if (surf == surf_one) surf_one = NULL; if (surf == surf_two) surf_two = NULL; } MirSurface* surf_one; MirSurface* surf_two; } client_config; launch_client_process(client_config); } } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_test_framework.cpp0000644000015301777760000000444112322054223026066 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_framework/testing_server_configuration.h" #include "mir_test_framework/in_process_server.h" #include "mir_toolkit/mir_client_library.h" #include #include #include #include namespace mf = mir::frontend; // We need some tests to prove that errors are reported by the // display server test fixture. But don't want them to fail in // normal builds. TEST_F(BespokeDisplayServerTestFixture, DISABLED_failing_server_side_test) { struct Server : TestingServerConfiguration { void exec() { using namespace testing; FAIL() << "Proving a test can fail"; } } fail; launch_server_process(fail); } TEST_F(BespokeDisplayServerTestFixture, DISABLED_failing_without_server) { } TEST_F(DefaultDisplayServerTestFixture, demonstrate_multiple_clients) { struct Client : TestingClientConfiguration { void exec() { SCOPED_TRACE("Demo Client"); } } demo; for(int i = 0; i != 10; ++i) { launch_client_process(demo); } } namespace { struct DemoInProcessServer : mir_test_framework::InProcessServer { virtual mir::DefaultServerConfiguration& server_config() { return server_config_; } mir_test_framework::StubbedServerConfiguration server_config_; }; } TEST_F(DemoInProcessServer, client_can_connect) { auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__); EXPECT_TRUE(mir_connection_is_valid(connection)); mir_connection_release(connection); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_surfaceloop.cpp0000644000015301777760000002160212322054223025352 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/common.h" #include "mir/geometry/size.h" #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/mir_client_library_debug.h" #include "src/client/mir_connection.h" #include "mir_protobuf.pb.h" #include "mir_test_framework/display_server_test_fixture.h" #include #include #include #include "mir_test/gmock_fixes.h" namespace geom = mir::geometry; namespace mcl = mir::client; namespace mtf = mir_test_framework; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); geom::Size const size{640, 480}; } namespace mir { namespace { struct SurfaceSync { SurfaceSync() : surface(0) { } void surface_created(MirSurface * new_surface) { std::unique_lock lock(guard); surface = new_surface; wait_condition.notify_all(); } void surface_released(MirSurface * /*released_surface*/) { std::unique_lock lock(guard); surface = NULL; wait_condition.notify_all(); } void wait_for_surface_create() { std::unique_lock lock(guard); while (!surface) wait_condition.wait(lock); } void wait_for_surface_release() { std::unique_lock lock(guard); while (surface) wait_condition.wait(lock); } std::mutex guard; std::condition_variable wait_condition; MirSurface * surface; }; struct ClientConfigCommon : TestingClientConfiguration { ClientConfigCommon() : connection(NULL) { } static void connection_callback(MirConnection * connection, void * context) { ClientConfigCommon * config = reinterpret_cast(context); config->connected(connection); } void connected(MirConnection * new_connection) { std::unique_lock lock(guard); connection = new_connection; wait_condition.notify_all(); } void wait_for_connect() { std::unique_lock lock(guard); while (!connection) wait_condition.wait(lock); } std::mutex guard; std::condition_variable wait_condition; MirConnection * connection; static const int max_surface_count = 5; SurfaceSync ssync[max_surface_count]; }; const int ClientConfigCommon::max_surface_count; } } using mir::SurfaceSync; using mir::ClientConfigCommon; namespace { void create_surface_callback(MirSurface* surface, void * context) { SurfaceSync* config = reinterpret_cast(context); config->surface_created(surface); } void release_surface_callback(MirSurface* surface, void * context) { SurfaceSync* config = reinterpret_cast(context); config->surface_released(surface); } void wait_for_surface_create(SurfaceSync* context) { context->wait_for_surface_create(); } void wait_for_surface_release(SurfaceSync* context) { context->wait_for_surface_release(); } } TEST_F(DefaultDisplayServerTestFixture, creates_surface_of_correct_size) { struct Client : ClientConfigCommon { void exec() { mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this); wait_for_connect(); MirSurfaceParameters request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_connection_create_surface(connection, &request_params, create_surface_callback, ssync); wait_for_surface_create(ssync); request_params.width = 1600; request_params.height = 1200; mir_connection_create_surface(connection, &request_params, create_surface_callback, ssync+1); wait_for_surface_create(ssync+1); MirSurfaceParameters response_params; mir_surface_get_parameters(ssync->surface, &response_params); EXPECT_EQ(640, response_params.width); EXPECT_EQ(480, response_params.height); EXPECT_EQ(mir_pixel_format_abgr_8888, response_params.pixel_format); EXPECT_EQ(mir_buffer_usage_hardware, response_params.buffer_usage); mir_surface_get_parameters(ssync[1].surface, &response_params); EXPECT_EQ(1600, response_params.width); EXPECT_EQ(1200, response_params.height); EXPECT_EQ(mir_pixel_format_abgr_8888, response_params.pixel_format); EXPECT_EQ(mir_buffer_usage_hardware, response_params.buffer_usage); mir_surface_release(ssync[1].surface, release_surface_callback, ssync+1); wait_for_surface_release(ssync+1); mir_surface_release(ssync->surface, release_surface_callback, ssync); wait_for_surface_release(ssync); mir_connection_release(connection); } } client_creates_surfaces; launch_client_process(client_creates_surfaces); } TEST_F(DefaultDisplayServerTestFixture, surfaces_have_distinct_ids) { struct Client : ClientConfigCommon { void exec() { mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this); wait_for_connect(); MirSurfaceParameters request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_connection_create_surface(connection, &request_params, create_surface_callback, ssync); wait_for_surface_create(ssync); request_params.width = 1600; request_params.height = 1200; mir_connection_create_surface(connection, &request_params, create_surface_callback, ssync+1); wait_for_surface_create(ssync+1); EXPECT_NE( mir_debug_surface_id(ssync[0].surface), mir_debug_surface_id(ssync[1].surface)); mir_surface_release(ssync[1].surface, release_surface_callback, ssync+1); wait_for_surface_release(ssync+1); mir_surface_release(ssync[0].surface, release_surface_callback, ssync); wait_for_surface_release(ssync); mir_connection_release(connection); } } client_creates_surfaces; launch_client_process(client_creates_surfaces); } TEST_F(DefaultDisplayServerTestFixture, creates_multiple_surfaces_async) { struct Client : ClientConfigCommon { void exec() { mir_connect(mir_test_socket, __PRETTY_FUNCTION__, connection_callback, this); wait_for_connect(); MirSurfaceParameters request_params = { __PRETTY_FUNCTION__, 640, 480, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; for (int i = 0; i != max_surface_count; ++i) mir_connection_create_surface(connection, &request_params, create_surface_callback, ssync+i); for (int i = 0; i != max_surface_count; ++i) wait_for_surface_create(ssync+i); for (int i = 0; i != max_surface_count; ++i) { for (int j = 0; j != max_surface_count; ++j) { if (i == j) EXPECT_EQ( mir_debug_surface_id(ssync[i].surface), mir_debug_surface_id(ssync[j].surface)); else EXPECT_NE( mir_debug_surface_id(ssync[i].surface), mir_debug_surface_id(ssync[j].surface)); } } for (int i = 0; i != max_surface_count; ++i) mir_surface_release(ssync[i].surface, release_surface_callback, ssync+i); for (int i = 0; i != max_surface_count; ++i) wait_for_surface_release(ssync+i); mir_connection_release(connection); } } client_creates_surfaces; launch_client_process(client_creates_surfaces); } mir-0.1.8+14.04.20140411/tests/acceptance-tests/test_client_focus_notification.cpp0000644000015301777760000001617312322054223030262 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "mir_test/wait_condition.h" #include "mir_test/event_matchers.h" #include "mir_test_framework/display_server_test_fixture.h" #include "mir_test_framework/cross_process_sync.h" #include #include namespace mt = mir::test; namespace mtf = mir_test_framework; namespace { char const* const mir_test_socket = mtf::test_socket_file().c_str(); } namespace { struct MockEventObserver { MOCK_METHOD1(see, void(MirEvent const*)); }; struct EventObservingClient : mtf::TestingClientConfiguration { EventObservingClient() : observer(std::make_shared()) { } static void handle_event(MirSurface* /* surface */, MirEvent const* ev, void* context) { auto client = static_cast(context); client->observer->see(ev); } virtual void expect_events(mt::WaitCondition* /* all_events_received */) = 0; static void surface_created(MirSurface *surface_, void *ctx) { auto client = static_cast(ctx); client->surface = surface_; // We need to set the event delegate from the surface_created // callback so we can block the reading of new events // until we are ready MirEventDelegate const event_delegate = { handle_event, client }; mir_surface_set_event_handler(surface_, &event_delegate); } void exec() { mt::WaitCondition all_events_received; expect_events(&all_events_received); connection = mir_connect_sync(mir_test_socket, __PRETTY_FUNCTION__); ASSERT_TRUE(connection != NULL); MirSurfaceParameters const request_params = { __PRETTY_FUNCTION__, surface_width, surface_height, mir_pixel_format_abgr_8888, mir_buffer_usage_hardware, mir_display_output_id_invalid }; mir_wait_for(mir_connection_create_surface(connection, &request_params, surface_created, this)); all_events_received.wait_for_at_most_seconds(60); mir_surface_release_sync(surface); mir_connection_release(connection); // The ClientConfig is not destroyed before the testing process // exits. observer.reset(); } std::shared_ptr observer; static int const surface_width = 100; static int const surface_height = 100; MirConnection *connection; MirSurface *surface; }; } TEST_F(BespokeDisplayServerTestFixture, a_surface_is_notified_of_receiving_focus) { using namespace ::testing; TestingServerConfiguration server_config; launch_server_process(server_config); struct FocusObservingClient : public EventObservingClient { void expect_events(mt::WaitCondition* all_events_received) override { EXPECT_CALL(*observer, see(Pointee(mt::SurfaceEvent(mir_surface_attrib_focus, mir_surface_focused)))).Times(1) .WillOnce(mt::WakeUp(all_events_received)); // We may not see mir_surface_unfocused before connection closes EXPECT_CALL(*observer, see(Pointee(mt::SurfaceEvent(mir_surface_attrib_focus, mir_surface_unfocused)))).Times(AtMost(1)); } } client_config; launch_client_process(client_config); } namespace { ACTION_P(SignalFence, fence) { fence->try_signal_ready_for(); } } TEST_F(BespokeDisplayServerTestFixture, two_surfaces_are_notified_of_gaining_and_losing_focus) { using namespace ::testing; TestingServerConfiguration server_config; launch_server_process(server_config); // We use this for synchronization to ensure the two clients // are launched in a defined order. mtf::CrossProcessSync ready_for_second_client; struct FocusObservingClientOne : public EventObservingClient { mtf::CrossProcessSync ready_for_second_client; FocusObservingClientOne(mtf::CrossProcessSync const& ready_for_second_client) : ready_for_second_client(ready_for_second_client) { } void expect_events(mt::WaitCondition* all_events_received) override { InSequence seq; // We should receive focus as we are created EXPECT_CALL(*observer, see(Pointee(mt::SurfaceEvent(mir_surface_attrib_focus, mir_surface_focused)))).Times(1) .WillOnce(SignalFence(&ready_for_second_client)); // And lose it as the second surface is created EXPECT_CALL(*observer, see(Pointee(mt::SurfaceEvent(mir_surface_attrib_focus, mir_surface_unfocused)))).Times(1); // And regain it when the second surface is closed EXPECT_CALL(*observer, see(Pointee(mt::SurfaceEvent(mir_surface_attrib_focus, mir_surface_focused)))).Times(1).WillOnce(mt::WakeUp(all_events_received)); // And then lose it as we are closed (but we may not see confirmation before connection closes) EXPECT_CALL(*observer, see(Pointee(mt::SurfaceEvent(mir_surface_attrib_focus, mir_surface_unfocused)))).Times(AtMost(1)); } } client_one_config(ready_for_second_client); launch_client_process(client_one_config); struct FocusObservingClientTwo : public EventObservingClient { mtf::CrossProcessSync ready_for_second_client; FocusObservingClientTwo(mtf::CrossProcessSync const& ready_for_second_client) : ready_for_second_client(ready_for_second_client) { } void exec() override { // We need some synchronization to ensure client two does not connect before client one. ready_for_second_client.wait_for_signal_ready_for(); EventObservingClient::exec(); } void expect_events(mt::WaitCondition* all_events_received) override { EXPECT_CALL(*observer, see(Pointee( mt::SurfaceEvent(mir_surface_attrib_focus, mir_surface_focused)))) .Times(1).WillOnce(mt::WakeUp(all_events_received)); // We may not see mir_surface_unfocused before connection closes EXPECT_CALL(*observer, see(Pointee( mt::SurfaceEvent(mir_surface_attrib_focus, mir_surface_unfocused)))) .Times(AtMost(1)); } } client_two_config(ready_for_second_client); launch_client_process(client_two_config); } mir-0.1.8+14.04.20140411/deploy-and-test.sh0000755000015301777760000000221312322054247020250 0ustar pbusernogroup00000000000000#!/bin/sh if [ ! -d build-android-arm ] ; then echo "Built tree not found in $(pwd)/build-android-arm" exit 1 fi # Unpack umockdev requirements ( cd build-android-arm ; apt-get download umockdev:armhf libumockdev0:armhf ; dpkg -x umockdev_*armhf*.deb . ; dpkg -x libumockdev0_*armhf*.deb . ) adb push build-android-arm/bin /home/phablet/mir/bin adb push build-android-arm/lib /home/phablet/mir/lib adb push build-android-arm/usr /home/phablet/mir/usr adb shell "LD_LIBRARY_PATH=/home/phablet/mir/usr/lib/arm-linux-gnueabihf/:/home/phablet/mir/lib PATH=$PATH:/home/phablet/mir/usr/bin bash -c \"cd /home/phablet/mir/usr/bin ; umockdev-run /home/phablet/mir/bin/mir_unit_tests\"" adb shell "LD_LIBRARY_PATH=/home/phablet/mir/usr/lib/arm-linux-gnueabihf/:/home/phablet/mir/lib PATH=$PATH:/home/phablet/mir/usr/bin bash -c \"cd /home/phablet/mir/usr/bin ; umockdev-run /home/phablet/mir/bin/mir_integration_tests\"" adb shell "LD_LIBRARY_PATH=/home/phablet/mir/usr/lib/arm-linux-gnueabihf/:/home/phablet/mir/lib PATH=$PATH:/home/phablet/mir/usr/bin bash -c \"cd /home/phablet/mir/usr/bin ; umockdev-run /home/phablet/mir/bin/mir_acceptance_tests\"" mir-0.1.8+14.04.20140411/cross-compile-chroot.sh0000755000015301777760000000360712322054223021314 0ustar pbusernogroup00000000000000#!/bin/bash # build script to compile Mir for armhf devices # set -e usage() { echo "usage: $(basename $0) [-c] [-u]" echo "-c clean before building" echo "-u update partial chroot directory" echo "-h this message" } clean_build_dir() { rm -rf ${1} mkdir ${1} } BUILD_DIR=build-android-arm NUM_JOBS=$(( $(grep -c ^processor /proc/cpuinfo) + 1 )) _do_update_chroot=0 while getopts "cuh" OPTNAME do case $OPTNAME in c ) clean_build_dir ${BUILD_DIR} ;; u ) _do_update_chroot=1 ;; h ) usage exit 0 ;; * ) echo "invalid option specified" usage exit 1 ;; esac done if [ "${MIR_NDK_PATH}" = "" ]; then export MIR_NDK_PATH=$(pwd)/partial-armhf-chroot fi if [ ! -d ${MIR_NDK_PATH} ]; 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 if [ ${_do_update_chroot} -eq 1 ] ; then pushd tools > /dev/null ./setup-partial-armhf-chroot.sh ${MIR_NDK_PATH} popd > /dev/null # force a clean build after an update, since CMake cache maybe out of date clean_build_dir ${BUILD_DIR} fi echo "Using MIR_NDK_PATH: ${MIR_NDK_PATH}" pushd ${BUILD_DIR} > /dev/null export PKG_CONFIG_PATH="${MIR_NDK_PATH}/usr/lib/pkgconfig:${MIR_NDK_PATH}/usr/lib/arm-linux-gnueabihf/pkgconfig" export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 export PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 export PKG_CONFIG_SYSROOT_DIR=$MIR_NDK_PATH export PKG_CONFIG_EXECUTABLE=`which pkg-config` echo "Using PKG_CONFIG_PATH: $PKG_CONFIG_PATH" echo "Using PKG_CONFIG_EXECUTABLE: $PKG_CONFIG_EXECUTABLE" cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/LinuxCrossCompile.cmake \ -DBoost_COMPILER=-gcc \ -DMIR_PLATFORM=android\;mesa \ .. make -j${NUM_JOBS} popd > /dev/null mir-0.1.8+14.04.20140411/design/0000755000015301777760000000000012322054703016150 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/design/Architecture.dia0000644000015301777760000001707012322054223021253 0ustar pbusernogroup00000000000000][sƕ~P)p vʞlık' 07 䌕{4" H M3U$_f[᏿Ίyo.|RNw\^ۯp;~U~c_}syZ-~u'R<,UYb&Ȯ࡫oxlmVf/,&*s(Y>.6z ^dwMg~5? y"v_;[)m YVM807E3X9LrQ# {n W:.ty(UMW7eYټA]U|8r^+@ժ|ebGOН{WMo_޸[OtvukjM~:_q^míU?|2~MǮ^NLú(ڼhl~|ٜ7OVa߯mV^|}_E1]Nl2'=a" Aآ|ZVPcN(Qjw&H.Dd"T;T"rb^IYQ%qjŲ/ݣR N.1!2ӻU7B?־|YVA댅3F K411`PAR W<0iyU(W%8a=#0; +ch zMg  c>g Tb W1; 즬n5`{2@u/?]Pv!0(wz9'E$ Tq)`/zTB(R܏a"ٍNyyRbFIz_UOe @+ ҃HJ 2IdQ@zmJE({t)9>MyM[ؕ?wjR<ߜl9UQi`iHbJwZs$)h@k f*|u;cLaeeVoc̻؎%Q: ô(z@lG¾c C)竬%] r5Yo|8& Ƙ^ǁ!r^ <8: xWden-VD(0$ )EZ;W Qc+iU!4wr]2]߯$x-Ԛz.YU^܅ g,?&xdP"hPzD:L S- N }z=4g#w(ݾM*N^m>al|C6]ŕa^VP~lZ<M,r'EmSw`Oj0d b(YY-A#P`&^|}( (>΋ Ƕ'ln6$hvϫV'%vGq6`<c*c3yfG^F?MWQEX6E+!|߅}Z$c14$m$m-O% fΏ"do[ `kWeQ:t@:t$ܘqB l[I82iN8VϏ!dzxmJd#G?2d#G"*ORybݯ L!\*pGZ(W+byϋ)>R|H#G)>R|H⟆*-E GHlĹN|M%󨝒G_;F'ξŢos #Gޏy?~#Gޏd_55<XxԤ~@RjDO&r{Y7!~C?w|^]i jr ?~$H#G ?~$HOCï\DZX„Yad #RNS2qDɸeCe}o Kd#Gv߇]zϑ#Gz={H J(Ks%j<H@D(5~7?n-n#GH#G?=B:r!1"'K#'UW%N*`?_Pwi州_ G?2d#G?2[m߄R-TxnLT;¤#\ Flߢh7sx;\e (c35loT{򓙹fg>Y:=ھyӣSmGZ//{Ӿ)y憌`oj8 H(,DQ\ %lVwvOlByz~QY}][;֦ 3=v.M?F姍s;v.VE. b #RI#}H#Gt>}HO[Yp"a幷Y +_}" :iJus#(YØ5<$Ŵ腉HE"Na0& c0& c0& ZB&}7cEJJ⌫C'_zHH1<ŨU׫r=G$zq HR H5j j#N$RT *S! Qr1t5=R ojX9"Ho$I $H2dL2dp<× QM~*Cmpd Pyк7~Q ʤxaH5>kpSf-$C"@l d# 6H<" 'ΤL-(Ěeֳ;LԳ1e}c"/U_p ;lR^ }v8$BOe Ϡ[`b)mj$m sdp8;SN)t2EdiH!k)*.Q`H5ԥU56~niRQ#Z"OD8'OOdp*mcM'R;9W ᑄ&U`JQpAm̍N9ڵzT= 4LT%*D$0097rfJ)f lTz'DR4>j~km7tNO$'POI)Q18>6[] C o#d=8iǡ5{tJ׭a9 OI7pb'-vHٺ=ې#j1.ŌV)Md|ݷA[;V%e2iX6IٕAsLjBv#ٗ6Rm 05MN9[7l0Yg|s iȖ˶E#k7NE'4H™T:kb(r|Fӡu= 7F?S- Au6Zrjh6Z7dszP"Z ł8]NoB="O͊G>gUq+P뢞ڃxVhԍ:UG^Fvc=3Fc8y|e=f={ݶuǂ{{Lޡ+3;e"nz刚-c \?H@1`n 5QD7@&|:Gg1HUfX(#Gޏy?~#Gޏy\#YŎgZcT8?$& HֹՄ:SʖjEu.˭%_:,YH󫬖fhvljĚ nM#9>FǮ씳[q1Xp|uBD1:5pmu[))=\N RjU[m:5Z gB+s #0b˦Zխ_~ r20Pg&Dr/D_AX*P"doQ_ZMbs ;O[Qֱ$Z`yoȊJ+v9댕K m)ƃqDO Trٔ\90#Z0ǥͳGh*gk7&0p* M+Up=DksoMOc׀t$)w9~A&&"ddГ!o&3O0)1)1)1)1)1)1)dI*7DFE%AVGɄr? UBD-c[S!M9+<[bޓ],6^7󯑴.}5 ;;F)gK۟MSo2^Zxp %(nb6{ |݌"—3w};L3}*|焪9InɍYGu伶w T=Wkֿ0٦ᾡ![ȇ! ])Zi_#v}|w=-6D_#o_uyȖ=E`DWD= IHubHY}=C6òZ_nIwMa %GbhH-@ :g-رw~pugؐh`upUh;mJ6 G¤-moAvM`L+ċ9eA¼:׈zOWU4SX*˘*xM fhξ;O PF}W?9<ѡ*U?y::ZU4?Wcr֡/# hE[,arx!GT_~WWUYoe;#5c8dAQȴUAFSpCQ[&vt^lfR GrDK^ityNMir޸M6Ebm*9*31%X>Y)P;F*Ǜ)t_]2ɱ4K34K34K34K34K34K34d:+1oX@R:}Z( 8.%gS)#V -+nݚ9-Dup3ܴDJ4#Rl H5t;%f1ωzȁM"EyA ŋ>Q_"b(FCfF%+ O Lyuc6z A`C 0! A`C8e"9G,&HT+_mR)X9IFEvv+;; /@ Dum![w{ iCe)qB%XP~5lGdX"T% U n㯎bΟ.U$YAMD{[;;S'>j/K4< ?>a][0HFNi`ņaZQ'Ͻ8}ۺ8=fDi7Jp4}*vIٲ%ђ,ֵ{suS6 Brߒ)}&7J#C}}o~#RD#1-g?Bh?U>xWVtt?lEv`DQz=O 㸯֑Pcv.3?F /4ߌ9[a$ExS#G(3)=E&ڲ#[c$ݏ%gMY+D,яZǓ9@(Vޛ\\x$|4Jr#M4Nݍ/\PV}pĒ!@H* e:fM y!=oyq _"75QsC>7 ;YDD`H:uJ4ZEH14aP$Y'Xw734:b8jk) d&M @61~?I7>DHfbS3RS;FuDZŕPmƄč#{j]U VP"f+êTò >h[Дa0aL²/;>(cqDZg*'ry͖5q)Yj2ZYr69@QÜb/&ՂPx]]B>[KìIwgsYGj{fB-R&3{ifX%c`9̕BIu=շ_5_wU64HDmir-0.1.8+14.04.20140411/native-compile.sh0000755000015301777760000000050612322054223020150 0ustar pbusernogroup00000000000000#!/bin/sh # Native build script for Mir # set -e BUILD_DIR=build-linux-x86 if [ ! -e ${BUILD_DIR} ]; then mkdir ${BUILD_DIR} ( cd ${BUILD_DIR} && cmake ..) fi cmake --build ${BUILD_DIR} GTEST_OUTPUT=xml:./ ${BUILD_DIR}/bin/mir_acceptance_tests ${BUILD_DIR}/bin/mir_integration_tests ${BUILD_DIR}/bin/mir_unit_tests mir-0.1.8+14.04.20140411/doc/0000755000015301777760000000000012322054703015444 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/doc/mainpage.md0000644000015301777760000000474212322054223017553 0ustar pbusernogroup00000000000000Welcome to Mir {#mainpage} ============== Mir is a next generation display server targeted as a replacement for the X window server system to unlock next-generation user experiences for devices ranging from Linux desktop to mobile devices powered by Ubuntu. The primary purpose of Mir is to enable the development of the next generation [Unity](http://unity.ubuntu.com). More detailed information about the motivation, scope, and high-level design of Mir can be found at http://wiki.ubuntu.com/MirSpec . Getting and installing Mir -------------------------- ### Using pre-built packages If you just want to try out mir, or write client applications, then the easiest way is to use the pre-built packages: - \ref installing_prebuilt_on_pc - \ref installing_prebuilt_on_android ### Building and installing from source If you are curious about Mir internals or intend to contribute to it, you should get the source and build it: - \ref building_source_for_pc - \ref building_source_for_android Using Mir --------- - \ref using_mir_on_pc - \ref using_mir_on_android - \ref debug_for_xmir Getting involved ---------------- The best place to ask questions and discuss about the Mir project is the #ubuntu-mir IRC channel on freenode. The Mir project is hosted on Launchpad: https://launchpad.net/mir Currently, the Mir code activity is performed on a development branch: lp:~mir-team/mir/development-branch Approximately fortnightly, this development branch is promoted to the branch used for the ubuntu archive and touch images. Please submit any merge proposals against the development branch. Please file bug reports at: https://bugs.launchpad.net/mir The Mir development mailing list can be found at: https://lists.ubuntu.com/mailman/listinfo/Mir-devel The Mir coding guidelines are [here](cppguide/index.html). Learn about Mir ---------------- Android technical info: - \ref android_technical_details Writing client applications --------------------------- - \ref mir_toolkit "Mir API Documentation" - \subpage basic.c "basic.c: A basic Mir client (which does nothing)" Writing server applications --------------------------- Mir server is written as a library which allows the server code to be adapted for bespoke applications. - \subpage render_surfaces-example "render_surfaces.cpp: A simple program using the Mir library" - \ref demo_inprocess_egl Working on Mir code ------------------- - \ref md_README "Mir Read me" - \ref md_HACKING "Mir hacking guide" - \ref component_reports mir-0.1.8+14.04.20140411/doc/extra.css0000644000015301777760000000127112322054223017277 0ustar pbusernogroup00000000000000body, table, div, p, dl { font: 400 14px/19px Ubuntu,Arial,sans-serif; } #projectname { font: 300% Ubuntu,Arial,sans-serif; margin: 0px; padding: 2px 0px; } #projectbrief { font: 120% Ubuntu,Arial,sans-serif; margin: 0px; padding: 0px; } #projectnumber { font: 50% Ubuntu,Arial,sans-serif; margin: 0px; padding: 0px; } div.toc li { background: url("bdwn.png") no-repeat scroll 0 5px transparent; font: 10px/1.2 Ubuntu,Arial,sans-serif; margin-top: 5px; padding-left: 10px; padding-top: 2px; } div.toc h3 { font: bold 12px/1.2 Ubuntu,Arial,FreeSans,sans-serif; color: #E24106; border-bottom: 0 none; margin: 0; } mir-0.1.8+14.04.20140411/doc/using_mir_on_pc.md0000644000015301777760000001023412322054223021135 0ustar pbusernogroup00000000000000Using Mir on a PC {#using_mir_on_pc} ================= Before you begin ---------------- Make sure your hardware is supported. That means you're using a Mesa driver, of which intel, radeon, and nouveau families are supported. If you're logged in to X then run this command to verify an appropriate DRI driver is active: sudo pmap `pidof X` | grep dri.so or lsmod | grep drm Before you can use Mir you need to ensure you have the proper custom Mesa build installed. If you are running Ubuntu 13.10 or later (see \ref installing_prebuilt_on_pc), you should be good to go. If you built Mir from source code (see \ref building_source_for_pc), you need to ensure you are using the proper Mesa at runtime. You can do that by installing the Mesa packages from Ubuntu 13.10 (or later) or by building the custom Mesa yourself and ensuring it can be found by Mir, e.g., by using LD_LIBRARY_PATH. Using Mir as system compositor with X ------------------------------------- Note: for this to work you need to have Mir and all its dependencies (which include lightdm, Mesa and the Xorg drivers). The easiest way is to run Ubuntu 13.10 or later. If you are running Ubuntu 13.10, additionally install unity-system-compositor. If you are running Ubuntu 14.04 or later, instead install ubuntu-desktop-mir. These packages will install dependencies you need and will create a file in /etc/lightdm/lightdm.conf.d/10-unity-system-compositor.conf. If you have instead built from source, to set up the system compositor, create /etc/lightdm/lightdm.conf.d/10-unity-system-compositor.conf yourself and make it look like this: [SeatDefaults] type=unity Now restart lightdm: $ sudo restart lightdm Or you may simply reboot. In theory, you should now find yourself back in Ubuntu and not notice anything different. You can verify you're in Mir several ways: $ ps aux | grep unity-system-compositor $ grep -i xmir /var/log/Xorg.0.log $ ls -l /var/log/lightdm/unity-system-compositor.log If problems occur, have a look at the following log files: /var/log/lightdm/lightdm.log /var/log/lightdm/unity-system-compositor.log /var/log/lightdm/x-0.log /var/log/Xorg.0.log You may not be able to get to a terminal if your video system has locked up. In that case secure shell into to your machine and read / copy these logs. They are overwritten on next boot. In any case, if you wish to deactivate XMir upon boot, simply comment out the type=unity line from /etc/lightdm/lightdm.conf.d/10-unity-system-compositor.conf, like this: [SeatDefaults] #type=unity If you cannot boot into a graphical display or terminal to disable XMir, then enter recovery mode as described in https://wiki.ubuntu.com/RecoveryMode. From there edit / move / remove /etc/lightdm/lightdm.conf.d/10-unity-system-compositor.conf and then reboot. To modify the filesystem you will need to enter the following command: # mount / -o remount,rw Running Mir natively -------------------- You can also run Mir natively. To do so, log in to VT1 (Ctrl+Alt+F1) _after_ you are already logged in to X. If you do so before then you will not be assigned adequate credentials to access the graphics hardware and will get strange errors. VT switching away from Mir will only work if Mir is run as root. In this case we need to change the permissions to the Mir socket so that clients can connect: $ sudo mir_demo_server_basic - log in to VT 2 $ sudo chmod a+rw /tmp/mir_socket $ some-mir-client -m /tmp/mir_socket - switch back to Mir. Watch your friends be amazed! In case you accidentally killed your X login and ended up with a failsafe screen, you might find on subsequent reboots you can't log in to X at all any more (it instantly and silently takes you back to the login screen). The fix for this is to log in to a VT and: $ rm .Xauthority $ sudo restart lightdm Getting some example client applications ---------------------------------------- You can get some example programs by installing the `mir-demos` package: $ sudo apt-get install mir-demos If you are building from source you can find client applications in the bin/ subdirectory of the build directory. mir-0.1.8+14.04.20140411/doc/component_reports.md0000644000015301777760000000554612322054223021555 0ustar pbusernogroup00000000000000Mir component reports {#component_reports} ===================== Both the server library and the client library include facilities to provide debugging and tracing information at runtime. This is achieved through component reports, which are sets of interesting events provided by many Mir components. A component report can be usually handled in a number of different ways, configured using command-line options and/or environment variables. By default, component reports are turned off. Server reports -------------- The way component reports are handled on the server can be configured using either command-line options or environment variables. The environment variables are prefixed with `MIR_SERVER_` and contain underscores ('_') instead of dashes ('-'). The available component reports and handlers for the server are: Report | Handlers ----------------------- | -------- connector-report | log,lttng display-report | log,lttng input-report | log,lttng legacy-input-report | log msg-processor-report | log,lttng session-mediator-report | log,lttng scene-report | log,lttng For example, to enable the LTTng input report, one could either use the `--input-report=lttng` command-line option to the server, or set the `MIR_SERVER_INPUT_REPORT=lttng` environment variable. Client reports -------------- Client side reports can be configured only using environment variables. The environment variables are prefixed with `MIR_CLIENT_` and contain only underscores. The available reports and handlers for the client are: Report | Handlers ------------------- | -------- rpc-report | log,lttng input-receiver | log,lttng For example, to enable the logging RPC report, one should set the `MIR_CLIENT_RPC_REPORT=log` environment variable. LTTng support ------------- Mir provides LTTng tracepoints for various interesting events. You can enable LTTng tracing for a Mir component by using the corresponding command-line option or environment variable for that component's report: $ lttng create mirsession -o /tmp/mirsession $ lttng enable-event -u -a $ lttng start $ mir_demo_server_basic --msg-processor-report=lttng $ lttng stop $ babeltrace /tmp/mirsession/ LTTng-UST versions up to and including 2.1.2, and up to and including 2.2-rc2 contain a bug (lttng #538) that prevents event recording if the tracepoint provider is dlopen()-ed at runtime, like in the case of Mir. If you have a version of LTTng affected by this bug, you need to pre-load the server tracepoint provider library: $ LD_PRELOAD=libmirserverlttng.so mir_demo_server_basic --msg-processor-report=lttng The bug also affects client-side LTTng tracing, in which case you need to pre-load the client tracepoint provider library: $ LD_PRELOAD=libmirclientlttng.so MIR_CLIENT_RPC_REPORT=lttng myclient mir-0.1.8+14.04.20140411/doc/android_technical_details.md0000644000015301777760000000356412322054223023132 0ustar pbusernogroup00000000000000Android Technical Details {#android_technical_details} =============================== Mir Usage of Android Drivers ---------------------------- Mir relies on the libhybris library to use the Android drivers. This allows the drivers to use the bionic libc while Mir itself uses the standard GNU libc. Mir Display Modes ----------------- When you're using Mir to drive the display of the Android device, Mir has a default way to display, as well as a backup mode that it can try if the default mode isn't working. * Default Mode The default display mode uses the HWC HAL module from the Android drivers. Depending on the version and device, the default mode may also use the framebuffer HAL module. These modules are used to determine the display information, to synchronize with vsync, and to post to the display. The HWC is not used at this time to provide overlay support. * Backup Mode The backup mode is used when the primary display mode is unavailable (due to system problems, missing shared libraries, or similar conditions) The backup mode will only use the framebuffer HAL module. This module is a bit more limited than the HWC module, and the driver support might be a bit less thoroughly tested. It still should give you a display though. Mir Device Support ------------------ In theory, all devices with that use the normal Android drivers abstractions should run Mir. Currently, we support HWC (hardware composer) version 1.1 (JB/ICS devices). The other HWC versions should use the backup mode to draw to the screen. Development focus is currently on the Nexus line of devices, so these should be more thoroughly tested. If you have another sort of device, give Mir a try! If it doesn't work, please file a bug, being very specific about the chipset, GPU, and driver versions that your phone has. mir-0.1.8+14.04.20140411/doc/installing_prebuilt_on_pc.md0000644000015301777760000000076112322054223023217 0ustar pbusernogroup00000000000000Installing pre-built packages on a PC {#installing_prebuilt_on_pc} ===================================== Install Ubuntu 13.10 or later if you haven't done so already. Uninstall any proprietary drivers (-nvidia, -fglrx) and reboot on the FOSS drivers. Install Mir in Ubuntu 13.10: sudo apt-get update sudo apt-get install mir-demos unity-system-compositor Install Mir in Ubuntu 14.04 or later: sudo apt-get update sudo apt-get install mir-demos ubuntu-desktop-mir mir-0.1.8+14.04.20140411/doc/footer.html.in0000644000015301777760000000016612322054223020235 0ustar pbusernogroup00000000000000

Copyright © 2012,2013 Canonical Ltd.
Generated on @DATE_TODAY@

mir-0.1.8+14.04.20140411/doc/building_source_for_android.md0000644000015301777760000000517412322054223023515 0ustar pbusernogroup00000000000000Building the source for Android {#building_source_for_android} =============================== There are a few ways to compile for a target arm device. Only armhf (not armel) is supported at this time. Native Compile -------------- If you have a target device, you should be able to compile directly on the ARM device. This will be probably be slow, given the relative desktop/embedded CPU speeds these days. Emulated Compile ---------------- This method uses QEMU ARM emulation and an armhf chroot on a amd64/ia32 system to produce armhf binaries. This is useful in packaging, but is still slower than a cross compile. There are many ways to do this, depending on your workflow. You can set up a qemu pbuilder armhf setup to do compile with. This is typically useful for packaging when you only have a desktop computer. Alternatively, you can set up an armhf chroot on your device. Typically this involves getting an armhf base image, and installing qemu emulation. This guide gives an overview of how to get emulation in the armhf chroot: http://wiki.debian.org/QemuUserEmulation Native Compile or Emulated Compile Instructions ----------------------------------------------- From within the armhf system: - Set up Dependencies $ apt-get install devscripts equivs cmake $ mk-build-deps --install --tool "apt-get -y" --build-dep debian/control - Build $ bzr branch lp:mir $ mkdir mir/build; cd mir/build $ cmake -DBoost_COMPILER=-gcc -DMIR_PLATFORM=android .. Cross Compile ------------- This method uses a cross compiler (e.g., the `g++-arm-linux-gnueabihf` ubuntu package) to produce armhf code. This is typically the quickest way to compile and run code, and is well suited for a development workflow. Initial setup of a desktop machine for cross-compiling to armhf is simple: $ sudo apt-get install g++-arm-linux-gnueabihf/trusty debootstrap $ sudo sh -c 'echo "deb [arch=armhf] http://ports.ubuntu.com/ubuntu-ports/ trusty main restricted universe multiverse" > /etc/apt/sources.list.d/armhf-xcompile.list' $ sudo apt-get update Now to test that everything is working you can try downloading a package like this: $ apt-get download gcc:armhf Once you're able to download armhf packages from the repository, the cross-compile-chroot.sh script provides an example of how to build Mir for armhf: $ ./cross-compile-chroot.sh $ ls -l build-android-arm/* # binaries to copy to your device To speed up the process for future branches you may wish to cache the files downloaded by setting environment variable MIR_NDK_PATH to point to a directory that cross-compile-chroot.sh should reuse each time. mir-0.1.8+14.04.20140411/doc/building_source_for_pc.md0000644000015301777760000000664012322054223022476 0ustar pbusernogroup00000000000000Building the source for a PC {#building_source_for_pc} ============================ Getting Mir ----------- Mir is a project on Launchpad (https://launchpad.net/mir). To grab a copy use the command: $ bzr branch lp:mir Getting dependencies -------------------- To succesfully build Mir there are a few packages required. The easiest way to get them is to use the packaging build dependencies: $ sudo apt-get install devscripts equivs cmake $ sudo mk-build-deps --install --tool "apt-get -y" --build-dep debian/control Building Mir ------------ Mir is built using CMake. You first need to create the build directory and configure the build: $ mkdir build $ cd build $ cmake .. (possibly passing configuration options to CMake) There are many configuration options for the Mir project. The default options will work fine, but you may want to customize the build depending on your needs. The best way to get an overview and set them is to use the cmake-gui tool: $ cmake-gui .. The next step is to build the source and run the tests: $ make (-j8) $ ctest To install Mir just use the normal make install command: $ make install This will install the Mir libraries, executable, example clients and header files to the configured installation location (/usr/local by default). If you install to a non-standard location, keep in mind that you will probably need to properly set the PKG_CONFIG_PATH environment variable to allow other applications to build against Mir, and LD_LIBRARY_PATH to allow applications to find the Mir libraries at runtime. Building Mesa ------------- For GL accelerated clients to use Mir they need to use a patched version of Mesa that supports Mir. The patch is hosted on GitHub: $ git clone https://github.com/RAOF/mesa.git Compile as per normal instructions and pass --with-egl-platforms="mir,drm" to the configure options. You will need libmirclient installed as shown above. Building X.Org -------------- To run an X server inside Mir you need to build a patched version of the X.Org X server. The patch is hosted on GitHub: $ git clone https://github.com/RAOF/xserver.git Compile as per normal instructions and pass --enable-xmir to the configure options. You will need libmirclient installed as shown above. Building the X.Org drivers -------------------------- To run an X server inside Mir you also need a patched version of your X.Org video driver. The three drivers - Intel, Radeon, and Nouveau - are available on Launchpad: $ bzr branch lp:~mir-team/mir/xf86-video-intel-vladmir $ bzr branch lp:~mir-team/mir/xf86-video-ati-vladmir $ bzr branch lp:~mir-team/mir/xf86-video-nouveau Compile as per normal instructions. These need to be built after the X server, as they depend on new interfaces there. Building Unity System Compositor -------------------------------- If you want to run a full system using XMir then you need to use a system compositor. For Ubuntu we have a system compositor project on Launchpad (https://launchpad.net/unity-system-compositor). Compile with the following: $ bzr branch lp:unity-system-compositor $ cd unity-system-compositor $ mkdir build $ cd build $ cmake .. You will need libmirserver installed as shown above. To use the system compositor you need a display manager that supports it. At the time of writing LightDM is the only display manager with support and has been available since version 1.7.4. mir-0.1.8+14.04.20140411/doc/Doxyfile.in0000644000015301777760000024135112322054223017562 0ustar pbusernogroup00000000000000# Doxyfile 1.8.4 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed # in front of the TAG it is preceding . # All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or sequence of words) that should # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. PROJECT_NAME = Mir # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer # a quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify an logo or icon that is # included in the documentation. The maximum height of the logo should not # exceed 55 pixels and the maximum width should not exceed 200 pixels. # Doxygen will copy the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/doc # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Latvian, Lithuanian, Norwegian, Macedonian, # Persian, Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, # Slovak, Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = YES # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. Note that you specify absolute paths here, but also # relative paths, which will be relative from the directory where doxygen is # started. STRIP_FROM_PATH = @CMAKE_CURRENT_SOURCE_DIR@ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = YES # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding # "class=itcl::class" will allow you to use the command class in the # itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, # and language is one of the parsers supported by doxygen: IDL, Java, # Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, # C++. For instance to make doxygen treat .inc files as Fortran files (default # is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note # that for custom extensions you also need to set FILE_PATTERNS otherwise the # files are not read by doxygen. EXTENSION_MAPPING = # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all # comments according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you # can mix doxygen, HTML, and XML commands with Markdown formatting. # Disable only in case of backward compatibilities issues. MARKDOWN_SUPPORT = YES # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by by putting a % sign in front of the word # or globally by setting AUTOLINK_SUPPORT to NO. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES (the # default) will make doxygen replace the get and set methods by a property in # the documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and # unions are shown inside the group in which they are included (e.g. using # @ingroup) instead of on a separate page (for HTML and Man pages) or # section (for LaTeX and RTF). INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and # unions with only public data fields or simple typedef fields will be shown # inline in the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO (the default), structs, classes, and unions are shown on a separate # page (for HTML and Man pages) or section (for LaTeX and RTF). INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can # be an expensive process and often the same symbol appear multiple times in # the code, doxygen keeps a cache of pre-resolved symbols. If the cache is too # small doxygen will become slower. If the cache is too large, memory is wasted. # The cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid # range is 0..9, the default is 0, corresponding to a cache size of 2^16 = 65536 # symbols. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES all members with package or internal # scope will be included in the documentation. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespaces are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to # do proper type resolution of all parameters of a function it will reject a # match between the prototype and the implementation of a member function even # if there is only one candidate or it is obvious which candidate to choose # by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen # will still accept a match between prototype and implementation in such cases. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if section-label ... \endif # and \cond section-label ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or macro consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and macros in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also # http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. Do not use # file names with spaces, bibtex cannot handle them. CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_NO_PARAMDOC option can be enabled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = @CMAKE_CURRENT_SOURCE_DIR@/README.md \ @CMAKE_CURRENT_SOURCE_DIR@/HACKING.md \ @CMAKE_CURRENT_SOURCE_DIR@/doc \ @CMAKE_CURRENT_SOURCE_DIR@/src \ @CMAKE_CURRENT_SOURCE_DIR@/examples \ @CMAKE_CURRENT_SOURCE_DIR@/include # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh # *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py # *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.markdown \ *.md \ *.mm \ *.dox \ *.py \ *.f90 \ *.f \ *.for \ *.vhd \ *.vhdl # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = */include/mir_test* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = android \ google \ mfd \ mgg \ mp # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/examples # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be ignored. # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty or if # non of the patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) # and it is also possible to disable source filtering for a specific pattern # using *.ext= (so without naming a filter). This option only has effect when # FILTER_SOURCE_FILES is enabled. FILTER_SOURCE_PATTERNS = # If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. Note that when using a custom header you are responsible # for the proper inclusion of any scripts and style sheets that doxygen # needs, which is dependent on the configuration options used. # It is advised to generate a default header using "doxygen -w html # header.html footer.html stylesheet.css YourConfigFile" and then modify # that header. Note that the header is subject to change so you typically # have to redo this when upgrading to a newer version of doxygen or when # changing the value of configuration settings such as GENERATE_TREEVIEW! HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = @CMAKE_BINARY_DIR@/doc/footer.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If left blank doxygen will # generate a default style sheet. Note that it is recommended to use # HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this # tag will in the future become obsolete. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional # user-defined cascading style sheet that is included after the standard # style sheets created by doxygen. Using this option one can overrule # certain style aspects. This is preferred over using HTML_STYLESHEET # since it does not replace the standard style sheet and is therefor more # robust against future updates. Doxygen will copy the style sheet file to # the output directory. HTML_EXTRA_STYLESHEET = @CMAKE_BINARY_DIR@/doc/extra.css # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that # the files will be copied as-is; there are no commands or markers available. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 16 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 240 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. HTML_DYNAMIC_SECTIONS = NO # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of # entries shown in the various tree structured indices initially; the user # can expand and collapse entries dynamically later on. Doxygen will expand # the tree to such a level that at most the specified number of entries are # visible (unless a fully collapsed tree already exceeds this amount). # So setting the number of entries 1 will produce a full collapsed tree by # default. 0 is a special value representing an infinite number of entries # and will result in a full expanded tree by default. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely # identify the documentation publisher. This should be a reverse domain-name # style string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) # at top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. Since the tabs have the same information as the # navigation tree you can set this option to NO if you already set # GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. # Since the tree basically has the same information as the tab index you # could consider to set DISABLE_INDEX to NO when enabling this option. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values # (range [0,1..20]) that doxygen will group on one line in the generated HTML # documentation. Note that a value of 0 will completely suppress the enum # values from appearing in the overview section. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax # (see http://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you may also need to install MathJax separately and # configure the path to it using the MATHJAX_RELPATH option. USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and # SVG. The default value is HTML-CSS, which is slower, but has the best # compatibility. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the # HTML output directory using the MATHJAX_RELPATH option. The destination # directory should contain the MathJax.js script. For instance, if the mathjax # directory is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to # the MathJax Content Delivery Network so you can quickly see the result without # installing MathJax. # However, it is strongly recommended to install a local # copy of MathJax from http://www.mathjax.org before deployment. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript # pieces of code that will be used on startup of the MathJax code. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. # There are two flavours of web server based search depending on the # EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for # searching and an index file used by the script. When EXTERNAL_SEARCH is # enabled the indexing and searching needs to be provided by external tools. # See the manual for details. SERVER_BASED_SEARCH = NO # When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP # script for searching. Instead the search results are written to an XML file # which needs to be processed by an external indexer. Doxygen will invoke an # external search engine pointed to by the SEARCHENGINE_URL option to obtain # the search results. Doxygen ships with an example indexer (doxyindexer) and # search engine (doxysearch.cgi) which are based on the open source search # engine library Xapian. See the manual for configuration details. EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will returned the search results when EXTERNAL_SEARCH is enabled. # Doxygen ships with an example search engine (doxysearch) which is based on # the open source search engine library Xapian. See the manual for configuration # details. SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the # SEARCHDATA_FILE tag the name of this file can be specified. SEARCHDATA_FILE = searchdata.xml # When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the # EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is # useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple # projects and redirect the results back to the right project. EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are # all added to the same external search index. Each project needs to have a # unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id # of to a relative location where the documentation can be found. # The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ... EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4 will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for # the generated latex document. The footer should contain everything after # the last chapter. If it is left blank doxygen will generate a # standard footer. Notice: only use this tag if you know what you are doing! LATEX_FOOTER = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images # or other source files which should be copied to the LaTeX output directory. # Note that the files will be copied as-is; there are no commands or markers # available. LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See # http://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load style sheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- # If the GENERATE_DOCBOOK tag is set to YES Doxygen will generate DOCBOOK files # that can be used to generate PDF. GENERATE_DOCBOOK = NO # The DOCBOOK_OUTPUT tag is used to specify where the DOCBOOK pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be put in # front of it. If left blank docbook will be used as the default path. DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = __cplusplus # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition that # overrules the definition found in the source code. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all references to function-like macros # that are alone on a line, have an all uppercase name, and do not end with a # semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. For each # tag file the location of the external documentation should be added. The # format of a tag file without this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths # or URLs. Note that each tag file must have a unique name (where the name does # NOT include the path). If a tag file is not located in the directory in which # doxygen is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # If the EXTERNAL_PAGES tag is set to YES all external pages will be listed # in the related pages index. If set to NO, only the current project's # pages will be listed. EXTERNAL_PAGES = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option also works with HAVE_DOT disabled, but it is recommended to # install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = @DOXYGEN_DOT_FOUND@ # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will use the Helvetica font for all dot files that # doxygen generates. When you want a differently looking font you can specify # the font name using DOT_FONTNAME. You need to make sure dot is able to find # the font, which can be done by putting it in a standard location or by setting # the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. DOT_FONTNAME = Arial # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the Helvetica font. # If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to # set the path where dot can find it. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = NO # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If the UML_LOOK tag is enabled, the fields and methods are shown inside # the class node. If there are many fields or methods and many nodes the # graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS # threshold limits the number of items for each type to make the size more # manageable. Set this to 0 for no limit. Note that the threshold may be # exceeded by 50% before the limit is enforced. UML_LIMIT_NUM_FIELDS = 10 # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are svg, png, jpg, or gif. # If left blank png will be used. If you choose svg you need to set # HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # Note that this requires a modern browser other than Internet Explorer. # Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you # need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files # visible. Older versions of IE do not have SVG support. INTERACTIVE_SVG = NO # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the # \mscfile command). MSCFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES mir-0.1.8+14.04.20140411/doc/using_mir_on_android.md0000644000015301777760000000146512322054223022161 0ustar pbusernogroup00000000000000Using Mir on an Android device {#using_mir_on_android} ============================== After installing mir on your device (see \ref installing_prebuilt_on_android) switch off SurfaceFlinger (see: https://wiki.ubuntu.com/Touch/Testing/Mir#Switch_from_SurfaceFlinger_to_Mir). (Alternatively, you can install a mir based image as described here: https://wiki.ubuntu.com/Touch/Testing/Mir#Easiest_way) Open a shell on the device: $ adb shell Now, start Mir and a client application: # mir_demo_server_basic & # mir_demo_client_something # take your pick of something Getting some example client applications ---------------------------------------- You can get some example programs by installing the `mir-demos` package inside the Ubuntu touch chroot shell (see above): # apt-get install mir-demos mir-0.1.8+14.04.20140411/doc/installing_prebuilt_on_android.md0000644000015301777760000000216512322054223024235 0ustar pbusernogroup00000000000000Installing pre-built packages on an Android device {#installing_prebuilt_on_android} ================================================== Supported Devices ----------------- The following devices have been tested with Mir: | Device | Status | | ------------------ | ------ | | Galaxy Nexus (SGX) | tested | | Nexus 7 (nvidia) | tested - needs special hybris for nvidia atm | | Nexus 4 (qualcomm) | tested | Installing Mir -------------- 1. First you must install a phablet image on your device, by following the directions at https://wiki.ubuntu.com/Touch/Install on one of the supported devices. Once you have booted into the device with Ubuntu Touch ensure you then connect the device to the internet. 2. With your device connected via USB, type: $ adb devices just to ensure you are connected, then open the android shell: $ adb root $ adb shell 3. Add the Mir staging PPA to your device's sources list: # apt-get install software-properties-common # add-apt-repository ppa:mir-team/staging # apt-get update 4. Install Mir: # apt-get install mir-demos mir-0.1.8+14.04.20140411/doc/debug_for_xmir.md0000644000015301777760000000763612322054223020772 0ustar pbusernogroup00000000000000Debug for XMir {#debug_for_xmir} ================= What is XMir ? ---------------- In order to help with debugging, it's important to understand what XMir is and what bugs are likely to occur. XMir is not a replacement to X and does not alter X or compiz window management functionality in the current Ubuntu stack. XMir is an addition to the system. XMir enables Mir to be employed as a system compositor under the X stack, in this configuration Mir composites the greeter and the desktop sessions. XMir is currently targeted at the Ubuntu 13.10 release as being the default configuration. It currently supports open source graphics drivers based on Mesa, Nouveau and Radeon. Once XMir is installed and properly configured, upon boot or restart of the LightDM daemon, Mir will determine if there is proper driver support; in the instance where proprietary drivers not supporting the Mir driver model are detected, LightDM will continue to boot into the standalone X configuration without error. From a visual perspective on Ubuntu desktop, XMir and standalone X are identical (note, currently there is an X cursor present on XMir but this soon be disabled, making the experience truly identical and indiscernible without checking on what processes are running, see \ref using_mir_on_pc). How to toggle between XMir and standalone X ? ------------------------------------- In order to return to a standalone X configuration, comment out the following line in /etc/lightdm/lightdm.conf.d/10-unity-system-compositor.conf to look to look like this: [SeatDefaults] #type=unity Simply reboot or restart LightDM. To reverse the process, simply comment the line back in to enable XMir. Most common bugs ------------------------------------- At the moment, the most common bugs are related to failures to boot into XMir. Due to the robust fallback mechanisms in place, most failures will result in completing the boot sequence standalone X configuration, when you expected XMir. 1. First check your /etc/lightdm/lightdm.conf.d/10-unity-system-compositor.conf has type=unity properly enabled. 2. When logging a bug, please include the log files contained in the /var/log/lightdm/ directory. Note, it is good to inspect the last update to these files to see if they were written to in your boot attempt, obviously if they were not updated their contents are irrelevant. The most important of these files is likely the lightdm.log and unity-system-compositor.log. You are more than welcome to inspect these files, frequently there will be an error statement in unity-system-compositor.log which can be traced back into the source code for further debug. 3. If you have the experience of booting to a black screen which seems frozen, you may attempt to switch VT's by selecting to see if there is a UI present. Alternatively, , login at the console, copy out the log files mentioned above, then toggle back to standalone X as described above and rebooting. Other bugs ------------------------------------- If you experience a UI lock up or a crash, it would be helpful to double check for X backtracing which can be found here: https://wiki.ubuntu.com/X/Debugging Note, it is highly unlikely you will see any visual corruption due to XMir. If you experience a visual corruption during use, it is most likely that it a bug that exists in the standalone X Ubuntu configuration. Please attempt to toggle back to the standalone X configuration and replicate the use case. If you succeed in only being able to repeat the visual corruption in XMir and not in standalone X, please file a bug with a detailed description of hardware used, XMir component versions used and the use case steps. You may check the versions of key XMir components by the following dpkg -s libmirclient3 | grep Version dpkg -s libmirserver0 | grep Version dpkg -s lightdm | grep Version dpkg -s unity-system-compositor | grep Version mir-0.1.8+14.04.20140411/README.md0000644000015301777760000000263512322054223016161 0ustar pbusernogroup00000000000000Readme ====== mir - cross-platform display manager ------------------------------------ Mir is a display manager that provides efficient support for graphics coprocessors. License (server) ------- 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 . License (client) ------- This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . \copyright Copyright © 2012 Canonical Ltd. \author Alan Griffiths mir-0.1.8+14.04.20140411/3rd_party/0000755000015301777760000000000012322054703016606 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/0000755000015301777760000000000012322054703021363 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/0000755000015301777760000000000012322054703023003 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/external/0000755000015301777760000000000012322054703024625 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/external/kernel-headers/0000755000015301777760000000000012322054703027516 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/external/kernel-headers/original/0000755000015301777760000000000012322054703031322 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/external/kernel-headers/original/linux/0000755000015301777760000000000012322054703032461 5ustar pbusernogroup00000000000000././@LongLink0000000000000000000000000000015000000000000011211 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/external/kernel-headers/original/linux/input.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/external/kernel-headers/original/linux/inpu0000644000015301777760000007727012322054223033371 0ustar pbusernogroup00000000000000#ifndef _INPUT_H #define _INPUT_H /* * Copyright (c) 1999-2002 Vojtech Pavlik * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. */ #include #include #include #include /* * The event structure itself */ struct input_event { struct timeval time; __u16 type; __u16 code; __s32 value; }; /* * Protocol version. */ #define EV_VERSION 0x010001 /* * IOCTLs (0x00 - 0x7f) */ struct input_id { __u16 bustype; __u16 vendor; __u16 product; __u16 version; }; /** * struct input_absinfo - used by EVIOCGABS/EVIOCSABS ioctls * @value: latest reported value for the axis. * @minimum: specifies minimum value for the axis. * @maximum: specifies maximum value for the axis. * @fuzz: specifies fuzz value that is used to filter noise from * the event stream. * @flat: values that are within this value will be discarded by * joydev interface and reported as 0 instead. * @resolution: specifies resolution for the values reported for * the axis. * * Note that input core does not clamp reported values to the * [minimum, maximum] limits, such task is left to userspace. * * Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in * units per millimeter (units/mm), resolution for rotational axes * (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian. */ struct input_absinfo { __s32 value; __s32 minimum; __s32 maximum; __s32 fuzz; __s32 flat; __s32 resolution; }; /** * struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls * @scancode: scancode represented in machine-endian form. * @len: length of the scancode that resides in @scancode buffer. * @index: index in the keymap, may be used instead of scancode * @flags: allows to specify how kernel should handle the request. For * example, setting INPUT_KEYMAP_BY_INDEX flag indicates that kernel * should perform lookup in keymap by @index instead of @scancode * @keycode: key code assigned to this scancode * * The structure is used to retrieve and modify keymap data. Users have * option of performing lookup either by @scancode itself or by @index * in keymap entry. EVIOCGKEYCODE will also return scancode or index * (depending on which element was used to perform lookup). */ struct input_keymap_entry { #define INPUT_KEYMAP_BY_INDEX (1 << 0) __u8 flags; __u8 len; __u16 index; __u32 keycode; __u8 scancode[32]; }; #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ #define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ #define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */ #define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */ #define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */ #define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry) #define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */ #define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry) #define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ #define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ #define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ #define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) /* get device properties */ /** * EVIOCGMTSLOTS(len) - get MT slot values * @len: size of the data buffer in bytes * * The ioctl buffer argument should be binary equivalent to * * struct input_mt_request_layout { * __u32 code; * __s32 values[num_slots]; * }; * * where num_slots is the (arbitrary) number of MT slots to extract. * * The ioctl size argument (len) is the size of the buffer, which * should satisfy len = (num_slots + 1) * sizeof(__s32). If len is * too small to fit all available slots, the first num_slots are * returned. * * Before the call, code is set to the wanted ABS_MT event type. On * return, values[] is filled with the slot values for the specified * ABS_MT code. * * If the request code is not an ABS_MT value, -EINVAL is returned. */ #define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len) #define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global key state */ #define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */ #define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */ #define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */ #define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) /* get event bits */ #define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) /* get abs value/limits */ #define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) /* set abs value/limits */ #define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */ #define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ #define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ #define EVIOCGSUSPENDBLOCK _IOR('E', 0x91, int) /* get suspend block enable */ #define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int) /* set suspend block enable */ #define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */ /* * Device properties and quirks */ #define INPUT_PROP_POINTER 0x00 /* needs a pointer */ #define INPUT_PROP_DIRECT 0x01 /* direct input devices */ #define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */ #define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */ #define INPUT_PROP_MAX 0x1f #define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) /* * Event types */ #define EV_SYN 0x00 #define EV_KEY 0x01 #define EV_REL 0x02 #define EV_ABS 0x03 #define EV_MSC 0x04 #define EV_SW 0x05 #define EV_LED 0x11 #define EV_SND 0x12 #define EV_REP 0x14 #define EV_FF 0x15 #define EV_PWR 0x16 #define EV_FF_STATUS 0x17 #define EV_MAX 0x1f #define EV_CNT (EV_MAX+1) /* * Synchronization events. */ #define SYN_REPORT 0 #define SYN_CONFIG 1 #define SYN_MT_REPORT 2 #define SYN_DROPPED 3 /* * Keys and buttons * * Most of the keys/buttons are modeled after USB HUT 1.12 * (see http://www.usb.org/developers/hidpage). * Abbreviations in the comments: * AC - Application Control * AL - Application Launch Button * SC - System Control */ #define KEY_RESERVED 0 #define KEY_ESC 1 #define KEY_1 2 #define KEY_2 3 #define KEY_3 4 #define KEY_4 5 #define KEY_5 6 #define KEY_6 7 #define KEY_7 8 #define KEY_8 9 #define KEY_9 10 #define KEY_0 11 #define KEY_MINUS 12 #define KEY_EQUAL 13 #define KEY_BACKSPACE 14 #define KEY_TAB 15 #define KEY_Q 16 #define KEY_W 17 #define KEY_E 18 #define KEY_R 19 #define KEY_T 20 #define KEY_Y 21 #define KEY_U 22 #define KEY_I 23 #define KEY_O 24 #define KEY_P 25 #define KEY_LEFTBRACE 26 #define KEY_RIGHTBRACE 27 #define KEY_ENTER 28 #define KEY_LEFTCTRL 29 #define KEY_A 30 #define KEY_S 31 #define KEY_D 32 #define KEY_F 33 #define KEY_G 34 #define KEY_H 35 #define KEY_J 36 #define KEY_K 37 #define KEY_L 38 #define KEY_SEMICOLON 39 #define KEY_APOSTROPHE 40 #define KEY_GRAVE 41 #define KEY_LEFTSHIFT 42 #define KEY_BACKSLASH 43 #define KEY_Z 44 #define KEY_X 45 #define KEY_C 46 #define KEY_V 47 #define KEY_B 48 #define KEY_N 49 #define KEY_M 50 #define KEY_COMMA 51 #define KEY_DOT 52 #define KEY_SLASH 53 #define KEY_RIGHTSHIFT 54 #define KEY_KPASTERISK 55 #define KEY_LEFTALT 56 #define KEY_SPACE 57 #define KEY_CAPSLOCK 58 #define KEY_F1 59 #define KEY_F2 60 #define KEY_F3 61 #define KEY_F4 62 #define KEY_F5 63 #define KEY_F6 64 #define KEY_F7 65 #define KEY_F8 66 #define KEY_F9 67 #define KEY_F10 68 #define KEY_NUMLOCK 69 #define KEY_SCROLLLOCK 70 #define KEY_KP7 71 #define KEY_KP8 72 #define KEY_KP9 73 #define KEY_KPMINUS 74 #define KEY_KP4 75 #define KEY_KP5 76 #define KEY_KP6 77 #define KEY_KPPLUS 78 #define KEY_KP1 79 #define KEY_KP2 80 #define KEY_KP3 81 #define KEY_KP0 82 #define KEY_KPDOT 83 #define KEY_ZENKAKUHANKAKU 85 #define KEY_102ND 86 #define KEY_F11 87 #define KEY_F12 88 #define KEY_RO 89 #define KEY_KATAKANA 90 #define KEY_HIRAGANA 91 #define KEY_HENKAN 92 #define KEY_KATAKANAHIRAGANA 93 #define KEY_MUHENKAN 94 #define KEY_KPJPCOMMA 95 #define KEY_KPENTER 96 #define KEY_RIGHTCTRL 97 #define KEY_KPSLASH 98 #define KEY_SYSRQ 99 #define KEY_RIGHTALT 100 #define KEY_LINEFEED 101 #define KEY_HOME 102 #define KEY_UP 103 #define KEY_PAGEUP 104 #define KEY_LEFT 105 #define KEY_RIGHT 106 #define KEY_END 107 #define KEY_DOWN 108 #define KEY_PAGEDOWN 109 #define KEY_INSERT 110 #define KEY_DELETE 111 #define KEY_MACRO 112 #define KEY_MUTE 113 #define KEY_VOLUMEDOWN 114 #define KEY_VOLUMEUP 115 #define KEY_POWER 116 /* SC System Power Down */ #define KEY_KPEQUAL 117 #define KEY_KPPLUSMINUS 118 #define KEY_PAUSE 119 #define KEY_SCALE 120 /* AL Compiz Scale (Expose) */ #define KEY_KPCOMMA 121 #define KEY_HANGEUL 122 #define KEY_HANGUEL KEY_HANGEUL #define KEY_HANJA 123 #define KEY_YEN 124 #define KEY_LEFTMETA 125 #define KEY_RIGHTMETA 126 #define KEY_COMPOSE 127 #define KEY_STOP 128 /* AC Stop */ #define KEY_AGAIN 129 #define KEY_PROPS 130 /* AC Properties */ #define KEY_UNDO 131 /* AC Undo */ #define KEY_FRONT 132 #define KEY_COPY 133 /* AC Copy */ #define KEY_OPEN 134 /* AC Open */ #define KEY_PASTE 135 /* AC Paste */ #define KEY_FIND 136 /* AC Search */ #define KEY_CUT 137 /* AC Cut */ #define KEY_HELP 138 /* AL Integrated Help Center */ #define KEY_MENU 139 /* Menu (show menu) */ #define KEY_CALC 140 /* AL Calculator */ #define KEY_SETUP 141 #define KEY_SLEEP 142 /* SC System Sleep */ #define KEY_WAKEUP 143 /* System Wake Up */ #define KEY_FILE 144 /* AL Local Machine Browser */ #define KEY_SENDFILE 145 #define KEY_DELETEFILE 146 #define KEY_XFER 147 #define KEY_PROG1 148 #define KEY_PROG2 149 #define KEY_WWW 150 /* AL Internet Browser */ #define KEY_MSDOS 151 #define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */ #define KEY_SCREENLOCK KEY_COFFEE #define KEY_DIRECTION 153 #define KEY_CYCLEWINDOWS 154 #define KEY_MAIL 155 #define KEY_BOOKMARKS 156 /* AC Bookmarks */ #define KEY_COMPUTER 157 #define KEY_BACK 158 /* AC Back */ #define KEY_FORWARD 159 /* AC Forward */ #define KEY_CLOSECD 160 #define KEY_EJECTCD 161 #define KEY_EJECTCLOSECD 162 #define KEY_NEXTSONG 163 #define KEY_PLAYPAUSE 164 #define KEY_PREVIOUSSONG 165 #define KEY_STOPCD 166 #define KEY_RECORD 167 #define KEY_REWIND 168 #define KEY_PHONE 169 /* Media Select Telephone */ #define KEY_ISO 170 #define KEY_CONFIG 171 /* AL Consumer Control Configuration */ #define KEY_HOMEPAGE 172 /* AC Home */ #define KEY_REFRESH 173 /* AC Refresh */ #define KEY_EXIT 174 /* AC Exit */ #define KEY_MOVE 175 #define KEY_EDIT 176 #define KEY_SCROLLUP 177 #define KEY_SCROLLDOWN 178 #define KEY_KPLEFTPAREN 179 #define KEY_KPRIGHTPAREN 180 #define KEY_NEW 181 /* AC New */ #define KEY_REDO 182 /* AC Redo/Repeat */ #define KEY_F13 183 #define KEY_F14 184 #define KEY_F15 185 #define KEY_F16 186 #define KEY_F17 187 #define KEY_F18 188 #define KEY_F19 189 #define KEY_F20 190 #define KEY_F21 191 #define KEY_F22 192 #define KEY_F23 193 #define KEY_F24 194 #define KEY_PLAYCD 200 #define KEY_PAUSECD 201 #define KEY_PROG3 202 #define KEY_PROG4 203 #define KEY_DASHBOARD 204 /* AL Dashboard */ #define KEY_SUSPEND 205 #define KEY_CLOSE 206 /* AC Close */ #define KEY_PLAY 207 #define KEY_FASTFORWARD 208 #define KEY_BASSBOOST 209 #define KEY_PRINT 210 /* AC Print */ #define KEY_HP 211 #define KEY_CAMERA 212 #define KEY_SOUND 213 #define KEY_QUESTION 214 #define KEY_EMAIL 215 #define KEY_CHAT 216 #define KEY_SEARCH 217 #define KEY_CONNECT 218 #define KEY_FINANCE 219 /* AL Checkbook/Finance */ #define KEY_SPORT 220 #define KEY_SHOP 221 #define KEY_ALTERASE 222 #define KEY_CANCEL 223 /* AC Cancel */ #define KEY_BRIGHTNESSDOWN 224 #define KEY_BRIGHTNESSUP 225 #define KEY_MEDIA 226 #define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video outputs (Monitor/LCD/TV-out/etc) */ #define KEY_KBDILLUMTOGGLE 228 #define KEY_KBDILLUMDOWN 229 #define KEY_KBDILLUMUP 230 #define KEY_SEND 231 /* AC Send */ #define KEY_REPLY 232 /* AC Reply */ #define KEY_FORWARDMAIL 233 /* AC Forward Msg */ #define KEY_SAVE 234 /* AC Save */ #define KEY_DOCUMENTS 235 #define KEY_BATTERY 236 #define KEY_BLUETOOTH 237 #define KEY_WLAN 238 #define KEY_UWB 239 #define KEY_UNKNOWN 240 #define KEY_VIDEO_NEXT 241 /* drive next video source */ #define KEY_VIDEO_PREV 242 /* drive previous video source */ #define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */ #define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */ #define KEY_DISPLAY_OFF 245 /* display device to off state */ #define KEY_WIMAX 246 #define KEY_RFKILL 247 /* Key that controls all radios */ #define KEY_MICMUTE 248 /* Mute / unmute the microphone */ /* Code 255 is reserved for special needs of AT keyboard driver */ #define BTN_MISC 0x100 #define BTN_0 0x100 #define BTN_1 0x101 #define BTN_2 0x102 #define BTN_3 0x103 #define BTN_4 0x104 #define BTN_5 0x105 #define BTN_6 0x106 #define BTN_7 0x107 #define BTN_8 0x108 #define BTN_9 0x109 #define BTN_MOUSE 0x110 #define BTN_LEFT 0x110 #define BTN_RIGHT 0x111 #define BTN_MIDDLE 0x112 #define BTN_SIDE 0x113 #define BTN_EXTRA 0x114 #define BTN_FORWARD 0x115 #define BTN_BACK 0x116 #define BTN_TASK 0x117 #define BTN_JOYSTICK 0x120 #define BTN_TRIGGER 0x120 #define BTN_THUMB 0x121 #define BTN_THUMB2 0x122 #define BTN_TOP 0x123 #define BTN_TOP2 0x124 #define BTN_PINKIE 0x125 #define BTN_BASE 0x126 #define BTN_BASE2 0x127 #define BTN_BASE3 0x128 #define BTN_BASE4 0x129 #define BTN_BASE5 0x12a #define BTN_BASE6 0x12b #define BTN_DEAD 0x12f #define BTN_GAMEPAD 0x130 #define BTN_A 0x130 #define BTN_B 0x131 #define BTN_C 0x132 #define BTN_X 0x133 #define BTN_Y 0x134 #define BTN_Z 0x135 #define BTN_TL 0x136 #define BTN_TR 0x137 #define BTN_TL2 0x138 #define BTN_TR2 0x139 #define BTN_SELECT 0x13a #define BTN_START 0x13b #define BTN_MODE 0x13c #define BTN_THUMBL 0x13d #define BTN_THUMBR 0x13e #define BTN_DIGI 0x140 #define BTN_TOOL_PEN 0x140 #define BTN_TOOL_RUBBER 0x141 #define BTN_TOOL_BRUSH 0x142 #define BTN_TOOL_PENCIL 0x143 #define BTN_TOOL_AIRBRUSH 0x144 #define BTN_TOOL_FINGER 0x145 #define BTN_TOOL_MOUSE 0x146 #define BTN_TOOL_LENS 0x147 #define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */ #define BTN_TOUCH 0x14a #define BTN_STYLUS 0x14b #define BTN_STYLUS2 0x14c #define BTN_TOOL_DOUBLETAP 0x14d #define BTN_TOOL_TRIPLETAP 0x14e #define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */ #define BTN_WHEEL 0x150 #define BTN_GEAR_DOWN 0x150 #define BTN_GEAR_UP 0x151 #define KEY_OK 0x160 #define KEY_SELECT 0x161 #define KEY_GOTO 0x162 #define KEY_CLEAR 0x163 #define KEY_POWER2 0x164 #define KEY_OPTION 0x165 #define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */ #define KEY_TIME 0x167 #define KEY_VENDOR 0x168 #define KEY_ARCHIVE 0x169 #define KEY_PROGRAM 0x16a /* Media Select Program Guide */ #define KEY_CHANNEL 0x16b #define KEY_FAVORITES 0x16c #define KEY_EPG 0x16d #define KEY_PVR 0x16e /* Media Select Home */ #define KEY_MHP 0x16f #define KEY_LANGUAGE 0x170 #define KEY_TITLE 0x171 #define KEY_SUBTITLE 0x172 #define KEY_ANGLE 0x173 #define KEY_ZOOM 0x174 #define KEY_MODE 0x175 #define KEY_KEYBOARD 0x176 #define KEY_SCREEN 0x177 #define KEY_PC 0x178 /* Media Select Computer */ #define KEY_TV 0x179 /* Media Select TV */ #define KEY_TV2 0x17a /* Media Select Cable */ #define KEY_VCR 0x17b /* Media Select VCR */ #define KEY_VCR2 0x17c /* VCR Plus */ #define KEY_SAT 0x17d /* Media Select Satellite */ #define KEY_SAT2 0x17e #define KEY_CD 0x17f /* Media Select CD */ #define KEY_TAPE 0x180 /* Media Select Tape */ #define KEY_RADIO 0x181 #define KEY_TUNER 0x182 /* Media Select Tuner */ #define KEY_PLAYER 0x183 #define KEY_TEXT 0x184 #define KEY_DVD 0x185 /* Media Select DVD */ #define KEY_AUX 0x186 #define KEY_MP3 0x187 #define KEY_AUDIO 0x188 /* AL Audio Browser */ #define KEY_VIDEO 0x189 /* AL Movie Browser */ #define KEY_DIRECTORY 0x18a #define KEY_LIST 0x18b #define KEY_MEMO 0x18c /* Media Select Messages */ #define KEY_CALENDAR 0x18d #define KEY_RED 0x18e #define KEY_GREEN 0x18f #define KEY_YELLOW 0x190 #define KEY_BLUE 0x191 #define KEY_CHANNELUP 0x192 /* Channel Increment */ #define KEY_CHANNELDOWN 0x193 /* Channel Decrement */ #define KEY_FIRST 0x194 #define KEY_LAST 0x195 /* Recall Last */ #define KEY_AB 0x196 #define KEY_NEXT 0x197 #define KEY_RESTART 0x198 #define KEY_SLOW 0x199 #define KEY_SHUFFLE 0x19a #define KEY_BREAK 0x19b #define KEY_PREVIOUS 0x19c #define KEY_DIGITS 0x19d #define KEY_TEEN 0x19e #define KEY_TWEN 0x19f #define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */ #define KEY_GAMES 0x1a1 /* Media Select Games */ #define KEY_ZOOMIN 0x1a2 /* AC Zoom In */ #define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */ #define KEY_ZOOMRESET 0x1a4 /* AC Zoom */ #define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */ #define KEY_EDITOR 0x1a6 /* AL Text Editor */ #define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */ #define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */ #define KEY_PRESENTATION 0x1a9 /* AL Presentation App */ #define KEY_DATABASE 0x1aa /* AL Database App */ #define KEY_NEWS 0x1ab /* AL Newsreader */ #define KEY_VOICEMAIL 0x1ac /* AL Voicemail */ #define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ #define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ #define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ #define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ #define KEY_LOGOFF 0x1b1 /* AL Logoff */ #define KEY_DOLLAR 0x1b2 #define KEY_EURO 0x1b3 #define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */ #define KEY_FRAMEFORWARD 0x1b5 #define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */ #define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */ #define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */ #define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */ #define KEY_IMAGES 0x1ba /* AL Image Browser */ #define KEY_DEL_EOL 0x1c0 #define KEY_DEL_EOS 0x1c1 #define KEY_INS_LINE 0x1c2 #define KEY_DEL_LINE 0x1c3 #define KEY_FN 0x1d0 #define KEY_FN_ESC 0x1d1 #define KEY_FN_F1 0x1d2 #define KEY_FN_F2 0x1d3 #define KEY_FN_F3 0x1d4 #define KEY_FN_F4 0x1d5 #define KEY_FN_F5 0x1d6 #define KEY_FN_F6 0x1d7 #define KEY_FN_F7 0x1d8 #define KEY_FN_F8 0x1d9 #define KEY_FN_F9 0x1da #define KEY_FN_F10 0x1db #define KEY_FN_F11 0x1dc #define KEY_FN_F12 0x1dd #define KEY_FN_1 0x1de #define KEY_FN_2 0x1df #define KEY_FN_D 0x1e0 #define KEY_FN_E 0x1e1 #define KEY_FN_F 0x1e2 #define KEY_FN_S 0x1e3 #define KEY_FN_B 0x1e4 #define KEY_BRL_DOT1 0x1f1 #define KEY_BRL_DOT2 0x1f2 #define KEY_BRL_DOT3 0x1f3 #define KEY_BRL_DOT4 0x1f4 #define KEY_BRL_DOT5 0x1f5 #define KEY_BRL_DOT6 0x1f6 #define KEY_BRL_DOT7 0x1f7 #define KEY_BRL_DOT8 0x1f8 #define KEY_BRL_DOT9 0x1f9 #define KEY_BRL_DOT10 0x1fa #define KEY_NUMERIC_0 0x200 /* used by phones, remote controls, */ #define KEY_NUMERIC_1 0x201 /* and other keypads */ #define KEY_NUMERIC_2 0x202 #define KEY_NUMERIC_3 0x203 #define KEY_NUMERIC_4 0x204 #define KEY_NUMERIC_5 0x205 #define KEY_NUMERIC_6 0x206 #define KEY_NUMERIC_7 0x207 #define KEY_NUMERIC_8 0x208 #define KEY_NUMERIC_9 0x209 #define KEY_NUMERIC_STAR 0x20a #define KEY_NUMERIC_POUND 0x20b #define KEY_CAMERA_FOCUS 0x210 #define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */ #define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */ #define KEY_TOUCHPAD_ON 0x213 #define KEY_TOUCHPAD_OFF 0x214 #define KEY_CAMERA_ZOOMIN 0x215 #define KEY_CAMERA_ZOOMOUT 0x216 #define KEY_CAMERA_UP 0x217 #define KEY_CAMERA_DOWN 0x218 #define KEY_CAMERA_LEFT 0x219 #define KEY_CAMERA_RIGHT 0x21a #define BTN_TRIGGER_HAPPY 0x2c0 #define BTN_TRIGGER_HAPPY1 0x2c0 #define BTN_TRIGGER_HAPPY2 0x2c1 #define BTN_TRIGGER_HAPPY3 0x2c2 #define BTN_TRIGGER_HAPPY4 0x2c3 #define BTN_TRIGGER_HAPPY5 0x2c4 #define BTN_TRIGGER_HAPPY6 0x2c5 #define BTN_TRIGGER_HAPPY7 0x2c6 #define BTN_TRIGGER_HAPPY8 0x2c7 #define BTN_TRIGGER_HAPPY9 0x2c8 #define BTN_TRIGGER_HAPPY10 0x2c9 #define BTN_TRIGGER_HAPPY11 0x2ca #define BTN_TRIGGER_HAPPY12 0x2cb #define BTN_TRIGGER_HAPPY13 0x2cc #define BTN_TRIGGER_HAPPY14 0x2cd #define BTN_TRIGGER_HAPPY15 0x2ce #define BTN_TRIGGER_HAPPY16 0x2cf #define BTN_TRIGGER_HAPPY17 0x2d0 #define BTN_TRIGGER_HAPPY18 0x2d1 #define BTN_TRIGGER_HAPPY19 0x2d2 #define BTN_TRIGGER_HAPPY20 0x2d3 #define BTN_TRIGGER_HAPPY21 0x2d4 #define BTN_TRIGGER_HAPPY22 0x2d5 #define BTN_TRIGGER_HAPPY23 0x2d6 #define BTN_TRIGGER_HAPPY24 0x2d7 #define BTN_TRIGGER_HAPPY25 0x2d8 #define BTN_TRIGGER_HAPPY26 0x2d9 #define BTN_TRIGGER_HAPPY27 0x2da #define BTN_TRIGGER_HAPPY28 0x2db #define BTN_TRIGGER_HAPPY29 0x2dc #define BTN_TRIGGER_HAPPY30 0x2dd #define BTN_TRIGGER_HAPPY31 0x2de #define BTN_TRIGGER_HAPPY32 0x2df #define BTN_TRIGGER_HAPPY33 0x2e0 #define BTN_TRIGGER_HAPPY34 0x2e1 #define BTN_TRIGGER_HAPPY35 0x2e2 #define BTN_TRIGGER_HAPPY36 0x2e3 #define BTN_TRIGGER_HAPPY37 0x2e4 #define BTN_TRIGGER_HAPPY38 0x2e5 #define BTN_TRIGGER_HAPPY39 0x2e6 #define BTN_TRIGGER_HAPPY40 0x2e7 /* We avoid low common keys in module aliases so they don't get huge. */ #define KEY_MIN_INTERESTING KEY_MUTE #define KEY_MAX 0x2ff #define KEY_CNT (KEY_MAX+1) /* * Relative axes */ #define REL_X 0x00 #define REL_Y 0x01 #define REL_Z 0x02 #define REL_RX 0x03 #define REL_RY 0x04 #define REL_RZ 0x05 #define REL_HWHEEL 0x06 #define REL_DIAL 0x07 #define REL_WHEEL 0x08 #define REL_MISC 0x09 #define REL_MAX 0x0f #define REL_CNT (REL_MAX+1) /* * Absolute axes */ #define ABS_X 0x00 #define ABS_Y 0x01 #define ABS_Z 0x02 #define ABS_RX 0x03 #define ABS_RY 0x04 #define ABS_RZ 0x05 #define ABS_THROTTLE 0x06 #define ABS_RUDDER 0x07 #define ABS_WHEEL 0x08 #define ABS_GAS 0x09 #define ABS_BRAKE 0x0a #define ABS_HAT0X 0x10 #define ABS_HAT0Y 0x11 #define ABS_HAT1X 0x12 #define ABS_HAT1Y 0x13 #define ABS_HAT2X 0x14 #define ABS_HAT2Y 0x15 #define ABS_HAT3X 0x16 #define ABS_HAT3Y 0x17 #define ABS_PRESSURE 0x18 #define ABS_DISTANCE 0x19 #define ABS_TILT_X 0x1a #define ABS_TILT_Y 0x1b #define ABS_TOOL_WIDTH 0x1c #define ABS_VOLUME 0x20 #define ABS_MISC 0x28 #define ABS_MT_SLOT 0x2f /* MT slot being modified */ #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ #define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ #define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ #define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ #define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ #define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */ #define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ #define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */ #define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ #define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ #define ABS_MT_DISTANCE 0x3b /* Contact hover distance */ #define ABS_MAX 0x3f #define ABS_CNT (ABS_MAX+1) /* * Switch events */ #define SW_LID 0x00 /* set = lid shut */ #define SW_TABLET_MODE 0x01 /* set = tablet mode */ #define SW_HEADPHONE_INSERT 0x02 /* set = inserted */ #define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any" set = radio enabled */ #define SW_RADIO SW_RFKILL_ALL /* deprecated */ #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_DOCK 0x05 /* set = plugged into dock */ #define SW_LINEOUT_INSERT 0x06 /* set = inserted */ #define SW_JACK_PHYSICAL_INSERT 0x07 /* set = mechanical switch set */ #define SW_VIDEOOUT_INSERT 0x08 /* set = inserted */ #define SW_CAMERA_LENS_COVER 0x09 /* set = lens covered */ #define SW_KEYPAD_SLIDE 0x0a /* set = keypad slide out */ #define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */ #define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */ #define SW_LINEIN_INSERT 0x0d /* set = inserted */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1) /* * Misc events */ #define MSC_SERIAL 0x00 #define MSC_PULSELED 0x01 #define MSC_GESTURE 0x02 #define MSC_RAW 0x03 #define MSC_SCAN 0x04 #define MSC_MAX 0x07 #define MSC_CNT (MSC_MAX+1) /* * LEDs */ #define LED_NUML 0x00 #define LED_CAPSL 0x01 #define LED_SCROLLL 0x02 #define LED_COMPOSE 0x03 #define LED_KANA 0x04 #define LED_SLEEP 0x05 #define LED_SUSPEND 0x06 #define LED_MUTE 0x07 #define LED_MISC 0x08 #define LED_MAIL 0x09 #define LED_CHARGING 0x0a #define LED_MAX 0x0f #define LED_CNT (LED_MAX+1) /* * Autorepeat values */ #define REP_DELAY 0x00 #define REP_PERIOD 0x01 #define REP_MAX 0x01 #define REP_CNT (REP_MAX+1) /* * Sounds */ #define SND_CLICK 0x00 #define SND_BELL 0x01 #define SND_TONE 0x02 #define SND_MAX 0x07 #define SND_CNT (SND_MAX+1) /* * IDs. */ #define ID_BUS 0 #define ID_VENDOR 1 #define ID_PRODUCT 2 #define ID_VERSION 3 #define BUS_PCI 0x01 #define BUS_ISAPNP 0x02 #define BUS_USB 0x03 #define BUS_HIL 0x04 #define BUS_BLUETOOTH 0x05 #define BUS_VIRTUAL 0x06 #define BUS_ISA 0x10 #define BUS_I8042 0x11 #define BUS_XTKBD 0x12 #define BUS_RS232 0x13 #define BUS_GAMEPORT 0x14 #define BUS_PARPORT 0x15 #define BUS_AMIGA 0x16 #define BUS_ADB 0x17 #define BUS_I2C 0x18 #define BUS_HOST 0x19 #define BUS_GSC 0x1A #define BUS_ATARI 0x1B #define BUS_SPI 0x1C /* * MT_TOOL types */ #define MT_TOOL_FINGER 0 #define MT_TOOL_PEN 1 #define MT_TOOL_MAX 1 /* * Values describing the status of a force-feedback effect */ #define FF_STATUS_STOPPED 0x00 #define FF_STATUS_PLAYING 0x01 #define FF_STATUS_MAX 0x01 /* * Structures used in ioctls to upload effects to a device * They are pieces of a bigger structure (called ff_effect) */ /* * All duration values are expressed in ms. Values above 32767 ms (0x7fff) * should not be used and have unspecified results. */ /** * struct ff_replay - defines scheduling of the force-feedback effect * @length: duration of the effect * @delay: delay before effect should start playing */ struct ff_replay { __u16 length; __u16 delay; }; /** * struct ff_trigger - defines what triggers the force-feedback effect * @button: number of the button triggering the effect * @interval: controls how soon the effect can be re-triggered */ struct ff_trigger { __u16 button; __u16 interval; }; /** * struct ff_envelope - generic force-feedback effect envelope * @attack_length: duration of the attack (ms) * @attack_level: level at the beginning of the attack * @fade_length: duration of fade (ms) * @fade_level: level at the end of fade * * The @attack_level and @fade_level are absolute values; when applying * envelope force-feedback core will convert to positive/negative * value based on polarity of the default level of the effect. * Valid range for the attack and fade levels is 0x0000 - 0x7fff */ struct ff_envelope { __u16 attack_length; __u16 attack_level; __u16 fade_length; __u16 fade_level; }; /** * struct ff_constant_effect - defines parameters of a constant force-feedback effect * @level: strength of the effect; may be negative * @envelope: envelope data */ struct ff_constant_effect { __s16 level; struct ff_envelope envelope; }; /** * struct ff_ramp_effect - defines parameters of a ramp force-feedback effect * @start_level: beginning strength of the effect; may be negative * @end_level: final strength of the effect; may be negative * @envelope: envelope data */ struct ff_ramp_effect { __s16 start_level; __s16 end_level; struct ff_envelope envelope; }; /** * struct ff_condition_effect - defines a spring or friction force-feedback effect * @right_saturation: maximum level when joystick moved all way to the right * @left_saturation: same for the left side * @right_coeff: controls how fast the force grows when the joystick moves * to the right * @left_coeff: same for the left side * @deadband: size of the dead zone, where no force is produced * @center: position of the dead zone */ struct ff_condition_effect { __u16 right_saturation; __u16 left_saturation; __s16 right_coeff; __s16 left_coeff; __u16 deadband; __s16 center; }; /** * struct ff_periodic_effect - defines parameters of a periodic force-feedback effect * @waveform: kind of the effect (wave) * @period: period of the wave (ms) * @magnitude: peak value * @offset: mean value of the wave (roughly) * @phase: 'horizontal' shift * @envelope: envelope data * @custom_len: number of samples (FF_CUSTOM only) * @custom_data: buffer of samples (FF_CUSTOM only) * * Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, * FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined * for the time being as no driver supports it yet. * * Note: the data pointed by custom_data is copied by the driver. * You can therefore dispose of the memory after the upload/update. */ struct ff_periodic_effect { __u16 waveform; __u16 period; __s16 magnitude; __s16 offset; __u16 phase; struct ff_envelope envelope; __u32 custom_len; __s16 *custom_data; }; /** * struct ff_rumble_effect - defines parameters of a periodic force-feedback effect * @strong_magnitude: magnitude of the heavy motor * @weak_magnitude: magnitude of the light one * * Some rumble pads have two motors of different weight. Strong_magnitude * represents the magnitude of the vibration generated by the heavy one. */ struct ff_rumble_effect { __u16 strong_magnitude; __u16 weak_magnitude; }; /** * struct ff_effect - defines force feedback effect * @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING, * FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM) * @id: an unique id assigned to an effect * @direction: direction of the effect * @trigger: trigger conditions (struct ff_trigger) * @replay: scheduling of the effect (struct ff_replay) * @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect, * ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further * defining effect parameters * * This structure is sent through ioctl from the application to the driver. * To create a new effect application should set its @id to -1; the kernel * will return assigned @id which can later be used to update or delete * this effect. * * Direction of the effect is encoded as follows: * 0 deg -> 0x0000 (down) * 90 deg -> 0x4000 (left) * 180 deg -> 0x8000 (up) * 270 deg -> 0xC000 (right) */ struct ff_effect { __u16 type; __s16 id; __u16 direction; struct ff_trigger trigger; struct ff_replay replay; union { struct ff_constant_effect constant; struct ff_ramp_effect ramp; struct ff_periodic_effect periodic; struct ff_condition_effect condition[2]; /* One for each axis */ struct ff_rumble_effect rumble; } u; }; /* * Force feedback effect types */ #define FF_RUMBLE 0x50 #define FF_PERIODIC 0x51 #define FF_CONSTANT 0x52 #define FF_SPRING 0x53 #define FF_FRICTION 0x54 #define FF_DAMPER 0x55 #define FF_INERTIA 0x56 #define FF_RAMP 0x57 #define FF_EFFECT_MIN FF_RUMBLE #define FF_EFFECT_MAX FF_RAMP /* * Force feedback periodic effect types */ #define FF_SQUARE 0x58 #define FF_TRIANGLE 0x59 #define FF_SINE 0x5a #define FF_SAW_UP 0x5b #define FF_SAW_DOWN 0x5c #define FF_CUSTOM 0x5d #define FF_WAVEFORM_MIN FF_SQUARE #define FF_WAVEFORM_MAX FF_CUSTOM /* * Set ff device properties */ #define FF_GAIN 0x60 #define FF_AUTOCENTER 0x61 #define FF_MAX 0x7f #define FF_CNT (FF_MAX+1) #endif mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/0000755000015301777760000000000012322054703025163 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/0000755000015301777760000000000012322054703026451 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/libs/0000755000015301777760000000000012322054703027402 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/libs/utils/0000755000015301777760000000000012322054703030542 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/libs/utils/Looper.cpp0000644000015301777760000004330612322054223032511 0ustar pbusernogroup00000000000000// // Copyright 2010 The Android Open Source Project // // A looper implementation based on epoll(). // #define LOG_TAG "Looper" //#define LOG_NDEBUG 0 // Debugs poll and wake interactions. #define DEBUG_POLL_AND_WAKE 0 // Debugs callback registration and invocation. #define DEBUG_CALLBACKS 0 #include #include #include #include #include #include namespace android { // --- WeakMessageHandler --- WeakMessageHandler::WeakMessageHandler(const wp& handler) : mHandler(handler) { } WeakMessageHandler::~WeakMessageHandler() { } void WeakMessageHandler::handleMessage(const Message& message) { sp handler = mHandler.promote(); if (handler != NULL) { handler->handleMessage(message); } } // --- SimpleLooperCallback --- SimpleLooperCallback::SimpleLooperCallback(ALooper_callbackFunc callback) : mCallback(callback) { } SimpleLooperCallback::~SimpleLooperCallback() { } int SimpleLooperCallback::handleEvent(int fd, int events, void* data) { return mCallback(fd, events, data); } // --- Looper --- // Hint for number of file descriptors to be associated with the epoll instance. static const int EPOLL_SIZE_HINT = 8; // Maximum number of file descriptors for which to retrieve poll events each iteration. static const int EPOLL_MAX_EVENTS = 16; static pthread_once_t gTLSOnce = PTHREAD_ONCE_INIT; static pthread_key_t gTLSKey = 0; Looper::Looper(bool allowNonCallbacks) : mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false), mResponseIndex(0), mNextMessageUptime(LLONG_MAX) { int wakeFds[2]; int result = pipe(wakeFds); LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); mWakeReadPipeFd = wakeFds[0]; mWakeWritePipeFd = wakeFds[1]; result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", errno); result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", errno); // Allocate the epoll instance and register the wake pipe. mEpollFd = epoll_create(EPOLL_SIZE_HINT); LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); struct epoll_event eventItem; memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union eventItem.events = EPOLLIN; eventItem.data.fd = mWakeReadPipeFd; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem); LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", errno); } Looper::~Looper() { close(mWakeReadPipeFd); close(mWakeWritePipeFd); close(mEpollFd); } void Looper::initTLSKey() { int result = pthread_key_create(& gTLSKey, threadDestructor); LOG_ALWAYS_FATAL_IF(result != 0, "Could not allocate TLS key."); } void Looper::threadDestructor(void *st) { Looper* const self = static_cast(st); if (self != NULL) { self->decStrong((void*)threadDestructor); } } void Looper::setForThread(const sp& looper) { sp old = getForThread(); // also has side-effect of initializing TLS if (looper != NULL) { looper->incStrong((void*)threadDestructor); } pthread_setspecific(gTLSKey, looper.get()); if (old != NULL) { old->decStrong((void*)threadDestructor); } } sp Looper::getForThread() { int result = pthread_once(& gTLSOnce, initTLSKey); LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed"); return (Looper*)pthread_getspecific(gTLSKey); } sp Looper::prepare(int opts) { bool allowNonCallbacks = opts & ALOOPER_PREPARE_ALLOW_NON_CALLBACKS; sp looper = Looper::getForThread(); if (looper == NULL) { looper = new Looper(allowNonCallbacks); Looper::setForThread(looper); } if (looper->getAllowNonCallbacks() != allowNonCallbacks) { ALOGW("Looper already prepared for this thread with a different value for the " "ALOOPER_PREPARE_ALLOW_NON_CALLBACKS option."); } return looper; } bool Looper::getAllowNonCallbacks() const { return mAllowNonCallbacks; } int Looper::pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData) { int result = 0; for (;;) { while (mResponseIndex < mResponses.size()) { const Response& response = mResponses.itemAt(mResponseIndex++); int ident = response.request.ident; if (ident >= 0) { int fd = response.request.fd; int events = response.events; void* data = response.request.data; #if DEBUG_POLL_AND_WAKE ALOGD("%p ~ pollOnce - returning signalled identifier %d: " "fd=%d, events=0x%x, data=%p", this, ident, fd, events, data); #endif if (outFd != NULL) *outFd = fd; if (outEvents != NULL) *outEvents = events; if (outData != NULL) *outData = data; return ident; } } if (result != 0) { #if DEBUG_POLL_AND_WAKE ALOGD("%p ~ pollOnce - returning result %d", this, result); #endif if (outFd != NULL) *outFd = 0; if (outEvents != NULL) *outEvents = 0; if (outData != NULL) *outData = NULL; return result; } result = pollInner(timeoutMillis); } } int Looper::pollInner(int timeoutMillis) { #if DEBUG_POLL_AND_WAKE ALOGD("%p ~ pollOnce - waiting: timeoutMillis=%d", this, timeoutMillis); #endif // Adjust the timeout based on when the next message is due. if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime); if (messageTimeoutMillis >= 0 && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) { timeoutMillis = messageTimeoutMillis; } #if DEBUG_POLL_AND_WAKE ALOGD("%p ~ pollOnce - next message in %lldns, adjusted timeout: timeoutMillis=%d", this, mNextMessageUptime - now, timeoutMillis); #endif } // Poll. int result = ALOOPER_POLL_WAKE; mResponses.clear(); mResponseIndex = 0; struct epoll_event eventItems[EPOLL_MAX_EVENTS]; int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis); // Acquire lock. mLock.lock(); // Check for poll error. if (eventCount < 0) { if (errno == EINTR) { goto Done; } ALOGW("Poll failed with an unexpected error, errno=%d", errno); result = ALOOPER_POLL_ERROR; goto Done; } // Check for poll timeout. if (eventCount == 0) { #if DEBUG_POLL_AND_WAKE ALOGD("%p ~ pollOnce - timeout", this); #endif result = ALOOPER_POLL_TIMEOUT; goto Done; } // Handle all events. #if DEBUG_POLL_AND_WAKE ALOGD("%p ~ pollOnce - handling events from %d fds", this, eventCount); #endif for (int i = 0; i < eventCount; i++) { int fd = eventItems[i].data.fd; uint32_t epollEvents = eventItems[i].events; if (fd == mWakeReadPipeFd) { if (epollEvents & EPOLLIN) { awoken(); } else { ALOGW("Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents); } } else { ssize_t requestIndex = mRequests.indexOfKey(fd); if (requestIndex >= 0) { int events = 0; if (epollEvents & EPOLLIN) events |= ALOOPER_EVENT_INPUT; if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT; if (epollEvents & EPOLLERR) events |= ALOOPER_EVENT_ERROR; if (epollEvents & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP; pushResponse(events, mRequests.valueAt(requestIndex)); } else { ALOGW("Ignoring unexpected epoll events 0x%x on fd %d that is " "no longer registered.", epollEvents, fd); } } } Done: ; // Invoke pending message callbacks. mNextMessageUptime = LLONG_MAX; while (mMessageEnvelopes.size() != 0) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0); if (messageEnvelope.uptime <= now) { // Remove the envelope from the list. // We keep a strong reference to the handler until the call to handleMessage // finishes. Then we drop it so that the handler can be deleted *before* // we reacquire our lock. { // obtain handler sp handler = messageEnvelope.handler; Message message = messageEnvelope.message; mMessageEnvelopes.removeAt(0); mSendingMessage = true; mLock.unlock(); #if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS ALOGD("%p ~ pollOnce - sending message: handler=%p, what=%d", this, handler.get(), message.what); #endif handler->handleMessage(message); } // release handler mLock.lock(); mSendingMessage = false; result = ALOOPER_POLL_CALLBACK; } else { // The last message left at the head of the queue determines the next wakeup time. mNextMessageUptime = messageEnvelope.uptime; break; } } // Release lock. mLock.unlock(); // Invoke all response callbacks. for (size_t i = 0; i < mResponses.size(); i++) { Response& response = mResponses.editItemAt(i); if (response.request.ident == ALOOPER_POLL_CALLBACK) { int fd = response.request.fd; int events = response.events; void* data = response.request.data; #if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS ALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p", this, response.request.callback.get(), fd, events, data); #endif int callbackResult = response.request.callback->handleEvent(fd, events, data); if (callbackResult == 0) { removeFd(fd); } // Clear the callback reference in the response structure promptly because we // will not clear the response vector itself until the next poll. response.request.callback.clear(); result = ALOOPER_POLL_CALLBACK; } } return result; } int Looper::pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) { if (timeoutMillis <= 0) { int result; do { result = pollOnce(timeoutMillis, outFd, outEvents, outData); } while (result == ALOOPER_POLL_CALLBACK); return result; } else { nsecs_t endTime = systemTime(SYSTEM_TIME_MONOTONIC) + milliseconds_to_nanoseconds(timeoutMillis); for (;;) { int result = pollOnce(timeoutMillis, outFd, outEvents, outData); if (result != ALOOPER_POLL_CALLBACK) { return result; } nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); timeoutMillis = toMillisecondTimeoutDelay(now, endTime); if (timeoutMillis == 0) { return ALOOPER_POLL_TIMEOUT; } } } } void Looper::wake() { #if DEBUG_POLL_AND_WAKE ALOGD("%p ~ wake", this); #endif ssize_t nWrite; do { nWrite = write(mWakeWritePipeFd, "W", 1); } while (nWrite == -1 && errno == EINTR); if (nWrite != 1) { if (errno != EAGAIN) { ALOGW("Could not write wake signal, errno=%d", errno); } } } void Looper::awoken() { #if DEBUG_POLL_AND_WAKE ALOGD("%p ~ awoken", this); #endif char buffer[16]; ssize_t nRead; do { nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer)); } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); } void Looper::pushResponse(int events, const Request& request) { Response response; response.events = events; response.request = request; mResponses.push(response); } int Looper::addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data) { return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data); } int Looper::addFd(int fd, int ident, int events, const sp& callback, void* data) { #if DEBUG_CALLBACKS ALOGD("%p ~ addFd - fd=%d, ident=%d, events=0x%x, callback=%p, data=%p", this, fd, ident, events, callback.get(), data); #endif if (!callback.get()) { if (! mAllowNonCallbacks) { ALOGE("Invalid attempt to set NULL callback but not allowed for this looper."); return -1; } if (ident < 0) { ALOGE("Invalid attempt to set NULL callback with ident < 0."); return -1; } } else { ident = ALOOPER_POLL_CALLBACK; } int epollEvents = 0; if (events & ALOOPER_EVENT_INPUT) epollEvents |= EPOLLIN; if (events & ALOOPER_EVENT_OUTPUT) epollEvents |= EPOLLOUT; { // acquire lock AutoMutex _l(mLock); Request request; request.fd = fd; request.ident = ident; request.callback = callback; request.data = data; struct epoll_event eventItem; memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union eventItem.events = epollEvents; eventItem.data.fd = fd; ssize_t requestIndex = mRequests.indexOfKey(fd); if (requestIndex < 0) { int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem); if (epollResult < 0) { ALOGE("Error adding epoll events for fd %d, errno=%d", fd, errno); return -1; } mRequests.add(fd, request); } else { int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem); if (epollResult < 0) { ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno); return -1; } mRequests.replaceValueAt(requestIndex, request); } } // release lock return 1; } int Looper::removeFd(int fd) { #if DEBUG_CALLBACKS ALOGD("%p ~ removeFd - fd=%d", this, fd); #endif { // acquire lock AutoMutex _l(mLock); ssize_t requestIndex = mRequests.indexOfKey(fd); if (requestIndex < 0) { return 0; } int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL); if (epollResult < 0) { ALOGE("Error removing epoll events for fd %d, errno=%d", fd, errno); return -1; } mRequests.removeItemsAt(requestIndex); } // release lock return 1; } void Looper::sendMessage(const sp& handler, const Message& message) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); sendMessageAtTime(now, handler, message); } void Looper::sendMessageDelayed(nsecs_t uptimeDelay, const sp& handler, const Message& message) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); sendMessageAtTime(now + uptimeDelay, handler, message); } void Looper::sendMessageAtTime(nsecs_t uptime, const sp& handler, const Message& message) { #if DEBUG_CALLBACKS ALOGD("%p ~ sendMessageAtTime - uptime=%lld, handler=%p, what=%d", this, uptime, handler.get(), message.what); #endif size_t i = 0; { // acquire lock AutoMutex _l(mLock); size_t messageCount = mMessageEnvelopes.size(); while (i < messageCount && uptime >= mMessageEnvelopes.itemAt(i).uptime) { i += 1; } MessageEnvelope messageEnvelope(uptime, handler, message); mMessageEnvelopes.insertAt(messageEnvelope, i, 1); // Optimization: If the Looper is currently sending a message, then we can skip // the call to wake() because the next thing the Looper will do after processing // messages is to decide when the next wakeup time should be. In fact, it does // not even matter whether this code is running on the Looper thread. if (mSendingMessage) { return; } } // release lock // Wake the poll loop only when we enqueue a new message at the head. if (i == 0) { wake(); } } void Looper::removeMessages(const sp& handler) { #if DEBUG_CALLBACKS ALOGD("%p ~ removeMessages - handler=%p", this, handler.get()); #endif { // acquire lock AutoMutex _l(mLock); for (size_t i = mMessageEnvelopes.size(); i != 0; ) { const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i); if (messageEnvelope.handler == handler) { mMessageEnvelopes.removeAt(i); } } } // release lock } void Looper::removeMessages(const sp& handler, int what) { #if DEBUG_CALLBACKS ALOGD("%p ~ removeMessages - handler=%p, what=%d", this, handler.get(), what); #endif { // acquire lock AutoMutex _l(mLock); for (size_t i = mMessageEnvelopes.size(); i != 0; ) { const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(--i); if (messageEnvelope.handler == handler && messageEnvelope.message.what == what) { mMessageEnvelopes.removeAt(i); } } } // release lock } } // namespace android mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/libs/utils/Tokenizer.cpp0000644000015301777760000001165212322054223033222 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Tokenizer" #include #include #include #include #include #include #include #include #include // Enables debug output for the tokenizer. #define DEBUG_TOKENIZER 0 namespace android { static inline bool isDelimiter(char ch, const char* delimiters) { return strchr(delimiters, ch) != NULL; } Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, bool ownBuffer, size_t length) : mFilename(filename), mFileMap(fileMap), mBuffer(buffer), mOwnBuffer(ownBuffer), mLength(length), mCurrent(buffer), mLineNumber(1) { } Tokenizer::~Tokenizer() { if (mFileMap) { mFileMap->release(); } if (mOwnBuffer) { delete[] mBuffer; } } status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) { *outTokenizer = NULL; int result = NO_ERROR; int fd = ::open(c_str(filename), O_RDONLY); if (fd < 0) { result = -errno; ALOGE("Error opening file '%s', %s.", c_str(filename), strerror(errno)); } else { struct stat stat; if (fstat(fd, &stat)) { result = -errno; ALOGE("Error getting size of file '%s', %s.", c_str(filename), strerror(errno)); } else { size_t length = size_t(stat.st_size); FileMap* fileMap = new FileMap(); bool ownBuffer = false; char* buffer; if (fileMap->create(NULL, fd, 0, length, true)) { fileMap->advise(FileMap::SEQUENTIAL); buffer = static_cast(fileMap->getDataPtr()); } else { fileMap->release(); fileMap = NULL; // Fall back to reading into a buffer since we can't mmap files in sysfs. // The length we obtained from stat is wrong too (it will always be 4096) // so we must trust that read will read the entire file. buffer = new char[length]; ownBuffer = true; ssize_t nrd = read(fd, buffer, length); if (nrd < 0) { result = -errno; ALOGE("Error reading file '%s', %s.", c_str(filename), strerror(errno)); delete[] buffer; buffer = NULL; } else { length = size_t(nrd); } } if (!result) { *outTokenizer = new Tokenizer(filename, fileMap, buffer, ownBuffer, length); } } close(fd); } return result; } status_t Tokenizer::fromContents(const String8& filename, const char* contents, Tokenizer** outTokenizer) { *outTokenizer = new Tokenizer(filename, NULL, const_cast(contents), false, strlen(contents)); return OK; } String8 Tokenizer::getLocation() const { String8 result; appendFormat(result, "%s:%d", c_str(mFilename), mLineNumber); return result; } String8 Tokenizer::peekRemainderOfLine() const { const char* end = getEnd(); const char* eol = mCurrent; while (eol != end) { char ch = *eol; if (ch == '\n') { break; } eol += 1; } return String8(mCurrent, eol - mCurrent); } String8 Tokenizer::nextToken(const char* delimiters) { #if DEBUG_TOKENIZER ALOGD("nextToken"); #endif const char* end = getEnd(); const char* tokenStart = mCurrent; while (mCurrent != end) { char ch = *mCurrent; if (ch == '\n' || isDelimiter(ch, delimiters)) { break; } mCurrent += 1; } return String8(tokenStart, mCurrent - tokenStart); } void Tokenizer::nextLine() { #if DEBUG_TOKENIZER ALOGD("nextLine"); #endif const char* end = getEnd(); while (mCurrent != end) { char ch = *(mCurrent++); if (ch == '\n') { mLineNumber += 1; break; } } } void Tokenizer::skipDelimiters(const char* delimiters) { #if DEBUG_TOKENIZER ALOGD("skipDelimiters"); #endif const char* end = getEnd(); while (mCurrent != end) { char ch = *mCurrent; if (ch == '\n' || !isDelimiter(ch, delimiters)) { break; } mCurrent += 1; } } } // namespace android mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/libs/utils/RefBase.cpp0000644000015301777760000004366312322054223032566 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "RefBase" #include #include #include #include #include #include #include #include #include #include #include // compile with refcounting debugging enabled #define DEBUG_REFS 0 #define DEBUG_REFS_FATAL_SANITY_CHECKS 0 #define DEBUG_REFS_ENABLED_BY_DEFAULT 1 #define DEBUG_REFS_CALLSTACK_ENABLED 1 // log all reference counting operations #define PRINT_REFS 0 // --------------------------------------------------------------------------- namespace android { #define INITIAL_STRONG_VALUE (1<<28) // --------------------------------------------------------------------------- class RefBase::weakref_impl : public RefBase::weakref_type { public: android_atomic_int32_t mStrong; android_atomic_int32_t mWeak; RefBase* const mBase; android_atomic_int32_t mFlags; #if !DEBUG_REFS weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE) , mWeak(0) , mBase(base) , mFlags(0) { } void addStrongRef(const void* /*id*/) { } void removeStrongRef(const void* /*id*/) { } void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { } void addWeakRef(const void* /*id*/) { } void removeWeakRef(const void* /*id*/) { } void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { } void printRefs() const { } void trackMe(bool, bool) { } #else weakref_impl(RefBase* base) : mStrong(INITIAL_STRONG_VALUE) , mWeak(0) , mBase(base) , mFlags(0) , mStrongRefs(NULL) , mWeakRefs(NULL) , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT) , mRetain(false) { } ~weakref_impl() { bool dumpStack = false; if (!mRetain && mStrongRefs != NULL) { dumpStack = true; #if DEBUG_REFS_FATAL_SANITY_CHECKS LOG_ALWAYS_FATAL("Strong references remain!"); #else ALOGE("Strong references remain:"); #endif ref_entry* refs = mStrongRefs; while (refs) { char inc = refs->ref >= 0 ? '+' : '-'; ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref); #if DEBUG_REFS_CALLSTACK_ENABLED refs->stack.dump(); #endif refs = refs->next; } } if (!mRetain && mWeakRefs != NULL) { dumpStack = true; #if DEBUG_REFS_FATAL_SANITY_CHECKS LOG_ALWAYS_FATAL("Weak references remain:"); #else ALOGE("Weak references remain!"); #endif ref_entry* refs = mWeakRefs; while (refs) { char inc = refs->ref >= 0 ? '+' : '-'; ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref); #if DEBUG_REFS_CALLSTACK_ENABLED refs->stack.dump(); #endif refs = refs->next; } } if (dumpStack) { ALOGE("above errors at:"); CallStack stack; stack.update(); stack.dump(); } } void addStrongRef(const void* id) { //ALOGD_IF(mTrackEnabled, // "addStrongRef: RefBase=%p, id=%p", mBase, id); addRef(&mStrongRefs, id, mStrong); } void removeStrongRef(const void* id) { //ALOGD_IF(mTrackEnabled, // "removeStrongRef: RefBase=%p, id=%p", mBase, id); if (!mRetain) { removeRef(&mStrongRefs, id); } else { addRef(&mStrongRefs, id, -mStrong); } } void renameStrongRefId(const void* old_id, const void* new_id) { //ALOGD_IF(mTrackEnabled, // "renameStrongRefId: RefBase=%p, oid=%p, nid=%p", // mBase, old_id, new_id); renameRefsId(mStrongRefs, old_id, new_id); } void addWeakRef(const void* id) { addRef(&mWeakRefs, id, mWeak); } void removeWeakRef(const void* id) { if (!mRetain) { removeRef(&mWeakRefs, id); } else { addRef(&mWeakRefs, id, -mWeak); } } void renameWeakRefId(const void* old_id, const void* new_id) { renameRefsId(mWeakRefs, old_id, new_id); } void trackMe(bool track, bool retain) { mTrackEnabled = track; mRetain = retain; } void printRefs() const { String8 text; { Mutex::Autolock _l(mMutex); char buf[128]; sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this); text.append(buf); printRefsLocked(&text, mStrongRefs); sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this); text.append(buf); printRefsLocked(&text, mWeakRefs); } { char name[100]; snprintf(name, 100, "/data/%p.stack", this); int rc = open(name, O_RDWR | O_CREAT | O_APPEND); if (rc >= 0) { write(rc, text.string(), text.length()); close(rc); ALOGD("STACK TRACE for %p saved in %s", this, name); } else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this, name, strerror(errno)); } } private: struct ref_entry { ref_entry* next; const void* id; #if DEBUG_REFS_CALLSTACK_ENABLED CallStack stack; #endif int32_t ref; }; void addRef(ref_entry** refs, const void* id, int32_t mRef) { if (mTrackEnabled) { AutoMutex _l(mMutex); ref_entry* ref = new ref_entry; // Reference count at the time of the snapshot, but before the // update. Positive value means we increment, negative--we // decrement the reference count. ref->ref = mRef; ref->id = id; #if DEBUG_REFS_CALLSTACK_ENABLED ref->stack.update(2); #endif ref->next = *refs; *refs = ref; } } void removeRef(ref_entry** refs, const void* id) { if (mTrackEnabled) { AutoMutex _l(mMutex); ref_entry* const head = *refs; ref_entry* ref = head; while (ref != NULL) { if (ref->id == id) { *refs = ref->next; delete ref; return; } refs = &ref->next; ref = *refs; } #if DEBUG_REFS_FATAL_SANITY_CHECKS LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p" "(weakref_type %p) that doesn't exist!", id, mBase, this); #endif ALOGE("RefBase: removing id %p on RefBase %p" "(weakref_type %p) that doesn't exist!", id, mBase, this); ref = head; while (ref) { char inc = ref->ref >= 0 ? '+' : '-'; ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref); ref = ref->next; } CallStack stack; stack.update(); stack.dump(); } } void renameRefsId(ref_entry* r, const void* old_id, const void* new_id) { if (mTrackEnabled) { AutoMutex _l(mMutex); ref_entry* ref = r; while (ref != NULL) { if (ref->id == old_id) { ref->id = new_id; } ref = ref->next; } } } void printRefsLocked(String8* out, const ref_entry* refs) const { char buf[128]; while (refs) { char inc = refs->ref >= 0 ? '+' : '-'; sprintf(buf, "\t%c ID %p (ref %d):\n", inc, refs->id, refs->ref); out->append(buf); #if DEBUG_REFS_CALLSTACK_ENABLED out->append(refs->stack.toString("\t\t")); #else out->append("\t\t(call stacks disabled)"); #endif refs = refs->next; } } mutable Mutex mMutex; ref_entry* mStrongRefs; ref_entry* mWeakRefs; bool mTrackEnabled; // Collect stack traces on addref and removeref, instead of deleting the stack references // on removeref that match the address ones. bool mRetain; #endif }; // --------------------------------------------------------------------------- void RefBase::incStrong(const void* id) const { weakref_impl* const refs = mRefs; refs->incWeak(id); refs->addStrongRef(id); const int32_t c = android_atomic_inc(&refs->mStrong); ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs); #if PRINT_REFS ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c); #endif if (c != INITIAL_STRONG_VALUE) { return; } android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); refs->mBase->onFirstRef(); } void RefBase::decStrong(const void* id) const { weakref_impl* const refs = mRefs; refs->removeStrongRef(id); const int32_t c = android_atomic_dec(&refs->mStrong); #if PRINT_REFS ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c); #endif ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs); if (c == 1) { refs->mBase->onLastStrongRef(id); if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) { delete this; } } refs->decWeak(id); } void RefBase::forceIncStrong(const void* id) const { weakref_impl* const refs = mRefs; refs->incWeak(id); refs->addStrongRef(id); const int32_t c = android_atomic_inc(&refs->mStrong); ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow", refs); #if PRINT_REFS ALOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c); #endif switch (c) { case INITIAL_STRONG_VALUE: android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); // fall through... case 0: refs->mBase->onFirstRef(); } } int32_t RefBase::getStrongCount() const { return mRefs->mStrong; } RefBase* RefBase::weakref_type::refBase() const { return static_cast(this)->mBase; } void RefBase::weakref_type::incWeak(const void* id) { weakref_impl* const impl = static_cast(this); impl->addWeakRef(id); const int32_t c = android_atomic_inc(&impl->mWeak); ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this); } void RefBase::weakref_type::decWeak(const void* id) { weakref_impl* const impl = static_cast(this); impl->removeWeakRef(id); const int32_t c = android_atomic_dec(&impl->mWeak); ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this); if (c != 1) return; if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) { // This is the regular lifetime case. The object is destroyed // when the last strong reference goes away. Since weakref_impl // outlive the object, it is not destroyed in the dtor, and // we'll have to do it here. if (impl->mStrong == INITIAL_STRONG_VALUE) { // Special case: we never had a strong reference, so we need to // destroy the object now. delete impl->mBase; } else { // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); delete impl; } } else { // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER} impl->mBase->onLastWeakRef(id); if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) { // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference // is gone, we can destroy the object. delete impl->mBase; } } } bool RefBase::weakref_type::attemptIncStrong(const void* id) { incWeak(id); weakref_impl* const impl = static_cast(this); int32_t curCount = impl->mStrong; ALOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow", this); while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) { if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) { break; } curCount = impl->mStrong; } if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) { bool allow; if (curCount == INITIAL_STRONG_VALUE) { // Attempting to acquire first strong reference... this is allowed // if the object does NOT have a longer lifetime (meaning the // implementation doesn't need to see this), or if the implementation // allows it to happen. allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); } else { // Attempting to revive the object... this is allowed // if the object DOES have a longer lifetime (so we can safely // call the object with only a weak ref) and the implementation // allows it to happen. allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id); } if (!allow) { decWeak(id); return false; } curCount = android_atomic_inc(&impl->mStrong); // If the strong reference count has already been incremented by // someone else, the implementor of onIncStrongAttempted() is holding // an unneeded reference. So call onLastStrongRef() here to remove it. // (No, this is not pretty.) Note that we MUST NOT do this if we // are in fact acquiring the first reference. if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) { impl->mBase->onLastStrongRef(id); } } impl->addStrongRef(id); #if PRINT_REFS ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount); #endif if (curCount == INITIAL_STRONG_VALUE) { android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong); impl->mBase->onFirstRef(); } return true; } bool RefBase::weakref_type::attemptIncWeak(const void* id) { weakref_impl* const impl = static_cast(this); int32_t curCount = impl->mWeak; ALOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow", this); while (curCount > 0) { if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) { break; } curCount = impl->mWeak; } if (curCount > 0) { impl->addWeakRef(id); } return curCount > 0; } int32_t RefBase::weakref_type::getWeakCount() const { return static_cast(this)->mWeak; } void RefBase::weakref_type::printRefs() const { static_cast(this)->printRefs(); } void RefBase::weakref_type::trackMe(bool enable, bool retain) { static_cast(this)->trackMe(enable, retain); } RefBase::weakref_type* RefBase::createWeak(const void* id) const { mRefs->incWeak(id); return mRefs; } RefBase::weakref_type* RefBase::getWeakRefs() const { return mRefs; } RefBase::RefBase() : mRefs(new weakref_impl(this)) { } RefBase::~RefBase() { if (mRefs->mStrong == INITIAL_STRONG_VALUE) { // we never acquired a strong (and/or weak) reference on this object. delete mRefs; } else { // life-time of this object is extended to WEAK or FOREVER, in // which case weakref_impl doesn't out-live the object and we // can free it now. if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) { // It's possible that the weak count is not 0 if the object // re-acquired a weak reference in its destructor if (mRefs->mWeak == 0) { delete mRefs; } } } // for debugging purposes, clear this. const_cast(mRefs) = NULL; } void RefBase::extendObjectLifetime(int32_t mode) { android_atomic_or(mode, &mRefs->mFlags); } void RefBase::onFirstRef() { } void RefBase::onLastStrongRef(const void* /*id*/) { } bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id) { return (flags&FIRST_INC_STRONG) ? true : false; } void RefBase::onLastWeakRef(const void* /*id*/) { } // --------------------------------------------------------------------------- void RefBase::moveReferences(void* dst, void const* src, size_t n, const ReferenceConverterBase& caster) { #if DEBUG_REFS const size_t itemSize = caster.getReferenceTypeSize(); for (size_t i=0 ; i(intptr_t(dst) + i*itemSize); void const* s = reinterpret_cast(intptr_t(src) + i*itemSize); RefBase* ref(reinterpret_cast(caster.getReferenceBase(d))); ref->mRefs->renameStrongRefId(s, d); ref->mRefs->renameWeakRefId(s, d); } #endif } // --------------------------------------------------------------------------- TextOutput& printStrongPointer(TextOutput& to, const void* val) { to << "sp<>(" << val << ")"; return to; } TextOutput& printWeakPointer(TextOutput& to, const void* val) { to << "wp<>(" << val << ")"; return to; } }; // namespace android mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/libs/utils/FileMap.cpp0000644000015301777760000001334012322054223032561 0ustar pbusernogroup00000000000000/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // // Shared file mapping class. // #define LOG_TAG "filemap" #include #include #include #include #ifdef HAVE_POSIX_FILEMAP #include #endif #include #include #include #include using namespace android; /*static*/ long FileMap::mPageSize = -1; /* * Constructor. Create an empty object. */ FileMap::FileMap(void) : mRefCount(1), mFileName(NULL), mBasePtr(NULL), mBaseLength(0), mDataPtr(NULL), mDataLength(0) { } /* * Destructor. */ FileMap::~FileMap(void) { assert(mRefCount == 0); //printf("+++ removing FileMap %p %u\n", mDataPtr, mDataLength); mRefCount = -100; // help catch double-free if (mFileName != NULL) { free(mFileName); } #ifdef HAVE_POSIX_FILEMAP if (mBasePtr && munmap(mBasePtr, mBaseLength) != 0) { ALOGD("munmap(%p, %d) failed\n", mBasePtr, (int) mBaseLength); } #endif #ifdef HAVE_WIN32_FILEMAP if (mBasePtr && UnmapViewOfFile(mBasePtr) == 0) { ALOGD("UnmapViewOfFile(%p) failed, error = %ld\n", mBasePtr, GetLastError() ); } if (mFileMapping != INVALID_HANDLE_VALUE) { CloseHandle(mFileMapping); } CloseHandle(mFileHandle); #endif } /* * Create a new mapping on an open file. * * Closing the file descriptor does not unmap the pages, so we don't * claim ownership of the fd. * * Returns "false" on failure. */ bool FileMap::create(const char* origFileName, int fd, off64_t offset, size_t length, bool readOnly) { #ifdef HAVE_WIN32_FILEMAP int adjust; off64_t adjOffset; size_t adjLength; if (mPageSize == -1) { SYSTEM_INFO si; GetSystemInfo( &si ); mPageSize = si.dwAllocationGranularity; } DWORD protect = readOnly ? PAGE_READONLY : PAGE_READWRITE; mFileHandle = (HANDLE) _get_osfhandle(fd); mFileMapping = CreateFileMapping( mFileHandle, NULL, protect, 0, 0, NULL); if (mFileMapping == NULL) { ALOGE("CreateFileMapping(%p, %lx) failed with error %ld\n", mFileHandle, protect, GetLastError() ); return false; } adjust = offset % mPageSize; adjOffset = offset - adjust; adjLength = length + adjust; mBasePtr = MapViewOfFile( mFileMapping, readOnly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, 0, (DWORD)(adjOffset), adjLength ); if (mBasePtr == NULL) { ALOGE("MapViewOfFile(%ld, %ld) failed with error %ld\n", adjOffset, adjLength, GetLastError() ); CloseHandle(mFileMapping); mFileMapping = INVALID_HANDLE_VALUE; return false; } #endif #ifdef HAVE_POSIX_FILEMAP int prot, flags, adjust; off64_t adjOffset; size_t adjLength; void* ptr; assert(mRefCount == 1); assert(fd >= 0); assert(offset >= 0); assert(length > 0); /* init on first use */ if (mPageSize == -1) { #if NOT_USING_KLIBC mPageSize = sysconf(_SC_PAGESIZE); if (mPageSize == -1) { ALOGE("could not get _SC_PAGESIZE\n"); return false; } #else /* this holds for Linux, Darwin, Cygwin, and doesn't pain the ARM */ mPageSize = 4096; #endif } adjust = offset % mPageSize; try_again: adjOffset = offset - adjust; adjLength = length + adjust; flags = MAP_SHARED; prot = PROT_READ; if (!readOnly) prot |= PROT_WRITE; ptr = mmap(NULL, adjLength, prot, flags, fd, adjOffset); if (ptr == MAP_FAILED) { // Cygwin does not seem to like file mapping files from an offset. // So if we fail, try again with offset zero if (adjOffset > 0) { adjust = offset; goto try_again; } ALOGE("mmap(%ld,%ld) failed: %s\n", (long) adjOffset, (long) adjLength, strerror(errno)); return false; } mBasePtr = ptr; #endif /* HAVE_POSIX_FILEMAP */ mFileName = origFileName != NULL ? strdup(origFileName) : NULL; mBaseLength = adjLength; mDataOffset = offset; mDataPtr = (char*) mBasePtr + adjust; mDataLength = length; assert(mBasePtr != NULL); ALOGV("MAP: base %p/%d data %p/%d\n", mBasePtr, (int) mBaseLength, mDataPtr, (int) mDataLength); return true; } /* * Provide guidance to the system. */ int FileMap::advise(MapAdvice advice) { #if HAVE_MADVISE int cc, sysAdvice; switch (advice) { case NORMAL: sysAdvice = MADV_NORMAL; break; case RANDOM: sysAdvice = MADV_RANDOM; break; case SEQUENTIAL: sysAdvice = MADV_SEQUENTIAL; break; case WILLNEED: sysAdvice = MADV_WILLNEED; break; case DONTNEED: sysAdvice = MADV_DONTNEED; break; default: assert(false); return -1; } cc = madvise(mBasePtr, mBaseLength, sysAdvice); if (cc != 0) ALOGW("madvise(%d) failed: %s\n", sysAdvice, strerror(errno)); return cc; #else return -1; #endif // HAVE_MADVISE } mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/libs/utils/Timers.cpp0000644000015301777760000000676712322054223032526 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // // Timer functions. // #include #include #include #include #include #include #include #include #include #ifdef HAVE_WIN32_THREADS #include #endif nsecs_t systemTime(int clock) { #if defined(HAVE_POSIX_CLOCKS) static const clockid_t clocks[] = { CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID }; struct timespec t; t.tv_sec = t.tv_nsec = 0; clock_gettime(clocks[clock], &t); return nsecs_t(t.tv_sec)*1000000000LL + t.tv_nsec; #else // we don't support the clocks here. struct timeval t; t.tv_sec = t.tv_usec = 0; gettimeofday(&t, NULL); return nsecs_t(t.tv_sec)*1000000000LL + nsecs_t(t.tv_usec)*1000LL; #endif } int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) { int timeoutDelayMillis; if (timeoutTime > referenceTime) { uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime); if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) { timeoutDelayMillis = -1; } else { timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL; } } else { timeoutDelayMillis = 0; } return timeoutDelayMillis; } /* * =========================================================================== * DurationTimer * =========================================================================== */ using namespace android; // Start the timer. void DurationTimer::start(void) { gettimeofday(&mStartWhen, NULL); } // Stop the timer. void DurationTimer::stop(void) { gettimeofday(&mStopWhen, NULL); } // Get the duration in microseconds. long long DurationTimer::durationUsecs(void) const { return (long) subtractTimevals(&mStopWhen, &mStartWhen); } // Subtract two timevals. Returns the difference (ptv1-ptv2) in // microseconds. /*static*/ long long DurationTimer::subtractTimevals(const struct timeval* ptv1, const struct timeval* ptv2) { long long stop = ((long long) ptv1->tv_sec) * 1000000LL + ((long long) ptv1->tv_usec); long long start = ((long long) ptv2->tv_sec) * 1000000LL + ((long long) ptv2->tv_usec); return stop - start; } // Add the specified amount of time to the timeval. /*static*/ void DurationTimer::addToTimeval(struct timeval* ptv, long usec) { if (usec < 0) { ALOG(LOG_WARN, "", "Negative values not supported in addToTimeval\n"); return; } // normalize tv_usec if necessary if (ptv->tv_usec >= 1000000) { ptv->tv_sec += ptv->tv_usec / 1000000; ptv->tv_usec %= 1000000; } ptv->tv_usec += usec % 1000000; if (ptv->tv_usec >= 1000000) { ptv->tv_usec -= 1000000; ptv->tv_sec++; } ptv->tv_sec += usec / 1000000; } mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/0000755000015301777760000000000012322054703030074 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/private/0000755000015301777760000000000012322054703031546 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/private/utils/0000755000015301777760000000000012322054703032706 5ustar pbusernogroup00000000000000././@LongLink0000000000000000000000000000015200000000000011213 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/private/utils/Static.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/private/utils/Sta0000644000015301777760000000203712322054223033357 0ustar pbusernogroup00000000000000/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // All static variables go here, to control initialization and // destruction order in the library. #include #include namespace android { // For TextStream.cpp extern Vector gTextBuffers; // For String8.cpp extern void initialize_string8(); extern void terminate_string8(); // For String16.cpp extern void initialize_string16(); extern void terminate_string16(); } // namespace android mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/0000755000015301777760000000000012322054703031234 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/FileMap.h0000644000015301777760000000741512322054223032726 0ustar pbusernogroup00000000000000/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // // Encapsulate a shared file mapping. // #ifndef __LIBS_FILE_MAP_H #define __LIBS_FILE_MAP_H #include #include #ifdef HAVE_WIN32_FILEMAP #include #endif namespace android { /* * This represents a memory-mapped file. It might be the entire file or * only part of it. This requires a little bookkeeping because the mapping * needs to be aligned on page boundaries, and in some cases we'd like to * have multiple references to the mapped area without creating additional * maps. * * This always uses MAP_SHARED. * * TODO: we should be able to create a new FileMap that is a subset of * an existing FileMap and shares the underlying mapped pages. Requires * completing the refcounting stuff and possibly introducing the notion * of a FileMap hierarchy. */ class FileMap { public: FileMap(void); /* * Create a new mapping on an open file. * * Closing the file descriptor does not unmap the pages, so we don't * claim ownership of the fd. * * Returns "false" on failure. */ bool create(const char* origFileName, int fd, off64_t offset, size_t length, bool readOnly); /* * Return the name of the file this map came from, if known. */ const char* getFileName(void) const { return mFileName; } /* * Get a pointer to the piece of the file we requested. */ void* getDataPtr(void) const { return mDataPtr; } /* * Get the length we requested. */ size_t getDataLength(void) const { return mDataLength; } /* * Get the data offset used to create this map. */ off64_t getDataOffset(void) const { return mDataOffset; } /* * Get a "copy" of the object. */ FileMap* acquire(void) { mRefCount++; return this; } /* * Call this when mapping is no longer needed. */ void release(void) { if (--mRefCount <= 0) delete this; } /* * This maps directly to madvise() values, but allows us to avoid * including everywhere. */ enum MapAdvice { NORMAL, RANDOM, SEQUENTIAL, WILLNEED, DONTNEED }; /* * Apply an madvise() call to the entire file. * * Returns 0 on success, -1 on failure. */ int advise(MapAdvice advice); protected: // don't delete objects; call release() ~FileMap(void); private: // these are not implemented FileMap(const FileMap& src); const FileMap& operator=(const FileMap& src); int mRefCount; // reference count char* mFileName; // original file name, if known void* mBasePtr; // base of mmap area; page aligned size_t mBaseLength; // length, measured from "mBasePtr" off64_t mDataOffset; // offset used when map was created void* mDataPtr; // start of requested data, offset from base size_t mDataLength; // length, measured from "mDataPtr" #ifdef HAVE_WIN32_FILEMAP HANDLE mFileHandle; // Win32 file handle HANDLE mFileMapping; // Win32 file mapping handle #endif static long mPageSize; }; } // namespace android #endif // __LIBS_FILE_MAP_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/Endian.h0000644000015301777760000000201512322054223032576 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // // Android endian-ness defines. // #ifndef _LIBS_UTILS_ENDIAN_H #define _LIBS_UTILS_ENDIAN_H #if defined(HAVE_ENDIAN_H) #include #else /*not HAVE_ENDIAN_H*/ #define __BIG_ENDIAN 0x1000 #define __LITTLE_ENDIAN 0x0001 #if defined(HAVE_LITTLE_ENDIAN) # define __BYTE_ORDER __LITTLE_ENDIAN #else # define __BYTE_ORDER __BIG_ENDIAN #endif #endif /*not HAVE_ENDIAN_H*/ #endif /*_LIBS_UTILS_ENDIAN_H*/ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/CallStack.h0000644000015301777760000000372012322054223033245 0ustar pbusernogroup00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_CALLSTACK_H #define ANDROID_CALLSTACK_H #include #include #include #include // --------------------------------------------------------------------------- namespace android { class CallStack { public: enum { MAX_DEPTH = 31 }; CallStack(); CallStack(const CallStack& rhs); ~CallStack(); CallStack& operator = (const CallStack& rhs); bool operator == (const CallStack& rhs) const; bool operator != (const CallStack& rhs) const; bool operator < (const CallStack& rhs) const; bool operator >= (const CallStack& rhs) const; bool operator > (const CallStack& rhs) const; bool operator <= (const CallStack& rhs) const; const void* operator [] (int index) const; void clear(); void update(int32_t ignoreDepth=1, int32_t maxDepth=MAX_DEPTH); // Dump a stack trace to the log void dump(const char* prefix = 0) const; // Return a string (possibly very long) containing the complete stack trace String8 toString(const char* prefix = 0) const; size_t size() const { return mCount; } private: size_t mCount; backtrace_frame_t mStack[MAX_DEPTH]; }; }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_CALLSTACK_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/List.h0000644000015301777760000002401112322054223032313 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // // Templated list class. Normally we'd use STL, but we don't have that. // This class mimics STL's interfaces. // // Objects are copied into the list with the '=' operator or with copy- // construction, so if the compiler's auto-generated versions won't work for // you, define your own. // // The only class you want to use from here is "List". // #ifndef _LIBS_UTILS_LIST_H #define _LIBS_UTILS_LIST_H #include #include namespace android { /* * Doubly-linked list. Instantiate with "List myList". * * Objects added to the list are copied using the assignment operator, * so this must be defined. */ template class List { protected: /* * One element in the list. */ class _Node { public: explicit _Node(const T& val) : mVal(val) {} ~_Node() {} inline T& getRef() { return mVal; } inline const T& getRef() const { return mVal; } inline _Node* getPrev() const { return mpPrev; } inline _Node* getNext() const { return mpNext; } inline void setVal(const T& val) { mVal = val; } inline void setPrev(_Node* ptr) { mpPrev = ptr; } inline void setNext(_Node* ptr) { mpNext = ptr; } private: friend class List; friend class _ListIterator; T mVal; _Node* mpPrev; _Node* mpNext; }; /* * Iterator for walking through the list. */ template struct CONST_ITERATOR { typedef _Node const * NodePtr; typedef const TYPE Type; }; template struct NON_CONST_ITERATOR { typedef _Node* NodePtr; typedef TYPE Type; }; template< typename U, template class Constness > class _ListIterator { typedef _ListIterator _Iter; typedef typename Constness::NodePtr _NodePtr; typedef typename Constness::Type _Type; explicit _ListIterator(_NodePtr ptr) : mpNode(ptr) {} public: _ListIterator() {} _ListIterator(const _Iter& rhs) : mpNode(rhs.mpNode) {} ~_ListIterator() {} // this will handle conversions from iterator to const_iterator // (and also all convertible iterators) // Here, in this implementation, the iterators can be converted // if the nodes can be converted template explicit _ListIterator(const V& rhs) : mpNode(rhs.mpNode) {} /* * Dereference operator. Used to get at the juicy insides. */ _Type& operator*() const { return mpNode->getRef(); } _Type* operator->() const { return &(mpNode->getRef()); } /* * Iterator comparison. */ inline bool operator==(const _Iter& right) const { return mpNode == right.mpNode; } inline bool operator!=(const _Iter& right) const { return mpNode != right.mpNode; } /* * handle comparisons between iterator and const_iterator */ template inline bool operator==(const OTHER& right) const { return mpNode == right.mpNode; } template inline bool operator!=(const OTHER& right) const { return mpNode != right.mpNode; } /* * Incr/decr, used to move through the list. */ inline _Iter& operator++() { // pre-increment mpNode = mpNode->getNext(); return *this; } const _Iter operator++(int) { // post-increment _Iter tmp(*this); mpNode = mpNode->getNext(); return tmp; } inline _Iter& operator--() { // pre-increment mpNode = mpNode->getPrev(); return *this; } const _Iter operator--(int) { // post-increment _Iter tmp(*this); mpNode = mpNode->getPrev(); return tmp; } inline _NodePtr getNode() const { return mpNode; } _NodePtr mpNode; /* should be private, but older gcc fails */ private: friend class List; }; public: List() { prep(); } List(const List& src) { // copy-constructor prep(); insert(begin(), src.begin(), src.end()); } virtual ~List() { clear(); delete[] (unsigned char*) mpMiddle; } typedef _ListIterator iterator; typedef _ListIterator const_iterator; List& operator=(const List& right); /* returns true if the list is empty */ inline bool empty() const { return mpMiddle->getNext() == mpMiddle; } /* return #of elements in list */ size_t size() const { return size_t(distance(begin(), end())); } /* * Return the first element or one past the last element. The * _Node* we're returning is converted to an "iterator" by a * constructor in _ListIterator. */ inline iterator begin() { return iterator(mpMiddle->getNext()); } inline const_iterator begin() const { return const_iterator(const_cast<_Node const*>(mpMiddle->getNext())); } inline iterator end() { return iterator(mpMiddle); } inline const_iterator end() const { return const_iterator(const_cast<_Node const*>(mpMiddle)); } /* add the object to the head or tail of the list */ void push_front(const T& val) { insert(begin(), val); } void push_back(const T& val) { insert(end(), val); } /* insert before the current node; returns iterator at new node */ iterator insert(iterator posn, const T& val) { _Node* newNode = new _Node(val); // alloc & copy-construct newNode->setNext(posn.getNode()); newNode->setPrev(posn.getNode()->getPrev()); posn.getNode()->getPrev()->setNext(newNode); posn.getNode()->setPrev(newNode); return iterator(newNode); } /* insert a range of elements before the current node */ void insert(iterator posn, const_iterator first, const_iterator last) { for ( ; first != last; ++first) insert(posn, *first); } /* remove one entry; returns iterator at next node */ iterator erase(iterator posn) { _Node* pNext = posn.getNode()->getNext(); _Node* pPrev = posn.getNode()->getPrev(); pPrev->setNext(pNext); pNext->setPrev(pPrev); delete posn.getNode(); return iterator(pNext); } /* remove a range of elements */ iterator erase(iterator first, iterator last) { while (first != last) erase(first++); // don't erase than incr later! return iterator(last); } /* remove all contents of the list */ void clear() { _Node* pCurrent = mpMiddle->getNext(); _Node* pNext; while (pCurrent != mpMiddle) { pNext = pCurrent->getNext(); delete pCurrent; pCurrent = pNext; } mpMiddle->setPrev(mpMiddle); mpMiddle->setNext(mpMiddle); } /* * Measure the distance between two iterators. On exist, "first" * will be equal to "last". The iterators must refer to the same * list. * * FIXME: This is actually a generic iterator function. It should be a * template function at the top-level with specializations for things like * vector<>, which can just do pointer math). Here we limit it to * _ListIterator of the same type but different constness. */ template< typename U, template class CL, template class CR > ptrdiff_t distance( _ListIterator first, _ListIterator last) const { ptrdiff_t count = 0; while (first != last) { ++first; ++count; } return count; } private: /* * I want a _Node but don't need it to hold valid data. More * to the point, I don't want T's constructor to fire, since it * might have side-effects or require arguments. So, we do this * slightly uncouth storage alloc. */ void prep() { mpMiddle = (_Node*) new unsigned char[sizeof(_Node)]; mpMiddle->setPrev(mpMiddle); mpMiddle->setNext(mpMiddle); } /* * This node plays the role of "pointer to head" and "pointer to tail". * It sits in the middle of a circular list of nodes. The iterator * runs around the circle until it encounters this one. */ _Node* mpMiddle; }; /* * Assignment operator. * * The simplest way to do this would be to clear out the target list and * fill it with the source. However, we can speed things along by * re-using existing elements. */ template List& List::operator=(const List& right) { if (this == &right) return *this; // self-assignment iterator firstDst = begin(); iterator lastDst = end(); const_iterator firstSrc = right.begin(); const_iterator lastSrc = right.end(); while (firstSrc != lastSrc && firstDst != lastDst) *firstDst++ = *firstSrc++; if (firstSrc == lastSrc) // ran out of elements in source? erase(firstDst, lastDst); // yes, erase any extras else insert(lastDst, firstSrc, lastSrc); // copy remaining over return *this; } } // namespace android #endif // _LIBS_UTILS_LIST_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/Tokenizer.h0000644000015301777760000000747512322054223033371 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _UTILS_TOKENIZER_H #define _UTILS_TOKENIZER_H #include #include #include #include namespace android { /** * A simple tokenizer for loading and parsing ASCII text files line by line. */ class Tokenizer { Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, bool ownBuffer, size_t length); public: ~Tokenizer(); /** * Opens a file and maps it into memory. * * Returns NO_ERROR and a tokenizer for the file, if successful. * Otherwise returns an error and sets outTokenizer to NULL. */ static status_t open(const String8& filename, Tokenizer** outTokenizer); /** * Prepares to tokenize the contents of a string. * * Returns NO_ERROR and a tokenizer for the string, if successful. * Otherwise returns an error and sets outTokenizer to NULL. */ static status_t fromContents(const String8& filename, const char* contents, Tokenizer** outTokenizer); /** * Returns true if at the end of the file. */ inline bool isEof() const { return mCurrent == getEnd(); } /** * Returns true if at the end of the line or end of the file. */ inline bool isEol() const { return isEof() || *mCurrent == '\n'; } /** * Gets the name of the file. */ inline String8 getFilename() const { return mFilename; } /** * Gets a 1-based line number index for the current position. */ inline int32_t getLineNumber() const { return mLineNumber; } /** * Formats a location string consisting of the filename and current line number. * Returns a string like "MyFile.txt:33". */ String8 getLocation() const; /** * Gets the character at the current position. * Returns null at end of file. */ inline char peekChar() const { return isEof() ? '\0' : *mCurrent; } /** * Gets the remainder of the current line as a string, excluding the newline character. */ String8 peekRemainderOfLine() const; /** * Gets the character at the current position and advances past it. * Returns null at end of file. */ inline char nextChar() { return isEof() ? '\0' : *(mCurrent++); } /** * Gets the next token on this line stopping at the specified delimiters * or the end of the line whichever comes first and advances past it. * Also stops at embedded nulls. * Returns the token or an empty string if the current character is a delimiter * or is at the end of the line. */ String8 nextToken(const char* delimiters); /** * Advances to the next line. * Does nothing if already at the end of the file. */ void nextLine(); /** * Skips over the specified delimiters in the line. * Also skips embedded nulls. */ void skipDelimiters(const char* delimiters); private: Tokenizer(const Tokenizer& other); // not copyable String8 mFilename; FileMap* mFileMap; char* mBuffer; bool mOwnBuffer; size_t mLength; const char* mCurrent; int32_t mLineNumber; inline const char* getEnd() const { return mBuffer + mLength; } }; } // namespace android #endif // _UTILS_TOKENIZER_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/RWLock.h0000644000015301777760000000665412322054223032556 0ustar pbusernogroup00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _LIBS_UTILS_RWLOCK_H #define _LIBS_UTILS_RWLOCK_H #include #include #if defined(HAVE_PTHREADS) # include #endif #include #include // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- #if defined(HAVE_PTHREADS) /* * Simple mutex class. The implementation is system-dependent. * * The mutex must be unlocked by the thread that locked it. They are not * recursive, i.e. the same thread can't lock it multiple times. */ class RWLock { public: enum { PRIVATE = 0, SHARED = 1 }; RWLock(); RWLock(const char* name); RWLock(int type, const char* name = NULL); ~RWLock(); status_t readLock(); status_t tryReadLock(); status_t writeLock(); status_t tryWriteLock(); void unlock(); class AutoRLock { public: inline AutoRLock(RWLock& rwlock) : mLock(rwlock) { mLock.readLock(); } inline ~AutoRLock() { mLock.unlock(); } private: RWLock& mLock; }; class AutoWLock { public: inline AutoWLock(RWLock& rwlock) : mLock(rwlock) { mLock.writeLock(); } inline ~AutoWLock() { mLock.unlock(); } private: RWLock& mLock; }; private: // A RWLock cannot be copied RWLock(const RWLock&); RWLock& operator = (const RWLock&); pthread_rwlock_t mRWLock; }; inline RWLock::RWLock() { pthread_rwlock_init(&mRWLock, NULL); } inline RWLock::RWLock(const char* name) { (void)name; pthread_rwlock_init(&mRWLock, NULL); } inline RWLock::RWLock(int type, const char* name) { (void)name; if (type == SHARED) { pthread_rwlockattr_t attr; pthread_rwlockattr_init(&attr); pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); pthread_rwlock_init(&mRWLock, &attr); pthread_rwlockattr_destroy(&attr); } else { pthread_rwlock_init(&mRWLock, NULL); } } inline RWLock::~RWLock() { pthread_rwlock_destroy(&mRWLock); } inline status_t RWLock::readLock() { return -pthread_rwlock_rdlock(&mRWLock); } inline status_t RWLock::tryReadLock() { return -pthread_rwlock_tryrdlock(&mRWLock); } inline status_t RWLock::writeLock() { return -pthread_rwlock_wrlock(&mRWLock); } inline status_t RWLock::tryWriteLock() { return -pthread_rwlock_trywrlock(&mRWLock); } inline void RWLock::unlock() { pthread_rwlock_unlock(&mRWLock); } #endif // HAVE_PTHREADS // --------------------------------------------------------------------------- } // namespace android // --------------------------------------------------------------------------- #endif // _LIBS_UTILS_RWLOCK_H ././@LongLink0000000000000000000000000000015200000000000011213 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/AndroidThreads.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/AndroidThre0000644000015301777760000001115712322054223033364 0ustar pbusernogroup00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _LIBS_UTILS_ANDROID_THREADS_H #define _LIBS_UTILS_ANDROID_THREADS_H #include #include #if defined(HAVE_PTHREADS) # include #endif #include // --------------------------------------------------------------------------- // C API #ifdef __cplusplus extern "C" { #endif // Create and run a new thread. extern int androidCreateThread(android_thread_func_t, void *); // Create thread with lots of parameters extern int androidCreateThreadEtc(android_thread_func_t entryFunction, void *userData, const char* threadName, int32_t threadPriority, size_t threadStackSize, android_thread_id_t *threadId); // Get some sort of unique identifier for the current thread. extern android_thread_id_t androidGetThreadId(); // Low-level thread creation -- never creates threads that can // interact with the Java VM. extern int androidCreateRawThreadEtc(android_thread_func_t entryFunction, void *userData, const char* threadName, int32_t threadPriority, size_t threadStackSize, android_thread_id_t *threadId); // Used by the Java Runtime to control how threads are created, so that // they can be proper and lovely Java threads. typedef int (*android_create_thread_fn)(android_thread_func_t entryFunction, void *userData, const char* threadName, int32_t threadPriority, size_t threadStackSize, android_thread_id_t *threadId); extern void androidSetCreateThreadFunc(android_create_thread_fn func); // ------------------------------------------------------------------ // Extra functions working with raw pids. // Get pid for the current thread. extern pid_t androidGetTid(); #ifdef HAVE_ANDROID_OS // Change the priority AND scheduling group of a particular thread. The priority // should be one of the ANDROID_PRIORITY constants. Returns INVALID_OPERATION // if the priority set failed, else another value if just the group set failed; // in either case errno is set. Thread ID zero means current thread. extern int androidSetThreadPriority(pid_t tid, int prio); // Get the current priority of a particular thread. Returns one of the // ANDROID_PRIORITY constants or a negative result in case of error. extern int androidGetThreadPriority(pid_t tid); #endif #ifdef __cplusplus } // extern "C" #endif // ---------------------------------------------------------------------------- // C++ API #ifdef __cplusplus namespace android { // ---------------------------------------------------------------------------- // Create and run a new thread. inline bool createThread(thread_func_t f, void *a) { return androidCreateThread(f, a) ? true : false; } // Create thread with lots of parameters inline bool createThreadEtc(thread_func_t entryFunction, void *userData, const char* threadName = "android:unnamed_thread", int32_t threadPriority = PRIORITY_DEFAULT, size_t threadStackSize = 0, thread_id_t *threadId = 0) { return androidCreateThreadEtc(entryFunction, userData, threadName, threadPriority, threadStackSize, threadId) ? true : false; } // Get some sort of unique identifier for the current thread. inline thread_id_t getThreadId() { return androidGetThreadId(); } // ---------------------------------------------------------------------------- } // namespace android #endif // __cplusplus // ---------------------------------------------------------------------------- #endif // _LIBS_UTILS_ANDROID_THREADS_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/misc.h0000644000015301777760000000532512322054223032342 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // // Handy utility functions and portability code. // #ifndef _LIBS_UTILS_MISC_H #define _LIBS_UTILS_MISC_H #include #include namespace android { /* get #of elements in a static array */ #ifndef NELEM # define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) #endif /* * Make a copy of the string, using "new[]" instead of "malloc". Free the * string with delete[]. * * Returns NULL if "str" is NULL. */ char* strdupNew(const char* str); /* * Concatenate an argument vector into a single string. If argc is >= 0 * it will be used; if it's < 0 then the last element in the arg vector * must be NULL. * * This inserts a space between each argument. * * This does not automatically add double quotes around arguments with * spaces in them. This practice is necessary for Win32, because Win32's * CreateProcess call is stupid. * * The caller should delete[] the returned string. */ char* concatArgv(int argc, const char* const argv[]); /* * Count up the number of arguments in "argv". The count does not include * the final NULL entry. */ int countArgv(const char* const argv[]); /* * Some utility functions for working with files. These could be made * part of a "File" class. */ typedef enum FileType { kFileTypeUnknown = 0, kFileTypeNonexistent, // i.e. ENOENT kFileTypeRegular, kFileTypeDirectory, kFileTypeCharDev, kFileTypeBlockDev, kFileTypeFifo, kFileTypeSymlink, kFileTypeSocket, } FileType; /* get the file's type; follows symlinks */ FileType getFileType(const char* fileName); /* get the file's modification date; returns -1 w/errno set on failure */ time_t getFileModDate(const char* fileName); /* * Round up to the nearest power of 2. Handy for hash tables. */ unsigned int roundUpPower2(unsigned int val); void strreverse(char* begin, char* end); void k_itoa(int value, char* str, int base); char* itoa(int val, int base); typedef void (*sysprop_change_callback)(void); void add_sysprop_change_callback(sysprop_change_callback cb, int priority); void report_sysprop_change(); }; // namespace android #endif // _LIBS_UTILS_MISC_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/Atomic.h0000644000015301777760000000135112322054223032616 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_UTILS_ATOMIC_H #define ANDROID_UTILS_ATOMIC_H #include #endif // ANDROID_UTILS_ATOMIC_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/Compat.h0000644000015301777760000000240512322054223032626 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __LIB_UTILS_COMPAT_H #define __LIB_UTILS_COMPAT_H #include /* Compatibility definitions for non-Linux (i.e., BSD-based) hosts. */ #ifndef HAVE_OFF64_T #if _FILE_OFFSET_BITS < 64 #error "_FILE_OFFSET_BITS < 64; large files are not supported on this platform" #endif /* _FILE_OFFSET_BITS < 64 */ typedef off_t off64_t; static inline off64_t lseek64(int fd, off64_t offset, int whence) { return lseek(fd, offset, whence); } #ifdef HAVE_PREAD static inline ssize_t pread64(int fd, void* buf, size_t nbytes, off64_t offset) { return pread(fd, buf, nbytes, offset); } #endif #endif /* !HAVE_OFF64_T */ #endif /* __LIB_UTILS_COMPAT_H */ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/BitSet.h0000644000015301777760000000731212322054223032577 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef UTILS_BITSET_H #define UTILS_BITSET_H #include #include /* * Contains some bit manipulation helpers. */ namespace android { // A simple set of 32 bits that can be individually marked or cleared. struct BitSet32 { uint32_t value; inline BitSet32() : value(0) { } explicit inline BitSet32(uint32_t value) : value(value) { } // Gets the value associated with a particular bit index. static inline uint32_t valueForBit(uint32_t n) { return 0x80000000 >> n; } // Clears the bit set. inline void clear() { value = 0; } // Returns the number of marked bits in the set. inline uint32_t count() const { return __builtin_popcount(value); } // Returns true if the bit set does not contain any marked bits. inline bool isEmpty() const { return ! value; } // Returns true if the bit set does not contain any unmarked bits. inline bool isFull() const { return value == 0xffffffff; } // Returns true if the specified bit is marked. inline bool hasBit(uint32_t n) const { return value & valueForBit(n); } // Marks the specified bit. inline void markBit(uint32_t n) { value |= valueForBit(n); } // Clears the specified bit. inline void clearBit(uint32_t n) { value &= ~ valueForBit(n); } // Finds the first marked bit in the set. // Result is undefined if all bits are unmarked. inline uint32_t firstMarkedBit() const { return __builtin_clz(value); } // Finds the first unmarked bit in the set. // Result is undefined if all bits are marked. inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); } // Finds the last marked bit in the set. // Result is undefined if all bits are unmarked. inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); } // Finds the first marked bit in the set and clears it. Returns the bit index. // Result is undefined if all bits are unmarked. inline uint32_t clearFirstMarkedBit() { uint32_t n = firstMarkedBit(); clearBit(n); return n; } // Finds the first unmarked bit in the set and marks it. Returns the bit index. // Result is undefined if all bits are marked. inline uint32_t markFirstUnmarkedBit() { uint32_t n = firstUnmarkedBit(); markBit(n); return n; } // Finds the last marked bit in the set and clears it. Returns the bit index. // Result is undefined if all bits are unmarked. inline uint32_t clearLastMarkedBit() { uint32_t n = lastMarkedBit(); clearBit(n); return n; } // Gets the index of the specified bit in the set, which is the number of // marked bits that appear before the specified bit. inline uint32_t getIndexOfBit(uint32_t n) const { return __builtin_popcount(value & ~(0xffffffffUL >> n)); } inline bool operator== (const BitSet32& other) const { return value == other.value; } inline bool operator!= (const BitSet32& other) const { return value != other.value; } }; ANDROID_BASIC_TYPES_TRAITS(BitSet32) } // namespace android #endif // UTILS_BITSET_H ././@LongLink0000000000000000000000000000015600000000000011217 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/BufferedTextOutput.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/BufferedTex0000644000015301777760000000363112322054223033362 0ustar pbusernogroup00000000000000/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_BUFFEREDTEXTOUTPUT_H #define ANDROID_BUFFEREDTEXTOUTPUT_H #include #include #include // --------------------------------------------------------------------------- namespace android { class BufferedTextOutput : public TextOutput { public: //** Flags for constructor */ enum { MULTITHREADED = 0x0001 }; BufferedTextOutput(uint32_t flags = 0); virtual ~BufferedTextOutput(); virtual status_t print(const char* txt, size_t len); virtual void moveIndent(int delta); virtual void pushBundle(); virtual void popBundle(); protected: virtual status_t writeLines(const struct iovec& vec, size_t N) = 0; private: struct BufferState; struct ThreadState; static ThreadState*getThreadState(); static void threadDestructor(void *st); BufferState*getBuffer() const; uint32_t mFlags; const int32_t mSeq; const int32_t mIndex; Mutex mLock; BufferState* mGlobalState; }; // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_BUFFEREDTEXTOUTPUT_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/Debug.h0000644000015301777760000000421412322054223032431 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_DEBUG_H #define ANDROID_DEBUG_H #include #include namespace android { // --------------------------------------------------------------------------- #ifdef __cplusplus template struct CompileTimeAssert; template<> struct CompileTimeAssert {}; #define COMPILE_TIME_ASSERT(_exp) \ template class CompileTimeAssert< (_exp) >; #endif #define COMPILE_TIME_ASSERT_FUNCTION_SCOPE(_exp) \ CompileTimeAssert<( _exp )>(); // --------------------------------------------------------------------------- #ifdef __cplusplus template struct CompileTimeIfElse; template struct CompileTimeIfElse { typedef LHS TYPE; }; template struct CompileTimeIfElse { typedef RHS TYPE; }; #endif // --------------------------------------------------------------------------- #ifdef __cplusplus extern "C" { #endif const char* stringForIndent(int32_t indentLevel); typedef void (*debugPrintFunc)(void* cookie, const char* txt); void printTypeCode(uint32_t typeCode, debugPrintFunc func = 0, void* cookie = 0); void printHexData(int32_t indent, const void *buf, size_t length, size_t bytesPerLine=16, int32_t singleLineBytesCutoff=16, size_t alignment=0, bool cArrayStyle=false, debugPrintFunc func = 0, void* cookie = 0); #ifdef __cplusplus } #endif // --------------------------------------------------------------------------- }; // namespace android #endif // ANDROID_DEBUG_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/native/include/utils/Looper.h0000644000015301777760000003106512322054223032647 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef UTILS_LOOPER_H #define UTILS_LOOPER_H #include #include #include #include #include #include #include #include #include /* * Declare a concrete type for the NDK's looper forward declaration. */ struct ALooper { }; namespace android { /** * A message that can be posted to a Looper. */ struct Message { Message() : what(0) { } Message(int what) : what(what) { } /* The message type. (interpretation is left up to the handler) */ int what; }; /** * Interface for a Looper message handler. * * The Looper holds a strong reference to the message handler whenever it has * a message to deliver to it. Make sure to call Looper::removeMessages * to remove any pending messages destined for the handler so that the handler * can be destroyed. */ class MessageHandler : public virtual RefBase { protected: virtual ~MessageHandler() { } public: /** * Handles a message. */ virtual void handleMessage(const Message& message) = 0; }; /** * A simple proxy that holds a weak reference to a message handler. */ class WeakMessageHandler : public MessageHandler { protected: virtual ~WeakMessageHandler(); public: WeakMessageHandler(const wp& handler); virtual void handleMessage(const Message& message); private: wp mHandler; }; /** * A looper callback. */ class LooperCallback : public virtual RefBase { protected: virtual ~LooperCallback() { } public: /** * Handles a poll event for the given file descriptor. * It is given the file descriptor it is associated with, * a bitmask of the poll events that were triggered (typically ALOOPER_EVENT_INPUT), * and the data pointer that was originally supplied. * * Implementations should return 1 to continue receiving callbacks, or 0 * to have this file descriptor and callback unregistered from the looper. */ virtual int handleEvent(int fd, int events, void* data) = 0; }; /** * Wraps a ALooper_callbackFunc function pointer. */ class SimpleLooperCallback : public LooperCallback { protected: virtual ~SimpleLooperCallback(); public: SimpleLooperCallback(ALooper_callbackFunc callback); virtual int handleEvent(int fd, int events, void* data); private: ALooper_callbackFunc mCallback; }; /** * A polling loop that supports monitoring file descriptor events, optionally * using callbacks. The implementation uses epoll() internally. * * A looper can be associated with a thread although there is no requirement that it must be. */ class Looper : public ALooper, public RefBase { protected: virtual ~Looper(); public: /** * Creates a looper. * * If allowNonCallbaks is true, the looper will allow file descriptors to be * registered without associated callbacks. This assumes that the caller of * pollOnce() is prepared to handle callback-less events itself. */ Looper(bool allowNonCallbacks); /** * Returns whether this looper instance allows the registration of file descriptors * using identifiers instead of callbacks. */ bool getAllowNonCallbacks() const; /** * Waits for events to be available, with optional timeout in milliseconds. * Invokes callbacks for all file descriptors on which an event occurred. * * If the timeout is zero, returns immediately without blocking. * If the timeout is negative, waits indefinitely until an event appears. * * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before * the timeout expired and no callbacks were invoked and no other file * descriptors were ready. * * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked. * * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given * timeout expired. * * Returns ALOOPER_POLL_ERROR if an error occurred. * * Returns a value >= 0 containing an identifier if its file descriptor has data * and it has no callback function (requiring the caller here to handle it). * In this (and only this) case outFd, outEvents and outData will contain the poll * events and data associated with the fd, otherwise they will be set to NULL. * * This method does not return until it has finished invoking the appropriate callbacks * for all file descriptors that were signalled. */ int pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData); inline int pollOnce(int timeoutMillis) { return pollOnce(timeoutMillis, NULL, NULL, NULL); } /** * Like pollOnce(), but performs all pending callbacks until all * data has been consumed or a file descriptor is available with no callback. * This function will never return ALOOPER_POLL_CALLBACK. */ int pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData); inline int pollAll(int timeoutMillis) { return pollAll(timeoutMillis, NULL, NULL, NULL); } /** * Wakes the poll asynchronously. * * This method can be called on any thread. * This method returns immediately. */ void wake(); /** * Adds a new file descriptor to be polled by the looper. * If the same file descriptor was previously added, it is replaced. * * "fd" is the file descriptor to be added. * "ident" is an identifier for this event, which is returned from pollOnce(). * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback. * "events" are the poll events to wake up on. Typically this is ALOOPER_EVENT_INPUT. * "callback" is the function to call when there is an event on the file descriptor. * "data" is a private data pointer to supply to the callback. * * There are two main uses of this function: * * (1) If "callback" is non-NULL, then this function will be called when there is * data on the file descriptor. It should execute any events it has pending, * appropriately reading from the file descriptor. The 'ident' is ignored in this case. * * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce * when its file descriptor has data available, requiring the caller to take * care of processing it. * * Returns 1 if the file descriptor was added, 0 if the arguments were invalid. * * This method can be called on any thread. * This method may block briefly if it needs to wake the poll. * * The callback may either be specified as a bare function pointer or as a smart * pointer callback object. The smart pointer should be preferred because it is * easier to avoid races when the callback is removed from a different thread. * See removeFd() for details. */ int addFd(int fd, int ident, int events, ALooper_callbackFunc callback, void* data); int addFd(int fd, int ident, int events, const sp& callback, void* data); /** * Removes a previously added file descriptor from the looper. * * When this method returns, it is safe to close the file descriptor since the looper * will no longer have a reference to it. However, it is possible for the callback to * already be running or for it to run one last time if the file descriptor was already * signalled. Calling code is responsible for ensuring that this case is safely handled. * For example, if the callback takes care of removing itself during its own execution either * by returning 0 or by calling this method, then it can be guaranteed to not be invoked * again at any later time unless registered anew. * * A simple way to avoid this problem is to use the version of addFd() that takes * a sp instead of a bare function pointer. The LooperCallback will * be released at the appropriate time by the Looper. * * Returns 1 if the file descriptor was removed, 0 if none was previously registered. * * This method can be called on any thread. * This method may block briefly if it needs to wake the poll. */ int removeFd(int fd); /** * Enqueues a message to be processed by the specified handler. * * The handler must not be null. * This method can be called on any thread. */ void sendMessage(const sp& handler, const Message& message); /** * Enqueues a message to be processed by the specified handler after all pending messages * after the specified delay. * * The time delay is specified in uptime nanoseconds. * The handler must not be null. * This method can be called on any thread. */ void sendMessageDelayed(nsecs_t uptimeDelay, const sp& handler, const Message& message); /** * Enqueues a message to be processed by the specified handler after all pending messages * at the specified time. * * The time is specified in uptime nanoseconds. * The handler must not be null. * This method can be called on any thread. */ void sendMessageAtTime(nsecs_t uptime, const sp& handler, const Message& message); /** * Removes all messages for the specified handler from the queue. * * The handler must not be null. * This method can be called on any thread. */ void removeMessages(const sp& handler); /** * Removes all messages of a particular type for the specified handler from the queue. * * The handler must not be null. * This method can be called on any thread. */ void removeMessages(const sp& handler, int what); /** * Prepares a looper associated with the calling thread, and returns it. * If the thread already has a looper, it is returned. Otherwise, a new * one is created, associated with the thread, and returned. * * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0. */ static sp prepare(int opts); /** * Sets the given looper to be associated with the calling thread. * If another looper is already associated with the thread, it is replaced. * * If "looper" is NULL, removes the currently associated looper. */ static void setForThread(const sp& looper); /** * Returns the looper associated with the calling thread, or NULL if * there is not one. */ static sp getForThread(); private: struct Request { int fd; int ident; sp callback; void* data; }; struct Response { int events; Request request; }; struct MessageEnvelope { MessageEnvelope() : uptime(0) { } MessageEnvelope(nsecs_t uptime, const sp handler, const Message& message) : uptime(uptime), handler(handler), message(message) { } nsecs_t uptime; sp handler; Message message; }; const bool mAllowNonCallbacks; // immutable int mWakeReadPipeFd; // immutable int mWakeWritePipeFd; // immutable Mutex mLock; Vector mMessageEnvelopes; // guarded by mLock bool mSendingMessage; // guarded by mLock int mEpollFd; // immutable // Locked list of file descriptor monitoring requests. KeyedVector mRequests; // guarded by mLock // This state is only used privately by pollOnce and does not require a lock since // it runs on a single thread. Vector mResponses; size_t mResponseIndex; nsecs_t mNextMessageUptime; // set to LLONG_MAX when none int pollInner(int timeoutMillis); void awoken(); void pushResponse(int events, const Request& request); static void initTLSKey(); static void threadDestructor(void *st); }; } // namespace android #endif // UTILS_LOOPER_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/0000755000015301777760000000000012322054703026075 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/0000755000015301777760000000000012322054703027720 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/0000755000015301777760000000000012322054703031057 5ustar pbusernogroup00000000000000././@LongLink0000000000000000000000000000015400000000000011215 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/KeyCharacterMap.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/KeyCharacter0000644000015301777760000011733112322054223033352 0ustar pbusernogroup00000000000000/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "KeyCharacterMap" #include #include #include #include #include #if HAVE_ANDROID_OS #include #endif #include #include #include #include // Enables debug output for the parser. #define DEBUG_PARSER 0 // Enables debug output for parser performance. #define DEBUG_PARSER_PERFORMANCE 0 // Enables debug output for mapping. #define DEBUG_MAPPING 0 namespace android { static const char* WHITESPACE = " \t\r"; static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:"; struct Modifier { const char* label; int32_t metaState; }; static const Modifier modifiers[] = { { "shift", AMETA_SHIFT_ON }, { "lshift", AMETA_SHIFT_LEFT_ON }, { "rshift", AMETA_SHIFT_RIGHT_ON }, { "alt", AMETA_ALT_ON }, { "lalt", AMETA_ALT_LEFT_ON }, { "ralt", AMETA_ALT_RIGHT_ON }, { "ctrl", AMETA_CTRL_ON }, { "lctrl", AMETA_CTRL_LEFT_ON }, { "rctrl", AMETA_CTRL_RIGHT_ON }, { "meta", AMETA_META_ON }, { "lmeta", AMETA_META_LEFT_ON }, { "rmeta", AMETA_META_RIGHT_ON }, { "sym", AMETA_SYM_ON }, { "fn", AMETA_FUNCTION_ON }, { "capslock", AMETA_CAPS_LOCK_ON }, { "numlock", AMETA_NUM_LOCK_ON }, { "scrolllock", AMETA_SCROLL_LOCK_ON }, }; #if DEBUG_MAPPING static String8 toString(const char16_t* chars, size_t numChars) { String8 result; for (size_t i = 0; i < numChars; i++) { result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]); } return result; } #endif // --- KeyCharacterMap --- KeyCharacterMap::KeyCharacterMap() : mType(KEYBOARD_TYPE_UNKNOWN) { } KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) : RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode), mKeysByUsageCode(other.mKeysByUsageCode) { for (size_t i = 0; i < other.mKeys.size(); i++) { mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i))); } } KeyCharacterMap::~KeyCharacterMap() { for (size_t i = 0; i < mKeys.size(); i++) { Key* key = mKeys.editValueAt(i); delete key; } } status_t KeyCharacterMap::load(const String8& filename, Format format, sp* outMap) { outMap->clear(); Tokenizer* tokenizer; status_t status = Tokenizer::open(filename, &tokenizer); if (status) { ALOGE("Error %d opening key character map file %s.", status, c_str(filename)); } else { status = load(tokenizer, format, outMap); delete tokenizer; } return status; } status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents, Format format, sp* outMap) { outMap->clear(); Tokenizer* tokenizer; status_t status = Tokenizer::fromContents(filename, contents, &tokenizer); if (status) { ALOGE("Error %d opening key character map.", status); } else { status = load(tokenizer, format, outMap); delete tokenizer; } return status; } status_t KeyCharacterMap::load(Tokenizer* tokenizer, Format format, sp* outMap) { status_t status = OK; sp map = new KeyCharacterMap(); if (!map.get()) { ALOGE("Error allocating key character map."); status = NO_MEMORY; } else { #if DEBUG_PARSER_PERFORMANCE nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); #endif Parser parser(map.get(), tokenizer, format); status = parser.parse(); #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", c_str(tokenizer->getFilename()), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (!status) { *outMap = map; } } return status; } sp KeyCharacterMap::combine(const sp& base, const sp& overlay) { if (overlay == NULL) { return base; } if (base == NULL) { return overlay; } sp map = new KeyCharacterMap(*base.get()); for (size_t i = 0; i < overlay->mKeys.size(); i++) { int32_t keyCode = overlay->mKeys.keyAt(i); Key* key = overlay->mKeys.valueAt(i); ssize_t oldIndex = map->mKeys.indexOfKey(keyCode); if (oldIndex >= 0) { delete map->mKeys.valueAt(oldIndex); map->mKeys.editValueAt(oldIndex) = new Key(*key); } else { map->mKeys.add(keyCode, new Key(*key)); } } for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) { map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i), overlay->mKeysByScanCode.valueAt(i)); } for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) { map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i), overlay->mKeysByUsageCode.valueAt(i)); } return map; } sp KeyCharacterMap::empty() { static sp sEmpty = new KeyCharacterMap(); return sEmpty; } int32_t KeyCharacterMap::getKeyboardType() const { return mType; } char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const { char16_t result = 0; const Key* key; if (getKey(keyCode, &key)) { result = key->label; } #if DEBUG_MAPPING ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result); #endif return result; } char16_t KeyCharacterMap::getNumber(int32_t keyCode) const { char16_t result = 0; const Key* key; if (getKey(keyCode, &key)) { result = key->number; } #if DEBUG_MAPPING ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result); #endif return result; } char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const { char16_t result = 0; const Key* key; const Behavior* behavior; if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { result = behavior->character; } #if DEBUG_MAPPING ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result); #endif return result; } bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState, FallbackAction* outFallbackAction) const { outFallbackAction->keyCode = 0; outFallbackAction->metaState = 0; bool result = false; const Key* key; const Behavior* behavior; if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { if (behavior->fallbackKeyCode) { outFallbackAction->keyCode = behavior->fallbackKeyCode; outFallbackAction->metaState = metaState & ~behavior->metaState; result = true; } } #if DEBUG_MAPPING ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, " "fallback keyCode=%d, fallback metaState=0x%08x.", keyCode, metaState, result ? "true" : "false", outFallbackAction->keyCode, outFallbackAction->metaState); #endif return result; } char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars, int32_t metaState) const { char16_t result = 0; const Key* key; if (getKey(keyCode, &key)) { // Try to find the most general behavior that maps to this character. // For example, the base key behavior will usually be last in the list. // However, if we find a perfect meta state match for one behavior then use that one. for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { if (behavior->character) { for (size_t i = 0; i < numChars; i++) { if (behavior->character == chars[i]) { result = behavior->character; if ((behavior->metaState & metaState) == behavior->metaState) { goto ExactMatch; } break; } } } } ExactMatch: ; } #if DEBUG_MAPPING ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.", keyCode, c_str(toString(chars, numChars)), metaState, result); #endif return result; } bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, Vector& outEvents) const { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); for (size_t i = 0; i < numChars; i++) { int32_t keyCode, metaState; char16_t ch = chars[i]; if (!findKey(ch, &keyCode, &metaState)) { #if DEBUG_MAPPING ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.", deviceId, c_str(toString(chars, numChars)), ch); #endif return false; } int32_t currentMetaState = 0; addMetaKeys(outEvents, deviceId, metaState, true, now, ¤tMetaState); addKey(outEvents, deviceId, keyCode, currentMetaState, true, now); addKey(outEvents, deviceId, keyCode, currentMetaState, false, now); addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState); } #if DEBUG_MAPPING ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", deviceId, c_str(toString(chars, numChars)), int32_t(outEvents.size())); for (size_t i = 0; i < outEvents.size(); i++) { ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.", outEvents[i].getKeyCode(), outEvents[i].getMetaState(), outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up"); } #endif return true; } status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const { if (usageCode) { ssize_t index = mKeysByUsageCode.indexOfKey(usageCode); if (index >= 0) { #if DEBUG_MAPPING ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.", scanCode, usageCode, *outKeyCode); #endif *outKeyCode = mKeysByUsageCode.valueAt(index); return OK; } } if (scanCode) { ssize_t index = mKeysByScanCode.indexOfKey(scanCode); if (index >= 0) { #if DEBUG_MAPPING ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.", scanCode, usageCode, *outKeyCode); #endif *outKeyCode = mKeysByScanCode.valueAt(index); return OK; } } #if DEBUG_MAPPING ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode); #endif *outKeyCode = AKEYCODE_UNKNOWN; return NAME_NOT_FOUND; } bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const { ssize_t index = mKeys.indexOfKey(keyCode); if (index >= 0) { *outKey = mKeys.valueAt(index); return true; } return false; } bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState, const Key** outKey, const Behavior** outBehavior) const { const Key* key; if (getKey(keyCode, &key)) { const Behavior* behavior = key->firstBehavior; while (behavior) { if (matchesMetaState(metaState, behavior->metaState)) { *outKey = key; *outBehavior = behavior; return true; } behavior = behavior->next; } } return false; } bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) { // Behavior must have at least the set of meta states specified. // And if the key event has CTRL, ALT or META then the behavior must exactly // match those, taking into account that a behavior can specify that it handles // one, both or either of a left/right modifier pair. if ((eventMetaState & behaviorMetaState) == behaviorMetaState) { const int32_t EXACT_META_STATES = AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON; int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES; if (behaviorMetaState & AMETA_CTRL_ON) { unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON); } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { unmatchedMetaState &= ~AMETA_CTRL_ON; } if (behaviorMetaState & AMETA_ALT_ON) { unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON); } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { unmatchedMetaState &= ~AMETA_ALT_ON; } if (behaviorMetaState & AMETA_META_ON) { unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON); } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { unmatchedMetaState &= ~AMETA_META_ON; } return !unmatchedMetaState; } return false; } bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const { if (!ch) { return false; } for (size_t i = 0; i < mKeys.size(); i++) { const Key* key = mKeys.valueAt(i); // Try to find the most general behavior that maps to this character. // For example, the base key behavior will usually be last in the list. const Behavior* found = NULL; for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { if (behavior->character == ch) { found = behavior; } } if (found) { *outKeyCode = mKeys.keyAt(i); *outMetaState = found->metaState; return true; } } return false; } void KeyCharacterMap::addKey(Vector& outEvents, int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) { outEvents.push(); KeyEvent& event = outEvents.editTop(); event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, 0, keyCode, 0, metaState, 0, time, time); } void KeyCharacterMap::addMetaKeys(Vector& outEvents, int32_t deviceId, int32_t metaState, bool down, nsecs_t time, int32_t* currentMetaState) { // Add and remove meta keys symmetrically. if (down) { addLockedMetaKey(outEvents, deviceId, metaState, time, AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); addLockedMetaKey(outEvents, deviceId, metaState, time, AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); addLockedMetaKey(outEvents, deviceId, metaState, time, AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, AMETA_SHIFT_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, AMETA_ALT_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, AMETA_CTRL_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, AMETA_META_ON, currentMetaState); addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); } else { addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, AMETA_META_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, AMETA_CTRL_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, AMETA_ALT_ON, currentMetaState); addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, AMETA_SHIFT_ON, currentMetaState); addLockedMetaKey(outEvents, deviceId, metaState, time, AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); addLockedMetaKey(outEvents, deviceId, metaState, time, AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); addLockedMetaKey(outEvents, deviceId, metaState, time, AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); } } bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector& outEvents, int32_t deviceId, int32_t metaState, bool down, nsecs_t time, int32_t keyCode, int32_t keyMetaState, int32_t* currentMetaState) { if ((metaState & keyMetaState) == keyMetaState) { *currentMetaState = updateMetaState(keyCode, down, *currentMetaState); addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time); return true; } return false; } void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector& outEvents, int32_t deviceId, int32_t metaState, bool down, nsecs_t time, int32_t leftKeyCode, int32_t leftKeyMetaState, int32_t rightKeyCode, int32_t rightKeyMetaState, int32_t eitherKeyMetaState, int32_t* currentMetaState) { bool specific = false; specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, leftKeyCode, leftKeyMetaState, currentMetaState); specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, rightKeyCode, rightKeyMetaState, currentMetaState); if (!specific) { addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, leftKeyCode, eitherKeyMetaState, currentMetaState); } } void KeyCharacterMap::addLockedMetaKey(Vector& outEvents, int32_t deviceId, int32_t metaState, nsecs_t time, int32_t keyCode, int32_t keyMetaState, int32_t* currentMetaState) { if ((metaState & keyMetaState) == keyMetaState) { *currentMetaState = updateMetaState(keyCode, true, *currentMetaState); addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time); *currentMetaState = updateMetaState(keyCode, false, *currentMetaState); addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time); } } #if HAVE_ANDROID_OS sp KeyCharacterMap::readFromParcel(Parcel* parcel) { sp map = new KeyCharacterMap(); map->mType = parcel->readInt32(); size_t numKeys = parcel->readInt32(); if (parcel->errorCheck()) { return NULL; } for (size_t i = 0; i < numKeys; i++) { int32_t keyCode = parcel->readInt32(); char16_t label = parcel->readInt32(); char16_t number = parcel->readInt32(); if (parcel->errorCheck()) { return NULL; } Key* key = new Key(); key->label = label; key->number = number; map->mKeys.add(keyCode, key); Behavior* lastBehavior = NULL; while (parcel->readInt32()) { int32_t metaState = parcel->readInt32(); char16_t character = parcel->readInt32(); int32_t fallbackKeyCode = parcel->readInt32(); if (parcel->errorCheck()) { return NULL; } Behavior* behavior = new Behavior(); behavior->metaState = metaState; behavior->character = character; behavior->fallbackKeyCode = fallbackKeyCode; if (lastBehavior) { lastBehavior->next = behavior; } else { key->firstBehavior = behavior; } lastBehavior = behavior; } if (parcel->errorCheck()) { return NULL; } } return map; } void KeyCharacterMap::writeToParcel(Parcel* parcel) const { parcel->writeInt32(mType); size_t numKeys = mKeys.size(); parcel->writeInt32(numKeys); for (size_t i = 0; i < numKeys; i++) { int32_t keyCode = mKeys.keyAt(i); const Key* key = mKeys.valueAt(i); parcel->writeInt32(keyCode); parcel->writeInt32(key->label); parcel->writeInt32(key->number); for (const Behavior* behavior = key->firstBehavior; behavior != NULL; behavior = behavior->next) { parcel->writeInt32(1); parcel->writeInt32(behavior->metaState); parcel->writeInt32(behavior->character); parcel->writeInt32(behavior->fallbackKeyCode); } parcel->writeInt32(0); } } #endif // --- KeyCharacterMap::Key --- KeyCharacterMap::Key::Key() : label(0), number(0), firstBehavior(NULL) { } KeyCharacterMap::Key::Key(const Key& other) : label(other.label), number(other.number), firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) { } KeyCharacterMap::Key::~Key() { Behavior* behavior = firstBehavior; while (behavior) { Behavior* next = behavior->next; delete behavior; behavior = next; } } // --- KeyCharacterMap::Behavior --- KeyCharacterMap::Behavior::Behavior() : next(NULL), metaState(0), character(0), fallbackKeyCode(0) { } KeyCharacterMap::Behavior::Behavior(const Behavior& other) : next(other.next ? new Behavior(*other.next) : NULL), metaState(other.metaState), character(other.character), fallbackKeyCode(other.fallbackKeyCode) { } // --- KeyCharacterMap::Parser --- KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) : mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) { } KeyCharacterMap::Parser::~Parser() { } status_t KeyCharacterMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER ALOGD("Parsing %s: '%s'.", c_str(mTokenizer->getLocation()), c_str(mTokenizer->peekRemainderOfLine())); #endif mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { switch (mState) { case STATE_TOP: { String8 keywordToken = mTokenizer->nextToken(WHITESPACE); if (keywordToken == "type") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseType(); if (status) return status; } else if (keywordToken == "map") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseMap(); if (status) return status; } else if (keywordToken == "key") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseKey(); if (status) return status; } else { ALOGE("%s: Expected keyword, got '%s'.", c_str(mTokenizer->getLocation()), c_str(keywordToken)); return BAD_VALUE; } break; } case STATE_KEY: { status_t status = parseKeyProperty(); if (status) return status; break; } } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { ALOGE("%s: Expected end of line or trailing comment, got '%s'.", c_str(mTokenizer->getLocation()), c_str(mTokenizer->peekRemainderOfLine())); return BAD_VALUE; } } mTokenizer->nextLine(); } if (mState != STATE_TOP) { ALOGE("%s: Unterminated key description at end of file.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) { ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } if (mFormat == FORMAT_BASE) { if (mMap->mType == KEYBOARD_TYPE_OVERLAY) { ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } } else if (mFormat == FORMAT_OVERLAY) { if (mMap->mType != KEYBOARD_TYPE_OVERLAY) { ALOGE("%s: Overlay keyboard layout missing required keyboard " "'type OVERLAY' declaration.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } } return NO_ERROR; } status_t KeyCharacterMap::Parser::parseType() { if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) { ALOGE("%s: Duplicate keyboard 'type' declaration.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } KeyboardType type; String8 typeToken = mTokenizer->nextToken(WHITESPACE); if (typeToken == "NUMERIC") { type = KEYBOARD_TYPE_NUMERIC; } else if (typeToken == "PREDICTIVE") { type = KEYBOARD_TYPE_PREDICTIVE; } else if (typeToken == "ALPHA") { type = KEYBOARD_TYPE_ALPHA; } else if (typeToken == "FULL") { type = KEYBOARD_TYPE_FULL; } else if (typeToken == "SPECIAL_FUNCTION") { type = KEYBOARD_TYPE_SPECIAL_FUNCTION; } else if (typeToken == "OVERLAY") { type = KEYBOARD_TYPE_OVERLAY; } else { ALOGE("%s: Expected keyboard type label, got '%s'.", c_str(mTokenizer->getLocation()), c_str(typeToken)); return BAD_VALUE; } #if DEBUG_PARSER ALOGD("Parsed type: type=%d.", type); #endif mMap->mType = type; return NO_ERROR; } status_t KeyCharacterMap::Parser::parseMap() { String8 keywordToken = mTokenizer->nextToken(WHITESPACE); if (keywordToken == "key") { mTokenizer->skipDelimiters(WHITESPACE); return parseMapKey(); } ALOGE("%s: Expected keyword after 'map', got '%s'.", c_str(mTokenizer->getLocation()), c_str(keywordToken)); return BAD_VALUE; } status_t KeyCharacterMap::Parser::parseMapKey() { String8 codeToken = mTokenizer->nextToken(WHITESPACE); bool mapUsage = false; if (codeToken == "usage") { mapUsage = true; mTokenizer->skipDelimiters(WHITESPACE); codeToken = mTokenizer->nextToken(WHITESPACE); } char* end; int32_t code = int32_t(strtol(c_str(codeToken), &end, 0)); if (*end) { ALOGE("%s: Expected key %s number, got '%s'.", c_str(mTokenizer->getLocation()), mapUsage ? "usage" : "scan code", c_str(codeToken)); return BAD_VALUE; } KeyedVector& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; if (map.indexOfKey(code) >= 0) { ALOGE("%s: Duplicate entry for key %s '%s'.", c_str(mTokenizer->getLocation()), mapUsage ? "usage" : "scan code", c_str(codeToken)); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); int32_t keyCode = getKeyCodeByLabel(c_str(keyCodeToken)); if (!keyCode) { ALOGE("%s: Expected key code label, got '%s'.", c_str(mTokenizer->getLocation()), c_str(keyCodeToken)); return BAD_VALUE; } #if DEBUG_PARSER ALOGD("Parsed map key %s: code=%d, keyCode=%d.", mapUsage ? "usage" : "scan code", code, keyCode); #endif map.add(code, keyCode); return NO_ERROR; } status_t KeyCharacterMap::Parser::parseKey() { String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); int32_t keyCode = getKeyCodeByLabel(c_str(keyCodeToken)); if (!keyCode) { ALOGE("%s: Expected key code label, got '%s'.", c_str(mTokenizer->getLocation()), c_str(keyCodeToken)); return BAD_VALUE; } if (mMap->mKeys.indexOfKey(keyCode) >= 0) { ALOGE("%s: Duplicate entry for key code '%s'.", c_str(mTokenizer->getLocation()), c_str(keyCodeToken)); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 openBraceToken = mTokenizer->nextToken(WHITESPACE); if (openBraceToken != "{") { ALOGE("%s: Expected '{' after key code label, got '%s'.", c_str(mTokenizer->getLocation()), c_str(openBraceToken)); return BAD_VALUE; } #if DEBUG_PARSER ALOGD("Parsed beginning of key: keyCode=%d.", keyCode); #endif mKeyCode = keyCode; mMap->mKeys.add(keyCode, new Key()); mState = STATE_KEY; return NO_ERROR; } status_t KeyCharacterMap::Parser::parseKeyProperty() { Key* key = mMap->mKeys.valueFor(mKeyCode); String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); if (token == "}") { mState = STATE_TOP; return finishKey(key); } Vector properties; // Parse all comma-delimited property names up to the first colon. for (;;) { if (token == "label") { properties.add(Property(PROPERTY_LABEL)); } else if (token == "number") { properties.add(Property(PROPERTY_NUMBER)); } else { int32_t metaState; status_t status = parseModifier(token, &metaState); if (status) { ALOGE("%s: Expected a property name or modifier, got '%s'.", c_str(mTokenizer->getLocation()), c_str(token)); return status; } properties.add(Property(PROPERTY_META, metaState)); } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol()) { char ch = mTokenizer->nextChar(); if (ch == ':') { break; } else if (ch == ',') { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); continue; } } ALOGE("%s: Expected ',' or ':' after property name.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } // Parse behavior after the colon. mTokenizer->skipDelimiters(WHITESPACE); Behavior behavior; bool haveCharacter = false; bool haveFallback = false; do { char ch = mTokenizer->peekChar(); if (ch == '\'') { char16_t character; status_t status = parseCharacterLiteral(&character); if (status || !character) { ALOGE("%s: Invalid character literal for key.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } if (haveCharacter) { ALOGE("%s: Cannot combine multiple character literals or 'none'.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } behavior.character = character; haveCharacter = true; } else { token = mTokenizer->nextToken(WHITESPACE); if (token == "none") { if (haveCharacter) { ALOGE("%s: Cannot combine multiple character literals or 'none'.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } haveCharacter = true; } else if (token == "fallback") { mTokenizer->skipDelimiters(WHITESPACE); token = mTokenizer->nextToken(WHITESPACE); int32_t keyCode = getKeyCodeByLabel(c_str(token)); if (!keyCode) { ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.", c_str(mTokenizer->getLocation()), c_str(token)); return BAD_VALUE; } if (haveFallback) { ALOGE("%s: Cannot combine multiple fallback key codes.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } behavior.fallbackKeyCode = keyCode; haveFallback = true; } else { ALOGE("%s: Expected a key behavior after ':'.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } } mTokenizer->skipDelimiters(WHITESPACE); } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#'); // Add the behavior. for (size_t i = 0; i < properties.size(); i++) { const Property& property = properties.itemAt(i); switch (property.property) { case PROPERTY_LABEL: if (key->label) { ALOGE("%s: Duplicate label for key.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } key->label = behavior.character; #if DEBUG_PARSER ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label); #endif break; case PROPERTY_NUMBER: if (key->number) { ALOGE("%s: Duplicate number for key.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } key->number = behavior.character; #if DEBUG_PARSER ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number); #endif break; case PROPERTY_META: { for (Behavior* b = key->firstBehavior; b; b = b->next) { if (b->metaState == property.metaState) { ALOGE("%s: Duplicate key behavior for modifier.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } } Behavior* newBehavior = new Behavior(behavior); newBehavior->metaState = property.metaState; newBehavior->next = key->firstBehavior; key->firstBehavior = newBehavior; #if DEBUG_PARSER ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode, newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode); #endif break; } } } return NO_ERROR; } status_t KeyCharacterMap::Parser::finishKey(Key* key) { // Fill in default number property. if (!key->number) { char16_t digit = 0; char16_t symbol = 0; for (Behavior* b = key->firstBehavior; b; b = b->next) { char16_t ch = b->character; if (ch) { if (ch >= '0' && ch <= '9') { digit = ch; } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*' || ch == '-' || ch == '+' || ch == ',' || ch == '.' || ch == '\'' || ch == ':' || ch == ';' || ch == '/') { symbol = ch; } } } key->number = digit ? digit : symbol; } return NO_ERROR; } status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) { if (token == "base") { *outMetaState = 0; return NO_ERROR; } int32_t combinedMeta = 0; const char* str = c_str(token); const char* start = str; for (const char* cur = str; ; cur++) { char ch = *cur; if (ch == '+' || ch == '\0') { size_t len = cur - start; int32_t metaState = 0; for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) { if (strlen(modifiers[i].label) == len && strncmp(modifiers[i].label, start, len) == 0) { metaState = modifiers[i].metaState; break; } } if (!metaState) { return BAD_VALUE; } if (combinedMeta & metaState) { ALOGE("%s: Duplicate modifier combination '%s'.", c_str(mTokenizer->getLocation()), c_str(token)); return BAD_VALUE; } combinedMeta |= metaState; start = cur + 1; if (ch == '\0') { break; } } } *outMetaState = combinedMeta; return NO_ERROR; } status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) { char ch = mTokenizer->nextChar(); if (ch != '\'') { goto Error; } ch = mTokenizer->nextChar(); if (ch == '\\') { // Escape sequence. ch = mTokenizer->nextChar(); if (ch == 'n') { *outCharacter = '\n'; } else if (ch == 't') { *outCharacter = '\t'; } else if (ch == '\\') { *outCharacter = '\\'; } else if (ch == '\'') { *outCharacter = '\''; } else if (ch == '"') { *outCharacter = '"'; } else if (ch == 'u') { *outCharacter = 0; for (int i = 0; i < 4; i++) { ch = mTokenizer->nextChar(); int digit; if (ch >= '0' && ch <= '9') { digit = ch - '0'; } else if (ch >= 'A' && ch <= 'F') { digit = ch - 'A' + 10; } else if (ch >= 'a' && ch <= 'f') { digit = ch - 'a' + 10; } else { goto Error; } *outCharacter = (*outCharacter << 4) | digit; } } else { goto Error; } } else if (ch >= 32 && ch <= 126 && ch != '\'') { // ASCII literal character. *outCharacter = ch; } else { goto Error; } ch = mTokenizer->nextChar(); if (ch != '\'') { goto Error; } // Ensure that we consumed the entire token. if (isEmpty(mTokenizer->nextToken(WHITESPACE))) { return NO_ERROR; } Error: ALOGE("%s: Malformed character literal.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } } // namespace android mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/MirLog.cpp0000644000015301777760000001613412322054223032756 0ustar pbusernogroup00000000000000/* * 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 * Daniel d'Andrada */ // License of the original configureInitialState() function: /* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */ #define kTagSetSize 16 /* arbitrary */ namespace { struct LogState { /* global minimum priority */ int globalMinPriority; /* tags and priorities */ struct { char tag[kMaxTagLen]; int minPriority; } tagSet[kTagSetSize]; } gLogState = { .globalMinPriority = ANDROID_LOG_UNKNOWN }; } /* * Configure logging based on ANDROID_LOG_TAGS environment variable. We * need to parse a string that looks like * * *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i * * The tag (or '*' for the global level) comes first, followed by a colon * and a letter indicating the minimum priority level we're expected to log. * This can be used to reveal or conceal logs with specific tags. * * We also want to check ANDROID_PRINTF_LOG to determine how the output * will look. */ static void configureInitialState(struct LogState* logState) { /* global min priority defaults to "info" level */ logState->globalMinPriority = ANDROID_LOG_INFO; int entry = 0; /* * This is based on the the long-dead utils/Log.cpp code. */ const char* tags = getenv("ANDROID_LOG_TAGS"); if (tags != NULL) { while (*tags != '\0') { char tagName[kMaxTagLen]; int i, minPrio; while (isspace(*tags)) tags++; i = 0; while (*tags != '\0' && !isspace(*tags) && *tags != ':' && i < kMaxTagLen) { tagName[i++] = *tags++; } if (i == kMaxTagLen) { break; } tagName[i] = '\0'; /* default priority, if there's no ":" part; also zero out '*' */ minPrio = ANDROID_LOG_VERBOSE; if (tagName[0] == '*' && tagName[1] == '\0') { minPrio = ANDROID_LOG_DEBUG; tagName[0] = '\0'; } if (*tags == ':') { tags++; if (*tags >= '0' && *tags <= '9') { if (*tags >= ('0' + ANDROID_LOG_SILENT)) minPrio = ANDROID_LOG_VERBOSE; else minPrio = *tags - '\0'; } else { switch (*tags) { case 'v': minPrio = ANDROID_LOG_VERBOSE; break; case 'd': minPrio = ANDROID_LOG_DEBUG; break; case 'i': minPrio = ANDROID_LOG_INFO; break; case 'w': minPrio = ANDROID_LOG_WARN; break; case 'e': minPrio = ANDROID_LOG_ERROR; break; case 'f': minPrio = ANDROID_LOG_FATAL; break; case 's': minPrio = ANDROID_LOG_SILENT; break; default: minPrio = ANDROID_LOG_DEFAULT; break; } } tags++; if (*tags != '\0' && !isspace(*tags)) { break; } } if (tagName[0] == 0) { logState->globalMinPriority = minPrio; } else { logState->tagSet[entry].minPriority = minPrio; strcpy(logState->tagSet[entry].tag, tagName); entry++; } } } if (entry < kTagSetSize) { // Mark the end of this array logState->tagSet[entry].minPriority = ANDROID_LOG_UNKNOWN; logState->tagSet[entry].tag[0] = '\0'; } } extern "C" int __android_log_print(int prio, const char *tag, const char *fmt, ...) { char buffer[1024] = {'0'}; va_list ap; va_start(ap, fmt); int result = vsnprintf(buffer, sizeof buffer - 1, fmt, ap); va_end(ap); if (gLogState.globalMinPriority == ANDROID_LOG_UNKNOWN) { configureInitialState(&gLogState); } /* see if this log tag is configured */ int minPrio = gLogState.globalMinPriority; for (int i = 0; i < kTagSetSize; i++) { if (gLogState.tagSet[i].minPriority == ANDROID_LOG_UNKNOWN) break; /* reached end of configured values */ if (strcmp(gLogState.tagSet[i].tag, tag) == 0) { minPrio = gLogState.tagSet[i].minPriority; break; } } if (prio >= minPrio) { char taggedBuffer[1024]; sprintf(taggedBuffer, "[%s]%s", tag, buffer); mir::write_to_log(prio, taggedBuffer); } else { // filter out log message } return result; } extern "C" void __android_log_assert(const char *cond, const char *tag, const char *fmt, ...) { char buffer[1024] = {'0'}; if (fmt) { va_list ap; va_start(ap, fmt); vsnprintf(buffer, sizeof buffer - 1, fmt, ap); va_end(ap); mir::write_to_log(ANDROID_LOG_ERROR, buffer); } else { /* Msg not provided, log condition. N.B. Do not use cond directly as * format string as it could contain spurious '%' syntax (e.g. * "%d" in "blocks%devs == 0"). */ if (cond) { snprintf(buffer, sizeof buffer - 1, "Assertion failed: %s", cond); mir::write_to_log(ANDROID_LOG_ERROR, buffer); } else mir::write_to_log(ANDROID_LOG_ERROR, "Unspecified assertion failed"); } __builtin_trap(); /* trap so we have a chance to debug the situation */ } namespace { static void default_write_to_log(int /*prio*/, char const* /*buffer*/) { // By default don't log } } void (*mir::write_to_log)(int prio, char const* buffer) = ::default_write_to_log; ././@LongLink0000000000000000000000000000015500000000000011216 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputApplication.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputApplica0000644000015301777760000000203412322054223033367 0ustar pbusernogroup00000000000000/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "InputApplication" #include "InputApplication.h" #include namespace android { // --- InputApplicationHandle --- InputApplicationHandle::InputApplicationHandle() : mInfo(NULL) { } InputApplicationHandle::~InputApplicationHandle() { delete mInfo; } void InputApplicationHandle::releaseInfo() { if (mInfo) { delete mInfo; mInfo = NULL; } } } // namespace android mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/EventHub.h0000644000015301777760000003516712322054247032767 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // #ifndef _RUNTIME_EVENT_HUB_H #define _RUNTIME_EVENT_HUB_H #include "mir/udev/wrapper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mir { namespace input { class InputReport; } } /* Convenience constants. */ #define BTN_FIRST 0x100 // first button code #define BTN_LAST 0x15f // last button code namespace android { enum { // Device id of a special "virtual" keyboard that is always present. VIRTUAL_KEYBOARD_ID = -1, // Device id of the "built-in" keyboard if there is one. BUILT_IN_KEYBOARD_ID = 0 }; /* * A raw event as retrieved from the EventHub. */ struct RawEvent { nsecs_t when; int32_t deviceId; int32_t type; int32_t code; int32_t value; }; /* Describes an absolute axis. */ struct RawAbsoluteAxisInfo { bool valid; // true if the information is valid, false otherwise int32_t minValue; // minimum value int32_t maxValue; // maximum value int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise int32_t resolution; // resolution in units per mm or radians per mm inline void clear() { valid = false; minValue = 0; maxValue = 0; flat = 0; fuzz = 0; resolution = 0; } }; /* * Input device classes. */ enum { /* The input device is a keyboard or has buttons. */ INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001, /* The input device is an alpha-numeric keyboard (not just a dial pad). */ INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002, /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */ INPUT_DEVICE_CLASS_TOUCH = 0x00000004, /* The input device is a cursor device such as a trackball or mouse. */ INPUT_DEVICE_CLASS_CURSOR = 0x00000008, /* The input device is a multi-touch touchscreen. */ INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010, /* The input device is a directional pad (implies keyboard, has DPAD keys). */ INPUT_DEVICE_CLASS_DPAD = 0x00000020, /* The input device is a gamepad (implies keyboard, has BUTTON keys). */ INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040, /* The input device has switches. */ INPUT_DEVICE_CLASS_SWITCH = 0x00000080, /* The input device is a joystick (implies gamepad, has joystick absolute axes). */ INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100, /* The input device has a vibrator (supports FF_RUMBLE). */ INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, /* The input device is virtual (not a real device, not part of UI configuration). */ INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, /* The input device is external (not built-in). */ INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000 }; /* * Gets the class that owns an axis, in cases where multiple classes might claim * the same axis for different purposes. */ extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses); /* * Grand Central Station for events. * * The event hub aggregates input events received across all known input * devices on the system, including devices that may be emulated by the simulator * environment. In addition, the event hub generates fake input events to indicate * when devices are added or removed. * * The event hub provides a stream of input events (via the getEvent function). * It also supports querying the current actual state of input devices such as identifying * which keys are currently down. Finally, the event hub keeps track of the capabilities of * individual input devices, such as their class and the set of key codes that they support. */ class EventHubInterface : public virtual RefBase { protected: EventHubInterface() { } virtual ~EventHubInterface() { } public: // Synthetic raw event type codes produced when devices are added or removed. enum { // Sent when a device is added. DEVICE_ADDED = 0x10000000, // Sent when a device is removed. DEVICE_REMOVED = 0x20000000, // Sent when all added/removed devices from the most recent scan have been reported. // This event is always sent at least once. FINISHED_DEVICE_SCAN = 0x30000000, FIRST_SYNTHETIC_EVENT = DEVICE_ADDED }; virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0; virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0; virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0; virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const = 0; virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0; virtual bool hasInputProperty(int32_t deviceId, int property) const = 0; virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t* outKeycode, uint32_t* outFlags) const = 0; virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const = 0; // Sets devices that are excluded from opening. // This can be used to ignore input devices for sensors. virtual void setExcludedDevices(const Vector& devices) = 0; /* * Wait for events to become available and returns them. * After returning, the EventHub holds onto a wake lock until the next call to getEvent. * This ensures that the device will not go to sleep while the event is being processed. * If the device needs to remain awake longer than that, then the caller is responsible * for taking care of it (say, by poking the power manager user activity timer). * * The timeout is advisory only. If the device is asleep, it will not wake just to * service the timeout. * * Returns the number of events obtained, or 0 if the timeout expired. */ virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0; /* * Query current input state. */ virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0; virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0; virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0; virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const = 0; /* * Examine key input devices for specific framework keycode support */ virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const = 0; virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0; virtual bool hasLed(int32_t deviceId, int32_t led) const = 0; virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0; virtual void getVirtualKeyDefinitions(int32_t deviceId, Vector& outVirtualKeys) const = 0; virtual sp getKeyCharacterMap(int32_t deviceId) const = 0; virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp& map) = 0; /* Control the vibrator. */ virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0; virtual void cancelVibrate(int32_t deviceId) = 0; /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */ virtual void requestReopenDevices() = 0; /* Wakes up getEvents() if it is blocked on a read. */ virtual void wake() = 0; /* Dump EventHub state to a string. */ virtual void dump(String8& dump) = 0; /* Called by the heatbeat to ensures that the reader has not deadlocked. */ virtual void monitor() = 0; /* Flush all pending events not yet read from the input devices */ virtual void flush() = 0; }; class EventHub : public EventHubInterface { public: EventHub(std::shared_ptr const& input_report); virtual uint32_t getDeviceClasses(int32_t deviceId) const; virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const; virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const; virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const; virtual bool hasRelativeAxis(int32_t deviceId, int axis) const; virtual bool hasInputProperty(int32_t deviceId, int property) const; virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t* outKeycode, uint32_t* outFlags) const; virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const; virtual void setExcludedDevices(const Vector& devices); virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const; virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const; virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const; virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const; virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const; virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize); virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const; virtual bool hasLed(int32_t deviceId, int32_t led) const; virtual void setLedState(int32_t deviceId, int32_t led, bool on); virtual void getVirtualKeyDefinitions(int32_t deviceId, Vector& outVirtualKeys) const; virtual sp getKeyCharacterMap(int32_t deviceId) const; virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp& map); virtual void vibrate(int32_t deviceId, nsecs_t duration); virtual void cancelVibrate(int32_t deviceId); virtual void requestReopenDevices(); virtual void wake(); virtual void dump(String8& dump); virtual void monitor(); virtual void flush(); protected: virtual ~EventHub(); private: std::shared_ptr const input_report; struct Device { Device* next; int fd; // may be -1 if device is virtual const int32_t id; const String8 path; const InputDeviceIdentifier identifier; uint32_t classes; uint8_t keyBitmask[(KEY_MAX + 1) / 8]; uint8_t absBitmask[(ABS_MAX + 1) / 8]; uint8_t relBitmask[(REL_MAX + 1) / 8]; uint8_t swBitmask[(SW_MAX + 1) / 8]; uint8_t ledBitmask[(LED_MAX + 1) / 8]; uint8_t ffBitmask[(FF_MAX + 1) / 8]; uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8]; String8 configurationFile; PropertyMap* configuration; VirtualKeyMap* virtualKeyMap; KeyMap keyMap; sp overlayKeyMap; sp combinedKeyMap; bool ffEffectPlaying; int16_t ffEffectId; // initially -1 Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier); ~Device(); void close(); inline bool isVirtual() const { return fd < 0; } const sp& getKeyCharacterMap() const { if (combinedKeyMap != NULL) { return combinedKeyMap; } return keyMap.keyCharacterMap; } }; status_t openDeviceLocked(const char *devicePath); void createVirtualKeyboardLocked(); void addDeviceLocked(Device* device); status_t closeDeviceByPathLocked(const char *devicePath); void closeDeviceLocked(Device* device); void closeAllDevicesLocked(); void scanDevicesLocked(); void handleUdevEventsLocked(); Device* getDeviceLocked(int32_t deviceId) const; Device* getDeviceByPathLocked(const char* devicePath) const; bool hasKeycodeLocked(Device* device, int keycode) const; void loadConfigurationLocked(Device* device); status_t loadVirtualKeyMapLocked(Device* device); status_t loadKeyMapLocked(Device* device); bool isExternalDeviceLocked(Device* device); // Protect all internal state. mutable Mutex mLock; // The actual id of the built-in keyboard, or NO_BUILT_IN_KEYBOARD if none. // EventHub remaps the built-in keyboard to id 0 externally as required by the API. enum { // Must not conflict with any other assigned device ids, including // the virtual keyboard id (-1). NO_BUILT_IN_KEYBOARD = -2 }; int32_t mBuiltInKeyboardId; int32_t mNextDeviceId; bool hasDeviceByPathLocked(String8 const& path); KeyedVector mDevices; Device *mOpeningDevices; Device *mClosingDevices; bool mNeedToSendFinishedDeviceScan; bool mNeedToReopenDevices; bool mNeedToScanDevices; Vector mExcludedDevices; int mEpollFd; mir::udev::Monitor device_listener; int mWakeReadPipeFd; int mWakeWritePipeFd; // Ids used for epoll notifications not associated with devices. static const uint32_t EPOLL_ID_UDEV = 0x80000001; static const uint32_t EPOLL_ID_WAKE = 0x80000002; // Epoll FD list size hint. static const int EPOLL_SIZE_HINT = 8; // Maximum number of signalled FDs to handle at a time. static const int EPOLL_MAX_EVENTS = 16; // The array of pending epoll events and the index of the next event to be handled. struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS]; size_t mPendingEventCount; size_t mPendingEventIndex; bool mPendingUdevEvent; }; // Made available to test namespace detail { String8 sha1(const String8& in); } } // namespace android #endif // _RUNTIME_EVENT_HUB_H ././@LongLink0000000000000000000000000000014600000000000011216 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputWindow.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputWindow.0000644000015301777760000001610612322054223033350 0ustar pbusernogroup00000000000000/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _UI_INPUT_WINDOW_H #define _UI_INPUT_WINDOW_H #include #include #include #include #include #include "InputApplication.h" namespace android { /* * Describes the properties of a window that can receive input. */ struct InputWindowInfo { virtual ~InputWindowInfo() = default; // Window flags from WindowManager.LayoutParams enum { FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, FLAG_DIM_BEHIND = 0x00000002, FLAG_BLUR_BEHIND = 0x00000004, FLAG_NOT_FOCUSABLE = 0x00000008, FLAG_NOT_TOUCHABLE = 0x00000010, FLAG_NOT_TOUCH_MODAL = 0x00000020, FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, FLAG_KEEP_SCREEN_ON = 0x00000080, FLAG_LAYOUT_IN_SCREEN = 0x00000100, FLAG_LAYOUT_NO_LIMITS = 0x00000200, FLAG_FULLSCREEN = 0x00000400, FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, FLAG_DITHER = 0x00001000, FLAG_SECURE = 0x00002000, FLAG_SCALED = 0x00004000, FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, FLAG_LAYOUT_INSET_DECOR = 0x00010000, FLAG_ALT_FOCUSABLE_IM = 0x00020000, FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, FLAG_SHOW_WHEN_LOCKED = 0x00080000, FLAG_SHOW_WALLPAPER = 0x00100000, FLAG_TURN_SCREEN_ON = 0x00200000, FLAG_DISMISS_KEYGUARD = 0x00400000, FLAG_SPLIT_TOUCH = 0x00800000, FLAG_HARDWARE_ACCELERATED = 0x01000000, FLAG_HARDWARE_ACCELERATED_SYSTEM = 0x02000000, FLAG_SLIPPERY = 0x04000000, FLAG_NEEDS_MENU_KEY = 0x08000000, FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000, FLAG_COMPATIBLE_WINDOW = 0x20000000, FLAG_SYSTEM_ERROR = 0x40000000 }; // Window types from WindowManager.LayoutParams enum { FIRST_APPLICATION_WINDOW = 1, TYPE_BASE_APPLICATION = 1, TYPE_APPLICATION = 2, TYPE_APPLICATION_STARTING = 3, LAST_APPLICATION_WINDOW = 99, FIRST_SUB_WINDOW = 1000, TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW, TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1, TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2, TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3, TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4, LAST_SUB_WINDOW = 1999, FIRST_SYSTEM_WINDOW = 2000, TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW, TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1, TYPE_PHONE = FIRST_SYSTEM_WINDOW+2, TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3, TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4, TYPE_TOAST = FIRST_SYSTEM_WINDOW+5, TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6, TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7, TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8, TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9, TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10, TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11, TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12, TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13, TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14, TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15, TYPE_DRAG = FIRST_SYSTEM_WINDOW+16, TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17, TYPE_POINTER = FIRST_SYSTEM_WINDOW+18, TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19, TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20, TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21, LAST_SYSTEM_WINDOW = 2999 }; enum { INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001 }; sp inputChannel; String8 name; int32_t layoutParamsFlags; int32_t layoutParamsType; nsecs_t dispatchingTimeout; int32_t frameLeft; int32_t frameTop; int32_t frameRight; int32_t frameBottom; float scaleFactor; //SkRegion touchableRegion; remove dependency from skia lib int32_t touchableRegionLeft; int32_t touchableRegionTop; int32_t touchableRegionRight; int32_t touchableRegionBottom; bool visible; bool canReceiveKeys; bool hasFocus; bool hasWallpaper; bool paused; int32_t layer; int32_t ownerPid; int32_t ownerUid; int32_t inputFeatures; virtual bool touchableRegionContainsPoint(int32_t x, int32_t y) const; bool frameContainsPoint(int32_t x, int32_t y) const; /* Returns true if the window is of a trusted type that is allowed to silently * overlay other windows for the purpose of implementing the secure views feature. * Trusted overlays, such as IME windows, can partly obscure other windows without causing * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ bool isTrustedOverlay() const; bool supportsSplitTouch() const; }; /* * Handle for a window that can receive input. * * Used by the native input dispatcher to indirectly refer to the window manager objects * that describe a window. */ class InputWindowHandle : public RefBase { public: const sp inputApplicationHandle; inline const InputWindowInfo* getInfo() const { return mInfo; } inline sp getInputChannel() const { return mInfo ? mInfo->inputChannel : NULL; } inline String8 getName() const { return mInfo ? mInfo->name : String8(""); } inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { return mInfo ? mInfo->dispatchingTimeout : defaultValue; } /** * Requests that the state of this object be updated to reflect * the most current available information about the application. * * This method should only be called from within the input dispatcher's * critical section. * * Returns true on success, or false if the handle is no longer valid. */ virtual bool updateInfo() = 0; /** * Releases the storage used by the associated information when it is * no longer needed. */ void releaseInfo(); protected: InputWindowHandle(const sp& inputApplicationHandle); virtual ~InputWindowHandle(); InputWindowInfo* mInfo; }; } // namespace android #endif // _UI_INPUT_WINDOW_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/IntSet.cpp0000644000015301777760000000632112322054223032770 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Daniel d'Andrada */ #include #ifdef ANDROID_INPUT_INTSET_TEST using namespace test::android; #else using namespace android; #endif IntSet::IntSet() { #ifdef ANDROID_INPUT_INTSET_TEST ++constructionCount; #endif } IntSet::IntSet(std::initializer_list list) : stdSet(list) { #ifdef ANDROID_INPUT_INTSET_TEST ++constructionCount; #endif } IntSet::~IntSet() { #ifdef ANDROID_INPUT_INTSET_TEST ++destructionCount; #endif } IntSet IntSet::operator -(const IntSet &other) const { IntSet result; std::set_difference(stdSet.cbegin(), stdSet.cend(), other.stdSet.cbegin(), other.stdSet.cend(), std::inserter(result.stdSet, result.stdSet.begin())); return result; } IntSet IntSet::operator &(const IntSet &other) const { IntSet result; std::set_intersection(stdSet.cbegin(), stdSet.cend(), other.stdSet.cbegin(), other.stdSet.cend(), std::inserter(result.stdSet, result.stdSet.begin())); return result; } bool IntSet::operator ==(const IntSet &other) const { return stdSet == other.stdSet; } void IntSet::remove(const IntSet &values) { remove(stdSet.begin(), values.stdSet.begin(), values.stdSet.end()); } bool IntSet::contains(int32_t value) const { return stdSet.find(value) != stdSet.end(); } size_t IntSet::indexOf(int32_t value) const { auto it = stdSet.begin(); size_t index = 0; while (it != stdSet.end() && *it != value) { it++; ++index; } assert(it != stdSet.end()); return index; } std::string IntSet::toString() const { std::ostringstream stream; bool isFirst = true; forEach([&](int32_t value) { if (isFirst) { isFirst = false; } else { stream << ", "; } stream << value; }); return stream.str(); } void IntSet::remove(std::set::iterator selfIterator, std::set::const_iterator otherIterator, std::set::const_iterator otherEnd) { if (selfIterator == stdSet.end() || otherIterator == otherEnd) return; if (*selfIterator < *otherIterator) { selfIterator++; remove(selfIterator, otherIterator, otherEnd); } else if (*selfIterator == *otherIterator) { selfIterator = stdSet.erase(selfIterator); otherIterator++; remove(selfIterator, otherIterator, otherEnd); } else /* *selfIterator > *otherIterator */ { otherIterator++; remove(selfIterator, otherIterator, otherEnd); } } ././@LongLink0000000000000000000000000000015400000000000011215 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputEventPrinter.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputEventPr0000644000015301777760000001171612322054223033410 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Daniel d'Andrada */ #ifndef INPUT_EVENT_PRINTER_H #define INPUT_EVENT_PRINTER_H #include void synEvCodeToStr(char *codeStr, int code) { switch(code) { case SYN_REPORT: sprintf(codeStr, "SYN_REPORT"); break; case SYN_CONFIG: sprintf(codeStr, "SYN_CONFIG"); break; case SYN_MT_REPORT: sprintf(codeStr, "SYN_MT_REPORT"); break; case SYN_DROPPED: sprintf(codeStr, "SYN_DROPPED"); break; default: sprintf(codeStr, "0x%08x", code); break; } } void absEvCodeToStr(char *codeStr, int code) { switch(code) { case ABS_X: sprintf(codeStr, "ABS_X"); break; case ABS_Y: sprintf(codeStr, "ABS_Y"); break; case ABS_MT_SLOT: sprintf(codeStr, "ABS_MT_SLOT"); break; case ABS_MT_TOUCH_MAJOR: sprintf(codeStr, "ABS_MT_TOUCH_MAJOR"); break; case ABS_MT_TOUCH_MINOR: sprintf(codeStr, "ABS_MT_TOUCH_MINOR"); break; case ABS_MT_WIDTH_MAJOR: sprintf(codeStr, "ABS_MT_WIDTH_MAJOR"); break; case ABS_MT_WIDTH_MINOR: sprintf(codeStr, "ABS_MT_WIDTH_MINOR"); break; case ABS_MT_ORIENTATION: sprintf(codeStr, "ABS_MT_ORIENTATION"); break; case ABS_MT_POSITION_X: sprintf(codeStr, "ABS_MT_POSITION_X"); break; case ABS_MT_POSITION_Y: sprintf(codeStr, "ABS_MT_POSITION_Y"); break; case ABS_MT_TOOL_TYPE: sprintf(codeStr, "ABS_MT_TOOL_TYPE"); break; case ABS_MT_BLOB_ID: sprintf(codeStr, "ABS_MT_BLOB_ID"); break; case ABS_MT_TRACKING_ID: sprintf(codeStr, "ABS_MT_TRACKING_ID"); break; case ABS_MT_PRESSURE: sprintf(codeStr, "ABS_MT_PRESSURE"); break; case ABS_MT_DISTANCE: sprintf(codeStr, "ABS_MT_DISTANCE"); break; default: sprintf(codeStr, "0x%08x", code); break; } } void keyEvCodeToStr(char *codeStr, int code) { switch(code) { case BTN_TOOL_PEN: sprintf(codeStr, "BTN_TOOL_PEN"); break; case BTN_TOOL_FINGER: sprintf(codeStr, "BTN_TOOL_FINGER"); break; case BTN_TOOL_MOUSE: sprintf(codeStr, "BTN_TOOL_MOUSE"); break; case BTN_TOUCH: sprintf(codeStr, "BTN_TOUCH"); break; case BTN_STYLUS: sprintf(codeStr, "BTN_STYLUS"); break; default: sprintf(codeStr, "0x%08x", code); break; } } void inputEvToStr(char *buffer, int type, int code, int value) { char codeStr[100]; switch (type) { case EV_SYN: synEvCodeToStr(codeStr, code); sprintf(buffer, "EV_SYN, %s, 0x%08x", codeStr, value); break; case EV_KEY: keyEvCodeToStr(codeStr, code); sprintf(buffer, "EV_KEY, %s, 0x%08x", codeStr, value); break; case EV_REL: sprintf(buffer, "EV_REL, 0x%08x, 0x%08x", code, value); break; case EV_ABS: absEvCodeToStr(codeStr, code); sprintf(buffer, "EV_ABS, %s, 0x%08x", codeStr, value); break; case EV_MSC: sprintf(buffer, "EV_MSC, 0x%08x, 0x%08x", code, value); break; case EV_SW: sprintf(buffer, "EV_SW, 0x%08x, 0x%08x", code, value); break; case EV_LED: sprintf(buffer, "EV_LED, 0x%08x, 0x%08x", code, value); break; case EV_SND: sprintf(buffer, "EV_SND, 0x%08x, 0x%08x", code, value); break; case EV_REP: sprintf(buffer, "EV_REP, 0x%08x, 0x%08x", code, value); break; case EV_FF: sprintf(buffer, "EV_FF, 0x%08x, 0x%08x", code, value); break; case EV_PWR: sprintf(buffer, "EV_PWR, 0x%08x, 0x%08x", code, value); break; case EV_FF_STATUS: sprintf(buffer, "EV_FF_STATUS, 0x%08x, 0x%08x", code, value); break; default: sprintf(buffer, "0x%08x, 0x%08x, 0x%08x", type, code, value); break; } } #endif // INPUT_EVENT_PRINTER_H ././@LongLink0000000000000000000000000000015400000000000011215 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/VelocityControl.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/VelocityCont0000644000015301777760000000665312322054223033433 0ustar pbusernogroup00000000000000/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "VelocityControl" //#define LOG_NDEBUG 0 // Log debug messages about acceleration. #define DEBUG_ACCELERATION 0 #include #include #include #include namespace android { // --- VelocityControl --- const nsecs_t VelocityControl::STOP_TIME; VelocityControl::VelocityControl() { reset(); mIds.insert(1); } void VelocityControl::setParameters(const VelocityControlParameters& parameters) { mParameters = parameters; reset(); } void VelocityControl::reset() { mLastMovementTime = LLONG_MIN; mRawPosition.x = 0; mRawPosition.y = 0; mVelocityTracker.clear(); } void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) { if ((deltaX && *deltaX) || (deltaY && *deltaY)) { if (eventTime >= mLastMovementTime + STOP_TIME) { #if DEBUG_ACCELERATION ALOGD("VelocityControl: stopped, last movement was %0.3fms ago", (eventTime - mLastMovementTime) * 0.000001f); #endif reset(); } mLastMovementTime = eventTime; if (deltaX) { mRawPosition.x += *deltaX; } if (deltaY) { mRawPosition.y += *deltaY; } mVelocityTracker.addMovement(eventTime, mIds, &mRawPosition); float vx, vy; float scale = mParameters.scale; if (mVelocityTracker.getVelocity(0, &vx, &vy)) { float speed = hypotf(vx, vy) * scale; if (speed >= mParameters.highThreshold) { // Apply full acceleration above the high speed threshold. scale *= mParameters.acceleration; } else if (speed > mParameters.lowThreshold) { // Linearly interpolate the acceleration to apply between the low and high // speed thresholds. scale *= 1 + (speed - mParameters.lowThreshold) / (mParameters.highThreshold - mParameters.lowThreshold) * (mParameters.acceleration - 1); } #if DEBUG_ACCELERATION ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): " "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f", mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, mParameters.acceleration, vx, vy, speed, scale / mParameters.scale); #endif } else { #if DEBUG_ACCELERATION ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity", mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, mParameters.acceleration); #endif } if (deltaX) { *deltaX *= scale; } if (deltaY) { *deltaY *= scale; } } } } // namespace android ././@LongLink0000000000000000000000000000015300000000000011214 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputTransport.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputTranspo0000644000015301777760000007735512322054223033466 0ustar pbusernogroup00000000000000// // Copyright 2010 The Android Open Source Project // // Provides a shared memory transport for input events. // #define LOG_TAG "InputTransport" //#define LOG_NDEBUG 0 // Log debug messages about channel messages (send message, receive message) #define DEBUG_CHANNEL_MESSAGES 0 // Log debug messages whenever InputChannel objects are created/destroyed #define DEBUG_CHANNEL_LIFECYCLE 0 // Log debug messages about transport actions #define DEBUG_TRANSPORT_ACTIONS 0 // Log debug messages about touch event resampling #define DEBUG_RESAMPLING 0 #include #include #include #include #include #include #include #include #include namespace android { // Socket buffer size. The default is typically about 128KB, which is much larger than // we really need. So we make it smaller. It just needs to be big enough to hold // a few dozen large multi-finger motion events in the case where an application gets // behind processing touches. static const size_t SOCKET_BUFFER_SIZE = 32 * 1024; // Nanoseconds per milliseconds. static const nsecs_t NANOS_PER_MS = 1000000; // Latency added during resampling. A few milliseconds doesn't hurt much but // reduces the impact of mispredicted touch positions. static const nsecs_t RESAMPLE_LATENCY = 5 * NANOS_PER_MS; // Minimum time difference between consecutive samples before attempting to resample. static const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS; // Maximum time to predict forward from the last known state, to avoid predicting too // far into the future. This time is further bounded by 50% of the last time delta. static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS; template inline static T min(const T& a, const T& b) { return a < b ? a : b; } inline static float lerp(float a, float b, float alpha) { return a + alpha * (b - a); } // --- InputMessage --- InputMessage::InputMessage() { memset(this, 0, sizeof(InputMessage)); } bool InputMessage::isValid(size_t actualSize) const { if (size() == actualSize) { switch (header.type) { case TYPE_KEY: return true; case TYPE_MOTION: return body.motion.pointerCount > 0 && body.motion.pointerCount <= MAX_POINTERS; case TYPE_FINISHED: return true; } } return false; } size_t InputMessage::size() const { switch (header.type) { case TYPE_KEY: return sizeof(Header) + body.key.size(); case TYPE_MOTION: return sizeof(Header) + body.motion.size(); case TYPE_FINISHED: return sizeof(Header) + body.finished.size(); } return sizeof(Header); } // --- InputChannel --- InputChannel::InputChannel(const String8& name, int fd) : mName(name), mFd(fd) { #if DEBUG_CHANNEL_LIFECYCLE ALOGD("Input channel constructed: name='%s', fd=%d", c_str(mName), fd); #endif int result = fcntl(mFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket " "non-blocking. errno=%d", c_str(mName), errno); } InputChannel::~InputChannel() { #if DEBUG_CHANNEL_LIFECYCLE ALOGD("Input channel destroyed: name='%s', fd=%d", c_str(mName), mFd); #endif } status_t InputChannel::openInputFdPair(int& server_fd, int& client_fd) { int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) { status_t result = -errno; ALOGE("InputChannel ~ Could not create socket pair. errno=%d", errno); server_fd = client_fd = 0; return result; } int bufferSize = SOCKET_BUFFER_SIZE; setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); server_fd = sockets[0]; client_fd = sockets[1]; return OK; } status_t InputChannel::sendMessage(const InputMessage* msg) { size_t msgLength = msg->size(); ssize_t nWrite; do { nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); } while (nWrite == -1 && errno == EINTR); if (nWrite < 0) { int error = errno; #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", c_str(mName), msg->header.type, error); #endif if (error == EAGAIN || error == EWOULDBLOCK) { return WOULD_BLOCK; } if (error == EPIPE || error == ENOTCONN) { return DEAD_OBJECT; } return -error; } if (size_t(nWrite) != msgLength) { #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ error sending message type %d, send was incomplete", c_str(mName), msg->header.type); #endif return DEAD_OBJECT; } #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ sent message of type %d", c_str(mName), msg->header.type); #endif return OK; } status_t InputChannel::receiveMessage(InputMessage* msg) { ssize_t nRead; do { nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT); } while (nRead == -1 && errno == EINTR); if (nRead < 0) { int error = errno; #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ receive message failed, errno=%d", c_str(mName), errno); #endif if (error == EAGAIN || error == EWOULDBLOCK) { return WOULD_BLOCK; } if (error == EPIPE || error == ENOTCONN) { return DEAD_OBJECT; } return -error; } if (nRead == 0) { // check for EOF #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ receive message failed because peer was closed", c_str(mName)); #endif return DEAD_OBJECT; } if (!msg->isValid(nRead)) { #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ received invalid message", c_str(mName)); #endif return BAD_VALUE; } #if DEBUG_CHANNEL_MESSAGES ALOGD("channel '%s' ~ received message of type %d", c_str(mName), msg->header.type); #endif return OK; } // --- InputPublisher --- InputPublisher::InputPublisher(const sp& channel) : mChannel(channel) { } InputPublisher::~InputPublisher() { } status_t InputPublisher::publishKeyEvent( uint32_t seq, int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, " "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d," "downTime=%lld, eventTime=%lld", c_str(mChannel->getName()), seq, deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount, downTime, eventTime); #endif if (!seq) { ALOGE("Attempted to publish a key event with sequence number 0."); return BAD_VALUE; } InputMessage msg; msg.header.type = InputMessage::TYPE_KEY; msg.body.key.seq = seq; msg.body.key.deviceId = deviceId; msg.body.key.source = source; msg.body.key.action = action; msg.body.key.flags = flags; msg.body.key.keyCode = keyCode; msg.body.key.scanCode = scanCode; msg.body.key.metaState = metaState; msg.body.key.repeatCount = repeatCount; msg.body.key.downTime = downTime; msg.body.key.eventTime = eventTime; return mChannel->sendMessage(&msg); } status_t InputPublisher::publishMotionEvent( uint32_t seq, int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, float xOffset, float yOffset, float xPrecision, float yPrecision, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, " "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, " "xOffset=%f, yOffset=%f, " "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, " "pointerCount=%d", c_str(mChannel->getName()), seq, deviceId, source, action, flags, edgeFlags, metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount); #endif if (!seq) { ALOGE("Attempted to publish a motion event with sequence number 0."); return BAD_VALUE; } if (pointerCount > MAX_POINTERS || pointerCount < 1) { ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.", c_str(mChannel->getName()), pointerCount); return BAD_VALUE; } InputMessage msg; msg.header.type = InputMessage::TYPE_MOTION; msg.body.motion.seq = seq; msg.body.motion.deviceId = deviceId; msg.body.motion.source = source; msg.body.motion.action = action; msg.body.motion.flags = flags; msg.body.motion.edgeFlags = edgeFlags; msg.body.motion.metaState = metaState; msg.body.motion.buttonState = buttonState; msg.body.motion.xOffset = xOffset; msg.body.motion.yOffset = yOffset; msg.body.motion.xPrecision = xPrecision; msg.body.motion.yPrecision = yPrecision; msg.body.motion.downTime = downTime; msg.body.motion.eventTime = eventTime; msg.body.motion.pointerCount = pointerCount; for (size_t i = 0; i < pointerCount; i++) { msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]); msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]); } return mChannel->sendMessage(&msg); } status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' publisher ~ receiveFinishedSignal", c_str(mChannel->getName())); #endif InputMessage msg; status_t result = mChannel->receiveMessage(&msg); if (result) { *outSeq = 0; *outHandled = false; return result; } if (msg.header.type != InputMessage::TYPE_FINISHED) { ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer", c_str(mChannel->getName()), msg.header.type); return UNKNOWN_ERROR; } *outSeq = msg.body.finished.seq; *outHandled = msg.body.finished.handled; return OK; } // --- InputConsumer --- InputConsumer::InputConsumer(const sp& channel) : mResampleTouch(isTouchResamplingEnabled()), mChannel(channel), mMsgDeferred(false) { } InputConsumer::~InputConsumer() { } bool InputConsumer::isTouchResamplingEnabled() { char value[PROPERTY_VALUE_MAX]; int length = property_get("debug.inputconsumer.resample", value, NULL); if (length > 0) { if (!strcmp("0", value)) { return false; } if (strcmp("1", value)) { ALOGD("Unrecognized property value for 'debug.inputconsumer.resample'. " "Use '1' or '0'."); } } return true; } status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld", c_str(mChannel->getName()), consumeBatches ? "true" : "false", frameTime); #endif *outSeq = 0; *outEvent = NULL; // Fetch the next input message. // Loop until an event can be returned or no additional events are received. while (!*outEvent) { if (mMsgDeferred) { // mMsg contains a valid input message from the previous call to consume // that has not yet been processed. mMsgDeferred = false; } else { // Receive a fresh message. status_t result = mChannel->receiveMessage(&mMsg); if (result) { // Consume the next batched event unless batches are being held for later. if (consumeBatches || result != WOULD_BLOCK) { result = consumeBatch(factory, frameTime, outSeq, outEvent); if (*outEvent) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u", c_str(mChannel->getName()), *outSeq); #endif break; } } return result; } } switch (mMsg.header.type) { case InputMessage::TYPE_KEY: { KeyEvent* keyEvent = factory->createKeyEvent(); if (!keyEvent) return NO_MEMORY; initializeKeyEvent(keyEvent, &mMsg); *outSeq = mMsg.body.key.seq; *outEvent = keyEvent; #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed key event, seq=%u", c_str(mChannel->getName()), *outSeq); #endif break; } case AINPUT_EVENT_TYPE_MOTION: { ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source); if (batchIndex >= 0) { Batch& batch = mBatches.editItemAt(batchIndex); if (canAddSample(batch, &mMsg)) { batch.samples.push(mMsg); #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ appended to batch event", c_str(mChannel->getName())); #endif break; } else { // We cannot append to the batch in progress, so we need to consume // the previous batch right now and defer the new message until later. mMsgDeferred = true; status_t result = consumeSamples(factory, batch, batch.samples.size(), outSeq, outEvent); mBatches.removeAt(batchIndex); if (result) { return result; } #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed batch event and " "deferred current event, seq=%u", c_str(mChannel->getName()), *outSeq); #endif break; } } // Start a new batch if needed. if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) { mBatches.push(); Batch& batch = mBatches.editTop(); batch.samples.push(mMsg); #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ started batch event", c_str(mChannel->getName())); #endif break; } MotionEvent* motionEvent = factory->createMotionEvent(); if (! motionEvent) return NO_MEMORY; updateTouchState(&mMsg); initializeMotionEvent(motionEvent, &mMsg); *outSeq = mMsg.body.motion.seq; *outEvent = motionEvent; #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u", c_str(mChannel->getName()), *outSeq); #endif break; } default: ALOGE("channel '%s' consumer ~ Received unexpected message of type %d", c_str(mChannel->getName()), mMsg.header.type); return UNKNOWN_ERROR; } } return OK; } status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) { status_t result; for (size_t i = mBatches.size(); i-- > 0; ) { Batch& batch = mBatches.editItemAt(i); if (frameTime < 0) { result = consumeSamples(factory, batch, batch.samples.size(), outSeq, outEvent); mBatches.removeAt(i); return result; } nsecs_t sampleTime = frameTime - RESAMPLE_LATENCY; ssize_t split = findSampleNoLaterThan(batch, sampleTime); if (split < 0) { continue; } result = consumeSamples(factory, batch, split + 1, outSeq, outEvent); const InputMessage* next; if (batch.samples.isEmpty()) { mBatches.removeAt(i); next = NULL; } else { next = &batch.samples.itemAt(0); } if (!result) { resampleTouchState(sampleTime, static_cast(*outEvent), next); } return result; } return WOULD_BLOCK; } status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory, Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) { MotionEvent* motionEvent = factory->createMotionEvent(); if (! motionEvent) return NO_MEMORY; uint32_t chain = 0; for (size_t i = 0; i < count; i++) { InputMessage& msg = batch.samples.editItemAt(i); updateTouchState(&msg); if (i) { SeqChain seqChain; seqChain.seq = msg.body.motion.seq; seqChain.chain = chain; mSeqChains.push(seqChain); addSample(motionEvent, &msg); } else { initializeMotionEvent(motionEvent, &msg); } chain = msg.body.motion.seq; } batch.samples.removeItemsAt(0, count); *outSeq = chain; *outEvent = motionEvent; return OK; } void InputConsumer::updateTouchState(InputMessage* msg) { if (!mResampleTouch || !(msg->body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) { return; } int32_t deviceId = msg->body.motion.deviceId; int32_t source = msg->body.motion.source; nsecs_t eventTime = msg->body.motion.eventTime; // Update the touch state history to incorporate the new input message. // If the message is in the past relative to the most recently produced resampled // touch, then use the resampled time and coordinates instead. switch (msg->body.motion.action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: { ssize_t index = findTouchState(deviceId, source); if (index < 0) { mTouchStates.push(); index = mTouchStates.size() - 1; } TouchState& touchState = mTouchStates.editItemAt(index); touchState.initialize(deviceId, source); touchState.addHistory(msg); break; } case AMOTION_EVENT_ACTION_MOVE: { ssize_t index = findTouchState(deviceId, source); if (index >= 0) { TouchState& touchState = mTouchStates.editItemAt(index); touchState.addHistory(msg); if (eventTime < touchState.lastResample.eventTime) { rewriteMessage(touchState, msg); } else { touchState.lastResample.ids.clear(); } } break; } case AMOTION_EVENT_ACTION_POINTER_DOWN: { ssize_t index = findTouchState(deviceId, source); if (index >= 0) { TouchState& touchState = mTouchStates.editItemAt(index); touchState.lastResample.ids.remove(msg->body.motion.getActionId()); rewriteMessage(touchState, msg); } break; } case AMOTION_EVENT_ACTION_POINTER_UP: { ssize_t index = findTouchState(deviceId, source); if (index >= 0) { TouchState& touchState = mTouchStates.editItemAt(index); rewriteMessage(touchState, msg); touchState.lastResample.ids.remove(msg->body.motion.getActionId()); } break; } case AMOTION_EVENT_ACTION_SCROLL: { ssize_t index = findTouchState(deviceId, source); if (index >= 0) { const TouchState& touchState = mTouchStates.itemAt(index); rewriteMessage(touchState, msg); } break; } case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: { ssize_t index = findTouchState(deviceId, source); if (index >= 0) { const TouchState& touchState = mTouchStates.itemAt(index); rewriteMessage(touchState, msg); mTouchStates.removeAt(index); } break; } } } void InputConsumer::rewriteMessage(const TouchState& state, InputMessage* msg) { for (size_t i = 0; i < msg->body.motion.pointerCount; i++) { uint32_t id = msg->body.motion.pointers[i].properties.id; if (state.lastResample.ids.contains(id)) { PointerCoords& msgCoords = msg->body.motion.pointers[i].coords; const PointerCoords& resampleCoords = state.lastResample.getPointerById(id); #if DEBUG_RESAMPLING ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id, resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_X), resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_Y), msgCoords.getAxisValue(AMOTION_EVENT_AXIS_X), msgCoords.getAxisValue(AMOTION_EVENT_AXIS_Y)); #endif msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX()); msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY()); } } } void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, const InputMessage* next) { if (!mResampleTouch || !(event->getSource() & AINPUT_SOURCE_CLASS_POINTER) || event->getAction() != AMOTION_EVENT_ACTION_MOVE) { return; } ssize_t index = findTouchState(event->getDeviceId(), event->getSource()); if (index < 0) { #if DEBUG_RESAMPLING ALOGD("Not resampled, no touch state for device."); #endif return; } TouchState& touchState = mTouchStates.editItemAt(index); if (touchState.historySize < 1) { #if DEBUG_RESAMPLING ALOGD("Not resampled, no history for device."); #endif return; } // Ensure that the current sample has all of the pointers that need to be reported. const History* current = touchState.getHistory(0); size_t pointerCount = event->getPointerCount(); for (size_t i = 0; i < pointerCount; i++) { uint32_t id = event->getPointerId(i); if (!current->ids.contains(id)) { #if DEBUG_RESAMPLING ALOGD("Not resampled, missing id %d", id); #endif return; } } // Find the data to use for resampling. const History* other; History future; float alpha; if (next) { // Interpolate between current sample and future sample. // So current->eventTime <= sampleTime <= future.eventTime. future.initializeFrom(next); other = &future; nsecs_t delta = future.eventTime - current->eventTime; if (delta < RESAMPLE_MIN_DELTA) { #if DEBUG_RESAMPLING ALOGD("Not resampled, delta time is %lld ns.", delta); #endif return; } alpha = float(sampleTime - current->eventTime) / delta; } else if (touchState.historySize >= 2) { // Extrapolate future sample using current sample and past sample. // So other->eventTime <= current->eventTime <= sampleTime. other = touchState.getHistory(1); nsecs_t delta = current->eventTime - other->eventTime; if (delta < RESAMPLE_MIN_DELTA) { #if DEBUG_RESAMPLING ALOGD("Not resampled, delta time is %lld ns.", delta); #endif return; } nsecs_t maxPredict = current->eventTime + min(delta / 2, RESAMPLE_MAX_PREDICTION); if (sampleTime > maxPredict) { #if DEBUG_RESAMPLING ALOGD("Sample time is too far in the future, adjusting prediction " "from %lld to %lld ns.", sampleTime - current->eventTime, maxPredict - current->eventTime); #endif sampleTime = maxPredict; } alpha = float(current->eventTime - sampleTime) / delta; } else { #if DEBUG_RESAMPLING ALOGD("Not resampled, insufficient data."); #endif return; } // Resample touch coordinates. touchState.lastResample.eventTime = sampleTime; touchState.lastResample.ids.clear(); for (size_t i = 0; i < pointerCount; i++) { uint32_t id = event->getPointerId(i); touchState.lastResample.idToIndex[id] = i; touchState.lastResample.ids.insert(id); PointerCoords& resampledCoords = touchState.lastResample.pointers[i]; const PointerCoords& currentCoords = current->getPointerById(id); if (other->ids.contains(id) && shouldResampleTool(event->getToolType(i))) { const PointerCoords& otherCoords = other->getPointerById(id); resampledCoords.copyFrom(currentCoords); resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X, lerp(currentCoords.getX(), otherCoords.getX(), alpha)); resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, lerp(currentCoords.getY(), otherCoords.getY(), alpha)); #if DEBUG_RESAMPLING ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), " "other (%0.3f, %0.3f), alpha %0.3f", id, resampledCoords.getX(), resampledCoords.getY(), currentCoords.getX(), currentCoords.getY(), otherCoords.getX(), otherCoords.getY(), alpha); #endif } else { resampledCoords.copyFrom(currentCoords); #if DEBUG_RESAMPLING ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)", id, resampledCoords.getX(), resampledCoords.getY(), currentCoords.getX(), currentCoords.getY()); #endif } } event->addSample(sampleTime, touchState.lastResample.pointers); } bool InputConsumer::shouldResampleTool(int32_t toolType) { return toolType == AMOTION_EVENT_TOOL_TYPE_FINGER || toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN; } status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) { #if DEBUG_TRANSPORT_ACTIONS ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s", c_str(mChannel->getName()), seq, handled ? "true" : "false"); #endif if (!seq) { ALOGE("Attempted to send a finished signal with sequence number 0."); return BAD_VALUE; } // Send finished signals for the batch sequence chain first. size_t seqChainCount = mSeqChains.size(); if (seqChainCount) { uint32_t currentSeq = seq; uint32_t chainSeqs[seqChainCount]; size_t chainIndex = 0; for (size_t i = seqChainCount; i-- > 0; ) { const SeqChain& seqChain = mSeqChains.itemAt(i); if (seqChain.seq == currentSeq) { currentSeq = seqChain.chain; chainSeqs[chainIndex++] = currentSeq; mSeqChains.removeAt(i); } } status_t status = OK; while (!status && chainIndex-- > 0) { status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled); } if (status) { // An error occurred so at least one signal was not sent, reconstruct the chain. do { SeqChain seqChain; seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq; seqChain.chain = chainSeqs[chainIndex]; mSeqChains.push(seqChain); } while (chainIndex-- > 0); return status; } } // Send finished signal for the last message in the batch. return sendUnchainedFinishedSignal(seq, handled); } status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) { InputMessage msg; msg.header.type = InputMessage::TYPE_FINISHED; msg.body.finished.seq = seq; msg.body.finished.handled = handled; return mChannel->sendMessage(&msg); } bool InputConsumer::hasDeferredEvent() const { return mMsgDeferred; } bool InputConsumer::hasPendingBatch() const { return !mBatches.isEmpty(); } ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const { for (size_t i = 0; i < mBatches.size(); i++) { const Batch& batch = mBatches.itemAt(i); const InputMessage& head = batch.samples.itemAt(0); if (head.body.motion.deviceId == deviceId && head.body.motion.source == source) { return i; } } return -1; } ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const { for (size_t i = 0; i < mTouchStates.size(); i++) { const TouchState& touchState = mTouchStates.itemAt(i); if (touchState.deviceId == deviceId && touchState.source == source) { return i; } } return -1; } void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) { event->initialize( msg->body.key.deviceId, msg->body.key.source, msg->body.key.action, msg->body.key.flags, msg->body.key.keyCode, msg->body.key.scanCode, msg->body.key.metaState, msg->body.key.repeatCount, msg->body.key.downTime, msg->body.key.eventTime); } void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) { size_t pointerCount = msg->body.motion.pointerCount; PointerProperties pointerProperties[pointerCount]; PointerCoords pointerCoords[pointerCount]; for (size_t i = 0; i < pointerCount; i++) { pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties); pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); } event->initialize( msg->body.motion.deviceId, msg->body.motion.source, msg->body.motion.action, msg->body.motion.flags, msg->body.motion.edgeFlags, msg->body.motion.metaState, msg->body.motion.buttonState, msg->body.motion.xOffset, msg->body.motion.yOffset, msg->body.motion.xPrecision, msg->body.motion.yPrecision, msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords); } void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) { size_t pointerCount = msg->body.motion.pointerCount; PointerCoords pointerCoords[pointerCount]; for (size_t i = 0; i < pointerCount; i++) { pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); } event->setMetaState(event->getMetaState() | msg->body.motion.metaState); event->addSample(msg->body.motion.eventTime, pointerCoords); } bool InputConsumer::canAddSample(const Batch& batch, const InputMessage *msg) { const InputMessage& head = batch.samples.itemAt(0); size_t pointerCount = msg->body.motion.pointerCount; if (head.body.motion.pointerCount != pointerCount || head.body.motion.action != msg->body.motion.action) { return false; } for (size_t i = 0; i < pointerCount; i++) { if (head.body.motion.pointers[i].properties != msg->body.motion.pointers[i].properties) { return false; } } return true; } ssize_t InputConsumer::findSampleNoLaterThan(const Batch& batch, nsecs_t time) { size_t numSamples = batch.samples.size(); size_t index = 0; while (index < numSamples && batch.samples.itemAt(index).body.motion.eventTime <= time) { index += 1; } return ssize_t(index) - 1; } } // namespace android ././@LongLink0000000000000000000000000000015200000000000011213 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputListener.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputListene0000644000015301777760000001411012322054223033417 0ustar pbusernogroup00000000000000/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "InputListener" //#define LOG_NDEBUG 0 #include "InputListener.h" #include namespace android { // --- NotifyConfigurationChangedArgs --- NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(nsecs_t eventTime) : eventTime(eventTime) { } NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs( const NotifyConfigurationChangedArgs& other) : eventTime(other.eventTime) { } void NotifyConfigurationChangedArgs::notify(const sp& listener) const { listener->notifyConfigurationChanged(this); } // --- NotifyKeyArgs --- NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) : eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags), action(action), flags(flags), keyCode(keyCode), scanCode(scanCode), metaState(metaState), downTime(downTime) { } NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) : eventTime(other.eventTime), deviceId(other.deviceId), source(other.source), policyFlags(other.policyFlags), action(other.action), flags(other.flags), keyCode(other.keyCode), scanCode(other.scanCode), metaState(other.metaState), downTime(other.downTime) { } void NotifyKeyArgs::notify(const sp& listener) const { listener->notifyKey(this); } // --- NotifyMotionArgs --- NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime) : eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags), action(action), flags(flags), metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags), pointerCount(pointerCount), xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) { for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); } } NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) : eventTime(other.eventTime), deviceId(other.deviceId), source(other.source), policyFlags(other.policyFlags), action(other.action), flags(other.flags), metaState(other.metaState), buttonState(other.buttonState), edgeFlags(other.edgeFlags), pointerCount(other.pointerCount), xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) { for (uint32_t i = 0; i < pointerCount; i++) { pointerProperties[i].copyFrom(other.pointerProperties[i]); pointerCoords[i].copyFrom(other.pointerCoords[i]); } } void NotifyMotionArgs::notify(const sp& listener) const { listener->notifyMotion(this); } // --- NotifySwitchArgs --- NotifySwitchArgs::NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags, int32_t switchCode, int32_t switchValue) : eventTime(eventTime), policyFlags(policyFlags), switchCode(switchCode), switchValue(switchValue) { } NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) : eventTime(other.eventTime), policyFlags(other.policyFlags), switchCode(other.switchCode), switchValue(other.switchValue) { } void NotifySwitchArgs::notify(const sp& listener) const { listener->notifySwitch(this); } // --- NotifyDeviceResetArgs --- NotifyDeviceResetArgs::NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId) : eventTime(eventTime), deviceId(deviceId) { } NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) : eventTime(other.eventTime), deviceId(other.deviceId) { } void NotifyDeviceResetArgs::notify(const sp& listener) const { listener->notifyDeviceReset(this); } // --- QueuedInputListener --- QueuedInputListener::QueuedInputListener(const sp& innerListener) : mInnerListener(innerListener) { } QueuedInputListener::~QueuedInputListener() { size_t count = mArgsQueue.size(); for (size_t i = 0; i < count; i++) { delete mArgsQueue[i]; } } void QueuedInputListener::notifyConfigurationChanged( const NotifyConfigurationChangedArgs* args) { mArgsQueue.push(new NotifyConfigurationChangedArgs(*args)); } void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) { mArgsQueue.push(new NotifyKeyArgs(*args)); } void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { mArgsQueue.push(new NotifyMotionArgs(*args)); } void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) { mArgsQueue.push(new NotifySwitchArgs(*args)); } void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) { mArgsQueue.push(new NotifyDeviceResetArgs(*args)); } void QueuedInputListener::flush() { size_t count = mArgsQueue.size(); for (size_t i = 0; i < count; i++) { NotifyArgs* args = mArgsQueue[i]; args->notify(mInnerListener); delete args; } mArgsQueue.clear(); } } // namespace android mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/Input.cpp0000644000015301777760000004546612322054223032676 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Input" //#define LOG_NDEBUG 0 #include #include #include #include #include #ifdef HAVE_ANDROID_OS #include #include #include #include #endif namespace android { // --- InputEvent --- void InputEvent::initialize(int32_t deviceId, int32_t source) { mDeviceId = deviceId; mSource = source; } void InputEvent::initialize(const InputEvent& from) { mDeviceId = from.mDeviceId; mSource = from.mSource; } // --- KeyEvent --- bool KeyEvent::hasDefaultAction(int32_t keyCode) { switch (keyCode) { case AKEYCODE_HOME: case AKEYCODE_BACK: case AKEYCODE_CALL: case AKEYCODE_ENDCALL: case AKEYCODE_VOLUME_UP: case AKEYCODE_VOLUME_DOWN: case AKEYCODE_VOLUME_MUTE: case AKEYCODE_POWER: case AKEYCODE_CAMERA: case AKEYCODE_HEADSETHOOK: case AKEYCODE_MENU: case AKEYCODE_NOTIFICATION: case AKEYCODE_FOCUS: case AKEYCODE_SEARCH: case AKEYCODE_MEDIA_PLAY: case AKEYCODE_MEDIA_PAUSE: case AKEYCODE_MEDIA_PLAY_PAUSE: case AKEYCODE_MEDIA_STOP: case AKEYCODE_MEDIA_NEXT: case AKEYCODE_MEDIA_PREVIOUS: case AKEYCODE_MEDIA_REWIND: case AKEYCODE_MEDIA_RECORD: case AKEYCODE_MEDIA_FAST_FORWARD: case AKEYCODE_MUTE: return true; } return false; } bool KeyEvent::hasDefaultAction() const { return hasDefaultAction(getKeyCode()); } bool KeyEvent::isSystemKey(int32_t keyCode) { switch (keyCode) { case AKEYCODE_MENU: case AKEYCODE_SOFT_RIGHT: case AKEYCODE_HOME: case AKEYCODE_BACK: case AKEYCODE_CALL: case AKEYCODE_ENDCALL: case AKEYCODE_VOLUME_UP: case AKEYCODE_VOLUME_DOWN: case AKEYCODE_VOLUME_MUTE: case AKEYCODE_MUTE: case AKEYCODE_POWER: case AKEYCODE_HEADSETHOOK: case AKEYCODE_MEDIA_PLAY: case AKEYCODE_MEDIA_PAUSE: case AKEYCODE_MEDIA_PLAY_PAUSE: case AKEYCODE_MEDIA_STOP: case AKEYCODE_MEDIA_NEXT: case AKEYCODE_MEDIA_PREVIOUS: case AKEYCODE_MEDIA_REWIND: case AKEYCODE_MEDIA_RECORD: case AKEYCODE_MEDIA_FAST_FORWARD: case AKEYCODE_CAMERA: case AKEYCODE_FOCUS: case AKEYCODE_SEARCH: return true; } return false; } bool KeyEvent::isSystemKey() const { return isSystemKey(getKeyCode()); } void KeyEvent::initialize( int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime) { InputEvent::initialize(deviceId, source); mAction = action; mFlags = flags; mKeyCode = keyCode; mScanCode = scanCode; mMetaState = metaState; mRepeatCount = repeatCount; mDownTime = downTime; mEventTime = eventTime; } void KeyEvent::initialize(const KeyEvent& from) { InputEvent::initialize(from); mAction = from.mAction; mFlags = from.mFlags; mKeyCode = from.mKeyCode; mScanCode = from.mScanCode; mMetaState = from.mMetaState; mRepeatCount = from.mRepeatCount; mDownTime = from.mDownTime; mEventTime = from.mEventTime; } // --- PointerCoords --- float PointerCoords::getAxisValue(int32_t axis) const { if (axis < 0 || axis > 63) { return 0; } uint64_t axisBit = 1LL << axis; if (!(bits & axisBit)) { return 0; } uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); return values[index]; } status_t PointerCoords::setAxisValue(int32_t axis, float value) { if (axis < 0 || axis > 63) { return NAME_NOT_FOUND; } uint64_t axisBit = 1LL << axis; uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); if (!(bits & axisBit)) { if (value == 0) { return OK; // axes with value 0 do not need to be stored } uint32_t count = __builtin_popcountll(bits); if (count >= MAX_AXES) { tooManyAxes(axis); return NO_MEMORY; } bits |= axisBit; for (uint32_t i = count; i > index; i--) { values[i] = values[i - 1]; } } values[index] = value; return OK; } static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) { float value = c.getAxisValue(axis); if (value != 0) { c.setAxisValue(axis, value * scaleFactor); } } void PointerCoords::scale(float scaleFactor) { // No need to scale pressure or size since they are normalized. // No need to scale orientation since it is meaningless to do so. scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor); scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor); } #ifdef HAVE_ANDROID_OS status_t PointerCoords::readFromParcel(Parcel* parcel) { bits = parcel->readInt64(); uint32_t count = __builtin_popcountll(bits); if (count > MAX_AXES) { return BAD_VALUE; } for (uint32_t i = 0; i < count; i++) { values[i] = parcel->readInt32(); } return OK; } status_t PointerCoords::writeToParcel(Parcel* parcel) const { parcel->writeInt64(bits); uint32_t count = __builtin_popcountll(bits); for (uint32_t i = 0; i < count; i++) { parcel->writeInt32(values[i]); } return OK; } #endif void PointerCoords::tooManyAxes(int axis) { ALOGW("Could not set value for axis %d because the PointerCoords structure is full and " "cannot contain more than %d axis values.", axis, int(MAX_AXES)); } bool PointerCoords::operator==(const PointerCoords& other) const { if (bits != other.bits) { return false; } uint32_t count = __builtin_popcountll(bits); for (uint32_t i = 0; i < count; i++) { if (values[i] != other.values[i]) { return false; } } return true; } void PointerCoords::copyFrom(const PointerCoords& other) { bits = other.bits; uint32_t count = __builtin_popcountll(bits); for (uint32_t i = 0; i < count; i++) { values[i] = other.values[i]; } } // --- PointerProperties --- bool PointerProperties::operator==(const PointerProperties& other) const { return id == other.id && toolType == other.toolType; } void PointerProperties::copyFrom(const PointerProperties& other) { id = other.id; toolType = other.toolType; } // --- MotionEvent --- void MotionEvent::initialize( int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, float xOffset, float yOffset, float xPrecision, float yPrecision, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { InputEvent::initialize(deviceId, source); mAction = action; mFlags = flags; mEdgeFlags = edgeFlags; mMetaState = metaState; mButtonState = buttonState; mXOffset = xOffset; mYOffset = yOffset; mXPrecision = xPrecision; mYPrecision = yPrecision; mDownTime = downTime; mPointerProperties.clear(); mPointerProperties.appendArray(pointerProperties, pointerCount); mSampleEventTimes.clear(); mSamplePointerCoords.clear(); addSample(eventTime, pointerCoords); } void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { InputEvent::initialize(other->mDeviceId, other->mSource); mAction = other->mAction; mFlags = other->mFlags; mEdgeFlags = other->mEdgeFlags; mMetaState = other->mMetaState; mButtonState = other->mButtonState; mXOffset = other->mXOffset; mYOffset = other->mYOffset; mXPrecision = other->mXPrecision; mYPrecision = other->mYPrecision; mDownTime = other->mDownTime; mPointerProperties = other->mPointerProperties; if (keepHistory) { mSampleEventTimes = other->mSampleEventTimes; mSamplePointerCoords = other->mSamplePointerCoords; } else { mSampleEventTimes.clear(); mSampleEventTimes.push(other->getEventTime()); mSamplePointerCoords.clear(); size_t pointerCount = other->getPointerCount(); size_t historySize = other->getHistorySize(); mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array() + (historySize * pointerCount), pointerCount); } } void MotionEvent::addSample( int64_t eventTime, const PointerCoords* pointerCoords) { mSampleEventTimes.push(eventTime); mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); } const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const { return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex]; } float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const { return getRawPointerCoords(pointerIndex)->getAxisValue(axis); } float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const { float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis); switch (axis) { case AMOTION_EVENT_AXIS_X: return value + mXOffset; case AMOTION_EVENT_AXIS_Y: return value + mYOffset; } return value; } const PointerCoords* MotionEvent::getHistoricalRawPointerCoords( size_t pointerIndex, size_t historicalIndex) const { return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex]; } float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const { return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); } float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const { float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); switch (axis) { case AMOTION_EVENT_AXIS_X: return value + mXOffset; case AMOTION_EVENT_AXIS_Y: return value + mYOffset; } return value; } ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { size_t pointerCount = mPointerProperties.size(); for (size_t i = 0; i < pointerCount; i++) { if (mPointerProperties.itemAt(i).id == pointerId) { return i; } } return -1; } void MotionEvent::offsetLocation(float xOffset, float yOffset) { mXOffset += xOffset; mYOffset += yOffset; } void MotionEvent::scale(float scaleFactor) { mXOffset *= scaleFactor; mYOffset *= scaleFactor; mXPrecision *= scaleFactor; mYPrecision *= scaleFactor; size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { mSamplePointerCoords.editItemAt(i).scale(scaleFactor); } } #ifdef HAVE_ANDROID_OS static inline float transformAngle(const SkMatrix* matrix, float angleRadians) { // Construct and transform a vector oriented at the specified clockwise angle from vertical. // Coordinate system: down is increasing Y, right is increasing X. SkPoint vector; vector.fX = SkFloatToScalar(sinf(angleRadians)); vector.fY = SkFloatToScalar(-cosf(angleRadians)); matrix->mapVectors(& vector, 1); // Derive the transformed vector's clockwise angle from vertical. float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY)); if (result < - M_PI_2) { result += M_PI; } else if (result > M_PI_2) { result -= M_PI; } return result; } void MotionEvent::transform(const SkMatrix* matrix) { float oldXOffset = mXOffset; float oldYOffset = mYOffset; // The tricky part of this implementation is to preserve the value of // rawX and rawY. So we apply the transformation to the first point // then derive an appropriate new X/Y offset that will preserve rawX and rawY. SkPoint point; float rawX = getRawX(0); float rawY = getRawY(0); matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset), & point); float newX = SkScalarToFloat(point.fX); float newY = SkScalarToFloat(point.fY); float newXOffset = newX - rawX; float newYOffset = newY - rawY; mXOffset = newXOffset; mYOffset = newYOffset; // Apply the transformation to all samples. size_t numSamples = mSamplePointerCoords.size(); for (size_t i = 0; i < numSamples; i++) { PointerCoords& c = mSamplePointerCoords.editItemAt(i); float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset; float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset; matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point); c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset); c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset); float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation)); } } status_t MotionEvent::readFromParcel(Parcel* parcel) { size_t pointerCount = parcel->readInt32(); size_t sampleCount = parcel->readInt32(); if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) { return BAD_VALUE; } mDeviceId = parcel->readInt32(); mSource = parcel->readInt32(); mAction = parcel->readInt32(); mFlags = parcel->readInt32(); mEdgeFlags = parcel->readInt32(); mMetaState = parcel->readInt32(); mButtonState = parcel->readInt32(); mXOffset = parcel->readFloat(); mYOffset = parcel->readFloat(); mXPrecision = parcel->readFloat(); mYPrecision = parcel->readFloat(); mDownTime = parcel->readInt64(); mPointerProperties.clear(); mPointerProperties.setCapacity(pointerCount); mSampleEventTimes.clear(); mSampleEventTimes.setCapacity(sampleCount); mSamplePointerCoords.clear(); mSamplePointerCoords.setCapacity(sampleCount * pointerCount); for (size_t i = 0; i < pointerCount; i++) { mPointerProperties.push(); PointerProperties& properties = mPointerProperties.editTop(); properties.id = parcel->readInt32(); properties.toolType = parcel->readInt32(); } while (sampleCount-- > 0) { mSampleEventTimes.push(parcel->readInt64()); for (size_t i = 0; i < pointerCount; i++) { mSamplePointerCoords.push(); status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel); if (status) { return status; } } } return OK; } status_t MotionEvent::writeToParcel(Parcel* parcel) const { size_t pointerCount = mPointerProperties.size(); size_t sampleCount = mSampleEventTimes.size(); parcel->writeInt32(pointerCount); parcel->writeInt32(sampleCount); parcel->writeInt32(mDeviceId); parcel->writeInt32(mSource); parcel->writeInt32(mAction); parcel->writeInt32(mFlags); parcel->writeInt32(mEdgeFlags); parcel->writeInt32(mMetaState); parcel->writeInt32(mButtonState); parcel->writeFloat(mXOffset); parcel->writeFloat(mYOffset); parcel->writeFloat(mXPrecision); parcel->writeFloat(mYPrecision); parcel->writeInt64(mDownTime); for (size_t i = 0; i < pointerCount; i++) { const PointerProperties& properties = mPointerProperties.itemAt(i); parcel->writeInt32(properties.id); parcel->writeInt32(properties.toolType); } const PointerCoords* pc = mSamplePointerCoords.array(); for (size_t h = 0; h < sampleCount; h++) { parcel->writeInt64(mSampleEventTimes.itemAt(h)); for (size_t i = 0; i < pointerCount; i++) { status_t status = (pc++)->writeToParcel(parcel); if (status) { return status; } } } return OK; } #endif bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { if (source & AINPUT_SOURCE_CLASS_POINTER) { // Specifically excludes HOVER_MOVE and SCROLL. switch (action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_MOVE: case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_POINTER_DOWN: case AMOTION_EVENT_ACTION_POINTER_UP: case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_OUTSIDE: return true; } } return false; } // --- PooledInputEventFactory --- PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) : mMaxPoolSize(maxPoolSize) { } PooledInputEventFactory::~PooledInputEventFactory() { for (size_t i = 0; i < mKeyEventPool.size(); i++) { delete mKeyEventPool.itemAt(i); } for (size_t i = 0; i < mMotionEventPool.size(); i++) { delete mMotionEventPool.itemAt(i); } } KeyEvent* PooledInputEventFactory::createKeyEvent() { if (!mKeyEventPool.isEmpty()) { KeyEvent* event = mKeyEventPool.top(); mKeyEventPool.pop(); return event; } return new KeyEvent(); } MotionEvent* PooledInputEventFactory::createMotionEvent() { if (!mMotionEventPool.isEmpty()) { MotionEvent* event = mMotionEventPool.top(); mMotionEventPool.pop(); return event; } return new MotionEvent(); } void PooledInputEventFactory::recycle(InputEvent* event) { switch (event->getType()) { case AINPUT_EVENT_TYPE_KEY: if (mKeyEventPool.size() < mMaxPoolSize) { mKeyEventPool.push(static_cast(event)); return; } break; case AINPUT_EVENT_TYPE_MOTION: if (mMotionEventPool.size() < mMaxPoolSize) { mMotionEventPool.push(static_cast(event)); return; } break; } delete event; } } // namespace android ././@LongLink0000000000000000000000000000015100000000000011212 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/KeyLayoutMap.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/KeyLayoutMap0000644000015301777760000003071212322054223033366 0ustar pbusernogroup00000000000000/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "KeyLayoutMap" #include #include #include #include #include #include #include #include // Enables debug output for the parser. #define DEBUG_PARSER 0 // Enables debug output for parser performance. #define DEBUG_PARSER_PERFORMANCE 0 // Enables debug output for mapping. #define DEBUG_MAPPING 0 namespace android { static const char* WHITESPACE = " \t\r"; // --- KeyLayoutMap --- KeyLayoutMap::KeyLayoutMap() { } KeyLayoutMap::~KeyLayoutMap() { } status_t KeyLayoutMap::load(Tokenizer *tokenizer, sp* outMap) { status_t status = 0; outMap->clear(); sp map = new KeyLayoutMap(); if (!map.get()) { ALOGE("Error allocating key layout map."); status = NO_MEMORY; } else { #if DEBUG_PARSER_PERFORMANCE nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); #endif Parser parser(map.get(), tokenizer); status = parser.parse(); #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.", tokenizer->getFilename().string(), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (!status) { *outMap = map; } } return status; } status_t KeyLayoutMap::load(const String8& filename, sp* outMap) { outMap->clear(); Tokenizer* tokenizer; status_t status = Tokenizer::open(filename, &tokenizer); if (status) { ALOGE("Error %d opening key layout map file %s.", status, c_str(filename)); } else { status = load(tokenizer, outMap); delete tokenizer; } return status; } status_t KeyLayoutMap::load(const String8& filename, const char* contents, sp* outMap) { outMap->clear(); Tokenizer* tokenizer; status_t status = Tokenizer::fromContents(filename, contents, &tokenizer); if (status) { ALOGE("Error %d opening key layout map file %s.", status, c_str(filename)); } else { status = load(tokenizer, outMap); delete tokenizer; } return status; } status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode, uint32_t* outFlags) const { const Key* key = getKey(scanCode, usageCode); if (!key) { #if DEBUG_MAPPING ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode); #endif *outKeyCode = AKEYCODE_UNKNOWN; *outFlags = 0; return NAME_NOT_FOUND; } *outKeyCode = key->keyCode; *outFlags = key->flags; #if DEBUG_MAPPING ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.", scanCode, usageCode, *outKeyCode, *outFlags); #endif return NO_ERROR; } const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const { if (usageCode) { ssize_t index = mKeysByUsageCode.indexOfKey(usageCode); if (index >= 0) { return &mKeysByUsageCode.valueAt(index); } } if (scanCode) { ssize_t index = mKeysByScanCode.indexOfKey(scanCode); if (index >= 0) { return &mKeysByScanCode.valueAt(index); } } return NULL; } status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector* outScanCodes) const { const size_t N = mKeysByScanCode.size(); for (size_t i=0; iadd(mKeysByScanCode.keyAt(i)); } } return NO_ERROR; } status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const { ssize_t index = mAxes.indexOfKey(scanCode); if (index < 0) { #if DEBUG_MAPPING ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode); #endif return NAME_NOT_FOUND; } *outAxisInfo = mAxes.valueAt(index); #if DEBUG_MAPPING ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, " "splitValue=%d, flatOverride=%d.", scanCode, outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis, outAxisInfo->splitValue, outAxisInfo->flatOverride); #endif return NO_ERROR; } // --- KeyLayoutMap::Parser --- KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) : mMap(map), mTokenizer(tokenizer) { } KeyLayoutMap::Parser::~Parser() { } status_t KeyLayoutMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER ALOGD("Parsing %s: '%s'.", c_str(mTokenizer->getLocation()), mTokenizer->peekRemainderOfLine().string()); #endif mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { String8 keywordToken = mTokenizer->nextToken(WHITESPACE); if (keywordToken == "key") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseKey(); if (status) return status; } else if (keywordToken == "axis") { mTokenizer->skipDelimiters(WHITESPACE); status_t status = parseAxis(); if (status) return status; } else { ALOGE("%s: Expected keyword, got '%s'.", c_str(mTokenizer->getLocation()), c_str(keywordToken)); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { ALOGE("%s: Expected end of line or trailing comment, got '%s'.", c_str(mTokenizer->getLocation()), c_str(mTokenizer->peekRemainderOfLine())); return BAD_VALUE; } } mTokenizer->nextLine(); } return NO_ERROR; } status_t KeyLayoutMap::Parser::parseKey() { String8 codeToken = mTokenizer->nextToken(WHITESPACE); bool mapUsage = false; if (codeToken == "usage") { mapUsage = true; mTokenizer->skipDelimiters(WHITESPACE); codeToken = mTokenizer->nextToken(WHITESPACE); } char* end; int32_t code = int32_t(strtol(c_str(codeToken), &end, 0)); if (*end) { ALOGE("%s: Expected key %s number, got '%s'.", c_str(mTokenizer->getLocation()), mapUsage ? "usage" : "scan code", c_str(codeToken)); return BAD_VALUE; } KeyedVector& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; if (map.indexOfKey(code) >= 0) { ALOGE("%s: Duplicate entry for key %s '%s'.", c_str(mTokenizer->getLocation()), mapUsage ? "usage" : "scan code", c_str(codeToken)); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); int32_t keyCode = getKeyCodeByLabel(c_str(keyCodeToken)); if (!keyCode) { ALOGE("%s: Expected key code label, got '%s'.", c_str(mTokenizer->getLocation()), c_str(keyCodeToken)); return BAD_VALUE; } uint32_t flags = 0; for (;;) { mTokenizer->skipDelimiters(WHITESPACE); if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break; String8 flagToken = mTokenizer->nextToken(WHITESPACE); uint32_t flag = getKeyFlagByLabel(c_str(flagToken)); if (!flag) { ALOGE("%s: Expected key flag label, got '%s'.", c_str(mTokenizer->getLocation()), c_str(flagToken)); return BAD_VALUE; } if (flags & flag) { ALOGE("%s: Duplicate key flag '%s'.", c_str(mTokenizer->getLocation()), c_str(flagToken)); return BAD_VALUE; } flags |= flag; } #if DEBUG_PARSER ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.", mapUsage ? "usage" : "scan code", code, keyCode, flags); #endif Key key; key.keyCode = keyCode; key.flags = flags; map.add(code, key); return NO_ERROR; } status_t KeyLayoutMap::Parser::parseAxis() { String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); char* end; int32_t scanCode = int32_t(strtol(c_str(scanCodeToken), &end, 0)); if (*end) { ALOGE("%s: Expected axis scan code number, got '%s'.", c_str(mTokenizer->getLocation()), c_str(scanCodeToken)); return BAD_VALUE; } if (mMap->mAxes.indexOfKey(scanCode) >= 0) { ALOGE("%s: Duplicate entry for axis scan code '%s'.", c_str(mTokenizer->getLocation()), c_str(scanCodeToken)); return BAD_VALUE; } AxisInfo axisInfo; mTokenizer->skipDelimiters(WHITESPACE); String8 token = mTokenizer->nextToken(WHITESPACE); if (token == "invert") { axisInfo.mode = AxisInfo::MODE_INVERT; mTokenizer->skipDelimiters(WHITESPACE); String8 axisToken = mTokenizer->nextToken(WHITESPACE); axisInfo.axis = getAxisByLabel(c_str(axisToken)); if (axisInfo.axis < 0) { ALOGE("%s: Expected inverted axis label, got '%s'.", c_str(mTokenizer->getLocation()), c_str(axisToken)); return BAD_VALUE; } } else if (token == "split") { axisInfo.mode = AxisInfo::MODE_SPLIT; mTokenizer->skipDelimiters(WHITESPACE); String8 splitToken = mTokenizer->nextToken(WHITESPACE); axisInfo.splitValue = int32_t(strtol(c_str(splitToken), &end, 0)); if (*end) { ALOGE("%s: Expected split value, got '%s'.", c_str(mTokenizer->getLocation()), c_str(splitToken)); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE); axisInfo.axis = getAxisByLabel(c_str(lowAxisToken)); if (axisInfo.axis < 0) { ALOGE("%s: Expected low axis label, got '%s'.", c_str(mTokenizer->getLocation()), c_str(lowAxisToken)); return BAD_VALUE; } mTokenizer->skipDelimiters(WHITESPACE); String8 highAxisToken = mTokenizer->nextToken(WHITESPACE); axisInfo.highAxis = getAxisByLabel(c_str(highAxisToken)); if (axisInfo.highAxis < 0) { ALOGE("%s: Expected high axis label, got '%s'.", c_str(mTokenizer->getLocation()), c_str(highAxisToken)); return BAD_VALUE; } } else { axisInfo.axis = getAxisByLabel(c_str(token)); if (axisInfo.axis < 0) { ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.", c_str(mTokenizer->getLocation()), c_str(token)); return BAD_VALUE; } } for (;;) { mTokenizer->skipDelimiters(WHITESPACE); if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') { break; } String8 keywordToken = mTokenizer->nextToken(WHITESPACE); if (keywordToken == "flat") { mTokenizer->skipDelimiters(WHITESPACE); String8 flatToken = mTokenizer->nextToken(WHITESPACE); axisInfo.flatOverride = int32_t(strtol(c_str(flatToken), &end, 0)); if (*end) { ALOGE("%s: Expected flat value, got '%s'.", c_str(mTokenizer->getLocation()), c_str(flatToken)); return BAD_VALUE; } } else { ALOGE("%s: Expected keyword 'flat', got '%s'.", c_str(mTokenizer->getLocation()), c_str(keywordToken)); return BAD_VALUE; } } #if DEBUG_PARSER ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, " "splitValue=%d, flatOverride=%d.", scanCode, axisInfo.mode, axisInfo.axis, axisInfo.highAxis, axisInfo.splitValue, axisInfo.flatOverride); #endif mMap->mAxes.add(scanCode, axisInfo); return NO_ERROR; } }; ././@LongLink0000000000000000000000000000015400000000000011215 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputDispatc0000644000015301777760000051274312322054223033422 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "InputDispatcher" #define ATRACE_TAG ATRACE_TAG_INPUT //#define LOG_NDEBUG 0 // Log detailed debug messages about each inbound event notification to the dispatcher. #define DEBUG_INBOUND_EVENT_DETAILS 0 // Log detailed debug messages about each outbound event processed by the dispatcher. #define DEBUG_OUTBOUND_EVENT_DETAILS 0 // Log debug messages about the dispatch cycle. #define DEBUG_DISPATCH_CYCLE 0 // Log debug messages about registrations. #define DEBUG_REGISTRATION 0 // Log debug messages about input event injection. #define DEBUG_INJECTION 0 // Log debug messages about input focus tracking. #define DEBUG_FOCUS 0 // Log debug messages about the app switch latency optimization. #define DEBUG_APP_SWITCH 0 // Log debug messages about hover events. #define DEBUG_HOVER 0 #include "InputDispatcher.h" #include "mir/input/input_report.h" #include #include #include #include #include #include #include #define INDENT " " #define INDENT2 " " #define INDENT3 " " #define INDENT4 " " namespace mi = mir::input; namespace android { // Default input dispatching timeout if there is no focused application or paused window // from which to determine an appropriate dispatching timeout. const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec // Amount of time to allow for all pending events to be processed when an app switch // key is on the way. This is used to preempt input dispatch and drop input events // when an application takes too long to respond and the user has pressed an app switch key. const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec // Amount of time to allow for an event to be dispatched (measured since its eventTime) // before considering it stale and dropping it. const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec // Amount of time to allow touch events to be streamed out to a connection before requiring // that the first event be finished. This value extends the ANR timeout by the specified // amount. For example, if streaming is allowed to get ahead by one second relative to the // queue of waiting unfinished events, then ANRs will similarly be delayed by one second. const nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec // Log a warning when an event takes longer than this to process, even if an ANR does not occur. const nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec static inline nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); } static inline const char* toString(bool value) { return value ? "true" : "false"; } static inline int32_t getMotionEventActionPointerIndex(int32_t action) { return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } static bool isValidKeyAction(int32_t action) { switch (action) { case AKEY_EVENT_ACTION_DOWN: case AKEY_EVENT_ACTION_UP: return true; default: return false; } } static bool validateKeyEvent(int32_t action) { if (! isValidKeyAction(action)) { ALOGE("Key event has invalid action code 0x%x", action); return false; } return true; } static bool isValidMotionAction(int32_t action, size_t pointerCount) { switch (action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: case AMOTION_EVENT_ACTION_MOVE: case AMOTION_EVENT_ACTION_OUTSIDE: case AMOTION_EVENT_ACTION_HOVER_ENTER: case AMOTION_EVENT_ACTION_HOVER_MOVE: case AMOTION_EVENT_ACTION_HOVER_EXIT: case AMOTION_EVENT_ACTION_SCROLL: return true; case AMOTION_EVENT_ACTION_POINTER_DOWN: case AMOTION_EVENT_ACTION_POINTER_UP: { int32_t index = getMotionEventActionPointerIndex(action); return index >= 0 && size_t(index) < pointerCount; } default: return false; } } static bool validateMotionEvent(int32_t action, size_t pointerCount, const PointerProperties* pointerProperties) { if (! isValidMotionAction(action, pointerCount)) { ALOGE("Motion event has invalid action code 0x%x", action); return false; } if (pointerCount < 1 || pointerCount > MAX_POINTERS) { ALOGE("Motion event has invalid pointer count %d; value must be between 1 and %d.", pointerCount, MAX_POINTERS); return false; } IntSet pointerIds; for (size_t i = 0; i < pointerCount; i++) { int32_t id = pointerProperties[i].id; if (id < 0 || id > MAX_POINTER_ID) { ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", id, MAX_POINTER_ID); return false; } if (pointerIds.contains(id)) { ALOGE("Motion event has duplicate pointer id %d", id); return false; } pointerIds.insert(id); } return true; } // --- InputDispatcher --- InputDispatcher::InputDispatcher(const sp& policy, std::shared_ptr const& input_report) : input_report(input_report), mPolicy(policy), mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), mNextUnblockedEvent(NULL), mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { mLooper = new Looper(false); mKeyRepeatState.lastKeyEntry = NULL; policy->getDispatcherConfiguration(&mConfig); } void InputDispatcher::setInputEnumerator(sp const& enumerator) { AutoMutex _l(mLock); mEnumerator = enumerator; } InputDispatcher::~InputDispatcher() { { // acquire lock AutoMutex _l(mLock); resetKeyRepeatLocked(); releasePendingEventLocked(); drainInboundQueueLocked(); } while (mConnectionsByFd.size() != 0) { unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel); } } void InputDispatcher::dispatchOnce() { nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock AutoMutex _l(mLock); broadcast(mDispatcherIsAliveCondition); dispatchOnceInnerLocked(&nextWakeupTime); if (runCommandsLockedInterruptible()) { nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately } } // release lock // Wait for callback or timeout or wake. (make sure we round up, not down) nsecs_t currentTime = now(); int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); mLooper->pollOnce(timeoutMillis); } void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { nsecs_t currentTime = now(); // Reset the key repeat timer whenever we disallow key events, even if the next event // is not a key. This is to ensure that we abort a key repeat if the device is just coming // out of sleep. if (!mPolicy->isKeyRepeatEnabled()) { resetKeyRepeatLocked(); } // If dispatching is frozen, do not process timeouts or try to deliver any new events. if (mDispatchFrozen) { #if DEBUG_FOCUS ALOGD("Dispatch frozen. Waiting some more."); #endif return; } // Optimize latency of app switches. // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has // been pressed. When it expires, we preempt dispatch and drop all other pending events. bool isAppSwitchDue = mAppSwitchDueTime <= currentTime; if (mAppSwitchDueTime < *nextWakeupTime) { *nextWakeupTime = mAppSwitchDueTime; } // Ready to start a new event. // If we don't already have a pending event, go grab one. if (! mPendingEvent) { if (mInboundQueue.isEmpty()) { if (isAppSwitchDue) { // The inbound queue is empty so the app switch key we were waiting // for will never arrive. Stop waiting for it. resetPendingAppSwitchLocked(false); isAppSwitchDue = false; } // Synthesize a key repeat if appropriate. if (mKeyRepeatState.lastKeyEntry) { if (currentTime >= mKeyRepeatState.nextRepeatTime) { mPendingEvent = synthesizeKeyRepeatLocked(currentTime); } else { if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) { *nextWakeupTime = mKeyRepeatState.nextRepeatTime; } } } // Nothing to do if there is no pending event. if (!mPendingEvent) { return; } } else { // Inbound queue has at least one entry. mPendingEvent = mInboundQueue.dequeueAtHead(); } // Get ready to dispatch the event. resetANRTimeoutsLocked(); } // Now we have an event to dispatch. // All events are eventually dequeued and processed this way, even if we intend to drop them. ALOG_ASSERT(mPendingEvent != NULL); bool done = false; DropReason dropReason = DROP_REASON_NOT_DROPPED; if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) { dropReason = DROP_REASON_POLICY; } else if (!mDispatchEnabled) { dropReason = DROP_REASON_DISABLED; } if (mNextUnblockedEvent == mPendingEvent) { mNextUnblockedEvent = NULL; } switch (mPendingEvent->type) { case EventEntry::TYPE_CONFIGURATION_CHANGED: { ConfigurationChangedEntry* typedEntry = static_cast(mPendingEvent); done = dispatchConfigurationChangedLocked(currentTime, typedEntry); dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped break; } case EventEntry::TYPE_DEVICE_RESET: { DeviceResetEntry* typedEntry = static_cast(mPendingEvent); done = dispatchDeviceResetLocked(currentTime, typedEntry); dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped break; } case EventEntry::TYPE_KEY: { KeyEntry* typedEntry = static_cast(mPendingEvent); if (isAppSwitchDue) { if (isAppSwitchKeyEventLocked(typedEntry)) { resetPendingAppSwitchLocked(true); isAppSwitchDue = false; } else if (dropReason == DROP_REASON_NOT_DROPPED) { dropReason = DROP_REASON_APP_SWITCH; } } if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEventLocked(currentTime, typedEntry)) { dropReason = DROP_REASON_STALE; } if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; } case EventEntry::TYPE_MOTION: { MotionEntry* typedEntry = static_cast(mPendingEvent); if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { dropReason = DROP_REASON_APP_SWITCH; } if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEventLocked(currentTime, typedEntry)) { dropReason = DROP_REASON_STALE; } if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { dropReason = DROP_REASON_BLOCKED; } done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); break; } default: ALOG_ASSERT(false); break; } if (done) { if (dropReason != DROP_REASON_NOT_DROPPED) { dropInboundEventLocked(mPendingEvent, dropReason); } releasePendingEventLocked(); *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately } } bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { bool needWake = mInboundQueue.isEmpty(); mInboundQueue.enqueueAtTail(entry); switch (entry->type) { case EventEntry::TYPE_KEY: { // Optimize app switch latency. // If the application takes too long to catch up then we drop all events preceding // the app switch key. KeyEntry* keyEntry = static_cast(entry); if (isAppSwitchKeyEventLocked(keyEntry)) { if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { mAppSwitchSawKeyDown = true; } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { if (mAppSwitchSawKeyDown) { #if DEBUG_APP_SWITCH ALOGD("App switch is pending!"); #endif mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; mAppSwitchSawKeyDown = false; needWake = true; } } } break; } case EventEntry::TYPE_MOTION: { // Optimize case where the current application is unresponsive and the user // decides to touch a window in a different application. // If the application takes too long to catch up then we drop all events preceding // the touch into the other window. MotionEntry* motionEntry = static_cast(entry); if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY && mInputTargetWaitApplicationHandle != NULL) { int32_t x = int32_t(motionEntry->pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(motionEntry->pointerCoords[0]. getAxisValue(AMOTION_EVENT_AXIS_Y)); sp touchedWindowHandle = findTouchedWindowAtLocked(x, y); if (touchedWindowHandle != NULL && touchedWindowHandle->inputApplicationHandle != mInputTargetWaitApplicationHandle) { // User touched a different application than the one we are waiting on. // Flag the event, and start pruning the input queue. mNextUnblockedEvent = motionEntry; needWake = true; } } break; } } return needWake; } sp InputDispatcher::findTouchedWindowAtLocked(int32_t x, int32_t y) { sp foundHandle = NULL; mEnumerator->for_each([&](sp windowHandle) { windowHandle->updateInfo(); const InputWindowInfo* windowInfo = windowHandle->getInfo(); int32_t flags = windowInfo->layoutParamsFlags; if (windowInfo->visible) { if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { // Found window. foundHandle = windowHandle; } } } if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) { foundHandle = NULL; } }); return foundHandle; } void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { const char* reason; switch (dropReason) { case DROP_REASON_POLICY: #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("Dropped event because policy consumed it."); #endif reason = "inbound event was dropped because the policy consumed it"; break; case DROP_REASON_DISABLED: ALOGI("Dropped event because input dispatch is disabled."); reason = "inbound event was dropped because input dispatch is disabled"; break; case DROP_REASON_APP_SWITCH: ALOGI("Dropped event because of pending overdue app switch."); reason = "inbound event was dropped because of pending overdue app switch"; break; case DROP_REASON_BLOCKED: ALOGI("Dropped event because the current application is not responding and the user " "has started interacting with a different application."); reason = "inbound event was dropped because the current application is not responding " "and the user has started interacting with a different application"; break; case DROP_REASON_STALE: ALOGI("Dropped event because it is stale."); reason = "inbound event was dropped because it is stale"; break; default: ALOG_ASSERT(false); return; } switch (entry->type) { case EventEntry::TYPE_KEY: { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); synthesizeCancelationEventsForAllConnectionsLocked(options); break; } case EventEntry::TYPE_MOTION: { MotionEntry* motionEntry = static_cast(entry); if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason); synthesizeCancelationEventsForAllConnectionsLocked(options); } else { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); synthesizeCancelationEventsForAllConnectionsLocked(options); } break; } } } bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) { return keyCode == AKEYCODE_HOME || keyCode == AKEYCODE_ENDCALL; } bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) { return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) && isAppSwitchKeyCode(keyEntry->keyCode) && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); } bool InputDispatcher::isAppSwitchPendingLocked() { return mAppSwitchDueTime != LONG_LONG_MAX; } void InputDispatcher::resetPendingAppSwitchLocked(bool handled) { mAppSwitchDueTime = LONG_LONG_MAX; #if DEBUG_APP_SWITCH if (handled) { ALOGD("App switch has arrived."); } else { ALOGD("App switch was abandoned."); } #endif } bool InputDispatcher::isStaleEventLocked(nsecs_t currentTime, EventEntry* entry) { return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT; } bool InputDispatcher::runCommandsLockedInterruptible() { if (mCommandQueue.isEmpty()) { return false; } do { CommandEntry* commandEntry = mCommandQueue.dequeueAtHead(); Command command = commandEntry->command; (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible' commandEntry->connection.clear(); delete commandEntry; } while (! mCommandQueue.isEmpty()); return true; } InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { CommandEntry* commandEntry = new CommandEntry(command); mCommandQueue.enqueueAtTail(commandEntry); return commandEntry; } void InputDispatcher::drainInboundQueueLocked() { while (! mInboundQueue.isEmpty()) { EventEntry* entry = mInboundQueue.dequeueAtHead(); releaseInboundEventLocked(entry); } } void InputDispatcher::releasePendingEventLocked() { if (mPendingEvent) { resetANRTimeoutsLocked(); releaseInboundEventLocked(mPendingEvent); mPendingEvent = NULL; } } void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) { InjectionState* injectionState = entry->injectionState; if (injectionState && injectionState->injectionResult == INPUT_EVENT_INJECTION_PENDING) { #if DEBUG_DISPATCH_CYCLE ALOGD("Injected inbound event was dropped."); #endif setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED); } if (entry == mNextUnblockedEvent) { mNextUnblockedEvent = NULL; } entry->release(); } void InputDispatcher::resetKeyRepeatLocked() { if (mKeyRepeatState.lastKeyEntry) { mKeyRepeatState.lastKeyEntry->release(); mKeyRepeatState.lastKeyEntry = NULL; } } InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { KeyEntry* entry = mKeyRepeatState.lastKeyEntry; // Reuse the repeated key entry if it is otherwise unreferenced. uint32_t policyFlags = (entry->policyFlags & POLICY_FLAG_RAW_MASK) | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED; if (entry->refCount == 1) { entry->recycle(); entry->eventTime = currentTime; entry->policyFlags = policyFlags; entry->repeatCount += 1; } else { KeyEntry* newEntry = new KeyEntry(currentTime, entry->deviceId, entry->source, policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount + 1, entry->downTime); mKeyRepeatState.lastKeyEntry = newEntry; entry->release(); entry = newEntry; } entry->syntheticRepeat = true; // Increment reference count since we keep a reference to the event in // mKeyRepeatState.lastKeyEntry in addition to the one we return. entry->refCount += 1; mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay; return entry; } bool InputDispatcher::dispatchConfigurationChangedLocked( nsecs_t currentTime, ConfigurationChangedEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("dispatchConfigurationChanged - eventTime=%lld", entry->eventTime); #endif // Reset key repeating in case a keyboard device was added or removed or something. resetKeyRepeatLocked(); // Enqueue a command to run outside the lock to tell the policy that the configuration changed. CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doNotifyConfigurationChangedInterruptible); commandEntry->eventTime = entry->eventTime; return true; } bool InputDispatcher::dispatchDeviceResetLocked( nsecs_t currentTime, DeviceResetEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("dispatchDeviceReset - eventTime=%lld, deviceId=%d", entry->eventTime, entry->deviceId); #endif CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "device was reset"); options.deviceId = entry->deviceId; synthesizeCancelationEventsForAllConnectionsLocked(options); return true; } bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { // Preprocessing. if (! entry->dispatchInProgress) { if (entry->repeatCount == 0 && entry->action == AKEY_EVENT_ACTION_DOWN && (entry->policyFlags & POLICY_FLAG_TRUSTED) && (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) { if (mKeyRepeatState.lastKeyEntry && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { // We have seen two identical key downs in a row which indicates that the device // driver is automatically generating key repeats itself. We take note of the // repeat here, but we disable our own next key repeat timer since it is clear that // we will not need to synthesize key repeats ourselves. entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1; resetKeyRepeatLocked(); mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves } else { // Not a repeat. Save key down state in case we do see a repeat later. resetKeyRepeatLocked(); mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout; } mKeyRepeatState.lastKeyEntry = entry; entry->refCount += 1; } else if (! entry->syntheticRepeat) { resetKeyRepeatLocked(); } if (entry->repeatCount == 1) { entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS; } else { entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS; } entry->dispatchInProgress = true; logOutboundKeyDetailsLocked("dispatchKey - ", entry); } // Handle case where the policy asked us to try again later last time. if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) { if (currentTime < entry->interceptKeyWakeupTime) { if (entry->interceptKeyWakeupTime < *nextWakeupTime) { *nextWakeupTime = entry->interceptKeyWakeupTime; } return false; // wait until next wakeup } entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; entry->interceptKeyWakeupTime = 0; } // Give the policy a chance to intercept the key. if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); if (mFocusedWindowHandle != NULL) { commandEntry->inputWindowHandle = mFocusedWindowHandle; } commandEntry->keyEntry = entry; entry->refCount += 1; return false; // wait for the command to run } else { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; } } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) { if (*dropReason == DROP_REASON_NOT_DROPPED) { *dropReason = DROP_REASON_POLICY; } } // Clean up if dropping the event. if (*dropReason != DROP_REASON_NOT_DROPPED) { setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); return true; } // Identify targets. Vector inputTargets; int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; } setInjectionResultLocked(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { return true; } addMonitoringTargetsLocked(inputTargets); // Dispatch the key. dispatchEventLocked(currentTime, entry, inputTargets); return true; } void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, " "repeatCount=%d, downTime=%lld", prefix, entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, entry->downTime); #endif } bool InputDispatcher::dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { // Preprocessing. if (! entry->dispatchInProgress) { entry->dispatchInProgress = true; logOutboundMotionDetailsLocked("dispatchMotion - ", entry); } // Clean up if dropping the event. if (*dropReason != DROP_REASON_NOT_DROPPED) { setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); return true; } bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER; // Identify targets. Vector inputTargets; bool conflictingPointerActions = false; int32_t injectionResult; if (isPointerEvent) { // Pointer event. (eg. touchscreen) injectionResult = findTouchedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime, &conflictingPointerActions); } else { // Non touch event. (eg. trackball) injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, inputTargets, nextWakeupTime); } if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { return false; } setInjectionResultLocked(entry, injectionResult); if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { return true; } addMonitoringTargetsLocked(inputTargets); // Dispatch the motion. if (conflictingPointerActions) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "conflicting pointer actions"); synthesizeCancelationEventsForAllConnectionsLocked(options); } dispatchEventLocked(currentTime, entry, inputTargets); return true; } void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, " "metaState=0x%x, buttonState=0x%x, " "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", prefix, entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, entry->action, entry->flags, entry->metaState, entry->buttonState, entry->edgeFlags, entry->xPrecision, entry->yPrecision, entry->downTime); for (uint32_t i = 0; i < entry->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " "x=%f, y=%f, pressure=%f, size=%f, " "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " "orientation=%f", i, entry->pointerProperties[i].id, entry->pointerProperties[i].toolType, entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } #endif } void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry, const Vector& inputTargets) { #if DEBUG_DISPATCH_CYCLE ALOGD("dispatchEventToCurrentInputTargets"); #endif ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true for (size_t i = 0; i < inputTargets.size(); i++) { const InputTarget& inputTarget = inputTargets.itemAt(i); ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); if (connectionIndex >= 0) { sp connection = mConnectionsByFd.valueAt(connectionIndex); prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); } else { #if DEBUG_FOCUS ALOGD("Dropping event delivery to target with channel '%s' because it " "is no longer registered with the input dispatcher.", c_str(inputTarget.inputChannel->getName())); #endif } } } int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, const sp& applicationHandle, const sp& windowHandle, nsecs_t* nextWakeupTime, const char* reason) { if (applicationHandle == NULL && windowHandle == NULL) { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) { #if DEBUG_FOCUS ALOGD("Waiting for system to become ready for input. Reason: %s", reason); #endif mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY; mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = LONG_LONG_MAX; mInputTargetWaitTimeoutExpired = false; mInputTargetWaitApplicationHandle.clear(); } } else { if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { #if DEBUG_FOCUS ALOGD("Waiting for application to become ready for input: %s. Reason: %s", c_str(getApplicationWindowLabelLocked(applicationHandle, windowHandle)), reason); #endif nsecs_t timeout; if (windowHandle != NULL) { timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else if (applicationHandle != NULL) { timeout = applicationHandle->getDispatchingTimeout( DEFAULT_INPUT_DISPATCHING_TIMEOUT); } else { timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; } mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY; mInputTargetWaitStartTime = currentTime; mInputTargetWaitTimeoutTime = currentTime + timeout; mInputTargetWaitTimeoutExpired = false; mInputTargetWaitApplicationHandle.clear(); if (windowHandle != NULL) { mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle; } if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) { mInputTargetWaitApplicationHandle = applicationHandle; } } } if (mInputTargetWaitTimeoutExpired) { return INPUT_EVENT_INJECTION_TIMED_OUT; } if (currentTime >= mInputTargetWaitTimeoutTime) { onANRLocked(currentTime, applicationHandle, windowHandle, entry->eventTime, mInputTargetWaitStartTime, reason); // Force poll loop to wake up immediately on next iteration once we get the // ANR response back from the policy. *nextWakeupTime = LONG_LONG_MIN; return INPUT_EVENT_INJECTION_PENDING; } else { // Force poll loop to wake up when timeout is due. if (mInputTargetWaitTimeoutTime < *nextWakeupTime) { *nextWakeupTime = mInputTargetWaitTimeoutTime; } return INPUT_EVENT_INJECTION_PENDING; } } void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, const sp& inputChannel) { if (newTimeout > 0) { // Extend the timeout. mInputTargetWaitTimeoutTime = now() + newTimeout; } else { // Give up. mInputTargetWaitTimeoutExpired = true; // Input state will not be realistic. Mark it out of sync. if (inputChannel.get()) { ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); if (connectionIndex >= 0) { sp connection = mConnectionsByFd.valueAt(connectionIndex); sp windowHandle = connection->inputWindowHandle; if (windowHandle != NULL) { mTouchState.removeWindow(windowHandle); } if (connection->status == Connection::STATUS_NORMAL) { CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "application not responding"); synthesizeCancelationEventsForConnectionLocked(connection, options); } } } } } nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked( nsecs_t currentTime) { if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { return currentTime - mInputTargetWaitStartTime; } return 0; } void InputDispatcher::resetANRTimeoutsLocked() { #if DEBUG_FOCUS ALOGD("Resetting ANR timeouts."); #endif // Reset input target wait timeout. mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; mInputTargetWaitApplicationHandle.clear(); } int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime) { int32_t injectionResult; // If there is no currently focused window and no focused application // then drop the event. if (mFocusedWindowHandle == NULL) { if (mFocusedApplicationHandle != NULL) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, NULL, nextWakeupTime, "Waiting because no window has focus but there is a " "focused application that may eventually add a window " "when it finishes starting up."); goto Unresponsive; } ALOGI("Dropping event because there is no focused window or focused application."); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } // Check permissions. if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) { injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; goto Failed; } // If the currently focused window is paused then keep waiting. if (mFocusedWindowHandle->getInfo()->paused) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, "Waiting because the focused window is paused."); goto Unresponsive; } // If the currently focused window is still working on previous events then keep waiting. if (!isWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry)) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, "Waiting because the focused window has not finished " "processing the input events that were previously delivered to it."); goto Unresponsive; } // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; addWindowTargetLocked(mFocusedWindowHandle, InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, IntSet(), inputTargets); // Done. Failed: Unresponsive: nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); updateDispatchStatisticsLocked(currentTime, entry, injectionResult, timeSpentWaitingForApplication); #if DEBUG_FOCUS ALOGD("findFocusedWindow finished: injectionResult=%d, " "timeSpentWaitingForApplication=%0.1fms", injectionResult, timeSpentWaitingForApplication / 1000000.0); #endif return injectionResult; } int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) { enum InjectionPermission { INJECTION_PERMISSION_UNKNOWN, INJECTION_PERMISSION_GRANTED, INJECTION_PERMISSION_DENIED }; nsecs_t startTime = now(); // For security reasons, we defer updating the touch state until we are sure that // event injection will be allowed. // // FIXME In the original code, screenWasOff could never be set to true. // The reason is that the POLICY_FLAG_WOKE_HERE // and POLICY_FLAG_BRIGHT_HERE flags were set only when preprocessing raw // EV_KEY, EV_REL and EV_ABS events. As it happens, the touch event was // actually enqueued using the policyFlags that appeared in the final EV_SYN // events upon which no preprocessing took place. So policyFlags was always 0. // In the new native input dispatcher we're a bit more careful about event // preprocessing so the touches we receive can actually have non-zero policyFlags. // Unfortunately we obtain undesirable behavior. // // Here's what happens: // // When the device dims in anticipation of going to sleep, touches // in windows which have FLAG_TOUCHABLE_WHEN_WAKING cause // the device to brighten and reset the user activity timer. // Touches on other windows (such as the launcher window) // are dropped. Then after a moment, the device goes to sleep. Oops. // // Also notice how screenWasOff was being initialized using POLICY_FLAG_BRIGHT_HERE // instead of POLICY_FLAG_WOKE_HERE... // bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE; int32_t action = entry->action; int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; // Update the touch state as needed based on the properties of the touch event. int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING; InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; sp newHoverWindowHandle; bool isSplit = mTouchState.split; bool switchedDevice = mTouchState.deviceId >= 0 && (mTouchState.deviceId != entry->deviceId || mTouchState.source != entry->source); bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN || maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction); bool wrongDevice = false; if (newGesture) { bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; if (switchedDevice && mTouchState.down && !down) { #if DEBUG_FOCUS ALOGD("Dropping event because a pointer for a different device is already down."); #endif mTempTouchState.copyFrom(mTouchState); injectionResult = INPUT_EVENT_INJECTION_FAILED; switchedDevice = false; wrongDevice = true; goto Failed; } mTempTouchState.reset(); mTempTouchState.down = down; mTempTouchState.deviceId = entry->deviceId; mTempTouchState.source = entry->source; isSplit = false; } else { mTempTouchState.copyFrom(mTouchState); } if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ int32_t pointerIndex = getMotionEventActionPointerIndex(action); int32_t x = int32_t(entry->pointerCoords[pointerIndex]. getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(entry->pointerCoords[pointerIndex]. getAxisValue(AMOTION_EVENT_AXIS_Y)); sp newTouchedWindowHandle = NULL; sp topErrorWindowHandle; bool isTouchModal = false; // Traverse windows from front to back to find touched window and outside targets. mEnumerator->for_each([&](sp const& windowHandle){ windowHandle->updateInfo(); const InputWindowInfo* windowInfo = windowHandle->getInfo(); int32_t flags = windowInfo->layoutParamsFlags; if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) { if (topErrorWindowHandle == NULL) { topErrorWindowHandle = windowHandle; } } if (windowInfo->visible) { if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { if (! screenWasOff || (flags & InputWindowInfo::FLAG_TOUCHABLE_WHEN_WAKING)) { newTouchedWindowHandle = windowHandle; } return; // found touched window, exit window loop } } if (maskedAction == AMOTION_EVENT_ACTION_DOWN && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) { int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE; if (isWindowObscuredAtPointLocked(windowHandle, x, y)) { outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } mTempTouchState.addOrUpdateWindow( windowHandle, outsideTargetFlags, IntSet()); } } }); // If there is an error window but it is not taking focus (typically because // it is invisible) then wait for it. Any other focused window may in // fact be in ANR state. if (topErrorWindowHandle != NULL && newTouchedWindowHandle != topErrorWindowHandle) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, NULL, NULL, nextWakeupTime, "Waiting because a system error window is about to be displayed."); injectionPermission = INJECTION_PERMISSION_UNKNOWN; goto Unresponsive; } // Figure out whether splitting will be allowed for this window. if (newTouchedWindowHandle != NULL && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { // New window supports splitting. isSplit = true; } else if (isSplit) { // New window does not support splitting but we have already split events. // Ignore the new window. newTouchedWindowHandle = NULL; } // Handle the case where we did not find a window. if (newTouchedWindowHandle == NULL) { // Try to assign the pointer to the first foreground window we find, if there is one. newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); if (newTouchedWindowHandle == NULL) { // There is no touched window. If this is an initial down event // then wait for a window to appear that will handle the touch. This is // to ensure that we report an ANR in the case where an application has started // but not yet put up a window and the user is starting to get impatient. if (maskedAction == AMOTION_EVENT_ACTION_DOWN && mFocusedApplicationHandle != NULL) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, NULL, nextWakeupTime, "Waiting because there is no touchable window that can " "handle the event but there is focused application that may " "eventually add a new window when it finishes starting up."); goto Unresponsive; } ALOGI("Dropping event because there is no touched window."); injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } } // Set target flags. int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS; if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; } if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } // Update hover state. if (isHoverAction) { newHoverWindowHandle = newTouchedWindowHandle; } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { newHoverWindowHandle = mLastHoverWindowHandle; } // Update the temporary touch state. IntSet pointerIds; if (isSplit) { int32_t pointerId = entry->pointerProperties[pointerIndex].id; pointerIds.insert(pointerId); } mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ // If the pointer is not currently down, then ignore the event. if (! mTempTouchState.down) { #if DEBUG_FOCUS ALOGD("Dropping event because the pointer is not down or we previously " "dropped the pointer down event."); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } // Check whether touches should slip outside of the current foreground window. if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry->pointerCount == 1 && mTempTouchState.isSlippery()) { int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); sp oldTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); sp newTouchedWindowHandle = findTouchedWindowAtLocked(x, y); if (oldTouchedWindowHandle != newTouchedWindowHandle && newTouchedWindowHandle != NULL) { #if DEBUG_FOCUS ALOGD("Touch is slipping out of window %s into window %s.", c_str(oldTouchedWindowHandle->getName()), c_str(newTouchedWindowHandle->getName())); #endif // Make a slippery exit from the old window. mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, IntSet()); // Make a slippery entrance into the new window. if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { isSplit = true; } int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER; if (isSplit) { targetFlags |= InputTarget::FLAG_SPLIT; } if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; } IntSet pointerIds; if (isSplit) { pointerIds.insert(entry->pointerProperties[0].id); } mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); } } } if (newHoverWindowHandle != mLastHoverWindowHandle) { // Let the previous window know that the hover sequence is over. if (mLastHoverWindowHandle != NULL) { #if DEBUG_HOVER ALOGD("Sending hover exit event to window %s.", c_str(mLastHoverWindowHandle->getName())); #endif mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, IntSet()); } // Let the new window know that the hover sequence is starting. if (newHoverWindowHandle != NULL) { #if DEBUG_HOVER ALOGD("Sending hover enter event to window %s.", c_str(newHoverWindowHandle->getName())); #endif mTempTouchState.addOrUpdateWindow(newHoverWindowHandle, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, IntSet()); } } // Check permission to inject into all touched foreground windows and ensure there // is at least one touched foreground window. { bool haveForegroundWindow = false; for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { haveForegroundWindow = true; if (! checkInjectionPermission(touchedWindow.windowHandle, entry->injectionState)) { injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; injectionPermission = INJECTION_PERMISSION_DENIED; goto Failed; } } } if (! haveForegroundWindow) { #if DEBUG_FOCUS ALOGD("Dropping event because there is no touched foreground window to receive it."); #endif injectionResult = INPUT_EVENT_INJECTION_FAILED; goto Failed; } // Permission granted to injection into all touched foreground windows. injectionPermission = INJECTION_PERMISSION_GRANTED; } // Check whether windows listening for outside touches are owned by the same UID. If it is // set the policy flag that we will not reveal coordinate information to this window. if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { sp foregroundWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid; for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { sp inputWindowHandle = touchedWindow.windowHandle; if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) { mTempTouchState.addOrUpdateWindow(inputWindowHandle, InputTarget::FLAG_ZERO_COORDS, IntSet()); } } } } // Ensure all touched foreground windows are ready for new input. for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { // If the touched window is paused then keep waiting. if (touchedWindow.windowHandle->getInfo()->paused) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, NULL, touchedWindow.windowHandle, nextWakeupTime, "Waiting because the touched window is paused."); goto Unresponsive; } // If the touched window is still working on previous events then keep waiting. if (!isWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, entry)) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, NULL, touchedWindow.windowHandle, nextWakeupTime, "Waiting because the touched window has not finished " "processing the input events that were previously delivered to it."); goto Unresponsive; } } } // If this is the first pointer going down and the touched window has a wallpaper // then also add the touched wallpaper windows so they are locked in for the duration // of the touch gesture. // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper // engine only supports touch events. We would need to add a mechanism similar // to View.onGenericMotionEvent to enable wallpapers to handle these events. // TODO: What does any of this mean? ~racarr if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { sp foregroundWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); if (foregroundWindowHandle->getInfo()->hasWallpaper) { mEnumerator->for_each([&](sp const& windowHandle){ if (windowHandle->getInfo()->layoutParamsType == InputWindowInfo::TYPE_WALLPAPER) { mTempTouchState.addOrUpdateWindow(windowHandle, InputTarget::FLAG_WINDOW_IS_OBSCURED | InputTarget::FLAG_DISPATCH_AS_IS, IntSet()); } }); } } // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i); addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, touchedWindow.pointerIds, inputTargets); } // Drop the outside or hover touch windows since we will not care about them // in the next iteration. mTempTouchState.filterNonAsIsTouchWindows(); Failed: // Check injection permission once and for all. if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) { if (checkInjectionPermission(NULL, entry->injectionState)) { injectionPermission = INJECTION_PERMISSION_GRANTED; } else { injectionPermission = INJECTION_PERMISSION_DENIED; } } // Update final pieces of touch state if the injector had permission. if (injectionPermission == INJECTION_PERMISSION_GRANTED) { if (!wrongDevice) { if (switchedDevice) { #if DEBUG_FOCUS ALOGD("Conflicting pointer actions: Switched to a different device."); #endif *outConflictingPointerActions = true; } if (isHoverAction) { // Started hovering, therefore no longer down. if (mTouchState.down) { #if DEBUG_FOCUS ALOGD("Conflicting pointer actions: Hover received while pointer was down."); #endif *outConflictingPointerActions = true; } mTouchState.reset(); if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { mTouchState.deviceId = entry->deviceId; mTouchState.source = entry->source; } } else if (maskedAction == AMOTION_EVENT_ACTION_UP || maskedAction == AMOTION_EVENT_ACTION_CANCEL) { // All pointers up or canceled. mTouchState.reset(); } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { // First pointer went down. if (mTouchState.down) { #if DEBUG_FOCUS ALOGD("Conflicting pointer actions: Down received while already down."); #endif *outConflictingPointerActions = true; } mTouchState.copyFrom(mTempTouchState); } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { // One pointer went up. if (isSplit) { int32_t pointerIndex = getMotionEventActionPointerIndex(action); int32_t pointerId = entry->pointerProperties[pointerIndex].id; for (size_t i = 0; i < mTempTouchState.windows.size(); ) { TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i); if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) { touchedWindow.pointerIds.remove(pointerId); if (touchedWindow.pointerIds.isEmpty()) { mTempTouchState.windows.removeAt(i); continue; } } i += 1; } } mTouchState.copyFrom(mTempTouchState); } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { // Discard temporary touch state since it was only valid for this action. } else { // Save changes to touch state as-is for all other actions. mTouchState.copyFrom(mTempTouchState); } // Update hover state. mLastHoverWindowHandle = newHoverWindowHandle; } } else { #if DEBUG_FOCUS ALOGD("Not updating touch focus because injection was denied."); #endif } Unresponsive: // Reset temporary touch state to ensure we release unnecessary references to input channels. mTempTouchState.reset(); nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); updateDispatchStatisticsLocked(currentTime, entry, injectionResult, timeSpentWaitingForApplication); #if DEBUG_FOCUS ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, " "timeSpentWaitingForApplication=%0.1fms", injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0); #endif return injectionResult; } void InputDispatcher::addWindowTargetLocked(const sp& windowHandle, int32_t targetFlags, const IntSet &pointerIds, Vector& inputTargets) { inputTargets.push(); const InputWindowInfo* windowInfo = windowHandle->getInfo(); InputTarget& target = inputTargets.editTop(); target.inputChannel = windowInfo->inputChannel; target.flags = targetFlags; target.xOffset = - windowInfo->frameLeft; target.yOffset = - windowInfo->frameTop; target.scaleFactor = windowInfo->scaleFactor; target.pointerIds = pointerIds; } namespace { static inline bool targets_contains_channel(Vector const& input_targets, sp const& channel) { for (size_t i = 0; i < input_targets.size(); i++) { auto target = input_targets[i]; if (target.inputChannel == channel) return true; } return false; } } void InputDispatcher::addMonitoringTargetsLocked(Vector& inputTargets) { for (size_t i = 0; i < mMonitoringChannels.size(); i++) { if (targets_contains_channel(inputTargets, mMonitoringChannels[i])) continue; inputTargets.push(); InputTarget& target = inputTargets.editTop(); target.inputChannel = mMonitoringChannels[i]; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; target.xOffset = 0; target.yOffset = 0; target.pointerIds.clear(); target.scaleFactor = 1.0f; } } bool InputDispatcher::checkInjectionPermission(const sp& windowHandle, const InjectionState* injectionState) { if (injectionState && (windowHandle == NULL || windowHandle->getInfo()->ownerUid != injectionState->injectorUid) && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { if (windowHandle != NULL) { ALOGW("Permission denied: injecting event from pid %d uid %d to window %s " "owned by uid %d", injectionState->injectorPid, injectionState->injectorUid, c_str(windowHandle->getName()), windowHandle->getInfo()->ownerUid); } else { ALOGW("Permission denied: injecting event from pid %d uid %d", injectionState->injectorPid, injectionState->injectorUid); } return false; } return true; } bool InputDispatcher::isWindowObscuredAtPointLocked( const sp& windowHandle, int32_t x, int32_t y) const { bool obscured = false; bool seen_handle = false; mEnumerator->for_each([&](sp const& otherHandle){ if (otherHandle == windowHandle) { seen_handle = true; return; } if (seen_handle) { const InputWindowInfo* otherInfo = otherHandle->getInfo(); if (otherInfo->visible && ! otherInfo->isTrustedOverlay() && otherInfo->frameContainsPoint(x, y)) { obscured = true; } } }); return obscured; } bool InputDispatcher::isWindowReadyForMoreInputLocked(nsecs_t currentTime, const sp& windowHandle, const EventEntry* eventEntry) { ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel()); if (connectionIndex >= 0) { sp connection = mConnectionsByFd.valueAt(connectionIndex); if (connection->inputPublisherBlocked) { return false; } if (eventEntry->type == EventEntry::TYPE_KEY) { // If the event is a key event, then we must wait for all previous events to // complete before delivering it because previous events may have the // side-effect of transferring focus to a different window and we want to // ensure that the following keys are sent to the new window. // // Suppose the user touches a button in a window then immediately presses "A". // If the button causes a pop-up window to appear then we want to ensure that // the "A" key is delivered to the new pop-up window. This is because users // often anticipate pending UI changes when typing on a keyboard. // To obtain this behavior, we must serialize key events with respect to all // prior input events. return connection->outboundQueue.isEmpty() && connection->waitQueue.isEmpty(); } // Touch events can always be sent to a window immediately because the user intended // to touch whatever was visible at the time. Even if focus changes or a new // window appears moments later, the touch event was meant to be delivered to // whatever window happened to be on screen at the time. // // Generic motion events, such as trackball or joystick events are a little trickier. // Like key events, generic motion events are delivered to the focused window. // Unlike key events, generic motion events don't tend to transfer focus to other // windows and it is not important for them to be serialized. So we prefer to deliver // generic motion events as soon as possible to improve efficiency and reduce lag // through batching. // // The one case where we pause input event delivery is when the wait queue is piling // up with lots of events because the application is not responding. // This condition ensures that ANRs are detected reliably. if (!connection->waitQueue.isEmpty() && currentTime >= connection->waitQueue.head->eventEntry->eventTime + STREAM_AHEAD_EVENT_TIMEOUT) { return false; } } return true; } String8 InputDispatcher::getApplicationWindowLabelLocked( const sp& applicationHandle, const sp& windowHandle) { if (applicationHandle != NULL) { if (windowHandle != NULL) { String8 label(applicationHandle->getName()); label.append(" - "); label.append(windowHandle->getName()); return label; } else { return applicationHandle->getName(); } } else if (windowHandle != NULL) { return windowHandle->getName(); } else { return String8(""); } } void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { #if DEBUG_DISPATCH_CYCLE std::string pointerIdsString = inputTarget->pointerIds.toString(); ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, " "xOffset=%f, yOffset=%f, scaleFactor=%f, " "pointerIds=%s", connection->getInputChannelName(), inputTarget->flags, inputTarget->xOffset, inputTarget->yOffset, inputTarget->scaleFactor, pointerIdsString.c_str()); #endif // Skip this event if the connection status is not normal. // We don't want to enqueue additional outbound events if the connection is broken. if (connection->status != Connection::STATUS_NORMAL) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Dropping event because the channel status is %s", connection->getInputChannelName(), connection->getStatusLabel()); #endif return; } // Split a motion event if needed. if (inputTarget->flags & InputTarget::FLAG_SPLIT) { ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION); MotionEntry* originalMotionEntry = static_cast(eventEntry); if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) { MotionEntry* splitMotionEntry = splitMotionEvent( originalMotionEntry, inputTarget->pointerIds); if (!splitMotionEntry) { return; // split event was dropped } #if DEBUG_FOCUS ALOGD("channel '%s' ~ Split motion event.", connection->getInputChannelName()); logOutboundMotionDetailsLocked(" ", splitMotionEntry); #endif enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget); splitMotionEntry->release(); return; } } // Not splitting. Enqueue dispatch entries for the event as is. enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget); } void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { bool wasEmpty = connection->outboundQueue.isEmpty(); // Enqueue dispatch entries for the requested modes. enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_OUTSIDE); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_IS); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); // If the outbound queue was previously empty, start the dispatch cycle going. if (wasEmpty && !connection->outboundQueue.isEmpty()) { startDispatchCycleLocked(currentTime, connection); } } void InputDispatcher::enqueueDispatchEntryLocked( const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode) { int32_t inputTargetFlags = inputTarget->flags; if (!(inputTargetFlags & dispatchMode)) { return; } inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode; // This is a new event. // Enqueue a new dispatch entry onto the outbound queue for this connection. DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, inputTarget->scaleFactor); // Apply target flags and update the connection's input state. switch (eventEntry->type) { case EventEntry::TYPE_KEY: { KeyEntry* keyEntry = static_cast(eventEntry); dispatchEntry->resolvedAction = keyEntry->action; dispatchEntry->resolvedFlags = keyEntry->flags; if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event", connection->getInputChannelName()); #endif delete dispatchEntry; return; // skip the inconsistent event } break; } case EventEntry::TYPE_MOTION: { MotionEntry* motionEntry = static_cast(eventEntry); if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE; } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT; } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) { dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL; } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) { dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN; } else { dispatchEntry->resolvedAction = motionEntry->action; } if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE && !connection->inputState.isHovering( motionEntry->deviceId, motionEntry->source)) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event", connection->getInputChannelName()); #endif dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; } dispatchEntry->resolvedFlags = motionEntry->flags; if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; } if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event", connection->getInputChannelName()); #endif delete dispatchEntry; return; // skip the inconsistent event } break; } } // Remember that we are waiting for this dispatch to complete. if (dispatchEntry->hasForegroundTarget()) { incrementPendingForegroundDispatchesLocked(eventEntry); } // Enqueue the dispatch entry. connection->outboundQueue.enqueueAtTail(dispatchEntry); } void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const sp& connection) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName()); #endif while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.isEmpty()) { DispatchEntry* dispatchEntry = connection->outboundQueue.head; dispatchEntry->deliveryTime = currentTime; // Publish the event. status_t status; EventEntry* eventEntry = dispatchEntry->eventEntry; switch (eventEntry->type) { case EventEntry::TYPE_KEY: { KeyEntry* keyEntry = static_cast(eventEntry); // Publish the key event. status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId, keyEntry->source, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, keyEntry->keyCode, keyEntry->scanCode, keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, keyEntry->eventTime); input_report->published_key_event(connection->inputChannel->getFd(), dispatchEntry->seq, keyEntry->eventTime); break; } case EventEntry::TYPE_MOTION: { MotionEntry* motionEntry = static_cast(eventEntry); PointerCoords scaledCoords[MAX_POINTERS]; const PointerCoords* usingCoords = motionEntry->pointerCoords; // Set the X and Y offset depending on the input source. float xOffset, yOffset, scaleFactor; if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { scaleFactor = dispatchEntry->scaleFactor; xOffset = dispatchEntry->xOffset * scaleFactor; yOffset = dispatchEntry->yOffset * scaleFactor; if (scaleFactor != 1.0f) { for (size_t i = 0; i < motionEntry->pointerCount; i++) { scaledCoords[i] = motionEntry->pointerCoords[i]; scaledCoords[i].scale(scaleFactor); } usingCoords = scaledCoords; } } else { xOffset = 0.0f; yOffset = 0.0f; scaleFactor = 1.0f; // We don't want the dispatch target to know. if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { for (size_t i = 0; i < motionEntry->pointerCount; i++) { scaledCoords[i].clear(); } usingCoords = scaledCoords; } } // Publish the motion event. status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId, motionEntry->source, dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState, xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision, motionEntry->downTime, motionEntry->eventTime, motionEntry->pointerCount, motionEntry->pointerProperties, usingCoords); input_report->published_motion_event(connection->inputChannel->getFd(), dispatchEntry->seq, motionEntry->eventTime); break; } default: ALOG_ASSERT(false); return; } // Check the result. if (status) { if (status == WOULD_BLOCK) { if (connection->waitQueue.isEmpty()) { ALOGE("channel '%s' ~ Could not publish event because the pipe is full. " "This is unexpected because the wait queue is empty, so the pipe " "should be empty and we shouldn't have any problems writing an " "event to it, status=%d", connection->getInputChannelName(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } else { // Pipe is full and we are waiting for the app to finish process some events // before sending more events to it. #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ Could not publish event because the pipe is full, " "waiting for the application to catch up", connection->getInputChannelName()); #endif connection->inputPublisherBlocked = true; } } else { ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, " "status=%d", connection->getInputChannelName(), status); abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); } return; } // Re-enqueue the event on the wait queue. connection->outboundQueue.dequeue(dispatchEntry); connection->waitQueue.enqueueAtTail(dispatchEntry); } } void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s", connection->getInputChannelName(), seq, toString(handled)); #endif connection->inputPublisherBlocked = false; if (connection->status == Connection::STATUS_BROKEN || connection->status == Connection::STATUS_ZOMBIE) { return; } // Notify other system components and prepare to start the next dispatch cycle. onDispatchCycleFinishedLocked(currentTime, connection, seq, handled); } void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp& connection, bool notify) { #if DEBUG_DISPATCH_CYCLE ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s", connection->getInputChannelName(), toString(notify)); #endif // Clear the dispatch queues. drainDispatchQueueLocked(&connection->outboundQueue); drainDispatchQueueLocked(&connection->waitQueue); // The connection appears to be unrecoverably broken. // Ignore already broken or zombie connections. if (connection->status == Connection::STATUS_NORMAL) { connection->status = Connection::STATUS_BROKEN; if (notify) { // Notify other system components. onDispatchCycleBrokenLocked(currentTime, connection); } } } void InputDispatcher::drainDispatchQueueLocked(Queue* queue) { while (!queue->isEmpty()) { DispatchEntry* dispatchEntry = queue->dequeueAtHead(); releaseDispatchEntryLocked(dispatchEntry); } } void InputDispatcher::releaseDispatchEntryLocked(DispatchEntry* dispatchEntry) { if (dispatchEntry->hasForegroundTarget()) { decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry); } delete dispatchEntry; } int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { InputDispatcher* d = static_cast(data); { // acquire lock AutoMutex _l(d->mLock); ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd); if (connectionIndex < 0) { ALOGE("Received spurious receive callback for unknown input channel. " "fd=%d, events=0x%x", fd, events); return 0; // remove the callback } bool notify; sp connection = d->mConnectionsByFd.valueAt(connectionIndex); if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) { if (!(events & ALOOPER_EVENT_INPUT)) { ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " "events=0x%x", connection->getInputChannelName(), events); return 1; } nsecs_t currentTime = now(); bool gotOne = false; status_t status; for (;;) { uint32_t seq; bool handled; status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled); if (status) { break; } d->input_report->received_event_finished_signal(connection->inputChannel->getFd(), seq); d->finishDispatchCycleLocked(currentTime, connection, seq, handled); gotOne = true; } if (gotOne) { d->runCommandsLockedInterruptible(); if (status == WOULD_BLOCK) { return 1; } } notify = status != DEAD_OBJECT || !connection->monitor; if (notify) { ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d", connection->getInputChannelName(), status); } } else { // Monitor channels are never explicitly unregistered. // We do it automatically when the remote endpoint is closed so don't warn // about them. notify = !connection->monitor; if (notify) { ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. " "events=0x%x", connection->getInputChannelName(), events); } } // Unregister the channel. d->unregisterInputChannelLocked(connection->inputChannel, notify); return 0; // remove the callback } // release lock } void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( const CancelationOptions& options) { for (size_t i = 0; i < mConnectionsByFd.size(); i++) { synthesizeCancelationEventsForConnectionLocked( mConnectionsByFd.valueAt(i), options); } } void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( const sp& channel, const CancelationOptions& options) { ssize_t index = getConnectionIndexLocked(channel); if (index >= 0) { synthesizeCancelationEventsForConnectionLocked( mConnectionsByFd.valueAt(index), options); } } void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( const sp& connection, const CancelationOptions& options) { if (connection->status == Connection::STATUS_BROKEN) { return; } nsecs_t currentTime = now(); Vector cancelationEvents; connection->inputState.synthesizeCancelationEvents(currentTime, cancelationEvents, options); if (!cancelationEvents.isEmpty()) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync " "with reality: %s, mode=%d.", connection->getInputChannelName(), cancelationEvents.size(), options.reason, options.mode); #endif for (size_t i = 0; i < cancelationEvents.size(); i++) { EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i); switch (cancelationEventEntry->type) { case EventEntry::TYPE_KEY: logOutboundKeyDetailsLocked("cancel - ", static_cast(cancelationEventEntry)); break; case EventEntry::TYPE_MOTION: logOutboundMotionDetailsLocked("cancel - ", static_cast(cancelationEventEntry)); break; } InputTarget target; sp windowHandle = getWindowHandleLocked(connection->inputChannel); if (windowHandle != NULL) { const InputWindowInfo* windowInfo = windowHandle->getInfo(); target.xOffset = -windowInfo->frameLeft; target.yOffset = -windowInfo->frameTop; target.scaleFactor = windowInfo->scaleFactor; } else { target.xOffset = 0; target.yOffset = 0; target.scaleFactor = 1.0f; } target.inputChannel = connection->inputChannel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref &target, InputTarget::FLAG_DISPATCH_AS_IS); cancelationEventEntry->release(); } startDispatchCycleLocked(currentTime, connection); } } InputDispatcher::MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, const IntSet &pointerIds) { ALOG_ASSERT(!pointerIds.isEmpty()); uint32_t splitPointerIndexMap[MAX_POINTERS]; PointerProperties splitPointerProperties[MAX_POINTERS]; PointerCoords splitPointerCoords[MAX_POINTERS]; uint32_t originalPointerCount = originalMotionEntry->pointerCount; uint32_t splitPointerCount = 0; for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount; originalPointerIndex++) { const PointerProperties& pointerProperties = originalMotionEntry->pointerProperties[originalPointerIndex]; uint32_t pointerId = uint32_t(pointerProperties.id); if (pointerIds.contains(pointerId)) { splitPointerIndexMap[splitPointerCount] = originalPointerIndex; splitPointerProperties[splitPointerCount].copyFrom(pointerProperties); splitPointerCoords[splitPointerCount].copyFrom( originalMotionEntry->pointerCoords[originalPointerIndex]); splitPointerCount += 1; } } if (splitPointerCount != pointerIds.count()) { // This is bad. We are missing some of the pointers that we expected to deliver. // Most likely this indicates that we received an ACTION_MOVE events that has // different pointer ids than we expected based on the previous ACTION_DOWN // or ACTION_POINTER_DOWN events that caused us to decide to split the pointers // in this way. ALOGW("Dropping split motion event because the pointer count is %d but " "we expected there to be %d pointers. This probably means we received " "a broken sequence of pointer ids from the input device.", splitPointerCount, pointerIds.count()); return NULL; } int32_t action = originalMotionEntry->action; int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { int32_t originalPointerIndex = getMotionEventActionPointerIndex(action); const PointerProperties& pointerProperties = originalMotionEntry->pointerProperties[originalPointerIndex]; int32_t pointerId = pointerProperties.id; if (pointerIds.contains(pointerId)) { if (pointerIds.count() == 1) { // The first/last pointer went down/up. action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; } else { // A secondary pointer went down/up. uint32_t splitPointerIndex = 0; while (pointerId != splitPointerProperties[splitPointerIndex].id) { splitPointerIndex += 1; } action = maskedAction | (splitPointerIndex << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); } } else { // An unrelated pointer changed. action = AMOTION_EVENT_ACTION_MOVE; } } MotionEntry* splitMotionEntry = new MotionEntry( originalMotionEntry->eventTime, originalMotionEntry->deviceId, originalMotionEntry->source, originalMotionEntry->policyFlags, action, originalMotionEntry->flags, originalMotionEntry->metaState, originalMotionEntry->buttonState, originalMotionEntry->edgeFlags, originalMotionEntry->xPrecision, originalMotionEntry->yPrecision, originalMotionEntry->downTime, splitPointerCount, splitPointerProperties, splitPointerCoords); if (originalMotionEntry->injectionState) { splitMotionEntry->injectionState = originalMotionEntry->injectionState; splitMotionEntry->injectionState->refCount += 1; } return splitMotionEntry; } void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyConfigurationChanged - eventTime=%lld", args->eventTime); #endif bool needWake; { // acquire lock AutoMutex _l(mLock); ConfigurationChangedEntry* newEntry = new ConfigurationChangedEntry(args->eventTime); needWake = enqueueInboundEventLocked(newEntry); } // release lock if (needWake) { mLooper->wake(); } } void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, " "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld", args->eventTime, args->deviceId, args->source, args->policyFlags, args->action, args->flags, args->keyCode, args->scanCode, args->metaState, args->downTime); #endif if (!validateKeyEvent(args->action)) { return; } uint32_t policyFlags = args->policyFlags; int32_t flags = args->flags; int32_t metaState = args->metaState; if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) { policyFlags |= POLICY_FLAG_VIRTUAL; flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; } if (policyFlags & POLICY_FLAG_ALT) { metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON; } if (policyFlags & POLICY_FLAG_ALT_GR) { metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON; } if (policyFlags & POLICY_FLAG_SHIFT) { metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON; } if (policyFlags & POLICY_FLAG_CAPS_LOCK) { metaState |= AMETA_CAPS_LOCK_ON; } if (policyFlags & POLICY_FLAG_FUNCTION) { metaState |= AMETA_FUNCTION_ON; } policyFlags |= POLICY_FLAG_TRUSTED; KeyEvent event; event.initialize(args->deviceId, args->source, args->action, flags, args->keyCode, args->scanCode, metaState, 0, args->downTime, args->eventTime); mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); if (policyFlags & POLICY_FLAG_WOKE_HERE) { flags |= AKEY_EVENT_FLAG_WOKE_HERE; } bool needWake; { // acquire lock mLock.lock(); if (mInputFilterEnabled) { mLock.unlock(); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { return; // event was consumed by the filter } mLock.lock(); } int32_t repeatCount = 0; KeyEntry* newEntry = new KeyEntry(args->eventTime, args->deviceId, args->source, policyFlags, args->action, flags, args->keyCode, args->scanCode, metaState, repeatCount, args->downTime); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); } // release lock if (needWake) { mLooper->wake(); } } void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " "action=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, edgeFlags=0x%x, " "xPrecision=%f, yPrecision=%f, downTime=%lld", args->eventTime, args->deviceId, args->source, args->policyFlags, args->action, args->flags, args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); for (uint32_t i = 0; i < args->pointerCount; i++) { ALOGD(" Pointer %d: id=%d, toolType=%d, " "x=%f, y=%f, pressure=%f, size=%f, " "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " "orientation=%f", i, args->pointerProperties[i].id, args->pointerProperties[i].toolType, args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); } #endif if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) { return; } uint32_t policyFlags = args->policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags); bool needWake; { // acquire lock mLock.lock(); if (mInputFilterEnabled) { mLock.unlock(); MotionEvent event; event.initialize(args->deviceId, args->source, args->action, args->flags, args->edgeFlags, args->metaState, args->buttonState, 0, 0, args->xPrecision, args->yPrecision, args->downTime, args->eventTime, args->pointerCount, args->pointerProperties, args->pointerCoords); policyFlags |= POLICY_FLAG_FILTERED; if (!mPolicy->filterInputEvent(&event, policyFlags)) { return; // event was consumed by the filter } mLock.lock(); } // Just enqueue a new motion event. MotionEntry* newEntry = new MotionEntry(args->eventTime, args->deviceId, args->source, policyFlags, args->action, args->flags, args->metaState, args->buttonState, args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, args->pointerCount, args->pointerProperties, args->pointerCoords); needWake = enqueueInboundEventLocked(newEntry); mLock.unlock(); } // release lock if (needWake) { mLooper->wake(); } } void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchCode=%d, switchValue=%d", args->eventTime, args->policyFlags, args->switchCode, args->switchValue); #endif uint32_t policyFlags = args->policyFlags; policyFlags |= POLICY_FLAG_TRUSTED; mPolicy->notifySwitch(args->eventTime, args->switchCode, args->switchValue, policyFlags); } void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("notifyDeviceReset - eventTime=%lld, deviceId=%d", args->eventTime, args->deviceId); #endif bool needWake; { // acquire lock AutoMutex _l(mLock); DeviceResetEntry* newEntry = new DeviceResetEntry(args->eventTime, args->deviceId); needWake = enqueueInboundEventLocked(newEntry); } // release lock if (needWake) { mLooper->wake(); } } int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) { #if DEBUG_INBOUND_EVENT_DETAILS ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); #endif nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); policyFlags |= POLICY_FLAG_INJECTED; if (hasInjectionPermission(injectorPid, injectorUid)) { policyFlags |= POLICY_FLAG_TRUSTED; } EventEntry* firstInjectedEntry; EventEntry* lastInjectedEntry; switch (event->getType()) { case AINPUT_EVENT_TYPE_KEY: { const KeyEvent* keyEvent = static_cast(event); int32_t action = keyEvent->getAction(); if (! validateKeyEvent(action)) { return INPUT_EVENT_INJECTION_FAILED; } int32_t flags = keyEvent->getFlags(); if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { policyFlags |= POLICY_FLAG_VIRTUAL; } if (!(policyFlags & POLICY_FLAG_FILTERED)) { mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags); } if (policyFlags & POLICY_FLAG_WOKE_HERE) { flags |= AKEY_EVENT_FLAG_WOKE_HERE; } mLock.lock(); firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(), keyEvent->getDeviceId(), keyEvent->getSource(), policyFlags, action, flags, keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(), keyEvent->getRepeatCount(), keyEvent->getDownTime()); lastInjectedEntry = firstInjectedEntry; break; } case AINPUT_EVENT_TYPE_MOTION: { const MotionEvent* motionEvent = static_cast(event); int32_t action = motionEvent->getAction(); size_t pointerCount = motionEvent->getPointerCount(); const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); if (! validateMotionEvent(action, pointerCount, pointerProperties)) { return INPUT_EVENT_INJECTION_FAILED; } if (!(policyFlags & POLICY_FLAG_FILTERED)) { nsecs_t eventTime = motionEvent->getEventTime(); mPolicy->interceptMotionBeforeQueueing(eventTime, /*byref*/ policyFlags); } mLock.lock(); const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); firstInjectedEntry = new MotionEntry(*sampleEventTimes, motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, action, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), motionEvent->getYPrecision(), motionEvent->getDownTime(), uint32_t(pointerCount), pointerProperties, samplePointerCoords); lastInjectedEntry = firstInjectedEntry; for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { sampleEventTimes += 1; samplePointerCoords += pointerCount; MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes, motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, action, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), motionEvent->getEdgeFlags(), motionEvent->getXPrecision(), motionEvent->getYPrecision(), motionEvent->getDownTime(), uint32_t(pointerCount), pointerProperties, samplePointerCoords); lastInjectedEntry->next = nextInjectedEntry; lastInjectedEntry = nextInjectedEntry; } break; } default: ALOGW("Cannot inject event of type %d", event->getType()); return INPUT_EVENT_INJECTION_FAILED; } InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { injectionState->injectionIsAsync = true; } injectionState->refCount += 1; lastInjectedEntry->injectionState = injectionState; bool needWake = false; for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) { EventEntry* nextEntry = entry->next; needWake |= enqueueInboundEventLocked(entry); entry = nextEntry; } mLock.unlock(); if (needWake) { mLooper->wake(); } int32_t injectionResult; { // acquire lock AutoMutex _l(mLock); if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; } else { for (;;) { injectionResult = injectionState->injectionResult; if (injectionResult != INPUT_EVENT_INJECTION_PENDING) { break; } nsecs_t remainingTimeout = endTime - now(); if (remainingTimeout <= 0) { #if DEBUG_INJECTION ALOGD("injectInputEvent - Timed out waiting for injection result " "to become available."); #endif injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; break; } waitRelative(mInjectionResultAvailableCondition, mLock, remainingTimeout); } if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) { while (injectionState->pendingForegroundDispatches != 0) { #if DEBUG_INJECTION ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.", injectionState->pendingForegroundDispatches); #endif nsecs_t remainingTimeout = endTime - now(); if (remainingTimeout <= 0) { #if DEBUG_INJECTION ALOGD("injectInputEvent - Timed out waiting for pending foreground " "dispatches to finish."); #endif injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; break; } waitRelative(mInjectionSyncFinishedCondition, mLock, remainingTimeout); } } } injectionState->release(); } // release lock #if DEBUG_INJECTION ALOGD("injectInputEvent - Finished with result %d. " "injectorPid=%d, injectorUid=%d", injectionResult, injectorPid, injectorUid); #endif return injectionResult; } bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { return injectorUid == 0 || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); } void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) { InjectionState* injectionState = entry->injectionState; if (injectionState) { #if DEBUG_INJECTION ALOGD("Setting input event injection result to %d. " "injectorPid=%d, injectorUid=%d", injectionResult, injectionState->injectorPid, injectionState->injectorUid); #endif if (injectionState->injectionIsAsync && !(entry->policyFlags & POLICY_FLAG_FILTERED)) { // Log the outcome since the injector did not wait for the injection result. switch (injectionResult) { case INPUT_EVENT_INJECTION_SUCCEEDED: ALOGV("Asynchronous input event injection succeeded."); break; case INPUT_EVENT_INJECTION_FAILED: ALOGW("Asynchronous input event injection failed."); break; case INPUT_EVENT_INJECTION_PERMISSION_DENIED: ALOGW("Asynchronous input event injection permission denied."); break; case INPUT_EVENT_INJECTION_TIMED_OUT: ALOGW("Asynchronous input event injection timed out."); break; } } injectionState->injectionResult = injectionResult; broadcast(mInjectionResultAvailableCondition); } } void InputDispatcher::incrementPendingForegroundDispatchesLocked(EventEntry* entry) { InjectionState* injectionState = entry->injectionState; if (injectionState) { injectionState->pendingForegroundDispatches += 1; } } void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* entry) { InjectionState* injectionState = entry->injectionState; if (injectionState) { injectionState->pendingForegroundDispatches -= 1; if (injectionState->pendingForegroundDispatches == 0) { broadcast(mInjectionSyncFinishedCondition); } } } sp InputDispatcher::getWindowHandleLocked( const sp& inputChannel) const { sp foundHandle = NULL; mEnumerator->for_each([&](sp const& windowHandle){ if (windowHandle->getInputChannel() == inputChannel) { foundHandle = windowHandle; } }); return foundHandle; } bool InputDispatcher::hasWindowHandleLocked( const sp& windowHandle) const { bool found_handle = false; mEnumerator->for_each([&](sp const& otherHandle){ if (otherHandle == windowHandle) { found_handle = true; } }); return found_handle; } void InputDispatcher::setKeyboardFocus(const sp& newFocusedWindowHandle) { #if DEBUG_FOCUS ALOGD("setKeyboardFocus"); #endif { AutoMutex _l(mLock); setKeyboardFocusLocked(newFocusedWindowHandle); } mLooper->wake(); } void InputDispatcher::setKeyboardFocusLocked(const sp& newFocusedWindowHandle) { if (mFocusedWindowHandle != newFocusedWindowHandle) { if (mFocusedWindowHandle != NULL) { #if DEBUG_FOCUS ALOGD("Focus left window: %s", c_str(mFocusedWindowHandle->getName())); #endif sp focusedInputChannel = mFocusedWindowHandle->getInputChannel(); if (focusedInputChannel != NULL) { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, "focus left window"); synthesizeCancelationEventsForInputChannelLocked( focusedInputChannel, options); } } if (newFocusedWindowHandle != NULL) { #if DEBUG_FOCUS ALOGD("Focus entered window: %s", c_str(newFocusedWindowHandle->getName())); #endif } if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_NONE) { releasePendingEventLocked(); drainInboundQueueLocked(); } mFocusedWindowHandle = newFocusedWindowHandle; } } void InputDispatcher::notifyWindowRemoved(const sp& windowHandle) { #if DEBUG_FOCUS ALOGD("notifyWindowRemoved"); #endif { // acquire lock AutoMutex _l(mLock); if (windowHandle == mLastHoverWindowHandle) mLastHoverWindowHandle = NULL; for (size_t i = 0; i < mTouchState.windows.size(); i++) { TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i); if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { #if DEBUG_FOCUS ALOGD("Touched window was removed: %s", c_str(touchedWindow.windowHandle->getName())); #endif sp touchedInputChannel = touchedWindow.windowHandle->getInputChannel(); if (touchedInputChannel != NULL) { CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "touched window was removed"); synthesizeCancelationEventsForInputChannelLocked( touchedInputChannel, options); } mTouchState.windows.removeAt(i--); } } if (windowHandle == mFocusedWindowHandle) setKeyboardFocusLocked(NULL); } // release lock mLooper->wake(); } void InputDispatcher::setFocusedApplication( const sp& inputApplicationHandle) { #if DEBUG_FOCUS ALOGD("setFocusedApplication"); #endif { // acquire lock AutoMutex _l(mLock); if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) { if (mFocusedApplicationHandle != inputApplicationHandle) { if (mFocusedApplicationHandle != NULL) { resetANRTimeoutsLocked(); mFocusedApplicationHandle->releaseInfo(); } mFocusedApplicationHandle = inputApplicationHandle; } } else if (mFocusedApplicationHandle != NULL) { resetANRTimeoutsLocked(); mFocusedApplicationHandle->releaseInfo(); mFocusedApplicationHandle.clear(); } #if DEBUG_FOCUS //logDispatchStateLocked(); #endif } // release lock // Wake up poll loop since it may need to make new input dispatching choices. mLooper->wake(); } void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { #if DEBUG_FOCUS ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen); #endif if (enabled) assert(mEnumerator != NULL); bool changed; { // acquire lock AutoMutex _l(mLock); if (mDispatchEnabled != enabled || mDispatchFrozen != frozen) { if (mDispatchFrozen && !frozen) { resetANRTimeoutsLocked(); } if (mDispatchEnabled && !enabled) { resetAndDropEverythingLocked("dispatcher is being disabled"); } mDispatchEnabled = enabled; mDispatchFrozen = frozen; changed = true; } else { changed = false; } #if DEBUG_FOCUS //logDispatchStateLocked(); #endif } // release lock if (changed) { // Wake up poll loop since it may need to make new input dispatching choices. mLooper->wake(); } } void InputDispatcher::setInputFilterEnabled(bool enabled) { #if DEBUG_FOCUS ALOGD("setInputFilterEnabled: enabled=%d", enabled); #endif { // acquire lock AutoMutex _l(mLock); if (mInputFilterEnabled == enabled) { return; } mInputFilterEnabled = enabled; resetAndDropEverythingLocked("input filter is being enabled or disabled"); } // release lock // Wake up poll loop since there might be work to do to drop everything. mLooper->wake(); } bool InputDispatcher::transferTouchFocus(const sp& fromChannel, const sp& toChannel) { #if DEBUG_FOCUS ALOGD("transferTouchFocus: fromChannel=%s, toChannel=%s", c_str(fromChannel->getName()), c_str(toChannel->getName())); #endif { // acquire lock AutoMutex _l(mLock); sp fromWindowHandle = getWindowHandleLocked(fromChannel); sp toWindowHandle = getWindowHandleLocked(toChannel); if (fromWindowHandle == NULL || toWindowHandle == NULL) { #if DEBUG_FOCUS ALOGD("Cannot transfer focus because from or to window not found."); #endif return false; } if (fromWindowHandle == toWindowHandle) { #if DEBUG_FOCUS ALOGD("Trivial transfer to same window."); #endif return true; } bool found = false; for (size_t i = 0; i < mTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTouchState.windows[i]; if (touchedWindow.windowHandle == fromWindowHandle) { int32_t oldTargetFlags = touchedWindow.targetFlags; IntSet pointerIds = touchedWindow.pointerIds; mTouchState.windows.removeAt(i); int32_t newTargetFlags = oldTargetFlags & (InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); mTouchState.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); found = true; break; } } if (! found) { #if DEBUG_FOCUS ALOGD("Focus transfer failed because from window did not have focus."); #endif return false; } ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel); if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) { sp fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex); sp toConnection = mConnectionsByFd.valueAt(toConnectionIndex); fromConnection->inputState.copyPointerStateTo(toConnection->inputState); CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "transferring touch focus from this window to another window"); synthesizeCancelationEventsForConnectionLocked(fromConnection, options); } #if DEBUG_FOCUS logDispatchStateLocked(); #endif } // release lock // Wake up poll loop since it may need to make new input dispatching choices. mLooper->wake(); return true; } void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { #if DEBUG_FOCUS ALOGD("Resetting and dropping all events (%s).", reason); #endif CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, reason); synthesizeCancelationEventsForAllConnectionsLocked(options); resetKeyRepeatLocked(); releasePendingEventLocked(); drainInboundQueueLocked(); resetANRTimeoutsLocked(); mTouchState.reset(); mLastHoverWindowHandle.clear(); } void InputDispatcher::logDispatchStateLocked() { String8 dump; dumpDispatchStateLocked(dump); char* text = lockBuffer(dump, dump.size()); char* start = text; while (*start != '\0') { char* end = strchr(start, '\n'); if (*end == '\n') { *(end++) = '\0'; } ALOGD("%s", start); start = end; } } void InputDispatcher::dumpDispatchStateLocked(String8& dump) { appendFormat(dump, INDENT "DispatchEnabled: %d\n", mDispatchEnabled); appendFormat(dump, INDENT "DispatchFrozen: %d\n", mDispatchFrozen); if (mFocusedApplicationHandle != NULL) { appendFormat(dump, INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", c_str(mFocusedApplicationHandle->getName()), mFocusedApplicationHandle->getDispatchingTimeout( DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0); } else { dump.append(INDENT "FocusedApplication: \n"); } appendFormat(dump, INDENT "FocusedWindow: name='%s'\n", mFocusedWindowHandle != NULL ? c_str(mFocusedWindowHandle->getName()) : ""); appendFormat(dump, INDENT "TouchDown: %s\n", toString(mTouchState.down)); appendFormat(dump, INDENT "TouchSplit: %s\n", toString(mTouchState.split)); appendFormat(dump, INDENT "TouchDeviceId: %d\n", mTouchState.deviceId); appendFormat(dump, INDENT "TouchSource: 0x%08x\n", mTouchState.source); if (!mTouchState.windows.isEmpty()) { dump.append(INDENT "TouchedWindows:\n"); for (size_t i = 0; i < mTouchState.windows.size(); i++) { const TouchedWindow& touchedWindow = mTouchState.windows[i]; appendFormat(dump, INDENT2 "%d: name='%s'", i, c_str(touchedWindow.windowHandle->getName())); dump.append(", pointerIds=("); touchedWindow.pointerIds.forEach([&](int32_t id) {appendFormat(dump, ", %d", id);}); dump.append(")"); appendFormat(dump, ", targetFlags=0x%x\n", touchedWindow.targetFlags); } } else { dump.append(INDENT "TouchedWindows: \n"); } dump.append(INDENT "Windows:\n"); mEnumerator->for_each([&](sp const& windowHandle){ const InputWindowInfo* windowInfo = windowHandle->getInfo(); appendFormat(dump, INDENT2 "name='%s', paused=%s, hasFocus=%s, hasWallpaper=%s, " "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " "frame=[%d,%d][%d,%d], scale=%f, " "touchableRegion=[%d,%d][%d,%d]", c_str(windowInfo->name), toString(windowInfo->paused), toString(windowInfo->hasFocus), toString(windowInfo->hasWallpaper), toString(windowInfo->visible), toString(windowInfo->canReceiveKeys), windowInfo->layoutParamsFlags, windowInfo->layoutParamsType, windowInfo->layer, windowInfo->frameLeft, windowInfo->frameTop, windowInfo->frameRight, windowInfo->frameBottom, windowInfo->scaleFactor, windowInfo->touchableRegionLeft, windowInfo->touchableRegionTop, windowInfo->touchableRegionRight, windowInfo->touchableRegionBottom); appendFormat(dump, ", inputFeatures=0x%08x", windowInfo->inputFeatures); appendFormat(dump, ", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", windowInfo->ownerPid, windowInfo->ownerUid, windowInfo->dispatchingTimeout / 1000000.0); }); if (!mMonitoringChannels.isEmpty()) { dump.append(INDENT "MonitoringChannels:\n"); for (size_t i = 0; i < mMonitoringChannels.size(); i++) { const sp& channel = mMonitoringChannels[i]; appendFormat(dump, INDENT2 "%d: '%s'\n", i, c_str(channel->getName())); } } else { dump.append(INDENT "MonitoringChannels: \n"); } nsecs_t currentTime = now(); if (!mInboundQueue.isEmpty()) { appendFormat(dump, INDENT "InboundQueue: length=%u\n", mInboundQueue.count()); for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) { dump.append(INDENT2); entry->appendDescription(dump); appendFormat(dump, ", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f); } } else { dump.append(INDENT "InboundQueue: \n"); } if (!mConnectionsByFd.isEmpty()) { dump.append(INDENT "Connections:\n"); for (size_t i = 0; i < mConnectionsByFd.size(); i++) { const sp& connection = mConnectionsByFd.valueAt(i); appendFormat(dump, INDENT2 "%d: channelName='%s', windowName='%s', " "status=%s, monitor=%s, inputPublisherBlocked=%s\n", i, connection->getInputChannelName(), connection->getWindowName(), connection->getStatusLabel(), toString(connection->monitor), toString(connection->inputPublisherBlocked)); if (!connection->outboundQueue.isEmpty()) { appendFormat(dump, INDENT3 "OutboundQueue: length=%u\n", connection->outboundQueue.count()); for (DispatchEntry* entry = connection->outboundQueue.head; entry; entry = entry->next) { dump.append(INDENT4); entry->eventEntry->appendDescription(dump); appendFormat(dump, ", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n", entry->targetFlags, entry->resolvedAction, (currentTime - entry->eventEntry->eventTime) * 0.000001f); } } else { dump.append(INDENT3 "OutboundQueue: \n"); } if (!connection->waitQueue.isEmpty()) { appendFormat(dump, INDENT3 "WaitQueue: length=%u\n", connection->waitQueue.count()); for (DispatchEntry* entry = connection->waitQueue.head; entry; entry = entry->next) { dump.append(INDENT4); entry->eventEntry->appendDescription(dump); appendFormat(dump, ", targetFlags=0x%08x, resolvedAction=%d, " "age=%0.1fms, wait=%0.1fms\n", entry->targetFlags, entry->resolvedAction, (currentTime - entry->eventEntry->eventTime) * 0.000001f, (currentTime - entry->deliveryTime) * 0.000001f); } } else { dump.append(INDENT3 "WaitQueue: \n"); } } } else { dump.append(INDENT "Connections: \n"); } if (isAppSwitchPendingLocked()) { appendFormat(dump, INDENT "AppSwitch: pending, due in %0.1fms\n", (mAppSwitchDueTime - now()) / 1000000.0); } else { dump.append(INDENT "AppSwitch: not pending\n"); } dump.append(INDENT "Configuration:\n"); appendFormat(dump, INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f); appendFormat(dump, INDENT2 "KeyRepeatTimeout: %0.1fms\n", mConfig.keyRepeatTimeout * 0.000001f); } status_t InputDispatcher::registerInputChannel(const sp& inputChannel, const sp& inputWindowHandle, bool monitor) { #if DEBUG_REGISTRATION ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", c_str(inputChannel->getName()), toString(monitor)); #endif { // acquire lock AutoMutex _l(mLock); if (getConnectionIndexLocked(inputChannel) >= 0) { ALOGW("Attempted to register already registered input channel '%s'", c_str(inputChannel->getName())); return BAD_VALUE; } sp connection = new Connection(inputChannel, inputWindowHandle, monitor); int fd = inputChannel->getFd(); mConnectionsByFd.add(fd, connection); if (monitor) { mMonitoringChannels.push(inputChannel); } mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); runCommandsLockedInterruptible(); } // release lock return OK; } status_t InputDispatcher::unregisterInputChannel(const sp& inputChannel) { #if DEBUG_REGISTRATION ALOGD("channel '%s' ~ unregisterInputChannel", c_str(inputChannel->getName())); #endif { // acquire lock AutoMutex _l(mLock); status_t status = unregisterInputChannelLocked(inputChannel, false /*notify*/); if (status) { return status; } } // release lock // Wake the poll loop because removing the connection may have changed the current // synchronization state. mLooper->wake(); return OK; } status_t InputDispatcher::unregisterInputChannelLocked(const sp& inputChannel, bool notify) { ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); if (connectionIndex < 0) { ALOGW("Attempted to unregister already unregistered input channel '%s'", c_str(inputChannel->getName())); return BAD_VALUE; } sp connection = mConnectionsByFd.valueAt(connectionIndex); mConnectionsByFd.removeItemsAt(connectionIndex); if (connection->monitor) { removeMonitorChannelLocked(inputChannel); } mLooper->removeFd(inputChannel->getFd()); nsecs_t currentTime = now(); abortBrokenDispatchCycleLocked(currentTime, connection, notify); runCommandsLockedInterruptible(); connection->status = Connection::STATUS_ZOMBIE; return OK; } void InputDispatcher::removeMonitorChannelLocked(const sp& inputChannel) { for (size_t i = 0; i < mMonitoringChannels.size(); i++) { if (mMonitoringChannels[i] == inputChannel) { mMonitoringChannels.removeAt(i); break; } } } ssize_t InputDispatcher::getConnectionIndexLocked(const sp& inputChannel) { ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd()); if (connectionIndex >= 0) { sp connection = mConnectionsByFd.valueAt(connectionIndex); if (connection->inputChannel.get() == inputChannel.get()) { return connectionIndex; } } return -1; } void InputDispatcher::onDispatchCycleFinishedLocked( nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled) { CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doDispatchCycleFinishedLockedInterruptible); commandEntry->connection = connection; commandEntry->eventTime = currentTime; commandEntry->seq = seq; commandEntry->handled = handled; } void InputDispatcher::onDispatchCycleBrokenLocked( nsecs_t currentTime, const sp& connection) { ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!", connection->getInputChannelName()); CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); commandEntry->connection = connection; } void InputDispatcher::onANRLocked( nsecs_t currentTime, const sp& applicationHandle, const sp& windowHandle, nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) { float dispatchLatency = (currentTime - eventTime) * 0.000001f; float waitDuration = (currentTime - waitStartTime) * 0.000001f; ALOGI("Application is not responding: %s. " "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", c_str(getApplicationWindowLabelLocked(applicationHandle, windowHandle)), dispatchLatency, waitDuration, reason); // Capture a record of the InputDispatcher state at the time of the ANR. time_t t = time(NULL); struct tm tm; localtime_r(&t, &tm); char timestr[64]; strftime(timestr, sizeof(timestr), "%F %T", &tm); mLastANRState.clear(); mLastANRState.append(INDENT "ANR:\n"); appendFormat(mLastANRState, INDENT2 "Time: %s\n", timestr); appendFormat(mLastANRState, INDENT2 "Window: %s\n", c_str(getApplicationWindowLabelLocked(applicationHandle, windowHandle))); appendFormat(mLastANRState, INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency); appendFormat(mLastANRState, INDENT2 "WaitDuration: %0.1fms\n", waitDuration); appendFormat(mLastANRState, INDENT2 "Reason: %s\n", reason); dumpDispatchStateLocked(mLastANRState); CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doNotifyANRLockedInterruptible); commandEntry->inputApplicationHandle = applicationHandle; commandEntry->inputWindowHandle = windowHandle; } void InputDispatcher::doNotifyConfigurationChangedInterruptible( CommandEntry* commandEntry) { mLock.unlock(); mPolicy->notifyConfigurationChanged(commandEntry->eventTime); mLock.lock(); } void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( CommandEntry* commandEntry) { sp connection = commandEntry->connection; if (connection->status != Connection::STATUS_ZOMBIE) { mLock.unlock(); mPolicy->notifyInputChannelBroken(connection->inputWindowHandle); mLock.lock(); } } void InputDispatcher::doNotifyANRLockedInterruptible( CommandEntry* commandEntry) { mLock.unlock(); nsecs_t newTimeout = mPolicy->notifyANR( commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle); mLock.lock(); resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, commandEntry->inputWindowHandle != NULL ? commandEntry->inputWindowHandle->getInputChannel() : NULL); } void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( CommandEntry* commandEntry) { KeyEntry* entry = commandEntry->keyEntry; KeyEvent event; initializeKeyEvent(&event, entry); mLock.unlock(); nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, &event, entry->policyFlags); mLock.lock(); if (delay < 0) { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP; } else if (!delay) { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; } else { entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER; entry->interceptKeyWakeupTime = now() + delay; } entry->release(); } void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( CommandEntry* commandEntry) { sp connection = commandEntry->connection; nsecs_t finishTime = commandEntry->eventTime; uint32_t seq = commandEntry->seq; bool handled = commandEntry->handled; // Handle post-event policy actions. DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq); if (dispatchEntry) { nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime; if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { String8 msg; appendFormat(msg, "Window '%s' spent %0.1fms processing the last input event: ", connection->getWindowName(), eventDuration * 0.000001f); dispatchEntry->eventEntry->appendDescription(msg); ALOGI("%s", c_str(msg)); } bool restartEvent; if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { KeyEntry* keyEntry = static_cast(dispatchEntry->eventEntry); restartEvent = afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled); } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) { MotionEntry* motionEntry = static_cast(dispatchEntry->eventEntry); restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry, handled); } else { restartEvent = false; } // Dequeue the event and start the next cycle. // Note that because the lock might have been released, it is possible that the // contents of the wait queue to have been drained, so we need to double-check // a few things. if (dispatchEntry == connection->findWaitQueueEntry(seq)) { connection->waitQueue.dequeue(dispatchEntry); if (restartEvent && connection->status == Connection::STATUS_NORMAL) { connection->outboundQueue.enqueueAtHead(dispatchEntry); } else { releaseDispatchEntryLocked(dispatchEntry); } } // Start the next dispatch cycle for this connection. startDispatchCycleLocked(now(), connection); } } bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& connection, DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) { if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) { // Get the fallback key state. // Clear it out after dispatching the UP. int32_t originalKeyCode = keyEntry->keyCode; int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode); if (keyEntry->action == AKEY_EVENT_ACTION_UP) { connection->inputState.removeFallbackKey(originalKeyCode); } if (handled || !dispatchEntry->hasForegroundTarget()) { // If the application handles the original key for which we previously // generated a fallback or if the window is not a foreground window, // then cancel the associated fallback key, if any. if (fallbackKeyCode != -1) { // Dispatch the unhandled key to the policy with the cancel flag. #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Asking policy to cancel fallback action. " "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags); #endif KeyEvent event; initializeKeyEvent(&event, keyEntry); event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED); mLock.unlock(); mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, &event, keyEntry->policyFlags, &event); mLock.lock(); // Cancel the fallback key. if (fallbackKeyCode != AKEYCODE_UNKNOWN) { CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, "application handled the original non-fallback key " "or is no longer a foreground target, " "canceling previously dispatched fallback key"); options.keyCode = fallbackKeyCode; synthesizeCancelationEventsForConnectionLocked(connection, options); } connection->inputState.removeFallbackKey(originalKeyCode); } } else { // If the application did not handle a non-fallback key, first check // that we are in a good state to perform unhandled key event processing // Then ask the policy what to do with it. bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN && keyEntry->repeatCount == 0; if (fallbackKeyCode == -1 && !initialDown) { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Skipping unhandled key event processing " "since this is not an initial down. " "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", originalKeyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags); #endif return false; } // Dispatch the unhandled key to the policy. #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Asking policy to perform fallback action. " "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags); #endif KeyEvent event; initializeKeyEvent(&event, keyEntry); mLock.unlock(); bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, &event, keyEntry->policyFlags, &event); mLock.lock(); if (connection->status != Connection::STATUS_NORMAL) { connection->inputState.removeFallbackKey(originalKeyCode); return false; } // Latch the fallback keycode for this key on an initial down. // The fallback keycode cannot change at any other point in the lifecycle. if (initialDown) { if (fallback) { fallbackKeyCode = event.getKeyCode(); } else { fallbackKeyCode = AKEYCODE_UNKNOWN; } connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode); } ALOG_ASSERT(fallbackKeyCode != -1); // Cancel the fallback key if the policy decides not to send it anymore. // We will continue to dispatch the key to the policy but we will no // longer dispatch a fallback key to the application. if (fallbackKeyCode != AKEYCODE_UNKNOWN && (!fallback || fallbackKeyCode != event.getKeyCode())) { #if DEBUG_OUTBOUND_EVENT_DETAILS if (fallback) { ALOGD("Unhandled key event: Policy requested to send key %d" "as a fallback for %d, but on the DOWN it had requested " "to send %d instead. Fallback canceled.", event.getKeyCode(), originalKeyCode, fallbackKeyCode); } else { ALOGD("Unhandled key event: Policy did not request fallback for %d, " "but on the DOWN it had requested to send %d. " "Fallback canceled.", originalKeyCode, fallbackKeyCode); } #endif CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, "canceling fallback, policy no longer desires it"); options.keyCode = fallbackKeyCode; synthesizeCancelationEventsForConnectionLocked(connection, options); fallback = false; fallbackKeyCode = AKEYCODE_UNKNOWN; if (keyEntry->action != AKEY_EVENT_ACTION_UP) { connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode); } } #if DEBUG_OUTBOUND_EVENT_DETAILS { String8 msg; const KeyedVector& fallbackKeys = connection->inputState.getFallbackKeys(); for (size_t i = 0; i < fallbackKeys.size(); i++) { appendFormat(msg, ", %d->%d", fallbackKeys.keyAt(i), fallbackKeys.valueAt(i)); } ALOGD("Unhandled key event: %d currently tracked fallback keys%s.", fallbackKeys.size(), c_str(msg)); } #endif if (fallback) { // Restart the dispatch cycle using the fallback key. keyEntry->eventTime = event.getEventTime(); keyEntry->deviceId = event.getDeviceId(); keyEntry->source = event.getSource(); keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK; keyEntry->keyCode = fallbackKeyCode; keyEntry->scanCode = event.getScanCode(); keyEntry->metaState = event.getMetaState(); keyEntry->repeatCount = event.getRepeatCount(); keyEntry->downTime = event.getDownTime(); keyEntry->syntheticRepeat = false; #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Dispatching fallback key. " "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", originalKeyCode, fallbackKeyCode, keyEntry->metaState); #endif return true; // restart the event } else { #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: No fallback key."); #endif } } } return false; } bool InputDispatcher::afterMotionEventLockedInterruptible(const sp& connection, DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) { return false; } void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) { mLock.unlock(); mPolicy->pokeUserActivity(commandEntry->eventTime, commandEntry->userActivityEventType); mLock.lock(); } void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) { event->initialize(entry->deviceId, entry->source, entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, entry->downTime, entry->eventTime); } void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry, int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) { // TODO Write some statistics about how long we spend waiting. } void InputDispatcher::dump(String8& dump) { AutoMutex _l(mLock); dump.append("Input Dispatcher State:\n"); dumpDispatchStateLocked(dump); if (!isEmpty(mLastANRState)) { dump.append("\nInput Dispatcher State at time of last ANR:\n"); dump.append(mLastANRState); } } void InputDispatcher::monitor() { // Acquire and release the lock to ensure that the dispatcher has not deadlocked. mLock.lock(); mLooper->wake(); mDispatcherIsAliveCondition.wait(mLock); mLock.unlock(); } // --- InputDispatcher::Queue --- template uint32_t InputDispatcher::Queue::count() const { uint32_t result = 0; for (const T* entry = head; entry; entry = entry->next) { result += 1; } return result; } // --- InputDispatcher::InjectionState --- InputDispatcher::InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) : refCount(1), injectorPid(injectorPid), injectorUid(injectorUid), injectionResult(INPUT_EVENT_INJECTION_PENDING), injectionIsAsync(false), pendingForegroundDispatches(0) { } InputDispatcher::InjectionState::~InjectionState() { } void InputDispatcher::InjectionState::release() { refCount -= 1; if (refCount == 0) { delete this; } else { ALOG_ASSERT(refCount > 0); } } // --- InputDispatcher::EventEntry --- InputDispatcher::EventEntry::EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags) : refCount(1), type(type), eventTime(eventTime), policyFlags(policyFlags), injectionState(NULL), dispatchInProgress(false) { } InputDispatcher::EventEntry::~EventEntry() { releaseInjectionState(); } void InputDispatcher::EventEntry::release() { refCount -= 1; if (refCount == 0) { delete this; } else { ALOG_ASSERT(refCount > 0); } } void InputDispatcher::EventEntry::releaseInjectionState() { if (injectionState) { injectionState->release(); injectionState = NULL; } } // --- InputDispatcher::ConfigurationChangedEntry --- InputDispatcher::ConfigurationChangedEntry::ConfigurationChangedEntry(nsecs_t eventTime) : EventEntry(TYPE_CONFIGURATION_CHANGED, eventTime, 0) { } InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() { } void InputDispatcher::ConfigurationChangedEntry::appendDescription(String8& msg) const { msg.append("ConfigurationChangedEvent()"); } // --- InputDispatcher::DeviceResetEntry --- InputDispatcher::DeviceResetEntry::DeviceResetEntry(nsecs_t eventTime, int32_t deviceId) : EventEntry(TYPE_DEVICE_RESET, eventTime, 0), deviceId(deviceId) { } InputDispatcher::DeviceResetEntry::~DeviceResetEntry() { } void InputDispatcher::DeviceResetEntry::appendDescription(String8& msg) const { appendFormat(msg, "DeviceResetEvent(deviceId=%d)", deviceId); } // --- InputDispatcher::KeyEntry --- InputDispatcher::KeyEntry::KeyEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime) : EventEntry(TYPE_KEY, eventTime, policyFlags), deviceId(deviceId), source(source), action(action), flags(flags), keyCode(keyCode), scanCode(scanCode), metaState(metaState), repeatCount(repeatCount), downTime(downTime), syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN), interceptKeyWakeupTime(0) { } InputDispatcher::KeyEntry::~KeyEntry() { } void InputDispatcher::KeyEntry::appendDescription(String8& msg) const { appendFormat(msg, "KeyEvent(action=%d, deviceId=%d, source=0x%08x)", action, deviceId, source); } void InputDispatcher::KeyEntry::recycle() { releaseInjectionState(); dispatchInProgress = false; syntheticRepeat = false; interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; interceptKeyWakeupTime = 0; } // --- InputDispatcher::MotionEntry --- InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) : EventEntry(TYPE_MOTION, eventTime, policyFlags), eventTime(eventTime), deviceId(deviceId), source(source), action(action), flags(flags), metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags), xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime), pointerCount(pointerCount) { for (uint32_t i = 0; i < pointerCount; i++) { this->pointerProperties[i].copyFrom(pointerProperties[i]); this->pointerCoords[i].copyFrom(pointerCoords[i]); } } InputDispatcher::MotionEntry::~MotionEntry() { } void InputDispatcher::MotionEntry::appendDescription(String8& msg) const { appendFormat(msg, "MotionEvent(action=%d, deviceId=%d, source=0x%08x)", action, deviceId, source); } // --- InputDispatcher::DispatchEntry --- android_atomic_int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic; InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) : seq(nextSeq()), eventEntry(eventEntry), targetFlags(targetFlags), xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor), deliveryTime(0), resolvedAction(0), resolvedFlags(0) { eventEntry->refCount += 1; } InputDispatcher::DispatchEntry::~DispatchEntry() { eventEntry->release(); } uint32_t InputDispatcher::DispatchEntry::nextSeq() { // Sequence number 0 is reserved and will never be returned. uint32_t seq; do { seq = android_atomic_inc(&sNextSeqAtomic); } while (!seq); return seq; } // --- InputDispatcher::InputState --- InputDispatcher::InputState::InputState() { } InputDispatcher::InputState::~InputState() { } bool InputDispatcher::InputState::isNeutral() const { return mKeyMementos.isEmpty() && mMotionMementos.isEmpty(); } bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source) const { for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos.itemAt(i); if (memento.deviceId == deviceId && memento.source == source && memento.hovering) { return true; } } return false; } bool InputDispatcher::InputState::trackKey(const KeyEntry* entry, int32_t action, int32_t flags) { switch (action) { case AKEY_EVENT_ACTION_UP: { if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) { for (size_t i = 0; i < mFallbackKeys.size(); ) { if (mFallbackKeys.valueAt(i) == entry->keyCode) { mFallbackKeys.removeItemsAt(i); } else { i += 1; } } } ssize_t index = findKeyMemento(entry); if (index >= 0) { mKeyMementos.removeAt(index); return true; } /* FIXME: We can't just drop the key up event because that prevents creating * popup windows that are automatically shown when a key is held and then * dismissed when the key is released. The problem is that the popup will * not have received the original key down, so the key up will be considered * to be inconsistent with its observed state. We could perhaps handle this * by synthesizing a key down but that will cause other problems. * * So for now, allow inconsistent key up events to be dispatched. * #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, " "keyCode=%d, scanCode=%d", entry->deviceId, entry->source, entry->keyCode, entry->scanCode); #endif return false; */ return true; } case AKEY_EVENT_ACTION_DOWN: { ssize_t index = findKeyMemento(entry); if (index >= 0) { mKeyMementos.removeAt(index); } addKeyMemento(entry, flags); return true; } default: return true; } } bool InputDispatcher::InputState::trackMotion(const MotionEntry* entry, int32_t action, int32_t flags) { int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK; switch (actionMasked) { case AMOTION_EVENT_ACTION_UP: case AMOTION_EVENT_ACTION_CANCEL: { ssize_t index = findMotionMemento(entry, false /*hovering*/); if (index >= 0) { mMotionMementos.removeAt(index); return true; } #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, " "actionMasked=%d", entry->deviceId, entry->source, actionMasked); #endif return false; } case AMOTION_EVENT_ACTION_DOWN: { ssize_t index = findMotionMemento(entry, false /*hovering*/); if (index >= 0) { mMotionMementos.removeAt(index); } addMotionMemento(entry, flags, false /*hovering*/); return true; } case AMOTION_EVENT_ACTION_POINTER_UP: case AMOTION_EVENT_ACTION_POINTER_DOWN: case AMOTION_EVENT_ACTION_MOVE: { ssize_t index = findMotionMemento(entry, false /*hovering*/); if (index >= 0) { MotionMemento& memento = mMotionMementos.editItemAt(index); memento.setPointers(entry); return true; } if (actionMasked == AMOTION_EVENT_ACTION_MOVE && (entry->source & (AINPUT_SOURCE_CLASS_JOYSTICK | AINPUT_SOURCE_CLASS_NAVIGATION))) { // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP. return true; } #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Dropping inconsistent motion pointer up/down or move event: " "deviceId=%d, source=%08x, actionMasked=%d", entry->deviceId, entry->source, actionMasked); #endif return false; } case AMOTION_EVENT_ACTION_HOVER_EXIT: { ssize_t index = findMotionMemento(entry, true /*hovering*/); if (index >= 0) { mMotionMementos.removeAt(index); return true; } #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x", entry->deviceId, entry->source); #endif return false; } case AMOTION_EVENT_ACTION_HOVER_ENTER: case AMOTION_EVENT_ACTION_HOVER_MOVE: { ssize_t index = findMotionMemento(entry, true /*hovering*/); if (index >= 0) { mMotionMementos.removeAt(index); } addMotionMemento(entry, flags, true /*hovering*/); return true; } default: return true; } } ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const { for (size_t i = 0; i < mKeyMementos.size(); i++) { const KeyMemento& memento = mKeyMementos.itemAt(i); if (memento.deviceId == entry->deviceId && memento.source == entry->source && memento.keyCode == entry->keyCode && memento.scanCode == entry->scanCode) { return i; } } return -1; } ssize_t InputDispatcher::InputState::findMotionMemento(const MotionEntry* entry, bool hovering) const { for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos.itemAt(i); if (memento.deviceId == entry->deviceId && memento.source == entry->source && memento.hovering == hovering) { return i; } } return -1; } void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) { mKeyMementos.push(); KeyMemento& memento = mKeyMementos.editTop(); memento.deviceId = entry->deviceId; memento.source = entry->source; memento.keyCode = entry->keyCode; memento.scanCode = entry->scanCode; memento.metaState = entry->metaState; memento.flags = flags; memento.downTime = entry->downTime; memento.policyFlags = entry->policyFlags; } void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering) { mMotionMementos.push(); MotionMemento& memento = mMotionMementos.editTop(); memento.deviceId = entry->deviceId; memento.source = entry->source; memento.flags = flags; memento.xPrecision = entry->xPrecision; memento.yPrecision = entry->yPrecision; memento.downTime = entry->downTime; memento.setPointers(entry); memento.hovering = hovering; memento.policyFlags = entry->policyFlags; } void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) { pointerCount = entry->pointerCount; for (uint32_t i = 0; i < entry->pointerCount; i++) { pointerProperties[i].copyFrom(entry->pointerProperties[i]); pointerCoords[i].copyFrom(entry->pointerCoords[i]); } } void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime, Vector& outEvents, const CancelationOptions& options) { for (size_t i = 0; i < mKeyMementos.size(); i++) { const KeyMemento& memento = mKeyMementos.itemAt(i); if (shouldCancelKey(memento, options)) { outEvents.push(new KeyEntry(currentTime, memento.deviceId, memento.source, memento.policyFlags, AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime)); } } for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos.itemAt(i); if (shouldCancelMotion(memento, options)) { outEvents.push(new MotionEntry(currentTime, memento.deviceId, memento.source, memento.policyFlags, memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL, memento.flags, 0, 0, 0, memento.xPrecision, memento.yPrecision, memento.downTime, memento.pointerCount, memento.pointerProperties, memento.pointerCoords)); } } } void InputDispatcher::InputState::clear() { mKeyMementos.clear(); mMotionMementos.clear(); mFallbackKeys.clear(); } void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const { for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos.itemAt(i); if (memento.source & AINPUT_SOURCE_CLASS_POINTER) { for (size_t j = 0; j < other.mMotionMementos.size(); ) { const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j); if (memento.deviceId == otherMemento.deviceId && memento.source == otherMemento.source) { other.mMotionMementos.removeAt(j); } else { j += 1; } } other.mMotionMementos.push(memento); } } } int32_t InputDispatcher::InputState::getFallbackKey(int32_t originalKeyCode) { ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); return index >= 0 ? mFallbackKeys.valueAt(index) : -1; } void InputDispatcher::InputState::setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode) { ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); if (index >= 0) { mFallbackKeys.replaceValueAt(index, fallbackKeyCode); } else { mFallbackKeys.add(originalKeyCode, fallbackKeyCode); } } void InputDispatcher::InputState::removeFallbackKey(int32_t originalKeyCode) { mFallbackKeys.removeItem(originalKeyCode); } bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) { if (options.keyCode != -1 && memento.keyCode != options.keyCode) { return false; } if (options.deviceId != -1 && memento.deviceId != options.deviceId) { return false; } switch (options.mode) { case CancelationOptions::CANCEL_ALL_EVENTS: case CancelationOptions::CANCEL_NON_POINTER_EVENTS: return true; case CancelationOptions::CANCEL_FALLBACK_EVENTS: return memento.flags & AKEY_EVENT_FLAG_FALLBACK; default: return false; } } bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options) { if (options.deviceId != -1 && memento.deviceId != options.deviceId) { return false; } switch (options.mode) { case CancelationOptions::CANCEL_ALL_EVENTS: return true; case CancelationOptions::CANCEL_POINTER_EVENTS: return memento.source & AINPUT_SOURCE_CLASS_POINTER; case CancelationOptions::CANCEL_NON_POINTER_EVENTS: return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); default: return false; } } // --- InputDispatcher::Connection --- InputDispatcher::Connection::Connection(const sp& inputChannel, const sp& inputWindowHandle, bool monitor) : status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle), monitor(monitor), inputPublisher(inputChannel), inputPublisherBlocked(false) { } InputDispatcher::Connection::~Connection() { } const char* InputDispatcher::Connection::getWindowName() const { if (inputWindowHandle != NULL) { return c_str(inputWindowHandle->getName()); } if (monitor) { return "monitor"; } return "?"; } const char* InputDispatcher::Connection::getStatusLabel() const { switch (status) { case STATUS_NORMAL: return "NORMAL"; case STATUS_BROKEN: return "BROKEN"; case STATUS_ZOMBIE: return "ZOMBIE"; default: return "UNKNOWN"; } } InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) { for (DispatchEntry* entry = waitQueue.head; entry != NULL; entry = entry->next) { if (entry->seq == seq) { return entry; } } return NULL; } // --- InputDispatcher::CommandEntry --- InputDispatcher::CommandEntry::CommandEntry(Command command) : command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0), seq(0), handled(false) { } InputDispatcher::CommandEntry::~CommandEntry() { } // --- InputDispatcher::TouchState --- InputDispatcher::TouchState::TouchState() : down(false), split(false), deviceId(-1), source(0) { } InputDispatcher::TouchState::~TouchState() { } void InputDispatcher::TouchState::reset() { down = false; split = false; deviceId = -1; source = 0; windows.clear(); } void InputDispatcher::TouchState::copyFrom(const TouchState& other) { down = other.down; split = other.split; deviceId = other.deviceId; source = other.source; windows = other.windows; } void InputDispatcher::TouchState::addOrUpdateWindow(const sp& windowHandle, int32_t targetFlags, const IntSet &pointerIds) { if (targetFlags & InputTarget::FLAG_SPLIT) { split = true; } for (size_t i = 0; i < windows.size(); i++) { TouchedWindow& touchedWindow = windows.editItemAt(i); if (touchedWindow.windowHandle == windowHandle) { touchedWindow.targetFlags |= targetFlags; if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS; } pointerIds.forEach([&](int32_t id) { touchedWindow.pointerIds.insert(id); }); return; } } windows.push(); TouchedWindow& touchedWindow = windows.editTop(); touchedWindow.windowHandle = windowHandle; touchedWindow.targetFlags = targetFlags; touchedWindow.pointerIds = pointerIds; } void InputDispatcher::TouchState::removeWindow(const sp& windowHandle) { for (size_t i = 0; i < windows.size(); i++) { if (windows.itemAt(i).windowHandle == windowHandle) { windows.removeAt(i); return; } } } void InputDispatcher::TouchState::filterNonAsIsTouchWindows() { for (size_t i = 0 ; i < windows.size(); ) { TouchedWindow& window = windows.editItemAt(i); if (window.targetFlags & (InputTarget::FLAG_DISPATCH_AS_IS | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) { window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK; window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS; i += 1; } else { windows.removeAt(i); } } } sp InputDispatcher::TouchState::getFirstForegroundWindowHandle() const { for (size_t i = 0; i < windows.size(); i++) { const TouchedWindow& window = windows.itemAt(i); if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { return window.windowHandle; } } return NULL; } bool InputDispatcher::TouchState::isSlippery() const { // Must have exactly one foreground window. bool haveSlipperyForegroundWindow = false; for (size_t i = 0; i < windows.size(); i++) { const TouchedWindow& window = windows.itemAt(i); if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { if (haveSlipperyForegroundWindow || !(window.windowHandle->getInfo()->layoutParamsFlags & InputWindowInfo::FLAG_SLIPPERY)) { return false; } haveSlipperyForegroundWindow = true; } } return haveSlipperyForegroundWindow; } // --- InputDispatcherThread --- InputDispatcherThread::InputDispatcherThread(const sp& dispatcher) : Thread(/*canCallJava*/ true), mDispatcher(dispatcher) { } InputDispatcherThread::~InputDispatcherThread() { } bool InputDispatcherThread::threadLoop() { mDispatcher->dispatchOnce(); return true; } } // namespace android ././@LongLink0000000000000000000000000000015000000000000011211 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputDevice.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputDevice.0000644000015301777760000001372312322054223033302 0ustar pbusernogroup00000000000000/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "InputDevice" #include #define DEBUG_PROBE 0 #include #include #include #include namespace android { static const char* CONFIGURATION_FILE_DIR[] = { "idc/", "keylayout/", "keychars/", }; static const char* CONFIGURATION_FILE_EXTENSION[] = { ".idc", ".kl", ".kcm", }; static bool isValidNameChar(char ch) { return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_'); } static void appendInputDeviceConfigurationFileRelativePath(String8& path, const String8& name, InputDeviceConfigurationFileType type) { path.append(CONFIGURATION_FILE_DIR[type]); for (size_t i = 0; i < name.length(); i++) { char ch = name[i]; if (!isValidNameChar(ch)) { ch = '_'; } path.append(&ch, 1); } path.append(CONFIGURATION_FILE_EXTENSION[type]); } String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type) { if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) { if (deviceIdentifier.version != 0) { // Try vendor product version. String8 versionPath(getInputDeviceConfigurationFilePathByName( formatString8("Vendor_%04x_Product_%04x_Version_%04x", deviceIdentifier.vendor, deviceIdentifier.product, deviceIdentifier.version), type)); if (!isEmpty(versionPath)) { return versionPath; } } // Try vendor product. String8 productPath(getInputDeviceConfigurationFilePathByName( formatString8("Vendor_%04x_Product_%04x", deviceIdentifier.vendor, deviceIdentifier.product), type)); if (!isEmpty(productPath)) { return productPath; } } // Try device name. return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type); } String8 getInputDeviceConfigurationFilePathByName( const String8& name, InputDeviceConfigurationFileType type) { // Search system repository. String8 path; // { const char *root_env = getenv("ANDROID_ROOT"); if (root_env == NULL) root_env = ""; setTo(path, root_env); } // path.append("/usr/"); appendInputDeviceConfigurationFileRelativePath(path, name, type); #if DEBUG_PROBE ALOGD("Probing for system provided input device configuration file: path='%s'", path.c_str()); #endif if (!access(c_str(path), R_OK)) { #if DEBUG_PROBE ALOGD("Found"); #endif return path; } // Search user repository. // TODO Should only look here if not in safe mode. // { const char *data_env = getenv("ANDROID_DATA"); if (data_env == NULL) data_env = ""; setTo(path, data_env); } // path.append("/system/devices/"); appendInputDeviceConfigurationFileRelativePath(path, name, type); #if DEBUG_PROBE ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str()); #endif if (!access(c_str(path), R_OK)) { #if DEBUG_PROBE ALOGD("Found"); #endif return path; } // Not found. #if DEBUG_PROBE ALOGD("Probe failed to find input device configuration file: name='%s', type=%d", name.c_str(), type); #endif return String8(); } // --- InputDeviceInfo --- InputDeviceInfo::InputDeviceInfo() { initialize(-1, -1, InputDeviceIdentifier(), String8(), false); } InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) : mId(other.mId), mGeneration(other.mGeneration), mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal), mSources(other.mSources), mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap), mHasVibrator(other.mHasVibrator), mMotionRanges(other.mMotionRanges) { } InputDeviceInfo::~InputDeviceInfo() { } void InputDeviceInfo::initialize(int32_t id, int32_t generation, const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) { mId = id; mGeneration = generation; mIdentifier = identifier; mAlias = alias; mIsExternal = isExternal; mSources = 0; mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; mHasVibrator = false; mMotionRanges.clear(); } const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( int32_t axis, uint32_t source) const { size_t numRanges = mMotionRanges.size(); for (size_t i = 0; i < numRanges; i++) { const MotionRange& range = mMotionRanges.itemAt(i); if (range.axis == axis && range.source == source) { return ⦥ } } return NULL; } void InputDeviceInfo::addSource(uint32_t source) { mSources |= source; } void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) { MotionRange range = { axis, source, min, max, flat, fuzz }; mMotionRanges.add(range); } void InputDeviceInfo::addMotionRange(const MotionRange& range) { mMotionRanges.add(range); } } // namespace android ././@LongLink0000000000000000000000000000015000000000000011211 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputReader.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputReader.0000644000015301777760000074215112322054223033311 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "InputReader" //#define LOG_NDEBUG 0 // Log debug messages for each raw event received from the EventHub. #define DEBUG_RAW_EVENTS 0 // Log debug messages about touch screen filtering hacks. #define DEBUG_HACKS 0 // Log debug messages about virtual key processing. #define DEBUG_VIRTUAL_KEYS 0 // Log debug messages about pointers. #define DEBUG_POINTERS 0 // Log debug messages about pointer assignment calculations. #define DEBUG_POINTER_ASSIGNMENT 0 // Log debug messages about gesture detection. #define DEBUG_GESTURES 0 // Log debug messages about the vibrator. #define DEBUG_VIBRATOR 0 #include "InputReader.h" #include #include #include #include #include #include #include #include #include #include #include #if DEBUG_RAW_EVENTS #include "InputEventPrinter.h" #endif #define INDENT " " #define INDENT2 " " #define INDENT3 " " #define INDENT4 " " #define INDENT5 " " namespace android { // --- Constants --- // Maximum number of slots supported when using the slot-based Multitouch Protocol B. static const size_t MAX_SLOTS = 32; // --- Static Functions --- template inline static T abs(const T& value) { return value < 0 ? - value : value; } template inline static T min(const T& a, const T& b) { return a < b ? a : b; } template inline static void swap(T& a, T& b) { T temp = a; a = b; b = temp; } inline static float avg(float x, float y) { return (x + y) / 2; } inline static float distance(float x1, float y1, float x2, float y2) { return hypotf(x1 - x2, y1 - y2); } inline static int32_t signExtendNybble(int32_t value) { return value >= 8 ? value - 16 : value; } static inline const char* toString(bool value) { return value ? "true" : "false"; } static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation, const int32_t map[][4], size_t mapSize) { if (orientation != DISPLAY_ORIENTATION_0) { for (size_t i = 0; i < mapSize; i++) { if (value == map[i][0]) { return map[i][orientation]; } } } return value; } static const int32_t keyCodeRotationMap[][4] = { // key codes enumerated counter-clockwise with the original (unrotated) key first // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation { AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT }, { AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN }, { AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT }, { AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP }, }; static const size_t keyCodeRotationMapSize = sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { return rotateValueUsingRotationMap(keyCode, orientation, keyCodeRotationMap, keyCodeRotationMapSize); } static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { float temp; switch (orientation) { case DISPLAY_ORIENTATION_90: temp = *deltaX; *deltaX = *deltaY; *deltaY = -temp; break; case DISPLAY_ORIENTATION_180: *deltaX = -*deltaX; *deltaY = -*deltaY; break; case DISPLAY_ORIENTATION_270: temp = *deltaX; *deltaX = -*deltaY; *deltaY = temp; break; } } static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0; } // Returns true if the pointer should be reported as being down given the specified // button states. This determines whether the event is reported as a touch event. static bool isPointerDown(int32_t buttonState) { return buttonState & (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY | AMOTION_EVENT_BUTTON_TERTIARY); } static float calculateCommonVector(float a, float b) { if (a > 0 && b > 0) { return a < b ? a : b; } else if (a < 0 && b < 0) { return a > b ? a : b; } else { return 0; } } static void synthesizeButtonKey(InputReaderContext* context, int32_t action, nsecs_t when, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState, int32_t buttonState, int32_t keyCode) { if ( (action == AKEY_EVENT_ACTION_DOWN && !(lastButtonState & buttonState) && (currentButtonState & buttonState)) || (action == AKEY_EVENT_ACTION_UP && (lastButtonState & buttonState) && !(currentButtonState & buttonState))) { NotifyKeyArgs args(when, deviceId, source, policyFlags, action, 0, keyCode, 0, context->getGlobalMetaState(), when); context->getListener()->notifyKey(&args); } } static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, nsecs_t when, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) { synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK); synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, lastButtonState, currentButtonState, AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD); } // --- InputReaderConfiguration --- bool InputReaderConfiguration::getDisplayInfo(int32_t displayId, bool external, int32_t* width, int32_t* height, int32_t* orientation) const { if (displayId == 0) { const DisplayInfo& info = external ? mExternalDisplay : mInternalDisplay; if (info.width > 0 && info.height > 0) { if (width) { *width = info.width; } if (height) { *height = info.height; } if (orientation) { *orientation = info.orientation; } return true; } } return false; } void InputReaderConfiguration::setDisplayInfo(int32_t displayId, bool external, int32_t width, int32_t height, int32_t orientation) { if (displayId == 0) { DisplayInfo& info = external ? mExternalDisplay : mInternalDisplay; info.width = width; info.height = height; info.orientation = orientation; } } // --- InputReader --- InputReader::InputReader(const sp& eventHub, const sp& policy, const sp& listener) : mContext(this), mEventHub(eventHub), mPolicy(policy), mGlobalMetaState(0), mGeneration(1), mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), mConfigurationChangesToRefresh(0) { mQueuedListener = new QueuedInputListener(listener); { // acquire lock AutoMutex _l(mLock); refreshConfigurationLocked(0); updateGlobalMetaStateLocked(); } // release lock } InputReader::~InputReader() { for (size_t i = 0; i < mDevices.size(); i++) { delete mDevices.valueAt(i); } } void InputReader::loopOnce() { int32_t oldGeneration; int32_t timeoutMillis; bool inputDevicesChanged = false; Vector inputDevices; { // acquire lock AutoMutex _l(mLock); oldGeneration = mGeneration; timeoutMillis = -1; uint32_t changes = mConfigurationChangesToRefresh; if (changes) { mConfigurationChangesToRefresh = 0; timeoutMillis = 0; refreshConfigurationLocked(changes); } else if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); } } // release lock size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { // acquire lock AutoMutex _l(mLock); broadcast(mReaderIsAliveCondition); if (count) { processEventsLocked(mEventBuffer, count); } if (mNextTimeout != LLONG_MAX) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (now >= mNextTimeout) { #if DEBUG_RAW_EVENTS ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); #endif mNextTimeout = LLONG_MAX; timeoutExpiredLocked(now); } } if (oldGeneration != mGeneration) { inputDevicesChanged = true; getInputDevicesLocked(inputDevices); } } // release lock // Send out a message that the describes the changed input devices. if (inputDevicesChanged) { mPolicy->notifyInputDevicesChanged(inputDevices); } // Flush queued events out to the listener. // This must happen outside of the lock because the listener could potentially call // back into the InputReader's methods, such as getScanCodeState, or become blocked // on another thread similarly waiting to acquire the InputReader lock thereby // resulting in a deadlock. This situation is actually quite plausible because the // listener is actually the input dispatcher, which calls into the window manager, // which occasionally calls into the input reader. mQueuedListener->flush(); } void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { for (const RawEvent* rawEvent = rawEvents; count;) { int32_t type = rawEvent->type; size_t batchSize = 1; if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { int32_t deviceId = rawEvent->deviceId; while (batchSize < count) { if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT || rawEvent[batchSize].deviceId != deviceId) { break; } batchSize += 1; } #if DEBUG_RAW_EVENTS ALOGD("BatchSize: %zu Count: %zu", batchSize, count); #endif processEventsForDeviceLocked(deviceId, rawEvent, batchSize); } else { switch (rawEvent->type) { case EventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::DEVICE_REMOVED: removeDeviceLocked(rawEvent->when, rawEvent->deviceId); break; case EventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent->when); break; default: ALOG_ASSERT(false); // can't happen break; } } count -= batchSize; rawEvent += batchSize; } } void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); return; } InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId); uint32_t classes = mEventHub->getDeviceClasses(deviceId); InputDevice* device = createDeviceLocked(deviceId, identifier, classes); device->configure(when, &mConfig, 0); device->reset(when); if (device->isIgnored()) { ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, c_str(identifier.name)); } else { ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, c_str(identifier.name), device->getSources()); } mDevices.add(deviceId, device); bumpGenerationLocked(); } void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { InputDevice* device = NULL; ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex < 0) { ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId); return; } device = mDevices.valueAt(deviceIndex); mDevices.removeItemsAt(deviceIndex, 1); bumpGenerationLocked(); if (device->isIgnored()) { ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", device->getId(), c_str(device->getName())); } else { ALOGI("Device removed: id=%d, name='%s', sources=0x%08x", device->getId(), c_str(device->getName()), device->getSources()); } device->reset(when); delete device; } InputDevice* InputReader::createDeviceLocked(int32_t deviceId, const InputDeviceIdentifier& identifier, uint32_t classes) { InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), identifier, classes); // External devices. if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { device->setExternal(true); } // Switch-like devices. if (classes & INPUT_DEVICE_CLASS_SWITCH) { device->addMapper(new SwitchInputMapper(device)); } // Vibrator-like devices. if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { device->addMapper(new VibratorInputMapper(device)); } // Keyboard-like devices. uint32_t keyboardSource = 0; int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { keyboardSource |= AINPUT_SOURCE_KEYBOARD; } if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; } if (classes & INPUT_DEVICE_CLASS_DPAD) { keyboardSource |= AINPUT_SOURCE_DPAD; } if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { keyboardSource |= AINPUT_SOURCE_GAMEPAD; } if (keyboardSource != 0) { device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); } // Cursor-like devices. if (classes & INPUT_DEVICE_CLASS_CURSOR) { device->addMapper(new CursorInputMapper(device)); } // Touchscreens and touchpad devices. if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { device->addMapper(new MultiTouchInputMapper(device)); } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { device->addMapper(new SingleTouchInputMapper(device)); } // Joystick-like devices. if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { device->addMapper(new JoystickInputMapper(device)); } return device; } void InputReader::processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex < 0) { ALOGW("Discarding event for unknown deviceId %d.", deviceId); return; } InputDevice* device = mDevices.valueAt(deviceIndex); if (device->isIgnored()) { //ALOGD("Discarding event for ignored deviceId %d.", deviceId); return; } device->process(rawEvents, count); } void InputReader::timeoutExpiredLocked(nsecs_t when) { for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); if (!device->isIgnored()) { device->timeoutExpired(when); } } } void InputReader::handleConfigurationChangedLocked(nsecs_t when) { // Reset global meta state because it depends on the list of all configured devices. updateGlobalMetaStateLocked(); // Enqueue configuration changed. NotifyConfigurationChangedArgs args(when); mQueuedListener->notifyConfigurationChanged(&args); } void InputReader::refreshConfigurationLocked(uint32_t changes) { mPolicy->getReaderConfiguration(&mConfig); mEventHub->setExcludedDevices(mConfig.excludedDeviceNames); if (changes) { ALOGI("Reconfiguring input devices. changes=0x%08x", changes); nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { mEventHub->requestReopenDevices(); } else { for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); device->configure(now, &mConfig, changes); } } } } void InputReader::updateGlobalMetaStateLocked() { mGlobalMetaState = 0; for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); mGlobalMetaState |= device->getMetaState(); } } int32_t InputReader::getGlobalMetaStateLocked() { return mGlobalMetaState; } void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { mDisableVirtualKeysTimeout = time; } bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode) { if (now < mDisableVirtualKeysTimeout) { ALOGI("Dropping virtual key from device %s because virtual keys are " "temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d", c_str(device->getName()), (mDisableVirtualKeysTimeout - now) * 0.000001, keyCode, scanCode); return true; } else { return false; } } void InputReader::fadePointerLocked() { for (size_t i = 0; i < mDevices.size(); i++) { InputDevice* device = mDevices.valueAt(i); device->fadePointer(); } } void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) { if (when < mNextTimeout) { mNextTimeout = when; mEventHub->wake(); } } int32_t InputReader::bumpGenerationLocked() { return ++mGeneration; } void InputReader::getInputDevices(Vector& outInputDevices) { AutoMutex _l(mLock); getInputDevicesLocked(outInputDevices); } void InputReader::getInputDevicesLocked(Vector& outInputDevices) { outInputDevices.clear(); size_t numDevices = mDevices.size(); for (size_t i = 0; i < numDevices; i++) { InputDevice* device = mDevices.valueAt(i); if (!device->isIgnored()) { outInputDevices.push(); device->getDeviceInfo(&outInputDevices.editTop()); } } } int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) { AutoMutex _l(mLock); return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState); } int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode) { AutoMutex _l(mLock); return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState); } int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) { AutoMutex _l(mLock); return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState); } int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { int32_t result = AKEY_STATE_UNKNOWN; if (deviceId >= 0) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { InputDevice* device = mDevices.valueAt(deviceIndex); if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { result = (device->*getStateFunc)(sourceMask, code); } } } else { size_t numDevices = mDevices.size(); for (size_t i = 0; i < numDevices; i++) { InputDevice* device = mDevices.valueAt(i); if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that // value. Otherwise, return AKEY_STATE_UP as long as one device reports it. int32_t currentResult = (device->*getStateFunc)(sourceMask, code); if (currentResult >= AKEY_STATE_DOWN) { return currentResult; } else if (currentResult == AKEY_STATE_UP) { result = currentResult; } } } } return result; } bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { AutoMutex _l(mLock); memset(outFlags, 0, numCodes); return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags); } bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { bool result = false; if (deviceId >= 0) { ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { InputDevice* device = mDevices.valueAt(deviceIndex); if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); } } } else { size_t numDevices = mDevices.size(); for (size_t i = 0; i < numDevices; i++) { InputDevice* device = mDevices.valueAt(i); if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { result |= device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); } } } return result; } void InputReader::requestRefreshConfiguration(uint32_t changes) { AutoMutex _l(mLock); if (changes) { bool needWake = !mConfigurationChangesToRefresh; mConfigurationChangesToRefresh |= changes; if (needWake) { mEventHub->wake(); } } } void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) { AutoMutex _l(mLock); ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { InputDevice* device = mDevices.valueAt(deviceIndex); device->vibrate(pattern, patternSize, repeat, token); } } void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { AutoMutex _l(mLock); ssize_t deviceIndex = mDevices.indexOfKey(deviceId); if (deviceIndex >= 0) { InputDevice* device = mDevices.valueAt(deviceIndex); device->cancelVibrate(token); } } void InputReader::dump(String8& dump) { AutoMutex _l(mLock); mEventHub->dump(dump); dump.append("\n"); dump.append("Input Reader State:\n"); for (size_t i = 0; i < mDevices.size(); i++) { mDevices.valueAt(i)->dump(dump); } dump.append(INDENT "Configuration:\n"); dump.append(INDENT2 "ExcludedDeviceNames: ["); for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { if (i != 0) { dump.append(", "); } dump.append(c_str(mConfig.excludedDeviceNames.itemAt(i))); } dump.append("]\n"); appendFormat(dump, INDENT2 "VirtualKeyQuietTime: %0.1fms\n", mConfig.virtualKeyQuietTime * 0.000001f); appendFormat(dump, INDENT2 "PointerVelocityControlParameters: " "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", mConfig.pointerVelocityControlParameters.scale, mConfig.pointerVelocityControlParameters.lowThreshold, mConfig.pointerVelocityControlParameters.highThreshold, mConfig.pointerVelocityControlParameters.acceleration); appendFormat(dump, INDENT2 "WheelVelocityControlParameters: " "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", mConfig.wheelVelocityControlParameters.scale, mConfig.wheelVelocityControlParameters.lowThreshold, mConfig.wheelVelocityControlParameters.highThreshold, mConfig.wheelVelocityControlParameters.acceleration); appendFormat(dump, INDENT2 "PointerGesture:\n"); appendFormat(dump, INDENT3 "Enabled: %s\n", toString(mConfig.pointerGesturesEnabled)); appendFormat(dump, INDENT3 "QuietInterval: %0.1fms\n", mConfig.pointerGestureQuietInterval * 0.000001f); appendFormat(dump, INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", mConfig.pointerGestureDragMinSwitchSpeed); appendFormat(dump, INDENT3 "TapInterval: %0.1fms\n", mConfig.pointerGestureTapInterval * 0.000001f); appendFormat(dump, INDENT3 "TapDragInterval: %0.1fms\n", mConfig.pointerGestureTapDragInterval * 0.000001f); appendFormat(dump, INDENT3 "TapSlop: %0.1fpx\n", mConfig.pointerGestureTapSlop); appendFormat(dump, INDENT3 "MultitouchSettleInterval: %0.1fms\n", mConfig.pointerGestureMultitouchSettleInterval * 0.000001f); appendFormat(dump, INDENT3 "MultitouchMinDistance: %0.1fpx\n", mConfig.pointerGestureMultitouchMinDistance); appendFormat(dump, INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", mConfig.pointerGestureSwipeTransitionAngleCosine); appendFormat(dump, INDENT3 "SwipeMaxWidthRatio: %0.1f\n", mConfig.pointerGestureSwipeMaxWidthRatio); appendFormat(dump, INDENT3 "MovementSpeedRatio: %0.1f\n", mConfig.pointerGestureMovementSpeedRatio); appendFormat(dump, INDENT3 "ZoomSpeedRatio: %0.1f\n", mConfig.pointerGestureZoomSpeedRatio); } void InputReader::monitor() { // Acquire and release the lock to ensure that the reader has not deadlocked. mLock.lock(); mEventHub->wake(); mReaderIsAliveCondition.wait(mLock); mLock.unlock(); // Check the EventHub mEventHub->monitor(); } // --- InputReader::ContextImpl --- InputReader::ContextImpl::ContextImpl(InputReader* reader) : mReader(reader) { } void InputReader::ContextImpl::updateGlobalMetaState() { // lock is already held by the input loop mReader->updateGlobalMetaStateLocked(); } int32_t InputReader::ContextImpl::getGlobalMetaState() { // lock is already held by the input loop return mReader->getGlobalMetaStateLocked(); } void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) { // lock is already held by the input loop mReader->disableVirtualKeysUntilLocked(time); } bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode) { // lock is already held by the input loop return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode); } void InputReader::ContextImpl::fadePointer() { // lock is already held by the input loop mReader->fadePointerLocked(); } void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) { // lock is already held by the input loop mReader->requestTimeoutAtTimeLocked(when); } int32_t InputReader::ContextImpl::bumpGeneration() { // lock is already held by the input loop return mReader->bumpGenerationLocked(); } InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { return mReader->mPolicy.get(); } InputListenerInterface* InputReader::ContextImpl::getListener() { return mReader->mQueuedListener.get(); } EventHubInterface* InputReader::ContextImpl::getEventHub() { return mReader->mEventHub.get(); } // --- InputReaderThread --- InputReaderThread::InputReaderThread(const sp& reader) : Thread(/*canCallJava*/ true), mReader(reader) { } InputReaderThread::~InputReaderThread() { } bool InputReaderThread::threadLoop() { mReader->loopOnce(); return true; } // --- InputDevice --- InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, const InputDeviceIdentifier& identifier, uint32_t classes) : mContext(context), mId(id), mGeneration(generation), mIdentifier(identifier), mClasses(classes), mSources(0), mIsExternal(false), mDropUntilNextSync(false) { } InputDevice::~InputDevice() { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { delete mMappers[i]; } mMappers.clear(); } void InputDevice::dump(String8& dump) { InputDeviceInfo deviceInfo; getDeviceInfo(& deviceInfo); appendFormat(dump, INDENT "Device %d: %s\n", deviceInfo.getId(), c_str(deviceInfo.getDisplayName())); appendFormat(dump, INDENT2 "Generation: %d\n", mGeneration); appendFormat(dump, INDENT2 "IsExternal: %s\n", toString(mIsExternal)); appendFormat(dump, INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); appendFormat(dump, INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); const Vector& ranges = deviceInfo.getMotionRanges(); if (!ranges.isEmpty()) { dump.append(INDENT2 "Motion Ranges:\n"); for (size_t i = 0; i < ranges.size(); i++) { const InputDeviceInfo::MotionRange& range = ranges.itemAt(i); const char* label = getAxisLabel(range.axis); char name[32]; if (label) { strncpy(name, label, sizeof(name)); name[sizeof(name) - 1] = '\0'; } else { snprintf(name, sizeof(name), "%d", range.axis); } appendFormat(dump, INDENT3 "%s: source=0x%08x, " "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n", name, range.source, range.min, range.max, range.flat, range.fuzz); } } size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->dump(dump); } } void InputDevice::addMapper(InputMapper* mapper) { mMappers.add(mapper); } void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { mSources = 0; if (!isIgnored()) { if (!changes) { // first time only mContext->getEventHub()->getConfiguration(mId, &mConfiguration); } if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { sp keyboardLayout = mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier.descriptor); if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { bumpGeneration(); } } } if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) { if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { String8 alias = mContext->getPolicy()->getDeviceAlias(mIdentifier); if (mAlias != alias) { mAlias = alias; bumpGeneration(); } } } size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->configure(when, config, changes); mSources |= mapper->getSources(); } } } void InputDevice::reset(nsecs_t when) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->reset(when); } mContext->updateGlobalMetaState(); notifyReset(when); } void InputDevice::process(const RawEvent* rawEvents, size_t count) { // Process all of the events in order for each mapper. // We cannot simply ask each mapper to process them in bulk because mappers may // have side-effects that must be interleaved. For example, joystick movement events and // gamepad button presses are handled by different mappers but they should be dispatched // in the order received. size_t numMappers = mMappers.size(); for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { #if DEBUG_RAW_EVENTS char inputStr[200]; inputEvToStr(inputStr, rawEvent->type, rawEvent->code, rawEvent->value); ALOGD("Input event: device=%d %s", rawEvent->deviceId, inputStr); #endif if (mDropUntilNextSync) { if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { mDropUntilNextSync = false; #if DEBUG_RAW_EVENTS ALOGD("Recovered from input event buffer overrun."); #endif } else { #if DEBUG_RAW_EVENTS ALOGD("Dropped input event while waiting for next input sync."); #endif } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { ALOGI("Detected input event buffer overrun for device %s.", c_str(getName())); mDropUntilNextSync = true; reset(rawEvent->when); } else { for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->process(rawEvent); } } } } void InputDevice::timeoutExpired(nsecs_t when) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->timeoutExpired(when); } } void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { outDeviceInfo->initialize(mId, mGeneration, mIdentifier, mAlias, mIsExternal); size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->populateDeviceInfo(outDeviceInfo); } } int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState); } int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { return getState(sourceMask, scanCode, & InputMapper::getScanCodeState); } int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) { return getState(sourceMask, switchCode, & InputMapper::getSwitchState); } int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { int32_t result = AKEY_STATE_UNKNOWN; size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; if (sourcesMatchMask(mapper->getSources(), sourceMask)) { // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it. int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code); if (currentResult >= AKEY_STATE_DOWN) { return currentResult; } else if (currentResult == AKEY_STATE_UP) { result = currentResult; } } } return result; } bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { bool result = false; size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; if (sourcesMatchMask(mapper->getSources(), sourceMask)) { result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); } } return result; } void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->vibrate(pattern, patternSize, repeat, token); } } void InputDevice::cancelVibrate(int32_t token) { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->cancelVibrate(token); } } int32_t InputDevice::getMetaState() { int32_t result = 0; size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; result |= mapper->getMetaState(); } return result; } void InputDevice::fadePointer() { size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; mapper->fadePointer(); } } void InputDevice::bumpGeneration() { mGeneration = mContext->bumpGeneration(); } void InputDevice::notifyReset(nsecs_t when) { NotifyDeviceResetArgs args(when, mId); mContext->getListener()->notifyDeviceReset(&args); } // --- CursorButtonAccumulator --- CursorButtonAccumulator::CursorButtonAccumulator() { clearButtons(); } void CursorButtonAccumulator::reset(InputDevice* device) { mBtnLeft = device->isKeyPressed(BTN_LEFT); mBtnRight = device->isKeyPressed(BTN_RIGHT); mBtnMiddle = device->isKeyPressed(BTN_MIDDLE); mBtnBack = device->isKeyPressed(BTN_BACK); mBtnSide = device->isKeyPressed(BTN_SIDE); mBtnForward = device->isKeyPressed(BTN_FORWARD); mBtnExtra = device->isKeyPressed(BTN_EXTRA); mBtnTask = device->isKeyPressed(BTN_TASK); } void CursorButtonAccumulator::clearButtons() { mBtnLeft = 0; mBtnRight = 0; mBtnMiddle = 0; mBtnBack = 0; mBtnSide = 0; mBtnForward = 0; mBtnExtra = 0; mBtnTask = 0; } void CursorButtonAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_KEY) { switch (rawEvent->code) { case BTN_LEFT: mBtnLeft = rawEvent->value; break; case BTN_RIGHT: mBtnRight = rawEvent->value; break; case BTN_MIDDLE: mBtnMiddle = rawEvent->value; break; case BTN_BACK: mBtnBack = rawEvent->value; break; case BTN_SIDE: mBtnSide = rawEvent->value; break; case BTN_FORWARD: mBtnForward = rawEvent->value; break; case BTN_EXTRA: mBtnExtra = rawEvent->value; break; case BTN_TASK: mBtnTask = rawEvent->value; break; } } } uint32_t CursorButtonAccumulator::getButtonState() const { uint32_t result = 0; if (mBtnLeft) { result |= AMOTION_EVENT_BUTTON_PRIMARY; } if (mBtnRight) { result |= AMOTION_EVENT_BUTTON_SECONDARY; } if (mBtnMiddle) { result |= AMOTION_EVENT_BUTTON_TERTIARY; } if (mBtnBack || mBtnSide) { result |= AMOTION_EVENT_BUTTON_BACK; } if (mBtnForward || mBtnExtra) { result |= AMOTION_EVENT_BUTTON_FORWARD; } return result; } // --- CursorMotionAccumulator --- CursorMotionAccumulator::CursorMotionAccumulator() { clearRelativeAxes(); } void CursorMotionAccumulator::reset(InputDevice* device) { clearRelativeAxes(); } void CursorMotionAccumulator::clearRelativeAxes() { mRelX = 0; mRelY = 0; } void CursorMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_REL) { switch (rawEvent->code) { case REL_X: mRelX = rawEvent->value; break; case REL_Y: mRelY = rawEvent->value; break; } } } void CursorMotionAccumulator::finishSync() { clearRelativeAxes(); } // --- CursorScrollAccumulator --- CursorScrollAccumulator::CursorScrollAccumulator() : mHaveRelWheel(false), mHaveRelHWheel(false) { clearRelativeAxes(); } void CursorScrollAccumulator::configure(InputDevice* device) { mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL); mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL); } void CursorScrollAccumulator::reset(InputDevice* device) { clearRelativeAxes(); } void CursorScrollAccumulator::clearRelativeAxes() { mRelWheel = 0; mRelHWheel = 0; } void CursorScrollAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_REL) { switch (rawEvent->code) { case REL_WHEEL: mRelWheel = rawEvent->value; break; case REL_HWHEEL: mRelHWheel = rawEvent->value; break; } } } void CursorScrollAccumulator::finishSync() { clearRelativeAxes(); } // --- TouchButtonAccumulator --- TouchButtonAccumulator::TouchButtonAccumulator() : mHaveBtnTouch(false), mHaveStylus(false) { clearButtons(); } void TouchButtonAccumulator::configure(InputDevice* device) { mHaveBtnTouch = device->hasKey(BTN_TOUCH); mHaveStylus = device->hasKey(BTN_TOOL_PEN) || device->hasKey(BTN_TOOL_RUBBER) || device->hasKey(BTN_TOOL_BRUSH) || device->hasKey(BTN_TOOL_PENCIL) || device->hasKey(BTN_TOOL_AIRBRUSH); } void TouchButtonAccumulator::reset(InputDevice* device) { mBtnTouch = device->isKeyPressed(BTN_TOUCH); mBtnStylus = device->isKeyPressed(BTN_STYLUS); mBtnStylus2 = device->isKeyPressed(BTN_STYLUS); mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH); mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL); mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH); mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE); mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS); mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP); mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP); mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP); } void TouchButtonAccumulator::clearButtons() { mBtnTouch = 0; mBtnStylus = 0; mBtnStylus2 = 0; mBtnToolFinger = 0; mBtnToolPen = 0; mBtnToolRubber = 0; mBtnToolBrush = 0; mBtnToolPencil = 0; mBtnToolAirbrush = 0; mBtnToolMouse = 0; mBtnToolLens = 0; mBtnToolDoubleTap = 0; mBtnToolTripleTap = 0; mBtnToolQuadTap = 0; } void TouchButtonAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_KEY) { switch (rawEvent->code) { case BTN_TOUCH: mBtnTouch = rawEvent->value; break; case BTN_STYLUS: mBtnStylus = rawEvent->value; break; case BTN_STYLUS2: mBtnStylus2 = rawEvent->value; break; case BTN_TOOL_FINGER: mBtnToolFinger = rawEvent->value; break; case BTN_TOOL_PEN: mBtnToolPen = rawEvent->value; break; case BTN_TOOL_RUBBER: mBtnToolRubber = rawEvent->value; break; case BTN_TOOL_BRUSH: mBtnToolBrush = rawEvent->value; break; case BTN_TOOL_PENCIL: mBtnToolPencil = rawEvent->value; break; case BTN_TOOL_AIRBRUSH: mBtnToolAirbrush = rawEvent->value; break; case BTN_TOOL_MOUSE: mBtnToolMouse = rawEvent->value; break; case BTN_TOOL_LENS: mBtnToolLens = rawEvent->value; break; case BTN_TOOL_DOUBLETAP: mBtnToolDoubleTap = rawEvent->value; break; case BTN_TOOL_TRIPLETAP: mBtnToolTripleTap = rawEvent->value; break; case BTN_TOOL_QUADTAP: mBtnToolQuadTap = rawEvent->value; break; } } } uint32_t TouchButtonAccumulator::getButtonState() const { uint32_t result = 0; if (mBtnStylus) { result |= AMOTION_EVENT_BUTTON_SECONDARY; } if (mBtnStylus2) { result |= AMOTION_EVENT_BUTTON_TERTIARY; } return result; } int32_t TouchButtonAccumulator::getToolType() const { if (mBtnToolMouse || mBtnToolLens) { return AMOTION_EVENT_TOOL_TYPE_MOUSE; } if (mBtnToolRubber) { return AMOTION_EVENT_TOOL_TYPE_ERASER; } if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { return AMOTION_EVENT_TOOL_TYPE_STYLUS; } if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) { return AMOTION_EVENT_TOOL_TYPE_FINGER; } return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; } bool TouchButtonAccumulator::isToolActive() const { return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush || mBtnToolMouse || mBtnToolLens || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap; } bool TouchButtonAccumulator::isHovering() const { return mHaveBtnTouch && !mBtnTouch; } bool TouchButtonAccumulator::hasStylus() const { return mHaveStylus; } // --- RawPointerAxes --- RawPointerAxes::RawPointerAxes() { clear(); } void RawPointerAxes::clear() { x.clear(); y.clear(); pressure.clear(); touchMajor.clear(); touchMinor.clear(); toolMajor.clear(); toolMinor.clear(); orientation.clear(); distance.clear(); tiltX.clear(); tiltY.clear(); trackingId.clear(); slot.clear(); } // --- RawPointerData --- RawPointerData::RawPointerData() { clear(); } void RawPointerData::clear() { pointerCount = 0; clearIds(); } void RawPointerData::copyFrom(const RawPointerData& other) { pointerCount = other.pointerCount; hoveringIds = other.hoveringIds; touchingIds = other.touchingIds; for (uint32_t i = 0; i < pointerCount; i++) { pointers[i] = other.pointers[i]; int id = pointers[i].id; } } void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const { float x = 0, y = 0; uint32_t count = touchingIds.count(); if (count) { touchingIds.forEach([&](int32_t id) { const Pointer& pointer = pointerForId(id); x += pointer.x; y += pointer.y; }); x /= count; y /= count; } *outX = x; *outY = y; } // --- CookedPointerData --- CookedPointerData::CookedPointerData() { clear(); } void CookedPointerData::clear() { pointerCount = 0; hoveringIds.clear(); touchingIds.clear(); } void CookedPointerData::copyFrom(const CookedPointerData& other) { pointerCount = other.pointerCount; hoveringIds = other.hoveringIds; touchingIds = other.touchingIds; for (uint32_t i = 0; i < pointerCount; i++) { pointerProperties[i].copyFrom(other.pointerProperties[i]); pointerCoords[i].copyFrom(other.pointerCoords[i]); } } // --- SingleTouchMotionAccumulator --- SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() { clearAbsoluteAxes(); } void SingleTouchMotionAccumulator::reset(InputDevice* device) { mAbsX = device->getAbsoluteAxisValue(ABS_X); mAbsY = device->getAbsoluteAxisValue(ABS_Y); mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE); mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH); mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE); mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X); mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y); } void SingleTouchMotionAccumulator::clearAbsoluteAxes() { mAbsX = 0; mAbsY = 0; mAbsPressure = 0; mAbsToolWidth = 0; mAbsDistance = 0; mAbsTiltX = 0; mAbsTiltY = 0; } void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_ABS) { switch (rawEvent->code) { case ABS_X: mAbsX = rawEvent->value; break; case ABS_Y: mAbsY = rawEvent->value; break; case ABS_PRESSURE: mAbsPressure = rawEvent->value; break; case ABS_TOOL_WIDTH: mAbsToolWidth = rawEvent->value; break; case ABS_DISTANCE: mAbsDistance = rawEvent->value; break; case ABS_TILT_X: mAbsTiltX = rawEvent->value; break; case ABS_TILT_Y: mAbsTiltY = rawEvent->value; break; } } } // --- MultiTouchMotionAccumulator --- MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false), mHaveStylus(false) { } MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { delete[] mSlots; } void MultiTouchMotionAccumulator::configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol) { mSlotCount = slotCount; mUsingSlotsProtocol = usingSlotsProtocol; mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE); delete[] mSlots; mSlots = new Slot[slotCount]; } void MultiTouchMotionAccumulator::reset(InputDevice* device) { // Unfortunately there is no way to read the initial contents of the slots. // So when we reset the accumulator, we must assume they are all zeroes. if (mUsingSlotsProtocol) { // Query the driver for the current slot index and use it as the initial slot // before we start reading events from the device. It is possible that the // current slot index will not be the same as it was when the first event was // written into the evdev buffer, which means the input mapper could start // out of sync with the initial state of the events in the evdev buffer. // In the extremely unlikely case that this happens, the data from // two slots will be confused until the next ABS_MT_SLOT event is received. // This can cause the touch point to "jump", but at least there will be // no stuck touches. int32_t initialSlot; status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(), ABS_MT_SLOT, &initialSlot); if (status) { ALOGD("Could not retrieve current multitouch slot index. status=%d", status); initialSlot = -1; } clearSlots(initialSlot); } else { clearSlots(-1); } } void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { if (mSlots) { for (size_t i = 0; i < mSlotCount; i++) { mSlots[i].clear(); } } mCurrentSlot = initialSlot; } void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_ABS) { bool newSlot = false; if (mUsingSlotsProtocol) { if (rawEvent->code == ABS_MT_SLOT) { mCurrentSlot = rawEvent->value; newSlot = true; } } else if (mCurrentSlot < 0) { mCurrentSlot = 0; } if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { #if DEBUG_POINTERS if (newSlot) { ALOGW("MultiTouch device emitted invalid slot index %d but it " "should be between 0 and %d; ignoring this slot.", mCurrentSlot, mSlotCount - 1); } #endif } else { Slot* slot = &mSlots[mCurrentSlot]; switch (rawEvent->code) { case ABS_MT_POSITION_X: slot->mInUse = true; slot->mAbsMTPositionX = rawEvent->value; break; case ABS_MT_POSITION_Y: slot->mInUse = true; slot->mAbsMTPositionY = rawEvent->value; break; case ABS_MT_TOUCH_MAJOR: slot->mInUse = true; slot->mAbsMTTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: slot->mInUse = true; slot->mAbsMTTouchMinor = rawEvent->value; slot->mHaveAbsMTTouchMinor = true; break; case ABS_MT_WIDTH_MAJOR: slot->mInUse = true; slot->mAbsMTWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: slot->mInUse = true; slot->mAbsMTWidthMinor = rawEvent->value; slot->mHaveAbsMTWidthMinor = true; break; case ABS_MT_ORIENTATION: slot->mInUse = true; slot->mAbsMTOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: if (mUsingSlotsProtocol && rawEvent->value < 0) { // The slot is no longer in use but it retains its previous contents, // which may be reused for subsequent touches. slot->mInUse = false; } else { slot->mInUse = true; slot->mAbsMTTrackingId = rawEvent->value; } break; case ABS_MT_PRESSURE: slot->mInUse = true; slot->mAbsMTPressure = rawEvent->value; slot->mHaveAbsMTPressure = true; break; case ABS_MT_DISTANCE: slot->mInUse = true; slot->mAbsMTDistance = rawEvent->value; break; case ABS_MT_TOOL_TYPE: slot->mInUse = true; slot->mAbsMTToolType = rawEvent->value; slot->mHaveAbsMTToolType = true; break; } } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { // MultiTouch Sync: The driver has returned all data for *one* of the pointers. mCurrentSlot += 1; } } void MultiTouchMotionAccumulator::finishSync() { if (!mUsingSlotsProtocol) { clearSlots(-1); } } bool MultiTouchMotionAccumulator::hasStylus() const { return mHaveStylus; } // --- MultiTouchMotionAccumulator::Slot --- MultiTouchMotionAccumulator::Slot::Slot() { clear(); } void MultiTouchMotionAccumulator::Slot::clear() { mInUse = false; mHaveAbsMTTouchMinor = false; mHaveAbsMTWidthMinor = false; mHaveAbsMTPressure = false; mHaveAbsMTToolType = false; mAbsMTPositionX = 0; mAbsMTPositionY = 0; mAbsMTTouchMajor = 0; mAbsMTTouchMinor = 0; mAbsMTWidthMajor = 0; mAbsMTWidthMinor = 0; mAbsMTOrientation = 0; mAbsMTTrackingId = -1; mAbsMTPressure = 0; mAbsMTDistance = 0; mAbsMTToolType = 0; } int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { if (mHaveAbsMTToolType) { switch (mAbsMTToolType) { case MT_TOOL_FINGER: return AMOTION_EVENT_TOOL_TYPE_FINGER; case MT_TOOL_PEN: return AMOTION_EVENT_TOOL_TYPE_STYLUS; } } return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; } // --- InputMapper --- InputMapper::InputMapper(InputDevice* device) : mDevice(device), mContext(device->getContext()) { } InputMapper::~InputMapper() { } void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->addSource(getSources()); } void InputMapper::dump(String8& dump) { } void InputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { } void InputMapper::reset(nsecs_t when) { } void InputMapper::timeoutExpired(nsecs_t when) { } int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { return AKEY_STATE_UNKNOWN; } int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { return AKEY_STATE_UNKNOWN; } int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { return AKEY_STATE_UNKNOWN; } bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { return false; } void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) { } void InputMapper::cancelVibrate(int32_t token) { } int32_t InputMapper::getMetaState() { return 0; } void InputMapper::fadePointer() { } status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) { return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo); } void InputMapper::bumpGeneration() { mDevice->bumpGeneration(); } void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump, const RawAbsoluteAxisInfo& axis, const char* name) { if (axis.valid) { appendFormat(dump, INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n", name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution); } else { appendFormat(dump, INDENT4 "%s: unknown range\n", name); } } // --- SwitchInputMapper --- SwitchInputMapper::SwitchInputMapper(InputDevice* device) : InputMapper(device) { } SwitchInputMapper::~SwitchInputMapper() { } uint32_t SwitchInputMapper::getSources() { return AINPUT_SOURCE_SWITCH; } void SwitchInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_SW: processSwitch(rawEvent->when, rawEvent->code, rawEvent->value); break; } } void SwitchInputMapper::processSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) { NotifySwitchArgs args(when, 0, switchCode, switchValue); getListener()->notifySwitch(&args); } int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { return getEventHub()->getSwitchState(getDeviceId(), switchCode); } // --- VibratorInputMapper --- VibratorInputMapper::VibratorInputMapper(InputDevice* device) : InputMapper(device), mVibrating(false) { } VibratorInputMapper::~VibratorInputMapper() { } uint32_t VibratorInputMapper::getSources() { return 0; } void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); info->setVibrator(true); } void VibratorInputMapper::process(const RawEvent* rawEvent) { // TODO: Handle FF_STATUS, although it does not seem to be widely supported. } void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) { #if DEBUG_VIBRATOR String8 patternStr; for (size_t i = 0; i < patternSize; i++) { if (i != 0) { patternStr.append(", "); } patternStr.appendFormat("%lld", pattern[i]); } ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d", getDeviceId(), c_str(patternStr), repeat, token); #endif mVibrating = true; memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t)); mPatternSize = patternSize; mRepeat = repeat; mToken = token; mIndex = -1; nextStep(); } void VibratorInputMapper::cancelVibrate(int32_t token) { #if DEBUG_VIBRATOR ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token); #endif if (mVibrating && mToken == token) { stopVibrating(); } } void VibratorInputMapper::timeoutExpired(nsecs_t when) { if (mVibrating) { if (when >= mNextStepTime) { nextStep(); } else { getContext()->requestTimeoutAtTime(mNextStepTime); } } } void VibratorInputMapper::nextStep() { mIndex += 1; if (size_t(mIndex) >= mPatternSize) { if (mRepeat < 0) { // We are done. stopVibrating(); return; } mIndex = mRepeat; } bool vibratorOn = mIndex & 1; nsecs_t duration = mPattern[mIndex]; if (vibratorOn) { #if DEBUG_VIBRATOR ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld", getDeviceId(), duration); #endif getEventHub()->vibrate(getDeviceId(), duration); } else { #if DEBUG_VIBRATOR ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId()); #endif getEventHub()->cancelVibrate(getDeviceId()); } nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); mNextStepTime = now + duration; getContext()->requestTimeoutAtTime(mNextStepTime); #if DEBUG_VIBRATOR ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f); #endif } void VibratorInputMapper::stopVibrating() { mVibrating = false; #if DEBUG_VIBRATOR ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId()); #endif getEventHub()->cancelVibrate(getDeviceId()); } void VibratorInputMapper::dump(String8& dump) { dump.append(INDENT2 "Vibrator Input Mapper:\n"); appendFormat(dump, INDENT3 "Vibrating: %s\n", toString(mVibrating)); } // --- KeyboardInputMapper --- KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType) : InputMapper(device), mSource(source), mKeyboardType(keyboardType) { } KeyboardInputMapper::~KeyboardInputMapper() { } uint32_t KeyboardInputMapper::getSources() { return mSource; } void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); info->setKeyboardType(mKeyboardType); info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId())); } void KeyboardInputMapper::dump(String8& dump) { dump.append(INDENT2 "Keyboard Input Mapper:\n"); dumpParameters(dump); appendFormat(dump, INDENT3 "KeyboardType: %d\n", mKeyboardType); appendFormat(dump, INDENT3 "Orientation: %d\n", mOrientation); appendFormat(dump, INDENT3 "KeyDowns: %d keys currently down\n", mKeyDowns.size()); appendFormat(dump, INDENT3 "MetaState: 0x%0x\n", mMetaState); appendFormat(dump, INDENT3 "DownTime: %lld\n", mDownTime); } void KeyboardInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { InputMapper::configure(when, config, changes); if (!changes) { // first time only // Configure basic parameters. configureParameters(); } if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) { if (!config->getDisplayInfo(mParameters.associatedDisplayId, false /*external*/, NULL, NULL, &mOrientation)) { mOrientation = DISPLAY_ORIENTATION_0; } } else { mOrientation = DISPLAY_ORIENTATION_0; } } } void KeyboardInputMapper::configureParameters() { mParameters.orientationAware = false; getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"), mParameters.orientationAware); mParameters.associatedDisplayId = -1; if (mParameters.orientationAware) { mParameters.associatedDisplayId = 0; } } void KeyboardInputMapper::dumpParameters(String8& dump) { dump.append(INDENT3 "Parameters:\n"); appendFormat(dump, INDENT4 "AssociatedDisplayId: %d\n", mParameters.associatedDisplayId); appendFormat(dump, INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); } void KeyboardInputMapper::reset(nsecs_t when) { mMetaState = AMETA_NONE; mDownTime = 0; mKeyDowns.clear(); mCurrentHidUsage = 0; resetLedState(); InputMapper::reset(when); } void KeyboardInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_KEY: { int32_t scanCode = rawEvent->code; int32_t usageCode = mCurrentHidUsage; mCurrentHidUsage = 0; if (isKeyboardOrGamepadKey(scanCode)) { int32_t keyCode; uint32_t flags; if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) { keyCode = AKEYCODE_UNKNOWN; flags = 0; } processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags); } break; } case EV_MSC: { if (rawEvent->code == MSC_SCAN) { mCurrentHidUsage = rawEvent->value; } break; } case EV_SYN: { if (rawEvent->code == SYN_REPORT) { mCurrentHidUsage = 0; } } } } bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { return scanCode < BTN_MOUSE || scanCode >= KEY_OK || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI); } void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) { if (down) { // Rotate key codes according to orientation if needed. if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) { keyCode = rotateKeyCode(keyCode, mOrientation); } // Add key down. ssize_t keyDownIndex = findKeyDown(scanCode); if (keyDownIndex >= 0) { // key repeat, be sure to use same keycode as before in case of rotation keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; } else { // key down if ((policyFlags & POLICY_FLAG_VIRTUAL) && mContext->shouldDropVirtualKey(when, getDevice(), keyCode, scanCode)) { return; } mKeyDowns.push(); KeyDown& keyDown = mKeyDowns.editTop(); keyDown.keyCode = keyCode; keyDown.scanCode = scanCode; } mDownTime = when; } else { // Remove key down. ssize_t keyDownIndex = findKeyDown(scanCode); if (keyDownIndex >= 0) { // key up, be sure to use same keycode as before in case of rotation keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; mKeyDowns.removeAt(size_t(keyDownIndex)); } else { // key was not actually down ALOGI("Dropping key up from device %s because the key was not down. " "keyCode=%d, scanCode=%d", c_str(getDeviceName()), keyCode, scanCode); return; } } bool metaStateChanged = false; int32_t oldMetaState = mMetaState; int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState); if (oldMetaState != newMetaState) { mMetaState = newMetaState; metaStateChanged = true; updateLedState(false); } nsecs_t downTime = mDownTime; // Key down on external an keyboard should wake the device. // We don't do this for internal keyboards to prevent them from waking up in your pocket. // For internal keyboards, the key layout file should specify the policy flags for // each wake key individually. // TODO: Use the input device configuration to control this behavior more finely. if (down && getDevice()->isExternal() && !(policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED))) { policyFlags |= POLICY_FLAG_WAKE_DROPPED; } if (metaStateChanged) { getContext()->updateGlobalMetaState(); } if (down && !isMetaKey(keyCode)) { getContext()->fadePointer(); } NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime); getListener()->notifyKey(&args); } ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) { size_t n = mKeyDowns.size(); for (size_t i = 0; i < n; i++) { if (mKeyDowns[i].scanCode == scanCode) { return i; } } return -1; } int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { return getEventHub()->getKeyCodeState(getDeviceId(), keyCode); } int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { return getEventHub()->getScanCodeState(getDeviceId(), scanCode); } bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags); } int32_t KeyboardInputMapper::getMetaState() { return mMetaState; } void KeyboardInputMapper::resetLedState() { initializeLedState(mCapsLockLedState, LED_CAPSL); initializeLedState(mNumLockLedState, LED_NUML); initializeLedState(mScrollLockLedState, LED_SCROLLL); updateLedState(true); } void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) { ledState.avail = getEventHub()->hasLed(getDeviceId(), led); ledState.on = false; } void KeyboardInputMapper::updateLedState(bool reset) { updateLedStateForModifier(mCapsLockLedState, LED_CAPSL, AMETA_CAPS_LOCK_ON, reset); updateLedStateForModifier(mNumLockLedState, LED_NUML, AMETA_NUM_LOCK_ON, reset); updateLedStateForModifier(mScrollLockLedState, LED_SCROLLL, AMETA_SCROLL_LOCK_ON, reset); } void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset) { if (ledState.avail) { bool desiredState = (mMetaState & modifier) != 0; if (reset || ledState.on != desiredState) { getEventHub()->setLedState(getDeviceId(), led, desiredState); ledState.on = desiredState; } } } // --- CursorInputMapper --- CursorInputMapper::CursorInputMapper(InputDevice* device) : InputMapper(device) { } CursorInputMapper::~CursorInputMapper() { } uint32_t CursorInputMapper::getSources() { return mSource; } void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); if (mParameters.mode == Parameters::MODE_POINTER) { float minX, minY, maxX, maxY; if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f); info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f); } } else { info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale); info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale); } info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f); if (mCursorScrollAccumulator.haveRelativeVWheel()) { info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f); } if (mCursorScrollAccumulator.haveRelativeHWheel()) { info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f); } } void CursorInputMapper::dump(String8& dump) { dump.append(INDENT2 "Cursor Input Mapper:\n"); dumpParameters(dump); appendFormat(dump, INDENT3 "XScale: %0.3f\n", mXScale); appendFormat(dump, INDENT3 "YScale: %0.3f\n", mYScale); appendFormat(dump, INDENT3 "XPrecision: %0.3f\n", mXPrecision); appendFormat(dump, INDENT3 "YPrecision: %0.3f\n", mYPrecision); appendFormat(dump, INDENT3 "HaveVWheel: %s\n", toString(mCursorScrollAccumulator.haveRelativeVWheel())); appendFormat(dump, INDENT3 "HaveHWheel: %s\n", toString(mCursorScrollAccumulator.haveRelativeHWheel())); appendFormat(dump, INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); appendFormat(dump, INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); appendFormat(dump, INDENT3 "Orientation: %d\n", mOrientation); appendFormat(dump, INDENT3 "ButtonState: 0x%08x\n", mButtonState); appendFormat(dump, INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); appendFormat(dump, INDENT3 "DownTime: %lld\n", mDownTime); } void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { InputMapper::configure(when, config, changes); if (!changes) { // first time only mCursorScrollAccumulator.configure(getDevice()); // Configure basic parameters. configureParameters(); // Configure device mode. switch (mParameters.mode) { case Parameters::MODE_POINTER: mSource = AINPUT_SOURCE_MOUSE; mXPrecision = 1.0f; mYPrecision = 1.0f; mXScale = 1.0f; mYScale = 1.0f; mPointerController = getPolicy()->obtainPointerController(getDeviceId()); break; case Parameters::MODE_NAVIGATION: mSource = AINPUT_SOURCE_TRACKBALL; mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; break; } mVWheelScale = 1.0f; mHWheelScale = 1.0f; } if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters); mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters); mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters); } if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) { if (!config->getDisplayInfo(mParameters.associatedDisplayId, false /*external*/, NULL, NULL, &mOrientation)) { mOrientation = DISPLAY_ORIENTATION_0; } } else { mOrientation = DISPLAY_ORIENTATION_0; } bumpGeneration(); } } void CursorInputMapper::configureParameters() { mParameters.mode = Parameters::MODE_POINTER; String8 cursorModeString; if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) { if (cursorModeString == "navigation") { mParameters.mode = Parameters::MODE_NAVIGATION; } else if (cursorModeString != "pointer" && cursorModeString != "default") { ALOGW("Invalid value for cursor.mode: '%s'", c_str(cursorModeString)); } } mParameters.orientationAware = false; getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"), mParameters.orientationAware); mParameters.associatedDisplayId = -1; if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) { mParameters.associatedDisplayId = 0; } } void CursorInputMapper::dumpParameters(String8& dump) { dump.append(INDENT3 "Parameters:\n"); appendFormat(dump, INDENT4 "AssociatedDisplayId: %d\n", mParameters.associatedDisplayId); switch (mParameters.mode) { case Parameters::MODE_POINTER: dump.append(INDENT4 "Mode: pointer\n"); break; case Parameters::MODE_NAVIGATION: dump.append(INDENT4 "Mode: navigation\n"); break; default: ALOG_ASSERT(false); } appendFormat(dump, INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); } void CursorInputMapper::reset(nsecs_t when) { mButtonState = 0; mDownTime = 0; mPointerVelocityControl.reset(); mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); mCursorButtonAccumulator.reset(getDevice()); mCursorMotionAccumulator.reset(getDevice()); mCursorScrollAccumulator.reset(getDevice()); InputMapper::reset(when); } void CursorInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorMotionAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { sync(rawEvent->when); } } void CursorInputMapper::sync(nsecs_t when) { int32_t lastButtonState = mButtonState; int32_t currentButtonState = mCursorButtonAccumulator.getButtonState(); mButtonState = currentButtonState; bool wasDown = isPointerDown(lastButtonState); bool down = isPointerDown(currentButtonState); bool downChanged; if (!wasDown && down) { mDownTime = when; downChanged = true; } else if (wasDown && !down) { downChanged = true; } else { downChanged = false; } nsecs_t downTime = mDownTime; bool buttonsChanged = currentButtonState != lastButtonState; bool buttonsPressed = currentButtonState & ~lastButtonState; float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; bool moved = deltaX != 0 || deltaY != 0; // Rotate delta according to orientation if needed. if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0 && (deltaX != 0.0f || deltaY != 0.0f)) { rotateDelta(mOrientation, &deltaX, &deltaY); } // Move the pointer. PointerProperties pointerProperties; pointerProperties.clear(); pointerProperties.id = 0; pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE; PointerCoords pointerCoords; pointerCoords.clear(); float vscroll = mCursorScrollAccumulator.getRelativeVWheel(); float hscroll = mCursorScrollAccumulator.getRelativeHWheel(); bool scrolled = vscroll != 0 || hscroll != 0; mWheelYVelocityControl.move(when, NULL, &vscroll); mWheelXVelocityControl.move(when, &hscroll, NULL); mPointerVelocityControl.move(when, &deltaX, &deltaY); if (mPointerController != NULL) { if (moved || scrolled || buttonsChanged) { mPointerController->setPresentation( PointerControllerInterface::PRESENTATION_POINTER); if (moved) { mPointerController->move(deltaX, deltaY); } if (buttonsChanged) { mPointerController->setButtonState(currentButtonState); } mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); } float x, y; mPointerController->getPosition(&x, &y); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); } else { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); } pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); // Moving an external trackball or mouse should wake the device. // We don't do this for internal cursor devices to prevent them from waking up // the device in your pocket. // TODO: Use the input device configuration to control this behavior more finely. uint32_t policyFlags = 0; if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) { policyFlags |= POLICY_FLAG_WAKE_DROPPED; } // Synthesize key down from buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, policyFlags, lastButtonState, currentButtonState); // Send motion event. if (downChanged || moved || scrolled || buttonsChanged) { int32_t metaState = mContext->getGlobalMetaState(); int32_t motionEventAction; if (downChanged) { motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; } else if (down || mPointerController == NULL) { motionEventAction = AMOTION_EVENT_ACTION_MOVE; } else { motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; } NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, motionEventAction, 0, metaState, currentButtonState, 0, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); getListener()->notifyMotion(&args); // Send hover move after UP to tell the application that the mouse is hovering now. if (motionEventAction == AMOTION_EVENT_ACTION_UP && mPointerController != NULL) { NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); getListener()->notifyMotion(&hoverArgs); } // Send scroll events. if (scrolled) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, mXPrecision, mYPrecision, downTime); getListener()->notifyMotion(&scrollArgs); } } // Synthesize key up from buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, policyFlags, lastButtonState, currentButtonState); mCursorMotionAccumulator.finishSync(); mCursorScrollAccumulator.finishSync(); } int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { return getEventHub()->getScanCodeState(getDeviceId(), scanCode); } else { return AKEY_STATE_UNKNOWN; } } void CursorInputMapper::fadePointer() { if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); } } // --- TouchInputMapper --- TouchInputMapper::TouchInputMapper(InputDevice* device) : InputMapper(device), mSource(0), mDeviceMode(DEVICE_MODE_DISABLED), mSurfaceOrientation(-1), mSurfaceWidth(-1), mSurfaceHeight(-1), mPointerUsage(POINTER_USAGE_NONE), mNextNewPointerId(0) { } TouchInputMapper::~TouchInputMapper() { } uint32_t TouchInputMapper::getSources() { return mSource; } void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); if (mDeviceMode != DEVICE_MODE_DISABLED) { info->addMotionRange(mOrientedRanges.x); info->addMotionRange(mOrientedRanges.y); info->addMotionRange(mOrientedRanges.pressure); if (mOrientedRanges.haveSize) { info->addMotionRange(mOrientedRanges.size); } if (mOrientedRanges.haveTouchSize) { info->addMotionRange(mOrientedRanges.touchMajor); info->addMotionRange(mOrientedRanges.touchMinor); } if (mOrientedRanges.haveToolSize) { info->addMotionRange(mOrientedRanges.toolMajor); info->addMotionRange(mOrientedRanges.toolMinor); } if (mOrientedRanges.haveOrientation) { info->addMotionRange(mOrientedRanges.orientation); } if (mOrientedRanges.haveDistance) { info->addMotionRange(mOrientedRanges.distance); } if (mOrientedRanges.haveTilt) { info->addMotionRange(mOrientedRanges.tilt); } if (mCursorScrollAccumulator.haveRelativeVWheel()) { info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f); } if (mCursorScrollAccumulator.haveRelativeHWheel()) { info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f); } } } void TouchInputMapper::dump(String8& dump) { dump.append(INDENT2 "Touch Input Mapper:\n"); dumpParameters(dump); dumpVirtualKeys(dump); dumpRawPointerAxes(dump); dumpCalibration(dump); dumpSurface(dump); appendFormat(dump, INDENT3 "Translation and Scaling Factors:\n"); appendFormat(dump, INDENT4 "XScale: %0.3f\n", mXScale); appendFormat(dump, INDENT4 "YScale: %0.3f\n", mYScale); appendFormat(dump, INDENT4 "XPrecision: %0.3f\n", mXPrecision); appendFormat(dump, INDENT4 "YPrecision: %0.3f\n", mYPrecision); appendFormat(dump, INDENT4 "GeometricScale: %0.3f\n", mGeometricScale); appendFormat(dump, INDENT4 "PressureScale: %0.3f\n", mPressureScale); appendFormat(dump, INDENT4 "SizeScale: %0.3f\n", mSizeScale); appendFormat(dump, INDENT4 "OrientationCenter: %0.3f\n", mOrientationCenter); appendFormat(dump, INDENT4 "OrientationScale: %0.3f\n", mOrientationScale); appendFormat(dump, INDENT4 "DistanceScale: %0.3f\n", mDistanceScale); appendFormat(dump, INDENT4 "HaveTilt: %s\n", toString(mHaveTilt)); appendFormat(dump, INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter); appendFormat(dump, INDENT4 "TiltXScale: %0.3f\n", mTiltXScale); appendFormat(dump, INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); appendFormat(dump, INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); appendFormat(dump, INDENT3 "Last Button State: 0x%08x\n", mLastButtonState); appendFormat(dump, INDENT3 "Last Raw Touch: pointerCount=%d\n", mLastRawPointerData.pointerCount); for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) { const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i]; appendFormat(dump, INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " "toolType=%d, isHovering=%s\n", i, pointer.id, pointer.x, pointer.y, pointer.pressure, pointer.touchMajor, pointer.touchMinor, pointer.toolMajor, pointer.toolMinor, pointer.orientation, pointer.tiltX, pointer.tiltY, pointer.distance, pointer.toolType, toString(pointer.isHovering)); } appendFormat(dump, INDENT3 "Last Cooked Touch: pointerCount=%d\n", mLastCookedPointerData.pointerCount); for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) { const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i]; const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i]; appendFormat(dump, INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " "toolType=%d, isHovering=%s\n", i, pointerProperties.id, pointerCoords.getX(), pointerCoords.getY(), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), pointerProperties.toolType, toString(mLastCookedPointerData.isHovering(i))); } if (mDeviceMode == DEVICE_MODE_POINTER) { appendFormat(dump, INDENT3 "Pointer Gesture Detector:\n"); appendFormat(dump, INDENT4 "XMovementScale: %0.3f\n", mPointerXMovementScale); appendFormat(dump, INDENT4 "YMovementScale: %0.3f\n", mPointerYMovementScale); appendFormat(dump, INDENT4 "XZoomScale: %0.3f\n", mPointerXZoomScale); appendFormat(dump, INDENT4 "YZoomScale: %0.3f\n", mPointerYZoomScale); appendFormat(dump, INDENT4 "MaxSwipeWidth: %f\n", mPointerGestureMaxSwipeWidth); } } void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { InputMapper::configure(when, config, changes); mConfig = *config; if (!changes) { // first time only // Configure basic parameters. configureParameters(); // Configure common accumulators. mCursorScrollAccumulator.configure(getDevice()); mTouchButtonAccumulator.configure(getDevice()); // Configure absolute axis information. configureRawPointerAxes(); // Prepare input device calibration. parseCalibration(); resolveCalibration(); } if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { // Update pointer speed. mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters); mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); } bool resetNeeded = false; if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) { // Configure device sources, surface dimensions, orientation and // scaling factors. configureSurface(when, &resetNeeded); } if (changes && resetNeeded) { // Send reset, unless this is the first time the device has been configured, // in which case the reader will call reset itself after all mappers are ready. getDevice()->notifyReset(when); } } void TouchInputMapper::configureParameters() { // Use the pointer presentation mode for devices that do not support distinct // multitouch. The spot-based presentation relies on being able to accurately // locate two or more fingers on the touch pad. mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT) ? Parameters::GESTURE_MODE_POINTER : Parameters::GESTURE_MODE_SPOTS; String8 gestureModeString; if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"), gestureModeString)) { if (gestureModeString == "pointer") { mParameters.gestureMode = Parameters::GESTURE_MODE_POINTER; } else if (gestureModeString == "spots") { mParameters.gestureMode = Parameters::GESTURE_MODE_SPOTS; } else if (gestureModeString != "default") { ALOGW("Invalid value for touch.gestureMode: '%s'", c_str(gestureModeString)); } } if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) { // The device is a touch screen. mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) { // The device is a pointing device like a track pad. mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { // The device is a cursor device with a touch pad attached. // By default don't use the touch pad to move the pointer. mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; } else { // The device is a touch pad of unknown purpose. mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; } String8 deviceTypeString; if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), deviceTypeString)) { if (deviceTypeString == "touchScreen") { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; } else if (deviceTypeString == "touchPad") { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; } else if (deviceTypeString == "pointer") { mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; } else if (deviceTypeString != "default") { ALOGW("Invalid value for touch.deviceType: '%s'", c_str(deviceTypeString)); } } mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), mParameters.orientationAware); mParameters.associatedDisplayId = -1; mParameters.associatedDisplayIsExternal = false; if (mParameters.orientationAware || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { mParameters.associatedDisplayIsExternal = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN && getDevice()->isExternal(); mParameters.associatedDisplayId = 0; } } void TouchInputMapper::dumpParameters(String8& dump) { dump.append(INDENT3 "Parameters:\n"); switch (mParameters.gestureMode) { case Parameters::GESTURE_MODE_POINTER: dump.append(INDENT4 "GestureMode: pointer\n"); break; case Parameters::GESTURE_MODE_SPOTS: dump.append(INDENT4 "GestureMode: spots\n"); break; default: assert(false); } switch (mParameters.deviceType) { case Parameters::DEVICE_TYPE_TOUCH_SCREEN: dump.append(INDENT4 "DeviceType: touchScreen\n"); break; case Parameters::DEVICE_TYPE_TOUCH_PAD: dump.append(INDENT4 "DeviceType: touchPad\n"); break; case Parameters::DEVICE_TYPE_POINTER: dump.append(INDENT4 "DeviceType: pointer\n"); break; default: ALOG_ASSERT(false); } appendFormat(dump, INDENT4 "AssociatedDisplay: id=%d, isExternal=%s\n", mParameters.associatedDisplayId, toString(mParameters.associatedDisplayIsExternal)); appendFormat(dump, INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); } void TouchInputMapper::configureRawPointerAxes() { mRawPointerAxes.clear(); } void TouchInputMapper::dumpRawPointerAxes(String8& dump) { dump.append(INDENT3 "Raw Touch Axes:\n"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId"); dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); } void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { int32_t oldDeviceMode = mDeviceMode; // Determine device mode. if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER && mConfig.pointerGesturesEnabled) { mSource = AINPUT_SOURCE_MOUSE; mDeviceMode = DEVICE_MODE_POINTER; if (hasStylus()) { mSource |= AINPUT_SOURCE_STYLUS; } } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN && mParameters.associatedDisplayId >= 0) { mSource = AINPUT_SOURCE_TOUCHSCREEN; mDeviceMode = DEVICE_MODE_DIRECT; if (hasStylus()) { mSource |= AINPUT_SOURCE_STYLUS; } } else { mSource = AINPUT_SOURCE_TOUCHPAD; mDeviceMode = DEVICE_MODE_UNSCALED; } // Ensure we have valid X and Y axes. if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) { ALOGW(INDENT "Touch device '%s' did not report support for X or Y axis! " "The device will be inoperable.", c_str(getDeviceName())); mDeviceMode = DEVICE_MODE_DISABLED; return; } // Get associated display dimensions. if (mParameters.associatedDisplayId >= 0) { if (!mConfig.getDisplayInfo(mParameters.associatedDisplayId, mParameters.associatedDisplayIsExternal, &mAssociatedDisplayWidth, &mAssociatedDisplayHeight, &mAssociatedDisplayOrientation)) { ALOGI(INDENT "Touch device '%s' could not query the properties of its associated " "display %d. The device will be inoperable until the display size " "becomes available.", c_str(getDeviceName()), mParameters.associatedDisplayId); mDeviceMode = DEVICE_MODE_DISABLED; return; } } // Configure dimensions. int32_t width, height, orientation; if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) { width = mAssociatedDisplayWidth; height = mAssociatedDisplayHeight; orientation = mParameters.orientationAware ? mAssociatedDisplayOrientation : DISPLAY_ORIENTATION_0; } else { width = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; height = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; orientation = DISPLAY_ORIENTATION_0; } // If moving between pointer modes, need to reset some state. bool deviceModeChanged = false; if (mDeviceMode != oldDeviceMode) { deviceModeChanged = true; mOrientedRanges.clear(); } // Create pointer controller if needed. if (mDeviceMode == DEVICE_MODE_POINTER || (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) { if (mPointerController == NULL) { mPointerController = getPolicy()->obtainPointerController(getDeviceId()); } } else { mPointerController.clear(); } bool orientationChanged = mSurfaceOrientation != orientation; if (orientationChanged) { mSurfaceOrientation = orientation; } bool sizeChanged = mSurfaceWidth != width || mSurfaceHeight != height; if (sizeChanged || deviceModeChanged) { ALOGI("Device reconfigured: id=%d, name='%s', surface size is now %dx%d, mode is %d", getDeviceId(), c_str(getDeviceName()), width, height, mDeviceMode); mSurfaceWidth = width; mSurfaceHeight = height; // Configure X and Y factors. mXScale = float(width) / (mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1); mYScale = float(height) / (mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1); mXPrecision = 1.0f / mXScale; mYPrecision = 1.0f / mYScale; mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X; mOrientedRanges.x.source = mSource; mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; mOrientedRanges.y.source = mSource; configureVirtualKeys(); // Scale factor for terms that are not oriented in a particular axis. // If the pixels are square then xScale == yScale otherwise we fake it // by choosing an average. mGeometricScale = avg(mXScale, mYScale); // Size of diagonal axis. float diagonalSize = hypotf(width, height); // Size factors. if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) { if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) { mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue; } else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) { mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue; } else { mSizeScale = 0.0f; } mOrientedRanges.haveTouchSize = true; mOrientedRanges.haveToolSize = true; mOrientedRanges.haveSize = true; mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; mOrientedRanges.touchMajor.source = mSource; mOrientedRanges.touchMajor.min = 0; mOrientedRanges.touchMajor.max = diagonalSize; mOrientedRanges.touchMajor.flat = 0; mOrientedRanges.touchMajor.fuzz = 0; mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; mOrientedRanges.toolMajor.source = mSource; mOrientedRanges.toolMajor.min = 0; mOrientedRanges.toolMajor.max = diagonalSize; mOrientedRanges.toolMajor.flat = 0; mOrientedRanges.toolMajor.fuzz = 0; mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; mOrientedRanges.size.source = mSource; mOrientedRanges.size.min = 0; mOrientedRanges.size.max = 1.0; mOrientedRanges.size.flat = 0; mOrientedRanges.size.fuzz = 0; } else { mSizeScale = 0.0f; } // Pressure factors. mPressureScale = 0; if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL || mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { if (mCalibration.havePressureScale) { mPressureScale = mCalibration.pressureScale; } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) { mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; } } mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; mOrientedRanges.pressure.source = mSource; mOrientedRanges.pressure.min = 0; mOrientedRanges.pressure.max = 1.0; mOrientedRanges.pressure.flat = 0; mOrientedRanges.pressure.fuzz = 0; // Tilt mTiltXCenter = 0; mTiltXScale = 0; mTiltYCenter = 0; mTiltYScale = 0; mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid; if (mHaveTilt) { mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, mRawPointerAxes.tiltX.maxValue); mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, mRawPointerAxes.tiltY.maxValue); mTiltXScale = M_PI / 180; mTiltYScale = M_PI / 180; mOrientedRanges.haveTilt = true; mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; mOrientedRanges.tilt.source = mSource; mOrientedRanges.tilt.min = 0; mOrientedRanges.tilt.max = M_PI_2; mOrientedRanges.tilt.flat = 0; mOrientedRanges.tilt.fuzz = 0; } // Orientation mOrientationCenter = 0; mOrientationScale = 0; if (mHaveTilt) { mOrientedRanges.haveOrientation = true; mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; mOrientedRanges.orientation.source = mSource; mOrientedRanges.orientation.min = -M_PI; mOrientedRanges.orientation.max = M_PI; mOrientedRanges.orientation.flat = 0; mOrientedRanges.orientation.fuzz = 0; } else if (mCalibration.orientationCalibration != Calibration::ORIENTATION_CALIBRATION_NONE) { if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { if (mRawPointerAxes.orientation.valid) { mOrientationCenter = avg(mRawPointerAxes.orientation.minValue, mRawPointerAxes.orientation.maxValue); mOrientationScale = M_PI / (mRawPointerAxes.orientation.maxValue - mRawPointerAxes.orientation.minValue); } } mOrientedRanges.haveOrientation = true; mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; mOrientedRanges.orientation.source = mSource; mOrientedRanges.orientation.min = -M_PI_2; mOrientedRanges.orientation.max = M_PI_2; mOrientedRanges.orientation.flat = 0; mOrientedRanges.orientation.fuzz = 0; } // Distance mDistanceScale = 0; if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) { if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_SCALED) { if (mCalibration.haveDistanceScale) { mDistanceScale = mCalibration.distanceScale; } else { mDistanceScale = 1.0f; } } mOrientedRanges.haveDistance = true; mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; mOrientedRanges.distance.source = mSource; mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale; mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale; mOrientedRanges.distance.flat = 0; mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale; } } if (orientationChanged || sizeChanged || deviceModeChanged) { // Compute oriented surface dimensions, precision, scales and ranges. // Note that the maximum value reported is an inclusive maximum value so it is one // unit less than the total width or height of surface. switch (mSurfaceOrientation) { case DISPLAY_ORIENTATION_90: case DISPLAY_ORIENTATION_270: mOrientedSurfaceWidth = mSurfaceHeight; mOrientedSurfaceHeight = mSurfaceWidth; mOrientedXPrecision = mYPrecision; mOrientedYPrecision = mXPrecision; mOrientedRanges.x.min = 0; mOrientedRanges.x.max = (mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue) * mYScale; mOrientedRanges.x.flat = 0; mOrientedRanges.x.fuzz = mYScale; mOrientedRanges.y.min = 0; mOrientedRanges.y.max = (mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue) * mXScale; mOrientedRanges.y.flat = 0; mOrientedRanges.y.fuzz = mXScale; break; default: mOrientedSurfaceWidth = mSurfaceWidth; mOrientedSurfaceHeight = mSurfaceHeight; mOrientedXPrecision = mXPrecision; mOrientedYPrecision = mYPrecision; mOrientedRanges.x.min = 0; mOrientedRanges.x.max = (mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue) * mXScale; mOrientedRanges.x.flat = 0; mOrientedRanges.x.fuzz = mXScale; mOrientedRanges.y.min = 0; mOrientedRanges.y.max = (mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue) * mYScale; mOrientedRanges.y.flat = 0; mOrientedRanges.y.fuzz = mYScale; break; } // Compute pointer gesture detection parameters. if (mDeviceMode == DEVICE_MODE_POINTER) { int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; float rawDiagonal = hypotf(rawWidth, rawHeight); float displayDiagonal = hypotf(mAssociatedDisplayWidth, mAssociatedDisplayHeight); // Scale movements such that one whole swipe of the touch pad covers a // given area relative to the diagonal size of the display when no acceleration // is applied. // Assume that the touch pad has a square aspect ratio such that movements in // X and Y of the same number of raw units cover the same physical distance. mPointerXMovementScale = mConfig.pointerGestureMovementSpeedRatio * displayDiagonal / rawDiagonal; mPointerYMovementScale = mPointerXMovementScale; // Scale zooms to cover a smaller range of the display than movements do. // This value determines the area around the pointer that is affected by freeform // pointer gestures. mPointerXZoomScale = mConfig.pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal; mPointerYZoomScale = mPointerXZoomScale; // Max width between pointers to detect a swipe gesture is more than some fraction // of the diagonal axis of the touch pad. Touches that are wider than this are // translated into freeform gestures. mPointerGestureMaxSwipeWidth = mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal; } // Abort current pointer usages because the state has changed. abortPointerUsage(when, 0 /*policyFlags*/); // Inform the dispatcher about the changes. *outResetNeeded = true; bumpGeneration(); } } void TouchInputMapper::dumpSurface(String8& dump) { appendFormat(dump, INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth); appendFormat(dump, INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight); appendFormat(dump, INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation); } void TouchInputMapper::configureVirtualKeys() { Vector virtualKeyDefinitions; getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); mVirtualKeys.clear(); if (virtualKeyDefinitions.size() == 0) { return; } mVirtualKeys.setCapacity(virtualKeyDefinitions.size()); int32_t touchScreenLeft = mRawPointerAxes.x.minValue; int32_t touchScreenTop = mRawPointerAxes.y.minValue; int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { const VirtualKeyDefinition& virtualKeyDefinition = virtualKeyDefinitions[i]; mVirtualKeys.add(); VirtualKey& virtualKey = mVirtualKeys.editTop(); virtualKey.scanCode = virtualKeyDefinition.scanCode; int32_t keyCode; uint32_t flags; if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, &keyCode, &flags)) { ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode); mVirtualKeys.pop(); // drop the key continue; } virtualKey.keyCode = keyCode; virtualKey.flags = flags; // convert the key definition's display coordinates into touch coordinates for a hit box int32_t halfWidth = virtualKeyDefinition.width / 2; int32_t halfHeight = virtualKeyDefinition.height / 2; virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mSurfaceWidth + touchScreenLeft; virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mSurfaceWidth + touchScreenLeft; virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / mSurfaceHeight + touchScreenTop; virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mSurfaceHeight + touchScreenTop; } } void TouchInputMapper::dumpVirtualKeys(String8& dump) { if (!mVirtualKeys.isEmpty()) { dump.append(INDENT3 "Virtual Keys:\n"); for (size_t i = 0; i < mVirtualKeys.size(); i++) { const VirtualKey& virtualKey = mVirtualKeys.itemAt(i); appendFormat(dump, INDENT4 "%d: scanCode=%d, keyCode=%d, " "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", i, virtualKey.scanCode, virtualKey.keyCode, virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom); } } } void TouchInputMapper::parseCalibration() { const PropertyMap& in = getDevice()->getConfiguration(); Calibration& out = mCalibration; // Size out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT; String8 sizeCalibrationString; if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) { if (sizeCalibrationString == "none") { out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; } else if (sizeCalibrationString == "geometric") { out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; } else if (sizeCalibrationString == "diameter") { out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER; } else if (sizeCalibrationString == "area") { out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA; } else if (sizeCalibrationString != "default") { ALOGW("Invalid value for touch.size.calibration: '%s'", c_str(sizeCalibrationString)); } } out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), out.sizeScale); out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), out.sizeBias); out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), out.sizeIsSummed); // Pressure out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT; String8 pressureCalibrationString; if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) { if (pressureCalibrationString == "none") { out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; } else if (pressureCalibrationString == "physical") { out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; } else if (pressureCalibrationString == "amplitude") { out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; } else if (pressureCalibrationString != "default") { ALOGW("Invalid value for touch.pressure.calibration: '%s'", c_str(pressureCalibrationString)); } } out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), out.pressureScale); // Orientation out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT; String8 orientationCalibrationString; if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) { if (orientationCalibrationString == "none") { out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; } else if (orientationCalibrationString == "interpolated") { out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; } else if (orientationCalibrationString == "vector") { out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR; } else if (orientationCalibrationString != "default") { ALOGW("Invalid value for touch.orientation.calibration: '%s'", c_str(orientationCalibrationString)); } } // Distance out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT; String8 distanceCalibrationString; if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) { if (distanceCalibrationString == "none") { out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; } else if (distanceCalibrationString == "scaled") { out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; } else if (distanceCalibrationString != "default") { ALOGW("Invalid value for touch.distance.calibration: '%s'", c_str(distanceCalibrationString)); } } out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), out.distanceScale); } void TouchInputMapper::resolveCalibration() { // Size if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) { if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) { mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; } } else { mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; } // Pressure if (mRawPointerAxes.pressure.valid) { if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) { mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; } } else { mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; } // Orientation if (mRawPointerAxes.orientation.valid) { if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) { mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; } } else { mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; } // Distance if (mRawPointerAxes.distance.valid) { if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) { mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; } } else { mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; } } void TouchInputMapper::dumpCalibration(String8& dump) { dump.append(INDENT3 "Calibration:\n"); // Size switch (mCalibration.sizeCalibration) { case Calibration::SIZE_CALIBRATION_NONE: dump.append(INDENT4 "touch.size.calibration: none\n"); break; case Calibration::SIZE_CALIBRATION_GEOMETRIC: dump.append(INDENT4 "touch.size.calibration: geometric\n"); break; case Calibration::SIZE_CALIBRATION_DIAMETER: dump.append(INDENT4 "touch.size.calibration: diameter\n"); break; case Calibration::SIZE_CALIBRATION_AREA: dump.append(INDENT4 "touch.size.calibration: area\n"); break; default: ALOG_ASSERT(false); } if (mCalibration.haveSizeScale) { appendFormat(dump, INDENT4 "touch.size.scale: %0.3f\n", mCalibration.sizeScale); } if (mCalibration.haveSizeBias) { appendFormat(dump, INDENT4 "touch.size.bias: %0.3f\n", mCalibration.sizeBias); } if (mCalibration.haveSizeIsSummed) { appendFormat(dump, INDENT4 "touch.size.isSummed: %s\n", toString(mCalibration.sizeIsSummed)); } // Pressure switch (mCalibration.pressureCalibration) { case Calibration::PRESSURE_CALIBRATION_NONE: dump.append(INDENT4 "touch.pressure.calibration: none\n"); break; case Calibration::PRESSURE_CALIBRATION_PHYSICAL: dump.append(INDENT4 "touch.pressure.calibration: physical\n"); break; case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: dump.append(INDENT4 "touch.pressure.calibration: amplitude\n"); break; default: ALOG_ASSERT(false); } if (mCalibration.havePressureScale) { appendFormat(dump, INDENT4 "touch.pressure.scale: %0.3f\n", mCalibration.pressureScale); } // Orientation switch (mCalibration.orientationCalibration) { case Calibration::ORIENTATION_CALIBRATION_NONE: dump.append(INDENT4 "touch.orientation.calibration: none\n"); break; case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: dump.append(INDENT4 "touch.orientation.calibration: interpolated\n"); break; case Calibration::ORIENTATION_CALIBRATION_VECTOR: dump.append(INDENT4 "touch.orientation.calibration: vector\n"); break; default: ALOG_ASSERT(false); } // Distance switch (mCalibration.distanceCalibration) { case Calibration::DISTANCE_CALIBRATION_NONE: dump.append(INDENT4 "touch.distance.calibration: none\n"); break; case Calibration::DISTANCE_CALIBRATION_SCALED: dump.append(INDENT4 "touch.distance.calibration: scaled\n"); break; default: ALOG_ASSERT(false); } if (mCalibration.haveDistanceScale) { appendFormat(dump, INDENT4 "touch.distance.scale: %0.3f\n", mCalibration.distanceScale); } } void TouchInputMapper::reset(nsecs_t when) { mCursorButtonAccumulator.reset(getDevice()); mCursorScrollAccumulator.reset(getDevice()); mTouchButtonAccumulator.reset(getDevice()); mPointerVelocityControl.reset(); mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); mCurrentRawPointerData.clear(); mLastRawPointerData.clear(); mCurrentCookedPointerData.clear(); mLastCookedPointerData.clear(); mCurrentButtonState = 0; mLastButtonState = 0; mCurrentRawVScroll = 0; mCurrentRawHScroll = 0; mCurrentFingerIds.clear(); mLastFingerIds.clear(); mCurrentStylusIds.clear(); mLastStylusIds.clear(); mCurrentMouseIds.clear(); mLastMouseIds.clear(); mPointerUsage = POINTER_USAGE_NONE; mSentHoverEnter = false; mDownTime = 0; mCurrentVirtualKey.down = false; mPointerGesture.reset(); mPointerSimple.reset(); if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); mPointerController->clearSpots(); } InputMapper::reset(when); } void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); mTouchButtonAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { sync(rawEvent->when); } } void TouchInputMapper::sync(nsecs_t when) { // Sync button state. mCurrentButtonState = mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); // Sync scroll state. mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); mCursorScrollAccumulator.finishSync(); // Sync touch state. bool havePointerIds = true; mCurrentRawPointerData.clear(); syncTouch(when, &havePointerIds); #if DEBUG_RAW_EVENTS if (!havePointerIds) { ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids", mLastRawPointerData.pointerCount, mCurrentRawPointerData.pointerCount); } else { std::string lastTouchingIdsString = mLastRawPointerData.touchingIds.toString(); std::string currentTouchingIdsString = mCurrentRawPointerData.touchingIds.toString(); std::string lastHoveringIdsString = mLastRawPointerData.hoveringIds.toString(); std::string currentHoveringIdsString = mCurrentRawPointerData.hoveringIds.toString(); ALOGD("syncTouch: pointerCount %u -> %u, touching ids (%s) -> (%s), " "hovering ids (%s) -> (%s)", mLastRawPointerData.pointerCount, mCurrentRawPointerData.pointerCount, lastTouchingIdsString.c_str(), currentTouchingIdsString.c_str(), lastHoveringIdsString.c_str(), currentHoveringIdsString.c_str()); } #endif // Reset state that we will compute below. mCurrentFingerIds.clear(); mCurrentStylusIds.clear(); mCurrentMouseIds.clear(); mCurrentCookedPointerData.clear(); if (mDeviceMode == DEVICE_MODE_DISABLED) { // Drop all input if the device is disabled. mCurrentRawPointerData.clear(); mCurrentButtonState = 0; } else { // Preprocess pointer data. if (!havePointerIds) { assignPointerIds(); } // Handle policy on initial down or hover events. uint32_t policyFlags = 0; bool initialDown = mLastRawPointerData.pointerCount == 0 && mCurrentRawPointerData.pointerCount != 0; bool buttonsPressed = mCurrentButtonState & ~mLastButtonState; if (initialDown || buttonsPressed) { // If this is a touch screen, hide the pointer on an initial down. if (mDeviceMode == DEVICE_MODE_DIRECT) { getContext()->fadePointer(); } // Initial downs on external touch devices should wake the device. // We don't do this for internal touch screens to prevent them from waking // up in your pocket. // TODO: Use the input device configuration to control this behavior more finely. if (getDevice()->isExternal()) { policyFlags |= POLICY_FLAG_WAKE_DROPPED; } } // Synthesize key down from raw buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, policyFlags, mLastButtonState, mCurrentButtonState); // Consume raw off-screen touches before cooking pointer data. // If touches are consumed, subsequent code will not receive any pointer data. if (consumeRawTouches(when, policyFlags)) { mCurrentRawPointerData.clear(); } // Cook pointer data. This call populates the mCurrentCookedPointerData structure // with cooked pointer data that has the same ids and indices as the raw data. // The following code can use either the raw or cooked data, as needed. cookPointerData(); // Dispatch the touches either directly or by translation through a pointer on screen. if (mDeviceMode == DEVICE_MODE_POINTER) { for (uint32_t i = 0; i < mCurrentRawPointerData.pointerCount; ++i) { const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointers[i]; if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { mCurrentStylusIds.insert(pointer.id); } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { mCurrentFingerIds.insert(pointer.id); } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { mCurrentMouseIds.insert(pointer.id); } } mCurrentRawPointerData.hoveringIds.forEach([&](int32_t id) { const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { mCurrentStylusIds.insert(id); } }); // Stylus takes precedence over all tools, then mouse, then finger. PointerUsage pointerUsage = mPointerUsage; if (!mCurrentStylusIds.isEmpty()) { mCurrentMouseIds.clear(); mCurrentFingerIds.clear(); pointerUsage = POINTER_USAGE_STYLUS; } else if (!mCurrentMouseIds.isEmpty()) { mCurrentFingerIds.clear(); pointerUsage = POINTER_USAGE_MOUSE; } else if (!mCurrentFingerIds.isEmpty() || isPointerDown(mCurrentButtonState)) { pointerUsage = POINTER_USAGE_GESTURES; } dispatchPointerUsage(when, policyFlags, pointerUsage); } else { if (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches && mPointerController != NULL) { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); mPointerController->setButtonState(mCurrentButtonState); mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.pointerCount); } dispatchHoverExit(when, policyFlags); dispatchTouches(when, policyFlags); dispatchHoverEnterAndMove(when, policyFlags); } // Synthesize key up from raw buttons if needed. synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, policyFlags, mLastButtonState, mCurrentButtonState); } // Copy current touch to last touch in preparation for the next cycle. mLastRawPointerData.copyFrom(mCurrentRawPointerData); mLastCookedPointerData.copyFrom(mCurrentCookedPointerData); mLastButtonState = mCurrentButtonState; mLastFingerIds = mCurrentFingerIds; mLastStylusIds = mCurrentStylusIds; mLastMouseIds = mCurrentMouseIds; // Clear some transient state. mCurrentRawVScroll = 0; mCurrentRawHScroll = 0; } void TouchInputMapper::timeoutExpired(nsecs_t when) { if (mDeviceMode == DEVICE_MODE_POINTER) { if (mPointerUsage == POINTER_USAGE_GESTURES) { dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); } } } bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { // Check for release of a virtual key. if (mCurrentVirtualKey.down) { if (mCurrentRawPointerData.touchingIds.isEmpty()) { // Pointer went up while virtual key was down. mCurrentVirtualKey.down = false; if (!mCurrentVirtualKey.ignored) { #if DEBUG_VIRTUAL_KEYS ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); #endif dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); } return true; } if (mCurrentRawPointerData.touchingIds.count() == 1) { int32_t id = mCurrentRawPointerData.touchingIds.first(); const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { // Pointer is still within the space of the virtual key. return true; } } // Pointer left virtual key area or another pointer also went down. // Send key cancellation but do not consume the touch yet. // This is useful when the user swipes through from the virtual key area // into the main display surface. mCurrentVirtualKey.down = false; if (!mCurrentVirtualKey.ignored) { #if DEBUG_VIRTUAL_KEYS ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); #endif dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY | AKEY_EVENT_FLAG_CANCELED); } } if (mLastRawPointerData.touchingIds.isEmpty() && !mCurrentRawPointerData.touchingIds.isEmpty()) { // Pointer just went down. Check for virtual key press or off-screen touches. int32_t id = mCurrentRawPointerData.touchingIds.first(); const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); if (!isPointInsideSurface(pointer.x, pointer.y)) { // If exactly one pointer went down, check for virtual key hit. // Otherwise we will drop the entire stroke. if (mCurrentRawPointerData.touchingIds.count() == 1) { const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); if (virtualKey) { mCurrentVirtualKey.down = true; mCurrentVirtualKey.downTime = when; mCurrentVirtualKey.keyCode = virtualKey->keyCode; mCurrentVirtualKey.scanCode = virtualKey->scanCode; mCurrentVirtualKey.ignored = mContext->shouldDropVirtualKey( when, getDevice(), virtualKey->keyCode, virtualKey->scanCode); if (!mCurrentVirtualKey.ignored) { #if DEBUG_VIRTUAL_KEYS ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); #endif dispatchVirtualKey(when, policyFlags, AKEY_EVENT_ACTION_DOWN, AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); } } } return true; } } // Disable all virtual key touches that happen within a short time interval of the // most recent touch within the screen area. The idea is to filter out stray // virtual key presses when interacting with the touch screen. // // Problems we're trying to solve: // // 1. While scrolling a list or dragging the window shade, the user swipes down into a // virtual key area that is implemented by a separate touch panel and accidentally // triggers a virtual key. // // 2. While typing in the on screen keyboard, the user taps slightly outside the screen // area and accidentally triggers a virtual key. This often happens when virtual keys // are layed out below the screen near to where the on screen keyboard's space bar // is displayed. if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIds.isEmpty()) { mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); } return false; } void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyEventAction, int32_t keyEventFlags) { int32_t keyCode = mCurrentVirtualKey.keyCode; int32_t scanCode = mCurrentVirtualKey.scanCode; nsecs_t downTime = mCurrentVirtualKey.downTime; int32_t metaState = mContext->getGlobalMetaState(); policyFlags |= POLICY_FLAG_VIRTUAL; NotifyKeyArgs args(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); getListener()->notifyKey(&args); } void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { IntSet ¤tIds = mCurrentCookedPointerData.touchingIds; IntSet &lastIds = mLastCookedPointerData.touchingIds; int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentButtonState; if (currentIds == lastIds) { if (!currentIds.isEmpty()) { // No pointer id changes so this is a move event. // The listener takes care of batching moves so we don't have to deal with that here. dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.pointerCount, currentIds, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } else { // There may be pointers going up and pointers going down and pointers moving // all at the same time. IntSet upIds = lastIds - currentIds; IntSet downIds = currentIds - lastIds; IntSet moveIds = lastIds & currentIds; IntSet dispatchedIds = lastIds; // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. bool moveNeeded = updateMovedPointers( mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.pointerCount, mLastCookedPointerData.pointerProperties, mLastCookedPointerData.pointerCoords, mLastCookedPointerData.pointerCount, moveIds); if (buttonState != mLastButtonState) { moveNeeded = true; } // Dispatch pointer up events. upIds.forEach([&](int32_t upId) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0, mLastCookedPointerData.pointerProperties, mLastCookedPointerData.pointerCoords, mLastCookedPointerData.pointerCount, dispatchedIds, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); dispatchedIds.remove(upId); }); // Dispatch move events if any of the remaining pointers moved from their old locations. // Although applications receive new locations as part of individual pointer up // events, they do not generally handle them except when presented in a move event. if (moveNeeded) { ALOG_ASSERT(moveIds == dispatchedIds); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.pointerCount, dispatchedIds, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } // Dispatch pointer down events using the new pointer locations. downIds.forEach([&](int32_t downId) { dispatchedIds.insert(downId); if (dispatchedIds.count() == 1) { // First pointer is going down. Set down time. mDownTime = when; } dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.pointerCount, dispatchedIds, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); }); } } void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { if (mSentHoverEnter && (mCurrentCookedPointerData.hoveringIds.isEmpty() || !mCurrentCookedPointerData.touchingIds.isEmpty())) { int32_t metaState = getContext()->getGlobalMetaState(); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, mLastCookedPointerData.pointerProperties, mLastCookedPointerData.pointerCoords, mLastCookedPointerData.pointerCount, mLastCookedPointerData.hoveringIds, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mSentHoverEnter = false; } } void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { if (mCurrentCookedPointerData.touchingIds.isEmpty() && !mCurrentCookedPointerData.hoveringIds.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); if (!mSentHoverEnter) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.pointerCount, mCurrentCookedPointerData.hoveringIds, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mSentHoverEnter = true; } dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, mCurrentCookedPointerData.pointerProperties, mCurrentCookedPointerData.pointerCoords, mCurrentCookedPointerData.pointerCount, mCurrentCookedPointerData.hoveringIds, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } void TouchInputMapper::cookPointerData() { uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; mCurrentCookedPointerData.clear(); mCurrentCookedPointerData.pointerCount = currentPointerCount; mCurrentCookedPointerData.hoveringIds = mCurrentRawPointerData.hoveringIds; mCurrentCookedPointerData.touchingIds = mCurrentRawPointerData.touchingIds; // Walk through the the active pointers and map device coordinates onto // surface coordinates and adjust for display orientation. for (uint32_t i = 0; i < currentPointerCount; i++) { const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i]; // Size float touchMajor, touchMinor, toolMajor, toolMinor, size; switch (mCalibration.sizeCalibration) { case Calibration::SIZE_CALIBRATION_GEOMETRIC: case Calibration::SIZE_CALIBRATION_DIAMETER: case Calibration::SIZE_CALIBRATION_AREA: if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) { touchMajor = in.touchMajor; touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; toolMajor = in.toolMajor; toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; } else if (mRawPointerAxes.touchMajor.valid) { toolMajor = touchMajor = in.touchMajor; toolMinor = touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; size = mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; } else if (mRawPointerAxes.toolMajor.valid) { touchMajor = toolMajor = in.toolMajor; touchMinor = toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; size = mRawPointerAxes.toolMinor.valid ? avg(in.toolMajor, in.toolMinor) : in.toolMajor; } else { ALOG_ASSERT(false, "No touch or tool axes. " "Size calibration should have been resolved to NONE."); touchMajor = 0; touchMinor = 0; toolMajor = 0; toolMinor = 0; size = 0; } if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { uint32_t touchingCount = mCurrentRawPointerData.touchingIds.count(); if (touchingCount > 1) { touchMajor /= touchingCount; touchMinor /= touchingCount; toolMajor /= touchingCount; toolMinor /= touchingCount; size /= touchingCount; } } if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) { touchMajor *= mGeometricScale; touchMinor *= mGeometricScale; toolMajor *= mGeometricScale; toolMinor *= mGeometricScale; } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) { touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0; touchMinor = touchMajor; toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0; toolMinor = toolMajor; } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) { touchMinor = touchMajor; toolMinor = toolMajor; } mCalibration.applySizeScaleAndBias(&touchMajor); mCalibration.applySizeScaleAndBias(&touchMinor); mCalibration.applySizeScaleAndBias(&toolMajor); mCalibration.applySizeScaleAndBias(&toolMinor); size *= mSizeScale; break; default: touchMajor = 0; touchMinor = 0; toolMajor = 0; toolMinor = 0; size = 0; break; } // Pressure float pressure; switch (mCalibration.pressureCalibration) { case Calibration::PRESSURE_CALIBRATION_PHYSICAL: case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: pressure = in.pressure * mPressureScale; break; default: pressure = in.isHovering ? 0 : 1; break; } // Tilt and Orientation float tilt; float orientation; if (mHaveTilt) { float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale; float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale; orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); } else { tilt = 0; switch (mCalibration.orientationCalibration) { case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: orientation = (in.orientation - mOrientationCenter) * mOrientationScale; break; case Calibration::ORIENTATION_CALIBRATION_VECTOR: { int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); int32_t c2 = signExtendNybble(in.orientation & 0x0f); if (c1 != 0 || c2 != 0) { orientation = atan2f(c1, c2) * 0.5f; float confidence = hypotf(c1, c2); float scale = 1.0f + confidence / 16.0f; touchMajor *= scale; touchMinor /= scale; toolMajor *= scale; toolMinor /= scale; } else { orientation = 0; } break; } default: orientation = 0; } } // Distance float distance; switch (mCalibration.distanceCalibration) { case Calibration::DISTANCE_CALIBRATION_SCALED: distance = in.distance * mDistanceScale; break; default: distance = 0; } // X and Y // Adjust coords for surface orientation. float x, y; switch (mSurfaceOrientation) { case DISPLAY_ORIENTATION_90: x = float(in.y - mRawPointerAxes.y.minValue) * mYScale; y = float(mRawPointerAxes.x.maxValue - in.x) * mXScale; orientation -= M_PI_2; if (orientation < - M_PI_2) { orientation += M_PI; } break; case DISPLAY_ORIENTATION_180: x = float(mRawPointerAxes.x.maxValue - in.x) * mXScale; y = float(mRawPointerAxes.y.maxValue - in.y) * mYScale; break; case DISPLAY_ORIENTATION_270: x = float(mRawPointerAxes.y.maxValue - in.y) * mYScale; y = float(in.x - mRawPointerAxes.x.minValue) * mXScale; orientation += M_PI_2; if (orientation > M_PI_2) { orientation -= M_PI; } break; default: x = float(in.x - mRawPointerAxes.x.minValue) * mXScale; y = float(in.y - mRawPointerAxes.y.minValue) * mYScale; break; } // Write output coords. PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i]; out.clear(); out.setAxisValue(AMOTION_EVENT_AXIS_X, x); out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); // Write output properties. PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i]; uint32_t id = in.id; properties.clear(); properties.id = id; properties.toolType = in.toolType; } } void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage) { if (pointerUsage != mPointerUsage) { abortPointerUsage(when, policyFlags); mPointerUsage = pointerUsage; } switch (mPointerUsage) { case POINTER_USAGE_GESTURES: dispatchPointerGestures(when, policyFlags, false /*isTimeout*/); break; case POINTER_USAGE_STYLUS: dispatchPointerStylus(when, policyFlags); break; case POINTER_USAGE_MOUSE: dispatchPointerMouse(when, policyFlags); break; default: break; } } void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) { switch (mPointerUsage) { case POINTER_USAGE_GESTURES: abortPointerGestures(when, policyFlags); break; case POINTER_USAGE_STYLUS: abortPointerStylus(when, policyFlags); break; case POINTER_USAGE_MOUSE: abortPointerMouse(when, policyFlags); break; default: break; } mPointerUsage = POINTER_USAGE_NONE; } void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout) { // Update current gesture coordinates. bool cancelPreviousGesture, finishPreviousGesture; bool sendEvents = preparePointerGestures(when, &cancelPreviousGesture, &finishPreviousGesture, isTimeout); if (!sendEvents) { return; } if (finishPreviousGesture) { cancelPreviousGesture = false; } // Update the pointer presentation and spots. if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); if (finishPreviousGesture || cancelPreviousGesture) { mPointerController->clearSpots(); } mPointerController->setSpots(mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIds.count()); } else { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); } // Show or hide the pointer if needed. switch (mPointerGesture.currentGestureMode) { case PointerGesture::NEUTRAL: case PointerGesture::QUIET: if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS && (mPointerGesture.lastGestureMode == PointerGesture::SWIPE || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)) { // Remind the user of where the pointer is after finishing a gesture with spots. mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL); } break; case PointerGesture::TAP: case PointerGesture::TAP_DRAG: case PointerGesture::BUTTON_CLICK_OR_DRAG: case PointerGesture::HOVER: case PointerGesture::PRESS: // Unfade the pointer when the current gesture manipulates the // area directly under the pointer. mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); break; case PointerGesture::SWIPE: case PointerGesture::FREEFORM: // Fade the pointer when the current gesture manipulates a different // area and there are spots to guide the user experience. if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); } else { mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); } break; } // Send events! int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentButtonState; // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP || mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG || mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG || mPointerGesture.currentGestureMode == PointerGesture::PRESS || mPointerGesture.currentGestureMode == PointerGesture::SWIPE || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM; bool moveNeeded = false; if (down && !cancelPreviousGesture && !finishPreviousGesture && !(mPointerGesture.lastGestureIds.isEmpty()) && !(mPointerGesture.currentGestureIds.isEmpty())) { IntSet movedGestureIds = mPointerGesture.currentGestureIds & mPointerGesture.lastGestureIds; moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIds.count(), mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIds.count(), movedGestureIds); if (buttonState != mLastButtonState) { moveNeeded = true; } } // Send motion events for all pointers that went up or were canceled. IntSet dispatchedGestureIds = mPointerGesture.lastGestureIds; if (!dispatchedGestureIds.isEmpty()) { if (cancelPreviousGesture) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIds.count(), dispatchedGestureIds, -1, 0, 0, mPointerGesture.downTime); dispatchedGestureIds.clear(); } else { IntSet upGestureIds; if (finishPreviousGesture) { upGestureIds = dispatchedGestureIds; } else { upGestureIds = dispatchedGestureIds - mPointerGesture.currentGestureIds; } upGestureIds.forEach([&](int32_t upId) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIds.count(), dispatchedGestureIds, upId, 0, 0, mPointerGesture.downTime); dispatchedGestureIds.remove(upId); }); } } // Send motion events for all pointers that moved. if (moveNeeded) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIds.count(), dispatchedGestureIds, -1, 0, 0, mPointerGesture.downTime); } // Send motion events for all pointers that went down. if (down) { IntSet downGestureIds = mPointerGesture.currentGestureIds - dispatchedGestureIds; downGestureIds.forEach([&](int32_t downId) { dispatchedGestureIds.insert(downId); if (dispatchedGestureIds.size() == 1) { mPointerGesture.downTime = when; } dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIds.count(), dispatchedGestureIds, downId, 0, 0, mPointerGesture.downTime); }); } // Send motion events for hover. if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.currentGestureProperties, mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIds.count(), -1, 0, 0, mPointerGesture.downTime); } else if (dispatchedGestureIds.isEmpty() && !mPointerGesture.lastGestureIds.isEmpty()) { // Synthesize a hover move event after all pointers go up to indicate that // the pointer is hovering again even if the user is not currently touching // the touch pad. This ensures that a view will receive a fresh hover enter // event after a tap. float x, y; mPointerController->getPosition(&x, &y); PointerProperties pointerProperties; pointerProperties.clear(); pointerProperties.id = 0; pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; PointerCoords pointerCoords; pointerCoords.clear(); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, mPointerGesture.downTime); getListener()->notifyMotion(&args); } // Update state. mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode; if (!down) { mPointerGesture.lastGestureIds.clear(); } else { mPointerGesture.lastGestureIds = mPointerGesture.currentGestureIds; mPointerGesture.lastGestureIdToIndex = mPointerGesture.currentGestureIdToIndex; for (uint32_t index = 0; index < mPointerGesture.currentGestureIds.count(); ++index) { mPointerGesture.lastGestureProperties[index].copyFrom( mPointerGesture.currentGestureProperties[index]); mPointerGesture.lastGestureCoords[index].copyFrom( mPointerGesture.currentGestureCoords[index]); } } } void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) { // Cancel previously dispatches pointers. if (!mPointerGesture.lastGestureIds.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); int32_t buttonState = mCurrentButtonState; dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIds.count(), -1, 0, 0, mPointerGesture.downTime); } // Reset the current pointer gesture. mPointerGesture.reset(); mPointerVelocityControl.reset(); // Remove any current spots. if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); mPointerController->clearSpots(); } } bool TouchInputMapper::preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout) { *outCancelPreviousGesture = false; *outFinishPreviousGesture = false; // Handle TAP timeout. if (isTimeout) { #if DEBUG_GESTURES ALOGD("Gestures: Processing timeout"); #endif if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { // The tap/drag timeout has not yet expired. getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval); } else { // The tap is finished. #if DEBUG_GESTURES ALOGD("Gestures: TAP finished"); #endif *outFinishPreviousGesture = true; mPointerGesture.activeGestureId = -1; mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; mPointerGesture.currentGestureIds.clear(); mPointerVelocityControl.reset(); return true; } } // We did not handle this timeout. return false; } const uint32_t currentFingerCount = mCurrentFingerIds.size(); const uint32_t lastFingerCount = mLastFingerIds.size(); // Update the velocity tracker. { VelocityTracker::Position positions[MAX_POINTERS]; uint32_t count = 0; mCurrentFingerIds.forEach([&](int32_t id) { const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); positions[count].x = pointer.x * mPointerXMovementScale; positions[count].y = pointer.y * mPointerYMovementScale; count++; }); mPointerGesture.velocityTracker.addMovement(when, mCurrentFingerIds, positions); } // Pick a new active touch id if needed. // Choose an arbitrary pointer that just went down, if there is one. // Otherwise choose an arbitrary remaining pointer. // This guarantees we always have an active touch id when there is at least one pointer. // We keep the same active touch id for as long as possible. bool activeTouchChanged = false; int32_t lastActiveTouchId = mPointerGesture.activeTouchId; int32_t activeTouchId = lastActiveTouchId; if (activeTouchId < 0) { if (!mCurrentFingerIds.isEmpty()) { activeTouchChanged = true; activeTouchId = mPointerGesture.activeTouchId = mCurrentFingerIds.first(); mPointerGesture.firstTouchTime = when; } } else if (!mCurrentFingerIds.contains(activeTouchId)) { activeTouchChanged = true; if (!mCurrentFingerIds.isEmpty()) { activeTouchId = mPointerGesture.activeTouchId = mCurrentFingerIds.first(); } else { activeTouchId = mPointerGesture.activeTouchId = -1; } } // Determine whether we are in quiet time. bool isQuietTime = false; if (activeTouchId < 0) { mPointerGesture.resetQuietTime(); } else { isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval; if (!isQuietTime) { if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS || mPointerGesture.lastGestureMode == PointerGesture::SWIPE || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) && currentFingerCount < 2) { // Enter quiet time when exiting swipe or freeform state. // This is to prevent accidentally entering the hover state and flinging the // pointer when finishing a swipe and there is still one pointer left onscreen. isQuietTime = true; } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG && currentFingerCount >= 2 && !isPointerDown(mCurrentButtonState)) { // Enter quiet time when releasing the button and there are still two or more // fingers down. This may indicate that one finger was used to press the button // but it has not gone up yet. isQuietTime = true; } if (isQuietTime) { mPointerGesture.quietTime = when; } } } // Switch states based on button and pointer state. if (isQuietTime) { // Case 1: Quiet time. (QUIET) #if DEBUG_GESTURES ALOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval - when) * 0.000001f); #endif if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) { *outFinishPreviousGesture = true; } mPointerGesture.activeGestureId = -1; mPointerGesture.currentGestureMode = PointerGesture::QUIET; mPointerGesture.currentGestureIds.clear(); mPointerVelocityControl.reset(); } else if (isPointerDown(mCurrentButtonState)) { // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) // The pointer follows the active touch point. // Emit DOWN, MOVE, UP events at the pointer location. // // Only the active touch matters; other fingers are ignored. This policy helps // to handle the case where the user places a second finger on the touch pad // to apply the necessary force to depress an integrated button below the surface. // We don't want the second finger to be delivered to applications. // // For this to work well, we need to make sure to track the pointer that is really // active. If the user first puts one finger down to click then adds another // finger to drag then the active pointer should switch to the finger that is // being dragged. #if DEBUG_GESTURES ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, " "currentFingerCount=%d", activeTouchId, currentFingerCount); #endif // Reset state when just starting. if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) { *outFinishPreviousGesture = true; mPointerGesture.activeGestureId = 0; } // Switch pointers if needed. // Find the fastest pointer and follow it. if (activeTouchId >= 0 && currentFingerCount > 1) { int32_t bestId = -1; float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; mCurrentFingerIds.forEach([&](int32_t id) { float vx, vy; if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { float speed = hypotf(vx, vy); if (speed > bestSpeed) { bestId = id; bestSpeed = speed; } } }); if (bestId >= 0 && bestId != activeTouchId) { mPointerGesture.activeTouchId = activeTouchId = bestId; activeTouchChanged = true; #if DEBUG_GESTURES ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed); #endif } } if (activeTouchId >= 0 && mLastFingerIds.contains(activeTouchId)) { const RawPointerData::Pointer& currentPointer = mCurrentRawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = mLastRawPointerData.pointerForId(activeTouchId); float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); // Move the pointer using a relative motion. // When using spots, the click will occur at the position of the anchor // spot and all other spots will move there. mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } float x, y; mPointerController->getPosition(&x, &y); mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG; mPointerGesture.currentGestureIds.clear(); mPointerGesture.currentGestureIds.insert(mPointerGesture.activeGestureId); mPointerGesture.currentGestureProperties[0].clear(); mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); } else if (currentFingerCount == 0) { // Case 3. No fingers down and button is not pressed. (NEUTRAL) if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) { *outFinishPreviousGesture = true; } // Watch for taps coming out of HOVER or TAP_DRAG mode. // Checking for taps after TAP_DRAG allows us to detect double-taps. bool tapped = false; if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) && lastFingerCount == 1) { if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { float x, y; mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { #if DEBUG_GESTURES ALOGD("Gestures: TAP"); #endif mPointerGesture.tapUpTime = when; getContext()->requestTimeoutAtTime(when + mConfig.pointerGestureTapDragInterval); mPointerGesture.activeGestureId = 0; mPointerGesture.currentGestureMode = PointerGesture::TAP; mPointerGesture.currentGestureIds.clear(); mPointerGesture.currentGestureIds.insert( mPointerGesture.activeGestureId); mPointerGesture.currentGestureProperties[0].clear(); mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue( AMOTION_EVENT_AXIS_X, mPointerGesture.tapX); mPointerGesture.currentGestureCoords[0].setAxisValue( AMOTION_EVENT_AXIS_Y, mPointerGesture.tapY); mPointerGesture.currentGestureCoords[0].setAxisValue( AMOTION_EVENT_AXIS_PRESSURE, 1.0f); tapped = true; } else { #if DEBUG_GESTURES ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f", x - mPointerGesture.tapX, y - mPointerGesture.tapY); #endif } } else { #if DEBUG_GESTURES ALOGD("Gestures: Not a TAP, %0.3fms since down", (when - mPointerGesture.tapDownTime) * 0.000001f); #endif } } mPointerVelocityControl.reset(); if (!tapped) { #if DEBUG_GESTURES ALOGD("Gestures: NEUTRAL"); #endif mPointerGesture.activeGestureId = -1; mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; mPointerGesture.currentGestureIds.clear(); } } else if (currentFingerCount == 1) { // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG) // The pointer follows the active touch point. // When in HOVER, emit HOVER_MOVE events at the pointer location. // When in TAP_DRAG, emit MOVE events at the pointer location. ALOG_ASSERT(activeTouchId >= 0); mPointerGesture.currentGestureMode = PointerGesture::HOVER; if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { float x, y; mPointerController->getPosition(&x, &y); if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; } else { #if DEBUG_GESTURES ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f", x - mPointerGesture.tapX, y - mPointerGesture.tapY); #endif } } else { #if DEBUG_GESTURES ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up", (when - mPointerGesture.tapUpTime) * 0.000001f); #endif } } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) { mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; } if (mLastFingerIds.contains(activeTouchId)) { const RawPointerData::Pointer& currentPointer = mCurrentRawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = mLastRawPointerData.pointerForId(activeTouchId); float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); // Move the pointer using a relative motion. // When using spots, the hover or drag will occur at the position of the anchor spot. mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } bool down; if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) { #if DEBUG_GESTURES ALOGD("Gestures: TAP_DRAG"); #endif down = true; } else { #if DEBUG_GESTURES ALOGD("Gestures: HOVER"); #endif if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) { *outFinishPreviousGesture = true; } mPointerGesture.activeGestureId = 0; down = false; } float x, y; mPointerController->getPosition(&x, &y); mPointerGesture.currentGestureIds.clear(); mPointerGesture.currentGestureIds.insert(mPointerGesture.activeGestureId); mPointerGesture.currentGestureProperties[0].clear(); mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); if (lastFingerCount == 0 && currentFingerCount != 0) { mPointerGesture.resetTap(); mPointerGesture.tapDownTime = when; mPointerGesture.tapX = x; mPointerGesture.tapY = y; } } else { // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM) // We need to provide feedback for each finger that goes down so we cannot wait // for the fingers to move before deciding what to do. // // The ambiguous case is deciding what to do when there are two fingers down but they // have not moved enough to determine whether they are part of a drag or part of a // freeform gesture, or just a press or long-press at the pointer location. // // When there are two fingers we start with the PRESS hypothesis and we generate a // down at the pointer location. // // When the two fingers move enough or when additional fingers are added, we make // a decision to transition into SWIPE or FREEFORM mode accordingly. ALOG_ASSERT(activeTouchId >= 0); bool settled = when >= mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval; if (mPointerGesture.lastGestureMode != PointerGesture::PRESS && mPointerGesture.lastGestureMode != PointerGesture::SWIPE && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { *outFinishPreviousGesture = true; } else if (!settled && currentFingerCount > lastFingerCount) { // Additional pointers have gone down but not yet settled. // Reset the gesture. #if DEBUG_GESTURES ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval - when) * 0.000001f); #endif *outCancelPreviousGesture = true; } else { // Continue previous gesture. mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; } if (*outFinishPreviousGesture || *outCancelPreviousGesture) { mPointerGesture.currentGestureMode = PointerGesture::PRESS; mPointerGesture.activeGestureId = 0; mPointerGesture.referenceIds.clear(); mPointerVelocityControl.reset(); // Use the centroid and pointer location as the reference points for the gesture. #if DEBUG_GESTURES ALOGD("Gestures: Using centroid as reference for MULTITOUCH, " "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime + mConfig.pointerGestureMultitouchSettleInterval - when) * 0.000001f); #endif mCurrentRawPointerData.getCentroidOfTouchingPointers( &mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); mPointerController->getPosition(&mPointerGesture.referenceGestureX, &mPointerGesture.referenceGestureY); } // Clear the reference deltas for fingers not yet included in the reference calculation. (mCurrentFingerIds - mPointerGesture.referenceIds).forEach([&](int32_t id) { mPointerGesture.referenceDeltas[id].dx = 0; mPointerGesture.referenceDeltas[id].dy = 0; }); mPointerGesture.referenceIds = mCurrentFingerIds; // Add delta for all fingers and calculate a common movement delta. float commonDeltaX = 0, commonDeltaY = 0; IntSet commonIds = mLastFingerIds & mCurrentFingerIds; bool first = true; commonIds.forEach([&](int32_t id) { const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id); const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id); PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; delta.dx += cpd.x - lpd.x; delta.dy += cpd.y - lpd.y; if (first) { commonDeltaX = delta.dx; commonDeltaY = delta.dy; first = false; } else { commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx); commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy); } }); // Consider transitions from PRESS to SWIPE or MULTITOUCH. if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) { std::unordered_map dist; int32_t distOverThreshold = 0; mPointerGesture.referenceIds.forEach([&](int32_t id) { PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; dist[id] = hypotf(delta.dx * mPointerXZoomScale, delta.dy * mPointerYZoomScale); if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) { distOverThreshold += 1; } }); // Only transition when at least two pointers have moved further than // the minimum distance threshold. if (distOverThreshold >= 2) { if (currentFingerCount > 2) { // There are more than two pointers, switch to FREEFORM. #if DEBUG_GESTURES ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", currentFingerCount); #endif *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } else { // There are exactly two pointers. int32_t id1; int32_t id2; { auto currentFingerIdsIt = mCurrentFingerIds.cbegin(); id1 = *currentFingerIdsIt; ++currentFingerIdsIt; id2 = *currentFingerIdsIt; } const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1); const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2); float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); if (mutualDistance > mPointerGestureMaxSwipeWidth) { // There are two pointers but they are too far apart for a SWIPE, // switch to FREEFORM. #if DEBUG_GESTURES ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f", mutualDistance, mPointerGestureMaxSwipeWidth); #endif *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } else { // There are two pointers. Wait for both pointers to start moving // before deciding whether this is a SWIPE or FREEFORM gesture. float dist1 = dist[id1]; float dist2 = dist[id2]; if (dist1 >= mConfig.pointerGestureMultitouchMinDistance && dist2 >= mConfig.pointerGestureMultitouchMinDistance) { // Calculate the dot product of the displacement vectors. // When the vectors are oriented in approximately the same direction, // the angle betweeen them is near zero and the cosine of the angle // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1]; PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2]; float dx1 = delta1.dx * mPointerXZoomScale; float dy1 = delta1.dy * mPointerYZoomScale; float dx2 = delta2.dx * mPointerXZoomScale; float dy2 = delta2.dy * mPointerYZoomScale; float dot = dx1 * dx2 + dy1 * dy2; float cosine = dot / (dist1 * dist2); // denominator always > 0 if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) { // Pointers are moving in the same direction. Switch to SWIPE. #if DEBUG_GESTURES ALOGD("Gestures: PRESS transitioned to SWIPE, " "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " "cosine %0.3f >= %0.3f", dist1, mConfig.pointerGestureMultitouchMinDistance, dist2, mConfig.pointerGestureMultitouchMinDistance, cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); #endif mPointerGesture.currentGestureMode = PointerGesture::SWIPE; } else { // Pointers are moving in different directions. Switch to FREEFORM. #if DEBUG_GESTURES ALOGD("Gestures: PRESS transitioned to FREEFORM, " "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " "cosine %0.3f < %0.3f", dist1, mConfig.pointerGestureMultitouchMinDistance, dist2, mConfig.pointerGestureMultitouchMinDistance, cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); #endif *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } } } } } } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { // Switch from SWIPE to FREEFORM if additional pointers go down. // Cancel previous gesture. if (currentFingerCount > 2) { #if DEBUG_GESTURES ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2", currentFingerCount); #endif *outCancelPreviousGesture = true; mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } } // Move the reference points based on the overall group motion of the fingers // except in PRESS mode while waiting for a transition to occur. if (mPointerGesture.currentGestureMode != PointerGesture::PRESS && (commonDeltaX || commonDeltaY)) { mPointerGesture.referenceIds.forEach([&](int32_t id) { PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; delta.dx = 0; delta.dy = 0; }); mPointerGesture.referenceTouchX += commonDeltaX; mPointerGesture.referenceTouchY += commonDeltaY; commonDeltaX *= mPointerXMovementScale; commonDeltaY *= mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY); mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); mPointerGesture.referenceGestureX += commonDeltaX; mPointerGesture.referenceGestureY += commonDeltaY; } // Report gestures. if (mPointerGesture.currentGestureMode == PointerGesture::PRESS || mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { // PRESS or SWIPE mode. #if DEBUG_GESTURES ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d," "activeGestureId=%d, currentTouchPointerCount=%d", activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); #endif ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); mPointerGesture.currentGestureIds.clear(); mPointerGesture.currentGestureIds.insert(mPointerGesture.activeGestureId); mPointerGesture.currentGestureProperties[0].clear(); mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; mPointerGesture.currentGestureCoords[0].clear(); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY); mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { // FREEFORM mode. #if DEBUG_GESTURES ALOGD("Gestures: FREEFORM activeTouchId=%d," "activeGestureId=%d, currentTouchPointerCount=%d", activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); #endif ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); mPointerGesture.currentGestureIds.clear(); IntSet mappedTouchIds; IntSet usedGestureIds; if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { // Initially, assign the active gesture id to the active touch point // if there is one. No other touch id bits are mapped yet. if (!*outCancelPreviousGesture) { mappedTouchIds.insert(activeTouchId); usedGestureIds.insert(mPointerGesture.activeGestureId); mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] = mPointerGesture.activeGestureId; } else { mPointerGesture.activeGestureId = -1; } } else { // Otherwise, assume we mapped all touches from the previous frame. // Reuse all mappings that are still applicable. mappedTouchIds = mLastFingerIds & mCurrentFingerIds; usedGestureIds = mPointerGesture.lastGestureIds; // Check whether we need to choose a new active gesture id because the // current went went up. auto it = mLastFingerIds.cbegin(); while (it != mLastFingerIds.cend()) { int32_t id = *it; if (!mCurrentFingerIds.contains(id)) { int32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[id]; if (upGestureId == mPointerGesture.activeGestureId) { mPointerGesture.activeGestureId = -1; break; } } it++; } } #if DEBUG_GESTURES { std::string mappedTouchIdsString = mappedTouchIds.toString(); std::string usedGestureIdsString = usedGestureIds.toString(); ALOGD("Gestures: FREEFORM follow up " "mappedTouchIds=%s, usedGestureIds=%s, " "activeGestureId=%d", mappedTouchIdsString.c_str(), usedGestureIdsString.c_str(), mPointerGesture.activeGestureId); } #endif uint32_t i = 0; mCurrentFingerIds.forEach([&](int32_t touchId) { int32_t gestureId; if (mappedTouchIds.contains(touchId)) { gestureId = usedGestureIds.first(); mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId; #if DEBUG_GESTURES ALOGD("Gestures: FREEFORM " "new mapping for touch id %d -> gesture id %d", touchId, gestureId); #endif } else { gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId]; #if DEBUG_GESTURES ALOGD("Gestures: FREEFORM " "existing mapping for touch id %d -> gesture id %d", touchId, gestureId); #endif } mPointerGesture.currentGestureIds.insert(gestureId); const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(touchId); float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale; float deltaY = (pointer.y - mPointerGesture.referenceTouchY) * mPointerYZoomScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); mPointerGesture.currentGestureProperties[i].clear(); mPointerGesture.currentGestureProperties[i].id = gestureId; mPointerGesture.currentGestureProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; mPointerGesture.currentGestureCoords[i].clear(); mPointerGesture.currentGestureCoords[i].setAxisValue( AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + deltaX); mPointerGesture.currentGestureCoords[i].setAxisValue( AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY + deltaY); mPointerGesture.currentGestureCoords[i].setAxisValue( AMOTION_EVENT_AXIS_PRESSURE, 1.0f); ++i; }); if (mPointerGesture.activeGestureId < 0) { mPointerGesture.activeGestureId = mPointerGesture.currentGestureIds.first(); #if DEBUG_GESTURES ALOGD("Gestures: FREEFORM new " "activeGestureId=%d", mPointerGesture.activeGestureId); #endif } } } mPointerController->setButtonState(mCurrentButtonState); #if DEBUG_GESTURES { std::string lastGestureIdsString = mPointerGesture.lastGestureIds.toString(); ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " "currentGestureMode=%d, currentGestureIds.count()=%u, " "lastGestureMode=%d, lastGestureIds=%s", toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture), mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIds.count(), mPointerGesture.lastGestureMode, lastGestureIdsString.c_str()); for (uint32_t index = 0; index < mPointerGesture.currentGestureIds.count(); ++index) { const PointerProperties& properties = mPointerGesture.currentGestureProperties[index]; const PointerCoords& coords = mPointerGesture.currentGestureCoords[index]; ALOGD(" currentGesture[%d]: index=%d, toolType=%d, " "x=%0.3f, y=%0.3f, pressure=%0.3f", properties.id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X), coords.getAxisValue(AMOTION_EVENT_AXIS_Y), coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); } for (uint32_t index = 0; index < mPointerGesture.lastGestureIds.count(); ++index) { const PointerProperties& properties = mPointerGesture.lastGestureProperties[index]; const PointerCoords& coords = mPointerGesture.lastGestureCoords[index]; ALOGD(" lastGesture[%d]: index=%d, toolType=%d, " "x=%0.3f, y=%0.3f, pressure=%0.3f", properties.id, index, properties.toolType, coords.getAxisValue(AMOTION_EVENT_AXIS_X), coords.getAxisValue(AMOTION_EVENT_AXIS_Y), coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); } } #endif return true; } void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) { mPointerSimple.currentCoords.clear(); mPointerSimple.currentProperties.clear(); bool down, hovering; if (!mCurrentStylusIds.isEmpty()) { int32_t id = mCurrentStylusIds.first(); uint32_t index = mCurrentCookedPointerData.idToIndex(id); float x = mCurrentCookedPointerData.pointerCoords[index].getX(); float y = mCurrentCookedPointerData.pointerCoords[index].getY(); mPointerController->setPosition(x, y); hovering = mCurrentCookedPointerData.hoveringIds.contains(id); down = !hovering; mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentProperties.id = 0; mPointerSimple.currentProperties.toolType = mCurrentCookedPointerData.pointerProperties[index].toolType; } else { down = false; hovering = false; } dispatchPointerSimple(when, policyFlags, down, hovering); } void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) { abortPointerSimple(when, policyFlags); } void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) { mPointerSimple.currentCoords.clear(); mPointerSimple.currentProperties.clear(); bool down, hovering; if (!mCurrentMouseIds.isEmpty()) { uint32_t id = mCurrentMouseIds.first(); uint32_t currentIndex = mCurrentRawPointerData.idToIndex(id); if (mLastMouseIds.contains(id)) { uint32_t lastIndex = mCurrentRawPointerData.idToIndex(id); float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x - mLastRawPointerData.pointers[lastIndex].x) * mPointerXMovementScale; float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y - mLastRawPointerData.pointers[lastIndex].y) * mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); mPointerVelocityControl.move(when, &deltaX, &deltaY); mPointerController->move(deltaX, deltaY); } else { mPointerVelocityControl.reset(); } down = isPointerDown(mCurrentButtonState); hovering = !down; float x, y; mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( mCurrentCookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, hovering ? 0.0f : 1.0f); mPointerSimple.currentProperties.id = 0; mPointerSimple.currentProperties.toolType = mCurrentCookedPointerData.pointerProperties[currentIndex].toolType; } else { mPointerVelocityControl.reset(); down = false; hovering = false; } dispatchPointerSimple(when, policyFlags, down, hovering); } void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) { abortPointerSimple(when, policyFlags); mPointerVelocityControl.reset(); } void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, bool down, bool hovering) { int32_t metaState = getContext()->getGlobalMetaState(); if (mPointerController != NULL) { if (down || hovering) { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); mPointerController->clearSpots(); mPointerController->setButtonState(mCurrentButtonState); mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); } } if (mPointerSimple.down && !down) { mPointerSimple.down = false; // Send up. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } if (mPointerSimple.hovering && !hovering) { mPointerSimple.hovering = false; // Send hover exit. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } if (down) { if (!mPointerSimple.down) { mPointerSimple.down = true; mPointerSimple.downTime = when; // Send down. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } // Send move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } if (hovering) { if (!mPointerSimple.hovering) { mPointerSimple.hovering = true; // Send hover enter. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } // Send hover move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } if (mCurrentRawVScroll || mCurrentRawHScroll) { float vscroll = mCurrentRawVScroll; float hscroll = mCurrentRawHScroll; mWheelYVelocityControl.move(when, NULL, &vscroll); mWheelXVelocityControl.move(when, &hscroll, NULL); // Send scroll. PointerCoords pointerCoords; pointerCoords.copyFrom(mPointerSimple.currentCoords); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0, 1, &mPointerSimple.currentProperties, &pointerCoords, mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime); getListener()->notifyMotion(&args); } // Save state. if (down || hovering) { mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords); mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties); } else { mPointerSimple.reset(); } } void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { mPointerSimple.currentCoords.clear(); mPointerSimple.currentProperties.clear(); dispatchPointerSimple(when, policyFlags, false, false); } void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, uint32_t inPointerCount, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { PointerCoords pointerCoords[MAX_POINTERS]; PointerProperties pointerProperties[MAX_POINTERS]; uint32_t pointerCount = 0; while (pointerCount < inPointerCount) { pointerProperties[pointerCount].copyFrom(properties[pointerCount]); pointerCoords[pointerCount].copyFrom(coords[pointerCount]); if (changedId >= 0 && properties[pointerCount].id == uint32_t(changedId)) { action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } pointerCount += 1; } ALOG_ASSERT(pointerCount != 0); if (changedId >= 0 && pointerCount == 1) { // Replace initial down and final up action. // We can compare the action without masking off the changed pointer index // because we know the index is 0. if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { action = AMOTION_EVENT_ACTION_DOWN; } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { action = AMOTION_EVENT_ACTION_UP; } else { // Can't happen. ALOG_ASSERT(false); } } NotifyMotionArgs args(when, getDeviceId(), source, policyFlags, action, flags, metaState, buttonState, edgeFlags, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime); getListener()->notifyMotion(&args); } void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, uint32_t inPointerCount, const IntSet &idsToDispatch, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { PointerCoords pointerCoords[MAX_POINTERS]; PointerProperties pointerProperties[MAX_POINTERS]; uint32_t pointerCount = 0; for (uint32_t i = 0; i < inPointerCount && pointerCount < idsToDispatch.size(); ++i) { if (!idsToDispatch.contains(properties[i].id)) continue; pointerProperties[pointerCount].copyFrom(properties[i]); pointerCoords[pointerCount].copyFrom(coords[i]); if (changedId >= 0 && properties[i].id == uint32_t(changedId)) { action |= i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } pointerCount += 1; } ALOG_ASSERT(pointerCount != 0); if (changedId >= 0 && pointerCount == 1) { // Remove the poiter index part int actionPart = action & AMOTION_EVENT_ACTION_MASK; // Replace initial down and final up action. // We can compare the action without masking off the changed pointer index // because we know the index is 0. if (actionPart == AMOTION_EVENT_ACTION_POINTER_DOWN) { actionPart = AMOTION_EVENT_ACTION_DOWN; } else if (actionPart & AMOTION_EVENT_ACTION_POINTER_UP) { actionPart = AMOTION_EVENT_ACTION_UP; } else { // Can't happen. ALOG_ASSERT(false); } // And put it back into the action integer action = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) | actionPart; } NotifyMotionArgs args(when, getDeviceId(), source, policyFlags, action, flags, metaState, buttonState, edgeFlags, pointerCount, pointerProperties, pointerCoords, xPrecision, yPrecision, downTime); getListener()->notifyMotion(&args); } bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties, const PointerCoords* inCoords, uint32_t inPointerCount, PointerProperties* outProperties, PointerCoords* outCoords, uint32_t outPointerCount, const IntSet &commonTouchingIds) const { bool changed = false; if (commonTouchingIds.isEmpty()) { return changed; } for (uint32_t inIndex = 0; inIndex < inPointerCount; ++inIndex) { int32_t inId = inProperties[inIndex].id; if (!commonTouchingIds.contains(inId)) { continue; } for (uint32_t outIndex = 0; outIndex < outPointerCount; ++outIndex) { int32_t outId = outProperties[outIndex].id; if (inId == outId) { // The pointer is present in both sets. Let's see if it has moved. const PointerProperties& curInProperties = inProperties[inIndex]; const PointerCoords& curInCoords = inCoords[inIndex]; PointerProperties& curOutProperties = outProperties[outIndex]; PointerCoords& curOutCoords = outCoords[outIndex]; if (curInProperties != curOutProperties) { curOutProperties.copyFrom(curInProperties); changed = true; } if (curInCoords != curOutCoords) { curOutCoords.copyFrom(curInCoords); changed = true; } } } } return changed; } void TouchInputMapper::fadePointer() { if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); } } bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue; } const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit( int32_t x, int32_t y) { size_t numVirtualKeys = mVirtualKeys.size(); for (size_t i = 0; i < numVirtualKeys; i++) { const VirtualKey& virtualKey = mVirtualKeys[i]; #if DEBUG_VIRTUAL_KEYS ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " "left=%d, top=%d, right=%d, bottom=%d", x, y, virtualKey.keyCode, virtualKey.scanCode, virtualKey.hitLeft, virtualKey.hitTop, virtualKey.hitRight, virtualKey.hitBottom); #endif if (virtualKey.isHit(x, y)) { return & virtualKey; } } return NULL; } void TouchInputMapper::assignPointerIds() { uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; uint32_t lastPointerCount = mLastRawPointerData.pointerCount; mCurrentRawPointerData.clearIds(); if (currentPointerCount == 0) { // No pointers to assign. return; } if (lastPointerCount == 0) { // All pointers are new. for (uint32_t i = 0; i < currentPointerCount; i++) { int32_t id = fetchNewPointerId(); mCurrentRawPointerData.pointers[i].id = id; mCurrentRawPointerData.insertId(id, mCurrentRawPointerData.isHovering(i)); } return; } if (currentPointerCount == 1 && lastPointerCount == 1 && mCurrentRawPointerData.pointers[0].toolType == mLastRawPointerData.pointers[0].toolType) { // Only one pointer and no change in count so it must have the same id as before. int32_t id = mLastRawPointerData.pointers[0].id; mCurrentRawPointerData.pointers[0].id = id; mCurrentRawPointerData.insertId(id, mCurrentRawPointerData.isHovering(0)); return; } // General case. // We build a heap of squared euclidean distances between current and last pointers // associated with the current and last pointer indices. Then, we find the best // match (by distance) for each current pointer. // The pointers must have the same tool type but it is possible for them to // transition from hovering to touching or vice-versa while retaining the same id. PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; uint32_t heapSize = 0; for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; currentPointerIndex++) { for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; lastPointerIndex++) { const RawPointerData::Pointer& currentPointer = mCurrentRawPointerData.pointers[currentPointerIndex]; const RawPointerData::Pointer& lastPointer = mLastRawPointerData.pointers[lastPointerIndex]; if (currentPointer.toolType == lastPointer.toolType) { int64_t deltaX = currentPointer.x - lastPointer.x; int64_t deltaY = currentPointer.y - lastPointer.y; uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); // Insert new element into the heap (sift up). heap[heapSize].currentPointerIndex = currentPointerIndex; heap[heapSize].lastPointerIndex = lastPointerIndex; heap[heapSize].distance = distance; heapSize += 1; } } } // Heapify for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) { startIndex -= 1; for (uint32_t parentIndex = startIndex; ;) { uint32_t childIndex = parentIndex * 2 + 1; if (childIndex >= heapSize) { break; } if (childIndex + 1 < heapSize && heap[childIndex + 1].distance < heap[childIndex].distance) { childIndex += 1; } if (heap[parentIndex].distance <= heap[childIndex].distance) { break; } swap(heap[parentIndex], heap[childIndex]); parentIndex = childIndex; } } #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - initial distance min-heap: size=%u", heapSize); for (size_t i = 0; i < heapSize; i++) { ALOGD(" heap[%d]: cur=%u, last=%u, distance=%llu", i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance); } #endif // Pull matches out by increasing order of distance. // To avoid reassigning pointers that have already been matched, the loop keeps track // of which last and current pointers have been matched using the matchedXXXBits variables. BitSet32 matchedLastBits(0); BitSet32 matchedCurrentBits(0); bool first = true; for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) { while (heapSize > 0) { if (first) { // The first time through the loop, we just consume the root element of // the heap (the one with smallest distance). first = false; } else { // Previous iterations consumed the root element of the heap. // Pop root element off of the heap (sift down). heap[0] = heap[heapSize]; for (uint32_t parentIndex = 0; ;) { uint32_t childIndex = parentIndex * 2 + 1; if (childIndex >= heapSize) { break; } if (childIndex + 1 < heapSize && heap[childIndex + 1].distance < heap[childIndex].distance) { childIndex += 1; } if (heap[parentIndex].distance <= heap[childIndex].distance) { break; } swap(heap[parentIndex], heap[childIndex]); parentIndex = childIndex; } #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize); for (size_t i = 0; i < heapSize; i++) { ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance); } #endif } heapSize -= 1; uint32_t currentPointerIndex = heap[0].currentPointerIndex; if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched uint32_t lastPointerIndex = heap[0].lastPointerIndex; if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched matchedCurrentBits.markBit(currentPointerIndex); matchedLastBits.markBit(lastPointerIndex); int32_t id = mLastRawPointerData.pointers[lastPointerIndex].id; mCurrentRawPointerData.pointers[currentPointerIndex].id = id; mCurrentRawPointerData.insertId(id, mCurrentRawPointerData.isHovering(currentPointerIndex)); #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld", lastPointerIndex, currentPointerIndex, id, heap[0].distance); #endif break; } } // Assign fresh ids to pointers that were not matched in the process. for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) { uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); int32_t id = fetchNewPointerId(); mCurrentRawPointerData.pointers[currentPointerIndex].id = id; mCurrentRawPointerData.insertId(id, mCurrentRawPointerData.isHovering(currentPointerIndex)); #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - assigned: cur=%d, id=%d", currentPointerIndex, id); #endif } } int32_t TouchInputMapper::fetchNewPointerId() { int32_t id = mNextNewPointerId++; if (mNextNewPointerId > MAX_POINTER_ID) { mNextNewPointerId = 0; } return id; } int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) { return AKEY_STATE_VIRTUAL; } size_t numVirtualKeys = mVirtualKeys.size(); for (size_t i = 0; i < numVirtualKeys; i++) { const VirtualKey& virtualKey = mVirtualKeys[i]; if (virtualKey.keyCode == keyCode) { return AKEY_STATE_UP; } } return AKEY_STATE_UNKNOWN; } int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) { return AKEY_STATE_VIRTUAL; } size_t numVirtualKeys = mVirtualKeys.size(); for (size_t i = 0; i < numVirtualKeys; i++) { const VirtualKey& virtualKey = mVirtualKeys[i]; if (virtualKey.scanCode == scanCode) { return AKEY_STATE_UP; } } return AKEY_STATE_UNKNOWN; } bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { size_t numVirtualKeys = mVirtualKeys.size(); for (size_t i = 0; i < numVirtualKeys; i++) { const VirtualKey& virtualKey = mVirtualKeys[i]; for (size_t i = 0; i < numCodes; i++) { if (virtualKey.keyCode == keyCodes[i]) { outFlags[i] = 1; } } } return true; } // --- SingleTouchInputMapper --- SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : TouchInputMapper(device) { } SingleTouchInputMapper::~SingleTouchInputMapper() { } void SingleTouchInputMapper::reset(nsecs_t when) { mSingleTouchMotionAccumulator.reset(getDevice()); TouchInputMapper::reset(when); } void SingleTouchInputMapper::process(const RawEvent* rawEvent) { TouchInputMapper::process(rawEvent); mSingleTouchMotionAccumulator.process(rawEvent); } void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { if (mTouchButtonAccumulator.isToolActive()) { mCurrentRawPointerData.pointerCount = 1; bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || (mRawPointerAxes.pressure.valid && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0]; if (mLastRawPointerData.pointerCount == 1) { outPointer.id = mLastRawPointerData.pointers[0].id; mCurrentRawPointerData.insertId(outPointer.id, isHovering); } else { outPointer.id = -1; *outHavePointerIds = false; } outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); outPointer.touchMajor = 0; outPointer.touchMinor = 0; outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); outPointer.orientation = 0; outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance(); outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX(); outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY(); outPointer.toolType = mTouchButtonAccumulator.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; } outPointer.isHovering = isHovering; } } void SingleTouchInputMapper::configureRawPointerAxes() { TouchInputMapper::configureRawPointerAxes(); getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x); getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y); getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure); getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor); getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance); getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX); getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY); } bool SingleTouchInputMapper::hasStylus() const { return mTouchButtonAccumulator.hasStylus(); } // --- MultiTouchInputMapper --- MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : TouchInputMapper(device) { } MultiTouchInputMapper::~MultiTouchInputMapper() { } void MultiTouchInputMapper::reset(nsecs_t when) { mMultiTouchMotionAccumulator.reset(getDevice()); mPointerIds.clear(); TouchInputMapper::reset(when); } void MultiTouchInputMapper::process(const RawEvent* rawEvent) { TouchInputMapper::process(rawEvent); mMultiTouchMotionAccumulator.process(rawEvent); } void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); size_t outCount = 0; IntSet newPointerIds; for (size_t inIndex = 0; inIndex < inCount; inIndex++) { const MultiTouchMotionAccumulator::Slot* inSlot = mMultiTouchMotionAccumulator.getSlot(inIndex); if (!inSlot->isInUse()) { continue; } if (outCount >= MAX_POINTERS) { #if DEBUG_POINTERS ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; " "ignoring the rest.", c_str(getDeviceName()), MAX_POINTERS); #endif break; // too many fingers! } RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount]; outPointer.x = inSlot->getX(); outPointer.y = inSlot->getY(); outPointer.pressure = inSlot->getPressure(); outPointer.touchMajor = inSlot->getTouchMajor(); outPointer.touchMinor = inSlot->getTouchMinor(); outPointer.toolMajor = inSlot->getToolMajor(); outPointer.toolMinor = inSlot->getToolMinor(); outPointer.orientation = inSlot->getOrientation(); outPointer.distance = inSlot->getDistance(); outPointer.tiltX = 0; outPointer.tiltY = 0; outPointer.toolType = inSlot->getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = mTouchButtonAccumulator.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; } } bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || (mRawPointerAxes.pressure.valid && inSlot->havePressure() && inSlot->getPressure() <= 0)); outPointer.isHovering = isHovering; // Assign pointer id using tracking id if available. if (*outHavePointerIds) { int32_t trackingId = inSlot->getTrackingId(); int32_t id = -1; if (trackingId >= 0) { mPointerIds.forEach([&](int32_t n) { if (mPointerTrackingIdMap[n] == trackingId) { id = n; } }); if (id < 0) { id = fetchNewPointerId(); mPointerIds.insert(id); mPointerTrackingIdMap[id] = trackingId; } } if (id < 0) { *outHavePointerIds = false; mCurrentRawPointerData.clearIds(); newPointerIds.clear(); } else { outPointer.id = id; mCurrentRawPointerData.insertId(id, isHovering); newPointerIds.insert(id); } } outCount += 1; } mCurrentRawPointerData.pointerCount = outCount; mPointerIds = newPointerIds; mMultiTouchMotionAccumulator.finishSync(); } void MultiTouchInputMapper::configureRawPointerAxes() { TouchInputMapper::configureRawPointerAxes(); getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x); getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y); getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor); getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor); getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor); getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor); getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation); getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure); getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance); getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId); getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot); if (mRawPointerAxes.trackingId.valid && mRawPointerAxes.slot.valid && mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) { size_t slotCount = mRawPointerAxes.slot.maxValue + 1; if (slotCount > MAX_SLOTS) { ALOGW("MultiTouch Device %s reported %lu slots but the framework " "only supports a maximum of %lu slots at this time.", c_str(getDeviceName()), slotCount, MAX_SLOTS); slotCount = MAX_SLOTS; } mMultiTouchMotionAccumulator.configure(getDevice(), slotCount, true /*usingSlotsProtocol*/); } else { mMultiTouchMotionAccumulator.configure(getDevice(), MAX_POINTERS, false /*usingSlotsProtocol*/); } } bool MultiTouchInputMapper::hasStylus() const { return mMultiTouchMotionAccumulator.hasStylus() || mTouchButtonAccumulator.hasStylus(); } // --- JoystickInputMapper --- JoystickInputMapper::JoystickInputMapper(InputDevice* device) : InputMapper(device) { } JoystickInputMapper::~JoystickInputMapper() { } uint32_t JoystickInputMapper::getSources() { return AINPUT_SOURCE_JOYSTICK; } void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { InputMapper::populateDeviceInfo(info); for (size_t i = 0; i < mAxes.size(); i++) { const Axis& axis = mAxes.valueAt(i); info->addMotionRange(axis.axisInfo.axis, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat, axis.fuzz); if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { info->addMotionRange(axis.axisInfo.highAxis, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat, axis.fuzz); } } } void JoystickInputMapper::dump(String8& dump) { dump.append(INDENT2 "Joystick Input Mapper:\n"); dump.append(INDENT3 "Axes:\n"); size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { const Axis& axis = mAxes.valueAt(i); const char* label = getAxisLabel(axis.axisInfo.axis); if (label) { appendFormat(dump, INDENT4 "%s", label); } else { appendFormat(dump, INDENT4 "%d", axis.axisInfo.axis); } if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { label = getAxisLabel(axis.axisInfo.highAxis); if (label) { appendFormat(dump, " / %s (split at %d)", label, axis.axisInfo.splitValue); } else { appendFormat(dump, " / %d (split at %d)", axis.axisInfo.highAxis, axis.axisInfo.splitValue); } } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) { dump.append(" (invert)"); } appendFormat(dump, ": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f\n", axis.min, axis.max, axis.flat, axis.fuzz); appendFormat(dump, INDENT4 " scale=%0.5f, offset=%0.5f, " "highScale=%0.5f, highOffset=%0.5f\n", axis.scale, axis.offset, axis.highScale, axis.highOffset); appendFormat(dump, INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, " "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n", mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution); } } void JoystickInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { InputMapper::configure(when, config, changes); if (!changes) { // first time only // Collect all axes. for (int32_t abs = 0; abs <= ABS_MAX; abs++) { if (!(getAbsAxisUsage(abs, getDevice()->getClasses()) & INPUT_DEVICE_CLASS_JOYSTICK)) { continue; // axis must be claimed by a different device } RawAbsoluteAxisInfo rawAxisInfo; getAbsoluteAxisInfo(abs, &rawAxisInfo); if (rawAxisInfo.valid) { // Map axis. AxisInfo axisInfo; bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo); if (!explicitlyMapped) { // Axis is not explicitly mapped, will choose a generic axis later. axisInfo.mode = AxisInfo::MODE_NORMAL; axisInfo.axis = -1; } // Apply flat override. int32_t rawFlat = axisInfo.flatOverride < 0 ? rawAxisInfo.flat : axisInfo.flatOverride; // Calculate scaling factors and limits. Axis axis; if (axisInfo.mode == AxisInfo::MODE_SPLIT) { float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue); float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue); axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, highScale, 0.0f, 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale); } else if (isCenteredAxis(axisInfo.axis)) { float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, offset, scale, offset, -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale); } else { float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, scale, 0.0f, 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale); } // To eliminate noise while the joystick is at rest, filter out small variations // in axis values up front. axis.filter = axis.flat * 0.25f; mAxes.add(abs, axis); } } // If there are too many axes, start dropping them. // Prefer to keep explicitly mapped axes. if (mAxes.size() > PointerCoords::MAX_AXES) { ALOGI("Joystick '%s' has %lu axes but the framework only supports a maximum of %d.", c_str(getDeviceName()), mAxes.size(), PointerCoords::MAX_AXES); pruneAxes(true); pruneAxes(false); } // Assign generic axis ids to remaining axes. int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1; size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { Axis& axis = mAxes.editValueAt(i); if (axis.axisInfo.axis < 0) { while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 && haveAxis(nextGenericAxisId)) { nextGenericAxisId += 1; } if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { axis.axisInfo.axis = nextGenericAxisId; nextGenericAxisId += 1; } else { ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " "have already been assigned to other axes.", c_str(getDeviceName()), mAxes.keyAt(i)); mAxes.removeItemsAt(i--); numAxes -= 1; } } } } } bool JoystickInputMapper::haveAxis(int32_t axisId) { size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { const Axis& axis = mAxes.valueAt(i); if (axis.axisInfo.axis == axisId || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT && axis.axisInfo.highAxis == axisId)) { return true; } } return false; } void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) { size_t i = mAxes.size(); while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) { if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) { continue; } ALOGI("Discarding joystick '%s' axis %d because there are too many axes.", c_str(getDeviceName()), mAxes.keyAt(i)); mAxes.removeItemsAt(i); } } bool JoystickInputMapper::isCenteredAxis(int32_t axis) { switch (axis) { case AMOTION_EVENT_AXIS_X: case AMOTION_EVENT_AXIS_Y: case AMOTION_EVENT_AXIS_Z: case AMOTION_EVENT_AXIS_RX: case AMOTION_EVENT_AXIS_RY: case AMOTION_EVENT_AXIS_RZ: case AMOTION_EVENT_AXIS_HAT_X: case AMOTION_EVENT_AXIS_HAT_Y: case AMOTION_EVENT_AXIS_ORIENTATION: case AMOTION_EVENT_AXIS_RUDDER: case AMOTION_EVENT_AXIS_WHEEL: return true; default: return false; } } void JoystickInputMapper::reset(nsecs_t when) { // Recenter all axes. size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { Axis& axis = mAxes.editValueAt(i); axis.resetValue(); } InputMapper::reset(when); } void JoystickInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_ABS: { ssize_t index = mAxes.indexOfKey(rawEvent->code); if (index >= 0) { Axis& axis = mAxes.editValueAt(index); float newValue, highNewValue; switch (axis.axisInfo.mode) { case AxisInfo::MODE_INVERT: newValue = (axis.rawAxisInfo.maxValue - rawEvent->value) * axis.scale + axis.offset; highNewValue = 0.0f; break; case AxisInfo::MODE_SPLIT: if (rawEvent->value < axis.axisInfo.splitValue) { newValue = (axis.axisInfo.splitValue - rawEvent->value) * axis.scale + axis.offset; highNewValue = 0.0f; } else if (rawEvent->value > axis.axisInfo.splitValue) { newValue = 0.0f; highNewValue = (rawEvent->value - axis.axisInfo.splitValue) * axis.highScale + axis.highOffset; } else { newValue = 0.0f; highNewValue = 0.0f; } break; default: newValue = rawEvent->value * axis.scale + axis.offset; highNewValue = 0.0f; break; } axis.newValue = newValue; axis.highNewValue = highNewValue; } break; } case EV_SYN: switch (rawEvent->code) { case SYN_REPORT: sync(rawEvent->when, false /*force*/); break; } break; } } void JoystickInputMapper::sync(nsecs_t when, bool force) { if (!filterAxes(force)) { return; } int32_t metaState = mContext->getGlobalMetaState(); int32_t buttonState = 0; PointerProperties pointerProperties; pointerProperties.clear(); pointerProperties.id = 0; pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; PointerCoords pointerCoords; pointerCoords.clear(); size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { const Axis& axis = mAxes.valueAt(i); pointerCoords.setAxisValue(axis.axisInfo.axis, axis.currentValue); if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { pointerCoords.setAxisValue(axis.axisInfo.highAxis, axis.highCurrentValue); } } // Moving a joystick axis should not wake the devide because joysticks can // be fairly noisy even when not in use. On the other hand, pushing a gamepad // button will likely wake the device. // TODO: Use the input device configuration to control this behavior more finely. uint32_t policyFlags = 0; NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0); getListener()->notifyMotion(&args); } bool JoystickInputMapper::filterAxes(bool force) { bool atLeastOneSignificantChange = force; size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { Axis& axis = mAxes.editValueAt(i); if (force || hasValueChangedSignificantly(axis.filter, axis.newValue, axis.currentValue, axis.min, axis.max)) { axis.currentValue = axis.newValue; atLeastOneSignificantChange = true; } if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { if (force || hasValueChangedSignificantly(axis.filter, axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) { axis.highCurrentValue = axis.highNewValue; atLeastOneSignificantChange = true; } } } return atLeastOneSignificantChange; } bool JoystickInputMapper::hasValueChangedSignificantly( float filter, float newValue, float currentValue, float min, float max) { if (newValue != currentValue) { // Filter out small changes in value unless the value is converging on the axis // bounds or center point. This is intended to reduce the amount of information // sent to applications by particularly noisy joysticks (such as PS3). if (fabs(newValue - currentValue) > filter || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min) || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max) || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) { return true; } } return false; } bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange( float filter, float newValue, float currentValue, float thresholdValue) { float newDistance = fabs(newValue - thresholdValue); if (newDistance < filter) { float oldDistance = fabs(currentValue - thresholdValue); if (newDistance < oldDistance) { return true; } } return false; } } // namespace android ././@LongLink0000000000000000000000000000014600000000000011216 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputReader.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputReader.0000644000015301777760000016170312322054223033307 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _UI_INPUT_READER_H #define _UI_INPUT_READER_H #include "EventHub.h" #include "PointerController.h" #include "InputListener.h" #include #include #include #include #include #include #include #include #include #include #include #include #include // C++ std lib #include // Maximum supported size of a vibration pattern. // Must be at least 2. #define MAX_VIBRATE_PATTERN_SIZE 100 // Maximum allowable delay value in a vibration pattern before // which the delay will be truncated. #define MAX_VIBRATE_PATTERN_DELAY_NSECS (1000000 * 1000000000LL) namespace android { class InputDevice; class InputMapper; /* * Input reader configuration. * * Specifies various options that modify the behavior of the input reader. */ struct InputReaderConfiguration { // Describes changes that have occurred. enum { // The pointer speed changed. CHANGE_POINTER_SPEED = 1 << 0, // The pointer gesture control changed. CHANGE_POINTER_GESTURE_ENABLEMENT = 1 << 1, // The display size or orientation changed. CHANGE_DISPLAY_INFO = 1 << 2, // The visible touches option changed. CHANGE_SHOW_TOUCHES = 1 << 3, // The keyboard layouts must be reloaded. CHANGE_KEYBOARD_LAYOUTS = 1 << 4, // The device name alias supplied by the may have changed for some devices. CHANGE_DEVICE_ALIAS = 1 << 5, // All devices must be reopened. CHANGE_MUST_REOPEN = 1 << 31 }; // Gets the amount of time to disable virtual keys after the screen is touched // in order to filter out accidental virtual key presses due to swiping gestures // or taps near the edge of the display. May be 0 to disable the feature. nsecs_t virtualKeyQuietTime; // The excluded device names for the platform. // Devices with these names will be ignored. Vector excludedDeviceNames; // Velocity control parameters for mouse pointer movements. VelocityControlParameters pointerVelocityControlParameters; // Velocity control parameters for mouse wheel movements. VelocityControlParameters wheelVelocityControlParameters; // True if pointer gestures are enabled. bool pointerGesturesEnabled; // Quiet time between certain pointer gesture transitions. // Time to allow for all fingers or buttons to settle into a stable state before // starting a new gesture. nsecs_t pointerGestureQuietInterval; // The minimum speed that a pointer must travel for us to consider switching the active // touch pointer to it during a drag. This threshold is set to avoid switching due // to noise from a finger resting on the touch pad (perhaps just pressing it down). float pointerGestureDragMinSwitchSpeed; // in pixels per second // Tap gesture delay time. // The time between down and up must be less than this to be considered a tap. nsecs_t pointerGestureTapInterval; // Tap drag gesture delay time. // The time between the previous tap's up and the next down must be less than // this to be considered a drag. Otherwise, the previous tap is finished and a // new tap begins. // // Note that the previous tap will be held down for this entire duration so this // interval must be shorter than the long press timeout. nsecs_t pointerGestureTapDragInterval; // The distance in pixels that the pointer is allowed to move from initial down // to up and still be called a tap. float pointerGestureTapSlop; // in pixels // Time after the first touch points go down to settle on an initial centroid. // This is intended to be enough time to handle cases where the user puts down two // fingers at almost but not quite exactly the same time. nsecs_t pointerGestureMultitouchSettleInterval; // The transition from PRESS to SWIPE or FREEFORM gesture mode is made when // at least two pointers have moved at least this far from their starting place. float pointerGestureMultitouchMinDistance; // in pixels // The transition from PRESS to SWIPE gesture mode can only occur when the // cosine of the angle between the two vectors is greater than or equal to than this value // which indicates that the vectors are oriented in the same direction. // When the vectors are oriented in the exactly same direction, the cosine is 1.0. // (In exactly opposite directions, the cosine is -1.0.) float pointerGestureSwipeTransitionAngleCosine; // The transition from PRESS to SWIPE gesture mode can only occur when the // fingers are no more than this far apart relative to the diagonal size of // the touch pad. For example, a ratio of 0.5 means that the fingers must be // no more than half the diagonal size of the touch pad apart. float pointerGestureSwipeMaxWidthRatio; // The gesture movement speed factor relative to the size of the display. // Movement speed applies when the fingers are moving in the same direction. // Without acceleration, a full swipe of the touch pad diagonal in movement mode // will cover this portion of the display diagonal. float pointerGestureMovementSpeedRatio; // The gesture zoom speed factor relative to the size of the display. // Zoom speed applies when the fingers are mostly moving relative to each other // to execute a scale gesture or similar. // Without acceleration, a full swipe of the touch pad diagonal in zoom mode // will cover this portion of the display diagonal. float pointerGestureZoomSpeedRatio; // True to show the location of touches on the touch screen as spots. bool showTouches; InputReaderConfiguration() : virtualKeyQuietTime(0), pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f), wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f), pointerGesturesEnabled(true), pointerGestureQuietInterval(100 * 1000000LL), // 100 ms pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second pointerGestureTapInterval(150 * 1000000LL), // 150 ms pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms pointerGestureTapSlop(10.0f), // 10 pixels pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms pointerGestureMultitouchMinDistance(15), // 15 pixels pointerGestureSwipeTransitionAngleCosine(0.2588f), // cosine of 75 degrees pointerGestureSwipeMaxWidthRatio(0.25f), pointerGestureMovementSpeedRatio(0.8f), pointerGestureZoomSpeedRatio(0.3f), showTouches(false) { } bool getDisplayInfo(int32_t displayId, bool external, int32_t* width, int32_t* height, int32_t* orientation) const; void setDisplayInfo(int32_t displayId, bool external, int32_t width, int32_t height, int32_t orientation); private: struct DisplayInfo { int32_t width; int32_t height; int32_t orientation; DisplayInfo() : width(-1), height(-1), orientation(DISPLAY_ORIENTATION_0) { } }; DisplayInfo mInternalDisplay; DisplayInfo mExternalDisplay; }; /* * Input reader policy interface. * * The input reader policy is used by the input reader to interact with the Window Manager * and other system components. * * The actual implementation is partially supported by callbacks into the DVM * via JNI. This interface is also mocked in the unit tests. * * These methods must NOT re-enter the input reader since they may be called while * holding the input reader lock. */ class InputReaderPolicyInterface : public virtual RefBase { protected: InputReaderPolicyInterface() { } virtual ~InputReaderPolicyInterface() { } public: /* Gets the input reader configuration. */ virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0; /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */ virtual sp obtainPointerController(int32_t deviceId) = 0; /* Notifies the input reader policy that some input devices have changed * and provides information about all current input devices. */ virtual void notifyInputDevicesChanged(const Vector& inputDevices) = 0; /* Gets the keyboard layout for a particular input device. */ virtual sp getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) = 0; /* Gets a user-supplied alias for a particular input device, or an empty string if none. */ virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) = 0; }; /* Processes raw input events and sends cooked event data to an input listener. */ class InputReaderInterface : public virtual RefBase { protected: InputReaderInterface() { } virtual ~InputReaderInterface() { } public: /* Dumps the state of the input reader. * * This method may be called on any thread (usually by the input manager). */ virtual void dump(String8& dump) = 0; /* Called by the heatbeat to ensures that the reader has not deadlocked. */ virtual void monitor() = 0; /* Runs a single iteration of the processing loop. * Nominally reads and processes one incoming message from the EventHub. * * This method should be called on the input reader thread. */ virtual void loopOnce() = 0; /* Gets information about all input devices. * * This method may be called on any thread (usually by the input manager). */ virtual void getInputDevices(Vector& outInputDevices) = 0; /* Query current input state. */ virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode) = 0; virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) = 0; virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) = 0; /* Determine whether physical keys exist for the given framework-domain key codes. */ virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0; /* Requests that a reconfiguration of all input devices. * The changes flag is a bitfield that indicates what has changed and whether * the input devices must all be reopened. */ virtual void requestRefreshConfiguration(uint32_t changes) = 0; /* Controls the vibrator of a particular input device. */ virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token) = 0; virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0; }; /* Internal interface used by individual input devices to access global input device state * and parameters maintained by the input reader. */ class InputReaderContext { public: InputReaderContext() { } virtual ~InputReaderContext() { } virtual void updateGlobalMetaState() = 0; virtual int32_t getGlobalMetaState() = 0; virtual void disableVirtualKeysUntil(nsecs_t time) = 0; virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode) = 0; virtual void fadePointer() = 0; virtual void requestTimeoutAtTime(nsecs_t when) = 0; virtual int32_t bumpGeneration() = 0; virtual InputReaderPolicyInterface* getPolicy() = 0; virtual InputListenerInterface* getListener() = 0; virtual EventHubInterface* getEventHub() = 0; }; /* The input reader reads raw event data from the event hub and processes it into input events * that it sends to the input listener. Some functions of the input reader, such as early * event filtering in low power states, are controlled by a separate policy object. * * The InputReader owns a collection of InputMappers. Most of the work it does happens * on the input reader thread but the InputReader can receive queries from other system * components running on arbitrary threads. To keep things manageable, the InputReader * uses a single Mutex to guard its state. The Mutex may be held while calling into the * EventHub or the InputReaderPolicy but it is never held while calling into the * InputListener. */ class InputReader : public InputReaderInterface { public: InputReader(const sp& eventHub, const sp& policy, const sp& listener); virtual ~InputReader(); virtual void dump(String8& dump); virtual void monitor(); virtual void loopOnce(); virtual void getInputDevices(Vector& outInputDevices); virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode); virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode); virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw); virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); virtual void requestRefreshConfiguration(uint32_t changes); virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); virtual void cancelVibrate(int32_t deviceId, int32_t token); protected: // These members are protected so they can be instrumented by test cases. virtual InputDevice* createDeviceLocked(int32_t deviceId, const InputDeviceIdentifier& identifier, uint32_t classes); class ContextImpl : public InputReaderContext { InputReader* mReader; public: ContextImpl(InputReader* reader); virtual void updateGlobalMetaState(); virtual int32_t getGlobalMetaState(); virtual void disableVirtualKeysUntil(nsecs_t time); virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode); virtual void fadePointer(); virtual void requestTimeoutAtTime(nsecs_t when); virtual int32_t bumpGeneration(); virtual InputReaderPolicyInterface* getPolicy(); virtual InputListenerInterface* getListener(); virtual EventHubInterface* getEventHub(); } mContext; friend class ContextImpl; private: Mutex mLock; Condition mReaderIsAliveCondition; sp mEventHub; sp mPolicy; sp mQueuedListener; InputReaderConfiguration mConfig; // The event queue. static const int EVENT_BUFFER_SIZE = 256; RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; KeyedVector mDevices; // low-level input event decoding and device management void processEventsLocked(const RawEvent* rawEvents, size_t count); void addDeviceLocked(nsecs_t when, int32_t deviceId); void removeDeviceLocked(nsecs_t when, int32_t deviceId); void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count); void timeoutExpiredLocked(nsecs_t when); void handleConfigurationChangedLocked(nsecs_t when); int32_t mGlobalMetaState; void updateGlobalMetaStateLocked(); int32_t getGlobalMetaStateLocked(); void fadePointerLocked(); int32_t mGeneration; int32_t bumpGenerationLocked(); void getInputDevicesLocked(Vector& outInputDevices); nsecs_t mDisableVirtualKeysTimeout; void disableVirtualKeysUntilLocked(nsecs_t time); bool shouldDropVirtualKeyLocked(nsecs_t now, InputDevice* device, int32_t keyCode, int32_t scanCode); nsecs_t mNextTimeout; void requestTimeoutAtTimeLocked(nsecs_t when); uint32_t mConfigurationChangesToRefresh; void refreshConfigurationLocked(uint32_t changes); // state queries typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); }; /* Reads raw events from the event hub and processes them, endlessly. */ class InputReaderThread : public Thread { public: InputReaderThread(const sp& reader); virtual ~InputReaderThread(); private: sp mReader; virtual bool threadLoop(); }; /* Represents the state of a single input device. */ class InputDevice { public: InputDevice(InputReaderContext* context, int32_t id, int32_t generation, const InputDeviceIdentifier& identifier, uint32_t classes); ~InputDevice(); inline InputReaderContext* getContext() { return mContext; } inline int32_t getId() { return mId; } inline int32_t getGeneration() { return mGeneration; } inline const String8& getName() { return mIdentifier.name; } inline uint32_t getClasses() { return mClasses; } inline uint32_t getSources() { return mSources; } inline bool isExternal() { return mIsExternal; } inline void setExternal(bool external) { mIsExternal = external; } inline bool isIgnored() { return mMappers.isEmpty(); } void dump(String8& dump); void addMapper(InputMapper* mapper); void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); void reset(nsecs_t when); void process(const RawEvent* rawEvents, size_t count); void timeoutExpired(nsecs_t when); void getDeviceInfo(InputDeviceInfo* outDeviceInfo); int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); void cancelVibrate(int32_t token); int32_t getMetaState(); void fadePointer(); void bumpGeneration(); void notifyReset(nsecs_t when); inline const PropertyMap& getConfiguration() { return mConfiguration; } inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } bool hasKey(int32_t code) { return getEventHub()->hasScanCode(mId, code); } bool hasAbsoluteAxis(int32_t code) { RawAbsoluteAxisInfo info; getEventHub()->getAbsoluteAxisInfo(mId, code, &info); return info.valid; } bool isKeyPressed(int32_t code) { return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN; } int32_t getAbsoluteAxisValue(int32_t code) { int32_t value; getEventHub()->getAbsoluteAxisValue(mId, code, &value); return value; } private: InputReaderContext* mContext; int32_t mId; int32_t mGeneration; InputDeviceIdentifier mIdentifier; String8 mAlias; uint32_t mClasses; Vector mMappers; uint32_t mSources; bool mIsExternal; bool mDropUntilNextSync; typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); PropertyMap mConfiguration; }; /* Keeps track of the state of mouse or touch pad buttons. */ class CursorButtonAccumulator { public: CursorButtonAccumulator(); void reset(InputDevice* device); void process(const RawEvent* rawEvent); uint32_t getButtonState() const; private: bool mBtnLeft; bool mBtnRight; bool mBtnMiddle; bool mBtnBack; bool mBtnSide; bool mBtnForward; bool mBtnExtra; bool mBtnTask; void clearButtons(); }; /* Keeps track of cursor movements. */ class CursorMotionAccumulator { public: CursorMotionAccumulator(); void reset(InputDevice* device); void process(const RawEvent* rawEvent); void finishSync(); inline int32_t getRelativeX() const { return mRelX; } inline int32_t getRelativeY() const { return mRelY; } private: int32_t mRelX; int32_t mRelY; void clearRelativeAxes(); }; /* Keeps track of cursor scrolling motions. */ class CursorScrollAccumulator { public: CursorScrollAccumulator(); void configure(InputDevice* device); void reset(InputDevice* device); void process(const RawEvent* rawEvent); void finishSync(); inline bool haveRelativeVWheel() const { return mHaveRelWheel; } inline bool haveRelativeHWheel() const { return mHaveRelHWheel; } inline int32_t getRelativeVWheel() const { return mRelWheel; } inline int32_t getRelativeHWheel() const { return mRelHWheel; } private: bool mHaveRelWheel; bool mHaveRelHWheel; int32_t mRelWheel; int32_t mRelHWheel; void clearRelativeAxes(); }; /* Keeps track of the state of touch, stylus and tool buttons. */ class TouchButtonAccumulator { public: TouchButtonAccumulator(); void configure(InputDevice* device); void reset(InputDevice* device); void process(const RawEvent* rawEvent); uint32_t getButtonState() const; int32_t getToolType() const; bool isToolActive() const; bool isHovering() const; bool hasStylus() const; private: bool mHaveBtnTouch; bool mHaveStylus; bool mBtnTouch; bool mBtnStylus; bool mBtnStylus2; bool mBtnToolFinger; bool mBtnToolPen; bool mBtnToolRubber; bool mBtnToolBrush; bool mBtnToolPencil; bool mBtnToolAirbrush; bool mBtnToolMouse; bool mBtnToolLens; bool mBtnToolDoubleTap; bool mBtnToolTripleTap; bool mBtnToolQuadTap; void clearButtons(); }; /* Raw axis information from the driver. */ struct RawPointerAxes { RawAbsoluteAxisInfo x; RawAbsoluteAxisInfo y; RawAbsoluteAxisInfo pressure; RawAbsoluteAxisInfo touchMajor; RawAbsoluteAxisInfo touchMinor; RawAbsoluteAxisInfo toolMajor; RawAbsoluteAxisInfo toolMinor; RawAbsoluteAxisInfo orientation; RawAbsoluteAxisInfo distance; RawAbsoluteAxisInfo tiltX; RawAbsoluteAxisInfo tiltY; RawAbsoluteAxisInfo trackingId; RawAbsoluteAxisInfo slot; RawPointerAxes(); void clear(); }; /* Raw data for a collection of pointers including a pointer id mapping table. */ struct RawPointerData { struct Pointer { int32_t id; int32_t x; int32_t y; int32_t pressure; int32_t touchMajor; int32_t touchMinor; int32_t toolMajor; int32_t toolMinor; int32_t orientation; int32_t distance; int32_t tiltX; int32_t tiltY; int32_t toolType; // a fully decoded AMOTION_EVENT_TOOL_TYPE constant bool isHovering; }; uint32_t pointerCount; Pointer pointers[MAX_POINTERS]; IntSet hoveringIds, touchingIds; uint32_t idToIndex(int32_t id) const { uint32_t i = 0; while (pointers[i].id != id && i < pointerCount) { ++i; } assert(pointers[i].id == id); return i; } RawPointerData(); void clear(); void copyFrom(const RawPointerData& other); void getCentroidOfTouchingPointers(float* outX, float* outY) const; inline void insertId(int32_t id, bool isHovering) { if (isHovering) { hoveringIds.insert(id); } else { touchingIds.insert(id); } } inline void clearIds() { hoveringIds.clear(); touchingIds.clear(); } inline const Pointer& pointerForId(int32_t id) const { return pointers[idToIndex(id)]; } inline bool isHovering(uint32_t pointerIndex) { return pointers[pointerIndex].isHovering; } }; /* Cooked data for a collection of pointers including a pointer id mapping table. */ struct CookedPointerData { uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; IntSet hoveringIds, touchingIds; uint32_t idToIndex(int32_t id) const { uint32_t i = 0; while (pointerProperties[i].id != id && i < pointerCount) { ++i; } assert(pointerProperties[i].id == id); return i; } CookedPointerData(); void clear(); void copyFrom(const CookedPointerData& other); inline bool isHovering(uint32_t pointerIndex) { return hoveringIds.contains(pointerProperties[pointerIndex].id); } }; /* Keeps track of the state of single-touch protocol. */ class SingleTouchMotionAccumulator { public: SingleTouchMotionAccumulator(); void process(const RawEvent* rawEvent); void reset(InputDevice* device); inline int32_t getAbsoluteX() const { return mAbsX; } inline int32_t getAbsoluteY() const { return mAbsY; } inline int32_t getAbsolutePressure() const { return mAbsPressure; } inline int32_t getAbsoluteToolWidth() const { return mAbsToolWidth; } inline int32_t getAbsoluteDistance() const { return mAbsDistance; } inline int32_t getAbsoluteTiltX() const { return mAbsTiltX; } inline int32_t getAbsoluteTiltY() const { return mAbsTiltY; } private: int32_t mAbsX; int32_t mAbsY; int32_t mAbsPressure; int32_t mAbsToolWidth; int32_t mAbsDistance; int32_t mAbsTiltX; int32_t mAbsTiltY; void clearAbsoluteAxes(); }; /* Keeps track of the state of multi-touch protocol. */ class MultiTouchMotionAccumulator { public: class Slot { public: inline bool isInUse() const { return mInUse; } inline int32_t getX() const { return mAbsMTPositionX; } inline int32_t getY() const { return mAbsMTPositionY; } inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; } inline int32_t getTouchMinor() const { return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; } inline int32_t getToolMajor() const { return mAbsMTWidthMajor; } inline int32_t getToolMinor() const { return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; } inline int32_t getOrientation() const { return mAbsMTOrientation; } inline int32_t getTrackingId() const { return mAbsMTTrackingId; } inline int32_t getPressure() const { return mAbsMTPressure; } inline bool havePressure() const { return mHaveAbsMTPressure; } inline int32_t getDistance() const { return mAbsMTDistance; } inline int32_t getToolType() const; private: friend class MultiTouchMotionAccumulator; bool mInUse; bool mHaveAbsMTTouchMinor; bool mHaveAbsMTWidthMinor; bool mHaveAbsMTPressure; bool mHaveAbsMTToolType; int32_t mAbsMTPositionX; int32_t mAbsMTPositionY; int32_t mAbsMTTouchMajor; int32_t mAbsMTTouchMinor; int32_t mAbsMTWidthMajor; int32_t mAbsMTWidthMinor; int32_t mAbsMTOrientation; int32_t mAbsMTTrackingId; int32_t mAbsMTPressure; int32_t mAbsMTDistance; int32_t mAbsMTToolType; Slot(); void clear(); }; MultiTouchMotionAccumulator(); ~MultiTouchMotionAccumulator(); void configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol); void reset(InputDevice* device); void process(const RawEvent* rawEvent); void finishSync(); bool hasStylus() const; inline size_t getSlotCount() const { return mSlotCount; } inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } private: int32_t mCurrentSlot; Slot* mSlots; size_t mSlotCount; bool mUsingSlotsProtocol; bool mHaveStylus; void clearSlots(int32_t initialSlot); }; /* An input mapper transforms raw input events into cooked event data. * A single input device can have multiple associated input mappers in order to interpret * different classes of events. * * InputMapper lifecycle: * - create * - configure with 0 changes * - reset * - process, process, process (may occasionally reconfigure with non-zero changes or reset) * - reset * - destroy */ class InputMapper { public: InputMapper(InputDevice* device); virtual ~InputMapper(); inline InputDevice* getDevice() { return mDevice; } inline int32_t getDeviceId() { return mDevice->getId(); } inline const String8 getDeviceName() { return mDevice->getName(); } inline InputReaderContext* getContext() { return mContext; } inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } inline InputListenerInterface* getListener() { return mContext->getListener(); } inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } virtual uint32_t getSources() = 0; virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent) = 0; virtual void timeoutExpired(nsecs_t when); virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); virtual void cancelVibrate(int32_t token); virtual int32_t getMetaState(); virtual void fadePointer(); protected: InputDevice* mDevice; InputReaderContext* mContext; status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); void bumpGeneration(); static void dumpRawAbsoluteAxisInfo(String8& dump, const RawAbsoluteAxisInfo& axis, const char* name); }; class SwitchInputMapper : public InputMapper { public: SwitchInputMapper(InputDevice* device); virtual ~SwitchInputMapper(); virtual uint32_t getSources(); virtual void process(const RawEvent* rawEvent); virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); private: void processSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue); }; class VibratorInputMapper : public InputMapper { public: VibratorInputMapper(InputDevice* device); virtual ~VibratorInputMapper(); virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void process(const RawEvent* rawEvent); virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); virtual void cancelVibrate(int32_t token); virtual void timeoutExpired(nsecs_t when); virtual void dump(String8& dump); private: bool mVibrating; nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE]; size_t mPatternSize; ssize_t mRepeat; int32_t mToken; ssize_t mIndex; nsecs_t mNextStepTime; void nextStep(); void stopVibrating(); }; class KeyboardInputMapper : public InputMapper { public: KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType); virtual ~KeyboardInputMapper(); virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); virtual int32_t getMetaState(); private: struct KeyDown { int32_t keyCode; int32_t scanCode; }; uint32_t mSource; int32_t mKeyboardType; int32_t mOrientation; // orientation for dpad keys Vector mKeyDowns; // keys that are down int32_t mMetaState; nsecs_t mDownTime; // time of most recent key down int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none struct LedState { bool avail; // led is available bool on; // we think the led is currently on }; LedState mCapsLockLedState; LedState mNumLockLedState; LedState mScrollLockLedState; // Immutable configuration parameters. struct Parameters { int32_t associatedDisplayId; bool orientationAware; } mParameters; void configureParameters(); void dumpParameters(String8& dump); bool isKeyboardOrGamepadKey(int32_t scanCode); void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags); ssize_t findKeyDown(int32_t scanCode); void resetLedState(); void initializeLedState(LedState& ledState, int32_t led); void updateLedState(bool reset); void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset); }; class CursorInputMapper : public InputMapper { public: CursorInputMapper(InputDevice* device); virtual ~CursorInputMapper(); virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); virtual void fadePointer(); private: // Amount that trackball needs to move in order to generate a key event. static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; // Immutable configuration parameters. struct Parameters { enum Mode { MODE_POINTER, MODE_NAVIGATION }; Mode mode; int32_t associatedDisplayId; bool orientationAware; } mParameters; CursorButtonAccumulator mCursorButtonAccumulator; CursorMotionAccumulator mCursorMotionAccumulator; CursorScrollAccumulator mCursorScrollAccumulator; int32_t mSource; float mXScale; float mYScale; float mXPrecision; float mYPrecision; float mVWheelScale; float mHWheelScale; // Velocity controls for mouse pointer and wheel movements. // The controls for X and Y wheel movements are separate to keep them decoupled. VelocityControl mPointerVelocityControl; VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; int32_t mOrientation; sp mPointerController; int32_t mButtonState; nsecs_t mDownTime; void configureParameters(); void dumpParameters(String8& dump); void sync(nsecs_t when); }; class TouchInputMapper : public InputMapper { public: TouchInputMapper(InputDevice* device); virtual ~TouchInputMapper(); virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); virtual void fadePointer(); virtual void timeoutExpired(nsecs_t when); protected: CursorButtonAccumulator mCursorButtonAccumulator; CursorScrollAccumulator mCursorScrollAccumulator; TouchButtonAccumulator mTouchButtonAccumulator; struct VirtualKey { int32_t keyCode; int32_t scanCode; uint32_t flags; // computed hit box, specified in touch screen coords based on known display size int32_t hitLeft; int32_t hitTop; int32_t hitRight; int32_t hitBottom; inline bool isHit(int32_t x, int32_t y) const { return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom; } }; // Input sources and device mode. uint32_t mSource; enum DeviceMode { DEVICE_MODE_DISABLED, // input is disabled DEVICE_MODE_DIRECT, // direct mapping (touchscreen) DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad) DEVICE_MODE_POINTER // pointer mapping (pointer) }; DeviceMode mDeviceMode; // The reader's configuration. InputReaderConfiguration mConfig; // Immutable configuration parameters. struct Parameters { enum DeviceType { DEVICE_TYPE_TOUCH_SCREEN, DEVICE_TYPE_TOUCH_PAD, DEVICE_TYPE_POINTER }; DeviceType deviceType; int32_t associatedDisplayId; bool associatedDisplayIsExternal; bool orientationAware; enum GestureMode { GESTURE_MODE_POINTER, GESTURE_MODE_SPOTS }; GestureMode gestureMode; } mParameters; // Immutable calibration parameters in parsed form. struct Calibration { // Size enum SizeCalibration { SIZE_CALIBRATION_DEFAULT, SIZE_CALIBRATION_NONE, SIZE_CALIBRATION_GEOMETRIC, SIZE_CALIBRATION_DIAMETER, SIZE_CALIBRATION_AREA }; SizeCalibration sizeCalibration; bool haveSizeScale; float sizeScale; bool haveSizeBias; float sizeBias; bool haveSizeIsSummed; bool sizeIsSummed; // Pressure enum PressureCalibration { PRESSURE_CALIBRATION_DEFAULT, PRESSURE_CALIBRATION_NONE, PRESSURE_CALIBRATION_PHYSICAL, PRESSURE_CALIBRATION_AMPLITUDE }; PressureCalibration pressureCalibration; bool havePressureScale; float pressureScale; // Orientation enum OrientationCalibration { ORIENTATION_CALIBRATION_DEFAULT, ORIENTATION_CALIBRATION_NONE, ORIENTATION_CALIBRATION_INTERPOLATED, ORIENTATION_CALIBRATION_VECTOR }; OrientationCalibration orientationCalibration; // Distance enum DistanceCalibration { DISTANCE_CALIBRATION_DEFAULT, DISTANCE_CALIBRATION_NONE, DISTANCE_CALIBRATION_SCALED }; DistanceCalibration distanceCalibration; bool haveDistanceScale; float distanceScale; inline void applySizeScaleAndBias(float* outSize) const { if (haveSizeScale) { *outSize *= sizeScale; } if (haveSizeBias) { *outSize += sizeBias; } } } mCalibration; // Raw pointer axis information from the driver. RawPointerAxes mRawPointerAxes; // Raw pointer sample data. RawPointerData mCurrentRawPointerData; RawPointerData mLastRawPointerData; // Cooked pointer sample data. CookedPointerData mCurrentCookedPointerData; CookedPointerData mLastCookedPointerData; // Button state. int32_t mCurrentButtonState; int32_t mLastButtonState; // Scroll state. int32_t mCurrentRawVScroll; int32_t mCurrentRawHScroll; // Id sets used to differentiate fingers, stylus and mouse tools. IntSet mCurrentFingerIds; // finger or unknown IntSet mLastFingerIds; IntSet mCurrentStylusIds; // stylus or eraser IntSet mLastStylusIds; IntSet mCurrentMouseIds; // mouse or lens IntSet mLastMouseIds; // True if we sent a HOVER_ENTER event. bool mSentHoverEnter; // The time the primary pointer last went down. nsecs_t mDownTime; // The pointer controller, or null if the device is not a pointer. sp mPointerController; Vector mVirtualKeys; virtual void configureParameters(); virtual void dumpParameters(String8& dump); virtual void configureRawPointerAxes(); virtual void dumpRawPointerAxes(String8& dump); virtual void configureSurface(nsecs_t when, bool* outResetNeeded); virtual void dumpSurface(String8& dump); virtual void configureVirtualKeys(); virtual void dumpVirtualKeys(String8& dump); virtual void parseCalibration(); virtual void resolveCalibration(); virtual void dumpCalibration(String8& dump); virtual bool hasStylus() const = 0; virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0; int32_t fetchNewPointerId(); private: // The surface orientation and width and height set by configureSurface(). int32_t mSurfaceOrientation; int32_t mSurfaceWidth; int32_t mSurfaceHeight; // The associated display orientation and width and height set by configureSurface(). int32_t mAssociatedDisplayOrientation; int32_t mAssociatedDisplayWidth; int32_t mAssociatedDisplayHeight; // Translation and scaling factors, orientation-independent. float mXScale; float mXPrecision; float mYScale; float mYPrecision; float mGeometricScale; float mPressureScale; float mSizeScale; float mOrientationCenter; float mOrientationScale; float mDistanceScale; bool mHaveTilt; float mTiltXCenter; float mTiltXScale; float mTiltYCenter; float mTiltYScale; // Oriented motion ranges for input device info. struct OrientedRanges { InputDeviceInfo::MotionRange x; InputDeviceInfo::MotionRange y; InputDeviceInfo::MotionRange pressure; bool haveSize; InputDeviceInfo::MotionRange size; bool haveTouchSize; InputDeviceInfo::MotionRange touchMajor; InputDeviceInfo::MotionRange touchMinor; bool haveToolSize; InputDeviceInfo::MotionRange toolMajor; InputDeviceInfo::MotionRange toolMinor; bool haveOrientation; InputDeviceInfo::MotionRange orientation; bool haveDistance; InputDeviceInfo::MotionRange distance; bool haveTilt; InputDeviceInfo::MotionRange tilt; OrientedRanges() { clear(); } void clear() { haveSize = false; haveTouchSize = false; haveToolSize = false; haveOrientation = false; haveDistance = false; haveTilt = false; } } mOrientedRanges; // Oriented dimensions and precision. float mOrientedSurfaceWidth; float mOrientedSurfaceHeight; float mOrientedXPrecision; float mOrientedYPrecision; struct CurrentVirtualKeyState { bool down; bool ignored; nsecs_t downTime; int32_t keyCode; int32_t scanCode; } mCurrentVirtualKey; // Scale factor for gesture or mouse based pointer movements. float mPointerXMovementScale; float mPointerYMovementScale; // Scale factor for gesture based zooming and other freeform motions. float mPointerXZoomScale; float mPointerYZoomScale; // The maximum swipe width. float mPointerGestureMaxSwipeWidth; struct PointerDistanceHeapElement { uint32_t currentPointerIndex : 8; uint32_t lastPointerIndex : 8; uint64_t distance : 48; // squared distance }; enum PointerUsage { POINTER_USAGE_NONE, POINTER_USAGE_GESTURES, POINTER_USAGE_STYLUS, POINTER_USAGE_MOUSE }; PointerUsage mPointerUsage; struct PointerGesture { enum Mode { // No fingers, button is not pressed. // Nothing happening. NEUTRAL, // No fingers, button is not pressed. // Tap detected. // Emits DOWN and UP events at the pointer location. TAP, // Exactly one finger dragging following a tap. // Pointer follows the active finger. // Emits DOWN, MOVE and UP events at the pointer location. // // Detect double-taps when the finger goes up while in TAP_DRAG mode. TAP_DRAG, // Button is pressed. // Pointer follows the active finger if there is one. Other fingers are ignored. // Emits DOWN, MOVE and UP events at the pointer location. BUTTON_CLICK_OR_DRAG, // Exactly one finger, button is not pressed. // Pointer follows the active finger. // Emits HOVER_MOVE events at the pointer location. // // Detect taps when the finger goes up while in HOVER mode. HOVER, // Exactly two fingers but neither have moved enough to clearly indicate // whether a swipe or freeform gesture was intended. We consider the // pointer to be pressed so this enables clicking or long-pressing on buttons. // Pointer does not move. // Emits DOWN, MOVE and UP events with a single stationary pointer coordinate. PRESS, // Exactly two fingers moving in the same direction, button is not pressed. // Pointer does not move. // Emits DOWN, MOVE and UP events with a single pointer coordinate that // follows the midpoint between both fingers. SWIPE, // Two or more fingers moving in arbitrary directions, button is not pressed. // Pointer does not move. // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow // each finger individually relative to the initial centroid of the finger. FREEFORM, // Waiting for quiet time to end before starting the next gesture. QUIET }; // Time the first finger went down. nsecs_t firstTouchTime; // The active pointer id from the raw touch data. int32_t activeTouchId; // -1 if none // The active pointer id from the gesture last delivered to the application. int32_t activeGestureId; // -1 if none // Pointer coords and ids for the current and previous pointer gesture. Mode currentGestureMode; IntSet currentGestureIds; std::unordered_map currentGestureIdToIndex; PointerProperties currentGestureProperties[MAX_POINTERS]; PointerCoords currentGestureCoords[MAX_POINTERS]; Mode lastGestureMode; IntSet lastGestureIds; std::unordered_map lastGestureIdToIndex; PointerProperties lastGestureProperties[MAX_POINTERS]; PointerCoords lastGestureCoords[MAX_POINTERS]; // Time the pointer gesture last went down. nsecs_t downTime; // Time when the pointer went down for a TAP. nsecs_t tapDownTime; // Time when the pointer went up for a TAP. nsecs_t tapUpTime; // Location of initial tap. float tapX, tapY; // Time we started waiting for quiescence. nsecs_t quietTime; // Reference points for multitouch gestures. float referenceTouchX; // reference touch X/Y coordinates in surface units float referenceTouchY; float referenceGestureX; // reference gesture X/Y coordinates in pixels float referenceGestureY; // Distance that each pointer has traveled which has not yet been // subsumed into the reference gesture position. IntSet referenceIds; struct Delta { float dx, dy; }; std::unordered_map referenceDeltas; // Describes how touch ids are mapped to gesture ids for freeform gestures. std::unordered_map freeformTouchToGestureIdMap; // A velocity tracker for determining whether to switch active pointers during drags. VelocityTracker velocityTracker; void reset() { firstTouchTime = LLONG_MIN; activeTouchId = -1; activeGestureId = -1; currentGestureMode = NEUTRAL; currentGestureIds.clear(); lastGestureMode = NEUTRAL; lastGestureIds.clear(); downTime = 0; velocityTracker.clear(); resetTap(); resetQuietTime(); } void resetTap() { tapDownTime = LLONG_MIN; tapUpTime = LLONG_MIN; } void resetQuietTime() { quietTime = LLONG_MIN; } } mPointerGesture; struct PointerSimple { PointerCoords currentCoords; PointerProperties currentProperties; PointerCoords lastCoords; PointerProperties lastProperties; // True if the pointer is down. bool down; // True if the pointer is hovering. bool hovering; // Time the pointer last went down. nsecs_t downTime; void reset() { currentCoords.clear(); currentProperties.clear(); lastCoords.clear(); lastProperties.clear(); down = false; hovering = false; downTime = 0; } } mPointerSimple; // The pointer and scroll velocity controls. VelocityControl mPointerVelocityControl; VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; void sync(nsecs_t when); bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyEventAction, int32_t keyEventFlags); void dispatchTouches(nsecs_t when, uint32_t policyFlags); void dispatchHoverExit(nsecs_t when, uint32_t policyFlags); void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags); void cookPointerData(); void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage); void abortPointerUsage(nsecs_t when, uint32_t policyFlags); void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout); void abortPointerGestures(nsecs_t when, uint32_t policyFlags); bool preparePointerGestures(nsecs_t when, bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout); void dispatchPointerStylus(nsecs_t when, uint32_t policyFlags); void abortPointerStylus(nsecs_t when, uint32_t policyFlags); void dispatchPointerMouse(nsecs_t when, uint32_t policyFlags); void abortPointerMouse(nsecs_t when, uint32_t policyFlags); void dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, bool down, bool hovering); void abortPointerSimple(nsecs_t when, uint32_t policyFlags); // Dispatches a motion event. // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the // method will take care of setting the index and transmuting the action to DOWN or UP // it is the first / last pointer to go down / up. void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, uint32_t inPointerCount, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, const PointerProperties* properties, const PointerCoords* coords, uint32_t inPointerCount, const IntSet &idsToDispatch, int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); // Updates pointer coords and properties for pointers that have moved. // Returns true if any of them changed. bool updateMovedPointers(const PointerProperties* inProperties, const PointerCoords* inCoords, uint32_t inPointerCount, PointerProperties* outProperties, PointerCoords* outCoords, uint32_t outPointerCount, const IntSet &commonTouchingIds) const; bool isPointInsideSurface(int32_t x, int32_t y); const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); void assignPointerIds(); int32_t mNextNewPointerId; }; class SingleTouchInputMapper : public TouchInputMapper { public: SingleTouchInputMapper(InputDevice* device); virtual ~SingleTouchInputMapper(); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); protected: virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); virtual void configureRawPointerAxes(); virtual bool hasStylus() const; private: SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; }; class MultiTouchInputMapper : public TouchInputMapper { public: MultiTouchInputMapper(InputDevice* device); virtual ~MultiTouchInputMapper(); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); protected: virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); virtual void configureRawPointerAxes(); virtual bool hasStylus() const; private: MultiTouchMotionAccumulator mMultiTouchMotionAccumulator; // Specifies the pointer ids that are in use, and their associated tracking id. IntSet mPointerIds; std::unordered_map mPointerTrackingIdMap; }; class JoystickInputMapper : public InputMapper { public: JoystickInputMapper(InputDevice* device); virtual ~JoystickInputMapper(); virtual uint32_t getSources(); virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); virtual void dump(String8& dump); virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); virtual void reset(nsecs_t when); virtual void process(const RawEvent* rawEvent); private: struct Axis { RawAbsoluteAxisInfo rawAxisInfo; AxisInfo axisInfo; bool explicitlyMapped; // true if the axis was explicitly assigned an axis id float scale; // scale factor from raw to normalized values float offset; // offset to add after scaling for normalization float highScale; // scale factor from raw to normalized values of high split float highOffset; // offset to add after scaling for normalization of high split float min; // normalized inclusive minimum float max; // normalized inclusive maximum float flat; // normalized flat region size float fuzz; // normalized error tolerance float filter; // filter out small variations of this size float currentValue; // current value float newValue; // most recent value float highCurrentValue; // current value of high split float highNewValue; // most recent value of high split void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo, bool explicitlyMapped, float scale, float offset, float highScale, float highOffset, float min, float max, float flat, float fuzz) { this->rawAxisInfo = rawAxisInfo; this->axisInfo = axisInfo; this->explicitlyMapped = explicitlyMapped; this->scale = scale; this->offset = offset; this->highScale = highScale; this->highOffset = highOffset; this->min = min; this->max = max; this->flat = flat; this->fuzz = fuzz; this->filter = 0; resetValue(); } void resetValue() { this->currentValue = 0; this->newValue = 0; this->highCurrentValue = 0; this->highNewValue = 0; } }; // Axes indexed by raw ABS_* axis index. KeyedVector mAxes; void sync(nsecs_t when, bool force); bool haveAxis(int32_t axisId); void pruneAxes(bool ignoreExplicitlyMappedAxes); bool filterAxes(bool force); static bool hasValueChangedSignificantly(float filter, float newValue, float currentValue, float min, float max); static bool hasMovedNearerToValueWithinFilteredRange(float filter, float newValue, float currentValue, float thresholdValue); static bool isCenteredAxis(int32_t axis); }; } // namespace android #endif // _UI_INPUT_READER_H ././@LongLink0000000000000000000000000000015400000000000011215 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/VelocityTracker.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/VelocityTrac0000644000015301777760000007745012322054223033424 0ustar pbusernogroup00000000000000/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "VelocityTracker" //#define LOG_NDEBUG 0 // Log debug messages about velocity tracking. #define DEBUG_VELOCITY 0 // Log debug messages about the progress of the algorithm itself. #define DEBUG_STRATEGY 0 #include #include #include #include #include #include #include #include namespace android { // Nanoseconds per milliseconds. static const nsecs_t NANOS_PER_MS = 1000000; // Threshold for determining that a pointer has stopped moving. // Some input devices do not send ACTION_MOVE events in the case where a pointer has // stopped. We need to detect this case so that we can accurately predict the // velocity after the pointer starts moving again. static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS; static float vectorDot(const float* a, const float* b, uint32_t m) { float r = 0; while (m--) { r += *(a++) * *(b++); } return r; } static float vectorNorm(const float* a, uint32_t m) { float r = 0; while (m--) { float t = *(a++); r += t * t; } return sqrtf(r); } #if DEBUG_STRATEGY || DEBUG_VELOCITY static String8 vectorToString(const float* a, uint32_t m) { String8 str; str.append("["); while (m--) { str.appendFormat(" %f", *(a++)); if (m) { str.append(","); } } str.append(" ]"); return str; } static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) { String8 str; str.append("["); for (size_t i = 0; i < m; i++) { if (i) { str.append(","); } str.append(" ["); for (size_t j = 0; j < n; j++) { if (j) { str.append(","); } str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]); } str.append(" ]"); } str.append(" ]"); return str; } #endif // --- VelocityTracker --- // The default velocity tracker strategy. // Although other strategies are available for testing and comparison purposes, // this is the strategy that applications will actually use. Be very careful // when adjusting the default strategy because it can dramatically affect // (often in a bad way) the user experience. const char* VelocityTracker::DEFAULT_STRATEGY = "lsq2"; VelocityTracker::VelocityTracker(const char* strategy) : mLastEventTime(0), mActivePointerId(-1) { char value[PROPERTY_VALUE_MAX]; // Allow the default strategy to be overridden using a system property for debugging. if (!strategy) { int length = property_get("debug.velocitytracker.strategy", value, NULL); if (length > 0) { strategy = value; } else { strategy = DEFAULT_STRATEGY; } } // Configure the strategy. if (!configureStrategy(strategy)) { ALOGD("Unrecognized velocity tracker strategy name '%s'.", strategy); if (!configureStrategy(DEFAULT_STRATEGY)) { LOG_ALWAYS_FATAL("Could not create the default velocity tracker strategy '%s'!", strategy); } } } VelocityTracker::~VelocityTracker() { delete mStrategy; } bool VelocityTracker::configureStrategy(const char* strategy) { mStrategy = createStrategy(strategy); return mStrategy != NULL; } VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) { if (!strcmp("lsq1", strategy)) { // 1st order least squares. Quality: POOR. // Frequently underfits the touch data especially when the finger accelerates // or changes direction. Often underestimates velocity. The direction // is overly influenced by historical touch points. return new LeastSquaresVelocityTrackerStrategy(1); } if (!strcmp("lsq2", strategy)) { // 2nd order least squares. Quality: VERY GOOD. // Pretty much ideal, but can be confused by certain kinds of touch data, // particularly if the panel has a tendency to generate delayed, // duplicate or jittery touch coordinates when the finger is released. return new LeastSquaresVelocityTrackerStrategy(2); } if (!strcmp("lsq3", strategy)) { // 3rd order least squares. Quality: UNUSABLE. // Frequently overfits the touch data yielding wildly divergent estimates // of the velocity when the finger is released. return new LeastSquaresVelocityTrackerStrategy(3); } if (!strcmp("wlsq2-delta", strategy)) { // 2nd order weighted least squares, delta weighting. Quality: EXPERIMENTAL return new LeastSquaresVelocityTrackerStrategy(2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_DELTA); } if (!strcmp("wlsq2-central", strategy)) { // 2nd order weighted least squares, central weighting. Quality: EXPERIMENTAL return new LeastSquaresVelocityTrackerStrategy(2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_CENTRAL); } if (!strcmp("wlsq2-recent", strategy)) { // 2nd order weighted least squares, recent weighting. Quality: EXPERIMENTAL return new LeastSquaresVelocityTrackerStrategy(2, LeastSquaresVelocityTrackerStrategy::WEIGHTING_RECENT); } if (!strcmp("int1", strategy)) { // 1st order integrating filter. Quality: GOOD. // Not as good as 'lsq2' because it cannot estimate acceleration but it is // more tolerant of errors. Like 'lsq1', this strategy tends to underestimate // the velocity of a fling but this strategy tends to respond to changes in // direction more quickly and accurately. return new IntegratingVelocityTrackerStrategy(1); } if (!strcmp("int2", strategy)) { // 2nd order integrating filter. Quality: EXPERIMENTAL. // For comparison purposes only. Unlike 'int1' this strategy can compensate // for acceleration but it typically overestimates the effect. return new IntegratingVelocityTrackerStrategy(2); } if (!strcmp("legacy", strategy)) { // Legacy velocity tracker algorithm. Quality: POOR. // For comparison purposes only. This algorithm is strongly influenced by // old data points, consistently underestimates velocity and takes a very long // time to adjust to changes in direction. return new LegacyVelocityTrackerStrategy(); } return NULL; } void VelocityTracker::clear() { mCurrentPointerIds.clear(); mActivePointerId = -1; mStrategy->clear(); } void VelocityTracker::clearPointers(const IntSet &ids) { mCurrentPointerIds.remove(ids); if (mActivePointerId >= 0 && ids.contains(mActivePointerId)) { mActivePointerId = !mCurrentPointerIds.isEmpty() ? mCurrentPointerIds.first() : -1; } mStrategy->clearPointers(ids); } void VelocityTracker::addMovement(nsecs_t eventTime, const IntSet &ids, const Position* positions) { if (!(mCurrentPointerIds & ids).isEmpty() && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) { #if DEBUG_VELOCITY ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.", (eventTime - mLastEventTime) * 0.000001f); #endif // We have not received any movements for too long. Assume that all pointers // have stopped. mStrategy->clear(); } mLastEventTime = eventTime; mCurrentPointerIds = ids; if (mActivePointerId < 0 || !ids.contains(mActivePointerId)) { mActivePointerId = ids.isEmpty() ? -1 : ids.first(); } mStrategy->addMovement(eventTime, ids, positions); #if DEBUG_VELOCITY ALOGD("VelocityTracker: addMovement eventTime=%lld, ids.cont()=%d, activePointerId=%d", eventTime, ids.count(), mActivePointerId); size_t index = 0; ids.forEach([&](int32_t id) { Estimator estimator; getEstimator(id, &estimator); ALOGD(" %d: position (%0.3f, %0.3f), " "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)", id, positions[index].x, positions[index].y, int(estimator.degree), vectorToString(estimator.xCoeff, estimator.degree + 1).string(), vectorToString(estimator.yCoeff, estimator.degree + 1).string(), estimator.confidence); ++index; } #endif } void VelocityTracker::addMovement(const MotionEvent* event) { int32_t actionMasked = event->getActionMasked(); switch (actionMasked) { case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_HOVER_ENTER: // Clear all pointers on down before adding the new movement. clear(); break; case AMOTION_EVENT_ACTION_POINTER_DOWN: { // Start a new movement trace for a pointer that just went down. // We do this on down instead of on up because the client may want to query the // final velocity for a pointer that just went up. IntSet downIds; downIds.insert(event->getPointerId(event->getActionIndex())); clearPointers(downIds); break; } case AMOTION_EVENT_ACTION_MOVE: case AMOTION_EVENT_ACTION_HOVER_MOVE: break; default: // Ignore all other actions because they do not convey any new information about // pointer movement. We also want to preserve the last known velocity of the pointers. // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position // of the pointers that went up. ACTION_POINTER_UP does include the new position of // pointers that remained down but we will also receive an ACTION_MOVE with this // information if any of them actually moved. Since we don't know how many pointers // will be going up at once it makes sense to just wait for the following ACTION_MOVE // before adding the movement. return; } size_t pointerCount = event->getPointerCount(); if (pointerCount > MAX_POINTERS) { pointerCount = MAX_POINTERS; } IntSet ids; for (size_t i = 0; i < pointerCount; i++) { ids.insert(event->getPointerId(i)); } uint32_t pointerIndex[MAX_POINTERS]; for (size_t i = 0; i < pointerCount; i++) { pointerIndex[i] = ids.indexOf(event->getPointerId(i)); } nsecs_t eventTime; Position positions[pointerCount]; size_t historySize = event->getHistorySize(); for (size_t h = 0; h < historySize; h++) { eventTime = event->getHistoricalEventTime(h); for (size_t i = 0; i < pointerCount; i++) { uint32_t index = pointerIndex[i]; positions[index].x = event->getHistoricalX(i, h); positions[index].y = event->getHistoricalY(i, h); } addMovement(eventTime, ids, positions); } eventTime = event->getEventTime(); for (size_t i = 0; i < pointerCount; i++) { uint32_t index = pointerIndex[i]; positions[index].x = event->getX(i); positions[index].y = event->getY(i); } addMovement(eventTime, ids, positions); } bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const { Estimator estimator; if (getEstimator(id, &estimator) && estimator.degree >= 1) { *outVx = estimator.xCoeff[1]; *outVy = estimator.yCoeff[1]; return true; } *outVx = 0; *outVy = 0; return false; } bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const { return mStrategy->getEstimator(id, outEstimator); } // --- LeastSquaresVelocityTrackerStrategy --- const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON; const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE; LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy( uint32_t degree, Weighting weighting) : mDegree(degree), mWeighting(weighting) { clear(); } LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() { } void LeastSquaresVelocityTrackerStrategy::clear() { mIndex = 0; mMovements[0].ids.clear(); } void LeastSquaresVelocityTrackerStrategy::clearPointers(const IntSet &ids) { mMovements[mIndex].ids.remove(ids); } void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, const IntSet &ids, const VelocityTracker::Position* positions) { if (++mIndex == HISTORY_SIZE) { mIndex = 0; } Movement& movement = mMovements[mIndex]; movement.eventTime = eventTime; movement.ids = ids; size_t count = ids.count(); for (size_t i = 0; i < count; i++) { movement.positions[i] = positions[i]; } } /** * Solves a linear least squares problem to obtain a N degree polynomial that fits * the specified input data as nearly as possible. * * Returns true if a solution is found, false otherwise. * * The input consists of two vectors of data points X and Y with indices 0..m-1 * along with a weight vector W of the same size. * * The output is a vector B with indices 0..n that describes a polynomial * that fits the data, such the sum of W[i] * W[i] * abs(Y[i] - (B[0] + B[1] X[i] * + B[2] X[i]^2 ... B[n] X[i]^n)) for all i between 0 and m-1 is minimized. * * Accordingly, the weight vector W should be initialized by the caller with the * reciprocal square root of the variance of the error in each input data point. * In other words, an ideal choice for W would be W[i] = 1 / var(Y[i]) = 1 / stddev(Y[i]). * The weights express the relative importance of each data point. If the weights are * all 1, then the data points are considered to be of equal importance when fitting * the polynomial. It is a good idea to choose weights that diminish the importance * of data points that may have higher than usual error margins. * * Errors among data points are assumed to be independent. W is represented here * as a vector although in the literature it is typically taken to be a diagonal matrix. * * That is to say, the function that generated the input data can be approximated * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n. * * The coefficient of determination (R^2) is also returned to describe the goodness * of fit of the model for the given data. It is a value between 0 and 1, where 1 * indicates perfect correspondence. * * This function first expands the X vector to a m by n matrix A such that * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n, then * multiplies it by w[i]./ * * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q * and an m by n upper triangular matrix R. Because R is upper triangular (lower * part is all zeroes), we can simplify the decomposition into an m by n matrix * Q1 and a n by n matrix R1 such that A = Q1 R1. * * Finally we solve the system of linear equations given by R1 B = (Qtranspose W Y) * to find B. * * For efficiency, we lay out A and Q column-wise in memory because we frequently * operate on the column vectors. Conversely, we lay out R row-wise. * * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares * http://en.wikipedia.org/wiki/Gram-Schmidt */ static bool solveLeastSquares(const float* x, const float* y, const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) { #if DEBUG_STRATEGY ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n), vectorToString(x, m).string(), vectorToString(y, m).string(), vectorToString(w, m).string()); #endif // Expand the X vector to a matrix A, pre-multiplied by the weights. float a[n][m]; // column-major order for (uint32_t h = 0; h < m; h++) { a[0][h] = w[h]; for (uint32_t i = 1; i < n; i++) { a[i][h] = a[i - 1][h] * x[h]; } } #if DEBUG_STRATEGY ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string()); #endif // Apply the Gram-Schmidt process to A to obtain its QR decomposition. float q[n][m]; // orthonormal basis, column-major order float r[n][n]; // upper triangular matrix, row-major order for (uint32_t j = 0; j < n; j++) { for (uint32_t h = 0; h < m; h++) { q[j][h] = a[j][h]; } for (uint32_t i = 0; i < j; i++) { float dot = vectorDot(&q[j][0], &q[i][0], m); for (uint32_t h = 0; h < m; h++) { q[j][h] -= dot * q[i][h]; } } float norm = vectorNorm(&q[j][0], m); if (norm < 0.000001f) { // vectors are linearly dependent or zero so no solution #if DEBUG_STRATEGY ALOGD(" - no solution, norm=%f", norm); #endif return false; } float invNorm = 1.0f / norm; for (uint32_t h = 0; h < m; h++) { q[j][h] *= invNorm; } for (uint32_t i = 0; i < n; i++) { r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m); } } #if DEBUG_STRATEGY ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string()); ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string()); // calculate QR, if we factored A correctly then QR should equal A float qr[n][m]; for (uint32_t h = 0; h < m; h++) { for (uint32_t i = 0; i < n; i++) { qr[i][h] = 0; for (uint32_t j = 0; j < n; j++) { qr[i][h] += q[j][h] * r[j][i]; } } } ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string()); #endif // Solve R B = Qt W Y to find B. This is easy because R is upper triangular. // We just work from bottom-right to top-left calculating B's coefficients. float wy[m]; for (uint32_t h = 0; h < m; h++) { wy[h] = y[h] * w[h]; } for (uint32_t i = n; i-- != 0; ) { outB[i] = vectorDot(&q[i][0], wy, m); for (uint32_t j = n - 1; j > i; j--) { outB[i] -= r[i][j] * outB[j]; } outB[i] /= r[i][i]; } #if DEBUG_STRATEGY ALOGD(" - b=%s", vectorToString(outB, n).string()); #endif // Calculate the coefficient of determination as 1 - (SSerr / SStot) where // SSerr is the residual sum of squares (variance of the error), // and SStot is the total sum of squares (variance of the data) where each // has been weighted. float ymean = 0; for (uint32_t h = 0; h < m; h++) { ymean += y[h]; } ymean /= m; float sserr = 0; float sstot = 0; for (uint32_t h = 0; h < m; h++) { float err = y[h] - outB[0]; float term = 1; for (uint32_t i = 1; i < n; i++) { term *= x[h]; err -= term * outB[i]; } sserr += w[h] * w[h] * err * err; float var = y[h] - ymean; sstot += w[h] * w[h] * var * var; } *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1; #if DEBUG_STRATEGY ALOGD(" - sserr=%f", sserr); ALOGD(" - sstot=%f", sstot); ALOGD(" - det=%f", *outDet); #endif return true; } bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const { outEstimator->clear(); // Iterate over movement samples in reverse time order and collect samples. float x[HISTORY_SIZE]; float y[HISTORY_SIZE]; float w[HISTORY_SIZE]; float time[HISTORY_SIZE]; uint32_t m = 0; uint32_t index = mIndex; const Movement& newestMovement = mMovements[mIndex]; do { const Movement& movement = mMovements[index]; if (!movement.ids.contains(id)) { break; } nsecs_t age = newestMovement.eventTime - movement.eventTime; if (age > HORIZON) { break; } const VelocityTracker::Position& position = movement.getPosition(id); x[m] = position.x; y[m] = position.y; w[m] = chooseWeight(index); time[m] = -age * 0.000000001f; index = (index == 0 ? HISTORY_SIZE : index) - 1; } while (++m < HISTORY_SIZE); if (m == 0) { return false; // no data } // Calculate a least squares polynomial fit. uint32_t degree = mDegree; if (degree > m - 1) { degree = m - 1; } if (degree >= 1) { float xdet, ydet; uint32_t n = degree + 1; if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet) && solveLeastSquares(time, y, w, m, n, outEstimator->yCoeff, &ydet)) { outEstimator->time = newestMovement.eventTime; outEstimator->degree = degree; outEstimator->confidence = xdet * ydet; #if DEBUG_STRATEGY ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f", int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).string(), vectorToString(outEstimator->yCoeff, n).string(), outEstimator->confidence); #endif return true; } } // No velocity data available for this pointer, but we do have its current position. outEstimator->xCoeff[0] = x[0]; outEstimator->yCoeff[0] = y[0]; outEstimator->time = newestMovement.eventTime; outEstimator->degree = 0; outEstimator->confidence = 1; return true; } float LeastSquaresVelocityTrackerStrategy::chooseWeight(uint32_t index) const { switch (mWeighting) { case WEIGHTING_DELTA: { // Weight points based on how much time elapsed between them and the next // point so that points that "cover" a shorter time span are weighed less. // delta 0ms: 0.5 // delta 10ms: 1.0 if (index == mIndex) { return 1.0f; } uint32_t nextIndex = (index + 1) % HISTORY_SIZE; float deltaMillis = (mMovements[nextIndex].eventTime- mMovements[index].eventTime) * 0.000001f; if (deltaMillis < 0) { return 0.5f; } if (deltaMillis < 10) { return 0.5f + deltaMillis * 0.05; } return 1.0f; } case WEIGHTING_CENTRAL: { // Weight points based on their age, weighing very recent and very old points less. // age 0ms: 0.5 // age 10ms: 1.0 // age 50ms: 1.0 // age 60ms: 0.5 float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime) * 0.000001f; if (ageMillis < 0) { return 0.5f; } if (ageMillis < 10) { return 0.5f + ageMillis * 0.05; } if (ageMillis < 50) { return 1.0f; } if (ageMillis < 60) { return 0.5f + (60 - ageMillis) * 0.05; } return 0.5f; } case WEIGHTING_RECENT: { // Weight points based on their age, weighing older points less. // age 0ms: 1.0 // age 50ms: 1.0 // age 100ms: 0.5 float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime) * 0.000001f; if (ageMillis < 50) { return 1.0f; } if (ageMillis < 100) { return 0.5f + (100 - ageMillis) * 0.01f; } return 0.5f; } case WEIGHTING_NONE: default: return 1.0f; } } // --- IntegratingVelocityTrackerStrategy --- IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy(uint32_t degree) : mDegree(degree) { } IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() { } void IntegratingVelocityTrackerStrategy::clear() { mPointerIds.clear(); } void IntegratingVelocityTrackerStrategy::clearPointers(const IntSet &ids) { mPointerIds.remove(ids); } void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, const IntSet &ids, const VelocityTracker::Position* positions) { { auto pointerIdsIt = mPointerIds.begin(); uint32_t index = 0; for_each(ids.begin(), ids.end(), [&](int32_t id) { State& state = mPointerState[id]; const VelocityTracker::Position& position = positions[index++]; while (*pointerIdsIt < id && pointerIdsIt != mPointerIds.end()) pointerIdsIt++; if (pointerIdsIt != mPointerIds.end() && *pointerIdsIt == id) { updateState(state, eventTime, position.x, position.y); } else { initState(state, eventTime, position.x, position.y); } }); } mPointerIds = ids; } bool IntegratingVelocityTrackerStrategy::getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const { outEstimator->clear(); if (mPointerIds.contains(id)) { const State& state = mPointerState.at(id); populateEstimator(state, outEstimator); return true; } return false; } void IntegratingVelocityTrackerStrategy::initState(State& state, nsecs_t eventTime, float xpos, float ypos) const { state.updateTime = eventTime; state.degree = 0; state.xpos = xpos; state.xvel = 0; state.xaccel = 0; state.ypos = ypos; state.yvel = 0; state.yaccel = 0; } void IntegratingVelocityTrackerStrategy::updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const { const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS; const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds if (eventTime <= state.updateTime + MIN_TIME_DELTA) { return; } float dt = (eventTime - state.updateTime) * 0.000000001f; state.updateTime = eventTime; float xvel = (xpos - state.xpos) / dt; float yvel = (ypos - state.ypos) / dt; if (state.degree == 0) { state.xvel = xvel; state.yvel = yvel; state.degree = 1; } else { float alpha = dt / (FILTER_TIME_CONSTANT + dt); if (mDegree == 1) { state.xvel += (xvel - state.xvel) * alpha; state.yvel += (yvel - state.yvel) * alpha; } else { float xaccel = (xvel - state.xvel) / dt; float yaccel = (yvel - state.yvel) / dt; if (state.degree == 1) { state.xaccel = xaccel; state.yaccel = yaccel; state.degree = 2; } else { state.xaccel += (xaccel - state.xaccel) * alpha; state.yaccel += (yaccel - state.yaccel) * alpha; } state.xvel += (state.xaccel * dt) * alpha; state.yvel += (state.yaccel * dt) * alpha; } } state.xpos = xpos; state.ypos = ypos; } void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const { outEstimator->time = state.updateTime; outEstimator->confidence = 1.0f; outEstimator->degree = state.degree; outEstimator->xCoeff[0] = state.xpos; outEstimator->xCoeff[1] = state.xvel; outEstimator->xCoeff[2] = state.xaccel / 2; outEstimator->yCoeff[0] = state.ypos; outEstimator->yCoeff[1] = state.yvel; outEstimator->yCoeff[2] = state.yaccel / 2; } // --- LegacyVelocityTrackerStrategy --- const nsecs_t LegacyVelocityTrackerStrategy::HORIZON; const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE; const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION; LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() { clear(); } LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() { } void LegacyVelocityTrackerStrategy::clear() { mIndex = 0; mMovements[0].ids.clear(); } void LegacyVelocityTrackerStrategy::clearPointers(const IntSet &ids) { mMovements[mIndex].ids.remove(ids); } void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, const IntSet &ids, const VelocityTracker::Position* positions) { if (++mIndex == HISTORY_SIZE) { mIndex = 0; } Movement& movement = mMovements[mIndex]; movement.eventTime = eventTime; movement.ids = ids; memcpy(movement.positions, positions, sizeof(VelocityTracker::Position) * ids.count()); } bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const { outEstimator->clear(); const Movement& newestMovement = mMovements[mIndex]; if (!newestMovement.ids.contains(id)) { return false; // no data } // Find the oldest sample that contains the pointer and that is not older than HORIZON. nsecs_t minTime = newestMovement.eventTime - HORIZON; uint32_t oldestIndex = mIndex; uint32_t numTouches = 1; do { uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1; const Movement& nextOldestMovement = mMovements[nextOldestIndex]; if (!nextOldestMovement.ids.contains(id) || nextOldestMovement.eventTime < minTime) { break; } oldestIndex = nextOldestIndex; } while (++numTouches < HISTORY_SIZE); // Calculate an exponentially weighted moving average of the velocity estimate // at different points in time measured relative to the oldest sample. // This is essentially an IIR filter. Newer samples are weighted more heavily // than older samples. Samples at equal time points are weighted more or less // equally. // // One tricky problem is that the sample data may be poorly conditioned. // Sometimes samples arrive very close together in time which can cause us to // overestimate the velocity at that time point. Most samples might be measured // 16ms apart but some consecutive samples could be only 0.5sm apart because // the hardware or driver reports them irregularly or in bursts. float accumVx = 0; float accumVy = 0; uint32_t index = oldestIndex; uint32_t samplesUsed = 0; const Movement& oldestMovement = mMovements[oldestIndex]; const VelocityTracker::Position& oldestPosition = oldestMovement.getPosition(id); nsecs_t lastDuration = 0; while (numTouches-- > 1) { if (++index == HISTORY_SIZE) { index = 0; } const Movement& movement = mMovements[index]; nsecs_t duration = movement.eventTime - oldestMovement.eventTime; // If the duration between samples is small, we may significantly overestimate // the velocity. Consequently, we impose a minimum duration constraint on the // samples that we include in the calculation. if (duration >= MIN_DURATION) { const VelocityTracker::Position& position = movement.getPosition(id); float scale = 1000000000.0f / duration; // one over time delta in seconds float vx = (position.x - oldestPosition.x) * scale; float vy = (position.y - oldestPosition.y) * scale; accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration); accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration); lastDuration = duration; samplesUsed += 1; } } // Report velocity. const VelocityTracker::Position& newestPosition = newestMovement.getPosition(id); outEstimator->time = newestMovement.eventTime; outEstimator->confidence = 1; outEstimator->xCoeff[0] = newestPosition.x; outEstimator->yCoeff[0] = newestPosition.y; if (samplesUsed) { outEstimator->xCoeff[1] = accumVx; outEstimator->yCoeff[1] = accumVy; outEstimator->degree = 1; } else { outEstimator->degree = 0; } return true; } } // namespace android ././@LongLink0000000000000000000000000000015600000000000011217 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/PointerController.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/PointerContr0000644000015301777760000001652312322054223033434 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "PointerController" //#define LOG_NDEBUG 0 // Log debug messages about pointer updates #define DEBUG_POINTER_UPDATES 0 #include "PointerController.h" #include namespace android { // --- PointerController --- PointerController::PointerController() { AutoMutex _l(mLock); mLocked.displayWidth = -1; mLocked.displayHeight = -1; mLocked.displayOrientation = DISPLAY_ORIENTATION_0; mLocked.presentation = PRESENTATION_POINTER; mLocked.presentationChanged = false; mLocked.pointerX = 0; mLocked.pointerY = 0; mLocked.pointerAlpha = 0.0f; // pointer is initially faded mLocked.buttonState = 0; } PointerController::~PointerController() { AutoMutex _l(mLock); } bool PointerController::getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const { AutoMutex _l(mLock); return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY); } bool PointerController::getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const { if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) { return false; } *outMinX = 0; *outMinY = 0; switch (mLocked.displayOrientation) { case DISPLAY_ORIENTATION_90: case DISPLAY_ORIENTATION_270: *outMaxX = mLocked.displayHeight - 1; *outMaxY = mLocked.displayWidth - 1; break; default: *outMaxX = mLocked.displayWidth - 1; *outMaxY = mLocked.displayHeight - 1; break; } return true; } void PointerController::move(float deltaX, float deltaY) { #if DEBUG_POINTER_UPDATES ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY); #endif if (deltaX == 0.0f && deltaY == 0.0f) { return; } AutoMutex _l(mLock); setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY); } void PointerController::setButtonState(int32_t buttonState) { #if DEBUG_POINTER_UPDATES ALOGD("Set button state 0x%08x", buttonState); #endif AutoMutex _l(mLock); if (mLocked.buttonState != buttonState) { mLocked.buttonState = buttonState; } } int32_t PointerController::getButtonState() const { AutoMutex _l(mLock); return mLocked.buttonState; } void PointerController::setPosition(float x, float y) { #if DEBUG_POINTER_UPDATES ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y); #endif AutoMutex _l(mLock); setPositionLocked(x, y); } void PointerController::setPositionLocked(float x, float y) { float minX, minY, maxX, maxY; if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { if (x <= minX) { mLocked.pointerX = minX; } else if (x >= maxX) { mLocked.pointerX = maxX; } else { mLocked.pointerX = x; } if (y <= minY) { mLocked.pointerY = minY; } else if (y >= maxY) { mLocked.pointerY = maxY; } else { mLocked.pointerY = y; } updatePointerLocked(); } } void PointerController::getPosition(float* outX, float* outY) const { AutoMutex _l(mLock); *outX = mLocked.pointerX; *outY = mLocked.pointerY; } void PointerController::fade(Transition transition) { // TODO: Implement } void PointerController::unfade(Transition transition) { // TODO: Implement } void PointerController::setPresentation(Presentation presentation) { AutoMutex _l(mLock); if (mLocked.presentation != presentation) { mLocked.presentation = presentation; mLocked.presentationChanged = true; updatePointerLocked(); } } void PointerController::setSpots(const PointerCoords* spotCoords, uint32_t spotCount) { #if DEBUG_POINTER_UPDATES ALOGD("setSpots: spotCount=%d", spotCount); for (size_t i = 0; i < spotCount; ++i) { const PointerCoords& c = spotCoords[i]; ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", i, c.getAxisValue(AMOTION_EVENT_AXIS_X), c.getAxisValue(AMOTION_EVENT_AXIS_Y), c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); } #endif AutoMutex _l(mLock); //TODO: Implement } void PointerController::clearSpots() { #if DEBUG_POINTER_UPDATES ALOGD("clearSpots"); #endif AutoMutex _l(mLock); } void PointerController::setDisplaySize(int32_t width, int32_t height) { AutoMutex _l(mLock); if (mLocked.displayWidth != width || mLocked.displayHeight != height) { mLocked.displayWidth = width; mLocked.displayHeight = height; float minX, minY, maxX, maxY; if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { mLocked.pointerX = (minX + maxX) * 0.5f; mLocked.pointerY = (minY + maxY) * 0.5f; } else { mLocked.pointerX = 0; mLocked.pointerY = 0; } updatePointerLocked(); } } void PointerController::setDisplayOrientation(int32_t orientation) { AutoMutex _l(mLock); if (mLocked.displayOrientation != orientation) { // Apply offsets to convert from the pixel top-left corner position to the pixel center. // This creates an invariant frame of reference that we can easily rotate when // taking into account that the pointer may be located at fractional pixel offsets. float x = mLocked.pointerX + 0.5f; float y = mLocked.pointerY + 0.5f; float temp; // Undo the previous rotation. switch (mLocked.displayOrientation) { case DISPLAY_ORIENTATION_90: temp = x; x = mLocked.displayWidth - y; y = temp; break; case DISPLAY_ORIENTATION_180: x = mLocked.displayWidth - x; y = mLocked.displayHeight - y; break; case DISPLAY_ORIENTATION_270: temp = x; x = y; y = mLocked.displayHeight - temp; break; } // Perform the new rotation. switch (orientation) { case DISPLAY_ORIENTATION_90: temp = x; x = y; y = mLocked.displayWidth - temp; break; case DISPLAY_ORIENTATION_180: x = mLocked.displayWidth - x; y = mLocked.displayHeight - y; break; case DISPLAY_ORIENTATION_270: temp = x; x = mLocked.displayHeight - y; y = temp; break; } // Apply offsets to convert from the pixel center to the pixel top-left corner position // and save the results. mLocked.pointerX = x - 0.5f; mLocked.pointerY = y - 0.5f; mLocked.displayOrientation = orientation; updatePointerLocked(); } } void PointerController::updatePointerLocked() { // TODO: Implement } } // namespace android mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/Keyboard.cpp0000644000015301777760000002337712322054223033334 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "Keyboard" #include #include #include #include #include #include #include #include // #include // #include #include #include namespace android { // --- KeyMap --- KeyMap::KeyMap() { } KeyMap::~KeyMap() { } status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { String8 keyLayoutName; if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), keyLayoutName)) { status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " "it was not found.", c_str(deviceIdenfifier.name), c_str(keyLayoutName)); } } String8 keyCharacterMapName; if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), keyCharacterMapName)) { status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " "map '%s' but it was not found.", c_str(deviceIdenfifier.name), c_str(keyLayoutName)); } } if (isComplete()) { return OK; } } // Try searching by device identifier. if (probeKeyMap(deviceIdenfifier, emptyString8())) { return OK; } // Fall back on the Generic key map. // TODO Apply some additional heuristics here to figure out what kind of // generic key map to use (US English, etc.) for typical external keyboards. if (probeKeyMap(deviceIdenfifier, String8("Generic"))) { return OK; } // Try the Virtual key map as a last resort. if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) { return OK; } // Give up! ALOGE("Could not determine key map for device '%s' and no default key maps were found!", c_str(deviceIdenfifier.name)); return NAME_NOT_FOUND; } bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& keyMapName) { if (!haveKeyLayout()) { loadKeyLayout(deviceIdentifier, keyMapName); } if (!haveKeyCharacterMap()) { loadKeyCharacterMap(deviceIdentifier, keyMapName); } return isComplete(); } // status_t KeyMap::loadGenericMaps() { status_t status = 0; setTo(keyLayoutFile, "Generic.kl"); setTo(keyCharacterMapFile, "Generic.kcm"); status = KeyCharacterMap::loadContents( String8("Generic.kcm"), GenericKeyMap::keymap_contents(), KeyCharacterMap::FORMAT_BASE, &keyCharacterMap); if (status) return status; status = KeyLayoutMap::load( String8("Generic.kl"), GenericKeyMap::key_layout_contents(), &keyLayoutMap); return status; } // status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name) { String8 path(getPath(deviceIdentifier, name, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT)); if (isEmpty(path)) { return NAME_NOT_FOUND; } status_t status = KeyLayoutMap::load(path, &keyLayoutMap); if (status) { return status; } setTo(keyLayoutFile, path); return OK; } status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name) { String8 path(getPath(deviceIdentifier, name, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP)); if (isEmpty(path)) { return NAME_NOT_FOUND; } status_t status = KeyCharacterMap::load(path, KeyCharacterMap::FORMAT_BASE, &keyCharacterMap); if (status) { return status; } setTo(keyCharacterMapFile, path); return OK; } String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier, const String8& name, InputDeviceConfigurationFileType type) { return isEmpty(name) ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type) : getInputDeviceConfigurationFilePathByName(name, type); } // --- Global functions --- bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration, const KeyMap* keyMap) { if (!keyMap->haveKeyCharacterMap() || keyMap->keyCharacterMap->getKeyboardType() == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) { return false; } if (deviceConfiguration) { bool builtIn = false; if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn) && builtIn) { return true; } } return strstr(c_str(deviceIdentifier.name), "-keypad"); } static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) { while (list->literal) { if (strcmp(literal, list->literal) == 0) { return list->value; } list++; } return list->value; } static const char* lookupLabelByValue(int value, const KeycodeLabel *list) { while (list->literal) { if (list->value == value) { return list->literal; } list++; } return NULL; } int32_t getKeyCodeByLabel(const char* label) { return int32_t(lookupValueByLabel(label, KEYCODES)); } uint32_t getKeyFlagByLabel(const char* label) { return uint32_t(lookupValueByLabel(label, FLAGS)); } int32_t getAxisByLabel(const char* label) { return int32_t(lookupValueByLabel(label, AXES)); } const char* getAxisLabel(int32_t axisId) { return lookupLabelByValue(axisId, AXES); } static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) { int32_t newMetaState; if (down) { newMetaState = oldMetaState | mask; } else { newMetaState = oldMetaState & ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON); } if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { newMetaState |= AMETA_ALT_ON; } if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) { newMetaState |= AMETA_SHIFT_ON; } if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { newMetaState |= AMETA_CTRL_ON; } if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { newMetaState |= AMETA_META_ON; } return newMetaState; } static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) { if (down) { return oldMetaState; } else { return oldMetaState ^ mask; } } int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { int32_t mask; switch (keyCode) { case AKEYCODE_ALT_LEFT: return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState); case AKEYCODE_ALT_RIGHT: return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState); case AKEYCODE_SHIFT_LEFT: return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState); case AKEYCODE_SHIFT_RIGHT: return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState); case AKEYCODE_SYM: return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState); case AKEYCODE_FUNCTION: return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState); case AKEYCODE_CTRL_LEFT: return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState); case AKEYCODE_CTRL_RIGHT: return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState); case AKEYCODE_META_LEFT: return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState); case AKEYCODE_META_RIGHT: return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState); case AKEYCODE_CAPS_LOCK: return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState); case AKEYCODE_NUM_LOCK: return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState); case AKEYCODE_SCROLL_LOCK: return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState); default: return oldMetaState; } } bool isMetaKey(int32_t keyCode) { switch (keyCode) { case AKEYCODE_ALT_LEFT: case AKEYCODE_ALT_RIGHT: case AKEYCODE_SHIFT_LEFT: case AKEYCODE_SHIFT_RIGHT: case AKEYCODE_SYM: case AKEYCODE_FUNCTION: case AKEYCODE_CTRL_LEFT: case AKEYCODE_CTRL_RIGHT: case AKEYCODE_META_LEFT: case AKEYCODE_META_RIGHT: case AKEYCODE_CAPS_LOCK: case AKEYCODE_NUM_LOCK: case AKEYCODE_SCROLL_LOCK: return true; default: return false; } } } // namespace android ././@LongLink0000000000000000000000000000015200000000000011213 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/VirtualKeyMap.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/VirtualKeyMa0000644000015301777760000001240612322054223033357 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "VirtualKeyMap" #include #include #include #include #include #include #include // Enables debug output for the parser. #define DEBUG_PARSER 0 // Enables debug output for parser performance. #define DEBUG_PARSER_PERFORMANCE 0 namespace android { static const char* WHITESPACE = " \t\r"; static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:"; // --- VirtualKeyMap --- VirtualKeyMap::VirtualKeyMap() { } VirtualKeyMap::~VirtualKeyMap() { } status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) { *outMap = NULL; Tokenizer* tokenizer; status_t status = Tokenizer::open(filename, &tokenizer); if (status) { ALOGE("Error %d opening virtual key map file %s.", status, c_str(filename)); } else { VirtualKeyMap* map = new VirtualKeyMap(); if (!map) { ALOGE("Error allocating virtual key map."); status = NO_MEMORY; } else { #if DEBUG_PARSER_PERFORMANCE nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); #endif Parser parser(map, tokenizer); status = parser.parse(); #if DEBUG_PARSER_PERFORMANCE nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", c_str(tokenizer->getFilename()), tokenizer->getLineNumber(), elapsedTime / 1000000.0); #endif if (status) { delete map; } else { *outMap = map; } } delete tokenizer; } return status; } // --- VirtualKeyMap::Parser --- VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) : mMap(map), mTokenizer(tokenizer) { } VirtualKeyMap::Parser::~Parser() { } status_t VirtualKeyMap::Parser::parse() { while (!mTokenizer->isEof()) { #if DEBUG_PARSER ALOGD("Parsing %s: '%s'.", c_str(mTokenizer->getLocation()), c_str(mTokenizer->peekRemainderOfLine())); #endif mTokenizer->skipDelimiters(WHITESPACE); if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { // Multiple keys can appear on one line or they can be broken up across multiple lines. do { String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); if (token != "0x01") { ALOGE("%s: Unknown virtual key type, expected 0x01.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } VirtualKeyDefinition defn; bool success = parseNextIntField(&defn.scanCode) && parseNextIntField(&defn.centerX) && parseNextIntField(&defn.centerY) && parseNextIntField(&defn.width) && parseNextIntField(&defn.height); if (!success) { ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.", c_str(mTokenizer->getLocation())); return BAD_VALUE; } #if DEBUG_PARSER ALOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, " "width=%d, height=%d", defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height); #endif mMap->mVirtualKeys.push(defn); } while (consumeFieldDelimiterAndSkipWhitespace()); if (!mTokenizer->isEol()) { ALOGE("%s: Expected end of line, got '%s'.", c_str(mTokenizer->getLocation()), c_str(mTokenizer->peekRemainderOfLine())); return BAD_VALUE; } } mTokenizer->nextLine(); } return NO_ERROR; } bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() { mTokenizer->skipDelimiters(WHITESPACE); if (mTokenizer->peekChar() == ':') { mTokenizer->nextChar(); mTokenizer->skipDelimiters(WHITESPACE); return true; } return false; } bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) { if (!consumeFieldDelimiterAndSkipWhitespace()) { return false; } String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); char* end; *outValue = strtol(c_str(token), &end, 0); if (isEmpty(token) || *end != '\0') { ALOGE("Expected an integer, got '%s'.", c_str(token)); return false; } return true; } } // namespace android ././@LongLink0000000000000000000000000000015000000000000011211 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputListener.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputListene0000644000015301777760000001304412322054223033424 0ustar pbusernogroup00000000000000/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _UI_INPUT_LISTENER_H #define _UI_INPUT_LISTENER_H #include #include #include namespace android { class InputListenerInterface; /* Superclass of all input event argument objects */ struct NotifyArgs { virtual ~NotifyArgs() { } virtual void notify(const sp& listener) const = 0; }; /* Describes a configuration change event. */ struct NotifyConfigurationChangedArgs : public NotifyArgs { nsecs_t eventTime; inline NotifyConfigurationChangedArgs() : eventTime{0} { } NotifyConfigurationChangedArgs(nsecs_t eventTime); NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other); virtual ~NotifyConfigurationChangedArgs() { } virtual void notify(const sp& listener) const; }; /* Describes a key event. */ struct NotifyKeyArgs : public NotifyArgs { nsecs_t eventTime; int32_t deviceId; uint32_t source; uint32_t policyFlags; int32_t action; int32_t flags; int32_t keyCode; int32_t scanCode; int32_t metaState; nsecs_t downTime; inline NotifyKeyArgs() { } NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime); NotifyKeyArgs(const NotifyKeyArgs& other); virtual ~NotifyKeyArgs() { } virtual void notify(const sp& listener) const; }; /* Describes a motion event. */ struct NotifyMotionArgs : public NotifyArgs { nsecs_t eventTime; int32_t deviceId; uint32_t source; uint32_t policyFlags; int32_t action; int32_t flags; int32_t metaState; int32_t buttonState; int32_t edgeFlags; uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; float xPrecision; float yPrecision; nsecs_t downTime; inline NotifyMotionArgs() { } NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, float xPrecision, float yPrecision, nsecs_t downTime); NotifyMotionArgs(const NotifyMotionArgs& other); virtual ~NotifyMotionArgs() { } virtual void notify(const sp& listener) const; }; /* Describes a switch event. */ struct NotifySwitchArgs : public NotifyArgs { nsecs_t eventTime; uint32_t policyFlags; int32_t switchCode; int32_t switchValue; inline NotifySwitchArgs() { } NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags, int32_t switchCode, int32_t switchValue); NotifySwitchArgs(const NotifySwitchArgs& other); virtual ~NotifySwitchArgs() { } virtual void notify(const sp& listener) const; }; /* Describes a device reset event, such as when a device is added, * reconfigured, or removed. */ struct NotifyDeviceResetArgs : public NotifyArgs { nsecs_t eventTime; int32_t deviceId; inline NotifyDeviceResetArgs() { } NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId); NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other); virtual ~NotifyDeviceResetArgs() { } virtual void notify(const sp& listener) const; }; /* * The interface used by the InputReader to notify the InputListener about input events. */ class InputListenerInterface : public virtual RefBase { protected: InputListenerInterface() { } virtual ~InputListenerInterface() { } public: virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0; virtual void notifyKey(const NotifyKeyArgs* args) = 0; virtual void notifyMotion(const NotifyMotionArgs* args) = 0; virtual void notifySwitch(const NotifySwitchArgs* args) = 0; virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0; }; /* * An implementation of the listener interface that queues up and defers dispatch * of decoded events until flushed. */ class QueuedInputListener : public InputListenerInterface { protected: virtual ~QueuedInputListener(); public: QueuedInputListener(const sp& innerListener); virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); virtual void notifyKey(const NotifyKeyArgs* args); virtual void notifyMotion(const NotifyMotionArgs* args); virtual void notifySwitch(const NotifySwitchArgs* args); virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); void flush(); private: sp mInnerListener; Vector mArgsQueue; }; } // namespace android #endif // _UI_INPUT_LISTENER_H ././@LongLink0000000000000000000000000000015200000000000011213 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/GenericKeyMap.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/GenericKeyMa0000644000015301777760000012036012322054223033304 0ustar pbusernogroup00000000000000// Copyright (C) 2010 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include const char* android::GenericKeyMap::key_layout_contents() { static const char* result = "key 1 ESCAPE\n" \ "key 2 1\n" \ "key 3 2\n" \ "key 4 3\n" \ "key 5 4\n" \ "key 6 5\n" \ "key 7 6\n" \ "key 8 7\n" \ "key 9 8\n" \ "key 10 9\n" \ "key 11 0\n" \ "key 12 MINUS\n" \ "key 13 EQUALS\n" \ "key 14 DEL\n" \ "key 15 TAB\n" \ "key 16 Q\n" \ "key 17 W\n" \ "key 18 E\n" \ "key 19 R\n" \ "key 20 T\n" \ "key 21 Y\n" \ "key 22 U\n" \ "key 23 I\n" \ "key 24 O\n" \ "key 25 P\n" \ "key 26 LEFT_BRACKET\n" \ "key 27 RIGHT_BRACKET\n" \ "key 28 ENTER\n" \ "key 29 CTRL_LEFT\n" \ "key 30 A\n" \ "key 31 S\n" \ "key 32 D\n" \ "key 33 F\n" \ "key 34 G\n" \ "key 35 H\n" \ "key 36 J\n" \ "key 37 K\n" \ "key 38 L\n" \ "key 39 SEMICOLON\n" \ "key 40 APOSTROPHE\n" \ "key 41 GRAVE\n" \ "key 42 SHIFT_LEFT\n" \ "key 43 BACKSLASH\n" \ "key 44 Z\n" \ "key 45 X\n" \ "key 46 C\n" \ "key 47 V\n" \ "key 48 B\n" \ "key 49 N\n" \ "key 50 M\n" \ "key 51 COMMA\n" \ "key 52 PERIOD\n" \ "key 53 SLASH\n" \ "key 54 SHIFT_RIGHT\n" \ "key 55 NUMPAD_MULTIPLY\n" \ "key 56 ALT_LEFT\n" \ "key 57 SPACE\n" \ "key 58 CAPS_LOCK\n" \ "key 59 F1\n" \ "key 60 F2\n" \ "key 61 F3\n" \ "key 62 F4\n" \ "key 63 F5\n" \ "key 64 F6\n" \ "key 65 F7\n" \ "key 66 F8\n" \ "key 67 F9\n" \ "key 68 F10\n" \ "key 69 NUM_LOCK\n" \ "key 70 SCROLL_LOCK\n" \ "key 71 NUMPAD_7\n" \ "key 72 NUMPAD_8\n" \ "key 73 NUMPAD_9\n" \ "key 74 NUMPAD_SUBTRACT\n" \ "key 75 NUMPAD_4\n" \ "key 76 NUMPAD_5\n" \ "key 77 NUMPAD_6\n" \ "key 78 NUMPAD_ADD\n" \ "key 79 NUMPAD_1\n" \ "key 80 NUMPAD_2\n" \ "key 81 NUMPAD_3\n" \ "key 82 NUMPAD_0\n" \ "key 83 NUMPAD_DOT\n" \ "# key 84 (undefined)\n" \ "key 85 ZENKAKU_HANKAKU\n" \ "key 86 BACKSLASH\n" \ "key 87 F11\n" \ "key 88 F12\n" \ "key 89 RO\n" \ "# key 90 \"KEY_KATAKANA\"\n" \ "# key 91 \"KEY_HIRAGANA\"\n" \ "key 92 HENKAN\n" \ "key 93 KATAKANA_HIRAGANA\n" \ "key 94 MUHENKAN\n" \ "key 95 NUMPAD_COMMA\n" \ "key 96 NUMPAD_ENTER\n" \ "key 97 CTRL_RIGHT\n" \ "key 98 NUMPAD_DIVIDE\n" \ "key 99 SYSRQ\n" \ "key 100 ALT_RIGHT\n" \ "# key 101 \"KEY_LINEFEED\"\n" \ "key 102 MOVE_HOME\n" \ "key 103 DPAD_UP\n" \ "key 104 PAGE_UP\n" \ "key 105 DPAD_LEFT\n" \ "key 106 DPAD_RIGHT\n" \ "key 107 MOVE_END\n" \ "key 108 DPAD_DOWN\n" \ "key 109 PAGE_DOWN\n" \ "key 110 INSERT\n" \ "key 111 FORWARD_DEL\n" \ "# key 112 \"KEY_MACRO\"\n" \ "key 113 VOLUME_MUTE\n" \ "key 114 VOLUME_DOWN\n" \ "key 115 VOLUME_UP\n" \ "key 116 POWER WAKE\n" \ "key 117 NUMPAD_EQUALS\n" \ "# key 118 \"KEY_KPPLUSMINUS\"\n" \ "key 119 BREAK\n" \ "# key 120 (undefined)\n" \ "key 121 NUMPAD_COMMA\n" \ "key 122 KANA\n" \ "key 123 EISU\n" \ "key 124 YEN\n" \ "key 125 META_LEFT\n" \ "key 126 META_RIGHT\n" \ "key 127 MENU WAKE_DROPPED\n" \ "key 128 MEDIA_STOP\n" \ "# key 129 \"KEY_AGAIN\"\n" \ "# key 130 \"KEY_PROPS\"\n" \ "# key 131 \"KEY_UNDO\"\n" \ "# key 132 \"KEY_FRONT\"\n" \ "# key 133 \"KEY_COPY\"\n" \ "# key 134 \"KEY_OPEN\"\n" \ "# key 135 \"KEY_PASTE\"\n" \ "# key 136 \"KEY_FIND\"\n" \ "# key 137 \"KEY_CUT\"\n" \ "# key 138 \"KEY_HELP\"\n" \ "key 139 MENU WAKE_DROPPED\n" \ "key 140 CALCULATOR\n" \ "# key 141 \"KEY_SETUP\"\n" \ "key 142 POWER WAKE\n" \ "key 143 POWER WAKE\n" \ "# key 144 \"KEY_FILE\"\n" \ "# key 145 \"KEY_SENDFILE\"\n" \ "# key 146 \"KEY_DELETEFILE\"\n" \ "# key 147 \"KEY_XFER\"\n" \ "# key 148 \"KEY_PROG1\"\n" \ "# key 149 \"KEY_PROG2\"\n" \ "key 150 EXPLORER\n" \ "# key 151 \"KEY_MSDOS\"\n" \ "key 152 POWER WAKE\n" \ "# key 153 \"KEY_DIRECTION\"\n" \ "# key 154 \"KEY_CYCLEWINDOWS\"\n" \ "key 155 ENVELOPE\n" \ "key 156 BOOKMARK\n" \ "# key 157 \"KEY_COMPUTER\"\n" \ "key 158 BACK WAKE_DROPPED\n" \ "key 159 FORWARD\n" \ "key 160 MEDIA_CLOSE\n" \ "key 161 MEDIA_EJECT\n" \ "key 162 MEDIA_EJECT\n" \ "key 163 MEDIA_NEXT\n" \ "key 164 MEDIA_PLAY_PAUSE\n" \ "key 165 MEDIA_PREVIOUS\n" \ "key 166 MEDIA_STOP\n" \ "key 167 MEDIA_RECORD\n" \ "key 168 MEDIA_REWIND\n" \ "key 169 CALL\n" \ "# key 170 \"KEY_ISO\"\n" \ "key 171 MUSIC\n" \ "key 172 HOME\n" \ "# key 173 \"KEY_REFRESH\"\n" \ "# key 174 \"KEY_EXIT\"\n" \ "# key 175 \"KEY_MOVE\"\n" \ "# key 176 \"KEY_EDIT\"\n" \ "key 177 PAGE_UP\n" \ "key 178 PAGE_DOWN\n" \ "key 179 NUMPAD_LEFT_PAREN\n" \ "key 180 NUMPAD_RIGHT_PAREN\n" \ "# key 181 \"KEY_NEW\"\n" \ "# key 182 \"KEY_REDO\"\n" \ "# key 183 F13\n" \ "# key 184 F14\n" \ "# key 185 F15\n" \ "# key 186 F16\n" \ "# key 187 F17\n" \ "# key 188 F18\n" \ "# key 189 F19\n" \ "# key 190 F20\n" \ "# key 191 F21\n" \ "# key 192 F22\n" \ "# key 193 F23\n" \ "# key 194 F24\n" \ "# key 195 (undefined)\n" \ "# key 196 (undefined)\n" \ "# key 197 (undefined)\n" \ "# key 198 (undefined)\n" \ "# key 199 (undefined)\n" \ "key 200 MEDIA_PLAY\n" \ "key 201 MEDIA_PAUSE\n" \ "# key 202 \"KEY_PROG3\"\n" \ "# key 203 \"KEY_PROG4\"\n" \ "# key 204 (undefined)\n" \ "# key 205 \"KEY_SUSPEND\"\n" \ "# key 206 \"KEY_CLOSE\"\n" \ "key 207 MEDIA_PLAY\n" \ "key 208 MEDIA_FAST_FORWARD\n" \ "# key 209 \"KEY_BASSBOOST\"\n" \ "# key 210 \"KEY_PRINT\"\n" \ "# key 211 \"KEY_HP\"\n" \ "key 212 CAMERA\n" \ "key 213 MUSIC\n" \ "# key 214 \"KEY_QUESTION\"\n" \ "key 215 ENVELOPE\n" \ "# key 216 \"KEY_CHAT\"\n" \ "key 217 SEARCH\n" \ "# key 218 \"KEY_CONNECT\"\n" \ "# key 219 \"KEY_FINANCE\"\n" \ "# key 220 \"KEY_SPORT\"\n" \ "# key 221 \"KEY_SHOP\"\n" \ "# key 222 \"KEY_ALTERASE\"\n" \ "# key 223 \"KEY_CANCEL\"\n" \ "# key 224 \"KEY_BRIGHTNESSDOWN\"\n" \ "# key 225 \"KEY_BRIGHTNESSUP\"\n" \ "key 226 HEADSETHOOK\n" \ "\n" \ "key 256 BUTTON_1\n" \ "key 257 BUTTON_2\n" \ "key 258 BUTTON_3\n" \ "key 259 BUTTON_4\n" \ "key 260 BUTTON_5\n" \ "key 261 BUTTON_6\n" \ "key 262 BUTTON_7\n" \ "key 263 BUTTON_8\n" \ "key 264 BUTTON_9\n" \ "key 265 BUTTON_10\n" \ "key 266 BUTTON_11\n" \ "key 267 BUTTON_12\n" \ "key 268 BUTTON_13\n" \ "key 269 BUTTON_14\n" \ "key 270 BUTTON_15\n" \ "key 271 BUTTON_16\n" \ "\n" \ "key 288 BUTTON_1\n" \ "key 289 BUTTON_2\n" \ "key 290 BUTTON_3\n" \ "key 291 BUTTON_4\n" \ "key 292 BUTTON_5\n" \ "key 293 BUTTON_6\n" \ "key 294 BUTTON_7\n" \ "key 295 BUTTON_8\n" \ "key 296 BUTTON_9\n" \ "key 297 BUTTON_10\n" \ "key 298 BUTTON_11\n" \ "key 299 BUTTON_12\n" \ "key 300 BUTTON_13\n" \ "key 301 BUTTON_14\n" \ "key 302 BUTTON_15\n" \ "key 303 BUTTON_16\n" \ "\n" \ "\n" \ "key 304 BUTTON_A\n" \ "key 305 BUTTON_B\n" \ "key 306 BUTTON_C\n" \ "key 307 BUTTON_X\n" \ "key 308 BUTTON_Y\n" \ "key 309 BUTTON_Z\n" \ "key 310 BUTTON_L1\n" \ "key 311 BUTTON_R1\n" \ "key 312 BUTTON_L2\n" \ "key 313 BUTTON_R2\n" \ "key 314 BUTTON_SELECT\n" \ "key 315 BUTTON_START\n" \ "key 316 BUTTON_MODE\n" \ "key 317 BUTTON_THUMBL\n" \ "key 318 BUTTON_THUMBR\n" \ "\n" \ "\n" \ "# key 352 \"KEY_OK\"\n" \ "key 353 DPAD_CENTER\n" \ "# key 354 \"KEY_GOTO\"\n" \ "# key 355 \"KEY_CLEAR\"\n" \ "# key 356 \"KEY_POWER2\"\n" \ "# key 357 \"KEY_OPTION\"\n" \ "# key 358 \"KEY_INFO\"\n" \ "# key 359 \"KEY_TIME\"\n" \ "# key 360 \"KEY_VENDOR\"\n" \ "# key 361 \"KEY_ARCHIVE\"\n" \ "key 362 GUIDE\n" \ "# key 363 \"KEY_CHANNEL\"\n" \ "# key 364 \"KEY_FAVORITES\"\n" \ "# key 365 \"KEY_EPG\"\n" \ "key 366 DVR\n" \ "# key 367 \"KEY_MHP\"\n" \ "# key 368 \"KEY_LANGUAGE\"\n" \ "# key 369 \"KEY_TITLE\"\n" \ "# key 370 \"KEY_SUBTITLE\"\n" \ "# key 371 \"KEY_ANGLE\"\n" \ "# key 372 \"KEY_ZOOM\"\n" \ "# key 373 \"KEY_MODE\"\n" \ "# key 374 \"KEY_KEYBOARD\"\n" \ "# key 375 \"KEY_SCREEN\"\n" \ "# key 376 \"KEY_PC\"\n" \ "key 377 TV\n" \ "# key 378 \"KEY_TV2\"\n" \ "# key 379 \"KEY_VCR\"\n" \ "# key 380 \"KEY_VCR2\"\n" \ "# key 381 \"KEY_SAT\"\n" \ "# key 382 \"KEY_SAT2\"\n" \ "# key 383 \"KEY_CD\"\n" \ "# key 384 \"KEY_TAPE\"\n" \ "# key 385 \"KEY_RADIO\"\n" \ "# key 386 \"KEY_TUNER\"\n" \ "# key 387 \"KEY_PLAYER\"\n" \ "# key 388 \"KEY_TEXT\"\n" \ "# key 389 \"KEY_DVD\"\n" \ "# key 390 \"KEY_AUX\"\n" \ "# key 391 \"KEY_MP3\"\n" \ "# key 392 \"KEY_AUDIO\"\n" \ "# key 393 \"KEY_VIDEO\"\n" \ "# key 394 \"KEY_DIRECTORY\"\n" \ "# key 395 \"KEY_LIST\"\n" \ "# key 396 \"KEY_MEMO\"\n" \ "key 397 CALENDAR\n" \ "# key 398 \"KEY_RED\"\n" \ "# key 399 \"KEY_GREEN\"\n" \ "# key 400 \"KEY_YELLOW\"\n" \ "# key 401 \"KEY_BLUE\"\n" \ "key 402 CHANNEL_UP\n" \ "key 403 CHANNEL_DOWN\n" \ "# key 404 \"KEY_FIRST\"\n" \ "# key 405 \"KEY_LAST\"\n" \ "# key 406 \"KEY_AB\"\n" \ "# key 407 \"KEY_NEXT\"\n" \ "# key 408 \"KEY_RESTART\"\n" \ "# key 409 \"KEY_SLOW\"\n" \ "# key 410 \"KEY_SHUFFLE\"\n" \ "# key 411 \"KEY_BREAK\"\n" \ "# key 412 \"KEY_PREVIOUS\"\n" \ "# key 413 \"KEY_DIGITS\"\n" \ "# key 414 \"KEY_TEEN\"\n" \ "# key 415 \"KEY_TWEN\"\n" \ "key 429 CONTACTS\n" \ "\n" \ "# key 448 \"KEY_DEL_EOL\"\n" \ "# key 449 \"KEY_DEL_EOS\"\n" \ "# key 450 \"KEY_INS_LINE\"\n" \ "# key 451 \"KEY_DEL_LINE\"\n" \ "\n" \ "\n" \ "key 464 FUNCTION\n" \ "key 465 ESCAPE FUNCTION\n" \ "key 466 F1 FUNCTION\n" \ "key 467 F2 FUNCTION\n" \ "key 468 F3 FUNCTION\n" \ "key 469 F4 FUNCTION\n" \ "key 470 F5 FUNCTION\n" \ "key 471 F6 FUNCTION\n" \ "key 472 F7 FUNCTION\n" \ "key 473 F8 FUNCTION\n" \ "key 474 F9 FUNCTION\n" \ "key 475 F10 FUNCTION\n" \ "key 476 F11 FUNCTION\n" \ "key 477 F12 FUNCTION\n" \ "key 478 1 FUNCTION\n" \ "key 479 2 FUNCTION\n" \ "key 480 D FUNCTION\n" \ "key 481 E FUNCTION\n" \ "key 482 F FUNCTION\n" \ "key 483 S FUNCTION\n" \ "key 484 B FUNCTION\n" \ "\n" \ "\n" \ "# key 497 KEY_BRL_DOT1\n" \ "# key 498 KEY_BRL_DOT2\n" \ "# key 499 KEY_BRL_DOT3\n" \ "# key 500 KEY_BRL_DOT4\n" \ "# key 501 KEY_BRL_DOT5\n" \ "# key 502 KEY_BRL_DOT6\n" \ "# key 503 KEY_BRL_DOT7\n" \ "# key 504 KEY_BRL_DOT8\n" \ "\n" \ "\n" \ "# Joystick and game controller axes.\n" \ "# Axes that are not mapped will be assigned generic axis numbers by the input subsystem.\n" \ "axis 0x00 X\n" \ "axis 0x01 Y\n" \ "axis 0x02 Z\n" \ "axis 0x03 RX\n" \ "axis 0x04 RY\n" \ "axis 0x05 RZ\n" \ "axis 0x06 THROTTLE\n" \ "axis 0x07 RUDDER\n" \ "axis 0x08 WHEEL\n" \ "axis 0x09 GAS\n" \ "axis 0x0a BRAKE\n" \ "axis 0x10 HAT_X\n" \ "axis 0x11 HAT_Y\n"; return result; } const char* android::GenericKeyMap::keymap_contents() { static const char* result = "type FULL\n" \ "\n" \ "### Basic QWERTY keys ###\n" \ "\n" \ "key A {\n" \ " label: 'A'\n" \ " base: 'a'\n" \ " shift, capslock: 'A'\n" \ "}\n" \ "\n" \ "key B {\n" \ " label: 'B'\n" \ " base: 'b'\n" \ " shift, capslock: 'B'\n" \ "}\n" \ "\n" \ "key C {\n" \ " label: 'C'\n" \ " base: 'c'\n" \ " shift, capslock: 'C'\n" \ " alt: '\\u00e7'\n" \ " shift+alt: '\\u00c7'\n" \ "}\n" \ "\n" \ "key D {\n" \ " label: 'D'\n" \ " base: 'd'\n" \ " shift, capslock: 'D'\n" \ "}\n" \ "\n" \ "key E {\n" \ " label: 'E'\n" \ " base: 'e'\n" \ " shift, capslock: 'E'\n" \ " alt: '\\u0301'\n" \ "}\n" \ "\n" \ "key F {\n" \ " label: 'F'\n" \ " base: 'f'\n" \ " shift, capslock: 'F'\n" \ "}\n" \ "\n" \ "key G {\n" \ " label: 'G'\n" \ " base: 'g'\n" \ " shift, capslock: 'G'\n" \ "}\n" \ "\n" \ "key H {\n" \ " label: 'H'\n" \ " base: 'h'\n" \ " shift, capslock: 'H'\n" \ "}\n" \ "\n" \ "key I {\n" \ " label: 'I'\n" \ " base: 'i'\n" \ " shift, capslock: 'I'\n" \ " alt: '\\u0302'\n" \ "}\n" \ "\n" \ "key J {\n" \ " label: 'J'\n" \ " base: 'j'\n" \ " shift, capslock: 'J'\n" \ "}\n" \ "\n" \ "key K {\n" \ " label: 'K'\n" \ " base: 'k'\n" \ " shift, capslock: 'K'\n" \ "}\n" \ "\n" \ "key L {\n" \ " label: 'L'\n" \ " base: 'l'\n" \ " shift, capslock: 'L'\n" \ "}\n" \ "\n" \ "key M {\n" \ " label: 'M'\n" \ " base: 'm'\n" \ " shift, capslock: 'M'\n" \ "}\n" \ "\n" \ "key N {\n" \ " label: 'N'\n" \ " base: 'n'\n" \ " shift, capslock: 'N'\n" \ " alt: '\\u0303'\n" \ "}\n" \ "\n" \ "key O {\n" \ " label: 'O'\n" \ " base: 'o'\n" \ " shift, capslock: 'O'\n" \ "}\n" \ "\n" \ "key P {\n" \ " label: 'P'\n" \ " base: 'p'\n" \ " shift, capslock: 'P'\n" \ "}\n" \ "\n" \ "key Q {\n" \ " label: 'Q'\n" \ " base: 'q'\n" \ " shift, capslock: 'Q'\n" \ "}\n" \ "\n" \ "key R {\n" \ " label: 'R'\n" \ " base: 'r'\n" \ " shift, capslock: 'R'\n" \ "}\n" \ "\n" \ "key S {\n" \ " label: 'S'\n" \ " base: 's'\n" \ " shift, capslock: 'S'\n" \ " alt: '\\u00df'\n" \ "}\n" \ "\n" \ "key T {\n" \ " label: 'T'\n" \ " base: 't'\n" \ " shift, capslock: 'T'\n" \ "}\n" \ "\n" \ "key U {\n" \ " label: 'U'\n" \ " base: 'u'\n" \ " shift, capslock: 'U'\n" \ " alt: '\\u0308'\n" \ "}\n" \ "\n" \ "key V {\n" \ " label: 'V'\n" \ " base: 'v'\n" \ " shift, capslock: 'V'\n" \ "}\n" \ "\n" \ "key W {\n" \ " label: 'W'\n" \ " base: 'w'\n" \ " shift, capslock: 'W'\n" \ "}\n" \ "\n" \ "key X {\n" \ " label: 'X'\n" \ " base: 'x'\n" \ " shift, capslock: 'X'\n" \ "}\n" \ "\n" \ "key Y {\n" \ " label: 'Y'\n" \ " base: 'y'\n" \ " shift, capslock: 'Y'\n" \ "}\n" \ "\n" \ "key Z {\n" \ " label: 'Z'\n" \ " base: 'z'\n" \ " shift, capslock: 'Z'\n" \ "}\n" \ "\n" \ "key 0 {\n" \ " label: '0'\n" \ " base: '0'\n" \ " shift: ')'\n" \ "}\n" \ "\n" \ "key 1 {\n" \ " label: '1'\n" \ " base: '1'\n" \ " shift: '!'\n" \ "}\n" \ "\n" \ "key 2 {\n" \ " label: '2'\n" \ " base: '2'\n" \ " shift: '@'\n" \ "}\n" \ "\n" \ "key 3 {\n" \ " label: '3'\n" \ " base: '3'\n" \ " shift: '#'\n" \ "}\n" \ "\n" \ "key 4 {\n" \ " label: '4'\n" \ " base: '4'\n" \ " shift: '$'\n" \ "}\n" \ "\n" \ "key 5 {\n" \ " label: '5'\n" \ " base: '5'\n" \ " shift: '%'\n" \ "}\n" \ "\n" \ "key 6 {\n" \ " label: '6'\n" \ " base: '6'\n" \ " shift: '^'\n" \ " alt+shift: '\\u0302'\n" \ "}\n" \ "\n" \ "key 7 {\n" \ " label: '7'\n" \ " base: '7'\n" \ " shift: '&'\n" \ "}\n" \ "\n" \ "key 8 {\n" \ " label: '8'\n" \ " base: '8'\n" \ " shift: '*'\n" \ "}\n" \ "\n" \ "key 9 {\n" \ " label: '9'\n" \ " base: '9'\n" \ " shift: '('\n" \ "}\n" \ "\n" \ "key SPACE {\n" \ " label: ' '\n" \ " base: ' '\n" \ " alt, meta: fallback SEARCH\n" \ " ctrl: fallback LANGUAGE_SWITCH\n" \ "}\n" \ "\n" \ "key ENTER {\n" \ " label: '\\n'\n" \ " base: '\\n'\n" \ "}\n" \ "\n" \ "key TAB {\n" \ " label: '\\t'\n" \ " base: '\\t'\n" \ "}\n" \ "\n" \ "key COMMA {\n" \ " label: ','\n" \ " base: ','\n" \ " shift: '<'\n" \ "}\n" \ "\n" \ "key PERIOD {\n" \ " label: '.'\n" \ " base: '.'\n" \ " shift: '>'\n" \ "}\n" \ "\n" \ "key SLASH {\n" \ " label: '/'\n" \ " base: '/'\n" \ " shift: '?'\n" \ "}\n" \ "\n" \ "key GRAVE {\n" \ " label: '`'\n" \ " base: '`'\n" \ " shift: '~'\n" \ " alt: '\\u0300'\n" \ " alt+shift: '\\u0303'\n" \ "}\n" \ "\n" \ "key MINUS {\n" \ " label: '-'\n" \ " base: '-'\n" \ " shift: '_'\n" \ "}\n" \ "\n" \ "key EQUALS {\n" \ " label: '='\n" \ " base: '='\n" \ " shift: '+'\n" \ "}\n" \ "\n" \ "key LEFT_BRACKET {\n" \ " label: '['\n" \ " base: '['\n" \ " shift: '{'\n" \ "}\n" \ "\n" \ "key RIGHT_BRACKET {\n" \ " label: ']'\n" \ " base: ']'\n" \ " shift: '}'\n" \ "}\n" \ "\n" \ "key BACKSLASH {\n" \ " label: '\\\\'\n" \ " base: '\\\\'\n" \ " shift: '|'\n" \ "}\n" \ "\n" \ "key SEMICOLON {\n" \ " label: ';'\n" \ " base: ';'\n" \ " shift: ':'\n" \ "}\n" \ "\n" \ "key APOSTROPHE {\n" \ " label: '\\''\n" \ " base: '\\''\n" \ " shift: '\"'\n" \ "}\n" \ "\n" \ "### Numeric keypad ###\n" \ "\n" \ "key NUMPAD_0 {\n" \ " label: '0'\n" \ " base: fallback INSERT\n" \ " numlock: '0'\n" \ "}\n" \ "\n" \ "key NUMPAD_1 {\n" \ " label: '1'\n" \ " base: fallback MOVE_END\n" \ " numlock: '1'\n" \ "}\n" \ "\n" \ "key NUMPAD_2 {\n" \ " label: '2'\n" \ " base: fallback DPAD_DOWN\n" \ " numlock: '2'\n" \ "}\n" \ "\n" \ "key NUMPAD_3 {\n" \ " label: '3'\n" \ " base: fallback PAGE_DOWN\n" \ " numlock: '3'\n" \ "}\n" \ "\n" \ "key NUMPAD_4 {\n" \ " label: '4'\n" \ " base: fallback DPAD_LEFT\n" \ " numlock: '4'\n" \ "}\n" \ "\n" \ "key NUMPAD_5 {\n" \ " label: '5'\n" \ " base: fallback DPAD_CENTER\n" \ " numlock: '5'\n" \ "}\n" \ "\n" \ "key NUMPAD_6 {\n" \ " label: '6'\n" \ " base: fallback DPAD_RIGHT\n" \ " numlock: '6'\n" \ "}\n" \ "\n" \ "key NUMPAD_7 {\n" \ " label: '7'\n" \ " base: fallback MOVE_HOME\n" \ " numlock: '7'\n" \ "}\n" \ "\n" \ "key NUMPAD_8 {\n" \ " label: '8'\n" \ " base: fallback DPAD_UP\n" \ " numlock: '8'\n" \ "}\n" \ "\n" \ "key NUMPAD_9 {\n" \ " label: '9'\n" \ " base: fallback PAGE_UP\n" \ " numlock: '9'\n" \ "}\n" \ "\n" \ "key NUMPAD_LEFT_PAREN {\n" \ " label: '('\n" \ " base: '('\n" \ "}\n" \ "\n" \ "key NUMPAD_RIGHT_PAREN {\n" \ " label: ')'\n" \ " base: ')'\n" \ "}\n" \ "\n" \ "key NUMPAD_DIVIDE {\n" \ " label: '/'\n" \ " base: '/'\n" \ "}\n" \ "\n" \ "key NUMPAD_MULTIPLY {\n" \ " label: '*'\n" \ " base: '*'\n" \ "}\n" \ "\n" \ "key NUMPAD_SUBTRACT {\n" \ " label: '-'\n" \ " base: '-'\n" \ "}\n" \ "\n" \ "key NUMPAD_ADD {\n" \ " label: '+'\n" \ " base: '+'\n" \ "}\n" \ "\n" \ "key NUMPAD_DOT {\n" \ " label: '.'\n" \ " base: fallback FORWARD_DEL\n" \ " numlock: '.'\n" \ "}\n" \ "\n" \ "key NUMPAD_COMMA {\n" \ " label: ','\n" \ " base: ','\n" \ "}\n" \ "\n" \ "key NUMPAD_EQUALS {\n" \ " label: '='\n" \ " base: '='\n" \ "}\n" \ "\n" \ "key NUMPAD_ENTER {\n" \ " label: '\\n'\n" \ " base: '\\n' fallback ENTER\n" \ " ctrl, alt, meta: none fallback ENTER\n" \ "}\n" \ "\n" \ "### Special keys on phones ###\n" \ "\n" \ "key AT {\n" \ " label: '@'\n" \ " base: '@'\n" \ "}\n" \ "\n" \ "key STAR {\n" \ " label: '*'\n" \ " base: '*'\n" \ "}\n" \ "\n" \ "key POUND {\n" \ " label: '#'\n" \ " base: '#'\n" \ "}\n" \ "\n" \ "key PLUS {\n" \ " label: '+'\n" \ " base: '+'\n" \ "}\n" \ "\n" \ "### Non-printing keys ###\n" \ "\n" \ "key ESCAPE {\n" \ " base: fallback BACK\n" \ " alt, meta: fallback HOME\n" \ " ctrl: fallback MENU\n" \ "}\n" \ "\n" \ "### Gamepad buttons ###\n" \ "\n" \ "key BUTTON_A {\n" \ " base: fallback BACK\n" \ "}\n" \ "\n" \ "key BUTTON_B {\n" \ " base: fallback BACK\n" \ "}\n" \ "\n" \ "key BUTTON_C {\n" \ " base: fallback BACK\n" \ "}\n" \ "\n" \ "key BUTTON_X {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_Y {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_Z {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_L1 {\n" \ " base: none\n" \ "}\n" \ "\n" \ "key BUTTON_R1 {\n" \ " base: none\n" \ "}\n" \ "\n" \ "key BUTTON_L2 {\n" \ " base: none\n" \ "}\n" \ "\n" \ "key BUTTON_R2 {\n" \ " base: none\n" \ "}\n" \ "\n" \ "key BUTTON_THUMBL {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_THUMBR {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_START {\n" \ " base: fallback HOME\n" \ "}\n" \ "\n" \ "key BUTTON_SELECT {\n" \ " base: fallback MENU\n" \ "}\n" \ "\n" \ "key BUTTON_MODE {\n" \ " base: fallback MENU\n" \ "}\n" \ "\n" \ "key BUTTON_1 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_2 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_3 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_4 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_5 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_6 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_7 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_8 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_9 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_10 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_11 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_12 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_13 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_14 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_15 {\n" \ " base: fallback DPAD_CENTER\n" \ "}\n" \ "\n" \ "key BUTTON_16 {\n" \ " base: fallback DPAD_CENTER\n" \ "}"; return result; } ././@LongLink0000000000000000000000000000015200000000000011213 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputEnumerator.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputEnumera0000644000015301777760000000222212322054223033411 0ustar pbusernogroup00000000000000/* * Copyright (C) 2013 Canonical LTD * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Author: Robert Carr */ // TODO: ~racarr. What license should this file be under? #ifndef _UI_INPUT_ENUMERATOR_H #define _UI_INPUT_ENUMERATOR_H #include #include namespace android { class InputWindowHandle; class InputEnumerator : public RefBase { public: virtual void for_each(std::function const&)> const& callback) = 0; protected: InputEnumerator() = default; virtual ~InputEnumerator() = default; }; } // namespace android #endif // _UI_INPUT_ENUMERATOR_H ././@LongLink0000000000000000000000000000015400000000000011215 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/PointerController.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/PointerContr0000644000015301777760000001246412322054223033434 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _UI_POINTER_CONTROLLER_H #define _UI_POINTER_CONTROLLER_H #include #include #include #include namespace android { enum { DISPLAY_ORIENTATION_0 = 0, DISPLAY_ORIENTATION_90 = 1, DISPLAY_ORIENTATION_180 = 2, DISPLAY_ORIENTATION_270 = 3 }; /** * Interface for tracking a mouse / touch pad pointer and touch pad spots. * * The spots are sprites on screen that visually represent the positions of * fingers * * The pointer controller is responsible for providing synchronization and for tracking * display orientation changes if needed. */ class PointerControllerInterface : public virtual RefBase { protected: PointerControllerInterface() { } virtual ~PointerControllerInterface() { } public: /* Gets the bounds of the region that the pointer can traverse. * Returns true if the bounds are available. */ virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const = 0; /* Move the pointer. */ virtual void move(float deltaX, float deltaY) = 0; /* Sets a mask that indicates which buttons are pressed. */ virtual void setButtonState(int32_t buttonState) = 0; /* Gets a mask that indicates which buttons are pressed. */ virtual int32_t getButtonState() const = 0; /* Sets the absolute location of the pointer. */ virtual void setPosition(float x, float y) = 0; /* Gets the absolute location of the pointer. */ virtual void getPosition(float* outX, float* outY) const = 0; enum Transition { // Fade/unfade immediately. TRANSITION_IMMEDIATE, // Fade/unfade gradually. TRANSITION_GRADUAL }; /* Fades the pointer out now. */ virtual void fade(Transition transition) = 0; /* Makes the pointer visible if it has faded out. * The pointer never unfades itself automatically. This method must be called * by the client whenever the pointer is moved or a button is pressed and it * wants to ensure that the pointer becomes visible again. */ virtual void unfade(Transition transition) = 0; enum Presentation { // Show the mouse pointer. PRESENTATION_POINTER, // Show spots and a spot anchor in place of the mouse pointer. PRESENTATION_SPOT }; /* Sets the mode of the pointer controller. */ virtual void setPresentation(Presentation presentation) = 0; /* Sets the spots for the current gesture. * The spots are not subject to the inactivity timeout like the pointer * itself it since they are expected to remain visible for so long as * the fingers are on the touch pad. * * The values of the AMOTION_EVENT_AXIS_PRESSURE axis is significant. * For spotCoords, pressure != 0 indicates that the spot's location is being * pressed (not hovering). */ virtual void setSpots(const PointerCoords* spotCoords, uint32_t spotCount) = 0; /* Removes all spots. */ virtual void clearSpots() = 0; }; /* * Tracks pointer movements and draws the pointer sprite to a surface. * * Handles pointer acceleration and animation. */ class PointerController : public PointerControllerInterface/*, public MessageHandler*/ { protected: virtual ~PointerController(); public: enum InactivityTimeout { INACTIVITY_TIMEOUT_NORMAL = 0, INACTIVITY_TIMEOUT_SHORT = 1 }; PointerController(); virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; virtual void move(float deltaX, float deltaY); virtual void setButtonState(int32_t buttonState); virtual int32_t getButtonState() const; virtual void setPosition(float x, float y); virtual void getPosition(float* outX, float* outY) const; virtual void fade(Transition transition); virtual void unfade(Transition transition); virtual void setPresentation(Presentation presentation); virtual void setSpots(const PointerCoords* spotCoords, uint32_t spotCount); virtual void clearSpots(); void setDisplaySize(int32_t width, int32_t height); void setDisplayOrientation(int32_t orientation); private: mutable Mutex mLock; struct Locked { int32_t displayWidth; int32_t displayHeight; int32_t displayOrientation; Presentation presentation; bool presentationChanged; float pointerX; float pointerY; float pointerAlpha; int32_t buttonState; } mLocked; bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; void setPositionLocked(float x, float y); void updatePointerLocked(); }; } // namespace android #endif // _UI_POINTER_CONTROLLER_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/EventHub.cpp0000644000015301777760000015201012322054247033305 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "EventHub" // #define LOG_NDEBUG 0 #include "EventHub.h" #define acquire_wake_lock(lock, id) {} #define release_wake_lock(id) {} #include "mir/input/input_report.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // // Needed to build on android platform (PATH_MAX) #ifdef HAVE_ANDROID_OS #include #endif #include // /* this macro is used to tell if "bit" is set in "array" * it selects a byte from the array, and does a boolean AND * operation with a byte that only has the relevant bit set. * eg. to check for the 12th bit, we do (array[1] & 1<<4) */ #define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) /* this macro computes the number of bytes needed to represent a bit array of the specified size */ #define sizeof_bit_array(bits) ((bits + 7) / 8) #define INDENT " " #define INDENT2 " " #define INDENT3 " " namespace mi = mir::input; namespace android { static const char *WAKE_LOCK_ID = "KeyEvents"; static const char *DEVICE_PATH = "/dev/input"; /* return the larger integer */ static inline int max(int v1, int v2) { return (v1 > v2) ? v1 : v2; } static inline const char* toString(bool value) { return value ? "true" : "false"; } namespace detail { String8 sha1(const String8& in) { boost::uuids::detail::sha1 hasher; hasher.process_bytes(in.data(), in.size()); unsigned int digest[5]; hasher.get_digest(digest); String8 out; for(int i : digest) { appendFormat(out, "%08x", i); } return out; } } using detail::sha1; static void setDescriptor(InputDeviceIdentifier& identifier) { // Compute a device descriptor that uniquely identifies the device. // The descriptor is assumed to be a stable identifier. Its value should not // change between reboots, reconnections, firmware updates or new releases of Android. // Ideally, we also want the descriptor to be short and relatively opaque. String8 rawDescriptor; appendFormat(rawDescriptor, ":%04x:%04x:", identifier.vendor, identifier.product); if (!isEmpty(identifier.uniqueId)) { rawDescriptor.append("uniqueId:"); rawDescriptor.append(identifier.uniqueId); } if (identifier.vendor == 0 && identifier.product == 0) { // If we don't know the vendor and product id, then the device is probably // built-in so we need to rely on other information to uniquely identify // the input device. Usually we try to avoid relying on the device name or // location but for built-in input device, they are unlikely to ever change. if (!isEmpty(identifier.name)) { rawDescriptor.append("name:"); rawDescriptor.append(identifier.name); } else if (!isEmpty(identifier.location)) { rawDescriptor.append("location:"); rawDescriptor.append(identifier.location); } } identifier.descriptor = sha1(rawDescriptor); ALOGV("Created descriptor: raw=%s, cooked=%s", c_str(rawDescriptor), c_str(identifier.descriptor)); } // --- Global Functions --- uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { // Touch devices get dibs on touch-related axes. if (deviceClasses & INPUT_DEVICE_CLASS_TOUCH) { switch (axis) { case ABS_X: case ABS_Y: case ABS_PRESSURE: case ABS_TOOL_WIDTH: case ABS_DISTANCE: case ABS_TILT_X: case ABS_TILT_Y: case ABS_MT_SLOT: case ABS_MT_TOUCH_MAJOR: case ABS_MT_TOUCH_MINOR: case ABS_MT_WIDTH_MAJOR: case ABS_MT_WIDTH_MINOR: case ABS_MT_ORIENTATION: case ABS_MT_POSITION_X: case ABS_MT_POSITION_Y: case ABS_MT_TOOL_TYPE: case ABS_MT_BLOB_ID: case ABS_MT_TRACKING_ID: case ABS_MT_PRESSURE: case ABS_MT_DISTANCE: return INPUT_DEVICE_CLASS_TOUCH; } } // Joystick devices get the rest. return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK; } // --- EventHub::Device --- EventHub::Device::Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier) : next(NULL), fd(fd), id(id), path(path), identifier(identifier), classes(0), configuration(NULL), virtualKeyMap(NULL), ffEffectPlaying(false), ffEffectId(-1) { memset(keyBitmask, 0, sizeof(keyBitmask)); memset(absBitmask, 0, sizeof(absBitmask)); memset(relBitmask, 0, sizeof(relBitmask)); memset(swBitmask, 0, sizeof(swBitmask)); memset(ledBitmask, 0, sizeof(ledBitmask)); memset(ffBitmask, 0, sizeof(ffBitmask)); memset(propBitmask, 0, sizeof(propBitmask)); } EventHub::Device::~Device() { close(); delete configuration; delete virtualKeyMap; } void EventHub::Device::close() { if (fd >= 0) { ::close(fd); fd = -1; } } // --- EventHub --- const uint32_t EventHub::EPOLL_ID_UDEV; const uint32_t EventHub::EPOLL_ID_WAKE; const int EventHub::EPOLL_SIZE_HINT; const int EventHub::EPOLL_MAX_EVENTS; EventHub::EventHub(std::shared_ptr const& input_report) : input_report(input_report), device_listener{mir::udev::Context()}, mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mOpeningDevices(0), mClosingDevices(0), mNeedToSendFinishedDeviceScan(false), mNeedToReopenDevices(false), mNeedToScanDevices(true), mPendingEventCount(0), mPendingEventIndex(0), mPendingUdevEvent(false) { acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); mEpollFd = epoll_create(EPOLL_SIZE_HINT); LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); device_listener.filter_by_subsystem("input"); device_listener.enable(); struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = EPOLL_ID_UDEV; int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, device_listener.fd(), &eventItem); LOG_ALWAYS_FATAL_IF(result != 0, "Could not add Udev monitor to epoll instance. errno=%d", errno); int wakeFds[2]; result = pipe(wakeFds); LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); mWakeReadPipeFd = wakeFds[0]; mWakeWritePipeFd = wakeFds[1]; result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", errno); result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", errno); eventItem.data.u32 = EPOLL_ID_WAKE; result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", errno); } EventHub::~EventHub(void) { closeAllDevicesLocked(); while (mClosingDevices) { Device* device = mClosingDevices; mClosingDevices = device->next; delete device; } ::close(mEpollFd); ::close(mWakeReadPipeFd); ::close(mWakeWritePipeFd); release_wake_lock(WAKE_LOCK_ID); } InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device == NULL) return InputDeviceIdentifier(); return device->identifier; } uint32_t EventHub::getDeviceClasses(int32_t deviceId) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device == NULL) return 0; return device->classes; } void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && device->configuration) { *outConfiguration = *device->configuration; } else { outConfiguration->clear(); } } status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, RawAbsoluteAxisInfo* outAxisInfo) const { outAxisInfo->clear(); if (axis >= 0 && axis <= ABS_MAX) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { struct input_absinfo info; if(ioctl(device->fd, EVIOCGABS(axis), &info)) { ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", axis, c_str(device->identifier.name), device->fd, errno); return -errno; } if (info.minimum != info.maximum) { outAxisInfo->valid = true; outAxisInfo->minValue = info.minimum; outAxisInfo->maxValue = info.maximum; outAxisInfo->flat = info.flat; outAxisInfo->fuzz = info.fuzz; outAxisInfo->resolution = info.resolution; } return OK; } } return -1; } bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const { if (axis >= 0 && axis <= REL_MAX) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { return test_bit(axis, device->relBitmask); } } return false; } bool EventHub::hasInputProperty(int32_t deviceId, int property) const { if (property >= 0 && property <= INPUT_PROP_MAX) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { return test_bit(property, device->propBitmask); } } return false; } int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { if (scanCode >= 0 && scanCode <= KEY_MAX) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual() && test_bit(scanCode, device->keyBitmask)) { uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)]; memset(keyState, 0, sizeof(keyState)); if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) { return test_bit(scanCode, keyState) ? AKEY_STATE_DOWN : AKEY_STATE_UP; } } } return AKEY_STATE_UNKNOWN; } int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual() && device->keyMap.haveKeyLayout()) { Vector scanCodes; device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes); if (scanCodes.size() != 0) { uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)]; memset(keyState, 0, sizeof(keyState)); if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) { for (size_t i = 0; i < scanCodes.size(); i++) { int32_t sc = scanCodes.itemAt(i); if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, keyState)) { return AKEY_STATE_DOWN; } } return AKEY_STATE_UP; } } } return AKEY_STATE_UNKNOWN; } int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { if (sw >= 0 && sw <= SW_MAX) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual() && test_bit(sw, device->swBitmask)) { uint8_t swState[sizeof_bit_array(SW_MAX + 1)]; memset(swState, 0, sizeof(swState)); if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) { return test_bit(sw, swState) ? AKEY_STATE_DOWN : AKEY_STATE_UP; } } } return AKEY_STATE_UNKNOWN; } status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const { *outValue = 0; if (axis >= 0 && axis <= ABS_MAX) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { struct input_absinfo info; if(ioctl(device->fd, EVIOCGABS(axis), &info)) { ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", axis, c_str(device->identifier.name), device->fd, errno); return -errno; } *outValue = info.value; return OK; } } return -1; } bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && device->keyMap.haveKeyLayout()) { Vector scanCodes; for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { scanCodes.clear(); status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey( keyCodes[codeIndex], &scanCodes); if (! err) { // check the possible scan codes identified by the layout map against the // map of codes actually emitted by the driver for (size_t sc = 0; sc < scanCodes.size(); sc++) { if (test_bit(scanCodes[sc], device->keyBitmask)) { outFlags[codeIndex] = 1; break; } } } } return true; } return false; } status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t* outKeycode, uint32_t* outFlags) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { // Check the key character map first. sp kcm = device->getKeyCharacterMap(); if (kcm != NULL) { if (!kcm->mapKey(scanCode, usageCode, outKeycode)) { *outFlags = 0; return NO_ERROR; } } // Check the key layout next. if (device->keyMap.haveKeyLayout()) { if (!device->keyMap.keyLayoutMap->mapKey( scanCode, usageCode, outKeycode, outFlags)) { return NO_ERROR; } } } *outKeycode = 0; *outFlags = 0; return NAME_NOT_FOUND; } status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && device->keyMap.haveKeyLayout()) { status_t err = device->keyMap.keyLayoutMap->mapAxis(scanCode, outAxisInfo); if (err == NO_ERROR) { return NO_ERROR; } } return NAME_NOT_FOUND; } void EventHub::setExcludedDevices(const Vector& devices) { AutoMutex _l(mLock); mExcludedDevices = devices; } bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && scanCode >= 0 && scanCode <= KEY_MAX) { if (test_bit(scanCode, device->keyBitmask)) { return true; } } return false; } bool EventHub::hasLed(int32_t deviceId, int32_t led) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && led >= 0 && led <= LED_MAX) { if (test_bit(led, device->ledBitmask)) { return true; } } return false; } void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual() && led >= 0 && led <= LED_MAX) { struct input_event ev; ev.time.tv_sec = 0; ev.time.tv_usec = 0; ev.type = EV_LED; ev.code = led; ev.value = on ? 1 : 0; ssize_t nWrite; do { nWrite = write(device->fd, &ev, sizeof(struct input_event)); } while (nWrite == -1 && errno == EINTR); } } void EventHub::getVirtualKeyDefinitions(int32_t deviceId, Vector& outVirtualKeys) const { outVirtualKeys.clear(); AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && device->virtualKeyMap) { outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys()); } } sp EventHub::getKeyCharacterMap(int32_t deviceId) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { return device->getKeyCharacterMap(); } return NULL; } bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, const sp& map) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { if (map != device->overlayKeyMap) { device->overlayKeyMap = map; device->combinedKeyMap = KeyCharacterMap::combine( device->keyMap.keyCharacterMap, map); return true; } } return false; } void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual()) { ff_effect effect; memset(&effect, 0, sizeof(effect)); effect.type = FF_RUMBLE; effect.id = device->ffEffectId; effect.u.rumble.strong_magnitude = 0xc000; effect.u.rumble.weak_magnitude = 0xc000; effect.replay.length = (duration + 999999LL) / 1000000LL; effect.replay.delay = 0; if (ioctl(device->fd, EVIOCSFF, &effect)) { ALOGW("Could not upload force feedback effect to device %s due to error %d.", c_str(device->identifier.name), errno); return; } device->ffEffectId = effect.id; struct input_event ev; ev.time.tv_sec = 0; ev.time.tv_usec = 0; ev.type = EV_FF; ev.code = device->ffEffectId; ev.value = 1; if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { ALOGW("Could not start force feedback effect on device %s due to error %d.", c_str(device->identifier.name), errno); return; } device->ffEffectPlaying = true; } } void EventHub::cancelVibrate(int32_t deviceId) { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device && !device->isVirtual()) { if (device->ffEffectPlaying) { device->ffEffectPlaying = false; struct input_event ev; ev.time.tv_sec = 0; ev.time.tv_usec = 0; ev.type = EV_FF; ev.code = device->ffEffectId; ev.value = 0; if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { ALOGW("Could not stop force feedback effect on device %s due to error %d.", c_str(device->identifier.name), errno); return; } } } } EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const { if (deviceId == BUILT_IN_KEYBOARD_ID) { deviceId = mBuiltInKeyboardId; } ssize_t index = mDevices.indexOfKey(deviceId); return index >= 0 ? mDevices.valueAt(index) : NULL; } EventHub::Device* EventHub::getDeviceByPathLocked(const char* devicePath) const { for (size_t i = 0; i < mDevices.size(); i++) { Device* device = mDevices.valueAt(i); if (device->path == devicePath) { return device; } } return NULL; } size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { ALOG_ASSERT(bufferSize >= 1); AutoMutex _l(mLock); struct input_event readBuffer[bufferSize]; RawEvent* event = buffer; size_t capacity = bufferSize; bool awoken = false; for (;;) { nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); // Reopen input devices if needed. if (mNeedToReopenDevices) { mNeedToReopenDevices = false; ALOGI("Reopening all input devices due to a configuration change."); closeAllDevicesLocked(); mNeedToScanDevices = true; break; // return to the caller before we actually rescan } // Report any devices that had last been added/removed. while (mClosingDevices) { Device* device = mClosingDevices; ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, c_str(device->path)); mClosingDevices = device->next; event->when = now; event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id; event->type = DEVICE_REMOVED; event += 1; delete device; mNeedToSendFinishedDeviceScan = true; if (--capacity == 0) { break; } } if (mNeedToScanDevices) { mNeedToScanDevices = false; scanDevicesLocked(); mNeedToSendFinishedDeviceScan = true; } while (mOpeningDevices != NULL) { Device* device = mOpeningDevices; ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, c_str(device->path)); mOpeningDevices = device->next; event->when = now; event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; event->type = DEVICE_ADDED; event += 1; mNeedToSendFinishedDeviceScan = true; if (--capacity == 0) { break; } } if (mNeedToSendFinishedDeviceScan) { mNeedToSendFinishedDeviceScan = false; event->when = now; event->type = FINISHED_DEVICE_SCAN; event += 1; if (--capacity == 0) { break; } } // Grab the next input event. bool deviceChanged = false; while (mPendingEventIndex < mPendingEventCount) { const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++]; if (eventItem.data.u32 == EPOLL_ID_UDEV) { if (eventItem.events & EPOLLIN) { mPendingUdevEvent = true; } else { ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events); } continue; } if (eventItem.data.u32 == EPOLL_ID_WAKE) { if (eventItem.events & EPOLLIN) { ALOGV("awoken after wake()"); awoken = true; char buffer[16]; ssize_t nRead; do { nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer)); } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); } else { ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.", eventItem.events); } continue; } ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32); if (deviceIndex < 0) { ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.", eventItem.events, eventItem.data.u32); continue; } Device* device = mDevices.valueAt(deviceIndex); if (eventItem.events & EPOLLIN) { int32_t readSize = read(device->fd, readBuffer, sizeof(struct input_event) * capacity); if (readSize == 0 || (readSize < 0 && errno == ENODEV)) { // Device was removed before INotify noticed. ALOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d " "capacity: %d errno: %d)\n", device->fd, readSize, bufferSize, capacity, errno); deviceChanged = true; closeDeviceLocked(device); } else if (readSize < 0) { if (errno != EAGAIN && errno != EINTR) { ALOGW("could not get event (errno=%d)", errno); } } else if ((readSize % sizeof(struct input_event)) != 0) { ALOGE("could not get event (wrong size: %d)", readSize); } else { int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; size_t count = size_t(readSize) / sizeof(struct input_event); for (size_t i = 0; i < count; i++) { const struct input_event& iev = readBuffer[i]; ALOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, value=%d", c_str(device->path), (int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value); #ifdef HAVE_POSIX_CLOCKS // Use the time specified in the event instead of the current time // so that downstream code can get more accurate estimates of // event dispatch latency from the time the event is enqueued onto // the evdev client buffer. // // The event's timestamp fortuitously uses the same monotonic clock // time base as the rest of Android. The kernel event device driver // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts(). // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a // system call that also queries ktime_get_ts(). event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL + nsecs_t(iev.time.tv_usec) * 1000LL; ALOGV("event time %lld, now %lld", event->when, now); #else event->when = now; #endif event->deviceId = deviceId; event->type = iev.type; event->code = iev.code; event->value = iev.value; input_report->received_event_from_kernel(event->when, event->type, event->code, event->value); event += 1; } capacity -= count; if (capacity == 0) { // The result buffer is full. Reset the pending event index // so we will try to read the device again on the next iteration. mPendingEventIndex -= 1; break; } } } else if (eventItem.events & EPOLLHUP) { ALOGI("Removing device %s due to epoll hang-up event.", c_str(device->identifier.name)); deviceChanged = true; closeDeviceLocked(device); } else { ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events, c_str(device->identifier.name)); } } // readNotify() will modify the list of devices so this must be done after // processing all other events to ensure that we read all remaining events // before closing the devices. if (mPendingUdevEvent && mPendingEventIndex >= mPendingEventCount) { mPendingUdevEvent = false; handleUdevEventsLocked(); deviceChanged = true; } // Report added or removed devices immediately. if (deviceChanged) { continue; } // Return now if we have collected any events or if we were explicitly awoken. if (event != buffer || awoken) { break; } // Poll for events. Mind the wake lock dance! // We hold a wake lock at all times except during epoll_wait(). This works due to some // subtle choreography. When a device driver has pending (unread) events, it acquires // a kernel wake lock. However, once the last pending event has been read, the device // driver will release the kernel wake lock. To prevent the system from going to sleep // when this happens, the EventHub holds onto its own user wake lock while the client // is processing events. Thus the system can only sleep if there are no events // pending or currently being processed. // // The timeout is advisory only. If the device is asleep, it will not wake just to // service the timeout. mPendingEventIndex = 0; mLock.unlock(); // release lock before poll, must be before release_wake_lock release_wake_lock(WAKE_LOCK_ID); int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock if (pollResult == 0) { // Timed out. mPendingEventCount = 0; break; } if (pollResult < 0) { // An error occurred. mPendingEventCount = 0; // Sleep after errors to avoid locking up the system. // Hopefully the error is transient. if (errno != EINTR) { ALOGW("poll failed (errno=%d)\n", errno); usleep(100000); } } else { // Some events occurred. mPendingEventCount = size_t(pollResult); } } // All done, return the number of events we read. return event - buffer; } void EventHub::wake() { ALOGV("wake() called"); ssize_t nWrite; do { nWrite = write(mWakeWritePipeFd, "W", 1); } while (nWrite == -1 && errno == EINTR); if (nWrite != 1 && errno != EAGAIN) { ALOGW("Could not write wake signal, errno=%d", errno); } } void EventHub::scanDevicesLocked() { mir::udev::Enumerator input_enumerator{std::make_shared()}; input_enumerator.match_subsystem("input"); input_enumerator.scan_devices(); for (auto& device : input_enumerator) { if (device.devnode() != nullptr) { openDeviceLocked(device.devnode()); } } if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) { createVirtualKeyboardLocked(); } } void EventHub::handleUdevEventsLocked() { device_listener.process_events([this](mir::udev::Monitor::EventType type, mir::udev::Device const& dev){ if (type == mir::udev::Monitor::ADDED) { if (dev.devnode() != nullptr) { openDeviceLocked(dev.devnode()); } } else if (type == mir::udev::Monitor::REMOVED) { if (dev.devnode() != nullptr) { closeDeviceByPathLocked(dev.devnode()); } } }); } // ---------------------------------------------------------------------------- static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) { const uint8_t* end = array + endIndex; array += startIndex; while (array != end) { if (*(array++) != 0) { return true; } } return false; } static const int32_t GAMEPAD_KEYCODES[] = { AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C, AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z, AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1, AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2, AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR, AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, AKEYCODE_BUTTON_1, AKEYCODE_BUTTON_2, AKEYCODE_BUTTON_3, AKEYCODE_BUTTON_4, AKEYCODE_BUTTON_5, AKEYCODE_BUTTON_6, AKEYCODE_BUTTON_7, AKEYCODE_BUTTON_8, AKEYCODE_BUTTON_9, AKEYCODE_BUTTON_10, AKEYCODE_BUTTON_11, AKEYCODE_BUTTON_12, AKEYCODE_BUTTON_13, AKEYCODE_BUTTON_14, AKEYCODE_BUTTON_15, AKEYCODE_BUTTON_16, }; status_t EventHub::openDeviceLocked(const char *devicePath) { char buffer[80]; ALOGV("Opening device: %s", devicePath); if (hasDeviceByPathLocked(String8(devicePath))) { ALOGV("Not opening device (%s), as it is already opened", devicePath); return -1; } int fd = open(devicePath, O_RDWR | O_CLOEXEC); if(fd < 0) { ALOGE("could not open %s, %s\n", devicePath, strerror(errno)); return -1; } InputDeviceIdentifier identifier; // Get device name. if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; setTo(identifier.name, buffer); } // Check to see if the device is on our excluded list for (size_t i = 0; i < mExcludedDevices.size(); i++) { const String8& item = mExcludedDevices.itemAt(i); if (identifier.name == item) { ALOGI("ignoring event id %s driver %s\n", devicePath, c_str(item)); close(fd); return -1; } } // Get device driver version. int driverVersion; if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; } // Get device identifier. struct input_id inputId; if(ioctl(fd, EVIOCGID, &inputId)) { ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); close(fd); return -1; } identifier.bus = inputId.bustype; identifier.product = inputId.product; identifier.vendor = inputId.vendor; identifier.version = inputId.version; // Get device physical location. if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; setTo(identifier.location, buffer); } // Get device unique id. if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); } else { buffer[sizeof(buffer) - 1] = '\0'; setTo(identifier.uniqueId, buffer); } // Fill in the descriptor. setDescriptor(identifier); // Make file descriptor non-blocking for use with poll(). if (fcntl(fd, F_SETFL, O_NONBLOCK)) { ALOGE("Error %d making device file descriptor non-blocking.", errno); close(fd); return -1; } // Allocate device. (The device object takes ownership of the fd at this point.) int32_t deviceId = mNextDeviceId++; Device* device = new Device(fd, deviceId, String8(devicePath), identifier); ALOGV("add device %d: %s\n", deviceId, devicePath); ALOGV(" bus: %04x\n" " vendor %04x\n" " product %04x\n" " version %04x\n", identifier.bus, identifier.vendor, identifier.product, identifier.version); ALOGV(" name: \"%s\"\n", c_str(identifier.name)); ALOGV(" location: \"%s\"\n", c_str(identifier.location)); ALOGV(" unique id: \"%s\"\n", c_str(identifier.uniqueId)); ALOGV(" descriptor: \"%s\"\n", c_str(identifier.descriptor)); ALOGV(" driver: v%d.%d.%d\n", driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); // Load the configuration file for the device. loadConfigurationLocked(device); // Figure out the kinds of events the device reports. ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask); ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask); ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask); ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask); ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask); ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask); ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask); // See if this is a keyboard. Ignore everything in the button range except for // joystick and gamepad buttons which are handled like keyboards for the most part. bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), sizeof_bit_array(KEY_MAX + 1)); bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC), sizeof_bit_array(BTN_MOUSE)) || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), sizeof_bit_array(BTN_DIGI)); if (haveKeyboardKeys || haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } // See if this is a cursor device such as a trackball or mouse. if (test_bit(BTN_MOUSE, device->keyBitmask) && test_bit(REL_X, device->relBitmask) && test_bit(REL_Y, device->relBitmask)) { device->classes |= INPUT_DEVICE_CLASS_CURSOR; } // See if this is a touch pad. // Is this a new modern multi-touch driver? if (test_bit(ABS_MT_POSITION_X, device->absBitmask) && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { // Some joysticks such as the PS3 controller report axes that conflict // with the ABS_MT range. Try to confirm that the device really is // a touch screen. if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) { device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT; } // Is this an old style single-touch driver? } else if (test_bit(BTN_TOUCH, device->keyBitmask) && test_bit(ABS_X, device->absBitmask) && test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCH; } // See if this device is a joystick. // Assumes that joysticks always have gamepad buttons in order to distinguish them // from other devices such as accelerometers that also have absolute axes. if (haveGamepadButtons) { uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK; for (int i = 0; i <= ABS_MAX; i++) { if (test_bit(i, device->absBitmask) && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { device->classes = assumedClasses; break; } } } // Check whether this device has switches. for (int i = 0; i <= SW_MAX; i++) { if (test_bit(i, device->swBitmask)) { device->classes |= INPUT_DEVICE_CLASS_SWITCH; break; } } // Check whether this device supports the vibrator. if (test_bit(FF_RUMBLE, device->ffBitmask)) { device->classes |= INPUT_DEVICE_CLASS_VIBRATOR; } // Configure virtual keys. if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) { // Load the virtual keys for the touch screen, if any. // We do this now so that we can make sure to load the keymap if necessary. status_t status = loadVirtualKeyMapLocked(device); if (!status) { device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; } } // Load the key map. // We need to do this for joysticks too because the key layout may specify axes. status_t keyMapStatus = NAME_NOT_FOUND; if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) { // Load the keymap for the device. keyMapStatus = loadKeyMapLocked(device); } // Configure the keyboard, gamepad or virtual keyboard. if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { // Register the keyboard as a built-in keyboard if it is eligible. if (!keyMapStatus && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD && isEligibleBuiltInKeyboard(device->identifier, device->configuration, &device->keyMap)) { mBuiltInKeyboardId = device->id; } // 'Q' key support = cheap test of whether this is an alpha-capable kbd if (hasKeycodeLocked(device, AKEYCODE_Q)) { device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; } // See if this device has a DPAD. if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { device->classes |= INPUT_DEVICE_CLASS_DPAD; } // See if this device has a gamepad. for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; break; } } } // If the device isn't recognized as something we handle, don't monitor it. if (device->classes == 0) { ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath, c_str(device->identifier.name)); delete device; return -1; } // Determine whether the device is external or internal. if (isExternalDeviceLocked(device)) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; } // Register with epoll. struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.u32 = deviceId; if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { ALOGE("Could not add device fd to epoll instance. errno=%d", errno); delete device; return -1; } // Enable wake-lock behavior on kernels that support it. // TODO: Only need this for devices that can really wake the system. bool usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 1); // Tell the kernel that we want to use the monotonic clock for reporting timestamps // associated with input events. This is important because the input system // uses the timestamps extensively and assumes they were recorded using the monotonic // clock. // // In older kernel, before Linux 3.4, there was no way to tell the kernel which // clock to use to input event timestamps. The standard kernel behavior was to // record a real time timestamp, which isn't what we want. Android kernels therefore // contained a patch to the evdev_event() function in drivers/input/evdev.c to // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic // clock to be used instead of the real time clock. // // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock. // Therefore, we no longer require the Android-specific kernel patch described above // as long as we make sure to set select the monotonic clock. We do that here. int clockId = CLOCK_MONOTONIC; bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId); ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, " "usingSuspendBlockIoctl=%s, usingClockIoctl=%s", deviceId, fd, devicePath, c_str(device->identifier.name), device->classes, c_str(device->configurationFile), c_str(device->keyMap.keyLayoutFile), c_str(device->keyMap.keyCharacterMapFile), toString(mBuiltInKeyboardId == deviceId), toString(usingSuspendBlockIoctl), toString(usingClockIoctl)); addDeviceLocked(device); return 0; } void EventHub::createVirtualKeyboardLocked() { InputDeviceIdentifier identifier; identifier.name = "Virtual"; identifier.uniqueId = ""; setDescriptor(identifier); Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, String8(""), identifier); device->classes = INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_ALPHAKEY | INPUT_DEVICE_CLASS_DPAD | INPUT_DEVICE_CLASS_VIRTUAL; loadKeyMapLocked(device); addDeviceLocked(device); } void EventHub::addDeviceLocked(Device* device) { mDevices.add(device->id, device); device->next = mOpeningDevices; mOpeningDevices = device; } void EventHub::loadConfigurationLocked(Device* device) { device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier( device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); if (isEmpty(device->configurationFile)) { ALOGD("No input device configuration file found for device '%s'.", c_str(device->identifier.name)); } else { status_t status = PropertyMap::load(device->configurationFile, &device->configuration); if (status) { ALOGE("Error loading input device configuration file for device '%s'. " "Using default configuration.", c_str(device->identifier.name)); } } } status_t EventHub::loadVirtualKeyMapLocked(Device* device) { // The virtual key map is supplied by the kernel as a system board property file. String8 path; path.append("/sys/board_properties/virtualkeys."); path.append(device->identifier.name); if (access(c_str(path), R_OK)) { return NAME_NOT_FOUND; } return VirtualKeyMap::load(path, &device->virtualKeyMap); } status_t EventHub::loadKeyMapLocked(Device* device) { // status_t status = device->keyMap.load(device->identifier, device->configuration); if (status) status = device->keyMap.loadGenericMaps(); return status; // } bool EventHub::isExternalDeviceLocked(Device* device) { if (device->configuration) { bool value; if (device->configuration->tryGetProperty(String8("device.internal"), value)) { return !value; } } return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH; } bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) { return false; } Vector scanCodes; device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes); const size_t N = scanCodes.size(); for (size_t i=0; i= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) { return true; } } return false; } status_t EventHub::closeDeviceByPathLocked(const char *devicePath) { Device* device = getDeviceByPathLocked(devicePath); if (device) { closeDeviceLocked(device); return 0; } ALOGV("Remove device: %s not found, device may already have been removed.", devicePath); return -1; } void EventHub::closeAllDevicesLocked() { while (mDevices.size() > 0) { closeDeviceLocked(mDevices.valueAt(mDevices.size() - 1)); } } void EventHub::closeDeviceLocked(Device* device) { ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n", c_str(device->path), c_str(device->identifier.name), device->id, device->fd, device->classes); if (device->id == mBuiltInKeyboardId) { ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", c_str(device->path), mBuiltInKeyboardId); mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD; } if (!device->isVirtual()) { if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) { ALOGW("Could not remove device fd from epoll instance. errno=%d", errno); } } mDevices.removeItem(device->id); device->close(); // Unlink for opening devices list if it is present. Device* pred = NULL; bool found = false; for (Device* entry = mOpeningDevices; entry != NULL; ) { if (entry == device) { found = true; break; } pred = entry; entry = entry->next; } if (found) { // Unlink the device from the opening devices list then delete it. // We don't need to tell the client that the device was closed because // it does not even know it was opened in the first place. ALOGI("Device %s was immediately closed after opening.", c_str(device->path)); if (pred) { pred->next = device->next; } else { mOpeningDevices = device->next; } delete device; } else { // Link into closing devices list. // The device will be deleted later after we have informed the client. device->next = mClosingDevices; mClosingDevices = device; } } void EventHub::requestReopenDevices() { ALOGV("requestReopenDevices() called"); AutoMutex _l(mLock); mNeedToReopenDevices = true; } void EventHub::dump(String8& dump) { dump.append("Event Hub State:\n"); { // acquire lock AutoMutex _l(mLock); appendFormat(dump, INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId); dump.append(INDENT "Devices:\n"); for (size_t i = 0; i < mDevices.size(); i++) { const Device* device = mDevices.valueAt(i); if (mBuiltInKeyboardId == device->id) { appendFormat(dump, INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n", device->id, c_str(device->identifier.name)); } else { appendFormat(dump, INDENT2 "%d: %s\n", device->id, c_str(device->identifier.name)); } appendFormat(dump, INDENT3 "Classes: 0x%08x\n", device->classes); appendFormat(dump, INDENT3 "Path: %s\n", c_str(device->path)); appendFormat(dump, INDENT3 "Descriptor: %s\n", c_str(device->identifier.descriptor)); appendFormat(dump, INDENT3 "Location: %s\n", c_str(device->identifier.location)); appendFormat(dump, INDENT3 "UniqueId: %s\n", c_str(device->identifier.uniqueId)); appendFormat(dump, INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, " "product=0x%04x, version=0x%04x\n", device->identifier.bus, device->identifier.vendor, device->identifier.product, device->identifier.version); appendFormat(dump, INDENT3 "KeyLayoutFile: %s\n", c_str(device->keyMap.keyLayoutFile)); appendFormat(dump, INDENT3 "KeyCharacterMapFile: %s\n", c_str(device->keyMap.keyCharacterMapFile)); appendFormat(dump, INDENT3 "ConfigurationFile: %s\n", c_str(device->configurationFile)); appendFormat(dump, INDENT3 "HaveKeyboardLayoutOverlay: %s\n", toString(device->overlayKeyMap != NULL)); } } // release lock } void EventHub::monitor() { // Acquire and release the lock to ensure that the event hub has not deadlocked. mLock.lock(); mLock.unlock(); } void EventHub::flush() { static const int bufferSize = 256; AutoMutex _l(mLock); char readBuffer[bufferSize]; int32_t readSize; // Read any pending events from the input devices. Note that // the device fds are in non-blocking mode (see openDeviceLocked). for (size_t i = 0; i < mDevices.size(); i++) { const Device* device = mDevices.valueAt(i); do { readSize = read(device->fd, readBuffer, bufferSize); } while (readSize > 0); } } bool EventHub::hasDeviceByPathLocked(String8 const& path) { for (size_t i = 0; i < mDevices.size(); i++) { auto const& device = mDevices.valueAt(i); if (device->path == path) return true; } return false; } }; // namespace android ././@LongLink0000000000000000000000000000015200000000000011213 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputDispatcher.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputDispatc0000644000015301777760000012512412322054223033413 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _UI_INPUT_DISPATCHER_H #define _UI_INPUT_DISPATCHER_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "InputWindow.h" #include "InputApplication.h" #include "InputListener.h" #include "InputEnumerator.h" #include namespace mir { namespace input { class InputReport; } } namespace android { /* * Constants used to report the outcome of input event injection. */ enum { /* (INTERNAL USE ONLY) Specifies that injection is pending and its outcome is unknown. */ INPUT_EVENT_INJECTION_PENDING = -1, /* Injection succeeded. */ INPUT_EVENT_INJECTION_SUCCEEDED = 0, /* Injection failed because the injector did not have permission to inject * into the application with input focus. */ INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1, /* Injection failed because there were no available input targets. */ INPUT_EVENT_INJECTION_FAILED = 2, /* Injection failed due to a timeout. */ INPUT_EVENT_INJECTION_TIMED_OUT = 3 }; /* * Constants used to determine the input event injection synchronization mode. */ enum { /* Injection is asynchronous and is assumed always to be successful. */ INPUT_EVENT_INJECTION_SYNC_NONE = 0, /* Waits for previous events to be dispatched so that the input dispatcher can determine * whether input event injection willbe permitted based on the current input focus. * Does not wait for the input event to finish processing. */ INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1, /* Waits for the input event to be completely processed. */ INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2 }; /* * An input target specifies how an input event is to be dispatched to a particular window * including the window's input channel, control flags, a timeout, and an X / Y offset to * be added to input event coordinates to compensate for the absolute position of the * window area. */ struct InputTarget { enum { /* This flag indicates that the event is being delivered to a foreground application. */ FLAG_FOREGROUND = 1 << 0, /* This flag indicates that the target of a MotionEvent is partly or wholly * obscured by another visible window above it. The motion event should be * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ FLAG_WINDOW_IS_OBSCURED = 1 << 1, /* This flag indicates that a motion event is being split across multiple windows. */ FLAG_SPLIT = 1 << 2, /* This flag indicates that the pointer coordinates dispatched to the application * will be zeroed out to avoid revealing information to an application. This is * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing * the same UID from watching all touches. */ FLAG_ZERO_COORDS = 1 << 3, /* This flag indicates that the event should be sent as is. * Should always be set unless the event is to be transmuted. */ FLAG_DISPATCH_AS_IS = 1 << 8, /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside * of the area of this target and so should instead be delivered as an * AMOTION_EVENT_ACTION_OUTSIDE to this target. */ FLAG_DISPATCH_AS_OUTSIDE = 1 << 9, /* This flag indicates that a hover sequence is starting in the given window. * The event is transmuted into ACTION_HOVER_ENTER. */ FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10, /* This flag indicates that a hover event happened outside of a window which handled * previous hover events, signifying the end of the current hover sequence for that * window. * The event is transmuted into ACTION_HOVER_ENTER. */ FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11, /* This flag indicates that the event should be canceled. * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips * outside of a window. */ FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12, /* This flag indicates that the event should be dispatched as an initial down. * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips * into a new window. */ FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13, /* Mask for all dispatch modes. */ FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS | FLAG_DISPATCH_AS_OUTSIDE | FLAG_DISPATCH_AS_HOVER_ENTER | FLAG_DISPATCH_AS_HOVER_EXIT | FLAG_DISPATCH_AS_SLIPPERY_EXIT | FLAG_DISPATCH_AS_SLIPPERY_ENTER }; // The input channel to be targeted. sp inputChannel; // Flags for the input target. int32_t flags; // The x and y offset to add to a MotionEvent as it is delivered. // (ignored for KeyEvents) float xOffset, yOffset; // Scaling factor to apply to MotionEvent as it is delivered. // (ignored for KeyEvents) float scaleFactor; // The subset of pointer ids to include in motion events dispatched to this input target // if FLAG_SPLIT is set. IntSet pointerIds; }; /* * Input dispatcher configuration. * * Specifies various options that modify the behavior of the input dispatcher. */ struct InputDispatcherConfiguration { // The key repeat initial timeout. nsecs_t keyRepeatTimeout; // The key repeat inter-key delay. nsecs_t keyRepeatDelay; InputDispatcherConfiguration() : keyRepeatTimeout(500 * 1000000LL), keyRepeatDelay(50 * 1000000LL) { } }; /* * Input dispatcher policy interface. * * The input reader policy is used by the input reader to interact with the Window Manager * and other system components. * * The actual implementation is partially supported by callbacks into the DVM * via JNI. This interface is also mocked in the unit tests. */ class InputDispatcherPolicyInterface : public virtual RefBase { protected: InputDispatcherPolicyInterface() { } virtual ~InputDispatcherPolicyInterface() { } public: /* Notifies the system that a configuration change has occurred. */ virtual void notifyConfigurationChanged(nsecs_t when) = 0; /* Notifies the system that an application is not responding. * Returns a new timeout to continue waiting, or 0 to abort dispatch. */ virtual nsecs_t notifyANR(const sp& inputApplicationHandle, const sp& inputWindowHandle) = 0; /* Notifies the system that an input channel is unrecoverably broken. */ virtual void notifyInputChannelBroken(const sp& inputWindowHandle) = 0; /* Gets the input dispatcher configuration. */ virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0; /* Returns true if automatic key repeating is enabled. */ virtual bool isKeyRepeatEnabled() = 0; /* Filters an input event. * Return true to dispatch the event unmodified, false to consume the event. * A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED * to injectInputEvent. */ virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0; /* Intercepts a key event immediately before queueing it. * The policy can use this method as an opportunity to perform power management functions * and early event preprocessing such as updating policy flags. * * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event * should be dispatched to applications. */ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0; /* Intercepts a touch, trackball or other motion event before queueing it. * The policy can use this method as an opportunity to perform power management functions * and early event preprocessing such as updating policy flags. * * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event * should be dispatched to applications. */ virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0; /* Allows the policy a chance to intercept a key before dispatching. */ virtual nsecs_t interceptKeyBeforeDispatching(const sp& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) = 0; /* Allows the policy a chance to perform default processing for an unhandled key. * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */ virtual bool dispatchUnhandledKey(const sp& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0; /* Notifies the policy about switch events. */ virtual void notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, uint32_t policyFlags) = 0; /* Poke user activity for an event dispatched to a window. */ virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0; /* Checks whether a given application pid/uid has permission to inject input events * into other applications. * * This method is special in that its implementation promises to be non-reentrant and * is safe to call while holding other locks. (Most other methods make no such guarantees!) */ virtual bool checkInjectEventsPermissionNonReentrant( int32_t injectorPid, int32_t injectorUid) = 0; }; /* Notifies the system about input events generated by the input reader. * The dispatcher is expected to be mostly asynchronous. */ class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface { protected: InputDispatcherInterface() { } virtual ~InputDispatcherInterface() { } public: /* * Sets the enumerator of input targets. This must be called prior to enabling input dispatch. * * This method may be called by any thread. */ virtual void setInputEnumerator(sp const& enumerator) = 0; /* Dumps the state of the input dispatcher. * * This method may be called on any thread (usually by the input manager). */ virtual void dump(String8& dump) = 0; /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */ virtual void monitor() = 0; /* Runs a single iteration of the dispatch loop. * Nominally processes one queued event, a timeout, or a response from an input consumer. * * This method should only be called on the input dispatcher thread. */ virtual void dispatchOnce() = 0; /* Injects an input event and optionally waits for sync. * The synchronization mode determines whether the method blocks while waiting for * input injection to proceed. * Returns one of the INPUT_EVENT_INJECTION_XXX constants. * * This method may be called on any thread (usually by the input manager). */ virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags) = 0; /* * Sets the keyboard focus target. * * This method may be called on any thread. */ virtual void setKeyboardFocus(const sp& windowHandle) = 0; /* * Notify that a window handle is about to vanish * This method may be called on any thread. */ virtual void notifyWindowRemoved(const sp& windowHandle) = 0; /* Sets the focused application. * * This method may be called on any thread (usually by the input manager). */ virtual void setFocusedApplication( const sp& inputApplicationHandle) = 0; /* Sets the input dispatching mode. * * This method may be called on any thread (usually by the input manager). */ virtual void setInputDispatchMode(bool enabled, bool frozen) = 0; /* Sets whether input event filtering is enabled. * When enabled, incoming input events are sent to the policy's filterInputEvent * method instead of being dispatched. The filter is expected to use * injectInputEvent to inject the events it would like to have dispatched. * It should include POLICY_FLAG_FILTERED in the policy flags during injection. */ virtual void setInputFilterEnabled(bool enabled) = 0; /* Transfers touch focus from the window associated with one channel to the * window associated with the other channel. * * Returns true on success. False if the window did not actually have touch focus. */ virtual bool transferTouchFocus(const sp& fromChannel, const sp& toChannel) = 0; /* Registers or unregister input channels that may be used as targets for input events. * If monitor is true, the channel will receive a copy of all input events. * * These methods may be called on any thread (usually by the input manager). */ virtual status_t registerInputChannel(const sp& inputChannel, const sp& inputWindowHandle, bool monitor) = 0; virtual status_t unregisterInputChannel(const sp& inputChannel) = 0; }; /* Dispatches events to input targets. Some functions of the input dispatcher, such as * identifying input targets, are controlled by a separate policy object. * * IMPORTANT INVARIANT: * Because the policy can potentially block or cause re-entrance into the input dispatcher, * the input dispatcher never calls into the policy while holding its internal locks. * The implementation is also carefully designed to recover from scenarios such as an * input channel becoming unregistered while identifying input targets or processing timeouts. * * Methods marked 'Locked' must be called with the lock acquired. * * Methods marked 'LockedInterruptible' must be called with the lock acquired but * may during the course of their execution release the lock, call into the policy, and * then reacquire the lock. The caller is responsible for recovering gracefully. * * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa. */ class InputDispatcher : public InputDispatcherInterface { protected: virtual ~InputDispatcher(); public: explicit InputDispatcher(const sp& policy, std::shared_ptr const& input_report); virtual void setInputEnumerator(sp const& enumerator); virtual void dump(String8& dump); virtual void monitor(); virtual void dispatchOnce(); virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); virtual void notifyKey(const NotifyKeyArgs* args); virtual void notifyMotion(const NotifyMotionArgs* args); virtual void notifySwitch(const NotifySwitchArgs* args); virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); virtual int32_t injectInputEvent(const InputEvent* event, int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, uint32_t policyFlags); virtual void setKeyboardFocus(const sp& windowHandle); virtual void notifyWindowRemoved(const sp& windowHandle); virtual void setFocusedApplication(const sp& inputApplicationHandle); virtual void setInputDispatchMode(bool enabled, bool frozen); virtual void setInputFilterEnabled(bool enabled); virtual bool transferTouchFocus(const sp& fromChannel, const sp& toChannel); virtual status_t registerInputChannel(const sp& inputChannel, const sp& inputWindowHandle, bool monitor); virtual status_t unregisterInputChannel(const sp& inputChannel); private: std::shared_ptr const input_report; template struct Link { T* next; T* prev; protected: inline Link() : next(NULL), prev(NULL) { } }; struct InjectionState { mutable int32_t refCount; int32_t injectorPid; int32_t injectorUid; int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING bool injectionIsAsync; // set to true if injection is not waiting for the result int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress InjectionState(int32_t injectorPid, int32_t injectorUid); void release(); private: ~InjectionState(); }; struct EventEntry : Link { enum { TYPE_CONFIGURATION_CHANGED, TYPE_DEVICE_RESET, TYPE_KEY, TYPE_MOTION }; mutable int32_t refCount; int32_t type; nsecs_t eventTime; uint32_t policyFlags; InjectionState* injectionState; bool dispatchInProgress; // initially false, set to true while dispatching inline bool isInjected() const { return injectionState != NULL; } void release(); virtual void appendDescription(String8& msg) const = 0; protected: EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags); virtual ~EventEntry(); void releaseInjectionState(); }; struct ConfigurationChangedEntry : EventEntry { ConfigurationChangedEntry(nsecs_t eventTime); virtual void appendDescription(String8& msg) const; protected: virtual ~ConfigurationChangedEntry(); }; struct DeviceResetEntry : EventEntry { int32_t deviceId; DeviceResetEntry(nsecs_t eventTime, int32_t deviceId); virtual void appendDescription(String8& msg) const; protected: virtual ~DeviceResetEntry(); }; struct KeyEntry : EventEntry { int32_t deviceId; uint32_t source; int32_t action; int32_t flags; int32_t keyCode; int32_t scanCode; int32_t metaState; int32_t repeatCount; nsecs_t downTime; bool syntheticRepeat; // set to true for synthetic key repeats enum InterceptKeyResult { INTERCEPT_KEY_RESULT_UNKNOWN, INTERCEPT_KEY_RESULT_SKIP, INTERCEPT_KEY_RESULT_CONTINUE, INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER }; InterceptKeyResult interceptKeyResult; // set based on the interception result nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER KeyEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime); virtual void appendDescription(String8& msg) const; void recycle(); protected: virtual ~KeyEntry(); }; struct MotionEntry : EventEntry { nsecs_t eventTime; int32_t deviceId; uint32_t source; int32_t action; int32_t flags; int32_t metaState; int32_t buttonState; int32_t edgeFlags; float xPrecision; float yPrecision; nsecs_t downTime; uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; MotionEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime, uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); virtual void appendDescription(String8& msg) const; protected: virtual ~MotionEntry(); }; // Tracks the progress of dispatching a particular event to a particular connection. struct DispatchEntry : Link { const uint32_t seq; // unique sequence number, never 0 EventEntry* eventEntry; // the event to dispatch int32_t targetFlags; float xOffset; float yOffset; float scaleFactor; nsecs_t deliveryTime; // time when the event was actually delivered // Set to the resolved action and flags when the event is enqueued. int32_t resolvedAction; int32_t resolvedFlags; DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, float xOffset, float yOffset, float scaleFactor); ~DispatchEntry(); inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; } inline bool isSplit() const { return targetFlags & InputTarget::FLAG_SPLIT; } private: static android_atomic_int32_t sNextSeqAtomic; static uint32_t nextSeq(); }; // A command entry captures state and behavior for an action to be performed in the // dispatch loop after the initial processing has taken place. It is essentially // a kind of continuation used to postpone sensitive policy interactions to a point // in the dispatch loop where it is safe to release the lock (generally after finishing // the critical parts of the dispatch cycle). // // The special thing about commands is that they can voluntarily release and reacquire // the dispatcher lock at will. Initially when the command starts running, the // dispatcher lock is held. However, if the command needs to call into the policy to // do some work, it can release the lock, do the work, then reacquire the lock again // before returning. // // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch // never calls into the policy while holding its lock. // // Commands are implicitly 'LockedInterruptible'. struct CommandEntry; typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry); class Connection; struct CommandEntry : Link { CommandEntry(Command command); ~CommandEntry(); Command command; // parameters for the command (usage varies by command) sp connection; nsecs_t eventTime; KeyEntry* keyEntry; sp inputApplicationHandle; sp inputWindowHandle; int32_t userActivityEventType; uint32_t seq; bool handled; }; // Generic queue implementation. template struct Queue { T* head; T* tail; inline Queue() : head(NULL), tail(NULL) { } inline bool isEmpty() const { return !head; } inline void enqueueAtTail(T* entry) { entry->prev = tail; if (tail) { tail->next = entry; } else { head = entry; } entry->next = NULL; tail = entry; } inline void enqueueAtHead(T* entry) { entry->next = head; if (head) { head->prev = entry; } else { tail = entry; } entry->prev = NULL; head = entry; } inline void dequeue(T* entry) { if (entry->prev) { entry->prev->next = entry->next; } else { head = entry->next; } if (entry->next) { entry->next->prev = entry->prev; } else { tail = entry->prev; } } inline T* dequeueAtHead() { T* entry = head; head = entry->next; if (head) { head->prev = NULL; } else { tail = NULL; } return entry; } uint32_t count() const; }; /* Specifies which events are to be canceled and why. */ struct CancelationOptions { enum Mode { CANCEL_ALL_EVENTS = 0, CANCEL_POINTER_EVENTS = 1, CANCEL_NON_POINTER_EVENTS = 2, CANCEL_FALLBACK_EVENTS = 3 }; // The criterion to use to determine which events should be canceled. Mode mode; // Descriptive reason for the cancelation. const char* reason; // The specific keycode of the key event to cancel, or -1 to cancel any key event. int32_t keyCode; // The specific device id of events to cancel, or -1 to cancel events from any device. int32_t deviceId; CancelationOptions(Mode mode, const char* reason) : mode(mode), reason(reason), keyCode(-1), deviceId(-1) { } }; /* Tracks dispatched key and motion event state so that cancelation events can be * synthesized when events are dropped. */ class InputState { public: InputState(); ~InputState(); // Returns true if there is no state to be canceled. bool isNeutral() const; // Returns true if the specified source is known to have received a hover enter // motion event. bool isHovering(int32_t deviceId, uint32_t source) const; // Records tracking information for a key event that has just been published. // Returns true if the event should be delivered, false if it is inconsistent // and should be skipped. bool trackKey(const KeyEntry* entry, int32_t action, int32_t flags); // Records tracking information for a motion event that has just been published. // Returns true if the event should be delivered, false if it is inconsistent // and should be skipped. bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags); // Synthesizes cancelation events for the current state and resets the tracked state. void synthesizeCancelationEvents(nsecs_t currentTime, Vector& outEvents, const CancelationOptions& options); // Clears the current state. void clear(); // Copies pointer-related parts of the input state to another instance. void copyPointerStateTo(InputState& other) const; // Gets the fallback key associated with a keycode. // Returns -1 if none. // Returns AKEYCODE_UNKNOWN if we are only dispatching the unhandled key to the policy. int32_t getFallbackKey(int32_t originalKeyCode); // Sets the fallback key for a particular keycode. void setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode); // Removes the fallback key for a particular keycode. void removeFallbackKey(int32_t originalKeyCode); inline const KeyedVector& getFallbackKeys() const { return mFallbackKeys; } private: struct KeyMemento { int32_t deviceId; uint32_t source; int32_t keyCode; int32_t scanCode; int32_t metaState; int32_t flags; nsecs_t downTime; uint32_t policyFlags; }; struct MotionMemento { int32_t deviceId; uint32_t source; int32_t flags; float xPrecision; float yPrecision; nsecs_t downTime; uint32_t pointerCount; PointerProperties pointerProperties[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; bool hovering; uint32_t policyFlags; void setPointers(const MotionEntry* entry); }; Vector mKeyMementos; Vector mMotionMementos; KeyedVector mFallbackKeys; ssize_t findKeyMemento(const KeyEntry* entry) const; ssize_t findMotionMemento(const MotionEntry* entry, bool hovering) const; void addKeyMemento(const KeyEntry* entry, int32_t flags); void addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering); static bool shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options); static bool shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options); }; /* Manages the dispatch state associated with a single input channel. */ class Connection : public RefBase { protected: virtual ~Connection(); public: enum ConnStatus { // Everything is peachy. STATUS_NORMAL, // An unrecoverable communication error has occurred. STATUS_BROKEN, // The input channel has been unregistered. STATUS_ZOMBIE }; ConnStatus status; sp inputChannel; // never null sp inputWindowHandle; // may be null bool monitor; InputPublisher inputPublisher; InputState inputState; // True if the socket is full and no further events can be published until // the application consumes some of the input. bool inputPublisherBlocked; // Queue of events that need to be published to the connection. Queue outboundQueue; // Queue of events that have been published to the connection but that have not // yet received a "finished" response from the application. Queue waitQueue; explicit Connection(const sp& inputChannel, const sp& inputWindowHandle, bool monitor); inline const char* getInputChannelName() const { return c_str(inputChannel->getName()); } const char* getWindowName() const; const char* getStatusLabel() const; DispatchEntry* findWaitQueueEntry(uint32_t seq); }; enum DropReason { DROP_REASON_NOT_DROPPED = 0, DROP_REASON_POLICY = 1, DROP_REASON_APP_SWITCH = 2, DROP_REASON_DISABLED = 3, DROP_REASON_BLOCKED = 4, DROP_REASON_STALE = 5 }; sp mPolicy; InputDispatcherConfiguration mConfig; Mutex mLock; Condition mDispatcherIsAliveCondition; sp mLooper; EventEntry* mPendingEvent; Queue mInboundQueue; Queue mCommandQueue; void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime); // Enqueues an inbound event. Returns true if mLooper->wake() should be called. bool enqueueInboundEventLocked(EventEntry* entry); // Cleans up input state when dropping an inbound event. void dropInboundEventLocked(EventEntry* entry, DropReason dropReason); // App switch latency optimization. bool mAppSwitchSawKeyDown; nsecs_t mAppSwitchDueTime; static bool isAppSwitchKeyCode(int32_t keyCode); bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry); bool isAppSwitchPendingLocked(); void resetPendingAppSwitchLocked(bool handled); // Stale event latency optimization. static bool isStaleEventLocked(nsecs_t currentTime, EventEntry* entry); // Blocked event latency optimization. Drops old events when the user intends // to transfer focus to a new application. EventEntry* mNextUnblockedEvent; sp findTouchedWindowAtLocked(int32_t x, int32_t y); // All registered connections mapped by channel file descriptor. KeyedVector > mConnectionsByFd; ssize_t getConnectionIndexLocked(const sp& inputChannel); // Input channels that will receive a copy of all input events. Vector > mMonitoringChannels; // Event injection and synchronization. Condition mInjectionResultAvailableCondition; bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult); Condition mInjectionSyncFinishedCondition; void incrementPendingForegroundDispatchesLocked(EventEntry* entry); void decrementPendingForegroundDispatchesLocked(EventEntry* entry); // Key repeat tracking. struct KeyRepeatState { KeyEntry* lastKeyEntry; // or null if no repeat nsecs_t nextRepeatTime; } mKeyRepeatState; void resetKeyRepeatLocked(); KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime); // Deferred command processing. bool runCommandsLockedInterruptible(); CommandEntry* postCommandLocked(Command command); // Inbound event processing. void drainInboundQueueLocked(); void releasePendingEventLocked(); void releaseInboundEventLocked(EventEntry* entry); // Dispatch state. bool mDispatchEnabled; bool mDispatchFrozen; bool mInputFilterEnabled; sp mEnumerator; sp getWindowHandleLocked(const sp& inputChannel) const; bool hasWindowHandleLocked(const sp& windowHandle) const; // Focus tracking for keys, trackball, etc. sp mFocusedWindowHandle; // Focus tracking for touch. struct TouchedWindow { sp windowHandle; int32_t targetFlags; IntSet pointerIds; // empty unless target flag FLAG_SPLIT is set }; struct TouchState { bool down; bool split; int32_t deviceId; // id of the device that is currently down, others are rejected uint32_t source; // source of the device that is current down, others are rejected Vector windows; TouchState(); ~TouchState(); void reset(); void copyFrom(const TouchState& other); void addOrUpdateWindow(const sp& windowHandle, int32_t targetFlags, const IntSet &pointerIds); void removeWindow(const sp& windowHandle); void filterNonAsIsTouchWindows(); sp getFirstForegroundWindowHandle() const; bool isSlippery() const; }; TouchState mTouchState; TouchState mTempTouchState; // Focused application. sp mFocusedApplicationHandle; // Dispatcher state at time of last ANR. String8 mLastANRState; // Dispatch inbound events. bool dispatchConfigurationChangedLocked( nsecs_t currentTime, ConfigurationChangedEntry* entry); bool dispatchDeviceResetLocked( nsecs_t currentTime, DeviceResetEntry* entry); bool dispatchKeyLocked( nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime); bool dispatchMotionLocked( nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime); void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry, const Vector& inputTargets); void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry); void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry); // Keeping track of ANR timeouts. enum InputTargetWaitCause { INPUT_TARGET_WAIT_CAUSE_NONE, INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY, INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY }; InputTargetWaitCause mInputTargetWaitCause; nsecs_t mInputTargetWaitStartTime; nsecs_t mInputTargetWaitTimeoutTime; bool mInputTargetWaitTimeoutExpired; sp mInputTargetWaitApplicationHandle; // Contains the last window which received a hover event. sp mLastHoverWindowHandle; // Finding targets for input events. int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, const sp& applicationHandle, const sp& windowHandle, nsecs_t* nextWakeupTime, const char* reason); void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, const sp& inputChannel); nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime); void resetANRTimeoutsLocked(); int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime); int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions); void addWindowTargetLocked(const sp& windowHandle, int32_t targetFlags, const IntSet &pointerIds, Vector& inputTargets); void addMonitoringTargetsLocked(Vector& inputTargets); bool checkInjectionPermission(const sp& windowHandle, const InjectionState* injectionState); bool isWindowObscuredAtPointLocked(const sp& windowHandle, int32_t x, int32_t y) const; bool isWindowReadyForMoreInputLocked(nsecs_t currentTime, const sp& windowHandle, const EventEntry* eventEntry); String8 getApplicationWindowLabelLocked(const sp& applicationHandle, const sp& windowHandle); // Manage the dispatch cycle for a single connection. // These methods are deliberately not Interruptible because doing all of the work // with the mutex held makes it easier to ensure that connection invariants are maintained. // If needed, the methods post commands to run later once the critical bits are done. void prepareDispatchCycleLocked(nsecs_t currentTime, const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget); void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget); void enqueueDispatchEntryLocked(const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode); void startDispatchCycleLocked(nsecs_t currentTime, const sp& connection); void finishDispatchCycleLocked(nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled); void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp& connection, bool notify); void drainDispatchQueueLocked(Queue* queue); void releaseDispatchEntryLocked(DispatchEntry* dispatchEntry); static int handleReceiveCallback(int fd, int events, void* data); void synthesizeCancelationEventsForAllConnectionsLocked( const CancelationOptions& options); void synthesizeCancelationEventsForInputChannelLocked(const sp& channel, const CancelationOptions& options); void synthesizeCancelationEventsForConnectionLocked(const sp& connection, const CancelationOptions& options); // Splitting motion events across windows. MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, const IntSet &pointerIds); // Reset and drop everything the dispatcher is doing. void resetAndDropEverythingLocked(const char* reason); // Dump state. void dumpDispatchStateLocked(String8& dump); void logDispatchStateLocked(); // Registration. void removeMonitorChannelLocked(const sp& inputChannel); status_t unregisterInputChannelLocked(const sp& inputChannel, bool notify); // Add or remove a connection to the mActiveConnections vector. void activateConnectionLocked(Connection* connection); void deactivateConnectionLocked(Connection* connection); // Interesting events that we might like to log or tell the framework about. void onDispatchCycleFinishedLocked( nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled); void onDispatchCycleBrokenLocked( nsecs_t currentTime, const sp& connection); void onANRLocked( nsecs_t currentTime, const sp& applicationHandle, const sp& windowHandle, nsecs_t eventTime, nsecs_t waitStartTime, const char* reason); // Outbound policy interactions. void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry); void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry); void doNotifyANRLockedInterruptible(CommandEntry* commandEntry); void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry); void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry); bool afterKeyEventLockedInterruptible(const sp& connection, DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled); bool afterMotionEventLockedInterruptible(const sp& connection, DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled); void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry); void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); // Statistics gathering. void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry, int32_t injectionResult, nsecs_t timeSpentWaitingForApplication); void setKeyboardFocusLocked(const sp& windowHandle); }; /* Enqueues and dispatches input events, endlessly. */ class InputDispatcherThread : public Thread { public: explicit InputDispatcherThread(const sp& dispatcher); ~InputDispatcherThread(); private: virtual bool threadLoop(); sp mDispatcher; }; } // namespace android #endif // _UI_INPUT_DISPATCHER_H ././@LongLink0000000000000000000000000000015000000000000011211 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputWindow.cppmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputWindow.0000644000015301777760000000350412322054223033346 0ustar pbusernogroup00000000000000/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "InputWindow" #include "InputWindow.h" #include namespace android { // --- InputWindowInfo --- bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { return x >= touchableRegionLeft && x <= touchableRegionRight && y >= touchableRegionTop && y <= touchableRegionBottom; } bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { return x >= frameLeft && x <= frameRight && y >= frameTop && y <= frameBottom; } bool InputWindowInfo::isTrustedOverlay() const { return layoutParamsType == TYPE_INPUT_METHOD || layoutParamsType == TYPE_INPUT_METHOD_DIALOG || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; } bool InputWindowInfo::supportsSplitTouch() const { return layoutParamsFlags & FLAG_SPLIT_TOUCH; } // --- InputWindowHandle --- InputWindowHandle::InputWindowHandle(const sp& inputApplicationHandle) : inputApplicationHandle(inputApplicationHandle), mInfo(NULL) { } InputWindowHandle::~InputWindowHandle() { delete mInfo; } void InputWindowHandle::releaseInfo() { if (mInfo) { delete mInfo; mInfo = NULL; } } } // namespace android ././@LongLink0000000000000000000000000000015300000000000011214 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputApplication.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/services/input/InputApplica0000644000015301777760000000427312322054223033376 0ustar pbusernogroup00000000000000/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _UI_INPUT_APPLICATION_H #define _UI_INPUT_APPLICATION_H #include #include #include #include namespace android { /* * Describes the properties of an application that can receive input. */ struct InputApplicationInfo { String8 name; nsecs_t dispatchingTimeout; }; /* * Handle for an application that can receive input. * * Used by the native input dispatcher as a handle for the window manager objects * that describe an application. */ class InputApplicationHandle : public RefBase { public: inline const InputApplicationInfo* getInfo() const { return mInfo; } inline String8 getName() const { return mInfo ? mInfo->name : String8(""); } inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { return mInfo ? mInfo->dispatchingTimeout : defaultValue; } /** * Requests that the state of this object be updated to reflect * the most current available information about the application. * * This method should only be called from within the input dispatcher's * critical section. * * Returns true on success, or false if the handle is no longer valid. */ virtual bool updateInfo() = 0; /** * Releases the storage used by the associated information when it is * no longer needed. */ void releaseInfo(); protected: InputApplicationHandle(); virtual ~InputApplicationHandle(); InputApplicationInfo* mInfo; }; } // namespace android #endif // _UI_INPUT_APPLICATION_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/libs/0000755000015301777760000000000012322054703027026 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/0000755000015301777760000000000012322054703027520 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/0000755000015301777760000000000012322054703031475 5ustar pbusernogroup00000000000000././@LongLink0000000000000000000000000000015300000000000011214 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/KeycodeLabels.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/KeycodeLa0000755000015301777760000001726012322054223033266 0ustar pbusernogroup00000000000000/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROIDFW_KEYCODE_LABELS_H #define _ANDROIDFW_KEYCODE_LABELS_H #include struct KeycodeLabel { const char *literal; int value; }; static const KeycodeLabel KEYCODES[] = { { "SOFT_LEFT", 1 }, { "SOFT_RIGHT", 2 }, { "HOME", 3 }, { "BACK", 4 }, { "CALL", 5 }, { "ENDCALL", 6 }, { "0", 7 }, { "1", 8 }, { "2", 9 }, { "3", 10 }, { "4", 11 }, { "5", 12 }, { "6", 13 }, { "7", 14 }, { "8", 15 }, { "9", 16 }, { "STAR", 17 }, { "POUND", 18 }, { "DPAD_UP", 19 }, { "DPAD_DOWN", 20 }, { "DPAD_LEFT", 21 }, { "DPAD_RIGHT", 22 }, { "DPAD_CENTER", 23 }, { "VOLUME_UP", 24 }, { "VOLUME_DOWN", 25 }, { "POWER", 26 }, { "CAMERA", 27 }, { "CLEAR", 28 }, { "A", 29 }, { "B", 30 }, { "C", 31 }, { "D", 32 }, { "E", 33 }, { "F", 34 }, { "G", 35 }, { "H", 36 }, { "I", 37 }, { "J", 38 }, { "K", 39 }, { "L", 40 }, { "M", 41 }, { "N", 42 }, { "O", 43 }, { "P", 44 }, { "Q", 45 }, { "R", 46 }, { "S", 47 }, { "T", 48 }, { "U", 49 }, { "V", 50 }, { "W", 51 }, { "X", 52 }, { "Y", 53 }, { "Z", 54 }, { "COMMA", 55 }, { "PERIOD", 56 }, { "ALT_LEFT", 57 }, { "ALT_RIGHT", 58 }, { "SHIFT_LEFT", 59 }, { "SHIFT_RIGHT", 60 }, { "TAB", 61 }, { "SPACE", 62 }, { "SYM", 63 }, { "EXPLORER", 64 }, { "ENVELOPE", 65 }, { "ENTER", 66 }, { "DEL", 67 }, { "GRAVE", 68 }, { "MINUS", 69 }, { "EQUALS", 70 }, { "LEFT_BRACKET", 71 }, { "RIGHT_BRACKET", 72 }, { "BACKSLASH", 73 }, { "SEMICOLON", 74 }, { "APOSTROPHE", 75 }, { "SLASH", 76 }, { "AT", 77 }, { "NUM", 78 }, { "HEADSETHOOK", 79 }, { "FOCUS", 80 }, { "PLUS", 81 }, { "MENU", 82 }, { "NOTIFICATION", 83 }, { "SEARCH", 84 }, { "MEDIA_PLAY_PAUSE", 85 }, { "MEDIA_STOP", 86 }, { "MEDIA_NEXT", 87 }, { "MEDIA_PREVIOUS", 88 }, { "MEDIA_REWIND", 89 }, { "MEDIA_FAST_FORWARD", 90 }, { "MUTE", 91 }, { "PAGE_UP", 92 }, { "PAGE_DOWN", 93 }, { "PICTSYMBOLS", 94 }, { "SWITCH_CHARSET", 95 }, { "BUTTON_A", 96 }, { "BUTTON_B", 97 }, { "BUTTON_C", 98 }, { "BUTTON_X", 99 }, { "BUTTON_Y", 100 }, { "BUTTON_Z", 101 }, { "BUTTON_L1", 102 }, { "BUTTON_R1", 103 }, { "BUTTON_L2", 104 }, { "BUTTON_R2", 105 }, { "BUTTON_THUMBL", 106 }, { "BUTTON_THUMBR", 107 }, { "BUTTON_START", 108 }, { "BUTTON_SELECT", 109 }, { "BUTTON_MODE", 110 }, { "ESCAPE", 111 }, { "FORWARD_DEL", 112 }, { "CTRL_LEFT", 113 }, { "CTRL_RIGHT", 114 }, { "CAPS_LOCK", 115 }, { "SCROLL_LOCK", 116 }, { "META_LEFT", 117 }, { "META_RIGHT", 118 }, { "FUNCTION", 119 }, { "SYSRQ", 120 }, { "BREAK", 121 }, { "MOVE_HOME", 122 }, { "MOVE_END", 123 }, { "INSERT", 124 }, { "FORWARD", 125 }, { "MEDIA_PLAY", 126 }, { "MEDIA_PAUSE", 127 }, { "MEDIA_CLOSE", 128 }, { "MEDIA_EJECT", 129 }, { "MEDIA_RECORD", 130 }, { "F1", 131 }, { "F2", 132 }, { "F3", 133 }, { "F4", 134 }, { "F5", 135 }, { "F6", 136 }, { "F7", 137 }, { "F8", 138 }, { "F9", 139 }, { "F10", 140 }, { "F11", 141 }, { "F12", 142 }, { "NUM_LOCK", 143 }, { "NUMPAD_0", 144 }, { "NUMPAD_1", 145 }, { "NUMPAD_2", 146 }, { "NUMPAD_3", 147 }, { "NUMPAD_4", 148 }, { "NUMPAD_5", 149 }, { "NUMPAD_6", 150 }, { "NUMPAD_7", 151 }, { "NUMPAD_8", 152 }, { "NUMPAD_9", 153 }, { "NUMPAD_DIVIDE", 154 }, { "NUMPAD_MULTIPLY", 155 }, { "NUMPAD_SUBTRACT", 156 }, { "NUMPAD_ADD", 157 }, { "NUMPAD_DOT", 158 }, { "NUMPAD_COMMA", 159 }, { "NUMPAD_ENTER", 160 }, { "NUMPAD_EQUALS", 161 }, { "NUMPAD_LEFT_PAREN", 162 }, { "NUMPAD_RIGHT_PAREN", 163 }, { "VOLUME_MUTE", 164 }, { "INFO", 165 }, { "CHANNEL_UP", 166 }, { "CHANNEL_DOWN", 167 }, { "ZOOM_IN", 168 }, { "ZOOM_OUT", 169 }, { "TV", 170 }, { "WINDOW", 171 }, { "GUIDE", 172 }, { "DVR", 173 }, { "BOOKMARK", 174 }, { "CAPTIONS", 175 }, { "SETTINGS", 176 }, { "TV_POWER", 177 }, { "TV_INPUT", 178 }, { "STB_POWER", 179 }, { "STB_INPUT", 180 }, { "AVR_POWER", 181 }, { "AVR_INPUT", 182 }, { "PROG_RED", 183 }, { "PROG_GREEN", 184 }, { "PROG_YELLOW", 185 }, { "PROG_BLUE", 186 }, { "APP_SWITCH", 187 }, { "BUTTON_1", 188 }, { "BUTTON_2", 189 }, { "BUTTON_3", 190 }, { "BUTTON_4", 191 }, { "BUTTON_5", 192 }, { "BUTTON_6", 193 }, { "BUTTON_7", 194 }, { "BUTTON_8", 195 }, { "BUTTON_9", 196 }, { "BUTTON_10", 197 }, { "BUTTON_11", 198 }, { "BUTTON_12", 199 }, { "BUTTON_13", 200 }, { "BUTTON_14", 201 }, { "BUTTON_15", 202 }, { "BUTTON_16", 203 }, { "LANGUAGE_SWITCH", 204 }, { "MANNER_MODE", 205 }, { "3D_MODE", 206 }, { "CONTACTS", 207 }, { "CALENDAR", 208 }, { "MUSIC", 209 }, { "CALCULATOR", 210 }, { "ZENKAKU_HANKAKU", 211 }, { "EISU", 212 }, { "MUHENKAN", 213 }, { "HENKAN", 214 }, { "KATAKANA_HIRAGANA", 215 }, { "YEN", 216 }, { "RO", 217 }, { "KANA", 218 }, { "ASSIST", 219 }, // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. { NULL, 0 } }; // NOTE: If you edit these flags, also edit policy flags in Input.h. static const KeycodeLabel FLAGS[] = { { "WAKE", 0x00000001 }, { "WAKE_DROPPED", 0x00000002 }, { "SHIFT", 0x00000004 }, { "CAPS_LOCK", 0x00000008 }, { "ALT", 0x00000010 }, { "ALT_GR", 0x00000020 }, { "MENU", 0x00000040 }, { "LAUNCHER", 0x00000080 }, { "VIRTUAL", 0x00000100 }, { "FUNCTION", 0x00000200 }, { NULL, 0 } }; static const KeycodeLabel AXES[] = { { "X", 0 }, { "Y", 1 }, { "PRESSURE", 2 }, { "SIZE", 3 }, { "TOUCH_MAJOR", 4 }, { "TOUCH_MINOR", 5 }, { "TOOL_MAJOR", 6 }, { "TOOL_MINOR", 7 }, { "ORIENTATION", 8 }, { "VSCROLL", 9 }, { "HSCROLL", 10 }, { "Z", 11 }, { "RX", 12 }, { "RY", 13 }, { "RZ", 14 }, { "HAT_X", 15 }, { "HAT_Y", 16 }, { "LTRIGGER", 17 }, { "RTRIGGER", 18 }, { "THROTTLE", 19 }, { "RUDDER", 20 }, { "WHEEL", 21 }, { "GAS", 22 }, { "BRAKE", 23 }, { "DISTANCE", 24 }, { "TILT", 25 }, { "GENERIC_1", 32 }, { "GENERIC_2", 33 }, { "GENERIC_3", 34 }, { "GENERIC_4", 35 }, { "GENERIC_5", 36 }, { "GENERIC_6", 37 }, { "GENERIC_7", 38 }, { "GENERIC_8", 39 }, { "GENERIC_9", 40 }, { "GENERIC_10", 41 }, { "GENERIC_11", 42 }, { "GENERIC_12", 43 }, { "GENERIC_13", 44 }, { "GENERIC_14", 45 }, { "GENERIC_15", 46 }, { "GENERIC_16", 47 }, // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. { NULL, -1 } }; #endif // _ANDROIDFW_KEYCODE_LABELS_H ././@LongLink0000000000000000000000000000015100000000000011212 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/InputDevice.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/InputDevi0000644000015301777760000001223512322054223033327 0ustar pbusernogroup00000000000000/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROIDFW_INPUT_DEVICE_H #define _ANDROIDFW_INPUT_DEVICE_H #include #include namespace android { /* * Identifies a device. */ struct InputDeviceIdentifier { inline InputDeviceIdentifier() : bus(0), vendor(0), product(0), version(0) { } // Information provided by the kernel. String8 name; String8 location; String8 uniqueId; uint16_t bus; uint16_t vendor; uint16_t product; uint16_t version; // A composite input device descriptor string that uniquely identifies the device // even across reboots or reconnections. The value of this field is used by // upper layers of the input system to associate settings with individual devices. // It is hashed from whatever kernel provided information is available. // Ideally, the way this value is computed should not change between Android releases // because that would invalidate persistent settings that rely on it. String8 descriptor; }; /* * Describes the characteristics and capabilities of an input device. */ class InputDeviceInfo { public: InputDeviceInfo(); InputDeviceInfo(const InputDeviceInfo& other); ~InputDeviceInfo(); struct MotionRange { int32_t axis; uint32_t source; float min; float max; float flat; float fuzz; }; void initialize(int32_t id, int32_t generation, const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal); inline int32_t getId() const { return mId; } inline int32_t getGeneration() const { return mGeneration; } inline const InputDeviceIdentifier& getIdentifier() const { return mIdentifier; } inline const String8& getAlias() const { return mAlias; } inline const String8& getDisplayName() const { return isEmpty(mAlias) ? mIdentifier.name : mAlias; } inline bool isExternal() const { return mIsExternal; } inline uint32_t getSources() const { return mSources; } const MotionRange* getMotionRange(int32_t axis, uint32_t source) const; void addSource(uint32_t source); void addMotionRange(int32_t axis, uint32_t source, float min, float max, float flat, float fuzz); void addMotionRange(const MotionRange& range); inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } inline int32_t getKeyboardType() const { return mKeyboardType; } inline void setKeyCharacterMap(const sp& value) { mKeyCharacterMap = value; } inline sp getKeyCharacterMap() const { return mKeyCharacterMap; } inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; } inline bool hasVibrator() const { return mHasVibrator; } inline const Vector& getMotionRanges() const { return mMotionRanges; } private: int32_t mId; int32_t mGeneration; InputDeviceIdentifier mIdentifier; String8 mAlias; bool mIsExternal; uint32_t mSources; int32_t mKeyboardType; sp mKeyCharacterMap; bool mHasVibrator; Vector mMotionRanges; }; /* Types of input device configuration files. */ enum InputDeviceConfigurationFileType { INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2 /* .kcm file */ }; /* * Gets the path of an input device configuration file, if one is available. * Considers both system provided and user installed configuration files. * * The device identifier is used to construct several default configuration file * names to try based on the device name, vendor, product, and version. * * Returns an empty string if not found. */ extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( const InputDeviceIdentifier& deviceIdentifier, InputDeviceConfigurationFileType type); /* * Gets the path of an input device configuration file, if one is available. * Considers both system provided and user installed configuration files. * * The name is case-sensitive and is used to construct the filename to resolve. * All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores. * * Returns an empty string if not found. */ extern String8 getInputDeviceConfigurationFilePathByName( const String8& name, InputDeviceConfigurationFileType type); } // namespace android #endif // _ANDROIDFW_INPUT_DEVICE_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/Input.h0000644000015301777760000004401312322054223032744 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROIDFW_INPUT_H #define _ANDROIDFW_INPUT_H /** * Native input event structures. */ #include #include #include #include #include #include #ifdef HAVE_ANDROID_OS class SkMatrix; #endif /* * Additional private constants not defined in ndk/ui/input.h. */ enum { /* Private control to determine when an app is tracking a key sequence. */ AKEY_EVENT_FLAG_START_TRACKING = 0x40000000, /* Key event is inconsistent with previously sent key events. */ AKEY_EVENT_FLAG_TAINTED = 0x80000000 }; enum { /* Motion event is inconsistent with previously sent motion events. */ AMOTION_EVENT_FLAG_TAINTED = 0x80000000 }; enum { /* * Indicates that an input device has switches. * This input source flag is hidden from the API because switches are only used by the system * and applications have no way to interact with them. */ AINPUT_SOURCE_SWITCH = 0x80000000 }; /* * SystemUiVisibility constants from View. */ enum { ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE = 0, ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN = 0x00000001 }; /* * Maximum number of pointers supported per motion event. * Smallest number of pointers is 1. * (We want at least 10 but some touch controllers obstensibly configured for 10 pointers * will occasionally emit 11. There is not much harm making this constant bigger.) */ #define MAX_POINTERS 16 /* * Maximum pointer id value supported in a motion event. * Smallest pointer id is 0. * Any reasonably large value that fits in a int32_t is fine. * A "reasonably large" number is one that guarantees uniqueness of a touch id for some 30 seconds * after its corresponding touch point has physically ended, under very heavy usage (many * simultaneous taps ongoing). */ #define MAX_POINTER_ID 100000000 /* * Declare a concrete type for the NDK's input event forward declaration. */ struct AInputEvent { virtual ~AInputEvent() { } }; /* * Declare a concrete type for the NDK's input device forward declaration. */ struct AInputDevice { virtual ~AInputDevice() { } }; namespace android { #ifdef HAVE_ANDROID_OS class Parcel; #endif /* * Flags that flow alongside events in the input dispatch system to help with certain * policy decisions such as waking from device sleep. * * These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java. */ enum { /* These flags originate in RawEvents and are generally set in the key map. * NOTE: If you edit these flags, also edit labels in KeycodeLabels.h. */ POLICY_FLAG_WAKE = 0x00000001, POLICY_FLAG_WAKE_DROPPED = 0x00000002, POLICY_FLAG_SHIFT = 0x00000004, POLICY_FLAG_CAPS_LOCK = 0x00000008, POLICY_FLAG_ALT = 0x00000010, POLICY_FLAG_ALT_GR = 0x00000020, POLICY_FLAG_MENU = 0x00000040, POLICY_FLAG_LAUNCHER = 0x00000080, POLICY_FLAG_VIRTUAL = 0x00000100, POLICY_FLAG_FUNCTION = 0x00000200, POLICY_FLAG_RAW_MASK = 0x0000ffff, /* These flags are set by the input dispatcher. */ // Indicates that the input event was injected. POLICY_FLAG_INJECTED = 0x01000000, // Indicates that the input event is from a trusted source such as a directly attached // input device or an application with system-wide event injection permission. POLICY_FLAG_TRUSTED = 0x02000000, // Indicates that the input event has passed through an input filter. POLICY_FLAG_FILTERED = 0x04000000, // Disables automatic key repeating behavior. POLICY_FLAG_DISABLE_KEY_REPEAT = 0x08000000, /* These flags are set by the input reader policy as it intercepts each event. */ // Indicates that the screen was off when the event was received and the event // should wake the device. POLICY_FLAG_WOKE_HERE = 0x10000000, // Indicates that the screen was dim when the event was received and the event // should brighten the device. POLICY_FLAG_BRIGHT_HERE = 0x20000000, // Indicates that the event should be dispatched to applications. // The input event should still be sent to the InputDispatcher so that it can see all // input events received include those that it will not deliver. POLICY_FLAG_PASS_TO_USER = 0x40000000 }; /* * Pointer coordinate data. */ struct PointerCoords { enum { MAX_AXES = 14 }; // 14 so that sizeof(PointerCoords) == 64 // Bitfield of axes that are present in this structure. uint64_t bits; // Values of axes that are stored in this structure packed in order by axis id // for each axis that is present in the structure according to 'bits'. float values[MAX_AXES]; inline void clear() { bits = 0; } float getAxisValue(int32_t axis) const; status_t setAxisValue(int32_t axis, float value); void scale(float scale); inline float getX() const { return getAxisValue(AMOTION_EVENT_AXIS_X); } inline float getY() const { return getAxisValue(AMOTION_EVENT_AXIS_Y); } #ifdef HAVE_ANDROID_OS status_t readFromParcel(Parcel* parcel); status_t writeToParcel(Parcel* parcel) const; #endif bool operator==(const PointerCoords& other) const; inline bool operator!=(const PointerCoords& other) const { return !(*this == other); } void copyFrom(const PointerCoords& other); private: void tooManyAxes(int axis); }; /* * Pointer property data. */ struct PointerProperties { // The id of the pointer. int32_t id; // The pointer tool type. int32_t toolType; inline void clear() { id = -1; toolType = 0; } bool operator==(const PointerProperties& other) const; inline bool operator!=(const PointerProperties& other) const { return !(*this == other); } void copyFrom(const PointerProperties& other); }; /* * Input events. */ class InputEvent : public AInputEvent { public: virtual ~InputEvent() { } virtual int32_t getType() const = 0; inline int32_t getDeviceId() const { return mDeviceId; } inline int32_t getSource() const { return mSource; } inline void setSource(int32_t source) { mSource = source; } protected: void initialize(int32_t deviceId, int32_t source); void initialize(const InputEvent& from); int32_t mDeviceId; int32_t mSource; }; /* * Key events. */ class KeyEvent : public InputEvent { public: virtual ~KeyEvent() { } virtual int32_t getType() const { return AINPUT_EVENT_TYPE_KEY; } inline int32_t getAction() const { return mAction; } inline int32_t getFlags() const { return mFlags; } inline void setFlags(int32_t flags) { mFlags = flags; } inline int32_t getKeyCode() const { return mKeyCode; } inline int32_t getScanCode() const { return mScanCode; } inline int32_t getMetaState() const { return mMetaState; } inline int32_t getRepeatCount() const { return mRepeatCount; } inline nsecs_t getDownTime() const { return mDownTime; } inline nsecs_t getEventTime() const { return mEventTime; } // Return true if this event may have a default action implementation. static bool hasDefaultAction(int32_t keyCode); bool hasDefaultAction() const; // Return true if this event represents a system key. static bool isSystemKey(int32_t keyCode); bool isSystemKey() const; void initialize( int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime); void initialize(const KeyEvent& from); protected: int32_t mAction; int32_t mFlags; int32_t mKeyCode; int32_t mScanCode; int32_t mMetaState; int32_t mRepeatCount; nsecs_t mDownTime; nsecs_t mEventTime; }; /* * Motion events. */ class MotionEvent : public InputEvent { public: virtual ~MotionEvent() { } virtual int32_t getType() const { return AINPUT_EVENT_TYPE_MOTION; } inline int32_t getAction() const { return mAction; } inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; } inline int32_t getActionIndex() const { return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; } inline void setAction(int32_t action) { mAction = action; } inline int32_t getFlags() const { return mFlags; } inline void setFlags(int32_t flags) { mFlags = flags; } inline int32_t getEdgeFlags() const { return mEdgeFlags; } inline void setEdgeFlags(int32_t edgeFlags) { mEdgeFlags = edgeFlags; } inline int32_t getMetaState() const { return mMetaState; } inline void setMetaState(int32_t metaState) { mMetaState = metaState; } inline int32_t getButtonState() const { return mButtonState; } inline float getXOffset() const { return mXOffset; } inline float getYOffset() const { return mYOffset; } inline float getXPrecision() const { return mXPrecision; } inline float getYPrecision() const { return mYPrecision; } inline nsecs_t getDownTime() const { return mDownTime; } inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; } inline size_t getPointerCount() const { return mPointerProperties.size(); } inline const PointerProperties* getPointerProperties(size_t pointerIndex) const { return &mPointerProperties[pointerIndex]; } inline int32_t getPointerId(size_t pointerIndex) const { return mPointerProperties[pointerIndex].id; } inline int32_t getToolType(size_t pointerIndex) const { return mPointerProperties[pointerIndex].toolType; } inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; } const PointerCoords* getRawPointerCoords(size_t pointerIndex) const; float getRawAxisValue(int32_t axis, size_t pointerIndex) const; inline float getRawX(size_t pointerIndex) const { return getRawAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex); } inline float getRawY(size_t pointerIndex) const { return getRawAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex); } float getAxisValue(int32_t axis, size_t pointerIndex) const; inline float getX(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex); } inline float getY(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex); } inline float getPressure(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerIndex); } inline float getSize(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_SIZE, pointerIndex); } inline float getTouchMajor(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex); } inline float getTouchMinor(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex); } inline float getToolMajor(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex); } inline float getToolMinor(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex); } inline float getOrientation(size_t pointerIndex) const { return getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex); } inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; } inline nsecs_t getHistoricalEventTime(size_t historicalIndex) const { return mSampleEventTimes[historicalIndex]; } const PointerCoords* getHistoricalRawPointerCoords( size_t pointerIndex, size_t historicalIndex) const; float getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const; inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalRawAxisValue( AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex); } inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalRawAxisValue( AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex); } float getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const; inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex); } inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex); } inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_PRESSURE, pointerIndex, historicalIndex); } inline float getHistoricalSize(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_SIZE, pointerIndex, historicalIndex); } inline float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex, historicalIndex); } inline float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex, historicalIndex); } inline float getHistoricalToolMajor(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex, historicalIndex); } inline float getHistoricalToolMinor(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex, historicalIndex); } inline float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) const { return getHistoricalAxisValue( AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex); } ssize_t findPointerIndex(int32_t pointerId) const; void initialize( int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, float xOffset, float yOffset, float xPrecision, float yPrecision, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); void copyFrom(const MotionEvent* other, bool keepHistory); void addSample( nsecs_t eventTime, const PointerCoords* pointerCoords); void offsetLocation(float xOffset, float yOffset); void scale(float scaleFactor); #ifdef HAVE_ANDROID_OS void transform(const SkMatrix* matrix); status_t readFromParcel(Parcel* parcel); status_t writeToParcel(Parcel* parcel) const; #endif static bool isTouchEvent(int32_t source, int32_t action); inline bool isTouchEvent() const { return isTouchEvent(mSource, mAction); } // Low-level accessors. inline const PointerProperties* getPointerProperties() const { return mPointerProperties.array(); } inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); } inline const PointerCoords* getSamplePointerCoords() const { return mSamplePointerCoords.array(); } protected: int32_t mAction; int32_t mFlags; int32_t mEdgeFlags; int32_t mMetaState; int32_t mButtonState; float mXOffset; float mYOffset; float mXPrecision; float mYPrecision; nsecs_t mDownTime; Vector mPointerProperties; Vector mSampleEventTimes; Vector mSamplePointerCoords; }; /* * Input event factory. */ class InputEventFactoryInterface { protected: virtual ~InputEventFactoryInterface() { } public: InputEventFactoryInterface() { } virtual KeyEvent* createKeyEvent() = 0; virtual MotionEvent* createMotionEvent() = 0; }; /* * A simple input event factory implementation that uses a single preallocated instance * of each type of input event that are reused for each request. */ class PreallocatedInputEventFactory : public InputEventFactoryInterface { public: PreallocatedInputEventFactory() { } virtual ~PreallocatedInputEventFactory() { } virtual KeyEvent* createKeyEvent() { return & mKeyEvent; } virtual MotionEvent* createMotionEvent() { return & mMotionEvent; } private: KeyEvent mKeyEvent; MotionEvent mMotionEvent; }; /* * An input event factory implementation that maintains a pool of input events. */ class PooledInputEventFactory : public InputEventFactoryInterface { public: PooledInputEventFactory(size_t maxPoolSize = 20); virtual ~PooledInputEventFactory(); virtual KeyEvent* createKeyEvent(); virtual MotionEvent* createMotionEvent(); void recycle(InputEvent* event); private: const size_t mMaxPoolSize; Vector mKeyEventPool; Vector mMotionEventPool; }; } // namespace android #endif // _ANDROIDFW_INPUT_H ././@LongLink0000000000000000000000000000015300000000000011214 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/GenericKeyMap.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/GenericKe0000644000015301777760000000233312322054223033252 0ustar pbusernogroup00000000000000// Copyright (C) 2010 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // Generic key layout file for full alphabetic US English PC style // external keyboards. This file is intentionally very generic and is // intended to support a broad rang of keyboards. Do not edit the // generic key layout to support a specific keyboard; instead, create // a new key layout file with the required keyboard configuration. // Taken from android source tree Generic.kl and Generic.kcm #ifndef GENERIC_KEY_MAP_H_ #define GENERIC_KEY_MAP_H_ namespace android { struct GenericKeyMap { static const char* key_layout_contents(); static const char* keymap_contents(); }; } #endif // GENERIC_KEY_MAP_H_ ././@LongLink0000000000000000000000000000015400000000000011215 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/InputTransport.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/InputTran0000644000015301777760000003617112322054223033351 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROIDFW_INPUT_TRANSPORT_H #define _ANDROIDFW_INPUT_TRANSPORT_H /** * Native input transport. * * The InputChannel provides a mechanism for exchanging InputMessage structures across processes. * * The InputPublisher and InputConsumer each handle one end-point of an input channel. * The InputPublisher is used by the input dispatcher to send events to the application. * The InputConsumer is used by the application to receive events from the input dispatcher. */ #include #include #include #include #include #include #include // C++ std lib #include namespace android { /* * Intermediate representation used to send input events and related signals. */ struct InputMessage { InputMessage(); enum { TYPE_KEY = 1, TYPE_MOTION = 2, TYPE_FINISHED = 3 }; struct Header { uint32_t type; uint32_t padding; // 8 byte alignment for the body that follows } header; union Body { struct Key { uint32_t seq; nsecs_t eventTime; int32_t deviceId; int32_t source; int32_t action; int32_t flags; int32_t keyCode; int32_t scanCode; int32_t metaState; int32_t repeatCount; nsecs_t downTime; inline size_t size() const { return sizeof(Key); } } key; struct Motion { uint32_t seq; nsecs_t eventTime; int32_t deviceId; int32_t source; int32_t action; int32_t flags; int32_t metaState; int32_t buttonState; int32_t edgeFlags; nsecs_t downTime; float xOffset; float yOffset; float xPrecision; float yPrecision; size_t pointerCount; struct Pointer { PointerProperties properties; PointerCoords coords; } pointers[MAX_POINTERS]; int32_t getActionId() const { uint32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; return pointers[index].properties.id; } inline size_t size() const { return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS + sizeof(Pointer) * pointerCount; } } motion; struct Finished { uint32_t seq; bool handled; inline size_t size() const { return sizeof(Finished); } } finished; } body; bool isValid(size_t actualSize) const; size_t size() const; }; /* * An input channel consists of a local unix domain socket used to send and receive * input messages across processes. Each channel has a descriptive name for debugging purposes. * * Each endpoint has its own InputChannel object that specifies its file descriptor. * * The input channel is closed when all references to it are released. */ class InputChannel : public RefBase { protected: virtual ~InputChannel(); public: InputChannel(const String8& name, int fd); /* Creates a pair of input channels. * * Returns OK on success. */ static status_t openInputFdPair(int& server_fd, int& client_fd); inline String8 getName() const { return mName; } inline int getFd() const { return mFd; } /* Sends a message to the other endpoint. * * If the channel is full then the message is guaranteed not to have been sent at all. * Try again after the consumer has sent a finished signal indicating that it has * consumed some of the pending messages from the channel. * * Returns OK on success. * Returns WOULD_BLOCK if the channel is full. * Returns DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ status_t sendMessage(const InputMessage* msg); /* Receives a message sent by the other endpoint. * * If there is no message present, try again after poll() indicates that the fd * is readable. * * Returns OK on success. * Returns WOULD_BLOCK if there is no message present. * Returns DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ status_t receiveMessage(InputMessage* msg); private: String8 mName; int mFd; }; /* * Publishes input events to an input channel. */ class InputPublisher { public: /* Creates a publisher associated with an input channel. */ explicit InputPublisher(const sp& channel); /* Destroys the publisher and releases its input channel. */ ~InputPublisher(); /* Gets the underlying input channel. */ inline sp getChannel() { return mChannel; } /* Publishes a key event to the input channel. * * Returns OK on success. * Returns WOULD_BLOCK if the channel is full. * Returns DEAD_OBJECT if the channel's peer has been closed. * Returns BAD_VALUE if seq is 0. * Other errors probably indicate that the channel is broken. */ status_t publishKeyEvent( uint32_t seq, int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime); /* Publishes a motion event to the input channel. * * Returns OK on success. * Returns WOULD_BLOCK if the channel is full. * Returns DEAD_OBJECT if the channel's peer has been closed. * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS. * Other errors probably indicate that the channel is broken. */ status_t publishMotionEvent( uint32_t seq, int32_t deviceId, int32_t source, int32_t action, int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState, float xOffset, float yOffset, float xPrecision, float yPrecision, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); /* Receives the finished signal from the consumer in reply to the original dispatch signal. * If a signal was received, returns the message sequence number, * and whether the consumer handled the message. * * The returned sequence number is never 0 unless the operation failed. * * Returns OK on success. * Returns WOULD_BLOCK if there is no signal present. * Returns DEAD_OBJECT if the channel's peer has been closed. * Other errors probably indicate that the channel is broken. */ status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled); private: sp mChannel; }; /* * Consumes input events from an input channel. */ class InputConsumer { public: /* Creates a consumer associated with an input channel. */ explicit InputConsumer(const sp& channel); /* Destroys the consumer and releases its input channel. */ ~InputConsumer(); /* Gets the underlying input channel. */ inline sp getChannel() { return mChannel; } /* Consumes an input event from the input channel and copies its contents into * an InputEvent object created using the specified factory. * * Tries to combine a series of move events into larger batches whenever possible. * * If consumeBatches is false, then defers consuming pending batched events if it * is possible for additional samples to be added to them later. Call hasPendingBatch() * to determine whether a pending batch is available to be consumed. * * If consumeBatches is true, then events are still batched but they are consumed * immediately as soon as the input channel is exhausted. * * The frameTime parameter specifies the time when the current display frame started * rendering in the CLOCK_MONOTONIC time base, or -1 if unknown. * * The returned sequence number is never 0 unless the operation failed. * * Returns OK on success. * Returns WOULD_BLOCK if there is no event present. * Returns DEAD_OBJECT if the channel's peer has been closed. * Returns NO_MEMORY if the event could not be created. * Other errors probably indicate that the channel is broken. */ status_t consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent); /* Sends a finished signal to the publisher to inform it that the message * with the specified sequence number has finished being process and whether * the message was handled by the consumer. * * Returns OK on success. * Returns BAD_VALUE if seq is 0. * Other errors probably indicate that the channel is broken. */ status_t sendFinishedSignal(uint32_t seq, bool handled); /* Returns true if there is a deferred event waiting. * * Should be called after calling consume() to determine whether the consumer * has a deferred event to be processed. Deferred events are somewhat special in * that they have already been removed from the input channel. If the input channel * becomes empty, the client may need to do extra work to ensure that it processes * the deferred event despite the fact that the input channel's file descriptor * is not readable. * * One option is simply to call consume() in a loop until it returns WOULD_BLOCK. * This guarantees that all deferred events will be processed. * * Alternately, the caller can call hasDeferredEvent() to determine whether there is * a deferred event waiting and then ensure that its event loop wakes up at least * one more time to consume the deferred event. */ bool hasDeferredEvent() const; /* Returns true if there is a pending batch. * * Should be called after calling consume() with consumeBatches == false to determine * whether consume() should be called again later on with consumeBatches == true. */ bool hasPendingBatch() const; private: // True if touch resampling is enabled. const bool mResampleTouch; // The input channel. sp mChannel; // The current input message. InputMessage mMsg; // True if mMsg contains a valid input message that was deferred from the previous // call to consume and that still needs to be handled. bool mMsgDeferred; // Batched motion events per device and source. struct Batch { Vector samples; }; Vector mBatches; // Touch state per device and source, only for sources of class pointer. struct History { nsecs_t eventTime; IntSet ids; std::unordered_map idToIndex; PointerCoords pointers[MAX_POINTERS]; void initializeFrom(const InputMessage* msg) { eventTime = msg->body.motion.eventTime; ids.clear(); for (size_t i = 0; i < msg->body.motion.pointerCount; i++) { uint32_t id = msg->body.motion.pointers[i].properties.id; ids.insert(id); idToIndex[id] = i; pointers[i].copyFrom(msg->body.motion.pointers[i].coords); } } const PointerCoords& getPointerById(uint32_t id) const { return pointers[idToIndex.at(id)]; } }; struct TouchState { int32_t deviceId; int32_t source; size_t historyCurrent; size_t historySize; History history[2]; History lastResample; void initialize(int32_t deviceId, int32_t source) { this->deviceId = deviceId; this->source = source; historyCurrent = 0; historySize = 0; lastResample.eventTime = 0; lastResample.ids.clear(); } void addHistory(const InputMessage* msg) { historyCurrent ^= 1; if (historySize < 2) { historySize += 1; } history[historyCurrent].initializeFrom(msg); } const History* getHistory(size_t index) const { return &history[(historyCurrent + index) & 1]; } }; Vector mTouchStates; // Chain of batched sequence numbers. When multiple input messages are combined into // a batch, we append a record here that associates the last sequence number in the // batch with the previous one. When the finished signal is sent, we traverse the // chain to individually finish all input messages that were part of the batch. struct SeqChain { uint32_t seq; // sequence number of batched input message uint32_t chain; // sequence number of previous batched input message }; Vector mSeqChains; status_t consumeBatch(InputEventFactoryInterface* factory, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent); status_t consumeSamples(InputEventFactoryInterface* factory, Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent); void updateTouchState(InputMessage* msg); void rewriteMessage(const TouchState& state, InputMessage* msg); void resampleTouchState(nsecs_t frameTime, MotionEvent* event, const InputMessage *next); ssize_t findBatch(int32_t deviceId, int32_t source) const; ssize_t findTouchState(int32_t deviceId, int32_t source) const; status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled); static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg); static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg); static void addSample(MotionEvent* event, const InputMessage* msg); static bool canAddSample(const Batch& batch, const InputMessage* msg); static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time); static bool shouldResampleTool(int32_t toolType); static bool isTouchResamplingEnabled(); }; } // namespace android #endif // _ANDROIDFW_INPUT_TRANSPORT_H ././@LongLink0000000000000000000000000000014600000000000011216 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/Keyboard.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/Keyboard.0000644000015301777760000000657112322054223033244 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROIDFW_KEYBOARD_H #define _ANDROIDFW_KEYBOARD_H #include #include #include #include #include namespace android { enum { /* Device id of the built in keyboard. */ DEVICE_ID_BUILT_IN_KEYBOARD = 0, /* Device id of a generic virtual keyboard with a full layout that can be used * to synthesize key events. */ DEVICE_ID_VIRTUAL_KEYBOARD = -1 }; class KeyLayoutMap; class KeyCharacterMap; /** * Loads the key layout map and key character map for a keyboard device. */ class KeyMap { public: String8 keyLayoutFile; sp keyLayoutMap; String8 keyCharacterMapFile; sp keyCharacterMap; KeyMap(); ~KeyMap(); status_t load(const InputDeviceIdentifier& deviceIdenfier, const PropertyMap* deviceConfiguration); // status_t loadGenericMaps(); // inline bool haveKeyLayout() const { return !isEmpty(keyLayoutFile); } inline bool haveKeyCharacterMap() const { return !isEmpty(keyCharacterMapFile); } inline bool isComplete() const { return haveKeyLayout() && haveKeyCharacterMap(); } private: bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name); status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name); status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name); String8 getPath(const InputDeviceIdentifier& deviceIdentifier, const String8& name, InputDeviceConfigurationFileType type); }; /** * Returns true if the keyboard is eligible for use as a built-in keyboard. */ extern bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration, const KeyMap* keyMap); /** * Gets a key code by its short form label, eg. "HOME". * Returns 0 if unknown. */ extern int32_t getKeyCodeByLabel(const char* label); /** * Gets a key flag by its short form label, eg. "WAKE". * Returns 0 if unknown. */ extern uint32_t getKeyFlagByLabel(const char* label); /** * Gets a axis by its short form label, eg. "X". * Returns -1 if unknown. */ extern int32_t getAxisByLabel(const char* label); /** * Gets a axis label by its id. * Returns NULL if unknown. */ extern const char* getAxisLabel(int32_t axisId); /** * Updates a meta state field when a key is pressed or released. */ extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState); /** * Returns true if a key is a meta key like ALT or CAPS_LOCK. */ extern bool isMetaKey(int32_t keyCode); } // namespace android #endif // _ANDROIDFW_KEYBOARD_H ././@LongLink0000000000000000000000000000015500000000000011216 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/KeyCharacterMap.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/KeyCharac0000644000015301777760000002066212322054223033255 0ustar pbusernogroup00000000000000/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROIDFW_KEY_CHARACTER_MAP_H #define _ANDROIDFW_KEY_CHARACTER_MAP_H #include #if HAVE_ANDROID_OS #include #endif #include #include #include #include #include #include namespace android { /** * Describes a mapping from Android key codes to characters. * Also specifies other functions of the keyboard such as the keyboard type * and key modifier semantics. * * This object is immutable after it has been loaded. */ class KeyCharacterMap : public RefBase { public: enum KeyboardType { KEYBOARD_TYPE_UNKNOWN = 0, KEYBOARD_TYPE_NUMERIC = 1, KEYBOARD_TYPE_PREDICTIVE = 2, KEYBOARD_TYPE_ALPHA = 3, KEYBOARD_TYPE_FULL = 4, KEYBOARD_TYPE_SPECIAL_FUNCTION = 5, KEYBOARD_TYPE_OVERLAY = 6 }; enum Format { // Base keyboard layout, may contain device-specific options, such as "type" declaration. FORMAT_BASE = 0, // Overlay keyboard layout, more restrictive, may be published by applications, // cannot override device-specific options. FORMAT_OVERLAY = 1, // Either base or overlay layout ok. FORMAT_ANY = 2 }; // Substitute key code and meta state for fallback action. struct FallbackAction { int32_t keyCode; int32_t metaState; }; /* Loads a key character map from a file. */ static status_t load(const String8& filename, Format format, sp* outMap); /* Loads a key character map from its string contents. */ static status_t loadContents(const String8& filename, const char* contents, Format format, sp* outMap); /* Combines a base key character map and an overlay. */ static sp combine(const sp& base, const sp& overlay); /* Returns an empty key character map. */ static sp empty(); /* Gets the keyboard type. */ int32_t getKeyboardType() const; /* Gets the primary character for this key as in the label physically printed on it. * Returns 0 if none (eg. for non-printing keys). */ char16_t getDisplayLabel(int32_t keyCode) const; /* Gets the Unicode character for the number or symbol generated by the key * when the keyboard is used as a dialing pad. * Returns 0 if no number or symbol is generated. */ char16_t getNumber(int32_t keyCode) const; /* Gets the Unicode character generated by the key and meta key modifiers. * Returns 0 if no character is generated. */ char16_t getCharacter(int32_t keyCode, int32_t metaState) const; /* Gets the fallback action to use by default if the application does not * handle the specified key. * Returns true if an action was available, false if none. */ bool getFallbackAction(int32_t keyCode, int32_t metaState, FallbackAction* outFallbackAction) const; /* Gets the first matching Unicode character that can be generated by the key, * preferring the one with the specified meta key modifiers. * Returns 0 if no matching character is generated. */ char16_t getMatch(int32_t keyCode, const char16_t* chars, size_t numChars, int32_t metaState) const; /* Gets a sequence of key events that could plausibly generate the specified * character sequence. Returns false if some of the characters cannot be generated. */ bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, Vector& outEvents) const; /* Maps a scan code and usage code to a key code, in case this key map overrides * the mapping in some way. */ status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const; #if HAVE_ANDROID_OS /* Reads a key map from a parcel. */ static sp readFromParcel(Parcel* parcel); /* Writes a key map to a parcel. */ void writeToParcel(Parcel* parcel) const; #endif protected: virtual ~KeyCharacterMap(); private: struct Behavior { Behavior(); Behavior(const Behavior& other); /* The next behavior in the list, or NULL if none. */ Behavior* next; /* The meta key modifiers for this behavior. */ int32_t metaState; /* The character to insert. */ char16_t character; /* The fallback keycode if the key is not handled. */ int32_t fallbackKeyCode; }; struct Key { Key(); Key(const Key& other); ~Key(); /* The single character label printed on the key, or 0 if none. */ char16_t label; /* The number or symbol character generated by the key, or 0 if none. */ char16_t number; /* The list of key behaviors sorted from most specific to least specific * meta key binding. */ Behavior* firstBehavior; }; class Parser { enum State { STATE_TOP = 0, STATE_KEY = 1 }; enum { PROPERTY_LABEL = 1, PROPERTY_NUMBER = 2, PROPERTY_META = 3 }; struct Property { inline Property(int32_t property = 0, int32_t metaState = 0) : property(property), metaState(metaState) { } int32_t property; int32_t metaState; }; KeyCharacterMap* mMap; Tokenizer* mTokenizer; Format mFormat; State mState; int32_t mKeyCode; public: Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format); ~Parser(); status_t parse(); private: status_t parseType(); status_t parseMap(); status_t parseMapKey(); status_t parseKey(); status_t parseKeyProperty(); status_t finishKey(Key* key); status_t parseModifier(const String8& token, int32_t* outMetaState); status_t parseCharacterLiteral(char16_t* outCharacter); }; KeyedVector mKeys; int mType; KeyedVector mKeysByScanCode; KeyedVector mKeysByUsageCode; KeyCharacterMap(); KeyCharacterMap(const KeyCharacterMap& other); bool getKey(int32_t keyCode, const Key** outKey) const; bool getKeyBehavior(int32_t keyCode, int32_t metaState, const Key** outKey, const Behavior** outBehavior) const; static bool matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState); bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const; static status_t load(Tokenizer* tokenizer, Format format, sp* outMap); static void addKey(Vector& outEvents, int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time); static void addMetaKeys(Vector& outEvents, int32_t deviceId, int32_t metaState, bool down, nsecs_t time, int32_t* currentMetaState); static bool addSingleEphemeralMetaKey(Vector& outEvents, int32_t deviceId, int32_t metaState, bool down, nsecs_t time, int32_t keyCode, int32_t keyMetaState, int32_t* currentMetaState); static void addDoubleEphemeralMetaKey(Vector& outEvents, int32_t deviceId, int32_t metaState, bool down, nsecs_t time, int32_t leftKeyCode, int32_t leftKeyMetaState, int32_t rightKeyCode, int32_t rightKeyMetaState, int32_t eitherKeyMetaState, int32_t* currentMetaState); static void addLockedMetaKey(Vector& outEvents, int32_t deviceId, int32_t metaState, nsecs_t time, int32_t keyCode, int32_t keyMetaState, int32_t* currentMetaState); }; } // namespace android #endif // _ANDROIDFW_KEY_CHARACTER_MAP_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/IntSet.h0000644000015301777760000000602712322054223033056 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Daniel d'Andrada */ #ifndef ANDROID_INTSET_H #define ANDROID_INTSET_H #include // C++ std lib #include #include #include #ifdef ANDROID_INPUT_INTSET_TEST namespace test { #endif namespace android { /* A set of integers It serves two purposes: - Provide a convenience wrapper for std::set. Because the std API is cumbersome. - Provide an API similar to the BitSet32 class that it's replacing. */ class IntSet { public: #ifdef ANDROID_INPUT_INTSET_TEST static int constructionCount; static int destructionCount; #endif IntSet(); IntSet(std::initializer_list list); virtual ~IntSet(); IntSet operator -(const IntSet &other) const; IntSet operator &(const IntSet &other) const; bool operator ==(const IntSet &other) const; std::set::iterator begin() { return stdSet.begin(); } std::set::const_iterator begin() const { return stdSet.begin(); } std::set::iterator end() { return stdSet.end(); } std::set::const_iterator end() const { return stdSet.end(); } std::set::const_iterator cbegin() const { return stdSet.cbegin(); } std::set::const_iterator cend() const { return stdSet.cend(); } void clear() { stdSet.clear(); } void insert(int32_t value) { stdSet.insert(value); } template void forEach(Func func) { std::for_each(stdSet.begin(), stdSet.end(), func); } template void forEach(Func func) const { std::for_each(stdSet.begin(), stdSet.end(), func); } void remove(int32_t value) { stdSet.erase(value); } void remove(const IntSet &values); size_t size() const { return stdSet.size(); } size_t count() const { return stdSet.size(); } bool isEmpty() const { return stdSet.empty(); } bool contains(int32_t value) const; int32_t first() const { return *stdSet.cbegin(); } // It's assumed that the given value does exist in the set size_t indexOf(int32_t value) const; std::string toString() const; private: void remove(std::set::iterator selfIterator, std::set::const_iterator otherIterator, std::set::const_iterator otherEnd); std::set stdSet; }; } // namespace android #ifdef ANDROID_INPUT_INTSET_TEST } // namespace test #endif #endif ././@LongLink0000000000000000000000000000015200000000000011213 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/KeyLayoutMap.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/KeyLayout0000644000015301777760000000606612322054223033353 0ustar pbusernogroup00000000000000/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROIDFW_KEY_LAYOUT_MAP_H #define _ANDROIDFW_KEY_LAYOUT_MAP_H #include #include #include #include #include namespace android { struct AxisInfo { enum Mode { // Axis value is reported directly. MODE_NORMAL = 0, // Axis value should be inverted before reporting. MODE_INVERT = 1, // Axis value should be split into two axes MODE_SPLIT = 2 }; // Axis mode. Mode mode; // Axis id. // When split, this is the axis used for values smaller than the split position. int32_t axis; // When split, this is the axis used for values after higher than the split position. int32_t highAxis; // The split value, or 0 if not split. int32_t splitValue; // The flat value, or -1 if none. int32_t flatOverride; AxisInfo() : mode(MODE_NORMAL), axis(-1), highAxis(-1), splitValue(0), flatOverride(-1) { } }; /** * Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes. * * This object is immutable after it has been loaded. */ class KeyLayoutMap : public RefBase { public: static status_t load(const String8& filename, sp* outMap); // static status_t load(const String8& filename, const char* contents, sp* outMap); // status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode, uint32_t* outFlags) const; status_t findScanCodesForKey(int32_t keyCode, Vector* outScanCodes) const; status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const; protected: virtual ~KeyLayoutMap(); private: // static status_t load(Tokenizer* tokenizer, sp* outMap); // struct Key { int32_t keyCode; uint32_t flags; }; KeyedVector mKeysByScanCode; KeyedVector mKeysByUsageCode; KeyedVector mAxes; KeyLayoutMap(); const Key* getKey(int32_t scanCode, int32_t usageCode) const; class Parser { KeyLayoutMap* mMap; Tokenizer* mTokenizer; public: Parser(KeyLayoutMap* map, Tokenizer* tokenizer); ~Parser(); status_t parse(); private: status_t parseKey(); status_t parseAxis(); }; }; } // namespace android #endif // _ANDROIDFW_KEY_LAYOUT_MAP_H ././@LongLink0000000000000000000000000000015300000000000011214 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/VirtualKeyMap.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/VirtualKe0000644000015301777760000000370712322054223033332 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROIDFW_VIRTUAL_KEY_MAP_H #define _ANDROIDFW_VIRTUAL_KEY_MAP_H #include #include #include #include #include #include namespace android { /* Describes a virtual key. */ struct VirtualKeyDefinition { int32_t scanCode; // configured position data, specified in display coords int32_t centerX; int32_t centerY; int32_t width; int32_t height; }; /** * Describes a collection of virtual keys on a touch screen in terms of * virtual scan codes and hit rectangles. * * This object is immutable after it has been loaded. */ class VirtualKeyMap { public: ~VirtualKeyMap(); static status_t load(const String8& filename, VirtualKeyMap** outMap); inline const Vector& getVirtualKeys() const { return mVirtualKeys; } private: class Parser { VirtualKeyMap* mMap; Tokenizer* mTokenizer; public: Parser(VirtualKeyMap* map, Tokenizer* tokenizer); ~Parser(); status_t parse(); private: bool consumeFieldDelimiterAndSkipWhitespace(); bool parseNextIntField(int32_t* outValue); }; Vector mVirtualKeys; VirtualKeyMap(); }; } // namespace android #endif // _ANDROIDFW_KEY_CHARACTER_MAP_H ././@LongLink0000000000000000000000000000015500000000000011216 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/VelocityTracker.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/VelocityT0000644000015301777760000002123612322054223033343 0ustar pbusernogroup00000000000000/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROIDFW_VELOCITY_TRACKER_H #define _ANDROIDFW_VELOCITY_TRACKER_H #include #include #include // C++ std lib #include namespace android { class VelocityTrackerStrategy; /* * Calculates the velocity of pointer movements over time. */ class VelocityTracker { public: struct Position { float x, y; }; struct Estimator { static const size_t MAX_DEGREE = 4; // Estimator time base. nsecs_t time; // Polynomial coefficients describing motion in X and Y. float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1]; // Polynomial degree (number of coefficients), or zero if no information is // available. uint32_t degree; // Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit). float confidence; inline void clear() { time = 0; degree = 0; confidence = 0; for (size_t i = 0; i <= MAX_DEGREE; i++) { xCoeff[i] = 0; yCoeff[i] = 0; } } }; // Creates a velocity tracker using the specified strategy. // If strategy is NULL, uses the default strategy for the platform. VelocityTracker(const char* strategy = NULL); ~VelocityTracker(); // Resets the velocity tracker state. void clear(); // Resets the velocity tracker state for specific pointers. // Call this method when some pointers have changed and may be reusing // an id that was assigned to a different pointer earlier. void clearPointers(const IntSet &ids); // Adds movement information for a set of pointers. // The ids set specifies the pointer ids of the pointers whose positions // are included in the movement. // The positions array contains position information for each pointer in order by // increasing id. Its size should be equal to the size of ids. void addMovement(nsecs_t eventTime, const IntSet &ids, const Position* positions); // Adds movement information for all pointers in a MotionEvent, including historical samples. void addMovement(const MotionEvent* event); // Gets the velocity of the specified pointer id in position units per second. // Returns false and sets the velocity components to zero if there is // insufficient movement information for the pointer. bool getVelocity(uint32_t id, float* outVx, float* outVy) const; // Gets an estimator for the recent movements of the specified pointer id. // Returns false and clears the estimator if there is no information available // about the pointer. bool getEstimator(uint32_t id, Estimator* outEstimator) const; // Gets the active pointer id, or -1 if none. inline int32_t getActivePointerId() const { return mActivePointerId; } // Gets a bitset containing all pointer ids from the most recent movement. inline const IntSet &getCurrentPointerIds() const { return mCurrentPointerIds; } private: static const char* DEFAULT_STRATEGY; nsecs_t mLastEventTime; IntSet mCurrentPointerIds; int32_t mActivePointerId; VelocityTrackerStrategy* mStrategy; bool configureStrategy(const char* strategy); static VelocityTrackerStrategy* createStrategy(const char* strategy); }; /* * Implements a particular velocity tracker algorithm. */ class VelocityTrackerStrategy { protected: VelocityTrackerStrategy() { } public: virtual ~VelocityTrackerStrategy() { } virtual void clear() = 0; virtual void clearPointers(const IntSet &ids) = 0; virtual void addMovement(nsecs_t eventTime, const IntSet &ids, const VelocityTracker::Position* positions) = 0; virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0; }; /* * Velocity tracker algorithm based on least-squares linear regression. */ class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy { public: enum Weighting { // No weights applied. All data points are equally reliable. WEIGHTING_NONE, // Weight by time delta. Data points clustered together are weighted less. WEIGHTING_DELTA, // Weight such that points within a certain horizon are weighed more than those // outside of that horizon. WEIGHTING_CENTRAL, // Weight such that points older than a certain amount are weighed less. WEIGHTING_RECENT }; // Degree must be no greater than Estimator::MAX_DEGREE. LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE); virtual ~LeastSquaresVelocityTrackerStrategy(); virtual void clear(); virtual void clearPointers(const IntSet &ids); virtual void addMovement(nsecs_t eventTime, const IntSet &ids, const VelocityTracker::Position* positions); virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: // Sample horizon. // We don't use too much history by default since we want to react to quick // changes in direction. static const nsecs_t HORIZON = 100 * 1000000; // 100 ms // Number of samples to keep. static const uint32_t HISTORY_SIZE = 20; struct Movement { nsecs_t eventTime; IntSet ids; VelocityTracker::Position positions[MAX_POINTERS]; inline const VelocityTracker::Position& getPosition(uint32_t id) const { return positions[ids.indexOf(id)]; } }; float chooseWeight(uint32_t index) const; const uint32_t mDegree; const Weighting mWeighting; uint32_t mIndex; Movement mMovements[HISTORY_SIZE]; }; /* * Velocity tracker algorithm that uses an IIR filter. */ class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy { public: // Degree must be 1 or 2. IntegratingVelocityTrackerStrategy(uint32_t degree); ~IntegratingVelocityTrackerStrategy(); virtual void clear(); virtual void clearPointers(const IntSet &ids); virtual void addMovement(nsecs_t eventTime, const IntSet &ids, const VelocityTracker::Position* positions); virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: // Current state estimate for a particular pointer. struct State { nsecs_t updateTime; uint32_t degree; float xpos, xvel, xaccel; float ypos, yvel, yaccel; }; const uint32_t mDegree; IntSet mPointerIds; std::unordered_map mPointerState; // maps the id of a pointer to its state void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const; void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const; void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const; }; /* * Velocity tracker strategy used prior to ICS. */ class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy { public: LegacyVelocityTrackerStrategy(); virtual ~LegacyVelocityTrackerStrategy(); virtual void clear(); virtual void clearPointers(const IntSet &ids); virtual void addMovement(nsecs_t eventTime, const IntSet &ids, const VelocityTracker::Position* positions); virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; private: // Oldest sample to consider when calculating the velocity. static const nsecs_t HORIZON = 200 * 1000000; // 100 ms // Number of samples to keep. static const uint32_t HISTORY_SIZE = 20; // The minimum duration between samples when estimating velocity. static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms struct Movement { nsecs_t eventTime; IntSet ids; VelocityTracker::Position positions[MAX_POINTERS]; inline const VelocityTracker::Position& getPosition(uint32_t id) const { return positions[ids.indexOf(id)]; } }; uint32_t mIndex; Movement mMovements[HISTORY_SIZE]; }; } // namespace android #endif // _ANDROIDFW_VELOCITY_TRACKER_H ././@LongLink0000000000000000000000000000015500000000000011216 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/VelocityControl.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/frameworks/base/include/androidfw/VelocityC0000644000015301777760000000732312322054223033323 0ustar pbusernogroup00000000000000/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROIDFW_VELOCITY_CONTROL_H #define _ANDROIDFW_VELOCITY_CONTROL_H #include #include #include #include namespace android { /* * Specifies parameters that govern pointer or wheel acceleration. */ struct VelocityControlParameters { // A scale factor that is multiplied with the raw velocity deltas // prior to applying any other velocity control factors. The scale // factor should be used to adapt the input device resolution // (eg. counts per inch) to the output device resolution (eg. pixels per inch). // // Must be a positive value. // Default is 1.0 (no scaling). float scale; // The scaled speed at which acceleration begins to be applied. // This value establishes the upper bound of a low speed regime for // small precise motions that are performed without any acceleration. // // Must be a non-negative value. // Default is 0.0 (no low threshold). float lowThreshold; // The scaled speed at which maximum acceleration is applied. // The difference between highThreshold and lowThreshold controls // the range of speeds over which the acceleration factor is interpolated. // The wider the range, the smoother the acceleration. // // Must be a non-negative value greater than or equal to lowThreshold. // Default is 0.0 (no high threshold). float highThreshold; // The acceleration factor. // When the speed is above the low speed threshold, the velocity will scaled // by an interpolated value between 1.0 and this amount. // // Must be a positive greater than or equal to 1.0. // Default is 1.0 (no acceleration). float acceleration; VelocityControlParameters() : scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) { } VelocityControlParameters(float scale, float lowThreshold, float highThreshold, float acceleration) : scale(scale), lowThreshold(lowThreshold), highThreshold(highThreshold), acceleration(acceleration) { } }; /* * Implements mouse pointer and wheel speed control and acceleration. */ class VelocityControl { public: VelocityControl(); /* Sets the various parameters. */ void setParameters(const VelocityControlParameters& parameters); /* Resets the current movement counters to zero. * This has the effect of nullifying any acceleration. */ void reset(); /* Translates a raw movement delta into an appropriately * scaled / accelerated delta based on the current velocity. */ void move(nsecs_t eventTime, float* deltaX, float* deltaY); private: // If no movements are received within this amount of time, // we assume the movement has stopped and reset the movement counters. static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms VelocityControlParameters mParameters; nsecs_t mLastMovementTime; VelocityTracker::Position mRawPosition; VelocityTracker mVelocityTracker; IntSet mIds; }; } // namespace android #endif // _ANDROIDFW_VELOCITY_CONTROL_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/0000755000015301777760000000000012322054703024327 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/0000755000015301777760000000000012322054703025257 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/0000755000015301777760000000000012322054703026702 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/android/0000755000015301777760000000000012322054703030322 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/arch/0000755000015301777760000000000012322054703027617 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/arch/linux-x86/0000755000015301777760000000000012322054703031401 5ustar pbusernogroup00000000000000././@LongLink0000000000000000000000000000015400000000000011215 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/arch/linux-x86/AndroidConfig.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/arch/linux-x86/AndroidC0000644000015301777760000001646712322054223033022 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Android config -- "Linux". Used for desktop x86 Linux. */ #ifndef _ANDROID_CONFIG_H #define _ANDROID_CONFIG_H /* * =========================================================================== * !!! IMPORTANT !!! * =========================================================================== * * This file is included by ALL C/C++ source files. Don't put anything in * here unless you are absolutely certain it can't go anywhere else. * * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//" * comments. */ /* * Threading model. Choose one: * * HAVE_PTHREADS - use the pthreads library. * HAVE_WIN32_THREADS - use Win32 thread primitives. * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX */ #define HAVE_PTHREADS /* * Do we have the futex syscall? */ #define HAVE_FUTEX /* * Process creation model. Choose one: * * HAVE_FORKEXEC - use fork() and exec() * HAVE_WIN32_PROC - use CreateProcess() */ #define HAVE_FORKEXEC /* * Process out-of-memory adjustment. Set if running on Linux, * where we can write to /proc//oom_adj to modify the out-of-memory * badness adjustment. */ #define HAVE_OOM_ADJ /* * IPC model. Choose one: * * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget). * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap). * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping). * HAVE_ANDROID_IPC - use Android versions (?, mmap). */ #define HAVE_SYSV_IPC /* * Memory-mapping model. Choose one: * * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h * HAVE_WIN32_FILEMAP - use Win32 filemaps */ #define HAVE_POSIX_FILEMAP /* * Define this if you have */ #define HAVE_TERMIO_H 1 /* * Define this if you have */ #define HAVE_SYS_SENDFILE_H 1 /* * Define this if you build against MSVCRT.DLL */ /* #define HAVE_MS_C_RUNTIME */ /* * Define this if you have sys/uio.h */ #define HAVE_SYS_UIO_H 1 /* * Define this if your platforms implements symbolic links * in its filesystems */ #define HAVE_SYMLINKS /* * Define this if we have localtime_r(). */ #define HAVE_LOCALTIME_R 1 /* * Define this if we have gethostbyname_r(). */ #define HAVE_GETHOSTBYNAME_R /* * Define this if we have ioctl(). */ #define HAVE_IOCTL /* * Define this if we want to use WinSock. */ /* #define HAVE_WINSOCK */ /* * Define this if have clock_gettime() and friends * * Desktop Linux has this in librt, but it's broken in goobuntu, yielding * mildly or wildly inaccurate results. */ /*#define HAVE_POSIX_CLOCKS*/ /* * Define this if we have pthread_cond_timedwait_monotonic() and * clock_gettime(CLOCK_MONOTONIC). */ /* #define HAVE_TIMEDWAIT_MONOTONIC */ /* * Define this if we have linux style epoll() */ #define HAVE_EPOLL /* * Endianness of the target machine. Choose one: * * HAVE_ENDIAN_H -- have endian.h header we can include. * HAVE_LITTLE_ENDIAN -- we are little endian. * HAVE_BIG_ENDIAN -- we are big endian. */ #define HAVE_ENDIAN_H #define HAVE_LITTLE_ENDIAN /* * We need to choose between 32-bit and 64-bit off_t. All of our code should * agree on the same size. For desktop systems, use 64-bit values, * because some of our libraries (e.g. wxWidgets) expect to be built that way. */ #define _FILE_OFFSET_BITS 64 #define _LARGEFILE_SOURCE 1 /* * Define if platform has off64_t (and lseek64 and other xxx64 functions) */ #define HAVE_OFF64_T /* * Defined if we have the backtrace() call for retrieving a stack trace. * Needed for CallStack to operate; if not defined, CallStack is * non-functional. */ #define HAVE_BACKTRACE 1 /* * Defined if we have the dladdr() call for retrieving the symbol associated * with a memory address. If not defined, stack crawls will not have symbolic * information. */ #define HAVE_DLADDR 1 /* * Defined if we have the cxxabi.h header for demangling C++ symbols. If * not defined, stack crawls will be displayed with raw mangled symbols */ #define HAVE_CXXABI 0 /* * Defined if we have the gettid() system call. */ /* #define HAVE_GETTID */ /* * Defined if we have the sched_setscheduler() call */ #define HAVE_SCHED_SETSCHEDULER /* * Add any extra platform-specific defines here. */ /* * Define if we have header */ #define HAVE_MALLOC_H /* * Define if we have Linux-style non-filesystem Unix Domain Sockets */ /* * What CPU architecture does this platform use? */ #define ARCH_X86 /* * Define if we have Linux's inotify in . */ /*#define HAVE_INOTIFY 1*/ /* * Define if we have madvise() in */ #define HAVE_MADVISE 1 /* * Define if tm struct has tm_gmtoff field */ #define HAVE_TM_GMTOFF 1 /* * Define if dirent struct has d_type field */ #define HAVE_DIRENT_D_TYPE 1 /* * Define if libc includes Android system properties implementation. */ /* #define HAVE_LIBC_SYSTEM_PROPERTIES */ /* * Define if system provides a system property server (should be * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES). */ #define HAVE_SYSTEM_PROPERTY_SERVER /* * sprintf() format string for shared library naming. */ #define OS_SHARED_LIB_FORMAT_STR "lib%s.so" /* * type for the third argument to mincore(). */ #define MINCORE_POINTER_TYPE unsigned char * /* * Do we have the sigaction flag SA_NOCLDWAIT? */ #define HAVE_SA_NOCLDWAIT /* * The default path separator for the platform */ #define OS_PATH_SEPARATOR '/' /* * Is the filesystem case sensitive? */ #define OS_CASE_SENSITIVE /* * Define if exists. */ #define HAVE_SYS_SOCKET_H 1 /* * Define if the strlcpy() function exists on the system. */ /* #define HAVE_STRLCPY 1 */ /* * Define if the open_memstream() function exists on the system. */ #define HAVE_OPEN_MEMSTREAM 1 /* * Define if the BSD funopen() function exists on the system. */ /* #define HAVE_FUNOPEN 1 */ /* * Define if prctl() exists */ #define HAVE_PRCTL 1 /* * Define if writev() exists */ #define HAVE_WRITEV 1 /* * Define if exists. */ #define HAVE_STDINT_H 1 /* * Define if exists. */ #define HAVE_STDBOOL_H 1 /* * Define if exists. */ #define HAVE_SCHED_H 1 /* * Define if pread() exists */ #define HAVE_PREAD 1 /* * Define if we have st_mtim in struct stat */ #define HAVE_STAT_ST_MTIM 1 /* * Define if printf() supports %zd for size_t arguments */ #define HAVE_PRINTF_ZD 1 /* * Define to 1 if provides qsort_r() with a BSD style function prototype. */ #define HAVE_BSD_QSORT_R 0 /* * Define to 1 if provides qsort_r() with a GNU style function prototype. */ #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) #define HAVE_GNU_QSORT_R 1 #else #define HAVE_GNU_QSORT_R 0 #endif #endif /*_ANDROID_CONFIG_H*/ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/arch/ubuntu-android/0000755000015301777760000000000012322054703032557 5ustar pbusernogroup00000000000000././@LongLink0000000000000000000000000000016100000000000011213 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/arch/ubuntu-android/AndroidConfig.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/arch/ubuntu-android/And0000644000015301777760000001224312322054223033203 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Android config -- "Ubuntu". Used for Ubuntu desktop x86 Linux. */ #ifndef _ANDROID_CONFIG_H #define _ANDROID_CONFIG_H /* * =========================================================================== * !!! IMPORTANT !!! * =========================================================================== * * This file is included by ALL C/C++ source files. Don't put anything in * here unless you are absolutely certain it can't go anywhere else. * * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//" * comments. */ /* * Threading model. Choose one: * * HAVE_PTHREADS - use the pthreads library. * HAVE_WIN32_THREADS - use Win32 thread primitives. * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX */ #define HAVE_PTHREADS /* * Define this if you have */ #define HAVE_TERMIO_H 1 /* * Define this if you have */ #define HAVE_SYS_SENDFILE_H 1 /* * Define this if you build against MSVCRT.DLL */ /* #define HAVE_MS_C_RUNTIME */ /* * Define this if you have sys/uio.h */ #define HAVE_SYS_UIO_H 1 /* * Define this if we have localtime_r(). */ #define HAVE_LOCALTIME_R 1 /* * Define this if we have gethostbyname_r(). */ #define HAVE_GETHOSTBYNAME_R /* * Define this if we want to use WinSock. */ /* #define HAVE_WINSOCK */ /* * Define this if have clock_gettime() and friends * * Desktop Linux has this in librt, but it's broken in goobuntu, yielding * mildly or wildly inaccurate results. */ /*#define HAVE_POSIX_CLOCKS*/ /* * Define this if we have pthread_cond_timedwait_monotonic() and * clock_gettime(CLOCK_MONOTONIC). */ /* #define HAVE_TIMEDWAIT_MONOTONIC */ /* * We need to choose between 32-bit and 64-bit off_t. All of our code should * agree on the same size. For desktop systems, use 64-bit values, * because some of our libraries (e.g. wxWidgets) expect to be built that way. */ #define _FILE_OFFSET_BITS 64 #define _LARGEFILE_SOURCE 1 /* * Define if platform has off64_t (and lseek64 and other xxx64 functions) */ #define HAVE_OFF64_T /* * Defined if we have the cxxabi.h header for demangling C++ symbols. If * not defined, stack crawls will be displayed with raw mangled symbols */ #define HAVE_CXXABI 0 /* * Defined if we have the gettid() system call. */ /* #define HAVE_GETTID */ /* * Add any extra platform-specific defines here. */ /* * Define if we have Linux-style non-filesystem Unix Domain Sockets */ /* * What CPU architecture does this platform use? */ #define ARCH_X86 /* * Define if we have Linux's inotify in . */ /*#define HAVE_INOTIFY 1*/ /* * Define if we have madvise() in */ #define HAVE_MADVISE 1 /* * Define if tm struct has tm_gmtoff field */ #define HAVE_TM_GMTOFF 1 /* * Define if dirent struct has d_type field */ #define HAVE_DIRENT_D_TYPE 1 /* * Define if libc includes Android system properties implementation. */ /* #define HAVE_LIBC_SYSTEM_PROPERTIES */ /* * Define if system provides a system property server (should be * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES). */ #define HAVE_SYSTEM_PROPERTY_SERVER /* * sprintf() format string for shared library naming. */ #define OS_SHARED_LIB_FORMAT_STR "lib%s.so" /* * The default path separator for the platform */ #define OS_PATH_SEPARATOR '/' /* * Define if exists. */ #define HAVE_SYS_SOCKET_H 1 /* * Define if the strlcpy() function exists on the system. */ /* #define HAVE_STRLCPY 1 */ /* * Define if the open_memstream() function exists on the system. */ #define HAVE_OPEN_MEMSTREAM 1 /* * Define if the BSD funopen() function exists on the system. */ /* #define HAVE_FUNOPEN 1 */ /* * Define if prctl() exists */ #define HAVE_PRCTL 1 /* * Define if writev() exists */ #define HAVE_WRITEV 1 /* * Define if exists. */ #define HAVE_STDINT_H 1 /* * Define if exists. */ #define HAVE_STDBOOL_H 1 /* * Define if exists. */ #define HAVE_SCHED_H 1 /* * Define if pread() exists */ #define HAVE_PREAD 1 /* * Define if we have st_mtim in struct stat */ #define HAVE_STAT_ST_MTIM 1 /* * Define if printf() supports %zd for size_t arguments */ #define HAVE_PRINTF_ZD 1 /* * Define to 1 if provides qsort_r() with a BSD style function prototype. */ #define HAVE_BSD_QSORT_R 0 /* * Define to 1 if provides qsort_r() with a GNU style function prototype. */ #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) #define HAVE_GNU_QSORT_R 1 #else #define HAVE_GNU_QSORT_R 0 #endif #endif /*_ANDROID_CONFIG_H*/ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/arch/ubuntu-x86/0000755000015301777760000000000012322054703031564 5ustar pbusernogroup00000000000000././@LongLink0000000000000000000000000000015500000000000011216 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/arch/ubuntu-x86/AndroidConfig.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/arch/ubuntu-x86/Android0000644000015301777760000001647712322054223033103 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Android config -- "Ubuntu". Used for Ubuntu desktop x86 Linux. */ #ifndef _ANDROID_CONFIG_H #define _ANDROID_CONFIG_H /* * =========================================================================== * !!! IMPORTANT !!! * =========================================================================== * * This file is included by ALL C/C++ source files. Don't put anything in * here unless you are absolutely certain it can't go anywhere else. * * Any C++ stuff must be wrapped with "#ifdef __cplusplus". Do not use "//" * comments. */ /* * Threading model. Choose one: * * HAVE_PTHREADS - use the pthreads library. * HAVE_WIN32_THREADS - use Win32 thread primitives. * -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX */ #define HAVE_PTHREADS /* * Do we have the futex syscall? */ #define HAVE_FUTEX /* * Process creation model. Choose one: * * HAVE_FORKEXEC - use fork() and exec() * HAVE_WIN32_PROC - use CreateProcess() */ #define HAVE_FORKEXEC /* * Process out-of-memory adjustment. Set if running on Linux, * where we can write to /proc//oom_adj to modify the out-of-memory * badness adjustment. */ #define HAVE_OOM_ADJ /* * IPC model. Choose one: * * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget). * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap). * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping). * HAVE_ANDROID_IPC - use Android versions (?, mmap). */ #define HAVE_SYSV_IPC /* * Memory-mapping model. Choose one: * * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h * HAVE_WIN32_FILEMAP - use Win32 filemaps */ #define HAVE_POSIX_FILEMAP /* * Define this if you have */ #define HAVE_TERMIO_H 1 /* * Define this if you have */ #define HAVE_SYS_SENDFILE_H 1 /* * Define this if you build against MSVCRT.DLL */ /* #define HAVE_MS_C_RUNTIME */ /* * Define this if you have sys/uio.h */ #define HAVE_SYS_UIO_H 1 /* * Define this if your platforms implements symbolic links * in its filesystems */ #define HAVE_SYMLINKS /* * Define this if we have localtime_r(). */ #define HAVE_LOCALTIME_R 1 /* * Define this if we have gethostbyname_r(). */ #define HAVE_GETHOSTBYNAME_R /* * Define this if we have ioctl(). */ #define HAVE_IOCTL /* * Define this if we want to use WinSock. */ /* #define HAVE_WINSOCK */ /* * Define this if have clock_gettime() and friends * * Desktop Linux has this in librt, but it's broken in goobuntu, yielding * mildly or wildly inaccurate results. */ /*#define HAVE_POSIX_CLOCKS*/ /* * Define this if we have pthread_cond_timedwait_monotonic() and * clock_gettime(CLOCK_MONOTONIC). */ /* #define HAVE_TIMEDWAIT_MONOTONIC */ /* * Define this if we have linux style epoll() */ #define HAVE_EPOLL /* * Endianness of the target machine. Choose one: * * HAVE_ENDIAN_H -- have endian.h header we can include. * HAVE_LITTLE_ENDIAN -- we are little endian. * HAVE_BIG_ENDIAN -- we are big endian. */ #define HAVE_ENDIAN_H #define HAVE_LITTLE_ENDIAN /* * We need to choose between 32-bit and 64-bit off_t. All of our code should * agree on the same size. For desktop systems, use 64-bit values, * because some of our libraries (e.g. wxWidgets) expect to be built that way. */ #define _FILE_OFFSET_BITS 64 #define _LARGEFILE_SOURCE 1 /* * Define if platform has off64_t (and lseek64 and other xxx64 functions) */ #define HAVE_OFF64_T /* * Defined if we have the backtrace() call for retrieving a stack trace. * Needed for CallStack to operate; if not defined, CallStack is * non-functional. */ #define HAVE_BACKTRACE 1 /* * Defined if we have the dladdr() call for retrieving the symbol associated * with a memory address. If not defined, stack crawls will not have symbolic * information. */ #define HAVE_DLADDR 1 /* * Defined if we have the cxxabi.h header for demangling C++ symbols. If * not defined, stack crawls will be displayed with raw mangled symbols */ #define HAVE_CXXABI 0 /* * Defined if we have the gettid() system call. */ /* #define HAVE_GETTID */ /* * Defined if we have the sched_setscheduler() call */ #define HAVE_SCHED_SETSCHEDULER /* * Add any extra platform-specific defines here. */ /* * Define if we have header */ #define HAVE_MALLOC_H /* * Define if we have Linux-style non-filesystem Unix Domain Sockets */ /* * What CPU architecture does this platform use? */ #define ARCH_X86 /* * Define if we have Linux's inotify in . */ /*#define HAVE_INOTIFY 1*/ /* * Define if we have madvise() in */ #define HAVE_MADVISE 1 /* * Define if tm struct has tm_gmtoff field */ #define HAVE_TM_GMTOFF 1 /* * Define if dirent struct has d_type field */ #define HAVE_DIRENT_D_TYPE 1 /* * Define if libc includes Android system properties implementation. */ /* #define HAVE_LIBC_SYSTEM_PROPERTIES */ /* * Define if system provides a system property server (should be * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES). */ #define HAVE_SYSTEM_PROPERTY_SERVER /* * sprintf() format string for shared library naming. */ #define OS_SHARED_LIB_FORMAT_STR "lib%s.so" /* * type for the third argument to mincore(). */ #define MINCORE_POINTER_TYPE unsigned char * /* * Do we have the sigaction flag SA_NOCLDWAIT? */ #define HAVE_SA_NOCLDWAIT /* * The default path separator for the platform */ #define OS_PATH_SEPARATOR '/' /* * Is the filesystem case sensitive? */ #define OS_CASE_SENSITIVE /* * Define if exists. */ #define HAVE_SYS_SOCKET_H 1 /* * Define if the strlcpy() function exists on the system. */ /* #define HAVE_STRLCPY 1 */ /* * Define if the open_memstream() function exists on the system. */ #define HAVE_OPEN_MEMSTREAM 1 /* * Define if the BSD funopen() function exists on the system. */ /* #define HAVE_FUNOPEN 1 */ /* * Define if prctl() exists */ #define HAVE_PRCTL 1 /* * Define if writev() exists */ #define HAVE_WRITEV 1 /* * Define if exists. */ #define HAVE_STDINT_H 1 /* * Define if exists. */ #define HAVE_STDBOOL_H 1 /* * Define if exists. */ #define HAVE_SCHED_H 1 /* * Define if pread() exists */ #define HAVE_PREAD 1 /* * Define if we have st_mtim in struct stat */ #define HAVE_STAT_ST_MTIM 1 /* * Define if printf() supports %zd for size_t arguments */ #define HAVE_PRINTF_ZD 1 /* * Define to 1 if provides qsort_r() with a BSD style function prototype. */ #define HAVE_BSD_QSORT_R 0 /* * Define to 1 if provides qsort_r() with a GNU style function prototype. */ #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) #define HAVE_GNU_QSORT_R 1 #else #define HAVE_GNU_QSORT_R 0 #endif #endif /*_ANDROID_CONFIG_H*/ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/cutils/0000755000015301777760000000000012322054703030205 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/cutils/threads.h0000644000015301777760000000773312322054223032017 0ustar pbusernogroup00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _LIBS_CUTILS_THREADS_H #define _LIBS_CUTILS_THREADS_H #ifdef __cplusplus extern "C" { #endif /***********************************************************************/ /***********************************************************************/ /***** *****/ /***** local thread storage *****/ /***** *****/ /***********************************************************************/ /***********************************************************************/ #ifdef HAVE_PTHREADS #include typedef struct { pthread_mutex_t lock; int has_tls; pthread_key_t tls; } thread_store_t; #define THREAD_STORE_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, 0 } #elif defined HAVE_WIN32_THREADS #include typedef struct { int lock_init; int has_tls; DWORD tls; CRITICAL_SECTION lock; } thread_store_t; #define THREAD_STORE_INITIALIZER { 0, 0, 0, {0, 0, 0, 0, 0, 0} } #else # error "no thread_store_t implementation for your platform !!" #endif typedef void (*thread_store_destruct_t)(void* value); extern void* thread_store_get(thread_store_t* store); extern void thread_store_set(thread_store_t* store, void* value, thread_store_destruct_t destroy); /***********************************************************************/ /***********************************************************************/ /***** *****/ /***** mutexes *****/ /***** *****/ /***********************************************************************/ /***********************************************************************/ #ifdef HAVE_PTHREADS typedef pthread_mutex_t mutex_t; #define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER static __inline__ void mutex_lock(mutex_t* lock) { pthread_mutex_lock(lock); } static __inline__ void mutex_unlock(mutex_t* lock) { pthread_mutex_unlock(lock); } static __inline__ int mutex_init(mutex_t* lock) { return pthread_mutex_init(lock, NULL); } static __inline__ void mutex_destroy(mutex_t* lock) { pthread_mutex_destroy(lock); } #endif #ifdef HAVE_WIN32_THREADS typedef struct { int init; CRITICAL_SECTION lock[1]; } mutex_t; #define MUTEX_INITIALIZER { 0, {{ NULL, 0, 0, NULL, NULL, 0 }} } static __inline__ void mutex_lock(mutex_t* lock) { if (!lock->init) { lock->init = 1; InitializeCriticalSection( lock->lock ); lock->init = 2; } else while (lock->init != 2) Sleep(10); EnterCriticalSection(lock->lock); } static __inline__ void mutex_unlock(mutex_t* lock) { LeaveCriticalSection(lock->lock); } static __inline__ int mutex_init(mutex_t* lock) { InitializeCriticalSection(lock->lock); lock->init = 2; return 0; } static __inline__ void mutex_destroy(mutex_t* lock) { if (lock->init) { lock->init = 0; DeleteCriticalSection(lock->lock); } } #endif #ifdef __cplusplus } #endif #endif /* _LIBS_CUTILS_THREADS_H */ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/cutils/event_tag_map.h0000644000015301777760000000241712322054223033170 0ustar pbusernogroup00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _LIBS_CUTILS_EVENTTAGMAP_H #define _LIBS_CUTILS_EVENTTAGMAP_H #ifdef __cplusplus extern "C" { #endif #define EVENT_TAG_MAP_FILE "/system/etc/event-log-tags" struct EventTagMap; typedef struct EventTagMap EventTagMap; /* * Open the specified file as an event log tag map. * * Returns NULL on failure. */ EventTagMap* android_openEventTagMap(const char* fileName); /* * Close the map. */ void android_closeEventTagMap(EventTagMap* map); /* * Look up a tag by index. Returns the tag string, or NULL if not found. */ const char* android_lookupEventTag(const EventTagMap* map, int tag); #ifdef __cplusplus } #endif #endif /*_LIBS_CUTILS_EVENTTAGMAP_H*/ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/cutils/atomic-arm.h0000644000015301777760000001722712322054223032415 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_CUTILS_ATOMIC_ARM_H #define ANDROID_CUTILS_ATOMIC_ARM_H #include #include extern inline void android_compiler_barrier(void) { __asm__ __volatile__ ("" : : : "memory"); } #if ANDROID_SMP == 0 extern inline void android_memory_barrier(void) { android_compiler_barrier(); } extern inline void android_memory_store_barrier(void) { android_compiler_barrier(); } #elif defined(__ARM_HAVE_DMB) extern inline void android_memory_barrier(void) { __asm__ __volatile__ ("dmb" : : : "memory"); } extern inline void android_memory_store_barrier(void) { __asm__ __volatile__ ("dmb st" : : : "memory"); } #elif defined(__ARM_HAVE_LDREX_STREX) extern inline void android_memory_barrier(void) { __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory"); } extern inline void android_memory_store_barrier(void) { android_memory_barrier(); } #else extern inline void android_memory_barrier(void) { typedef void (kuser_memory_barrier)(void); (*(kuser_memory_barrier *)0xffff0fa0)(); } extern inline void android_memory_store_barrier(void) { android_memory_barrier(); } #endif extern inline int32_t android_atomic_acquire_load(volatile const int32_t *ptr) { int32_t value = *ptr; android_memory_barrier(); return value; } extern inline int32_t android_atomic_release_load(volatile const int32_t *ptr) { android_memory_barrier(); return *ptr; } extern inline void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr) { *ptr = value; android_memory_barrier(); } extern inline void android_atomic_release_store(int32_t value, volatile int32_t *ptr) { android_memory_barrier(); *ptr = value; } #if defined(__thumb__) extern int android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr); #elif defined(__ARM_HAVE_LDREX_STREX) extern inline int android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) { int32_t prev, status; do { __asm__ __volatile__ ("ldrex %0, [%3]\n" "mov %1, #0\n" "teq %0, %4\n" "strexeq %1, %5, [%3]" : "=&r" (prev), "=&r" (status), "+m"(*ptr) : "r" (ptr), "Ir" (old_value), "r" (new_value) : "cc"); } while (__builtin_expect(status != 0, 0)); return prev != old_value; } #else extern inline int android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) { typedef int (kuser_cmpxchg)(int32_t, int32_t, volatile int32_t *); int32_t prev, status; prev = *ptr; do { status = (*(kuser_cmpxchg *)0xffff0fc0)(old_value, new_value, ptr); if (__builtin_expect(status == 0, 1)) return 0; prev = *ptr; } while (prev == old_value); return 1; } #endif extern inline int android_atomic_acquire_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) { int status = android_atomic_cas(old_value, new_value, ptr); android_memory_barrier(); return status; } extern inline int android_atomic_release_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) { android_memory_barrier(); return android_atomic_cas(old_value, new_value, ptr); } #if defined(__thumb__) extern int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr); #elif defined(__ARM_HAVE_LDREX_STREX) extern inline int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) { int32_t prev, tmp, status; android_memory_barrier(); do { __asm__ __volatile__ ("ldrex %0, [%4]\n" "add %1, %0, %5\n" "strex %2, %1, [%4]" : "=&r" (prev), "=&r" (tmp), "=&r" (status), "+m" (*ptr) : "r" (ptr), "Ir" (increment) : "cc"); } while (__builtin_expect(status != 0, 0)); return prev; } #else extern inline int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) { int32_t prev, status; android_memory_barrier(); do { prev = *ptr; status = android_atomic_cas(prev, prev + increment, ptr); } while (__builtin_expect(status != 0, 0)); return prev; } #endif extern inline int32_t android_atomic_inc(volatile int32_t *addr) { return android_atomic_add(1, addr); } extern inline int32_t android_atomic_dec(volatile int32_t *addr) { return android_atomic_add(-1, addr); } #if defined(__thumb__) extern int32_t android_atomic_and(int32_t value, volatile int32_t *ptr); #elif defined(__ARM_HAVE_LDREX_STREX) extern inline int32_t android_atomic_and(int32_t value, volatile int32_t *ptr) { int32_t prev, tmp, status; android_memory_barrier(); do { __asm__ __volatile__ ("ldrex %0, [%4]\n" "and %1, %0, %5\n" "strex %2, %1, [%4]" : "=&r" (prev), "=&r" (tmp), "=&r" (status), "+m" (*ptr) : "r" (ptr), "Ir" (value) : "cc"); } while (__builtin_expect(status != 0, 0)); return prev; } #else extern inline int32_t android_atomic_and(int32_t value, volatile int32_t *ptr) { int32_t prev, status; android_memory_barrier(); do { prev = *ptr; status = android_atomic_cas(prev, prev & value, ptr); } while (__builtin_expect(status != 0, 0)); return prev; } #endif #if defined(__thumb__) extern int32_t android_atomic_or(int32_t value, volatile int32_t *ptr); #elif defined(__ARM_HAVE_LDREX_STREX) extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr) { int32_t prev, tmp, status; android_memory_barrier(); do { __asm__ __volatile__ ("ldrex %0, [%4]\n" "orr %1, %0, %5\n" "strex %2, %1, [%4]" : "=&r" (prev), "=&r" (tmp), "=&r" (status), "+m" (*ptr) : "r" (ptr), "Ir" (value) : "cc"); } while (__builtin_expect(status != 0, 0)); return prev; } #else extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr) { int32_t prev, status; android_memory_barrier(); do { prev = *ptr; status = android_atomic_cas(prev, prev | value, ptr); } while (__builtin_expect(status != 0, 0)); return prev; } #endif #endif /* ANDROID_CUTILS_ATOMIC_ARM_H */ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/cutils/atomic-x86.h0000644000015301777760000000776512322054223032271 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_CUTILS_ATOMIC_X86_H #define ANDROID_CUTILS_ATOMIC_X86_H #include extern inline void android_compiler_barrier(void) { __asm__ __volatile__ ("" : : : "memory"); } #if ANDROID_SMP == 0 extern inline void android_memory_barrier(void) { android_compiler_barrier(); } extern inline void android_memory_store_barrier(void) { android_compiler_barrier(); } #else extern inline void android_memory_barrier(void) { __asm__ __volatile__ ("mfence" : : : "memory"); } extern inline void android_memory_store_barrier(void) { android_compiler_barrier(); } #endif extern inline int32_t android_atomic_acquire_load(volatile const int32_t *ptr) { int32_t value = *ptr; android_compiler_barrier(); return value; } extern inline int32_t android_atomic_release_load(volatile const int32_t *ptr) { android_memory_barrier(); return *ptr; } extern inline void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr) { *ptr = value; android_memory_barrier(); } extern inline void android_atomic_release_store(int32_t value, volatile int32_t *ptr) { android_compiler_barrier(); *ptr = value; } extern inline int android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) { int32_t prev; __asm__ __volatile__ ("lock; cmpxchgl %1, %2" : "=a" (prev) : "q" (new_value), "m" (*ptr), "0" (old_value) : "memory"); return prev != old_value; } extern inline int android_atomic_acquire_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) { /* Loads are not reordered with other loads. */ return android_atomic_cas(old_value, new_value, ptr); } extern inline int android_atomic_release_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) { /* Stores are not reordered with other stores. */ return android_atomic_cas(old_value, new_value, ptr); } extern inline int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) { __asm__ __volatile__ ("lock; xaddl %0, %1" : "+r" (increment), "+m" (*ptr) : : "memory"); /* increment now holds the old value of *ptr */ return increment; } extern inline int32_t android_atomic_inc(volatile int32_t *addr) { return android_atomic_add(1, addr); } extern inline int32_t android_atomic_dec(volatile int32_t *addr) { return android_atomic_add(-1, addr); } extern inline int32_t android_atomic_and(int32_t value, volatile int32_t *ptr) { int32_t prev, status; do { prev = *ptr; status = android_atomic_cas(prev, prev & value, ptr); } while (__builtin_expect(status != 0, 0)); return prev; } extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr) { int32_t prev, status; do { prev = *ptr; status = android_atomic_cas(prev, prev | value, ptr); } while (__builtin_expect(status != 0, 0)); return prev; } #endif /* ANDROID_CUTILS_ATOMIC_X86_H */ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/cutils/atomic-inline.h0000644000015301777760000000376212322054223033113 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_CUTILS_ATOMIC_INLINE_H #define ANDROID_CUTILS_ATOMIC_INLINE_H #ifdef __cplusplus extern "C" { #endif /* * Inline declarations and macros for some special-purpose atomic * operations. These are intended for rare circumstances where a * memory barrier needs to be issued inline rather than as a function * call. * * Most code should not use these. * * Anything that does include this file must set ANDROID_SMP to either * 0 or 1, indicating compilation for UP or SMP, respectively. * * Macros defined in this header: * * void ANDROID_MEMBAR_FULL(void) * Full memory barrier. Provides a compiler reordering barrier, and * on SMP systems emits an appropriate instruction. */ #if !defined(ANDROID_SMP) # error "Must define ANDROID_SMP before including atomic-inline.h" #endif #if defined(__arm__) #include #elif defined(__i386__) || defined(__x86_64__) #include #elif defined(__mips__) #include #else #error atomic operations are unsupported #endif #if ANDROID_SMP == 0 #define ANDROID_MEMBAR_FULL android_compiler_barrier #else #define ANDROID_MEMBAR_FULL android_memory_barrier #endif #if ANDROID_SMP == 0 #define ANDROID_MEMBAR_STORE android_compiler_barrier #else #define ANDROID_MEMBAR_STORE android_memory_store_barrier #endif #ifdef __cplusplus } #endif #endif /* ANDROID_CUTILS_ATOMIC_INLINE_H */ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/cutils/atomic-mips.h0000644000015301777760000001261412322054223032601 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_CUTILS_ATOMIC_MIPS_H #define ANDROID_CUTILS_ATOMIC_MIPS_H #include extern inline void android_compiler_barrier(void) { __asm__ __volatile__ ("" : : : "memory"); } #if ANDROID_SMP == 0 extern inline void android_memory_barrier(void) { android_compiler_barrier(); } extern inline void android_memory_store_barrier(void) { android_compiler_barrier(); } #else extern inline void android_memory_barrier(void) { __asm__ __volatile__ ("sync" : : : "memory"); } extern inline void android_memory_store_barrier(void) { __asm__ __volatile__ ("sync" : : : "memory"); } #endif extern inline int32_t android_atomic_acquire_load(volatile const int32_t *ptr) { int32_t value = *ptr; android_memory_barrier(); return value; } extern inline int32_t android_atomic_release_load(volatile const int32_t *ptr) { android_memory_barrier(); return *ptr; } extern inline void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr) { *ptr = value; android_memory_barrier(); } extern inline void android_atomic_release_store(int32_t value, volatile int32_t *ptr) { android_memory_barrier(); *ptr = value; } extern inline int android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) { int32_t prev, status; do { __asm__ __volatile__ ( " ll %[prev], (%[ptr])\n" " li %[status], 1\n" " bne %[prev], %[old], 9f\n" " move %[status], %[new_value]\n" " sc %[status], (%[ptr])\n" "9:\n" : [prev] "=&r" (prev), [status] "=&r" (status) : [ptr] "r" (ptr), [old] "r" (old_value), [new_value] "r" (new_value) ); } while (__builtin_expect(status == 0, 0)); return prev != old_value; } extern inline int android_atomic_acquire_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) { int status = android_atomic_cas(old_value, new_value, ptr); android_memory_barrier(); return status; } extern inline int android_atomic_release_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) { android_memory_barrier(); return android_atomic_cas(old_value, new_value, ptr); } extern inline int32_t android_atomic_swap(int32_t new_value, volatile int32_t *ptr) { int32_t prev, status; do { __asm__ __volatile__ ( " move %[status], %[new_value]\n" " ll %[prev], (%[ptr])\n" " sc %[status], (%[ptr])\n" : [prev] "=&r" (prev), [status] "=&r" (status) : [ptr] "r" (ptr), [new_value] "r" (new_value) ); } while (__builtin_expect(status == 0, 0)); android_memory_barrier(); return prev; } extern inline int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) { int32_t prev, status; android_memory_barrier(); do { __asm__ __volatile__ ( " ll %[prev], (%[ptr])\n" " addu %[status], %[prev], %[inc]\n" " sc %[status], (%[ptr])\n" : [status] "=&r" (status), [prev] "=&r" (prev) : [ptr] "r" (ptr), [inc] "Ir" (increment) ); } while (__builtin_expect(status == 0, 0)); return prev; } extern inline int32_t android_atomic_inc(volatile int32_t *addr) { return android_atomic_add(1, addr); } extern inline int32_t android_atomic_dec(volatile int32_t *addr) { return android_atomic_add(-1, addr); } extern inline int32_t android_atomic_and(int32_t value, volatile int32_t *ptr) { int32_t prev, status; android_memory_barrier(); do { __asm__ __volatile__ ( " ll %[prev], (%[ptr])\n" " and %[status], %[prev], %[value]\n" " sc %[status], (%[ptr])\n" : [prev] "=&r" (prev), [status] "=&r" (status) : [ptr] "r" (ptr), [value] "Ir" (value) ); } while (__builtin_expect(status == 0, 0)); return prev; } extern inline int32_t android_atomic_or(int32_t value, volatile int32_t *ptr) { int32_t prev, status; android_memory_barrier(); do { __asm__ __volatile__ ( " ll %[prev], (%[ptr])\n" " or %[status], %[prev], %[value]\n" " sc %[status], (%[ptr])\n" : [prev] "=&r" (prev), [status] "=&r" (status) : [ptr] "r" (ptr), [value] "Ir" (value) ); } while (__builtin_expect(status == 0, 0)); return prev; } #endif /* ANDROID_CUTILS_ATOMIC_MIPS_H */ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/cutils/sockets.h0000644000015301777760000000655712322054223032043 0ustar pbusernogroup00000000000000/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __CUTILS_SOCKETS_H #define __CUTILS_SOCKETS_H #include #include #include #include #ifdef HAVE_WINSOCK #include typedef int socklen_t; #elif HAVE_SYS_SOCKET_H #include #endif #define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_" #define ANDROID_SOCKET_DIR "/dev/socket" #ifdef __cplusplus extern "C" { #endif /* * android_get_control_socket - simple helper function to get the file * descriptor of our init-managed Unix domain socket. `name' is the name of the * socket, as given in init.rc. Returns -1 on error. * * This is inline and not in libcutils proper because we want to use this in * third-party daemons with minimal modification. */ static inline int android_get_control_socket(const char *name) { char key[64] = ANDROID_SOCKET_ENV_PREFIX; const char *val; int fd; /* build our environment variable, counting cycles like a wolf ... */ #if HAVE_STRLCPY strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); #else /* for the host, which may lack the almightly strncpy ... */ strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX)); key[sizeof(key)-1] = '\0'; #endif val = getenv(key); if (!val) return -1; errno = 0; fd = strtol(val, NULL, 10); if (errno) return -1; return fd; } /* * See also android.os.LocalSocketAddress.Namespace */ // Linux "abstract" (non-filesystem) namespace #define ANDROID_SOCKET_NAMESPACE_ABSTRACT 0 // Android "reserved" (/dev/socket) namespace #define ANDROID_SOCKET_NAMESPACE_RESERVED 1 // Normal filesystem namespace #define ANDROID_SOCKET_NAMESPACE_FILESYSTEM 2 extern int socket_loopback_client(int port, int type); extern int socket_network_client(const char *host, int port, int type); extern int socket_loopback_server(int port, int type); extern int socket_local_server(const char *name, int namespaceId, int type); extern int socket_local_server_bind(int s, const char *name, int namespaceId); extern int socket_local_client_connect(int fd, const char *name, int namespaceId, int type); extern int socket_local_client(const char *name, int namespaceId, int type); extern int socket_inaddr_any_server(int port, int type); /* * socket_peer_is_trusted - Takes a socket which is presumed to be a * connected local socket (e.g. AF_LOCAL) and returns whether the peer * (the userid that owns the process on the other end of that socket) * is one of the two trusted userids, root or shell. * * Note: This only works as advertised on the Android OS and always * just returns true when called on other operating systems. */ extern bool socket_peer_is_trusted(int fd); #ifdef __cplusplus } #endif #endif /* __CUTILS_SOCKETS_H */ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/cutils/logprint.h0000644000015301777760000000724412322054223032220 0ustar pbusernogroup00000000000000/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _LOGPRINT_H #define _LOGPRINT_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif typedef enum { FORMAT_OFF = 0, FORMAT_BRIEF, FORMAT_PROCESS, FORMAT_TAG, FORMAT_THREAD, FORMAT_RAW, FORMAT_TIME, FORMAT_THREADTIME, FORMAT_LONG, } AndroidLogPrintFormat; typedef struct AndroidLogFormat_t AndroidLogFormat; typedef struct AndroidLogEntry_t { time_t tv_sec; long tv_nsec; android_LogPriority priority; int32_t pid; int32_t tid; const char * tag; size_t messageLen; const char * message; } AndroidLogEntry; AndroidLogFormat *android_log_format_new(); void android_log_format_free(AndroidLogFormat *p_format); void android_log_setPrintFormat(AndroidLogFormat *p_format, AndroidLogPrintFormat format); /** * Returns FORMAT_OFF on invalid string */ AndroidLogPrintFormat android_log_formatFromString(const char *s); /** * filterExpression: a single filter expression * eg "AT:d" * * returns 0 on success and -1 on invalid expression * * Assumes single threaded execution * */ int android_log_addFilterRule(AndroidLogFormat *p_format, const char *filterExpression); /** * filterString: a whitespace-separated set of filter expressions * eg "AT:d *:i" * * returns 0 on success and -1 on invalid expression * * Assumes single threaded execution * */ int android_log_addFilterString(AndroidLogFormat *p_format, const char *filterString); /** * returns 1 if this log line should be printed based on its priority * and tag, and 0 if it should not */ int android_log_shouldPrintLine ( AndroidLogFormat *p_format, const char *tag, android_LogPriority pri); /** * Splits a wire-format buffer into an AndroidLogEntry * entry allocated by caller. Pointers will point directly into buf * * Returns 0 on success and -1 on invalid wire format (entry will be * in unspecified state) */ int android_log_processLogBuffer(struct logger_entry *buf, AndroidLogEntry *entry); /** * Like android_log_processLogBuffer, but for binary logs. * * If "map" is non-NULL, it will be used to convert the log tag number * into a string. */ int android_log_processBinaryLogBuffer(struct logger_entry *buf, AndroidLogEntry *entry, const EventTagMap* map, char* messageBuf, int messageBufLen); /** * Formats a log message into a buffer * * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer * If return value != defaultBuffer, caller must call free() * Returns NULL on malloc error */ char *android_log_formatLogLine ( AndroidLogFormat *p_format, char *defaultBuffer, size_t defaultBufferSize, const AndroidLogEntry *p_line, size_t *p_outLength); /** * Either print or do not print log line, based on filter * * Assumes single threaded execution * */ int android_log_printLogLine( AndroidLogFormat *p_format, int fd, const AndroidLogEntry *entry); #ifdef __cplusplus } #endif #endif /*_LOGPRINT_H*/ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/cutils/logger.h0000644000015301777760000000521512322054223031635 0ustar pbusernogroup00000000000000/* utils/logger.h ** ** Copyright 2007, The Android Open Source Project ** ** This file is dual licensed. It may be redistributed and/or modified ** under the terms of the Apache 2.0 License OR version 2 of the GNU ** General Public License. */ #ifndef _UTILS_LOGGER_H #define _UTILS_LOGGER_H #include /* * The userspace structure for version 1 of the logger_entry ABI. * This structure is returned to userspace by the kernel logger * driver unless an upgrade to a newer ABI version is requested. */ struct logger_entry { uint16_t len; /* length of the payload */ uint16_t __pad; /* no matter what, we get 2 bytes of padding */ int32_t pid; /* generating process's pid */ int32_t tid; /* generating process's tid */ int32_t sec; /* seconds since Epoch */ int32_t nsec; /* nanoseconds */ char msg[0]; /* the entry's payload */ }; /* * The userspace structure for version 2 of the logger_entry ABI. * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION) * is called with version==2 */ struct logger_entry_v2 { uint16_t len; /* length of the payload */ uint16_t hdr_size; /* sizeof(struct logger_entry_v2) */ int32_t pid; /* generating process's pid */ int32_t tid; /* generating process's tid */ int32_t sec; /* seconds since Epoch */ int32_t nsec; /* nanoseconds */ uint32_t euid; /* effective UID of logger */ char msg[0]; /* the entry's payload */ }; #define LOGGER_LOG_MAIN "log/main" #define LOGGER_LOG_RADIO "log/radio" #define LOGGER_LOG_EVENTS "log/events" #define LOGGER_LOG_SYSTEM "log/system" /* * The maximum size of the log entry payload that can be * written to the kernel logger driver. An attempt to write * more than this amount to /dev/log/* will result in a * truncated log entry. */ #define LOGGER_ENTRY_MAX_PAYLOAD 4076 /* * The maximum size of a log entry which can be read from the * kernel logger driver. An attempt to read less than this amount * may result in read() returning EINVAL. */ #define LOGGER_ENTRY_MAX_LEN (5*1024) #ifdef HAVE_IOCTL #include #define __LOGGERIO 0xAE #define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */ #define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */ #define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */ #define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */ #define LOGGER_GET_VERSION _IO(__LOGGERIO, 5) /* abi version */ #define LOGGER_SET_VERSION _IO(__LOGGERIO, 6) /* abi version */ #endif // HAVE_IOCTL #endif /* _UTILS_LOGGER_H */ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/cutils/properties.h0000644000015301777760000000407012322054223032550 0ustar pbusernogroup00000000000000/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __CUTILS_PROPERTIES_H #define __CUTILS_PROPERTIES_H #ifdef __cplusplus extern "C" { #endif /* System properties are *small* name value pairs managed by the ** property service. If your data doesn't fit in the provided ** space it is not appropriate for a system property. ** ** WARNING: system/bionic/include/sys/system_properties.h also defines ** these, but with different names. (TODO: fix that) */ #define PROPERTY_KEY_MAX 32 #define PROPERTY_VALUE_MAX 92 /* property_get: returns the length of the value which will never be ** greater than PROPERTY_VALUE_MAX - 1 and will always be zero terminated. ** (the length does not include the terminating zero). ** ** If the property read fails or returns an empty value, the default ** value is used (if nonnull). */ int property_get(const char *key, char *value, const char *default_value); /* property_set: returns 0 on success, < 0 on failure */ int property_set(const char *key, const char *value); int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie); #ifdef HAVE_SYSTEM_PROPERTY_SERVER /* * We have an external property server instead of built-in libc support. * Used by the simulator. */ #define SYSTEM_PROPERTY_PIPE_NAME "/tmp/android-sysprop" enum { kSystemPropertyUnknown = 0, kSystemPropertyGet, kSystemPropertySet, kSystemPropertyList }; #endif /*HAVE_SYSTEM_PROPERTY_SERVER*/ #ifdef __cplusplus } #endif #endif mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/cutils/sched_policy.h0000644000015301777760000000413012322054223033016 0ustar pbusernogroup00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __CUTILS_SCHED_POLICY_H #define __CUTILS_SCHED_POLICY_H #ifdef __cplusplus extern "C" { #endif /* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */ typedef enum { SP_DEFAULT = -1, SP_BACKGROUND = 0, SP_FOREGROUND = 1, SP_SYSTEM = 2, // can't be used with set_sched_policy() SP_AUDIO_APP = 3, SP_AUDIO_SYS = 4, SP_CNT, SP_MAX = SP_CNT - 1, SP_SYSTEM_DEFAULT = SP_FOREGROUND, } SchedPolicy; /* Assign thread tid to the cgroup associated with the specified policy. * If the thread is a thread group leader, that is it's gettid() == getpid(), * then the other threads in the same thread group are _not_ affected. * On platforms which support gettid(), zero tid means current thread. * Return value: 0 for success, or -errno for error. */ extern int set_sched_policy(int tid, SchedPolicy policy); /* Return the policy associated with the cgroup of thread tid via policy pointer. * On platforms which support gettid(), zero tid means current thread. * Return value: 0 for success, or -1 for error and set errno. */ extern int get_sched_policy(int tid, SchedPolicy *policy); /* Return a displayable string corresponding to policy. * Return value: non-NULL NUL-terminated name of unspecified length; * the caller is responsible for displaying the useful part of the string. */ extern const char *get_sched_policy_name(SchedPolicy policy); #ifdef __cplusplus } #endif #endif /* __CUTILS_SCHED_POLICY_H */ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/machine/0000755000015301777760000000000012322054703030306 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/machine/cpu-features.h0000644000015301777760000001200012322054223033050 0ustar pbusernogroup00000000000000/* * Copyright (C) 2008 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _ARM_MACHINE_CPU_FEATURES_H #define _ARM_MACHINE_CPU_FEATURES_H /* The purpose of this file is to define several macros corresponding * to CPU features that may or may not be available at build time on * on the target CPU. * * This is done to abstract us from the various ARM Architecture * quirks and alphabet soup. * * IMPORTANT: We have no intention to support anything below an ARMv4T ! */ /* _ARM_ARCH_REVISION is a number corresponding to the ARM revision * we're going to support * * it looks like our toolchain doesn't define __ARM_ARCH__ * so try to guess it. * * * */ #ifndef __ARM_ARCH__ # if defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ || \ defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__ # define __ARM_ARCH__ 7 # elif defined __ARM_ARCH_6__ || defined __ARM_ARCH_6J__ || \ defined __ARM_ARCH_6K__ || defined __ARM_ARCH_6Z__ || \ defined __ARM_ARCH_6KZ__ || defined __ARM_ARCH_6T2__ # # define __ARM_ARCH__ 6 # # elif defined __ARM_ARCH_5__ || defined __ARM_ARCH_5T__ || \ defined __ARM_ARCH_5TE__ || defined __ARM_ARCH_5TEJ__ # # define __ARM_ARCH__ 5 # # elif defined __ARM_ARCH_4T__ # # define __ARM_ARCH__ 4 # # elif defined __ARM_ARCH_4__ # error ARMv4 is not supported, please use ARMv4T at a minimum # else # error Unknown or unsupported ARM architecture # endif #endif /* experimental feature used to check that our ARMv4 workarounds * work correctly without a real ARMv4 machine */ #ifdef BIONIC_EXPERIMENTAL_FORCE_ARMV4 # undef __ARM_ARCH__ # define __ARM_ARCH__ 4 #endif /* define __ARM_HAVE_5TE if we have the ARMv5TE instructions */ #if __ARM_ARCH__ > 5 # define __ARM_HAVE_5TE 1 #elif __ARM_ARCH__ == 5 # if defined __ARM_ARCH_5TE__ || defined __ARM_ARCH_5TEJ__ # define __ARM_HAVE_5TE 1 # endif #endif /* instructions introduced in ARMv5 */ #if __ARM_ARCH__ >= 5 # define __ARM_HAVE_BLX 1 # define __ARM_HAVE_CLZ 1 # define __ARM_HAVE_LDC2 1 # define __ARM_HAVE_MCR2 1 # define __ARM_HAVE_MRC2 1 # define __ARM_HAVE_STC2 1 #endif /* ARMv5TE introduces a few instructions */ #if __ARM_HAVE_5TE # define __ARM_HAVE_PLD 1 # define __ARM_HAVE_MCRR 1 # define __ARM_HAVE_MRRC 1 #endif /* define __ARM_HAVE_HALFWORD_MULTIPLY when half-word multiply instructions * this means variants of: smul, smulw, smla, smlaw, smlal */ #if __ARM_HAVE_5TE # define __ARM_HAVE_HALFWORD_MULTIPLY 1 #endif /* define __ARM_HAVE_PAIR_LOAD_STORE when 64-bit memory loads and stored * into/from a pair of 32-bit registers is supported throuhg 'ldrd' and 'strd' */ #if __ARM_HAVE_5TE # define __ARM_HAVE_PAIR_LOAD_STORE 1 #endif /* define __ARM_HAVE_SATURATED_ARITHMETIC is you have the saturated integer * arithmetic instructions: qdd, qdadd, qsub, qdsub */ #if __ARM_HAVE_5TE # define __ARM_HAVE_SATURATED_ARITHMETIC 1 #endif /* define __ARM_HAVE_PC_INTERWORK when a direct assignment to the * pc register will switch into thumb/ARM mode depending on bit 0 * of the new instruction address. Before ARMv5, this was not the * case, and you have to write: * * mov r0, [] * bx r0 * * instead of: * * ldr pc, [] * * note that this affects any instruction that explicitely changes the * value of the pc register, including ldm { ...,pc } or 'add pc, #offset' */ #if __ARM_ARCH__ >= 5 # define __ARM_HAVE_PC_INTERWORK #endif /* Assembly-only macros */ /* define a handy PLD(address) macro since the cache preload * is an optional opcode */ #if __ARM_HAVE_PLD # define PLD(reg,offset) pld [reg, offset] #else # define PLD(reg,offset) /* nothing */ #endif #endif /* _ARM_MACHINE_CPU_FEATURES_H */ mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/corkscrew/0000755000015301777760000000000012322054703030704 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/corkscrew/backtrace.h0000644000015301777760000001025512322054223032774 0ustar pbusernogroup00000000000000/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* A stack unwinder. */ #ifndef _CORKSCREW_BACKTRACE_H #define _CORKSCREW_BACKTRACE_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include /* * Describes a single frame of a backtrace. */ typedef struct { uintptr_t absolute_pc; /* absolute PC offset */ uintptr_t stack_top; /* top of stack for this frame */ size_t stack_size; /* size of this stack frame */ } backtrace_frame_t; /* * Describes the symbols associated with a backtrace frame. */ typedef struct { uintptr_t relative_pc; /* relative frame PC offset from the start of the library, or the absolute PC if the library is unknown */ uintptr_t relative_symbol_addr; /* relative offset of the symbol from the start of the library or 0 if the library is unknown */ char* map_name; /* executable or library name, or NULL if unknown */ char* symbol_name; /* symbol name, or NULL if unknown */ char* demangled_name; /* demangled symbol name, or NULL if unknown */ } backtrace_symbol_t; /* * Unwinds the call stack for the current thread of execution. * Populates the backtrace array with the program counters from the call stack. * Returns the number of frames collected, or -1 if an error occurred. */ ssize_t unwind_backtrace(backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth); /* * Unwinds the call stack for a thread within this process. * Populates the backtrace array with the program counters from the call stack. * Returns the number of frames collected, or -1 if an error occurred. * * The task is briefly suspended while the backtrace is being collected. */ ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth); /* * Unwinds the call stack of a task within a remote process using ptrace(). * Populates the backtrace array with the program counters from the call stack. * Returns the number of frames collected, or -1 if an error occurred. */ ssize_t unwind_backtrace_ptrace(pid_t tid, const ptrace_context_t* context, backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth); /* * Gets the symbols for each frame of a backtrace. * The symbols array must be big enough to hold one symbol record per frame. * The symbols must later be freed using free_backtrace_symbols. */ void get_backtrace_symbols(const backtrace_frame_t* backtrace, size_t frames, backtrace_symbol_t* backtrace_symbols); /* * Gets the symbols for each frame of a backtrace from a remote process. * The symbols array must be big enough to hold one symbol record per frame. * The symbols must later be freed using free_backtrace_symbols. */ void get_backtrace_symbols_ptrace(const ptrace_context_t* context, const backtrace_frame_t* backtrace, size_t frames, backtrace_symbol_t* backtrace_symbols); /* * Frees the storage associated with backtrace symbols. */ void free_backtrace_symbols(backtrace_symbol_t* backtrace_symbols, size_t frames); enum { // A hint for how big to make the line buffer for format_backtrace_line MAX_BACKTRACE_LINE_LENGTH = 800, }; /** * Formats a line from a backtrace as a zero-terminated string into the specified buffer. */ void format_backtrace_line(unsigned frameNumber, const backtrace_frame_t* frame, const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize); #ifdef __cplusplus } #endif #endif // _CORKSCREW_BACKTRACE_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/corkscrew/ptrace.h0000644000015301777760000000700512322054223032332 0ustar pbusernogroup00000000000000/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* Useful ptrace() utility functions. */ #ifndef _CORKSCREW_PTRACE_H #define _CORKSCREW_PTRACE_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* Stores information about a process that is used for several different * ptrace() based operations. */ typedef struct { map_info_t* map_info_list; } ptrace_context_t; /* Describes how to access memory from a process. */ typedef struct { pid_t tid; const map_info_t* map_info_list; } memory_t; #if __i386__ /* ptrace() register context. */ typedef struct pt_regs_x86 { uint32_t ebx; uint32_t ecx; uint32_t edx; uint32_t esi; uint32_t edi; uint32_t ebp; uint32_t eax; uint32_t xds; uint32_t xes; uint32_t xfs; uint32_t xgs; uint32_t orig_eax; uint32_t eip; uint32_t xcs; uint32_t eflags; uint32_t esp; uint32_t xss; } pt_regs_x86_t; #endif #if __mips__ /* ptrace() GET_REGS context. */ typedef struct pt_regs_mips { uint64_t regs[32]; uint64_t lo; uint64_t hi; uint64_t cp0_epc; uint64_t cp0_badvaddr; uint64_t cp0_status; uint64_t cp0_cause; } pt_regs_mips_t; #endif /* * Initializes a memory structure for accessing memory from this process. */ void init_memory(memory_t* memory, const map_info_t* map_info_list); /* * Initializes a memory structure for accessing memory from another process * using ptrace(). */ void init_memory_ptrace(memory_t* memory, pid_t tid); /* * Reads a word of memory safely. * If the memory is local, ensures that the address is readable before dereferencing it. * Returns false and a value of 0xffffffff if the word could not be read. */ bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value); /* * Reads a word of memory safely using ptrace(). * Returns false and a value of 0xffffffff if the word could not be read. */ bool try_get_word_ptrace(pid_t tid, uintptr_t ptr, uint32_t* out_value); /* * Loads information needed for examining a remote process using ptrace(). * The caller must already have successfully attached to the process * using ptrace(). * * The context can be used for any threads belonging to that process * assuming ptrace() is attached to them before performing the actual * unwinding. The context can continue to be used to decode backtraces * even after ptrace() has been detached from the process. */ ptrace_context_t* load_ptrace_context(pid_t pid); /* * Frees a ptrace context. */ void free_ptrace_context(ptrace_context_t* context); /* * Finds a symbol using ptrace. * Returns the containing map and information about the symbol, or * NULL if one or the other is not available. */ void find_symbol_ptrace(const ptrace_context_t* context, uintptr_t addr, const map_info_t** out_map_info, const symbol_t** out_symbol); #ifdef __cplusplus } #endif #endif // _CORKSCREW_PTRACE_H ././@LongLink0000000000000000000000000000014600000000000011216 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/corkscrew/symbol_table.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/corkscrew/symbol_table.0000644000015301777760000000254412322054223033363 0ustar pbusernogroup00000000000000/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _CORKSCREW_SYMBOL_TABLE_H #define _CORKSCREW_SYMBOL_TABLE_H #include #ifdef __cplusplus extern "C" { #endif typedef struct { uintptr_t start; uintptr_t end; char* name; } symbol_t; typedef struct { symbol_t* symbols; size_t num_symbols; } symbol_table_t; /* * Loads a symbol table from a given file. * Returns NULL on error. */ symbol_table_t* load_symbol_table(const char* filename); /* * Frees a symbol table. */ void free_symbol_table(symbol_table_t* table); /* * Finds a symbol associated with an address in the symbol table. * Returns NULL if not found. */ const symbol_t* find_symbol(const symbol_table_t* table, uintptr_t addr); #ifdef __cplusplus } #endif #endif // _CORKSCREW_SYMBOL_TABLE_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/corkscrew/demangle.h0000644000015301777760000000221012322054223032621 0ustar pbusernogroup00000000000000/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* C++ symbol name demangling. */ #ifndef _CORKSCREW_DEMANGLE_H #define _CORKSCREW_DEMANGLE_H #include #include #ifdef __cplusplus extern "C" { #endif /* * Demangles a C++ symbol name. * If name is NULL or if the name cannot be demangled, returns NULL. * Otherwise, returns a newly allocated string that contains the demangled name. * * The caller must free the returned string using free(). */ char* demangle_symbol_name(const char* name); #ifdef __cplusplus } #endif #endif // _CORKSCREW_DEMANGLE_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/system/core/include/corkscrew/map_info.h0000644000015301777760000000376312322054223032653 0ustar pbusernogroup00000000000000/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* Process memory map. */ #ifndef _CORKSCREW_MAP_INFO_H #define _CORKSCREW_MAP_INFO_H #include #include #ifdef __cplusplus extern "C" { #endif typedef struct map_info { struct map_info* next; uintptr_t start; uintptr_t end; bool is_readable; bool is_executable; void* data; // arbitrary data associated with the map by the user, initially NULL char name[]; } map_info_t; /* Loads memory map from /proc//maps. */ map_info_t* load_map_info_list(pid_t tid); /* Frees memory map. */ void free_map_info_list(map_info_t* milist); /* Finds the memory map that contains the specified address. */ const map_info_t* find_map_info(const map_info_t* milist, uintptr_t addr); /* Returns true if the addr is in an readable map. */ bool is_readable_map(const map_info_t* milist, uintptr_t addr); /* Returns true if the addr is in an executable map. */ bool is_executable_map(const map_info_t* milist, uintptr_t addr); /* Acquires a reference to the memory map for this process. * The result is cached and refreshed automatically. * Make sure to release the map info when done. */ map_info_t* acquire_my_map_info_list(); /* Releases a reference to the map info for this process that was * previous acquired using acquire_my_map_info_list(). */ void release_my_map_info_list(map_info_t* milist); #ifdef __cplusplus } #endif #endif // _CORKSCREW_MAP_INFO_H mir-0.1.8+14.04.20140411/3rd_party/android-input/android/CMakeLists.txt0000644000015301777760000000432312322054247025550 0ustar pbusernogroup00000000000000include_directories( external/kernel-headers/original frameworks/base/include frameworks/native/include hardware/libhardware_legacy/include system/core/include system/extras/ext4_utils ${PROJECT_SOURCE_DIR}/include/server ${PROJECT_SOURCE_DIR}/include/platform ) add_definitions( -DANDROID_SMP=1 ) # This is stuff for which we want non-android versions set( UTIL_SOURCES frameworks/native/libs/utils/Looper.cpp # used by InputDispatcher.cpp frameworks/native/libs/utils/RefBase.cpp # used a lot frameworks/native/libs/utils/Timers.cpp # used by KeyCharacterMap.cpp, InputReader.cpp, InputDispatcher.cpp, Looper.cpp ) add_library( android-input STATIC # The stuff that we want frameworks/base/services/input/EventHub.cpp frameworks/base/services/input/InputApplication.cpp frameworks/base/services/input/InputDispatcher.cpp frameworks/base/services/input/InputListener.cpp frameworks/base/services/input/InputReader.cpp frameworks/base/services/input/InputTransport.cpp frameworks/base/services/input/InputWindow.cpp frameworks/base/services/input/IntSet.cpp frameworks/base/services/input/PointerController.cpp # Keyboard/keymap handling frameworks/base/services/input/GenericKeyMap.cpp # The stuff that is used internally by the implementation above. # We're not directly interested in those: frameworks/base/services/input/Input.cpp frameworks/base/services/input/InputDevice.cpp frameworks/base/services/input/Keyboard.cpp frameworks/base/services/input/KeyCharacterMap.cpp frameworks/base/services/input/KeyLayoutMap.cpp frameworks/base/services/input/VelocityControl.cpp frameworks/base/services/input/VelocityTracker.cpp frameworks/base/services/input/VirtualKeyMap.cpp frameworks/base/services/input/MirLog.cpp frameworks/native/libs/utils/Tokenizer.cpp frameworks/native/libs/utils/FileMap.cpp ${UTIL_SOURCES} ) #we don't have binder or skia available on hybris/linux platforms if(MIR_USE_BIONIC) target_link_libraries( android-input binder skia) endif() target_link_libraries( android-input mirplatform ${Boost_LIBRARIES} ) set_target_properties( android-input PROPERTIES COMPILE_FLAGS ${ANDROID_INPUT_COMPILE_FLAGS} ) mir-0.1.8+14.04.20140411/3rd_party/android-input/android/hardware/0000755000015301777760000000000012322054703024600 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/hardware/libhardware_legacy/0000755000015301777760000000000012322054703030410 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/hardware/libhardware_legacy/include/0000755000015301777760000000000012322054703032033 5ustar pbusernogroup00000000000000././@LongLink0000000000000000000000000000015600000000000011217 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/hardware/libhardware_legacy/include/hardware_legacy/mir-0.1.8+14.04.20140411/3rd_party/android-input/android/hardware/libhardware_legacy/include/hardwar0000755000015301777760000000000012322054703033404 5ustar pbusernogroup00000000000000././@LongLink0000000000000000000000000000016500000000000011217 Lustar 00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-input/android/hardware/libhardware_legacy/include/hardware_legacy/power.hmir-0.1.8+14.04.20140411/3rd_party/android-input/android/hardware/libhardware_legacy/include/hardwar0000644000015301777760000000213612322054223033405 0ustar pbusernogroup00000000000000/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _HARDWARE_POWER_H #define _HARDWARE_POWER_H #include #if __cplusplus extern "C" { #endif enum { PARTIAL_WAKE_LOCK = 1, // the cpu stays on, but the screen is off FULL_WAKE_LOCK = 2 // the screen is also on }; // while you have a lock held, the device will stay on at least at the // level you request. int acquire_wake_lock(int lock, const char* id); int release_wake_lock(const char* id); #if __cplusplus } // extern "C" #endif #endif // _HARDWARE_POWER_H mir-0.1.8+14.04.20140411/3rd_party/android-input/CMakeLists.txt0000644000015301777760000000256412322054223024127 0ustar pbusernogroup00000000000000# Don't be so strict on warnings etc as android code won't compile with them on. # A *big* number of warnings would ensue. Therefore locally define CMAKE_CXX_FLAGS # without things such as -Werror, -Wall, etc STRING(REGEX REPLACE "-pedantic" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) STRING(REGEX REPLACE "-W[^ ]*" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) set(ANDROID_INPUT_COMPILE_FLAGS "-include ${CMAKE_CURRENT_SOURCE_DIR}/android/system/core/include/arch/ubuntu-x86/AndroidConfig.h") set(MIR_ANDROID_INPUT_COMPILE_FLAGS "${ANDROID_INPUT_COMPILE_FLAGS} -DUSING_STD_CPP11" PARENT_SCOPE) add_subdirectory(android) # Make those include directories available to mir source code list( APPEND MIR_ANDROID_INCLUDE_DIRECTORIES # That's what mir is really interested in ${CMAKE_CURRENT_SOURCE_DIR}/android/frameworks/base/services/input # And those are referenced by the headers in the directory above ${CMAKE_CURRENT_SOURCE_DIR}/android/frameworks/base/include ${CMAKE_CURRENT_SOURCE_DIR}/android/frameworks/native/include ${CMAKE_CURRENT_SOURCE_DIR}/android/hardware/libhardware_legacy/include ${CMAKE_CURRENT_SOURCE_DIR}/android/system/core/include ${CMAKE_CURRENT_SOURCE_DIR}/android/system/extras/ext4_utils ${CMAKE_CURRENT_SOURCE_DIR}/android/external/kernel-headers/original ) set(MIR_ANDROID_INCLUDE_DIRECTORIES ${MIR_ANDROID_INCLUDE_DIRECTORIES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/3rd_party/android-input/README0000644000015301777760000000103312322054223022235 0ustar pbusernogroup00000000000000A stand-alone android input stack (EventHub, InputReader, InputChannel, etc) so that it can be used isolatedly, outside android proper. All the needed base, helper and utility classes (e.g. String8) were also brought along. Debugging ========= Define FAKE_LOG_DEVICE=1 in android/CMakeLists.txt to make log be printed to the stderr. Set the ANDROID_LOG_TAGS environment variable to "*:v" (make everything verbose). In the beginning of, say, InputReader.cpp, change the defines you're interesed in (e.g. DEBUG_RAW_EVENTS) from 0 to 1. mir-0.1.8+14.04.20140411/3rd_party/CMakeLists.txt0000644000015301777760000000142612322054223021346 0ustar pbusernogroup00000000000000 # Warnings in 3rd party code are not to be considered errors. :( string (REPLACE " -Werror " " " CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) list( APPEND MIR_3RD_PARTY_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/android-deps ) add_library( 3rd_party ${MIR_3RD_PARTY_SOURCES} ) set(MIR_3RD_PARTY_INCLUDE_DIRECTORIES ${MIR_3RD_PARTY_INCLUDE_DIRECTORIES} PARENT_SCOPE) set(MIR_INPUT_ANDROID_COMPILE_FLAGS ${MIR_INPUT_ANDROID_COMPILE_FLAGS} PARENT_SCOPE) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/android-deps) add_subdirectory(android-input) set(MIR_ANDROID_INCLUDE_DIRECTORIES ${MIR_ANDROID_INCLUDE_DIRECTORIES} PARENT_SCOPE) set( MIR_ANDROID_INPUT_COMPILE_FLAGS ${MIR_ANDROID_INPUT_COMPILE_FLAGS} PARENT_SCOPE) target_link_libraries( 3rd_party android-input) mir-0.1.8+14.04.20140411/3rd_party/android-deps/0000755000015301777760000000000012322054703021157 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/0000755000015301777760000000000012322054703022577 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/obb.h0000644000015301777760000000260012322054223023505 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_OBB_H #define ANDROID_OBB_H #include #ifdef __cplusplus extern "C" { #endif struct AObbInfo; typedef struct AObbInfo AObbInfo; enum { AOBBINFO_OVERLAY = 0x0001, }; /** * Scan an OBB and get information about it. */ AObbInfo* AObbScanner_getObbInfo(const char* filename); /** * Destroy the AObbInfo object. You must call this when finished with the object. */ void AObbInfo_delete(AObbInfo* obbInfo); /** * Get the package name for the OBB. */ const char* AObbInfo_getPackageName(AObbInfo* obbInfo); /** * Get the version of an OBB file. */ int32_t AObbInfo_getVersion(AObbInfo* obbInfo); /** * Get the flags of an OBB file. */ int32_t AObbInfo_getFlags(AObbInfo* obbInfo); #ifdef __cplusplus }; #endif #endif // ANDROID_OBB_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/window.h0000644000015301777760000000423412322054223024257 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_WINDOW_H #define ANDROID_WINDOW_H #ifdef __cplusplus extern "C" { #endif /** * Window flags, as per the Java API at android.view.WindowManager.LayoutParams. */ enum { AWINDOW_FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, AWINDOW_FLAG_DIM_BEHIND = 0x00000002, AWINDOW_FLAG_BLUR_BEHIND = 0x00000004, AWINDOW_FLAG_NOT_FOCUSABLE = 0x00000008, AWINDOW_FLAG_NOT_TOUCHABLE = 0x00000010, AWINDOW_FLAG_NOT_TOUCH_MODAL = 0x00000020, AWINDOW_FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, AWINDOW_FLAG_KEEP_SCREEN_ON = 0x00000080, AWINDOW_FLAG_LAYOUT_IN_SCREEN = 0x00000100, AWINDOW_FLAG_LAYOUT_NO_LIMITS = 0x00000200, AWINDOW_FLAG_FULLSCREEN = 0x00000400, AWINDOW_FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, AWINDOW_FLAG_DITHER = 0x00001000, AWINDOW_FLAG_SECURE = 0x00002000, AWINDOW_FLAG_SCALED = 0x00004000, AWINDOW_FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, AWINDOW_FLAG_LAYOUT_INSET_DECOR = 0x00010000, AWINDOW_FLAG_ALT_FOCUSABLE_IM = 0x00020000, AWINDOW_FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, AWINDOW_FLAG_SHOW_WHEN_LOCKED = 0x00080000, AWINDOW_FLAG_SHOW_WALLPAPER = 0x00100000, AWINDOW_FLAG_TURN_SCREEN_ON = 0x00200000, AWINDOW_FLAG_DISMISS_KEYGUARD = 0x00400000, }; #ifdef __cplusplus }; #endif #endif // ANDROID_WINDOW_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/api-level.h0000644000015301777760000000275412322054223024633 0ustar pbusernogroup00000000000000/* * Copyright (C) 2008 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef ANDROID_API_LEVEL_H #define ANDROID_API_LEVEL_H #define __ANDROID_API__ 14 #endif /* ANDROID_API_LEVEL_H */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/asset_manager.h0000644000015301777760000000723612322054223025566 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_ASSET_MANAGER_H #define ANDROID_ASSET_MANAGER_H #include #ifdef __cplusplus extern "C" { #endif struct AAssetManager; typedef struct AAssetManager AAssetManager; struct AAssetDir; typedef struct AAssetDir AAssetDir; struct AAsset; typedef struct AAsset AAsset; /* Available modes for opening assets */ enum { AASSET_MODE_UNKNOWN = 0, AASSET_MODE_RANDOM = 1, AASSET_MODE_STREAMING = 2, AASSET_MODE_BUFFER = 3 }; /** * Open the named directory within the asset hierarchy. The directory can then * be inspected with the AAssetDir functions. To open the top-level directory, * pass in "" as the dirName. * * The object returned here should be freed by calling AAssetDir_close(). */ AAssetDir* AAssetManager_openDir(AAssetManager* mgr, const char* dirName); /** * Open an asset. * * The object returned here should be freed by calling AAsset_close(). */ AAsset* AAssetManager_open(AAssetManager* mgr, const char* filename, int mode); /** * Iterate over the files in an asset directory. A NULL string is returned * when all the file names have been returned. * * The returned file name is suitable for passing to AAssetManager_open(). * * The string returned here is owned by the AssetDir implementation and is not * guaranteed to remain valid if any other calls are made on this AAssetDir * instance. */ const char* AAssetDir_getNextFileName(AAssetDir* assetDir); /** * Reset the iteration state of AAssetDir_getNextFileName() to the beginning. */ void AAssetDir_rewind(AAssetDir* assetDir); /** * Close an opened AAssetDir, freeing any related resources. */ void AAssetDir_close(AAssetDir* assetDir); /** * Attempt to read 'count' bytes of data from the current offset. * * Returns the number of bytes read, zero on EOF, or < 0 on error. */ int AAsset_read(AAsset* asset, void* buf, size_t count); /** * Seek to the specified offset within the asset data. 'whence' uses the * same constants as lseek()/fseek(). * * Returns the new position on success, or (off_t) -1 on error. */ off_t AAsset_seek(AAsset* asset, off_t offset, int whence); /** * Close the asset, freeing all associated resources. */ void AAsset_close(AAsset* asset); /** * Get a pointer to a buffer holding the entire contents of the assset. * * Returns NULL on failure. */ const void* AAsset_getBuffer(AAsset* asset); /** * Report the total size of the asset data. */ off_t AAsset_getLength(AAsset* asset); /** * Report the total amount of asset data that can be read from the current position. */ off_t AAsset_getRemainingLength(AAsset* asset); /** * Open a new file descriptor that can be used to read the asset data. * * Returns < 0 if direct fd access is not possible (for example, if the asset is * compressed). */ int AAsset_openFileDescriptor(AAsset* asset, off_t* outStart, off_t* outLength); /** * Returns whether this asset's internal buffer is allocated in ordinary RAM (i.e. not * mmapped). */ int AAsset_isAllocated(AAsset* asset); #ifdef __cplusplus }; #endif #endif // ANDROID_ASSET_MANAGER_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/bitmap.h0000644000015301777760000000456112322054223024227 0ustar pbusernogroup00000000000000/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_BITMAP_H #define ANDROID_BITMAP_H #include #include #include __BEGIN_DECLS #define ANDROID_BITMAP_RESUT_SUCCESS 0 #define ANDROID_BITMAP_RESULT_BAD_PARAMETER -1 #define ANDROID_BITMAP_RESULT_JNI_EXCEPTION -2 #define ANDROID_BITMAP_RESULT_ALLOCATION_FAILED -3 enum AndroidBitmapFormat { ANDROID_BITMAP_FORMAT_NONE = 0, ANDROID_BITMAP_FORMAT_RGBA_8888 = 1, ANDROID_BITMAP_FORMAT_RGB_565 = 4, ANDROID_BITMAP_FORMAT_RGBA_4444 = 7, ANDROID_BITMAP_FORMAT_A_8 = 8, }; typedef struct { uint32_t width; uint32_t height; uint32_t stride; int32_t format; uint32_t flags; // 0 for now } AndroidBitmapInfo; /** * Given a java bitmap object, fill out the AndroidBitmap struct for it. * If the call fails, the info parameter will be ignored */ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, AndroidBitmapInfo* info); /** * Given a java bitmap object, attempt to lock the pixel address. * Locking will ensure that the memory for the pixels will not move * until the unlockPixels call, and ensure that, if the pixels had been * previously purged, they will have been restored. * * If this call succeeds, it must be balanced by a call to * AndroidBitmap_unlockPixels, after which time the address of the pixels should * no longer be used. * * If this succeeds, *addrPtr will be set to the pixel address. If the call * fails, addrPtr will be ignored. */ int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr); /** * Call this to balanace a successful call to AndroidBitmap_lockPixels */ int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap); __END_DECLS #endif /* ANDROID_BITMAP_H */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/configuration.h0000644000015301777760000002340312322054223025616 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_CONFIGURATION_H #define ANDROID_CONFIGURATION_H #include #ifdef __cplusplus extern "C" { #endif struct AConfiguration; typedef struct AConfiguration AConfiguration; enum { ACONFIGURATION_ORIENTATION_ANY = 0x0000, ACONFIGURATION_ORIENTATION_PORT = 0x0001, ACONFIGURATION_ORIENTATION_LAND = 0x0002, ACONFIGURATION_ORIENTATION_SQUARE = 0x0003, ACONFIGURATION_TOUCHSCREEN_ANY = 0x0000, ACONFIGURATION_TOUCHSCREEN_NOTOUCH = 0x0001, ACONFIGURATION_TOUCHSCREEN_STYLUS = 0x0002, ACONFIGURATION_TOUCHSCREEN_FINGER = 0x0003, ACONFIGURATION_DENSITY_DEFAULT = 0, ACONFIGURATION_DENSITY_LOW = 120, ACONFIGURATION_DENSITY_MEDIUM = 160, ACONFIGURATION_DENSITY_HIGH = 240, ACONFIGURATION_DENSITY_NONE = 0xffff, ACONFIGURATION_KEYBOARD_ANY = 0x0000, ACONFIGURATION_KEYBOARD_NOKEYS = 0x0001, ACONFIGURATION_KEYBOARD_QWERTY = 0x0002, ACONFIGURATION_KEYBOARD_12KEY = 0x0003, ACONFIGURATION_NAVIGATION_ANY = 0x0000, ACONFIGURATION_NAVIGATION_NONAV = 0x0001, ACONFIGURATION_NAVIGATION_DPAD = 0x0002, ACONFIGURATION_NAVIGATION_TRACKBALL = 0x0003, ACONFIGURATION_NAVIGATION_WHEEL = 0x0004, ACONFIGURATION_KEYSHIDDEN_ANY = 0x0000, ACONFIGURATION_KEYSHIDDEN_NO = 0x0001, ACONFIGURATION_KEYSHIDDEN_YES = 0x0002, ACONFIGURATION_KEYSHIDDEN_SOFT = 0x0003, ACONFIGURATION_NAVHIDDEN_ANY = 0x0000, ACONFIGURATION_NAVHIDDEN_NO = 0x0001, ACONFIGURATION_NAVHIDDEN_YES = 0x0002, ACONFIGURATION_SCREENSIZE_ANY = 0x00, ACONFIGURATION_SCREENSIZE_SMALL = 0x01, ACONFIGURATION_SCREENSIZE_NORMAL = 0x02, ACONFIGURATION_SCREENSIZE_LARGE = 0x03, ACONFIGURATION_SCREENSIZE_XLARGE = 0x04, ACONFIGURATION_SCREENLONG_ANY = 0x00, ACONFIGURATION_SCREENLONG_NO = 0x1, ACONFIGURATION_SCREENLONG_YES = 0x2, ACONFIGURATION_UI_MODE_TYPE_ANY = 0x00, ACONFIGURATION_UI_MODE_TYPE_NORMAL = 0x01, ACONFIGURATION_UI_MODE_TYPE_DESK = 0x02, ACONFIGURATION_UI_MODE_TYPE_CAR = 0x03, ACONFIGURATION_UI_MODE_NIGHT_ANY = 0x00, ACONFIGURATION_UI_MODE_NIGHT_NO = 0x1, ACONFIGURATION_UI_MODE_NIGHT_YES = 0x2, ACONFIGURATION_MCC = 0x0001, ACONFIGURATION_MNC = 0x0002, ACONFIGURATION_LOCALE = 0x0004, ACONFIGURATION_TOUCHSCREEN = 0x0008, ACONFIGURATION_KEYBOARD = 0x0010, ACONFIGURATION_KEYBOARD_HIDDEN = 0x0020, ACONFIGURATION_NAVIGATION = 0x0040, ACONFIGURATION_ORIENTATION = 0x0080, ACONFIGURATION_DENSITY = 0x0100, ACONFIGURATION_SCREEN_SIZE = 0x0200, ACONFIGURATION_VERSION = 0x0400, ACONFIGURATION_SCREEN_LAYOUT = 0x0800, ACONFIGURATION_UI_MODE = 0x1000, }; /** * Create a new AConfiguration, initialized with no values set. */ AConfiguration* AConfiguration_new(); /** * Free an AConfiguration that was previously created with * AConfiguration_new(). */ void AConfiguration_delete(AConfiguration* config); /** * Create and return a new AConfiguration based on the current configuration in * use in the given AssetManager. */ void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am); /** * Copy the contents of 'src' to 'dest'. */ void AConfiguration_copy(AConfiguration* dest, AConfiguration* src); /** * Return the current MCC set in the configuration. 0 if not set. */ int32_t AConfiguration_getMcc(AConfiguration* config); /** * Set the current MCC in the configuration. 0 to clear. */ void AConfiguration_setMcc(AConfiguration* config, int32_t mcc); /** * Return the current MNC set in the configuration. 0 if not set. */ int32_t AConfiguration_getMnc(AConfiguration* config); /** * Set the current MNC in the configuration. 0 to clear. */ void AConfiguration_setMnc(AConfiguration* config, int32_t mnc); /** * Return the current language code set in the configuration. The output will * be filled with an array of two characters. They are not 0-terminated. If * a language is not set, they will be 0. */ void AConfiguration_getLanguage(AConfiguration* config, char* outLanguage); /** * Set the current language code in the configuration, from the first two * characters in the string. */ void AConfiguration_setLanguage(AConfiguration* config, const char* language); /** * Return the current country code set in the configuration. The output will * be filled with an array of two characters. They are not 0-terminated. If * a country is not set, they will be 0. */ void AConfiguration_getCountry(AConfiguration* config, char* outCountry); /** * Set the current country code in the configuration, from the first two * characters in the string. */ void AConfiguration_setCountry(AConfiguration* config, const char* country); /** * Return the current ACONFIGURATION_ORIENTATION_* set in the configuration. */ int32_t AConfiguration_getOrientation(AConfiguration* config); /** * Set the current orientation in the configuration. */ void AConfiguration_setOrientation(AConfiguration* config, int32_t orientation); /** * Return the current ACONFIGURATION_TOUCHSCREEN_* set in the configuration. */ int32_t AConfiguration_getTouchscreen(AConfiguration* config); /** * Set the current touchscreen in the configuration. */ void AConfiguration_setTouchscreen(AConfiguration* config, int32_t touchscreen); /** * Return the current ACONFIGURATION_DENSITY_* set in the configuration. */ int32_t AConfiguration_getDensity(AConfiguration* config); /** * Set the current density in the configuration. */ void AConfiguration_setDensity(AConfiguration* config, int32_t density); /** * Return the current ACONFIGURATION_KEYBOARD_* set in the configuration. */ int32_t AConfiguration_getKeyboard(AConfiguration* config); /** * Set the current keyboard in the configuration. */ void AConfiguration_setKeyboard(AConfiguration* config, int32_t keyboard); /** * Return the current ACONFIGURATION_NAVIGATION_* set in the configuration. */ int32_t AConfiguration_getNavigation(AConfiguration* config); /** * Set the current navigation in the configuration. */ void AConfiguration_setNavigation(AConfiguration* config, int32_t navigation); /** * Return the current ACONFIGURATION_KEYSHIDDEN_* set in the configuration. */ int32_t AConfiguration_getKeysHidden(AConfiguration* config); /** * Set the current keys hidden in the configuration. */ void AConfiguration_setKeysHidden(AConfiguration* config, int32_t keysHidden); /** * Return the current ACONFIGURATION_NAVHIDDEN_* set in the configuration. */ int32_t AConfiguration_getNavHidden(AConfiguration* config); /** * Set the current nav hidden in the configuration. */ void AConfiguration_setNavHidden(AConfiguration* config, int32_t navHidden); /** * Return the current SDK (API) version set in the configuration. */ int32_t AConfiguration_getSdkVersion(AConfiguration* config); /** * Set the current SDK version in the configuration. */ void AConfiguration_setSdkVersion(AConfiguration* config, int32_t sdkVersion); /** * Return the current ACONFIGURATION_SCREENSIZE_* set in the configuration. */ int32_t AConfiguration_getScreenSize(AConfiguration* config); /** * Set the current screen size in the configuration. */ void AConfiguration_setScreenSize(AConfiguration* config, int32_t screenSize); /** * Return the current ACONFIGURATION_SCREENLONG_* set in the configuration. */ int32_t AConfiguration_getScreenLong(AConfiguration* config); /** * Set the current screen long in the configuration. */ void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong); /** * Return the current ACONFIGURATION_UI_MODE_TYPE_* set in the configuration. */ int32_t AConfiguration_getUiModeType(AConfiguration* config); /** * Set the current UI mode type in the configuration. */ void AConfiguration_setUiModeType(AConfiguration* config, int32_t uiModeType); /** * Return the current ACONFIGURATION_UI_MODE_NIGHT_* set in the configuration. */ int32_t AConfiguration_getUiModeNight(AConfiguration* config); /** * Set the current UI mode night in the configuration. */ void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight); /** * Perform a diff between two configurations. Returns a bit mask of * ACONFIGURATION_* constants, each bit set meaning that configuration element * is different between them. */ int32_t AConfiguration_diff(AConfiguration* config1, AConfiguration* config2); /** * Determine whether 'base' is a valid configuration for use within the * environment 'requested'. Returns 0 if there are any values in 'base' * that conflict with 'requested'. Returns 1 if it does not conflict. */ int32_t AConfiguration_match(AConfiguration* base, AConfiguration* requested); /** * Determine whether the configuration in 'test' is better than the existing * configuration in 'base'. If 'requested' is non-NULL, this decision is based * on the overall configuration given there. If it is NULL, this decision is * simply based on which configuration is more specific. Returns non-0 if * 'test' is better than 'base'. * * This assumes you have already filtered the configurations with * AConfiguration_match(). */ int32_t AConfiguration_isBetterThan(AConfiguration* base, AConfiguration* test, AConfiguration* requested); #ifdef __cplusplus }; #endif #endif // ANDROID_CONFIGURATION_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/native_window_jni.h0000644000015301777760000000226212322054223026464 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_NATIVE_WINDOW_JNI_H #define ANDROID_NATIVE_WINDOW_JNI_H #include #include #ifdef __cplusplus extern "C" { #endif /** * Return the ANativeWindow associated with a Java Surface object, * for interacting with it through native code. This acquires a reference * on the ANativeWindow that is returned; be sure to use ANativeWindow_release() * when done with it so that it doesn't leak. */ ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface); #ifdef __cplusplus }; #endif #endif // ANDROID_NATIVE_WINDOW_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/asset_manager_jni.h0000644000015301777760000000227512322054223026424 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_ASSET_MANAGER_JNI_H #define ANDROID_ASSET_MANAGER_JNI_H #include #include #ifdef __cplusplus extern "C" { #endif /** * Given a Dalvik AssetManager object, obtain the corresponding native AAssetManager * object. Note that the caller is responsible for obtaining and holding a VM reference * to the jobject to prevent its being garbage collected while the native object is * in use. */ AAssetManager* AAssetManager_fromJava(JNIEnv* env, jobject assetManager); #ifdef __cplusplus }; #endif #endif // ANDROID_ASSET_MANAGER_JNI_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/rect.h0000644000015301777760000000166612322054223023713 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_RECT_H #define ANDROID_RECT_H #include #ifdef __cplusplus extern "C" { #endif typedef struct ARect { #ifdef __cplusplus typedef int32_t value_type; #endif int32_t left; int32_t top; int32_t right; int32_t bottom; } ARect; #ifdef __cplusplus }; #endif #endif // ANDROID_RECT_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/native_window.h0000644000015301777760000000721112322054223025623 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_NATIVE_WINDOW_H #define ANDROID_NATIVE_WINDOW_H #include #ifdef __cplusplus extern "C" { #endif /* * Pixel formats that a window can use. */ enum { WINDOW_FORMAT_RGBA_8888 = 1, WINDOW_FORMAT_RGBX_8888 = 2, WINDOW_FORMAT_RGB_565 = 4, }; struct ANativeWindow; typedef struct ANativeWindow ANativeWindow; typedef struct ANativeWindow_Buffer { // The number of pixels that are show horizontally. int32_t width; // The number of pixels that are shown vertically. int32_t height; // The number of *pixels* that a line in the buffer takes in // memory. This may be >= width. int32_t stride; // The format of the buffer. One of WINDOW_FORMAT_* int32_t format; // The actual bits. void* bits; // Do not touch. uint32_t reserved[6]; } ANativeWindow_Buffer; /** * Acquire a reference on the given ANativeWindow object. This prevents the object * from being deleted until the reference is removed. */ void ANativeWindow_acquire(ANativeWindow* window); /** * Remove a reference that was previously acquired with ANativeWindow_acquire(). */ void ANativeWindow_release(ANativeWindow* window); /* * Return the current width in pixels of the window surface. Returns a * negative value on error. */ int32_t ANativeWindow_getWidth(ANativeWindow* window); /* * Return the current height in pixels of the window surface. Returns a * negative value on error. */ int32_t ANativeWindow_getHeight(ANativeWindow* window); /* * Return the current pixel format of the window surface. Returns a * negative value on error. */ int32_t ANativeWindow_getFormat(ANativeWindow* window); /* * Change the format and size of the window buffers. * * The width and height control the number of pixels in the buffers, not the * dimensions of the window on screen. If these are different than the * window's physical size, then it buffer will be scaled to match that size * when compositing it to the screen. * * For all of these parameters, if 0 is supplied then the window's base * value will come back in force. * * width and height must be either both zero or both non-zero. * */ int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height, int32_t format); /** * Lock the window's next drawing surface for writing. * inOutDirtyBounds is used as an in/out parameter, upon entering the * function, it contains the dirty region, that is, the region the caller * intends to redraw. When the function returns, inOutDirtyBounds is updated * with the actual area the caller needs to redraw -- this region is often * extended by ANativeWindow_lock. */ int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds); /** * Unlock the window's drawing surface after previously locking it, * posting the new buffer to the display. */ int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); #ifdef __cplusplus }; #endif #endif // ANDROID_NATIVE_WINDOW_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/keycodes.h0000644000015301777760000002233612322054223024561 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROID_KEYCODES_H #define _ANDROID_KEYCODES_H /****************************************************************** * * IMPORTANT NOTICE: * * This file is part of Android's set of stable system headers * exposed by the Android NDK (Native Development Kit). * * Third-party source AND binary code relies on the definitions * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. * * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES */ #include #ifdef __cplusplus extern "C" { #endif /* * Key codes. */ enum { AKEYCODE_UNKNOWN = 0, AKEYCODE_SOFT_LEFT = 1, AKEYCODE_SOFT_RIGHT = 2, AKEYCODE_HOME = 3, AKEYCODE_BACK = 4, AKEYCODE_CALL = 5, AKEYCODE_ENDCALL = 6, AKEYCODE_0 = 7, AKEYCODE_1 = 8, AKEYCODE_2 = 9, AKEYCODE_3 = 10, AKEYCODE_4 = 11, AKEYCODE_5 = 12, AKEYCODE_6 = 13, AKEYCODE_7 = 14, AKEYCODE_8 = 15, AKEYCODE_9 = 16, AKEYCODE_STAR = 17, AKEYCODE_POUND = 18, AKEYCODE_DPAD_UP = 19, AKEYCODE_DPAD_DOWN = 20, AKEYCODE_DPAD_LEFT = 21, AKEYCODE_DPAD_RIGHT = 22, AKEYCODE_DPAD_CENTER = 23, AKEYCODE_VOLUME_UP = 24, AKEYCODE_VOLUME_DOWN = 25, AKEYCODE_POWER = 26, AKEYCODE_CAMERA = 27, AKEYCODE_CLEAR = 28, AKEYCODE_A = 29, AKEYCODE_B = 30, AKEYCODE_C = 31, AKEYCODE_D = 32, AKEYCODE_E = 33, AKEYCODE_F = 34, AKEYCODE_G = 35, AKEYCODE_H = 36, AKEYCODE_I = 37, AKEYCODE_J = 38, AKEYCODE_K = 39, AKEYCODE_L = 40, AKEYCODE_M = 41, AKEYCODE_N = 42, AKEYCODE_O = 43, AKEYCODE_P = 44, AKEYCODE_Q = 45, AKEYCODE_R = 46, AKEYCODE_S = 47, AKEYCODE_T = 48, AKEYCODE_U = 49, AKEYCODE_V = 50, AKEYCODE_W = 51, AKEYCODE_X = 52, AKEYCODE_Y = 53, AKEYCODE_Z = 54, AKEYCODE_COMMA = 55, AKEYCODE_PERIOD = 56, AKEYCODE_ALT_LEFT = 57, AKEYCODE_ALT_RIGHT = 58, AKEYCODE_SHIFT_LEFT = 59, AKEYCODE_SHIFT_RIGHT = 60, AKEYCODE_TAB = 61, AKEYCODE_SPACE = 62, AKEYCODE_SYM = 63, AKEYCODE_EXPLORER = 64, AKEYCODE_ENVELOPE = 65, AKEYCODE_ENTER = 66, AKEYCODE_DEL = 67, AKEYCODE_GRAVE = 68, AKEYCODE_MINUS = 69, AKEYCODE_EQUALS = 70, AKEYCODE_LEFT_BRACKET = 71, AKEYCODE_RIGHT_BRACKET = 72, AKEYCODE_BACKSLASH = 73, AKEYCODE_SEMICOLON = 74, AKEYCODE_APOSTROPHE = 75, AKEYCODE_SLASH = 76, AKEYCODE_AT = 77, AKEYCODE_NUM = 78, AKEYCODE_HEADSETHOOK = 79, AKEYCODE_FOCUS = 80, // *Camera* focus AKEYCODE_PLUS = 81, AKEYCODE_MENU = 82, AKEYCODE_NOTIFICATION = 83, AKEYCODE_SEARCH = 84, AKEYCODE_MEDIA_PLAY_PAUSE= 85, AKEYCODE_MEDIA_STOP = 86, AKEYCODE_MEDIA_NEXT = 87, AKEYCODE_MEDIA_PREVIOUS = 88, AKEYCODE_MEDIA_REWIND = 89, AKEYCODE_MEDIA_FAST_FORWARD = 90, AKEYCODE_MUTE = 91, AKEYCODE_PAGE_UP = 92, AKEYCODE_PAGE_DOWN = 93, AKEYCODE_PICTSYMBOLS = 94, AKEYCODE_SWITCH_CHARSET = 95, AKEYCODE_BUTTON_A = 96, AKEYCODE_BUTTON_B = 97, AKEYCODE_BUTTON_C = 98, AKEYCODE_BUTTON_X = 99, AKEYCODE_BUTTON_Y = 100, AKEYCODE_BUTTON_Z = 101, AKEYCODE_BUTTON_L1 = 102, AKEYCODE_BUTTON_R1 = 103, AKEYCODE_BUTTON_L2 = 104, AKEYCODE_BUTTON_R2 = 105, AKEYCODE_BUTTON_THUMBL = 106, AKEYCODE_BUTTON_THUMBR = 107, AKEYCODE_BUTTON_START = 108, AKEYCODE_BUTTON_SELECT = 109, AKEYCODE_BUTTON_MODE = 110, AKEYCODE_ESCAPE = 111, AKEYCODE_FORWARD_DEL = 112, AKEYCODE_CTRL_LEFT = 113, AKEYCODE_CTRL_RIGHT = 114, AKEYCODE_CAPS_LOCK = 115, AKEYCODE_SCROLL_LOCK = 116, AKEYCODE_META_LEFT = 117, AKEYCODE_META_RIGHT = 118, AKEYCODE_FUNCTION = 119, AKEYCODE_SYSRQ = 120, AKEYCODE_BREAK = 121, AKEYCODE_MOVE_HOME = 122, AKEYCODE_MOVE_END = 123, AKEYCODE_INSERT = 124, AKEYCODE_FORWARD = 125, AKEYCODE_MEDIA_PLAY = 126, AKEYCODE_MEDIA_PAUSE = 127, AKEYCODE_MEDIA_CLOSE = 128, AKEYCODE_MEDIA_EJECT = 129, AKEYCODE_MEDIA_RECORD = 130, AKEYCODE_F1 = 131, AKEYCODE_F2 = 132, AKEYCODE_F3 = 133, AKEYCODE_F4 = 134, AKEYCODE_F5 = 135, AKEYCODE_F6 = 136, AKEYCODE_F7 = 137, AKEYCODE_F8 = 138, AKEYCODE_F9 = 139, AKEYCODE_F10 = 140, AKEYCODE_F11 = 141, AKEYCODE_F12 = 142, AKEYCODE_NUM_LOCK = 143, AKEYCODE_NUMPAD_0 = 144, AKEYCODE_NUMPAD_1 = 145, AKEYCODE_NUMPAD_2 = 146, AKEYCODE_NUMPAD_3 = 147, AKEYCODE_NUMPAD_4 = 148, AKEYCODE_NUMPAD_5 = 149, AKEYCODE_NUMPAD_6 = 150, AKEYCODE_NUMPAD_7 = 151, AKEYCODE_NUMPAD_8 = 152, AKEYCODE_NUMPAD_9 = 153, AKEYCODE_NUMPAD_DIVIDE = 154, AKEYCODE_NUMPAD_MULTIPLY = 155, AKEYCODE_NUMPAD_SUBTRACT = 156, AKEYCODE_NUMPAD_ADD = 157, AKEYCODE_NUMPAD_DOT = 158, AKEYCODE_NUMPAD_COMMA = 159, AKEYCODE_NUMPAD_ENTER = 160, AKEYCODE_NUMPAD_EQUALS = 161, AKEYCODE_NUMPAD_LEFT_PAREN = 162, AKEYCODE_NUMPAD_RIGHT_PAREN = 163, AKEYCODE_VOLUME_MUTE = 164, AKEYCODE_INFO = 165, AKEYCODE_CHANNEL_UP = 166, AKEYCODE_CHANNEL_DOWN = 167, AKEYCODE_ZOOM_IN = 168, AKEYCODE_ZOOM_OUT = 169, AKEYCODE_TV = 170, AKEYCODE_WINDOW = 171, AKEYCODE_GUIDE = 172, AKEYCODE_DVR = 173, AKEYCODE_BOOKMARK = 174, AKEYCODE_CAPTIONS = 175, AKEYCODE_SETTINGS = 176, AKEYCODE_TV_POWER = 177, AKEYCODE_TV_INPUT = 178, AKEYCODE_STB_POWER = 179, AKEYCODE_STB_INPUT = 180, AKEYCODE_AVR_POWER = 181, AKEYCODE_AVR_INPUT = 182, AKEYCODE_PROG_RED = 183, AKEYCODE_PROG_GREEN = 184, AKEYCODE_PROG_YELLOW = 185, AKEYCODE_PROG_BLUE = 186, AKEYCODE_APP_SWITCH = 187, AKEYCODE_BUTTON_1 = 188, AKEYCODE_BUTTON_2 = 189, AKEYCODE_BUTTON_3 = 190, AKEYCODE_BUTTON_4 = 191, AKEYCODE_BUTTON_5 = 192, AKEYCODE_BUTTON_6 = 193, AKEYCODE_BUTTON_7 = 194, AKEYCODE_BUTTON_8 = 195, AKEYCODE_BUTTON_9 = 196, AKEYCODE_BUTTON_10 = 197, AKEYCODE_BUTTON_11 = 198, AKEYCODE_BUTTON_12 = 199, AKEYCODE_BUTTON_13 = 200, AKEYCODE_BUTTON_14 = 201, AKEYCODE_BUTTON_15 = 202, AKEYCODE_BUTTON_16 = 203, AKEYCODE_LANGUAGE_SWITCH = 204, AKEYCODE_MANNER_MODE = 205, AKEYCODE_3D_MODE = 206, AKEYCODE_CONTACTS = 207, AKEYCODE_CALENDAR = 208, AKEYCODE_MUSIC = 209, AKEYCODE_CALCULATOR = 210, AKEYCODE_ZENKAKU_HANKAKU = 211, AKEYCODE_EISU = 212, AKEYCODE_MUHENKAN = 213, AKEYCODE_HENKAN = 214, AKEYCODE_KATAKANA_HIRAGANA = 215, AKEYCODE_YEN = 216, AKEYCODE_RO = 217, AKEYCODE_KANA = 218, AKEYCODE_ASSIST = 219 // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. }; #ifdef __cplusplus } #endif #endif // _ANDROID_KEYCODES_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/input.h0000644000015301777760000004002312322054223024103 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROID_INPUT_H #define _ANDROID_INPUT_H /****************************************************************** * * IMPORTANT NOTICE: * * This file is part of Android's set of stable system headers * exposed by the Android NDK (Native Development Kit). * * Third-party source AND binary code relies on the definitions * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. * * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES */ /* * Structures and functions to receive and process input events in * native code. * * NOTE: These functions MUST be implemented by /system/lib/libui.so */ #include #include #ifdef __cplusplus extern "C" { #endif /* * Key states (may be returned by queries about the current state of a * particular key code, scan code or switch). */ enum { /* The key state is unknown or the requested key itself is not supported. */ AKEY_STATE_UNKNOWN = -1, /* The key is up. */ AKEY_STATE_UP = 0, /* The key is down. */ AKEY_STATE_DOWN = 1, /* The key is down but is a virtual key press that is being emulated by the system. */ AKEY_STATE_VIRTUAL = 2 }; /* * Meta key / modifer state. */ enum { /* No meta keys are pressed. */ AMETA_NONE = 0, /* This mask is used to check whether one of the ALT meta keys is pressed. */ AMETA_ALT_ON = 0x02, /* This mask is used to check whether the left ALT meta key is pressed. */ AMETA_ALT_LEFT_ON = 0x10, /* This mask is used to check whether the right ALT meta key is pressed. */ AMETA_ALT_RIGHT_ON = 0x20, /* This mask is used to check whether one of the SHIFT meta keys is pressed. */ AMETA_SHIFT_ON = 0x01, /* This mask is used to check whether the left SHIFT meta key is pressed. */ AMETA_SHIFT_LEFT_ON = 0x40, /* This mask is used to check whether the right SHIFT meta key is pressed. */ AMETA_SHIFT_RIGHT_ON = 0x80, /* This mask is used to check whether the SYM meta key is pressed. */ AMETA_SYM_ON = 0x04, /* This mask is used to check whether the FUNCTION meta key is pressed. */ AMETA_FUNCTION_ON = 0x08, /* This mask is used to check whether one of the CTRL meta keys is pressed. */ AMETA_CTRL_ON = 0x1000, /* This mask is used to check whether the left CTRL meta key is pressed. */ AMETA_CTRL_LEFT_ON = 0x2000, /* This mask is used to check whether the right CTRL meta key is pressed. */ AMETA_CTRL_RIGHT_ON = 0x4000, /* This mask is used to check whether one of the META meta keys is pressed. */ AMETA_META_ON = 0x10000, /* This mask is used to check whether the left META meta key is pressed. */ AMETA_META_LEFT_ON = 0x20000, /* This mask is used to check whether the right META meta key is pressed. */ AMETA_META_RIGHT_ON = 0x40000, /* This mask is used to check whether the CAPS LOCK meta key is on. */ AMETA_CAPS_LOCK_ON = 0x100000, /* This mask is used to check whether the NUM LOCK meta key is on. */ AMETA_NUM_LOCK_ON = 0x200000, /* This mask is used to check whether the SCROLL LOCK meta key is on. */ AMETA_SCROLL_LOCK_ON = 0x400000 }; /* * Input events. * * Input events are opaque structures. Use the provided accessors functions to * read their properties. */ struct AInputEvent; typedef struct AInputEvent AInputEvent; /* * Input event types. */ enum { /* Indicates that the input event is a key event. */ AINPUT_EVENT_TYPE_KEY = 1, /* Indicates that the input event is a motion event. */ AINPUT_EVENT_TYPE_MOTION = 2 }; /* * Key event actions. */ enum { /* The key has been pressed down. */ AKEY_EVENT_ACTION_DOWN = 0, /* The key has been released. */ AKEY_EVENT_ACTION_UP = 1, /* Multiple duplicate key events have occurred in a row, or a complex string is * being delivered. The repeat_count property of the key event contains the number * of times the given key code should be executed. */ AKEY_EVENT_ACTION_MULTIPLE = 2 }; /* * Key event flags. */ enum { /* This mask is set if the device woke because of this key event. */ AKEY_EVENT_FLAG_WOKE_HERE = 0x1, /* This mask is set if the key event was generated by a software keyboard. */ AKEY_EVENT_FLAG_SOFT_KEYBOARD = 0x2, /* This mask is set if we don't want the key event to cause us to leave touch mode. */ AKEY_EVENT_FLAG_KEEP_TOUCH_MODE = 0x4, /* This mask is set if an event was known to come from a trusted part * of the system. That is, the event is known to come from the user, * and could not have been spoofed by a third party component. */ AKEY_EVENT_FLAG_FROM_SYSTEM = 0x8, /* This mask is used for compatibility, to identify enter keys that are * coming from an IME whose enter key has been auto-labelled "next" or * "done". This allows TextView to dispatch these as normal enter keys * for old applications, but still do the appropriate action when * receiving them. */ AKEY_EVENT_FLAG_EDITOR_ACTION = 0x10, /* When associated with up key events, this indicates that the key press * has been canceled. Typically this is used with virtual touch screen * keys, where the user can slide from the virtual key area on to the * display: in that case, the application will receive a canceled up * event and should not perform the action normally associated with the * key. Note that for this to work, the application can not perform an * action for a key until it receives an up or the long press timeout has * expired. */ AKEY_EVENT_FLAG_CANCELED = 0x20, /* This key event was generated by a virtual (on-screen) hard key area. * Typically this is an area of the touchscreen, outside of the regular * display, dedicated to "hardware" buttons. */ AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY = 0x40, /* This flag is set for the first key repeat that occurs after the * long press timeout. */ AKEY_EVENT_FLAG_LONG_PRESS = 0x80, /* Set when a key event has AKEY_EVENT_FLAG_CANCELED set because a long * press action was executed while it was down. */ AKEY_EVENT_FLAG_CANCELED_LONG_PRESS = 0x100, /* Set for AKEY_EVENT_ACTION_UP when this event's key code is still being * tracked from its initial down. That is, somebody requested that tracking * started on the key down and a long press has not caused * the tracking to be canceled. */ AKEY_EVENT_FLAG_TRACKING = 0x200, /* Set when a key event has been synthesized to implement default behavior * for an event that the application did not handle. * Fallback key events are generated by unhandled trackball motions * (to emulate a directional keypad) and by certain unhandled key presses * that are declared in the key map (such as special function numeric keypad * keys when numlock is off). */ AKEY_EVENT_FLAG_FALLBACK = 0x400 }; /* * Motion event actions. */ /* Bit shift for the action bits holding the pointer index as * defined by AMOTION_EVENT_ACTION_POINTER_INDEX_MASK. */ #define AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT 8 enum { /* Bit mask of the parts of the action code that are the action itself. */ AMOTION_EVENT_ACTION_MASK = 0xff, /* Bits in the action code that represent a pointer index, used with * AMOTION_EVENT_ACTION_POINTER_DOWN and AMOTION_EVENT_ACTION_POINTER_UP. Shifting * down by AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT provides the actual pointer * index where the data for the pointer going up or down can be found. */ AMOTION_EVENT_ACTION_POINTER_INDEX_MASK = 0xff00, /* A pressed gesture has started, the motion contains the initial starting location. */ AMOTION_EVENT_ACTION_DOWN = 0, /* A pressed gesture has finished, the motion contains the final release location * as well as any intermediate points since the last down or move event. */ AMOTION_EVENT_ACTION_UP = 1, /* A change has happened during a press gesture (between AMOTION_EVENT_ACTION_DOWN and * AMOTION_EVENT_ACTION_UP). The motion contains the most recent point, as well as * any intermediate points since the last down or move event. */ AMOTION_EVENT_ACTION_MOVE = 2, /* The current gesture has been aborted. * You will not receive any more points in it. You should treat this as * an up event, but not perform any action that you normally would. */ AMOTION_EVENT_ACTION_CANCEL = 3, /* A movement has happened outside of the normal bounds of the UI element. * This does not provide a full gesture, but only the initial location of the movement/touch. */ AMOTION_EVENT_ACTION_OUTSIDE = 4, /* A non-primary pointer has gone down. * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed. */ AMOTION_EVENT_ACTION_POINTER_DOWN = 5, /* A non-primary pointer has gone up. * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed. */ AMOTION_EVENT_ACTION_POINTER_UP = 6, /* A change happened but the pointer is not down (unlike AMOTION_EVENT_ACTION_MOVE). * The motion contains the most recent point, as well as any intermediate points since * the last hover move event. */ AMOTION_EVENT_ACTION_HOVER_MOVE = 7, /* The motion event contains relative vertical and/or horizontal scroll offsets. * Use getAxisValue to retrieve the information from AMOTION_EVENT_AXIS_VSCROLL * and AMOTION_EVENT_AXIS_HSCROLL. * The pointer may or may not be down when this event is dispatched. * This action is always delivered to the winder under the pointer, which * may not be the window currently touched. */ AMOTION_EVENT_ACTION_SCROLL = 8, /* The pointer is not down but has entered the boundaries of a window or view. */ AMOTION_EVENT_ACTION_HOVER_ENTER = 9, /* The pointer is not down but has exited the boundaries of a window or view. */ AMOTION_EVENT_ACTION_HOVER_EXIT = 10 }; /* * Motion event flags. */ enum { /* This flag indicates that the window that received this motion event is partly * or wholly obscured by another visible window above it. This flag is set to true * even if the event did not directly pass through the obscured area. * A security sensitive application can check this flag to identify situations in which * a malicious application may have covered up part of its content for the purpose * of misleading the user or hijacking touches. An appropriate response might be * to drop the suspect touches or to take additional precautions to confirm the user's * actual intent. */ AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED = 0x1 }; /* * Motion event edge touch flags. */ enum { /* No edges intersected */ AMOTION_EVENT_EDGE_FLAG_NONE = 0, /* Flag indicating the motion event intersected the top edge of the screen. */ AMOTION_EVENT_EDGE_FLAG_TOP = 0x01, /* Flag indicating the motion event intersected the bottom edge of the screen. */ AMOTION_EVENT_EDGE_FLAG_BOTTOM = 0x02, /* Flag indicating the motion event intersected the left edge of the screen. */ AMOTION_EVENT_EDGE_FLAG_LEFT = 0x04, /* Flag indicating the motion event intersected the right edge of the screen. */ AMOTION_EVENT_EDGE_FLAG_RIGHT = 0x08 }; /* * Constants that identify each individual axis of a motion event. * Refer to the documentation on the MotionEvent class for descriptions of each axis. */ enum { AMOTION_EVENT_AXIS_X = 0, AMOTION_EVENT_AXIS_Y = 1, AMOTION_EVENT_AXIS_PRESSURE = 2, AMOTION_EVENT_AXIS_SIZE = 3, AMOTION_EVENT_AXIS_TOUCH_MAJOR = 4, AMOTION_EVENT_AXIS_TOUCH_MINOR = 5, AMOTION_EVENT_AXIS_TOOL_MAJOR = 6, AMOTION_EVENT_AXIS_TOOL_MINOR = 7, AMOTION_EVENT_AXIS_ORIENTATION = 8, AMOTION_EVENT_AXIS_VSCROLL = 9, AMOTION_EVENT_AXIS_HSCROLL = 10, AMOTION_EVENT_AXIS_Z = 11, AMOTION_EVENT_AXIS_RX = 12, AMOTION_EVENT_AXIS_RY = 13, AMOTION_EVENT_AXIS_RZ = 14, AMOTION_EVENT_AXIS_HAT_X = 15, AMOTION_EVENT_AXIS_HAT_Y = 16, AMOTION_EVENT_AXIS_LTRIGGER = 17, AMOTION_EVENT_AXIS_RTRIGGER = 18, AMOTION_EVENT_AXIS_THROTTLE = 19, AMOTION_EVENT_AXIS_RUDDER = 20, AMOTION_EVENT_AXIS_WHEEL = 21, AMOTION_EVENT_AXIS_GAS = 22, AMOTION_EVENT_AXIS_BRAKE = 23, AMOTION_EVENT_AXIS_DISTANCE = 24, AMOTION_EVENT_AXIS_TILT = 25, AMOTION_EVENT_AXIS_GENERIC_1 = 32, AMOTION_EVENT_AXIS_GENERIC_2 = 33, AMOTION_EVENT_AXIS_GENERIC_3 = 34, AMOTION_EVENT_AXIS_GENERIC_4 = 35, AMOTION_EVENT_AXIS_GENERIC_5 = 36, AMOTION_EVENT_AXIS_GENERIC_6 = 37, AMOTION_EVENT_AXIS_GENERIC_7 = 38, AMOTION_EVENT_AXIS_GENERIC_8 = 39, AMOTION_EVENT_AXIS_GENERIC_9 = 40, AMOTION_EVENT_AXIS_GENERIC_10 = 41, AMOTION_EVENT_AXIS_GENERIC_11 = 42, AMOTION_EVENT_AXIS_GENERIC_12 = 43, AMOTION_EVENT_AXIS_GENERIC_13 = 44, AMOTION_EVENT_AXIS_GENERIC_14 = 45, AMOTION_EVENT_AXIS_GENERIC_15 = 46, AMOTION_EVENT_AXIS_GENERIC_16 = 47 // NOTE: If you add a new axis here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. }; /* * Constants that identify buttons that are associated with motion events. * Refer to the documentation on the MotionEvent class for descriptions of each button. */ enum { AMOTION_EVENT_BUTTON_PRIMARY = 1 << 0, AMOTION_EVENT_BUTTON_SECONDARY = 1 << 1, AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2, AMOTION_EVENT_BUTTON_BACK = 1 << 3, AMOTION_EVENT_BUTTON_FORWARD = 1 << 4 }; /* * Constants that identify tool types. * Refer to the documentation on the MotionEvent class for descriptions of each tool type. */ enum { AMOTION_EVENT_TOOL_TYPE_UNKNOWN = 0, AMOTION_EVENT_TOOL_TYPE_FINGER = 1, AMOTION_EVENT_TOOL_TYPE_STYLUS = 2, AMOTION_EVENT_TOOL_TYPE_MOUSE = 3, AMOTION_EVENT_TOOL_TYPE_ERASER = 4 }; /* * Input sources. * * Refer to the documentation on android.view.InputDevice for more details about input sources * and their correct interpretation. */ enum { AINPUT_SOURCE_CLASS_MASK = 0x000000ff, AINPUT_SOURCE_CLASS_BUTTON = 0x00000001, AINPUT_SOURCE_CLASS_POINTER = 0x00000002, AINPUT_SOURCE_CLASS_NAVIGATION = 0x00000004, AINPUT_SOURCE_CLASS_POSITION = 0x00000008, AINPUT_SOURCE_CLASS_JOYSTICK = 0x00000010 }; enum { AINPUT_SOURCE_UNKNOWN = 0x00000000, AINPUT_SOURCE_KEYBOARD = 0x00000100 | AINPUT_SOURCE_CLASS_BUTTON, AINPUT_SOURCE_DPAD = 0x00000200 | AINPUT_SOURCE_CLASS_BUTTON, AINPUT_SOURCE_GAMEPAD = 0x00000400 | AINPUT_SOURCE_CLASS_BUTTON, AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER, AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER, AINPUT_SOURCE_STYLUS = 0x00004000 | AINPUT_SOURCE_CLASS_POINTER, AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION, AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION, AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK, AINPUT_SOURCE_ANY = 0xffffff00 }; /* * Keyboard types. * * Refer to the documentation on android.view.InputDevice for more details. */ enum { AINPUT_KEYBOARD_TYPE_NONE = 0, AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC = 1, AINPUT_KEYBOARD_TYPE_ALPHABETIC = 2 }; #ifdef __cplusplus } #endif #endif // _ANDROID_INPUT_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/storage_manager.h0000644000015301777760000000730712322054223026112 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_STORAGE_MANAGER_H #define ANDROID_STORAGE_MANAGER_H #include #ifdef __cplusplus extern "C" { #endif struct AStorageManager; typedef struct AStorageManager AStorageManager; enum { /* * The OBB container is now mounted and ready for use. Can be returned * as the status for callbacks made during asynchronous OBB actions. */ AOBB_STATE_MOUNTED = 1, /* * The OBB container is now unmounted and not usable. Can be returned * as the status for callbacks made during asynchronous OBB actions. */ AOBB_STATE_UNMOUNTED = 2, /* * There was an internal system error encountered while trying to * mount the OBB. Can be returned as the status for callbacks made * during asynchronous OBB actions. */ AOBB_STATE_ERROR_INTERNAL = 20, /* * The OBB could not be mounted by the system. Can be returned as the * status for callbacks made during asynchronous OBB actions. */ AOBB_STATE_ERROR_COULD_NOT_MOUNT = 21, /* * The OBB could not be unmounted. This most likely indicates that a * file is in use on the OBB. Can be returned as the status for * callbacks made during asynchronous OBB actions. */ AOBB_STATE_ERROR_COULD_NOT_UNMOUNT = 22, /* * A call was made to unmount the OBB when it was not mounted. Can be * returned as the status for callbacks made during asynchronous OBB * actions. */ AOBB_STATE_ERROR_NOT_MOUNTED = 23, /* * The OBB has already been mounted. Can be returned as the status for * callbacks made during asynchronous OBB actions. */ AOBB_STATE_ERROR_ALREADY_MOUNTED = 24, /* * The current application does not have permission to use this OBB. * This could be because the OBB indicates it's owned by a different * package. Can be returned as the status for callbacks made during * asynchronous OBB actions. */ AOBB_STATE_ERROR_PERMISSION_DENIED = 25, }; /** * Obtains a new instance of AStorageManager. */ AStorageManager* AStorageManager_new(); /** * Release AStorageManager instance. */ void AStorageManager_delete(AStorageManager* mgr); /** * Callback function for asynchronous calls made on OBB files. */ typedef void (*AStorageManager_obbCallbackFunc)(const char* filename, const int32_t state, void* data); /** * Attempts to mount an OBB file. This is an asynchronous operation. */ void AStorageManager_mountObb(AStorageManager* mgr, const char* filename, const char* key, AStorageManager_obbCallbackFunc cb, void* data); /** * Attempts to unmount an OBB file. This is an asynchronous operation. */ void AStorageManager_unmountObb(AStorageManager* mgr, const char* filename, const int force, AStorageManager_obbCallbackFunc cb, void* data); /** * Check whether an OBB is mounted. */ int AStorageManager_isObbMounted(AStorageManager* mgr, const char* filename); /** * Get the mounted path for an OBB. */ const char* AStorageManager_getMountedObbPath(AStorageManager* mgr, const char* filename); #ifdef __cplusplus }; #endif #endif // ANDROID_STORAGE_MANAGER_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/sensor.h0000644000015301777760000001535712322054223024271 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_SENSOR_H #define ANDROID_SENSOR_H /****************************************************************** * * IMPORTANT NOTICE: * * This file is part of Android's set of stable system headers * exposed by the Android NDK (Native Development Kit). * * Third-party source AND binary code relies on the definitions * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. * * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES */ /* * Structures and functions to receive and process sensor events in * native code. * */ #include #include #ifdef __cplusplus extern "C" { #endif /* * Sensor types * (keep in sync with hardware/sensor.h) */ enum { ASENSOR_TYPE_ACCELEROMETER = 1, ASENSOR_TYPE_MAGNETIC_FIELD = 2, ASENSOR_TYPE_GYROSCOPE = 4, ASENSOR_TYPE_LIGHT = 5, ASENSOR_TYPE_PROXIMITY = 8 }; /* * Sensor accuracy measure */ enum { ASENSOR_STATUS_UNRELIABLE = 0, ASENSOR_STATUS_ACCURACY_LOW = 1, ASENSOR_STATUS_ACCURACY_MEDIUM = 2, ASENSOR_STATUS_ACCURACY_HIGH = 3 }; /* * A few useful constants */ /* Earth's gravity in m/s^2 */ #define ASENSOR_STANDARD_GRAVITY (9.80665f) /* Maximum magnetic field on Earth's surface in uT */ #define ASENSOR_MAGNETIC_FIELD_EARTH_MAX (60.0f) /* Minimum magnetic field on Earth's surface in uT*/ #define ASENSOR_MAGNETIC_FIELD_EARTH_MIN (30.0f) /* * A sensor event. */ /* NOTE: Must match hardware/sensors.h */ typedef struct ASensorVector { union { float v[3]; struct { float x; float y; float z; }; struct { float azimuth; float pitch; float roll; }; }; int8_t status; uint8_t reserved[3]; } ASensorVector; /* NOTE: Must match hardware/sensors.h */ typedef struct ASensorEvent { int32_t version; /* sizeof(struct ASensorEvent) */ int32_t sensor; int32_t type; int32_t reserved0; int64_t timestamp; union { float data[16]; ASensorVector vector; ASensorVector acceleration; ASensorVector magnetic; float temperature; float distance; float light; float pressure; }; int32_t reserved1[4]; } ASensorEvent; struct ASensorManager; typedef struct ASensorManager ASensorManager; struct ASensorEventQueue; typedef struct ASensorEventQueue ASensorEventQueue; struct ASensor; typedef struct ASensor ASensor; typedef ASensor const* ASensorRef; typedef ASensorRef const* ASensorList; /*****************************************************************************/ /* * Get a reference to the sensor manager. ASensorManager is a singleton. * * Example: * * ASensorManager* sensorManager = ASensorManager_getInstance(); * */ ASensorManager* ASensorManager_getInstance(); /* * Returns the list of available sensors. */ int ASensorManager_getSensorList(ASensorManager* manager, ASensorList* list); /* * Returns the default sensor for the given type, or NULL if no sensor * of that type exist. */ ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type); /* * Creates a new sensor event queue and associate it with a looper. */ ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager, ALooper* looper, int ident, ALooper_callbackFunc callback, void* data); /* * Destroys the event queue and free all resources associated to it. */ int ASensorManager_destroyEventQueue(ASensorManager* manager, ASensorEventQueue* queue); /*****************************************************************************/ /* * Enable the selected sensor. Returns a negative error code on failure. */ int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor); /* * Disable the selected sensor. Returns a negative error code on failure. */ int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor const* sensor); /* * Sets the delivery rate of events in microseconds for the given sensor. * Note that this is a hint only, generally event will arrive at a higher * rate. It is an error to set a rate inferior to the value returned by * ASensor_getMinDelay(). * Returns a negative error code on failure. */ int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor const* sensor, int32_t usec); /* * Returns true if there are one or more events available in the * sensor queue. Returns 1 if the queue has events; 0 if * it does not have events; and a negative value if there is an error. */ int ASensorEventQueue_hasEvents(ASensorEventQueue* queue); /* * Returns the next available events from the queue. Returns a negative * value if no events are available or an error has occurred, otherwise * the number of events returned. * * Examples: * ASensorEvent event; * ssize_t numEvent = ASensorEventQueue_getEvents(queue, &event, 1); * * ASensorEvent eventBuffer[8]; * ssize_t numEvent = ASensorEventQueue_getEvents(queue, eventBuffer, 8); * */ ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count); /*****************************************************************************/ /* * Returns this sensor's name (non localized) */ const char* ASensor_getName(ASensor const* sensor); /* * Returns this sensor's vendor's name (non localized) */ const char* ASensor_getVendor(ASensor const* sensor); /* * Return this sensor's type */ int ASensor_getType(ASensor const* sensor); /* * Returns this sensors's resolution */ float ASensor_getResolution(ASensor const* sensor); /* * Returns the minimum delay allowed between events in microseconds. * A value of zero means that this sensor doesn't report events at a * constant rate, but rather only when a new data is available. */ int ASensor_getMinDelay(ASensor const* sensor); #ifdef __cplusplus }; #endif #endif // ANDROID_SENSOR_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/looper.h0000644000015301777760000002200012322054223024237 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_LOOPER_H #define ANDROID_LOOPER_H #ifdef __cplusplus extern "C" { #endif /** * ALooper * * A looper is the state tracking an event loop for a thread. * Loopers do not define event structures or other such things; rather * they are a lower-level facility to attach one or more discrete objects * listening for an event. An "event" here is simply data available on * a file descriptor: each attached object has an associated file descriptor, * and waiting for "events" means (internally) polling on all of these file * descriptors until one or more of them have data available. * * A thread can have only one ALooper associated with it. */ struct ALooper; typedef struct ALooper ALooper; /** * Returns the looper associated with the calling thread, or NULL if * there is not one. */ ALooper* ALooper_forThread(); enum { /** * Option for ALooper_prepare: this looper will accept calls to * ALooper_addFd() that do not have a callback (that is provide NULL * for the callback). In this case the caller of ALooper_pollOnce() * or ALooper_pollAll() MUST check the return from these functions to * discover when data is available on such fds and process it. */ ALOOPER_PREPARE_ALLOW_NON_CALLBACKS = 1<<0 }; /** * Prepares a looper associated with the calling thread, and returns it. * If the thread already has a looper, it is returned. Otherwise, a new * one is created, associated with the thread, and returned. * * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0. */ ALooper* ALooper_prepare(int opts); enum { /** * Result from ALooper_pollOnce() and ALooper_pollAll(): * The poll was awoken using wake() before the timeout expired * and no callbacks were executed and no other file descriptors were ready. */ ALOOPER_POLL_WAKE = -1, /** * Result from ALooper_pollOnce() and ALooper_pollAll(): * One or more callbacks were executed. */ ALOOPER_POLL_CALLBACK = -2, /** * Result from ALooper_pollOnce() and ALooper_pollAll(): * The timeout expired. */ ALOOPER_POLL_TIMEOUT = -3, /** * Result from ALooper_pollOnce() and ALooper_pollAll(): * An error occurred. */ ALOOPER_POLL_ERROR = -4 }; /** * Acquire a reference on the given ALooper object. This prevents the object * from being deleted until the reference is removed. This is only needed * to safely hand an ALooper from one thread to another. */ void ALooper_acquire(ALooper* looper); /** * Remove a reference that was previously acquired with ALooper_acquire(). */ void ALooper_release(ALooper* looper); /** * Flags for file descriptor events that a looper can monitor. * * These flag bits can be combined to monitor multiple events at once. */ enum { /** * The file descriptor is available for read operations. */ ALOOPER_EVENT_INPUT = 1 << 0, /** * The file descriptor is available for write operations. */ ALOOPER_EVENT_OUTPUT = 1 << 1, /** * The file descriptor has encountered an error condition. * * The looper always sends notifications about errors; it is not necessary * to specify this event flag in the requested event set. */ ALOOPER_EVENT_ERROR = 1 << 2, /** * The file descriptor was hung up. * For example, indicates that the remote end of a pipe or socket was closed. * * The looper always sends notifications about hangups; it is not necessary * to specify this event flag in the requested event set. */ ALOOPER_EVENT_HANGUP = 1 << 3, /** * The file descriptor is invalid. * For example, the file descriptor was closed prematurely. * * The looper always sends notifications about invalid file descriptors; it is not necessary * to specify this event flag in the requested event set. */ ALOOPER_EVENT_INVALID = 1 << 4 }; /** * For callback-based event loops, this is the prototype of the function * that is called when a file descriptor event occurs. * It is given the file descriptor it is associated with, * a bitmask of the poll events that were triggered (typically ALOOPER_EVENT_INPUT), * and the data pointer that was originally supplied. * * Implementations should return 1 to continue receiving callbacks, or 0 * to have this file descriptor and callback unregistered from the looper. */ typedef int (*ALooper_callbackFunc)(int fd, int events, void* data); /** * Waits for events to be available, with optional timeout in milliseconds. * Invokes callbacks for all file descriptors on which an event occurred. * * If the timeout is zero, returns immediately without blocking. * If the timeout is negative, waits indefinitely until an event appears. * * Returns ALOOPER_POLL_WAKE if the poll was awoken using wake() before * the timeout expired and no callbacks were invoked and no other file * descriptors were ready. * * Returns ALOOPER_POLL_CALLBACK if one or more callbacks were invoked. * * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given * timeout expired. * * Returns ALOOPER_POLL_ERROR if an error occurred. * * Returns a value >= 0 containing an identifier if its file descriptor has data * and it has no callback function (requiring the caller here to handle it). * In this (and only this) case outFd, outEvents and outData will contain the poll * events and data associated with the fd, otherwise they will be set to NULL. * * This method does not return until it has finished invoking the appropriate callbacks * for all file descriptors that were signalled. */ int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outData); /** * Like ALooper_pollOnce(), but performs all pending callbacks until all * data has been consumed or a file descriptor is available with no callback. * This function will never return ALOOPER_POLL_CALLBACK. */ int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData); /** * Wakes the poll asynchronously. * * This method can be called on any thread. * This method returns immediately. */ void ALooper_wake(ALooper* looper); /** * Adds a new file descriptor to be polled by the looper. * If the same file descriptor was previously added, it is replaced. * * "fd" is the file descriptor to be added. * "ident" is an identifier for this event, which is returned from ALooper_pollOnce(). * The identifier must be >= 0, or ALOOPER_POLL_CALLBACK if providing a non-NULL callback. * "events" are the poll events to wake up on. Typically this is ALOOPER_EVENT_INPUT. * "callback" is the function to call when there is an event on the file descriptor. * "data" is a private data pointer to supply to the callback. * * There are two main uses of this function: * * (1) If "callback" is non-NULL, then this function will be called when there is * data on the file descriptor. It should execute any events it has pending, * appropriately reading from the file descriptor. The 'ident' is ignored in this case. * * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce * when its file descriptor has data available, requiring the caller to take * care of processing it. * * Returns 1 if the file descriptor was added or -1 if an error occurred. * * This method can be called on any thread. * This method may block briefly if it needs to wake the poll. */ int ALooper_addFd(ALooper* looper, int fd, int ident, int events, ALooper_callbackFunc callback, void* data); /** * Removes a previously added file descriptor from the looper. * * When this method returns, it is safe to close the file descriptor since the looper * will no longer have a reference to it. However, it is possible for the callback to * already be running or for it to run one last time if the file descriptor was already * signalled. Calling code is responsible for ensuring that this case is safely handled. * For example, if the callback takes care of removing itself during its own execution either * by returning 0 or by calling this method, then it can be guaranteed to not be invoked * again at any later time unless registered anew. * * Returns 1 if the file descriptor was removed, 0 if none was previously registered * or -1 if an error occurred. * * This method can be called on any thread. * This method may block briefly if it needs to wake the poll. */ int ALooper_removeFd(ALooper* looper, int fd); #ifdef __cplusplus } #endif #endif // ANDROID_NATIVE_WINDOW_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/native_activity.h0000644000015301777760000002515612322054223026160 0ustar pbusernogroup00000000000000/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_NATIVE_ACTIVITY_H #define ANDROID_NATIVE_ACTIVITY_H #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif struct ANativeActivityCallbacks; /** * This structure defines the native side of an android.app.NativeActivity. * It is created by the framework, and handed to the application's native * code as it is being launched. */ typedef struct ANativeActivity { /** * Pointer to the callback function table of the native application. * You can set the functions here to your own callbacks. The callbacks * pointer itself here should not be changed; it is allocated and managed * for you by the framework. */ struct ANativeActivityCallbacks* callbacks; /** * The global handle on the process's Java VM. */ JavaVM* vm; /** * JNI context for the main thread of the app. Note that this field * can ONLY be used from the main thread of the process; that is, the * thread that calls into the ANativeActivityCallbacks. */ JNIEnv* env; /** * The NativeActivity object handle. * * IMPORTANT NOTE: This member is mis-named. It should really be named * 'activity' instead of 'clazz', since it's a reference to the * NativeActivity instance created by the system for you. * * We unfortunately cannot change this without breaking NDK * source-compatibility. */ jobject clazz; /** * Path to this application's internal data directory. */ const char* internalDataPath; /** * Path to this application's external (removable/mountable) data directory. */ const char* externalDataPath; /** * The platform's SDK version code. */ int32_t sdkVersion; /** * This is the native instance of the application. It is not used by * the framework, but can be set by the application to its own instance * state. */ void* instance; /** * Pointer to the Asset Manager instance for the application. The application * uses this to access binary assets bundled inside its own .apk file. */ AAssetManager* assetManager; } ANativeActivity; /** * These are the callbacks the framework makes into a native application. * All of these callbacks happen on the main thread of the application. * By default, all callbacks are NULL; set to a pointer to your own function * to have it called. */ typedef struct ANativeActivityCallbacks { /** * NativeActivity has started. See Java documentation for Activity.onStart() * for more information. */ void (*onStart)(ANativeActivity* activity); /** * NativeActivity has resumed. See Java documentation for Activity.onResume() * for more information. */ void (*onResume)(ANativeActivity* activity); /** * Framework is asking NativeActivity to save its current instance state. * See Java documentation for Activity.onSaveInstanceState() for more * information. The returned pointer needs to be created with malloc(); * the framework will call free() on it for you. You also must fill in * outSize with the number of bytes in the allocation. Note that the * saved state will be persisted, so it can not contain any active * entities (pointers to memory, file descriptors, etc). */ void* (*onSaveInstanceState)(ANativeActivity* activity, size_t* outSize); /** * NativeActivity has paused. See Java documentation for Activity.onPause() * for more information. */ void (*onPause)(ANativeActivity* activity); /** * NativeActivity has stopped. See Java documentation for Activity.onStop() * for more information. */ void (*onStop)(ANativeActivity* activity); /** * NativeActivity is being destroyed. See Java documentation for Activity.onDestroy() * for more information. */ void (*onDestroy)(ANativeActivity* activity); /** * Focus has changed in this NativeActivity's window. This is often used, * for example, to pause a game when it loses input focus. */ void (*onWindowFocusChanged)(ANativeActivity* activity, int hasFocus); /** * The drawing window for this native activity has been created. You * can use the given native window object to start drawing. */ void (*onNativeWindowCreated)(ANativeActivity* activity, ANativeWindow* window); /** * The drawing window for this native activity has been resized. You should * retrieve the new size from the window and ensure that your rendering in * it now matches. */ void (*onNativeWindowResized)(ANativeActivity* activity, ANativeWindow* window); /** * The drawing window for this native activity needs to be redrawn. To avoid * transient artifacts during screen changes (such resizing after rotation), * applications should not return from this function until they have finished * drawing their window in its current state. */ void (*onNativeWindowRedrawNeeded)(ANativeActivity* activity, ANativeWindow* window); /** * The drawing window for this native activity is going to be destroyed. * You MUST ensure that you do not touch the window object after returning * from this function: in the common case of drawing to the window from * another thread, that means the implementation of this callback must * properly synchronize with the other thread to stop its drawing before * returning from here. */ void (*onNativeWindowDestroyed)(ANativeActivity* activity, ANativeWindow* window); /** * The input queue for this native activity's window has been created. * You can use the given input queue to start retrieving input events. */ void (*onInputQueueCreated)(ANativeActivity* activity, AInputQueue* queue); /** * The input queue for this native activity's window is being destroyed. * You should no longer try to reference this object upon returning from this * function. */ void (*onInputQueueDestroyed)(ANativeActivity* activity, AInputQueue* queue); /** * The rectangle in the window in which content should be placed has changed. */ void (*onContentRectChanged)(ANativeActivity* activity, const ARect* rect); /** * The current device AConfiguration has changed. The new configuration can * be retrieved from assetManager. */ void (*onConfigurationChanged)(ANativeActivity* activity); /** * The system is running low on memory. Use this callback to release * resources you do not need, to help the system avoid killing more * important processes. */ void (*onLowMemory)(ANativeActivity* activity); } ANativeActivityCallbacks; /** * This is the function that must be in the native code to instantiate the * application's native activity. It is called with the activity instance (see * above); if the code is being instantiated from a previously saved instance, * the savedState will be non-NULL and point to the saved data. You must make * any copy of this data you need -- it will be released after you return from * this function. */ typedef void ANativeActivity_createFunc(ANativeActivity* activity, void* savedState, size_t savedStateSize); /** * The name of the function that NativeInstance looks for when launching its * native code. This is the default function that is used, you can specify * "android.app.func_name" string meta-data in your manifest to use a different * function. */ extern ANativeActivity_createFunc ANativeActivity_onCreate; /** * Finish the given activity. Its finish() method will be called, causing it * to be stopped and destroyed. Note that this method can be called from * *any* thread; it will send a message to the main thread of the process * where the Java finish call will take place. */ void ANativeActivity_finish(ANativeActivity* activity); /** * Change the window format of the given activity. Calls getWindow().setFormat() * of the given activity. Note that this method can be called from * *any* thread; it will send a message to the main thread of the process * where the Java finish call will take place. */ void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format); /** * Change the window flags of the given activity. Calls getWindow().setFlags() * of the given activity. Note that this method can be called from * *any* thread; it will send a message to the main thread of the process * where the Java finish call will take place. See window.h for flag constants. */ void ANativeActivity_setWindowFlags(ANativeActivity* activity, uint32_t addFlags, uint32_t removeFlags); /** * Flags for ANativeActivity_showSoftInput; see the Java InputMethodManager * API for documentation. */ enum { ANATIVEACTIVITY_SHOW_SOFT_INPUT_IMPLICIT = 0x0001, ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED = 0x0002, }; /** * Show the IME while in the given activity. Calls InputMethodManager.showSoftInput() * for the given activity. Note that this method can be called from * *any* thread; it will send a message to the main thread of the process * where the Java finish call will take place. */ void ANativeActivity_showSoftInput(ANativeActivity* activity, uint32_t flags); /** * Flags for ANativeActivity_hideSoftInput; see the Java InputMethodManager * API for documentation. */ enum { ANATIVEACTIVITY_HIDE_SOFT_INPUT_IMPLICIT_ONLY = 0x0001, ANATIVEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS = 0x0002, }; /** * Hide the IME while in the given activity. Calls InputMethodManager.hideSoftInput() * for the given activity. Note that this method can be called from * *any* thread; it will send a message to the main thread of the process * where the Java finish call will take place. */ void ANativeActivity_hideSoftInput(ANativeActivity* activity, uint32_t flags); #ifdef __cplusplus }; #endif #endif // ANDROID_NATIVE_ACTIVITY_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/android/log.h0000644000015301777760000000742612322054223023537 0ustar pbusernogroup00000000000000/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROID_LOG_H #define _ANDROID_LOG_H /****************************************************************** * * IMPORTANT NOTICE: * * This file is part of Android's set of stable system headers * exposed by the Android NDK (Native Development Kit) since * platform release 1.5 * * Third-party source AND binary code relies on the definitions * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. * * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES */ /* * Support routines to send messages to the Android in-kernel log buffer, * which can later be accessed through the 'logcat' utility. * * Each log message must have * - a priority * - a log tag * - some text * * The tag normally corresponds to the component that emits the log message, * and should be reasonably small. * * Log message text may be truncated to less than an implementation-specific * limit (e.g. 1023 characters max). * * Note that a newline character ("\n") will be appended automatically to your * log message, if not already there. It is not possible to send several messages * and have them appear on a single line in logcat. * * PLEASE USE LOGS WITH MODERATION: * * - Sending log messages eats CPU and slow down your application and the * system. * * - The circular log buffer is pretty small (<64KB), sending many messages * might push off other important log messages from the rest of the system. * * - In release builds, only send log messages to account for exceptional * conditions. * * NOTE: These functions MUST be implemented by /system/lib/liblog.so */ #include #ifdef __cplusplus extern "C" { #endif /* * Android log priority values, in ascending priority order. */ typedef enum android_LogPriority { ANDROID_LOG_UNKNOWN = 0, ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */ ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_SILENT /* only for SetMinPriority(); must be last */ } android_LogPriority; /* * Send a simple string to the log. */ int __android_log_write(int prio, const char *tag, const char *text); /* * Send a formatted string to the log, used like printf(fmt,...) */ int __android_log_print(int prio, const char *tag, const char *fmt, ...) #if defined(__GNUC__) __attribute__ ((format(printf, 3, 4))) #endif ; /* * A variant of __android_log_print() that takes a va_list to list * additional parameters. */ int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap); /* * Log an assertion failure and SIGTRAP the process to have a chance * to inspect it, if a debugger is attached. This uses the FATAL priority. */ void __android_log_assert(const char *cond, const char *tag, const char *fmt, ...) #if defined(__GNUC__) __attribute__ ((noreturn)) __attribute__ ((format(printf, 3, 4))) #endif ; #ifdef __cplusplus } #endif #endif /* _ANDROID_LOG_H */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/0000755000015301777760000000000012322054703021751 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/KeyedVector.h0000644000015301777760000000154012322054223024343 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_KEYEDVECTOR_H_ #define MIR_ANDROID_UBUNTU_KEYEDVECTOR_H_ #include #endif /* MIR_ANDROID_UBUNTU_KEYEDVECTOR_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/FileMap.h0000644000015301777760000000152012322054223023432 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_FILEMAP_H_ #define MIR_ANDROID_UBUNTU_FILEMAP_H_ #include #endif /* MIR_ANDROID_UBUNTU_FILEMAP_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/Timers.h0000644000015301777760000000151412322054223023363 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_TIMERS_H_ #define MIR_ANDROID_UBUNTU_TIMERS_H_ #include #endif /* MIR_ANDROID_UBUNTU_TIMERS_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/TextOutput.h0000644000015301777760000000164412322054223024271 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_TEXTOUTPUT_H_ #define MIR_ANDROID_UBUNTU_TEXTOUTPUT_H_ namespace android { inline class TextOutput& operator<<(TextOutput& to, const void*) { return to; } } #endif /* MIR_ANDROID_UBUNTU_TEXTOUTPUT_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/SortedVector.h0000644000015301777760000001176712322054223024556 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_SORTEDVECTOR_H_ #define MIR_ANDROID_UBUNTU_SORTEDVECTOR_H_ #include #include #include namespace mir_input { template class SortedVector : std::vector { typedef std::vector Impl; using Impl::begin; using Impl::end; using Impl::insert; using Impl::erase; using Impl::operator[]; public: using Impl::empty; using Impl::clear; using Impl::size; /* * the following inlines add some level of compatibility with android utils. * Stuff that is commented out isn't used in the input stack */ // typedef ValueType value_type; // // /*! // * Constructors and destructors // */ // // SortedVector(); // SortedVector(const SortedVector& rhs); // virtual ~SortedVector(); // // /*! copy operator */ // const SortedVector& operator = (const SortedVector& rhs) const; // SortedVector& operator = (const SortedVector& rhs); /*! * vector stats */ //! returns wether or not the vector is empty bool isEmpty() const { return empty(); } // //! returns how many items can be stored without reallocating the backing store // inline size_t capacity() const { return VectorImpl::capacity(); } // //! setst the capacity. capacity can never be reduced less than size() // inline ssize_t setCapacity(size_t size) { return VectorImpl::setCapacity(size); } // // /*! // * C-style array access // */ // // //! read-only C-style access // inline const ValueType* array() const; // // //! read-write C-style access. BE VERY CAREFUL when modifying the array // //! you ust keep it sorted! You usually don't use this function. // ValueType* editArray(); //! finds the index of an item ssize_t indexOf(const ValueType& item) const { auto p = lower_bound(begin(), end(), item); if (p != end() && *p == item) return distance(begin(), p); else return NAME_NOT_FOUND; } // //! finds where this item should be inserted // size_t orderOf(const ValueType& item) const; /*! * accessors */ // //! read-only access to an item at a given index // inline const ValueType& operator [] (size_t index) const; //! alternate name for operator [] const ValueType& itemAt(size_t index) const { return operator[](index); } // stack-usage of the vector. returns the top of the stack (last element) // const ValueType& top() const; // //! same as operator [], but allows to access the vector backward (from the end) with a negative index // const ValueType& mirrorItemAt(ssize_t index) const; // /*! * modifing the array */ //! add an item in the right place (and replace the one that is there) ssize_t add(const ValueType& item) { auto pos = lower_bound(begin(), end(), item); if (pos == end() || !(*pos == item)) pos = insert(pos, item); else *pos = item; return distance(begin(), pos); } //! editItemAt() MUST NOT change the order of this item ValueType& editItemAt(size_t index) { return operator[](index); } // //! merges a vector into this one // ssize_t merge(const Vector& vector); // ssize_t merge(const SortedVector& vector); //! removes an item ssize_t remove(const ValueType& item) { auto remove_pos = lower_bound(begin(), end(), item); if (remove_pos != end() && *remove_pos == item) { auto removed_at = erase(remove_pos); return distance(begin(), removed_at); } return NAME_NOT_FOUND; } //! remove several items ssize_t removeItemsAt(size_t index, size_t count = 1) { if (index+count > size()) return BAD_VALUE; auto i = begin() + index; erase(i, i+count); return index; } // //! remove one item // inline ssize_t removeAt(size_t index) { return removeItemsAt(index); } }; } namespace android { using ::mir_input::SortedVector; } // namespace android #endif /* MIR_ANDROID_UBUNTU_SORTEDVECTOR_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/Thread.h0000644000015301777760000000770212322054223023334 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_THREAD_H_ #define MIR_ANDROID_UBUNTU_THREAD_H_ #include #include #include #include #include #include #ifdef HAVE_PTHREADS #include #endif namespace mir_input { class Thread : virtual public RefBase { public: // Create a Thread object, but doesn't create or start the associated // thread. See the run() method. Thread(bool canCallJava = true) : exit_pending(false), thread(), status(NO_ERROR) { (void)canCallJava; } virtual ~Thread() { } // Start the thread in threadLoop() which needs to be implemented. virtual status_t run( const char* name = 0, int32_t priority = PRIORITY_DEFAULT, size_t stack = 0) { (void)name; (void)priority; (void)stack; status.store(NO_ERROR); exit_pending.store(false); thread = std::thread([this]() -> void { if (auto result = readyToRun()) status.store(result); else while (!exitPending() && threadLoop()); }); #ifdef HAVE_PTHREADS if (priority != PRIORITY_DEFAULT) { sched_param param; int policy; pthread_getschedparam(thread.native_handle(), &policy, ¶m); param.sched_priority = priority; pthread_setschedparam(thread.native_handle(), policy, ¶m); } #endif return OK; } // Ask this object's thread to exit. This function is asynchronous, when the // function returns the thread might still be running. Of course, this // function can be called from a different thread. virtual void requestExit() { exit_pending.store(true); } // Good place to do one-time initializations virtual status_t readyToRun() { return OK; } // Call requestExit() and wait until this object's thread exits. // BE VERY CAREFUL of deadlocks. In particular, it would be silly to call // this function from this object's thread. Will return WOULD_BLOCK in // that case. virtual status_t requestExitAndWait() { requestExit(); return join(); } // Wait until this object's thread exits. Returns immediately if not yet running. // Do not call from this object's thread; will return WOULD_BLOCK in that case. status_t join() { if (thread.joinable()) thread.join(); return status.load(); } protected: // exitPending() returns true if requestExit() has been called. bool exitPending() const { return exit_pending.load(); } private: // Derived class must implement threadLoop(). The thread starts its life // here. There are two ways of using the Thread object: // 1) loop: if threadLoop() returns true, it will be called again if // requestExit() wasn't called. // 2) once: if threadLoop() returns false, the thread will exit upon return. virtual bool threadLoop() = 0; private: std::atomic exit_pending; std::thread thread; std::atomic status; Thread(const Thread&) = delete; Thread& operator=(const Thread&) = delete; }; } namespace android { using ::mir_input::Thread; } #endif /* MIR_ANDROID_UBUNTU_THREAD_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/List.h0000644000015301777760000000150412322054223023032 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_LIST_H_ #define MIR_ANDROID_UBUNTU_LIST_H_ #include #endif /* MIR_ANDROID_UBUNTU_LIST_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/StrongPointer.h0000644000015301777760000000155012322054223024735 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_STRONGPOINTER_H_ #define MIR_ANDROID_UBUNTU_STRONGPOINTER_H_ #include #endif /* MIR_ANDROID_UBUNTU_STRONGPOINTER_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/Mutex.h0000644000015301777760000000164112322054223023223 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_MUTEX_H_ #define MIR_ANDROID_UBUNTU_MUTEX_H_ #include namespace android { typedef std::mutex Mutex; typedef std::lock_guard AutoMutex; } #endif /* MIR_ANDROID_UBUNTU_MUTEX_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/TypeHelpers.h0000644000015301777760000000154012322054223024363 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_TYPEHELPERS_H_ #define MIR_ANDROID_UBUNTU_TYPEHELPERS_H_ #include #endif /* MIR_ANDROID_UBUNTU_TYPEHELPERS_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/Tokenizer.h0000644000015301777760000000153012322054223024070 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_TOKENIZER_H_ #define MIR_ANDROID_UBUNTU_TOKENIZER_H_ #include #endif /* MIR_ANDROID_UBUNTU_TOKENIZER_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/Vector.h0000644000015301777760000001432512322054223023366 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_VECTOR_H_ #define MIR_ANDROID_UBUNTU_VECTOR_H_ #include namespace mir_input { template class Vector : std::vector // NB private inheritance of implementation { typedef std::vector Impl; public: using typename Impl::value_type; using typename Impl::iterator; using typename Impl::const_iterator; using Impl::clear; using Impl::size; using Impl::capacity; using Impl::begin; using Impl::end; using Impl::reserve; using Impl::empty; using Impl::push_back; using Impl::erase; using Impl::insert; using Impl::at; using Impl::operator[]; /* * the following inlines add some level of compatibility with android utils. * Stuff that is commented out isn't used in the input stack */ /*! * Constructors and destructors */ Vector() = default; Vector(const Vector& /* rhs */) = default; // explicit Vector(const SortedVector& rhs); virtual ~Vector() {} /*! copy operator */ // const Vector& operator = (const Vector& rhs) const; Vector& operator=(const Vector& /* rhs */) = default; // const Vector& operator = (const SortedVector& rhs) const; // Vector& operator = (const SortedVector& rhs); /*! * vector stats */ //! returns wether or not the vector is empty inline bool isEmpty() const { return empty(); } //! setst the capacity. capacity can never be reduced less than size() inline ssize_t setCapacity(size_t size) { reserve(size); return size; } /*! * C-style array access */ //! read-only C-style access inline const ValueType* array() const { return Impl::data(); } //! read-write C-style access ValueType* editArray() { return Impl::data(); } /*! * accessors */ //! alternate name for operator [] inline const ValueType& itemAt(size_t index) const { return at(index); } //! stack-usage of the vector. returns the top of the stack (last element) const ValueType& top() const { return Impl::back(); } // //! same as operator [], but allows to access the vector backward (from the end) with a negative index // const ValueType& mirrorItemAt(ssize_t index) const { return at((index >= 0) ? index : size()+index); } /*! * modifing the array */ //! copy-on write support, grants write access to an item ValueType& editItemAt(size_t index) { return Impl::operator[](index); } //! grants right acces to the top of the stack (last element) ValueType& editTop() { return Impl::back(); } /*! * append/insert another vector */ // //! insert another vector at a given index // ssize_t insertVectorAt(const Vector& vector, size_t index); //! append another vector at the end of this one ssize_t appendVector(const Vector& vector) { auto result = size(); insert(end(), vector.begin(), vector.end()); return result; } // //! insert an array at a given index // ssize_t insertArrayAt(const ValueType* array, size_t index, size_t length); //! append an array at the end of this vector ssize_t appendArray(const ValueType* array, size_t length) { auto result = size(); insert(end(), array, array + length); return result; } /*! * add/insert/replace items */ //! insert one or several items initialized with their default constructor inline ssize_t insertAt(size_t index, size_t numItems = 1) { return insertAt(ValueType(), index, numItems); } //! insert one or several items initialized from a prototype item ssize_t insertAt(const ValueType& prototype_item, size_t index, size_t numItems = 1) { insert(begin()+index, numItems, prototype_item); return index; } //! pop the top of the stack (removes the last element). No-op if the stack's empty inline void pop() { if (!empty()) erase(--end()); } //! pushes an item initialized with its default constructor inline void push() { push_back(ValueType()); } //! pushes an item on the top of the stack void push(const ValueType& item) { push_back(item); } //! same as push() but returns the index the item was added at (or an error) inline ssize_t add() { auto result = size(); push(); return result; } //! same as push() but returns the index the item was added at (or an error) ssize_t add(const ValueType& item) { auto result = size(); push(item); return result; } // //! replace an item with a new one initialized with its default constructor // inline ssize_t replaceAt(size_t index); // //! replace an item with a new one // ssize_t replaceAt(const ValueType& item, size_t index); /*! * remove items */ //! remove several items inline ssize_t removeItemsAt(size_t index, size_t count = 1) { auto i = begin() + index; erase(i, i+count); return index; } //! remove one item inline ssize_t removeAt(size_t index) { auto i = begin() + index; erase(i); return index; } // /*! // * sort (stable) the array // */ // // typedef int (*compar_t)(const ValueType* lhs, const ValueType* rhs); // typedef int (*compar_r_t)(const ValueType* lhs, const ValueType* rhs, void* state); // // inline status_t sort(compar_t cmp); // inline status_t sort(compar_r_t cmp, void* state); // // // for debugging only // inline size_t getItemSize() const { return itemSize(); } }; } namespace android { using ::mir_input::Vector; } #endif /* MIR_ANDROID_UBUNTU_VECTOR_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/MirLog.h0000644000015301777760000000147412322054223023316 0ustar pbusernogroup00000000000000/* * 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_LOG_H_ #define MIR_LOG_H_ namespace mir { extern void (*write_to_log)(int prio, char const* buffer); } #endif /* MIR_LOG_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/RefBase.h0000644000015301777760000000160312322054223023426 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_REFBASE_H_ #define MIR_ANDROID_UBUNTU_REFBASE_H_ #include namespace mir_input { using ::android::RefBase; } #endif /* MIR_ANDROID_UBUNTU_REFBASE_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/Log.h0000644000015301777760000001102712322054223022641 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_LOG_H_ #define MIR_ANDROID_UBUNTU_LOG_H_ /* * Android log priority values, in ascending priority order. */ typedef enum android_LogPriority { ANDROID_LOG_UNKNOWN = 0, ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */ ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, } android_LogPriority; /* * Basic log message macro. * * Example: * ALOG(LOG_WARN, NULL, "Failed with error %d", errno); * * The second argument may be NULL or "" to indicate the "global" tag. */ #ifndef ALOG #define ALOG(priority, tag, ...) \ LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) #endif /* * Log macro that allows you to specify a number for the priority. */ #ifndef LOG_PRI #define LOG_PRI(priority, tag, ...) \ android_printLog(priority, tag, __VA_ARGS__) #endif // --------------------------------------------------------------------- /* * Simplified macro to send a verbose log message using the current LOG_TAG. */ #ifndef ALOGV #define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) #endif /* * Simplified macro to send a debug log message using the current LOG_TAG. */ #ifndef ALOGD #define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) #endif /* * Simplified macro to send an info log message using the current LOG_TAG. */ #ifndef ALOGI #define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) #endif /* * Simplified macro to send a warning log message using the current LOG_TAG. */ #ifndef ALOGW #define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) #endif /* * Simplified macro to send an error log message using the current LOG_TAG. */ #ifndef ALOGE #define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) #endif // --------------------------------------------------------------------- #define android_printLog(prio, tag, ...) \ __android_log_print(prio, tag, __VA_ARGS__) extern "C" int __android_log_print(int /*prio*/, const char *tag, const char *fmt, ...); extern "C" void __android_log_assert(const char *cond, const char *tag, const char *fmt, ...); /* * Assertion that generates a log message when the assertion fails. * Stripped out of release builds. Uses the current LOG_TAG. */ #ifndef ALOG_ASSERT #define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__) #endif // --------------------------------------------------------------------- /* * Log a fatal error. If the given condition fails, this stops program * execution like a normal assertion, but also generating the given message. * It is NOT stripped from release builds. Note that the condition test * is -inverted- from the normal assert() semantics. */ #ifndef LOG_ALWAYS_FATAL_IF #define LOG_ALWAYS_FATAL_IF(cond, ...) \ ( (CONDITION(cond)) \ ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \ : (void)0 ) #endif #ifndef LOG_ALWAYS_FATAL #define LOG_ALWAYS_FATAL(...) \ ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) ) #endif /* * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that * are stripped out of release builds. */ #ifndef LOG_FATAL_IF #define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__) #endif #ifndef LOG_FATAL #define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__) #endif /* Returns 2nd arg. Used to substitute default value if caller's vararg list * is empty. */ #define __android_second(dummy, second, ...) second /* If passed multiple args, returns ',' followed by all but 1st arg, otherwise * returns nothing. */ #define __android_rest(first, ...) , ## __VA_ARGS__ #define android_printAssert(cond, tag, ...) \ __android_log_assert(cond, tag, \ __android_second(0, ## __VA_ARGS__, NULL) __android_rest(__VA_ARGS__)) #define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) #endif /* MIR_ANDROID_UBUNTU_LOG_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/atomic.h0000644000015301777760000000757412322054223023410 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_ATOMIC_H_ #define MIR_ANDROID_UBUNTU_ATOMIC_H_ #include #include namespace mir_input { /* * A handful of basic atomic operations. The appropriate * functions should be used instead of these whenever possible. * Only those functions needed by the input code are actually supported. * Others from the corresponding android cutils header are commented out. */ typedef std::atomic android_atomic_int32_t; /* * Basic arithmetic and bitwise operations. These all provide a * barrier with "release" ordering, and return the previous value. * * These have the same characteristics (e.g. what happens on overflow) * as the equivalent non-atomic C operations. */ inline int32_t android_atomic_inc(android_atomic_int32_t* addr) { return addr->fetch_add(1); } inline int32_t android_atomic_dec(android_atomic_int32_t* addr) { return addr->fetch_add(-1); } inline int32_t android_atomic_add(int32_t value, android_atomic_int32_t* addr) { return addr->fetch_add(value); } //int32_t android_atomic_and(int32_t value, volatile int32_t* addr); inline int32_t android_atomic_or(int32_t value, android_atomic_int32_t* addr) { return addr->fetch_or(value); } /* * Perform an atomic load with "acquire" or "release" ordering. * * This is only necessary if you need the memory barrier. A 32-bit read * from a 32-bit aligned address is atomic on all supported platforms. */ //int32_t android_atomic_acquire_load(volatile const int32_t* addr); //int32_t android_atomic_release_load(volatile const int32_t* addr); /* * Perform an atomic store with "acquire" or "release" ordering. * * This is only necessary if you need the memory barrier. A 32-bit write * to a 32-bit aligned address is atomic on all supported platforms. */ //void android_atomic_acquire_store(int32_t value, volatile int32_t* addr); //void android_atomic_release_store(int32_t value, volatile int32_t* addr); /* * Compare-and-set operation with "acquire" or "release" ordering. * * This returns zero if the new value was successfully stored, which will * only happen when *addr == oldvalue. * * (The return value is inverted from implementations on other platforms, * but matches the ARM ldrex/strex result.) * * Implementations that use the release CAS in a loop may be less efficient * than possible, because we re-issue the memory barrier on each iteration. */ //int android_atomic_acquire_cas(int32_t oldvalue, int32_t newvalue, // volatile int32_t* addr); inline int android_atomic_release_cas(int32_t oldvalue, int32_t newvalue, android_atomic_int32_t* addr) { return !addr->compare_exchange_weak(oldvalue, newvalue); } } /* * Aliases for code using an older version of this header. These are now * deprecated and should not be used. The definitions will be removed * in a future release. */ //#define android_atomic_write android_atomic_release_store #define android_atomic_cmpxchg android_atomic_release_cas using mir_input::android_atomic_int32_t; using mir_input::android_atomic_inc; using mir_input::android_atomic_dec; using mir_input::android_atomic_add; using mir_input::android_atomic_or; using mir_input::android_atomic_release_cas; #endif /* MIR_ANDROID_UBUNTU_ATOMIC_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/PropertyMap.h0000644000015301777760000001166412322054223024411 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_PROPERTYMAP_H_ #define MIR_ANDROID_UBUNTU_PROPERTYMAP_H_ #include #include #include #include #include #include #include namespace mir_input { /* * Provides a mechanism for passing around string-based property key / value pairs * and loading them from property files. * * The property files have the following simple structure: * * # Comment * key = value * * Keys and values are any sequence of printable ASCII characters. * The '=' separates the key from the value. * The key and value may not contain whitespace. * * The '\' character is reserved for escape sequences and is not currently supported. * The '"" character is reserved for quoting and is not currently supported. * Files that contain the '\' or '"' character will fail to parse. * * The file must not contain duplicate keys. * * TODO Support escape sequences and quoted values when needed. */ class PropertyMap { public: // /* Creates an empty property map. */ // PropertyMap(); // ~PropertyMap(); /* Clears the property map. */ void clear() { options = boost::program_options::variables_map(); } /* Adds a property. * Replaces the property with the same key if it is already present. */ void addProperty(const String8& key, const String8& value) { namespace po = boost::program_options; options.insert(std::make_pair(key, po::variable_value(value, false))); } void addAll(const PropertyMap* other) { options.insert(other->options.begin(), other->options.end()); } // // /* Returns true if the property map contains the specified key. */ // bool hasProperty(const String8& key) const; /* Gets the value of a property and parses it. * Returns true and sets outValue if the key was found and its value was parsed successfully. * Otherwise returns false and does not modify outValue. */ bool tryGetProperty(const String8& key, String8& outValue) const { if (!options.count(key)) return false; outValue = options[key].as(); return true; } bool tryGetProperty(const String8& key, bool& outValue) const { return tryGetPropertyImpl(key, outValue); } bool tryGetProperty(const String8& key, int32_t& outValue) const { return tryGetPropertyImpl(key, outValue); } bool tryGetProperty(const String8& key, float& outValue) const { return tryGetPropertyImpl(key, outValue); } // /* Adds all values from the specified property map. */ // void addAll(const PropertyMap* map); // // /* Gets the underlying property map. */ // inline const KeyedVector& getProperties() const { return mProperties; } /* Loads a property map from a file. */ static status_t load(const String8& filename, PropertyMap** outMap) { namespace po = boost::program_options; try { po::options_description description; std::ifstream file(filename); auto parsed_options = po::parse_config_file(file, description, true); // register the options we found so they'll be stored for (auto& option : parsed_options.options) { description.add_options()(option.string_key.data(), ""); option.unregistered = false; } *outMap = new PropertyMap(); po::store(parsed_options, (*outMap)->options); return NO_ERROR; } catch (std::exception const& error) { return BAD_VALUE; } } private: template bool tryGetPropertyImpl(const String8& key, Type& outValue) const { if (!options.count(key)) return false; try { outValue = boost::lexical_cast(options[key].as()); return true; } catch (...) { return false; } } boost::program_options::variables_map options; }; } namespace android { using ::mir_input::PropertyMap; } #endif /* MIR_ANDROID_UBUNTU_PROPERTYMAP_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/Errors.h0000644000015301777760000000615612322054223023403 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_ERRORS_H_ #define MIR_ANDROID_UBUNTU_ERRORS_H_ #include #include namespace mir_input { // use this type to return error codes #ifdef HAVE_MS_C_RUNTIME typedef int status_t; #else typedef int32_t status_t; #endif /* the MS C runtime lacks a few error codes */ /* * Error codes. * All error codes are negative values. */ // Win32 #defines NO_ERROR as well. It has the same value, so there's no // real conflict, though it's a bit awkward. #ifdef _WIN32 # undef NO_ERROR #endif enum { OK = 0, // Everything's swell. NO_ERROR = 0, // No errors. UNKNOWN_ERROR = 0x80000000, NO_MEMORY = -ENOMEM, INVALID_OPERATION = -ENOSYS, BAD_VALUE = -EINVAL, BAD_TYPE = 0x80000001, NAME_NOT_FOUND = -ENOENT, PERMISSION_DENIED = -EPERM, NO_INIT = -ENODEV, ALREADY_EXISTS = -EEXIST, DEAD_OBJECT = -EPIPE, FAILED_TRANSACTION = 0x80000002, JPARKS_BROKE_IT = -EPIPE, #if !defined(HAVE_MS_C_RUNTIME) BAD_INDEX = -EOVERFLOW, NOT_ENOUGH_DATA = -ENODATA, WOULD_BLOCK = -EWOULDBLOCK, TIMED_OUT = -ETIMEDOUT, UNKNOWN_TRANSACTION = -EBADMSG, #else BAD_INDEX = -E2BIG, NOT_ENOUGH_DATA = 0x80000003, WOULD_BLOCK = 0x80000004, TIMED_OUT = 0x80000005, UNKNOWN_TRANSACTION = 0x80000006, #endif FDS_NOT_ALLOWED = 0x80000007 }; // Restore define; enumeration is in "android" namespace, so the value defined // there won't work for Win32 code in a different namespace. #ifdef _WIN32 # define NO_ERROR 0L #endif } namespace android { using ::mir_input::status_t; using ::mir_input::OK; using ::mir_input::NO_ERROR; using ::mir_input::UNKNOWN_ERROR; using ::mir_input::NO_MEMORY; using ::mir_input::INVALID_OPERATION; using ::mir_input::BAD_VALUE; using ::mir_input::BAD_TYPE; using ::mir_input::NAME_NOT_FOUND; using ::mir_input::PERMISSION_DENIED; using ::mir_input::NO_INIT; using ::mir_input::ALREADY_EXISTS; using ::mir_input::DEAD_OBJECT; using ::mir_input::FAILED_TRANSACTION; using ::mir_input::JPARKS_BROKE_IT; using ::mir_input::BAD_INDEX; using ::mir_input::NOT_ENOUGH_DATA; using ::mir_input::WOULD_BLOCK; using ::mir_input::TIMED_OUT; using ::mir_input::UNKNOWN_TRANSACTION; using ::mir_input::FDS_NOT_ALLOWED; } #endif /* MIR_ANDROID_UBUNTU_ERRORS_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/String8.h0000644000015301777760000000432212322054223023456 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_STRING8_H_ #define MIR_ANDROID_UBUNTU_STRING8_H_ #include #include namespace mir_input { typedef ::std::string String8; inline bool isEmpty(String8 const& s) { return s.empty(); } inline char const* c_str(String8 const& s) { return s.c_str(); } inline String8& appendFormat(String8& ss, const char* fmt, ...) { ::va_list args; ::va_start(args, fmt); int n = ::vsnprintf(NULL, 0, fmt, args); if (n != 0) { char* s = (char*) malloc(n+1); if (s) { ::va_end(args); ::va_start(args, fmt); if (::vsnprintf(s, n+1, fmt, args)) { ss.append(s, s+n); } free(s); } } ::va_end(args); return ss; } inline void setTo(String8& s, char const* value) { s = value; } inline char* lockBuffer(String8& s, int) { return const_cast(s.data()); } template inline String8 formatString8(const char* fmt, Args... args) { String8 ss; appendFormat(ss, fmt, args...); return ss; } inline void setTo(String8& s, String8 const& value) { s = value; } inline String8 const& emptyString8() { static String8 empty; return empty; } } namespace android { using ::mir_input::String8; using ::mir_input::isEmpty; using ::mir_input::c_str; using ::mir_input::appendFormat; using ::mir_input::setTo; using ::mir_input::lockBuffer; using ::mir_input::formatString8; using ::mir_input::setTo; using ::mir_input::emptyString8; } #endif /* MIR_ANDROID_UBUNTU_STRING8_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/properties.h0000644000015301777760000000300012322054223024304 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_PROPERTIES_H_ #define MIR_ANDROID_UBUNTU_PROPERTIES_H_ #include #define PROPERTY_VALUE_MAX 92 namespace mir_input { inline int property_get(const char *key, char *value, const char *default_value) { int len = -1; if (default_value != NULL) { strcpy(value, default_value); len = strlen(value); } else { /* * If the value isn't defined, hand back an empty string and * a zero length, rather than a failure. This seems wrong, * since you can't tell the difference between "undefined" and * "defined but empty", but it's what the device does. */ value[0] = '\0'; len = 0; } return len; } } namespace android { using ::mir_input::property_get; } #endif /* MIR_ANDROID_UBUNTU_PROPERTIES_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/Compat.h0000644000015301777760000000151412322054223023343 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_COMPAT_H_ #define MIR_ANDROID_UBUNTU_COMPAT_H_ #include #endif /* MIR_ANDROID_UBUNTU_COMPAT_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/ThreadDefs.h0000644000015301777760000000202212322054223024124 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_THREADDEFS_H_ #define MIR_ANDROID_UBUNTU_THREADDEFS_H_ namespace mir_input { enum { PRIORITY_DEFAULT = 0, PRIORITY_URGENT_DISPLAY = -8 }; } namespace android { using ::mir_input::PRIORITY_DEFAULT; using ::mir_input::PRIORITY_URGENT_DISPLAY; } #endif /* MIR_ANDROID_UBUNTU_THREADDEFS_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/BitSet.h0000644000015301777760000000151412322054223023312 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_BITSET_H_ #define MIR_ANDROID_UBUNTU_BITSET_H_ #include #endif /* MIR_ANDROID_UBUNTU_BITSET_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/Looper.h0000644000015301777760000000151412322054223023360 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_LOOPER_H_ #define MIR_ANDROID_UBUNTU_LOOPER_H_ #include #endif /* MIR_ANDROID_UBUNTU_LOOPER_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/std/Condition.h0000644000015301777760000000241612322054223024050 0ustar pbusernogroup00000000000000/* * 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 General Public License for 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_ANDROID_UBUNTU_CONDITION_H_ #define MIR_ANDROID_UBUNTU_CONDITION_H_ #include #include #include namespace mir_input { typedef std::condition_variable_any Condition; inline void broadcast(Condition& c) { c.notify_all(); } template inline void waitRelative(Condition& c, Lock& l, nsecs_t reltime) { c.wait_for(l, std::chrono::nanoseconds(reltime)); } } namespace android { using ::mir_input::Condition; using ::mir_input::broadcast; using ::mir_input::waitRelative; } #endif /* MIR_ANDROID_UBUNTU_CONDITION_H_ */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/utils/0000755000015301777760000000000012322054703022317 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-deps/utils/KeyedVector.h0000644000015301777760000001470412322054223024717 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_KEYED_VECTOR_H #define ANDROID_KEYED_VECTOR_H #include #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { template class KeyedVector { public: typedef KEY key_type; typedef VALUE value_type; inline KeyedVector(); /* * empty the vector */ inline void clear() { mVector.clear(); } /*! * vector stats */ //! returns number of items in the vector inline size_t size() const { return mVector.size(); } //! returns wether or not the vector is empty inline bool isEmpty() const { return mVector.isEmpty(); } //! returns how many items can be stored without reallocating the backing store inline size_t capacity() const { return mVector.capacity(); } //! setst the capacity. capacity can never be reduced less than size() inline ssize_t setCapacity(size_t size) { return mVector.setCapacity(size); } /*! * accessors */ const VALUE& valueFor(const KEY& key) const; const VALUE& valueAt(size_t index) const; const KEY& keyAt(size_t index) const; ssize_t indexOfKey(const KEY& key) const; /*! * modifying the array */ VALUE& editValueFor(const KEY& key); VALUE& editValueAt(size_t index); /*! * add/insert/replace items */ ssize_t add(const KEY& key, const VALUE& item); ssize_t replaceValueFor(const KEY& key, const VALUE& item); ssize_t replaceValueAt(size_t index, const VALUE& item); /*! * remove items */ ssize_t removeItem(const KEY& key); ssize_t removeItemsAt(size_t index, size_t count = 1); private: SortedVector< key_value_pair_t > mVector; }; // KeyedVector can be trivially moved using memcpy() because its // underlying SortedVector can be trivially moved. template struct trait_trivial_move > { enum { value = trait_trivial_move > >::value }; }; // --------------------------------------------------------------------------- /** * Variation of KeyedVector that holds a default value to return when * valueFor() is called with a key that doesn't exist. */ template class DefaultKeyedVector : public KeyedVector { public: inline DefaultKeyedVector(const VALUE& defValue = VALUE()); const VALUE& valueFor(const KEY& key) const; private: VALUE mDefault; }; // --------------------------------------------------------------------------- template inline KeyedVector::KeyedVector() { } template inline ssize_t KeyedVector::indexOfKey(const KEY& key) const { return mVector.indexOf( key_value_pair_t(key) ); } template inline const VALUE& KeyedVector::valueFor(const KEY& key) const { ssize_t i = this->indexOfKey(key); assert(i>=0); return mVector.itemAt(i).value; } template inline const VALUE& KeyedVector::valueAt(size_t index) const { return mVector.itemAt(index).value; } template inline const KEY& KeyedVector::keyAt(size_t index) const { return mVector.itemAt(index).key; } template inline VALUE& KeyedVector::editValueFor(const KEY& key) { ssize_t i = this->indexOfKey(key); assert(i>=0); return mVector.editItemAt(i).value; } template inline VALUE& KeyedVector::editValueAt(size_t index) { return mVector.editItemAt(index).value; } template inline ssize_t KeyedVector::add(const KEY& key, const VALUE& value) { return mVector.add( key_value_pair_t(key, value) ); } template inline ssize_t KeyedVector::replaceValueFor(const KEY& key, const VALUE& value) { key_value_pair_t pair(key, value); mVector.remove(pair); return mVector.add(pair); } template inline ssize_t KeyedVector::replaceValueAt(size_t index, const VALUE& item) { if (index inline ssize_t KeyedVector::removeItem(const KEY& key) { return mVector.remove(key_value_pair_t(key)); } template inline ssize_t KeyedVector::removeItemsAt(size_t index, size_t count) { return mVector.removeItemsAt(index, count); } // --------------------------------------------------------------------------- template inline DefaultKeyedVector::DefaultKeyedVector(const VALUE& defValue) : mDefault(defValue) { } template inline const VALUE& DefaultKeyedVector::valueFor(const KEY& key) const { ssize_t i = this->indexOfKey(key); return i >= 0 ? KeyedVector::valueAt(i) : mDefault; } } // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_KEYED_VECTOR_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/utils/Timers.h0000644000015301777760000001012312322054223023725 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // // Timer functions. // #ifndef _LIBS_UTILS_TIMERS_H #define _LIBS_UTILS_TIMERS_H #include #include #include // ------------------------------------------------------------------ // C API #ifdef __cplusplus extern "C" { #endif typedef int64_t nsecs_t; // nano-seconds static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs) { return secs*1000000000; } static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs) { return secs*1000000; } static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs) { return secs*1000; } static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs) { return secs/1000000000; } static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs) { return secs/1000000; } static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs) { return secs/1000; } static inline nsecs_t s2ns(nsecs_t v) {return seconds_to_nanoseconds(v);} static inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);} static inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);} static inline nsecs_t ns2s(nsecs_t v) {return nanoseconds_to_seconds(v);} static inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);} static inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);} static inline nsecs_t seconds(nsecs_t v) { return s2ns(v); } static inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); } static inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); } enum { SYSTEM_TIME_REALTIME = 0, // system-wide realtime clock SYSTEM_TIME_MONOTONIC = 1, // monotonic time since unspecified starting point SYSTEM_TIME_PROCESS = 2, // high-resolution per-process clock SYSTEM_TIME_THREAD = 3 // high-resolution per-thread clock }; // return the system-time according to the specified clock #ifdef __cplusplus nsecs_t systemTime(int clock = SYSTEM_TIME_MONOTONIC); #else nsecs_t systemTime(int clock); #endif // def __cplusplus /** * Returns the number of milliseconds to wait between the reference time and the timeout time. * If the timeout is in the past relative to the reference time, returns 0. * If the timeout is more than INT_MAX milliseconds in the future relative to the reference time, * such as when timeoutTime == LLONG_MAX, returns -1 to indicate an infinite timeout delay. * Otherwise, returns the difference between the reference time and timeout time * rounded up to the next millisecond. */ int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime); #ifdef __cplusplus } // extern "C" #endif // ------------------------------------------------------------------ // C++ API #ifdef __cplusplus namespace android { /* * Time the duration of something. * * Includes some timeval manipulation functions. */ class DurationTimer { public: DurationTimer() {} ~DurationTimer() {} // Start the timer. void start(); // Stop the timer. void stop(); // Get the duration in microseconds. long long durationUsecs() const; // Subtract two timevals. Returns the difference (ptv1-ptv2) in // microseconds. static long long subtractTimevals(const struct timeval* ptv1, const struct timeval* ptv2); // Add the specified amount of time to the timeval. static void addToTimeval(struct timeval* ptv, long usec); private: struct timeval mStartWhen; struct timeval mStopWhen; }; } // android #endif // def __cplusplus #endif // _LIBS_UTILS_TIMERS_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/utils/threads.h0000644000015301777760000000201512322054223024115 0ustar pbusernogroup00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _LIBS_UTILS_THREADS_H #define _LIBS_UTILS_THREADS_H /* * Please, DO NOT USE! * * This file is here only for legacy reasons. Instead, include directly * the headers you need below. * */ #include #ifdef __cplusplus #include #include #include #include #include #endif #endif // _LIBS_UTILS_THREADS_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/utils/Unicode.h0000644000015301777760000001363312322054223024061 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_UNICODE_H #define ANDROID_UNICODE_H #include #include extern "C" { #ifndef USING_STD_CPP11 #if 0 // Mir changes typedef uint32_t char32_t; typedef uint16_t char16_t; #endif #endif // Standard string functions on char16_t strings. int strcmp16(const char16_t *, const char16_t *); int strncmp16(const char16_t *s1, const char16_t *s2, size_t n); size_t strlen16(const char16_t *); size_t strnlen16(const char16_t *, size_t); char16_t *strcpy16(char16_t *, const char16_t *); char16_t *strncpy16(char16_t *, const char16_t *, size_t); // Version of comparison that supports embedded nulls. // This is different than strncmp() because we don't stop // at a nul character and consider the strings to be different // if the lengths are different (thus we need to supply the // lengths of both strings). This can also be used when // your string is not nul-terminated as it will have the // equivalent result as strcmp16 (unlike strncmp16). int strzcmp16(const char16_t *s1, size_t n1, const char16_t *s2, size_t n2); // Version of strzcmp16 for comparing strings in different endianness. int strzcmp16_h_n(const char16_t *s1H, size_t n1, const char16_t *s2N, size_t n2); // Standard string functions on char32_t strings. size_t strlen32(const char32_t *); size_t strnlen32(const char32_t *, size_t); /** * Measure the length of a UTF-32 string in UTF-8. If the string is invalid * such as containing a surrogate character, -1 will be returned. */ ssize_t utf32_to_utf8_length(const char32_t *src, size_t src_len); /** * Stores a UTF-8 string converted from "src" in "dst", if "dst_length" is not * large enough to store the string, the part of the "src" string is stored * into "dst" as much as possible. See the examples for more detail. * Returns the size actually used for storing the string. * dst" is not null-terminated when dst_len is fully used (like strncpy). * * Example 1 * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84) * "src_len" == 2 * "dst_len" >= 7 * -> * Returned value == 6 * "dst" becomes \xE3\x81\x82\xE3\x81\x84\0 * (note that "dst" is null-terminated) * * Example 2 * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84) * "src_len" == 2 * "dst_len" == 5 * -> * Returned value == 3 * "dst" becomes \xE3\x81\x82\0 * (note that "dst" is null-terminated, but \u3044 is not stored in "dst" * since "dst" does not have enough size to store the character) * * Example 3 * "src" == \u3042\u3044 (\xE3\x81\x82\xE3\x81\x84) * "src_len" == 2 * "dst_len" == 6 * -> * Returned value == 6 * "dst" becomes \xE3\x81\x82\xE3\x81\x84 * (note that "dst" is NOT null-terminated, like strncpy) */ void utf32_to_utf8(const char32_t* src, size_t src_len, char* dst); /** * Returns the unicode value at "index". * Returns -1 when the index is invalid (equals to or more than "src_len"). * If returned value is positive, it is able to be converted to char32_t, which * is unsigned. Then, if "next_index" is not NULL, the next index to be used is * stored in "next_index". "next_index" can be NULL. */ int32_t utf32_from_utf8_at(const char *src, size_t src_len, size_t index, size_t *next_index); /** * Returns the UTF-8 length of UTF-16 string "src". */ ssize_t utf16_to_utf8_length(const char16_t *src, size_t src_len); /** * Converts a UTF-16 string to UTF-8. The destination buffer must be large * enough to fit the UTF-16 as measured by utf16_to_utf8_length with an added * NULL terminator. */ void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst); /** * Returns the length of "src" when "src" is valid UTF-8 string. * Returns 0 if src is NULL or 0-length string. Returns -1 when the source * is an invalid string. * * This function should be used to determine whether "src" is valid UTF-8 * characters with valid unicode codepoints. "src" must be null-terminated. * * If you are going to use other utf8_to_... functions defined in this header * with string which may not be valid UTF-8 with valid codepoint (form 0 to * 0x10FFFF), you should use this function before calling others, since the * other functions do not check whether the string is valid UTF-8 or not. * * If you do not care whether "src" is valid UTF-8 or not, you should use * strlen() as usual, which should be much faster. */ ssize_t utf8_length(const char *src); /** * Measure the length of a UTF-32 string. */ size_t utf8_to_utf32_length(const char *src, size_t src_len); /** * Stores a UTF-32 string converted from "src" in "dst". "dst" must be large * enough to store the entire converted string as measured by * utf8_to_utf32_length plus space for a NULL terminator. */ void utf8_to_utf32(const char* src, size_t src_len, char32_t* dst); /** * Returns the UTF-16 length of UTF-8 string "src". */ ssize_t utf8_to_utf16_length(const uint8_t* src, size_t srcLen); /** * Convert UTF-8 to UTF-16 including surrogate pairs. * Returns a pointer to the end of the string (where a null terminator might go * if you wanted to add one). */ char16_t* utf8_to_utf16_no_null_terminator(const uint8_t* src, size_t srcLen, char16_t* dst); /** * Convert UTF-8 to UTF-16 including surrogate pairs. The destination buffer * must be large enough to hold the result as measured by utf8_to_utf16_length * plus an added NULL terminator. */ void utf8_to_utf16(const uint8_t* src, size_t srcLen, char16_t* dst); } #endif mir-0.1.8+14.04.20140411/3rd_party/android-deps/utils/VectorImpl.h0000644000015301777760000002012512322054223024551 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_VECTOR_IMPL_H #define ANDROID_VECTOR_IMPL_H #include #include #include #include // --------------------------------------------------------------------------- // No user serviceable parts in here... // --------------------------------------------------------------------------- namespace android { /*! * Implementation of the guts of the vector<> class * this ensures backward binary compatibility and * reduces code size. * For performance reasons, we expose mStorage and mCount * so these fields are set in stone. * */ class VectorImpl { public: enum { // flags passed to the ctor HAS_TRIVIAL_CTOR = 0x00000001, HAS_TRIVIAL_DTOR = 0x00000002, HAS_TRIVIAL_COPY = 0x00000004 }; VectorImpl(size_t itemSize, uint32_t flags); VectorImpl(const VectorImpl& rhs); virtual ~VectorImpl(); /*! must be called from subclasses destructor */ void finish_vector(); VectorImpl& operator = (const VectorImpl& rhs); /*! C-style array access */ inline const void* arrayImpl() const { return mStorage; } void* editArrayImpl(); /*! vector stats */ inline size_t size() const { return mCount; } inline bool isEmpty() const { return mCount == 0; } size_t capacity() const; ssize_t setCapacity(size_t size); /*! append/insert another vector or array */ ssize_t insertVectorAt(const VectorImpl& vector, size_t index); ssize_t appendVector(const VectorImpl& vector); ssize_t insertArrayAt(const void* array, size_t index, size_t length); ssize_t appendArray(const void* array, size_t length); /*! add/insert/replace items */ ssize_t insertAt(size_t where, size_t numItems = 1); ssize_t insertAt(const void* item, size_t where, size_t numItems = 1); void pop(); void push(); void push(const void* item); ssize_t add(); ssize_t add(const void* item); ssize_t replaceAt(size_t index); ssize_t replaceAt(const void* item, size_t index); /*! remove items */ ssize_t removeItemsAt(size_t index, size_t count = 1); void clear(); const void* itemLocation(size_t index) const; void* editItemLocation(size_t index); typedef int (*compar_t)(const void* lhs, const void* rhs); typedef int (*compar_r_t)(const void* lhs, const void* rhs, void* state); status_t sort(compar_t cmp); status_t sort(compar_r_t cmp, void* state); protected: size_t itemSize() const; void release_storage(); virtual void do_construct(void* storage, size_t num) const = 0; virtual void do_destroy(void* storage, size_t num) const = 0; virtual void do_copy(void* dest, const void* from, size_t num) const = 0; virtual void do_splat(void* dest, const void* item, size_t num) const = 0; virtual void do_move_forward(void* dest, const void* from, size_t num) const = 0; virtual void do_move_backward(void* dest, const void* from, size_t num) const = 0; // take care of FBC... virtual void reservedVectorImpl1(); virtual void reservedVectorImpl2(); virtual void reservedVectorImpl3(); virtual void reservedVectorImpl4(); virtual void reservedVectorImpl5(); virtual void reservedVectorImpl6(); virtual void reservedVectorImpl7(); virtual void reservedVectorImpl8(); private: void* _grow(size_t where, size_t amount); void _shrink(size_t where, size_t amount); inline void _do_construct(void* storage, size_t num) const; inline void _do_destroy(void* storage, size_t num) const; inline void _do_copy(void* dest, const void* from, size_t num) const; inline void _do_splat(void* dest, const void* item, size_t num) const; inline void _do_move_forward(void* dest, const void* from, size_t num) const; inline void _do_move_backward(void* dest, const void* from, size_t num) const; // These 2 fields are exposed in the inlines below, // so they're set in stone. void * mStorage; // base address of the vector size_t mCount; // number of items const uint32_t mFlags; const size_t mItemSize; }; class SortedVectorImpl : public VectorImpl { public: SortedVectorImpl(size_t itemSize, uint32_t flags); SortedVectorImpl(const VectorImpl& rhs); virtual ~SortedVectorImpl(); SortedVectorImpl& operator = (const SortedVectorImpl& rhs); //! finds the index of an item ssize_t indexOf(const void* item) const; //! finds where this item should be inserted size_t orderOf(const void* item) const; //! add an item in the right place (or replaces it if there is one) ssize_t add(const void* item); //! merges a vector into this one ssize_t merge(const VectorImpl& vector); ssize_t merge(const SortedVectorImpl& vector); //! removes an item ssize_t remove(const void* item); protected: virtual int do_compare(const void* lhs, const void* rhs) const = 0; // take care of FBC... virtual void reservedSortedVectorImpl1(); virtual void reservedSortedVectorImpl2(); virtual void reservedSortedVectorImpl3(); virtual void reservedSortedVectorImpl4(); virtual void reservedSortedVectorImpl5(); virtual void reservedSortedVectorImpl6(); virtual void reservedSortedVectorImpl7(); virtual void reservedSortedVectorImpl8(); private: ssize_t _indexOrderOf(const void* item, size_t* order = 0) const; // these are made private, because they can't be used on a SortedVector // (they don't have an implementation either) ssize_t add(); void pop(); void push(); void push(const void* item); ssize_t insertVectorAt(const VectorImpl& vector, size_t index); ssize_t appendVector(const VectorImpl& vector); ssize_t insertArrayAt(const void* array, size_t index, size_t length); ssize_t appendArray(const void* array, size_t length); ssize_t insertAt(size_t where, size_t numItems = 1); ssize_t insertAt(const void* item, size_t where, size_t numItems = 1); ssize_t replaceAt(size_t index); ssize_t replaceAt(const void* item, size_t index); }; } // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_VECTOR_IMPL_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/utils/StrongPointer.h0000644000015301777760000001323212322054223025303 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_STRONG_POINTER_H #define ANDROID_STRONG_POINTER_H #include #include #include #include // --------------------------------------------------------------------------- namespace android { class TextOutput; TextOutput& printStrongPointer(TextOutput& to, const void* val); template class wp; // --------------------------------------------------------------------------- #define COMPARE(_op_) \ inline bool operator _op_ (const sp& o) const { \ return m_ptr _op_ o.m_ptr; \ } \ inline bool operator _op_ (const T* o) const { \ return m_ptr _op_ o; \ } \ template \ inline bool operator _op_ (const sp& o) const { \ return m_ptr _op_ o.m_ptr; \ } \ template \ inline bool operator _op_ (const U* o) const { \ return m_ptr _op_ o; \ } \ inline bool operator _op_ (const wp& o) const { \ return m_ptr _op_ o.m_ptr; \ } \ template \ inline bool operator _op_ (const wp& o) const { \ return m_ptr _op_ o.m_ptr; \ } // --------------------------------------------------------------------------- template class sp { public: inline sp() : m_ptr(0) { } sp(T* other); sp(const sp& other); template sp(U* other); template sp(const sp& other); ~sp(); // Assignment sp& operator = (T* other); sp& operator = (const sp& other); template sp& operator = (const sp& other); template sp& operator = (U* other); //! Special optimization for use by ProcessState (and nobody else). void force_set(T* other); // Reset void clear(); // Accessors inline T& operator* () const { return *m_ptr; } inline T* operator-> () const { return m_ptr; } inline T* get() const { return m_ptr; } // Operators COMPARE(==) COMPARE(!=) COMPARE(>) COMPARE(<) COMPARE(<=) COMPARE(>=) private: template friend class sp; template friend class wp; void set_pointer(T* ptr); T* m_ptr; }; #undef COMPARE template TextOutput& operator<<(TextOutput& to, const sp& val); // --------------------------------------------------------------------------- // No user serviceable parts below here. template sp::sp(T* other) : m_ptr(other) { if (other) other->incStrong(this); } template sp::sp(const sp& other) : m_ptr(other.m_ptr) { if (m_ptr) m_ptr->incStrong(this); } template template sp::sp(U* other) : m_ptr(other) { if (other) ((T*)other)->incStrong(this); } template template sp::sp(const sp& other) : m_ptr(other.m_ptr) { if (m_ptr) m_ptr->incStrong(this); } template sp::~sp() { if (m_ptr) m_ptr->decStrong(this); } template sp& sp::operator = (const sp& other) { T* otherPtr(other.m_ptr); if (otherPtr) otherPtr->incStrong(this); if (m_ptr) m_ptr->decStrong(this); m_ptr = otherPtr; return *this; } template sp& sp::operator = (T* other) { if (other) other->incStrong(this); if (m_ptr) m_ptr->decStrong(this); m_ptr = other; return *this; } template template sp& sp::operator = (const sp& other) { T* otherPtr(other.m_ptr); if (otherPtr) otherPtr->incStrong(this); if (m_ptr) m_ptr->decStrong(this); m_ptr = otherPtr; return *this; } template template sp& sp::operator = (U* other) { if (other) ((T*)other)->incStrong(this); if (m_ptr) m_ptr->decStrong(this); m_ptr = other; return *this; } template void sp::force_set(T* other) { other->forceIncStrong(this); m_ptr = other; } template void sp::clear() { if (m_ptr) { m_ptr->decStrong(this); m_ptr = 0; } } template void sp::set_pointer(T* ptr) { m_ptr = ptr; } template inline TextOutput& operator<<(TextOutput& to, const sp& val) { return printStrongPointer(to, val.get()); } } // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_STRONG_POINTER_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/utils/TypeHelpers.h0000644000015301777760000002210712322054223024733 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_TYPE_HELPERS_H #define ANDROID_TYPE_HELPERS_H #include #include #include #include // --------------------------------------------------------------------------- namespace android { /* * Types traits */ template struct trait_trivial_ctor { enum { value = false }; }; template struct trait_trivial_dtor { enum { value = false }; }; template struct trait_trivial_copy { enum { value = false }; }; template struct trait_trivial_move { enum { value = false }; }; template struct trait_pointer { enum { value = false }; }; template struct trait_pointer { enum { value = true }; }; template struct traits { enum { // whether this type is a pointer is_pointer = trait_pointer::value, // whether this type's constructor is a no-op has_trivial_ctor = is_pointer || trait_trivial_ctor::value, // whether this type's destructor is a no-op has_trivial_dtor = is_pointer || trait_trivial_dtor::value, // whether this type type can be copy-constructed with memcpy has_trivial_copy = is_pointer || trait_trivial_copy::value, // whether this type can be moved with memmove has_trivial_move = is_pointer || trait_trivial_move::value }; }; template struct aggregate_traits { enum { is_pointer = false, has_trivial_ctor = traits::has_trivial_ctor && traits::has_trivial_ctor, has_trivial_dtor = traits::has_trivial_dtor && traits::has_trivial_dtor, has_trivial_copy = traits::has_trivial_copy && traits::has_trivial_copy, has_trivial_move = traits::has_trivial_move && traits::has_trivial_move }; }; #define ANDROID_TRIVIAL_CTOR_TRAIT( T ) \ template<> struct trait_trivial_ctor< T > { enum { value = true }; }; #define ANDROID_TRIVIAL_DTOR_TRAIT( T ) \ template<> struct trait_trivial_dtor< T > { enum { value = true }; }; #define ANDROID_TRIVIAL_COPY_TRAIT( T ) \ template<> struct trait_trivial_copy< T > { enum { value = true }; }; #define ANDROID_TRIVIAL_MOVE_TRAIT( T ) \ template<> struct trait_trivial_move< T > { enum { value = true }; }; #define ANDROID_BASIC_TYPES_TRAITS( T ) \ ANDROID_TRIVIAL_CTOR_TRAIT( T ) \ ANDROID_TRIVIAL_DTOR_TRAIT( T ) \ ANDROID_TRIVIAL_COPY_TRAIT( T ) \ ANDROID_TRIVIAL_MOVE_TRAIT( T ) // --------------------------------------------------------------------------- /* * basic types traits */ ANDROID_BASIC_TYPES_TRAITS( void ) ANDROID_BASIC_TYPES_TRAITS( bool ) ANDROID_BASIC_TYPES_TRAITS( char ) ANDROID_BASIC_TYPES_TRAITS( unsigned char ) ANDROID_BASIC_TYPES_TRAITS( short ) ANDROID_BASIC_TYPES_TRAITS( unsigned short ) ANDROID_BASIC_TYPES_TRAITS( int ) ANDROID_BASIC_TYPES_TRAITS( unsigned int ) ANDROID_BASIC_TYPES_TRAITS( long ) ANDROID_BASIC_TYPES_TRAITS( unsigned long ) ANDROID_BASIC_TYPES_TRAITS( long long ) ANDROID_BASIC_TYPES_TRAITS( unsigned long long ) ANDROID_BASIC_TYPES_TRAITS( float ) ANDROID_BASIC_TYPES_TRAITS( double ) // --------------------------------------------------------------------------- /* * compare and order types */ template inline int strictly_order_type(const TYPE& lhs, const TYPE& rhs) { return (lhs < rhs) ? 1 : 0; } template inline int compare_type(const TYPE& lhs, const TYPE& rhs) { return strictly_order_type(rhs, lhs) - strictly_order_type(lhs, rhs); } /* * create, destroy, copy and move types... */ template inline void construct_type(TYPE* p, size_t n) { if (!traits::has_trivial_ctor) { while (n--) { new(p++) TYPE; } } } template inline void destroy_type(TYPE* p, size_t n) { if (!traits::has_trivial_dtor) { while (n--) { p->~TYPE(); p++; } } } template inline void copy_type(TYPE* d, const TYPE* s, size_t n) { if (!traits::has_trivial_copy) { while (n--) { new(d) TYPE(*s); d++, s++; } } else { memcpy(d,s,n*sizeof(TYPE)); } } template inline void splat_type(TYPE* where, const TYPE* what, size_t n) { if (!traits::has_trivial_copy) { while (n--) { new(where) TYPE(*what); where++; } } else { while (n--) { *where++ = *what; } } } template inline void move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) { if ((traits::has_trivial_dtor && traits::has_trivial_copy) || traits::has_trivial_move) { memmove(d,s,n*sizeof(TYPE)); } else { d += n; s += n; while (n--) { --d, --s; if (!traits::has_trivial_copy) { new(d) TYPE(*s); } else { *d = *s; } if (!traits::has_trivial_dtor) { s->~TYPE(); } } } } template inline void move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) { if ((traits::has_trivial_dtor && traits::has_trivial_copy) || traits::has_trivial_move) { memmove(d,s,n*sizeof(TYPE)); } else { while (n--) { if (!traits::has_trivial_copy) { new(d) TYPE(*s); } else { *d = *s; } if (!traits::has_trivial_dtor) { s->~TYPE(); } d++, s++; } } } // --------------------------------------------------------------------------- /* * a key/value pair */ template struct key_value_pair_t { typedef KEY key_t; typedef VALUE value_t; KEY key; VALUE value; key_value_pair_t() { } key_value_pair_t(const key_value_pair_t& o) : key(o.key), value(o.value) { } key_value_pair_t(const KEY& k, const VALUE& v) : key(k), value(v) { } key_value_pair_t(const KEY& k) : key(k) { } inline bool operator < (const key_value_pair_t& o) const { return strictly_order_type(key, o.key); } inline const KEY& getKey() const { return key; } inline const VALUE& getValue() const { return value; } friend bool operator == (const key_value_pair_t& lhs, const key_value_pair_t& rhs) { return !compare_type(lhs.key, rhs.key); } }; template struct trait_trivial_ctor< key_value_pair_t > { enum { value = aggregate_traits::has_trivial_ctor }; }; template struct trait_trivial_dtor< key_value_pair_t > { enum { value = aggregate_traits::has_trivial_dtor }; }; template struct trait_trivial_copy< key_value_pair_t > { enum { value = aggregate_traits::has_trivial_copy }; }; template struct trait_trivial_move< key_value_pair_t > { enum { value = aggregate_traits::has_trivial_move }; }; // --------------------------------------------------------------------------- /* * Hash codes. */ typedef uint32_t hash_t; template hash_t hash_type(const TKey& key); /* Built-in hash code specializations. * Assumes pointers are 32bit. */ #define ANDROID_INT32_HASH(T) \ template <> inline hash_t hash_type(const T& value) { return hash_t(value); } #define ANDROID_INT64_HASH(T) \ template <> inline hash_t hash_type(const T& value) { \ return hash_t((value >> 32) ^ value); } #define ANDROID_REINTERPRET_HASH(T, R) \ template <> inline hash_t hash_type(const T& value) { \ return hash_type(*reinterpret_cast(&value)); } ANDROID_INT32_HASH(bool) ANDROID_INT32_HASH(int8_t) ANDROID_INT32_HASH(uint8_t) ANDROID_INT32_HASH(int16_t) ANDROID_INT32_HASH(uint16_t) ANDROID_INT32_HASH(int32_t) ANDROID_INT32_HASH(uint32_t) ANDROID_INT64_HASH(int64_t) ANDROID_INT64_HASH(uint64_t) ANDROID_REINTERPRET_HASH(float, uint32_t) ANDROID_REINTERPRET_HASH(double, uint64_t) template inline hash_t hash_type(const T*& value) { return hash_type(uintptr_t(value)); } } // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_TYPE_HELPERS_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/utils/String16.h0000644000015301777760000001660212322054223024107 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_STRING16_H #define ANDROID_STRING16_H #include #include #include #include // --------------------------------------------------------------------------- extern "C" { } // --------------------------------------------------------------------------- namespace android { // --------------------------------------------------------------------------- class String8; class TextOutput; //! This is a string holding UTF-16 characters. class String16 { public: String16(); String16(const String16& o); String16(const String16& o, size_t len, size_t begin=0); explicit String16(const char16_t* o); explicit String16(const char16_t* o, size_t len); explicit String16(const String8& o); explicit String16(const char* o); explicit String16(const char* o, size_t len); ~String16(); inline const char16_t* string() const; inline size_t size() const; inline const SharedBuffer* sharedBuffer() const; void setTo(const String16& other); status_t setTo(const char16_t* other); status_t setTo(const char16_t* other, size_t len); status_t setTo(const String16& other, size_t len, size_t begin=0); status_t append(const String16& other); status_t append(const char16_t* other, size_t len); inline String16& operator=(const String16& other); inline String16& operator+=(const String16& other); inline String16 operator+(const String16& other) const; status_t insert(size_t pos, const char16_t* chrs); status_t insert(size_t pos, const char16_t* chrs, size_t len); ssize_t findFirst(char16_t c) const; ssize_t findLast(char16_t c) const; bool startsWith(const String16& prefix) const; bool startsWith(const char16_t* prefix) const; status_t makeLower(); status_t replaceAll(char16_t replaceThis, char16_t withThis); status_t remove(size_t len, size_t begin=0); inline int compare(const String16& other) const; inline bool operator<(const String16& other) const; inline bool operator<=(const String16& other) const; inline bool operator==(const String16& other) const; inline bool operator!=(const String16& other) const; inline bool operator>=(const String16& other) const; inline bool operator>(const String16& other) const; inline bool operator<(const char16_t* other) const; inline bool operator<=(const char16_t* other) const; inline bool operator==(const char16_t* other) const; inline bool operator!=(const char16_t* other) const; inline bool operator>=(const char16_t* other) const; inline bool operator>(const char16_t* other) const; inline operator const char16_t*() const; private: const char16_t* mString; }; // String16 can be trivially moved using memcpy() because moving does not // require any change to the underlying SharedBuffer contents or reference count. ANDROID_TRIVIAL_MOVE_TRAIT(String16) TextOutput& operator<<(TextOutput& to, const String16& val); // --------------------------------------------------------------------------- // No user servicable parts below. inline int compare_type(const String16& lhs, const String16& rhs) { return lhs.compare(rhs); } inline int strictly_order_type(const String16& lhs, const String16& rhs) { return compare_type(lhs, rhs) < 0; } inline const char16_t* String16::string() const { return mString; } inline size_t String16::size() const { return SharedBuffer::sizeFromData(mString)/sizeof(char16_t)-1; } inline const SharedBuffer* String16::sharedBuffer() const { return SharedBuffer::bufferFromData(mString); } inline String16& String16::operator=(const String16& other) { setTo(other); return *this; } inline String16& String16::operator+=(const String16& other) { append(other); return *this; } inline String16 String16::operator+(const String16& other) const { String16 tmp(*this); tmp += other; return tmp; } inline int String16::compare(const String16& other) const { return strzcmp16(mString, size(), other.mString, other.size()); } inline bool String16::operator<(const String16& other) const { return strzcmp16(mString, size(), other.mString, other.size()) < 0; } inline bool String16::operator<=(const String16& other) const { return strzcmp16(mString, size(), other.mString, other.size()) <= 0; } inline bool String16::operator==(const String16& other) const { return strzcmp16(mString, size(), other.mString, other.size()) == 0; } inline bool String16::operator!=(const String16& other) const { return strzcmp16(mString, size(), other.mString, other.size()) != 0; } inline bool String16::operator>=(const String16& other) const { return strzcmp16(mString, size(), other.mString, other.size()) >= 0; } inline bool String16::operator>(const String16& other) const { return strzcmp16(mString, size(), other.mString, other.size()) > 0; } inline bool String16::operator<(const char16_t* other) const { return strcmp16(mString, other) < 0; } inline bool String16::operator<=(const char16_t* other) const { return strcmp16(mString, other) <= 0; } inline bool String16::operator==(const char16_t* other) const { return strcmp16(mString, other) == 0; } inline bool String16::operator!=(const char16_t* other) const { return strcmp16(mString, other) != 0; } inline bool String16::operator>=(const char16_t* other) const { return strcmp16(mString, other) >= 0; } inline bool String16::operator>(const char16_t* other) const { return strcmp16(mString, other) > 0; } inline String16::operator const char16_t*() const { return mString; } }; // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_STRING16_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/utils/SharedBuffer.h0000644000015301777760000001063612322054223025033 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_SHARED_BUFFER_H #define ANDROID_SHARED_BUFFER_H #include #include // --------------------------------------------------------------------------- namespace android { class SharedBuffer { public: /* flags to use with release() */ enum { eKeepStorage = 0x00000001 }; /*! allocate a buffer of size 'size' and acquire() it. * call release() to free it. */ static SharedBuffer* alloc(size_t size); /*! free the memory associated with the SharedBuffer. * Fails if there are any users associated with this SharedBuffer. * In other words, the buffer must have been release by all its * users. */ static ssize_t dealloc(const SharedBuffer* released); //! get the SharedBuffer from the data pointer static inline const SharedBuffer* sharedBuffer(const void* data); //! access the data for read inline const void* data() const; //! access the data for read/write inline void* data(); //! get size of the buffer inline size_t size() const; //! get back a SharedBuffer object from its data static inline SharedBuffer* bufferFromData(void* data); //! get back a SharedBuffer object from its data static inline const SharedBuffer* bufferFromData(const void* data); //! get the size of a SharedBuffer object from its data static inline size_t sizeFromData(const void* data); //! edit the buffer (get a writtable, or non-const, version of it) SharedBuffer* edit() const; //! edit the buffer, resizing if needed SharedBuffer* editResize(size_t size) const; //! like edit() but fails if a copy is required SharedBuffer* attemptEdit() const; //! resize and edit the buffer, loose it's content. SharedBuffer* reset(size_t size) const; //! acquire/release a reference on this buffer void acquire() const; /*! release a reference on this buffer, with the option of not * freeing the memory associated with it if it was the last reference * returns the previous reference count */ int32_t release(uint32_t flags = 0) const; //! returns wether or not we're the only owner inline bool onlyOwner() const; private: inline SharedBuffer() { } inline ~SharedBuffer() { } inline SharedBuffer(const SharedBuffer&); // 16 bytes. must be sized to preserve correct alingment. mutable int32_t mRefs; size_t mSize; uint32_t mReserved[2]; }; // --------------------------------------------------------------------------- const SharedBuffer* SharedBuffer::sharedBuffer(const void* data) { return data ? reinterpret_cast(data)-1 : 0; } const void* SharedBuffer::data() const { return this + 1; } void* SharedBuffer::data() { return this + 1; } size_t SharedBuffer::size() const { return mSize; } SharedBuffer* SharedBuffer::bufferFromData(void* data) { return ((SharedBuffer*)data)-1; } const SharedBuffer* SharedBuffer::bufferFromData(const void* data) { return ((const SharedBuffer*)data)-1; } size_t SharedBuffer::sizeFromData(const void* data) { return (((const SharedBuffer*)data)-1)->mSize; } bool SharedBuffer::onlyOwner() const { return (mRefs == 1); } } // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_VECTOR_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/utils/RefBase.h0000644000015301777760000003625712322054223024011 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_REF_BASE_H #define ANDROID_REF_BASE_H #include #include #include #include #include #include #include // --------------------------------------------------------------------------- namespace android { class TextOutput; TextOutput& printWeakPointer(TextOutput& to, const void* val); // --------------------------------------------------------------------------- #define COMPARE_WEAK(_op_) \ inline bool operator _op_ (const sp& o) const { \ return m_ptr _op_ o.m_ptr; \ } \ inline bool operator _op_ (const T* o) const { \ return m_ptr _op_ o; \ } \ template \ inline bool operator _op_ (const sp& o) const { \ return m_ptr _op_ o.m_ptr; \ } \ template \ inline bool operator _op_ (const U* o) const { \ return m_ptr _op_ o; \ } // --------------------------------------------------------------------------- class ReferenceMover; class ReferenceConverterBase { public: virtual size_t getReferenceTypeSize() const = 0; virtual void* getReferenceBase(void const*) const = 0; inline virtual ~ReferenceConverterBase() { } }; // --------------------------------------------------------------------------- class RefBase { public: void incStrong(const void* id) const; void decStrong(const void* id) const; void forceIncStrong(const void* id) const; //! DEBUGGING ONLY: Get current strong ref count. int32_t getStrongCount() const; class weakref_type { public: RefBase* refBase() const; void incWeak(const void* id); void decWeak(const void* id); // acquires a strong reference if there is already one. bool attemptIncStrong(const void* id); // acquires a weak reference if there is already one. // This is not always safe. see ProcessState.cpp and BpBinder.cpp // for proper use. bool attemptIncWeak(const void* id); //! DEBUGGING ONLY: Get current weak ref count. int32_t getWeakCount() const; //! DEBUGGING ONLY: Print references held on object. void printRefs() const; //! DEBUGGING ONLY: Enable tracking for this object. // enable -- enable/disable tracking // retain -- when tracking is enable, if true, then we save a stack trace // for each reference and dereference; when retain == false, we // match up references and dereferences and keep only the // outstanding ones. void trackMe(bool enable, bool retain); }; weakref_type* createWeak(const void* id) const; weakref_type* getWeakRefs() const; //! DEBUGGING ONLY: Print references held on object. inline void printRefs() const { getWeakRefs()->printRefs(); } //! DEBUGGING ONLY: Enable tracking of object. inline void trackMe(bool enable, bool retain) { getWeakRefs()->trackMe(enable, retain); } typedef RefBase basetype; protected: RefBase(); virtual ~RefBase(); //! Flags for extendObjectLifetime() enum { OBJECT_LIFETIME_STRONG = 0x0000, OBJECT_LIFETIME_WEAK = 0x0001, OBJECT_LIFETIME_MASK = 0x0001 }; void extendObjectLifetime(int32_t mode); //! Flags for onIncStrongAttempted() enum { FIRST_INC_STRONG = 0x0001 }; virtual void onFirstRef(); virtual void onLastStrongRef(const void* id); virtual bool onIncStrongAttempted(uint32_t flags, const void* id); virtual void onLastWeakRef(const void* id); private: friend class ReferenceMover; static void moveReferences(void* d, void const* s, size_t n, const ReferenceConverterBase& caster); private: friend class weakref_type; class weakref_impl; RefBase(const RefBase& o); RefBase& operator=(const RefBase& o); weakref_impl* const mRefs; }; // --------------------------------------------------------------------------- template class LightRefBase { public: inline LightRefBase() : mCount(0) { } inline void incStrong(const void* /* id */) const { android_atomic_inc(&mCount); } inline void decStrong(const void* /* id */) const { if (android_atomic_dec(&mCount) == 1) { delete static_cast(this); } } //! DEBUGGING ONLY: Get current strong ref count. inline int32_t getStrongCount() const { return mCount; } typedef LightRefBase basetype; protected: inline ~LightRefBase() { } private: friend class ReferenceMover; inline static void moveReferences(void* /* d */, void const* /* s */, size_t /* n */, const ReferenceConverterBase& /* caster */) { } private: mutable android_atomic_int32_t mCount; }; // --------------------------------------------------------------------------- template class wp { public: typedef typename RefBase::weakref_type weakref_type; inline wp() : m_ptr(0) { } wp(T* other); wp(const wp& other); wp(const sp& other); template wp(U* other); template wp(const sp& other); template wp(const wp& other); ~wp(); // Assignment wp& operator = (T* other); wp& operator = (const wp& other); wp& operator = (const sp& other); template wp& operator = (U* other); template wp& operator = (const wp& other); template wp& operator = (const sp& other); void set_object_and_refs(T* other, weakref_type* refs); // promotion to sp sp promote() const; // Reset void clear(); // Accessors inline weakref_type* get_refs() const { return m_refs; } inline T* unsafe_get() const { return m_ptr; } // Operators COMPARE_WEAK(==) COMPARE_WEAK(!=) COMPARE_WEAK(>) COMPARE_WEAK(<) COMPARE_WEAK(<=) COMPARE_WEAK(>=) inline bool operator == (const wp& o) const { return (m_ptr == o.m_ptr) && (m_refs == o.m_refs); } template inline bool operator == (const wp& o) const { return m_ptr == o.m_ptr; } inline bool operator > (const wp& o) const { return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr); } template inline bool operator > (const wp& o) const { return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr); } inline bool operator < (const wp& o) const { return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr); } template inline bool operator < (const wp& o) const { return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr); } inline bool operator != (const wp& o) const { return m_refs != o.m_refs; } template inline bool operator != (const wp& o) const { return !operator == (o); } inline bool operator <= (const wp& o) const { return !operator > (o); } template inline bool operator <= (const wp& o) const { return !operator > (o); } inline bool operator >= (const wp& o) const { return !operator < (o); } template inline bool operator >= (const wp& o) const { return !operator < (o); } private: template friend class sp; template friend class wp; T* m_ptr; weakref_type* m_refs; }; template TextOutput& operator<<(TextOutput& to, const wp& val); #undef COMPARE_WEAK // --------------------------------------------------------------------------- // No user serviceable parts below here. template wp::wp(T* other) : m_ptr(other) { if (other) m_refs = other->createWeak(this); } template wp::wp(const wp& other) : m_ptr(other.m_ptr), m_refs(other.m_refs) { if (m_ptr) m_refs->incWeak(this); } template wp::wp(const sp& other) : m_ptr(other.m_ptr) { if (m_ptr) { m_refs = m_ptr->createWeak(this); } } template template wp::wp(U* other) : m_ptr(other) { if (other) m_refs = other->createWeak(this); } template template wp::wp(const wp& other) : m_ptr(other.m_ptr) { if (m_ptr) { m_refs = other.m_refs; m_refs->incWeak(this); } } template template wp::wp(const sp& other) : m_ptr(other.m_ptr) { if (m_ptr) { m_refs = m_ptr->createWeak(this); } } template wp::~wp() { if (m_ptr) m_refs->decWeak(this); } template wp& wp::operator = (T* other) { weakref_type* newRefs = other ? other->createWeak(this) : 0; if (m_ptr) m_refs->decWeak(this); m_ptr = other; m_refs = newRefs; return *this; } template wp& wp::operator = (const wp& other) { weakref_type* otherRefs(other.m_refs); T* otherPtr(other.m_ptr); if (otherPtr) otherRefs->incWeak(this); if (m_ptr) m_refs->decWeak(this); m_ptr = otherPtr; m_refs = otherRefs; return *this; } template wp& wp::operator = (const sp& other) { weakref_type* newRefs = other != NULL ? other->createWeak(this) : 0; T* otherPtr(other.m_ptr); if (m_ptr) m_refs->decWeak(this); m_ptr = otherPtr; m_refs = newRefs; return *this; } template template wp& wp::operator = (U* other) { weakref_type* newRefs = other ? other->createWeak(this) : 0; if (m_ptr) m_refs->decWeak(this); m_ptr = other; m_refs = newRefs; return *this; } template template wp& wp::operator = (const wp& other) { weakref_type* otherRefs(other.m_refs); U* otherPtr(other.m_ptr); if (otherPtr) otherRefs->incWeak(this); if (m_ptr) m_refs->decWeak(this); m_ptr = otherPtr; m_refs = otherRefs; return *this; } template template wp& wp::operator = (const sp& other) { weakref_type* newRefs = other != NULL ? other->createWeak(this) : 0; U* otherPtr(other.m_ptr); if (m_ptr) m_refs->decWeak(this); m_ptr = otherPtr; m_refs = newRefs; return *this; } template void wp::set_object_and_refs(T* other, weakref_type* refs) { if (other) refs->incWeak(this); if (m_ptr) m_refs->decWeak(this); m_ptr = other; m_refs = refs; } template sp wp::promote() const { sp result; if (m_ptr && m_refs->attemptIncStrong(&result)) { result.set_pointer(m_ptr); } return result; } template void wp::clear() { if (m_ptr) { m_refs->decWeak(this); m_ptr = 0; } } template inline TextOutput& operator<<(TextOutput& to, const wp& val) { return printWeakPointer(to, val.unsafe_get()); } // --------------------------------------------------------------------------- // this class just serves as a namespace so TYPE::moveReferences can stay // private. class ReferenceMover { // StrongReferenceCast and WeakReferenceCast do the impedance matching // between the generic (void*) implementation in Refbase and the strongly typed // template specializations below. template struct StrongReferenceCast : public ReferenceConverterBase { virtual size_t getReferenceTypeSize() const { return sizeof( sp ); } virtual void* getReferenceBase(void const* p) const { sp const* sptr(reinterpret_cast const*>(p)); return static_cast(sptr->get()); } }; template struct WeakReferenceCast : public ReferenceConverterBase { virtual size_t getReferenceTypeSize() const { return sizeof( wp ); } virtual void* getReferenceBase(void const* p) const { wp const* sptr(reinterpret_cast const*>(p)); return static_cast(sptr->unsafe_get()); } }; public: template static inline void move_references(sp* d, sp const* s, size_t n) { memmove(d, s, n*sizeof(sp)); StrongReferenceCast caster; TYPE::moveReferences(d, s, n, caster); } template static inline void move_references(wp* d, wp const* s, size_t n) { memmove(d, s, n*sizeof(wp)); WeakReferenceCast caster; TYPE::moveReferences(d, s, n, caster); } }; // specialization for moving sp<> and wp<> types. // these are used by the [Sorted|Keyed]Vector<> implementations // sp<> and wp<> need to be handled specially, because they do not // have trivial copy operation in the general case (see RefBase.cpp // when DEBUG ops are enabled), but can be implemented very // efficiently in most cases. template inline void move_forward_type(sp* d, sp const* s, size_t n) { ReferenceMover::move_references(d, s, n); } template inline void move_backward_type(sp* d, sp const* s, size_t n) { ReferenceMover::move_references(d, s, n); } template inline void move_forward_type(wp* d, wp const* s, size_t n) { ReferenceMover::move_references(d, s, n); } template inline void move_backward_type(wp* d, wp const* s, size_t n) { ReferenceMover::move_references(d, s, n); } } // namespace android // --------------------------------------------------------------------------- #endif // ANDROID_REF_BASE_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/cutils/0000755000015301777760000000000012322054703022462 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/3rd_party/android-deps/cutils/uio.h0000644000015301777760000000221212322054223023421 0ustar pbusernogroup00000000000000/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // // implementation of sys/uio.h for platforms that don't have it (Win32) // #ifndef _LIBS_CUTILS_UIO_H #define _LIBS_CUTILS_UIO_H #ifdef HAVE_SYS_UIO_H #include #else #ifdef __cplusplus extern "C" { #endif #include struct iovec { const void* iov_base; size_t iov_len; }; extern int readv( int fd, struct iovec* vecs, int count ); extern int writev( int fd, const struct iovec* vecs, int count ); #ifdef __cplusplus } #endif #endif /* !HAVE_SYS_UIO_H */ #endif /* _LIBS_UTILS_UIO_H */ mir-0.1.8+14.04.20140411/3rd_party/android-deps/cutils/log.h0000644000015301777760000003147312322054223023421 0ustar pbusernogroup00000000000000/* * Copyright (C) 2005 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // // C/C++ logging functions. See the logging documentation for API details. // // We'd like these to be available from C code (in case we import some from // somewhere), so this has a C interface. // // The output will be correct when the log file is shared between multiple // threads and/or multiple processes so long as the operating system // supports O_APPEND. These calls have mutex-protected data structures // and so are NOT reentrant. Do not use LOG in a signal handler. // #ifndef _LIBS_CUTILS_LOG_H #define _LIBS_CUTILS_LOG_H #include #include #include #include #ifdef HAVE_PTHREADS #include #endif #include #include #include #ifdef __cplusplus extern "C" { #endif // --------------------------------------------------------------------- /* * Normally we strip ALOGV (VERBOSE messages) from release builds. * You can modify this (for example with "#define LOG_NDEBUG 0" * at the top of your source file) to change that behavior. */ #ifndef LOG_NDEBUG #ifdef NDEBUG #define LOG_NDEBUG 1 #else #define LOG_NDEBUG 0 #endif #endif /* * This is the local tag used for the following simplified * logging macros. You can change this preprocessor definition * before using the other macros to change the tag. */ #ifndef LOG_TAG #define LOG_TAG NULL #endif // --------------------------------------------------------------------- /* * Simplified macro to send a verbose log message using the current LOG_TAG. */ #ifndef ALOGV #if LOG_NDEBUG #define ALOGV(...) ((void)0) #else #define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) #endif #endif #define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) #ifndef ALOGV_IF #if LOG_NDEBUG #define ALOGV_IF(cond, ...) ((void)0) #else #define ALOGV_IF(cond, ...) \ ( (CONDITION(cond)) \ ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif #endif /* * Simplified macro to send a debug log message using the current LOG_TAG. */ #ifndef ALOGD #define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) #endif #ifndef ALOGD_IF #define ALOGD_IF(cond, ...) \ ( (CONDITION(cond)) \ ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif /* * Simplified macro to send an info log message using the current LOG_TAG. */ #ifndef ALOGI #define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) #endif #ifndef ALOGI_IF #define ALOGI_IF(cond, ...) \ ( (CONDITION(cond)) \ ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif /* * Simplified macro to send a warning log message using the current LOG_TAG. */ #ifndef ALOGW #define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) #endif #ifndef ALOGW_IF #define ALOGW_IF(cond, ...) \ ( (CONDITION(cond)) \ ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif /* * Simplified macro to send an error log message using the current LOG_TAG. */ #ifndef ALOGE #define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) #endif #ifndef ALOGE_IF #define ALOGE_IF(cond, ...) \ ( (CONDITION(cond)) \ ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif // --------------------------------------------------------------------- /* * Conditional based on whether the current LOG_TAG is enabled at * verbose priority. */ #ifndef IF_ALOGV #if LOG_NDEBUG #define IF_ALOGV() if (false) #else #define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG) #endif #endif /* * Conditional based on whether the current LOG_TAG is enabled at * debug priority. */ #ifndef IF_ALOGD #define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG) #endif /* * Conditional based on whether the current LOG_TAG is enabled at * info priority. */ #ifndef IF_ALOGI #define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG) #endif /* * Conditional based on whether the current LOG_TAG is enabled at * warn priority. */ #ifndef IF_ALOGW #define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG) #endif /* * Conditional based on whether the current LOG_TAG is enabled at * error priority. */ #ifndef IF_ALOGE #define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG) #endif // --------------------------------------------------------------------- /* * Simplified macro to send a verbose system log message using the current LOG_TAG. */ #ifndef SLOGV #if LOG_NDEBUG #define SLOGV(...) ((void)0) #else #define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) #endif #endif #define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) #ifndef SLOGV_IF #if LOG_NDEBUG #define SLOGV_IF(cond, ...) ((void)0) #else #define SLOGV_IF(cond, ...) \ ( (CONDITION(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif #endif /* * Simplified macro to send a debug system log message using the current LOG_TAG. */ #ifndef SLOGD #define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) #endif #ifndef SLOGD_IF #define SLOGD_IF(cond, ...) \ ( (CONDITION(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif /* * Simplified macro to send an info system log message using the current LOG_TAG. */ #ifndef SLOGI #define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) #endif #ifndef SLOGI_IF #define SLOGI_IF(cond, ...) \ ( (CONDITION(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif /* * Simplified macro to send a warning system log message using the current LOG_TAG. */ #ifndef SLOGW #define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) #endif #ifndef SLOGW_IF #define SLOGW_IF(cond, ...) \ ( (CONDITION(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif /* * Simplified macro to send an error system log message using the current LOG_TAG. */ #ifndef SLOGE #define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) #endif #ifndef SLOGE_IF #define SLOGE_IF(cond, ...) \ ( (CONDITION(cond)) \ ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ : (void)0 ) #endif // --------------------------------------------------------------------- /* * Log a fatal error. If the given condition fails, this stops program * execution like a normal assertion, but also generating the given message. * It is NOT stripped from release builds. Note that the condition test * is -inverted- from the normal assert() semantics. */ #ifndef LOG_ALWAYS_FATAL_IF #define LOG_ALWAYS_FATAL_IF(cond, ...) \ ( (CONDITION(cond)) \ ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \ : (void)0 ) #endif #ifndef LOG_ALWAYS_FATAL #define LOG_ALWAYS_FATAL(...) \ ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) ) #endif /* * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that * are stripped out of release builds. */ #if LOG_NDEBUG #ifndef LOG_FATAL_IF #define LOG_FATAL_IF(cond, ...) ((void)0) #endif #ifndef LOG_FATAL #define LOG_FATAL(...) ((void)0) #endif #else #ifndef LOG_FATAL_IF #define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__) #endif #ifndef LOG_FATAL #define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__) #endif #endif /* * Assertion that generates a log message when the assertion fails. * Stripped out of release builds. Uses the current LOG_TAG. */ #ifndef ALOG_ASSERT #define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__) //#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond) #endif // --------------------------------------------------------------------- /* * Basic log message macro. * * Example: * ALOG(LOG_WARN, NULL, "Failed with error %d", errno); * * The second argument may be NULL or "" to indicate the "global" tag. */ #ifndef ALOG #define ALOG(priority, tag, ...) \ LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) #endif /* * Log macro that allows you to specify a number for the priority. */ #ifndef LOG_PRI #define LOG_PRI(priority, tag, ...) \ android_printLog(priority, tag, __VA_ARGS__) #endif /* * Log macro that allows you to pass in a varargs ("args" is a va_list). */ #ifndef LOG_PRI_VA #define LOG_PRI_VA(priority, tag, fmt, args) \ android_vprintLog(priority, NULL, tag, fmt, args) #endif /* * Conditional given a desired logging priority and tag. */ #ifndef IF_ALOG #define IF_ALOG(priority, tag) \ if (android_testLog(ANDROID_##priority, tag)) #endif // --------------------------------------------------------------------- /* * Event logging. */ /* * Event log entry types. These must match up with the declarations in * java/android/android/util/EventLog.java. */ typedef enum { EVENT_TYPE_INT = 0, EVENT_TYPE_LONG = 1, EVENT_TYPE_STRING = 2, EVENT_TYPE_LIST = 3 } AndroidEventLogType; #ifndef LOG_EVENT_INT #define LOG_EVENT_INT(_tag, _value) { \ int intBuf = _value; \ (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, \ sizeof(intBuf)); \ } #endif #ifndef LOG_EVENT_LONG #define LOG_EVENT_LONG(_tag, _value) { \ long long longBuf = _value; \ (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, \ sizeof(longBuf)); \ } #endif #ifndef LOG_EVENT_STRING #define LOG_EVENT_STRING(_tag, _value) \ ((void) 0) /* not implemented -- must combine len with string */ #endif /* TODO: something for LIST */ /* * =========================================================================== * * The stuff in the rest of this file should not be used directly. */ #define android_printLog(prio, tag, ...) \ __android_log_print(prio, tag, __VA_ARGS__) #define android_vprintLog(prio, cond, tag, ...) \ __android_log_vprint(prio, tag, __VA_ARGS__) /* XXX Macros to work around syntax errors in places where format string * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF * (happens only in debug builds). */ /* Returns 2nd arg. Used to substitute default value if caller's vararg list * is empty. */ #define __android_second(dummy, second, ...) second /* If passed multiple args, returns ',' followed by all but 1st arg, otherwise * returns nothing. */ #define __android_rest(first, ...) , ## __VA_ARGS__ #ifdef HAVE_ANDROID_OS #define android_printAssert(cond, tag, ...) \ __android_log_assert(cond, tag, \ __android_second(0, ## __VA_ARGS__, NULL) __android_rest(__VA_ARGS__)) #else #include #define android_printAssert(cond, tag, ...) \ assert(false && #cond) #endif // HAVE_ANDROID_OS #define android_writeLog(prio, tag, text) \ __android_log_write(prio, tag, text) #define android_bWriteLog(tag, payload, len) \ __android_log_bwrite(tag, payload, len) #define android_btWriteLog(tag, type, payload, len) \ __android_log_btwrite(tag, type, payload, len) // TODO: remove these prototypes and their users #define android_testLog(prio, tag) (1) #define android_writevLog(vec,num) do{}while(0) #define android_write1Log(str,len) do{}while (0) #define android_setMinPriority(tag, prio) do{}while(0) //#define android_logToCallback(func) do{}while(0) #define android_logToFile(tag, file) (0) #define android_logToFd(tag, fd) (0) typedef enum { LOG_ID_MAIN = 0, LOG_ID_RADIO = 1, LOG_ID_EVENTS = 2, LOG_ID_SYSTEM = 3, LOG_ID_MAX } log_id_t; /* * Send a simple string to the log. */ int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text); int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...); #ifdef __cplusplus } #endif #endif // _LIBS_CUTILS_LOG_H mir-0.1.8+14.04.20140411/3rd_party/android-deps/cutils/logd.h0000644000015301777760000000245012322054223023556 0ustar pbusernogroup00000000000000/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _ANDROID_CUTILS_LOGD_H #define _ANDROID_CUTILS_LOGD_H /* the stable/frozen log-related definitions have been * moved to this header, which is exposed by the NDK */ #include /* the rest is only used internally by the system */ #include #include #include #include #include #ifdef HAVE_PTHREADS #include #endif #include #include #ifdef __cplusplus extern "C" { #endif int __android_log_bwrite(int32_t tag, const void *payload, size_t len); int __android_log_btwrite(int32_t tag, char type, const void *payload, size_t len); #ifdef __cplusplus } #endif #endif /* _LOGD_H */ mir-0.1.8+14.04.20140411/guides/0000755000015301777760000000000012322054703016157 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/guides/styleguide.xsl0000644000015301777760000011101212322054223021056 0ustar pbusernogroup00000000000000 <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
_
mir-0.1.8+14.04.20140411/guides/styleguide.css0000644000015301777760000000443612322054223021053 0ustar pbusernogroup00000000000000body { 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; } mir-0.1.8+14.04.20140411/guides/CMakeLists.txt0000644000015301777760000000222212322054223020712 0ustar pbusernogroup00000000000000ADD_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_BINARY_DIR}/doc/html/cppguide/styleguide.css 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) mir-0.1.8+14.04.20140411/guides/cppguide.xml0000644000015301777760000042564612322054223020517 0ustar pbusernogroup00000000000000

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 two 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(); ... }
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!

mir-0.1.8+14.04.20140411/CMakeLists.txt0000644000015301777760000001430612322054247017446 0ustar pbusernogroup00000000000000# 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) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin) set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib) set(MIR_VERSION_MAJOR 0) set(MIR_VERSION_MINOR 1) set(MIR_VERSION_PATCH 8) 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 (cmake/Doxygen.cmake) include (cmake/PrePush.cmake) include (GNUInstallDirs) 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++0x -Werror -Wall -fno-strict-aliasing -pedantic -Wnon-virtual-dtor -Wextra -fPIC") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--no-undefined") if ("${CMAKE_CXX_COMPILER}" MATCHES "clang") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-return-type-c-linkage -Wno-mismatched-tags") endif() ##################################################################### # 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 MATCHES [cC][oO][vV][eE][rR][aA][gG][eE]) 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(CMAKE_BUILD_TYPE MATCHES [cC][oO][vV][eE][rR][aA][gG][eE]) enable_testing() include_directories(include/shared) # Check for boost find_package(Boost 1.48.0 COMPONENTS chrono date_time filesystem system thread program_options regex REQUIRED) include_directories ( ${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 mesa backend set( MIR_PLATFORM mesa CACHE STRING "a list of graphics backends to build (options are 'mesa' or 'android')" ) list(GET MIR_PLATFORM 0 MIR_TEST_PLATFORM) foreach(platform IN LISTS MIR_PLATFORM) if (platform STREQUAL "mesa") set(MIR_BUILD_PLATFORM_MESA TRUE) endif() if (platform STREQUAL "android") set(MIR_BUILD_PLATFORM_ANDROID TRUE) endif() endforeach(platform) find_package(EGL REQUIRED) find_package(GLESv2 REQUIRED) find_package(GLM REQUIRED) find_package(Protobuf REQUIRED ) find_package(GLog REQUIRED) find_package(GFlags REQUIRED) find_package(XKBCOMMON REQUIRED) find_package(LTTngUST REQUIRED) pkg_check_modules(UDEV REQUIRED libudev) include_directories (${GLESv2_INCLUDE_DIRS}) include_directories (${EGL_INCLUDE_DIRS}) include_directories (${GLM_INCLUDE_DIRS}) if (MIR_BUILD_PLATFORM_ANDROID) find_package(LibHardware REQUIRED) endif() if (MIR_BUILD_PLATFORM_MESA) find_package( PkgConfig ) pkg_check_modules( GBM REQUIRED gbm>=9.0.0) pkg_check_modules( DRM REQUIRED libdrm ) 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}) set (OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Don't treat warnings as errors in 3rd_party/{gmock} string (REPLACE " -Werror " " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # Restore -Werror for non-3rd-party code set (CMAKE_CXX_FLAGS ${OLD_CMAKE_CXX_FLAGS}) option(MIR_ENABLE_TESTS "Build tests" ON) if (MIR_ENABLE_TESTS) find_package(Gtest REQUIRED) include_directories(${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR}) add_subdirectory(tests/) endif () add_subdirectory(benchmarks/) add_subdirectory(tools/) add_subdirectory(examples/) add_subdirectory(guides/) add_subdirectory(cmake/) # There's no nice way to format this. Thanks CMake. add_test(LGPL-required /bin/sh -c "! grep -rl 'GNU General' ${PROJECT_SOURCE_DIR}/src/client ${PROJECT_SOURCE_DIR}/include/client ${PROJECT_SOURCE_DIR}/src/shared ${PROJECT_SOURCE_DIR}/include/shared ${PROJECT_SOURCE_DIR}/src/platform ${PROJECT_SOURCE_DIR}/include/platform" ) add_test(GPL-required /bin/sh -c "! grep -rl 'GNU Lesser' ${PROJECT_SOURCE_DIR}/src/server ${PROJECT_SOURCE_DIR}/include/server ${PROJECT_SOURCE_DIR}/include/test ${PROJECT_SOURCE_DIR}/tests ${PROJECT_SOURCE_DIR}/examples" ) enable_coverage_report(mirserver) mir-0.1.8+14.04.20140411/HACKING.md0000644000015301777760000000754712322054223016277 0ustar pbusernogroup00000000000000Mir hacking guide ================= Getting Mir ----------- If you're reading this file then you've probably solved this one. ;) However, for completeness Mir is a project on LaunchPad (https://launchpad.net/mir) to grab a copy use the command: $ bzr branch lp:mir Getting dependencies -------------------- To succesfully build Mir there are a few packages required: $ apt-get install devscripts equivs cmake $ mk-build-deps --install --tool "apt-get -y" --build-dep debian/control Building Mir ----------- Mir is built using cmake. There are other options, but here's one way to build the system: $ mkdir build $ cd build $ cmake .. $ make -j 8 $ ctest Coding Mir ---------- There's a coding style guide in the guides subdirectory. To build it into an html file: $ make guides (Or if you're reading the web version [here](cppguide/index.html)). Code structure -------------- Code structure: include The include subdirectory contains header files "published" by corresponding parts of the system. For example, include/mir/option/option.h provides a system-wide interface for accessing runtime options published by the options component. In many cases, there will be interfaces defined that are used by the component and implemented elsewhere. E.g. the compositor uses RenderView which is implemented by the surfaces component. Files under the include directory should contain minimal implementation detail: interfaces should not expose platform or implementation technology types etc. (And as public methods are normally implementations of interfaces they do not use these types.) Code structure: src This comprises the implementation of Mir. Header files for use within the component should be put here. The only headers from the source tree that should be included are ones from the current component (ones that do not require a path component). Code structure: test This contains unit, integration and acceptance tests written using gtest/gmock. Tests largely depend upon the public interfaces of components - but tests of units within a component will include headers from within the source tree. Code structure: 3rd_party Third party code imported into our source tree for use in Mir. We try not to change anything to avoid maintaining a fork. Error handling strategy ----------------------- If a function cannot meet its post-conditions it throws an exception and meets AT LEAST the basic exception safety guarantee. It is a good idea to document the strong and no-throw guarantees. http://www.boost.org/community/exception_safety.html A function is not required to check its preconditions (there should be no tests that preconditions failures are reported). This means that preconditions may be verified using the "assert" macro - which may or may not report problems (depending upon the NDEBUG define). Implicit rules -------------- There are a lot of pointers (mostly smart, but a few raw ones) passed around in the code. We have adopted the general rule that pointers are expected to refer to valid objects. This avoids repetitive tests for validity. Unless otherwise documented functions and constructors that take pointer parameters have validity of the referenced objects as a precondition. Exceptions to the rule must be of limited scope and documented. Running Mir ----------- There are some brief guides describing how to run the Mir binaries once you have them built. You might think it's obvious but there are some important things you need to know to get it working, and also to prevent your existing X server from dying at the same time. - \ref using_mir_on_pc - \ref using_mir_on_android You can configure Mir to provide runtime information helpful for debugging by enabling component reports: - \ref component_reports Documentation ------------- There are design notes and an architecture diagram (.dia) in the design subdirectory. mir-0.1.8+14.04.20140411/src/0000755000015301777760000000000012322054703015466 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/utils/0000755000015301777760000000000012322054703016626 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/utils/out.c0000644000015301777760000001314712322054223017604 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Daniel van Vugt */ #include "mir_toolkit/mir_client_library.h" #include #include static const char *output_type_name(MirDisplayOutputType t) { /* XXX it would be safer to define these strings in the client header */ static const char * const name[] = { "unknown", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite", "S-video", "LVDS", "Component", "9-pin", "DisplayPort", "HDMI-A", "HDMI-B", "TV", "eDP", }; return ((unsigned)t < sizeof(name)/sizeof(name[0])) ? name[t] : name[0]; } static const char *power_mode_name(MirPowerMode m) { /* XXX it would be safer to define these strings in the client header */ static const char * const name[] = { "on", "standby", "suspended", "off" }; return ((unsigned)m < sizeof(name)/sizeof(name[0])) ? name[m] : "unknown"; } static const char *orientation_name(MirOrientation ori) { static const char * const name[] = { "normal", "left", "inverted", "right" }; return name[(ori % 360) / 90]; } int main(int argc, char *argv[]) { const char *server = NULL; for (int a = 1; a < argc; a++) { const char *arg = argv[a]; if (arg[0] == '-') { switch (arg[1]) { case 'h': default: printf("Usage: %s [-h] []\n" "Options:\n" " -h Show this help information.\n" , argv[0]); return 0; } } else { server = arg; } } MirConnection *conn = mir_connect_sync(server, argv[0]); if (!mir_connection_is_valid(conn)) { fprintf(stderr, "Could not connect to a display server.\n"); return 1; } printf("Connected to server: %s\n", server ? server : ""); MirDisplayConfiguration *conf = mir_connection_create_display_config(conn); if (conf == NULL) { fprintf(stderr, "Failed to get display configuration (!?)\n"); } else { for (unsigned c = 0; c < conf->num_cards; ++c) { const MirDisplayCard *card = conf->cards + c; printf("Card %u: Max %u simultaneous outputs\n", card->card_id, card->max_simultaneous_outputs); } for (unsigned i = 0; i < conf->num_outputs; ++i) { const MirDisplayOutput *out = conf->outputs + i; printf("Output %u: Card %u, %s, %s", out->output_id, out->card_id, output_type_name(out->type), out->connected ? "connected" : "disconnected"); if (out->connected) { if (out->current_mode < out->num_modes) { const MirDisplayMode *cur = out->modes + out->current_mode; printf(", %ux%u", cur->horizontal_resolution, cur->vertical_resolution); } else { printf(", "); } float inches = sqrtf( (out->physical_width_mm * out->physical_width_mm) + (out->physical_height_mm * out->physical_height_mm)) / 25.4f; printf("%+d%+d, %s, %s, %umm x %umm (%.1f\"), %s", out->position_x, out->position_y, out->used ? "used" : "unused", power_mode_name(out->power_mode), out->physical_width_mm, out->physical_height_mm, inches, orientation_name(out->orientation)); } printf("\n"); for (unsigned m = 0; m < out->num_modes; ++m) { const MirDisplayMode *mode = out->modes + m; if (m == 0 || mode->horizontal_resolution != mode[-1].horizontal_resolution || mode->vertical_resolution != mode[-1].vertical_resolution) { if (m) printf("\n"); printf("%8ux%-8u", mode->horizontal_resolution, mode->vertical_resolution); } printf("%6.1f%c%c", mode->refresh_rate, (m == out->current_mode) ? '*' : ' ', (m == out->preferred_mode) ? '+' : ' '); } if (out->num_modes) printf("\n"); } mir_display_config_destroy(conf); } mir_connection_release(conn); return 0; } mir-0.1.8+14.04.20140411/src/utils/ping.c0000644000015301777760000000736012322054223017732 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Daniel van Vugt */ #define _POSIX_C_SOURCE 199309L /* to get struct timespec */ #include "mir_toolkit/mir_client_library.h" #include #include #include #include static volatile sig_atomic_t running = 1; static void shutdown(int signum) { if (running) { running = 0; printf("Signal %d received. Good night.\n", signum); } } static long long now() /* in nanoseconds */ { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (long long)ts.tv_sec * 1000000000LL + (long long)ts.tv_nsec; } int main(int argc, char *argv[]) { const char *server = NULL; int interval = 1; for (int a = 1; a < argc; a++) { const char *arg = argv[a]; if (arg[0] == '-') { switch (arg[1]) { case 'f': interval = 0; break; case 'h': default: printf("Usage: %s [-f] [-h] []\n" "Options:\n" " -f Flood (no delay). On multi-core systems this can eliminate context\n" " switching delays, at the expense of occupying all the CPU time.\n" " -h Show this help information.\n" , argv[0]); return 0; } } else { server = arg; } } MirConnection *conn = mir_connect_sync(server, argv[0]); if (!mir_connection_is_valid(conn)) { fprintf(stderr, "Could not connect to a display server.\n"); return 1; } MirPixelFormat formats[1]; unsigned int valid_formats = 0; mir_connection_get_available_surface_formats(conn, formats, 1, &valid_formats); MirSurfaceParameters parm; parm.buffer_usage = mir_buffer_usage_software; parm.output_id = mir_display_output_id_invalid; parm.pixel_format = formats[0]; parm.name = "ping"; parm.width = 1; parm.height = 1; MirSurface *surf = mir_connection_create_surface_sync(conn, &parm); if (surf == NULL || !mir_surface_is_valid(surf)) { fprintf(stderr, "Could not create a surface.\n"); mir_connection_release(conn); return 2; } signal(SIGINT, shutdown); signal(SIGTERM, shutdown); static const MirSurfaceType types[2] = { mir_surface_type_normal, mir_surface_type_overlay }; int t = 1; printf("Connected to server: %s\n", server == NULL ? "" : server); while (running) { long long start, duration; start = now(); mir_wait_for(mir_surface_set_type(surf, types[t])); duration = now() - start; t ^= 1; printf("Round-trip time: %ld.%06ld milliseconds\n", (long)(duration / 1000000), (long)(duration % 1000000)); if (interval) sleep(interval); } mir_surface_release_sync(surf); mir_connection_release(conn); return 0; } mir-0.1.8+14.04.20140411/src/utils/CMakeLists.txt0000644000015301777760000000112712322054223021364 0ustar pbusernogroup00000000000000set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -fno-strict-aliasing -Wextra" ) include_directories( ${PROJECT_SOURCE_DIR}/include/client ) # Note that production binaries don't have underscores in their names add_executable(mirping ping.c) target_link_libraries(mirping mirclient) add_executable(mirout out.c) target_link_libraries(mirout mirclient) add_executable(mirscreencast screencast.cpp) target_link_libraries(mirscreencast mirclient ${EGL_LIBRARIES} ${GLESv2_LIBRARIES} ) install(TARGETS mirping mirout mirscreencast RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) mir-0.1.8+14.04.20140411/src/utils/screencast.cpp0000644000015301777760000003167312322054223021473 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/mir_screencast.h" #include "mir/geometry/size.h" #include "mir/raii.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace po = boost::program_options; namespace { volatile sig_atomic_t running = 1; /* On devices with android based openGL drivers, the vendor dispatcher table * may be optimized if USE_FAST_TLS_KEY is set, which hardcodes a TLS slot where * the vendor opengl function pointers live. Since glibc is not aware of this * use, collisions may happen. * Allocating a thread_local array helps avoid collisions by any thread_local usage * in async/future implementations. */ thread_local int dummy_tls[2]; void shutdown(int) { running = 0; } void read_pixels(GLenum format, mir::geometry::Size const& size, void* buffer) { auto width = size.width.as_uint32_t(); auto height = size.height.as_uint32_t(); glReadPixels(0, 0, width, height, format, GL_UNSIGNED_BYTE, buffer); } uint32_t get_first_valid_output_id(MirConnection* connection) { auto const conf = mir::raii::deleter_for( mir_connection_create_display_config(connection), &mir_display_config_destroy); if (conf == nullptr) throw std::runtime_error("Failed to get display configuration\n"); for (unsigned i = 0; i < conf->num_outputs; ++i) { MirDisplayOutput const& output = conf->outputs[i]; if (output.connected && output.used && output.current_mode < output.num_modes) { return output.output_id; } } throw std::runtime_error("Couldn't find a valid output to screencast"); } MirRectangle get_screen_region_from(MirConnection* connection, uint32_t output_id) { if (output_id == mir_display_output_id_invalid) output_id = get_first_valid_output_id(connection); auto const conf = mir::raii::deleter_for( mir_connection_create_display_config(connection), &mir_display_config_destroy); if (conf == nullptr) throw std::runtime_error("Failed to get display configuration\n"); for (unsigned i = 0; i < conf->num_outputs; ++i) { MirDisplayOutput const& output = conf->outputs[i]; if (output.output_id == output_id && output.current_mode < output.num_modes) { MirDisplayMode const& mode = output.modes[output.current_mode]; return MirRectangle{output.position_x, output.position_y, mode.horizontal_resolution, mode.vertical_resolution}; } } throw std::runtime_error("Couldn't get screen region of specified output"); } MirScreencastParameters get_screencast_params(MirConnection* connection, std::vector const& requested_size, std::vector const& requested_region, uint32_t output_id) { MirScreencastParameters params; if (requested_region.size() == 4) { params.region.left = requested_region[0]; params.region.top = requested_region[1]; params.region.width = requested_region[2]; params.region.height = requested_region[3]; } else { params.region = get_screen_region_from(connection, output_id); } if (requested_size.size() == 2) { params.width = requested_size[0]; params.height = requested_size[1]; } else { params.width = params.region.width; params.height = params.region.height; } unsigned int num_valid_formats = 0; mir_connection_get_available_surface_formats(connection, ¶ms.pixel_format, 1, &num_valid_formats); if (num_valid_formats == 0) throw std::runtime_error("Couldn't find a valid pixel format for connection"); return params; } struct EGLSetup { EGLSetup(MirConnection* connection, MirScreencast* screencast) { static EGLint const attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE}; static EGLint const context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; auto native_display = reinterpret_cast( mir_connection_get_egl_native_display(connection)); auto native_window = reinterpret_cast( mir_screencast_egl_native_window(screencast)); egl_display = eglGetDisplay(native_display); eglInitialize(egl_display, nullptr, nullptr); int n; eglChooseConfig(egl_display, attribs, &egl_config, 1, &n); egl_surface = eglCreateWindowSurface(egl_display, egl_config, native_window, NULL); if (egl_surface == EGL_NO_SURFACE) throw std::runtime_error("Failed to create EGL screencast surface"); egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, context_attribs); if (egl_context == EGL_NO_CONTEXT) throw std::runtime_error("Failed to create EGL context for screencast"); if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) != EGL_TRUE) { throw std::runtime_error("Failed to make screencast surface current"); } uint32_t a_pixel; glReadPixels(0, 0, 1, 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, &a_pixel); if (glGetError() == GL_NO_ERROR) read_pixel_format = GL_BGRA_EXT; else read_pixel_format = GL_RGBA; } ~EGLSetup() { eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(egl_display, egl_surface); eglDestroyContext(egl_display, egl_context); eglTerminate(egl_display); } void swap_buffers() const { if (eglSwapBuffers(egl_display, egl_surface) != EGL_TRUE) throw std::runtime_error("Failed to swap screencast surface buffers"); } GLenum pixel_read_format() const { return read_pixel_format; } EGLDisplay egl_display; EGLContext egl_context; EGLSurface egl_surface; EGLConfig egl_config; GLenum read_pixel_format; }; void do_screencast(EGLSetup const& egl_setup, mir::geometry::Size const& size, int32_t number_of_captures, std::ostream& out_stream) { static int const rgba_pixel_size{4}; auto const frame_size_bytes = rgba_pixel_size * size.width.as_uint32_t() * size.height.as_uint32_t(); std::vector frame_data(frame_size_bytes, 0); auto format = egl_setup.pixel_read_format(); while (running && (number_of_captures != 0)) { read_pixels(format, size, frame_data.data()); auto write_out_future = std::async( std::launch::async, [&out_stream, &frame_data] { out_stream.write(frame_data.data(), frame_data.size()); }); egl_setup.swap_buffers(); write_out_future.wait(); if (number_of_captures > 0) number_of_captures--; } } } int main(int argc, char* argv[]) try { uint32_t output_id = mir_display_output_id_invalid; int number_of_captures = -1; std::string output_filename; std::string socket_filename; std::vector screen_region; std::vector requested_size; bool use_std_out = false; bool query_params_only = false; //avoid unused warning/error dummy_tls[0] = 0; po::options_description desc("Usage"); desc.add_options() ("help,h", "displays this message") ("number-of-frames,n", po::value(&number_of_captures), "number of frames to capture") ("display-id,d", po::value(&output_id), "id of the display to capture") ("mir-socket-file,m", po::value(&socket_filename), "mir server socket filename") ("file,f", po::value(&output_filename), "output filename (default is /tmp/mir_screencast_x.") ("size,s", po::value>(&requested_size)->multitoken(), "screencast size [width height]") ("screen-region,r", po::value>(&screen_region)->multitoken(), "screen region to capture [left top width height]") ("stdout", po::value(&use_std_out)->zero_tokens(), "use stdout for output (--file is ignored)") ("query", po::value(&query_params_only)->zero_tokens(), "only queries the colorspace and output size used but does not start screencast"); po::variables_map vm; try { po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); if (vm.count("size") && requested_size.size() != 2) throw po::error("invalid number of parameters specified for size"); if (vm.count("screen-region") && screen_region.size() != 4) throw po::error("invalid number of parameters specified for screen-region"); if (vm.count("display-id") && vm.count("screen-region")) throw po::error("cannot set both display-id and screen-region"); } catch(po::error& e) { std::cerr << e.what() << std::endl << std::endl; std::cerr << desc << std::endl; return EXIT_FAILURE; } if (vm.count("help")) { std::cout << desc << std::endl; return EXIT_SUCCESS; } signal(SIGINT, shutdown); signal(SIGTERM, shutdown); char const* socket_name = vm.count("mir-socket-file") ? socket_filename.c_str() : nullptr; auto const connection = mir::raii::deleter_for( mir_connect_sync(socket_name, "mirscreencast"), [](MirConnection* c) { if (c) mir_connection_release(c); }); if (connection == nullptr || !mir_connection_is_valid(connection.get())) { std::string msg("Failed to connect to server."); if (connection) { msg += " Error was :"; msg += mir_connection_get_error_message(connection.get()); } throw std::runtime_error(std::string(msg)); } MirScreencastParameters params = get_screencast_params(connection.get(), requested_size, screen_region, output_id); auto const screencast = mir::raii::deleter_for( mir_connection_create_screencast_sync(connection.get(), ¶ms), [](MirScreencast* s) { if (s) mir_screencast_release_sync(s); }); if (screencast == nullptr) throw std::runtime_error("Failed to create screencast"); EGLSetup egl_setup{connection.get(), screencast.get()}; mir::geometry::Size screencast_size {params.width, params.height}; if (output_filename.empty() && !use_std_out) { std::stringstream ss; ss << "/tmp/mir_screencast_" ; ss << screencast_size.width << "x" << screencast_size.height; ss << (egl_setup.pixel_read_format() == GL_BGRA_EXT ? ".bgra" : ".rgba"); output_filename = ss.str(); } if (query_params_only) { std::cout << "Colorspace: " << (egl_setup.pixel_read_format() == GL_BGRA_EXT ? "BGRA" : "RGBA") << std::endl; std::cout << "Output size: " << screencast_size.width << "x" << screencast_size.height << std::endl; std::cout << "Output to: " << (use_std_out ? "standard out" : output_filename) << std::endl; return EXIT_SUCCESS; } if (use_std_out) { do_screencast(egl_setup, screencast_size, number_of_captures, std::cout); } else { std::ofstream file_stream(output_filename); do_screencast(egl_setup, screencast_size, number_of_captures, file_stream); } return EXIT_SUCCESS; } catch(std::exception const& e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; } mir-0.1.8+14.04.20140411/src/server/0000755000015301777760000000000012322054703016774 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/frontend/0000755000015301777760000000000012322054703020613 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/frontend/protobuf_message_processor.h0000644000015301777760000000426212322054223026430 0ustar pbusernogroup00000000000000/* * 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_PROTOBUF_MESSAGE_PROCESSOR_H_ #define MIR_FRONTEND_PROTOBUF_MESSAGE_PROCESSOR_H_ #include "mir/frontend/message_processor.h" #include "mir_protobuf.pb.h" #include namespace mir { namespace protobuf { class DisplayServer; } namespace frontend { class MessageProcessorReport; namespace detail { class ProtobufMessageSender; class ProtobufMessageProcessor : public MessageProcessor { public: ProtobufMessageProcessor( std::shared_ptr const& sender, std::shared_ptr const& display_server, std::shared_ptr const& report); ~ProtobufMessageProcessor() noexcept {} void send_response(::google::protobuf::uint32 id, ::google::protobuf::Message* response); void send_response(::google::protobuf::uint32 id, protobuf::Buffer* response); void send_response(::google::protobuf::uint32 id, protobuf::Connection* response); void send_response(::google::protobuf::uint32 id, protobuf::Surface* response); void send_response(::google::protobuf::uint32 id, std::shared_ptr response); void send_response(::google::protobuf::uint32 id, mir::protobuf::Screencast* response); private: bool dispatch(Invocation const& invocation); std::shared_ptr const sender; std::shared_ptr const display_server; std::shared_ptr const report; }; } } } #endif /* PROTOBUF_MESSAGE_PROCESSOR_H_ */ mir-0.1.8+14.04.20140411/src/server/frontend/client_buffer_tracker.h0000644000015301777760000000350212322054223025303 0ustar pbusernogroup00000000000000/* * 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: Christopher James Halse Rogers */ #ifndef MIR_FRONTEND_CLIENT_BUFFER_TRACKER_H_ #define MIR_FRONTEND_CLIENT_BUFFER_TRACKER_H_ #include #include namespace mir { namespace graphics { class BufferID; } namespace frontend { /// Responsible for tracking what buffers the client library knows about for a surface. /// \sa mir::client::ClientBufferDepository for the client-side of this tracking /// \note Changes to the tracking algorithm of mir::client::ClientBufferDepository will need to be mirrored here class ClientBufferTracker { public: ClientBufferTracker(unsigned int client_cache_size); ClientBufferTracker(ClientBufferTracker const&) = delete; ClientBufferTracker& operator=(ClientBufferTracker const&) = delete; /// Add a BufferID to the list of buffers known by the client. /// /// Typically this should be done just prior to or just after sending the buffer information void add(graphics::BufferID const& id); bool client_has(graphics::BufferID const& id) const; private: std::list ids; unsigned int const cache_size; }; } } #endif // MIR_FRONTEND_CLIENT_BUFFER_TRACKER_H_ mir-0.1.8+14.04.20140411/src/server/frontend/message_receiver.h0000644000015301777760000000320712322054247024301 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_MESSAGE_RECEIVER_H_ #define MIR_FRONTEND_MESSAGE_RECEIVER_H_ #include #include namespace mir { namespace frontend { namespace detail { class MessageReceiver { public: //receive message from the socket. 'handler' will be called when 'buffer' has been filled with exactly 'size' typedef std::function MirReadHandler; virtual void async_receive_msg(MirReadHandler const& handler, boost::asio::mutable_buffers_1 const& buffer) = 0; virtual boost::system::error_code receive_msg(boost::asio::mutable_buffers_1 const& buffer) = 0; virtual size_t available_bytes() = 0; virtual pid_t client_pid() = 0; protected: MessageReceiver() = default; virtual ~MessageReceiver() = default; MessageReceiver(MessageReceiver const&) = delete; MessageReceiver& operator=(MessageReceiver const&) = delete; }; } } } #endif /* MIR_FRONTEND_MESSAGE_RECEIVER_H_ */ mir-0.1.8+14.04.20140411/src/server/frontend/socket_session.h0000644000015301777760000000361412322054247024026 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_DETAIL_SOCKET_SESSION_H_ #define MIR_FRONTEND_DETAIL_SOCKET_SESSION_H_ #include "mir/frontend/connected_sessions.h" #include #include namespace mir { namespace frontend { namespace detail { class MessageProcessor; class MessageReceiver; struct SocketSession { SocketSession( std::shared_ptr const& socket_receiver, int id_, std::shared_ptr> const& connected_sessions, std::shared_ptr const& processor); ~SocketSession() noexcept; int id() const { return id_; } void read_next_message(); private: void on_response_sent(boost::system::error_code const& error, std::size_t); void on_new_message(const boost::system::error_code& ec); void on_read_size(const boost::system::error_code& ec); std::shared_ptr const socket_receiver; int const id_; std::shared_ptr> const connected_sessions; std::shared_ptr processor; static size_t const header_size = 2; char header[header_size]; std::vector body; }; } } } #endif /* MIR_FRONTEND_DETAIL_SOCKET_SESSION_H_ */ mir-0.1.8+14.04.20140411/src/server/frontend/session_mediator.cpp0000644000015301777760000003700712322054247024700 0ustar pbusernogroup00000000000000/* * 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 */ #include "session_mediator.h" #include "client_buffer_tracker.h" #include "mir/frontend/session_mediator_report.h" #include "mir/frontend/shell.h" #include "mir/frontend/session.h" #include "mir/frontend/surface.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/frontend/display_changer.h" #include "resource_cache.h" #include "mir_toolkit/common.h" #include "mir/graphics/buffer_id.h" #include "mir/graphics/buffer.h" #include "mir/compositor/buffer_stream.h" #include "mir/geometry/dimensions.h" #include "mir/graphics/platform.h" #include "mir/frontend/display_changer.h" #include "mir/graphics/display_configuration.h" #include "mir/graphics/pixel_format_utils.h" #include "mir/graphics/platform_ipc_package.h" #include "mir/graphics/drm_authenticator.h" #include "mir/frontend/client_constants.h" #include "mir/frontend/event_sink.h" #include "mir/frontend/screencast.h" #include "mir/geometry/rectangles.h" #include "client_buffer_tracker.h" #include "protobuf_buffer_packer.h" #include #include #include #include #include namespace msh = mir::shell; namespace mf = mir::frontend; namespace mfd=mir::frontend::detail; namespace mg = mir::graphics; namespace geom = mir::geometry; mf::SessionMediator::SessionMediator( pid_t client_pid, std::shared_ptr const& shell, std::shared_ptr const & graphics_platform, std::shared_ptr const& display_changer, std::vector const& surface_pixel_formats, std::shared_ptr const& report, std::shared_ptr const& sender, std::shared_ptr const& resource_cache, std::shared_ptr const& screencast) : client_pid(client_pid), shell(shell), graphics_platform(graphics_platform), surface_pixel_formats(surface_pixel_formats), display_changer(display_changer), report(report), event_sink(sender), resource_cache(resource_cache), screencast(screencast) { } mf::SessionMediator::~SessionMediator() noexcept { if (auto session = weak_session.lock()) { report->session_error(session->name(), __PRETTY_FUNCTION__, "connection dropped without disconnect"); shell->close_session(session); } } void mf::SessionMediator::connect( ::google::protobuf::RpcController*, const ::mir::protobuf::ConnectParameters* request, ::mir::protobuf::Connection* response, ::google::protobuf::Closure* done) { report->session_connect_called(request->application_name()); { std::unique_lock lock(session_mutex); weak_session = shell->open_session(client_pid, request->application_name(), event_sink); } auto ipc_package = graphics_platform->get_ipc_package(); auto platform = response->mutable_platform(); for (auto& data : ipc_package->ipc_data) platform->add_data(data); for (auto& ipc_fds : ipc_package->ipc_fds) platform->add_fd(ipc_fds); auto display_config = display_changer->active_configuration(); auto protobuf_config = response->mutable_display_configuration(); mfd::pack_protobuf_display_configuration(*protobuf_config, *display_config); for (auto pf : surface_pixel_formats) response->add_surface_pixel_format(static_cast<::google::protobuf::uint32>(pf)); resource_cache->save_resource(response, ipc_package); done->Run(); } void mf::SessionMediator::advance_buffer( SurfaceId surf_id, Surface& surface, std::function complete) { auto& tracker = client_buffer_tracker[surf_id]; if (!tracker) tracker = std::make_shared(client_buffer_cache_size); auto& client_buffer = client_buffer_resource[surf_id]; surface.swap_buffers(client_buffer, [&tracker, &client_buffer, complete](mg::Buffer* new_buffer) { client_buffer = new_buffer; auto id = client_buffer->id(); auto need_full_ipc = !tracker->client_has(id); tracker->add(id); complete(client_buffer, need_full_ipc); }); } void mf::SessionMediator::create_surface( google::protobuf::RpcController* /*controller*/, const mir::protobuf::SurfaceParameters* request, mir::protobuf::Surface* response, google::protobuf::Closure* done) { auto const lock = std::make_shared>(session_mutex); auto const session = weak_session.lock(); if (session.get() == nullptr) BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session")); report->session_create_surface_called(session->name()); auto const surf_id = session->create_surface(msh::SurfaceCreationParameters() .of_name(request->surface_name()) .of_size(request->width(), request->height()) .of_buffer_usage(static_cast(request->buffer_usage())) .of_pixel_format(static_cast(request->pixel_format())) .with_output_id(graphics::DisplayConfigurationOutputId(request->output_id()))); auto surface = session->get_surface(surf_id); response->mutable_id()->set_value(surf_id.as_value()); response->set_width(surface->size().width.as_uint32_t()); response->set_height(surface->size().height.as_uint32_t()); response->set_pixel_format((int)surface->pixel_format()); response->set_buffer_usage(request->buffer_usage()); if (surface->supports_input()) response->add_fd(surface->client_input_fd()); advance_buffer(surf_id, *surface, [lock, this, response, done, session](graphics::Buffer* client_buffer, bool need_full_ipc) { lock->unlock(); auto buffer = response->mutable_buffer(); pack_protobuf_buffer(*buffer, client_buffer, need_full_ipc); // TODO: NOTE: We use the ordering here to ensure the shell acts on the surface after the surface ID is sent over the wire. // This guarantees that notifications such as, gained focus, etc, can be correctly interpreted by the client. // To achieve this order we rely on done->Run() sending messages synchronously. As documented in mfd::SocketMessenger::send. // this will require additional synchronization if mfd::SocketMessenger::send changes. done->Run(); shell->handle_surface_created(session); }); } void mf::SessionMediator::next_buffer( ::google::protobuf::RpcController* /*controller*/, ::mir::protobuf::SurfaceId const* request, ::mir::protobuf::Buffer* response, ::google::protobuf::Closure* done) { SurfaceId const surf_id{request->value()}; auto const lock = std::make_shared>(session_mutex); auto const session = weak_session.lock(); if (session.get() == nullptr) BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session")); report->session_next_buffer_called(session->name()); auto surface = session->get_surface(surf_id); advance_buffer(surf_id, *surface, [lock, this, response, done, session](graphics::Buffer* client_buffer, bool need_full_ipc) { lock->unlock(); pack_protobuf_buffer(*response, client_buffer, need_full_ipc); done->Run(); }); } void mf::SessionMediator::release_surface( google::protobuf::RpcController* /*controller*/, const mir::protobuf::SurfaceId* request, mir::protobuf::Void*, google::protobuf::Closure* done) { { std::unique_lock lock(session_mutex); auto session = weak_session.lock(); if (session.get() == nullptr) BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session")); report->session_release_surface_called(session->name()); auto const id = SurfaceId(request->value()); session->destroy_surface(id); client_buffer_tracker.erase(id); } // TODO: We rely on this sending responses synchronously. done->Run(); } void mf::SessionMediator::disconnect( google::protobuf::RpcController* /*controller*/, const mir::protobuf::Void* /*request*/, mir::protobuf::Void* /*response*/, google::protobuf::Closure* done) { { std::unique_lock lock(session_mutex); auto session = weak_session.lock(); if (session.get() == nullptr) BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session")); report->session_disconnect_called(session->name()); shell->close_session(session); weak_session.reset(); } done->Run(); } void mf::SessionMediator::configure_surface( google::protobuf::RpcController*, // controller, const mir::protobuf::SurfaceSetting* request, mir::protobuf::SurfaceSetting* response, google::protobuf::Closure* done) { MirSurfaceAttrib attrib = static_cast(request->attrib()); // Required response fields: response->mutable_surfaceid()->CopyFrom(request->surfaceid()); response->set_attrib(attrib); { std::unique_lock lock(session_mutex); auto session = weak_session.lock(); if (session.get() == nullptr) BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session")); report->session_configure_surface_called(session->name()); auto const id = frontend::SurfaceId(request->surfaceid().value()); int value = request->ivalue(); int newvalue = session->configure_surface(id, attrib, value); response->set_ivalue(newvalue); } done->Run(); } void mf::SessionMediator::configure_display( ::google::protobuf::RpcController*, const ::mir::protobuf::DisplayConfiguration* request, ::mir::protobuf::DisplayConfiguration* response, ::google::protobuf::Closure* done) { { std::unique_lock lock(session_mutex); auto session = weak_session.lock(); if (session.get() == nullptr) BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session")); report->session_configure_display_called(session->name()); auto config = display_changer->active_configuration(); config->for_each_output([&](mg::UserDisplayConfigurationOutput& dest){ unsigned id = dest.id.as_value(); int n = 0; for (; n < request->display_output_size(); ++n) { if (request->display_output(n).output_id() == id) break; } if (n >= request->display_output_size()) return; auto& src = request->display_output(n); dest.used = src.used(); dest.top_left = geom::Point{src.position_x(), src.position_y()}; dest.current_mode_index = src.current_mode(); dest.current_format = static_cast(src.current_format()); dest.power_mode = static_cast(src.power_mode()); dest.orientation = static_cast(src.orientation()); }); display_changer->configure(session, config); auto display_config = display_changer->active_configuration(); mfd::pack_protobuf_display_configuration(*response, *display_config); } done->Run(); } void mf::SessionMediator::create_screencast( google::protobuf::RpcController*, const mir::protobuf::ScreencastParameters* parameters, mir::protobuf::Screencast* protobuf_screencast, google::protobuf::Closure* done) { static bool const need_full_ipc{true}; geom::Rectangle const region{ {parameters->region().left(), parameters->region().top()}, {parameters->region().width(), parameters->region().height()} }; geom::Size const size{parameters->width(), parameters->height()}; MirPixelFormat const pixel_format = static_cast(parameters->pixel_format()); auto screencast_session_id = screencast->create_session(region, size, pixel_format); auto buffer = screencast->capture(screencast_session_id); protobuf_screencast->mutable_screencast_id()->set_value( screencast_session_id.as_value()); pack_protobuf_buffer(*protobuf_screencast->mutable_buffer(), buffer.get(), need_full_ipc); done->Run(); } void mf::SessionMediator::release_screencast( google::protobuf::RpcController*, const mir::protobuf::ScreencastId* protobuf_screencast_id, mir::protobuf::Void*, google::protobuf::Closure* done) { ScreencastSessionId const screencast_session_id{ protobuf_screencast_id->value()}; screencast->destroy_session(screencast_session_id); done->Run(); } void mf::SessionMediator::screencast_buffer( google::protobuf::RpcController*, const mir::protobuf::ScreencastId* protobuf_screencast_id, mir::protobuf::Buffer* protobuf_buffer, google::protobuf::Closure* done) { static bool const does_not_need_full_ipc{false}; ScreencastSessionId const screencast_session_id{ protobuf_screencast_id->value()}; auto buffer = screencast->capture(screencast_session_id); pack_protobuf_buffer(*protobuf_buffer, buffer.get(), does_not_need_full_ipc); done->Run(); } void mf::SessionMediator::drm_auth_magic( google::protobuf::RpcController* /*controller*/, const mir::protobuf::DRMMagic* request, mir::protobuf::DRMAuthMagicStatus* response, google::protobuf::Closure* done) { { std::unique_lock lock(session_mutex); auto session = weak_session.lock(); if (session.get() == nullptr) BOOST_THROW_EXCEPTION(std::logic_error("Invalid application session")); report->session_drm_auth_magic_called(session->name()); } auto const magic = static_cast(request->magic()); auto authenticator = std::dynamic_pointer_cast(graphics_platform); if (!authenticator) BOOST_THROW_EXCEPTION(std::logic_error("drm_auth_magic request not supported by the active platform")); try { authenticator->drm_auth_magic(magic); response->set_status_code(0); } catch (std::exception const& e) { auto errno_ptr = boost::get_error_info(e); if (errno_ptr != nullptr) response->set_status_code(*errno_ptr); else throw; } done->Run(); } void mf::SessionMediator::pack_protobuf_buffer( protobuf::Buffer& protobuf_buffer, graphics::Buffer* graphics_buffer, bool need_full_ipc) { protobuf_buffer.set_buffer_id(graphics_buffer->id().as_uint32_t()); if (need_full_ipc) { mfd::ProtobufBufferPacker packer{&protobuf_buffer}; graphics_platform->fill_ipc_package(&packer, graphics_buffer); } } mir-0.1.8+14.04.20140411/src/server/frontend/message_sender.h0000644000015301777760000000232312322054247023753 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_MESSAGE_SENDER_H_ #define MIR_FRONTEND_MESSAGE_SENDER_H_ #include "mir/frontend/fd_sets.h" #include namespace mir { namespace frontend { namespace detail { class MessageSender { public: virtual void send(char const* data, size_t length, FdSets const& fds) = 0; protected: MessageSender() = default; virtual ~MessageSender() = default; MessageSender(MessageSender const&) = delete; MessageSender& operator=(MessageSender const&) = delete; }; } } } #endif /* MIR_FRONTEND_MESSAGE_SENDER_H_ */ mir-0.1.8+14.04.20140411/src/server/frontend/default_configuration.cpp0000644000015301777760000001303012322054247025672 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/default_server_configuration.h" #include "mir/frontend/protobuf_session_creator.h" #include "mir/frontend/session_authorizer.h" #include "resource_cache.h" #include "protobuf_ipc_factory.h" #include "published_socket_connector.h" #include "session_mediator.h" #include "unauthorized_display_changer.h" #include "unauthorized_screencast.h" #include "mir/options/configuration.h" #include "mir/options/option.h" #include "mir/graphics/graphic_buffer_allocator.h" namespace mf = mir::frontend; namespace mg = mir::graphics; namespace msh = mir::shell; namespace { class DefaultIpcFactory : public mf::ProtobufIpcFactory { public: explicit DefaultIpcFactory( std::shared_ptr const& shell, std::shared_ptr const& sm_report, std::shared_ptr const& graphics_platform, std::shared_ptr const& display_changer, std::shared_ptr const& buffer_allocator, std::shared_ptr const& screencast, std::shared_ptr const& session_authorizer) : shell(shell), sm_report(sm_report), cache(std::make_shared()), graphics_platform(graphics_platform), display_changer(display_changer), buffer_allocator(buffer_allocator), screencast(screencast), session_authorizer(session_authorizer) { } private: std::shared_ptr shell; std::shared_ptr const sm_report; std::shared_ptr const cache; std::shared_ptr const graphics_platform; std::shared_ptr const display_changer; std::shared_ptr const buffer_allocator; std::shared_ptr const screencast; std::shared_ptr const session_authorizer; virtual std::shared_ptr make_ipc_server( pid_t client_pid, std::shared_ptr const& sink) override { std::shared_ptr changer; std::shared_ptr effective_screencast; if (session_authorizer->configure_display_is_allowed(client_pid)) { changer = display_changer; } else { changer = std::make_shared(display_changer); } if (session_authorizer->screencast_is_allowed(client_pid)) { effective_screencast = screencast; } else { effective_screencast = std::make_shared(); } return std::make_shared( client_pid, shell, graphics_platform, changer, buffer_allocator->supported_pixel_formats(), sm_report, sink, resource_cache(), effective_screencast); } virtual std::shared_ptr resource_cache() { return cache; } }; } std::shared_ptr mir::DefaultServerConfiguration::the_session_creator() { return session_creator([this] { return std::make_shared( the_ipc_factory(the_frontend_shell(), the_buffer_allocator()), the_session_authorizer(), the_message_processor_report()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_connector() { return connector( [&,this]() -> std::shared_ptr { auto const threads = the_options()->get(options::frontend_threads_opt); if (the_options()->is_set(options::no_server_socket_opt)) { return std::make_shared( the_session_creator(), threads, the_connector_report()); } else { return std::make_shared( the_socket_file(), the_session_creator(), threads, the_connector_report()); } }); } std::shared_ptr mir::DefaultServerConfiguration::the_ipc_factory( std::shared_ptr const& shell, std::shared_ptr const& allocator) { return ipc_factory( [&]() { return std::make_shared( shell, the_session_mediator_report(), the_graphics_platform(), the_frontend_display_changer(), allocator, the_screencast(), the_session_authorizer()); }); } mir-0.1.8+14.04.20140411/src/server/frontend/published_socket_connector.h0000644000015301777760000000521112322054223026361 0ustar pbusernogroup00000000000000/* * 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 Guest */ #ifndef MIR_FRONTEND_PROTOBUF_ASIO_COMMUNICATOR_H_ #define MIR_FRONTEND_PROTOBUF_ASIO_COMMUNICATOR_H_ #include "mir/frontend/connector.h" #include #include #include #include #include namespace google { namespace protobuf { class Message; } } namespace mir { namespace frontend { class SessionCreator; class ConnectorReport; /// provides a client-side socket fd for each connection class BasicConnector : public Connector { public: explicit BasicConnector( std::shared_ptr const& session_creator, int threads, std::shared_ptr const& report); ~BasicConnector() noexcept; void start() override; void stop() override; int client_socket_fd() const override; void remove_endpoint() const override; protected: void create_session_for(std::shared_ptr const& server_socket) const; boost::asio::io_service mutable io_service; boost::asio::io_service::work work; std::shared_ptr const report; private: std::vector io_service_threads; std::shared_ptr const session_creator; }; /// Accept connections over a published socket class PublishedSocketConnector : public BasicConnector { public: explicit PublishedSocketConnector( const std::string& socket_file, std::shared_ptr const& session_creator, int threads, std::shared_ptr const& report); ~PublishedSocketConnector() noexcept; void remove_endpoint() const override; private: void start_accept(); void on_new_connection(std::shared_ptr const& socket, boost::system::error_code const& ec); const std::string socket_file; boost::asio::local::stream_protocol::acceptor acceptor; }; } } #endif // MIR_FRONTEND_PROTOBUF_ASIO_COMMUNICATOR_H_ mir-0.1.8+14.04.20140411/src/server/frontend/protobuf_session_creator.cpp0000644000015301777760000000604212322054247026446 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/frontend/protobuf_session_creator.h" #include "event_sender.h" #include "protobuf_message_processor.h" #include "protobuf_responder.h" #include "socket_messenger.h" #include "socket_session.h" #include "protobuf_ipc_factory.h" #include "mir/frontend/session_authorizer.h" #include "mir/protobuf/google_protobuf_guard.h" namespace mf = mir::frontend; namespace mfd = mir::frontend::detail; namespace ba = boost::asio; mf::ProtobufSessionCreator::ProtobufSessionCreator( std::shared_ptr const& ipc_factory, std::shared_ptr const& session_authorizer, std::shared_ptr const& report) : ipc_factory(ipc_factory), session_authorizer(session_authorizer), report(report), next_session_id(0), connected_sessions(std::make_shared>()) { } mf::ProtobufSessionCreator::~ProtobufSessionCreator() noexcept { connected_sessions->clear(); } int mf::ProtobufSessionCreator::next_id() { return next_session_id.fetch_add(1); } void mf::ProtobufSessionCreator::create_session_for(std::shared_ptr const& socket) { auto const messenger = std::make_shared(socket); auto const client_pid = messenger->client_pid(); if (session_authorizer->connection_is_allowed(client_pid)) { auto const message_sender = std::make_shared( messenger, ipc_factory->resource_cache()); auto const event_sink = std::make_shared(messenger); auto const msg_processor = create_processor( message_sender, ipc_factory->make_ipc_server(client_pid, event_sink), report); const auto& session = std::make_shared(messenger, next_id(), connected_sessions, msg_processor); connected_sessions->add(session); session->read_next_message(); } } std::shared_ptr mf::ProtobufSessionCreator::create_processor( std::shared_ptr const& sender, std::shared_ptr const& display_server, std::shared_ptr const& report) const { return std::make_shared( sender, display_server, report); } mir-0.1.8+14.04.20140411/src/server/frontend/event_sender.cpp0000644000015301777760000000531612322054247024010 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/frontend/client_constants.h" #include "mir/graphics/display_configuration.h" #include "event_sender.h" #include "message_sender.h" #include "protobuf_buffer_packer.h" #include "mir_protobuf_wire.pb.h" #include "mir_protobuf.pb.h" namespace mg = mir::graphics; namespace mfd = mir::frontend::detail; namespace mp = mir::protobuf; mfd::EventSender::EventSender(std::shared_ptr const& socket_sender) : sender(socket_sender) { } void mfd::EventSender::handle_event(MirEvent const& e) { // Limit the types of events we wish to send over protobuf, for now. if (e.type != mir_event_type_key && e.type != mir_event_type_motion) { // In future we might send multiple events, or insert them into messages // containing other responses, but for now we send them individually. mp::EventSequence seq; mp::Event *ev = seq.add_event(); ev->set_raw(&e, sizeof(MirEvent)); send_event_sequence(seq); } } void mfd::EventSender::handle_display_config_change( graphics::DisplayConfiguration const& display_config) { mp::EventSequence seq; auto protobuf_config = seq.mutable_display_configuration(); mfd::pack_protobuf_display_configuration(*protobuf_config, display_config); send_event_sequence(seq); } void mfd::EventSender::handle_lifecycle_event( MirLifecycleState state) { mp::EventSequence seq; auto protobuf_life_event = seq.mutable_lifecycle_event(); protobuf_life_event->set_new_state(state); send_event_sequence(seq); } void mfd::EventSender::send_event_sequence(mp::EventSequence& seq) { std::string send_buffer; send_buffer.reserve(serialization_buffer_size); seq.SerializeToString(&send_buffer); mir::protobuf::wire::Result result; result.add_events(send_buffer); result.SerializeToString(&send_buffer); try { sender->send(send_buffer.data(), send_buffer.length(), {}); } catch (std::exception const& error) { // TODO: We should report this state. (void) error; } } mir-0.1.8+14.04.20140411/src/server/frontend/protobuf_buffer_packer.cpp0000644000015301777760000001043412322054223026034 0ustar pbusernogroup00000000000000/* * 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 */ #include "protobuf_buffer_packer.h" #include "mir/graphics/display_configuration.h" #include "mir_protobuf.pb.h" namespace mfd = mir::frontend::detail; namespace mg = mir::graphics; namespace mp = mir::protobuf; namespace { void pack_protobuf_display_card(mp::DisplayCard& protobuf_card, mg::DisplayConfigurationCard const& display_card) { protobuf_card.set_card_id(display_card.id.as_value()); protobuf_card.set_max_simultaneous_outputs(display_card.max_simultaneous_outputs); } void pack_protobuf_display_output(mp::DisplayOutput& protobuf_output, mg::DisplayConfigurationOutput const& display_output) { protobuf_output.set_output_id(display_output.id.as_value()); protobuf_output.set_card_id(display_output.card_id.as_value()); protobuf_output.set_type(static_cast(display_output.type)); for (auto const& pf : display_output.pixel_formats) { protobuf_output.add_pixel_format(static_cast(pf)); } for (auto const& mode : display_output.modes) { auto protobuf_output_mode = protobuf_output.add_mode(); protobuf_output_mode->set_horizontal_resolution(mode.size.width.as_uint32_t()); protobuf_output_mode->set_vertical_resolution(mode.size.height.as_uint32_t()); protobuf_output_mode->set_refresh_rate(mode.vrefresh_hz); } protobuf_output.set_preferred_mode(display_output.preferred_mode_index); protobuf_output.set_physical_width_mm(display_output.physical_size_mm.width.as_uint32_t()); protobuf_output.set_physical_height_mm(display_output.physical_size_mm.height.as_uint32_t()); protobuf_output.set_connected(display_output.connected); protobuf_output.set_used(display_output.used); protobuf_output.set_position_x(display_output.top_left.x.as_uint32_t()); protobuf_output.set_position_y(display_output.top_left.y.as_uint32_t()); protobuf_output.set_current_mode(display_output.current_mode_index); protobuf_output.set_current_format(static_cast(display_output.current_format)); protobuf_output.set_power_mode(static_cast(display_output.power_mode)); protobuf_output.set_orientation(display_output.orientation); } } void mfd::pack_protobuf_display_configuration(mp::DisplayConfiguration& protobuf_config, mg::DisplayConfiguration const& display_config) { display_config.for_each_card( [&protobuf_config](mg::DisplayConfigurationCard const& card) { auto protobuf_card = protobuf_config.add_display_card(); pack_protobuf_display_card(*protobuf_card, card); }); display_config.for_each_output( [&protobuf_config](mg::DisplayConfigurationOutput const& output) { auto protobuf_output = protobuf_config.add_display_output(); pack_protobuf_display_output(*protobuf_output, output); }); } mfd::ProtobufBufferPacker::ProtobufBufferPacker(protobuf::Buffer* response) : buffer_response(response) { } void mfd::ProtobufBufferPacker::pack_fd(int fd) { buffer_response->add_fd(fd); } void mfd::ProtobufBufferPacker::pack_data(int data) { buffer_response->add_data(data); } void mfd::ProtobufBufferPacker::pack_stride(geometry::Stride stride) { buffer_response->set_stride(stride.as_uint32_t()); } void mfd::ProtobufBufferPacker::pack_flags(unsigned int flags) { buffer_response->set_flags(flags); } void mfd::ProtobufBufferPacker::pack_size(geometry::Size const& size) { buffer_response->set_width(size.width.as_int()); buffer_response->set_height(size.height.as_int()); } mir-0.1.8+14.04.20140411/src/server/frontend/resource_cache.cpp0000644000015301777760000000235412322054223024272 0ustar pbusernogroup00000000000000/* * 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 */ #include "resource_cache.h" void mir::frontend::ResourceCache::save_resource( google::protobuf::Message* key, std::shared_ptr const& value) { std::lock_guard lock(guard); resources[key] = value; } void mir::frontend::ResourceCache::free_resource(google::protobuf::Message* key) { std::shared_ptr value; { std::lock_guard lock(guard); auto const& p = resources.find(key); if (p != resources.end()) { value = p->second; } resources.erase(key); } } mir-0.1.8+14.04.20140411/src/server/frontend/unauthorized_display_changer.h0000644000015301777760000000255412322054247026732 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_UNAUTHORIZED_DISPLAY_CHANGER_H_ #define MIR_FRONTEND_UNAUTHORIZED_DISPLAY_CHANGER_H_ #include "mir/frontend/display_changer.h" namespace mir { namespace frontend { class UnauthorizedDisplayChanger : public frontend::DisplayChanger { public: explicit UnauthorizedDisplayChanger(std::shared_ptr const& changer); std::shared_ptr active_configuration(); void configure(std::shared_ptr const&, std::shared_ptr const&); private: std::shared_ptr const changer; }; } } #endif /* MIR_FRONTEND_UNAUTHORIZED_DISPLAY_CHANGER_H_ */ mir-0.1.8+14.04.20140411/src/server/frontend/published_socket_connector.cpp0000644000015301777760000001066212322054223026722 0ustar pbusernogroup00000000000000/* * 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 Guest */ #include "published_socket_connector.h" #include "mir/frontend/protobuf_session_creator.h" #include "mir/frontend/connector_report.h" #include #include #include #include namespace mf = mir::frontend; namespace mfd = mir::frontend::detail; namespace ba = boost::asio; mf::PublishedSocketConnector::PublishedSocketConnector( const std::string& socket_file, std::shared_ptr const& session_creator, int threads, std::shared_ptr const& report) : BasicConnector(session_creator, threads, report), socket_file(socket_file), acceptor(io_service, socket_file) { start_accept(); } mf::PublishedSocketConnector::~PublishedSocketConnector() noexcept { remove_endpoint(); } void mf::PublishedSocketConnector::start_accept() { report->listening_on(socket_file); auto socket = std::make_shared(io_service); acceptor.async_accept( *socket, boost::bind( &PublishedSocketConnector::on_new_connection, this, socket, ba::placeholders::error)); } void mf::PublishedSocketConnector::remove_endpoint() const { std::remove(socket_file.c_str()); } void mf::PublishedSocketConnector::on_new_connection( std::shared_ptr const& socket, boost::system::error_code const& ec) { if (!ec) { create_session_for(socket); } start_accept(); } mf::BasicConnector::BasicConnector( std::shared_ptr const& session_creator, int threads, std::shared_ptr const& report) : work(io_service), report(report), io_service_threads(threads), session_creator{session_creator} { } void mf::BasicConnector::start() { auto run_io_service = [this] { while (true) try { report->thread_start(); io_service.run(); report->thread_end(); return; } catch (std::exception const& e) { report->error(e); } }; report->starting_threads(io_service_threads.size()); for (auto& thread : io_service_threads) { thread = std::thread(run_io_service); } } void mf::BasicConnector::stop() { /* Stop processing new requests */ io_service.stop(); report->stopping_threads(io_service_threads.size()); /* Wait for all io processing threads to finish */ for (auto& thread : io_service_threads) { if (thread.joinable()) { thread.join(); } } /* Prepare for a potential restart */ io_service.reset(); } void mf::BasicConnector::create_session_for(std::shared_ptr const& server_socket) const { report->creating_session_for(server_socket->native_handle()); session_creator->create_session_for(server_socket); } int mf::BasicConnector::client_socket_fd() const { enum { server, client, size }; int socket_fd[size]; if (socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fd)) { BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Could not create socket pair")) << boost::errinfo_errno(errno)); } auto const server_socket = std::make_shared( io_service, boost::asio::local::stream_protocol(), socket_fd[server]); report->creating_socket_pair(socket_fd[server], socket_fd[client]); create_session_for(server_socket); return socket_fd[client]; } void mf::BasicConnector::remove_endpoint() const { } mf::BasicConnector::~BasicConnector() noexcept { stop(); } mir-0.1.8+14.04.20140411/src/server/frontend/unauthorized_screencast.h0000644000015301777760000000245412322054247025727 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_UNAUTHORIZED_SCREENCAST_H_ #define MIR_FRONTEND_UNAUTHORIZED_SCREENCAST_H_ #include "mir/frontend/screencast.h" namespace mir { namespace frontend { class UnauthorizedScreencast : public Screencast { public: ScreencastSessionId create_session( geometry::Rectangle const& region, geometry::Size const& size, MirPixelFormat pixel_format) override; void destroy_session(frontend::ScreencastSessionId id) override; std::shared_ptr capture(frontend::ScreencastSessionId id) override; }; } } #endif /* MIR_FRONTEND_UNAUTHORIZED_SCREENCAST_H_ */ mir-0.1.8+14.04.20140411/src/server/frontend/socket_messenger.cpp0000644000015301777760000001060112322054247024660 0ustar pbusernogroup00000000000000/* * 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 */ #include "socket_messenger.h" #include "mir/frontend/client_constants.h" #include #include #include namespace mf = mir::frontend; namespace mfd = mf::detail; namespace bs = boost::system; namespace ba = boost::asio; mfd::SocketMessenger::SocketMessenger(std::shared_ptr const& socket) : socket(socket) { whole_message.reserve(serialization_buffer_size); } pid_t mfd::SocketMessenger::client_pid() { struct ucred cr; socklen_t cl = sizeof(cr); auto status = getsockopt(socket->native_handle(), SOL_SOCKET, SO_PEERCRED, &cr, &cl); if (status) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to query client socket credentials")); return cr.pid; } void mfd::SocketMessenger::send(char const* data, size_t length, FdSets const& fd_set) { const unsigned char header_bytes[2] = { static_cast((length >> 8) & 0xff), static_cast((length >> 0) & 0xff) }; std::unique_lock lg(message_lock); whole_message.resize(sizeof header_bytes + length); std::copy(header_bytes, header_bytes + sizeof header_bytes, whole_message.begin()); std::copy(data, data + length, whole_message.begin() + sizeof header_bytes); // TODO: This should be asynchronous, but we are not making sure // that a potential call to send_fds is executed _after_ this // function has completed (if it would be executed asynchronously. // NOTE: we rely on this synchronous behavior as per the comment in // mf::SessionMediator::create_surface ba::write(*socket, ba::buffer(whole_message)); for (auto const& fds : fd_set) send_fds_locked(lg, fds); } void mfd::SocketMessenger::send_fds_locked(std::unique_lock const&, std::vector const& fds) { auto n_fds = fds.size(); if (n_fds > 0) { // We send dummy data struct iovec iov; char dummy_iov_data = 'M'; iov.iov_base = &dummy_iov_data; iov.iov_len = 1; // Allocate space for control message std::vector control(sizeof(struct cmsghdr) + sizeof(int) * n_fds); // Message to send struct msghdr header; header.msg_name = NULL; header.msg_namelen = 0; header.msg_iov = &iov; header.msg_iovlen = 1; header.msg_controllen = control.size(); header.msg_control = control.data(); header.msg_flags = 0; // Control message contains file descriptors struct cmsghdr *message = CMSG_FIRSTHDR(&header); message->cmsg_len = header.msg_controllen; message->cmsg_level = SOL_SOCKET; message->cmsg_type = SCM_RIGHTS; int *data = (int *)CMSG_DATA(message); int i = 0; for (auto &fd: fds) data[i++] = fd; auto sent = sendmsg(socket->native_handle(), &header, 0); if (sent < 0) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to send fds: " + std::string(strerror(errno)))); } } void mfd::SocketMessenger::async_receive_msg( MirReadHandler const& handler, ba::mutable_buffers_1 const& buffer) { boost::asio::async_read( *socket, buffer, boost::asio::transfer_exactly(ba::buffer_size(buffer)), handler); } bs::error_code mfd::SocketMessenger::receive_msg( ba::mutable_buffers_1 const& buffer) { bs::error_code e; boost::asio::read( *socket, buffer, boost::asio::transfer_exactly(ba::buffer_size(buffer)), e); return e; } size_t mfd::SocketMessenger::available_bytes() { boost::asio::socket_base::bytes_readable command{true}; socket->io_control(command); return command.get(); } mir-0.1.8+14.04.20140411/src/server/frontend/surface.cpp0000644000015301777760000000430112322054223022742 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/frontend/surface.h" #include "mir/graphics/internal_surface.h" #include "mir/graphics/buffer.h" #include "mir/graphics/buffer_id.h" #include "mir/frontend/client_constants.h" #include "client_buffer_tracker.h" #include #include #include namespace mg = mir::graphics; namespace mf = mir::frontend; auto mf::as_internal_surface(std::shared_ptr const& surface) -> std::shared_ptr { class ForwardingInternalSurface : public mg::InternalSurface { public: ForwardingInternalSurface(std::shared_ptr const& surface) : surface(surface) {} private: void swap_buffers(graphics::Buffer*& buffer) { surface->swap_buffers_blocking(buffer); } virtual mir::geometry::Size size() const { return surface->size(); } virtual MirPixelFormat pixel_format() const { return surface->pixel_format(); } std::shared_ptr const surface; }; return std::make_shared(surface); } void mf::Surface::swap_buffers_blocking(graphics::Buffer*& buffer) { std::mutex mutex; std::condition_variable cv; bool done = false; swap_buffers(buffer, [&](mg::Buffer* new_buffer) { std::unique_lock lock(mutex); buffer = new_buffer; done = true; cv.notify_one(); }); std::unique_lock lock(mutex); cv.wait(lock, [&]{ return done; }); } mir-0.1.8+14.04.20140411/src/server/frontend/session_mediator.h0000644000015301777760000001363312322054223024336 0ustar pbusernogroup00000000000000/* * 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_H_ #define MIR_FRONTEND_SESSION_MEDIATOR_H_ #include "mir_protobuf.pb.h" #include "mir/frontend/surface_id.h" #include "mir_toolkit/common.h" #include #include #include #include #include namespace mir { namespace graphics { class Buffer; class Platform; class Display; class GraphicBufferAllocator; } /// Frontend interface. Mediates the interaction between client /// processes and the core of the mir system. namespace frontend { class ClientBufferTracker; class Shell; class Session; class Surface; class ResourceCache; class SessionMediatorReport; class EventSink; class DisplayChanger; class Screencast; // SessionMediator relays requests from the client process into the server. class SessionMediator : public mir::protobuf::DisplayServer { public: SessionMediator( pid_t client_pid, std::shared_ptr const& shell, std::shared_ptr const& graphics_platform, std::shared_ptr const& display_changer, std::vector const& surface_pixel_formats, std::shared_ptr const& report, std::shared_ptr const& event_sink, std::shared_ptr const& resource_cache, std::shared_ptr const& screencast); ~SessionMediator() noexcept; /* Platform independent requests */ void connect(::google::protobuf::RpcController* controller, const ::mir::protobuf::ConnectParameters* request, ::mir::protobuf::Connection* response, ::google::protobuf::Closure* done) override; void create_surface(google::protobuf::RpcController* controller, const mir::protobuf::SurfaceParameters* request, mir::protobuf::Surface* response, google::protobuf::Closure* done) override; void next_buffer( google::protobuf::RpcController* controller, mir::protobuf::SurfaceId const* request, mir::protobuf::Buffer* response, google::protobuf::Closure* done) override; void release_surface(google::protobuf::RpcController* controller, const mir::protobuf::SurfaceId*, mir::protobuf::Void*, google::protobuf::Closure* done) override; void disconnect(google::protobuf::RpcController* controller, const mir::protobuf::Void* request, mir::protobuf::Void* response, google::protobuf::Closure* done) override; void configure_surface(google::protobuf::RpcController* controller, const mir::protobuf::SurfaceSetting*, mir::protobuf::SurfaceSetting*, google::protobuf::Closure* done) override; void configure_display(::google::protobuf::RpcController* controller, const ::mir::protobuf::DisplayConfiguration* request, ::mir::protobuf::DisplayConfiguration* response, ::google::protobuf::Closure* done) override; void create_screencast(google::protobuf::RpcController*, const mir::protobuf::ScreencastParameters*, mir::protobuf::Screencast*, google::protobuf::Closure* done); void release_screencast(google::protobuf::RpcController*, const mir::protobuf::ScreencastId*, mir::protobuf::Void*, google::protobuf::Closure* done); void screencast_buffer(google::protobuf::RpcController*, const mir::protobuf::ScreencastId*, mir::protobuf::Buffer*, google::protobuf::Closure* done); /* Platform specific requests */ void drm_auth_magic(google::protobuf::RpcController* controller, const mir::protobuf::DRMMagic* request, mir::protobuf::DRMAuthMagicStatus* response, google::protobuf::Closure* done) override; private: void pack_protobuf_buffer(protobuf::Buffer& protobuf_buffer, graphics::Buffer* graphics_buffer, bool need_full_ipc); void advance_buffer(SurfaceId surf_id, Surface& surface, std::function complete); pid_t client_pid; std::shared_ptr const shell; std::shared_ptr const graphics_platform; std::vector const surface_pixel_formats; std::shared_ptr const display_changer; std::shared_ptr const report; std::shared_ptr const event_sink; std::shared_ptr const resource_cache; std::shared_ptr const screencast; std::unordered_map client_buffer_resource; std::unordered_map> client_buffer_tracker; std::mutex session_mutex; std::weak_ptr weak_session; }; } } #endif /* MIR_FRONTEND_SESSION_MEDIATOR_H_ */ mir-0.1.8+14.04.20140411/src/server/frontend/event_sender.h0000644000015301777760000000264212322054223023446 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_EVENT_SENDER_H_ #define MIR_FRONTEND_EVENT_SENDER_H_ #include "mir/frontend/event_sink.h" #include namespace mir { namespace protobuf { class EventSequence; } namespace frontend { namespace detail { class MessageSender; class EventSender : public mir::frontend::EventSink { public: explicit EventSender(std::shared_ptr const& socket_sender); void handle_event(MirEvent const& e); void handle_lifecycle_event(MirLifecycleState state); void handle_display_config_change(graphics::DisplayConfiguration const& config); private: void send_event_sequence(protobuf::EventSequence&); std::shared_ptr const sender; }; } } } #endif /* MIR_FRONTEND_EVENT_SENDER_H_ */ mir-0.1.8+14.04.20140411/src/server/frontend/unauthorized_display_changer.cpp0000644000015301777760000000252212322054247027260 0ustar pbusernogroup00000000000000/* * 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 */ #include "unauthorized_display_changer.h" #include namespace mf = mir::frontend; namespace mg = mir::graphics; mf::UnauthorizedDisplayChanger::UnauthorizedDisplayChanger(std::shared_ptr const& changer) : changer(changer) { } std::shared_ptr mf::UnauthorizedDisplayChanger::active_configuration() { return changer->active_configuration(); } void mf::UnauthorizedDisplayChanger::configure( std::shared_ptr const&, std::shared_ptr const&) { BOOST_THROW_EXCEPTION(std::runtime_error("not authorized to apply display configurations")); } mir-0.1.8+14.04.20140411/src/server/frontend/protobuf_message_processor.cpp0000644000015301777760000002002612322054223026757 0ustar pbusernogroup00000000000000/* * 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 */ #include "protobuf_message_processor.h" #include "mir/frontend/message_processor_report.h" #include "mir/frontend/protobuf_message_sender.h" #include "mir/frontend/template_protobuf_message_processor.h" #include "mir_protobuf_wire.pb.h" namespace mfd = mir::frontend::detail; namespace { template std::vector extract_fds_from(Response* response) { std::vector fd(response->fd().data(), response->fd().data() + response->fd().size()); response->clear_fd(); response->set_fds_on_side_channel(fd.size()); return fd; } } mfd::ProtobufMessageProcessor::ProtobufMessageProcessor( std::shared_ptr const& sender, std::shared_ptr const& display_server, std::shared_ptr const& report) : sender(sender), display_server(display_server), report(report) { } namespace mir { namespace frontend { namespace detail { template<> struct result_ptr_t<::mir::protobuf::Buffer> { typedef ::mir::protobuf::Buffer* type; }; template<> struct result_ptr_t<::mir::protobuf::Connection> { typedef ::mir::protobuf::Connection* type; }; template<> struct result_ptr_t<::mir::protobuf::Surface> { typedef ::mir::protobuf::Surface* type; }; template<> struct result_ptr_t<::mir::protobuf::Screencast> { typedef ::mir::protobuf::Screencast* type; }; template<> void invoke( ProtobufMessageProcessor* self, protobuf::DisplayServer* server, void (protobuf::DisplayServer::*function)( ::google::protobuf::RpcController* controller, const protobuf::SurfaceId* request, protobuf::Buffer* response, ::google::protobuf::Closure* done), Invocation const& invocation) { protobuf::SurfaceId parameter_message; parameter_message.ParseFromString(invocation.parameters()); auto const result_message = std::make_shared(); auto const callback = google::protobuf::NewCallback< ProtobufMessageProcessor, ::google::protobuf::uint32, std::shared_ptr>( self, &ProtobufMessageProcessor::send_response, invocation.id(), result_message); try { (server->*function)( 0, ¶meter_message, result_message.get(), callback); } catch (std::exception const& x) { delete callback; result_message->set_error(boost::diagnostic_information(x)); self->send_response(invocation.id(), result_message); } } } } } const std::string& mfd::Invocation::method_name() const { return invocation.method_name(); } const std::string& mfd::Invocation::parameters() const { return invocation.parameters(); } google::protobuf::uint32 mfd::Invocation::id() const { return invocation.id(); } bool mfd::ProtobufMessageProcessor::dispatch(Invocation const& invocation) { report->received_invocation(display_server.get(), invocation.id(), invocation.method_name()); bool result = true; try { // TODO comparing strings in an if-else chain isn't efficient. // It is probably possible to generate a Trie at compile time. if ("connect" == invocation.method_name()) { invoke(this, display_server.get(), &protobuf::DisplayServer::connect, invocation); } else if ("create_surface" == invocation.method_name()) { invoke(this, display_server.get(), &protobuf::DisplayServer::create_surface, invocation); } else if ("next_buffer" == invocation.method_name()) { invoke(this, display_server.get(), &protobuf::DisplayServer::next_buffer, invocation); } else if ("release_surface" == invocation.method_name()) { invoke(this, display_server.get(), &protobuf::DisplayServer::release_surface, invocation); } else if ("test_file_descriptors" == invocation.method_name()) { invoke(this, display_server.get(), &protobuf::DisplayServer::test_file_descriptors, invocation); } else if ("drm_auth_magic" == invocation.method_name()) { invoke(this, display_server.get(), &protobuf::DisplayServer::drm_auth_magic, invocation); } else if ("configure_display" == invocation.method_name()) { invoke(this, display_server.get(), &protobuf::DisplayServer::configure_display, invocation); } else if ("configure_surface" == invocation.method_name()) { invoke(this, display_server.get(), &protobuf::DisplayServer::configure_surface, invocation); } else if ("create_screencast" == invocation.method_name()) { invoke(this, display_server.get(), &protobuf::DisplayServer::create_screencast, invocation); } else if ("screencast_buffer" == invocation.method_name()) { invoke(this, display_server.get(), &protobuf::DisplayServer::screencast_buffer, invocation); } else if ("release_screencast" == invocation.method_name()) { invoke(this, display_server.get(), &protobuf::DisplayServer::release_screencast, invocation); } else if ("disconnect" == invocation.method_name()) { invoke(this, display_server.get(), &protobuf::DisplayServer::disconnect, invocation); result = false; } else { report->unknown_method(display_server.get(), invocation.id(), invocation.method_name()); result = false; } } catch (std::exception const& error) { report->exception_handled(display_server.get(), invocation.id(), error); result = false; } report->completed_invocation(display_server.get(), invocation.id(), result); return result; } void mfd::ProtobufMessageProcessor::send_response(::google::protobuf::uint32 id, ::google::protobuf::Message* response) { sender->send_response(id, response, {}); } void mfd::ProtobufMessageProcessor::send_response(::google::protobuf::uint32 id, mir::protobuf::Buffer* response) { const auto& fd = extract_fds_from(response); sender->send_response(id, response, {fd}); } void mfd::ProtobufMessageProcessor::send_response(::google::protobuf::uint32 id, std::shared_ptr response) { send_response(id, response.get()); } void mfd::ProtobufMessageProcessor::send_response(::google::protobuf::uint32 id, mir::protobuf::Connection* response) { const auto& fd = response->has_platform() ? extract_fds_from(response->mutable_platform()) : std::vector(); sender->send_response(id, response, {fd}); } void mfd::ProtobufMessageProcessor::send_response(::google::protobuf::uint32 id, mir::protobuf::Surface* response) { auto const& surface_fd = extract_fds_from(response); const auto& buffer_fd = response->has_buffer() ? extract_fds_from(response->mutable_buffer()) : std::vector(); sender->send_response(id, response, {surface_fd, buffer_fd}); } void mfd::ProtobufMessageProcessor::send_response( ::google::protobuf::uint32 id, mir::protobuf::Screencast* response) { auto const& buffer_fd = response->has_buffer() ? extract_fds_from(response->mutable_buffer()) : std::vector(); sender->send_response(id, response, {buffer_fd}); } mir-0.1.8+14.04.20140411/src/server/frontend/resource_cache.h0000644000015301777760000000246012322054223023735 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_RESOURCE_CACHE_H_ #define MIR_FRONTEND_RESOURCE_CACHE_H_ #include "mir_protobuf.pb.h" #include #include #include namespace mir { namespace frontend { // Used to save resources that must be retained until a call completes. class ResourceCache { public: void save_resource(google::protobuf::Message* key, std::shared_ptr const& value); void free_resource(google::protobuf::Message* key); private: typedef std::map> Resources; std::mutex guard; Resources resources; }; } } #endif /* MIR_FRONTEND_RESOURCE_CACHE_H_ */ mir-0.1.8+14.04.20140411/src/server/frontend/unauthorized_screencast.cpp0000644000015301777760000000273012322054247026257 0ustar pbusernogroup00000000000000/* * 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 */ #include "unauthorized_screencast.h" #include #include namespace mf = mir::frontend; mf::ScreencastSessionId mf::UnauthorizedScreencast::create_session( geometry::Rectangle const&, geometry::Size const&, MirPixelFormat) { BOOST_THROW_EXCEPTION( std::runtime_error("Process is not authorized to capture screencasts")); } void mf::UnauthorizedScreencast::destroy_session(mf::ScreencastSessionId) { BOOST_THROW_EXCEPTION( std::runtime_error("Process is not authorized to capture screencasts")); } std::shared_ptr mf::UnauthorizedScreencast::capture( mf::ScreencastSessionId) { BOOST_THROW_EXCEPTION( std::runtime_error("Process is not authorized to capture screencasts")); } mir-0.1.8+14.04.20140411/src/server/frontend/protobuf_responder.h0000644000015301777760000000311512322054247024710 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_PROTOBUF_RESPONDER_H_ #define MIR_FRONTEND_PROTOBUF_RESPONDER_H_ #include "mir/frontend/protobuf_message_sender.h" #include "mir_protobuf_wire.pb.h" #include namespace mir { namespace frontend { class ResourceCache; namespace detail { class MessageSender; class ProtobufResponder : public ProtobufMessageSender { public: ProtobufResponder( std::shared_ptr const& sender, std::shared_ptr const& resource_cache); void send_response( ::google::protobuf::uint32 id, ::google::protobuf::Message* response, FdSets const& fd_sets) override; private: std::shared_ptr const sender; std::shared_ptr const resource_cache; std::vector send_response_buffer; mir::protobuf::wire::Result send_response_result; }; } } } #endif /* PROTOBUF_MESSAGE_PROCESSOR_H_ */ mir-0.1.8+14.04.20140411/src/server/frontend/protobuf_buffer_packer.h0000644000015301777760000000302112322054223025473 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_PROTOBUF_BUFFER_PACKER_H_ #define MIR_FRONTEND_PROTOBUF_BUFFER_PACKER_H_ #include "mir/graphics/buffer_ipc_packer.h" #include "mir_protobuf.pb.h" namespace mir { namespace graphics { class DisplayConfiguration; } namespace frontend { namespace detail { void pack_protobuf_display_configuration(protobuf::DisplayConfiguration& protobuf_config, graphics::DisplayConfiguration const& display_config); class ProtobufBufferPacker : public graphics::BufferIPCPacker { public: ProtobufBufferPacker(protobuf::Buffer*); void pack_fd(int); void pack_data(int); void pack_stride(geometry::Stride); void pack_flags(unsigned int); void pack_size(geometry::Size const& size); private: protobuf::Buffer* buffer_response; }; } } } #endif /* MIR_FRONTEND_PROTOBUF_BUFFER_PACKER_H_ */ mir-0.1.8+14.04.20140411/src/server/frontend/client_buffer_tracker.cpp0000644000015301777760000000272312322054223025642 0ustar pbusernogroup00000000000000/* * 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: Christopher James Halse Rogers */ #include #include "client_buffer_tracker.h" #include "mir/graphics/buffer_id.h" namespace mf = mir::frontend; namespace mg = mir::graphics; mf::ClientBufferTracker::ClientBufferTracker(unsigned int client_cache_size) : ids(), cache_size{client_cache_size} { } void mf::ClientBufferTracker::add(mg::BufferID const& id) { auto existing_id = std::find(ids.begin(), ids.end(), id); if (existing_id != ids.end()) { ids.push_front(*existing_id); ids.erase(existing_id); } else { ids.push_front(id); } if (ids.size() > cache_size) ids.pop_back(); } bool mf::ClientBufferTracker::client_has(mg::BufferID const& id) const { return std::find(ids.begin(), ids.end(), id) != ids.end(); } mir-0.1.8+14.04.20140411/src/server/frontend/CMakeLists.txt0000644000015301777760000000131312322054247023354 0ustar pbusernogroup00000000000000set( FRONTEND_SOURCES client_buffer_tracker.cpp session_mediator.cpp protobuf_message_processor.cpp protobuf_responder.cpp protobuf_buffer_packer.cpp published_socket_connector.cpp protobuf_session_creator.cpp socket_session.cpp resource_cache.cpp socket_messenger.cpp event_sender.cpp surface.cpp unauthorized_display_changer.cpp unauthorized_screencast.cpp default_configuration.cpp ${PROTO_HDRS} ) add_library( mirfrontend STATIC ${FRONTEND_SOURCES} ) # Fix build race condition - ensure the protobuf header is built before us. add_dependencies(mirfrontend mirprotobuf) target_link_libraries( mirfrontend mirshell mirlogging 3rd_party ${Boost_LIBRARIES} ) mir-0.1.8+14.04.20140411/src/server/frontend/socket_messenger.h0000644000015301777760000000332212322054247024327 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_SOCKET_MESSENGER_H_ #define MIR_FRONTEND_SOCKET_MESSENGER_H_ #include "message_sender.h" #include "message_receiver.h" #include namespace mir { namespace frontend { namespace detail { class SocketMessenger : public MessageSender, public MessageReceiver { public: SocketMessenger(std::shared_ptr const& socket); void send(char const* data, size_t length, FdSets const& fds) override; void async_receive_msg(MirReadHandler const& handler, boost::asio::mutable_buffers_1 const& buffer); boost::system::error_code receive_msg(boost::asio::mutable_buffers_1 const& buffer); size_t available_bytes() override; pid_t client_pid(); private: std::shared_ptr socket; std::mutex message_lock; std::vector whole_message; void send_fds_locked(std::unique_lock const& lock, std::vector const& fds); }; } } } #endif /* MIR_FRONTEND_SOCKET_MESSENGER_H_ */ mir-0.1.8+14.04.20140411/src/server/frontend/protobuf_ipc_factory.h0000644000015301777760000000272112322054247025213 0ustar pbusernogroup00000000000000/* * 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_PROTOBUF_IPC_FACTORY_H_ #define MIR_FRONTEND_PROTOBUF_IPC_FACTORY_H_ #include #include namespace mir { namespace protobuf { class DisplayServer; } namespace frontend { class EventSink; class ResourceCache; class MessageProcessorReport; class ProtobufIpcFactory { public: virtual std::shared_ptr make_ipc_server( pid_t client_pid, std::shared_ptr const& sink) = 0; virtual std::shared_ptr resource_cache() = 0; protected: ProtobufIpcFactory() {} virtual ~ProtobufIpcFactory() {} ProtobufIpcFactory(ProtobufIpcFactory const&) = delete; ProtobufIpcFactory& operator =(ProtobufIpcFactory const&) = delete; }; } } #endif // MIR_FRONTEND_PROTOBUF_IPC_FACTORY_H_ mir-0.1.8+14.04.20140411/src/server/frontend/socket_session.cpp0000644000015301777760000000654612322054247024370 0ustar pbusernogroup00000000000000/* * 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 */ #include "socket_session.h" #include "message_sender.h" #include "message_receiver.h" #include "mir/frontend/message_processor.h" #include "mir_protobuf_wire.pb.h" #include #include #include #include #include namespace ba = boost::asio; namespace bs = boost::system; namespace mfd = mir::frontend::detail; mfd::SocketSession::SocketSession( std::shared_ptr const& receiver, int id_, std::shared_ptr> const& connected_sessions, std::shared_ptr const& processor) : socket_receiver(receiver), id_(id_), connected_sessions(connected_sessions), processor(processor) { } mfd::SocketSession::~SocketSession() noexcept { } void mfd::SocketSession::read_next_message() { auto callback = std::bind(&mfd::SocketSession::on_read_size, this, std::placeholders::_1); socket_receiver->async_receive_msg(callback, ba::buffer(header, header_size)); } void mfd::SocketSession::on_read_size(const boost::system::error_code& error) { if (error) { connected_sessions->remove(id()); BOOST_THROW_EXCEPTION(std::runtime_error(error.message())); } unsigned char const high_byte = header[0]; unsigned char const low_byte = header[1]; size_t const body_size = (high_byte << 8) + low_byte; body.resize(body_size); if (socket_receiver->available_bytes() >= body_size) { on_new_message(socket_receiver->receive_msg(ba::buffer(body))); } else { auto callback = std::bind(&mfd::SocketSession::on_new_message, this, std::placeholders::_1); socket_receiver->async_receive_msg(callback, ba::buffer(body)); } } void mfd::SocketSession::on_new_message(const boost::system::error_code& error) try { if (error) { BOOST_THROW_EXCEPTION(std::runtime_error(error.message())); } mir::protobuf::wire::Invocation invocation; invocation.ParseFromArray(body.data(), body.size()); if (!invocation.has_protocol_version() || invocation.protocol_version() != 1) BOOST_THROW_EXCEPTION(std::runtime_error("Unsupported protocol version")); if (processor->dispatch(invocation)) { read_next_message(); } else { connected_sessions->remove(id()); } } catch (...) { connected_sessions->remove(id()); throw; } void mfd::SocketSession::on_response_sent(bs::error_code const& error, std::size_t) { if (error) { connected_sessions->remove(id()); BOOST_THROW_EXCEPTION(std::runtime_error(error.message())); } } mir-0.1.8+14.04.20140411/src/server/frontend/protobuf_responder.cpp0000644000015301777760000000333712322054247025251 0ustar pbusernogroup00000000000000/* * 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 */ #include "protobuf_responder.h" #include "resource_cache.h" #include "message_sender.h" #include "mir/frontend/client_constants.h" #include "socket_messenger.h" namespace mfd = mir::frontend::detail; mfd::ProtobufResponder::ProtobufResponder( std::shared_ptr const& sender, std::shared_ptr const& resource_cache) : sender(sender), resource_cache(resource_cache), send_response_buffer(serialization_buffer_size) { } void mfd::ProtobufResponder::send_response( ::google::protobuf::uint32 id, google::protobuf::Message* response, FdSets const& fd_sets) { response->SerializeToArray(send_response_buffer.data(), send_response_buffer.size()); send_response_result.set_id(id); send_response_result.set_response(send_response_buffer.data(), response->ByteSize()); send_response_result.SerializeToArray(send_response_buffer.data(), send_response_buffer.size()); sender->send(send_response_buffer.data(), send_response_result.ByteSize(), fd_sets); resource_cache->free_resource(response); } mir-0.1.8+14.04.20140411/src/server/logging/0000755000015301777760000000000012322054703020422 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/logging/default_configuration.cpp0000644000015301777760000000311312322054223025474 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/logging/logger.h" #include "mir/logging/glog_logger.h" #include "mir/default_server_configuration.h" #include "mir/options/default_configuration.h" #include "mir/logging/dumb_console_logger.h" namespace ml = mir::logging; auto mir::DefaultServerConfiguration::the_logger() -> std::shared_ptr { return logger( [this]() -> std::shared_ptr { if (the_options()->is_set(options::glog)) { return std::make_shared( "mir", the_options()->get(options::glog_stderrthreshold), the_options()->get(options::glog_minloglevel), the_options()->get(options::glog_log_dir)); } else { return std::make_shared(); } }); } mir-0.1.8+14.04.20140411/src/server/logging/glog_logger.cpp0000644000015301777760000000434112322054223023414 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/logging/glog_logger.h" #include #include #include #include namespace { std::once_flag init_flag; std::once_flag shutdown_flag; std::once_flag shutdown_flag_gflags; struct google_glog_guard_t { google_glog_guard_t(const char* argv0) { std::call_once(init_flag, google::InitGoogleLogging, argv0); } ~google_glog_guard_t() { std::call_once(shutdown_flag, google::ShutdownGoogleLogging); } }; struct google_gflag_guard_t { ~google_gflag_guard_t() { std::call_once(shutdown_flag_gflags, google::ShutDownCommandLineFlags); } } google_gflag_guard; } mir::logging::GlogLogger::GlogLogger( const char* argv0, int stderrthreshold, int minloglevel, std::string const& log_dir) { FLAGS_stderrthreshold = stderrthreshold; FLAGS_minloglevel = minloglevel; FLAGS_log_dir = log_dir; static google_glog_guard_t guard(argv0); } void mir::logging::GlogLogger::log(Severity severity, const std::string& message, const std::string& component) { static int glog_level[] = { google::GLOG_FATAL, // critical = 0, google::GLOG_ERROR, // error = 1, google::GLOG_WARNING, // warning = 2, google::GLOG_INFO, // informational = 3, google::GLOG_INFO, // debug = 4 }; // Since we're not collecting __FILE__ or __LINE__ this is misleading google::LogMessage(__FILE__, __LINE__, glog_level[severity]).stream() << '[' << component << "] " << message; } mir-0.1.8+14.04.20140411/src/server/logging/CMakeLists.txt0000644000015301777760000000051712322054223023162 0ustar pbusernogroup00000000000000include_directories(${MIR_3RD_PARTY_INCLUDE_DIRECTORIES}) include_directories(${MIR_ANDROID_INCLUDE_DIRECTORIES}) set( LOGGING_SOURCES default_configuration.cpp glog_logger.cpp ) add_library( mirlogger STATIC ${LOGGING_SOURCES} ) target_link_libraries( mirlogger mirplatform ${GLog_LIBRARY} ${GFlags_LIBRARY} ) mir-0.1.8+14.04.20140411/src/server/asio_main_loop.cpp0000644000015301777760000001021012322054223022457 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/asio_main_loop.h" #include class mir::AsioMainLoop::SignalHandler { public: SignalHandler(boost::asio::io_service& io, std::initializer_list signals, std::function const& handler) : signal_set{io}, handler{handler} { for (auto sig : signals) signal_set.add(sig); } void async_wait() { signal_set.async_wait( std::bind(&SignalHandler::handle, this, std::placeholders::_1, std::placeholders::_2)); } private: void handle(boost::system::error_code err, int sig) { if (!err) { handler(sig); signal_set.async_wait( std::bind(&SignalHandler::handle, this, std::placeholders::_1, std::placeholders::_2)); } } boost::asio::signal_set signal_set; std::function handler; }; class mir::AsioMainLoop::FDHandler { public: FDHandler(boost::asio::io_service& io, std::initializer_list fds, std::function const& handler) : handler{handler} { for (auto fd : fds) { auto raw = new boost::asio::posix::stream_descriptor{io, fd}; auto s = std::unique_ptr(raw); stream_descriptors.push_back(std::move(s)); } } void async_wait() { for (auto const& s : stream_descriptors) { s->async_read_some( boost::asio::null_buffers(), std::bind(&FDHandler::handle, this, std::placeholders::_1, std::placeholders::_2, s.get())); } } private: void handle(boost::system::error_code err, size_t /*bytes*/, boost::asio::posix::stream_descriptor* s) { if (!err) { handler(s->native_handle()); s->async_read_some( boost::asio::null_buffers(), std::bind(&FDHandler::handle, this, std::placeholders::_1, std::placeholders::_2, s)); } } std::vector> stream_descriptors; std::function handler; }; /* * We need to define an empty constructor and destructor in the .cpp file, * so that we can use unique_ptr to hold SignalHandler. Otherwise, users * of AsioMainLoop end up creating default constructors and destructors * that don't have complete type information for SignalHandler and fail * to compile. */ mir::AsioMainLoop::AsioMainLoop() { } mir::AsioMainLoop::~AsioMainLoop() noexcept(true) { } void mir::AsioMainLoop::run() { io.run(); } void mir::AsioMainLoop::stop() { io.stop(); } void mir::AsioMainLoop::register_signal_handler( std::initializer_list signals, std::function const& handler) { assert(handler); auto sig_handler = std::unique_ptr{ new SignalHandler{io, signals, handler}}; sig_handler->async_wait(); signal_handlers.push_back(std::move(sig_handler)); } void mir::AsioMainLoop::register_fd_handler( std::initializer_list fds, std::function const& handler) { assert(handler); auto fd_handler = std::unique_ptr{ new FDHandler{io, fds, handler}}; fd_handler->async_wait(); fd_handlers.push_back(std::move(fd_handler)); } mir-0.1.8+14.04.20140411/src/server/display_server.cpp0000644000015301777760000001414012322054223022530 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/display_server.h" #include "mir/server_configuration.h" #include "mir/main_loop.h" #include "mir/server_status_listener.h" #include "mir/display_changer.h" #include "mir/compositor/compositor.h" #include "mir/frontend/connector.h" #include "mir/graphics/display.h" #include "mir/graphics/display_configuration.h" #include "mir/input/input_manager.h" #include namespace mc = mir::compositor; namespace mf = mir::frontend; namespace mg = mir::graphics; namespace mi = mir::input; namespace msh = mir::shell; namespace { class TryButRevertIfUnwinding { public: TryButRevertIfUnwinding(std::function const& apply, std::function const& revert) : revert{revert} { apply(); } ~TryButRevertIfUnwinding() { if (std::uncaught_exception()) revert(); } private: TryButRevertIfUnwinding(TryButRevertIfUnwinding const&) = delete; TryButRevertIfUnwinding& operator=(TryButRevertIfUnwinding const&) = delete; std::function const revert; }; } struct mir::DisplayServer::Private { Private(ServerConfiguration& config) : graphics_platform{config.the_graphics_platform()}, display{config.the_display()}, input_configuration{config.the_input_configuration()}, compositor{config.the_compositor()}, connector{config.the_connector()}, input_manager{config.the_input_manager()}, main_loop{config.the_main_loop()}, server_status_listener{config.the_server_status_listener()}, display_changer{config.the_display_changer()}, paused{false}, configure_display_on_resume{false} { display->register_configuration_change_handler( *main_loop, [this] { return configure_display(); }); display->register_pause_resume_handlers( *main_loop, [this] { return pause(); }, [this] { return resume(); }); } bool pause() { try { TryButRevertIfUnwinding input{ [this] { input_manager->stop(); }, [this] { input_manager->start(); }}; TryButRevertIfUnwinding comp{ [this] { compositor->stop(); }, [this] { compositor->start(); }}; TryButRevertIfUnwinding comm{ [this] { connector->stop(); }, [this] { connector->start(); }}; display->pause(); paused = true; } catch(std::runtime_error const&) { return false; } server_status_listener->paused(); return true; } bool resume() { try { TryButRevertIfUnwinding disp{ [this] { display->resume(); }, [this] { display->pause(); }}; TryButRevertIfUnwinding comm{ [this] { connector->start(); }, [this] { connector->stop(); }}; if (configure_display_on_resume) { std::shared_ptr conf = display->configuration(); display_changer->configure_for_hardware_change( conf, DisplayChanger::RetainSystemState); configure_display_on_resume = false; } TryButRevertIfUnwinding input{ [this] { input_manager->start(); }, [this] { input_manager->stop(); }}; compositor->start(); paused = false; } catch(std::runtime_error const&) { return false; } server_status_listener->resumed(); return true; } void configure_display() { if (!paused) { std::shared_ptr conf = display->configuration(); display_changer->configure_for_hardware_change( conf, DisplayChanger::PauseResumeSystem); } else { configure_display_on_resume = true; } } std::shared_ptr const graphics_platform; // Hold this so the platform is loaded once std::shared_ptr const display; std::shared_ptr const input_configuration; std::shared_ptr const compositor; std::shared_ptr const connector; std::shared_ptr const input_manager; std::shared_ptr const main_loop; std::shared_ptr const server_status_listener; std::shared_ptr const display_changer; bool paused; bool configure_display_on_resume; }; mir::DisplayServer::DisplayServer(ServerConfiguration& config) : p(new DisplayServer::Private{config}) { } /* * Need to define the destructor in the source file, so that we * can define the 'p' member variable as a unique_ptr to an * incomplete type (DisplayServerPrivate) in the header. */ mir::DisplayServer::~DisplayServer() { } void mir::DisplayServer::run() { p->connector->start(); p->compositor->start(); p->input_manager->start(); p->server_status_listener->started(); p->main_loop->run(); p->input_manager->stop(); p->compositor->stop(); p->connector->stop(); } void mir::DisplayServer::stop() { p->main_loop->stop(); } mir-0.1.8+14.04.20140411/src/server/scene/0000755000015301777760000000000012322054703020071 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/scene/threaded_snapshot_strategy.cpp0000644000015301777760000000621312322054223026215 0ustar pbusernogroup00000000000000/* * 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 */ #include "threaded_snapshot_strategy.h" #include "pixel_buffer.h" #include "mir/shell/surface_buffer_access.h" #include #include #include namespace geom = mir::geometry; namespace ms = mir::scene; namespace msh = mir::shell; namespace mir { namespace scene { struct WorkItem { std::shared_ptr const surface_buffer_access; msh::SnapshotCallback const snapshot_taken; }; class SnapshottingFunctor { public: SnapshottingFunctor(std::shared_ptr const& pixels) : running{true}, pixels{pixels} { } void operator()() { std::unique_lock lock{work_mutex}; while (running) { while (running && work.empty()) work_cv.wait(lock); if (running) { auto wi = work.front(); work.pop_front(); lock.unlock(); take_snapshot(wi); lock.lock(); } } } void take_snapshot(WorkItem const& wi) { wi.surface_buffer_access->with_most_recent_buffer_do( [this](graphics::Buffer& buffer) { pixels->fill_from(buffer); }); wi.snapshot_taken( msh::Snapshot{pixels->size(), pixels->stride(), pixels->as_argb_8888()}); } void schedule_snapshot(WorkItem const& wi) { std::lock_guard lg{work_mutex}; work.push_back(wi); work_cv.notify_one(); } void stop() { std::lock_guard lg{work_mutex}; running = false; work_cv.notify_one(); } private: bool running; std::shared_ptr const pixels; std::mutex work_mutex; std::condition_variable work_cv; std::deque work; }; } } ms::ThreadedSnapshotStrategy::ThreadedSnapshotStrategy( std::shared_ptr const& pixels) : pixels{pixels}, functor{new SnapshottingFunctor{pixels}}, thread{std::ref(*functor)} { } ms::ThreadedSnapshotStrategy::~ThreadedSnapshotStrategy() noexcept { functor->stop(); thread.join(); } void ms::ThreadedSnapshotStrategy::take_snapshot_of( std::shared_ptr const& surface_buffer_access, msh::SnapshotCallback const& snapshot_taken) { functor->schedule_snapshot(WorkItem{surface_buffer_access, snapshot_taken}); } mir-0.1.8+14.04.20140411/src/server/scene/surface_controller.h0000644000015301777760000000320012322054247024133 0ustar pbusernogroup00000000000000/* * 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_SCENE_SURFACE_CONTROLLER_H_ #define MIR_SCENE_SURFACE_CONTROLLER_H_ #include "mir/scene/surface_coordinator.h" namespace mir { namespace scene { class SurfaceStackModel; class SurfaceFactory; /// Will grow up to provide synchronization of model updates class SurfaceController : public SurfaceCoordinator { public: SurfaceController( std::shared_ptr const& surface_factory, std::shared_ptr const& surface_stack); std::shared_ptr add_surface( shell::SurfaceCreationParameters const& params, std::shared_ptr const& observer) override; void remove_surface(std::weak_ptr const& surface) override; void raise(std::weak_ptr const& surface) override; private: std::shared_ptr const surface_factory; std::shared_ptr const surface_stack; }; } } #endif /* MIR_SCENE_SURFACE_CONTROLLER_H_ */ mir-0.1.8+14.04.20140411/src/server/scene/mediating_display_changer.h0000644000015301777760000000630512322054247025426 0ustar pbusernogroup00000000000000/* * 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_SCENE_MEDIATING_DISPLAY_CHANGER_H_ #define MIR_SCENE_MEDIATING_DISPLAY_CHANGER_H_ #include "mir/frontend/display_changer.h" #include "mir/display_changer.h" #include #include namespace mir { namespace graphics { class Display; class DisplayConfigurationPolicy; } namespace compositor { class Compositor; } namespace scene { class SessionEventHandlerRegister; class SessionContainer; class MediatingDisplayChanger : public frontend::DisplayChanger, public mir::DisplayChanger { public: MediatingDisplayChanger( std::shared_ptr const& display, std::shared_ptr const& compositor, std::shared_ptr const& display_configuration_policy, std::shared_ptr const& session_container, std::shared_ptr const& session_event_handler_register); /* From mir::frontend::DisplayChanger */ std::shared_ptr active_configuration(); void configure(std::shared_ptr const& session, std::shared_ptr const& conf); /* From mir::DisplayChanger */ void configure_for_hardware_change( std::shared_ptr const& conf, SystemStateHandling pause_resume_system); private: void apply_config(std::shared_ptr const& conf, SystemStateHandling pause_resume_system); void apply_base_config(SystemStateHandling pause_resume_system); void send_config_to_all_sessions( std::shared_ptr const& conf); std::shared_ptr const display; std::shared_ptr const compositor; std::shared_ptr const display_configuration_policy; std::shared_ptr const session_container; std::shared_ptr const session_event_handler_register; std::mutex configuration_mutex; std::map, std::shared_ptr, std::owner_less>> config_map; std::weak_ptr focused_session; std::shared_ptr base_configuration; bool base_configuration_applied; }; } } #endif /* MIR_SCENE_MEDIATING_DISPLAY_CHANGER_H_ */ mir-0.1.8+14.04.20140411/src/server/scene/default_configuration.cpp0000644000015301777760000001435712322054247025165 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/default_server_configuration.h" #include "mir/graphics/display.h" #include "mir/graphics/gl_context.h" #include "mir/input/input_configuration.h" #include "mir/abnormal_exit.h" #include "mir/shell/session.h" #include "broadcasting_session_event_sink.h" #include "default_session_container.h" #include "gl_pixel_buffer.h" #include "global_event_sender.h" #include "mediating_display_changer.h" #include "session_container.h" #include "session_manager.h" #include "surface_allocator.h" #include "surface_controller.h" #include "surface_stack.h" #include "threaded_snapshot_strategy.h" namespace mc = mir::compositor; namespace mf = mir::frontend; namespace ms = mir::scene; namespace msh = mir::shell; std::shared_ptr mir::DefaultServerConfiguration::the_surface_stack_model() { return surface_stack( [this]() { auto const scene_report = the_scene_report(); auto const ss = std::make_shared( the_input_registrar(), scene_report); the_input_configuration()->set_input_targets(ss); return ss; }); } std::shared_ptr mir::DefaultServerConfiguration::the_scene() { return surface_stack( [this]() { auto const scene_report = the_scene_report(); auto const ss = std::make_shared( the_input_registrar(), scene_report); the_input_configuration()->set_input_targets(ss); return ss; }); } auto mir::DefaultServerConfiguration::the_surface_factory() -> std::shared_ptr { return surface_factory( [this]() { return std::make_shared( the_buffer_stream_factory(), the_input_channel_factory(), the_surface_configurator(), the_scene_report()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_surface_controller() { return surface_controller( [this]() { return std::make_shared( the_surface_factory(), the_surface_stack_model()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_surface_ranker() { return the_surface_controller(); } std::shared_ptr mir::DefaultServerConfiguration::the_surface_coordinator() { return the_surface_controller(); } std::shared_ptr mir::DefaultServerConfiguration::the_broadcasting_session_event_sink() { return broadcasting_session_event_sink( [] { return std::make_shared(); }); } std::shared_ptr mir::DefaultServerConfiguration::the_session_event_sink() { return the_broadcasting_session_event_sink(); } std::shared_ptr mir::DefaultServerConfiguration::the_session_event_handler_register() { return the_broadcasting_session_event_sink(); } std::shared_ptr mir::DefaultServerConfiguration::the_session_container() { return session_container( []{ return std::make_shared(); }); } std::shared_ptr mir::DefaultServerConfiguration::the_mediating_display_changer() { return mediating_display_changer( [this]() { return std::make_shared( the_display(), the_compositor(), the_display_configuration_policy(), the_session_container(), the_session_event_handler_register()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_frontend_display_changer() { return the_mediating_display_changer(); } std::shared_ptr mir::DefaultServerConfiguration::the_display_changer() { return the_mediating_display_changer(); } std::shared_ptr mir::DefaultServerConfiguration::the_global_event_sink() { return global_event_sink( [this]() { return std::make_shared(the_session_container()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_session_manager() { return session_manager( [this]() -> std::shared_ptr { return std::make_shared( the_shell_surface_factory(), the_session_container(), the_shell_focus_setter(), the_snapshot_strategy(), the_session_event_sink(), the_shell_session_listener()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_frontend_shell() { return the_session_manager(); } std::shared_ptr mir::DefaultServerConfiguration::the_focus_controller() { return the_session_manager(); } std::shared_ptr mir::DefaultServerConfiguration::the_pixel_buffer() { return pixel_buffer( [this]() { return std::make_shared( the_display()->create_gl_context()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_snapshot_strategy() { return snapshot_strategy( [this]() { return std::make_shared( the_pixel_buffer()); }); } mir-0.1.8+14.04.20140411/src/server/scene/gl_pixel_buffer.cpp0000644000015301777760000001221712322054247023737 0ustar pbusernogroup00000000000000/* * 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 */ #include "gl_pixel_buffer.h" #include "mir/graphics/gl_context.h" #include "mir/graphics/buffer.h" #include #include #include namespace mg = mir::graphics; namespace ms = mir::scene; namespace geom = mir::geometry; namespace { bool is_big_endian() { uint32_t n = 1; return (*reinterpret_cast(&n) != 1); } inline uint32_t abgr_to_argb(uint32_t p) { return ((p << 16) & 0x00ff0000) | /* Move R to new position */ ((p) & 0x0000ff00) | /* G remains at same position */ ((p >> 16) & 0x000000ff) | /* Move B to new position */ ((p) & 0xff000000); /* A remains at same position */ } } ms::GLPixelBuffer::GLPixelBuffer(std::unique_ptr gl_context) : gl_context{std::move(gl_context)}, tex{0}, fbo{0}, gl_pixel_format{0}, pixels_need_y_flip{false} { /* * TODO: Handle systems that are big-endian, and therefore GL_BGRA doesn't * give the 0xAARRGGBB pixel format we need. */ if (is_big_endian()) { BOOST_THROW_EXCEPTION(std::runtime_error( "GLPixelBuffer doesn't support big endian architectures")); } } ms::GLPixelBuffer::~GLPixelBuffer() noexcept { /* * This may be called from a different thread * than the one that called prepare */ if (tex != 0 || fbo != 0) gl_context->make_current(); if (tex != 0) glDeleteTextures(1, &tex); if (fbo != 0) glDeleteFramebuffers(1, &fbo); } void ms::GLPixelBuffer::prepare() { gl_context->make_current(); if (tex == 0) glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glActiveTexture(GL_TEXTURE0); if (fbo == 0) glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); } void ms::GLPixelBuffer::fill_from(graphics::Buffer& buffer) { auto width = buffer.size().width.as_uint32_t(); auto height = buffer.size().height.as_uint32_t(); pixels.resize(width * height * 4); prepare(); buffer.bind_to_texture(); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); /* First try to get pixels as BGRA */ glGetError(); gl_pixel_format = GL_BGRA_EXT; glReadPixels(0, 0, width, height, gl_pixel_format, GL_UNSIGNED_BYTE, pixels.data()); /* If getting pixels as BGRA failed, fall back to RGBA */ if (glGetError() != GL_NO_ERROR) { gl_pixel_format = GL_RGBA; glReadPixels(0, 0, width, height, gl_pixel_format, GL_UNSIGNED_BYTE, pixels.data()); } size_ = buffer.size(); pixels_need_y_flip = true; } void const* ms::GLPixelBuffer::as_argb_8888() { if (pixels_need_y_flip) { auto const stride_val = stride().as_uint32_t(); auto const height = size_.height.as_uint32_t(); std::vector tmp(stride_val); for (unsigned int i = 0; i < height / 2; i++) { /* Store line i */ tmp.assign(&pixels[i * stride_val], &pixels[(i + 1) * stride_val]); /* Copy line height - i - 1 to line i */ copy_and_convert_pixel_line(&pixels[(height - i - 1) * stride_val], &pixels[i * stride_val]); /* Copy stored line (i) to height - i - 1 */ copy_and_convert_pixel_line(tmp.data(), &pixels[(height - i - 1) * stride_val]); } /* Process middle line if there is one */ if (height % 2 == 1) { copy_and_convert_pixel_line(&pixels[(height / 2) * stride_val], &pixels[(height / 2) * stride_val]); } pixels_need_y_flip = false; } return pixels.data(); } geom::Size ms::GLPixelBuffer::size() const { return size_; } geom::Stride ms::GLPixelBuffer::stride() const { return geom::Stride{size_.width.as_uint32_t() * sizeof(uint32_t)}; } void ms::GLPixelBuffer::copy_and_convert_pixel_line(char* src, char* dst) { if (gl_pixel_format == GL_RGBA) { /* Convert from abgr_8888 to argb_8888 while copying */ auto pixels_src = reinterpret_cast(src); auto pixels_dst = reinterpret_cast(dst); auto const width = size_.width.as_uint32_t(); for (uint32_t n = 0; n < width; n++) pixels_dst[n] = abgr_to_argb(pixels_src[n]); } else if (src != dst) { std::copy(src, src + stride().as_uint32_t(), dst); } } mir-0.1.8+14.04.20140411/src/server/scene/surface_event_source.cpp0000644000015301777760000000337512322054247025021 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/scene/surface_event_source.h" #include #include namespace ms = mir::scene; namespace geom = mir::geometry; ms::SurfaceEventSource::SurfaceEventSource( frontend::SurfaceId id, std::shared_ptr const& event_sink) : id(id), event_sink(event_sink) { } void ms::SurfaceEventSource::resize(geom::Size const& size) { MirEvent e; memset(&e, 0, sizeof e); e.type = mir_event_type_resize; e.resize.surface_id = id.as_value(); e.resize.width = size.width.as_int(); e.resize.height = size.height.as_int(); event_sink->handle_event(e); } void ms::SurfaceEventSource::attrib_change(MirSurfaceAttrib attrib, int value) { MirEvent e; // This memset is not really required. However it does avoid some // harmless uninitialized memory reads that valgrind will complain // about, due to gaps in MirEvent. memset(&e, 0, sizeof e); e.type = mir_event_type_surface; e.surface.id = id.as_value(); e.surface.attrib = attrib; e.surface.value = value; event_sink->handle_event(e); } mir-0.1.8+14.04.20140411/src/server/scene/mediating_display_changer.cpp0000644000015301777760000001363112322054247025761 0ustar pbusernogroup00000000000000/* * 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 */ #include "mediating_display_changer.h" #include "session_container.h" #include "mir/shell/session.h" #include "session_event_handler_register.h" #include "mir/graphics/display.h" #include "mir/compositor/compositor.h" #include "mir/graphics/display_configuration_policy.h" #include "mir/graphics/display_configuration.h" namespace mf = mir::frontend; namespace ms = mir::scene; namespace msh = mir::shell; namespace mg = mir::graphics; namespace mc = mir::compositor; namespace { class ApplyNowAndRevertOnScopeExit { public: ApplyNowAndRevertOnScopeExit(std::function const& apply, std::function const& revert) : revert{revert} { apply(); } ~ApplyNowAndRevertOnScopeExit() { revert(); } private: ApplyNowAndRevertOnScopeExit(ApplyNowAndRevertOnScopeExit const&) = delete; ApplyNowAndRevertOnScopeExit& operator=(ApplyNowAndRevertOnScopeExit const&) = delete; std::function const revert; }; } ms::MediatingDisplayChanger::MediatingDisplayChanger( std::shared_ptr const& display, std::shared_ptr const& compositor, std::shared_ptr const& display_configuration_policy, std::shared_ptr const& session_container, std::shared_ptr const& session_event_handler_register) : display{display}, compositor{compositor}, display_configuration_policy{display_configuration_policy}, session_container{session_container}, session_event_handler_register{session_event_handler_register}, base_configuration{display->configuration()}, base_configuration_applied{true} { session_event_handler_register->register_focus_change_handler( [this](std::shared_ptr const& session) { std::lock_guard lg{configuration_mutex}; focused_session = session; /* * If the newly focused session has a display configuration, apply it. * Otherwise if we aren't currently using the base configuration, * apply that. */ auto it = config_map.find(session); if (it != config_map.end()) { apply_config(it->second, PauseResumeSystem); } else if (!base_configuration_applied) { apply_base_config(PauseResumeSystem); } }); session_event_handler_register->register_no_focus_handler( [this] { std::lock_guard lg{configuration_mutex}; focused_session.reset(); if (!base_configuration_applied) { apply_base_config(PauseResumeSystem); } }); session_event_handler_register->register_session_stopping_handler( [this](std::shared_ptr const& session) { std::lock_guard lg{configuration_mutex}; config_map.erase(session); }); } void ms::MediatingDisplayChanger::configure( std::shared_ptr const& session, std::shared_ptr const& conf) { std::lock_guard lg{configuration_mutex}; config_map[session] = conf; /* If the session is focused, apply the configuration */ if (focused_session.lock() == session) { apply_config(conf, PauseResumeSystem); } } std::shared_ptr ms::MediatingDisplayChanger::active_configuration() { std::lock_guard lg{configuration_mutex}; return display->configuration(); } void ms::MediatingDisplayChanger::configure_for_hardware_change( std::shared_ptr const& conf, SystemStateHandling pause_resume_system) { std::lock_guard lg{configuration_mutex}; display_configuration_policy->apply_to(*conf); base_configuration = conf; if (base_configuration_applied) apply_base_config(pause_resume_system); /* * Clear all the per-session configurations, since they may have become * invalid due to the hardware change. */ config_map.clear(); /* Send the new configuration to all the sessions */ send_config_to_all_sessions(conf); } void ms::MediatingDisplayChanger::apply_config( std::shared_ptr const& conf, SystemStateHandling pause_resume_system) { if (pause_resume_system) { ApplyNowAndRevertOnScopeExit comp{ [this] { compositor->stop(); }, [this] { compositor->start(); }}; display->configure(*conf); } else { display->configure(*conf); } base_configuration_applied = false; } void ms::MediatingDisplayChanger::apply_base_config( SystemStateHandling pause_resume_system) { apply_config(base_configuration, pause_resume_system); base_configuration_applied = true; } void ms::MediatingDisplayChanger::send_config_to_all_sessions( std::shared_ptr const& conf) { session_container->for_each( [&conf](std::shared_ptr const& session) { session->send_display_config(*conf); }); } mir-0.1.8+14.04.20140411/src/server/scene/application_session.h0000644000015301777760000000566712322054223024323 0ustar pbusernogroup00000000000000/* * 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_SCENE_APPLICATION_SESSION_H_ #define MIR_SCENE_APPLICATION_SESSION_H_ #include "mir/shell/session.h" #include namespace mir { namespace frontend { class EventSink; } namespace shell { class SurfaceFactory; class Surface; class SessionListener; } namespace scene { class SnapshotStrategy; class ApplicationSession : public shell::Session { public: ApplicationSession( std::shared_ptr const& surface_factory, pid_t pid, std::string const& session_name, std::shared_ptr const& snapshot_strategy, std::shared_ptr const& session_listener, std::shared_ptr const& sink); ~ApplicationSession(); frontend::SurfaceId create_surface(shell::SurfaceCreationParameters const& params); void destroy_surface(frontend::SurfaceId surface); std::shared_ptr get_surface(frontend::SurfaceId surface) const; void take_snapshot(shell::SnapshotCallback const& snapshot_taken); std::shared_ptr default_surface() const; std::string name() const; pid_t process_id() const override; void force_requests_to_complete(); void hide(); void show(); void send_display_config(graphics::DisplayConfiguration const& info); int configure_surface(frontend::SurfaceId id, MirSurfaceAttrib attrib, int value); void set_lifecycle_state(MirLifecycleState state); protected: ApplicationSession(ApplicationSession const&) = delete; ApplicationSession& operator=(ApplicationSession const&) = delete; private: std::shared_ptr const surface_factory; pid_t const pid; std::string const session_name; std::shared_ptr const snapshot_strategy; std::shared_ptr const session_listener; std::shared_ptr const event_sink; frontend::SurfaceId next_id(); std::atomic next_surface_id; typedef std::map> Surfaces; Surfaces::const_iterator checked_find(frontend::SurfaceId id) const; std::mutex mutable surfaces_mutex; Surfaces surfaces; }; } } // namespace mir #endif // MIR_SCENE_APPLICATION_SESSION_H_ mir-0.1.8+14.04.20140411/src/server/scene/session_manager.h0000644000015301777760000000624212322054223023420 0ustar pbusernogroup00000000000000/* * 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: Thomas Voss */ #ifndef MIR_SCENE_APPLICATION_MANAGER_H_ #define MIR_SCENE_APPLICATION_MANAGER_H_ #include "mir/frontend/surface_id.h" #include "mir/frontend/shell.h" #include "mir/shell/focus_controller.h" #include #include #include namespace mir { namespace shell { class SurfaceFactory; class FocusSetter; class SessionListener; } namespace scene { class SessionEventSink; class SessionContainer; class SnapshotStrategy; class SessionManager : public frontend::Shell, public shell::FocusController { public: explicit SessionManager(std::shared_ptr const& surface_factory, std::shared_ptr const& app_container, std::shared_ptr const& focus_setter, std::shared_ptr const& snapshot_strategy, std::shared_ptr const& session_event_sink, std::shared_ptr const& session_listener); virtual ~SessionManager(); virtual std::shared_ptr open_session( pid_t client_pid, std::string const& name, std::shared_ptr const& sink); virtual void close_session(std::shared_ptr const& session); frontend::SurfaceId create_surface_for(std::shared_ptr const& session, shell::SurfaceCreationParameters const& params); void focus_next(); std::weak_ptr focussed_application() const; void set_focus_to(std::shared_ptr const& focus); void handle_surface_created(std::shared_ptr const& session); protected: SessionManager(const SessionManager&) = delete; SessionManager& operator=(const SessionManager&) = delete; private: std::shared_ptr const surface_factory; std::shared_ptr const app_container; std::shared_ptr const focus_setter; std::shared_ptr const snapshot_strategy; std::shared_ptr const session_event_sink; std::shared_ptr const session_listener; std::mutex mutex; std::weak_ptr focus_application; void set_focus_to_locked(std::unique_lock const& lock, std::shared_ptr const& next_focus); }; } } #endif // MIR_SCENE_APPLICATION_MANAGER_H_ mir-0.1.8+14.04.20140411/src/server/scene/threaded_snapshot_strategy.h0000644000015301777760000000275312322054223025667 0ustar pbusernogroup00000000000000/* * 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_THREADED_SNAPSHOT_STRATEGY_H_ #define MIR_SCENE_THREADED_SNAPSHOT_STRATEGY_H_ #include "snapshot_strategy.h" #include #include #include namespace mir { namespace scene { class PixelBuffer; class SnapshottingFunctor; class ThreadedSnapshotStrategy : public SnapshotStrategy { public: ThreadedSnapshotStrategy(std::shared_ptr const& pixels); ~ThreadedSnapshotStrategy() noexcept; void take_snapshot_of( std::shared_ptr const& surface_buffer_access, shell::SnapshotCallback const& snapshot_taken); private: std::shared_ptr const pixels; std::unique_ptr functor; std::thread thread; }; } } #endif /* MIR_SCENE_THREADED_SNAPSHOT_STRATEGY_H_ */ mir-0.1.8+14.04.20140411/src/server/scene/pixel_buffer.h0000644000015301777760000000364712322054223022723 0ustar pbusernogroup00000000000000/* * 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_PIXEL_BUFFER_H_ #define MIR_SCENE_PIXEL_BUFFER_H_ #include "mir/geometry/size.h" #include "mir/geometry/dimensions.h" namespace mir { namespace graphics { class Buffer; } namespace scene { /** * Interface for extracting the pixels from a graphics::Buffer. */ class PixelBuffer { public: virtual ~PixelBuffer() = default; /** * Fills the PixelBuffer with the contents of a graphics::Buffer. * * \param [in] buffer the buffer to get the pixels of */ virtual void fill_from(graphics::Buffer& buffer) = 0; /** * The pixels in 0xAARRGGBB format. * * The pixel data is owned by the PixelBuffer object and is only valid * until the next call to fill_from(). * * This method may involve transformation of the extracted data. */ virtual void const* as_argb_8888() = 0; /** * The size of the pixel buffer. */ virtual geometry::Size size() const = 0; /** * The stride of the pixel buffer. */ virtual geometry::Stride stride() const = 0; protected: PixelBuffer() = default; PixelBuffer(PixelBuffer const&) = delete; PixelBuffer& operator=(PixelBuffer const&) = delete; }; } } #endif /* MIR_SCENE_PIXEL_BUFFER_H_ */ mir-0.1.8+14.04.20140411/src/server/scene/surface_stack_model.h0000644000015301777760000000316012322054247024242 0ustar pbusernogroup00000000000000/* * 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: Thomas Voss */ #ifndef MIR_SCENE_SURFACE_STACK_MODEL_H_ #define MIR_SCENE_SURFACE_STACK_MODEL_H_ #include "mir/frontend/surface_id.h" #include "mir/scene/depth_id.h" #include "mir/input/input_reception_mode.h" #include namespace mir { namespace frontend { class EventSink; } namespace shell { struct SurfaceCreationParameters; } namespace scene { class Surface; class SurfaceStackModel { public: virtual ~SurfaceStackModel() {} virtual void add_surface( std::shared_ptr const& surface, DepthId depth, input::InputReceptionMode input_mode) = 0; virtual void remove_surface(std::weak_ptr const& surface) = 0; virtual void raise(std::weak_ptr const& surface) = 0; protected: SurfaceStackModel() = default; SurfaceStackModel(const SurfaceStackModel&) = delete; SurfaceStackModel& operator=(const SurfaceStackModel&) = delete; }; } } #endif // MIR_SCENE_SURFACE_STACK_MODEL_H_ mir-0.1.8+14.04.20140411/src/server/scene/broadcasting_session_event_sink.h0000644000015301777760000000373512322054223026677 0ustar pbusernogroup00000000000000/* * 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_BROADCASTING_SESSION_EVENT_SINK_H_ #define MIR_SCENE_BROADCASTING_SESSION_EVENT_SINK_H_ #include "session_event_sink.h" #include "session_event_handler_register.h" #include #include namespace mir { namespace scene { class BroadcastingSessionEventSink : public SessionEventSink, public SessionEventHandlerRegister { public: void handle_focus_change(std::shared_ptr const& session); void handle_no_focus(); void handle_session_stopping(std::shared_ptr const& session); void register_focus_change_handler( std::function const& session)> const& handler); void register_no_focus_handler( std::function const& handler); void register_session_stopping_handler( std::function const& session)> const& handler); private: std::mutex handler_mutex; std::vector const&)>> focus_change_handlers; std::vector> no_focus_handlers; std::vector const&)>> session_stopping_handlers; }; } } #endif /* MIR_SCENE_BROADCASTING_SESSION_EVENT_SINK_H_ */ mir-0.1.8+14.04.20140411/src/server/scene/basic_surface.cpp0000644000015301777760000002634412322054247023402 0ustar pbusernogroup00000000000000/* * 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 * Thomas Voss */ #include "basic_surface.h" #include "mir/compositor/buffer_stream.h" #include "mir/frontend/event_sink.h" #include "mir/input/input_channel.h" #include "mir/shell/input_targeter.h" #include "mir/graphics/buffer.h" #include "mir/scene/scene_report.h" #include "mir/scene/surface_configurator.h" #include #include #include namespace mc = mir::compositor; namespace ms = mir::scene; namespace msh = mir::shell; namespace mg = mir::graphics; namespace mi = mir::input; namespace geom = mir::geometry; ms::ThreadsafeCallback::ThreadsafeCallback(std::function const& notify_change) : notify_change(notify_change) {} ms::ThreadsafeCallback& ms::ThreadsafeCallback::operator=(std::function const& notify_change) { std::unique_lock lock(mutex); this->notify_change = notify_change; return *this; } void ms::ThreadsafeCallback::operator()() const { std::unique_lock lock(mutex); auto const notifier = notify_change; lock.unlock(); notifier(); } void ms::SurfaceObservers::attrib_change(MirSurfaceAttrib attrib, int value) { std::unique_lock lock(mutex); // TBD Maybe we should copy observers so we can release the lock? for (auto const& p : observers) p->attrib_change(attrib, value); } void ms::SurfaceObservers::resize(geometry::Size const& size) { std::unique_lock lock(mutex); // TBD Maybe we should copy observers so we can release the lock? for (auto const& p : observers) p->resize(size); } void ms::SurfaceObservers::add(std::shared_ptr const& observer) { if (observer) { std::unique_lock lock(mutex); observers.push_back(observer); } } void ms::SurfaceObservers::remove(std::shared_ptr const& observer) { std::unique_lock lock(mutex); observers.erase(std::remove(observers.begin(),observers.end(), observer), observers.end()); } ms::BasicSurface::BasicSurface( std::string const& name, geometry::Rectangle rect, bool nonrectangular, std::shared_ptr const& buffer_stream, std::shared_ptr const& input_channel, std::shared_ptr const& configurator, std::shared_ptr const& report) : notify_change([](){}), surface_name(name), surface_rect(rect), surface_alpha(1.0f), first_frame_posted(false), hidden(false), nonrectangular(nonrectangular), input_rectangles{surface_rect}, surface_buffer_stream(buffer_stream), server_input_channel(input_channel), configurator(configurator), report(report), type_value(mir_surface_type_normal), state_value(mir_surface_state_restored) { report->surface_created(this, surface_name); } void ms::BasicSurface::force_requests_to_complete() { surface_buffer_stream->force_requests_to_complete(); } ms::BasicSurface::~BasicSurface() noexcept { report->surface_deleted(this, surface_name); } std::shared_ptr ms::BasicSurface::buffer_stream() const { return surface_buffer_stream; } std::string ms::BasicSurface::name() const { return surface_name; } void ms::BasicSurface::move_to(geometry::Point const& top_left) { { std::unique_lock lk(guard); surface_rect.top_left = top_left; } notify_change(); } float ms::BasicSurface::alpha() const { std::unique_lock lk(guard); return surface_alpha; } void ms::BasicSurface::set_hidden(bool hide) { { std::unique_lock lk(guard); hidden = hide; } notify_change(); } mir::geometry::Size ms::BasicSurface::size() const { std::unique_lock lk(guard); return surface_rect.size; } MirPixelFormat ms::BasicSurface::pixel_format() const { return surface_buffer_stream->get_stream_pixel_format(); } void ms::BasicSurface::swap_buffers(mg::Buffer* old_buffer, std::function complete) { bool const posting{!!old_buffer}; surface_buffer_stream->swap_client_buffers(old_buffer, complete); if (posting) { { std::unique_lock lk(guard); first_frame_posted = true; } notify_change(); } } void ms::BasicSurface::allow_framedropping(bool allow) { surface_buffer_stream->allow_framedropping(allow); } std::shared_ptr ms::BasicSurface::snapshot_buffer() const { return surface_buffer_stream->lock_snapshot_buffer(); } bool ms::BasicSurface::supports_input() const { if (server_input_channel) return true; return false; } int ms::BasicSurface::client_input_fd() const { if (!supports_input()) BOOST_THROW_EXCEPTION(std::logic_error("Surface does not support input")); return server_input_channel->client_fd(); } std::shared_ptr ms::BasicSurface::input_channel() const { return server_input_channel; } void ms::BasicSurface::on_change(std::function change_notification) { notify_change = change_notification; } void ms::BasicSurface::set_input_region(std::vector const& input_rectangles) { std::unique_lock lock(guard); this->input_rectangles = input_rectangles; } void ms::BasicSurface::resize(geom::Size const& size) { if (size == this->size()) return; if (size.width <= geom::Width{0} || size.height <= geom::Height{0}) { BOOST_THROW_EXCEPTION(std::logic_error("Impossible resize requested")); } /* * Other combinations may still be invalid (like dimensions too big or * insufficient resources), but those are runtime and platform-specific, so * not predictable here. Such critical exceptions would arise from * the platform buffer allocator as a runtime_error via: */ surface_buffer_stream->resize(size); // Now the buffer stream has successfully resized, update the state second; { std::unique_lock lock(guard); surface_rect.size = size; } notify_change(); observers.resize(size); } geom::Point ms::BasicSurface::top_left() const { std::unique_lock lk(guard); return surface_rect.top_left; } bool ms::BasicSurface::contains(geom::Point const& point) const { std::unique_lock lock(guard); if (hidden) return false; for (auto const& rectangle : input_rectangles) { if (rectangle.contains(point)) { return true; } } return false; } void ms::BasicSurface::frame_posted() { { std::unique_lock lk(guard); first_frame_posted = true; } notify_change(); } void ms::BasicSurface::set_alpha(float alpha) { { std::unique_lock lk(guard); surface_alpha = alpha; } notify_change(); } void ms::BasicSurface::set_transformation(glm::mat4 const& t) { { std::unique_lock lk(guard); transformation_matrix = t; } notify_change(); } glm::mat4 ms::BasicSurface::transformation() const { std::unique_lock lk(guard); return transformation_matrix; } bool ms::BasicSurface::visible() const { std::unique_lock lk(guard); return !hidden && first_frame_posted; } bool ms::BasicSurface::shaped() const { return nonrectangular; } std::shared_ptr ms::BasicSurface::buffer(void const* user_id) const { return buffer_stream()->lock_compositor_buffer(user_id); } bool ms::BasicSurface::alpha_enabled() const { return shaped() || alpha() < 1.0f; } geom::Rectangle ms::BasicSurface::screen_position() const { // This would be more efficient to return a const reference return surface_rect; } int ms::BasicSurface::buffers_ready_for_compositor() const { return surface_buffer_stream->buffers_ready_for_compositor(); } void ms::BasicSurface::with_most_recent_buffer_do( std::function const& exec) { auto buf = snapshot_buffer(); exec(*buf); } MirSurfaceType ms::BasicSurface::type() const { return type_value; } bool ms::BasicSurface::set_type(MirSurfaceType t) { bool valid = false; if (t >= 0 && t < mir_surface_types) { type_value = t; valid = true; } return valid; } MirSurfaceState ms::BasicSurface::state() const { return state_value; } bool ms::BasicSurface::set_state(MirSurfaceState s) { bool valid = false; if (s > mir_surface_state_unknown && s < mir_surface_states) { state_value = s; valid = true; observers.attrib_change(mir_surface_attrib_state, s); } return valid; } void ms::BasicSurface::take_input_focus(std::shared_ptr const& targeter) { targeter->focus_changed(input_channel()); } int ms::BasicSurface::configure(MirSurfaceAttrib attrib, int value) { int result = 0; bool allow_dropping = false; /* * TODO: In future, query the shell implementation for the subset of * attributes/types it implements. */ value = configurator->select_attribute_value(*this, attrib, value); switch (attrib) { case mir_surface_attrib_type: if (!set_type(static_cast(value))) BOOST_THROW_EXCEPTION(std::logic_error("Invalid surface " "type.")); result = type(); break; case mir_surface_attrib_state: if (value != mir_surface_state_unknown && !set_state(static_cast(value))) BOOST_THROW_EXCEPTION(std::logic_error("Invalid surface state.")); result = state(); break; case mir_surface_attrib_focus: observers.attrib_change(attrib, value); break; case mir_surface_attrib_swapinterval: allow_dropping = (value == 0); allow_framedropping(allow_dropping); result = value; break; default: BOOST_THROW_EXCEPTION(std::logic_error("Invalid surface " "attribute.")); break; } configurator->attribute_set(*this, attrib, result); return result; } void ms::BasicSurface::hide() { set_hidden(true); } void ms::BasicSurface::show() { set_hidden(false); } void ms::BasicSurface::add_observer(std::shared_ptr const& observer) { observers.add(observer); } void ms::BasicSurface::remove_observer(std::shared_ptr const& observer) { observers.remove(observer); } mir-0.1.8+14.04.20140411/src/server/scene/global_event_sender.h0000644000015301777760000000245012322054223024241 0ustar pbusernogroup00000000000000/* * 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_SCENE_GLOBAL_EVENT_SENDER_H_ #define MIR_SCENE_GLOBAL_EVENT_SENDER_H_ #include "mir/frontend/event_sink.h" #include namespace mir { namespace scene { class SessionContainer; class GlobalEventSender : public frontend::EventSink { public: GlobalEventSender(std::shared_ptr const&); void handle_event(MirEvent const& e); void handle_lifecycle_event(MirLifecycleState state); void handle_display_config_change(graphics::DisplayConfiguration const& config); private: std::shared_ptr const sessions; }; } } #endif /* MIR_SCENE_GLOBAL_EVENT_SENDER_H_ */ mir-0.1.8+14.04.20140411/src/server/scene/surface_stack.cpp0000644000015301777760000001236512322054247023424 0ustar pbusernogroup00000000000000/* * 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 * Thomas Voss */ #include "mir/graphics/buffer_properties.h" #include "mir/shell/surface_creation_parameters.h" #include "surface_stack.h" #include "mir/compositor/buffer_stream.h" #include "mir/scene/input_registrar.h" #include "mir/input/input_channel_factory.h" #include "mir/scene/scene_report.h" // TODO Including this doesn't seem right - why would SurfaceStack "know" about BasicSurface // It is needed by the following member functions: // for_each(), for_each_if(), create_surface() and destroy_surface() // to access: // buffer_stream() and input_channel() #include "basic_surface.h" #include #include #include #include #include #include namespace ms = mir::scene; namespace mc = mir::compositor; namespace mg = mir::graphics; namespace mi = mir::input; namespace geom = mir::geometry; ms::SurfaceStack::SurfaceStack( std::shared_ptr const& input_registrar, std::shared_ptr const& report) : input_registrar{input_registrar}, report{report}, change_cb{[this]() { emit_change_notification(); }}, notify_change{[]{}} { } mg::RenderableList ms::SurfaceStack::generate_renderable_list() const { std::lock_guard lg(guard); mg::RenderableList list; for (auto &layer : layers_by_depth) std::copy(layer.second.begin(), layer.second.end(), std::back_inserter(list)); return list; } void ms::SurfaceStack::for_each_if(mc::FilterForScene& filter, mc::OperatorForScene& op) { std::lock_guard lg(guard); for (auto &layer : layers_by_depth) { auto surfaces = layer.second; for (auto it = surfaces.begin(); it != surfaces.end(); ++it) { mg::Renderable& r = **it; if (filter(r)) op(r); } } } void ms::SurfaceStack::set_change_callback(std::function const& f) { std::lock_guard lg{notify_change_mutex}; assert(f); notify_change = f; } void ms::SurfaceStack::add_surface( std::shared_ptr const& surface, DepthId depth, mi::InputReceptionMode input_mode) { { std::lock_guard lg(guard); layers_by_depth[depth].push_back(surface); } input_registrar->input_channel_opened(surface->input_channel(), surface, input_mode); report->surface_added(surface.get(), surface.get()->name()); surface->on_change(change_cb); emit_change_notification(); } void ms::SurfaceStack::remove_surface(std::weak_ptr const& surface) { auto const keep_alive = surface.lock(); bool found_surface = false; { std::lock_guard lg(guard); for (auto &layer : layers_by_depth) { auto &surfaces = layer.second; auto const p = std::find(surfaces.begin(), surfaces.end(), keep_alive); if (p != surfaces.end()) { surfaces.erase(p); found_surface = true; break; } } } if (found_surface) { input_registrar->input_channel_closed(keep_alive->input_channel()); report->surface_removed(keep_alive.get(), keep_alive.get()->name()); emit_change_notification(); } // TODO: error logging when surface not found } void ms::SurfaceStack::emit_change_notification() { std::lock_guard lg{notify_change_mutex}; notify_change(); } void ms::SurfaceStack::for_each(std::function const&)> const& callback) { std::lock_guard lg(guard); for (auto &layer : layers_by_depth) { for (auto it = layer.second.begin(); it != layer.second.end(); ++it) callback((*it)->input_channel()); } } void ms::SurfaceStack::raise(std::weak_ptr const& s) { auto surface = s.lock(); { std::unique_lock ul(guard); for (auto &layer : layers_by_depth) { auto &surfaces = layer.second; auto const p = std::find(surfaces.begin(), surfaces.end(), surface); if (p != surfaces.end()) { surfaces.erase(p); surfaces.push_back(surface); ul.unlock(); emit_change_notification(); return; } } } BOOST_THROW_EXCEPTION(std::runtime_error("Invalid surface")); } void ms::SurfaceStack::lock() { guard.lock(); } void ms::SurfaceStack::unlock() { guard.unlock(); } mir-0.1.8+14.04.20140411/src/server/scene/application_session.cpp0000644000015301777760000001226512322054247024654 0ustar pbusernogroup00000000000000/* * 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 */ #include "application_session.h" #include "mir/shell/surface.h" #include "mir/scene/surface_event_source.h" #include "mir/shell/surface_factory.h" #include "snapshot_strategy.h" #include "mir/shell/session_listener.h" #include "mir/frontend/event_sink.h" #include #include #include #include #include namespace mf = mir::frontend; namespace ms = mir::scene; namespace msh = mir::shell; namespace mg = mir::graphics; ms::ApplicationSession::ApplicationSession( std::shared_ptr const& surface_factory, pid_t pid, std::string const& session_name, std::shared_ptr const& snapshot_strategy, std::shared_ptr const& session_listener, std::shared_ptr const& sink) : surface_factory(surface_factory), pid(pid), session_name(session_name), snapshot_strategy(snapshot_strategy), session_listener(session_listener), event_sink(sink), next_surface_id(0) { assert(surface_factory); } ms::ApplicationSession::~ApplicationSession() { std::unique_lock lock(surfaces_mutex); for (auto const& pair_id_surface : surfaces) { session_listener->destroying_surface(*this, pair_id_surface.second); surface_factory->destroy_surface(pair_id_surface.second); } } mf::SurfaceId ms::ApplicationSession::next_id() { return mf::SurfaceId(next_surface_id.fetch_add(1)); } mf::SurfaceId ms::ApplicationSession::create_surface(const msh::SurfaceCreationParameters& params) { auto const id = next_id(); auto const observer = std::make_shared(id, event_sink); auto surf = surface_factory->create_surface(this, params, observer); std::unique_lock lock(surfaces_mutex); surfaces[id] = surf; session_listener->surface_created(*this, surf); return id; } ms::ApplicationSession::Surfaces::const_iterator ms::ApplicationSession::checked_find(mf::SurfaceId id) const { auto p = surfaces.find(id); if (p == surfaces.end()) { BOOST_THROW_EXCEPTION(std::runtime_error("Invalid SurfaceId")); } return p; } std::shared_ptr ms::ApplicationSession::get_surface(mf::SurfaceId id) const { std::unique_lock lock(surfaces_mutex); return checked_find(id)->second; } void ms::ApplicationSession::take_snapshot(msh::SnapshotCallback const& snapshot_taken) { if (auto surface = default_surface()) snapshot_strategy->take_snapshot_of(surface, snapshot_taken); else snapshot_taken(msh::Snapshot()); } std::shared_ptr ms::ApplicationSession::default_surface() const { std::unique_lock lock(surfaces_mutex); if (surfaces.size()) return surfaces.begin()->second; else return std::shared_ptr(); } void ms::ApplicationSession::destroy_surface(mf::SurfaceId id) { std::unique_lock lock(surfaces_mutex); auto p = checked_find(id); auto const surface = p->second; session_listener->destroying_surface(*this, surface); surfaces.erase(p); lock.unlock(); surface_factory->destroy_surface(surface); } std::string ms::ApplicationSession::name() const { return session_name; } pid_t ms::ApplicationSession::process_id() const { return pid; } void ms::ApplicationSession::force_requests_to_complete() { std::unique_lock lock(surfaces_mutex); for (auto& id_s : surfaces) { id_s.second->force_requests_to_complete(); } } void ms::ApplicationSession::hide() { std::unique_lock lock(surfaces_mutex); for (auto& id_s : surfaces) { id_s.second->hide(); } } void ms::ApplicationSession::show() { std::unique_lock lock(surfaces_mutex); for (auto& id_s : surfaces) { id_s.second->show(); } } int ms::ApplicationSession::configure_surface(mf::SurfaceId id, MirSurfaceAttrib attrib, int requested_value) { std::unique_lock lock(surfaces_mutex); std::shared_ptr surf(checked_find(id)->second); return surf->configure(attrib, requested_value); } void ms::ApplicationSession::send_display_config(mg::DisplayConfiguration const& info) { event_sink->handle_display_config_change(info); } void ms::ApplicationSession::set_lifecycle_state(MirLifecycleState state) { event_sink->handle_lifecycle_event(state); } mir-0.1.8+14.04.20140411/src/server/scene/session_event_sink.h0000644000015301777760000000256612322054223024160 0ustar pbusernogroup00000000000000/* * 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_SESSION_EVENT_SINK_H_ #define MIR_SCENE_SESSION_EVENT_SINK_H_ #include namespace mir { namespace shell { class Session; } namespace scene { class SessionEventSink { public: virtual ~SessionEventSink() = default; virtual void handle_focus_change(std::shared_ptr const& session) = 0; virtual void handle_no_focus() = 0; virtual void handle_session_stopping(std::shared_ptr const& session) = 0; protected: SessionEventSink() = default; SessionEventSink(SessionEventSink const&) = delete; SessionEventSink& operator=(SessionEventSink const&) = delete; }; } } #endif /* MIR_SCENE_SESSION_EVENT_SINK_H_ */ mir-0.1.8+14.04.20140411/src/server/scene/surface_allocator.cpp0000644000015301777760000000462612322054247024300 0ustar pbusernogroup00000000000000/* * 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 */ #include "surface_allocator.h" #include "mir/scene/buffer_stream_factory.h" #include "mir/compositor/buffer_stream.h" #include "mir/input/input_channel_factory.h" #include "basic_surface.h" namespace geom=mir::geometry; namespace mc=mir::compositor; namespace mg=mir::graphics; namespace ms=mir::scene; namespace msh=mir::shell; namespace mi=mir::input; static inline bool has_alpha(MirPixelFormat fmt) { return (fmt == mir_pixel_format_abgr_8888) || (fmt == mir_pixel_format_argb_8888); } ms::SurfaceAllocator::SurfaceAllocator( std::shared_ptr const& stream_factory, std::shared_ptr const& input_factory, std::shared_ptr const& configurator, std::shared_ptr const& report) : buffer_stream_factory(stream_factory), input_factory(input_factory), configurator(configurator), report(report) { } std::shared_ptr ms::SurfaceAllocator::create_surface( shell::SurfaceCreationParameters const& params) { mg::BufferProperties buffer_properties{params.size, params.pixel_format, params.buffer_usage}; auto buffer_stream = buffer_stream_factory->create_buffer_stream(buffer_properties); auto actual_size = geom::Rectangle{params.top_left, buffer_stream->stream_size()}; bool nonrectangular = has_alpha(params.pixel_format); auto input_channel = input_factory->make_input_channel(); auto const surface = std::make_shared( params.name, actual_size, nonrectangular, buffer_stream, input_channel, configurator, report); return surface; } mir-0.1.8+14.04.20140411/src/server/scene/session_container.h0000644000015301777760000000325412322054223023770 0ustar pbusernogroup00000000000000/* * 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_SCENE_SESSION_CONTAINER_H_ #define MIR_SCENE_SESSION_CONTAINER_H_ #include #include #include namespace mir { namespace shell { class Session; } namespace scene { class SessionContainer { public: virtual void insert_session(std::shared_ptr const& session) = 0; virtual void remove_session(std::shared_ptr const& session) = 0; virtual void for_each(std::function const&)> f) const = 0; // For convenience the successor of the null session is defined as the last session // which would be passed to the for_each callback virtual std::shared_ptr successor_of(std::shared_ptr const&) const = 0; protected: SessionContainer() = default; virtual ~SessionContainer() = default; SessionContainer(const SessionContainer&) = delete; SessionContainer& operator=(const SessionContainer&) = delete; }; } } #endif // MIR_SCENE_SESSION_CONTAINER_H_ mir-0.1.8+14.04.20140411/src/server/scene/surface_controller.cpp0000644000015301777760000000331312322054247024473 0ustar pbusernogroup00000000000000/* * 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 */ #include "surface_controller.h" #include "surface_stack_model.h" #include "mir/scene/surface_factory.h" #include "mir/scene/surface.h" namespace ms = mir::scene; namespace msh = mir::shell; ms::SurfaceController::SurfaceController( std::shared_ptr const& surface_factory, std::shared_ptr const& surface_stack) : surface_factory(surface_factory), surface_stack(surface_stack) { } std::shared_ptr ms::SurfaceController::add_surface( shell::SurfaceCreationParameters const& params, std::shared_ptr const& observer) { auto const surface = surface_factory->create_surface(params); surface->add_observer(observer); surface_stack->add_surface(surface, params.depth, params.input_mode); return surface; } void ms::SurfaceController::remove_surface(std::weak_ptr const& surface) { surface_stack->remove_surface(surface); } void ms::SurfaceController::raise(std::weak_ptr const& surface) { surface_stack->raise(surface); } mir-0.1.8+14.04.20140411/src/server/scene/snapshot_strategy.h0000644000015301777760000000256112322054223024024 0ustar pbusernogroup00000000000000/* * 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_STRATEGY_H_ #define MIR_SCENE_SNAPSHOT_STRATEGY_H_ #include "mir/shell/snapshot.h" #include namespace mir { namespace shell { class SurfaceBufferAccess; } namespace scene { class SnapshotStrategy { public: virtual ~SnapshotStrategy() = default; virtual void take_snapshot_of( std::shared_ptr const& surface_buffer_access, shell::SnapshotCallback const& snapshot_taken) = 0; protected: SnapshotStrategy() = default; SnapshotStrategy(SnapshotStrategy const&) = delete; SnapshotStrategy& operator=(SnapshotStrategy const&) = delete; }; } } #endif /* MIR_SCENE_SNAPSHOT_STRATEGY_H_ */ mir-0.1.8+14.04.20140411/src/server/scene/surface_allocator.h0000644000015301777760000000333312322054247023737 0ustar pbusernogroup00000000000000/* * 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_ALLOCATOR_H_ #define MIR_SCENE_SURFACE_ALLOCATOR_H_ #include "mir/scene/surface_factory.h" namespace mir { namespace input { class InputChannelFactory; } namespace scene { class BufferStreamFactory; class SceneReport; class SurfaceConfigurator; class SurfaceAllocator : public SurfaceFactory { public: SurfaceAllocator(std::shared_ptr const& bb_factory, std::shared_ptr const& input_factory, std::shared_ptr const& configurator, std::shared_ptr const& report); std::shared_ptr create_surface( shell::SurfaceCreationParameters const& params) override; private: std::shared_ptr const buffer_stream_factory; std::shared_ptr const input_factory; std::shared_ptr const configurator; std::shared_ptr const report; }; } } #endif /* MIR_SCENE_SURFACE_ALLOCATOR_H_ */ mir-0.1.8+14.04.20140411/src/server/scene/session_event_handler_register.h0000644000015301777760000000324212322054223026525 0ustar pbusernogroup00000000000000/* * 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_SESSION_EVENT_HANDLER_REGISTER_H_ #define MIR_SCENE_SESSION_EVENT_HANDLER_REGISTER_H_ #include #include namespace mir { namespace shell { class Session; } namespace scene { class SessionEventHandlerRegister { public: virtual ~SessionEventHandlerRegister() = default; virtual void register_focus_change_handler( std::function const& session)> const& handler) = 0; virtual void register_no_focus_handler( std::function const& handler) = 0; virtual void register_session_stopping_handler( std::function const& session)> const& handler) = 0; protected: SessionEventHandlerRegister() = default; SessionEventHandlerRegister(SessionEventHandlerRegister const&) = delete; SessionEventHandlerRegister& operator=(SessionEventHandlerRegister const&) = delete; }; } } #endif /* MIR_SCENE_SESSION_EVENT_HANDLER_REGISTER_H_ */ mir-0.1.8+14.04.20140411/src/server/scene/basic_surface.h0000644000015301777760000001301112322054247023032 0ustar pbusernogroup00000000000000/* * 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: Thomas Voss */ #ifndef MIR_SCENE_BASIC_SURFACE_H_ #define MIR_SCENE_BASIC_SURFACE_H_ #include "mir/scene/surface.h" #include "mir/scene/surface_observer.h" #include "mir/geometry/rectangle.h" #include "mir_toolkit/common.h" #include #include #include #include #include namespace mir { namespace compositor { struct BufferIPCPackage; class BufferStream; } namespace frontend { class EventSink; } namespace graphics { class Buffer; } namespace input { class InputChannel; class Surface; } namespace scene { class SceneReport; class SurfaceConfigurator; // Thread safe wrapper around notification callback class ThreadsafeCallback { public: ThreadsafeCallback(std::function const& notify_change); ThreadsafeCallback& operator=(std::function const& notify_change); void operator()() const; private: ThreadsafeCallback(ThreadsafeCallback const&) = delete; ThreadsafeCallback& operator =(ThreadsafeCallback const&) = delete; std::mutex mutable mutex; std::function notify_change; }; class SurfaceObservers : public SurfaceObserver { public: void attrib_change(MirSurfaceAttrib attrib, int value) override; void resize(geometry::Size const& size) override; void add(std::shared_ptr const& observer); void remove(std::shared_ptr const& observer); private: std::mutex mutex; std::vector> observers; }; class BasicSurface : public Surface { public: BasicSurface( std::string const& name, geometry::Rectangle rect, bool nonrectangular, std::shared_ptr const& buffer_stream, std::shared_ptr const& input_channel, std::shared_ptr const& configurator, std::shared_ptr const& report); ~BasicSurface() noexcept; std::string name() const override; void move_to(geometry::Point const& top_left) override; float alpha() const override; void set_hidden(bool is_hidden); geometry::Size size() const override; MirPixelFormat pixel_format() const; std::shared_ptr snapshot_buffer() const; void swap_buffers(graphics::Buffer* old_buffer, std::function complete); void force_requests_to_complete(); bool supports_input() const; int client_input_fd() const; void allow_framedropping(bool); std::shared_ptr input_channel() const override; void on_change(std::function change_notification) override; void set_input_region(std::vector const& input_rectangles) override; std::shared_ptr buffer_stream() const; void resize(geometry::Size const& size) override; geometry::Point top_left() const override; bool contains(geometry::Point const& point) const override; void frame_posted(); void set_alpha(float alpha) override; void set_transformation(glm::mat4 const&) override; glm::mat4 transformation() const override; bool visible() const; bool shaped() const override; // meaning the pixel format has alpha // Renderable interface std::shared_ptr buffer(void const*) const override; bool alpha_enabled() const override; geometry::Rectangle screen_position() const override; int buffers_ready_for_compositor() const override; void with_most_recent_buffer_do( std::function const& exec) override; MirSurfaceType type() const override; MirSurfaceState state() const override; void take_input_focus(std::shared_ptr const& targeter) override; int configure(MirSurfaceAttrib attrib, int value) override; void hide() override; void show() override; void add_observer(std::shared_ptr const& observer) override; void remove_observer(std::shared_ptr const& observer) override; private: bool set_type(MirSurfaceType t); // Use configure() to make public changes bool set_state(MirSurfaceState s); SurfaceObservers observers; std::mutex mutable guard; ThreadsafeCallback notify_change; std::string const surface_name; geometry::Rectangle surface_rect; glm::mat4 transformation_matrix; float surface_alpha; bool first_frame_posted; bool hidden; const bool nonrectangular; std::vector input_rectangles; std::shared_ptr const surface_buffer_stream; std::shared_ptr const server_input_channel; std::shared_ptr const configurator; std::shared_ptr const report; MirSurfaceType type_value; MirSurfaceState state_value; }; } } #endif // MIR_SCENE_BASIC_SURFACE_H_ mir-0.1.8+14.04.20140411/src/server/scene/default_session_container.cpp0000644000015301777760000000436612322054223026034 0ustar pbusernogroup00000000000000/* * 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 */ #include "default_session_container.h" #include #include #include #include #include namespace ms = mir::scene; namespace msh = mir::shell; void ms::DefaultSessionContainer::insert_session(std::shared_ptr const& session) { std::unique_lock lk(guard); apps.push_back(session); } void ms::DefaultSessionContainer::remove_session(std::shared_ptr const& session) { std::unique_lock lk(guard); auto it = std::find(apps.begin(), apps.end(), session); if (it != apps.end()) { apps.erase(it); } else { BOOST_THROW_EXCEPTION(std::logic_error("Invalid Session")); } } void ms::DefaultSessionContainer::for_each(std::function const&)> f) const { std::unique_lock lk(guard); for (auto const ptr : apps) { f(ptr); } } std::shared_ptr ms::DefaultSessionContainer::successor_of(std::shared_ptr const& session) const { std::shared_ptr result, first; if (!session && apps.size()) return apps.back(); else if(!session) return std::shared_ptr(); for (auto it = apps.begin(); it != apps.end(); it++) { if (*it == session) { auto successor = ++it; if (successor == apps.end()) return *apps.begin(); else return *successor; } } BOOST_THROW_EXCEPTION(std::logic_error("Invalid session")); } mir-0.1.8+14.04.20140411/src/server/scene/CMakeLists.txt0000644000015301777760000000063112322054247022634 0ustar pbusernogroup00000000000000ADD_LIBRARY( mirscene STATIC application_session.cpp basic_surface.cpp broadcasting_session_event_sink.cpp default_configuration.cpp default_session_container.cpp gl_pixel_buffer.cpp global_event_sender.cpp mediating_display_changer.cpp session_manager.cpp surface_allocator.cpp surface_stack.cpp surface_controller.cpp surface_event_source.cpp threaded_snapshot_strategy.cpp ) mir-0.1.8+14.04.20140411/src/server/scene/session_manager.cpp0000644000015301777760000001256312322054223023756 0ustar pbusernogroup00000000000000/* * 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: Thomas Voss */ #include "session_manager.h" #include "application_session.h" #include "session_container.h" #include "mir/shell/surface_factory.h" #include "mir/shell/focus_setter.h" #include "mir/shell/session.h" #include "mir/shell/surface.h" #include "mir/shell/session_listener.h" #include "session_event_sink.h" #include #include #include namespace mf = mir::frontend; namespace ms = mir::scene; namespace msh = mir::shell; ms::SessionManager::SessionManager(std::shared_ptr const& surface_factory, std::shared_ptr const& container, std::shared_ptr const& focus_setter, std::shared_ptr const& snapshot_strategy, std::shared_ptr const& session_event_sink, std::shared_ptr const& session_listener) : surface_factory(surface_factory), app_container(container), focus_setter(focus_setter), snapshot_strategy(snapshot_strategy), session_event_sink(session_event_sink), session_listener(session_listener) { assert(surface_factory); assert(container); assert(focus_setter); assert(session_listener); } ms::SessionManager::~SessionManager() { /* * Close all open sessions. We need to do this manually here * to break the cyclic dependency between msh::Session * and mi::*, since our implementations * of these interfaces keep strong references to each other. * TODO: Investigate other solutions (e.g. weak_ptr) */ std::vector> sessions; app_container->for_each([&](std::shared_ptr const& session) { sessions.push_back(session); }); for (auto& session : sessions) close_session(session); } std::shared_ptr ms::SessionManager::open_session( pid_t client_pid, std::string const& name, std::shared_ptr const& sender) { std::shared_ptr new_session = std::make_shared( surface_factory, client_pid, name, snapshot_strategy, session_listener, sender); app_container->insert_session(new_session); session_listener->starting(new_session); set_focus_to(new_session); return new_session; } inline void ms::SessionManager::set_focus_to_locked(std::unique_lock const&, std::shared_ptr const& shell_session) { auto old_focus = focus_application.lock(); focus_application = shell_session; focus_setter->set_focus_to(shell_session); if (shell_session) { session_event_sink->handle_focus_change(shell_session); session_listener->focused(shell_session); } else { session_event_sink->handle_no_focus(); session_listener->unfocused(); } } void ms::SessionManager::set_focus_to(std::shared_ptr const& shell_session) { std::unique_lock lg(mutex); set_focus_to_locked(lg, shell_session); } void ms::SessionManager::close_session(std::shared_ptr const& session) { auto shell_session = std::dynamic_pointer_cast(session); shell_session->force_requests_to_complete(); session_event_sink->handle_session_stopping(shell_session); session_listener->stopping(shell_session); app_container->remove_session(shell_session); std::unique_lock lock(mutex); set_focus_to_locked(lock, app_container->successor_of(std::shared_ptr())); } void ms::SessionManager::focus_next() { std::unique_lock lock(mutex); auto focus = focus_application.lock(); if (!focus) { focus = app_container->successor_of(std::shared_ptr()); } else { focus = app_container->successor_of(focus); } set_focus_to_locked(lock, focus); } std::weak_ptr ms::SessionManager::focussed_application() const { return focus_application; } // TODO: We use this to work around the lack of a SessionMediator-like object for internal clients. // we could have an internal client mediator which acts as a factory for internal clients, taking responsibility // for invoking handle_surface_created. mf::SurfaceId ms::SessionManager::create_surface_for(std::shared_ptr const& session, msh::SurfaceCreationParameters const& params) { auto shell_session = std::dynamic_pointer_cast(session); auto id = shell_session->create_surface(params); handle_surface_created(session); return id; } void ms::SessionManager::handle_surface_created(std::shared_ptr const& session) { auto shell_session = std::dynamic_pointer_cast(session); set_focus_to(shell_session); } mir-0.1.8+14.04.20140411/src/server/scene/gl_pixel_buffer.h0000644000015301777760000000324712322054223023401 0ustar pbusernogroup00000000000000/* * 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_GL_PIXEL_BUFFER_H_ #define MIR_SCENE_GL_PIXEL_BUFFER_H_ #include "pixel_buffer.h" #include #include #include namespace mir { namespace graphics { class Buffer; class GLContext; } namespace scene { /** Extracts the pixels from a graphics::Buffer using GL facilities. */ class GLPixelBuffer : public PixelBuffer { public: GLPixelBuffer(std::unique_ptr gl_context); ~GLPixelBuffer() noexcept; void fill_from(graphics::Buffer& buffer); void const* as_argb_8888(); geometry::Size size() const; geometry::Stride stride() const; private: void prepare(); void copy_and_convert_pixel_line(char* src, char* dst); std::unique_ptr const gl_context; GLuint tex; GLuint fbo; std::vector pixels; GLuint gl_pixel_format; bool pixels_need_y_flip; geometry::Size size_; geometry::Stride stride_; }; } } #endif /* MIR_SCENE_GL_PIXEL_BUFFER_H_ */ mir-0.1.8+14.04.20140411/src/server/scene/default_session_container.h0000644000015301777760000000266412322054223025500 0ustar pbusernogroup00000000000000/* * 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_SCENE_DEFAULT_SESSION_CONTAINER_H_ #define MIR_SCENE_DEFAULT_SESSION_CONTAINER_H_ #include #include #include #include "session_container.h" namespace mir { namespace scene { class DefaultSessionContainer : public SessionContainer { public: void insert_session(std::shared_ptr const& session); void remove_session(std::shared_ptr const& session); void for_each(std::function const&)> f) const; std::shared_ptr successor_of(std::shared_ptr const& session) const; private: std::vector> apps; mutable std::mutex guard; }; } } #endif // MIR_SCENE_DEFAULT_SESSION_CONTAINER_H_ mir-0.1.8+14.04.20140411/src/server/scene/broadcasting_session_event_sink.cpp0000644000015301777760000000551712322054223027232 0ustar pbusernogroup00000000000000/* * 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 */ #include "broadcasting_session_event_sink.h" namespace ms = mir::scene; namespace msh = mir::shell; /* * TODO: Use Boost.Signals2 for this when we default to Boost 1.54, see * https://svn.boost.org/trac/boost/ticket/8102 . For now, just use a custom * mechanism with coarse locking. When emitting events, we copy the handlers * to a temporary vector to avoid calling handlers while locked, while still * being thread-safe. */ void ms::BroadcastingSessionEventSink::handle_focus_change( std::shared_ptr const& session) { std::vector const&)>> handlers; { std::lock_guard lg{handler_mutex}; handlers = focus_change_handlers; } for (auto& handler : handlers) handler(session); } void ms::BroadcastingSessionEventSink::handle_no_focus() { std::vector> handlers; { std::lock_guard lg{handler_mutex}; handlers = no_focus_handlers; } for (auto& handler : handlers) handler(); } void ms::BroadcastingSessionEventSink::handle_session_stopping( std::shared_ptr const& session) { std::vector const&)>> handlers; { std::lock_guard lg{handler_mutex}; handlers = session_stopping_handlers; } for (auto& handler : handlers) handler(session); } void ms::BroadcastingSessionEventSink::register_focus_change_handler( std::function const& session)> const& handler) { std::lock_guard lg{handler_mutex}; focus_change_handlers.push_back(handler); } void ms::BroadcastingSessionEventSink::register_no_focus_handler( std::function const& handler) { std::lock_guard lg{handler_mutex}; no_focus_handlers.push_back(handler); } void ms::BroadcastingSessionEventSink::register_session_stopping_handler( std::function const& session)> const& handler) { std::lock_guard lg{handler_mutex}; session_stopping_handlers.push_back(handler); } mir-0.1.8+14.04.20140411/src/server/scene/surface_stack.h0000644000015301777760000000577612322054247023101 0ustar pbusernogroup00000000000000/* * 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_SCENE_SCENETACK_H_ #define MIR_SCENE_SCENETACK_H_ #include "surface_stack_model.h" #include "mir/compositor/scene.h" #include "mir/scene/depth_id.h" #include "mir/input/input_targets.h" #include #include #include #include namespace mir { namespace compositor { class FilterForScene; class OperatorForScene; } namespace frontend { struct SurfaceCreationParameters; } namespace input { class InputChannelFactory; class InputChannel; } /// Management of Surface objects. Includes the model (SurfaceStack and Surface /// classes) and controller (SurfaceController) elements of an MVC design. namespace scene { class InputRegistrar; class BasicSurface; class SceneReport; class SurfaceStack : public compositor::Scene, public input::InputTargets, public SurfaceStackModel { public: explicit SurfaceStack( std::shared_ptr const& input_registrar, std::shared_ptr const& report); virtual ~SurfaceStack() noexcept(true) {} // From Scene graphics::RenderableList generate_renderable_list() const; virtual void set_change_callback(std::function const& f); //to be deprecated virtual void for_each_if(compositor::FilterForScene &filter, compositor::OperatorForScene &op); virtual void lock(); virtual void unlock(); //end to be deprecated // From InputTargets void for_each(std::function const&)> const& callback); virtual void remove_surface(std::weak_ptr const& surface) override; virtual void raise(std::weak_ptr const& surface) override; void add_surface( std::shared_ptr const& surface, DepthId depth, input::InputReceptionMode input_mode) override; private: SurfaceStack(const SurfaceStack&) = delete; SurfaceStack& operator=(const SurfaceStack&) = delete; void emit_change_notification(); std::recursive_mutex mutable guard; std::shared_ptr const input_registrar; std::shared_ptr const report; std::function const change_cb; typedef std::vector> Layer; std::map layers_by_depth; std::mutex notify_change_mutex; std::function notify_change; }; } } #endif /* MIR_SCENE_SCENETACK_H_ */ mir-0.1.8+14.04.20140411/src/server/scene/global_event_sender.cpp0000644000015301777760000000300412322054223024570 0ustar pbusernogroup00000000000000/* * 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 */ #include "global_event_sender.h" #include "session_container.h" #include "mir/shell/session.h" namespace mg=mir::graphics; namespace ms=mir::scene; namespace msh=mir::shell; ms::GlobalEventSender::GlobalEventSender(std::shared_ptr const& session_container) : sessions(session_container) { } void ms::GlobalEventSender::handle_event(MirEvent const&) { //TODO, no driving test cases, although messages like 'server shutdown' could go here } void ms::GlobalEventSender::handle_lifecycle_event(MirLifecycleState) { // Lifecycle events are per application session, never global } void ms::GlobalEventSender::handle_display_config_change(mg::DisplayConfiguration const& config) { sessions->for_each([&config](std::shared_ptr const& session) { session->send_display_config(config); }); } mir-0.1.8+14.04.20140411/src/server/graphics/0000755000015301777760000000000012322054703020574 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/graphics/default_configuration.cpp0000644000015301777760000001264312322054247025664 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/default_server_configuration.h" #include "mir/options/configuration.h" #include "mir/options/option.h" #include "default_display_configuration_policy.h" #include "nested/host_connection.h" #include "nested/nested_platform.h" #include "offscreen/display.h" #include "mir/graphics/buffer_initializer.h" #include "mir/graphics/gl_config.h" #include "mir/shared_library.h" #include "mir/shared_library_loader.h" #include "mir/abnormal_exit.h" #include #include namespace mg = mir::graphics; std::shared_ptr mir::DefaultServerConfiguration::the_buffer_initializer() { return buffer_initializer( []() { return std::make_shared(); }); } std::shared_ptr mir::DefaultServerConfiguration::the_display_configuration_policy() { return display_configuration_policy( [] { return std::make_shared(); }); } std::shared_ptr mir::DefaultServerConfiguration::the_graphics_platform() { return graphics_platform( [this]()->std::shared_ptr { auto graphics_lib = mir::load_library(the_options()->get(options::platform_graphics_lib)); if (!the_options()->is_set(options::host_socket_opt)) { // fallback to standalone if host socket is unset auto create_platform = graphics_lib->load_function("create_platform"); return create_platform(the_options(), the_display_report()); } auto create_native_platform = graphics_lib->load_function("create_native_platform"); return std::make_shared( the_host_connection(), the_nested_event_filter(), the_display_report(), create_native_platform(the_display_report())); }); } std::shared_ptr mir::DefaultServerConfiguration::the_buffer_allocator() { return buffer_allocator( [&]() { return the_graphics_platform()->create_buffer_allocator(the_buffer_initializer()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_display() { return display( [this]() -> std::shared_ptr { if (the_options()->is_set(options::offscreen_opt)) { return std::make_shared( the_graphics_platform(), the_display_configuration_policy(), the_display_report()); } else { return the_graphics_platform()->create_display( the_display_configuration_policy(), the_gl_config()); } }); } auto mir::DefaultServerConfiguration::the_host_connection() -> std::shared_ptr { return host_connection( [this]() -> std::shared_ptr { auto const options = the_options(); if (!options->is_set(options::host_socket_opt)) BOOST_THROW_EXCEPTION(mir::AbnormalExit( std::string("Exiting Mir! Reason: Nested Mir needs either $MIR_SOCKET or --") + options::host_socket_opt)); auto host_socket = options->get(options::host_socket_opt); std::string server_socket{"none"}; if (!the_options()->is_set(options::no_server_socket_opt)) { server_socket = the_socket_file(); if (server_socket == host_socket) BOOST_THROW_EXCEPTION(mir::AbnormalExit( "Exiting Mir! Reason: Nested Mir and Host Mir cannot use " "the same socket file to accept connections!")); } auto const my_name = options->is_set(options::name_opt) ? options->get(options::name_opt) : "nested-mir@:" + server_socket; return std::make_shared( host_socket, my_name); }); } std::shared_ptr mir::DefaultServerConfiguration::the_gl_config() { return gl_config( [this] { struct NoGLConfig : public mg::GLConfig { int depth_buffer_bits() const override { return 0; } int stencil_buffer_bits() const override { return 0; } }; return std::make_shared(); }); } mir-0.1.8+14.04.20140411/src/server/graphics/offscreen/0000755000015301777760000000000012322054703022546 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/graphics/offscreen/display.cpp0000644000015301777760000001136612322054223024723 0ustar pbusernogroup00000000000000/* * 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 */ #include "display.h" #include "display_buffer.h" #include "mir/graphics/basic_platform.h" #include "mir/graphics/display_configuration_policy.h" #include "mir/geometry/size.h" #include #include namespace mg = mir::graphics; namespace mgo = mg::offscreen; namespace geom = mir::geometry; namespace { mgo::detail::EGLDisplayHandle create_and_initialize_display(mg::BasicPlatform& basic_platform) { mgo::detail::EGLDisplayHandle egl_display{ basic_platform.egl_native_display()}; egl_display.initialize(); return egl_display; } } mgo::detail::EGLDisplayHandle::EGLDisplayHandle(EGLNativeDisplayType native_display) : egl_display{eglGetDisplay(native_display)} { if (egl_display == EGL_NO_DISPLAY) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to get EGL display")); } mgo::detail::EGLDisplayHandle::EGLDisplayHandle(EGLDisplayHandle&& other) : egl_display{other.egl_display} { other.egl_display = EGL_NO_DISPLAY; } void mgo::detail::EGLDisplayHandle::initialize() { int major, minor; if (eglInitialize(egl_display, &major, &minor) == EGL_FALSE) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize EGL")); if ((major != 1) || (minor != 4)) BOOST_THROW_EXCEPTION(std::runtime_error("EGL version 1.4 needed")); } mgo::detail::EGLDisplayHandle::~EGLDisplayHandle() noexcept { if (egl_display != EGL_NO_DISPLAY) eglTerminate(egl_display); } mgo::Display::Display( std::shared_ptr const& basic_platform, std::shared_ptr const& initial_conf_policy, std::shared_ptr const&) : basic_platform{basic_platform}, egl_display{create_and_initialize_display(*basic_platform)}, egl_context_shared{egl_display, EGL_NO_CONTEXT}, current_display_configuration{geom::Size{1024,768}} { /* * Make the shared context current. This needs to be done before we configure() * since mgo::DisplayBuffer creation needs a current GL context. */ egl_context_shared.make_current(); initial_conf_policy->apply_to(current_display_configuration); configure(current_display_configuration); } mgo::Display::~Display() noexcept { } void mgo::Display::for_each_display_buffer( std::function const& f) { std::lock_guard lock{configuration_mutex}; for (auto& db_ptr : display_buffers) f(*db_ptr); } std::unique_ptr mgo::Display::configuration() const { std::lock_guard lock{configuration_mutex}; return std::unique_ptr( new mgo::DisplayConfiguration(current_display_configuration) ); } void mgo::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}; display_buffers.clear(); conf.for_each_output( [this] (DisplayConfigurationOutput const& output) { if (output.connected && output.preferred_mode_index < output.modes.size()) { auto raw_db = new mgo::DisplayBuffer{ SurfacelessEGLContext{egl_display, egl_context_shared}, output.extents()}; display_buffers.push_back(std::unique_ptr(raw_db)); } }); } void mgo::Display::register_configuration_change_handler( EventHandlerRegister&, DisplayConfigurationChangeHandler const&) { } void mgo::Display::register_pause_resume_handlers( EventHandlerRegister&, DisplayPauseHandler const&, DisplayResumeHandler const&) { } void mgo::Display::pause() { } void mgo::Display::resume() { } std::weak_ptr mgo::Display::the_cursor() { return {}; } std::unique_ptr mgo::Display::create_gl_context() { return std::unique_ptr{ new SurfacelessEGLContext{egl_display, egl_context_shared}}; } mir-0.1.8+14.04.20140411/src/server/graphics/offscreen/display_configuration.h0000644000015301777760000000303612322054223027312 0ustar pbusernogroup00000000000000/* * 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 . */ #ifndef MIR_GRAPHICS_OFFSCREEN_DISPLAY_CONFIGURATION_H_ #define MIR_GRAPHICS_OFFSCREEN_DISPLAY_CONFIGURATION_H_ #include "mir/graphics/display_configuration.h" namespace mir { namespace graphics { namespace offscreen { class DisplayConfiguration : public graphics::DisplayConfiguration { public: DisplayConfiguration(geometry::Size const& display_size); DisplayConfiguration(DisplayConfiguration const& other); DisplayConfiguration& operator=(DisplayConfiguration const& other); 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; private: DisplayConfigurationOutput output; DisplayConfigurationCard card; }; } } } #endif /* MIR_GRAPHICS_OFFSCREEN_DISPLAY_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/src/server/graphics/offscreen/display_configuration.cpp0000644000015301777760000000440012322054223027641 0ustar pbusernogroup00000000000000/* * 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 . */ #include "display_configuration.h" namespace mg = mir::graphics; namespace mgo = mg::offscreen; namespace geom = mir::geometry; mgo::DisplayConfiguration::DisplayConfiguration(geom::Size const& display_size) : output{mg::DisplayConfigurationOutputId{1}, mg::DisplayConfigurationCardId{0}, mg::DisplayConfigurationOutputType::lvds, {mir_pixel_format_xrgb_8888}, {mg::DisplayConfigurationMode{display_size,0.0f}}, 0, geom::Size{0,0}, true, true, geom::Point{0,0}, 0, mir_pixel_format_xrgb_8888, mir_power_mode_on, mir_orientation_normal}, card{mg::DisplayConfigurationCardId{0}, 1} { } mgo::DisplayConfiguration::DisplayConfiguration(DisplayConfiguration const& other) : mg::DisplayConfiguration(), output(other.output), card(other.card) { } mgo::DisplayConfiguration& mgo::DisplayConfiguration::operator=(DisplayConfiguration const& other) { if (&other != this) { output = other.output; card = other.card; } return *this; } void mgo::DisplayConfiguration::for_each_card( std::function f) const { f(card); } void mgo::DisplayConfiguration::for_each_output( std::function f) const { f(output); } void mgo::DisplayConfiguration::for_each_output( std::function f) { mg::UserDisplayConfigurationOutput user(output); f(user); } mir-0.1.8+14.04.20140411/src/server/graphics/offscreen/display_buffer.h0000644000015301777760000000411512322054247025721 0ustar pbusernogroup00000000000000/* * 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_GRAPHICS_OFFSCREEN_DISPLAY_BUFFER_H_ #define MIR_GRAPHICS_OFFSCREEN_DISPLAY_BUFFER_H_ #include "mir/graphics/surfaceless_egl_context.h" #include "mir/graphics/display_buffer.h" #include "mir/geometry/size.h" #include "mir/geometry/rectangle.h" #include namespace mir { namespace graphics { namespace offscreen { namespace detail { class GLFramebufferObject { public: GLFramebufferObject(geometry::Size const& size); ~GLFramebufferObject(); void bind() const; void unbind() const; private: geometry::Size const size; int old_fbo; int old_viewport[4]; unsigned int color_renderbuffer; unsigned int depth_renderbuffer; unsigned int fbo; }; } class DisplayBuffer : public graphics::DisplayBuffer { public: DisplayBuffer(SurfacelessEGLContext egl_context, geometry::Rectangle const& area); geometry::Rectangle view_area() const; void make_current(); void release_current(); void post_update(); bool can_bypass() const; MirOrientation orientation() const override; void render_and_post_update( RenderableList const& renderlist, std::function const& render_fn); private: SurfacelessEGLContext const egl_context; detail::GLFramebufferObject const fbo; geometry::Rectangle const area; }; } } } #endif /* MIR_GRAPHICS_OFFSCREEN_DISPLAY_BUFFER_H_ */ mir-0.1.8+14.04.20140411/src/server/graphics/offscreen/CMakeLists.txt0000644000015301777760000000023612322054223025304 0ustar pbusernogroup00000000000000add_library( miroffscreengraphics STATIC display.cpp display_configuration.cpp display_buffer.cpp ) target_link_libraries( miroffscreengraphics ) mir-0.1.8+14.04.20140411/src/server/graphics/offscreen/display.h0000644000015301777760000000557212322054223024372 0ustar pbusernogroup00000000000000/* * 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_GRAPHICS_OFFSCREEN_DISPLAY_H_ #define MIR_GRAPHICS_OFFSCREEN_DISPLAY_H_ #include "mir/graphics/display.h" #include "display_configuration.h" #include "mir/graphics/surfaceless_egl_context.h" #include #include #include namespace mir { namespace graphics { class BasicPlatform; class DisplayConfigurationPolicy; class DisplayReport; namespace offscreen { namespace detail { class EGLDisplayHandle { public: explicit EGLDisplayHandle(EGLNativeDisplayType native_type); EGLDisplayHandle(EGLDisplayHandle&&); ~EGLDisplayHandle() noexcept; void initialize(); operator EGLDisplay() const { return egl_display; } private: EGLDisplayHandle(EGLDisplayHandle const&) = delete; EGLDisplayHandle operator=(EGLDisplayHandle const&) = delete; EGLDisplay egl_display; }; } class Display : public graphics::Display { public: Display(std::shared_ptr const& basic_platform, std::shared_ptr const& initial_conf_policy, std::shared_ptr const& listener); ~Display() noexcept; void for_each_display_buffer(std::function const& f); std::unique_ptr configuration() const override; void configure(graphics::DisplayConfiguration const& conf) override; void register_configuration_change_handler( EventHandlerRegister& handlers, DisplayConfigurationChangeHandler const& conf_change_handler); void register_pause_resume_handlers( EventHandlerRegister& handlers, DisplayPauseHandler const& pause_handler, DisplayResumeHandler const& resume_handler); void pause(); void resume(); std::weak_ptr the_cursor(); std::unique_ptr create_gl_context(); private: std::shared_ptr const basic_platform; detail::EGLDisplayHandle const egl_display; SurfacelessEGLContext const egl_context_shared; mutable std::mutex configuration_mutex; DisplayConfiguration current_display_configuration; std::vector> display_buffers; }; } } } #endif /* MIR_GRAPHICS_OFFSCREEN_DISPLAY_H_ */ mir-0.1.8+14.04.20140411/src/server/graphics/offscreen/display_buffer.cpp0000644000015301777760000001107412322054247026256 0ustar pbusernogroup00000000000000/* * 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 */ #include "display_buffer.h" #include "mir/graphics/gl_extensions_base.h" #include "mir/raii.h" #include #include #include #include namespace mg = mir::graphics; namespace mgo = mg::offscreen; namespace geom = mir::geometry; namespace { class GLExtensions : public mg::GLExtensionsBase { public: GLExtensions() : mg::GLExtensionsBase{ reinterpret_cast(glGetString(GL_EXTENSIONS))} { } }; } mgo::detail::GLFramebufferObject::GLFramebufferObject(geom::Size const& size) : size{size}, color_renderbuffer{0}, depth_renderbuffer{0}, fbo{0} { /* Save previous FBO state */ glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo); glGetIntegerv(GL_VIEWPORT, old_viewport); GLExtensions const extensions; GLenum gl_color_format{GL_RGBA4}; GLenum const gl_depth_format{GL_DEPTH_COMPONENT16}; if (extensions.support("GL_ARM_rgba8") || extensions.support("GL_OES_rgb8_rgba8")) { gl_color_format = GL_RGBA8_OES; } /* Create a renderbuffer for the color attachment */ glGenRenderbuffers(1, &color_renderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, color_renderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, gl_color_format, size.width.as_int(), size.height.as_int()); /* Create a renderbuffer for the depth attachment */ glGenRenderbuffers(1, &depth_renderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, depth_renderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, gl_depth_format, size.width.as_int(), size.height.as_int()); /* Create a FBO and set it up */ glGenFramebuffers(1, &fbo); auto const fbo_raii = mir::raii::paired_calls( [this] { glBindFramebuffer(GL_FRAMEBUFFER, fbo); }, [this] { glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); }); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color_renderbuffer); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_renderbuffer); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to set up FBO")); } mgo::detail::GLFramebufferObject::~GLFramebufferObject() { if (fbo) glDeleteFramebuffers(1, &fbo); if (color_renderbuffer) glDeleteRenderbuffers(1, &color_renderbuffer); if (depth_renderbuffer) glDeleteRenderbuffers(1, &depth_renderbuffer); } void mgo::detail::GLFramebufferObject::bind() const { glBindFramebuffer(GL_FRAMEBUFFER, fbo); glViewport(0, 0, size.width.as_int(), size.height.as_int()); } void mgo::detail::GLFramebufferObject::unbind() const { glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]); } mgo::DisplayBuffer::DisplayBuffer(SurfacelessEGLContext egl_context, geom::Rectangle const& area) : egl_context{std::move(egl_context)}, fbo{area.size}, area(area) { } geom::Rectangle mgo::DisplayBuffer::view_area() const { return area; } void mgo::DisplayBuffer::make_current() { egl_context.make_current(); fbo.bind(); } void mgo::DisplayBuffer::release_current() { fbo.unbind(); egl_context.release_current(); } void mgo::DisplayBuffer::post_update() { glFinish(); } bool mgo::DisplayBuffer::can_bypass() const { return false; } void mgo::DisplayBuffer::render_and_post_update( RenderableList const&, std::function const&) { } MirOrientation mgo::DisplayBuffer::orientation() const { /* * The display buffer's already constructed with rotated dimensions, * so nothing more to do. */ return mir_orientation_normal; } mir-0.1.8+14.04.20140411/src/server/graphics/default_display_configuration_policy.h0000644000015301777760000000173012322054223030422 0ustar pbusernogroup00000000000000/* * 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 { class DefaultDisplayConfigurationPolicy : public DisplayConfigurationPolicy { public: void apply_to(DisplayConfiguration& conf); }; } } #endif /* MIR_GRAPHICS_DEFAULT_DISPLAY_CONFIGURATION_POLICY_H_ */ mir-0.1.8+14.04.20140411/src/server/graphics/gl_extensions_base.cpp0000644000015301777760000000262512322054223025155 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/gl_extensions_base.h" #include #include #include namespace mg = mir::graphics; mg::GLExtensionsBase::GLExtensionsBase(char const* extensions) : extensions{extensions} { if (!extensions) { BOOST_THROW_EXCEPTION( std::runtime_error("Couldn't get list of GL extensions")); } } bool mg::GLExtensionsBase::support(char const* ext) const { char const* ext_ptr = extensions; size_t const len = strlen(ext); while ((ext_ptr = strstr(ext_ptr, ext)) != nullptr) { if (ext_ptr[len] == ' ' || ext_ptr[len] == '\0') break; ext_ptr += len; } return ext_ptr != nullptr; } mir-0.1.8+14.04.20140411/src/server/graphics/CMakeLists.txt0000644000015301777760000000041012322054223023324 0ustar pbusernogroup00000000000000include_directories(${GLESv2_INCLUDE_DIRS}) add_library( mirgraphics STATIC default_configuration.cpp default_display_configuration_policy.cpp gl_extensions_base.cpp surfaceless_egl_context.cpp ) add_subdirectory(nested/) add_subdirectory(offscreen/) mir-0.1.8+14.04.20140411/src/server/graphics/nested/0000755000015301777760000000000012322054703022056 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/graphics/nested/nested_platform.h0000644000015301777760000000433512322054247025425 0ustar pbusernogroup00000000000000/* * 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: Eleni Maria Stea */ #ifndef MIR_GRAPHICS_NESTED_NESTED_PLATFORM_H_ #define MIR_GRAPHICS_NESTED_NESTED_PLATFORM_H_ #include "mir/graphics/platform.h" #include "mir/graphics/native_platform.h" #include "host_connection.h" namespace mir { namespace input { class EventFilter; } namespace graphics { namespace nested { class NestedPlatform : public Platform { public: NestedPlatform( std::shared_ptr const& connection, std::shared_ptr const& event_handler, std::shared_ptr const& display_report, std::shared_ptr const& native_platform); ~NestedPlatform() noexcept; std::shared_ptr create_buffer_allocator( std::shared_ptr const& buffer_initializer) override; std::shared_ptr create_display( std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config); std::shared_ptr get_ipc_package() override; std::shared_ptr create_internal_client() override; void fill_ipc_package(BufferIPCPacker* packer, Buffer const* Buffer) const override; EGLNativeDisplayType egl_native_display() const; private: std::shared_ptr const native_platform; std::shared_ptr const event_handler; std::shared_ptr const display_report; std::shared_ptr const connection; }; } } } #endif // MIR_GRAPHICS_NESTED_NESTED_PLATFORM_H mir-0.1.8+14.04.20140411/src/server/graphics/nested/nested_display_configuration.cpp0000644000015301777760000001326012322054223030517 0ustar pbusernogroup00000000000000/* * 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: Eleni Maria Stea */ #include "nested_display_configuration.h" #include "mir/graphics/pixel_format_utils.h" #include #include #include namespace mg = mir::graphics; namespace mgn = mg::nested; mgn::NestedDisplayConfiguration::NestedDisplayConfiguration(MirDisplayConfiguration* connection) : display_config{connection} { } mgn::NestedDisplayConfiguration::~NestedDisplayConfiguration() noexcept { } void mgn::NestedDisplayConfiguration::for_each_card(std::function f) const { std::for_each( display_config->cards, display_config->cards+display_config->num_cards, [&f](MirDisplayCard const& mir_card) { f({DisplayConfigurationCardId(mir_card.card_id), mir_card.max_simultaneous_outputs}); }); } void mgn::NestedDisplayConfiguration::for_each_output(std::function f) const { std::for_each( display_config->outputs, display_config->outputs+display_config->num_outputs, [&f](MirDisplayOutput const& mir_output) { std::vector formats; formats.reserve(mir_output.num_output_formats); for (auto p = mir_output.output_formats; p != mir_output.output_formats+mir_output.num_output_formats; ++p) formats.push_back(MirPixelFormat(*p)); std::vector modes; modes.reserve(mir_output.num_modes); for (auto p = mir_output.modes; p != mir_output.modes+mir_output.num_modes; ++p) modes.push_back(DisplayConfigurationMode{{p->horizontal_resolution, p->vertical_resolution}, p->refresh_rate}); DisplayConfigurationOutput const output{ DisplayConfigurationOutputId(mir_output.output_id), DisplayConfigurationCardId(mir_output.card_id), DisplayConfigurationOutputType(mir_output.type), std::move(formats), std::move(modes), mir_output.preferred_mode, geometry::Size{mir_output.physical_width_mm, mir_output.physical_height_mm}, !!mir_output.connected, !!mir_output.used, geometry::Point{mir_output.position_x, mir_output.position_y}, mir_output.current_mode, mir_output.current_format, mir_output.power_mode, mir_output.orientation }; f(output); }); } void mgn::NestedDisplayConfiguration::for_each_output( std::function f) { // This is mostly copied and pasted from the const version above, but this // mutable version copies user-changes to the output structure at the end. std::for_each( display_config->outputs, display_config->outputs+display_config->num_outputs, [&f](MirDisplayOutput& mir_output) { std::vector formats; formats.reserve(mir_output.num_output_formats); for (auto p = mir_output.output_formats; p != mir_output.output_formats+mir_output.num_output_formats; ++p) { formats.push_back(*p); } std::vector modes; modes.reserve(mir_output.num_modes); for (auto p = mir_output.modes; p != mir_output.modes+mir_output.num_modes; ++p) { modes.push_back( DisplayConfigurationMode{ {p->horizontal_resolution, p->vertical_resolution}, p->refresh_rate}); } DisplayConfigurationOutput output{ DisplayConfigurationOutputId(mir_output.output_id), DisplayConfigurationCardId(mir_output.card_id), DisplayConfigurationOutputType(mir_output.type), std::move(formats), std::move(modes), mir_output.preferred_mode, geometry::Size{mir_output.physical_width_mm, mir_output.physical_height_mm}, !!mir_output.connected, !!mir_output.used, geometry::Point{mir_output.position_x, mir_output.position_y}, mir_output.current_mode, mir_output.current_format, mir_output.power_mode, mir_output.orientation }; UserDisplayConfigurationOutput user(output); f(user); mir_output.current_mode = output.current_mode_index; mir_output.current_format = output.current_format; mir_output.position_x = output.top_left.x.as_int(); mir_output.position_y = output.top_left.y.as_int(); mir_output.used = output.used; mir_output.power_mode = output.power_mode; mir_output.orientation = output.orientation; }); } mir-0.1.8+14.04.20140411/src/server/graphics/nested/nested_display.cpp0000644000015301777760000002325712322054247025605 0ustar pbusernogroup00000000000000/* * 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: Eleni Maria Stea */ #include "nested_display.h" #include "nested_display_configuration.h" #include "nested_output.h" #include "mir_api_wrappers.h" #include "mir/geometry/rectangle.h" #include "mir/graphics/pixel_format_utils.h" #include "mir/graphics/gl_context.h" #include "mir/graphics/surfaceless_egl_context.h" #include "mir/graphics/display_configuration_policy.h" #include "mir/graphics/overlapping_output_grouping.h" #include "mir/graphics/gl_config.h" #include "host_connection.h" #include #include namespace mg = mir::graphics; namespace mgn = mir::graphics::nested; namespace mgnw = mir::graphics::nested::mir_api_wrappers; namespace geom = mir::geometry; EGLint const mgn::detail::nested_egl_context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; mgn::detail::EGLSurfaceHandle::EGLSurfaceHandle(EGLDisplay display, EGLNativeWindowType native_window, EGLConfig cfg) : egl_display(display), egl_surface(eglCreateWindowSurface(egl_display, cfg, native_window, NULL)) { if (egl_surface == EGL_NO_SURFACE) { BOOST_THROW_EXCEPTION(std::runtime_error("Nested Mir Display Error: Failed to create EGL surface.")); } } mgn::detail::EGLSurfaceHandle::~EGLSurfaceHandle() noexcept { eglDestroySurface(egl_display, egl_surface); } mgn::detail::EGLDisplayHandle::EGLDisplayHandle( MirConnection* connection, std::shared_ptr const& gl_config) : egl_display(EGL_NO_DISPLAY), egl_context_(EGL_NO_CONTEXT), gl_config{gl_config} { auto const native_display = (EGLNativeDisplayType) mir_connection_get_egl_native_display(connection); egl_display = eglGetDisplay(native_display); if (egl_display == EGL_NO_DISPLAY) BOOST_THROW_EXCEPTION(std::runtime_error("Nested Mir Display Error: Failed to fetch EGL display.")); } void mgn::detail::EGLDisplayHandle::initialize(MirPixelFormat format) { int major; int minor; if (eglInitialize(egl_display, &major, &minor) != EGL_TRUE) { BOOST_THROW_EXCEPTION(std::runtime_error("Nested Mir Display Error: Failed to initialize EGL.")); } egl_context_ = eglCreateContext(egl_display, choose_windowed_es_config(format), EGL_NO_CONTEXT, detail::nested_egl_context_attribs); if (egl_context_ == EGL_NO_CONTEXT) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create shared EGL context")); } EGLConfig mgn::detail::EGLDisplayHandle::choose_windowed_es_config(MirPixelFormat format) const { EGLint const nested_egl_config_attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, mg::red_channel_depth(format), EGL_GREEN_SIZE, mg::green_channel_depth(format), EGL_BLUE_SIZE, mg::blue_channel_depth(format), EGL_ALPHA_SIZE, mg::alpha_channel_depth(format), EGL_DEPTH_SIZE, gl_config->depth_buffer_bits(), EGL_STENCIL_SIZE, gl_config->stencil_buffer_bits(), EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLConfig result; int n; int res = eglChooseConfig(egl_display, nested_egl_config_attribs, &result, 1, &n); if ((res != EGL_TRUE) || (n != 1)) BOOST_THROW_EXCEPTION(std::runtime_error("Nested Mir Display Error: Failed to choose EGL configuration.")); return result; } EGLNativeWindowType mgn::detail::EGLDisplayHandle::native_window(EGLConfig /*egl_config*/, MirSurface* mir_surface) const { auto const native_window = reinterpret_cast(mir_surface_get_egl_native_window(mir_surface)); if (!native_window) BOOST_THROW_EXCEPTION(std::runtime_error("Nested Mir Display Error: Failed to fetch EGL native window.")); return native_window; } EGLContext mgn::detail::EGLDisplayHandle::egl_context() const { return egl_context_; } mgn::detail::EGLDisplayHandle::~EGLDisplayHandle() noexcept { eglTerminate(egl_display); } mgn::NestedDisplay::NestedDisplay( std::shared_ptr const& connection, std::shared_ptr const& event_handler, std::shared_ptr const& display_report, std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config) : connection{connection}, event_handler{event_handler}, display_report{display_report}, egl_display{*connection, gl_config}, outputs{} { std::shared_ptr conf(configuration()); initial_conf_policy->apply_to(*conf); configure(*conf); } mgn::NestedDisplay::~NestedDisplay() noexcept { } void mgn::NestedDisplay::for_each_display_buffer(std::function const& f) { std::unique_lock lock(outputs_mutex); for (auto& i : outputs) f(*i.second); } std::unique_ptr mgn::NestedDisplay::configuration() const { return std::unique_ptr( new NestedDisplayConfiguration( mir_connection_create_display_config(*connection) ) ); } void mgn::NestedDisplay::complete_display_initialization(MirPixelFormat format) { if (egl_display.egl_context() != EGL_NO_CONTEXT) return; egl_display.initialize(format); eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_display.egl_context()); } void mgn::NestedDisplay::configure(mg::DisplayConfiguration const& configuration) { if (!configuration.valid()) { BOOST_THROW_EXCEPTION(std::logic_error("Invalid or inconsistent display configuration")); } decltype(outputs) result; OverlappingOutputGrouping unique_outputs{configuration}; unique_outputs.for_each_group( [&](mg::OverlappingOutputGroup const& group) { bool have_output_for_group = false; geometry::Rectangle const& area = group.bounding_rectangle(); group.for_each_output([&](mg::DisplayConfigurationOutput output) { if (!have_output_for_group) { auto const& egl_config_format = output.current_format; complete_display_initialization(egl_config_format); MirSurfaceParameters const request_params = { "Mir nested display", area.size.width.as_int(), area.size.height.as_int(), egl_config_format, mir_buffer_usage_hardware, static_cast(output.id.as_value()) }; auto const mir_surface = mir_connection_create_surface_sync(*connection, &request_params); if (!mir_surface_is_valid(mir_surface)) BOOST_THROW_EXCEPTION( std::runtime_error(mir_surface_get_error_message(mir_surface))); result[output.id] = std::make_shared( egl_display, mir_surface, area, event_handler, output.current_format); have_output_for_group = true; } }); }); if (result.empty()) BOOST_THROW_EXCEPTION(std::runtime_error("Nested Mir needs at least one output for display")); auto const& conf = dynamic_cast(configuration); { std::unique_lock lock(outputs_mutex); outputs.swap(result); } mir_connection_apply_display_config(*connection, conf); } namespace { void display_config_callback_thunk(MirConnection* /*connection*/, void* context) { (*static_cast(context))(); } } void mgn::NestedDisplay::register_configuration_change_handler( EventHandlerRegister& /*handlers*/, DisplayConfigurationChangeHandler const& conf_change_handler) { mir_connection_set_display_config_change_callback( *connection, &display_config_callback_thunk, &(my_conf_change_handler = conf_change_handler)); } void mgn::NestedDisplay::register_pause_resume_handlers( EventHandlerRegister& /*handlers*/, DisplayPauseHandler const& /*pause_handler*/, DisplayResumeHandler const& /*resume_handler*/) { // No need to do anything } void mgn::NestedDisplay::pause() { // TODO Do we "own" the cursor or does the host mir? // If we "own" the cursor then we need to hide it } void mgn::NestedDisplay::resume() { // TODO Do we "own" the cursor or does the host mir? // TODO If we "own" the cursor then we need to restore it } auto mgn::NestedDisplay::the_cursor()->std::weak_ptr { // TODO Do we "own" the cursor or does the host mir? return std::weak_ptr(); } std::unique_ptr mgn::NestedDisplay::create_gl_context() { return std::unique_ptr{new SurfacelessEGLContext(egl_display, EGL_NO_CONTEXT)}; } mir-0.1.8+14.04.20140411/src/server/graphics/nested/host_connection.cpp0000644000015301777760000000204612322054223025755 0ustar pbusernogroup00000000000000/* * 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: Eleni Maria Stea */ #include "host_connection.h" #include "mir_toolkit/mir_client_library.h" namespace mgn = mir::graphics::nested; mgn::HostConnection::HostConnection(std::string const& host_socket, std::string const& name) : connection{mir_connect_sync(host_socket.c_str(), name.c_str())} { } mgn::HostConnection::~HostConnection() { mir_connection_release(connection); } mir-0.1.8+14.04.20140411/src/server/graphics/nested/mir_api_wrappers.h0000644000015301777760000000344012322054223025570 0ustar pbusernogroup00000000000000/* * 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_GRAPHICS_NESTED_MIR_API_WRAPPERS_H_ #define MIR_GRAPHICS_NESTED_MIR_API_WRAPPERS_H_ #include "mir_toolkit/mir_client_library.h" namespace mir { namespace graphics { namespace nested { /// Utilities for making the Mir "toolkit" API more C++ friendly namespace mir_api_wrappers { class MirDisplayConfigHandle { public: explicit MirDisplayConfigHandle(MirDisplayConfiguration* display_config) : display_config{display_config} { } explicit MirDisplayConfigHandle(MirConnection* connection) : MirDisplayConfigHandle{mir_connection_create_display_config(connection)} { } ~MirDisplayConfigHandle() noexcept { mir_display_config_destroy(display_config); } MirDisplayConfiguration* operator->() const { return display_config; } operator MirDisplayConfiguration*() const { return display_config; } private: MirDisplayConfiguration* const display_config; MirDisplayConfigHandle(MirDisplayConfigHandle const&) = delete; MirDisplayConfigHandle operator=(MirDisplayConfigHandle const&) = delete; }; } } } } #endif /* MIR_GRAPHICS_NESTED_MIR_API_WRAPPERS_H_ */ mir-0.1.8+14.04.20140411/src/server/graphics/nested/nested_output.h0000644000015301777760000000504312322054247025136 0ustar pbusernogroup00000000000000/* * 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_GRAPHICS_NESTED_DETAIL_NESTED_OUTPUT_H_ #define MIR_GRAPHICS_NESTED_DETAIL_NESTED_OUTPUT_H_ #include "nested_display.h" namespace mir { namespace graphics { namespace nested { namespace detail { class EGLSurfaceHandle; class MirSurfaceHandle { public: explicit MirSurfaceHandle(MirSurface* mir_surface); ~MirSurfaceHandle() noexcept; operator MirSurface*() const { return mir_surface; } private: MirSurface* mir_surface; MirSurfaceHandle(MirSurfaceHandle const&) = delete; MirSurfaceHandle operator=(MirSurfaceHandle const&) = delete; }; class NestedOutput : public DisplayBuffer { public: NestedOutput( EGLDisplayHandle const& egl_display, MirSurface* mir_surface, geometry::Rectangle const& area, std::shared_ptr const& event_handler, MirPixelFormat preferred_format); ~NestedOutput() noexcept; geometry::Rectangle view_area() const override; void make_current() override; void release_current() override; void post_update() override; virtual bool can_bypass() const override; MirOrientation orientation() const override; void render_and_post_update( RenderableList const& renderlist, std::function const& render_fn); NestedOutput(NestedOutput const&) = delete; NestedOutput operator=(NestedOutput const&) = delete; private: EGLDisplayHandle const& egl_display; MirSurfaceHandle const mir_surface; EGLConfig const egl_config; EGLContextStore const egl_context; geometry::Rectangle const area; std::shared_ptr const event_handler; EGLSurfaceHandle const egl_surface; static void event_thunk(MirSurface* surface, MirEvent const* event, void* context); void mir_event(MirEvent const& event); }; } } } } #endif /* MIR_GRAPHICS_NESTED_DETAIL_NESTED_OUTPUT_H_ */ mir-0.1.8+14.04.20140411/src/server/graphics/nested/host_connection.h0000644000015301777760000000247012322054223025423 0ustar pbusernogroup00000000000000/* * 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: Eleni Maria Stea */ #ifndef MIR_GRAPHICS_NESTED_HOST_CONNECTION_H_ #define MIR_GRAPHICS_NESTED_HOST_CONNECTION_H_ #include struct MirConnection; namespace mir { namespace graphics { namespace nested { class HostConnection { public: HostConnection(std::string const& host_socket, std::string const& name); ~HostConnection(); HostConnection(HostConnection const&) = delete; HostConnection& operator=(HostConnection const& connection_handle) = delete; operator MirConnection*() const {return (MirConnection*)connection;} private: MirConnection* const connection; }; } } } #endif // MIR_GRAPHICS_NESTED_HOST_CONNECTION_H_ mir-0.1.8+14.04.20140411/src/server/graphics/nested/CMakeLists.txt0000644000015301777760000000042212322054223024611 0ustar pbusernogroup00000000000000include_directories( ${PROJECT_SOURCE_DIR}/include/client ) add_library( mirnestedgraphics STATIC nested_display.cpp nested_display_configuration.cpp nested_output.cpp nested_platform.cpp host_connection.cpp ) target_link_libraries( mirnestedgraphics ) mir-0.1.8+14.04.20140411/src/server/graphics/nested/nested_display_configuration.h0000644000015301777760000000317012322054223030163 0ustar pbusernogroup00000000000000/* * 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: Eleni Maria Stea */ #ifndef MIR_GRAPHICS_NESTED_NESTED_DISPLAY_CONFIGURATION_H_ #define MIR_GRAPHICS_NESTED_NESTED_DISPLAY_CONFIGURATION_H_ #include "mir/graphics/display_configuration.h" #include "mir_api_wrappers.h" namespace mir { namespace graphics { namespace nested { class NestedDisplayConfiguration : public DisplayConfiguration { public: explicit NestedDisplayConfiguration(MirDisplayConfiguration* display_config); virtual ~NestedDisplayConfiguration() noexcept; void for_each_card(std::function) const override; void for_each_output(std::function) const override; void for_each_output(std::function) override; operator MirDisplayConfiguration*() const { return display_config; } private: mir_api_wrappers::MirDisplayConfigHandle display_config; }; } } } #endif // MIR_GRAPHICS_NESTED_NESTED_DISPLAY_CONFIGURATION_H_ mir-0.1.8+14.04.20140411/src/server/graphics/nested/nested_platform.cpp0000644000015301777760000001063612322054247025761 0ustar pbusernogroup00000000000000/* * 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: Eleni Maria Stea */ #include "nested_platform.h" #include "host_connection.h" #include "mir/graphics/nested_context.h" #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/mir_client_library_drm.h" #include "nested_display.h" #include #include #include namespace mg = mir::graphics; namespace mgn = mir::graphics::nested; namespace mo = mir::options; namespace { class MirConnectionNestedContext : public mg::NestedContext { public: MirConnectionNestedContext(std::shared_ptr const& connection) : connection{connection} { } std::vector platform_fd_items() { MirPlatformPackage pkg; mir_connection_get_platform(*connection, &pkg); return std::vector(pkg.fd, pkg.fd + pkg.fd_items); } void drm_auth_magic(int magic) { int status; mir_wait_for(mir_connection_drm_auth_magic(*connection, magic, drm_auth_magic_callback, &status)); if (status) { std::string const msg("Nested Mir failed to authenticate magic"); BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error(msg)) << boost::errinfo_errno(status)); } } void drm_set_gbm_device(struct gbm_device* dev) { if (!mir_connection_drm_set_gbm_device(*connection, dev)) { std::string const msg("Nested Mir failed to set the gbm device"); BOOST_THROW_EXCEPTION(std::runtime_error(msg)); } } static void drm_auth_magic_callback(int status, void* context) { int* status_ret = static_cast(context); *status_ret = status; } private: std::shared_ptr const connection; }; } mgn::NestedPlatform::NestedPlatform( std::shared_ptr const& connection, std::shared_ptr const& event_handler, std::shared_ptr const& display_report, std::shared_ptr const& native_platform) : native_platform{native_platform}, event_handler{event_handler}, display_report{display_report}, connection{connection} { if (!mir_connection_is_valid(*connection)) { BOOST_THROW_EXCEPTION(std::runtime_error("Nested Mir Platform Connection Error: " + std::string(mir_connection_get_error_message(*connection)))); } native_platform->initialize(std::make_shared(connection)); } mgn::NestedPlatform::~NestedPlatform() noexcept { } std::shared_ptr mgn::NestedPlatform::create_buffer_allocator( std::shared_ptr const& buffer_initializer) { return native_platform->create_buffer_allocator(buffer_initializer); } std::shared_ptr mgn::NestedPlatform::create_display( std::shared_ptr const& conf_policy, std::shared_ptr const& gl_config) { return std::make_shared( connection, event_handler, display_report, conf_policy, gl_config); } std::shared_ptr mgn::NestedPlatform::get_ipc_package() { return native_platform->get_ipc_package(); } std::shared_ptr mgn::NestedPlatform::create_internal_client() { return native_platform->create_internal_client(); } void mgn::NestedPlatform::fill_ipc_package(BufferIPCPacker* packer, Buffer const* buffer) const { native_platform->fill_ipc_package(packer, buffer); } EGLNativeDisplayType mgn::NestedPlatform::egl_native_display() const { return reinterpret_cast( mir_connection_get_egl_native_display(*connection)); } mir-0.1.8+14.04.20140411/src/server/graphics/nested/nested_display.h0000644000015301777760000001010612322054247025237 0ustar pbusernogroup00000000000000/* * 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: Eleni Maria Stea */ #ifndef MIR_GRAPHICS_NESTED_NESTED_DISPLAY_H_ #define MIR_GRAPHICS_NESTED_NESTED_DISPLAY_H_ #include "mir/graphics/display.h" #include "mir/graphics/display_buffer.h" #include "mir/graphics/display_configuration.h" #include "mir/graphics/egl_resources.h" #include "mir_toolkit/client_types.h" #include #include #include namespace mir { namespace input { class EventFilter; } namespace geometry { struct Rectangle; } namespace graphics { class DisplayReport; class DisplayBuffer; class DisplayConfigurationPolicy; class GLConfig; namespace nested { namespace detail { class EGLSurfaceHandle { public: explicit EGLSurfaceHandle(EGLDisplay display, EGLNativeWindowType native_window, EGLConfig cfg); ~EGLSurfaceHandle() noexcept; operator EGLSurface() const { return egl_surface; } private: EGLDisplay const egl_display; EGLSurface const egl_surface; }; class EGLDisplayHandle { public: EGLDisplayHandle(MirConnection* connection, std::shared_ptr const& gl_config); ~EGLDisplayHandle() noexcept; void initialize(MirPixelFormat format); EGLConfig choose_windowed_es_config(MirPixelFormat format) const; EGLNativeWindowType native_window(EGLConfig egl_config, MirSurface* mir_surface) const; EGLContext egl_context() const; operator EGLDisplay() const { return egl_display; } private: EGLDisplay egl_display; EGLContext egl_context_; std::shared_ptr const gl_config; EGLDisplayHandle(EGLDisplayHandle const&) = delete; EGLDisplayHandle operator=(EGLDisplayHandle const&) = delete; }; class NestedOutput; extern EGLint const nested_egl_context_attribs[]; } class HostConnection; class NestedDisplay : public Display { public: NestedDisplay( std::shared_ptr const& connection, std::shared_ptr const& event_handler, std::shared_ptr const& display_report, std::shared_ptr const& conf_policy, std::shared_ptr const& gl_config); ~NestedDisplay() noexcept; void for_each_display_buffer(std::functionconst& f) override; std::unique_ptr configuration() const override; void configure(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::weak_ptr the_cursor() override; std::unique_ptr create_gl_context() override; private: std::shared_ptr const connection; std::shared_ptr const event_handler; std::shared_ptr const display_report; detail::EGLDisplayHandle egl_display; std::mutex outputs_mutex; std::unordered_map> outputs; DisplayConfigurationChangeHandler my_conf_change_handler; void complete_display_initialization(MirPixelFormat format); }; } } } #endif // MIR_GRAPHICS_NESTED_NESTED_DISPLAY_H_ mir-0.1.8+14.04.20140411/src/server/graphics/nested/nested_output.cpp0000644000015301777760000000723112322054247025472 0ustar pbusernogroup00000000000000/* * 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 */ #include "nested_output.h" #include "mir/input/event_filter.h" #include "mir_toolkit/mir_client_library.h" #include #include namespace mgn = mir::graphics::nested; namespace geom = mir::geometry; mgn::detail::MirSurfaceHandle::MirSurfaceHandle(MirSurface* mir_surface) : mir_surface(mir_surface) { } mgn::detail::MirSurfaceHandle::~MirSurfaceHandle() noexcept { mir_surface_release_sync(mir_surface); } mgn::detail::NestedOutput::NestedOutput( EGLDisplayHandle const& egl_display, MirSurface* mir_surface, geometry::Rectangle const& area, std::shared_ptr const& event_handler, MirPixelFormat preferred_format) : egl_display(egl_display), mir_surface{mir_surface}, egl_config{egl_display.choose_windowed_es_config(preferred_format)}, egl_context{egl_display, eglCreateContext(egl_display, egl_config, egl_display.egl_context(), nested_egl_context_attribs)}, area{area.top_left, area.size}, event_handler{event_handler}, egl_surface{egl_display, egl_display.native_window(egl_config, mir_surface), egl_config} { MirEventDelegate ed = {event_thunk, this}; mir_surface_set_event_handler(mir_surface, &ed); } geom::Rectangle mgn::detail::NestedOutput::view_area() const { return area; } void mgn::detail::NestedOutput::make_current() { if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) != EGL_TRUE) BOOST_THROW_EXCEPTION(std::runtime_error("Nested Mir Display Error: Failed to update EGL surface.\n")); } void mgn::detail::NestedOutput::release_current() { eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } void mgn::detail::NestedOutput::post_update() { eglSwapBuffers(egl_display, egl_surface); } bool mgn::detail::NestedOutput::can_bypass() const { // TODO we really should return "true" - but we need to support bypass properly then return false; } void mgn::detail::NestedOutput::render_and_post_update( RenderableList const&, std::function const&) { } MirOrientation mgn::detail::NestedOutput::orientation() const { /* * Always normal orientation. The real rotation is handled by the * native display. */ return mir_orientation_normal; } mgn::detail::NestedOutput::~NestedOutput() noexcept { } void mgn::detail::NestedOutput::event_thunk( MirSurface* /*surface*/, MirEvent const* event, void* context) try { static_cast(context)->mir_event(*event); } catch (std::exception const&) { // Just in case: do not allow exceptions to propagate. } void mgn::detail::NestedOutput::mir_event(MirEvent const& event) { if (event.type == mir_event_type_motion) { auto my_event = event; my_event.motion.x_offset += area.top_left.x.as_float(); my_event.motion.y_offset += area.top_left.y.as_float(); event_handler->handle(my_event); } else { event_handler->handle(event); } } mir-0.1.8+14.04.20140411/src/server/graphics/default_display_configuration_policy.cpp0000644000015301777760000000650112322054223030756 0ustar pbusernogroup00000000000000/* * 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 */ #include "default_display_configuration_policy.h" #include "mir/graphics/display_configuration.h" #include "mir/graphics/pixel_format_utils.h" #include #include namespace mg = mir::graphics; namespace geom = mir::geometry; namespace { size_t select_mode_index(size_t mode_index, std::vector const & modes) { if (modes.empty()) return std::numeric_limits::max(); if (mode_index >= modes.size()) return 0; return mode_index; } MirPixelFormat select_opaque_format(MirPixelFormat format, std::vector const& formats) { auto const format_in_formats = formats.end() != std::find(formats.begin(), formats.end(), format); if (!mg::contains_alpha(format) && format_in_formats) return format; // format is either unavailable or transparent auto const first_opaque = std::find_if_not(formats.begin(), formats.end(), mg::contains_alpha); if (first_opaque != formats.end()) return *first_opaque; // only tranparent options - allow choice if available if (format_in_formats) return format; if (formats.size()) return formats.at(0); return mir_pixel_format_invalid; } } void mg::DefaultDisplayConfigurationPolicy::apply_to(DisplayConfiguration& conf) { static MirPowerMode const default_power_state = mir_power_mode_on; std::unordered_map available_outputs_for_card; conf.for_each_card( [&](DisplayConfigurationCard const& card) { available_outputs_for_card[card.id] = card.max_simultaneous_outputs; }); conf.for_each_output( [&](UserDisplayConfigurationOutput& conf_output) { if (!conf_output.connected || conf_output.modes.empty() || available_outputs_for_card[conf_output.card_id] == 0) { conf_output.used = false; conf_output.power_mode = default_power_state; return; } size_t preferred_mode_index{select_mode_index(conf_output.preferred_mode_index, conf_output.modes)}; MirPixelFormat format{select_opaque_format(conf_output.current_format, conf_output.pixel_formats)}; conf_output.used = true; conf_output.top_left = geom::Point{0, 0}; conf_output.current_mode_index = preferred_mode_index; conf_output.current_format = format; conf_output.power_mode = default_power_state; conf_output.orientation = mir_orientation_normal; --available_outputs_for_card[conf_output.card_id]; }); } mir-0.1.8+14.04.20140411/src/server/graphics/surfaceless_egl_context.cpp0000644000015301777760000001304212322054223026207 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/surfaceless_egl_context.h" #include "mir/graphics/gl_extensions_base.h" #include #include #include namespace mg = mir::graphics; namespace { class EGLExtensions : public mg::GLExtensionsBase { public: EGLExtensions(EGLDisplay egl_display) : mg::GLExtensionsBase{ reinterpret_cast(eglQueryString(egl_display, EGL_EXTENSIONS))} { } }; bool supports_surfaceless_context(EGLDisplay egl_display) { EGLExtensions const extensions{egl_display}; return extensions.support("EGL_KHR_surfaceless_context"); } std::vector ensure_pbuffer_set(EGLint const* attribs) { bool has_preferred_surface = false; std::vector attribs_with_surface_type; int i = 0; while (attribs[i] != EGL_NONE) { attribs_with_surface_type.push_back(attribs[i]); if (attribs[i] == EGL_SURFACE_TYPE) { has_preferred_surface = true; if (attribs[i+1] == EGL_DONT_CARE) { /* Need to treat EGL_DONT_CARE specially, as it is defined as all-bits-set */ attribs_with_surface_type.push_back(EGL_PBUFFER_BIT); } else { attribs_with_surface_type.push_back(attribs[i+1] | EGL_PBUFFER_BIT); } } else { attribs_with_surface_type.push_back(attribs[i+1]); } i += 2; } if (!has_preferred_surface) { attribs_with_surface_type.push_back(EGL_SURFACE_TYPE); attribs_with_surface_type.push_back(EGL_PBUFFER_BIT); } attribs_with_surface_type.push_back(EGL_NONE); return attribs_with_surface_type; } EGLConfig choose_config(EGLDisplay egl_display, EGLint const* attribs, bool surfaceless) { EGLConfig egl_config{0}; int num_egl_configs{0}; std::vector validated_attribs; if (!surfaceless) { validated_attribs = ensure_pbuffer_set(attribs); attribs = validated_attribs.data(); } if (eglChooseConfig(egl_display, attribs, &egl_config, 1, &num_egl_configs) == EGL_FALSE || num_egl_configs != 1) { BOOST_THROW_EXCEPTION(std::runtime_error("Failed to choose EGL config")); } return egl_config; } EGLSurface create_surface(EGLDisplay egl_display, EGLConfig egl_config) { static EGLint const dummy_pbuffer_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE }; return eglCreatePbufferSurface(egl_display, egl_config, dummy_pbuffer_attribs); } EGLint const default_egl_context_attr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLint const default_attr[] = { EGL_SURFACE_TYPE, EGL_DONT_CARE, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 0, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; } mg::SurfacelessEGLContext::SurfacelessEGLContext(EGLDisplay egl_display, EGLContext shared_context) : SurfacelessEGLContext(egl_display, default_attr, shared_context) { } mg::SurfacelessEGLContext::SurfacelessEGLContext( EGLDisplay egl_display, EGLint const* attribs, EGLContext shared_context) : egl_display{egl_display}, surfaceless{supports_surfaceless_context(egl_display)}, egl_config{choose_config(egl_display, attribs, surfaceless)}, egl_surface{egl_display, surfaceless ? EGL_NO_SURFACE : create_surface(egl_display, egl_config), surfaceless ? EGLSurfaceStore::AllowNoSurface : EGLSurfaceStore::DisallowNoSurface}, egl_context{egl_display, eglCreateContext(egl_display, egl_config, shared_context, default_egl_context_attr)} { } mg::SurfacelessEGLContext::SurfacelessEGLContext(SurfacelessEGLContext&& move) : egl_display(move.egl_display), surfaceless(move.surfaceless), egl_config(move.egl_config), egl_surface{std::move(move.egl_surface)}, egl_context{std::move(move.egl_context)} { move.egl_display = EGL_NO_DISPLAY; } mg::SurfacelessEGLContext::~SurfacelessEGLContext() noexcept { release_current(); } void mg::SurfacelessEGLContext::make_current() const { if (eglGetCurrentContext() == egl_context) return; if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) == EGL_FALSE) { BOOST_THROW_EXCEPTION( std::runtime_error("could not make context current\n")); } } void mg::SurfacelessEGLContext::release_current() const { if (egl_context != EGL_NO_CONTEXT && eglGetCurrentContext() == egl_context) eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } mg::SurfacelessEGLContext::operator EGLContext() const { return egl_context; } mir-0.1.8+14.04.20140411/src/server/default_server_configuration.cpp0000644000015301777760000001275112322054247025452 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/default_server_configuration.h" #include "mir/options/default_configuration.h" #include "mir/abnormal_exit.h" #include "mir/asio_main_loop.h" #include "mir/default_server_status_listener.h" #include "mir/default_configuration.h" #include "mir/options/program_option.h" #include "mir/frontend/session_authorizer.h" #include "mir/scene/surface_configurator.h" #include "mir/graphics/cursor.h" #include "mir/shell/null_session_listener.h" #include "mir/graphics/display.h" #include "mir/input/cursor_listener.h" #include "mir/input/vt_filter.h" #include "mir/input/input_manager.h" #include "mir/time/high_resolution_clock.h" #include "mir/geometry/rectangles.h" #include "mir/default_configuration.h" #include namespace mc = mir::compositor; namespace geom = mir::geometry; namespace mf = mir::frontend; namespace mg = mir::graphics; namespace mo = mir::options; namespace ms = mir::scene; namespace msh = mir::shell; namespace mi = mir::input; mir::DefaultServerConfiguration::DefaultServerConfiguration(int argc, char const* argv[]) : DefaultServerConfiguration(std::make_shared(argc, argv)) { } mir::DefaultServerConfiguration::DefaultServerConfiguration(std::shared_ptr const& configuration_options) : configuration_options(configuration_options), default_filter(std::make_shared()) { } auto mir::DefaultServerConfiguration::the_options() const ->std::shared_ptr { return configuration_options->the_options(); } std::string mir::DefaultServerConfiguration::the_socket_file() const { auto socket_file = the_options()->get(options::server_socket_opt); // Record this for any children that want to know how to connect to us. // By both listening to this env var on startup and resetting it here, // we make it easier to nest Mir servers. setenv("MIR_SOCKET", socket_file.c_str(), 1); return socket_file; } std::shared_ptr mir::DefaultServerConfiguration::the_shell_session_listener() { return shell_session_listener( [this] { return std::make_shared(); }); } std::shared_ptr mir::DefaultServerConfiguration::the_cursor_listener() { struct DefaultCursorListener : mi::CursorListener { DefaultCursorListener(std::weak_ptr const& cursor) : cursor(cursor) { } void cursor_moved_to(float abs_x, float abs_y) { if (auto c = cursor.lock()) { c->move_to(geom::Point{abs_x, abs_y}); } } std::weak_ptr const cursor; }; return cursor_listener( [this]() -> std::shared_ptr { return std::make_shared(the_display()->the_cursor()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_surface_configurator() { struct DefaultSurfaceConfigurator : public ms::SurfaceConfigurator { int select_attribute_value(ms::Surface const&, MirSurfaceAttrib, int requested_value) { return requested_value; } void attribute_set(ms::Surface const&, MirSurfaceAttrib, int) { } }; return surface_configurator( [this]() { return std::make_shared(); }); } std::shared_ptr mir::DefaultServerConfiguration::the_session_authorizer() { struct DefaultSessionAuthorizer : public mf::SessionAuthorizer { bool connection_is_allowed(pid_t /* pid */) { return true; } bool configure_display_is_allowed(pid_t /* pid */) { return true; } bool screencast_is_allowed(pid_t /* pid */) { return true; } }; return session_authorizer( [&]() { return std::make_shared(); }); } std::shared_ptr mir::DefaultServerConfiguration::the_input_channel_factory() { return the_input_manager(); } std::shared_ptr mir::DefaultServerConfiguration::the_clock() { return clock( []() { return std::make_shared(); }); } std::shared_ptr mir::DefaultServerConfiguration::the_main_loop() { return main_loop( []() { return std::make_shared(); }); } std::shared_ptr mir::DefaultServerConfiguration::the_server_status_listener() { return server_status_listener( []() { return std::make_shared(); }); } mir-0.1.8+14.04.20140411/src/server/time/0000755000015301777760000000000012322054703017732 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/time/high_resolution_clock.cpp0000644000015301777760000000147212322054223025014 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/time/high_resolution_clock.h" mir::time::Timestamp mir::time::HighResolutionClock::sample() const { return clock.now(); } mir-0.1.8+14.04.20140411/src/server/time/CMakeLists.txt0000644000015301777760000000007512322054223022471 0ustar pbusernogroup00000000000000ADD_LIBRARY( mirtime STATIC high_resolution_clock.cpp ) mir-0.1.8+14.04.20140411/src/server/compositor/0000755000015301777760000000000012322054703021172 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/compositor/default_display_buffer_compositor_factory.h0000644000015301777760000000354412322054223032055 0ustar pbusernogroup00000000000000/* * 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_COMPOSITOR_DEFAULT_DISPLAY_BUFFER_COMPOSITOR_FACTORY_H_ #define MIR_COMPOSITOR_DEFAULT_DISPLAY_BUFFER_COMPOSITOR_FACTORY_H_ #include "mir/compositor/display_buffer_compositor_factory.h" #include "mir/compositor/compositor_report.h" namespace mir { /// Compositing. Combining renderables into a display image. namespace compositor { class RendererFactory; class Scene; // TODO this is ideally an implementation class. It is only in a public header // TODO because it is used in some example code (which probably needs rethinking). class DefaultDisplayBufferCompositorFactory : public DisplayBufferCompositorFactory { public: DefaultDisplayBufferCompositorFactory( std::shared_ptr const& scene, std::shared_ptr const& renderer_factory, std::shared_ptr const& report); std::unique_ptr create_compositor_for(graphics::DisplayBuffer& display_buffer); private: std::shared_ptr const scene; std::shared_ptr const renderer_factory; std::shared_ptr const report; }; } } #endif /* MIR_COMPOSITOR_DEFAULT_DISPLAY_BUFFER_COMPOSITOR_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/server/compositor/switching_bundle.cpp0000644000015301777760000003207412322054247025237 0ustar pbusernogroup00000000000000/* * 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 * * * The "bundle" of buffers is actually a ring (circular array) from which * buffers are allocated and progress through stages. * * The stages of a buffer are: * free -> client -> ready -> compositor <-> free * ready (dropped)-> free * * Dropping only happens when it's enabled, and only if the ring is * completely full. * * The successive stages are contiguous elements in the ring (starting at * element "first_compositor"): * first_compositor * ncompositors(zero or more) * first_ready * nready(zero or more) * first_client * nclients(zero or more) * * Therefore you will find: * first_compositor + ncompositors == first_ready * first_ready + nready == first_client * although the ring wraps around, so all addition is modulo (%) nbuffers. * * "free" is an implicit state for any buffer that is not in any of the * above three groups. So the next free buffer is always: * first_client + nclients * and free buffers extend up to but not including first_compositor. * * |<--------------------- nbuffers ----------------------->| * | ncompos | nready | nclients| * +----------+---------+--------------+---------+----------+ * | ... free | | | | | | | | free ... | * +----------+---------+--------------+---------+----------+ * ^ ^ first_ready ^ first_client * first_compositor * * Finally, there is a floating pointer called "snapshot" which can point to * any buffer other than an active client. If nsnappshotters>0 then "snapshot" * currently points to a buffer that is being snapshotted by one or more * threads. */ #include "mir/graphics/graphic_buffer_allocator.h" #include "switching_bundle.h" #include #include #include namespace mc=mir::compositor; namespace mg = mir::graphics; mc::SwitchingBundle::SwitchingBundle( int nbuffers, const std::shared_ptr &gralloc, const mg::BufferProperties &property_request) : bundle_properties{property_request}, gralloc{gralloc}, nbuffers{nbuffers}, first_compositor{0}, ncompositors{0}, first_ready{0}, nready{0}, first_client{0}, nclients{0}, snapshot{-1}, nsnapshotters{0}, overlapping_compositors{false}, framedropping{false}, force_drop{0} { if (nbuffers < min_buffers || nbuffers > max_buffers) { BOOST_THROW_EXCEPTION(std::logic_error("SwitchingBundle only supports " "nbuffers between " + std::to_string(min_buffers) + " and " + std::to_string(max_buffers))); } } mc::SwitchingBundle::~SwitchingBundle() noexcept { force_requests_to_complete(); } int mc::SwitchingBundle::nfree() const { return nbuffers - ncompositors - nready - nclients; } int mc::SwitchingBundle::first_free() const { return (first_client + nclients) % nbuffers; } int mc::SwitchingBundle::next(int slot) const { return (slot + 1) % nbuffers; } int mc::SwitchingBundle::prev(int slot) const { return (slot + nbuffers - 1) % nbuffers; } int mc::SwitchingBundle::last_compositor() const { return (first_compositor + ncompositors - 1) % nbuffers; } int mc::SwitchingBundle::drop_frames(int max) { // Drop up to max of the oldest ready frames, and put them on the free list int dropped = (max > nready) ? nready : max; for (int d = 0; d < dropped; d++) { auto tmp = ring[first_ready]; nready--; first_client = prev(first_client); int end = first_free(); int new_snapshot = snapshot; for (int i = first_ready, j = 0; i != end; i = j) { j = next(i); ring[i] = ring[j]; if (j == snapshot) new_snapshot = i; } if (snapshot == first_ready) new_snapshot = end; snapshot = new_snapshot; ring[end] = tmp; } return dropped; } const std::shared_ptr &mc::SwitchingBundle::alloc_buffer(int slot) { /* * Many clients will behave in a way that never requires more than 2 or 3 * buffers, even though nbuffers may be higher. So to optimize memory * usage for this common case, try to avoid allocating new buffers if * we don't need to. */ if (!ring[slot].buf) { int i = first_free(); while (i != first_compositor && !ring[i].buf) i = next(i); if (i != first_compositor && i != slot && ring[i].buf && ring[i].buf.unique()) { std::swap(ring[slot], ring[i]); } else { ring[slot].buf = gralloc->alloc_buffer(bundle_properties); } } return ring[slot].buf; } inline bool mc::SwitchingBundle::client_buffers_available(std::unique_lock const& /*lock*/) { /* * Even if there are free buffers available, we might wish to still * wait. This is so we don't touch (hence allocate) a third or higher * buffer until/unless it's absolutely necessary. It becomes necessary * only when framedropping (above) or with overlapping compositors * (like with bypass). * The performance benefit of triple buffering is usually minimal, * but always uses 50% more memory. So try to avoid it when possible. */ int min_free = #if 0 // FIXME: This memory optimization breaks timing tests (nbuffers > 2 && !overlapping_compositors) ? nbuffers - 1 : 1; #else 1; #endif return nfree() >= min_free; } void mc::SwitchingBundle::client_acquire(std::function complete) { std::unique_lock lock(guard); client_acquire_todo = std::move(complete); if ((framedropping || force_drop) && nbuffers > 1) { if (nfree() <= 0) { while (nready == 0) cond.wait(lock); drop_frames(1); } } else { if (!client_buffers_available(lock)) return; } complete_client_acquire(std::move(lock)); } void mc::SwitchingBundle::complete_client_acquire(std::unique_lock lock) { auto complete = std::move(client_acquire_todo); if (force_drop > 0) force_drop--; int client = first_free(); nclients++; auto ret = alloc_buffer(client); if (client == snapshot) { /* * In the rare case where a snapshot is still being taken of what is * the new client buffer, try to move it out the way, or if you can't * then wait for the snapshot to finish. */ if (nfree() > 0) { snapshot = next(client); std::swap(ring[snapshot], ring[client]); ret = alloc_buffer(client); } else { while (client == snapshot) cond.wait(lock); } } if (ret->size() != bundle_properties.size) { ret = gralloc->alloc_buffer(bundle_properties); ring[client].buf = ret; } lock.unlock(); try { complete(ret.get()); } catch (...) { // TODO comms errors should not propagate to compositing threads } } void mc::SwitchingBundle::client_release(graphics::Buffer* released_buffer) { std::unique_lock lock(guard); if (nclients <= 0 || ring[first_client].buf.get() != released_buffer) { BOOST_THROW_EXCEPTION(std::logic_error( "Client release out of order")); } first_client = next(first_client); nclients--; nready++; cond.notify_all(); } std::shared_ptr mc::SwitchingBundle::compositor_acquire( void const* user_id) { std::unique_lock lock(guard); int compositor; // Multi-monitor acquires close to each other get the same frame: bool same_frame = !users.empty() && users.find(user_id) == users.end(); int avail = nfree(); bool can_recycle = ncompositors || avail; if (!nready || (same_frame && can_recycle)) { if (ncompositors) { compositor = last_compositor(); } else if (avail) { first_compositor = prev(first_compositor); compositor = first_compositor; ncompositors++; } else { BOOST_THROW_EXCEPTION(std::logic_error( "compositor_acquire would block; probably too many clients.")); } } else { compositor = first_ready; first_ready = next(first_ready); nready--; ncompositors++; // Fresh frame! Ensure all users get it at most once... users.clear(); } users.insert(user_id); overlapping_compositors = (ncompositors > 1); ring[compositor].users++; return alloc_buffer(compositor); } void mc::SwitchingBundle::compositor_release(std::shared_ptr const& released_buffer) { std::unique_lock lock(guard); int compositor = -1; for (int n = 0, i = first_compositor; n < ncompositors; n++, i = next(i)) { if (ring[i].buf == released_buffer) { compositor = i; break; } } if (compositor < 0) { BOOST_THROW_EXCEPTION(std::logic_error( "compositor_release given a non-compositor buffer")); } ring[compositor].users--; if (compositor == first_compositor) { while (!ring[first_compositor].users && ncompositors) { first_compositor = next(first_compositor); ncompositors--; } if (client_buffers_available(lock) && client_acquire_todo) complete_client_acquire(std::move(lock)); } } std::shared_ptr mc::SwitchingBundle::snapshot_acquire() { std::unique_lock lock(guard); /* * Note that "nsnapshotters" is a separate counter to ring[x].users. * This is because snapshotters should be completely passive and should * not affect the compositing logic. */ if (!nsnapshotters) { /* * Always snapshot the newest complete frame, which is always the * one before the first client. But make sure there is at least one * non-client buffer first... */ while (nclients >= nbuffers) cond.wait(lock); if (!nsnapshotters) snapshot = prev(first_client); } nsnapshotters++; return alloc_buffer(snapshot); } void mc::SwitchingBundle::snapshot_release(std::shared_ptr const& released_buffer) { std::unique_lock lock(guard); if (nsnapshotters <= 0 || ring[snapshot].buf != released_buffer) { BOOST_THROW_EXCEPTION(std::logic_error( "snapshot_release passed a non-snapshot buffer")); } nsnapshotters--; if (!nsnapshotters) snapshot = -1; cond.notify_all(); } void mc::SwitchingBundle::force_requests_to_complete() { std::unique_lock lock(guard); if (client_acquire_todo) { drop_frames(nready); force_drop = nbuffers + 1; complete_client_acquire(std::move(lock)); } } void mc::SwitchingBundle::allow_framedropping(bool allow_dropping) { std::unique_lock lock(guard); framedropping = allow_dropping; } bool mc::SwitchingBundle::framedropping_allowed() const { std::unique_lock lock(guard); return framedropping; } mg::BufferProperties mc::SwitchingBundle::properties() const { std::unique_lock lock(guard); return bundle_properties; } void mc::SwitchingBundle::resize(const geometry::Size &newsize) { std::unique_lock lock(guard); bundle_properties.size = newsize; } int mc::SwitchingBundle::buffers_ready_for_compositor() const { std::unique_lock lock(guard); return nready; } std::ostream& mc::operator<<(std::ostream& os, const mc::SwitchingBundle& bundle) { os << "(" << (void*)(&bundle) << ",nbuffers=" << bundle.nbuffers << ",first_compositor=" << bundle.first_compositor << ",ncompositors=" << bundle.ncompositors << ",first_ready=" << bundle.first_ready << ",nready=" << bundle.nready << ",first_client=" << bundle.first_client << ",nclients=" << bundle.nclients << ")"; return os; } mir-0.1.8+14.04.20140411/src/server/compositor/default_configuration.cpp0000644000015301777760000000535612322054223026257 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/default_server_configuration.h" #include "buffer_stream_factory.h" #include "default_display_buffer_compositor_factory.h" #include "multi_threaded_compositor.h" #include "gl_renderer_factory.h" #include "compositing_screencast.h" #include "mir/frontend/screencast.h" #include "mir/options/configuration.h" #include namespace mc = mir::compositor; namespace ms = mir::scene; namespace mf = mir::frontend; std::shared_ptr mir::DefaultServerConfiguration::the_buffer_stream_factory() { return buffer_stream_factory( [this]() { return std::make_shared(the_buffer_allocator()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_display_buffer_compositor_factory() { return display_buffer_compositor_factory( [this]() { return std::make_shared( the_scene(), the_renderer_factory(), the_compositor_report()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_compositor() { return compositor( [this]() { return std::make_shared( the_display(), the_scene(), the_display_buffer_compositor_factory(), the_compositor_report(), !the_options()->is_set(options::host_socket_opt)); }); } std::shared_ptr mir::DefaultServerConfiguration::the_renderer_factory() { return renderer_factory( []() { return std::make_shared(); }); } std::shared_ptr mir::DefaultServerConfiguration::the_screencast() { return screencast( [this]() { return std::make_shared( the_display(), the_buffer_allocator(), the_display_buffer_compositor_factory() ); }); } mir-0.1.8+14.04.20140411/src/server/compositor/buffer_stream_surfaces.cpp0000644000015301777760000000464112322054247026425 0ustar pbusernogroup00000000000000/* * 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 */ #include "buffer_stream_surfaces.h" #include "buffer_bundle.h" #include "mir/graphics/buffer_properties.h" #include "temporary_buffers.h" namespace mc = mir::compositor; namespace mg = mir::graphics; namespace geom = mir::geometry; mc::BufferStreamSurfaces::BufferStreamSurfaces(std::shared_ptr const& buffer_bundle) : buffer_bundle(buffer_bundle) { } mc::BufferStreamSurfaces::~BufferStreamSurfaces() { force_requests_to_complete(); } std::shared_ptr mc::BufferStreamSurfaces::lock_compositor_buffer( void const* user_id) { return std::make_shared( buffer_bundle, user_id); } std::shared_ptr mc::BufferStreamSurfaces::lock_snapshot_buffer() { return std::make_shared(buffer_bundle); } void mc::BufferStreamSurfaces::swap_client_buffers(graphics::Buffer* old_buffer, std::function complete) { if (old_buffer) { buffer_bundle->client_release(old_buffer); } buffer_bundle->client_acquire(complete); } MirPixelFormat mc::BufferStreamSurfaces::get_stream_pixel_format() { return buffer_bundle->properties().format; } geom::Size mc::BufferStreamSurfaces::stream_size() { return buffer_bundle->properties().size; } void mc::BufferStreamSurfaces::resize(geom::Size const& size) { buffer_bundle->resize(size); } void mc::BufferStreamSurfaces::force_requests_to_complete() { buffer_bundle->force_requests_to_complete(); } void mc::BufferStreamSurfaces::allow_framedropping(bool allow) { buffer_bundle->allow_framedropping(allow); } int mc::BufferStreamSurfaces::buffers_ready_for_compositor() const { return buffer_bundle->buffers_ready_for_compositor(); } mir-0.1.8+14.04.20140411/src/server/compositor/occlusion.h0000644000015301777760000000210512322054247023342 0ustar pbusernogroup00000000000000/* * 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_OCCLUSION_H_ #define MIR_COMPOSITOR_OCCLUSION_H_ #include "mir/graphics/renderable.h" #include "mir/compositor/scene.h" #include #include namespace mir { namespace compositor { void filter_occlusions_from(graphics::RenderableList& list, geometry::Rectangle const& area); } // namespace compositor } // namespace mir #endif // MIR_COMPOSITOR_OCCLUSION_H_ mir-0.1.8+14.04.20140411/src/server/compositor/bypass.h0000644000015301777760000000312412322054223022641 0ustar pbusernogroup00000000000000/* * 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_BYPASS_H_ #define MIR_COMPOSITOR_BYPASS_H_ #include "mir/compositor/scene.h" namespace mir { namespace graphics { class DisplayBuffer; } namespace compositor { class BypassFilter : public FilterForScene { public: BypassFilter(const graphics::DisplayBuffer &display_buffer); bool operator()(const graphics::Renderable &) override; bool fullscreen_on_top() const; private: bool all_orthogonal = true; bool topmost_fits = false; const graphics::DisplayBuffer &display_buffer; }; class BypassMatch : public OperatorForScene { public: void operator()(const graphics::Renderable &) override; const graphics::Renderable *topmost_fullscreen() const; private: // This has to be a pointer. We have no control over Renderable lifetime const graphics::Renderable *latest = nullptr; }; } // namespace compositor } // namespace mir #endif // MIR_COMPOSITOR_BYPASS_H_ mir-0.1.8+14.04.20140411/src/server/compositor/compositing_screencast.h0000644000015301777760000000467512322054223026121 0ustar pbusernogroup00000000000000/* * 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_COMPOSITING_SCREENCAST_H_ #define MIR_COMPOSITOR_COMPOSITING_SCREENCAST_H_ #include "mir/frontend/screencast.h" #include #include namespace mir { namespace geometry { struct Rectangle; } namespace graphics { class Display; class DisplayBuffer; class GraphicBufferAllocator; } namespace compositor { namespace detail { struct ScreencastSessionContext; } class DisplayBufferCompositorFactory; class CompositingScreencast : public frontend::Screencast { public: CompositingScreencast( std::shared_ptr const& display, std::shared_ptr const& buffer_allocator, std::shared_ptr const& db_compositor_factory); frontend::ScreencastSessionId create_session( geometry::Rectangle const& region, geometry::Size const& size, MirPixelFormat pixel_format); void destroy_session(frontend::ScreencastSessionId id); std::shared_ptr capture(frontend::ScreencastSessionId id); private: frontend::ScreencastSessionId next_available_session_id(); std::shared_ptr create_session_context(geometry::Rectangle const& rect, geometry::Size const& size, MirPixelFormat pixel_format); std::mutex session_mutex; std::shared_ptr const display; std::shared_ptr const buffer_allocator; std::shared_ptr const db_compositor_factory; std::unordered_map> session_contexts; }; } } #endif /* MIR_FRONTEND_SCREENCAST_H_ */ mir-0.1.8+14.04.20140411/src/server/compositor/screencast_display_buffer.cpp0000644000015301777760000000665312322054247027123 0ustar pbusernogroup00000000000000/* * 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 */ #include "screencast_display_buffer.h" #include "mir/graphics/buffer.h" #include namespace mc = mir::compositor; namespace mg = mir::graphics; namespace geom = mir::geometry; mc::ScreencastDisplayBuffer::ScreencastDisplayBuffer( geom::Rectangle const& rect, mg::Buffer& buffer) : rect(rect), buffer(buffer), old_fbo(), old_viewport() { glGetIntegerv(GL_VIEWPORT, old_viewport); glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); /* Set up the color buffer... */ glBindTexture(GL_TEXTURE_2D, color_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* and the depth buffer */ auto const buf_size = buffer.size(); glBindRenderbuffer(GL_RENDERBUFFER, depth_rbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, buf_size.width.as_uint32_t(), buf_size.height.as_uint32_t()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_rbo); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create FBO for buffer")); } mc::ScreencastDisplayBuffer::~ScreencastDisplayBuffer() { release_current(); } geom::Rectangle mc::ScreencastDisplayBuffer::view_area() const { return rect; } void mc::ScreencastDisplayBuffer::make_current() { glBindTexture(GL_TEXTURE_2D, color_tex); buffer.bind_to_texture(); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_tex, 0); auto const buf_size = buffer.size(); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glViewport(0, 0, buf_size.width.as_uint32_t(), buf_size.height.as_uint32_t()); } void mc::ScreencastDisplayBuffer::release_current() { glBindFramebuffer(GL_FRAMEBUFFER, old_fbo); glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]); } void mc::ScreencastDisplayBuffer::render_and_post_update( mg::RenderableList const& renderables, std::function const& render) { for (auto const& renderable : renderables) render(*renderable); post_update(); } void mc::ScreencastDisplayBuffer::post_update() { glFinish(); } bool mc::ScreencastDisplayBuffer::can_bypass() const { return false; } MirOrientation mc::ScreencastDisplayBuffer::orientation() const { return mir_orientation_normal; } mir-0.1.8+14.04.20140411/src/server/compositor/rendering_operator.h0000644000015301777760000000243312322054247025240 0ustar pbusernogroup00000000000000/* * 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_COMPOSITOR_RENDERING_OPERATOR_H_ #define MIR_COMPOSITOR_RENDERING_OPERATOR_H_ #include "mir/compositor/renderer.h" #include "mir/compositor/scene.h" #include #include #include namespace mir { namespace compositor { class RenderingOperator : public OperatorForScene { public: explicit RenderingOperator( Renderer& renderer); ~RenderingOperator() = default; void operator()(graphics::Renderable const&); private: Renderer& renderer; std::vector> saved_resources; }; } } #endif /* MIR_COMPOSITOR_RENDERING_OPERATOR_H_ */ mir-0.1.8+14.04.20140411/src/server/compositor/gl_renderer.cpp0000644000015301777760000003065112322054247024176 0ustar pbusernogroup00000000000000/* 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 */ #include "mir/compositor/gl_renderer.h" #include "mir/compositor/buffer_stream.h" #include "mir/graphics/renderable.h" #include "mir/graphics/buffer.h" #define GLM_FORCE_RADIANS #include #include #include #include #include #include namespace mg = mir::graphics; namespace mc = mir::compositor; namespace geom = mir::geometry; namespace { const GLchar* vertex_shader_src = { "attribute vec3 position;\n" "attribute vec2 texcoord;\n" "uniform mat4 screen_to_gl_coords;\n" "uniform mat4 display_transform;\n" "uniform mat4 transform;\n" "uniform vec2 centre;\n" "varying vec2 v_texcoord;\n" "void main() {\n" " vec4 mid = vec4(centre, 0.0, 0.0);\n" " vec4 transformed = (transform * (vec4(position, 1.0) - mid)) + mid;\n" " gl_Position = display_transform * screen_to_gl_coords * transformed;\n" " v_texcoord = texcoord;\n" "}\n" }; const GLchar* fragment_shader_src = { "precision mediump float;\n" "uniform sampler2D tex;\n" "uniform float alpha;\n" "varying vec2 v_texcoord;\n" "void main() {\n" " vec4 frag = texture2D(tex, v_texcoord);\n" " gl_FragColor = vec4(frag.xyz, frag.a * alpha);\n" "}\n" }; typedef void(*MirGLGetObjectInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); typedef void(*MirGLGetObjectiv)(GLuint, GLenum, GLint *); void GetObjectLogAndThrow(MirGLGetObjectInfoLog getObjectInfoLog, MirGLGetObjectiv getObjectiv, std::string const & msg, GLuint object) { GLint object_log_length = 0; (*getObjectiv)(object, GL_INFO_LOG_LENGTH, &object_log_length); const GLuint object_log_buffer_length = object_log_length + 1; std::string object_info_log; object_info_log.resize(object_log_buffer_length); (*getObjectInfoLog)(object, object_log_length, NULL, const_cast(object_info_log.data())); std::string object_info_err(msg + "\n"); object_info_err += object_info_log; BOOST_THROW_EXCEPTION(std::runtime_error(object_info_err)); } } mc::GLRenderer::GLRenderer(geom::Rectangle const& display_area) : vertex_shader(0), fragment_shader(0), program(0), position_attr_loc(0), texcoord_attr_loc(0), centre_uniform_loc(0), transform_uniform_loc(0), alpha_uniform_loc(0), rotation(NAN) // ensure the first set_rotation succeeds { /* * We need to serialize renderer creation because some GL calls used * during renderer construction that create unique resource ids * (e.g. glCreateProgram) are not thread-safe when the threads are * have the same or shared EGL contexts. */ static std::mutex mutex; std::lock_guard lock(mutex); GLint param = 0; /* Create shaders and program */ vertex_shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex_shader, 1, &vertex_shader_src, 0); glCompileShader(vertex_shader); glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, ¶m); if (param == GL_FALSE) { GetObjectLogAndThrow(glGetShaderInfoLog, glGetShaderiv, "Failed to compile vertex shader:", vertex_shader); } fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment_shader, 1, &fragment_shader_src, 0); glCompileShader(fragment_shader); glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, ¶m); if (param == GL_FALSE) { GetObjectLogAndThrow(glGetShaderInfoLog, glGetShaderiv, "Failed to compile fragment shader:", fragment_shader); } program = glCreateProgram(); glAttachShader(program, vertex_shader); glAttachShader(program, fragment_shader); glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, ¶m); if (param == GL_FALSE) { GetObjectLogAndThrow(glGetProgramInfoLog, glGetProgramiv, "Failed to link program:", program); } glUseProgram(program); /* Set up program variables */ GLint tex_loc = glGetUniformLocation(program, "tex"); display_transform_uniform_loc = glGetUniformLocation(program, "display_transform"); transform_uniform_loc = glGetUniformLocation(program, "transform"); alpha_uniform_loc = glGetUniformLocation(program, "alpha"); position_attr_loc = glGetAttribLocation(program, "position"); texcoord_attr_loc = glGetAttribLocation(program, "texcoord"); centre_uniform_loc = glGetUniformLocation(program, "centre"); glUniform1i(tex_loc, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); glUseProgram(0); set_viewport(display_area); set_rotation(0.0f); } mc::GLRenderer::~GLRenderer() noexcept { if (vertex_shader) glDeleteShader(vertex_shader); if (fragment_shader) glDeleteShader(fragment_shader); if (program) glDeleteProgram(program); for (auto& t : textures) glDeleteTextures(1, &t.second.id); } void mc::GLRenderer::tessellate(std::vector& primitives, graphics::Renderable const& renderable, geometry::Size const& buf_size) 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(); primitives.resize(1); auto& client = primitives[0]; client.tex_id = 0; client.type = GL_TRIANGLE_STRIP; GLfloat tex_right = static_cast(rect.size.width.as_int()) / buf_size.width.as_int(); GLfloat tex_bottom = static_cast(rect.size.height.as_int()) / buf_size.height.as_int(); auto& vertices = client.vertices; vertices.resize(4); vertices[0] = {{left, top, 0.0f}, {0.0f, 0.0f}}; vertices[1] = {{left, bottom, 0.0f}, {0.0f, tex_bottom}}; vertices[2] = {{right, top, 0.0f}, {tex_right, 0.0f}}; vertices[3] = {{right, bottom, 0.0f}, {tex_right, tex_bottom}}; } void mc::GLRenderer::render(mg::Renderable const& renderable, mg::Buffer& buffer) const { glUseProgram(program); if (renderable.shaped() || renderable.alpha() < 1.0f) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } else { glDisable(GL_BLEND); } glActiveTexture(GL_TEXTURE0); auto const& rect = renderable.screen_position(); GLfloat centrex = rect.top_left.x.as_int() + rect.size.width.as_int() / 2.0f; GLfloat centrey = rect.top_left.y.as_int() + rect.size.height.as_int() / 2.0f; glUniform2f(centre_uniform_loc, centrex, centrey); glUniformMatrix4fv(transform_uniform_loc, 1, GL_FALSE, glm::value_ptr(renderable.transformation())); glUniform1f(alpha_uniform_loc, renderable.alpha()); GLuint surface_tex = load_texture(renderable, buffer); /* Draw */ glEnableVertexAttribArray(position_attr_loc); glEnableVertexAttribArray(texcoord_attr_loc); std::vector primitives; tessellate(primitives, renderable, buffer.size()); for (auto const& p : primitives) { // Note a primitive tex_id of zero means use the surface texture, // which is what you normally want. Other textures could be used // in decorations etc. glBindTexture(GL_TEXTURE_2D, p.tex_id ? p.tex_id : surface_tex); glVertexAttribPointer(position_attr_loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), &p.vertices[0].position); glVertexAttribPointer(texcoord_attr_loc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &p.vertices[0].texcoord); glDrawArrays(p.type, 0, p.vertices.size()); } glDisableVertexAttribArray(texcoord_attr_loc); glDisableVertexAttribArray(position_attr_loc); } GLuint mc::GLRenderer::load_texture(mg::Renderable const& renderable, mg::Buffer& buffer) const { SurfaceID surf = &renderable; // TODO: Add an id() to Renderable auto& tex = textures[surf]; bool changed = true; auto const& buf_id = buffer.id(); if (!tex.id) { glGenTextures(1, &tex.id); glBindTexture(GL_TEXTURE_2D, tex.id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glBindTexture(GL_TEXTURE_2D, tex.id); changed = (tex.origin != buf_id) || skipped; } tex.origin = buf_id; tex.used = true; if (changed) // Don't upload a new texture unless the surface has changed buffer.bind_to_texture(); return tex.id; } void mc::GLRenderer::set_viewport(geometry::Rectangle const& rect) { if (rect == viewport) return; /* * Create and set screen_to_gl_coords transformation matrix. * The screen_to_gl_coords matrix transforms from the screen coordinate system * (top-left is (0,0), bottom-right is (W,H)) to the normalized GL coordinate system * (top-left is (-1,1), bottom-right is (1,-1)) */ glm::mat4 screen_to_gl_coords = glm::translate(glm::mat4(1.0f), glm::vec3{-1.0f, 1.0f, 0.0f}); /* * Perspective division is one thing that can't be done in a matrix * multiplication. It happens after the matrix multiplications. GL just * scales {x,y} by 1/w. So modify the final part of the projection matrix * to set w ([3]) to be the incoming z coordinate ([2]). */ screen_to_gl_coords[2][3] = -1.0f; float const vertical_fov_degrees = 30.0f; float const near = (rect.size.height.as_float() / 2.0f) / std::tan((vertical_fov_degrees * M_PI / 180.0f) / 2.0f); float const far = -near; screen_to_gl_coords = glm::scale(screen_to_gl_coords, glm::vec3{2.0f / rect.size.width.as_float(), -2.0f / rect.size.height.as_float(), 2.0f / (near - far)}); screen_to_gl_coords = glm::translate(screen_to_gl_coords, glm::vec3{-rect.top_left.x.as_float(), -rect.top_left.y.as_float(), 0.0f}); glUseProgram(program); GLint mat_loc = glGetUniformLocation(program, "screen_to_gl_coords"); glUniformMatrix4fv(mat_loc, 1, GL_FALSE, glm::value_ptr(screen_to_gl_coords)); glUseProgram(0); viewport = rect; } void mc::GLRenderer::set_rotation(float degrees) { if (degrees == rotation) return; float rad = degrees * M_PI / 180.0f; GLfloat cos = cosf(rad); GLfloat sin = sinf(rad); GLfloat rot[16] = {cos, sin, 0.0f, 0.0f, -sin, cos, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; glUseProgram(program); glUniformMatrix4fv(display_transform_uniform_loc, 1, GL_FALSE, rot); glUseProgram(0); rotation = degrees; } void mc::GLRenderer::begin() const { glClear(GL_COLOR_BUFFER_BIT); } void mc::GLRenderer::end() const { auto t = textures.begin(); while (t != textures.end()) { auto& tex = t->second; if (tex.used) { tex.used = false; ++t; } else { glDeleteTextures(1, &tex.id); t = textures.erase(t); } } skipped = false; } void mc::GLRenderer::suspend() { skipped = true; } mir-0.1.8+14.04.20140411/src/server/compositor/buffer_bundle.h0000644000015301777760000000506512322054247024156 0ustar pbusernogroup00000000000000/* * 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_COMPOSITOR_BUFFER_BUNDLE_H_ #define MIR_COMPOSITOR_BUFFER_BUNDLE_H_ #include "mir/graphics/buffer_properties.h" #include namespace mir { namespace graphics { class Buffer; struct BufferProperties; } namespace compositor { class BufferBundle { public: virtual ~BufferBundle() noexcept {} virtual void client_acquire(std::function complete) = 0; virtual void client_release(graphics::Buffer*) = 0; /** * Acquire the next buffer that's ready to display/composite. * * \param [in] user_id A unique identifier of who is going to use the * buffer, to ensure that separate users representing * separate monitors who need the same frame will get * the same buffer. However consecutive calls for the * same user will get different buffers. To avoid * collisions, all callers should determine user_id * in the same way (e.g. always use "this" pointer). */ virtual std::shared_ptr compositor_acquire(void const* user_id) = 0; virtual void compositor_release(std::shared_ptr const&) = 0; virtual std::shared_ptr snapshot_acquire() = 0; virtual void snapshot_release(std::shared_ptr const&) = 0; virtual graphics::BufferProperties properties() const = 0; virtual void allow_framedropping(bool dropping_allowed) = 0; virtual void force_requests_to_complete() = 0; virtual void resize(const geometry::Size &newsize) = 0; virtual int buffers_ready_for_compositor() const = 0; protected: BufferBundle() = default; BufferBundle(BufferBundle const&) = delete; BufferBundle& operator=(BufferBundle const&) = delete; }; } } #endif /*MIR_COMPOSITOR_BUFFER_BUNDLE_H_*/ mir-0.1.8+14.04.20140411/src/server/compositor/compositing_screencast.cpp0000644000015301777760000001207712322054223026447 0ustar pbusernogroup00000000000000/* * 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 */ #include "compositing_screencast.h" #include "screencast_display_buffer.h" #include "mir/graphics/buffer.h" #include "mir/graphics/buffer_properties.h" #include "mir/graphics/display.h" #include "mir/graphics/display_buffer.h" #include "mir/graphics/gl_context.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "mir/compositor/display_buffer_compositor_factory.h" #include "mir/compositor/display_buffer_compositor.h" #include "mir/raii.h" #include namespace mc = mir::compositor; namespace mf = mir::frontend; namespace mg = mir::graphics; namespace geom = mir::geometry; namespace { uint32_t const max_screencast_sessions{100}; } struct mc::detail::ScreencastSessionContext { std::shared_ptr buffer; std::unique_ptr gl_context; std::unique_ptr display_buffer; std::unique_ptr display_buffer_compositor; }; mc::CompositingScreencast::CompositingScreencast( std::shared_ptr const& display, std::shared_ptr const& buffer_allocator, std::shared_ptr const& db_compositor_factory) : display{display}, buffer_allocator{buffer_allocator}, db_compositor_factory{db_compositor_factory} { } mf::ScreencastSessionId mc::CompositingScreencast::create_session( geom::Rectangle const& region, geom::Size const& size, MirPixelFormat const pixel_format) { if (size.width.as_int() == 0 || size.height.as_int() == 0 || region.size.width.as_int() == 0 || region.size.height.as_int() == 0 || pixel_format == mir_pixel_format_invalid) { BOOST_THROW_EXCEPTION(std::runtime_error("Invalid parameters")); } std::lock_guard lock{session_mutex}; auto const id = next_available_session_id(); session_contexts[id] = create_session_context(region, size, pixel_format); return id; } void mc::CompositingScreencast::destroy_session(mf::ScreencastSessionId id) { std::lock_guard lock{session_mutex}; auto gl_context = std::move(session_contexts.at(id)->gl_context); auto using_gl_context = mir::raii::paired_calls( [&] { gl_context->make_current(); }, [&] { gl_context->release_current(); }); session_contexts.erase(id); } std::shared_ptr mc::CompositingScreencast::capture(mf::ScreencastSessionId id) { std::shared_ptr session_context; { std::lock_guard lock{session_mutex}; session_context = session_contexts.at(id); } auto using_gl_context = mir::raii::paired_calls( [&] { session_context->gl_context->make_current(); }, [&] { session_context->gl_context->release_current(); }); session_context->display_buffer_compositor->composite(); return session_context->buffer; } mf::ScreencastSessionId mc::CompositingScreencast::next_available_session_id() { for (uint32_t i = 1; i <= max_screencast_sessions; ++i) { mf::ScreencastSessionId const id{i}; if (session_contexts.find(id) == session_contexts.end()) return id; } BOOST_THROW_EXCEPTION(std::runtime_error("Too many screencast sessions!")); } std::shared_ptr mc::CompositingScreencast::create_session_context( geometry::Rectangle const& rect, geometry::Size const& size, MirPixelFormat pixel_format) { mg::BufferProperties buffer_properties{ size, pixel_format, mg::BufferUsage::hardware}; auto gl_context = display->create_gl_context(); auto gl_context_raw = gl_context.get(); auto using_gl_context = mir::raii::paired_calls( [&] { gl_context_raw->make_current(); }, [&] { gl_context_raw->release_current(); }); auto buffer = buffer_allocator->alloc_buffer(buffer_properties); auto display_buffer = std::unique_ptr( new ScreencastDisplayBuffer{rect, *buffer}); auto db_compositor = db_compositor_factory->create_compositor_for(*display_buffer); return std::shared_ptr( new detail::ScreencastSessionContext{ buffer, std::move(gl_context), std::move(display_buffer), std::move(db_compositor)}); } mir-0.1.8+14.04.20140411/src/server/compositor/temporary_buffers.cpp0000644000015301777760000000416012322054247025440 0ustar pbusernogroup00000000000000/* * 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 */ #include "buffer_bundle.h" #include "temporary_buffers.h" namespace mc=mir::compositor; namespace mg=mir::graphics; namespace geom=mir::geometry; mc::TemporaryBuffer::TemporaryBuffer(std::shared_ptr const& real_buffer) : buffer(real_buffer) { } mc::TemporaryCompositorBuffer::TemporaryCompositorBuffer( std::shared_ptr const& bun, void const* user_id) : TemporaryBuffer(bun->compositor_acquire(user_id)), bundle(bun) { } mc::TemporaryCompositorBuffer::~TemporaryCompositorBuffer() { bundle->compositor_release(buffer); } mc::TemporarySnapshotBuffer::TemporarySnapshotBuffer( std::shared_ptr const& bun) : TemporaryBuffer(bun->snapshot_acquire()), bundle(bun) { } mc::TemporarySnapshotBuffer::~TemporarySnapshotBuffer() { bundle->snapshot_release(buffer); } geom::Size mc::TemporaryBuffer::size() const { return buffer->size(); } geom::Stride mc::TemporaryBuffer::stride() const { return buffer->stride(); } MirPixelFormat mc::TemporaryBuffer::pixel_format() const { return buffer->pixel_format(); } mg::BufferID mc::TemporaryBuffer::id() const { return buffer->id(); } void mc::TemporaryBuffer::bind_to_texture() { buffer->bind_to_texture(); } std::shared_ptr mc::TemporaryBuffer::native_buffer_handle() const { return buffer->native_buffer_handle(); } bool mc::TemporaryBuffer::can_bypass() const { return buffer->can_bypass(); } mir-0.1.8+14.04.20140411/src/server/compositor/occlusion.cpp0000644000015301777760000000444412322054247023705 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/geometry/rectangle.h" #include "mir/graphics/renderable.h" #include "occlusion.h" using namespace mir::geometry; using namespace mir::graphics; namespace { bool renderable_is_occluded( Renderable const& renderable, Rectangle const& area, std::vector& coverage) { static const glm::mat4 identity; if (renderable.transformation() != identity) return false; // Weirdly transformed. Assume never occluded. //TODO: remove this check, why are we getting a non visible renderable // in the list of surfaces? // This will check the surface is not hidden and has been posted. if (!renderable.visible()) return true; //invisible; definitely occluded. // Not weirdly transformed but also not on this monitor? Don't care... if (!area.overlaps(renderable.screen_position())) return true; // Not on the display; definitely occluded. bool occluded = false; Rectangle const& window = renderable.screen_position(); for (const auto &r : coverage) { if (r.contains(window)) { occluded = true; break; } } if (!occluded && renderable.alpha() == 1.0f && !renderable.shaped()) coverage.push_back(window); return occluded; } } void mir::compositor::filter_occlusions_from( RenderableList& list, Rectangle const& area) { std::vector coverage; auto it = list.rbegin(); while (it != list.rend()) { if (renderable_is_occluded(**it, area, coverage)) list.erase(std::prev(it.base())); else it++; } } mir-0.1.8+14.04.20140411/src/server/compositor/multi_threaded_compositor.h0000644000015301777760000000415112322054223026611 0ustar pbusernogroup00000000000000/* * 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_MULTI_THREADED_COMPOSITOR_H_ #define MIR_COMPOSITOR_MULTI_THREADED_COMPOSITOR_H_ #include "mir/compositor/compositor.h" #include #include #include #include namespace mir { namespace graphics { class Display; } namespace compositor { class DisplayBufferCompositorFactory; class CompositingFunctor; class Scene; class CompositorReport; class MultiThreadedCompositor : public Compositor { public: MultiThreadedCompositor(std::shared_ptr const& display, std::shared_ptr const& scene, std::shared_ptr const& db_compositor_factory, std::shared_ptr const& compositor_report, bool compose_on_start); ~MultiThreadedCompositor(); void start(); void stop(); private: std::shared_ptr const display; std::shared_ptr const scene; std::shared_ptr const display_buffer_compositor_factory; std::shared_ptr const report; std::vector> thread_functors; std::vector threads; std::mutex started_guard; bool started; bool compose_on_start; void schedule_compositing(); }; } } #endif /* MIR_COMPOSITOR_MULTI_THREADED_COMPOSITOR_H_ */ mir-0.1.8+14.04.20140411/src/server/compositor/switching_bundle.h0000644000015301777760000000740612322054247024705 0ustar pbusernogroup00000000000000/* * 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_COMPOSITOR_SWITCHING_BUNDLE_H_ #define MIR_COMPOSITOR_SWITCHING_BUNDLE_H_ #include "buffer_bundle.h" #include #include #include #include #include namespace mir { namespace graphics { class Buffer; class GraphicBufferAllocator; } namespace compositor { class SwitchingBundle : public BufferBundle { public: enum {min_buffers = 1, max_buffers = 5}; SwitchingBundle(int nbuffers, const std::shared_ptr &, const graphics::BufferProperties &); ~SwitchingBundle() noexcept; graphics::BufferProperties properties() const; void client_acquire(std::function complete) override; void client_release(graphics::Buffer* buffer); std::shared_ptr compositor_acquire(void const* user_id) override; void compositor_release(std::shared_ptr const& released_buffer); std::shared_ptr snapshot_acquire(); void snapshot_release(std::shared_ptr const& released_buffer); void force_requests_to_complete(); void allow_framedropping(bool dropping_allowed); bool framedropping_allowed() const; /** * Change the dimensions of the buffers contained in the bundle. For * client_acquire, the change is guaranteed to be immediate. For * compositors and snapshotters however, the change may be delayed by * nbuffers frames while old frames of the old size are consumed. */ void resize(const geometry::Size &newsize) override; int buffers_ready_for_compositor() const override; private: graphics::BufferProperties bundle_properties; std::shared_ptr gralloc; int drop_frames(int max); int nfree() const; int first_free() const; int next(int slot) const; int prev(int slot) const; int last_compositor() const; const std::shared_ptr &alloc_buffer(int slot); void complete_client_acquire(std::unique_lock lock); bool client_buffers_available(std::unique_lock const& lock); struct SharedBuffer { std::shared_ptr buf; int users = 0; // presently just a count of compositors sharing the buf }; SharedBuffer ring[max_buffers]; const int nbuffers; int first_compositor; int ncompositors; int first_ready; int nready; int first_client; int nclients; int snapshot; int nsnapshotters; mutable std::mutex guard; std::condition_variable cond; std::unordered_set users; bool overlapping_compositors; bool framedropping; int force_drop; std::function client_acquire_todo; friend std::ostream& operator<<(std::ostream& os, const SwitchingBundle& bundle); }; // for use when debugging. e.g "std::cout << *this << std::endl;" std::ostream& operator<<(std::ostream& os, const SwitchingBundle& bundle); } } #endif /* MIR_COMPOSITOR_SWITCHING_BUNDLE_H_ */ mir-0.1.8+14.04.20140411/src/server/compositor/buffer_stream_factory.cpp0000644000015301777760000000325112322054223026247 0ustar pbusernogroup00000000000000/* * 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 */ #include "buffer_stream_factory.h" #include "buffer_stream_surfaces.h" #include "mir/graphics/buffer_properties.h" #include "switching_bundle.h" #include "mir/graphics/buffer.h" #include "mir/graphics/buffer_id.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "mir/graphics/display.h" #include #include namespace mc = mir::compositor; namespace mg = mir::graphics; namespace ms = mir::scene; mc::BufferStreamFactory::BufferStreamFactory( const std::shared_ptr &gralloc) : gralloc(gralloc) { assert(gralloc); } std::shared_ptr mc::BufferStreamFactory::create_buffer_stream( mg::BufferProperties const& buffer_properties) { // Note: Framedropping and bypass both require a minimum 3 buffers auto switching_bundle = std::make_shared(3, gralloc, buffer_properties); return std::make_shared(switching_bundle); } mir-0.1.8+14.04.20140411/src/server/compositor/bypass.cpp0000644000015301777760000000435712322054247023213 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/graphics/renderable.h" #include "mir/graphics/display_buffer.h" #include "bypass.h" using namespace mir; using namespace mir::compositor; using namespace mir::graphics; BypassFilter::BypassFilter(const graphics::DisplayBuffer &display_buffer) : display_buffer(display_buffer) { } bool BypassFilter::operator()(const Renderable &renderable) { if (!all_orthogonal) return false; // Any weird transformations? Then we can't risk any bypass static const glm::mat4 identity; if (renderable.transformation() != identity) { all_orthogonal = false; return false; } auto const& view_area = display_buffer.view_area(); //TODO: remove this check, why are we getting a non visible renderable // in the list of surfaces? if (!renderable.visible()) return false; // Not weirdly transformed but also not on this monitor? Don't care... // This will also check the surface is not hidden and has been posted. if (!view_area.contains(renderable.screen_position())) return false; topmost_fits = false; if (renderable.alpha() != 1.0f || renderable.shaped()) return false; // Transformed perfectly to fit the monitor? Bypass! topmost_fits = renderable.screen_position() == view_area; return topmost_fits; } bool BypassFilter::fullscreen_on_top() const { return all_orthogonal && topmost_fits; } void BypassMatch::operator()(const Renderable &r) { latest = &r; } const Renderable *BypassMatch::topmost_fullscreen() const { return latest; } mir-0.1.8+14.04.20140411/src/server/compositor/default_display_buffer_compositor.cpp0000644000015301777760000001152512322054247030665 0ustar pbusernogroup00000000000000/* * 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 * Daniel van Vugt */ #include "default_display_buffer_compositor.h" #include "rendering_operator.h" #include "mir/compositor/scene.h" #include "mir/graphics/renderable.h" #include "mir/graphics/display_buffer.h" #include "mir/graphics/buffer.h" #include "mir/compositor/buffer_stream.h" #include "bypass.h" #include "occlusion.h" #include #include #include namespace mc = mir::compositor; namespace mg = mir::graphics; //TODO remove VisibilityFilter once we don't need filters/operators for rendering namespace { struct VisibilityFilter : public mc::FilterForScene { public: VisibilityFilter( mg::RenderableList const& renderable_list) : list(renderable_list) { } bool operator()(mg::Renderable const& r) { auto matcher = [&r](std::shared_ptr const& renderable) { return (renderable.get() == &r); }; return (std::find_if(list.begin(), list.end(), matcher) != list.end()); } private: mg::RenderableList const& list; }; } mc::DefaultDisplayBufferCompositor::DefaultDisplayBufferCompositor( mg::DisplayBuffer& display_buffer, std::shared_ptr const& scene, std::shared_ptr const& renderer, std::shared_ptr const& report) : display_buffer(display_buffer), scene{scene}, renderer{renderer}, report{report}, last_pass_rendered_anything{false} { } bool mc::DefaultDisplayBufferCompositor::composite() { report->began_frame(this); static bool const bypass_env{[] { auto const env = getenv("MIR_BYPASS"); return !env || env[0] != '0'; }()}; bool bypassed = false; bool uncomposited_buffers{false}; if (bypass_env && display_buffer.can_bypass()) { // It would be *really* nice not to lock the scene for a composite pass. // (C.f. lp:1234018) // A compositor shouldn't know anything about navigating the scene, // it should be passed a collection of objects to render. (And any // locks managed by the scene - which can just lock what is needed.) std::unique_lock lock(*scene); mc::BypassFilter filter(display_buffer); mc::BypassMatch match; // It would be *really* nice if Scene had an iterator to simplify this scene->for_each_if(filter, match); if (filter.fullscreen_on_top()) { /* * Notice the user_id we pass to buffer() here has to be * different to the one used in the Renderer. This is in case * the below if() fails we want to complete the frame using the * same buffer (different user_id required). */ auto bypass_buf = match.topmost_fullscreen()->buffer(this); if (bypass_buf->can_bypass()) { uncomposited_buffers = match.topmost_fullscreen()->buffers_ready_for_compositor() > 1; lock.unlock(); display_buffer.post_update(bypass_buf); bypassed = true; renderer->suspend(); } } } if (!bypassed) { display_buffer.make_current(); auto const& view_area = display_buffer.view_area(); auto renderable_list = scene->generate_renderable_list(); mc::filter_occlusions_from(renderable_list, view_area); for(auto const& renderable : renderable_list) uncomposited_buffers |= (renderable->buffers_ready_for_compositor() > 1); renderer->set_rotation(display_buffer.orientation()); renderer->begin(); mc::RenderingOperator applicator(*renderer); VisibilityFilter selector(renderable_list); scene->for_each_if(selector, applicator); renderer->end(); display_buffer.post_update(); // This is a frig to avoid lp:1286190 if (last_pass_rendered_anything && renderable_list.empty()) uncomposited_buffers = true; last_pass_rendered_anything = !renderable_list.empty(); // End of frig } report->finished_frame(bypassed, this); return uncomposited_buffers; } mir-0.1.8+14.04.20140411/src/server/compositor/temporary_buffers.h0000644000015301777760000000373212322054247025111 0ustar pbusernogroup00000000000000/* * 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_COMPOSITOR_TEMPORARY_BUFFERS_H_ #define MIR_COMPOSITOR_TEMPORARY_BUFFERS_H_ #include "mir/graphics/buffer.h" #include "mir/graphics/buffer_id.h" namespace mg = mir::graphics; namespace mir { namespace compositor { class BufferBundle; class BackBufferStrategy; class TemporaryBuffer : public mg::Buffer { public: geometry::Size size() const; geometry::Stride stride() const; MirPixelFormat pixel_format() const; mg::BufferID id() const; void bind_to_texture(); std::shared_ptr native_buffer_handle() const; bool can_bypass() const override; protected: explicit TemporaryBuffer(std::shared_ptr const& real_buffer); std::shared_ptr const buffer; }; class TemporaryCompositorBuffer : public TemporaryBuffer { public: explicit TemporaryCompositorBuffer( std::shared_ptr const& bun, void const* user_id); ~TemporaryCompositorBuffer(); private: std::shared_ptr const bundle; }; class TemporarySnapshotBuffer : public TemporaryBuffer { public: explicit TemporarySnapshotBuffer( std::shared_ptr const& bun); ~TemporarySnapshotBuffer(); private: std::shared_ptr const bundle; }; } } #endif /* MIR_COMPOSITOR_TEMPORARY_BUFFERS_H_ */ mir-0.1.8+14.04.20140411/src/server/compositor/CMakeLists.txt0000644000015301777760000000106712322054223023733 0ustar pbusernogroup00000000000000set( MIR_COMPOSITOR_SRCS default_display_buffer_compositor.cpp default_display_buffer_compositor_factory.cpp temporary_buffers.cpp buffer_stream_factory.cpp buffer_stream_surfaces.cpp rendering_operator.cpp gl_renderer.cpp gl_renderer_factory.cpp multi_threaded_compositor.cpp switching_bundle.cpp bypass.cpp occlusion.cpp default_configuration.cpp screencast_display_buffer.cpp compositing_screencast.cpp ) ADD_LIBRARY( mircompositor STATIC ${MIR_COMPOSITOR_SRCS} ) target_link_libraries(mircompositor ${Boost_LIBRARIES} ) mir-0.1.8+14.04.20140411/src/server/compositor/buffer_stream_factory.h0000644000015301777760000000270112322054223025713 0ustar pbusernogroup00000000000000/* * 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_COMPOSITOR_BUFFER_STREAM_FACTORY_H_ #define MIR_COMPOSITOR_BUFFER_STREAM_FACTORY_H_ #include "mir/scene/buffer_stream_factory.h" #include namespace mir { namespace graphics { class GraphicBufferAllocator; } namespace compositor { class BufferStreamFactory : public scene::BufferStreamFactory { public: explicit BufferStreamFactory( const std::shared_ptr &gralloc); virtual ~BufferStreamFactory() {} virtual std::shared_ptr create_buffer_stream( graphics::BufferProperties const& buffer_properties); private: std::shared_ptr gralloc; }; } } #endif /* MIR_COMPOSITOR_BUFFER_STREAM_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/server/compositor/default_display_buffer_compositor_factory.cpp0000644000015301777760000000346012322054223032405 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #include "default_display_buffer_compositor_factory.h" #include "mir/compositor/renderer_factory.h" #include "mir/compositor/renderer.h" #include "mir/graphics/display_buffer.h" #include "default_display_buffer_compositor.h" namespace mc = mir::compositor; namespace mg = mir::graphics; mc::DefaultDisplayBufferCompositorFactory::DefaultDisplayBufferCompositorFactory( std::shared_ptr const& scene, std::shared_ptr const& renderer_factory, std::shared_ptr const& report) : scene{scene}, renderer_factory{renderer_factory}, report{report} { } std::unique_ptr mc::DefaultDisplayBufferCompositorFactory::create_compositor_for( graphics::DisplayBuffer& display_buffer) { auto renderer = renderer_factory->create_renderer_for(display_buffer.view_area()); auto raw = new DefaultDisplayBufferCompositor{display_buffer, scene, std::move(renderer), report}; return std::unique_ptr(raw); } mir-0.1.8+14.04.20140411/src/server/compositor/screencast_display_buffer.h0000644000015301777760000000435512322054247026565 0ustar pbusernogroup00000000000000/* * 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_SCREENCAST_DISPLAY_BUFFER_H_ #define MIR_COMPOSITOR_SCREENCAST_DISPLAY_BUFFER_H_ #include "mir/graphics/display_buffer.h" #include namespace mir { namespace compositor { namespace detail { template class GLResource { public: GLResource() { Generate(1, &resource); } ~GLResource() { Delete(1, &resource); } operator GLuint() const { return resource; } private: GLResource(GLResource const&) = delete; GLResource& operator=(GLResource const&) = delete; GLuint resource = 0; }; } class ScreencastDisplayBuffer : public graphics::DisplayBuffer { public: ScreencastDisplayBuffer( geometry::Rectangle const& rect, graphics::Buffer& buffer); ~ScreencastDisplayBuffer(); geometry::Rectangle view_area() const; void make_current(); void release_current(); void render_and_post_update( graphics::RenderableList const&, std::function const&); void post_update(); bool can_bypass() const; MirOrientation orientation() const; private: geometry::Rectangle const rect; graphics::Buffer& buffer; GLint old_fbo; GLint old_viewport[4]; detail::GLResource const color_tex; detail::GLResource const depth_rbo; detail::GLResource const fbo; }; } } #endif /* MIR_COMPOSITOR_SCREENCAST_DISPLAY_BUFFER_H_ */ mir-0.1.8+14.04.20140411/src/server/compositor/buffer_stream_surfaces.h0000644000015301777760000000372412322054247026073 0ustar pbusernogroup00000000000000/* * 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_COMPOSITOR_BUFFER_STREAM_SCENE_H_ #define MIR_COMPOSITOR_BUFFER_STREAM_SCENE_H_ #include "mir/compositor/buffer_stream.h" #include namespace mir { namespace compositor { class BufferIDUniqueGenerator; class BufferBundle; class BackBufferStrategy; class BufferStreamSurfaces : public BufferStream { public: BufferStreamSurfaces(std::shared_ptr const& swapper); ~BufferStreamSurfaces(); void swap_client_buffers(graphics::Buffer* old_buffer, std::function complete) override; std::shared_ptr lock_compositor_buffer(void const* user_id) override; std::shared_ptr lock_snapshot_buffer() override; MirPixelFormat get_stream_pixel_format() override; geometry::Size stream_size() override; void resize(geometry::Size const& size) override; void allow_framedropping(bool) override; void force_requests_to_complete() override; int buffers_ready_for_compositor() const override; protected: BufferStreamSurfaces(const BufferStreamSurfaces&) = delete; BufferStreamSurfaces& operator=(const BufferStreamSurfaces&) = delete; private: std::shared_ptr const buffer_bundle; }; } } #endif /* MIR_COMPOSITOR_BUFFER_STREAM_SCENE_H_ */ mir-0.1.8+14.04.20140411/src/server/compositor/default_display_buffer_compositor.h0000644000015301777760000000324112322054247030326 0ustar pbusernogroup00000000000000/* * 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_COMPOSITOR_DEFAULT_DISPLAY_BUFFER_COMPOSITOR_H_ #define MIR_COMPOSITOR_DEFAULT_DISPLAY_BUFFER_COMPOSITOR_H_ #include "mir/compositor/display_buffer_compositor.h" #include "mir/compositor/compositor_report.h" #include namespace mir { namespace graphics { class DisplayBuffer; } namespace compositor { class Scene; class Renderer; class DefaultDisplayBufferCompositor : public DisplayBufferCompositor { public: DefaultDisplayBufferCompositor( graphics::DisplayBuffer& display_buffer, std::shared_ptr const& scene, std::shared_ptr const& renderer, std::shared_ptr const& report); bool composite() override; private: graphics::DisplayBuffer& display_buffer; std::shared_ptr const scene; std::shared_ptr const renderer; std::shared_ptr const report; bool last_pass_rendered_anything; }; } } #endif /* MIR_COMPOSITOR_DEFAULT_DISPLAY_BUFFER_COMPOSITOR_H_ */ mir-0.1.8+14.04.20140411/src/server/compositor/multi_threaded_compositor.cpp0000644000015301777760000001504212322054223027145 0ustar pbusernogroup00000000000000/* * 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 "multi_threaded_compositor.h" #include "mir/graphics/display.h" #include "mir/graphics/display_buffer.h" #include "mir/compositor/display_buffer_compositor.h" #include "mir/compositor/display_buffer_compositor_factory.h" #include "mir/compositor/scene.h" #include "mir/compositor/compositor_report.h" #include #include namespace mc = mir::compositor; namespace mg = mir::graphics; namespace mir { namespace compositor { class CurrentRenderingTarget { public: CurrentRenderingTarget(mg::DisplayBuffer& buffer) : buffer(buffer) { buffer.make_current(); } ~CurrentRenderingTarget() { buffer.release_current(); } private: mg::DisplayBuffer& buffer; }; class CompositingFunctor { public: CompositingFunctor(std::shared_ptr const& db_compositor_factory, mg::DisplayBuffer& buffer, std::shared_ptr const& report) : display_buffer_compositor_factory{db_compositor_factory}, buffer(buffer), running{true}, frames_scheduled{0}, report{report} { } void operator()() noexcept // noexcept is important! (LP: #1237332) { std::unique_lock lock{run_mutex}; /* * Make the buffer the current rendering target, and release * it when the thread is finished. */ CurrentRenderingTarget target{buffer}; auto display_buffer_compositor = display_buffer_compositor_factory->create_compositor_for(buffer); CompositorReport::SubCompositorId report_id = display_buffer_compositor.get(); const auto& r = buffer.view_area(); report->added_display(r.size.width.as_int(), r.size.height.as_int(), r.top_left.x.as_int(), r.top_left.y.as_int(), report_id); while (running) { /* Wait until compositing has been scheduled or we are stopped */ run_cv.wait(lock, [&]{ return frames_scheduled || !running; }); /* * Check if we are running before compositing, since we may have * been stopped while waiting for the run_cv above. */ if (running) { frames_scheduled = false; lock.unlock(); auto more_frames_pending = display_buffer_compositor->composite(); /* * Each surface could have a number of frames ready in its buffer * queue. And we need to ensure that we render all of them so that * none linger in the queue indefinitely (seen as input lag). * more_frames_pending indicates that there are we need to schedule * more frames to ensure all surfaces' queues are fully drained. */ lock.lock(); frames_scheduled |= more_frames_pending; } } } void schedule_compositing() { std::lock_guard lock{run_mutex}; frames_scheduled = true; run_cv.notify_one(); } void stop() { std::lock_guard lock{run_mutex}; running = false; run_cv.notify_one(); } private: std::shared_ptr const display_buffer_compositor_factory; mg::DisplayBuffer& buffer; bool running; bool frames_scheduled; std::mutex run_mutex; std::condition_variable run_cv; std::shared_ptr const report; }; } } mc::MultiThreadedCompositor::MultiThreadedCompositor( std::shared_ptr const& display, std::shared_ptr const& scene, std::shared_ptr const& db_compositor_factory, std::shared_ptr const& compositor_report, bool compose_on_start) : display{display}, scene{scene}, display_buffer_compositor_factory{db_compositor_factory}, report{compositor_report}, started{false}, compose_on_start{compose_on_start} { } mc::MultiThreadedCompositor::~MultiThreadedCompositor() { stop(); } void mc::MultiThreadedCompositor::schedule_compositing() { std::unique_lock lk(started_guard); report->scheduled(); for (auto& f : thread_functors) f->schedule_compositing(); } void mc::MultiThreadedCompositor::start() { std::unique_lock lk(started_guard); if (started) { return; } report->started(); /* Start the compositing threads */ display->for_each_display_buffer([this](mg::DisplayBuffer& buffer) { auto thread_functor_raw = new mc::CompositingFunctor{display_buffer_compositor_factory, buffer, report}; auto thread_functor = std::unique_ptr(thread_functor_raw); threads.push_back(std::thread{std::ref(*thread_functor)}); thread_functors.push_back(std::move(thread_functor)); }); /* Recomposite whenever the scene changes */ scene->set_change_callback([this]() { schedule_compositing(); }); started = true; /* Optional first render */ if (compose_on_start) { lk.unlock(); schedule_compositing(); } } void mc::MultiThreadedCompositor::stop() { std::unique_lock lk(started_guard); if (!started) { return; } lk.unlock(); scene->set_change_callback([]{}); lk.lock(); for (auto& f : thread_functors) f->stop(); for (auto& t : threads) t.join(); thread_functors.clear(); threads.clear(); report->stopped(); started = false; // If the compositor is restarted we've likely got clients blocked // so we will need to schedule compositing immediately compose_on_start = true; } mir-0.1.8+14.04.20140411/src/server/compositor/gl_renderer_factory.cpp0000644000015301777760000000205312322054223025712 0ustar pbusernogroup00000000000000/* * 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 */ #include "gl_renderer_factory.h" #include "mir/geometry/rectangle.h" #include "mir/compositor/gl_renderer.h" namespace mc = mir::compositor; namespace geom = mir::geometry; std::unique_ptr mc::GLRendererFactory::create_renderer_for(geom::Rectangle const& rect) { auto raw = new GLRenderer(rect); return std::unique_ptr(raw); } mir-0.1.8+14.04.20140411/src/server/compositor/rendering_operator.cpp0000644000015301777760000000233312322054247025572 0ustar pbusernogroup00000000000000/* * 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 */ #include "rendering_operator.h" #include "mir/compositor/buffer_stream.h" #include "mir/graphics/renderable.h" namespace mc=mir::compositor; mc::RenderingOperator::RenderingOperator( Renderer& renderer) : renderer(renderer) { } void mc::RenderingOperator::operator()(graphics::Renderable const& renderable) { auto compositor_buffer = renderable.buffer(&renderer); // preserves buffers used in rendering until after post_update() saved_resources.push_back(compositor_buffer); renderer.render(renderable, *compositor_buffer); } mir-0.1.8+14.04.20140411/src/server/compositor/gl_renderer_factory.h0000644000015301777760000000207412322054223025362 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #ifndef MIR_COMPOSITOR_GL_RENDERER_FACTORY_H_ #define MIR_COMPOSITOR_GL_RENDERER_FACTORY_H_ #include "mir/compositor/renderer_factory.h" namespace mir { namespace compositor { class GLRendererFactory : public RendererFactory { public: std::unique_ptr create_renderer_for(geometry::Rectangle const& rect); }; } } #endif /* MIR_COMPOSITOR_GL_RENDERER_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/server/report/0000755000015301777760000000000012322054703020307 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/report/logging/0000755000015301777760000000000012322054703021735 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/report/logging/session_mediator_report.h0000644000015301777760000000371512322054223027053 0ustar pbusernogroup00000000000000/* * 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_LOGGING_SESSION_MEDIATOR_REPORT_H_ #define MIR_REPORT_LOGGING_SESSION_MEDIATOR_REPORT_H_ #include "mir/frontend/session_mediator_report.h" #include namespace mir { namespace logging { class Logger; } namespace report { namespace logging { class SessionMediatorReport : public frontend::SessionMediatorReport { public: SessionMediatorReport(std::shared_ptr const& log); virtual void session_connect_called(std::string const& app_name); virtual void session_create_surface_called(std::string const& app_name); virtual void session_next_buffer_called(std::string const& app_name); virtual void session_release_surface_called(std::string const& app_name); virtual void session_disconnect_called(std::string const& app_name); virtual void session_drm_auth_magic_called(std::string const& app_name); virtual void session_configure_surface_called(std::string const& app_name); virtual void session_configure_display_called(std::string const& app_name); virtual void session_error( std::string const& app_name, char const* method, std::string const& what); private: std::shared_ptr const log; }; } } } #endif /* MIR_REPORT_LOGGING_SESSION_MEDIATOR_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/logging/compositor_report.h0000644000015301777760000000505012322054223025674 0ustar pbusernogroup00000000000000/* * 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_REPORT_LOGGING_COMPOSITOR_REPORT_H_ #define MIR_REPORT_LOGGING_COMPOSITOR_REPORT_H_ #include "mir/compositor/compositor_report.h" #include "mir/time/clock.h" #include #include #include #include namespace mir { namespace logging { class Logger; } namespace report { namespace logging { class CompositorReport : public mir::compositor::CompositorReport { public: CompositorReport(std::shared_ptr const& logger, std::shared_ptr const& clock); void added_display(int width, int height, int x, int y, SubCompositorId id) override; void began_frame(SubCompositorId id) override; void finished_frame(bool bypassed, SubCompositorId id) override; void started() override; void stopped() override; void scheduled() override; private: std::shared_ptr const logger; std::shared_ptr const clock; typedef time::Timestamp TimePoint; TimePoint now() const; struct Instance { TimePoint start_of_frame; TimePoint end_of_frame; TimePoint total_time_sum; TimePoint frame_time_sum; TimePoint latency_sum; long nframes = 0; long nbypassed = 0; bool prev_bypassed = false; TimePoint last_reported_total_time_sum; TimePoint last_reported_frame_time_sum; TimePoint last_reported_latency_sum; long last_reported_nframes = 0; long last_reported_bypassed = 0; void log(mir::logging::Logger& logger, SubCompositorId id); }; std::mutex mutex; // Protects the following... std::unordered_map instance; TimePoint last_scheduled; TimePoint last_report; }; } // namespace logging } // namespace report } // namespace mir #endif // MIR_REPORT_LOGGING_COMPOSITOR_REPORT_H_ mir-0.1.8+14.04.20140411/src/server/report/logging/message_processor_report.h0000644000015301777760000000445712322054223027233 0ustar pbusernogroup00000000000000/* * 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_LOGGING_MESSAGE_PROCESSOR_REPORT_H_ #define MIR_REPORT_LOGGING_MESSAGE_PROCESSOR_REPORT_H_ #include "mir/frontend/message_processor_report.h" #include "mir/time/clock.h" #include #include #include namespace mir { namespace logging { class Logger; } namespace report { namespace logging { namespace detail { struct InvocationDetails { time::Timestamp start; std::string method; std::string exception; }; typedef std::unordered_map Invocations; struct MediatorDetails { Invocations current_invocations; }; typedef std::unordered_map Mediators; } class MessageProcessorReport : public mir::frontend::MessageProcessorReport { public: MessageProcessorReport( std::shared_ptr const& log, std::shared_ptr const& clock); void received_invocation(void const* mediator, int id, std::string const& method); void completed_invocation(void const* mediator, int id, bool result); void unknown_method(void const* mediator, int id, std::string const& method); void exception_handled(void const* mediator, int id, std::exception const& error); void exception_handled(void const* mediator, std::exception const& error); void sent_event(void const* mediator, MirSurfaceEvent const& event); ~MessageProcessorReport() noexcept(true); private: std::shared_ptr const log; std::shared_ptr const clock; std::mutex mutex; detail::Mediators mediators; }; } } } #endif /* MIR_REPORT_LOGGING_MESSAGE_PROCESSOR_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/logging/connector_report.cpp0000644000015301777760000000561312322054223026030 0ustar pbusernogroup00000000000000/* * 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 */ #include "connector_report.h" #include "mir/logging/logger.h" #include #include #include namespace ml = mir::logging; namespace mrl = mir::report::logging; namespace { char const* const component = "frontend::Connector"; } mrl::ConnectorReport::ConnectorReport(std::shared_ptr const& log) : logger(log) { } void mrl::ConnectorReport::thread_start() { std::stringstream ss; ss << "thread (" << std::this_thread::get_id() << ") started."; logger->log(ml::Logger::informational, ss.str(), component); } void mrl::ConnectorReport::thread_end() { std::stringstream ss; ss << "thread (" << std::this_thread::get_id() << ") ended."; logger->log(ml::Logger::informational, ss.str(), component); } void mrl::ConnectorReport::starting_threads(int count) { std::stringstream ss; ss << "Starting " << count << " threads."; logger->log(ml::Logger::informational, ss.str(), component); } void mrl::ConnectorReport::stopping_threads(int count) { std::stringstream ss; ss << "Stopping " << count << " threads."; logger->log(ml::Logger::informational, ss.str(), component); } void mrl::ConnectorReport::creating_session_for(int socket_handle) { std::stringstream ss; ss << "thread (" << std::this_thread::get_id() << ") Creating session for socket " << socket_handle; logger->log(ml::Logger::informational, ss.str(), component); } void mrl::ConnectorReport::creating_socket_pair(int server_handle, int client_handle) { std::stringstream ss; ss << "thread (" << std::this_thread::get_id() << ") Creating socket pair (server=" << server_handle << ", client=" << client_handle << ")."; logger->log(ml::Logger::informational, ss.str(), component); } void mrl::ConnectorReport::listening_on(std::string const& endpoint) { std::stringstream ss; ss << "Listening on endpoint: " << endpoint; logger->log(ml::Logger::informational, ss.str(), component); } void mrl::ConnectorReport::error(std::exception const& error) { std::stringstream ss; ss << "thread (" << std::this_thread::get_id() << ") Error: " << boost::diagnostic_information(error); logger->log(ml::Logger::warning, ss.str(), component); } mir-0.1.8+14.04.20140411/src/server/report/logging/connector_report.h0000644000015301777760000000312212322054223025466 0ustar pbusernogroup00000000000000/* * 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_LOGGING_CONNECTOR_REPORT_H_ #define MIR_REPORT_LOGGING_CONNECTOR_REPORT_H_ #include "mir/frontend/connector_report.h" #include namespace mir { namespace logging { class Logger; } namespace report { namespace logging { class ConnectorReport : public frontend::ConnectorReport { public: ConnectorReport(std::shared_ptr const& log); void thread_start() override; void thread_end() override; void starting_threads(int count) override; void stopping_threads(int count) override; void creating_session_for(int socket_handle) override; void creating_socket_pair(int server_handle, int client_handle) override; void listening_on(std::string const& endpoint) override; void error(std::exception const& error) override; private: std::shared_ptr const logger; }; } } } #endif /* MIR_REPORT_LOGGING_CONNECTOR_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/logging/compositor_report.cpp0000644000015301777760000001255712322054223026241 0ustar pbusernogroup00000000000000/* * 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: Daniel van Vugt */ #include "compositor_report.h" #include "mir/logging/logger.h" using namespace mir::time; namespace ml = mir::logging; namespace mrl = mir::report::logging; namespace { const char * const component = "compositor"; const auto min_report_interval = std::chrono::seconds(1); } mrl::CompositorReport::CompositorReport( std::shared_ptr const& logger, std::shared_ptr const& clock) : logger(logger), clock(clock), last_report(now()) { } mrl::CompositorReport::TimePoint mrl::CompositorReport::now() const { return clock->sample(); } void mrl::CompositorReport::added_display(int width, int height, int x, int y, SubCompositorId id) { char msg[128]; snprintf(msg, sizeof msg, "Added display %p: %dx%d %+d%+d", id, width, height, x, y); logger->log(ml::Logger::informational, msg, component); } void mrl::CompositorReport::began_frame(SubCompositorId id) { std::lock_guard lock(mutex); auto& inst = instance[id]; auto t = now(); inst.start_of_frame = t; inst.latency_sum += t - last_scheduled; } void mrl::CompositorReport::Instance::log(ml::Logger& logger, SubCompositorId id) { // The first report is a valid sample, but don't log anything because // we need at least two samples for valid deltas. if (last_reported_total_time_sum > TimePoint()) { long long dt = std::chrono::duration_cast( total_time_sum - last_reported_total_time_sum ).count(); auto dn = nframes - last_reported_nframes; long long df = std::chrono::duration_cast( frame_time_sum - last_reported_frame_time_sum ).count(); long long dl = std::chrono::duration_cast( latency_sum - last_reported_latency_sum ).count(); long bypass_percent = (nbypassed - last_reported_bypassed) * 100L / dn; // Keep everything premultiplied by 1000 to guarantee accuracy // and avoid floating point. long frames_per_1000sec = dt ? dn * 1000000000LL / dt : 0; long avg_frame_time_usec = dn ? df / dn : 0; long avg_latency_usec = dn ? dl / dn : 0; long dt_msec = dt / 1000L; char msg[128]; snprintf(msg, sizeof msg, "Display %p averaged %ld.%03ld FPS, " "%ld.%03ld ms/frame, " "latency %ld.%03ld ms, " "%ld frames over %ld.%03ld sec, " "%ld%% bypassed", id, frames_per_1000sec / 1000, frames_per_1000sec % 1000, avg_frame_time_usec / 1000, avg_frame_time_usec % 1000, avg_latency_usec / 1000, avg_latency_usec % 1000, dn, dt_msec / 1000, dt_msec % 1000, bypass_percent ); logger.log(ml::Logger::informational, msg, component); } last_reported_total_time_sum = total_time_sum; last_reported_frame_time_sum = frame_time_sum; last_reported_latency_sum = latency_sum; last_reported_nframes = nframes; last_reported_bypassed = nbypassed; } void mrl::CompositorReport::finished_frame(bool bypassed, SubCompositorId id) { std::lock_guard lock(mutex); auto& inst = instance[id]; auto t = now(); inst.total_time_sum += t - inst.end_of_frame; inst.frame_time_sum += t - inst.start_of_frame; inst.end_of_frame = t; inst.nframes++; if (bypassed) ++inst.nbypassed; /* * The exact reporting interval doesn't matter because we count everything * as a Reimann sum. Results will simply be the average over the interval. */ if ((t - last_report) >= min_report_interval) { last_report = t; for (auto& i : instance) i.second.log(*logger, i.first); } if (bypassed != inst.prev_bypassed || inst.nframes == 1) { char msg[128]; snprintf(msg, sizeof msg, "Display %p bypass %s", id, bypassed ? "ON" : "OFF"); logger->log(ml::Logger::informational, msg, component); } inst.prev_bypassed = bypassed; } void mrl::CompositorReport::started() { logger->log(ml::Logger::informational, "Started", component); } void mrl::CompositorReport::stopped() { logger->log(ml::Logger::informational, "Stopped", component); std::lock_guard lock(mutex); instance.clear(); } void mrl::CompositorReport::scheduled() { std::lock_guard lock(mutex); last_scheduled = now(); } mir-0.1.8+14.04.20140411/src/server/report/logging/display_report.cpp0000644000015301777760000001207012322054223025476 0ustar pbusernogroup00000000000000/* * 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 */ #include "display_report.h" #include "mir/logging/logger.h" #include #include #include namespace ml=mir::logging; namespace mrl=mir::report::logging; mrl::DisplayReport::DisplayReport(const std::shared_ptr& logger) : logger(logger) { } mrl::DisplayReport::~DisplayReport() { } const char* mrl::DisplayReport::component() { static const char* s = "graphics"; return s; } void mrl::DisplayReport::report_successful_setup_of_native_resources() { logger->log(ml::Logger::informational, "Successfully setup native resources.", component()); } void mrl::DisplayReport::report_successful_egl_make_current_on_construction() { logger->log(ml::Logger::informational, "Successfully made egl context current on construction.", component()); } void mrl::DisplayReport::report_successful_egl_buffer_swap_on_construction() { logger->log(ml::Logger::informational, "Successfully performed egl buffer swap on construction.", component()); } void mrl::DisplayReport::report_successful_drm_mode_set_crtc_on_construction() { logger->log(ml::Logger::informational, "Successfully performed drm mode setup on construction.", component()); } void mrl::DisplayReport::report_successful_display_construction() { logger->log(ml::Logger::informational, "Successfully finished construction.", component()); } void mrl::DisplayReport::report_drm_master_failure(int error) { std::stringstream ss; ss << "Failed to change ownership of DRM master (error: " << strerror(error) << ")."; if (error == EPERM || error == EACCES) ss << " Try running Mir with root privileges."; logger->log(ml::Logger::warning, ss.str(), component()); } void mrl::DisplayReport::report_vt_switch_away_failure() { logger->log(ml::Logger::warning, "Failed to switch away from Mir VT.", component()); } void mrl::DisplayReport::report_vt_switch_back_failure() { logger->log(ml::Logger::warning, "Failed to switch back to Mir VT.", component()); } void mrl::DisplayReport::report_hwc_composition_in_use(int major, int minor) { std::stringstream ss; ss << "HWC version " << major << "." << minor << " in use for display."; logger->log(ml::Logger::informational, ss.str(), component()); } void mrl::DisplayReport::report_gpu_composition_in_use() { logger->log(ml::Logger::informational, "GPU backup in use for display.", component()); } void mrl::DisplayReport::report_egl_configuration(EGLDisplay disp, EGLConfig config) { #define STRMACRO(X) {#X, X} struct {std::string name; EGLint val;} egl_string_mapping [] = { STRMACRO(EGL_BUFFER_SIZE), STRMACRO(EGL_ALPHA_SIZE), STRMACRO(EGL_BLUE_SIZE), STRMACRO(EGL_GREEN_SIZE), STRMACRO(EGL_RED_SIZE), STRMACRO(EGL_DEPTH_SIZE), STRMACRO(EGL_STENCIL_SIZE), STRMACRO(EGL_CONFIG_CAVEAT), STRMACRO(EGL_CONFIG_ID), STRMACRO(EGL_LEVEL), STRMACRO(EGL_MAX_PBUFFER_HEIGHT), STRMACRO(EGL_MAX_PBUFFER_PIXELS), STRMACRO(EGL_MAX_PBUFFER_WIDTH), STRMACRO(EGL_NATIVE_RENDERABLE), STRMACRO(EGL_NATIVE_VISUAL_ID), STRMACRO(EGL_NATIVE_VISUAL_TYPE), STRMACRO(EGL_SAMPLES), STRMACRO(EGL_SAMPLE_BUFFERS), STRMACRO(EGL_SURFACE_TYPE), STRMACRO(EGL_TRANSPARENT_TYPE), STRMACRO(EGL_TRANSPARENT_BLUE_VALUE), STRMACRO(EGL_TRANSPARENT_GREEN_VALUE), STRMACRO(EGL_TRANSPARENT_RED_VALUE), STRMACRO(EGL_BIND_TO_TEXTURE_RGB), STRMACRO(EGL_BIND_TO_TEXTURE_RGBA), STRMACRO(EGL_MIN_SWAP_INTERVAL), STRMACRO(EGL_MAX_SWAP_INTERVAL), STRMACRO(EGL_LUMINANCE_SIZE), STRMACRO(EGL_ALPHA_MASK_SIZE), STRMACRO(EGL_COLOR_BUFFER_TYPE), STRMACRO(EGL_RENDERABLE_TYPE), STRMACRO(EGL_MATCH_NATIVE_PIXMAP), STRMACRO(EGL_CONFORMANT), STRMACRO(EGL_SLOW_CONFIG), STRMACRO(EGL_NON_CONFORMANT_CONFIG), STRMACRO(EGL_TRANSPARENT_RGB), STRMACRO(EGL_RGB_BUFFER), STRMACRO(EGL_LUMINANCE_BUFFER), STRMACRO(EGL_FRAMEBUFFER_TARGET_ANDROID) }; #undef STRMACRO logger->log(ml::Logger::informational, "Display EGL Configuration:", component()); for( auto &i : egl_string_mapping) { EGLint value; eglGetConfigAttrib(disp, config, i.val, &value); logger->log(ml::Logger::informational, " [" + i.name + "] : " + std::to_string(value), component()); } } mir-0.1.8+14.04.20140411/src/server/report/logging/session_mediator_report.cpp0000644000015301777760000000550012322054223027400 0ustar pbusernogroup00000000000000/* * 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 */ #include "session_mediator_report.h" #include "mir/logging/logger.h" namespace { char const* const component = "frontend::SessionMediator"; } namespace ml = mir::logging; namespace mrl = mir::report::logging; mrl::SessionMediatorReport::SessionMediatorReport(std::shared_ptr const& log) : log(log) { } void mrl::SessionMediatorReport::session_connect_called(std::string const& app_name) { log->log(ml::Logger::informational, "session_connect(\"" + app_name + "\")", component); } void mrl::SessionMediatorReport::session_create_surface_called(std::string const& app_name) { log->log(ml::Logger::informational, "session_create_surface(\"" + app_name + "\")", component); } void mrl::SessionMediatorReport::session_next_buffer_called(std::string const& app_name) { log->log(ml::Logger::informational, "session_next_buffer_called(\"" + app_name + "\")", component); } void mrl::SessionMediatorReport::session_release_surface_called(std::string const& app_name) { log->log(ml::Logger::informational, "session_release_surface_called(\"" + app_name + "\")", component); } void mrl::SessionMediatorReport::session_disconnect_called(std::string const& app_name) { log->log(ml::Logger::informational, "session_disconnect_called(\"" + app_name + "\")", component); } void mrl::SessionMediatorReport::session_drm_auth_magic_called(std::string const& app_name) { log->log(ml::Logger::informational, "session_drm_auth_magic_called(\"" + app_name + "\")", component); } void mrl::SessionMediatorReport::session_configure_surface_called(std::string const& app_name) { log->log(ml::Logger::informational, "session_configure_surface_called(\"" + app_name + "\")", component); } void mrl::SessionMediatorReport::session_configure_display_called(std::string const& app_name) { log->log(ml::Logger::informational, "session_configure_display_called(\"" + app_name + "\")", component); } void mrl::SessionMediatorReport::session_error( std::string const& app_name, char const* method, std::string const& what) { log->log(ml::Logger::error, std::string(method) + " - session_error(\"" + app_name + "\"):\n" + what, component); } mir-0.1.8+14.04.20140411/src/server/report/logging/display_report.h0000644000015301777760000000403312322054223025143 0ustar pbusernogroup00000000000000/* * 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_REPORT_LOGGING_DISPLAY_REPORTER_H_ #define MIR_REPORT_LOGGING_DISPLAY_REPORTER_H_ #include "mir/graphics/display_report.h" #include namespace mir { namespace logging { class Logger; } namespace report { namespace logging { class DisplayReport : public graphics::DisplayReport { public: static const char* component(); DisplayReport(const std::shared_ptr& logger); virtual ~DisplayReport(); virtual void report_successful_setup_of_native_resources(); virtual void report_successful_egl_make_current_on_construction(); virtual void report_successful_egl_buffer_swap_on_construction(); virtual void report_successful_drm_mode_set_crtc_on_construction(); virtual void report_successful_display_construction(); virtual void report_drm_master_failure(int error); virtual void report_vt_switch_away_failure(); virtual void report_vt_switch_back_failure(); virtual void report_hwc_composition_in_use(int major, int minor); virtual void report_gpu_composition_in_use(); virtual void report_egl_configuration(EGLDisplay disp, EGLConfig cfg); protected: DisplayReport(const DisplayReport&) = delete; DisplayReport& operator=(const DisplayReport&) = delete; private: std::shared_ptr logger; }; } } } #endif /* MIR_REPORT_LOGGING_DISPLAY_REPORTER_H_ */ mir-0.1.8+14.04.20140411/src/server/report/logging/logging_report_factory.cpp0000644000015301777760000000464012322054223027212 0ustar pbusernogroup00000000000000/* * 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 */ #include "../logging_report_factory.h" #include "compositor_report.h" #include "connector_report.h" #include "display_report.h" #include "message_processor_report.h" #include "scene_report.h" #include "session_mediator_report.h" #include "input_report.h" #include "mir/default_server_configuration.h" namespace mr = mir::report; mr::LoggingReportFactory::LoggingReportFactory(std::shared_ptr const& logger, std::shared_ptr const& clock) : logger(logger), clock(clock) { } std::shared_ptr mr::LoggingReportFactory::create_compositor_report() { return std::make_shared(logger, clock); } std::shared_ptr mr::LoggingReportFactory::create_display_report() { return std::make_shared(logger); } std::shared_ptr mr::LoggingReportFactory::create_scene_report() { return std::make_shared(logger); } std::shared_ptr mr::LoggingReportFactory::create_connector_report() { return std::make_shared(logger); } std::shared_ptr mr::LoggingReportFactory::create_session_mediator_report() { return std::make_shared(logger); } std::shared_ptr mr::LoggingReportFactory::create_message_processor_report() { return std::make_shared(logger, clock); } std::shared_ptr mr::LoggingReportFactory::create_input_report() { return std::make_shared(logger); } mir-0.1.8+14.04.20140411/src/server/report/logging/scene_report.h0000644000015301777760000000302212322054223024570 0ustar pbusernogroup00000000000000/* * 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_LOGGING_SCENE_REPORT_H_ #define MIR_REPORT_LOGGING_SCENE_REPORT_H_ #include "mir/scene/scene_report.h" #include #include #include namespace mir { namespace logging { class Logger; } namespace report { namespace logging { class SceneReport : public scene::SceneReport { public: SceneReport(std::shared_ptr const& log); void surface_created(BasicSurfaceId id, std::string const& name); void surface_added(BasicSurfaceId id, std::string const& name); void surface_removed(BasicSurfaceId id, std::string const& name); void surface_deleted(BasicSurfaceId id, std::string const& name); private: std::shared_ptr const logger; std::mutex mutex; std::map surfaces; }; } } } #endif /* MIR_REPORT_LOGGING_SCENE_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/logging/message_processor_report.cpp0000644000015301777760000001222112322054223027552 0ustar pbusernogroup00000000000000/* * 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 */ #include "message_processor_report.h" #include "mir/logging/logger.h" #include #include namespace ml = mir::logging; namespace mrl = mir::report::logging; namespace { char const* const component = "frontend::MessageProcessor"; } mrl::MessageProcessorReport::MessageProcessorReport( std::shared_ptr const& log, std::shared_ptr const& clock) : log(log), clock(clock) { } mrl::MessageProcessorReport::~MessageProcessorReport() noexcept(true) { if (!mediators.empty()) { std::ostringstream out; { out << "Calls outstanding on exit:\n"; std::lock_guard lock(mutex); for (auto const& med : mediators) { for (auto const & invocation: med.second.current_invocations) { out << "mediator=" << med.first << ": " << invocation.second.method << "()"; if (!invocation.second.exception.empty()) out << " ERROR=" << invocation.second.exception; out << '\n'; } } } log->log(ml::Logger::informational, out.str(), component); } } void mrl::MessageProcessorReport::received_invocation(void const* mediator, int id, std::string const& method) { std::ostringstream out; out << "mediator=" << mediator << ", method=" << method << "()"; log->log(ml::Logger::debug, out.str(), component); std::lock_guard lock(mutex); auto& invocations = mediators[mediator].current_invocations; auto& invocation = invocations[id]; invocation.start = clock->sample(); invocation.method = method; } void mrl::MessageProcessorReport::completed_invocation(void const* mediator, int id, bool result) { auto const end = clock->sample(); std::ostringstream out; { std::lock_guard lock(mutex); auto const pm = mediators.find(mediator); if (pm != mediators.end()) { auto& invocations = pm->second.current_invocations; auto const pi = invocations.find(id); if (pi != invocations.end()) { out << "mediator=" << mediator << ": " << pi->second.method << "(), elapsed=" << std::chrono::duration_cast(end - pi->second.start).count() << "µs"; if (!pi->second.exception.empty()) out << " ERROR=" << pi->second.exception; if (!result) out << " (disconnecting)"; } invocations.erase(pi); if (invocations.empty()) mediators.erase(mediator); } } log->log(ml::Logger::informational, out.str(), component); } void mrl::MessageProcessorReport::unknown_method(void const* mediator, int id, std::string const& method) { std::ostringstream out; out << "mediator=" << mediator << ", id=" << id << ", UNKNOWN method=\"" << method << "\""; log->log(ml::Logger::warning, out.str(), component); std::lock_guard lock(mutex); auto const pm = mediators.find(mediator); if (pm != mediators.end()) mediators.erase(mediator); } void mrl::MessageProcessorReport::exception_handled(void const* mediator, int id, std::exception const& error) { std::lock_guard lock(mutex); auto const pm = mediators.find(mediator); if (pm != mediators.end()) { auto& invocations = pm->second.current_invocations; auto const pi = invocations.find(id); if (pi != invocations.end()) { pi->second.exception = boost::diagnostic_information(error); } } } void mrl::MessageProcessorReport::exception_handled(void const* mediator, std::exception const& error) { std::ostringstream out; out << "mediator=" << mediator << ", ERROR: " << boost::diagnostic_information(error); log->log(ml::Logger::informational, out.str(), component); std::lock_guard lock(mutex); auto const pm = mediators.find(mediator); if (pm != mediators.end()) mediators.erase(mediator); } void mrl::MessageProcessorReport::sent_event(void const* mediator, MirSurfaceEvent const& event) { std::ostringstream out; out << "mediator=" << mediator << ", sent event, surface id=" << event.id; log->log(ml::Logger::debug, out.str(), component); } mir-0.1.8+14.04.20140411/src/server/report/logging/CMakeLists.txt0000644000015301777760000000074712322054223024502 0ustar pbusernogroup00000000000000include_directories(${MIR_3RD_PARTY_INCLUDE_DIRECTORIES}) include_directories(${MIR_ANDROID_INCLUDE_DIRECTORIES}) set( LOGGING_SOURCES connector_report.cpp session_mediator_report.cpp message_processor_report.cpp display_report.cpp input_report.cpp compositor_report.cpp scene_report.cpp logging_report_factory.cpp ) add_library( mirlogging STATIC ${LOGGING_SOURCES} ) target_link_libraries( mirlogging mirplatform ${GLog_LIBRARY} ${GFlags_LIBRARY} ) mir-0.1.8+14.04.20140411/src/server/report/logging/input_report.h0000644000015301777760000000304412322054223024636 0ustar pbusernogroup00000000000000/* * 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_LOGGING_INPUT_REPORT_H_ #define MIR_REPORT_LOGGING_INPUT_REPORT_H_ #include "mir/input/input_report.h" #include namespace mir { namespace logging { class Logger; } namespace report { namespace logging { class InputReport : public input::InputReport { public: InputReport(std::shared_ptr const& logger); virtual ~InputReport() noexcept(true) = default; void received_event_from_kernel(int64_t when, int type, int code, int value); void published_key_event(int dest_fd, uint32_t seq_id, int64_t event_time); void published_motion_event(int dest_fd, uint32_t seq_id, int64_t event_time); void received_event_finished_signal(int src_fd, uint32_t seq_id); private: char const* component(); std::shared_ptr const logger; }; } } } #endif /* MIR_REPORT_LOGGING_INPUT_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/logging/scene_report.cpp0000644000015301777760000000610312322054223025126 0ustar pbusernogroup00000000000000/* * 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 */ #include "scene_report.h" #include "mir/logging/logger.h" #include namespace ml = mir::logging; namespace mrl = mir::report::logging; namespace { char const* const component = "scene"; } mrl::SceneReport::SceneReport(std::shared_ptr const& logger) : logger(logger) { } void mrl::SceneReport::surface_created(BasicSurfaceId id, std::string const& name) { std::lock_guard lock(mutex); surfaces[id] = name; std::stringstream ss; ss << "surface_created(" << id << " [\"" << name << "\"])"; logger->log(ml::Logger::informational, ss.str(), component); } void mrl::SceneReport::surface_added(BasicSurfaceId id, std::string const& name) { std::lock_guard lock(mutex); auto const i = surfaces.find(id); std::stringstream ss; ss << "surface_added(" << id << " [\"" << name << "\"])"; if (i == surfaces.end()) { ss << " - ERROR not reported to surface_created()"; } else if (name != i->second) { ss << " - WARNING name changed from " << i->second; } ss << " - INFO surface count=" << surfaces.size(); logger->log(ml::Logger::informational, ss.str(), component); } void mrl::SceneReport::surface_removed(BasicSurfaceId id, std::string const& name) { std::lock_guard lock(mutex); auto const i = surfaces.find(id); std::stringstream ss; ss << "surface_removed(" << id << " [\"" << name << "\"])"; if (i == surfaces.end()) { ss << " - ERROR not reported to surface_created()"; } else if (name != i->second) { ss << " - WARNING name changed from " << i->second; } ss << " - INFO surface count=" << surfaces.size(); logger->log(ml::Logger::informational, ss.str(), component); } void mrl::SceneReport::surface_deleted(BasicSurfaceId id, std::string const& name) { std::lock_guard lock(mutex); auto const i = surfaces.find(id); std::stringstream ss; ss << "surface_deleted(" << id << " [\"" << name << "\"])"; if (i == surfaces.end()) { ss << " - ERROR not reported to surface_created()"; } else if (name != i->second) { ss << " - WARNING name changed from " << i->second; } if (i != surfaces.end()) surfaces.erase(i); ss << " - INFO surface count=" << surfaces.size() << std::endl; logger->log(ml::Logger::informational, ss.str(), component); } mir-0.1.8+14.04.20140411/src/server/report/logging/input_report.cpp0000644000015301777760000000760112322054223025174 0ustar pbusernogroup00000000000000/* * 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 */ #include "input_report.h" #include "mir/report/legacy_input_report.h" #include "mir/logging/logger.h" #include "mir/logging/input_timestamp.h" #include "std/MirLog.h" #include #include #include #include namespace mrl = mir::report::logging; namespace ml = mir::logging; namespace mrli = mir::report::legacy_input; namespace { char const* const component = "android-input"; class LegacyInputReport; std::mutex mutex; std::shared_ptr the_legacy_input_report; class LegacyInputReport { public: LegacyInputReport(std::shared_ptr const& logger) : logger(logger) { } void log(int prio, char const* buffer) { switch (prio) { case ANDROID_LOG_UNKNOWN: case ANDROID_LOG_DEFAULT: case ANDROID_LOG_VERBOSE: case ANDROID_LOG_DEBUG: logger->log(ml::Logger::debug, buffer, component); break; case ANDROID_LOG_INFO: logger->log(ml::Logger::informational, buffer, component); break; case ANDROID_LOG_WARN: logger->log(ml::Logger::warning, buffer, component); break; case ANDROID_LOG_ERROR: logger->log(ml::Logger::error, buffer, component); }; } private: std::shared_ptr const logger; }; void my_write_to_log(int prio, char const* buffer) { std::unique_lock lock(mutex); the_legacy_input_report->log(prio, buffer); } } void mrli::initialize(std::shared_ptr const& logger) { std::unique_lock lock(mutex); ::the_legacy_input_report = std::make_shared(logger); mir::write_to_log = my_write_to_log; } mrl::InputReport::InputReport(const std::shared_ptr& logger) : logger(logger) { } const char* mrl::InputReport::component() { static const char* s = "input"; return s; } void mrl::InputReport::received_event_from_kernel(int64_t when, int type, int code, int value) { std::stringstream ss; ss << "Received event" << " time=" << ml::input_timestamp(when) << " type=" << type << " code=" << code << " value=" << value; logger->log(ml::Logger::informational, ss.str(), component()); } void mrl::InputReport::published_key_event(int dest_fd, uint32_t seq_id, int64_t event_time) { std::stringstream ss; ss << "Published key event" << " seq_id=" << seq_id << " time=" << ml::input_timestamp(event_time) << " dest_fd=" << dest_fd; logger->log(ml::Logger::informational, ss.str(), component()); } void mrl::InputReport::published_motion_event(int dest_fd, uint32_t seq_id, int64_t event_time) { std::stringstream ss; ss << "Published motion event" << " seq_id=" << seq_id << " time=" << ml::input_timestamp(event_time) << " dest_fd=" << dest_fd; logger->log(ml::Logger::informational, ss.str(), component()); } void mrl::InputReport::received_event_finished_signal(int src_fd, uint32_t seq_id) { std::stringstream ss; ss << "Received event finished" << " seq_id=" << seq_id << " src_fd=" << src_fd; logger->log(ml::Logger::informational, ss.str(), component()); } mir-0.1.8+14.04.20140411/src/server/report/lttng_report_factory.h0000644000015301777760000000275412322054223024737 0ustar pbusernogroup00000000000000/* * 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_REPORT_LTTNG_REPORT_FACTORY_H_ #define MIR_REPORT_LTTNG_REPORT_FACTORY_H_ #include "report_factory.h" namespace mir { namespace report { class LttngReportFactory : public report::ReportFactory { public: std::shared_ptr create_compositor_report() override; std::shared_ptr create_display_report() override; std::shared_ptr create_scene_report() override; std::shared_ptr create_connector_report() override; std::shared_ptr create_session_mediator_report() override; std::shared_ptr create_message_processor_report() override; std::shared_ptr create_input_report() override; }; } } #endif mir-0.1.8+14.04.20140411/src/server/report/logging_report_factory.h0000644000015301777760000000353412322054223025232 0ustar pbusernogroup00000000000000/* * 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_REPORT_LOGGING_REPORT_FACTORY_H_ #define MIR_REPORT_LOGGING_REPORT_FACTORY_H_ #include "report_factory.h" namespace mir { namespace logging { class Logger; } namespace time { class Clock; } class DefaultServerConfiguration; namespace report { class LoggingReportFactory : public report::ReportFactory { public: LoggingReportFactory(std::shared_ptr const& logger, std::shared_ptr const& clock); std::shared_ptr create_compositor_report() override; std::shared_ptr create_display_report() override; std::shared_ptr create_scene_report() override; std::shared_ptr create_connector_report() override; std::shared_ptr create_session_mediator_report() override; std::shared_ptr create_message_processor_report() override; std::shared_ptr create_input_report() override; private: std::shared_ptr const logger; std::shared_ptr const clock; }; } } #endif mir-0.1.8+14.04.20140411/src/server/report/default_server_configuration.cpp0000644000015301777760000001011112322054223026743 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/default_server_configuration.h" #include "mir/options/configuration.h" #include "lttng_report_factory.h" #include "logging_report_factory.h" #include "null_report_factory.h" #include "mir/abnormal_exit.h" namespace mg = mir::graphics; namespace mf = mir::frontend; namespace mc = mir::compositor; namespace mi = mir::input; namespace ms = mir::scene; std::unique_ptr mir::DefaultServerConfiguration::report_factory(char const* report_opt) { auto opt = the_options()->get(report_opt); if (opt == options::log_opt_value) { return std::unique_ptr(new report::LoggingReportFactory(the_logger(), the_clock())); } else if (opt == options::lttng_opt_value) { return std::unique_ptr(new report::LttngReportFactory()); } else if (opt == options::off_opt_value) { return std::unique_ptr(new report::NullReportFactory()); } else { throw AbnormalExit(std::string("Invalid ") + report_opt + " option: " + opt + " (valid options are: \"" + options::off_opt_value + "\" and \"" + options::log_opt_value + "\" and \"" + options::lttng_opt_value + "\")"); } } auto mir::DefaultServerConfiguration::the_compositor_report() -> std::shared_ptr { return compositor_report( [this]()->std::shared_ptr { return report_factory(options::compositor_report_opt)->create_compositor_report(); }); } auto mir::DefaultServerConfiguration::the_connector_report() -> std::shared_ptr { return connector_report( [this]()->std::shared_ptr { return report_factory(options::connector_report_opt)->create_connector_report(); }); } auto mir::DefaultServerConfiguration::the_session_mediator_report() -> std::shared_ptr { return session_mediator_report( [this]()->std::shared_ptr { return report_factory(options::session_mediator_report_opt)->create_session_mediator_report(); }); } auto mir::DefaultServerConfiguration::the_message_processor_report() -> std::shared_ptr { return message_processor_report( [this]()->std::shared_ptr { return report_factory(options::msg_processor_report_opt)->create_message_processor_report(); }); } auto mir::DefaultServerConfiguration::the_display_report() -> std::shared_ptr { return display_report( [this]()->std::shared_ptr { return report_factory(options::display_report_opt)->create_display_report(); }); } auto mir::DefaultServerConfiguration::the_input_report() -> std::shared_ptr { return input_report( [this]()->std::shared_ptr { return report_factory(options::input_report_opt)->create_input_report(); }); } auto mir::DefaultServerConfiguration::the_scene_report() -> std::shared_ptr { return scene_report( [this]()->std::shared_ptr { return report_factory(options::scene_report_opt)->create_scene_report(); }); } mir-0.1.8+14.04.20140411/src/server/report/lttng/0000755000015301777760000000000012322054703021437 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/report/lttng/session_mediator_report.h0000644000015301777760000000351312322054223026551 0ustar pbusernogroup00000000000000/* * 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: Andreas Pokorny */ #ifndef MIR_REPORT_LTTNG_SESSION_MEDIATOR_REPORT_H_ #define MIR_REPORT_LTTNG_SESSION_MEDIATOR_REPORT_H_ #include "server_tracepoint_provider.h" #include "mir/frontend/session_mediator_report.h" namespace mir { namespace report { namespace lttng { // Interface for monitoring application activity class SessionMediatorReport : public frontend::SessionMediatorReport { public: void session_connect_called(std::string const& app_name) override; void session_create_surface_called(std::string const& app_name) override; void session_next_buffer_called(std::string const& app_name) override; void session_release_surface_called(std::string const& app_name) override; void session_disconnect_called(std::string const& app_name) override; void session_drm_auth_magic_called(std::string const& app_name) override; void session_configure_surface_called(std::string const& app_name) override; void session_configure_display_called(std::string const& app_name) override; void session_error(std::string const& app_name, char const* method, std::string const& what) override; private: ServerTracepointProvider tp_provider; }; } } } #endif mir-0.1.8+14.04.20140411/src/server/report/lttng/message_processor_report_tp.h0000644000015301777760000000562512322054223027436 0ustar pbusernogroup00000000000000/* * 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 */ #undef TRACEPOINT_PROVIDER #define TRACEPOINT_PROVIDER mir_server_msgproc #undef TRACEPOINT_INCLUDE #define TRACEPOINT_INCLUDE "./message_processor_report_tp.h" #if !defined(MIR_LTTNG_MESSAGE_PROCESSOR_REPORT_TP_H_) || defined(TRACEPOINT_HEADER_MULTI_READ) #define MIR_LTTNG_MESSAGE_PROCESSOR_REPORT_TP_H_ #include "lttng_utils.h" TRACEPOINT_EVENT_CLASS( mir_server_msgproc, method_event, TP_ARGS(const void*, mediator, int, id, const char*, method), TP_FIELDS( ctf_integer_hex(void*, mediator, mediator) ctf_integer(int, id, id) ctf_string(method, method) ) ) TRACEPOINT_EVENT_INSTANCE( mir_server_msgproc, method_event, received_invocation, TP_ARGS(const void*, mediator, int, id, const char*, method) ) TRACEPOINT_EVENT( mir_server_msgproc, completed_invocation, TP_ARGS(const void*, mediator, int, id, int, result), TP_FIELDS( ctf_integer_hex(void*, mediator, mediator) ctf_integer(int, id, id) ctf_integer(int, result, result) ) ) TRACEPOINT_EVENT_INSTANCE( mir_server_msgproc, method_event, unknown_method, TP_ARGS(const void*, mediator, int, id, char const*, method) ) TRACEPOINT_EVENT( mir_server_msgproc, exception_handled, TP_ARGS(const void*, mediator, int, id, char const*, exception), TP_FIELDS( ctf_integer_hex(void*, mediator, mediator) ctf_integer(int, id, id) ctf_string(exception, exception) ) ) TRACEPOINT_EVENT( mir_server_msgproc, exception_handled_wo_invocation, TP_ARGS(const void*, mediator, char const*, exception), TP_FIELDS( ctf_integer_hex(void*, mediator, mediator) ctf_string(exception, exception) ) ) TRACEPOINT_EVENT( mir_server_msgproc, sent_event, TP_ARGS(const void*, mediator, int, surface_id, int, attribute, int, value), TP_FIELDS( ctf_integer_hex(void*, mediator, mediator) ctf_integer(int, surface_id, surface_id) ctf_integer(int, attribute, attribute) ctf_integer(int, value, value) ) ) #include "lttng_utils_pop.h" #endif /* MIR_LTTNG_MESSAGE_PROCESSOR_REPORT_TP_H_ */ #include mir-0.1.8+14.04.20140411/src/server/report/lttng/compositor_report.h0000644000015301777760000000302412322054223025375 0ustar pbusernogroup00000000000000/* * 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_REPORT_LTTNG_COMPOSITOR_REPORT_H_ #define MIR_REPORT_LTTNG_COMPOSITOR_REPORT_H_ #include "server_tracepoint_provider.h" #include "mir/compositor/compositor_report.h" namespace mir { namespace report { namespace lttng { class CompositorReport : public compositor::CompositorReport { public: CompositorReport() = default; virtual ~CompositorReport() = default; void added_display(int width, int height, int x, int y, SubCompositorId id = 0) override; void began_frame(SubCompositorId id = 0) override; void finished_frame(bool bypassed, SubCompositorId id = 0) override; void started() override; void stopped() override; void scheduled() override; private: ServerTracepointProvider tp_provider; }; } // namespace lttng } // namespace report } // namespace mir #endif // MIR_REPORT_LTTNG_COMPOSITOR_REPORT_H_ mir-0.1.8+14.04.20140411/src/server/report/lttng/input_report_tp.h0000644000015301777760000000431712322054223025047 0ustar pbusernogroup00000000000000/* * 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 */ #undef TRACEPOINT_PROVIDER #define TRACEPOINT_PROVIDER mir_server_input #undef TRACEPOINT_INCLUDE #define TRACEPOINT_INCLUDE "./input_report_tp.h" #if !defined(MIR_LTTNG_INPUT_REPORT_TP_H_) || defined(TRACEPOINT_HEADER_MULTI_READ) #define MIR_LTTNG_INPUT_REPORT_TP_H_ #include "lttng_utils.h" TRACEPOINT_EVENT( mir_server_input, received_event_from_kernel, TP_ARGS(int64_t, when, int, type, int, code, int, value), TP_FIELDS( ctf_integer(int64_t, when, when) ctf_integer(int, type, type) ctf_integer(int, code, code) ctf_integer(int, value, value) ) ) TRACEPOINT_EVENT( mir_server_input, published_key_event, TP_ARGS(int, dest_fd, uint32_t, seq_id, int64_t, event_time), TP_FIELDS( ctf_integer(int, dest_fd, dest_fd) ctf_integer(uint32_t, seq_id, seq_id) ctf_integer(int64_t, event_time, event_time) ) ) TRACEPOINT_EVENT( mir_server_input, published_motion_event, TP_ARGS(int, dest_fd, uint32_t, seq_id, int64_t, event_time), TP_FIELDS( ctf_integer(int, dest_fd, dest_fd) ctf_integer(uint32_t, seq_id, seq_id) ctf_integer(int64_t, event_time, event_time) ) ) TRACEPOINT_EVENT( mir_server_input, received_event_finished_signal, TP_ARGS(int, src_fd, uint32_t, seq_id), TP_FIELDS( ctf_integer(int, src_fd, src_fd) ctf_integer(uint32_t, seq_id, seq_id) ) ) #include "lttng_utils_pop.h" #endif /* MIR_LTTNG_DISPLAY_REPORT_TP_H_ */ #include mir-0.1.8+14.04.20140411/src/server/report/lttng/compositor_report_tp.h0000644000015301777760000000416612322054223026110 0ustar pbusernogroup00000000000000/* * 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 */ #undef TRACEPOINT_PROVIDER #define TRACEPOINT_PROVIDER mir_server_compositor #undef TRACEPOINT_INCLUDE #define TRACEPOINT_INCLUDE "./compositor_report_tp.h" #if !defined(MIR_LTTNG_COMPOSITOR_REPORT_TP_H_) || defined(TRACEPOINT_HEADER_MULTI_READ) #define MIR_LTTNG_COMPOSITOR_REPORT_TP_H_ #include "lttng_utils.h" MIR_LTTNG_VOID_TRACE_CLASS(mir_server_compositor) #define COMPOSITOR_TRACE_POINT(name) MIR_LTTNG_VOID_TRACE_POINT(TRACEPOINT_PROVIDER, name) COMPOSITOR_TRACE_POINT(started) COMPOSITOR_TRACE_POINT(stopped) COMPOSITOR_TRACE_POINT(scheduled) #undef COMPOSITOR_TRACE_POINT TRACEPOINT_EVENT( mir_server_compositor, added_display, TP_ARGS(int, width, int, height, int, x, int, y, void const*, id), TP_FIELDS( ctf_integer(int, width, width) ctf_integer(int, height, height) ctf_integer(int, x, x) ctf_integer(int, y, y) ctf_integer_hex(uintptr_t, id, (uintptr_t)(id)) ) ) TRACEPOINT_EVENT( mir_server_compositor, began_frame, TP_ARGS(void const*, id), TP_FIELDS( ctf_integer_hex(uintptr_t, id, (uintptr_t)(id)) ) ) TRACEPOINT_EVENT( mir_server_compositor, finished_frame, TP_ARGS(int, bypassed, void const*, id), TP_FIELDS( ctf_integer(int, bypassed, bypassed) ctf_integer_hex(uintptr_t, id, (uintptr_t)(id)) ) ) #include "lttng_utils_pop.h" #endif /* MIR_LTTNG_COMPOSITOR_REPORT_TP_H_ */ #include mir-0.1.8+14.04.20140411/src/server/report/lttng/lttng_utils.h0000644000015301777760000000316612322054223024163 0ustar pbusernogroup00000000000000/* * 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 */ #include #include #ifdef __clang__ /* * TRACEPOINT_EVENT defines functions; since we disable tracepoints under clang * these functions are unused and so generate fatal warnings. * (see mir_tracepoint.h and http://sourceware.org/bugzilla/show_bug.cgi?id=13974) */ #pragma clang diagnostic push #pragma clang diagnostic warning "-Wunused-function" #endif #ifndef _MIR_LTTNG_UTILS_H_ #define _MIR_LTTNG_UTILS_H_ #define MIR_LTTNG_VOID_TRACE_CALL(klass, comp, name) \ void mir::report::lttng::klass::name() \ { \ mir_tracepoint(comp, name, 0); \ } #define MIR_LTTNG_VOID_TRACE_CLASS(comp) \ TRACEPOINT_EVENT_CLASS(comp, dummy_event, TP_ARGS(int,empty), TP_FIELDS(ctf_integer(int,empty,empty))) #define MIR_LTTNG_VOID_TRACE_POINT(comp, name) \ TRACEPOINT_EVENT_INSTANCE(comp, dummy_event, name, TP_ARGS(int,empty)) #endif mir-0.1.8+14.04.20140411/src/server/report/lttng/message_processor_report.h0000644000015301777760000000315712322054223026731 0ustar pbusernogroup00000000000000/* * 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_REPORT_LTTNG_MESSAGE_PROCESSOR_REPORT_H_ #define MIR_REPORT_LTTNG_MESSAGE_PROCESSOR_REPORT_H_ #include "server_tracepoint_provider.h" #include "mir/frontend/message_processor_report.h" namespace mir { namespace report { namespace lttng { class MessageProcessorReport : public mir::frontend::MessageProcessorReport { public: void received_invocation(void const* mediator, int id, std::string const& method); void completed_invocation(void const* mediator, int id, bool result); void unknown_method(void const* mediator, int id, std::string const& method); void exception_handled(void const* mediator, int id, std::exception const& error); void exception_handled(void const* mediator, std::exception const& error); void sent_event(void const* mediator, MirSurfaceEvent const& event); private: ServerTracepointProvider tp_provider; }; } } } #endif /* MIR_REPORT_LTTNG_MESSAGE_PROCESSOR_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/lttng/connector_report.cpp0000644000015301777760000000411412322054223025525 0ustar pbusernogroup00000000000000/* * 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 */ #include "connector_report.h" #include "mir/report/lttng/mir_tracepoint.h" #include #define TRACEPOINT_DEFINE #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE #include "connector_report_tp.h" #define CONNECTOR_TRACE_CALL(name) MIR_LTTNG_VOID_TRACE_CALL(ConnectorReport, mir_server_connector, name) CONNECTOR_TRACE_CALL(thread_start) CONNECTOR_TRACE_CALL(thread_end) #undef CONNECTOR_TRACE_CALL void mir::report::lttng::ConnectorReport::starting_threads(int count) { mir_tracepoint(mir_server_connector, starting_threads, count); } void mir::report::lttng::ConnectorReport::stopping_threads(int count) { mir_tracepoint(mir_server_connector, stopping_threads, count); } void mir::report::lttng::ConnectorReport::creating_session_for(int socket_handle) { mir_tracepoint(mir_server_connector, creating_session_for, socket_handle); } void mir::report::lttng::ConnectorReport::creating_socket_pair(int server_handle, int client_handle) { mir_tracepoint(mir_server_connector, creating_socket_pair, server_handle, client_handle); } void mir::report::lttng::ConnectorReport::listening_on(std::string const& endpoint) { mir_tracepoint(mir_server_connector, listening_on, endpoint.c_str()); } void mir::report::lttng::ConnectorReport::error(std::exception const& error) { mir_tracepoint(mir_server_connector, error, boost::diagnostic_information(error).c_str()); } mir-0.1.8+14.04.20140411/src/server/report/lttng/lttng_report_factory.cpp0000644000015301777760000000412312322054223026412 0ustar pbusernogroup00000000000000/* * 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 */ #include "../lttng_report_factory.h" #include "compositor_report.h" #include "connector_report.h" #include "display_report.h" #include "input_report.h" #include "message_processor_report.h" #include "scene_report.h" #include "session_mediator_report.h" std::shared_ptr mir::report::LttngReportFactory::create_compositor_report() { return std::make_shared(); } std::shared_ptr mir::report::LttngReportFactory::create_display_report() { return std::make_shared(); } std::shared_ptr mir::report::LttngReportFactory::create_scene_report() { return std::make_shared(); } std::shared_ptr mir::report::LttngReportFactory::create_connector_report() { return std::make_shared(); } std::shared_ptr mir::report::LttngReportFactory::create_session_mediator_report() { return std::make_shared(); } std::shared_ptr mir::report::LttngReportFactory::create_message_processor_report() { return std::make_shared(); } std::shared_ptr mir::report::LttngReportFactory::create_input_report() { return std::make_shared(); } mir-0.1.8+14.04.20140411/src/server/report/lttng/connector_report.h0000644000015301777760000000302512322054223025172 0ustar pbusernogroup00000000000000/* * 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_REPORT_LTTNG_CONNECTOR_REPORT_H_ #define MIR_REPORT_LTTNG_CONNECTOR_REPORT_H_ #include "server_tracepoint_provider.h" #include "mir/frontend/connector_report.h" #include #include namespace mir { namespace report { namespace lttng { class ConnectorReport : public frontend::ConnectorReport { public: void thread_start() override; void thread_end() override; void starting_threads(int count) override; void stopping_threads(int count) override; void creating_session_for(int socket_handle) override; void creating_socket_pair(int server_handle, int client_handle) override; void listening_on(std::string const& endpoint) override; void error(std::exception const& error) override; private: ServerTracepointProvider tp_provider; }; } } } #endif // MIR_REPORT_LTTNG_CONNECTOR_REPORT_H_ mir-0.1.8+14.04.20140411/src/server/report/lttng/scene_report_tp.h0000644000015301777760000000350112322054223024777 0ustar pbusernogroup00000000000000/* * 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 */ #undef TRACEPOINT_PROVIDER #define TRACEPOINT_PROVIDER mir_server_scene #undef TRACEPOINT_INCLUDE #define TRACEPOINT_INCLUDE "./scene_report_tp.h" #if !defined(MIR_LTTNG_SCENE_REPORT_TP_H_) || defined(TRACEPOINT_HEADER_MULTI_READ) #define MIR_LTTNG_SCENE_REPORT_TP_H_ #include #include #include "lttng_utils.h" #undef SCENE_TRACE_POINT TRACEPOINT_EVENT(TRACEPOINT_PROVIDER, surface_created, TP_ARGS(char const*, name), TP_FIELDS(ctf_string(name, name))) TRACEPOINT_EVENT(TRACEPOINT_PROVIDER, surface_added, TP_ARGS(char const*, name), TP_FIELDS(ctf_string(name, name))) TRACEPOINT_EVENT(TRACEPOINT_PROVIDER, surface_removed, TP_ARGS(char const*, name), TP_FIELDS(ctf_string(name, name))) TRACEPOINT_EVENT(TRACEPOINT_PROVIDER, surface_deleted, TP_ARGS(char const*, name), TP_FIELDS(ctf_string(name, name))) #include "lttng_utils_pop.h" #endif /* MIR_LTTNG_SCENE_REPORT_TP_H_ */ #include mir-0.1.8+14.04.20140411/src/server/report/lttng/compositor_report.cpp0000644000015301777760000000313112322054223025727 0ustar pbusernogroup00000000000000/* * 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 */ #include "compositor_report.h" #include "mir/report/lttng/mir_tracepoint.h" #define TRACEPOINT_DEFINE #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE #include "compositor_report_tp.h" #define COMPOSITOR_TRACE_CALL(name) MIR_LTTNG_VOID_TRACE_CALL(CompositorReport, mir_server_compositor, name) COMPOSITOR_TRACE_CALL(started) COMPOSITOR_TRACE_CALL(stopped) COMPOSITOR_TRACE_CALL(scheduled) #undef COMPOSITOR_TRACE_CALL void mir::report::lttng::CompositorReport::added_display(int width, int height, int x, int y, SubCompositorId id) { mir_tracepoint(mir_server_compositor, added_display, width, height, x, y, id); } void mir::report::lttng::CompositorReport::began_frame(SubCompositorId id) { mir_tracepoint(mir_server_compositor, began_frame, id); } void mir::report::lttng::CompositorReport::finished_frame(bool bypassed, SubCompositorId id) { mir_tracepoint(mir_server_compositor, finished_frame, bypassed, id); } mir-0.1.8+14.04.20140411/src/server/report/lttng/display_report.cpp0000644000015301777760000000377212322054223025211 0ustar pbusernogroup00000000000000/* * 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 */ #include "display_report.h" #include "mir/report/lttng/mir_tracepoint.h" #define TRACEPOINT_DEFINE #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE #include "display_report_tp.h" #include "lttng_utils.h" #define DISPLAY_REPORT_TRACE_CALL(name) MIR_LTTNG_VOID_TRACE_CALL(DisplayReport,mir_server_display,name) DISPLAY_REPORT_TRACE_CALL(report_successful_setup_of_native_resources) DISPLAY_REPORT_TRACE_CALL(report_successful_egl_make_current_on_construction) DISPLAY_REPORT_TRACE_CALL(report_successful_egl_buffer_swap_on_construction) DISPLAY_REPORT_TRACE_CALL(report_successful_display_construction) DISPLAY_REPORT_TRACE_CALL(report_successful_drm_mode_set_crtc_on_construction) DISPLAY_REPORT_TRACE_CALL(report_vt_switch_away_failure) DISPLAY_REPORT_TRACE_CALL(report_vt_switch_back_failure) DISPLAY_REPORT_TRACE_CALL(report_gpu_composition_in_use) #undef DISPLAY_REPORT_TRACE_CALL void mir::report::lttng::DisplayReport::report_egl_configuration(EGLDisplay /*disp*/, EGLConfig /*config*/) { } void mir::report::lttng::DisplayReport::report_drm_master_failure(int error) { mir_tracepoint(mir_server_display, report_drm_master_failure, strerror(error)); } void mir::report::lttng::DisplayReport::report_hwc_composition_in_use(int major, int minor) { mir_tracepoint(mir_server_display, report_hwc_composition_in_use, major, minor); } mir-0.1.8+14.04.20140411/src/server/report/lttng/session_mediator_report.cpp0000644000015301777760000000370212322054223027104 0ustar pbusernogroup00000000000000/* * 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 */ #include "session_mediator_report.h" #include "mir/report/lttng/mir_tracepoint.h" #define TRACEPOINT_DEFINE #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE #include "session_mediator_report_tp.h" #define MIR_SESSION_MEDIATOR_EVENT_METHOD(event) \ void mir::report::lttng::SessionMediatorReport::event(std::string const& app_name) \ { \ mir_tracepoint(mir_server_session_mediator, event, app_name.c_str()); \ } MIR_SESSION_MEDIATOR_EVENT_METHOD(session_connect_called) MIR_SESSION_MEDIATOR_EVENT_METHOD(session_create_surface_called) MIR_SESSION_MEDIATOR_EVENT_METHOD(session_next_buffer_called) MIR_SESSION_MEDIATOR_EVENT_METHOD(session_release_surface_called) MIR_SESSION_MEDIATOR_EVENT_METHOD(session_disconnect_called) MIR_SESSION_MEDIATOR_EVENT_METHOD(session_drm_auth_magic_called) MIR_SESSION_MEDIATOR_EVENT_METHOD(session_configure_surface_called) MIR_SESSION_MEDIATOR_EVENT_METHOD(session_configure_display_called) void mir::report::lttng::SessionMediatorReport::session_error(std::string const& app_name, char const* method, std::string const& what) { mir_tracepoint(mir_server_session_mediator, session_error, app_name.c_str(), method, what.c_str()); } mir-0.1.8+14.04.20140411/src/server/report/lttng/display_report.h0000644000015301777760000000344312322054223024651 0ustar pbusernogroup00000000000000/* * 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_REPORT_LTTNG_DISPLAY_REPORT_H_ #define MIR_REPORT_LTTNG_DISPLAY_REPORT_H_ #include "server_tracepoint_provider.h" #include "mir/graphics/display_report.h" namespace mir { namespace report { namespace lttng { class DisplayReport : public graphics::DisplayReport { public: DisplayReport() = default; virtual ~DisplayReport() noexcept(true) = default; virtual void report_successful_setup_of_native_resources(); virtual void report_successful_egl_make_current_on_construction(); virtual void report_successful_egl_buffer_swap_on_construction(); virtual void report_successful_display_construction(); virtual void report_egl_configuration(EGLDisplay disp, EGLConfig cfg); virtual void report_successful_drm_mode_set_crtc_on_construction(); virtual void report_drm_master_failure(int error); virtual void report_vt_switch_away_failure(); virtual void report_vt_switch_back_failure(); virtual void report_hwc_composition_in_use(int major, int minor); virtual void report_gpu_composition_in_use(); private: ServerTracepointProvider tp_provider; }; } } } #endif mir-0.1.8+14.04.20140411/src/server/report/lttng/server_tracepoint_provider.cpp0000644000015301777760000000170212322054223027610 0ustar pbusernogroup00000000000000/* * 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 */ #include "server_tracepoint_provider.h" namespace { std::string const server_tp_provider_lib_name{"libmirserverlttng.so"}; } mir::report::lttng::ServerTracepointProvider::ServerTracepointProvider() : TracepointProvider{server_tp_provider_lib_name} { } mir-0.1.8+14.04.20140411/src/server/report/lttng/connector_report_tp.h0000644000015301777760000000454412322054223025704 0ustar pbusernogroup00000000000000/* * 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 */ #undef TRACEPOINT_PROVIDER #define TRACEPOINT_PROVIDER mir_server_connector #undef TRACEPOINT_INCLUDE #define TRACEPOINT_INCLUDE "./connector_report_tp.h" #if !defined(MIR_LTTNG_CONNECTOR_REPORT_TP_H_) || defined(TRACEPOINT_HEADER_MULTI_READ) #define MIR_LTTNG_CONNECTOR_REPORT_TP_H_ #include "lttng_utils.h" MIR_LTTNG_VOID_TRACE_CLASS(mir_server_connector) #define CONNECTOR_TRACE_POINT(name) MIR_LTTNG_VOID_TRACE_POINT(mir_server_connector, name) CONNECTOR_TRACE_POINT(thread_start) CONNECTOR_TRACE_POINT(thread_end) CONNECTOR_TRACE_POINT(scheduled) #undef CONNECTOR_TRACE_POINT TRACEPOINT_EVENT(TRACEPOINT_PROVIDER, starting_threads, TP_ARGS(int, count), TP_FIELDS(ctf_integer(int, count, count))) TRACEPOINT_EVENT(TRACEPOINT_PROVIDER, stopping_threads, TP_ARGS(int, count), TP_FIELDS(ctf_integer(int, count, count))) TRACEPOINT_EVENT(TRACEPOINT_PROVIDER, creating_session_for, TP_ARGS(int, socket), TP_FIELDS(ctf_integer(int, socket, socket))) TRACEPOINT_EVENT(TRACEPOINT_PROVIDER, creating_socket_pair, TP_ARGS(int, server, int, client), TP_FIELDS(ctf_integer(int, server, server) ctf_integer(int, client, client))) TRACEPOINT_EVENT(TRACEPOINT_PROVIDER, listening_on, TP_ARGS(char const*, endpoint), TP_FIELDS(ctf_string(endpoint, endpoint))) TRACEPOINT_EVENT(TRACEPOINT_PROVIDER, error, TP_ARGS(char const*, diagnostics), TP_FIELDS(ctf_string(diagnostics, diagnostics))) #include "lttng_utils_pop.h" #endif /* MIR_LTTNG_CONNECTOR_REPORT_TP_H_ */ #include mir-0.1.8+14.04.20140411/src/server/report/lttng/scene_report.h0000644000015301777760000000255512322054223024304 0ustar pbusernogroup00000000000000/* * 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_REPORT_LTTNG_SCENE_REPORT_H_ #define MIR_REPORT_LTTNG_SCENE_REPORT_H_ #include "server_tracepoint_provider.h" #include "mir/scene/scene_report.h" namespace mir { namespace report { namespace lttng { class SceneReport : public scene::SceneReport { public: void surface_created(BasicSurfaceId id, std::string const& name) override; void surface_added(BasicSurfaceId id, std::string const& name) override; void surface_removed(BasicSurfaceId id, std::string const& name) override; void surface_deleted(BasicSurfaceId id, std::string const& name) override; private: ServerTracepointProvider tp_provider; }; } } } #endif /* MIR_REPORT_LTTNG_SCENE_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/lttng/message_processor_report.cpp0000644000015301777760000000425112322054223027260 0ustar pbusernogroup00000000000000/* * 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 */ #include "message_processor_report.h" #include "mir/report/lttng/mir_tracepoint.h" #define TRACEPOINT_DEFINE #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE #include "message_processor_report_tp.h" void mir::report::lttng::MessageProcessorReport::received_invocation( void const* mediator, int id, std::string const& method) { mir_tracepoint(mir_server_msgproc, received_invocation, mediator, id, method.c_str()); } void mir::report::lttng::MessageProcessorReport::completed_invocation( void const* mediator, int id, bool result) { mir_tracepoint(mir_server_msgproc, completed_invocation, mediator, id, result); } void mir::report::lttng::MessageProcessorReport::unknown_method( void const* mediator, int id, std::string const& method) { mir_tracepoint(mir_server_msgproc, unknown_method, mediator, id, method.c_str()); } void mir::report::lttng::MessageProcessorReport::exception_handled( void const* mediator, int id, std::exception const& error) { mir_tracepoint(mir_server_msgproc, exception_handled, mediator, id, error.what()); } void mir::report::lttng::MessageProcessorReport::exception_handled( void const* mediator, std::exception const& error) { mir_tracepoint(mir_server_msgproc, exception_handled_wo_invocation, mediator, error.what()); } void mir::report::lttng::MessageProcessorReport::sent_event( void const* mediator, MirSurfaceEvent const& event) { mir_tracepoint(mir_server_msgproc, sent_event, mediator, event.id, event.attrib, event.value); } mir-0.1.8+14.04.20140411/src/server/report/lttng/CMakeLists.txt0000644000015301777760000000201612322054223024173 0ustar pbusernogroup00000000000000include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${LTTNG_UST_INCLUDE_DIRS}) set( LTTNG_SOURCES compositor_report.cpp connector_report.cpp display_report.cpp input_report.cpp message_processor_report.cpp lttng_report_factory.cpp session_mediator_report.cpp scene_report.cpp server_tracepoint_provider.cpp ) add_library( mirlttng STATIC ${LTTNG_SOURCES} ) add_library(mirserverlttng SHARED tracepoints.c) # Don't treat missing-field-initializers as an error, since # the LTTng macros contain code that triggers this (but it's # harmless; it concerns a padding field) set_target_properties(mirlttng PROPERTIES COMPILE_FLAGS "-Wno-error=missing-field-initializers -Wno-error=unused-function" ) set_target_properties(mirserverlttng PROPERTIES COMPILE_FLAGS "-Wno-error=unused-function" ) target_link_libraries( mirlttng mirsharedlttng -ldl ) target_link_libraries( mirserverlttng ${LTTNG_UST_LIBRARIES} ) install(TARGETS mirserverlttng LIBRARY DESTINATION ${MIR_TRACEPOINT_LIB_INSTALL_DIR} ) mir-0.1.8+14.04.20140411/src/server/report/lttng/session_mediator_report_tp.h0000644000015301777760000000437712322054223027265 0ustar pbusernogroup00000000000000/* * 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 */ #undef TRACEPOINT_PROVIDER #define TRACEPOINT_PROVIDER mir_server_session_mediator #undef TRACEPOINT_INCLUDE #define TRACEPOINT_INCLUDE "./session_mediator_report_tp.h" #if !defined(MIR_LTTNG_SESSION_MEDIATOR_REPORT_TP_H_) || defined(TRACEPOINT_HEADER_MULTI_READ) #define MIR_LTTNG_SESSION_MEDIATOR_REPORT_TP_H_ #include "lttng_utils.h" TRACEPOINT_EVENT_CLASS( mir_server_session_mediator, application_event, TP_ARGS(char const*, application), TP_FIELDS( ctf_string(application, application) ) ) #define MIR_SESSION_MEDIATOR_EVENT(event) \ TRACEPOINT_EVENT_INSTANCE(mir_server_session_mediator, application_event, event, TP_ARGS(char const*, application)) MIR_SESSION_MEDIATOR_EVENT(session_connect_called) MIR_SESSION_MEDIATOR_EVENT(session_create_surface_called) MIR_SESSION_MEDIATOR_EVENT(session_next_buffer_called) MIR_SESSION_MEDIATOR_EVENT(session_release_surface_called) MIR_SESSION_MEDIATOR_EVENT(session_disconnect_called) MIR_SESSION_MEDIATOR_EVENT(session_drm_auth_magic_called) MIR_SESSION_MEDIATOR_EVENT(session_configure_surface_called) MIR_SESSION_MEDIATOR_EVENT(session_configure_display_called) TRACEPOINT_EVENT( mir_server_session_mediator, session_error, TP_ARGS(char const*, application, char const*, method, char const*, what), TP_FIELDS( ctf_string(application, application) ctf_string(method, method) ctf_string(what, what) ) ) #undef MIR_SESSION_MEDIATOR_EVENT #include "lttng_utils_pop.h" #endif /* MIR_LTTNG_SESSION_MEDIATOR_REPORT_TP_H_ */ #include mir-0.1.8+14.04.20140411/src/server/report/lttng/tracepoints.c0000644000015301777760000000051212322054223024131 0ustar pbusernogroup00000000000000/* The probes need to be compiled in a C file (not C++) */ #define TRACEPOINT_CREATE_PROBES #include "compositor_report_tp.h" #include "input_report_tp.h" #include "connector_report_tp.h" #include "display_report_tp.h" #include "session_mediator_report_tp.h" #include "scene_report_tp.h" #include "message_processor_report_tp.h" mir-0.1.8+14.04.20140411/src/server/report/lttng/input_report.h0000644000015301777760000000273612322054223024347 0ustar pbusernogroup00000000000000/* * 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_LTTNG_INPUT_REPORT_H_ #define MIR_REPORT_LTTNG_INPUT_REPORT_H_ #include "server_tracepoint_provider.h" #include "mir/input/input_report.h" namespace mir { namespace report { namespace lttng { class InputReport : public input::InputReport { public: InputReport() = default; virtual ~InputReport() noexcept(true) = default; void received_event_from_kernel(int64_t when, int type, int code, int value) override; void published_key_event(int dest_fd, uint32_t seq_id, int64_t event_time) override; void published_motion_event(int dest_fd, uint32_t seq_id, int64_t event_time) override; void received_event_finished_signal(int src_fd, uint32_t seq_id) override; private: ServerTracepointProvider tp_provider; }; } } } #endif /* MIR_REPORT_LTTNG_INPUT_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/lttng/display_report_tp.h0000644000015301777760000000430212322054223025347 0ustar pbusernogroup00000000000000/* * 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 */ #undef TRACEPOINT_PROVIDER #define TRACEPOINT_PROVIDER mir_server_display #undef TRACEPOINT_INCLUDE #define TRACEPOINT_INCLUDE "./display_report_tp.h" #if !defined(MIR_LTTNG_DISPLAY_REPORT_TP_H_) || defined(TRACEPOINT_HEADER_MULTI_READ) #define MIR_LTTNG_DISPLAY_REPORT_TP_H_ #include "lttng_utils.h" MIR_LTTNG_VOID_TRACE_CLASS(mir_server_display) #define DISPLAY_REPORT_TRACE_POINT(name) MIR_LTTNG_VOID_TRACE_POINT(mir_server_display,name) DISPLAY_REPORT_TRACE_POINT(report_successful_setup_of_native_resources) DISPLAY_REPORT_TRACE_POINT(report_successful_egl_make_current_on_construction) DISPLAY_REPORT_TRACE_POINT(report_successful_egl_buffer_swap_on_construction) DISPLAY_REPORT_TRACE_POINT(report_successful_display_construction) DISPLAY_REPORT_TRACE_POINT(report_successful_drm_mode_set_crtc_on_construction) DISPLAY_REPORT_TRACE_POINT(report_vt_switch_away_failure) DISPLAY_REPORT_TRACE_POINT(report_vt_switch_back_failure) DISPLAY_REPORT_TRACE_POINT(report_gpu_composition_in_use) #undef DISPLAY_REPORT_TRACE_POINT TRACEPOINT_EVENT( mir_server_display, report_drm_master_failure, TP_ARGS(char const*, error_string), TP_FIELDS( ctf_string(error_string, error_string) ) ) TRACEPOINT_EVENT( mir_server_display, report_hwc_composition_in_use, TP_ARGS(int, major, int, minor), TP_FIELDS( ctf_integer(int, major, major) ctf_integer(int, minor, minor) ) ) #include "lttng_utils_pop.h" #endif /* MIR_LTTNG_DISPLAY_REPORT_TP_H_ */ #include mir-0.1.8+14.04.20140411/src/server/report/lttng/scene_report.cpp0000644000015301777760000000300012322054223024621 0ustar pbusernogroup00000000000000/* * 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 */ #include "scene_report.h" #include "mir/report/lttng/mir_tracepoint.h" #define TRACEPOINT_DEFINE #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE #include "scene_report_tp.h" void mir::report::lttng::SceneReport::surface_created(BasicSurfaceId, std::string const& name) { mir_tracepoint(mir_server_scene, surface_created, name.c_str()); } void mir::report::lttng::SceneReport::surface_added(BasicSurfaceId, std::string const& name) { mir_tracepoint(mir_server_scene, surface_added, name.c_str()); } void mir::report::lttng::SceneReport::surface_removed(BasicSurfaceId, std::string const& name) { mir_tracepoint(mir_server_scene, surface_removed, name.c_str()); } void mir::report::lttng::SceneReport::surface_deleted(BasicSurfaceId, std::string const& name) { mir_tracepoint(mir_server_scene, surface_deleted, name.c_str()); } mir-0.1.8+14.04.20140411/src/server/report/lttng/input_report.cpp0000644000015301777760000000317112322054223024674 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/report/lttng/mir_tracepoint.h" #include "input_report.h" #define TRACEPOINT_DEFINE #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE #include "input_report_tp.h" void mir::report::lttng::InputReport::received_event_from_kernel(int64_t when, int type, int code, int value) { mir_tracepoint(mir_server_input, received_event_from_kernel, when, type, code, value); } void mir::report::lttng::InputReport::published_key_event(int dest_fd, uint32_t seq_id, int64_t event_time) { mir_tracepoint(mir_server_input, published_key_event, dest_fd, seq_id, event_time); } void mir::report::lttng::InputReport::published_motion_event(int dest_fd, uint32_t seq_id, int64_t event_time) { mir_tracepoint(mir_server_input, published_motion_event, dest_fd, seq_id, event_time); } void mir::report::lttng::InputReport::received_event_finished_signal(int src_fd, uint32_t seq_id) { mir_tracepoint(mir_server_input, received_event_finished_signal, src_fd, seq_id); } mir-0.1.8+14.04.20140411/src/server/report/lttng/lttng_utils_pop.h0000644000015301777760000000135612322054223025040 0ustar pbusernogroup00000000000000/* * 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 */ #ifdef __clang__ #pragma clang diagnostic pop #endif mir-0.1.8+14.04.20140411/src/server/report/lttng/server_tracepoint_provider.h0000644000015301777760000000210312322054223027251 0ustar pbusernogroup00000000000000/* * 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_LTTNG_SERVER_TRACEPOINT_PROVIDER_H_ #define MIR_LTTNG_SERVER_TRACEPOINT_PROVIDER_H_ #include "mir/report/lttng/tracepoint_provider.h" namespace mir { namespace report { namespace lttng { class ServerTracepointProvider : public mir::report::lttng::TracepointProvider { public: ServerTracepointProvider(); }; } } } #endif /* MIR_LTTNG_SERVER_TRACEPOINT_PROVIDER_H_ */ mir-0.1.8+14.04.20140411/src/server/report/null_report_factory.h0000644000015301777760000000372112322054223024554 0ustar pbusernogroup00000000000000/* * 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_REPORT_NULL_REPORT_FACTORY_H_ #define MIR_REPORT_NULL_REPORT_FACTORY_H_ #include "report_factory.h" namespace mir { namespace report { class NullReportFactory : public mir::report::ReportFactory { public: std::shared_ptr create_compositor_report() override; std::shared_ptr create_display_report() override; std::shared_ptr create_scene_report() override; std::shared_ptr create_connector_report() override; std::shared_ptr create_session_mediator_report() override; std::shared_ptr create_message_processor_report() override; std::shared_ptr create_input_report() override; }; std::shared_ptr null_compositor_report(); std::shared_ptr null_display_report(); std::shared_ptr null_scene_report(); std::shared_ptr null_connector_report(); std::shared_ptr null_session_mediator_report(); std::shared_ptr null_message_processor_report(); std::shared_ptr null_input_report(); } } #endif mir-0.1.8+14.04.20140411/src/server/report/report_factory.h0000644000015301777760000000370212322054223023521 0ustar pbusernogroup00000000000000/* * 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_REPORT_REPORT_FACTORY_H_ #define MIR_REPORT_REPORT_FACTORY_H_ #include namespace mir { namespace compositor { class CompositorReport; } namespace frontend { class ConnectorReport; class SessionMediatorReport; class MessageProcessorReport; } namespace graphics { class DisplayReport; } namespace input { class InputReport; } namespace scene { class SceneReport; } namespace report { class ReportFactory { public: virtual ~ReportFactory() = default; virtual std::shared_ptr create_compositor_report() = 0; virtual std::shared_ptr create_display_report() = 0; virtual std::shared_ptr create_scene_report() = 0; virtual std::shared_ptr create_connector_report() = 0; virtual std::shared_ptr create_session_mediator_report() = 0; virtual std::shared_ptr create_message_processor_report() = 0; virtual std::shared_ptr create_input_report() = 0; protected: ReportFactory() = default; ReportFactory(ReportFactory const&) = delete; ReportFactory& operator=(ReportFactory const &) = delete; }; } } #endif /* MIR_REPORT_REPORT_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/server/report/CMakeLists.txt0000644000015301777760000000034112322054223023042 0ustar pbusernogroup00000000000000add_subdirectory(logging) add_subdirectory(lttng) add_subdirectory(null) add_library( mirreport STATIC default_server_configuration.cpp ) target_link_libraries(mirreport mirserverlttng mirlogging mirnullreport) mir-0.1.8+14.04.20140411/src/server/report/null/0000755000015301777760000000000012322054703021261 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/report/null/session_mediator_report.h0000644000015301777760000000360612322054223026376 0ustar pbusernogroup00000000000000/* * 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 * Andreas Pokorny */ #ifndef MIR_REPORT_NULL_SESSION_MEDIATOR_REPORT_H_ #define MIR_REPORT_NULL_SESSION_MEDIATOR_REPORT_H_ #include "mir/frontend/session_mediator_report.h" #include namespace mir { namespace report { namespace null { // Do-nothing implementation to satisfy dependencies class SessionMediatorReport : public frontend::SessionMediatorReport { void session_connect_called(std::string const& app_name) override; void session_create_surface_called(std::string const& app_name) override; void session_next_buffer_called(std::string const& app_name) override; void session_release_surface_called(std::string const& app_name) override; void session_disconnect_called(std::string const& app_name) override; void session_drm_auth_magic_called(std::string const& app_name) override; void session_configure_surface_called(std::string const& app_name) override; void session_configure_display_called(std::string const& app_name) override; void session_error( std::string const& app_name, char const* method, std::string const& what) override; }; } } } #endif /* MIR_FRONTEND_SESSION_MEDIATOR_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/null/compositor_report.h0000644000015301777760000000254012322054223025221 0ustar pbusernogroup00000000000000/* * 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_REPORT_NULL_COMPOSITOR_REPORT_H_ #define MIR_REPORT_NULL_COMPOSITOR_REPORT_H_ #include "mir/compositor/compositor_report.h" namespace mir { namespace report { namespace null { class CompositorReport : public compositor::CompositorReport { public: void added_display(int width, int height, int x, int y, SubCompositorId id) override; void began_frame(SubCompositorId id) override; void finished_frame(bool bypassed, SubCompositorId id) override; void started() override; void stopped() override; void scheduled() override; }; } // namespace compositor } // namespace report } // namespace mir #endif // MIR_REPORT_NULL_COMPOSITOR_REPORT_H_ mir-0.1.8+14.04.20140411/src/server/report/null/message_processor_report.h0000644000015301777760000000261712322054223026553 0ustar pbusernogroup00000000000000/* * 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_REPORT_NULL_MESSAGE_PROCESSOR_REPORT_H_ #define MIR_REPORT_NULL_MESSAGE_PROCESSOR_REPORT_H_ #include "mir/frontend/message_processor_report.h" namespace mir { namespace report { namespace null { class MessageProcessorReport : public frontend::MessageProcessorReport { void received_invocation(void const*, int, std::string const&); void completed_invocation(void const*, int, bool); void unknown_method(void const*, int, std::string const&); void exception_handled(void const*, int, std::exception const&); void exception_handled(void const*, std::exception const&); void sent_event(void const*, MirSurfaceEvent const& e); }; } } } #endif /* MIR_REPORT_NULL_MESSAGE_PROCESSOR_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/null/connector_report.cpp0000644000015301777760000000241412322054223025350 0ustar pbusernogroup00000000000000/* * 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 */ #include "connector_report.h" namespace mrn = mir::report::null; void mrn::ConnectorReport::thread_start() {} void mrn::ConnectorReport::thread_end() {} void mrn::ConnectorReport::starting_threads(int /*count*/) {} void mrn::ConnectorReport::stopping_threads(int /*count*/) {} void mrn::ConnectorReport::creating_session_for(int /*socket_handle*/) {} void mrn::ConnectorReport::creating_socket_pair(int /*server_handle*/, int /*client_handle*/) {} void mrn::ConnectorReport::listening_on(std::string const& /*endpoint*/) {} void mrn::ConnectorReport::error(std::exception const& /*error*/) {} mir-0.1.8+14.04.20140411/src/server/report/null/null_report_factory.cpp0000644000015301777760000000612512322054223026062 0ustar pbusernogroup00000000000000/* * 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 */ #include "../null_report_factory.h" #include "compositor_report.h" #include "connector_report.h" #include "message_processor_report.h" #include "session_mediator_report.h" #include "display_report.h" #include "input_report.h" #include "scene_report.h" std::shared_ptr mir::report::NullReportFactory::create_compositor_report() { return std::make_shared(); } std::shared_ptr mir::report::NullReportFactory::create_display_report() { return std::make_shared(); } std::shared_ptr mir::report::NullReportFactory::create_scene_report() { return std::make_shared(); } std::shared_ptr mir::report::NullReportFactory::create_connector_report() { return std::make_shared(); } std::shared_ptr mir::report::NullReportFactory::create_session_mediator_report() { return std::make_shared(); } std::shared_ptr mir::report::NullReportFactory::create_message_processor_report() { return std::make_shared(); } std::shared_ptr mir::report::NullReportFactory::create_input_report() { return std::make_shared(); } std::shared_ptr mir::report::null_compositor_report() { return NullReportFactory{}.create_compositor_report(); } std::shared_ptr mir::report::null_display_report() { return NullReportFactory{}.create_display_report(); } std::shared_ptr mir::report::null_scene_report() { return NullReportFactory{}.create_scene_report(); } std::shared_ptr mir::report::null_connector_report() { return NullReportFactory{}.create_connector_report(); } std::shared_ptr mir::report::null_session_mediator_report() { return NullReportFactory{}.create_session_mediator_report(); } std::shared_ptr mir::report::null_message_processor_report() { return NullReportFactory{}.create_message_processor_report(); } std::shared_ptr mir::report::null_input_report() { return NullReportFactory{}.create_input_report(); } mir-0.1.8+14.04.20140411/src/server/report/null/connector_report.h0000644000015301777760000000261412322054223025017 0ustar pbusernogroup00000000000000/* * 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_REPORT_NULL_CONNECTOR_REPORT_H_ #define MIR_REPORT_NULL_CONNECTOR_REPORT_H_ #include "mir/frontend/connector_report.h" namespace mir { namespace report { namespace null { class ConnectorReport : public frontend::ConnectorReport { public: void thread_start() override; void thread_end() override; void starting_threads(int count) override; void stopping_threads(int count) override; void creating_session_for(int socket_handle) override; void creating_socket_pair(int server_handle, int client_handle) override; void listening_on(std::string const& endpoint) override; void error(std::exception const& error) override; }; } } } #endif // MIR_REPORT_NULL_CONNECTOR_REPORT_H_ mir-0.1.8+14.04.20140411/src/server/report/null/compositor_report.cpp0000644000015301777760000000212712322054223025555 0ustar pbusernogroup00000000000000/* * 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 */ #include "compositor_report.h" namespace mrn = mir::report::null; void mrn::CompositorReport::added_display(int, int, int, int, SubCompositorId) { } void mrn::CompositorReport::began_frame(SubCompositorId) { } void mrn::CompositorReport::finished_frame(bool, SubCompositorId) { } void mrn::CompositorReport::started() { } void mrn::CompositorReport::stopped() { } void mrn::CompositorReport::scheduled() { } mir-0.1.8+14.04.20140411/src/server/report/null/display_report.cpp0000644000015301777760000000275712322054223025035 0ustar pbusernogroup00000000000000/* * 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 */ #include "display_report.h" namespace mrn = mir::report::null; void mrn::DisplayReport::report_successful_setup_of_native_resources() {} void mrn::DisplayReport::report_successful_egl_make_current_on_construction() {} void mrn::DisplayReport::report_successful_egl_buffer_swap_on_construction() {} void mrn::DisplayReport::report_successful_drm_mode_set_crtc_on_construction() {} void mrn::DisplayReport::report_successful_display_construction() {} void mrn::DisplayReport::report_drm_master_failure(int) {} void mrn::DisplayReport::report_vt_switch_away_failure() {} void mrn::DisplayReport::report_vt_switch_back_failure() {} void mrn::DisplayReport::report_hwc_composition_in_use(int, int) {} void mrn::DisplayReport::report_gpu_composition_in_use() {} void mrn::DisplayReport::report_egl_configuration(EGLDisplay, EGLConfig) {} mir-0.1.8+14.04.20140411/src/server/report/null/session_mediator_report.cpp0000644000015301777760000000321512322054223026725 0ustar pbusernogroup00000000000000/* * 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 */ #include "session_mediator_report.h" void mir::report::null::SessionMediatorReport::session_connect_called(std::string const&) { } void mir::report::null::SessionMediatorReport::session_create_surface_called(std::string const&) { } void mir::report::null::SessionMediatorReport::session_next_buffer_called(std::string const&) { } void mir::report::null::SessionMediatorReport::session_release_surface_called(std::string const&) { } void mir::report::null::SessionMediatorReport::session_disconnect_called(std::string const&) { } void mir::report::null::SessionMediatorReport::session_drm_auth_magic_called(std::string const&) { } void mir::report::null::SessionMediatorReport::session_configure_surface_called(std::string const&) { } void mir::report::null::SessionMediatorReport::session_configure_display_called(std::string const&) { } void mir::report::null::SessionMediatorReport::session_error( std::string const&, char const* , std::string const& ) { } mir-0.1.8+14.04.20140411/src/server/report/null/display_report.h0000644000015301777760000000322512322054223024471 0ustar pbusernogroup00000000000000/* * 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_REPORT_NULL_DISPLAY_REPORT_H_ #define MIR_REPORT_NULL_DISPLAY_REPORT_H_ #include "mir/graphics/display_report.h" namespace mir { namespace report { namespace null { class DisplayReport : public graphics::DisplayReport { public: 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_drm_mode_set_crtc_on_construction() override; void report_successful_display_construction() override; void report_drm_master_failure(int error) override; void report_vt_switch_away_failure() override; void report_vt_switch_back_failure() override; void report_hwc_composition_in_use(int major, int minor) override; void report_gpu_composition_in_use() override; void report_egl_configuration(EGLDisplay disp, EGLConfig cfg) override; }; } } } #endif /* MIR_REPORT_NULL_DISPLAY_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/null/scene_report.h0000644000015301777760000000273512322054223024126 0ustar pbusernogroup00000000000000/* * 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 * Andreas Pokorny */ #ifndef MIR_REPORT_NULL_SCENE_REPORT_H_ #define MIR_REPORT_NULL_SCENE_REPORT_H_ #include "mir/scene/scene_report.h" namespace mir { namespace report { namespace null { class SceneReport : public scene::SceneReport { public: virtual void surface_created(BasicSurfaceId /*id*/, std::string const& /*name*/) override; virtual void surface_added(BasicSurfaceId /*id*/, std::string const& /*name*/) override; virtual void surface_removed(BasicSurfaceId /*id*/, std::string const& /*name*/) override; virtual void surface_deleted(BasicSurfaceId /*id*/, std::string const& /*name*/) override; SceneReport() = default; virtual ~SceneReport() noexcept(true) = default; }; } } } #endif /* MIR_REPORT_NULL_SCENE_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/null/message_processor_report.cpp0000644000015301777760000000244312322054223027103 0ustar pbusernogroup00000000000000/* * 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 */ #include "message_processor_report.h" namespace mrn = mir::report::null; void mrn::MessageProcessorReport::received_invocation(void const*, int, std::string const&) { } void mrn::MessageProcessorReport::completed_invocation(void const*, int, bool) { } void mrn::MessageProcessorReport::unknown_method(void const*, int, std::string const&) { } void mrn::MessageProcessorReport::exception_handled(void const*, int, std::exception const&) { } void mrn::MessageProcessorReport::exception_handled(void const*, std::exception const&) { } void mrn::MessageProcessorReport::sent_event(void const*, MirSurfaceEvent const&) { } mir-0.1.8+14.04.20140411/src/server/report/null/CMakeLists.txt0000644000015301777760000000037612322054223024024 0ustar pbusernogroup00000000000000add_library( mirnullreport STATIC compositor_report.cpp connector_report.cpp display_report.cpp input_report.cpp message_processor_report.cpp null_report_factory.cpp scene_report.cpp session_mediator_report.cpp ) mir-0.1.8+14.04.20140411/src/server/report/null/input_report.h0000644000015301777760000000253612322054223024167 0ustar pbusernogroup00000000000000/* * 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_REPORT_NULL_INPUT_REPORT_H_ #define MIR_REPORT_NULL_INPUT_REPORT_H_ #include "mir/input/input_report.h" namespace mir { namespace report { namespace null { class InputReport : public input::InputReport { public: InputReport() = default; virtual ~InputReport() noexcept(true) = default; void received_event_from_kernel(int64_t when, int type, int code, int value); void published_key_event(int dest_fd, uint32_t seq_id, int64_t event_time); void published_motion_event(int dest_fd, uint32_t seq_id, int64_t event_time); void received_event_finished_signal(int src_fd, uint32_t seq_id); }; } } } #endif /* MIR_REPORT_NULL_INPUT_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/server/report/null/scene_report.cpp0000644000015301777760000000224712322054223024457 0ustar pbusernogroup00000000000000/* * 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 * Andreas Pokorny */ #include "scene_report.h" namespace mrn = mir::report::null; void mrn::SceneReport::surface_created(BasicSurfaceId /*id*/, std::string const& /*name*/) { } void mrn::SceneReport::surface_added(BasicSurfaceId /*id*/, std::string const& /*name*/) { } void mrn::SceneReport::surface_removed(BasicSurfaceId /*id*/, std::string const& /*name*/) { } void mrn::SceneReport::surface_deleted(BasicSurfaceId /*id*/, std::string const& /*name*/) { } mir-0.1.8+14.04.20140411/src/server/report/null/input_report.cpp0000644000015301777760000000227312322054223024520 0ustar pbusernogroup00000000000000/* * 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 */ #include "input_report.h" namespace mrn = mir::report::null; void mrn::InputReport::received_event_from_kernel(int64_t /* when */, int /* type */, int /* code */, int /* value */) { } void mrn::InputReport::published_key_event(int /* dest_fd */, uint32_t /* seq_id */, int64_t /* event_time */) { } void mrn::InputReport::published_motion_event(int /* dest_fd */, uint32_t /* seq_id */, int64_t /* event_time */) { } void mrn::InputReport::received_event_finished_signal(int /* src_fd */, uint32_t /* seq_id */) { } mir-0.1.8+14.04.20140411/src/server/shell/0000755000015301777760000000000012322054703020103 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/shell/default_focus_mechanism.cpp0000644000015301777760000000431212322054247025461 0ustar pbusernogroup00000000000000/* * 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 */ #include "default_focus_mechanism.h" #include "mir/frontend/session.h" #include "mir/scene/surface_ranker.h" #include "mir/scene/surface.h" #include "mir/shell/input_targeter.h" #include "mir/shell/session.h" #include "mir/shell/surface.h" namespace mf = mir::frontend; namespace ms = mir::scene; namespace msh = mir::shell; msh::DefaultFocusMechanism::DefaultFocusMechanism(std::shared_ptr const& input_targeter, std::shared_ptr const& surface_controller) : input_targeter(input_targeter), surface_controller(surface_controller) { } void msh::DefaultFocusMechanism::set_focus_to(std::shared_ptr const& focus_session) { // TODO: This path should be encapsulated in a seperate clear_focus message if (!focus_session) { input_targeter->focus_cleared(); return; } auto surface = focus_session->default_surface(); if (surface) { std::lock_guard lg(surface_focus_lock); auto current_focus = currently_focused_surface.lock(); if (current_focus) current_focus->configure(mir_surface_attrib_focus, mir_surface_unfocused); surface->configure(mir_surface_attrib_focus, mir_surface_focused); currently_focused_surface = surface; surface_controller->raise(std::static_pointer_cast(surface)); // TODO deal with cast surface->take_input_focus(input_targeter); } else { input_targeter->focus_cleared(); } } mir-0.1.8+14.04.20140411/src/server/shell/default_configuration.cpp0000644000015301777760000000417012322054247025167 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/default_server_configuration.h" #include "consuming_placement_strategy.h" #include "default_focus_mechanism.h" #include "graphics_display_layout.h" #include "organising_surface_factory.h" namespace ms = mir::scene; namespace msh = mir::shell; namespace mf = mir::frontend; std::shared_ptr mir::DefaultServerConfiguration::the_shell_surface_factory() { return shell_surface_factory( [this]() { return std::make_shared( the_surface_coordinator(), the_shell_placement_strategy()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_shell_placement_strategy() { return shell_placement_strategy( [this] { return std::make_shared( the_shell_display_layout()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_shell_focus_setter() { return shell_focus_setter( [this] { return std::make_shared( the_input_targeter(), the_surface_ranker()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_shell_display_layout() { return shell_display_layout( [this]() { return std::make_shared(the_display()); }); } mir-0.1.8+14.04.20140411/src/server/shell/surface_creation_parameters.cpp0000644000015301777760000000637312322054223026354 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/shell/surface_creation_parameters.h" namespace mg = mir::graphics; namespace msh = mir::shell; namespace mi = mir::input; namespace geom = mir::geometry; msh::SurfaceCreationParameters::SurfaceCreationParameters() : name(), size(), top_left(), buffer_usage(mg::BufferUsage::undefined), pixel_format(mir_pixel_format_invalid), depth{0}, input_mode(mi::InputReceptionMode::normal) { } msh::SurfaceCreationParameters& msh::SurfaceCreationParameters::of_name(std::string const& new_name) { name = new_name; return *this; } msh::SurfaceCreationParameters& msh::SurfaceCreationParameters::of_size( geometry::Size new_size) { size = new_size; return *this; } msh::SurfaceCreationParameters& msh::SurfaceCreationParameters::of_size( geometry::Width::ValueType width, geometry::Height::ValueType height) { return of_size({width, height}); } msh::SurfaceCreationParameters& msh::SurfaceCreationParameters::of_position(geometry::Point const& new_top_left) { top_left = new_top_left; return *this; } msh::SurfaceCreationParameters& msh::SurfaceCreationParameters::of_buffer_usage( mg::BufferUsage new_buffer_usage) { buffer_usage = new_buffer_usage; return *this; } msh::SurfaceCreationParameters& msh::SurfaceCreationParameters::of_pixel_format( MirPixelFormat new_pixel_format) { pixel_format = new_pixel_format; return *this; } msh::SurfaceCreationParameters& msh::SurfaceCreationParameters::of_depth( scene::DepthId const& new_depth) { depth = new_depth; return *this; } msh::SurfaceCreationParameters& msh::SurfaceCreationParameters::with_input_mode(input::InputReceptionMode const& new_mode) { input_mode = new_mode; return *this; } msh::SurfaceCreationParameters& msh::SurfaceCreationParameters::with_output_id( graphics::DisplayConfigurationOutputId const& new_output_id) { output_id = new_output_id; return *this; } bool msh::operator==( const SurfaceCreationParameters& lhs, const msh::SurfaceCreationParameters& rhs) { return lhs.name == rhs.name && lhs.size == rhs.size && lhs.top_left == rhs.top_left && lhs.buffer_usage == rhs.buffer_usage && lhs.pixel_format == rhs.pixel_format && lhs.depth == rhs.depth && lhs.input_mode == rhs.input_mode && lhs.output_id == lhs.output_id; } bool msh::operator!=( const SurfaceCreationParameters& lhs, const msh::SurfaceCreationParameters& rhs) { return !(lhs == rhs); } msh::SurfaceCreationParameters msh::a_surface() { return SurfaceCreationParameters(); } mir-0.1.8+14.04.20140411/src/server/shell/graphics_display_layout.h0000644000015301777760000000272112322054223025175 0ustar pbusernogroup00000000000000/* * 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_GRAPHICS_DISPLAY_LAYOUT_H_ #define MIR_SHELL_GRAPHICS_DISPLAY_LAYOUT_H_ #include "mir/shell/display_layout.h" #include namespace mir { namespace graphics { class Display; } namespace shell { class GraphicsDisplayLayout : public DisplayLayout { public: GraphicsDisplayLayout(std::shared_ptr const& display); void clip_to_output(geometry::Rectangle& rect); void size_to_output(geometry::Rectangle& rect); void place_in_output(graphics::DisplayConfigurationOutputId output_id, geometry::Rectangle& rect); private: geometry::Rectangle get_output_for(geometry::Rectangle& rect); std::shared_ptr const display; }; } } #endif /* MIR_SHELL_GRAPHICS_DISPLAY_LAYOUT_H_ */ mir-0.1.8+14.04.20140411/src/server/shell/consuming_placement_strategy.h0000644000015301777760000000307212322054223026227 0ustar pbusernogroup00000000000000/* * 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_CONSUMING_PLACEMENT_STRATEGY_H_ #define MIR_SHELL_CONSUMING_PLACEMENT_STRATEGY_H_ #include "mir/shell/placement_strategy.h" #include namespace mir { namespace shell { class DisplayLayout; class ConsumingPlacementStrategy : public PlacementStrategy { public: explicit ConsumingPlacementStrategy( std::shared_ptr const& display_layout); virtual ~ConsumingPlacementStrategy() {} virtual shell::SurfaceCreationParameters place(shell::Session const& session, shell::SurfaceCreationParameters const& request_parameters); protected: ConsumingPlacementStrategy(ConsumingPlacementStrategy const&) = delete; ConsumingPlacementStrategy& operator=(ConsumingPlacementStrategy const&) = delete; private: std::shared_ptr const display_layout; }; } } // namespace mir #endif // MIR_SHELL_CONSUMING_PLACEMENT_STRATEGY_H_ mir-0.1.8+14.04.20140411/src/server/shell/organising_surface_factory.cpp0000644000015301777760000000413612322054247026215 0ustar pbusernogroup00000000000000/* * 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 */ #include "organising_surface_factory.h" #include "mir/shell/placement_strategy.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/scene/surface_coordinator.h" #include "mir/scene/surface.h" #include namespace mf = mir::frontend; namespace ms = mir::scene; namespace msh = mir::shell; msh::OrganisingSurfaceFactory::OrganisingSurfaceFactory( std::shared_ptr const& surface_coordinator, std::shared_ptr const& placement_strategy) : surface_coordinator(surface_coordinator), placement_strategy(placement_strategy) { } msh::OrganisingSurfaceFactory::~OrganisingSurfaceFactory() { } std::shared_ptr msh::OrganisingSurfaceFactory::create_surface( Session* session, SurfaceCreationParameters const& params, std::shared_ptr const& observer) { auto placed_params = placement_strategy->place(*session, params); return surface_coordinator->add_surface(placed_params, observer); } void msh::OrganisingSurfaceFactory::destroy_surface(std::shared_ptr const& surface) { if (auto const scene_surface = std::dynamic_pointer_cast(surface)) { surface_coordinator->remove_surface(scene_surface); } else { // We shouldn't be destroying surfaces we didn't create, // so we ought to be able to restore the original type! std::abort(); } } mir-0.1.8+14.04.20140411/src/server/shell/CMakeLists.txt0000644000015301777760000000041412322054223022637 0ustar pbusernogroup00000000000000set( SHELL_SOURCES default_focus_mechanism.cpp consuming_placement_strategy.cpp organising_surface_factory.cpp surface_creation_parameters.cpp graphics_display_layout.cpp default_configuration.cpp ) add_library( mirshell STATIC ${SHELL_SOURCES} ) mir-0.1.8+14.04.20140411/src/server/shell/graphics_display_layout.cpp0000644000015301777760000000630512322054223025532 0ustar pbusernogroup00000000000000/* * 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 */ #include "graphics_display_layout.h" #include "mir/graphics/display.h" #include "mir/graphics/display_buffer.h" #include "mir/geometry/rectangle.h" #include "mir/geometry/rectangles.h" #include "mir/geometry/displacement.h" #include #include namespace msh = mir::shell; namespace mg = mir::graphics; namespace geom = mir::geometry; msh::GraphicsDisplayLayout::GraphicsDisplayLayout( std::shared_ptr const& display) : display{display} { } void msh::GraphicsDisplayLayout::clip_to_output(geometry::Rectangle& rect) { auto output = get_output_for(rect); if (output.size.width > geom::Width{0} && output.size.height > geom::Height{0} && rect.size.width > geom::Width{0} && rect.size.height > geom::Height{0}) { auto tl = rect.top_left; auto br_closed = rect.bottom_right() - geom::Displacement{1,1}; geom::Rectangles rectangles; rectangles.add(output); rectangles.confine(br_closed); rect.size = geom::Size{br_closed.x.as_int() - tl.x.as_int() + 1, br_closed.y.as_int() - tl.y.as_int() + 1}; } else { rect.size = geom::Size{0,0}; } } void msh::GraphicsDisplayLayout::size_to_output(geometry::Rectangle& rect) { auto output = get_output_for(rect); rect = output; } void msh::GraphicsDisplayLayout::place_in_output( graphics::DisplayConfigurationOutputId id, geometry::Rectangle& rect) { auto config = display->configuration(); bool placed = false; /* Accept only fullscreen placements for now */ config->for_each_output([&](mg::DisplayConfigurationOutput const& output) { if (output.id == id && output.current_mode_index < output.modes.size() && rect.size == output.extents().size) { rect.top_left = output.top_left; placed = true; } }); if (!placed) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to place surface in requested output")); } geom::Rectangle msh::GraphicsDisplayLayout::get_output_for(geometry::Rectangle& rect) { geom::Rectangle output; /* * TODO: We need a better heuristic to decide in which output a * rectangle/surface belongs. */ display->for_each_display_buffer( [&output,&rect](mg::DisplayBuffer const& db) { auto view_area = db.view_area(); if (view_area.contains(rect.top_left)) output = view_area; }); return output; } mir-0.1.8+14.04.20140411/src/server/shell/consuming_placement_strategy.cpp0000644000015301777760000000404312322054223026561 0ustar pbusernogroup00000000000000/* * 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 */ #include "consuming_placement_strategy.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/shell/display_layout.h" #include "mir/geometry/rectangle.h" #include "mir_toolkit/client_types.h" #include namespace msh = mir::shell; namespace geom = mir::geometry; msh::ConsumingPlacementStrategy::ConsumingPlacementStrategy( std::shared_ptr const& display_layout) : display_layout(display_layout) { } msh::SurfaceCreationParameters msh::ConsumingPlacementStrategy::place( msh::Session const& /* session */, msh::SurfaceCreationParameters const& request_parameters) { mir::graphics::DisplayConfigurationOutputId const output_id_invalid{ mir_display_output_id_invalid}; auto placed_parameters = request_parameters; geom::Rectangle rect{request_parameters.top_left, request_parameters.size}; if (request_parameters.output_id != output_id_invalid) { display_layout->place_in_output(request_parameters.output_id, rect); } else if (request_parameters.size.width > geom::Width{0} && request_parameters.size.height > geom::Height{0}) { display_layout->clip_to_output(rect); } else { display_layout->size_to_output(rect); } placed_parameters.top_left = rect.top_left; placed_parameters.size = rect.size; return placed_parameters; } mir-0.1.8+14.04.20140411/src/server/shell/default_focus_mechanism.h0000644000015301777760000000341112322054223025117 0ustar pbusernogroup00000000000000/* * 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_SHELL_SINGLE_VISIBILITY_FOCUS_MECHANISM_H_ #define MIR_SHELL_SINGLE_VISIBILITY_FOCUS_MECHANISM_H_ #include "mir/shell/focus_setter.h" #include #include namespace mir { namespace scene { class SurfaceRanker; } namespace shell { class Surface; class InputTargeter; class DefaultFocusMechanism : public FocusSetter { public: explicit DefaultFocusMechanism(std::shared_ptr const& input_targeter, std::shared_ptr const& surface_controller); virtual ~DefaultFocusMechanism() = default; void set_focus_to(std::shared_ptr const& new_focus); protected: DefaultFocusMechanism(const DefaultFocusMechanism&) = delete; DefaultFocusMechanism& operator=(const DefaultFocusMechanism&) = delete; private: std::shared_ptr const input_targeter; std::shared_ptr const surface_controller; std::mutex surface_focus_lock; std::weak_ptr currently_focused_surface; }; } } #endif // MIR_SHELL_SINGLE_VISIBILITY_FOCUS_MECHANISM_H_ mir-0.1.8+14.04.20140411/src/server/shell/organising_surface_factory.h0000644000015301777760000000357412322054247025667 0ustar pbusernogroup00000000000000/* * 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_ORGANISING_SURFACE_FACTORY_H_ #define MIR_SHELL_ORGANISING_SURFACE_FACTORY_H_ #include "mir/shell/surface_factory.h" #include namespace mir { namespace scene { class SurfaceCoordinator; } namespace shell { class PlacementStrategy; class Session; class OrganisingSurfaceFactory : public SurfaceFactory { public: OrganisingSurfaceFactory( std::shared_ptr const& surface_coordinator, std::shared_ptr const& placement_strategy); virtual ~OrganisingSurfaceFactory(); std::shared_ptr create_surface( Session* session, SurfaceCreationParameters const& params, std::shared_ptr const& observer) override; void destroy_surface(std::shared_ptr const& surface) override; protected: OrganisingSurfaceFactory(OrganisingSurfaceFactory const&) = delete; OrganisingSurfaceFactory& operator=(OrganisingSurfaceFactory const&) = delete; private: std::shared_ptr const surface_coordinator; std::shared_ptr const placement_strategy; }; } } // namespace mir #endif // MIR_SHELL_ORGANISING_SURFACE_FACTORY_H_ mir-0.1.8+14.04.20140411/src/server/run_mir.cpp0000644000015301777760000000450412322054223021153 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/run_mir.h" #include "mir/display_server.h" #include "mir/main_loop.h" #include "mir/server_configuration.h" #include "mir/frontend/connector.h" #include "mir/raii.h" #include #include #include namespace { auto const intercepted = { SIGQUIT, SIGABRT, SIGFPE, SIGSEGV, SIGBUS }; std::weak_ptr weak_connector; extern "C" void delete_endpoint() { if (auto connector = weak_connector.lock()) { weak_connector.reset(); connector->remove_endpoint(); } } extern "C" { typedef void (*sig_handler)(int); } volatile sig_handler old_handler[SIGUNUSED] = { nullptr }; extern "C" void fatal_signal_cleanup(int sig) { delete_endpoint(); signal(sig, old_handler[sig]); raise(sig); } } void mir::run_mir(ServerConfiguration& config, std::function init) { DisplayServer* server_ptr{nullptr}; auto main_loop = config.the_main_loop(); main_loop->register_signal_handler( {SIGINT, SIGTERM}, [&server_ptr](int) { delete_endpoint(); assert(server_ptr); server_ptr->stop(); }); DisplayServer server(config); server_ptr = &server; weak_connector = config.the_connector(); auto const raii = raii::paired_calls( [&]{ for (auto sig : intercepted) old_handler[sig] = signal(sig, fatal_signal_cleanup); }, [&]{ for (auto sig : intercepted) signal(sig, old_handler[sig]); }); static bool atexit_called{false}; if (!atexit_called) { std::atexit(&delete_endpoint); atexit_called = true; } init(server); server.run(); } mir-0.1.8+14.04.20140411/src/server/mirserver.pc.in0000644000015301777760000000054512322054247021752 0ustar pbusernogroup00000000000000prefix=@PREFIX@ exec_prefix=@EXEC_PREFIX@ libdir=@LIBDIR@ includedir=@INCLUDEDIR@ Name: mirserver Description: Mir server library Version: @MIR_VERSION_MAJOR@.@MIR_VERSION_MINOR@.@MIR_VERSION_PATCH@ Requires.private: protobuf >= 2.4.1 Requires: mircommon Libs: -L@LIBDIR@ -lmirserver -Wl,-rpath-link,@LIBDIR@ Cflags: -I@PLATFORM_INCLUDEDIR@ -I@INCLUDEDIR@ mir-0.1.8+14.04.20140411/src/server/input/0000755000015301777760000000000012322054703020133 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/input/android/0000755000015301777760000000000012322054703021553 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/server/input/android/input_dispatcher_manager.cpp0000644000015301777760000000337712322054223027325 0ustar pbusernogroup00000000000000/* * 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 */ #include "input_dispatcher_manager.h" #include "android_input_constants.h" #include "android_input_thread.h" #include "android_input_channel.h" #include namespace mi = mir::input; namespace mia = mi::android; mia::InputDispatcherManager::InputDispatcherManager( droidinput::sp const& dispatcher, std::shared_ptr const& dispatcher_thread) : dispatcher(dispatcher), dispatcher_thread(dispatcher_thread) { } mia::InputDispatcherManager::~InputDispatcherManager() { } void mia::InputDispatcherManager::stop() { dispatcher_thread->request_stop(); dispatcher->setInputDispatchMode(mia::DispatchDisabled, mia::DispatchFrozen); dispatcher_thread->join(); } void mia::InputDispatcherManager::start() { dispatcher->setInputDispatchMode(mia::DispatchEnabled, mia::DispatchUnfrozen); dispatcher->setInputFilterEnabled(true); dispatcher_thread->start(); } std::shared_ptr mia::InputDispatcherManager::make_input_channel() { return std::make_shared(); } mir-0.1.8+14.04.20140411/src/server/input/android/android_input_channel.cpp0000644000015301777760000000225212322054223026604 0ustar pbusernogroup00000000000000/* * 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 */ #include "android_input_channel.h" #include #include namespace mia = mir::input::android; namespace droidinput = android; mia::AndroidInputChannel::AndroidInputChannel() { droidinput::InputChannel::openInputFdPair(s_fd, c_fd); } mia::AndroidInputChannel::~AndroidInputChannel() { close(s_fd); close(c_fd); } int mia::AndroidInputChannel::client_fd() const { return c_fd; } int mia::AndroidInputChannel::server_fd() const { return s_fd; } mir-0.1.8+14.04.20140411/src/server/input/android/android_input_channel.h0000644000015301777760000000260512322054223026253 0ustar pbusernogroup00000000000000/* * 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_ANDROID_INPUT_CHANNEL_H_ #define MIR_INPUT_ANDROID_INPUT_CHANNEL_H_ #include "mir/input/input_channel.h" #include namespace android { class InputChannel; } namespace droidinput = android; namespace mir { namespace input { namespace android { class AndroidInputChannel : public InputChannel { public: explicit AndroidInputChannel(); virtual ~AndroidInputChannel(); int client_fd() const; int server_fd() const; protected: AndroidInputChannel(AndroidInputChannel const&) = delete; AndroidInputChannel& operator=(AndroidInputChannel const&) = delete; private: int s_fd, c_fd; }; } } } // namespace mir #endif // MIR_INPUT_ANDROID_INPUT_CHANNEL_H_ mir-0.1.8+14.04.20140411/src/server/input/android/dispatcher_input_configuration.cpp0000644000015301777760000001052112322054223030547 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/input/android/dispatcher_input_configuration.h" #include "event_filter_dispatcher_policy.h" #include "android_input_thread.h" #include "android_input_registrar.h" #include "android_input_targeter.h" #include "android_input_target_enumerator.h" #include "android_input_manager.h" #include "mir/input/event_filter.h" #include #include namespace droidinput = android; namespace mi = mir::input; namespace mia = mi::android; namespace ms = mir::scene; namespace msh = mir::shell; namespace { class CommonInputThread : public mia::InputThread { public: CommonInputThread(std::string const& name, droidinput::sp const& thread) : name(name), thread(thread) { } virtual ~CommonInputThread() { } void start() { thread->run(name.c_str(), droidinput::PRIORITY_URGENT_DISPLAY); } void request_stop() { thread->requestExit(); } void join() { thread->join(); } private: CommonInputThread(const CommonInputThread&) = delete; CommonInputThread& operator=(const CommonInputThread&) = delete; std::string const name; droidinput::sp const thread; }; } mia::DispatcherInputConfiguration::DispatcherInputConfiguration( std::shared_ptr const& event_filter, std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener, std::shared_ptr const& input_report) : event_filter(event_filter), input_region(input_region), cursor_listener(cursor_listener), input_report(input_report) { } mia::DispatcherInputConfiguration::~DispatcherInputConfiguration() { } droidinput::sp mia::DispatcherInputConfiguration::the_dispatcher_policy() { return dispatcher_policy( [this]() { return new mia::EventFilterDispatcherPolicy(event_filter, is_key_repeat_enabled()); }); } std::shared_ptr mia::DispatcherInputConfiguration::the_dispatcher_thread() { return dispatcher_thread( [this]() { return std::make_shared("InputDispatcher", new droidinput::InputDispatcherThread(the_dispatcher())); }); } std::shared_ptr mia::DispatcherInputConfiguration::the_input_registrar() { return input_registrar( [this]() { return std::make_shared(the_dispatcher()); }); } std::shared_ptr mia::DispatcherInputConfiguration::the_window_handle_repository() { return input_registrar( [this]() { return std::make_shared(the_dispatcher()); }); } std::shared_ptr mia::DispatcherInputConfiguration::the_input_targeter() { return input_targeter( [this]() { return std::make_shared(the_dispatcher(), the_window_handle_repository()); }); } bool mia::DispatcherInputConfiguration::is_key_repeat_enabled() { return true; } void mia::DispatcherInputConfiguration::set_input_targets(std::shared_ptr const& targets) { the_dispatcher()->setInputEnumerator(new mia::InputTargetEnumerator(targets, the_window_handle_repository())); } std::shared_ptr mia::DispatcherInputConfiguration::the_input_manager() { return input_manager( [this]() { return std::make_shared(the_dispatcher(), the_dispatcher_thread()); }); } mir-0.1.8+14.04.20140411/src/server/input/android/android_input_application_handle.cpp0000644000015301777760000000240212322054223031007 0ustar pbusernogroup00000000000000/* * 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 */ #include "android_input_application_handle.h" #include "mir/input/input_channel.h" #include "mir/input/surface.h" #include namespace mi = mir::input; namespace mia = mir::input::android; mia::InputApplicationHandle::InputApplicationHandle(std::shared_ptr const& surface) : surface(surface) { updateInfo(); } bool mia::InputApplicationHandle::updateInfo() { if (mInfo == NULL) mInfo = new droidinput::InputApplicationInfo; mInfo->dispatchingTimeout = INT_MAX; mInfo->name = droidinput::String8(surface->name().c_str()); return true; } mir-0.1.8+14.04.20140411/src/server/input/android/android_input_registrar.cpp0000644000015301777760000000706312322054223027203 0ustar pbusernogroup00000000000000/* * 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 */ #include "android_input_registrar.h" #include "android_input_window_handle.h" #include "android_input_application_handle.h" #include #include #include #include namespace mi = mir::input; namespace mia = mi::android; namespace ms = mir::scene; mia::InputRegistrar::InputRegistrar(droidinput::sp const& input_dispatcher) : input_dispatcher(input_dispatcher) { } mia::InputRegistrar::~InputRegistrar() noexcept(true) { } // Be careful on the locking in these two functions. void mia::InputRegistrar::input_channel_opened(std::shared_ptr const& channel, std::shared_ptr const& surface, mi::InputReceptionMode input_mode) { droidinput::sp window_handle; { std::unique_lock lock(handles_mutex); // TODO: We don't have much use for InputApplicationHandle so we simply use one per channel. // it is only used in droidinput for logging and determining application not responding (ANR), // we determine ANR on a per channel basis. When we have time we should factor InputApplicationHandle out // of the input stack (merging it's state with WindowHandle). ~racarr if (window_handles.find(channel) != window_handles.end()) BOOST_THROW_EXCEPTION(std::logic_error("A channel was opened twice")); auto application_handle = new mia::InputApplicationHandle(surface); window_handle = new mia::InputWindowHandle(application_handle, channel, surface); window_handles[channel] = window_handle; } bool monitors_input = (input_mode == mi::InputReceptionMode::receives_all_input); input_dispatcher->registerInputChannel(window_handle->getInfo()->inputChannel, window_handle, monitors_input); } void mia::InputRegistrar::input_channel_closed(std::shared_ptr const& closed_channel) { droidinput::sp window_handle; { std::unique_lock lock(handles_mutex); auto it = window_handles.find(closed_channel); if (it == window_handles.end()) BOOST_THROW_EXCEPTION(std::logic_error("A channel was closed twice")); window_handle = it->second; window_handles.erase(it); } input_dispatcher->unregisterInputChannel(window_handle->getInputChannel()); } droidinput::sp mia::InputRegistrar::handle_for_channel( std::shared_ptr const& channel) { std::unique_lock lock(handles_mutex); if (window_handles.find(channel) == window_handles.end()) BOOST_THROW_EXCEPTION(std::logic_error("Requesting handle for an unregistered channel")); return window_handles[channel]; } mir-0.1.8+14.04.20140411/src/server/input/android/android_input_manager.h0000644000015301777760000000370212322054223026254 0ustar pbusernogroup00000000000000/* * 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 * Daniel d'Andradra */ #ifndef MIR_INPUT_ANDROID_INPUT_MANAGER_H_ #define MIR_INPUT_ANDROID_INPUT_MANAGER_H_ #include "input_dispatcher_manager.h" #include namespace android { class EventHubInterface; } namespace droidinput = android; namespace mir { namespace input { namespace android { class InputThread; /// Encapsulates an instance of the Android input stack, that is to say an EventHub tied /// to an InputReader tied to an InputDispatcher. Provides interfaces for controlling input /// policy and dispatch (through public API and policy objects in InputConfiguration). class InputManager : public InputDispatcherManager { public: explicit InputManager(droidinput::sp const& event_hub, droidinput::sp const& dispatcher, std::shared_ptr const& reader_thread, std::shared_ptr const& dispatcher_thread); virtual ~InputManager(); void start(); void stop(); private: droidinput::sp const event_hub; std::shared_ptr const reader_thread; }; } } } #endif // MIR_INPUT_INPUT_MANAGER mir-0.1.8+14.04.20140411/src/server/input/android/android_pointer_controller.h0000644000015301777760000000411512322054223027345 0ustar pbusernogroup00000000000000/* * 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_ANDROID_POINTER_CONTROLLER_H__ #define MIR_INPUT_ANDROID_POINTER_CONTROLLER_H__ #include "dummy_android_pointer_controller.h" #include "mir/input/cursor_listener.h" #include #include namespace mir { namespace input { class InputRegion; namespace android { class PointerController : public DummyPointerController { public: explicit PointerController(std::shared_ptr const& input_region); explicit PointerController(std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener); virtual bool getBounds(float* out_min_x, float* out_min_y, float* out_max_x, float* out_max_y) const; virtual void move(float delta_x, float delta_y); virtual void setButtonState(int32_t button_state); virtual int32_t getButtonState() const; virtual void setPosition(float x, float y); virtual void getPosition(float *out_x, float *out_y) const; private: bool get_bounds_locked(float *out_min_x, float* out_min_y, float* out_max_x, float* out_max_y) const; void notify_listener(); // Could be a read/write mutex as this is a latency sensitive class. mutable std::mutex guard; int32_t state; float x, y; std::shared_ptr const input_region; std::shared_ptr cursor_listener; }; } } } #endif // MIR_INPUT_ANDROID_POINTER_CONTROLLER_H__ mir-0.1.8+14.04.20140411/src/server/input/android/android_pointer_controller.cpp0000644000015301777760000000657312322054223027712 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/input/input_region.h" #include "mir/geometry/rectangle.h" #include "mir/geometry/point.h" #include "android_pointer_controller.h" #include namespace mi = mir::input; namespace mia = mi::android; namespace geom = mir::geometry; mia::PointerController::PointerController( std::shared_ptr const& input_region) : state(0), x(0.0), y(0.0), input_region(input_region), cursor_listener(std::shared_ptr()) { } mia::PointerController::PointerController( std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener) : state(0), x(0.0), y(0.0), input_region(input_region), cursor_listener(cursor_listener) { } void mia::PointerController::notify_listener() { if (cursor_listener) cursor_listener->cursor_moved_to(x, y); } bool mia::PointerController::getBounds( float* out_min_x, float* out_min_y, float* out_max_x, float* out_max_y) const { std::lock_guard lg(guard); return get_bounds_locked(out_min_x, out_min_y, out_max_x, out_max_y); } // Differs in name as not dictated by android bool mia::PointerController::get_bounds_locked( float *out_min_x, float* out_min_y, float* out_max_x, float* out_max_y) const { auto bounds = input_region->bounding_rectangle(); *out_min_x = bounds.top_left.x.as_float(); *out_min_y = bounds.top_left.y.as_float(); *out_max_x = bounds.top_left.x.as_float() + bounds.size.width.as_float(); *out_max_y = bounds.top_left.y.as_float() + bounds.size.height.as_float(); return true; } void mia::PointerController::move(float delta_x, float delta_y) { auto new_x = x + delta_x; auto new_y = y + delta_y; setPosition(new_x, new_y); } void mia::PointerController::setButtonState(int32_t button_state) { std::lock_guard lg(guard); state = button_state; } int32_t mia::PointerController::getButtonState() const { std::lock_guard lg(guard); return state; } void mia::PointerController::setPosition(float new_x, float new_y) { std::lock_guard lg(guard); geom::Point p{new_x, new_y}; input_region->confine(p); x = p.x.as_float(); y = p.y.as_float(); // I think it's correct to hold this lock while notifying the listener (i.e. cursor rendering update) // to prevent the InputReader from getting ahead of rendering. This may need to be thought about later. notify_listener(); } void mia::PointerController::getPosition(float *out_x, float *out_y) const { std::lock_guard lg(guard); *out_x = x; *out_y = y; } mir-0.1.8+14.04.20140411/src/server/input/android/android_input_targeter.cpp0000644000015301777760000000361712322054223027017 0ustar pbusernogroup00000000000000/* * 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 */ #include "android_input_targeter.h" #include "android_input_registrar.h" #include "android_input_window_handle.h" #include "android_input_application_handle.h" #include #include #include #include namespace mi = mir::input; namespace mia = mi::android; namespace ms = mir::scene; mia::InputTargeter::InputTargeter(droidinput::sp const& input_dispatcher, std::shared_ptr const& repository) : input_dispatcher(input_dispatcher), repository(repository) { } mia::InputTargeter::~InputTargeter() noexcept(true) {} void mia::InputTargeter::focus_cleared() { droidinput::sp null_window = nullptr; input_dispatcher->setKeyboardFocus(null_window); } void mia::InputTargeter::focus_changed(std::shared_ptr const& focus_channel) { auto window_handle = repository->handle_for_channel(focus_channel); if (window_handle == NULL) BOOST_THROW_EXCEPTION(std::logic_error("Attempt to set keyboard focus to an unregistered input channel")); input_dispatcher->setKeyboardFocus(window_handle); } mir-0.1.8+14.04.20140411/src/server/input/android/android_input_reader_policy.h0000644000015301777760000000313612322054223027464 0ustar pbusernogroup00000000000000/* * 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_ANDROID_INPUT_READER_POLICY_H_ #define MIR_ANDROID_INPUT_READER_POLICY_H_ #include "rudimentary_input_reader_policy.h" #include namespace mir { namespace input { class CursorListener; class InputRegion; namespace android { class InputReaderPolicy : public RudimentaryInputReaderPolicy { public: explicit InputReaderPolicy(std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener); virtual ~InputReaderPolicy() {} virtual droidinput::sp obtainPointerController(int32_t device_id); virtual void getReaderConfiguration(droidinput::InputReaderConfiguration* out_config); private: std::shared_ptr const input_region; droidinput::sp pointer_controller; }; } } } // namespace mir #endif // MIR_ANDROID_INPUT_READER_POLICY_H_ mir-0.1.8+14.04.20140411/src/server/input/android/android_input_target_enumerator.cpp0000644000015301777760000000313412322054223030723 0ustar pbusernogroup00000000000000/* * 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 */ #include "android_input_target_enumerator.h" #include "android_window_handle_repository.h" #include "mir/input/input_targets.h" #include namespace mi = mir::input; namespace mia = mi::android; mia::InputTargetEnumerator::InputTargetEnumerator(std::shared_ptr const& targets, std::shared_ptr const& repository) : targets(targets), repository(repository) { } mia::InputTargetEnumerator::~InputTargetEnumerator() noexcept(true) { } void mia::InputTargetEnumerator::for_each(std::function const&)> const& callback) { auto t = targets.lock(); auto r = repository.lock(); t->for_each([&callback, &r, this](std::shared_ptr const& target){ auto handle = r->handle_for_channel(target); callback(handle); }); } mir-0.1.8+14.04.20140411/src/server/input/android/event_filter_dispatcher_policy.h0000644000015301777760000000572512322054223030205 0ustar pbusernogroup00000000000000/* * 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_EVENT_FILTER_DISPATCHER_POLICY_H_ #define MIR_EVENT_FILTER_DISPATCHER_POLICY_H_ #include "mir/input/event_filter.h" #include namespace android { class InputEvent; } namespace droidinput = android; namespace mir { namespace input { namespace android { //class EventFilter; class EventFilterDispatcherPolicy : public droidinput::InputDispatcherPolicyInterface { public: EventFilterDispatcherPolicy(std::shared_ptr const& event_filter, bool key_repeat_enabled); virtual ~EventFilterDispatcherPolicy() {} void notifyConfigurationChanged(nsecs_t when); nsecs_t notifyANR(droidinput::sp const& inputApplicationHandle, droidinput::sp const& inputWindowHandle); void notifyInputChannelBroken(droidinput::sp const& inputWindowHandle); bool filterInputEvent(const droidinput::InputEvent* input_event, uint32_t policy_flags); void interceptKeyBeforeQueueing(const droidinput::KeyEvent* key_event, uint32_t& policy_flags); void getDispatcherConfiguration(droidinput::InputDispatcherConfiguration* outConfig); bool isKeyRepeatEnabled(); void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags); nsecs_t interceptKeyBeforeDispatching(droidinput::sp const& inputWindowHandle, droidinput::KeyEvent const* keyEvent, uint32_t policyFlags); bool dispatchUnhandledKey(droidinput::sp const& inputWindowHandle, droidinput::KeyEvent const* keyEvent, uint32_t policyFlags, droidinput::KeyEvent* outFallbackKeyEvent); void notifySwitch(nsecs_t when, int32_t switchCode, int32_t switchValue, uint32_t policyFlags); void pokeUserActivity(nsecs_t eventTime, int32_t eventType); bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid, int32_t injectorUid); protected: EventFilterDispatcherPolicy(const EventFilterDispatcherPolicy&) = delete; EventFilterDispatcherPolicy& operator=(const EventFilterDispatcherPolicy&) = delete; private: std::shared_ptr event_filter; bool key_repeat_enabled; }; } } } #endif // MIR_DUMMY_INPUT_DISPATCHER_POLICY_H_ mir-0.1.8+14.04.20140411/src/server/input/android/rudimentary_input_reader_policy.cpp0000644000015301777760000000325212322054223030741 0ustar pbusernogroup00000000000000/* * 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 */ #include "rudimentary_input_reader_policy.h" namespace mia = mir::input::android; void mia::RudimentaryInputReaderPolicy::getReaderConfiguration(droidinput::InputReaderConfiguration* out_config) { (void)out_config; } droidinput::sp mia::RudimentaryInputReaderPolicy::obtainPointerController(int32_t device_id) { (void)device_id; return pointer_controller; } void mia::RudimentaryInputReaderPolicy::notifyInputDevicesChanged( const droidinput::Vector& input_devices) { (void)input_devices; } droidinput::sp mia::RudimentaryInputReaderPolicy::getKeyboardLayoutOverlay( const droidinput::String8& input_device_descriptor) { (void)input_device_descriptor; return droidinput::KeyCharacterMap::empty(); } droidinput::String8 mia::RudimentaryInputReaderPolicy::getDeviceAlias(const droidinput::InputDeviceIdentifier& identifier) { (void)identifier; return droidinput::String8(); } mir-0.1.8+14.04.20140411/src/server/input/android/android_window_handle_repository.h0000644000015301777760000000320612322054223030543 0ustar pbusernogroup00000000000000/* * 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_ANDROID_WINDOW_HANDLE_REPOSITORY_H_ #define MIR_INPUT_ANDROID_WINDOW_HANDLE_REPOSITORY_H_ #include #include namespace android { class InputWindowHandle; } namespace droidinput = android; namespace mir { namespace input { class InputChannel; namespace android { /// Interface internal to mir::input::android used for tracking the assosciation between droidinput::InputWindowHandle /// and mir::input::InputChannel class WindowHandleRepository { public: virtual ~WindowHandleRepository() = default; virtual droidinput::sp handle_for_channel(std::shared_ptr const& channel) = 0; protected: WindowHandleRepository() = default; WindowHandleRepository(const WindowHandleRepository&) = delete; WindowHandleRepository& operator=(const WindowHandleRepository&) = delete; }; } } } // namespace mir #endif // MIR_INPUT_ANDROID_WINDOW_HANDLE_REPOSITORY_H_ mir-0.1.8+14.04.20140411/src/server/input/android/android_input_targeter.h0000644000015301777760000000344212322054223026460 0ustar pbusernogroup00000000000000/* * 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_ANDROID_TARGET_H_ #define MIR_INPUT_ANDROID_TARGET_H_ #include "mir/shell/input_targeter.h" #include #include namespace android { class InputDispatcherInterface; class InputWindowHandle; } namespace droidinput = android; namespace mir { namespace input { namespace android { class InputConfiguration; class WindowHandleRepository; class InputTargeter : public shell::InputTargeter { public: explicit InputTargeter(droidinput::sp const& input_dispatcher, std::shared_ptr const& repository); virtual ~InputTargeter() noexcept(true); void focus_changed(std::shared_ptr const& focus_channel); void focus_cleared(); protected: InputTargeter(const InputTargeter&) = delete; InputTargeter& operator=(const InputTargeter&) = delete; private: droidinput::sp input_dispatcher; std::shared_ptr const repository; }; } } } // namespace mir #endif // MIR_INPUT_ANDROID_TARGET_H_ mir-0.1.8+14.04.20140411/src/server/input/android/android_input_constants.h0000644000015301777760000000204112322054223026651 0ustar pbusernogroup00000000000000/* * 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_ANDROID_INPUT_CONSTANTS_H_ #define MIR_INPUT_ANDROID_INPUT_CONSTANTS_H_ namespace mir { namespace input { namespace android { static const bool DispatchEnabled = true; static const bool DispatchDisabled = false; static const bool DispatchFrozen = true; static const bool DispatchUnfrozen = false; } } } #endif // MIR_INPUT_ANDROID_INPUT_CONSTANTS_H mir-0.1.8+14.04.20140411/src/server/input/android/android_input_window_handle.cpp0000644000015301777760000000644312322054223030024 0ustar pbusernogroup00000000000000/* * 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 */ #include "android_input_window_handle.h" #include "android_input_application_handle.h" #include "mir/input/input_channel.h" #include "mir/input/surface.h" #include #include namespace mi = mir::input; namespace mia = mi::android; namespace geom = mir::geometry; namespace { struct WindowInfo : public droidinput::InputWindowInfo { WindowInfo(std::shared_ptr const& surface) : surface(surface) { } bool touchableRegionContainsPoint(int32_t x, int32_t y) const override { return surface->contains(geom::Point{x, y}); } std::shared_ptr const surface; }; } mia::InputWindowHandle::InputWindowHandle(droidinput::sp const& input_app_handle, std::shared_ptr const& channel, std::shared_ptr const& surface) : droidinput::InputWindowHandle(input_app_handle), input_channel(channel), surface(surface) { updateInfo(); } bool mia::InputWindowHandle::updateInfo() { if (!mInfo) { mInfo = new WindowInfo(surface); // TODO: How can we avoid recreating the InputChannel which the InputChannelFactory has already created? mInfo->inputChannel = new droidinput::InputChannel(droidinput::String8("TODO: Name"), input_channel->server_fd()); } auto surface_size = surface->size(); auto surface_position = surface->top_left(); mInfo->frameLeft = surface_position.x.as_uint32_t(); mInfo->frameTop = surface_position.y.as_uint32_t(); mInfo->frameRight = mInfo->frameLeft + surface_size.width.as_uint32_t(); mInfo->frameBottom = mInfo->frameTop + surface_size.height.as_uint32_t(); mInfo->touchableRegionLeft = mInfo->frameLeft; mInfo->touchableRegionTop = mInfo->frameTop; mInfo->touchableRegionRight = mInfo->frameRight; mInfo->touchableRegionBottom = mInfo->frameBottom; mInfo->name = droidinput::String8(surface->name().c_str()); mInfo->layoutParamsFlags = droidinput::InputWindowInfo::FLAG_NOT_TOUCH_MODAL; mInfo->layoutParamsType = droidinput::InputWindowInfo::TYPE_APPLICATION; mInfo->scaleFactor = 1.f; mInfo->visible = true; mInfo->canReceiveKeys = true; mInfo->hasFocus = true; mInfo->hasWallpaper = false; mInfo->paused = false; mInfo->dispatchingTimeout = INT_MAX; mInfo->ownerPid = 0; mInfo->ownerUid = 0; mInfo->inputFeatures = 0; // TODO: Set touchableRegion and layer for touch events. return true; } mir-0.1.8+14.04.20140411/src/server/input/android/android_input_window_handle.h0000644000015301777760000000316612322054223027470 0ustar pbusernogroup00000000000000/* * 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_ANDROID_INPUT_WINDOW_HANDLE_H_ #define MIR_INPUT_ANDROID_INPUT_WINDOW_HANDLE_H_ #include #include namespace droidinput = android; namespace mir { namespace input { class Surface; class InputChannel; namespace android { class InputWindowHandle : public droidinput::InputWindowHandle { public: InputWindowHandle(droidinput::sp const& input_app_handle, std::shared_ptr const& channel, std::shared_ptr const& surface); ~InputWindowHandle() {} bool updateInfo(); protected: InputWindowHandle(InputWindowHandle const&) = delete; InputWindowHandle& operator=(InputWindowHandle const&) = delete; private: std::shared_ptr input_channel; std::shared_ptr surface; }; } } } // namespace mir #endif // MIR_INPUT_ANDROID_INPUT_WINDOW_HANDLE_H_ mir-0.1.8+14.04.20140411/src/server/input/android/android_input_manager.cpp0000644000015301777760000000325512322054223026612 0ustar pbusernogroup00000000000000/* * 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 * Daniel d'Andradra */ #include "android_input_manager.h" #include "android_input_constants.h" #include "android_input_thread.h" #include "android_input_channel.h" #include namespace mi = mir::input; namespace mia = mi::android; mia::InputManager::InputManager(droidinput::sp const& event_hub, droidinput::sp const& dispatcher, std::shared_ptr const& reader_thread, std::shared_ptr const& dispatcher_thread) : InputDispatcherManager(dispatcher, dispatcher_thread), event_hub(event_hub), reader_thread(reader_thread) { } mia::InputManager::~InputManager() { } void mia::InputManager::stop() { InputDispatcherManager::stop(); reader_thread->request_stop(); event_hub->wake(); reader_thread->join(); } void mia::InputManager::start() { event_hub->flush(); reader_thread->start(); InputDispatcherManager::start(); } mir-0.1.8+14.04.20140411/src/server/input/android/android_input_reader_policy.cpp0000644000015301777760000000377712322054223030032 0ustar pbusernogroup00000000000000/* * 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 */ #include "android_input_reader_policy.h" #include "android_pointer_controller.h" #include "mir/input/input_region.h" #include "mir/geometry/rectangle.h" namespace mi = mir::input; namespace mia = mir::input::android; mia::InputReaderPolicy::InputReaderPolicy(std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener) : input_region(input_region), pointer_controller(new mia::PointerController(input_region, cursor_listener)) { } void mia::InputReaderPolicy::getReaderConfiguration(droidinput::InputReaderConfiguration* out_config) { static int32_t const default_display_id = 0; static bool const is_external = false; static int32_t const default_display_orientation = droidinput::DISPLAY_ORIENTATION_0; auto bounds = input_region->bounding_rectangle(); auto width = bounds.size.width.as_float(); auto height = bounds.size.height.as_float(); out_config->setDisplayInfo( default_display_id, is_external, width, height, default_display_orientation); out_config->pointerVelocityControlParameters.acceleration = 1.0; } droidinput::sp mia::InputReaderPolicy::obtainPointerController(int32_t /*device_id*/) { return pointer_controller; } mir-0.1.8+14.04.20140411/src/server/input/android/input_dispatcher_manager.h0000644000015301777760000000311212322054223026755 0ustar pbusernogroup00000000000000/* * 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_INPUT_ANDROID_INPUT_DISPATCHER_MANAGER_H_ #define MIR_INPUT_ANDROID_INPUT_DISPATCHER_MANAGER_H_ #include "mir/input/input_manager.h" #include namespace android { class InputDispatcherInterface; } namespace droidinput = android; namespace mir { namespace input { namespace android { class InputThread; class InputDispatcherManager : public mir::input::InputManager { public: InputDispatcherManager( droidinput::sp const& dispatcher, std::shared_ptr const& dispatcher_thread); ~InputDispatcherManager(); void start(); void stop(); std::shared_ptr make_input_channel(); private: droidinput::sp const dispatcher; std::shared_ptr const dispatcher_thread; }; } } } #endif /* MIR_INPUT_ANDROID_INPUT_DISPATCHER_MANAGER_H_ */ mir-0.1.8+14.04.20140411/src/server/input/android/CMakeLists.txt0000644000015301777760000000170012322054223024306 0ustar pbusernogroup00000000000000list( APPEND INPUT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/android_input_manager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/android_input_reader_policy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/android_pointer_controller.cpp ${CMAKE_CURRENT_SOURCE_DIR}/android_input_channel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rudimentary_input_reader_policy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/event_filter_dispatcher_policy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/default_android_input_configuration.cpp ${CMAKE_CURRENT_SOURCE_DIR}/android_input_application_handle.cpp ${CMAKE_CURRENT_SOURCE_DIR}/android_input_window_handle.cpp ${CMAKE_CURRENT_SOURCE_DIR}/android_input_registrar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/android_input_targeter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/android_input_target_enumerator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/dispatcher_input_configuration.cpp ${CMAKE_CURRENT_SOURCE_DIR}/input_dispatcher_manager.cpp ) set( INPUT_SOURCES ${INPUT_SOURCES} PARENT_SCOPE ) mir-0.1.8+14.04.20140411/src/server/input/android/default_android_input_configuration.cpp0000644000015301777760000001042012322054223031543 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/input/android/default_android_input_configuration.h" #include "event_filter_dispatcher_policy.h" #include "android_input_reader_policy.h" #include "android_input_thread.h" #include "android_input_registrar.h" #include "android_input_targeter.h" #include "android_input_target_enumerator.h" #include "android_input_manager.h" #include "mir/input/event_filter.h" #include #include #include #include namespace droidinput = android; namespace mi = mir::input; namespace mia = mi::android; namespace ms = mir::scene; namespace msh = mir::shell; namespace { class CommonInputThread : public mia::InputThread { public: CommonInputThread(std::string const& name, droidinput::sp const& thread) : name(name), thread(thread) { } virtual ~CommonInputThread() { } void start() { thread->run(name.c_str(), droidinput::PRIORITY_URGENT_DISPLAY); } void request_stop() { thread->requestExit(); } void join() { thread->join(); } private: CommonInputThread(const CommonInputThread&) = delete; CommonInputThread& operator=(const CommonInputThread&) = delete; std::string const name; droidinput::sp const thread; }; } mia::DefaultInputConfiguration::DefaultInputConfiguration(std::shared_ptr const& event_filter, std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener, std::shared_ptr const& input_report) : DispatcherInputConfiguration(event_filter, input_region, cursor_listener, input_report) { } mia::DefaultInputConfiguration::~DefaultInputConfiguration() { } droidinput::sp mia::DefaultInputConfiguration::the_dispatcher() { return dispatcher( [this]() -> droidinput::sp { return new droidinput::InputDispatcher(the_dispatcher_policy(), input_report); }); } droidinput::sp mia::DefaultInputConfiguration::the_event_hub() { return event_hub( [this]() { return new droidinput::EventHub(input_report); }); } droidinput::sp mia::DefaultInputConfiguration::the_reader_policy() { return reader_policy( [this]() { return new mia::InputReaderPolicy(input_region, cursor_listener); }); } droidinput::sp mia::DefaultInputConfiguration::the_reader() { return reader( [this]() { return new droidinput::InputReader(the_event_hub(), the_reader_policy(), the_dispatcher()); }); } std::shared_ptr mia::DefaultInputConfiguration::the_reader_thread() { return reader_thread( [this]() { return std::make_shared("InputReader", new droidinput::InputReaderThread(the_reader())); }); } std::shared_ptr mia::DefaultInputConfiguration::the_input_manager() { return input_manager( [this]() { return std::make_shared(the_event_hub(), the_dispatcher(), the_reader_thread(), the_dispatcher_thread()); }); } mir-0.1.8+14.04.20140411/src/server/input/android/dummy_android_pointer_controller.h0000644000015301777760000000502312322054223030557 0ustar pbusernogroup00000000000000/* * 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_ANDROID_DUMMY_POINTER_CONTROLLER_H__ #define MIR_INPUT_ANDROID_DUMMY_POINTER_CONTROLLER_H__ #include namespace droidinput = android; namespace mir { namespace input { namespace android { class DummyPointerController : public droidinput::PointerControllerInterface { public: // From PointerControllerInterface virtual bool getBounds(float* out_min_x, float* out_min_y, float* out_max_x, float* out_max_y) const { (void)out_min_x; (void)out_min_y; (void)out_max_x; (void)out_max_y; // The bounds could not be fetched return false; } virtual void move(float delta_x, float delta_y) { (void)delta_x; (void)delta_y; } virtual void setButtonState(int32_t button_state) { (void)button_state; } virtual int32_t getButtonState() const { return 0; } virtual void setPosition(float x, float y) { (void)x; (void)y; } virtual void getPosition(float* out_x, float* out_y) const { (void)out_x; (void)out_y; } virtual void fade(Transition transition) { (void)transition; } virtual void unfade(Transition transition) { (void)transition; } virtual void setPresentation(Presentation presentation) { (void)presentation; } virtual void setSpots(const droidinput::PointerCoords* spot_coords, uint32_t spot_count) { (void)spot_coords; (void)spot_count; } virtual void clearSpots() { } virtual void setDisplaySize(int32_t width, int32_t height) { (void)width; (void)height; } virtual void setDisplayOrientation(int32_t orientation) { (void)orientation; } }; } } } // namespace mir #endif // MIR_ANDROID_DUMMY_POINTER_CONTROLER_H__ mir-0.1.8+14.04.20140411/src/server/input/android/event_filter_dispatcher_policy.cpp0000644000015301777760000000677612322054223030547 0ustar pbusernogroup00000000000000/* * 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 */ #include "event_filter_dispatcher_policy.h" #include "mir/input/android/android_input_lexicon.h" namespace mi = mir::input; namespace mia = mi::android; mia::EventFilterDispatcherPolicy::EventFilterDispatcherPolicy(std::shared_ptr const& event_filter, bool key_repeat_enabled) : event_filter(event_filter), key_repeat_enabled(key_repeat_enabled) { } void mia::EventFilterDispatcherPolicy::notifyConfigurationChanged(nsecs_t /* when */) { } nsecs_t mia::EventFilterDispatcherPolicy::notifyANR(droidinput::sp const& /* inputApplicationHandle */, droidinput::sp const& /* inputWindowHandle */) { return 0; } void mia::EventFilterDispatcherPolicy::notifyInputChannelBroken(droidinput::sp const& /* inputWindowHandle */) { } void mia::EventFilterDispatcherPolicy::getDispatcherConfiguration(droidinput::InputDispatcherConfiguration* /* outConfig */) { } bool mia::EventFilterDispatcherPolicy::isKeyRepeatEnabled() { return key_repeat_enabled; } bool mia::EventFilterDispatcherPolicy::filterInputEvent(const droidinput::InputEvent* input_event, uint32_t /*policy_flags*/) { MirEvent mir_ev; mia::Lexicon::translate(input_event, mir_ev); // TODO: Use XKBMapper return !event_filter->handle(mir_ev); } void mia::EventFilterDispatcherPolicy::interceptKeyBeforeQueueing(const droidinput::KeyEvent* /*key_event*/, uint32_t& policy_flags) { policy_flags |= droidinput::POLICY_FLAG_PASS_TO_USER; } void mia::EventFilterDispatcherPolicy::interceptMotionBeforeQueueing(nsecs_t /* when */, uint32_t& policy_flags) { policy_flags |= droidinput::POLICY_FLAG_PASS_TO_USER; } nsecs_t mia::EventFilterDispatcherPolicy::interceptKeyBeforeDispatching( droidinput::sp const& /* inputWindowHandle */, droidinput::KeyEvent const* /* keyEvent */, uint32_t /* policyFlags */) { return 0; } bool mia::EventFilterDispatcherPolicy::dispatchUnhandledKey(droidinput::sp const& /* inputWindowHandle */, droidinput::KeyEvent const* /* keyEvent */, uint32_t /* policyFlags */, droidinput::KeyEvent* /* outFallbackKeyEvent */) { return false; } void mia::EventFilterDispatcherPolicy::notifySwitch(nsecs_t /* when */, int32_t /* switchCode */, int32_t /* switchValue */, uint32_t /* policyFlags */) { } void mia::EventFilterDispatcherPolicy::pokeUserActivity(nsecs_t /* eventTime */, int32_t /* eventType */) { } bool mia::EventFilterDispatcherPolicy::checkInjectEventsPermissionNonReentrant(int32_t /* injectorPid */, int32_t /* injectorUid */) { return true; } mir-0.1.8+14.04.20140411/src/server/input/android/android_input_target_enumerator.h0000644000015301777760000000333212322054223030370 0ustar pbusernogroup00000000000000/* * 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_ANDROID_TARGET_ENUMERATOR_H_ #define MIR_INPUT_ANDROID_TARGET_ENUMERATOR_H_ #include #include #include #include namespace android { class InputWindowHandle; } namespace droidinput = android; namespace mir { namespace scene { class InputRegitrar; } namespace input { class InputTargets; namespace android { class WindowHandleRepository; class InputTargetEnumerator : public droidinput::InputEnumerator { public: explicit InputTargetEnumerator(std::shared_ptr const& targets, std::shared_ptr const& repository); virtual ~InputTargetEnumerator() noexcept(true); void for_each(std::function const&)> const& callback); private: std::weak_ptr const targets; std::weak_ptr const repository; }; } } } // namespace mir #endif // MIR_INPUT_ANDROID_TARGET_ENUMERATOR_H_ mir-0.1.8+14.04.20140411/src/server/input/android/android_input_thread.h0000644000015301777760000000224712322054223026114 0ustar pbusernogroup00000000000000/* * 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_ANDROID_INPUT_THREAD_H_ #define MIR_INPUT_ANDROID_INPUT_THREAD_H_ namespace mir { namespace input { namespace android { class InputThread { public: virtual ~InputThread() {} virtual void start() = 0; virtual void request_stop() = 0; virtual void join() = 0; protected: InputThread() {}; InputThread(const InputThread&) = delete; InputThread& operator=(const InputThread&) = delete; }; } } } // namespace mir #endif // MIR_INPUT_ANDROID_INPUT_THREAD_H_ mir-0.1.8+14.04.20140411/src/server/input/android/android_input_registrar.h0000644000015301777760000000416512322054223026650 0ustar pbusernogroup00000000000000/* * 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_ANDROID_REGISTRAR_H_ #define MIR_INPUT_ANDROID_REGISTRAR_H_ #include "android_window_handle_repository.h" #include "mir/scene/input_registrar.h" #include #include #include namespace android { class InputDispatcherInterface; class InputWindowHandle; } namespace droidinput = android; namespace mir { namespace input { class Surface; namespace android { class InputConfiguration; class InputTargeter; class InputRegistrar : public scene::InputRegistrar, public WindowHandleRepository { public: explicit InputRegistrar(droidinput::sp const& input_dispatcher); virtual ~InputRegistrar() noexcept(true); void input_channel_opened(std::shared_ptr const& opened_channel, std::shared_ptr const& surface, InputReceptionMode mode); void input_channel_closed(std::shared_ptr const& closed_channel); virtual droidinput::sp handle_for_channel(std::shared_ptr const& channel); private: droidinput::sp const input_dispatcher; std::map, droidinput::sp> window_handles; std::mutex handles_mutex; }; } } } // namespace mir #endif // MIR_INPUT_ANDROID_REGISTRAR_H_ mir-0.1.8+14.04.20140411/src/server/input/android/rudimentary_input_reader_policy.h0000644000015301777760000000361012322054223030404 0ustar pbusernogroup00000000000000/* * 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_ANDROID_RUDIMENTARY_INPUT_READER_POLICY_H_ #define MIR_INPUT_ANDROID_RUDIMENTARY_INPUT_READER_POLICY_H_ // from android #include namespace droidinput = android; namespace mir { namespace input { namespace android { class RudimentaryInputReaderPolicy : public droidinput::InputReaderPolicyInterface { public: // From InputReaderPolicyInterface virtual void getReaderConfiguration( droidinput::InputReaderConfiguration* out_config); // TODO: We should think about refactoring the device identification approach virtual droidinput::sp obtainPointerController( int32_t device_id); virtual void notifyInputDevicesChanged( const droidinput::Vector& input_devices); virtual droidinput::sp getKeyboardLayoutOverlay( const droidinput::String8& input_device_descriptor); virtual droidinput::String8 getDeviceAlias( const droidinput::InputDeviceIdentifier& identifier); private: droidinput::sp pointer_controller; }; } } } // namespace mir #endif // MIR_INPUT_ANDROID_RUDIMENTARY_INPUT_READER_POLICY_H_ mir-0.1.8+14.04.20140411/src/server/input/android/android_input_application_handle.h0000644000015301777760000000267012322054223030463 0ustar pbusernogroup00000000000000/* * 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_ANDROID_INPUT_APPLICATION_HANDLE_H_ #define MIR_INPUT_ANDROID_INPUT_APPLICATION_HANDLE_H_ #include #include namespace droidinput = android; namespace mir { namespace input { class Surface; namespace android { class InputApplicationHandle : public droidinput::InputApplicationHandle { public: InputApplicationHandle(std::shared_ptr const& surface); ~InputApplicationHandle() {} bool updateInfo(); protected: InputApplicationHandle(InputApplicationHandle const&) = delete; InputApplicationHandle& operator=(InputApplicationHandle const&) = delete; private: std::shared_ptr surface; }; } } } // namespace mir #endif // MIR_INPUT_ANDROID_INPUT_APPLICATION_HANDLE_H_ mir-0.1.8+14.04.20140411/src/server/input/default_configuration.cpp0000644000015301777760000001022212322054223025204 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/default_server_configuration.h" #include "display_input_region.h" #include "event_filter_chain.h" #include "nested_input_configuration.h" #include "nested_input_relay.h" #include "null_input_configuration.h" #include "mir/input/android/default_android_input_configuration.h" #include "mir/options/configuration.h" #include "mir/options/option.h" #include "mir/report/legacy_input_report.h" namespace mi = mir::input; namespace mia = mi::android; namespace mr = mir::report; namespace ms = mir::scene; namespace msh = mir::shell; std::shared_ptr mir::DefaultServerConfiguration::the_input_region() { return input_region( [this]() { return std::make_shared(the_display()); }); } std::shared_ptr mir::DefaultServerConfiguration::the_composite_event_filter() { return composite_event_filter( [this]() -> std::shared_ptr { std::initializer_list const> filter_list {default_filter}; return std::make_shared(filter_list); }); } std::shared_ptr mir::DefaultServerConfiguration::the_input_configuration() { return input_configuration( [this]() -> std::shared_ptr { auto const options = the_options(); if (!options->get(options::enable_input_opt)) { return std::make_shared(); } else if (!options->is_set(options::host_socket_opt)) { // fallback to standalone if host socket is unset return std::make_shared( the_composite_event_filter(), the_input_region(), the_cursor_listener(), the_input_report()); } else { return std::make_shared( the_nested_input_relay(), the_composite_event_filter(), the_input_region(), the_cursor_listener(), the_input_report()); } }); } std::shared_ptr mir::DefaultServerConfiguration::the_input_manager() { return input_manager( [&, this]() -> std::shared_ptr { if (the_options()->get(options::legacy_input_report_opt) == options::log_opt_value) mr::legacy_input::initialize(the_logger()); return the_input_configuration()->the_input_manager(); }); } std::shared_ptr mir::DefaultServerConfiguration::the_input_targeter() { return input_targeter( [&]() -> std::shared_ptr { return the_input_configuration()->the_input_targeter(); }); } std::shared_ptr mir::DefaultServerConfiguration::the_input_registrar() { return input_registrar( [&]() -> std::shared_ptr { return the_input_configuration()->the_input_registrar(); }); } auto mir::DefaultServerConfiguration::the_nested_input_relay() -> std::shared_ptr { return nested_input_relay([]{ return std::make_shared(); }); } auto mir::DefaultServerConfiguration::the_nested_event_filter() -> std::shared_ptr { return the_nested_input_relay(); } mir-0.1.8+14.04.20140411/src/server/input/event_filter_chain.cpp0000644000015301777760000000275112322054223024471 0ustar pbusernogroup00000000000000/* * 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 */ #include "event_filter_chain.h" namespace mi = mir::input; mi::EventFilterChain::EventFilterChain( std::initializer_list const> const& values) : filters(values.begin(), values.end()) { } bool mi::EventFilterChain::handle(MirEvent const& event) { auto it = filters.begin(); while (it != filters.end()) { auto filter = (*it).lock(); if (!filter) { it = filters.erase(it); continue; } if (filter->handle(event)) return true; ++it; } return false; } void mi::EventFilterChain::append(std::shared_ptr const& filter) { filters.push_back(filter); } void mi::EventFilterChain::prepend(std::shared_ptr const& filter) { filters.insert(filters.begin(), filter); } mir-0.1.8+14.04.20140411/src/server/input/nested_input_configuration.cpp0000644000015301777760000000324412322054223026267 0ustar pbusernogroup00000000000000/* * 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 */ #include "nested_input_configuration.h" #include "nested_input_relay.h" #include namespace mi = mir::input; mi::NestedInputConfiguration::NestedInputConfiguration( std::shared_ptr const& input_relay, std::shared_ptr const& event_filter, std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener, std::shared_ptr const& input_report) : android::DispatcherInputConfiguration(event_filter, input_region, cursor_listener, input_report), input_relay(input_relay) { } mi::NestedInputConfiguration::~NestedInputConfiguration() { } droidinput::sp mi::NestedInputConfiguration::the_dispatcher() { return dispatcher( [this]() { auto const result = new droidinput::InputDispatcher(the_dispatcher_policy(), input_report); input_relay->set_dispatcher(result); return result; }); } mir-0.1.8+14.04.20140411/src/server/input/nested_input_relay.h0000644000015301777760000000237712322054223024207 0ustar pbusernogroup00000000000000/* * 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_INPUT_NESTED_INPUT_RELAY_H_ #define MIR_INPUT_NESTED_INPUT_RELAY_H_ #include "mir/input/event_filter.h" #include namespace android { class InputDispatcher; } namespace mir { namespace input { class NestedInputRelay : public EventFilter { public: NestedInputRelay(); ~NestedInputRelay() noexcept; void set_dispatcher(::android::sp<::android::InputDispatcher> const& dispatcher); private: bool handle(MirEvent const& event); ::android::sp<::android::InputDispatcher> dispatcher; }; } } #endif /* MIR_INPUT_NESTED_INPUT_RELAY_H_ */ mir-0.1.8+14.04.20140411/src/server/input/null_input_configuration.cpp0000644000015301777760000000460712322054223025763 0ustar pbusernogroup00000000000000/* * 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 */ #include "null_input_configuration.h" #include "mir/scene/input_registrar.h" #include "mir/shell/input_targeter.h" #include "mir/input/input_manager.h" namespace mi = mir::input; namespace ms = mir::scene; namespace msh = mir::shell; namespace { struct NullInputRegistrar : public ms::InputRegistrar { NullInputRegistrar() = default; virtual ~NullInputRegistrar() noexcept(true) = default; void input_channel_opened(std::shared_ptr const&, std::shared_ptr const&, mi::InputReceptionMode /* receives_all_input */) { } void input_channel_closed(std::shared_ptr const&) { } }; struct NullInputTargeter : public msh::InputTargeter { NullInputTargeter() = default; virtual ~NullInputTargeter() noexcept(true) = default; void focus_changed(std::shared_ptr const&) { } void focus_cleared() { } }; struct NullInputManager : public mi::InputManager { void start() { } void stop() { } std::shared_ptr make_input_channel() { return std::shared_ptr(); } }; } std::shared_ptr mi::NullInputConfiguration::the_input_registrar() { return std::make_shared(); } std::shared_ptr mi::NullInputConfiguration::the_input_targeter() { return std::make_shared(); } std::shared_ptr mi::NullInputConfiguration::the_input_manager() { return std::make_shared(); } void mi::NullInputConfiguration::set_input_targets(std::shared_ptr const&) { } mir-0.1.8+14.04.20140411/src/server/input/vt_filter.cpp0000644000015301777760000000435312322054223022637 0ustar pbusernogroup00000000000000/* * 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 Ancell */ #include "mir/input/vt_filter.h" #include #include #include #include #include namespace { void set_active_vt(int vt) { auto console_fd = open("/dev/console", O_RDONLY | O_NDELAY); ioctl(console_fd, VT_ACTIVATE, vt); close(console_fd); } } bool mir::input::VTFilter::handle(MirEvent const& event) { if (event.type == mir_event_type_key && event.key.action == mir_key_action_down && (event.key.modifiers & mir_key_modifier_alt) && (event.key.modifiers & mir_key_modifier_ctrl)) { switch (event.key.scan_code) { case KEY_F1: set_active_vt(1); return true; case KEY_F2: set_active_vt(2); return true; case KEY_F3: set_active_vt(3); return true; case KEY_F4: set_active_vt(4); return true; case KEY_F5: set_active_vt(5); return true; case KEY_F6: set_active_vt(6); return true; case KEY_F7: set_active_vt(7); return true; case KEY_F8: set_active_vt(8); return true; case KEY_F9: set_active_vt(9); return true; case KEY_F10: set_active_vt(10); return true; case KEY_F11: set_active_vt(11); return true; case KEY_F12: set_active_vt(12); return true; } } return false; } mir-0.1.8+14.04.20140411/src/server/input/nested_input_configuration.h0000644000015301777760000000317212322054223025734 0ustar pbusernogroup00000000000000/* * 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_INPUT_NESTED_INPUT_CONFIGURATION_H_ #define MIR_INPUT_NESTED_INPUT_CONFIGURATION_H_ #include "mir/input/android/dispatcher_input_configuration.h" namespace mir { namespace input { class NestedInputRelay; class NestedInputConfiguration : public android::DispatcherInputConfiguration { public: NestedInputConfiguration( std::shared_ptr const& input_relay, std::shared_ptr const& event_filter, std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener, std::shared_ptr const& input_report); virtual ~NestedInputConfiguration(); private: droidinput::sp the_dispatcher() override; std::shared_ptr const input_relay; android::CachedAndroidPtr dispatcher; }; } } #endif /* MIR_INPUT_NESTED_INPUT_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/src/server/input/CMakeLists.txt0000644000015301777760000000066212322054223022674 0ustar pbusernogroup00000000000000include_directories(${MIR_3RD_PARTY_INCLUDE_DIRECTORIES}) include_directories(${MIR_ANDROID_INCLUDE_DIRECTORIES}) set( INPUT_SOURCES event_filter_chain.cpp null_input_configuration.cpp nested_input_configuration.cpp nested_input_relay.cpp display_input_region.cpp vt_filter.cpp default_configuration.cpp ) add_subdirectory(android) add_library( mirinput STATIC ${INPUT_SOURCES} ) uses_android_input(mirinput) mir-0.1.8+14.04.20140411/src/server/input/display_input_region.h0000644000015301777760000000235312322054223024533 0ustar pbusernogroup00000000000000/* * 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_DISPLAY_INPUT_REGION_H_ #define MIR_INPUT_DISPLAY_INPUT_REGION_H_ #include "mir/input/input_region.h" #include namespace mir { namespace graphics { class Display; } namespace input { class DisplayInputRegion : public InputRegion { public: DisplayInputRegion(std::shared_ptr const& display); geometry::Rectangle bounding_rectangle(); void confine(geometry::Point& point); private: std::shared_ptr const display; }; } } #endif /* MIR_INPUT_DISPLAY_INPUT_REGION_H_ */ mir-0.1.8+14.04.20140411/src/server/input/display_input_region.cpp0000644000015301777760000000324112322054223025063 0ustar pbusernogroup00000000000000/* * 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 */ #include "display_input_region.h" #include "mir/graphics/display.h" #include "mir/graphics/display_buffer.h" #include "mir/geometry/rectangle.h" #include "mir/geometry/rectangles.h" namespace mi = mir::input; namespace mg = mir::graphics; namespace geom = mir::geometry; mi::DisplayInputRegion::DisplayInputRegion( std::shared_ptr const& display) : display{display} { } geom::Rectangle mi::DisplayInputRegion::bounding_rectangle() { geom::Rectangles rectangles; display->for_each_display_buffer( [&rectangles](mg::DisplayBuffer const& buffer) { rectangles.add(buffer.view_area()); }); return rectangles.bounding_rectangle(); } void mi::DisplayInputRegion::confine(geom::Point& point) { geom::Rectangles rectangles; display->for_each_display_buffer( [&rectangles](mg::DisplayBuffer const& buffer) { rectangles.add(buffer.view_area()); }); rectangles.confine(point); } mir-0.1.8+14.04.20140411/src/server/input/nested_input_relay.cpp0000644000015301777760000000752612322054223024543 0ustar pbusernogroup00000000000000/* * 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 */ #include "nested_input_relay.h" #include #include #include namespace mi = mir::input; mi::NestedInputRelay::NestedInputRelay() { } mi::NestedInputRelay::~NestedInputRelay() noexcept { } void mi::NestedInputRelay::set_dispatcher(::android::sp<::android::InputDispatcher> const& dispatcher) { this->dispatcher = dispatcher; } bool mi::NestedInputRelay::handle(MirEvent const& event) { if (dispatcher == nullptr) { return false; } static auto const policy_flags = 0; switch (event.type) { case mir_event_type_key: { ::android::NotifyKeyArgs const notify_key_args( event.key.event_time, event.key.device_id, event.key.source_id, policy_flags, event.key.action, event.key.flags, event.key.key_code, event.key.scan_code, event.key.modifiers, event.key.down_time); dispatcher->notifyKey(¬ify_key_args); break; } case mir_event_type_motion: { std::vector<::android::PointerProperties> pointer_properties(event.motion.pointer_count); std::vector<::android::PointerCoords> pointer_coords(event.motion.pointer_count); for(auto i = 0U; i != event.motion.pointer_count; ++i) { pointer_properties[i].id = event.motion.pointer_coordinates[i].id; pointer_properties[i].toolType = 0; pointer_coords[i].setAxisValue(AMOTION_EVENT_AXIS_X, event.motion.pointer_coordinates[i].x); pointer_coords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, event.motion.pointer_coordinates[i].y); pointer_coords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, event.motion.pointer_coordinates[i].pressure); pointer_coords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, event.motion.pointer_coordinates[i].size); pointer_coords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, event.motion.pointer_coordinates[i].touch_major); pointer_coords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, event.motion.pointer_coordinates[i].touch_minor); pointer_coords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, event.motion.pointer_coordinates[i].orientation); } ::android::NotifyMotionArgs const notify_motion_args( event.motion.event_time, event.motion.device_id, event.motion.source_id, policy_flags, event.motion.action, event.motion.flags, event.motion.modifiers, event.motion.button_state, event.motion.edge_flags, event.motion.pointer_count, pointer_properties.data(), pointer_coords.data(), event.motion.x_precision, event.motion.y_precision, event.motion.down_time); dispatcher->notifyMotion(¬ify_motion_args); break; } case mir_event_type_surface: // Just ignore these events: it doesn't make sense to pass them on. break; default: BOOST_THROW_EXCEPTION(std::logic_error("Unhandled event type")); } return true; } mir-0.1.8+14.04.20140411/src/server/input/null_input_configuration.h0000644000015301777760000000273012322054223025423 0ustar pbusernogroup00000000000000/* * 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_NULL_INPUT_CONFIGURATION_H_ #define MIR_INPUT_NULL_INPUT_CONFIGURATION_H_ #include "mir/input/input_configuration.h" namespace mir { namespace input { class NullInputConfiguration : public InputConfiguration { public: NullInputConfiguration() = default; virtual ~NullInputConfiguration() = default; std::shared_ptr the_input_registrar(); std::shared_ptr the_input_targeter(); std::shared_ptr the_input_manager(); void set_input_targets(std::shared_ptr const& /* targets */); protected: NullInputConfiguration(const NullInputConfiguration&) = delete; NullInputConfiguration& operator=(const NullInputConfiguration&) = delete; }; } } #endif // MIR_INPUT_NULL_INPUT_CONFIGURATION mir-0.1.8+14.04.20140411/src/server/input/event_filter_chain.h0000644000015301777760000000244312322054223024134 0ustar pbusernogroup00000000000000/* * 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_CHAIN_H_ #define MIR_INPUT_EVENT_FILTER_CHAIN_H_ #include "mir/input/composite_event_filter.h" #include namespace mir { namespace input { class EventFilterChain : public CompositeEventFilter { public: explicit EventFilterChain(std::initializer_list const> const& values); bool handle(MirEvent const& event); void append(std::shared_ptr const& filter); void prepend(std::shared_ptr const& filter); private: std::vector> filters; }; } } #endif // MIR_INPUT_EVENT_FILTER_CHAIN_H_ mir-0.1.8+14.04.20140411/src/server/report_exception.cpp0000644000015301777760000000231312322054223023065 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/report_exception.h" #include "mir/abnormal_exit.h" #include void mir::report_exception(std::ostream& out) { try { throw; } catch (mir::AbnormalExit const& error) { out << error.what() << std::endl; } catch (std::exception const& error) { out << "ERROR: " << boost::diagnostic_information(error) << std::endl; } catch (...) { out << "ERROR: unrecognised exception. (This is weird!)" << std::endl; } } mir-0.1.8+14.04.20140411/src/server/CMakeLists.txt0000644000015301777760000000430412322054247021540 0ustar pbusernogroup00000000000000include_directories( ${PROJECT_SOURCE_DIR}/include/platform ${PROJECT_SOURCE_DIR}/include/server) add_subdirectory(compositor/) add_subdirectory(graphics/) add_subdirectory(input/) add_subdirectory(report/) add_subdirectory(logging/) add_subdirectory(scene/) add_subdirectory(frontend/) add_subdirectory(shell/) add_subdirectory(time/) set(PREFIX "${CMAKE_INSTALL_PREFIX}") set(EXEC_PREFIX "${CMAKE_INSTALL_PREFIX}") set(LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}") set(INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include/mirserver") set(PLATFORM_INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include/mirplatform") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/mirserver.pc.in ${CMAKE_CURRENT_BINARY_DIR}/mirserver.pc ) set( SRCS run_mir.cpp report_exception.cpp display_server.cpp default_server_configuration.cpp asio_main_loop.cpp ) set(MIRSERVER_LINKAGE SHARED) add_library(mirserver ${MIRSERVER_LINKAGE} ${SRCS} ) list(APPEND MIRSERVER_ARCHIVES miroptions mircompositor mirfrontend mirgraphics mirinput mirsharedinput mirsharedgeometry mirsharedlogging mirsharedenv mirsharedsharedlibrary mirscene mirtime mirlttng mirreport mirlogger mirnestedgraphics miroffscreengraphics ) list(APPEND MIRSERVER_LINKS mirprotobuf mirplatform mirclient 3rd_party ${EGL_LDFLAGS} ${EGL_LIBRARIES} ${GLESv2_LDFLAGS} ${GLESv2_LIBRARIES} ${UDEV_LDFLAGS} ${UDEV_LIBRARIES} ) if(${MIRSERVER_LINKAGE} STREQUAL SHARED) target_link_libraries(mirserver LINK_PRIVATE -Wl,-whole-archive ${MIRSERVER_ARCHIVES} -Wl,-no-whole-archive LINK_PUBLIC ${MIRSERVER_LINKS} ) install(TARGETS mirserver LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/platform/mir DESTINATION "include/mirplatform" ) install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/server/mir DESTINATION "include/mirserver" ) else() target_link_libraries(mirserver LINK_PUBLIC ${MIRSERVER_ARCHIVES} ${MIRSERVER_LINKS} ) endif() set(MIRSERVER_ABI 18) set_target_properties( mirserver PROPERTIES SOVERSION ${MIRSERVER_ABI} ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mirserver.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) mir-0.1.8+14.04.20140411/src/shared/0000755000015301777760000000000012322054703016734 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/logging/0000755000015301777760000000000012322054703020362 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/logging/input_timestamp.cpp0000644000015301777760000000246312322054223024312 0ustar pbusernogroup00000000000000/* * 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/logging/input_timestamp.h" #include #include #include std::string mir::logging::input_timestamp(nsecs_t when) { // Input events use CLOCK_REALTIME, and so we must... struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); nsecs_t now = ts.tv_sec * 1000000000LL + ts.tv_nsec; nsecs_t age = now - when; char str[64]; snprintf(str, sizeof str, "%lld (%ld.%06ld ms ago)", static_cast(when), static_cast(age / 1000000LL), static_cast(age % 1000000LL)); return std::string(str); } mir-0.1.8+14.04.20140411/src/shared/logging/dumb_console_logger.cpp0000644000015301777760000000312712322054223025076 0ustar pbusernogroup00000000000000/* * 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 Voß */ #include "mir/logging/dumb_console_logger.h" #include #include #include namespace ml = mir::logging; void ml::DumbConsoleLogger::log(ml::Logger::Severity severity, const std::string& message, const std::string& component) { static const char* lut[5] = { "CC", "EE", "WW", "II", "DD" }; std::ostream& out = severity < Logger::informational ? std::cerr : std::cout; struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); char now[32]; snprintf(now, sizeof(now), "%ld.%06ld", (long)ts.tv_sec, ts.tv_nsec / 1000); out << "[" << now << "] (" << lut[severity] << ") " << component << ": " << message << "\n"; } mir-0.1.8+14.04.20140411/src/shared/logging/CMakeLists.txt0000644000015301777760000000142412322054223023120 0ustar pbusernogroup00000000000000# 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 add_library(mirsharedlogging STATIC dumb_console_logger.cpp input_timestamp.cpp ) mir-0.1.8+14.04.20140411/src/shared/geometry/0000755000015301777760000000000012322054703020567 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/geometry/rectangles.cpp0000644000015301777760000001115112322054223023416 0ustar pbusernogroup00000000000000/* * 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/geometry/rectangles.h" #include "mir/geometry/displacement.h" #include namespace geom = mir::geometry; namespace { template T clamp(T x, T min, T max) { return std::min(std::max(x, min), max); } geom::Rectangle rect_from_points(geom::Point const& tl, geom::Point const& br) { return {tl, geom::Size{geom::Width{br.x.as_int() - tl.x.as_int()}, geom::Height{br.y.as_int() - tl.y.as_int()}}}; } } geom::Rectangles::Rectangles() { } geom::Rectangles::Rectangles(std::initializer_list const& rects) : rectangles{rects} { } void geom::Rectangles::add(geom::Rectangle const& rect) { rectangles.push_back(rect); } void geom::Rectangles::clear() { rectangles.clear(); } void geom::Rectangles::confine(geom::Point& point) const { geom::Point ret_point{point}; geom::Displacement min_dp{geom::DeltaX{std::numeric_limits::max()}, geom::DeltaY{std::numeric_limits::max()}}; for (auto const& rect : rectangles) { /* * If a screen contains the point then no need to confine it further, * otherwise confine the point, keeping the confined position that * is closer to the original point. */ if (rect.contains(point)) { ret_point = point; break; } else if (rect.size.width > geom::Width{0} && rect.size.height > geom::Height{0}) { auto br = rect.bottom_right(); auto min_x = rect.top_left.x; auto max_x = geom::X{br.x.as_int() - 1}; auto min_y = rect.top_left.y; auto max_y = geom::Y{br.y.as_int() - 1}; geom::Point confined_point{clamp(point.x, min_x, max_x), clamp(point.y, min_y, max_y)}; /* * Keep the confined point that has the least distance to the * original point */ auto dp = confined_point - point; if (dp < min_dp) { ret_point = confined_point; min_dp = dp; } } } point = ret_point; } geom::Rectangle geom::Rectangles::bounding_rectangle() const { if (rectangles.size() == 0) return geom::Rectangle(); geom::Point tl; geom::Point br; bool points_initialized{false}; for (auto const& rect : rectangles) { geom::Point rtl = rect.top_left; geom::Point rbr = rect.bottom_right(); if (!points_initialized) { tl = rtl; br = rbr; points_initialized = true; } else { tl.x = std::min(rtl.x, tl.x); tl.y = std::min(rtl.y, tl.y); br.x = std::max(rbr.x, br.x); br.y = std::max(rbr.y, br.y); } } return rect_from_points(tl, br); } geom::Rectangles::const_iterator geom::Rectangles::begin() const { return rectangles.begin(); } geom::Rectangles::const_iterator geom::Rectangles::end() const { return rectangles.end(); } geom::Rectangles::size_type geom::Rectangles::size() const { return rectangles.size(); } bool geom::Rectangles::operator==(Rectangles const& other) const { if (rectangles.size() != other.rectangles.size()) return false; size_t const size{rectangles.size()}; std::vector element_used(size, false); for (auto const& rect : rectangles) { bool found{false}; for (size_t i = 0; i < size; i++) { if (!element_used[i] && other.rectangles[i] == rect) { found = true; element_used[i] = true; break; } } if (!found) return false; } return true; } bool geom::Rectangles::operator!=(Rectangles const& rects) const { return !(*this == rects); } mir-0.1.8+14.04.20140411/src/shared/geometry/rectangle.cpp0000644000015301777760000000413112322054223023233 0ustar pbusernogroup00000000000000/* * 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/geometry/rectangle.h" #include namespace geom = mir::geometry; geom::Point geom::Rectangle::bottom_right() const { return {top_left.x.as_int() + size.width.as_int(), top_left.y.as_int() + size.height.as_int()}; } bool geom::Rectangle::contains(Rectangle const& r) const { return r.top_left.x >= top_left.x && r.top_left.x.as_int() + r.size.width.as_int() <= top_left.x.as_int() + size.width.as_int() && r.top_left.y >= top_left.y && r.top_left.y.as_int() + r.size.height.as_int() <= top_left.y.as_int() + size.height.as_int(); } bool geom::Rectangle::contains(Point const& p) const { if (size.width == geom::Width{0} || size.height == geom::Height{0}) return false; auto br = bottom_right(); return p.x >= top_left.x && p.x < br.x && p.y >= top_left.y && p.y < br.y; } bool geom::Rectangle::overlaps(Rectangle const& r) const { if (size.width > geom::Width{0} && size.height > geom::Height{0} && r.size.width > geom::Width{0} && r.size.height > geom::Height{0}) { auto tl1 = top_left; auto br1 = bottom_right(); auto tl2 = r.top_left; auto br2 = r.bottom_right(); return !(tl2.x >= br1.x || br2.x <= tl1.x || tl2.y >= br1.y || br2.y <= tl1.y); } else { return false; } } mir-0.1.8+14.04.20140411/src/shared/geometry/ostream.cpp0000644000015301777760000000330312322054223022741 0ustar pbusernogroup00000000000000/* * 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/geometry/displacement.h" #include "mir/geometry/point.h" #include "mir/geometry/size.h" #include "mir/geometry/rectangle.h" #include "mir/geometry/rectangles.h" #include namespace geom = mir::geometry; std::ostream& geom::operator<<(std::ostream& out, Displacement const& value) { out << '(' << value.dx << ", " << value.dy << ')'; return out; } std::ostream& geom::operator<<(std::ostream& out, Point const& value) { out << '(' << value.x << ", " << value.y << ')'; return out; } std::ostream& geom::operator<<(std::ostream& out, Size const& value) { out << '(' << value.width << ", " << value.height << ')'; return out; } std::ostream& geom::operator<<(std::ostream& out, Rectangle const& value) { out << '(' << value.top_left << ", " << value.size << ')'; return out; } std::ostream& geom::operator<<(std::ostream& out, Rectangles const& value) { out << '['; for (auto const& rect : value) out << rect << ", "; out << ']'; return out; } mir-0.1.8+14.04.20140411/src/shared/geometry/CMakeLists.txt0000644000015301777760000000143112322054223023323 0ustar pbusernogroup00000000000000# 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 add_library( mirsharedgeometry STATIC rectangle.cpp rectangles.cpp ostream.cpp ) mir-0.1.8+14.04.20140411/src/shared/graphics/0000755000015301777760000000000012322054703020534 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/graphics/android/0000755000015301777760000000000012322054703022154 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/graphics/android/mir_native_window.cpp0000644000015301777760000001572612322054223026414 0ustar pbusernogroup00000000000000/* * 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/android/mir_native_window.h" #include "mir/graphics/android/android_driver_interpreter.h" #include "mir/graphics/android/sync_fence.h" 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->queueBuffer(buffer, -1); } 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) { return cancelBuffer_static(window, buffer, -1); } 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) : driver_interpreter(interpreter) { 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) { if (interval == 0) { driver_interpreter->sync_to_display(false); } else { driver_interpreter->sync_to_display(true); } return 0; } int mga::MirNativeWindow::dequeueBuffer(struct ANativeWindowBuffer** buffer_to_driver, int* fence_fd) { auto buffer = driver_interpreter->driver_requests_buffer(); //driver is responsible for closing this native handle *fence_fd = buffer->copy_fence(); *buffer_to_driver = buffer->anwb(); return 0; } int mga::MirNativeWindow::dequeueBufferAndWait(struct ANativeWindowBuffer** buffer_to_driver) { auto buffer = driver_interpreter->driver_requests_buffer(); *buffer_to_driver = buffer->anwb(); buffer->wait_for_content(); return 0; } int mga::MirNativeWindow::queueBuffer(struct ANativeWindowBuffer* buffer, int fence) { driver_interpreter->driver_returns_buffer(buffer, fence); return 0; } int mga::MirNativeWindow::cancelBuffer(struct ANativeWindowBuffer* buffer, int fence) { driver_interpreter->driver_returns_buffer(buffer, fence); return 0; } int mga::MirNativeWindow::query(int key, int* value) const { *value = driver_interpreter->driver_requests_info(key); return 0; } int mga::MirNativeWindow::perform(int key, va_list arg_list ) { int ret = 0; va_list args; va_copy(args, arg_list); int driver_format; switch(key) { case NATIVE_WINDOW_SET_BUFFERS_FORMAT: driver_format = va_arg(args, int); driver_interpreter->dispatch_driver_request_format(driver_format); break; default: break; } va_end(args); return ret; } mir-0.1.8+14.04.20140411/src/shared/graphics/android/syncfence.cpp0000644000015301777760000000420412322054223024632 0ustar pbusernogroup00000000000000/* * 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/android/sync_fence.h" #include #include #include namespace mga = mir::graphics::android; mga::SyncFence::SyncFence(std::shared_ptr const& ops, int fd) : fence_fd(fd), ops(ops) { } mga::SyncFence::~SyncFence() noexcept { if (fence_fd > 0) { ops->close(fence_fd); } } void mga::SyncFence::wait() { if (fence_fd > 0) { int timeout = infinite_timeout; ops->ioctl(fence_fd, SYNC_IOC_WAIT, &timeout); ops->close(fence_fd); fence_fd = -1; } } 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 = merge_fd; } else { //both fences were valid, must merge struct sync_merge_data data { merge_fd, "mirfence", infinite_timeout }; ops->ioctl(fence_fd, SYNC_IOC_MERGE, &data); ops->close(fence_fd); ops->close(merge_fd); fence_fd = data.fence; } merge_fd = -1; } mga::NativeFence mga::SyncFence::copy_native_handle() const { return ops->dup(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); } mir-0.1.8+14.04.20140411/src/shared/graphics/android/refcounted_buffer.cpp0000644000015301777760000000371512322054223026352 0ustar pbusernogroup00000000000000/* * 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/android/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; } mir-0.1.8+14.04.20140411/src/shared/graphics/android/android_native_buffer.cpp0000644000015301777760000000273312322054223027201 0ustar pbusernogroup00000000000000/* * 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/android/android_native_buffer.h" namespace mga=mir::graphics::android; mga::AndroidNativeBuffer::AndroidNativeBuffer( std::shared_ptr const& anwb, std::shared_ptr const& fence) : fence(fence), native_window_buffer(anwb) { } void mga::AndroidNativeBuffer::wait_for_content() { fence->wait(); } void mga::AndroidNativeBuffer::update_fence(NativeFence& merge_fd) { fence->merge_with(merge_fd); } 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(); } mir-0.1.8+14.04.20140411/src/shared/graphics/android/CMakeLists.txt0000644000015301777760000000043712322054223024715 0ustar pbusernogroup00000000000000include_directories(SYSTEM ${LIBHARDWARE_INCLUDE_DIRS}) add_definitions( -DANDROID ) add_library( mirsharedandroid STATIC mir_native_window.cpp refcounted_buffer.cpp android_native_buffer.cpp syncfence.cpp ) set(MIR_COMMON_PLATFORM_LIBRARIES mirsharedandroid PARENT_SCOPE) mir-0.1.8+14.04.20140411/src/shared/testdraw/0000755000015301777760000000000012322054703020571 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/testdraw/patterns.cpp0000644000015301777760000000374612322054223023144 0ustar pbusernogroup00000000000000/* * 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/common.h" #include "testdraw/patterns.h" namespace mtd=mir::test::draw; mtd::DrawPatternSolid::DrawPatternSolid(uint32_t color_value) : color_value(color_value) { } void mtd::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 mtd::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; } mir-0.1.8+14.04.20140411/src/shared/testdraw/CMakeLists.txt0000644000015301777760000000111412322054223023323 0ustar pbusernogroup00000000000000include_directories( ${Boost_INCLUDE_DIRS} ${GLESv2_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include/client ) set( DRAW_SRCS patterns.cpp ) if (MIR_TEST_PLATFORM STREQUAL "android") include_directories(SYSTEM ${LIBHARDWARE_INCLUDE_DIRS}) add_definitions(-DANDROID) set(DRAW_SRCS android_graphics_region_factory.cpp ${DRAW_SRCS}) else() set(DRAW_SRCS mesa_graphics_region_factory.cpp ${DRAW_SRCS}) endif() add_library( mirtestdraw STATIC ${DRAW_SRCS}) target_link_libraries( mirtestdraw ${LIBHARDWARE_LIBRARIES} ) mir-0.1.8+14.04.20140411/src/shared/testdraw/mesa_graphics_region_factory.cpp0000644000015301777760000000241512322054223027173 0ustar pbusernogroup00000000000000/* * 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 "testdraw/graphics_region_factory.h" #include #include namespace mtd=mir::test::draw; namespace { class MesaGraphicsRegionFactory : public mir::test::draw::GraphicsRegionFactory { public: std::shared_ptr graphic_region_from_handle(mir::graphics::NativeBuffer&) { BOOST_THROW_EXCEPTION(std::runtime_error("cannot map graphic region yet")); } }; } std::shared_ptr mtd::create_graphics_region_factory() { return std::make_shared(); } mir-0.1.8+14.04.20140411/src/shared/testdraw/android_graphics_region_factory.cpp0000644000015301777760000000561312322054223027671 0ustar pbusernogroup00000000000000/* * 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 */ #include "testdraw/graphics_region_factory.h" #include "mir_toolkit/mir_client_library.h" #include "mir/graphics/android/native_buffer.h" #include "mir_toolkit/common.h" #include #include namespace mtd=mir::test::draw; namespace { struct RegionDeleter { RegionDeleter(gralloc_module_t* grmod, native_handle_t const* handle) : grmod(grmod), handle(handle) { } void operator()(MirGraphicsRegion* region) { grmod->unlock(grmod, handle); delete region; } gralloc_module_t *grmod; native_handle_t const* handle; }; class AndroidGraphicsRegionFactory : public mir::test::draw::GraphicsRegionFactory { public: AndroidGraphicsRegionFactory() { const hw_module_t *hw_module; if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &hw_module) != 0) throw std::runtime_error("error, hw module not available!\n"); gralloc_open(hw_module, &alloc_dev); module = (gralloc_module_t*) hw_module; } ~AndroidGraphicsRegionFactory() { gralloc_close(alloc_dev); } std::shared_ptr graphic_region_from_handle( mir::graphics::NativeBuffer& native_buffer) { native_buffer.wait_for_content(); auto anwb = native_buffer.anwb(); int *vaddr; int usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN; module->lock( module, anwb->handle, usage, 0, 0, anwb->width, anwb->height, (void**) &vaddr); MirGraphicsRegion* region = new MirGraphicsRegion; RegionDeleter del(module, anwb->handle); region->vaddr = (char*) vaddr; region->stride = anwb->stride * MIR_BYTES_PER_PIXEL(mir_pixel_format_abgr_8888); region->width = anwb->width; region->height = anwb->height; region->pixel_format = mir_pixel_format_abgr_8888; return std::shared_ptr(region, del); } private: gralloc_module_t* module; alloc_device_t* alloc_dev; }; } std::shared_ptr mtd::create_graphics_region_factory() { return std::make_shared(); } mir-0.1.8+14.04.20140411/src/shared/env/0000755000015301777760000000000012322054703017524 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/env/default_configuration.cpp0000644000015301777760000000211412322054223024576 0ustar pbusernogroup00000000000000/* * 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/default_configuration.h" #include #include namespace { const char* init() { std::ostringstream formatter; char const* dir = getenv("XDG_RUNTIME_DIR"); if (!dir) dir = "/tmp"; formatter << dir << "/mir_socket"; static auto result = formatter.str(); return result.c_str(); } } const char *const mir::default_server_socket = init(); mir-0.1.8+14.04.20140411/src/shared/env/CMakeLists.txt0000644000015301777760000000136412322054223022265 0ustar pbusernogroup00000000000000# 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 add_library(mirsharedenv STATIC default_configuration.cpp ) mir-0.1.8+14.04.20140411/src/shared/mircommon.pc.in0000644000015301777760000000034512322054223021664 0ustar pbusernogroup00000000000000prefix=@PREFIX@ exec_prefix=@EXEC_PREFIX@ libdir=@LIBDIR@ includedir=@INCLUDEDIR@ Name: mircommon Description: Mir common headers Version: @MIR_VERSION_MAJOR@.@MIR_VERSION_MINOR@.@MIR_VERSION_PATCH@ Libs: Cflags: -I@INCLUDEDIR@ mir-0.1.8+14.04.20140411/src/shared/report/0000755000015301777760000000000012322054703020247 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/report/lttng/0000755000015301777760000000000012322054703021377 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/report/lttng/tracepoint_provider.cpp0000644000015301777760000000315512322054223026166 0ustar pbusernogroup00000000000000/* * 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/report/lttng/tracepoint_provider.h" #include #include #include namespace { std::string const tracepoint_lib_install_path{MIR_TRACEPOINT_LIB_INSTALL_PATH}; void* open_tracepoint_lib(std::string const& lib_name) { auto lib = dlopen(lib_name.c_str(), RTLD_NOW); if (lib == nullptr) { std::string path{tracepoint_lib_install_path + "/" + lib_name}; lib = dlopen(path.c_str(), RTLD_NOW); } if (lib == nullptr) { std::string msg{"Failed to load tracepoint provider: "}; msg += dlerror(); BOOST_THROW_EXCEPTION(std::runtime_error(msg)); } return lib; } } mir::report::lttng::TracepointProvider::TracepointProvider(std::string const& lib_name) : lib{open_tracepoint_lib(lib_name)} { } mir::report::lttng::TracepointProvider::~TracepointProvider() noexcept { dlclose(lib); } mir-0.1.8+14.04.20140411/src/shared/report/lttng/CMakeLists.txt0000644000015301777760000000026212322054223024134 0ustar pbusernogroup00000000000000add_definitions(-DMIR_TRACEPOINT_LIB_INSTALL_PATH="${CMAKE_INSTALL_PREFIX}/${MIR_TRACEPOINT_LIB_INSTALL_DIR}") add_library( mirsharedlttng STATIC tracepoint_provider.cpp ) mir-0.1.8+14.04.20140411/src/shared/sharedlibrary/0000755000015301777760000000000012322054703021567 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/sharedlibrary/shared_library.cpp0000644000015301777760000000270412322054223025265 0ustar pbusernogroup00000000000000/* * 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 #include #include #include mir::SharedLibrary::SharedLibrary(char const* library_name) : so(dlopen(library_name, RTLD_NOW | RTLD_GLOBAL)) { if (!so) { BOOST_THROW_EXCEPTION(std::runtime_error(dlerror())); } } mir::SharedLibrary::SharedLibrary(std::string const& library_name) : SharedLibrary(library_name.c_str()) {} mir::SharedLibrary::~SharedLibrary() { dlclose(so); } void* mir::SharedLibrary::load_symbol(char const* function_name) const { if (void* result = dlsym(so, function_name)) { return result; } else { BOOST_THROW_EXCEPTION(std::runtime_error(dlerror())); } } mir-0.1.8+14.04.20140411/src/shared/sharedlibrary/CMakeLists.txt0000644000015301777760000000147312322054247024337 0ustar pbusernogroup00000000000000# 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 add_library(mirsharedsharedlibrary STATIC shared_library.cpp ) target_link_libraries( mirsharedsharedlibrary dl ) mir-0.1.8+14.04.20140411/src/shared/protobuf/0000755000015301777760000000000012322054703020574 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/protobuf/mir_protobuf.proto0000644000015301777760000001162312322054223024370 0ustar pbusernogroup00000000000000option cc_generic_services = true; 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 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; // TODO: Make required when we bump protobuf and server ABI optional string surface_name = 5; optional uint32 output_id = 6; } message SurfaceId { required int32 value = 1; }; 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; } message Platform { repeated sint32 fd = 1; repeated int32 data = 2; optional int32 fds_on_side_channel = 3; optional string error = 127; } 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; } // DEPRECATED message DisplayInfo { required uint32 width = 1; required uint32 height = 2; repeated uint32 supported_pixel_format = 3; } 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 string error = 127; } 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; optional string error = 127; } message DRMMagic { optional uint32 magic = 1; optional string error = 127; } message DRMAuthMagicStatus { optional int32 status_code = 1; optional string error = 127; } message Void { optional string error = 127; } 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; } message Event { optional bytes raw = 1; // MirEvent structure } message DisplayConfiguration { repeated DisplayOutput display_output = 1; repeated DisplayCard display_card = 2; optional string error = 127; } message LifecycleEvent { required uint32 new_state = 1; // State transition optional string error = 127; } message EventSequence { repeated Event event = 1; optional DisplayConfiguration display_configuration = 2; optional LifecycleEvent lifecycle_event = 3; optional string error = 127; } 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; } message ScreencastId { required uint32 value = 1; } message Screencast { optional ScreencastId screencast_id = 1; optional Buffer buffer = 2; optional string error = 127; } service DisplayServer { // Platform independent requests rpc connect(ConnectParameters) returns (Connection); rpc disconnect(Void) returns (Void); rpc create_surface(SurfaceParameters) returns (Surface); rpc next_buffer(SurfaceId) returns (Buffer); rpc release_surface(SurfaceId) returns (Void); // Platform specific requests rpc drm_auth_magic(DRMMagic) returns (DRMAuthMagicStatus); rpc test_file_descriptors(Void) returns (Buffer); rpc configure_surface(SurfaceSetting) returns (SurfaceSetting); rpc configure_display(DisplayConfiguration) returns (DisplayConfiguration); rpc create_screencast(ScreencastParameters) returns (Screencast); rpc screencast_buffer(ScreencastId) returns (Buffer); rpc release_screencast(ScreencastId) returns (Void); } mir-0.1.8+14.04.20140411/src/shared/protobuf/mir_protobuf_wire.proto0000644000015301777760000000055512322054223025420 0ustar pbusernogroup00000000000000package mir.protobuf.wire; message Invocation { required uint32 id = 1; required string method_name = 2; required bytes parameters = 3; required uint32 protocol_version = 4; } message Result { // Invocation results have id and response. optional uint32 id = 1; optional bytes response = 2; // Events are in events. repeated bytes events = 3; } mir-0.1.8+14.04.20140411/src/shared/protobuf/CMakeLists.txt0000644000015301777760000000205012322054223023326 0ustar pbusernogroup00000000000000include_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} ) add_library( mirprotobuf SHARED google_protobuf_guard.cpp ${GENERATED_PROTOBUF_SRCS} ${GENERATED_PROTOBUF_HDRS}) set(MIRPROTOBUF_ABI 0) set_target_properties( mirprotobuf PROPERTIES SOVERSION ${MIRPROTOBUF_ABI} ) target_link_libraries( mirprotobuf ${PROTOBUF_LIBRARIES} ) # 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 the protobuf library install( TARGETS mirprotobuf RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install( FILES ${MIR_PROTOBUF_PROTOCOL_SPEC} DESTINATION share/mir/protocol ) mir-0.1.8+14.04.20140411/src/shared/protobuf/google_protobuf_guard.cpp0000644000015301777760000000274412322054223025662 0ustar pbusernogroup00000000000000/* * 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/protobuf/google_protobuf_guard.h" #include #include namespace mir { namespace { std::once_flag init_flag; std::once_flag shutdown_flag; void init_google_protobuf() { GOOGLE_PROTOBUF_VERIFY_VERSION; } void shutdown_google_protobuf() { google::protobuf::ShutdownProtobufLibrary(); } // Too clever? The idea is to ensure protbuf version is verified once (on // the first google_protobuf_guard() call) and memory is released on exit. struct google_protobuf_guard_t { google_protobuf_guard_t() { std::call_once(init_flag, init_google_protobuf); } ~google_protobuf_guard_t() { std::call_once(shutdown_flag, shutdown_google_protobuf); } }; } } void mir::protobuf::google_protobuf_guard() { static google_protobuf_guard_t guard; } mir-0.1.8+14.04.20140411/src/shared/input/0000755000015301777760000000000012322054703020073 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/input/android/0000755000015301777760000000000012322054703021513 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/shared/input/android/android_input_platform.cpp0000644000015301777760000000340712322054223026763 0ustar pbusernogroup00000000000000/* * 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_input_platform.h" #include "android_input_receiver.h" #include "android_input_receiver_thread.h" #include "mir/input/null_input_receiver_report.h" namespace mircv = mir::input::receiver; namespace mircva = mircv::android; mircva::AndroidInputPlatform::AndroidInputPlatform(std::shared_ptr const& report) : report(report) { } mircva::AndroidInputPlatform::~AndroidInputPlatform() { } std::shared_ptr mircva::AndroidInputPlatform::create_input_thread( int fd, std::function const& callback) { auto receiver = std::make_shared(fd, report); return std::make_shared(receiver, callback); } std::shared_ptr mircv::InputPlatform::create() { return create(std::make_shared()); } std::shared_ptr mircv::InputPlatform::create(std::shared_ptr const& report) { return std::make_shared(report); } mir-0.1.8+14.04.20140411/src/shared/input/android/android_input_platform.h0000644000015301777760000000306212322054223026425 0ustar pbusernogroup00000000000000/* * 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_INPUT_PLATFORM_H_ #define MIR_CLIENT_ANDROID_INPUT_PLATFORM_H_ #include "mir/input/input_platform.h" namespace mir { namespace input { namespace receiver { namespace android { /// Implementation of client input machinery for android input stack wire protocol. class AndroidInputPlatform : public InputPlatform { public: AndroidInputPlatform(std::shared_ptr const& report); virtual ~AndroidInputPlatform(); std::shared_ptr create_input_thread(int fd, std::function const& callback); protected: AndroidInputPlatform(const AndroidInputPlatform&) = delete; AndroidInputPlatform& operator=(const AndroidInputPlatform&) = delete; private: std::shared_ptr const report; }; } } } } // namespace mir #endif // MIR_CLIENT_ANDROID_INPUT_PLATFORM_H_ mir-0.1.8+14.04.20140411/src/shared/input/android/android_input_receiver.cpp0000644000015301777760000000725012322054223026743 0ustar pbusernogroup00000000000000/* * 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_input_receiver.h" #include "mir/input/xkb_mapper.h" #include "mir/input/input_receiver_report.h" #include "mir/input/android/android_input_lexicon.h" #include #include namespace mircv = mir::input::receiver; namespace mircva = mircv::android; namespace mia = mir::input::android; mircva::InputReceiver::InputReceiver(droidinput::sp const& input_channel, std::shared_ptr const& report) : input_channel(input_channel), report(report), input_consumer(std::make_shared(input_channel)), looper(new droidinput::Looper(true)), fd_added(false), xkb_mapper(std::make_shared()) { } mircva::InputReceiver::InputReceiver(int fd, std::shared_ptr const& report) : input_channel(new droidinput::InputChannel(droidinput::String8(""), fd)), report(report), input_consumer(std::make_shared(input_channel)), looper(new droidinput::Looper(true)), fd_added(false), xkb_mapper(std::make_shared()) { } mircva::InputReceiver::~InputReceiver() { } int mircva::InputReceiver::fd() const { return input_channel->getFd(); } namespace { static void map_key_event(std::shared_ptr const& xkb_mapper, MirEvent &ev) { // TODO: As XKBMapper is used to track modifier state we need to use a seperate instance // of XKBMapper per device id (or modify XKBMapper semantics) if (ev.type != mir_event_type_key) return; xkb_mapper->update_state_and_map_event(ev.key); } } bool mircva::InputReceiver::try_next_event(MirEvent &ev) { droidinput::InputEvent *android_event; uint32_t event_sequence_id; if(input_consumer->consume(&event_factory, true, -1, &event_sequence_id, &android_event) != droidinput::WOULD_BLOCK) { mia::Lexicon::translate(android_event, ev); map_key_event(xkb_mapper, ev); input_consumer->sendFinishedSignal(event_sequence_id, true); report->received_event(ev); return true; } return false; } // TODO: We use a droidinput::Looper here for polling functionality but it might be nice to integrate // with the existing client io_service ~racarr ~tvoss bool mircva::InputReceiver::next_event(std::chrono::milliseconds const& timeout, MirEvent &ev) { if (!fd_added) { // TODO: Why will this fail from the constructor? ~racarr looper->addFd(fd(), fd(), ALOOPER_EVENT_INPUT, nullptr, nullptr); fd_added = true; } if(try_next_event(ev)) return true; auto result = looper->pollOnce(timeout.count()); if (result == ALOOPER_POLL_WAKE) return false; if (result == ALOOPER_POLL_ERROR) // TODO: Exception? return false; return try_next_event(ev); } void mircva::InputReceiver::wake() { looper->wake(); } mir-0.1.8+14.04.20140411/src/shared/input/android/android_input_receiver.h0000644000015301777760000000506312322054223026410 0ustar pbusernogroup00000000000000/* * 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_INPUT_RECEIVER_ANDROID_INPUT_RECEIVER_H_ #define MIR_INPUT_RECEIVER_ANDROID_INPUT_RECEIVER_H_ #include "mir_toolkit/event.h" #include #include #include #include namespace droidinput = android; namespace android { class InputChannel; class InputConsumer; class Looper; } namespace mir { namespace input { namespace receiver { class XKBMapper; class InputReceiverReport; namespace android { /// Synchronously receives input events in a blocking manner class InputReceiver { public: InputReceiver(droidinput::sp const& input_channel, std::shared_ptr const& report); InputReceiver(int fd, std::shared_ptr const& report); virtual ~InputReceiver(); int fd() const; /// Synchronously receive an event with millisecond timeout. A negative timeout value /// is used to request indefinite polling. virtual bool next_event(std::chrono::milliseconds const& timeout, MirEvent &ev); virtual bool next_event(MirEvent &ev) { return next_event(std::chrono::milliseconds(-1), ev); } /// May be used from any thread to wake an InputReceiver blocked in next_event virtual void wake(); protected: InputReceiver(const InputReceiver&) = delete; InputReceiver& operator=(const InputReceiver&) = delete; private: droidinput::sp input_channel; std::shared_ptr const report; std::shared_ptr input_consumer; droidinput::PreallocatedInputEventFactory event_factory; droidinput::sp looper; bool fd_added; std::shared_ptr xkb_mapper; bool try_next_event(MirEvent &ev); }; } } } } // namespace mir #endif // MIR_INPUT_RECEIVER_ANDROID_INPUT_RECEIVER_H_ mir-0.1.8+14.04.20140411/src/shared/input/android/CMakeLists.txt0000644000015301777760000000203612322054223024251 0ustar pbusernogroup00000000000000# 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: Robert Carr list( APPEND ANDROID_SHARED_INPUT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/android_input_lexicon.cpp ${CMAKE_CURRENT_SOURCE_DIR}/android_input_receiver.cpp ${CMAKE_CURRENT_SOURCE_DIR}/android_input_receiver_thread.cpp ${CMAKE_CURRENT_SOURCE_DIR}/android_input_platform.cpp ) set( ANDROID_SHARED_INPUT_SOURCES ${ANDROID_SHARED_INPUT_SOURCES} PARENT_SCOPE ) mir-0.1.8+14.04.20140411/src/shared/input/android/android_input_lexicon.cpp0000644000015301777760000001102212322054223026570 0ustar pbusernogroup00000000000000/* * 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 Voss * Robert Carr */ #include "mir/input/android/android_input_lexicon.h" #include namespace mia = mir::input::android; void mia::Lexicon::translate(const droidinput::InputEvent *android_event, MirEvent &mir_event) { switch(android_event->getType()) { case AINPUT_EVENT_TYPE_KEY: { const droidinput::KeyEvent* kev = static_cast(android_event); mir_event.type = mir_event_type_key; mir_event.key.device_id = android_event->getDeviceId(); mir_event.key.source_id = android_event->getSource(); mir_event.key.action = static_cast(kev->getAction()); mir_event.key.flags = static_cast(kev->getFlags()); mir_event.key.modifiers = kev->getMetaState(); mir_event.key.key_code = kev->getKeyCode(); mir_event.key.scan_code = kev->getScanCode(); mir_event.key.repeat_count = kev->getRepeatCount(); mir_event.key.down_time = kev->getDownTime(); mir_event.key.event_time = kev->getEventTime(); mir_event.key.is_system_key = false; // TODO: Figure out what this is. //kev->isSystemKey(); break; } case AINPUT_EVENT_TYPE_MOTION: { const droidinput::MotionEvent* mev = static_cast(android_event); mir_event.type = mir_event_type_motion; mir_event.motion.device_id = android_event->getDeviceId(); mir_event.motion.source_id = android_event->getSource(); mir_event.motion.action = mev->getAction(); mir_event.motion.flags = static_cast(mev->getFlags()); mir_event.motion.modifiers = mev->getMetaState(); mir_event.motion.edge_flags = mev->getEdgeFlags(); mir_event.motion.button_state = static_cast(mev->getButtonState()); mir_event.motion.x_offset = mev->getXOffset(); mir_event.motion.y_offset = mev->getYOffset(); mir_event.motion.x_precision = mev->getXPrecision(); mir_event.motion.y_precision = mev->getYPrecision(); mir_event.motion.down_time = mev->getDownTime(); mir_event.motion.event_time = mev->getEventTime(); mir_event.motion.pointer_count = mev->getPointerCount(); for(unsigned int i = 0; i < mev->getPointerCount(); i++) { mir_event.motion.pointer_coordinates[i].id = mev->getPointerId(i); mir_event.motion.pointer_coordinates[i].x = mev->getX(i); mir_event.motion.pointer_coordinates[i].raw_x = mev->getRawX(i); mir_event.motion.pointer_coordinates[i].y = mev->getY(i); mir_event.motion.pointer_coordinates[i].raw_y = mev->getRawY(i); mir_event.motion.pointer_coordinates[i].touch_major = mev->getTouchMajor(i); mir_event.motion.pointer_coordinates[i].touch_minor = mev->getTouchMinor(i); mir_event.motion.pointer_coordinates[i].size = mev->getSize(i); mir_event.motion.pointer_coordinates[i].pressure = mev->getPressure(i); mir_event.motion.pointer_coordinates[i].orientation = mev->getOrientation(i); mir_event.motion.pointer_coordinates[i].vscroll = mev->getRawAxisValue(AMOTION_EVENT_AXIS_VSCROLL, i); mir_event.motion.pointer_coordinates[i].hscroll = mev->getRawAxisValue(AMOTION_EVENT_AXIS_HSCROLL, i); mir_event.motion.pointer_coordinates[i].tool_type = static_cast(mev->getToolType(i)); } break; } } } mir-0.1.8+14.04.20140411/src/shared/input/android/android_input_receiver_thread.h0000644000015301777760000000360612322054223027740 0ustar pbusernogroup00000000000000/* * 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_INPUT_RECEIVER_ANDROID_INPUT_RECEIVER_THREAD_H_ #define MIR_INPUT_RECEIVER_ANDROID_INPUT_RECEIVER_THREAD_H_ #include "mir/input/input_receiver_thread.h" #include "mir_toolkit/event.h" #include #include #include #include namespace mir { namespace input { namespace receiver { namespace android { class InputReceiver; /// Responsible for polling an InputReceiver to read and dispatch events when appropriate. class InputReceiverThread : public receiver::InputReceiverThread { public: InputReceiverThread(std::shared_ptr const& receiver, std::function const& event_handling_callback); virtual ~InputReceiverThread(); void start(); void stop(); void join(); protected: InputReceiverThread(const InputReceiverThread&) = delete; InputReceiverThread& operator=(const InputReceiverThread&) = delete; private: std::shared_ptr const receiver; std::function const handler; void thread_loop(); std::atomic running; std::thread thread; }; } } } } // namespace mir #endif // MIR_INPUT_RECEIVER_ANDROID_INPUT_RECEIVER_THREAD_H_ mir-0.1.8+14.04.20140411/src/shared/input/android/android_input_receiver_thread.cpp0000644000015301777760000000353412322054223030273 0ustar pbusernogroup00000000000000/* * 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_input_receiver_thread.h" #include "android_input_receiver.h" #include namespace mircva = mir::input::receiver::android; mircva::InputReceiverThread::InputReceiverThread(std::shared_ptr const& receiver, std::function const& event_handling_callback) : receiver(receiver), handler(event_handling_callback), running(false) { } mircva::InputReceiverThread::~InputReceiverThread() { if (running) stop(); if (thread.joinable()) join(); } void mircva::InputReceiverThread::start() { running = true; thread = std::thread(std::mem_fn(&mircva::InputReceiverThread::thread_loop), this); } void mircva::InputReceiverThread::stop() { running = false; receiver->wake(); } void mircva::InputReceiverThread::join() { thread.join(); } void mircva::InputReceiverThread::thread_loop() { while (running) { MirEvent ev; while(running && receiver->next_event(ev)) handler(&ev); std::this_thread::yield(); // yield() is needed to ensure reasonable runtime under valgrind } } mir-0.1.8+14.04.20140411/src/shared/input/CMakeLists.txt0000644000015301777760000000206012322054223022626 0ustar pbusernogroup00000000000000# 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 Voss set( ANDROID_SHARED_INPUT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/xkb_mapper.cpp ) include_directories(${MIR_3RD_PARTY_INCLUDE_DIRECTORIES}) include_directories(${MIR_ANDROID_INCLUDE_DIRECTORIES}) add_subdirectory(android) add_library( mirsharedinput STATIC ${ANDROID_SHARED_INPUT_SOURCES} ) target_link_libraries( mirsharedinput android-input ${XKBCOMMON_LIBRARIES} ) mir-0.1.8+14.04.20140411/src/shared/input/xkb_mapper.cpp0000644000015301777760000000541612322054223022732 0ustar pbusernogroup00000000000000/* * 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 "mir/input/xkb_mapper.h" #include namespace mircv = mir::input::receiver; namespace { struct XKBContextDeleter { void operator()(xkb_context *c) { xkb_context_unref(c); } }; struct XKBKeymapDeleter { void operator()(xkb_keymap *k) { xkb_map_unref(k); } }; struct XKBStateDeleter { void operator()(xkb_state *s) { xkb_state_unref(s); } }; } mircv::XKBMapper::XKBMapper() { xkb_rule_names names; names.rules = "evdev"; names.model = "pc105"; names.layout = "us"; names.variant = ""; names.options = ""; context = std::shared_ptr(xkb_context_new(xkb_context_flags(0)), XKBContextDeleter()); map = std::shared_ptr(xkb_map_new_from_names(context.get(), &names, xkb_map_compile_flags(0)), XKBKeymapDeleter()); state = std::shared_ptr(xkb_state_new(map.get()), XKBStateDeleter()); } namespace { static uint32_t to_xkb_scan_code(uint32_t evdev_scan_code) { // xkb scancodes are offset by 8 from evdev scancodes for compatibility with X protocol. return evdev_scan_code + 8; } static xkb_keysym_t keysym_for_scan_code(xkb_state *state, uint32_t xkb_scan_code) { const xkb_keysym_t *syms; uint32_t num_syms = xkb_key_get_syms(state, xkb_scan_code, &syms); if (num_syms == 1) { return syms[0]; } return XKB_KEY_NoSymbol; } } void mircv::XKBMapper::update_state_and_map_event(MirKeyEvent &key_ev) { xkb_key_direction direction; bool update_state = true; if (key_ev.action == mir_key_action_up) direction = XKB_KEY_UP; else if (key_ev.action == mir_key_action_down) direction = XKB_KEY_DOWN; else // mir_key_action_multiple does not correspond to a physical keypress update_state = false; if (key_ev.repeat_count > 0) update_state = false; uint32_t xkb_scan_code = to_xkb_scan_code(key_ev.scan_code); if (update_state) xkb_state_update_key(state.get(), xkb_scan_code, direction); key_ev.key_code = keysym_for_scan_code(state.get(), xkb_scan_code); } mir-0.1.8+14.04.20140411/src/shared/CMakeLists.txt0000644000015301777760000000211312322054223021466 0ustar pbusernogroup00000000000000set(MIR_GENERATED_INCLUDE_DIRECTORIES) set(MIR_COMMON_PLATFORM_LIBRARIES) add_subdirectory(protobuf/) if (MIR_BUILD_PLATFORM_ANDROID) add_subdirectory(graphics/android) endif() add_subdirectory(geometry) add_subdirectory(input) add_subdirectory(logging) add_subdirectory(report/lttng) add_subdirectory(env) add_subdirectory(sharedlibrary) add_subdirectory(testdraw) set( MIR_COMMON_PLATFORM_LIBRARIES ${MIR_COMMON_PLATFORM_LIBRARIES} PARENT_SCOPE) set(PREFIX "${CMAKE_INSTALL_PREFIX}") set(EXEC_PREFIX "${CMAKE_INSTALL_PREFIX}") set(LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}") set(INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include/mircommon") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/mircommon.pc.in ${CMAKE_CURRENT_BINARY_DIR}/mircommon.pc ) set( MIR_GENERATED_INCLUDE_DIRECTORIES ${MIR_GENERATED_INCLUDE_DIRECTORIES} PARENT_SCOPE) install( DIRECTORY ${CMAKE_SOURCE_DIR}/include/shared/mir ${CMAKE_SOURCE_DIR}/include/shared/mir_toolkit DESTINATION "include/mircommon" ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/mircommon.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) mir-0.1.8+14.04.20140411/src/platform/0000755000015301777760000000000012322054703017312 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/platform/udev_wrapper.cpp0000644000015301777760000001650212322054223022522 0ustar pbusernogroup00000000000000/* * 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; 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); } } 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(const_cast(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(const_cast(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); } mir-0.1.8+14.04.20140411/src/platform/shared_library_loader.cpp0000644000015301777760000000233512322054247024344 0ustar pbusernogroup00000000000000/* * 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/shared_library_loader.h" #include "mir/shared_library.h" #include #include mir::SharedLibrary const* mir::load_library(std::string const& libname) { // There's no point in loading twice, and it isn't safe to unload... static std::map> libraries_cache; if (auto& ptr = libraries_cache[libname]) { return ptr.get(); } else { ptr = std::make_shared(libname); return ptr.get(); } } mir-0.1.8+14.04.20140411/src/platform/graphics/0000755000015301777760000000000012322054703021112 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/platform/graphics/android/0000755000015301777760000000000012322054703022532 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/platform/graphics/android/resource_factory.cpp0000644000015301777760000001155012322054247026621 0ustar pbusernogroup00000000000000/* * 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/android/mir_native_window.h" #include "mir/graphics/android/sync_fence.h" #include "buffer.h" #include "resource_factory.h" #include "fb_device.h" #include "graphic_buffer_allocator.h" #include "server_render_window.h" #include "interpreter_cache.h" #include "hwc_device.h" #include "hwc_fb_device.h" #include "hwc_layerlist.h" #include "hwc_vsync.h" #include "android_display.h" #include "real_hwc_wrapper.h" #include "hwc_formatted_logger.h" #include #include #include namespace mg = mir::graphics; namespace mga=mir::graphics::android; mga::ResourceFactory::ResourceFactory(bool should_log_hwc) : should_log_hwc{should_log_hwc} { } 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::shared_ptr mga::ResourceFactory::create_hwc_native_device() const { 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")); } return std::shared_ptr( hwc_device_raw, [](hwc_composer_device_1* device) { device->common.close((hw_device_t*) device); }); } std::shared_ptr mga::ResourceFactory::create_native_window( std::shared_ptr const& fb_bundle) const { auto cache = std::make_shared(); auto interpreter = std::make_shared(fb_bundle, cache); return std::make_shared(interpreter); } std::shared_ptr mga::ResourceFactory::create_fb_device( std::shared_ptr const& fb_native_device) const { return std::make_shared(fb_native_device); } namespace { struct NullHwcLogger : public mga::HwcLogger { void log_list_submitted_to_prepare(hwc_display_contents_1_t const&) const override { } void log_prepare_done(hwc_display_contents_1_t const&) const override { } void log_set_list(hwc_display_contents_1_t const&) const override { } }; std::shared_ptr make_logger(bool should_log) { if (should_log) return std::make_shared(); else return std::make_shared(); } } std::shared_ptr mga::ResourceFactory::create_hwc_device( std::shared_ptr const& hwc_native_device) const { auto syncer = std::make_shared(); auto file_ops = std::make_shared(); auto wrapper = std::make_shared(hwc_native_device, make_logger(should_log_hwc)); return std::make_shared(hwc_native_device, wrapper, syncer, file_ops); } std::shared_ptr mga::ResourceFactory::create_hwc_fb_device( std::shared_ptr const& hwc_native_device, std::shared_ptr const& fb_native_device) const { auto syncer = std::make_shared(); auto logger = std::make_shared(); auto wrapper = std::make_shared(hwc_native_device, make_logger(should_log_hwc)); return std::make_shared(hwc_native_device, wrapper, fb_native_device, syncer); } mir-0.1.8+14.04.20140411/src/platform/graphics/android/interpreter_resource_cache.h0000644000015301777760000000317612322054223030304 0ustar pbusernogroup00000000000000/* * 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; class NativeBuffer; namespace android { 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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/fb_device.cpp0000644000015301777760000000456212322054247025156 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/android/native_buffer.h" #include "mir/graphics/android/sync_fence.h" #include "gl_context.h" #include "android_format_conversion-inl.h" #include "fb_device.h" #include "framebuffer_bundle.h" #include "buffer.h" #include #include namespace mg = mir::graphics; namespace mga=mir::graphics::android; namespace geom=mir::geometry; mga::FBDevice::FBDevice( std::shared_ptr const& fbdev) : fb_device(fbdev) { if (fb_device->setSwapInterval) { fb_device->setSwapInterval(fb_device.get(), 1); } mode(mir_power_mode_on); } void mga::FBDevice::render_gl(SwappingGLContext const& context) { context.swap_buffers(); } void mga::FBDevice::render_gl_and_overlays( SwappingGLContext const& context, RenderableList const& renderables, std::function const& render_fn) { for(auto const& renderable : renderables) render_fn(*renderable); context.swap_buffers(); } void mga::FBDevice::post(mg::Buffer const& buffer) { auto native_buffer = buffer.native_buffer_handle(); native_buffer->wait_for_content(); 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::apply_orientation(MirOrientation) const { return false; } void mga::FBDevice::mode(MirPowerMode mode) { int enable = 0; if (mode == mir_power_mode_on) { enable = 1; } if (fb_device->enableScreen) { fb_device->enableScreen(fb_device.get(), enable); } } mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_layers.h0000644000015301777760000000434712322054223025050 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/android/fence.h" #include "mir/geometry/rectangle.h" #include #include #include #include #include namespace mir { namespace graphics { class Renderable; class Buffer; class NativeBuffer; namespace android { enum LayerType { gl_rendered, overlay, framebuffer_target, skip }; class HWCLayer { public: HWCLayer(std::shared_ptr list, size_t layer_index); HWCLayer(LayerType, geometry::Rectangle screen_position, bool alpha_enabled, std::shared_ptr list, size_t layer_index); HWCLayer& operator=(HWCLayer && layer); HWCLayer(HWCLayer && layer); HWCLayer& operator=(HWCLayer const& layer) = delete; HWCLayer(HWCLayer const& layer) = delete; void set_layer_type(LayerType type); void set_render_parameters(geometry::Rectangle screen_position, bool alpha_enabled); void set_buffer(Buffer const& buffer); void update_fence_and_release_buffer(); bool needs_gl_render() const; bool needs_hwc_commit() const; void prepare_for_draw(); private: hwc_layer_1_t* hwc_layer; std::shared_ptr hwc_list; hwc_rect_t visible_rect; std::shared_ptr associated_buffer; bool updated{false}; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_LAYERS_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_vsync.cpp0000644000015301777760000000223512322054223025240 0ustar pbusernogroup00000000000000/* * 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_vsync.h" namespace mga=mir::graphics::android; mga::HWCVsync::HWCVsync() : vsync_occurred(false) { } void mga::HWCVsync::wait_for_vsync() { std::unique_lock lk(vsync_wait_mutex); vsync_occurred = false; while(!vsync_occurred) { vsync_trigger.wait(lk); } } void mga::HWCVsync::notify_vsync() { std::unique_lock lk(vsync_wait_mutex); vsync_occurred = true; vsync_trigger.notify_all(); } mir-0.1.8+14.04.20140411/src/platform/graphics/android/interpreter_cache.h0000644000015301777760000000305612322054223026372 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/buffer.cpp0000644000015301777760000000751512322054223024514 0ustar pbusernogroup00000000000000/* * 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/android/native_buffer.h" #include "mir/graphics/android/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(std::shared_ptr const& buffer_handle, std::shared_ptr const& extensions) : 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); } bool mga::Buffer::can_bypass() const { return false; } void mga::Buffer::bind_to_texture() { std::unique_lock lk(content_lock); native_buffer->wait_for_content(); DispContextPair current { eglGetCurrentDisplay(), eglGetCurrentContext() }; if (current.first == EGL_NO_DISPLAY) { BOOST_THROW_EXCEPTION(std::runtime_error("cannot bind buffer to texture without EGL context\n")); } 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(std::runtime_error("error binding buffer to texture\n")); } egl_image_map[current] = image; } else /* already had it in map */ { image = it->second; } egl_extensions->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); //TODO: we should make use of the android egl fence extension here to update the fence. // if the extension is not available, we should pass out a token that the user // will have to keep until the completion of the gl draw } 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; } mir-0.1.8+14.04.20140411/src/platform/graphics/android/fb_device.h0000644000015301777760000000302712322054247024616 0ustar pbusernogroup00000000000000/* * 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 #include namespace mir { namespace graphics { namespace android { class FBDevice : public DisplayDevice { public: FBDevice(std::shared_ptr const& fbdev); bool apply_orientation(MirOrientation orientation) const; void mode(MirPowerMode mode); virtual void render_gl(SwappingGLContext const& context); virtual void render_gl_and_overlays( SwappingGLContext const& context, RenderableList const& list, std::function const& render_fn); void post(Buffer const& buffer); private: std::shared_ptr const fb_device; }; } } } #endif /* MIR_GRAPHICS_ANDROID_FB_DEVICE_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/interpreter_cache.cpp0000644000015301777760000000414112322054223026721 0ustar pbusernogroup00000000000000/* * 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/android/sync_fence.h" #include "mir/graphics/android/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_fence(fence); } mir-0.1.8+14.04.20140411/src/platform/graphics/android/android_graphic_buffer_allocator.h0000644000015301777760000000376412322054223031420 0ustar pbusernogroup00000000000000/* * 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_ANDROID_BUFFER_ALLOCATOR_H_ #define MIR_PLATFORM_ANDROID_ANDROID_BUFFER_ALLOCATOR_H_ #include #include "mir/graphics/buffer_properties.h" #include "mir/graphics/graphic_buffer_allocator.h" #include "graphic_buffer_allocator.h" namespace mir { namespace graphics { class BufferInitializer; class EGLExtensions; namespace android { class GraphicAllocAdaptor; class AndroidGraphicBufferAllocator: public GraphicBufferAllocator, public graphics::GraphicBufferAllocator { public: AndroidGraphicBufferAllocator( std::shared_ptr const& buffer_initializer); std::shared_ptr alloc_buffer( graphics::BufferProperties const& buffer_properties); std::shared_ptr alloc_buffer_platform( geometry::Size sz, MirPixelFormat pf, BufferUsage use); std::vector supported_pixel_formats(); static BufferUsage convert_from_compositor_usage(graphics::BufferUsage usage); private: const hw_module_t *hw_module; std::shared_ptr alloc_device; std::shared_ptr const buffer_initializer; std::shared_ptr const egl_extensions; }; } } } #endif /* MIR_PLATFORM_ANDROID_ANDROID_BUFFER_ALLOCATOR_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/android_buffer_allocator.cpp0000644000015301777760000000717712322054223030260 0ustar pbusernogroup00000000000000/* * 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/buffer_initializer.h" #include "mir/graphics/egl_extensions.h" #include "mir/graphics/buffer_properties.h" #include "mir/graphics/android/sync_fence.h" #include "android_graphic_buffer_allocator.h" #include "android_alloc_adaptor.h" #include "buffer.h" #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace geom = mir::geometry; namespace { struct AllocDevDeleter { void operator()(alloc_device_t* t) { /* android takes care of delete for us */ t->common.close((hw_device_t*)t); } }; } mga::AndroidGraphicBufferAllocator::AndroidGraphicBufferAllocator( std::shared_ptr const& buffer_initializer) : buffer_initializer(buffer_initializer), egl_extensions(std::make_shared()) { 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 */ AllocDevDeleter del; std::shared_ptr alloc_dev_ptr(alloc_dev, del); alloc_device = std::shared_ptr(new AndroidAllocAdaptor(alloc_dev_ptr)); } std::shared_ptr mga::AndroidGraphicBufferAllocator::alloc_buffer( mg::BufferProperties const& buffer_properties) { auto usage = convert_from_compositor_usage(buffer_properties.usage); return alloc_buffer_platform(buffer_properties.size, buffer_properties.format, usage); } std::shared_ptr mga::AndroidGraphicBufferAllocator::alloc_buffer_platform( geom::Size sz, MirPixelFormat pf, mga::BufferUsage use) { auto native_handle = alloc_device->alloc_buffer(sz, pf, use); auto buffer = std::make_shared(native_handle, egl_extensions); (*buffer_initializer)(*buffer); return buffer; } std::vector mga::AndroidGraphicBufferAllocator::supported_pixel_formats() { static std::vector const pixel_formats{ mir_pixel_format_abgr_8888, mir_pixel_format_xbgr_8888, mir_pixel_format_bgr_888 }; return pixel_formats; } mga::BufferUsage mga::AndroidGraphicBufferAllocator::convert_from_compositor_usage(mg::BufferUsage usage) { switch (usage) { case mg::BufferUsage::software: return mga::BufferUsage::use_software; case mg::BufferUsage::hardware: default: return mga::BufferUsage::use_hardware; } } mir-0.1.8+14.04.20140411/src/platform/graphics/android/android_platform.cpp0000644000015301777760000001260712322054247026573 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/android/sync_fence.h" #include "android_platform.h" #include "android_graphic_buffer_allocator.h" #include "resource_factory.h" #include "android_display.h" #include "internal_client.h" #include "output_builder.h" #include "mir/graphics/platform_ipc_package.h" #include "mir/graphics/android/native_buffer.h" #include "mir/graphics/buffer_initializer.h" #include "mir/graphics/buffer_id.h" #include "mir/graphics/buffer_ipc_packer.h" #include "mir/graphics/display_report.h" #include "mir/options/option.h" #include "mir/options/configuration.h" #include "mir/abnormal_exit.h" #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"; bool should_log_hwc(mo::Option const& options) { if (!options.is_set(hwc_log_opt)) return false; auto opt = options.get(hwc_log_opt); if (opt == mo::log_opt_value) return true; else if (opt == mo::off_opt_value) return false; else throw mir::AbnormalExit( std::string("Invalid hwc-report option: " + opt + " (valid options are: \"" + mo::off_opt_value + "\" and \"" + mo::log_opt_value + "\")")); } } mga::AndroidPlatform::AndroidPlatform( std::shared_ptr const& display_builder, std::shared_ptr const& display_report) : display_builder(display_builder), display_report(display_report) { } std::shared_ptr mga::AndroidPlatform::create_buffer_allocator( std::shared_ptr const& buffer_initializer) { return std::make_shared(buffer_initializer); } std::shared_ptr mga::AndroidPlatform::create_mga_buffer_allocator( std::shared_ptr const& buffer_initializer) { return std::make_shared(buffer_initializer); } std::shared_ptr mga::AndroidPlatform::create_display( std::shared_ptr const&, std::shared_ptr const& gl_config) { return std::make_shared( display_builder, gl_config, display_report); } std::shared_ptr mga::AndroidPlatform::get_ipc_package() { return std::make_shared(); } void mga::AndroidPlatform::fill_ipc_package(BufferIPCPacker* packer, graphics::Buffer const* buffer) const { auto native_buffer = buffer->native_buffer_handle(); auto buffer_handle = native_buffer->handle(); int offset = 0; for(auto i=0; inumFds; i++) { packer->pack_fd(buffer_handle->data[offset++]); } for(auto i=0; inumInts; i++) { packer->pack_data(buffer_handle->data[offset++]); } packer->pack_stride(buffer->stride()); packer->pack_size(buffer->size()); } EGLNativeDisplayType mga::AndroidPlatform::egl_native_display() const { return EGL_DEFAULT_DISPLAY; } void mga::AndroidPlatform::initialize(std::shared_ptr const&) { } std::shared_ptr mga::AndroidPlatform::create_internal_client() { return std::make_shared(); } extern "C" std::shared_ptr mg::create_platform(std::shared_ptr const& options, std::shared_ptr const& display_report) { auto buffer_initializer = std::make_shared(); auto display_resource_factory = std::make_shared(should_log_hwc(*options)); auto fb_allocator = std::make_shared(buffer_initializer); auto display_builder = std::make_shared( fb_allocator, display_resource_factory, display_report); return std::make_shared(display_builder, display_report); } extern "C" std::shared_ptr create_native_platform(std::shared_ptr const& display_report) { //TODO: remove nullptr parameter once platform classes are sorted. // mg::NativePlatform cannot create a display anyways, so it doesnt need a display builder return std::make_shared(nullptr, display_report); } extern "C" void add_platform_options( boost::program_options::options_description& config) { 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}]"); } mir-0.1.8+14.04.20140411/src/platform/graphics/android/internal_client.cpp0000644000015301777760000000260312322054223026406 0ustar pbusernogroup00000000000000/* * 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 "internal_client.h" #include "interpreter_cache.h" #include "internal_client_window.h" #include "mir/graphics/android/mir_native_window.h" namespace mga=mir::graphics::android; mga::InternalClient::InternalClient() { } EGLNativeDisplayType mga::InternalClient::egl_native_display() { return EGL_DEFAULT_DISPLAY; } EGLNativeWindowType mga::InternalClient::egl_native_window(std::shared_ptr const& surface) { if (!client_windows[surface]) { auto interpreter = std::make_shared(surface); client_windows[surface] = std::make_shared(interpreter); } return client_windows[surface].get(); } mir-0.1.8+14.04.20140411/src/platform/graphics/android/output_builder.h0000644000015301777760000000366312322054223025756 0ustar pbusernogroup00000000000000/* * 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_OUTPUT_BUILDER_H_ #define MIR_GRAPHICS_ANDROID_OUTPUT_BUILDER_H_ #include "display_builder.h" #include "hardware/hwcomposer.h" #include "hardware/fb.h" namespace mir { namespace graphics { class DisplayReport; namespace android { class FramebufferBundle; class DisplayResourceFactory; class GraphicBufferAllocator; class DisplayDevice; class OutputBuilder : public DisplayBuilder { public: OutputBuilder( std::shared_ptr const& buffer_allocator, std::shared_ptr const& res_factory, std::shared_ptr const& display_report); MirPixelFormat display_format(); std::unique_ptr create_display_buffer( GLContext const& gl_context); private: std::shared_ptr const buffer_allocator; std::shared_ptr const res_factory; std::shared_ptr const display_report; std::shared_ptr framebuffers; bool force_backup_display; std::shared_ptr hwc_native; std::shared_ptr fb_native; }; } } } #endif /* MIR_GRAPHICS_ANDROID_OUTPUT_BUILDER_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_vsync.h0000644000015301777760000000232712322054223024707 0ustar pbusernogroup00000000000000/* * 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_VSYNC_H_ #define MIR_GRAPHICS_ANDROID_HWC_VSYNC_H_ #include "hwc_vsync_coordinator.h" #include #include namespace mir { namespace graphics { namespace android { class HWCVsync : public HWCVsyncCoordinator { public: HWCVsync(); void wait_for_vsync(); void notify_vsync(); private: std::mutex vsync_wait_mutex; std::condition_variable vsync_trigger; bool vsync_occurred; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_VSYNC_COORDINATOR_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/display_builder.h0000644000015301777760000000265612322054223026064 0ustar pbusernogroup00000000000000/* * 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_BUILDER_H_ #define MIR_GRAPHICS_ANDROID_DISPLAY_BUILDER_H_ #include "configurable_display_buffer.h" #include "mir_toolkit/common.h" #include namespace mir { namespace graphics { namespace android { class GLContext; class DisplayBuilder { public: virtual ~DisplayBuilder() = default; virtual MirPixelFormat display_format() = 0; virtual std::unique_ptr create_display_buffer( GLContext const& gl_context) = 0; protected: DisplayBuilder() = default; DisplayBuilder(DisplayBuilder const&) = delete; DisplayBuilder& operator=(DisplayBuilder const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DISPLAY_BUILDER_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_logger.h0000644000015301777760000000257012322054247025032 0ustar pbusernogroup00000000000000/* * 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_LOGGER_H_ #define MIR_GRAPHICS_ANDROID_HWC_LOGGER_H_ #include namespace mir { namespace graphics { namespace android { class HwcLogger { public: virtual ~HwcLogger() = default; virtual void log_list_submitted_to_prepare(hwc_display_contents_1_t const& list) const = 0; virtual void log_prepare_done(hwc_display_contents_1_t const& list) const = 0; virtual void log_set_list(hwc_display_contents_1_t const& list) const = 0; protected: HwcLogger() = default; HwcLogger& operator=(HwcLogger const&) = delete; HwcLogger(HwcLogger const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_LOGGER_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/output_builder.cpp0000644000015301777760000000657412322054223026315 0ustar pbusernogroup00000000000000/* * 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 "output_builder.h" #include "display_resource_factory.h" #include "display_buffer.h" #include "display_device.h" #include "framebuffers.h" #include "mir/graphics/display_buffer.h" #include "mir/graphics/display_report.h" #include "mir/graphics/egl_resources.h" namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace geom = mir::geometry; mga::OutputBuilder::OutputBuilder( std::shared_ptr const& buffer_allocator, std::shared_ptr const& res_factory, std::shared_ptr const& display_report) : buffer_allocator(buffer_allocator), res_factory(res_factory), display_report(display_report), force_backup_display(false) { try { hwc_native = res_factory->create_hwc_native_device(); } catch (...) { force_backup_display = true; } if (force_backup_display || hwc_native->common.version == HWC_DEVICE_API_VERSION_1_0) { fb_native = res_factory->create_fb_native_device(); framebuffers = std::make_shared(buffer_allocator, fb_native); } else { framebuffers = std::make_shared(buffer_allocator, hwc_native); } } MirPixelFormat mga::OutputBuilder::display_format() { return framebuffers->fb_format(); } std::unique_ptr mga::OutputBuilder::create_display_buffer( GLContext const& gl_context) { std::shared_ptr device; if (force_backup_display) { device = res_factory->create_fb_device(fb_native); display_report->report_gpu_composition_in_use(); } else { if (hwc_native->common.version == HWC_DEVICE_API_VERSION_1_0) { device = res_factory->create_hwc_fb_device(hwc_native, fb_native); } else //versions 1.1, 1.2 { device = res_factory->create_hwc_device(hwc_native); } switch (hwc_native->common.version) { case HWC_DEVICE_API_VERSION_1_2: display_report->report_hwc_composition_in_use(1,2); break; case HWC_DEVICE_API_VERSION_1_1: display_report->report_hwc_composition_in_use(1,1); break; case HWC_DEVICE_API_VERSION_1_0: display_report->report_hwc_composition_in_use(1,0); break; default: break; } } auto native_window = res_factory->create_native_window(framebuffers); return std::unique_ptr( new DisplayBuffer(framebuffers, device, native_window, gl_context)); } mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_common_device.cpp0000644000015301777760000000760312322054247026717 0ustar pbusernogroup00000000000000/* * 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_common_device.h" #include "hwc_vsync_coordinator.h" #include #include #include namespace mga=mir::graphics::android; namespace { static void invalidate_hook(const struct hwc_procs* /*procs*/) { } static void vsync_hook(const struct hwc_procs* procs, int /*disp*/, int64_t /*timestamp*/) { auto self = reinterpret_cast(procs)->self; self->notify_vsync(); } static void hotplug_hook(const struct hwc_procs* /*procs*/, int /*disp*/, int /*connected*/) { } } mga::HWCCommonDevice::HWCCommonDevice(std::shared_ptr const& hwc_device, std::shared_ptr const& coordinator) : coordinator(coordinator), hwc_device(hwc_device), current_mode(mir_power_mode_on) { callbacks.hooks.invalidate = invalidate_hook; callbacks.hooks.vsync = vsync_hook; callbacks.hooks.hotplug = hotplug_hook; callbacks.self = this; hwc_device->registerProcs(hwc_device.get(), &callbacks.hooks); turn_screen_on(); } mga::HWCCommonDevice::~HWCCommonDevice() noexcept { std::unique_lock lg(blanked_mutex); if (current_mode == mir_power_mode_on) turn_screen_off(); } void mga::HWCCommonDevice::notify_vsync() { coordinator->notify_vsync(); } void mga::HWCCommonDevice::mode(MirPowerMode mode_request) { std::unique_lock lg(blanked_mutex); int err = 0; if ((mode_request == mir_power_mode_suspend) || (mode_request == mir_power_mode_standby)) { BOOST_THROW_EXCEPTION(std::runtime_error("cannot set to suspend or standby")); } if ((mode_request == mir_power_mode_on) && (current_mode == mir_power_mode_off)) { err = turn_screen_on(); } else if ((mode_request == mir_power_mode_off) && (current_mode == mir_power_mode_on)) { err = turn_screen_off(); } if (err) { std::string blanking_status_msg = "Could not " + ((mode_request == mir_power_mode_off) ? std::string("blank") : std::string("unblank")) + " display"; BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error(blanking_status_msg)) << boost::errinfo_errno(-err)); } current_mode = mode_request; blanked_cond.notify_all(); } std::unique_lock mga::HWCCommonDevice::lock_unblanked() { std::unique_lock lg(blanked_mutex); while(current_mode == mir_power_mode_off) blanked_cond.wait(lg); return std::move(lg); } int mga::HWCCommonDevice::turn_screen_on() const noexcept(true) { if (auto err = hwc_device->blank(hwc_device.get(), HWC_DISPLAY_PRIMARY, 0)) return err; return hwc_device->eventControl(hwc_device.get(), 0, HWC_EVENT_VSYNC, 1); } int mga::HWCCommonDevice::turn_screen_off() const noexcept(true) { if (auto err = hwc_device->eventControl(hwc_device.get(), 0, HWC_EVENT_VSYNC, 0)) return err; return hwc_device->blank(hwc_device.get(), HWC_DISPLAY_PRIMARY, 1); } bool mga::HWCCommonDevice::apply_orientation(MirOrientation) const { return false; } mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_common_device.h0000644000015301777760000000370412322054247026362 0ustar pbusernogroup00000000000000/* * 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_COMMON_DEVICE_H_ #define MIR_GRAPHICS_ANDROID_HWC_COMMON_DEVICE_H_ #include "display_device.h" #include #include #include #include namespace mir { namespace graphics { namespace android { class HWCVsyncCoordinator; class HWCCommonDevice; struct HWCCallbacks { hwc_procs_t hooks; HWCCommonDevice* self; }; class HWCCommonDevice : public DisplayDevice { public: virtual ~HWCCommonDevice() noexcept; void notify_vsync(); void mode(MirPowerMode mode); bool apply_orientation(MirOrientation orientation) const; protected: HWCCommonDevice(std::shared_ptr const& hwc_device, std::shared_ptr const& coordinator); std::shared_ptr const coordinator; std::unique_lock lock_unblanked(); private: int turn_screen_on() const noexcept(true); int turn_screen_off() const noexcept(true); HWCCallbacks callbacks; std::shared_ptr const hwc_device; std::mutex blanked_mutex; std::condition_variable blanked_cond; MirPowerMode current_mode; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_COMMON_DEVICE_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/buffer.h0000644000015301777760000000374212322054223024157 0ustar pbusernogroup00000000000000/* * 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 "buffer_usage.h" #include #include #include #define GL_GLEXT_PROTOTYPES #define EGL_EGLEXT_PROTOTYPES #include #include namespace mir { namespace graphics { struct EGLExtensions; namespace android { class Buffer: public BufferBasic { public: Buffer(std::shared_ptr const& buffer_handle, std::shared_ptr const& extensions); ~Buffer(); geometry::Size size() const; geometry::Stride stride() const; MirPixelFormat pixel_format() const; void bind_to_texture(); bool can_bypass() const 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; private: 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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/resource_factory.h0000644000015301777760000000360012322054247026263 0ustar pbusernogroup00000000000000/* * 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: ResourceFactory(bool should_log_hwc); //native allocations std::shared_ptr create_hwc_native_device() const; std::shared_ptr create_fb_native_device() const; //devices std::shared_ptr create_fb_device( std::shared_ptr const& fb_native_device) const; std::shared_ptr create_hwc_device( std::shared_ptr const& hwc_native_device) const; std::shared_ptr create_hwc_fb_device( std::shared_ptr const& hwc_native_device, std::shared_ptr const& fb_native_device) const; std::shared_ptr create_native_window( std::shared_ptr const& fb_bundle) const; private: bool const should_log_hwc; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DEFAULT_FRAMEBUFFER_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/framebuffers.h0000644000015301777760000000367012322054223025355 0ustar pbusernogroup00000000000000/* * 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 #include namespace mir { namespace graphics { namespace android { class GraphicBufferAllocator; class Framebuffers : public FramebufferBundle { public: Framebuffers(std::shared_ptr const& buffer_allocator, std::shared_ptr const& hwc); Framebuffers(std::shared_ptr const& buffer_allocator, std::shared_ptr const& fb); MirPixelFormat fb_format(); geometry::Size fb_size(); std::shared_ptr buffer_for_render(); std::shared_ptr last_rendered_buffer(); void wait_for_consumed_buffer(bool); private: MirPixelFormat const format; geometry::Size const 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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_formatted_logger.cpp0000644000015301777760000001327712322054247027440 0ustar pbusernogroup00000000000000/* * 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_formatted_logger.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 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} << "}"; } } void mga::HwcFormattedLogger::log_list_submitted_to_prepare(hwc_display_contents_1_t const& list) const { std::cout << "before prepare():" << std::endl << " # | pos {l,t,r,b} | crop {l,t,r,b} | transform | blending | " << std::endl; for(auto i = 0u; i < list.numHwLayers; i++) std::cout << LayerNumber{i} << separator << HwcRect{list.hwLayers[i].displayFrame} << separator << HwcRect{list.hwLayers[i].sourceCrop} << separator << HwcRotation{list.hwLayers[i].transform} << separator << HwcBlending{list.hwLayers[i].blending} << separator << std::endl; } void mga::HwcFormattedLogger::log_prepare_done(hwc_display_contents_1_t const& list) const { std::cout << "after prepare():" << std::endl << " # | Type | " << std::endl; for(auto i = 0u; i < list.numHwLayers; i++) std::cout << LayerNumber{i} << separator << HwcType{list.hwLayers[i].compositionType,list.hwLayers[i].flags} << separator << std::endl; } void mga::HwcFormattedLogger::log_set_list(hwc_display_contents_1_t const& list) const { std::cout << "set list():" << std::endl << " # | handle" << std::endl; for(auto i = 0u; i < list.numHwLayers; i++) std::cout << LayerNumber{i} << separator << list.hwLayers[i].handle << std::endl; } mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_layers.cpp0000644000015301777760000001227512322054223025402 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/android/sync_fence.h" #include "mir/graphics/android/native_buffer.h" #include "hwc_layerlist.h" #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace geom=mir::geometry; mga::HWCLayer& mga::HWCLayer::operator=(HWCLayer && other) { hwc_layer = other.hwc_layer; hwc_list = std::move(other.hwc_list); visible_rect = std::move(other.visible_rect); return *this; } mga::HWCLayer::HWCLayer(HWCLayer && other) : hwc_layer(std::move(other.hwc_layer)), hwc_list(std::move(other.hwc_list)), visible_rect(std::move(other.visible_rect)) { } mga::HWCLayer::HWCLayer(std::shared_ptr list, size_t layer_index) : hwc_layer(&list->hwLayers[layer_index]), hwc_list(list), associated_buffer(nullptr) //todo: take this as a constructor param { 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->visibleRegionScreen.numRects=1; hwc_layer->visibleRegionScreen.rects= &visible_rect; } mga::HWCLayer::HWCLayer( LayerType type, geometry::Rectangle position, bool alpha_enabled, std::shared_ptr list, size_t layer_index) : HWCLayer(list, layer_index) { set_layer_type(type); set_render_parameters(position, alpha_enabled); } bool mga::HWCLayer::needs_gl_render() const { return ((hwc_layer->compositionType == HWC_FRAMEBUFFER) || (hwc_layer->flags == HWC_SKIP_LAYER)); } void mga::HWCLayer::update_fence_and_release_buffer() { if (hwc_layer->compositionType != HWC_FRAMEBUFFER) { associated_buffer->update_fence(hwc_layer->releaseFenceFd); hwc_layer->releaseFenceFd = -1; hwc_layer->acquireFenceFd = -1; associated_buffer.reset(); } } void mga::HWCLayer::set_layer_type(LayerType type) { 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")); } } void mga::HWCLayer::set_render_parameters(geometry::Rectangle position, bool alpha_enabled) { if (alpha_enabled) hwc_layer->blending = HWC_BLENDING_COVERAGE; else hwc_layer->blending = HWC_BLENDING_NONE; /* 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.size.width.as_int(), position.size.height.as_int() }; visible_rect = hwc_layer->displayFrame; } void mga::HWCLayer::set_buffer(Buffer const& buffer) { associated_buffer.reset(); associated_buffer = buffer.native_buffer_handle(); updated = (hwc_layer->handle != associated_buffer->handle()); hwc_layer->handle = associated_buffer->handle(); hwc_layer->sourceCrop = { 0, 0, associated_buffer->anwb()->width, associated_buffer->anwb()->height }; } void mga::HWCLayer::prepare_for_draw() { //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 (updated && (((hwc_layer->compositionType == HWC_OVERLAY) || (hwc_layer->compositionType == HWC_FRAMEBUFFER_TARGET)))) { hwc_layer->acquireFenceFd = associated_buffer->copy_fence(); } //the HWC is not interested in this buffer. we can release the buffer. else if (hwc_layer->compositionType == HWC_FRAMEBUFFER) { hwc_layer->acquireFenceFd = -1; associated_buffer.reset(); } hwc_layer->releaseFenceFd = -1; } bool mga::HWCLayer::needs_hwc_commit() const { return (updated || needs_gl_render()); } mir-0.1.8+14.04.20140411/src/platform/graphics/android/android_display.h0000644000015301777760000000445012322054247026056 0ustar pbusernogroup00000000000000/* * 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_ANDROID_DISPLAY_H_ #define MIR_GRAPHICS_ANDROID_ANDROID_DISPLAY_H_ #include "mir/graphics/display.h" #include "gl_context.h" #include namespace mir { namespace graphics { class DisplayReport; class GLConfig; namespace android { class DisplayBuilder; class DisplaySupportProvider; class ConfigurableDisplayBuffer; class AndroidDisplay : public Display { public: explicit AndroidDisplay(std::shared_ptr const& display_builder, std::shared_ptr const& gl_config, std::shared_ptr const& display_report); void for_each_display_buffer(std::function const& f); std::unique_ptr configuration() const override; void configure(DisplayConfiguration const&) override; void register_configuration_change_handler( EventHandlerRegister& handlers, DisplayConfigurationChangeHandler const& conf_change_handler); void register_pause_resume_handlers( EventHandlerRegister& handlers, DisplayPauseHandler const& pause_handler, DisplayResumeHandler const& resume_handler); void pause(); void resume(); std::weak_ptr the_cursor(); std::unique_ptr create_gl_context(); private: std::shared_ptr const display_builder; GLContext gl_context; //we only have a primary display at the moment std::unique_ptr const display_buffer; }; } } } #endif /* MIR_GRAPHICS_ANDROID_ANDROID_DISPLAY_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/server_render_window.cpp0000644000015301777760000000570012322054223027471 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/android/sync_fence.h" #include "server_render_window.h" #include "framebuffer_bundle.h" #include "buffer.h" #include "android_format_conversion-inl.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, std::shared_ptr const& cache) : fb_bundle(fb_bundle), resource_cache(cache), format(mga::to_android_format(fb_bundle->fb_format())) { } mg::NativeBuffer* mga::ServerRenderWindow::driver_requests_buffer() { auto buffer = fb_bundle->buffer_for_render(); auto handle = buffer->native_buffer_handle(); resource_cache->store_buffer(buffer, handle); return handle.get(); } void mga::ServerRenderWindow::driver_returns_buffer(ANativeWindowBuffer* buffer, int fence_fd) { 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; } 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; 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 sync) { fb_bundle->wait_for_consumed_buffer(sync); } mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_formatted_logger.h0000644000015301777760000000243212322054247027074 0ustar pbusernogroup00000000000000/* * 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_FORMATTED_LOGGER_H_ #define MIR_GRAPHICS_ANDROID_HWC_FORMATTED_LOGGER_H_ #include "hwc_logger.h" namespace mir { namespace graphics { namespace android { class HwcFormattedLogger : public HwcLogger { public: HwcFormattedLogger() = default; void log_list_submitted_to_prepare(hwc_display_contents_1_t const& list) const override; void log_prepare_done(hwc_display_contents_1_t const& list) const override; void log_set_list(hwc_display_contents_1_t const& list) const override; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_FORMATTED_LOGGER_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/android_display_configuration.cpp0000644000015301777760000000357112322054223031335 0ustar pbusernogroup00000000000000/* * 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 "android_display_configuration.h" namespace mg = mir::graphics; namespace mga = mg::android; namespace geom = mir::geometry; mga::AndroidDisplayConfiguration::AndroidDisplayConfiguration(mg::DisplayConfigurationOutput && output) : configuration(std::move(output)), card{mg::DisplayConfigurationCardId{0}, 1} { } mga::AndroidDisplayConfiguration::AndroidDisplayConfiguration(AndroidDisplayConfiguration const& other) : DisplayConfiguration(), configuration(other.configuration), card(other.card) { } mga::AndroidDisplayConfiguration& mga::AndroidDisplayConfiguration::operator=(AndroidDisplayConfiguration const& other) { if (&other != this) { configuration = other.configuration; card = other.card; } return *this; } void mga::AndroidDisplayConfiguration::for_each_card(std::function f) const { f(card); } void mga::AndroidDisplayConfiguration::for_each_output(std::function f) const { f(configuration); } void mga::AndroidDisplayConfiguration::for_each_output(std::function f) { mg::UserDisplayConfigurationOutput user(configuration); f(user); } mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_layerlist.h0000644000015301777760000000434512322054247025565 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/android/fence.h" #include "mir/geometry/rectangle.h" #include "hwc_layers.h" #include #include #include #include #include namespace mir { namespace graphics { class Renderable; class Buffer; namespace android { /* this is a partitioned list. renderlist makes up the first renderlist.size() elements of the list, and there are additional_layers added to the end. std::distance(begin(), additional_layers_begin()) == renderlist.size() std::distance(additional_layers_begin(), end()) == additional_layers std::distance(begin(), end()) == renderlist.size() + additional_layers */ class LayerList { public: LayerList(RenderableList const& renderlist, size_t additional_layers); bool update_list_and_check_if_changed( RenderableList const& renderlist, size_t additional_layers); std::list::iterator begin(); std::list::iterator additional_layers_begin(); std::list::iterator end(); std::weak_ptr native_list(); NativeFence retirement_fence(); private: LayerList& operator=(LayerList const&) = delete; LayerList(LayerList const&) = delete; std::list layers; std::shared_ptr hwc_representation; std::list::iterator first_additional_layer; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_LAYERLIST_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_fb_device.h0000644000015301777760000000356212322054247025463 0ustar pbusernogroup00000000000000/* * 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 "hwc_common_device.h" #include "hwc_layerlist.h" #include "hardware/gralloc.h" #include "hardware/fb.h" namespace mir { namespace graphics { namespace android { class HwcWrapper; class HwcFbDevice : public HWCCommonDevice { public: HwcFbDevice(std::shared_ptr const& hwc_device, std::shared_ptr const& hwc_wrapper, std::shared_ptr const& fb_device, std::shared_ptr const& coordinator); virtual void render_gl(SwappingGLContext const& context); virtual void render_gl_and_overlays( SwappingGLContext const& context, RenderableList const& list, std::function const& render_fn); void post(Buffer const& buffer); private: void prepare(); void gpu_render(); std::shared_ptr const hwc_wrapper; std::shared_ptr const fb_device; static int const num_displays{1}; LayerList layer_list; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_FB_DEVICE_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/display_device.h0000644000015301777760000000335212322054247025675 0ustar pbusernogroup00000000000000/* * 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/graphics/renderable.h" #include "mir_toolkit/common.h" #include #include namespace mir { namespace graphics { class Buffer; class Renderable; namespace android { class SwappingGLContext; class DisplayDevice { public: virtual ~DisplayDevice() = default; virtual void mode(MirPowerMode mode) = 0; virtual void render_gl(SwappingGLContext const& context) = 0; virtual void render_gl_and_overlays( SwappingGLContext const& context, RenderableList const& list, std::function const& render_fn) = 0; virtual void post(Buffer const& buffer) = 0; virtual bool apply_orientation(MirOrientation orientation) const = 0; protected: DisplayDevice() = default; DisplayDevice& operator=(DisplayDevice const&) = delete; DisplayDevice(DisplayDevice const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DISPLAY_SUPPORT_PROVIDER_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/internal_client_window.cpp0000644000015301777760000000620312322054223027775 0ustar pbusernogroup00000000000000/* * 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 "internal_client_window.h" #include "mir/graphics/internal_surface.h" #include "mir/graphics/android/sync_fence.h" #include "mir/graphics/buffer.h" #include "interpreter_resource_cache.h" #include "android_format_conversion-inl.h" #include #include #include namespace mg=mir::graphics; namespace mga=mg::android; namespace geom=mir::geometry; mga::InternalClientWindow::InternalClientWindow(std::shared_ptr const& surface) : surface(surface), buffer(nullptr) { format = mga::to_android_format(MirPixelFormat(surface->pixel_format())); } mg::NativeBuffer* mga::InternalClientWindow::driver_requests_buffer() { if (!buffer) { surface->swap_buffers(buffer); } auto handle = buffer->native_buffer_handle(); lookup[handle->anwb()] = {buffer, handle}; buffer = nullptr; return handle.get(); } void mga::InternalClientWindow::driver_returns_buffer(ANativeWindowBuffer* key, int fence_fd) { auto it = lookup.find(key); if (it == lookup.end()) { BOOST_THROW_EXCEPTION(std::runtime_error("driver is returning buffers it never was given!")); } auto handle = it->second.handle; buffer = it->second.buffer; lookup.erase(it); handle->update_fence(fence_fd); surface->swap_buffers(buffer); } void mga::InternalClientWindow::dispatch_driver_request_format(int request_format) { format = request_format; } int mga::InternalClientWindow::driver_requests_info(int key) const { geom::Size size; switch(key) { case NATIVE_WINDOW_DEFAULT_WIDTH: case NATIVE_WINDOW_WIDTH: size = surface->size(); return size.width.as_uint32_t(); case NATIVE_WINDOW_DEFAULT_HEIGHT: case NATIVE_WINDOW_HEIGHT: size = surface->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; default: { std::stringstream sstream; sstream << "driver requests info we dont provide. key: " << key; BOOST_THROW_EXCEPTION(std::runtime_error(sstream.str())); } } } void mga::InternalClientWindow::sync_to_display(bool) { //note: clients run with the swapinterval of the display. ignore their request for now } mir-0.1.8+14.04.20140411/src/platform/graphics/android/display_resource_factory.h0000644000015301777760000000425612322054223030012 0ustar pbusernogroup00000000000000/* * 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 namespace mir { namespace graphics { class Display; class DisplayReport; namespace android { class DisplayDevice; class FramebufferBundle; class DisplayResourceFactory { public: virtual ~DisplayResourceFactory() = default; virtual std::shared_ptr create_hwc_native_device() const = 0; virtual std::shared_ptr create_fb_native_device() const = 0; virtual std::shared_ptr create_native_window( std::shared_ptr const& device) const = 0; virtual std::shared_ptr create_fb_device( std::shared_ptr const& fb_native_device) const = 0; virtual std::shared_ptr create_hwc_device( std::shared_ptr const& hwc_native_device) const = 0; virtual std::shared_ptr create_hwc_fb_device( std::shared_ptr const& hwc_native_device, std::shared_ptr const& fb_native_device) const = 0; protected: DisplayResourceFactory() = default; DisplayResourceFactory& operator=(DisplayResourceFactory const&) = delete; DisplayResourceFactory(DisplayResourceFactory const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_FRAMEBUFFER_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/graphic_alloc_adaptor.h0000644000015301777760000000266212322054223027207 0ustar pbusernogroup00000000000000/* * 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_GRAPHIC_ALLOC_ADAPTOR_H_ #define MIR_GRAPHICS_ANDROID_GRAPHIC_ALLOC_ADAPTOR_H_ #include "mir/geometry/size.h" #include "mir_toolkit/common.h" #include "buffer_usage.h" #include namespace mir { namespace graphics { class NativeBuffer; namespace android { class GraphicAllocAdaptor { public: virtual std::shared_ptr alloc_buffer(geometry::Size size, MirPixelFormat, BufferUsage usage) = 0; protected: GraphicAllocAdaptor() = default; virtual ~GraphicAllocAdaptor() {} GraphicAllocAdaptor(const GraphicAllocAdaptor&) = delete; GraphicAllocAdaptor& operator=(const GraphicAllocAdaptor&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_GRAPHIC_ALLOC_ADAPTOR_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/android_display.cpp0000644000015301777760000000642212322054247026412 0ustar pbusernogroup00000000000000/* * 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 "android_display_configuration.h" #include "mir/graphics/display_report.h" #include "mir/graphics/display_buffer.h" #include "mir/graphics/gl_context.h" #include "mir/graphics/egl_resources.h" #include "android_display.h" #include "display_builder.h" #include "mir/geometry/rectangle.h" #include namespace mga=mir::graphics::android; namespace mg=mir::graphics; namespace geom=mir::geometry; mga::AndroidDisplay::AndroidDisplay(std::shared_ptr const& display_builder, std::shared_ptr const& gl_config, std::shared_ptr const& display_report) : display_builder{display_builder}, gl_context{display_builder->display_format(), *gl_config, *display_report}, display_buffer{display_builder->create_display_buffer(gl_context)} { 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(); } void mga::AndroidDisplay::for_each_display_buffer(std::function const& f) { f(*display_buffer); } std::unique_ptr mga::AndroidDisplay::configuration() const { return std::unique_ptr( new mga::AndroidDisplayConfiguration(display_buffer->configuration())); } void mga::AndroidDisplay::configure(mg::DisplayConfiguration const& configuration) { if (!configuration.valid()) { BOOST_THROW_EXCEPTION( std::logic_error("Invalid or inconsistent display configuration")); } configuration.for_each_output([&](mg::DisplayConfigurationOutput const& output) { display_buffer->configure(output); }); } void mga::AndroidDisplay::register_configuration_change_handler( EventHandlerRegister&, DisplayConfigurationChangeHandler const&) { } void mga::AndroidDisplay::register_pause_resume_handlers( EventHandlerRegister& /*handlers*/, DisplayPauseHandler const& /*pause_handler*/, DisplayResumeHandler const& /*resume_handler*/) { } void mga::AndroidDisplay::pause() { } void mga::AndroidDisplay::resume() { } auto mga::AndroidDisplay::the_cursor() -> std::weak_ptr { return std::weak_ptr(); } std::unique_ptr mga::AndroidDisplay::create_gl_context() { return std::unique_ptr{ new mga::GLContext(gl_context, mga::create_dummy_pbuffer_surface)}; } mir-0.1.8+14.04.20140411/src/platform/graphics/android/framebuffer_bundle.h0000644000015301777760000000302312322054223026513 0ustar pbusernogroup00000000000000/* * 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 MirPixelFormat fb_format() = 0; virtual geometry::Size fb_size() = 0; virtual std::shared_ptr buffer_for_render() = 0; virtual std::shared_ptr last_rendered_buffer() = 0; virtual void wait_for_consumed_buffer(bool) = 0; protected: FramebufferBundle() = default; FramebufferBundle(FramebufferBundle const&) = delete; FramebufferBundle& operator=(FramebufferBundle const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_FRAMEBUFFER_BUNDLE_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/android_platform.h0000644000015301777760000000465412322054247026243 0ustar pbusernogroup00000000000000/* * 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_ANDROID_PLATFORM_H_ #define MIR_GRAPHICS_ANDROID_ANDROID_PLATFORM_H_ #include "mir/graphics/platform.h" #include "mir/graphics/native_platform.h" namespace mir { namespace graphics { class DisplayReport; namespace android { class GraphicBufferAllocator; class FramebufferFactory; class DisplayBuilder; class AndroidPlatform : public Platform, public NativePlatform { public: AndroidPlatform( std::shared_ptr const& display_builder, std::shared_ptr const& display_report); /* From Platform */ std::shared_ptr create_buffer_allocator( std::shared_ptr const& buffer_initializer); std::shared_ptr create_display( std::shared_ptr const&, std::shared_ptr const& /*gl_config*/); std::shared_ptr get_ipc_package(); std::shared_ptr create_internal_client(); void fill_ipc_package(BufferIPCPacker* packer, graphics::Buffer const* buffer) const; EGLNativeDisplayType egl_native_display() const; private: std::shared_ptr create_fb_backup_display(); void initialize(std::shared_ptr const& nested_context) override; // TODO a design that has this and create_buffer_allocator is missing simplicity virtual std::shared_ptr create_mga_buffer_allocator( const std::shared_ptr& buffer_initializer); std::shared_ptr const display_builder; std::shared_ptr const display_report; }; } } } #endif /* MIR_GRAPHICS_ANDROID_ANDROID_PLATFORM_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/android_alloc_adaptor.h0000644000015301777760000000300712322054223027204 0ustar pbusernogroup00000000000000/* * 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_ANDROID_ALLOC_ADAPTOR_H_ #define MIR_GRAPHICS_ANDROID_ANDROID_ALLOC_ADAPTOR_H_ #include "graphic_alloc_adaptor.h" #include #include namespace mir { namespace graphics { namespace android { class AndroidAllocAdaptor : public GraphicAllocAdaptor { public: explicit AndroidAllocAdaptor(const std::shared_ptr& alloc_device); std::shared_ptr alloc_buffer(geometry::Size, MirPixelFormat, BufferUsage usage); /* note: alloc_device_t has a third method (dump) that isn't needed by us. it can be used to check buffer contents */ private: std::shared_ptr alloc_dev; int convert_to_android_usage(BufferUsage usage); }; } } } #endif /* MIR_GRAPHICS_ANDROID_ANDROID_ALLOC_ADAPTOR_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/android_format_conversion-inl.h0000644000015301777760000000406412322054223030721 0ustar pbusernogroup00000000000000/* * 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_toolkit/common.h" #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_bgr_888: return HAL_PIXEL_FORMAT_RGB_888; 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_bgr_888; default: return mir_pixel_format_invalid; } } } } } #endif /* MIR_GRAPHICS_ANDROID_ANDROID_FORMAT_CONVERSION_INL_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/android_display_configuration.h0000644000015301777760000000325312322054223030777 0ustar pbusernogroup00000000000000/* * 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_ANDROID_DISPLAY_CONFIGURATION_H_ #define MIR_GRAPHICS_ANDROID_ANDROID_DISPLAY_CONFIGURATION_H_ #include "mir/graphics/display_configuration.h" namespace mir { namespace graphics { namespace android { class AndroidDisplayConfiguration : public graphics::DisplayConfiguration { public: AndroidDisplayConfiguration(DisplayConfigurationOutput&& output); AndroidDisplayConfiguration(AndroidDisplayConfiguration const& other); AndroidDisplayConfiguration& operator=(AndroidDisplayConfiguration const& other); virtual ~AndroidDisplayConfiguration() = 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; private: DisplayConfigurationOutput configuration; DisplayConfigurationCard card; }; } } } #endif /* MIR_GRAPHICS_ANDROID_ANDROID_DISPLAY_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/internal_client.h0000644000015301777760000000251512322054223026055 0ustar pbusernogroup00000000000000/* * 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_INTERNAL_CLIENT_H_ #define MIR_GRAPHICS_ANDROID_INTERNAL_CLIENT_H_ #include "mir/graphics/internal_client.h" #include #include namespace mir { namespace graphics { namespace android { class MirNativeWindow; class InternalClient : public mir::graphics::InternalClient { public: InternalClient(); EGLNativeDisplayType egl_native_display(); EGLNativeWindowType egl_native_window(std::shared_ptr const&); private: std::map, std::shared_ptr> client_windows; }; } } } #endif /* MIR_GRAPHICS_ANDROID_INTERNAL_CLIENT_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/buffer_usage.h0000644000015301777760000000233412322054223025337 0ustar pbusernogroup00000000000000/* * 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_BUFFER_USAGE_H_ #define MIR_GRAPHICS_ANDROID_BUFFER_USAGE_H_ namespace mir { namespace graphics { namespace android { enum class BufferUsage : uint32_t { use_hardware, //buffer supports usage as a gles render target, and a gles texture use_software, //buffer supports usage as a cpu render target, and a gles texture use_framebuffer_gles //buffer supports usage as a gles render target, hwc layer, and is postable to framebuffer }; } } } #endif /* MIR_GRAPHICS_ANDROID_BUFFER_USAGE_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/graphic_buffer_allocator.h0000644000015301777760000000274612322054223027717 0ustar pbusernogroup00000000000000/* * 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_GRAPHIC_BUFFER_ALLOCATOR_H_ #define MIR_GRAPHICS_ANDROID_GRAPHIC_BUFFER_ALLOCATOR_H_ #include "buffer_usage.h" #include "mir/geometry/size.h" #include "mir_toolkit/common.h" #include namespace mir { namespace graphics { class Buffer; namespace android { class GraphicBufferAllocator { public: virtual std::shared_ptr alloc_buffer_platform( geometry::Size sz, MirPixelFormat pf, BufferUsage use) = 0; protected: GraphicBufferAllocator() = default; virtual ~GraphicBufferAllocator() = default; GraphicBufferAllocator(const GraphicBufferAllocator&) = delete; GraphicBufferAllocator& operator=(const GraphicBufferAllocator&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_GRAPHIC_BUFFER_ALLOCATOR_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/real_hwc_wrapper.cpp0000644000015301777760000000423412322054247026570 0ustar pbusernogroup00000000000000/* * 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 "real_hwc_wrapper.h" #include "hwc_logger.h" #include #include #include namespace mga=mir::graphics::android; mga::RealHwcWrapper::RealHwcWrapper( std::shared_ptr const& hwc_device, std::shared_ptr const& logger) : hwc_device(hwc_device), logger(logger) { } void mga::RealHwcWrapper::prepare(hwc_display_contents_1_t& display_list) const { //note, although we only have a primary display right now, // set the external and virtual displays to null as some drivers check for that hwc_display_contents_1_t* displays[num_displays] {&display_list, nullptr, nullptr}; logger->log_list_submitted_to_prepare(display_list); if (auto rc = hwc_device->prepare(hwc_device.get(), 1, displays)) { std::stringstream ss; ss << "error during hwc prepare(). rc = " << std::hex << rc; BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } logger->log_prepare_done(display_list); } void mga::RealHwcWrapper::set(hwc_display_contents_1_t& display_list) const { hwc_display_contents_1_t* displays[num_displays] {&display_list, nullptr, nullptr}; logger->log_set_list(display_list); if (auto rc = hwc_device->set(hwc_device.get(), 1, displays)) { std::stringstream ss; ss << "error during hwc prepare(). rc = " << std::hex << rc; BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } } mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_device.h0000644000015301777760000000414212322054247025007 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/android/sync_fence.h" #include "hwc_common_device.h" #include "hwc_layerlist.h" #include namespace mir { namespace graphics { class Buffer; namespace android { class HWCVsyncCoordinator; class SyncFileOps; class HwcWrapper; class HwcDevice : public HWCCommonDevice { public: //TODO: the first two constructor arguments are redundant. eliminate the 1st one when the 2nd // one can be used by the HWCCommonDevice HwcDevice(std::shared_ptr const& hwc_device, std::shared_ptr const& hwc_wrapper, std::shared_ptr const& coordinator, std::shared_ptr const& sync_ops); virtual void render_gl(SwappingGLContext const& context); virtual void render_gl_and_overlays( SwappingGLContext const& context, RenderableList const& list, std::function const& render_fn); void post(Buffer const& buffer); private: LayerList hwc_list; void set_list_framebuffer(Buffer const&); void setup_layer_types(); std::shared_ptr const hwc_wrapper; std::shared_ptr const sync_ops; bool list_needs_commit{false}; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_DEVICE_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/display_buffer.h0000644000015301777760000000433512322054247025711 0ustar pbusernogroup00000000000000/* * 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 "android_display_configuration.h" #include "gl_context.h" #include namespace mir { namespace graphics { namespace android { class DisplayDevice; class FramebufferBundle; class DisplayBuffer : public ConfigurableDisplayBuffer { public: DisplayBuffer(std::shared_ptr const& fb_bundle, std::shared_ptr const& display_device, std::shared_ptr const& native_window, GLContext const& shared_gl_context); geometry::Rectangle view_area() const; void make_current(); void release_current(); void post_update(); bool can_bypass() const override; void render_and_post_update( RenderableList const& renderlist, std::function const& render_fn); MirOrientation orientation() const override; DisplayConfigurationOutput configuration() const; void configure(DisplayConfigurationOutput const&); private: void post(); std::shared_ptr const fb_bundle; std::shared_ptr const display_device; std::shared_ptr const native_window; GLContext gl_context; bool prepared; DisplayConfigurationOutput current_configuration; MirOrientation rotation; }; } } } #endif /* MIR_GRAPHICS_ANDROID_DISPLAY_BUFFER_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/CMakeLists.txt0000644000015301777760000000357012322054247025302 0ustar pbusernogroup00000000000000include_directories(SYSTEM ${LIBHARDWARE_INCLUDE_DIRS}) include_directories( ${EGL_INCLUDE_DIRS} ${GLESv2_INCLUDE_DIRS} ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive") add_definitions( -DANDROID ) add_library( mirplatformgraphicsandroid SHARED android_platform.cpp android_buffer_allocator.cpp buffer.cpp android_display.cpp android_display_configuration.cpp display_buffer.cpp output_builder.cpp hwc_layerlist.cpp hwc_layers.cpp hwc_fb_device.cpp hwc_formatted_logger.cpp hwc_device.cpp hwc_common_device.cpp hwc_vsync.cpp android_alloc_adaptor.cpp server_render_window.cpp resource_factory.cpp framebuffers.cpp fb_device.cpp internal_client_window.cpp interpreter_cache.cpp internal_client.cpp gl_context.cpp real_hwc_wrapper.cpp ) set_target_properties( mirplatformgraphicsandroid PROPERTIES OUTPUT_NAME mirplatformgraphics LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}/android ) target_link_libraries( mirplatformgraphicsandroid miroptions mirplatform mirsharedandroid mirsharedenv ${Boost_PROGRAM_OPTIONS_LIBRARY} ${LIBHARDWARE_LIBRARIES} ${EGL_LDFLAGS} ${EGL_LIBRARIES} ${GLESv2_LDFLAGS} ${GLESv2_LIBRARIES} ) install(TARGETS mirplatformgraphicsandroid LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mir/platformgraphics/android) if (MIR_TEST_PLATFORM STREQUAL "android") add_custom_command(TARGET mirplatformgraphicsandroid POST_BUILD COMMAND ${CMAKE_COMMAND} -E remove libmirplatformgraphics.so COMMAND ${CMAKE_COMMAND} -E create_symlink android/$ libmirplatformgraphics.so WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH} ) install(CODE "execute_process( COMMAND ln -sf mir/platformgraphics/android/libmirplatformgraphics.so WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} )" ) endif() mir-0.1.8+14.04.20140411/src/platform/graphics/android/gl_context.h0000644000015301777760000000443112322054247025056 0ustar pbusernogroup00000000000000/* * 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_GL_CONTEXT_H_ #define MIR_GRAPHICS_ANDROID_GL_CONTEXT_H_ #include "mir/graphics/gl_context.h" #include "mir/graphics/egl_resources.h" #include "mir_toolkit/common.h" #include namespace mir { namespace graphics { class DisplayReport; class GLConfig; namespace android { //handy functions EGLSurface create_dummy_pbuffer_surface(EGLDisplay, EGLConfig); EGLSurface create_window_surface(EGLDisplay, EGLConfig, EGLNativeWindowType); class SwappingGLContext { public: virtual ~SwappingGLContext() = default; virtual void swap_buffers() const = 0; protected: SwappingGLContext() = default; SwappingGLContext(SwappingGLContext const&) = delete; SwappingGLContext& operator=(SwappingGLContext const&) = delete; }; class GLContext : public SwappingGLContext, public graphics::GLContext { public: //For creating a gl context GLContext(MirPixelFormat display_format, GLConfig const& gl_config, DisplayReport& report); //For creating a gl context shared with another GLContext GLContext(GLContext const& shared_gl_context, std::function const& create_egl_surface); ~GLContext(); void make_current() const override; void swap_buffers() const override; void release_current() const override; private: EGLDisplay const egl_display; bool const own_display; EGLConfig const egl_config; EGLContextStore const egl_context; EGLSurfaceStore const egl_surface; }; } } } #endif /* MIR_GRAPHICS_ANDROID_GL_CONTEXT_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/configurable_display_buffer.h0000644000015301777760000000236012322054223030417 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/display_configuration.h" namespace mir { namespace graphics { namespace android { class ConfigurableDisplayBuffer : public graphics::DisplayBuffer { public: virtual DisplayConfigurationOutput configuration() const = 0; virtual void configure(DisplayConfigurationOutput const&) = 0; }; } } } #endif /* MIR_GRAPHICS_ANDROID_CONFIGURABLE_DISPLAY_BUFFER_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_vsync_coordinator.h0000644000015301777760000000241212322054223027305 0ustar pbusernogroup00000000000000/* * 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_VSYNC_COORDINATOR_H_ #define MIR_GRAPHICS_ANDROID_HWC_VSYNC_COORDINATOR_H_ namespace mir { namespace graphics { namespace android { class HWCVsyncCoordinator { public: virtual ~HWCVsyncCoordinator() = default; virtual void wait_for_vsync() = 0; virtual void notify_vsync() = 0; protected: HWCVsyncCoordinator() = default; HWCVsyncCoordinator(HWCVsyncCoordinator const&) = delete; HWCVsyncCoordinator& operator=(HWCVsyncCoordinator const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_VSYNC_COORDINATOR_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/real_hwc_wrapper.h0000644000015301777760000000275312322054247026241 0ustar pbusernogroup00000000000000/* * 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 namespace mir { namespace graphics { namespace android { class HwcLogger; class RealHwcWrapper : public HwcWrapper { public: RealHwcWrapper( std::shared_ptr const& hwc_device, std::shared_ptr const& logger); void prepare(hwc_display_contents_1_t&) const override; void set(hwc_display_contents_1_t&) const override; private: static size_t const num_displays{3}; //primary, external, virtual std::shared_ptr const hwc_device; std::shared_ptr const logger; }; } } } #endif /* MIR_GRAPHICS_ANDROID_REAL_HWC_WRAPPER_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/framebuffers.cpp0000644000015301777760000001202112322054223025676 0ustar pbusernogroup00000000000000/* * 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 "android_format_conversion-inl.h" #include "graphic_buffer_allocator.h" #include #include #include #include #include namespace mg = mir::graphics; namespace mga=mir::graphics::android; namespace geom=mir::geometry; namespace { MirPixelFormat determine_hwc11_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_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); } else { //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; } eglTerminate(egl_display); return fb_format; } geom::Size determine_hwc11_size( std::shared_ptr const& hwc_device) { size_t num_configs = 1; uint32_t primary_display_config; auto rc = hwc_device->getDisplayConfigs(hwc_device.get(), HWC_DISPLAY_PRIMARY, &primary_display_config, &num_configs); if (rc != 0) { BOOST_THROW_EXCEPTION(std::runtime_error("could not determine hwc display config")); } /* note: some drivers (qcom msm8960) choke if this is not the same size array as the one surfaceflinger submits */ static uint32_t const display_attribute_request[] = { HWC_DISPLAY_WIDTH, HWC_DISPLAY_HEIGHT, HWC_DISPLAY_VSYNC_PERIOD, HWC_DISPLAY_DPI_X, HWC_DISPLAY_DPI_Y, HWC_DISPLAY_NO_ATTRIBUTE, }; int32_t size_values[sizeof(display_attribute_request) / sizeof (display_attribute_request[0])]; hwc_device->getDisplayAttributes(hwc_device.get(), HWC_DISPLAY_PRIMARY, primary_display_config, display_attribute_request, size_values); return {size_values[0], size_values[1]}; } } mga::Framebuffers::Framebuffers( std::shared_ptr const& buffer_allocator, std::shared_ptr const& hwc) : format(determine_hwc11_fb_format()), size(determine_hwc11_size(hwc)) { for(auto i = 0u; i < 2; i++) { queue.push(buffer_allocator->alloc_buffer_platform(size, format, mga::BufferUsage::use_framebuffer_gles)); } } mga::Framebuffers::Framebuffers( std::shared_ptr const& buffer_allocator, std::shared_ptr const& fb) : format{mga::to_mir_format(fb->format)}, size({fb->width, fb->height}) { //guarantee always 2 fb's allocated auto fb_num = static_cast(fb->numFramebuffers); fb_num = std::max(2u, fb_num); for(auto i = 0u; i < fb_num; i++) { queue.push(buffer_allocator->alloc_buffer_platform(size, format, mga::BufferUsage::use_framebuffer_gles)); } } MirPixelFormat mga::Framebuffers::fb_format() { return 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(); } void mga::Framebuffers::wait_for_consumed_buffer(bool) { //TODO: change swapping so buffer_for_render() does not wait } mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_device.cpp0000644000015301777760000001005112322054247025336 0ustar pbusernogroup00000000000000/* * 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 "hwc_device.h" #include "hwc_layerlist.h" #include "hwc_vsync_coordinator.h" #include "hwc_wrapper.h" #include "framebuffer_bundle.h" #include "buffer.h" #include "mir/graphics/buffer.h" namespace mg = mir::graphics; namespace mga=mir::graphics::android; namespace geom = mir::geometry; namespace { static const size_t fbtarget_plus_skip_size = 2; static const size_t fbtarget_size = 1; } void mga::HwcDevice::setup_layer_types() { auto it = hwc_list.additional_layers_begin(); auto const num_additional_layers = std::distance(it, hwc_list.end()); switch (num_additional_layers) { case fbtarget_plus_skip_size: it->set_layer_type(mga::LayerType::skip); ++it; case fbtarget_size: it->set_layer_type(mga::LayerType::framebuffer_target); default: break; } } void mga::HwcDevice::set_list_framebuffer(mg::Buffer const& buffer) { geom::Rectangle const disp_frame{{0,0}, {buffer.size()}}; for(auto it = hwc_list.additional_layers_begin(); it != hwc_list.end(); it++) { //TODO: the functions on mga::Layer should be consolidated it->set_render_parameters(disp_frame, false); it->set_buffer(buffer); it->prepare_for_draw(); } } mga::HwcDevice::HwcDevice(std::shared_ptr const& hwc_device, std::shared_ptr const& hwc_wrapper, std::shared_ptr const& coordinator, std::shared_ptr const& sync_ops) : HWCCommonDevice(hwc_device, coordinator), hwc_list{{}, 2}, hwc_wrapper(hwc_wrapper), sync_ops(sync_ops) { setup_layer_types(); } void mga::HwcDevice::render_gl(SwappingGLContext const& context) { hwc_list.update_list_and_check_if_changed({}, fbtarget_plus_skip_size); setup_layer_types(); list_needs_commit = true; hwc_wrapper->prepare(*hwc_list.native_list().lock()); context.swap_buffers(); } void mga::HwcDevice::render_gl_and_overlays( SwappingGLContext const& context, RenderableList const& renderables, std::function const& render_fn) { if (!(list_needs_commit = hwc_list.update_list_and_check_if_changed(renderables, fbtarget_size))) return; setup_layer_types(); hwc_wrapper->prepare(*hwc_list.native_list().lock()); //draw layers that the HWC did not accept for overlays here bool needs_swapbuffers = false; auto layers_it = hwc_list.begin(); for(auto const& renderable : renderables) { //prepare all layers for draw. layers_it->prepare_for_draw(); //trigger GL on the layers that are not overlays if (layers_it->needs_gl_render()) { render_fn(*renderable); needs_swapbuffers = true; } layers_it++; } if (needs_swapbuffers) context.swap_buffers(); } void mga::HwcDevice::post(mg::Buffer const& buffer) { if (!list_needs_commit) return; auto lg = lock_unblanked(); set_list_framebuffer(buffer); hwc_wrapper->set(*hwc_list.native_list().lock()); for(auto& layer : hwc_list) { layer.update_fence_and_release_buffer(); } mga::SyncFence retire_fence(sync_ops, hwc_list.retirement_fence()); list_needs_commit = false; } mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_layerlist.cpp0000644000015301777760000001041512322054247026113 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/android/sync_fence.h" #include "mir/graphics/android/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; } } bool mga::LayerList::update_list_and_check_if_changed( RenderableList const& renderlist, size_t additional_layers) { size_t needed_size = renderlist.size() + additional_layers; bool any_buffer_updated = false; if ((!hwc_representation) || hwc_representation->numHwLayers != needed_size) { hwc_representation = generate_hwc_list(needed_size); } if (layers.size() == needed_size) { auto layers_it = layers.begin(); for(auto renderable : renderlist) { layers_it->set_render_parameters( renderable->screen_position(), renderable->alpha_enabled()); layers_it->set_buffer(*renderable->buffer(this)); any_buffer_updated |= layers_it->needs_hwc_commit(); layers_it++; } } else { any_buffer_updated = true; std::list new_layers; auto i = 0u; for(auto const& renderable : renderlist) { new_layers.emplace_back( mga::HWCLayer( mga::LayerType::gl_rendered, renderable->screen_position(), renderable->alpha_enabled(), hwc_representation, i++)); new_layers.back().set_buffer(*renderable->buffer(this)); } for(; i < needed_size; i++) { new_layers.emplace_back(mga::HWCLayer(hwc_representation, i)); } layers = std::move(new_layers); } if (additional_layers == 0) { first_additional_layer = layers.end(); } else { first_additional_layer = layers.begin(); std::advance(first_additional_layer, renderlist.size()); } return any_buffer_updated; } std::list::iterator mga::LayerList::begin() { return layers.begin(); } std::list::iterator mga::LayerList::additional_layers_begin() { return first_additional_layer; } std::list::iterator mga::LayerList::end() { return layers.end(); } std::weak_ptr mga::LayerList::native_list() { return hwc_representation; } mga::NativeFence mga::LayerList::retirement_fence() { return hwc_representation->retireFenceFd; } mga::LayerList::LayerList( RenderableList const& renderlist, size_t additional_layers) { update_list_and_check_if_changed(renderlist, additional_layers); } mir-0.1.8+14.04.20140411/src/platform/graphics/android/gl_context.cpp0000644000015301777760000001310512322054247025407 0ustar pbusernogroup00000000000000/* * 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 "android_format_conversion-inl.h" #include "mir/graphics/display_report.h" #include "mir/graphics/gl_config.h" #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(std::runtime_error("eglGetDisplay failed\n")); if (eglInitialize(egl_display, &major, &minor) == EGL_FALSE) BOOST_THROW_EXCEPTION(std::runtime_error("eglInitialize failure\n")); if ((major != 1) || (minor != 4)) BOOST_THROW_EXCEPTION(std::runtime_error("must have EGL 1.4\n")); 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_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; } } EGLSurface mga::create_dummy_pbuffer_surface(EGLDisplay disp, EGLConfig config) { return eglCreatePbufferSurface(disp, config, dummy_pbuffer_attribs); } EGLSurface mga::create_window_surface(EGLDisplay disp, EGLConfig config, EGLNativeWindowType native) { return eglCreateWindowSurface(disp, config, native, NULL); } mga::GLContext::GLContext(MirPixelFormat display_format, mg::GLConfig const& gl_config, mg::DisplayReport& report) : egl_display(create_and_initialize_display()), own_display(true), 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)}, egl_surface{egl_display, eglCreatePbufferSurface(egl_display, egl_config, dummy_pbuffer_attribs)} { report.report_egl_configuration(egl_display, egl_config); } mga::GLContext::GLContext( GLContext const& shared_gl_context, std::function const& create_egl_surface) : egl_display(shared_gl_context.egl_display), own_display(false), 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)}, egl_surface{egl_display, create_egl_surface(egl_display, egl_config)} { } void mga::GLContext::make_current() const { if (eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context) == EGL_FALSE) { BOOST_THROW_EXCEPTION( std::runtime_error("could not activate surface with eglMakeCurrent\n")); } } void mga::GLContext::release_current() const { eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } void mga::GLContext::swap_buffers() const { eglGetError(); if (eglSwapBuffers(egl_display, egl_surface) == EGL_FALSE) { std::stringstream sstream; sstream << "eglSwapBuffers failure: EGL error code " << std::hex << eglGetError(); BOOST_THROW_EXCEPTION(std::runtime_error(sstream.str())); } } mga::GLContext::~GLContext() { if (eglGetCurrentContext() == egl_context) release_current(); if (own_display) eglTerminate(egl_display); } mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_fb_device.cpp0000644000015301777760000000655012322054247026016 0ustar pbusernogroup00000000000000/* * 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 "hwc_vsync_coordinator.h" #include "framebuffer_bundle.h" #include "android_format_conversion-inl.h" #include "hwc_wrapper.h" #include "mir/graphics/buffer.h" #include "mir/graphics/android/native_buffer.h" #include #include #include namespace mg = mir::graphics; namespace mga = mir::graphics::android; namespace geom = mir::geometry; mga::HwcFbDevice::HwcFbDevice(std::shared_ptr const& hwc_device, std::shared_ptr const& hwc_wrapper, std::shared_ptr const& fb_device, std::shared_ptr const& coordinator) : HWCCommonDevice(hwc_device, coordinator), hwc_wrapper(hwc_wrapper), fb_device(fb_device), layer_list{{},1} { layer_list.additional_layers_begin()->set_layer_type(mga::LayerType::skip); } void mga::HwcFbDevice::gpu_render() { if (auto display_list = layer_list.native_list().lock()) { 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); } else { std::stringstream ss; ss << "error locking list during hwc set()"; BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } } void mga::HwcFbDevice::prepare() { if (auto display_list = layer_list.native_list().lock()) { hwc_wrapper->prepare(*display_list); } else { std::stringstream ss; ss << "error accessing list during hwc prepare()"; BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } } void mga::HwcFbDevice::render_gl(SwappingGLContext const&) { prepare(); gpu_render(); } void mga::HwcFbDevice::render_gl_and_overlays( SwappingGLContext const&, RenderableList const& renderables, std::function const& render_fn) { prepare(); //TODO: filter this list based on the results of the preparation for(auto const& renderable : renderables) render_fn(*renderable); gpu_render(); } void mga::HwcFbDevice::post(mg::Buffer const& buffer) { auto lg = lock_unblanked(); auto native_buffer = buffer.native_buffer_handle(); native_buffer->wait_for_content(); if (fb_device->post(fb_device.get(), native_buffer->handle()) != 0) { BOOST_THROW_EXCEPTION(std::runtime_error("error posting with fb device")); } coordinator->wait_for_vsync(); } mir-0.1.8+14.04.20140411/src/platform/graphics/android/internal_client_window.h0000644000015301777760000000345412322054223027447 0ustar pbusernogroup00000000000000/* * 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_INTERNAL_CLIENT_WINDOW_H_ #define MIR_GRAPHICS_ANDROID_INTERNAL_CLIENT_WINDOW_H_ #include "mir/graphics/android/android_driver_interpreter.h" #include "mir/geometry/size.h" #include "mir_toolkit/common.h" #include #include namespace mir { namespace graphics { class Buffer; class InternalSurface; class NativeBuffer; namespace android { class InternalClientWindow : public AndroidDriverInterpreter { public: InternalClientWindow(std::shared_ptr const&); graphics::NativeBuffer* driver_requests_buffer(); void driver_returns_buffer(ANativeWindowBuffer*, int); void dispatch_driver_request_format(int); int driver_requests_info(int) const; void sync_to_display(bool sync); private: std::shared_ptr const surface; graphics::Buffer* buffer; struct Item { graphics::Buffer* buffer; std::shared_ptr handle; }; std::unordered_map lookup; int format; }; } } } #endif /* MIR_GRAPHICS_ANDROID_INTERNAL_CLIENT_WINDOW_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/server_render_window.h0000644000015301777760000000332312322054223027135 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/android/android_driver_interpreter.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, std::shared_ptr const&); graphics::NativeBuffer* driver_requests_buffer(); void driver_returns_buffer(ANativeWindowBuffer*, int fence_fd); void dispatch_driver_request_format(int format); int driver_requests_info(int key) const; void sync_to_display(bool sync); private: std::shared_ptr const fb_bundle; std::shared_ptr const resource_cache; int format; }; } } } #endif /* MIR_GRAPHICS_ANDROID_SERVER_RENDER_WINDOW_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/android/android_alloc_adaptor.cpp0000644000015301777760000000660512322054223027546 0ustar pbusernogroup00000000000000/* * 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/android/android_native_buffer.h" #include "mir/graphics/android/sync_fence.h" #include "android_alloc_adaptor.h" #include "android_format_conversion-inl.h" #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::AndroidAllocAdaptor::AndroidAllocAdaptor(const std::shared_ptr& alloc_device) : alloc_dev(alloc_device) { } std::shared_ptr mga::AndroidAllocAdaptor::alloc_buffer( geometry::Size size, MirPixelFormat pf, BufferUsage usage) { buffer_handle_t buf_handle = NULL; auto stride = 0; auto format = mga::to_android_format(pf); auto width = static_cast(size.width.as_uint32_t()); auto height = static_cast(size.height.as_uint32_t()); auto usage_flag = convert_to_android_usage(usage); auto ret = alloc_dev->alloc(alloc_dev.get(), width, height, format, usage_flag, &buf_handle, &stride); if (( ret ) || (buf_handle == NULL) || (stride == 0)) { BOOST_THROW_EXCEPTION(std::runtime_error("buffer allocation failed\n")); } AndroidBufferHandleDeleter del1(alloc_dev); std::shared_ptr handle(buf_handle, del1); auto ops = std::make_shared(); auto fence = std::make_shared(ops, -1); 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, fence); } int mga::AndroidAllocAdaptor::convert_to_android_usage(BufferUsage usage) { switch (usage) { case mga::BufferUsage::use_hardware: return (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER); case mga::BufferUsage::use_framebuffer_gles: return (GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB); case mga::BufferUsage::use_software: return (GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN); default: return -1; } } mir-0.1.8+14.04.20140411/src/platform/graphics/android/display_buffer.cpp0000644000015301777760000001206012322054247026236 0ustar pbusernogroup00000000000000/* * 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 #include #include #include #include namespace mg=mir::graphics; namespace mga=mir::graphics::android; namespace geom=mir::geometry; mga::DisplayBuffer::DisplayBuffer( std::shared_ptr const& fb_bundle, std::shared_ptr const& display_device, std::shared_ptr const& native_window, mga::GLContext const& shared_gl_context) : fb_bundle{fb_bundle}, display_device{display_device}, native_window{native_window}, gl_context{shared_gl_context, std::bind(mga::create_window_surface, std::placeholders::_1, std::placeholders::_2, native_window.get())}, current_configuration{ mg::DisplayConfigurationOutputId{1}, mg::DisplayConfigurationCardId{0}, mg::DisplayConfigurationOutputType::lvds, { fb_bundle->fb_format() }, {mg::DisplayConfigurationMode{fb_bundle->fb_size(),0.0f}}, 0, geom::Size{0,0}, //could use DPI information to fill this true, true, geom::Point{0,0}, 0, fb_bundle->fb_format(), mir_power_mode_on, mir_orientation_normal} { } 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 (current_configuration.orientation == mir_orientation_left || current_configuration.orientation == mir_orientation_right) { std::swap(width, height); } return {{0,0}, {width,height}}; } void mga::DisplayBuffer::make_current() { gl_context.make_current(); } void mga::DisplayBuffer::release_current() { gl_context.release_current(); } void mga::DisplayBuffer::render_and_post_update( RenderableList const& renderlist, std::function const& render_fn) { if (renderlist.empty()) { display_device->render_gl(gl_context); } else { display_device->render_gl_and_overlays(gl_context, renderlist, render_fn); } post(); } void mga::DisplayBuffer::post_update() { display_device->render_gl(gl_context); post(); } void mga::DisplayBuffer::post() { auto last_rendered = fb_bundle->last_rendered_buffer(); display_device->post(*last_rendered); } bool mga::DisplayBuffer::can_bypass() const { return false; } 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 current_configuration.orientation; } mg::DisplayConfigurationOutput mga::DisplayBuffer::configuration() const { return mg::DisplayConfigurationOutput(current_configuration); } void mga::DisplayBuffer::configure(DisplayConfigurationOutput const& new_configuration) { //power mode MirPowerMode intended_power_mode = new_configuration.power_mode; if ((intended_power_mode == mir_power_mode_standby) || (intended_power_mode == mir_power_mode_suspend)) { intended_power_mode = mir_power_mode_off; } if (intended_power_mode != current_configuration.power_mode) { display_device->mode(intended_power_mode); current_configuration.power_mode = intended_power_mode; } //If the hardware can rotate for us, we report normal orientation. If it can't //we preserve this orientation change so the compositor can rotate everything in GL if (display_device->apply_orientation(new_configuration.orientation)) { current_configuration.orientation = mir_orientation_normal; } else { current_configuration.orientation = new_configuration.orientation; } //do not allow fb format reallocation if (new_configuration.current_format != current_configuration.current_format) { std::stringstream err_msg; err_msg << std::string("could not change display buffer format to request: ") << new_configuration.current_format; BOOST_THROW_EXCEPTION(std::runtime_error(err_msg.str())); } } mir-0.1.8+14.04.20140411/src/platform/graphics/android/hwc_wrapper.h0000644000015301777760000000237412322054247025235 0ustar pbusernogroup00000000000000/* * 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 namespace mir { namespace graphics { namespace android { class HwcWrapper { public: virtual ~HwcWrapper() = default; virtual void prepare(hwc_display_contents_1_t&) const = 0; virtual void set(hwc_display_contents_1_t&) const = 0; protected: HwcWrapper() = default; HwcWrapper& operator=(HwcWrapper const&) = delete; HwcWrapper(HwcWrapper const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_HWC_WRAPPER_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/pixel_format_utils.cpp0000644000015301777760000000273412322054223025532 0ustar pbusernogroup00000000000000/* * 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: Andreas Pokorny */ #include "mir/graphics/pixel_format_utils.h" namespace mg = mir::graphics; bool mg::contains_alpha(MirPixelFormat format) { return (format == mir_pixel_format_abgr_8888 || format == mir_pixel_format_argb_8888); } bool mg::valid_pixel_format(MirPixelFormat format) { return (format > mir_pixel_format_invalid && format < mir_pixel_formats); } int mg::red_channel_depth(MirPixelFormat format) { return valid_pixel_format(format) ? 8 : 0; } int mg::blue_channel_depth(MirPixelFormat format) { return valid_pixel_format(format) ? 8 : 0; } int mg::green_channel_depth(MirPixelFormat format) { return valid_pixel_format(format) ? 8 : 0; } int mg::alpha_channel_depth(MirPixelFormat format) { return contains_alpha(format) ? 8 : 0; } mir-0.1.8+14.04.20140411/src/platform/graphics/egl_resources.cpp0000644000015301777760000000521212322054223024454 0ustar pbusernogroup00000000000000/* * 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 #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(std::runtime_error("Could not create egl context\n")); } 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(std::runtime_error("Could not create egl surface\n")); } 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_; } mir-0.1.8+14.04.20140411/src/platform/graphics/buffer_basic.cpp0000644000015301777760000000223712322054223024231 0ustar pbusernogroup00000000000000/* * 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}; auto id = mg::BufferID(next_id.fetch_add(1)); // Avoid returning an "invalid" id. (Not sure we need invalid ids) while (!id.is_valid()) id = mg::BufferID(next_id.fetch_add(1)); return id; } } mg::BufferBasic::BufferBasic() : buffer_id(generate_next_buffer_id()) { } mir-0.1.8+14.04.20140411/src/platform/graphics/overlapping_output_grouping.cpp0000644000015301777760000001063012322054223027473 0ustar pbusernogroup00000000000000/* * 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.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()}); } } mir-0.1.8+14.04.20140411/src/platform/graphics/egl_extensions.cpp0000644000015301777760000000315012322054223024640 0ustar pbusernogroup00000000000000/* * 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"))}, 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")); } mir-0.1.8+14.04.20140411/src/platform/graphics/display_configuration.cpp0000644000015301777760000001554412322054223026220 0ustar pbusernogroup00000000000000/* * 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 #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; }; char const* output_type_to_string(mg::DisplayConfigurationOutputType type) { static char const* type_names[] = { "unknown", "vga", "dvii", "dvid", "dvia", "composite", "lvds", "component", "9pindin", "displayport", "hdmia", "hdmib", "tv", "edp" }; auto index = static_cast(type); static auto const size = std::distance(std::begin(type_names), std::end(type_names)); if (index >= size || index < 0) return "invalid"; return type_names[index]; } } 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; } std::ostream& mg::operator<<(std::ostream& out, mg::DisplayConfigurationOutput const& val) { out << "{ id: " << val.id << ", card_id: " << val.card_id << " type: " << output_type_to_string(val.type) << " modes: ["; for (size_t i = 0; i < val.modes.size(); ++i) { out << val.modes[i]; if (i != val.modes.size() - 1) out << ", "; } out << "], preferred_mode: " << val.preferred_mode_index; out << " physical_size_mm: " << val.physical_size_mm.width << "x" << val.physical_size_mm.height; out << ", connected: " << (val.connected ? "true" : "false"); out << ", used: " << (val.used ? "true" : "false"); out << ", top_left: " << val.top_left; out << ", current_mode: " << val.current_mode_index << " ("; if (val.current_mode_index < val.modes.size()) out << val.modes[val.current_mode_index]; else out << "none"; out << ") }"; 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())}; 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); } mir::geometry::Rectangle mg::DisplayConfigurationOutput::extents() const { 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()}}; } } 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 (preferred_mode_index >= nmodes || 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) { } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/0000755000015301777760000000000012322054703022037 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/display_helpers.h0000644000015301777760000000633212322054247025406 0ustar pbusernogroup00000000000000/* * 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_mode_resources.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 { class DRMHelper { public: DRMHelper() : fd{-1} {} ~DRMHelper(); DRMHelper(const DRMHelper &) = delete; DRMHelper& operator=(const DRMHelper&) = delete; void setup(std::shared_ptr const& udev); int get_authenticated_fd(); void auth_magic(drm_magic_t magic) const; void drop_master() const; void set_master() const; int fd; 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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/real_kms_output_container.cpp0000644000015301777760000000313212322054223030016 0ustar pbusernogroup00000000000000/* * 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); } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/kms_page_flipper.h0000644000015301777760000000324712322054223025522 0ustar pbusernogroup00000000000000/* * 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 namespace mir { namespace graphics { class DisplayReport; namespace mesa { struct PageFlipEventData { std::unordered_map* pending; uint32_t crtc_id; }; class KMSPageFlipper : public PageFlipper { public: KMSPageFlipper(int drm_fd); bool schedule_flip(uint32_t crtc_id, uint32_t fb_id); void wait_for_flip(uint32_t crtc_id); std::thread::id debug_get_worker_tid(); private: bool page_flip_is_done(uint32_t crtc_id); int const drm_fd; std::unordered_map pending_page_flips; std::mutex pf_mutex; std::condition_variable pf_cv; std::thread::id worker_tid; }; } } } #endif /* MIR_GRAPHICS_MESA_KMS_PAGE_FLIPPER_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/platform.cpp0000644000015301777760000001467112322054247024403 0ustar pbusernogroup00000000000000/* * 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 "native_platform.h" #include "buffer_allocator.h" #include "display.h" #include "internal_client.h" #include "internal_native_display.h" #include "linux_virtual_terminal.h" #include "mir/graphics/platform_ipc_package.h" #include "mir/graphics/buffer_ipc_packer.h" #include "mir/options/option.h" #include "mir/graphics/native_buffer.h" #include "drm_close_threadsafe.h" #include #include #include #include namespace mg = mir::graphics; namespace mgm = mg::mesa; namespace mo = mir::options; namespace { struct MesaPlatformIPCPackage : public mg::PlatformIPCPackage { MesaPlatformIPCPackage(int drm_auth_fd) { ipc_fds.push_back(drm_auth_fd); } ~MesaPlatformIPCPackage() { if (ipc_fds.size() > 0 && ipc_fds[0] >= 0) mgm::drm_close_threadsafe(ipc_fds[0]); } }; 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(); } }; } std::shared_ptr mgm::Platform::internal_native_display; bool mgm::Platform::internal_display_clients_present; mgm::Platform::Platform(std::shared_ptr const& listener, std::shared_ptr const& vt) : udev{std::make_shared()}, listener{listener}, vt{vt} { drm.setup(udev); gbm.setup(drm); internal_display_clients_present = false; } mgm::Platform::~Platform() { internal_native_display.reset(); internal_display_clients_present = false; } std::shared_ptr mgm::Platform::create_buffer_allocator( const std::shared_ptr& buffer_initializer) { return std::make_shared(gbm.device, buffer_initializer); } std::shared_ptr mgm::Platform::create_display( std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config) { return std::make_shared( this->shared_from_this(), initial_conf_policy, gl_config, listener); } std::shared_ptr mgm::Platform::get_ipc_package() { return std::make_shared(drm.get_authenticated_fd()); } void mgm::Platform::fill_ipc_package(BufferIPCPacker* packer, Buffer const* buffer) const { auto native_handle = buffer->native_buffer_handle(); for(auto i=0; idata_items; i++) { packer->pack_data(native_handle->data[i]); } for(auto i=0; ifd_items; i++) { packer->pack_fd(native_handle->fd[i]); } packer->pack_stride(buffer->stride()); packer->pack_flags(native_handle->flags); packer->pack_size(buffer->size()); } void mgm::Platform::drm_auth_magic(unsigned int magic) { drm.auth_magic(magic); } std::shared_ptr mgm::Platform::create_internal_client() { if (!internal_native_display) internal_native_display = std::make_shared(get_ipc_package()); internal_display_clients_present = true; return std::make_shared(internal_native_display); } EGLNativeDisplayType mgm::Platform::egl_native_display() const { return gbm.device; } extern "C" std::shared_ptr mg::create_platform(std::shared_ptr const& options, std::shared_ptr const& report) { 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"), // TODO This option is mesa specific report); return std::make_shared(report, vt); } extern "C" int mir_server_mesa_egl_native_display_is_valid(MirMesaEGLNativeDisplay* display) { bool nested_internal_display_in_use = mgm::NativePlatform::internal_native_display_in_use(); bool host_internal_display_in_use = mgm::Platform::internal_display_clients_present; if (host_internal_display_in_use) return (display == mgm::Platform::internal_native_display.get()); else if (nested_internal_display_in_use) return (display == mgm::NativePlatform::internal_native_display().get()); return 0; } extern "C" void add_platform_options(boost::program_options::options_description& config) { config.add_options() ("vt", boost::program_options::value()->default_value(0), "[platform-specific] VT to run on or 0 to use current."); } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/native_platform.cpp0000644000015301777760000001107512322054223025736 0ustar pbusernogroup00000000000000/* * 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 "native_platform.h" #include "buffer_allocator.h" #include "mir/graphics/buffer_ipc_packer.h" #include "mir/graphics/platform_ipc_package.h" #include "mir/graphics/nested_context.h" #include "internal_client.h" #include "internal_native_display.h" #include #include #include #include namespace mg = mir::graphics; namespace mgm = mg::mesa; void mgm::NativePlatform::initialize( std::shared_ptr const& nested_context_arg) { nested_context = nested_context_arg; auto fds = nested_context->platform_fd_items(); drm_fd = fds.at(0); gbm.setup(drm_fd); nested_context->drm_set_gbm_device(gbm.device); } mgm::NativePlatform::~NativePlatform() { finish_internal_native_display(); } std::shared_ptr mgm::NativePlatform::create_buffer_allocator( std::shared_ptr const& buffer_initializer) { return std::make_shared(gbm.device, buffer_initializer); } std::shared_ptr mgm::NativePlatform::get_ipc_package() { struct MesaNativePlatformIPCPackage : public mg::PlatformIPCPackage { MesaNativePlatformIPCPackage(int fd) { ipc_fds.push_back(fd); } }; char* busid = drmGetBusid(drm_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); free(busid); 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)); } nested_context->drm_auth_magic(magic); return std::make_shared(auth_fd); } std::shared_ptr mgm::NativePlatform::create_internal_client() { auto nd = ensure_internal_native_display(get_ipc_package()); return std::make_shared(nd); } void mgm::NativePlatform::fill_ipc_package(BufferIPCPacker* packer, Buffer const* buffer) const { auto native_handle = buffer->native_buffer_handle(); for(auto i=0; idata_items; i++) { packer->pack_data(native_handle->data[i]); } for(auto i=0; ifd_items; i++) { packer->pack_fd(native_handle->fd[i]); } packer->pack_stride(buffer->stride()); packer->pack_flags(native_handle->flags); packer->pack_size(buffer->size()); } extern "C" std::shared_ptr create_native_platform(std::shared_ptr const& /*report*/) { return std::make_shared(); } namespace { std::shared_ptr native_display = nullptr; std::mutex native_display_guard; } bool mgm::NativePlatform::internal_native_display_in_use() { std::unique_lock lg(native_display_guard); return native_display != nullptr; } std::shared_ptr mgm::NativePlatform::internal_native_display() { std::unique_lock lg(native_display_guard); return native_display; } std::shared_ptr mgm::NativePlatform::ensure_internal_native_display( std::shared_ptr const& package) { std::unique_lock lg(native_display_guard); if (!native_display) native_display = std::make_shared(package); return native_display; } void mgm::NativePlatform::finish_internal_native_display() { std::unique_lock lg(native_display_guard); native_display.reset(); } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/internal_native_display.h0000644000015301777760000000261512322054223027120 0ustar pbusernogroup00000000000000/* * 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 * Kevin DuBois */ #ifndef MIR_GRAPHICS_MESA_INTERNAL_NATIVE_DISPLAY_H_ #define MIR_GRAPHICS_MESA_INTERNAL_NATIVE_DISPLAY_H_ #include "mir_toolkit/mesa/native_display.h" #include namespace mir { namespace graphics { struct PlatformIPCPackage; namespace mesa { class InternalNativeDisplay : public MirMesaEGLNativeDisplay { public: InternalNativeDisplay(std::shared_ptr const& platform_package); private: static int native_display_get_platform(MirMesaEGLNativeDisplay* display, MirPlatformPackage* package); std::shared_ptr platform_package; }; } } } #endif /* MIR_GRAPHICS_MESA_INTERNAL_NATIVE_DISPLAY_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/display_helpers.cpp0000644000015301777760000003116212322054247025740 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/gl_config.h" #include "mir/udev/wrapper.h" #include #include #include #include #include #include #include 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")); } int mgmh::DRMHelper::get_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")); 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); free(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)); } return auth_fd; } void mgmh::DRMHelper::auth_magic(drm_magic_t magic) 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 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(-ret)); } } 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(-ret)); } } 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) { DRMModeResources resources{fd}; int n_connected = 0; resources.for_each_connector([&](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"); devices.match_sysname("card[0-9]*"); devices.scan_devices(); for(auto& device : devices) { if ((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; } // 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; } 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) { static const EGLint context_attr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, 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(std::runtime_error("Failed to create EGL context")); } void mgmh::EGLHelper::setup(GBMHelper const& gbm, EGLContext shared_context) { static const EGLint context_attr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, 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(std::runtime_error("Failed to create EGL context")); } void mgmh::EGLHelper::setup(GBMHelper const& gbm, gbm_surface* surface_gbm, EGLContext shared_context) { static const EGLint context_attr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, 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(std::runtime_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(std::runtime_error("Failed to create EGL context")); } mgmh::EGLHelper::~EGLHelper() noexcept { if (egl_display != EGL_NO_DISPLAY) { if (egl_context != EGL_NO_CONTEXT) { 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); 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, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 0, EGL_DEPTH_SIZE, depth_buffer_bits, EGL_STENCIL_SIZE, stencil_buffer_bits, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_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(std::runtime_error("Failed to get EGL display")); if (initialize) { EGLint major, minor; if (eglInitialize(egl_display, &major, &minor) == EGL_FALSE) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize EGL display")); if ((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; } eglBindAPI(EGL_OPENGL_ES_API); if (eglChooseConfig(egl_display, config_attr, &egl_config, 1, &num_egl_configs) == EGL_FALSE || num_egl_configs != 1) { BOOST_THROW_EXCEPTION(std::runtime_error("Failed to choose ARGB EGL config")); } } void mgmh::EGLHelper::report_egl_configuration(std::function f) { f(egl_display, egl_config); } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/internal_client.cpp0000644000015301777760000000250412322054223025713 0ustar pbusernogroup00000000000000/* * 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 "internal_client.h" namespace mg=mir::graphics; namespace mgm=mir::graphics::mesa; mgm::InternalClient::InternalClient(std::shared_ptr const& native_display) : native_display(native_display) { } EGLNativeDisplayType mgm::InternalClient::egl_native_display() { return reinterpret_cast(native_display.get()); } EGLNativeWindowType mgm::InternalClient::egl_native_window(std::shared_ptr const& surface) { if (!client_window) { client_window = std::make_shared(surface); } return client_window.get(); } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/display.cpp0000644000015301777760000002564412322054247024226 0ustar pbusernogroup00000000000000/* * 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/display_report.h" #include "mir/graphics/gl_context.h" #include "mir/graphics/display_configuration_policy.h" #include "mir/geometry/rectangle.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 mg::GLContext { 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& platform, std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config, std::shared_ptr const& listener) : platform(platform), listener(listener), monitor(mir::udev::Context()), shared_egl{*gl_config}, output_container{platform->drm.fd, std::make_shared(platform->drm.fd)}, current_display_configuration{platform->drm.fd}, gl_config{gl_config} { platform->vt->set_graphics_mode(); shared_egl.setup(platform->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_buffer( 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}; /* Give back a copy of the latest configuration information */ current_display_configuration.update(); 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 lg{configuration_mutex}; auto const& kms_conf = dynamic_cast(conf); std::vector> display_buffers_new; /* * 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{conf}; 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); kms_output->set_power_mode(conf_output.power_mode); kms_outputs.push_back(kms_output); /* * Presently OverlappingOutputGroup guarantees all grouped * outputs have the same orientation. */ orientation = conf_output.orientation; }); 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 = platform->gbm.create_scanout_surface(width, height); std::unique_ptr db{ new DisplayBuffer{platform, listener, kms_outputs, std::move(surface), bounding_rect, orientation, *gl_config, shared_egl.context()}}; display_buffers_new.push_back(std::move(db)); }); display_buffers = std::move(display_buffers_new); /* Store applied configuration */ current_display_configuration = kms_conf; /* Clear connected but unused outputs */ clear_connected_unused_outputs(); } if (cursor) cursor->show_at_last_known_position(); } void mgm::Display::register_configuration_change_handler( EventHandlerRegister& handlers, DisplayConfigurationChangeHandler const& conf_change_handler) { handlers.register_fd_handler( {monitor.fd()}, [conf_change_handler, this](int) { monitor.process_events([conf_change_handler] (mir::udev::Monitor::EventType, mir::udev::Device const&) { conf_change_handler(); }); }); } void mgm::Display::register_pause_resume_handlers( EventHandlerRegister& handlers, DisplayPauseHandler const& pause_handler, DisplayResumeHandler const& resume_handler) { platform->vt->register_switch_handlers(handlers, pause_handler, resume_handler); } void mgm::Display::pause() { try { if (cursor) cursor->hide(); platform->drm.drop_master(); } catch(std::runtime_error const& e) { listener->report_drm_master_failure(errno_from_exception(e)); throw; } } void mgm::Display::resume() { try { platform->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 (cursor) cursor->show_at_last_known_position(); } auto mgm::Display::the_cursor() -> std::weak_ptr { if (!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; }; cursor = std::make_shared(platform->gbm.device, output_container, std::make_shared(*this)); } return cursor; } std::unique_ptr mgm::Display::create_gl_context() { return std::unique_ptr{ new GBMGLContext{ platform->gbm, *gl_config, shared_egl.context()}}; } void mgm::Display::clear_connected_unused_outputs() { current_display_configuration.for_each_output([&](DisplayConfigurationOutput const& conf_output) { if (conf_output.connected && !conf_output.used) { 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(); } }); } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/page_flipper.h0000644000015301777760000000236612322054223024651 0ustar pbusernogroup00000000000000/* * 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 namespace mir { namespace graphics { namespace mesa { class PageFlipper { public: virtual ~PageFlipper() {} virtual bool schedule_flip(uint32_t crtc_id, uint32_t fb_id) = 0; virtual void 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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/native_platform.h0000644000015301777760000000376512322054223025412 0ustar pbusernogroup00000000000000/* * 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_NATIVE_PLATFORM_H_ #define MIR_GRAPHICS_MESA_NATIVE_PLATFORM_H_ #include "mir/graphics/native_platform.h" #include "display_helpers.h" namespace mir { namespace graphics { namespace mesa { class InternalNativeDisplay; class NativePlatform : public graphics::NativePlatform { public: virtual ~NativePlatform(); void initialize(std::shared_ptr const& nested_context); std::shared_ptr create_buffer_allocator( std::shared_ptr const& buffer_initializer) override; std::shared_ptr get_ipc_package() override; std::shared_ptr create_internal_client() override; void fill_ipc_package(BufferIPCPacker* packer, Buffer const* buffer) const override; static std::shared_ptr internal_native_display(); static bool internal_native_display_in_use(); private: int drm_fd; std::shared_ptr nested_context; helpers::GBMHelper gbm; static std::shared_ptr ensure_internal_native_display(std::shared_ptr const& package); static void finish_internal_native_display(); }; } } } #endif // MIR_GRAPHICS_MESA_NATIVE_PLATFORM_H_ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/anonymous_shm_file.h0000644000015301777760000000327112322054223026106 0ustar pbusernogroup00000000000000/* * 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" namespace mir { namespace graphics { namespace mesa { namespace detail { class FdHandle { public: FdHandle(int fd); FdHandle(FdHandle&&); ~FdHandle() noexcept; operator int() const; private: FdHandle(FdHandle const&) = delete; FdHandle& operator=(FdHandle const&) = delete; int fd; }; 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: detail::FdHandle const fd_; detail::MapHandle const mapping; }; } } } #endif /* MIR_GRAPHICS_MESA_ANONYMOUS_SHM_FILE_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/buffer_allocator.h0000644000015301777760000000401112322054223025512 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/graphic_buffer_allocator.h" #include "mir/graphics/buffer_id.h" #pragma GCC diagnostic push #pragma GCC diagnostic warning "-Wall" #include #pragma GCC diagnostic pop #include namespace mir { namespace graphics { class BufferInitializer; struct EGLExtensions; namespace mesa { class BufferAllocator: public graphics::GraphicBufferAllocator { public: BufferAllocator(gbm_device* device, std::shared_ptr const& buffer_initializer); virtual std::shared_ptr alloc_buffer( graphics::BufferProperties const& buffer_properties); std::vector supported_pixel_formats(); private: bool is_pixel_format_supported(MirPixelFormat format); std::shared_ptr alloc_hardware_buffer( graphics::BufferProperties const& buffer_properties); std::shared_ptr alloc_software_buffer( graphics::BufferProperties const& buffer_properties); gbm_device* const device; std::shared_ptr buffer_initializer; std::shared_ptr const egl_extensions; bool bypass_env; }; } } } #endif // MIR_GRAPHICS_MESA_BUFFER_ALLOCATOR_H_ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/real_kms_output.cpp0000644000015301777760000002524412322054223025764 0ustar pbusernogroup00000000000000/* * 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 #include #include #include namespace mg = mir::graphics; namespace mgm = mg::mesa; namespace geom = mir::geometry; namespace { bool encoder_is_used(mgm::DRMModeResources const& resources, uint32_t encoder_id) { bool encoder_used{false}; resources.for_each_connector([&](mgm::DRMModeConnectorUPtr connector) { if (connector->encoder_id == encoder_id && connector->connection == DRM_MODE_CONNECTED) { auto encoder = resources.encoder(connector->encoder_id); if (encoder) { auto crtc = resources.crtc(encoder->crtc_id); if (crtc) encoder_used = true; } } }); return encoder_used; } bool crtc_is_used(mgm::DRMModeResources const& resources, uint32_t crtc_id) { bool crtc_used{false}; resources.for_each_connector([&](mgm::DRMModeConnectorUPtr connector) { if (connector->connection == DRM_MODE_CONNECTED) { auto encoder = resources.encoder(connector->encoder_id); if (encoder) { if (encoder->crtc_id == crtc_id) crtc_used = true; } } }); return crtc_used; } std::vector connector_available_encoders(mgm::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)); } const char *connector_type_name(uint32_t type) { static const int nnames = 15; static const char * const names[nnames] = { // Ordered according to xf86drmMode.h "Unknown", "VGA", "DVII", "DVID", "DVIA", "Composite", "SVIDEO", "LVDS", "Component", "9PinDIN", "DisplayPort", "HDMIA", "HDMIB", "TV", "eDP" }; if (type >= nnames) type = 0; return names[type]; } std::string connector_name(const drmModeConnector *conn) { std::string name = connector_type_name(conn->connector_type); name += '-'; name += std::to_string(conn->connector_type_id); return name; } } 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(); DRMModeResources resources{drm_fd}; auto encoder = resources.encoder(connector->encoder_id); if (encoder) { auto crtc = resources.crtc(encoder->crtc_id); if (crtc) saved_crtc = *crtc; } } mgm::RealKMSOutput::~RealKMSOutput() { restore_saved_crtc(); } void mgm::RealKMSOutput::reset() { DRMModeResources resources{drm_fd}; /* Update the connector to ensure we have the latest information */ connector = resources.connector(connector_id); if (!connector) BOOST_THROW_EXCEPTION(std::runtime_error("No DRM connector found\n")); // 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}; } 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()) BOOST_THROW_EXCEPTION(std::runtime_error("Output " + connector_name(connector.get()) + " has no associated CRTC to set a framebuffer on")); 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() { /* * 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. */ if (!ensure_crtc()) return; auto result = drmModeSetCrtc(drm_fd, current_crtc->crtc_id, 0, 0, 0, nullptr, 0, nullptr); if (result) { std::string const msg = "Couldn't clear output " + connector_name(connector.get()); BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error(msg)) << (boost::error_info(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) BOOST_THROW_EXCEPTION(std::runtime_error("Output " + connector_name(connector.get()) + " has no associated CRTC to schedule page flips on")); return page_flipper->schedule_flip(current_crtc->crtc_id, fb_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) BOOST_THROW_EXCEPTION(std::runtime_error("Output " + connector_name(connector.get()) + " has no associated CRTC to wait on")); page_flipper->wait_for_flip(current_crtc->crtc_id); } void mgm::RealKMSOutput::set_cursor(gbm_bo* buffer) { if (current_crtc) { 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))) { BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error("drmModeSetCursor() failed")) << (boost::error_info(result))); } has_cursor_ = true; } } 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())) { BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error("drmModeMoveCursor() failed")) << (boost::error_info(result))); } } } void mgm::RealKMSOutput::clear_cursor() { if (current_crtc) { drmModeSetCursor(drm_fd, current_crtc->crtc_id, 0, 0, 0); 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; DRMModeResources resources{drm_fd}; /* Check to see if there is a crtc already connected */ auto encoder = resources.encoder(connector->encoder_id); if (encoder) current_crtc = resources.crtc(encoder->crtc_id); /* If we don't have a current crtc, try to find one */ if (!current_crtc) { auto available_encoders = connector_available_encoders(resources, connector.get()); int crtc_index = 0; resources.for_each_crtc([&](DRMModeCrtcUPtr crtc) { if (!current_crtc && !crtc_is_used(resources, crtc->crtc_id)) { for (auto& enc : available_encoders) { if (encoder_supports_crtc_index(enc.get(), crtc_index)) { current_crtc = std::move(crtc); break; } } } crtc_index++; }); } 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); } } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/linux_virtual_terminal.cpp0000644000015301777760000002140412322054223027341 0ustar pbusernogroup00000000000000/* * 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) { 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); } } 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}, [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)); } } 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; } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/linux_virtual_terminal.h0000644000015301777760000000675512322054223027022 0ustar pbusernogroup00000000000000/* * 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(); void register_switch_handlers( EventHandlerRegister& handlers, std::function const& switch_away, std::function const& switch_back); 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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/real_kms_display_configuration.cpp0000644000015301777760000001713012322054223031013 0ustar pbusernogroup00000000000000/* * 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 "drm_mode_resources.h" #include "mir/graphics/pixel_format_utils.h" #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; 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 vrefresh_hz = mode.clock * 1000.0 / (mode.htotal * mode.vtotal); /* Round to first decimal */ return round(vrefresh_hz * 10.0) / 10.0; } mg::DisplayConfigurationOutputType kms_connector_type_to_output_type(uint32_t connector_type) { return static_cast(connector_type); } } 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); } } 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() { 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([&](DRMModeConnectorUPtr connector) { add_or_update_output(resources, *connector); }); } void mgm::RealKMSDisplayConfiguration::add_or_update_output( 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}; size_t current_mode_index{std::numeric_limits::max()}; size_t preferred_mode_index{std::numeric_limits::max()}; std::vector modes; std::vector formats {mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888}; drmModeModeInfo current_mode_info = drmModeModeInfo(); /* Get information about the current mode */ auto encoder = resources.encoder(connector.encoder_id); if (encoder) { auto crtc = resources.crtc(encoder->crtc_id); if (crtc) current_mode_info = 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); 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}); } else { auto& output = *iter; output.modes = modes; output.preferred_mode_index = preferred_mode_index; output.physical_size_mm = physical_size; output.connected = connected; output.current_mode_index = current_mode_index; output.current_format = mir_pixel_format_xrgb_8888; } } 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; }); } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/real_kms_output_container.h0000644000015301777760000000273512322054223027473 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/virtual_terminal.h0000644000015301777760000000266012322054223025572 0ustar pbusernogroup00000000000000/* * 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; protected: VirtualTerminal() = default; VirtualTerminal(VirtualTerminal const&) = delete; VirtualTerminal& operator=(VirtualTerminal const&) = delete; }; } } } #endif /* MIR_GRAPHICS_MESA_VIRTUAL_TERMINAL_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/real_kms_output.h0000644000015301777760000000415212322054223025424 0ustar pbusernogroup00000000000000/* * 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 "kms_output.h" #include "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(); void configure(geometry::Displacement fb_offset, size_t kms_mode_index); geometry::Size size() const; bool set_crtc(uint32_t fb_id); void clear_crtc(); bool schedule_page_flip(uint32_t fb_id); void wait_for_page_flip(); void set_cursor(gbm_bo* buffer); void move_cursor(geometry::Point destination); void clear_cursor(); bool has_cursor() const; void set_power_mode(MirPowerMode mode); private: bool ensure_crtc(); void restore_saved_crtc(); int const drm_fd; uint32_t const connector_id; std::shared_ptr const page_flipper; DRMModeConnectorUPtr connector; size_t mode_index; geometry::Displacement fb_offset; DRMModeCrtcUPtr current_crtc; drmModeCrtc saved_crtc; bool using_saved_crtc; bool has_cursor_; MirPowerMode power_mode; int dpms_enum_id; std::mutex power_mutex; }; } } } #endif /* MIR_GRAPHICS_MESA_REAL_KMS_OUTPUT_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/drm_mode_resources.h0000644000015301777760000000375212322054223026074 0ustar pbusernogroup00000000000000/* * 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_MODE_RESOURCES_H_ #define MIR_GRAPHICS_MESA_DRM_MODE_RESOURCES_H_ #include #include #include #include namespace mir { namespace graphics { namespace mesa { typedef std::unique_ptr> DRMModeCrtcUPtr; typedef std::unique_ptr> DRMModeEncoderUPtr; typedef std::unique_ptr> DRMModeConnectorUPtr; typedef std::unique_ptr> DRMModeResUPtr; 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(); size_t num_encoders(); size_t num_crtcs(); DRMModeConnectorUPtr connector(uint32_t id) const; DRMModeEncoderUPtr encoder(uint32_t id) const; DRMModeCrtcUPtr crtc(uint32_t id) const; private: int const drm_fd; DRMModeResUPtr const resources; }; } } } #endif /* MIR_GRAPHICS_MESA_DRM_MODE_RESOURCES_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/buffer_texture_binder.h0000644000015301777760000000234112322054223026561 0ustar pbusernogroup00000000000000/* * 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 mesa { class BufferTextureBinder { public: virtual ~BufferTextureBinder() {} virtual void bind_to_texture() = 0; protected: BufferTextureBinder() = default; BufferTextureBinder(BufferTextureBinder const&) = delete; BufferTextureBinder& operator=(BufferTextureBinder const&) = delete; }; } } } #endif /* MIR_GRAPHICS_MESA_BUFFER_TEXTURE_BINDER_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/shm_buffer.cpp0000644000015301777760000000435012322054223024662 0ustar pbusernogroup00000000000000/* * 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 #include namespace mgm = mir::graphics::mesa; namespace geom = mir::geometry; mgm::ShmBuffer::ShmBuffer( std::shared_ptr const& shm_file, geom::Size const& size, MirPixelFormat const& pixel_format) : shm_file{shm_file}, size_{size}, pixel_format_{pixel_format}, stride_{MIR_BYTES_PER_PIXEL(pixel_format_) * size_.width.as_uint32_t()}, pixels{shm_file->base_ptr()} { } mgm::ShmBuffer::~ShmBuffer() noexcept { } geom::Size mgm::ShmBuffer::size() const { return size_; } geom::Stride mgm::ShmBuffer::stride() const { return stride_; } MirPixelFormat mgm::ShmBuffer::pixel_format() const { return pixel_format_; } void mgm::ShmBuffer::bind_to_texture() { glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, size_.width.as_int(), size_.height.as_int(), 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels); } std::shared_ptr mgm::ShmBuffer::native_buffer_handle() 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; } bool mgm::ShmBuffer::can_bypass() const { return false; } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/anonymous_shm_file.cpp0000644000015301777760000000564112322054223026444 0ustar pbusernogroup00000000000000/* * 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 namespace mgm = mir::graphics::mesa; namespace { mgm::detail::FdHandle create_anonymous_file(size_t size) { char const* const tmpl = "/mir-buffer-XXXXXX"; char const* const runtime_dir = getenv("XDG_RUNTIME_DIR"); char const* const target_dir = runtime_dir ? runtime_dir : "/tmp"; /* We need a mutable array for mkostemp */ std::vector path(target_dir, target_dir + strlen(target_dir)); path.insert(path.end(), tmpl, tmpl + strlen(tmpl)); path.push_back('\0'); mgm::detail::FdHandle fd{mkostemp(path.data(), O_CLOEXEC)}; if (unlink(path.data()) < 0) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to unlink temporary file")); if (ftruncate(fd, size) < 0) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to resize temporary file")); return fd; } } /************* * FdHandle * *************/ mgm::detail::FdHandle::FdHandle(int fd) : fd{fd} { if (fd < 0) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create file")); } mgm::detail::FdHandle::FdHandle(FdHandle&& other) : fd{other.fd} { other.fd = -1; } mgm::detail::FdHandle::~FdHandle() noexcept { if (fd >= 0) close(fd); } mgm::detail::FdHandle::operator int() const { return fd; } /************* * MapHandle * *************/ mgm::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::runtime_error("Failed to map file")); } mgm::detail::MapHandle::~MapHandle() noexcept { munmap(mapping, size); } mgm::detail::MapHandle::operator void*() const { return mapping; } /******************** * AnonymousShmFile * ********************/ mgm::AnonymousShmFile::AnonymousShmFile(size_t size) : fd_{create_anonymous_file(size)}, mapping{fd_, size} { } void* mgm::AnonymousShmFile::base_ptr() const { return mapping; } int mgm::AnonymousShmFile::fd() const { return fd_; } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/cursor.h0000644000015301777760000000513112322054223023522 0ustar pbusernogroup00000000000000/* * 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_toolkit/common.h" #include #include namespace mir { namespace geometry { struct Rectangle; } namespace graphics { 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); ~Cursor() noexcept; void set_image(const void* raw_argb, geometry::Size size); void move_to(geometry::Point position); void show_at_last_known_position(); void hide(); private: enum ForceCursorState { UpdateState, ForceState }; void for_each_used_output(std::function const& f); void place_cursor_at(geometry::Point position, ForceCursorState force_state); KMSOutputContainer& output_container; geometry::Point current_position; struct GBMBOWrapper { GBMBOWrapper(gbm_device* gbm); operator gbm_bo*(); ~GBMBOWrapper(); private: gbm_bo* buffer; GBMBOWrapper(GBMBOWrapper const&) = delete; GBMBOWrapper& operator=(GBMBOWrapper const&) = delete; } buffer; std::shared_ptr const current_configuration; }; } } } #endif /* MIR_GRAPHICS_MESA_CURSOR_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/cursor.cpp0000644000015301777760000001235612322054223024064 0ustar pbusernogroup00000000000000/* * 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 #include #include namespace mgm = mir::graphics::mesa; namespace geom = mir::geometry; namespace { #include "black_arrow.c" int const width = black_arrow.width; int const height = black_arrow.height; // 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; } } } mgm::Cursor::GBMBOWrapper::GBMBOWrapper(gbm_device* gbm) : buffer(gbm_bo_create( gbm, width, height, GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR_64X64 | 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) : output_container(output_container), current_position(), buffer(gbm), current_configuration(current_configuration) { set_image(black_arrow.pixel_data, geometry::Size{width, height}); show_at_last_known_position(); } mgm::Cursor::~Cursor() noexcept { hide(); } void mgm::Cursor::set_image(const void* raw_argb, geometry::Size size) { if (size != geometry::Size{width, height}) BOOST_THROW_EXCEPTION(std::logic_error("No support for cursors that aren't 64x64")); auto const count = size.width.as_uint32_t() * size.height.as_uint32_t() * sizeof(uint32_t); if (auto result = gbm_bo_write(buffer, raw_argb, count)) { BOOST_THROW_EXCEPTION( ::boost::enable_error_info(std::runtime_error("failed to initialize gbm buffer")) << (boost::error_info(result))); } } void mgm::Cursor::move_to(geometry::Point position) { place_cursor_at(position, UpdateState); } void mgm::Cursor::show_at_last_known_position() { place_cursor_at(current_position, ForceState); } void mgm::Cursor::hide() { 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) { 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); output.move_cursor({dp.dx.as_int(), dp.dy.as_int()}); if (force_state || !output.has_cursor()) // TODO - or if orientation had changed - then set buffer.. { output.set_cursor(buffer);// TODO - select rotated buffer image } } else { if (force_state || output.has_cursor()) { output.clear_cursor(); } } }); current_position = position; } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/internal_client.h0000644000015301777760000000270412322054223025362 0ustar pbusernogroup00000000000000/* * 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_INTERNAL_CLIENT_H_ #define MIR_GRAPHICS_MESA_INTERNAL_CLIENT_H_ #include "mir/graphics/internal_client.h" #include "internal_native_display.h" #include "internal_native_surface.h" #include namespace mir { namespace graphics { class Platform; namespace mesa { class InternalClient : public mir::graphics::InternalClient { public: InternalClient(std::shared_ptr const&); EGLNativeDisplayType egl_native_display(); EGLNativeWindowType egl_native_window(std::shared_ptr const&); private: std::shared_ptr const native_display; std::shared_ptr client_window; }; } } } #endif /* MIR_GRAPHICS_MESA_INTERNAL_CLIENT_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/shm_buffer.h0000644000015301777760000000343412322054223024331 0ustar pbusernogroup00000000000000/* * 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" namespace mir { namespace graphics { namespace mesa { class ShmFile; class ShmBuffer : public BufferBasic { public: ShmBuffer(std::shared_ptr const& shm_file, geometry::Size const& size, MirPixelFormat const& pixel_format); ~ShmBuffer() noexcept; geometry::Size size() const; geometry::Stride stride() const; MirPixelFormat pixel_format() const; std::shared_ptr native_buffer_handle() const; void bind_to_texture(); bool can_bypass() const; private: ShmBuffer(ShmBuffer const&) = delete; ShmBuffer& operator=(ShmBuffer const&) = delete; std::shared_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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/internal_native_surface.h0000644000015301777760000000334212322054223027101 0ustar pbusernogroup00000000000000/* * 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_INTERNAL_NATIVE_SURFACE_H_ #define MIR_GRAPHICS_MESA_INTERNAL_NATIVE_SURFACE_H_ #include "mir_toolkit/mesa/native_display.h" #include namespace mir { namespace graphics { class InternalSurface; class Buffer; namespace mesa { class InternalNativeSurface : public MirMesaEGLNativeSurface { public: InternalNativeSurface(std::shared_ptr const& surface); int advance_buffer(MirBufferPackage* package); int get_parameters(MirSurfaceParameters* parameters); private: static int set_swapinterval_static(MirMesaEGLNativeSurface* surface, int interval); static int advance_buffer_static(MirMesaEGLNativeSurface* surface, MirBufferPackage* package); static int get_parameters_static(MirMesaEGLNativeSurface* surface, MirSurfaceParameters* parameters); std::shared_ptr surface; graphics::Buffer* current_buffer; }; } } } #endif /* MIR_GRAPHICS_MESA_INTERNAL_NATIVE_DISPLAY_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/black_arrow.c0000644000015301777760000010712512322054223024474 0ustar pbusernogroup00000000000000/* GIMP RGBA C-Source image dump (black_arrow.c) */ static const struct { unsigned int width; unsigned int height; unsigned int bytes_per_pixel; /* 2:RGB16, 3:RGB, 4:RGBA */ unsigned char pixel_data[64 * 64 * 4 + 1]; } black_arrow = { 64, 64, 4, "\0\0\0\4\371\371\371\227\\\\\\\31\0\0\0\7\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\10\377\377\377\277\347\347\347\235///$\0\0\0\10\0" "\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377\377\377\277\377\377\377" "\277\337\337\337\235!!!\"\0\0\0\10\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\12\377\377\377\277\231\231\231\277\365\365\365\276\332\332\332\232\30\30" "\30\37\0\0\0\7\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377\377\377\277aaa\277RR" "R\277\367\367\367\276\330\330\330\224\15\15\15\35\0\0\0\7\0\0\0\1\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\12\377\377\377\277___\277\23\23\23\277\\\\\\\277\372\372\372\276\324" "\324\324\217\6\6\6\34\0\0\0\7\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377\377\377\277\\\\\\\277\20" "\20\20\277\31\31\31\277fff\277\373\373\373\276\317\317\317\212\0\0\0\31\0" "\0\0\6\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\12\377\377\377\277YYY\277\14\14\14\277\25\25\25\277\36\36\36" "\277rrr\277\375\375\375\277\312\312\312\204\0\0\0\30\0\0\0\7\0\0\0\1\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377\377\377" "\277XXX\277\10\10\10\277\21\21\21\277\32\32\32\277$$$\277|||\277\376\376" "\376\277\305\305\305~\0\0\0\30\0\0\0\5\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377\377\377\277XXX\277\4\4\4\277\15\15\15" "\277\26\26\26\277\40\40\40\277)))\277\210\210\210\277\377\377\377\277\277" "\277\277x\0\0\0\26\0\0\0\5\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\12\377\377\377\277XXX\277\0\0\0\277\11\11\11\277\22\22\22\277\34" "\34\34\277%%%\277///\277\222\222\222\277\377\377\377\277\272\272\272r\0\0" "\0\26\0\0\0\5\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377\377\377" "\277XXX\277\0\0\0\277\5\5\5\277\16\16\16\277\30\30\30\277!!!\277+++\2774" "44\277\234\234\234\277\376\376\376\277\262\262\262l\0\0\0\25\0\0\0\4\0\0" "\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377\377\377\277XXX\277\0\0\0\277\1" "\1\1\277\12\12\12\277\24\24\24\277\35\35\35\277'''\277000\277999\277\247" "\247\247\277\375\375\375\276\254\254\254f\0\0\0\23\0\0\0\4\0\0\0\1\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\12\377\377\377\277XXX\277\0\0\0\277\0\0\0\277\7\7\7\277" "\20\20\20\277\31\31\31\277###\277,,,\277555\277???\277\260\260\260\277\374" "\374\374\276\246\246\246a\0\0\0\23\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377\377" "\377\277XXX\277\0\0\0\277\0\0\0\277\3\3\3\277\14\14\14\277\25\25\25\277\37" "\37\37\277(((\277111\277;;;\277EEE\277\266\266\266\277\373\373\373\276\236" "\236\236[\0\0\0\21\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377\377\377\277XXX\277\0\0\0" "\277\0\0\0\277\0\0\0\277\10\10\10\277\21\21\21\277\37\37\37\277aaa\277ii" "i\277ooo\277vvv\277}}}\277\341\341\341\277\373\373\373\275\231\231\231U\0" "\0\0\20\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\12\377\377\377\277XXX\277\0\0\0\277\0\0\0\277\0\0\0" "\277\4\4\4\277\15\15\15\277\27\27\27\277\314\314\314\277\377\377\377\277" "\377\377\377\277\377\377\377\277\377\377\377\277\377\377\377\277\377\377" "\377\277\372\372\372\273\230\230\230I\0\0\0\12\0\0\0\1\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377\377\377\277X" "XX\277\0\0\0\277\0\0\0\277\0\0\0\277[[[\277\20\20\20\277\23\23\23\277aaa" "\277\377\377\377\277\\\\\\|!!!\\$$$S%%%R&&&P***I***1\0\0\0\17\0\0\0\2\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377" "\377\377\277XXX\277\0\0\0\277\0\0\0\277mmm\277\376\376\376\277mmm\277\17" "\17\17\277\31\31\31\277\333\333\333\276\306\306\306\234\0\0\0""7\0\0\0\37" "\0\0\0\31\0\0\0\30\0\0\0\26\0\0\0\20\0\0\0\6\0\0\0\1\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377\377\377\277XXX" "\277\0\0\0\277uuu\277\377\377\377\277\345\345\345\262\342\342\342\276\20" "\20\20\277\24\24\24\277qqq\277\373\373\373\276JJJJ\0\0\0\23\0\0\0\4\0\0\0" "\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\12\377\377\377\277XXX\277~~~\277\377\377" "\377\277\232\232\232\214999a\372\372\372\276ggg\277\20\20\20\277\36\36\36" "\277\346\346\346\276\277\277\277\216\0\0\0\40\0\0\0\6\0\0\0\1\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\12\377\377\377\277\314\314\314\277\376\376\376\277\223" "\223\223\211\0\0\0F\0\0\0+\326\326\326\211\336\336\336\275\17\17\17\277\26" "\26\26\277\201\201\201\277\367\367\367\274444>\0\0\0\17\0\0\0\1\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\12\377\377\377\277\375\375\375\276\216\216\216\205\0" "\0\0D\0\0\0!\0\0\0\15\203\203\2030\374\374\374\276aaa\277\22\22\22\277%%" "%\277\370\370\370\276\230\230\230u\0\0\0\31\0\0\0\3\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\12\375\375\375\276\227\227\227v\0\0\0B\0\0\0\40\0\0\0\12\0\0\0\3" "\0\0\0\14\334\334\334\213\332\332\332\275\31\31\31\277444\277\371\371\371" "\276\231\231\231\177\0\0\0\37\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\10\302" "\302\302U\0\0\0.\0\0\0\36\0\0\0\10\0\0\0\1\0\0\0\1\0\0\0\4\220\220\2202\365" "\365\365\270\357\357\357\276\370\370\370\276\341\341\341\261888X\0\0\0\34" "\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\15\0\0\0\20\0\0\0\7\0\0\0" "\1\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\12aaa7\266\266\266\202\215\215\215{\34\34" "\34P\0\0\0.\0\0\0\16\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\3\0\0" "\0\2\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\14\0\0\0\33\0" "\0\0\"\0\0\0\34\0\0\0\15\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1" "\0\0\0\4\0\0\0\5\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", }; mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/internal_native_display.cpp0000644000015301777760000000341212322054223027447 0ustar pbusernogroup00000000000000/* * 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 "internal_native_display.h" #include "mir/graphics/platform_ipc_package.h" #include "mir_toolkit/mesa/native_display.h" namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; mgm::InternalNativeDisplay::InternalNativeDisplay(std::shared_ptr const& platform_package) : platform_package(platform_package) { context = this; this->display_get_platform = &InternalNativeDisplay::native_display_get_platform; } int mgm::InternalNativeDisplay::native_display_get_platform(MirMesaEGLNativeDisplay* display, MirPlatformPackage* package) { auto native_disp = static_cast(display); package->data_items = native_disp->platform_package->ipc_data.size(); for (int i = 0; i < package->data_items; i++) { package->data[i] = native_disp->platform_package->ipc_data[i]; } package->fd_items = native_disp->platform_package->ipc_fds.size(); for (int i = 0; i < package->fd_items; i++) { package->fd[i] = native_disp->platform_package->ipc_fds[i]; } return MIR_MESA_TRUE; } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/real_kms_display_configuration.h0000644000015301777760000000430012322054223030453 0ustar pbusernogroup00000000000000/* * 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 namespace mir { namespace graphics { namespace mesa { class RealKMSDisplayConfiguration : public KMSDisplayConfiguration { 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; 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(); private: void add_or_update_output(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; }; } } } #endif /* MIR_GRAPHICS_MESA_REAL_KMS_DISPLAY_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/platform.h0000644000015301777760000000505212322054247024041 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/drm_authenticator.h" #include "display_helpers.h" #include "mir_toolkit/mesa/native_display.h" namespace mir { namespace graphics { namespace mesa { class VirtualTerminal; class InternalNativeDisplay; class Platform : public graphics::Platform, public DRMAuthenticator, public std::enable_shared_from_this { public: explicit Platform(std::shared_ptr const& reporter, std::shared_ptr const& vt); ~Platform(); /* From Platform */ std::shared_ptr create_buffer_allocator( const std::shared_ptr& buffer_initializer); std::shared_ptr create_display( std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config); std::shared_ptr get_ipc_package(); std::shared_ptr create_internal_client(); void fill_ipc_package(BufferIPCPacker* packer, Buffer const* buffer) const; EGLNativeDisplayType egl_native_display() const; /* From DRMAuthenticator */ void drm_auth_magic(unsigned int magic); std::shared_ptr udev; helpers::DRMHelper drm; helpers::GBMHelper gbm; std::shared_ptr const listener; std::shared_ptr const vt; //connection shared by all internal clients static bool internal_display_clients_present; static std::shared_ptr internal_native_display; }; extern "C" int mir_server_mesa_egl_native_display_is_valid(MirMesaEGLNativeDisplay* display); } } } #endif /* MIR_GRAPHICS_MESA_PLATFORM_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/display_buffer.h0000644000015301777760000000552712322054247025222 0ustar pbusernogroup00000000000000/* * 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 "display_helpers.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: DisplayBuffer(std::shared_ptr const& platform, 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; void make_current(); void release_current(); void post_update(); bool can_bypass() const override; void post_update(std::shared_ptr bypass_buf) override; void render_and_post_update(RenderableList const& renderlist, std::function const& render_fn); MirOrientation orientation() const override; 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); BufferObject* last_flipped_bufobj; BufferObject* scheduled_bufobj; std::shared_ptr last_flipped_bypass_buf; std::shared_ptr const platform; std::shared_ptr const listener; /* DRM helper from mgm::Platform */ helpers::DRMHelper& drm; 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; bool page_flips_pending; }; } } } #endif /* MIR_GRAPHICS_MESA_DISPLAY_BUFFER_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/shm_file.h0000644000015301777760000000224712322054223024000 0ustar pbusernogroup00000000000000/* * 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 mesa { 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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/gbm_buffer.cpp0000644000015301777760000000731612322054223024645 0ustar pbusernogroup00000000000000/* * 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 #include #include #include #include namespace mgm=mir::graphics::mesa; namespace geom=mir::geometry; 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; 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; default: gbm_pf = mgm::invalid_gbm_format; break; } return gbm_pf; } 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( boost::enable_error_info( std::runtime_error(msg)) << boost::errinfo_errno(errno)); } } 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::bind_to_texture() { texture_binder->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 = can_bypass() ? 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; } bool mgm::GBMBuffer::can_bypass() const { return bo_flags & GBM_BO_USE_SCANOUT; } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/CMakeLists.txt0000644000015301777760000000366012322054247024607 0ustar pbusernogroup00000000000000include_directories( ${DRM_INCLUDE_DIRS} ${GBM_INCLUDE_DIRS} ${EGL_INCLUDE_DIRS} ${GLESv2_INCLUDE_DIRS} ${UDEV_INCLUDE_DIRS} ) # 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__) add_library( mirplatformgraphicsmesa SHARED platform.cpp buffer_allocator.cpp gbm_buffer.cpp cursor.cpp display_helpers.cpp display.cpp real_kms_display_configuration.cpp drm_mode_resources.cpp display_buffer.cpp real_kms_output.cpp real_kms_output_container.cpp kms_page_flipper.cpp linux_virtual_terminal.cpp internal_native_display.cpp internal_native_surface.cpp internal_client.cpp drm_close_threadsafe.cpp native_platform.cpp anonymous_shm_file.cpp shm_buffer.cpp ) set_target_properties( mirplatformgraphicsmesa PROPERTIES OUTPUT_NAME mirplatformgraphics LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}/mesa ) target_link_libraries( mirplatformgraphicsmesa mirplatform ${Boost_PROGRAM_OPTIONS_LIBRARY} ${DRM_LDFLAGS} ${DRM_LIBRARIES} ${GBM_LDFLAGS} ${GBM_LIBRARIES} ${EGL_LDFLAGS} ${EGL_LIBRARIES} ${GLESv2_LDFLAGS} ${GLESv2_LIBRARIES} ) install(TARGETS mirplatformgraphicsmesa LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mir/platformgraphics/mesa) if (MIR_TEST_PLATFORM STREQUAL "mesa") add_custom_command(TARGET mirplatformgraphicsmesa POST_BUILD COMMAND ${CMAKE_COMMAND} -E remove libmirplatformgraphics.so COMMAND ${CMAKE_COMMAND} -E create_symlink mesa/$ libmirplatformgraphics.so WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH} ) install(CODE "execute_process( COMMAND ln -sf mir/platformgraphics/mesa/libmirplatformgraphics.so WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} )" ) endif() mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/buffer_allocator.cpp0000644000015301777760000001616712322054223026064 0ustar pbusernogroup00000000000000/* * 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 "platform.h" #include "buffer_texture_binder.h" #include "anonymous_shm_file.h" #include "shm_buffer.h" #include "mir/graphics/buffer_initializer.h" #include "mir/graphics/egl_extensions.h" #include "mir/graphics/buffer_properties.h" #include #include #include #include #include #include #include #include #include namespace mg = mir::graphics; namespace mgm = mir::graphics::mesa; namespace geom = mir::geometry; namespace { class EGLImageBufferTextureBinder : public mgm::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 bind_to_texture() { ensure_egl_image(); egl_extensions->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image); } private: void ensure_egl_image() { if (egl_image == EGL_NO_IMAGE_KHR) { 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(std::runtime_error("Failed to create EGLImage from GBM bo")); } } std::shared_ptr const bo; std::shared_ptr const egl_extensions; EGLDisplay egl_display; EGLImageKHR egl_image; }; struct GBMBODeleter { void operator()(gbm_bo* handle) const { if (handle) gbm_bo_destroy(handle); } }; } mgm::BufferAllocator::BufferAllocator( gbm_device* device, const std::shared_ptr& buffer_initializer) : device(device), buffer_initializer(buffer_initializer), egl_extensions(std::make_shared()) { assert(buffer_initializer.get() != 0); const char *env = getenv("MIR_BYPASS"); bypass_env = env ? env[0] != '0' : true; } 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); 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); if (!is_pixel_format_supported(buffer_properties.format) || gbm_format == mgm::invalid_gbm_format) { BOOST_THROW_EXCEPTION( std::runtime_error("Trying to create GBM buffer with unsupported pixel 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: Be more intelligent about when to apply GBM_BO_USE_SCANOUT. That * may have to come after buffer reallocation support (surface * resizing). We may also want to check for * mir_surface_state_fullscreen later when it's fully wired up. */ if (bypass_env && buffer_properties.size.width.as_uint32_t() >= 800 && buffer_properties.size.height.as_uint32_t() >= 600) { bo_flags |= GBM_BO_USE_SCANOUT; } gbm_bo *bo_raw = gbm_bo_create( device, buffer_properties.size.width.as_uint32_t(), buffer_properties.size.height.as_uint32_t(), gbm_format, bo_flags); if (!bo_raw) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create GBM buffer object")); std::shared_ptr bo{bo_raw, GBMBODeleter()}; std::unique_ptr texture_binder{ new EGLImageBufferTextureBinder{bo, egl_extensions}}; /* Create the GBMBuffer */ auto const buffer = std::make_shared(bo, bo_flags, std::move(texture_binder)); (*buffer_initializer)(*buffer); return buffer; } std::shared_ptr mgm::BufferAllocator::alloc_software_buffer( BufferProperties const& buffer_properties) { if (!is_pixel_format_supported(buffer_properties.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(buffer_properties.format) * buffer_properties.size.width.as_uint32_t()}; size_t const size_in_bytes = stride.as_int() * buffer_properties.size.height.as_int(); auto const shm_file = std::make_shared(size_in_bytes); auto const buffer = std::make_shared(shm_file, buffer_properties.size, buffer_properties.format); (*buffer_initializer)(*buffer); return buffer; } std::vector mgm::BufferAllocator::supported_pixel_formats() { static std::vector const pixel_formats{ mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888 }; return pixel_formats; } bool mgm::BufferAllocator::is_pixel_format_supported(MirPixelFormat format) { auto formats = supported_pixel_formats(); auto iter = std::find(formats.begin(), formats.end(), format); return iter != formats.end(); } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/kms_output.h0000644000015301777760000000356612322054223024431 0ustar pbusernogroup00000000000000/* * 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_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; 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; protected: KMSOutput() = default; KMSOutput(const KMSOutput&) = delete; KMSOutput& operator=(const KMSOutput&) = delete; }; } } } #endif /* MIR_GRAPHICS_MESA_KMS_OUTPUT_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/gbm_buffer.h0000644000015301777760000000405112322054223024303 0ustar pbusernogroup00000000000000/* * 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 #include #include namespace mir { namespace graphics { namespace mesa { struct GBMNativeBuffer : MirNativeBuffer { struct gbm_bo *bo; }; MirPixelFormat gbm_format_to_mir_format(uint32_t format); uint32_t mir_format_to_gbm_format(MirPixelFormat format); enum : uint32_t { invalid_gbm_format = std::numeric_limits::max() }; class BufferTextureBinder; class GBMBuffer: public BufferBasic { 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; virtual geometry::Stride stride() const; virtual MirPixelFormat pixel_format() const; virtual std::shared_ptr native_buffer_handle() const; virtual void bind_to_texture(); bool can_bypass() const 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_ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/drm_mode_resources.cpp0000644000015301777760000000637112322054223026427 0ustar pbusernogroup00000000000000/* * 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 mgm = mir::graphics::mesa; namespace { struct CrtcDeleter { void operator()(drmModeCrtc* p) { if (p) drmModeFreeCrtc(p); } }; struct EncoderDeleter { void operator()(drmModeEncoder* p) { if (p) drmModeFreeEncoder(p); } }; struct ConnectorDeleter { void operator()(drmModeConnector* p) { if (p) drmModeFreeConnector(p); } }; struct ResourcesDeleter { void operator()(drmModeRes* p) { if (p) drmModeFreeResources(p); } }; } mgm::DRMModeResources::DRMModeResources(int drm_fd) : drm_fd{drm_fd}, resources{DRMModeResUPtr{drmModeGetResources(drm_fd), ResourcesDeleter()}} { if (!resources) BOOST_THROW_EXCEPTION(std::runtime_error("Couldn't get DRM resources\n")); } void mgm::DRMModeResources::for_each_connector(std::function const& f) const { for (int i = 0; i < resources->count_connectors; i++) { auto connector_ptr = connector(resources->connectors[i]); if (!connector_ptr) continue; f(std::move(connector_ptr)); } } void mgm::DRMModeResources::for_each_encoder(std::function const& f) const { for (int i = 0; i < resources->count_encoders; i++) { auto encoder_ptr = encoder(resources->encoders[i]); if (!encoder_ptr) continue; f(std::move(encoder_ptr)); } } void mgm::DRMModeResources::for_each_crtc(std::function const& f) const { for (int i = 0; i < resources->count_crtcs; i++) { auto crtc_ptr = crtc(resources->crtcs[i]); if (!crtc_ptr) continue; f(std::move(crtc_ptr)); } } size_t mgm::DRMModeResources::num_connectors() { return resources->count_connectors; } size_t mgm::DRMModeResources::num_encoders() { return resources->count_encoders; } size_t mgm::DRMModeResources::num_crtcs() { return resources->count_crtcs; } mgm::DRMModeConnectorUPtr mgm::DRMModeResources::connector(uint32_t id) const { auto connector_raw = drmModeGetConnector(drm_fd, id); return DRMModeConnectorUPtr{connector_raw, ConnectorDeleter()}; } mgm::DRMModeEncoderUPtr mgm::DRMModeResources::encoder(uint32_t id) const { auto encoder_raw = drmModeGetEncoder(drm_fd, id); return DRMModeEncoderUPtr{encoder_raw, EncoderDeleter()}; } mgm::DRMModeCrtcUPtr mgm::DRMModeResources::crtc(uint32_t id) const { auto crtc_raw = drmModeGetCrtc(drm_fd, id); return DRMModeCrtcUPtr{crtc_raw, CrtcDeleter()}; } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/drm_close_threadsafe.h0000644000015301777760000000172212322054223026344 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/display.h0000644000015301777760000000557412322054247023673 0ustar pbusernogroup00000000000000/* * 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 "real_kms_output_container.h" #include "real_kms_display_configuration.h" #include "display_helpers.h" #include #include namespace mir { namespace geometry { struct Rectangle; } namespace graphics { class DisplayReport; class DisplayBuffer; class DisplayConfigurationPolicy; class EventHandlerRegister; class GLConfig; namespace mesa { class Platform; class DisplayBuffer; class KMSOutput; class Cursor; class Display : public graphics::Display { public: Display(std::shared_ptr const& platform, 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_buffer( std::function const& f); std::unique_ptr configuration() const override; void configure(DisplayConfiguration const& conf) override; void register_configuration_change_handler( EventHandlerRegister& handlers, DisplayConfigurationChangeHandler const& conf_change_handler); void register_pause_resume_handlers( EventHandlerRegister& handlers, DisplayPauseHandler const& pause_handler, DisplayResumeHandler const& resume_handler); void pause(); void resume(); std::weak_ptr the_cursor(); std::unique_ptr create_gl_context(); private: void clear_connected_unused_outputs(); mutable std::mutex configuration_mutex; std::shared_ptr const platform; std::shared_ptr const listener; mir::udev::Monitor monitor; helpers::EGLHelper shared_egl; std::vector> display_buffers; RealKMSOutputContainer output_container; mutable RealKMSDisplayConfiguration current_display_configuration; std::shared_ptr cursor; std::shared_ptr const gl_config; }; } } } #endif /* MIR_GRAPHICS_MESA_DISPLAY_H_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/kms_display_configuration.h0000644000015301777760000000252512322054223027457 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/kms_page_flipper.cpp0000644000015301777760000001106112322054223026046 0ustar pbusernogroup00000000000000/* * 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 namespace mgm = mir::graphics::mesa; namespace { void page_flip_handler(int /*fd*/, unsigned int /*frame*/, unsigned int /*sec*/, unsigned int /*usec*/, void* data) { auto page_flip_data = static_cast(data); page_flip_data->pending->erase(page_flip_data->crtc_id); } } mgm::KMSPageFlipper::KMSPageFlipper(int drm_fd) : drm_fd{drm_fd}, pending_page_flips(), worker_tid() { } bool mgm::KMSPageFlipper::schedule_flip(uint32_t crtc_id, uint32_t fb_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{&pending_page_flips, crtc_id}; 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); } void mgm::KMSPageFlipper::wait_for_flip(uint32_t crtc_id) { static drmEventContext evctx = { DRM_EVENT_CONTEXT_VERSION, /* .version */ 0, /* .vblank_handler */ 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; /* ...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(); } } 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(); } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/internal_native_surface.cpp0000644000015301777760000000475712322054223027447 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/internal_surface.h" #include "internal_native_surface.h" #include namespace mgm = mir::graphics::mesa; mgm::InternalNativeSurface::InternalNativeSurface(std::shared_ptr const& surface) : surface(surface), current_buffer{nullptr} { surface_advance_buffer = advance_buffer_static; surface_get_parameters = get_parameters_static; surface_set_swapinterval = set_swapinterval_static; } int mgm::InternalNativeSurface::advance_buffer_static( MirMesaEGLNativeSurface* surface, MirBufferPackage* package) { auto native_surface = static_cast(surface); return native_surface->advance_buffer(package); } int mgm::InternalNativeSurface::advance_buffer(MirBufferPackage* package) { surface->swap_buffers(current_buffer); auto buffer_package = current_buffer->native_buffer_handle(); memcpy(package, buffer_package.get(), sizeof(MirBufferPackage)); return MIR_MESA_TRUE; } int mgm::InternalNativeSurface::get_parameters_static( MirMesaEGLNativeSurface* surface, MirSurfaceParameters* parameters) { auto native_surface = static_cast(surface); return native_surface->get_parameters(parameters); } int mgm::InternalNativeSurface::get_parameters(MirSurfaceParameters* parameters) { auto size = surface->size(); parameters->width = size.width.as_uint32_t(); parameters->height = size.height.as_uint32_t(); parameters->pixel_format = surface->pixel_format(); parameters->buffer_usage = mir_buffer_usage_hardware; return MIR_MESA_TRUE; } int mgm::InternalNativeSurface::set_swapinterval_static(MirMesaEGLNativeSurface* surface, int interval) { //TODO: (void) surface; (void) interval; return MIR_MESA_TRUE; } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/display_buffer.cpp0000644000015301777760000002555112322054247025554 0ustar pbusernogroup00000000000000/* * 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 "platform.h" #include "kms_output.h" #include "mir/graphics/display_report.h" #include "gbm_buffer.h" #include #include #include 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 = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS); if (exts) ext_string = exts; if (ext_string.find("EGL_MESA_drm_image") == std::string::npos) BOOST_THROW_EXCEPTION(std::runtime_error("EGL implementation doesn't support EGL_MESA_drm_image extension")); exts = reinterpret_cast(glGetString(GL_EXTENSIONS)); if (exts) ext_string = exts; else ext_string.clear(); 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( std::shared_ptr const& platform, 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) : last_flipped_bufobj{nullptr}, scheduled_bufobj{nullptr}, platform(platform), listener(listener), drm(platform->drm), 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(platform->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()) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to perform initial surface buffer swap")); listener->report_successful_egl_buffer_swap_on_construction(); scheduled_bufobj = get_front_buffer_object(); if (!scheduled_bufobj) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to get frontbuffer")); for (auto& output : outputs) { if (!output->set_crtc(scheduled_bufobj->get_drm_fb_id())) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to set DRM crtc")); } egl.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 last_flipped_bufobj manually. * It will be destroyed when its gbm_surface gets destroyed. */ if (last_flipped_bufobj) last_flipped_bufobj->release(); if (scheduled_bufobj) scheduled_bufobj->release(); } geom::Rectangle mgm::DisplayBuffer::view_area() const { return area; } bool mgm::DisplayBuffer::can_bypass() const { return (rotation == mir_orientation_normal); } MirOrientation mgm::DisplayBuffer::orientation() const { // Tell the renderer to do the rotation, since we're not doing it here. return rotation; } void mgm::DisplayBuffer::render_and_post_update( RenderableList const&, std::function const&) { post_update(nullptr); } void mgm::DisplayBuffer::post_update() { post_update(nullptr); } void mgm::DisplayBuffer::post_update( std::shared_ptr bypass_buf) { /* * If the last frame was composited then we haven't waited for the * page flips yet. This is good because it maximizes the time available * to spend rendering each frame. However we have to wait here, because * it will be unsafe to swap_buffers before guaranteeing the previous * page flip finished. */ wait_for_page_flip(); /* * Switching from bypass to compositing? Now is the earliest safe time * we can unreference the bypass buffer... */ if (scheduled_bufobj) last_flipped_bypass_buf = nullptr; /* * Release the last flipped buffer object (which is not displayed anymore) * to make it available for future rendering. */ if (last_flipped_bufobj) last_flipped_bufobj->release(); last_flipped_bufobj = scheduled_bufobj; scheduled_bufobj = nullptr; /* * Bring the back buffer to the front and get the buffer object * corresponding to the front buffer. */ if (!bypass_buf && !egl.swap_buffers()) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to perform initial surface buffer swap")); mgm::BufferObject *bufobj; if (bypass_buf) { auto native = bypass_buf->native_buffer_handle(); auto gbm_native = static_cast(native.get()); bufobj = get_buffer_object(gbm_native->bo); } else { bufobj = get_front_buffer_object(); } if (!bufobj) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to get front buffer object")); /* * Schedule the current front buffer object for display, and wait * for it to be actually displayed (flipped). * * If the flip fails, release the buffer object to make it available * for future rendering. */ if (!needs_set_crtc && !schedule_page_flip(bufobj)) { if (!bypass_buf) bufobj->release(); BOOST_THROW_EXCEPTION(std::runtime_error("Failed to schedule page flip")); } else if (needs_set_crtc) { for (auto& output : outputs) { if (!output->set_crtc(bufobj->get_drm_fb_id())) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to set DRM crtc")); } needs_set_crtc = false; } 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 * last_flipped_bypass_buf unacceptably, resulting in client stuttering * unless we allocate quad-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. */ wait_for_page_flip(); scheduled_bufobj = nullptr; /* * Keep a reference to the buffer being bypassed for the entire * duration of the frame. This ensures the buffer doesn't get reused by * the client while its on-screen, which would be seen as tearing or * worse. */ last_flipped_bypass_buf = bypass_buf; } else { scheduled_bufobj = bufobj; } } 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}; auto handle = gbm_bo_get_handle(bo).u32; auto stride = gbm_bo_get_stride(bo); /* Create a KMS FB object with the gbm_bo attached to it. */ auto ret = drmModeAddFB(drm.fd, fb_width, fb_height, 24, 32, stride, handle, &fb_id); 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; } } void mgm::DisplayBuffer::make_current() { if (!egl.make_current()) { BOOST_THROW_EXCEPTION(std::runtime_error("Failed to make EGL surface current")); } } void mgm::DisplayBuffer::release_current() { egl.release_current(); } void mgm::DisplayBuffer::schedule_set_crtc() { needs_set_crtc = true; } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/black_arrow.xcf0000644000015301777760000000564412322054223025035 0ustar pbusernogroup00000000000000gimp xcf file@@BB6gimp-image-grid(style solid) (fgcolor (color-rgba 0.000000 0.000000 0.000000 1.000000)) (bgcolor (color-rgba 1.000000 1.000000 1.000000 1.000000)) (xspacing 10.000000) (yspacing 10.000000) (spacing-unit inches) (xoffset 0.000000) (yoffset 0.000000) (offset-unit inches) hot-spot14 8@@(32px)_1 (50ms) (replace)     g@@{@@\</;!:9aR 8_\2\f\1Y r/0X$|!/X  ).X %/ -X!+4,X '09,X#,5?+X (1;E*Xaiov})X (X[a\!$%&**4'Xmm09&XuqJ,5?%X~9g(1;E$4aiov}#a% "4[a\!$%&**"8m0aqJ69g847a%14189a'\</;!:9aR 8_\2\f\1Y r/0X$|!/X  ).X %/ -X!+4,X '09,X#,5?+X (1;E*Xaiov})X (X[a\!$%&**4'Xmm09&XuqJ,5?%X~9g(1;E$4aiov}#a% "4[a\!$%&**"8m0aqJ69g847a%14189a'\</;!:9aR 8_\2\f\1Y r/0X$|!/X  ).X %/ -X!+4,X '09,X#,5?+X (1;E*Xaiov})X (X[a\!$%&**4'Xmm09&XuqJ,5?%X~9g(1;E$4aiov}#a% "4[a\!$%&**"8m0aqJ69g847a%14189a'! 9 0 8 . 7* 1' 5% 3"3 2 10/ . - , z+ q* a*{onkaB*J)! *c++.^:S.[,@". X+ *- q>( Cu%- Ik=.$-%79}=4mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/drm_close_threadsafe.cpp0000644000015301777760000000171212322054223026676 0ustar pbusernogroup00000000000000/* * 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); } mir-0.1.8+14.04.20140411/src/platform/graphics/mesa/kms_output_container.h0000644000015301777760000000263212322054223026464 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/src/platform/graphics/CMakeLists.txt0000644000015301777760000000127412322054223023653 0ustar pbusernogroup00000000000000# Workaround for bug 1208774 (spurious link errors on 32bit g++) string (REPLACE " -Wl,--no-undefined" " " CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}) include_directories(${GLESv2_INCLUDE_DIRS}) set( GRAPHICS_SOURCES egl_extensions.cpp egl_resources.cpp display_configuration.cpp buffer_basic.cpp pixel_format_utils.cpp overlapping_output_grouping.cpp ) add_library( mirplatformgraphicscommon STATIC ${GRAPHICS_SOURCES} ) target_link_libraries( mirplatformgraphicscommon mirsharedgeometry ${EGL_LDFLAGS} ${EGL_LIBRARIES} ) if (MIR_BUILD_PLATFORM_ANDROID) add_subdirectory(android/) endif() if (MIR_BUILD_PLATFORM_MESA) add_subdirectory(mesa/) endif() mir-0.1.8+14.04.20140411/src/platform/options/0000755000015301777760000000000012322054703021005 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/platform/options/default_configuration.cpp0000644000015301777760000002246212322054247026075 0ustar pbusernogroup00000000000000/* * 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/shared_library_loader.h" #include "mir/options/default_configuration.h" #include "mir/graphics/platform.h" #include "mir/default_configuration.h" #include "mir/abnormal_exit.h" namespace mo = mir::options; char const* const mo::server_socket_opt = "file,f"; char const* const mo::no_server_socket_opt = "no-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::host_socket_opt = "host-socket"; char const* const mo::frontend_threads_opt = "ipc-thread-pool"; char const* const mo::name_opt = "name"; char const* const mo::offscreen_opt = "offscreen"; char const* const mo::glog = "glog"; char const* const mo::glog_stderrthreshold = "glog-stderrthreshold"; char const* const mo::glog_minloglevel = "glog-minloglevel"; char const* const mo::glog_log_dir = "glog-log-dir"; 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"; namespace { int const default_ipc_threads = 1; int const glog_stderrthreshold_default = 2; int const glog_minloglevel_default = 0; char const* const glog_log_dir_default = ""; bool const enable_input_default = true; char const* const default_platform_graphics_lib = "libmirplatformgraphics.so"; } mo::DefaultConfiguration::DefaultConfiguration(int argc, char const* argv[]) : argc(argc), argv(argv), program_options(std::make_shared( "Command-line options.\n" "Environment variables capitalise long form with prefix \"MIR_SERVER_\" and \"_\" in place of \"-\"")) { 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") (platform_graphics_lib, po::value()->default_value(default_platform_graphics_lib), "Library to use for platform graphics support") (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}]") (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}]") (glog, "Use google::GLog for logging") (glog_stderrthreshold, po::value()->default_value(glog_stderrthreshold_default), "Copy log messages at or above this level " "to stderr in addition to logfiles. The numbers " "of severity levels INFO, WARNING, ERROR, and " "FATAL are 0, 1, 2, and 3, respectively.") (glog_minloglevel, po::value()->default_value(glog_minloglevel_default), "Log messages at or above this level. The numbers " "of severity levels INFO, WARNING, ERROR, and " "FATAL are 0, 1, 2, and 3, respectively." " [int:default=0]") (glog_log_dir, po::value()->default_value(glog_log_dir_default), "If specified, logfiles are written into this " "directory instead of the default logging directory.") (frontend_threads_opt, po::value()->default_value(default_ipc_threads), "threads in frontend thread pool.") (name_opt, po::value(), "When nested, the name Mir uses when registering with the host.") (offscreen_opt, "Render to offscreen buffers instead of the real outputs."); 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()->default_value(default_platform_graphics_lib), ""); mo::ProgramOption options; options.parse_arguments(program_options, argc, argv); std::string graphics_libname; auto env_libname = ::getenv("MIR_SERVER_PLATFORM_GRAPHICS_LIB"); if (!options.is_set(platform_graphics_lib) && env_libname) { graphics_libname = std::string{env_libname}; } else { graphics_libname = options.get(platform_graphics_lib); } auto graphics_lib = load_library(graphics_libname); auto add_platform_options = graphics_lib->load_function(std::string("add_platform_options")); add_platform_options(*this->program_options); } 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); 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 { // If MIR_SERVER_HOST_SOCKET is unset, we want to substitute the value of // MIR_SOCKET. Do this now, because MIR_SOCKET will get overwritten later. auto host_socket = getenv("MIR_SERVER_HOST_SOCKET"); auto mir_socket = getenv("MIR_SOCKET"); if (!host_socket && mir_socket) setenv("MIR_SERVER_HOST_SOCKET", mir_socket, 1); options.parse_environment(desc, "MIR_SERVER_"); } void mo::DefaultConfiguration::parse_config_file( boost::program_options::options_description& /*desc*/, mo::ProgramOption& /*options*/) const { } mir-0.1.8+14.04.20140411/src/platform/options/CMakeLists.txt0000644000015301777760000000020312322054223023535 0ustar pbusernogroup00000000000000set( CHOICE_SOURCES program_option.cpp default_configuration.cpp ) add_library( miroptions STATIC ${CHOICE_SOURCES} ) mir-0.1.8+14.04.20140411/src/platform/options/program_option.cpp0000644000015301777760000001023212322054223024543 0ustar pbusernogroup00000000000000/* * 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 #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[]) { // TODO: Don't allow unregistered options, once we allow better overriding of option parsing po::store(po::command_line_parser(argc, argv).options(desc).allow_unregistered().run(), options); po::notify(options); } 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 = tolower(ch); } 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) { std::cerr << "ERROR in " << filename << ": " << error.what() << std::endl; } } 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_; } mir-0.1.8+14.04.20140411/src/platform/CMakeLists.txt0000644000015301777760000000067512322054247022065 0ustar pbusernogroup00000000000000include_directories(${PROJECT_SOURCE_DIR}/include/platform) include_directories(${UDEV_INCLUDE_DIRS}) add_library( mirplatform SHARED shared_library_loader.cpp udev_wrapper.cpp ) target_link_libraries( mirplatform mirplatformgraphicscommon mirsharedsharedlibrary ${UDEV_LDFLAGS} ${UDEV_LIBRARIES} ) install(TARGETS mirplatform LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) add_subdirectory(graphics/) add_subdirectory(options) mir-0.1.8+14.04.20140411/src/client/0000755000015301777760000000000012322054703016744 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/client/default_connection_configuration.cpp0000644000015301777760000001314512322054247026251 0ustar pbusernogroup00000000000000/* * 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 "default_connection_configuration.h" #include "display_configuration.h" #include "rpc/make_rpc_channel.h" #include "rpc/null_rpc_report.h" #include "mir/logging/dumb_console_logger.h" #include "mir/input/input_platform.h" #include "mir/input/null_input_receiver_report.h" #include "logging/rpc_report.h" #include "logging/input_receiver_report.h" #include "lttng/rpc_report.h" #include "lttng/input_receiver_report.h" #include "connection_surface_map.h" #include "lifecycle_control.h" #include "mir/shared_library.h" #include "client_platform_factory.h" namespace mcl = mir::client; namespace { std::string const off_opt_val{"off"}; std::string const log_opt_val{"log"}; std::string const lttng_opt_val{"lttng"}; std::string const default_platform_lib{"libmirclientplatform.so"}; mir::SharedLibrary const* load_library(std::string const& libname) { // There's no point in loading twice, and it isn't safe to unload... static std::map> libraries_cache; if (auto& ptr = libraries_cache[libname]) { return ptr.get(); } else { ptr = std::make_shared(libname); return ptr.get(); } } } mcl::DefaultConnectionConfiguration::DefaultConnectionConfiguration( std::string const& socket_file) : socket_file{socket_file} { } std::shared_ptr mcl::DefaultConnectionConfiguration::the_surface_map() { return surface_map([] { return std::make_shared(); }); } std::shared_ptr mcl::DefaultConnectionConfiguration::the_rpc_channel() { return rpc_channel( [this] { return mcl::rpc::make_rpc_channel( the_socket_file(), the_surface_map(), the_display_configuration(), the_rpc_report(), the_lifecycle_control()); }); } std::shared_ptr mcl::DefaultConnectionConfiguration::the_logger() { return logger( [] { return std::make_shared(); }); } std::shared_ptr mcl::DefaultConnectionConfiguration::the_client_platform_factory() { return client_platform_factory( [] { auto const val_raw = getenv("MIR_CLIENT_PLATFORM_LIB"); std::string const val{val_raw ? val_raw : default_platform_lib}; auto const platform_lib = ::load_library(val); auto const create_client_platform_factory = platform_lib->load_function( "create_client_platform_factory"); return create_client_platform_factory(); }); } std::shared_ptr mcl::DefaultConnectionConfiguration::the_input_platform() { return input_platform( [this] { return mir::input::receiver::InputPlatform::create(the_input_receiver_report()); }); } std::string mcl::DefaultConnectionConfiguration::the_socket_file() { return socket_file; } std::shared_ptr mcl::DefaultConnectionConfiguration::the_rpc_report() { return rpc_report( [this] () -> std::shared_ptr { auto val_raw = getenv("MIR_CLIENT_RPC_REPORT"); std::string const val{val_raw ? val_raw : off_opt_val}; if (val == log_opt_val) return std::make_shared(the_logger()); else if (val == lttng_opt_val) return std::make_shared(); else return std::make_shared(); }); } std::shared_ptr mcl::DefaultConnectionConfiguration::the_input_receiver_report() { return input_receiver_report( [this] () -> std::shared_ptr { auto val_raw = getenv("MIR_CLIENT_INPUT_RECEIVER_REPORT"); std::string const val{val_raw ? val_raw : off_opt_val}; if (val == log_opt_val) return std::make_shared(the_logger()); else if (val == lttng_opt_val) return std::make_shared(); else return std::make_shared(); }); } std::shared_ptr mcl::DefaultConnectionConfiguration::the_display_configuration() { return display_configuration( [] { return std::make_shared(); }); } std::shared_ptr mcl::DefaultConnectionConfiguration::the_lifecycle_control() { return lifecycle_control( [] { return std::make_shared(); }); } mir-0.1.8+14.04.20140411/src/client/android/0000755000015301777760000000000012322054703020364 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/client/android/android_registrar.cpp0000644000015301777760000000767112322054223024602 0ustar pbusernogroup00000000000000/* * 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 "android_registrar_gralloc.h" #include "../client_buffer.h" #include #include 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; }; struct MemoryRegionDeleter { MemoryRegionDeleter(const std::shared_ptr& mod, const std::shared_ptr& han) : handle(han), module(mod) {} void operator()(char *) { module->unlock(module.get(), handle.get()); //we didn't alloc region(just mapped it), so we don't delete } private: const std::shared_ptr handle; const std::shared_ptr module; }; } mcla::AndroidRegistrarGralloc::AndroidRegistrarGralloc(const std::shared_ptr& gr_module) : gralloc_module(gr_module) { } std::shared_ptr mcla::AndroidRegistrarGralloc::register_buffer( std::shared_ptr const& package) const { 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; handle->numFds = package->fd_items; handle->numInts = package->data_items; for (auto i=0; i< handle->numFds; i++) { handle->data[i] = package->fd[i]; } int offset_i = handle->numFds; for (auto i=0; i< handle->numInts; i++) { handle->data[offset_i+i] = package->data[i]; } if ( gralloc_module->registerBuffer(gralloc_module.get(), handle) ) { ::operator delete(const_cast(handle)); BOOST_THROW_EXCEPTION(std::runtime_error("error registering graphics buffer for client use\n")); } NativeHandleDeleter del(gralloc_module); return std::shared_ptr(handle, del); } std::shared_ptr mcla::AndroidRegistrarGralloc::secure_for_cpu(std::shared_ptr handle, const geometry::Rectangle 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.get(), usage, top, left, width, height, (void**) &vaddr) ) BOOST_THROW_EXCEPTION(std::runtime_error("error securing buffer for client cpu use")); MemoryRegionDeleter del(gralloc_module, handle); return std::shared_ptr(vaddr, del); } mir-0.1.8+14.04.20140411/src/client/android/android_client_platform.h0000644000015301777760000000261112322054223025414 0ustar pbusernogroup00000000000000/* * 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 "../client_platform.h" namespace mir { namespace client { class ClientBufferDepository; namespace android { class AndroidClientPlatform : public ClientPlatform { public: MirPlatformType platform_type() const; std::shared_ptr create_buffer_factory(); std::shared_ptr create_egl_native_window(ClientSurface *surface); std::shared_ptr create_egl_native_display(); MirNativeBuffer* convert_native_buffer(graphics::NativeBuffer*) const; }; } } } #endif /* MIR_CLIENT_ANDROID_ANDROID_CLIENT_PLATFORM_H_ */ mir-0.1.8+14.04.20140411/src/client/android/android_registrar_gralloc.h0000644000015301777760000000275512322054223025750 0ustar pbusernogroup00000000000000/* * 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_REGISTRAR_GRALLOC_H_ #define MIR_CLIENT_ANDROID_ANDROID_REGISTRAR_GRALLOC_H_ #include "mir_toolkit/common.h" #include "android_registrar.h" #include namespace mir { namespace client { namespace android { class AndroidRegistrarGralloc : public AndroidRegistrar { public: AndroidRegistrarGralloc(const std::shared_ptr& gralloc_dev); std::shared_ptr register_buffer( std::shared_ptr const& package) const; std::shared_ptr secure_for_cpu(std::shared_ptr handle, const geometry::Rectangle); private: std::shared_ptr gralloc_module; }; } } } #endif /* MIR_CLIENT_ANDROID_ANDROID_REGISTRAR_GRALLOC_H_ */ mir-0.1.8+14.04.20140411/src/client/android/client_platform_factory.cpp0000644000015301777760000000226512322054223026003 0ustar pbusernogroup00000000000000/* * 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 "client_platform_factory.h" #include "android_client_platform.h" namespace mcl = mir::client; namespace mcla = mcl::android; std::shared_ptr mcla::ClientPlatformFactory::create_client_platform(mcl::ClientContext* /*context*/) { return std::make_shared(); } extern "C" std::shared_ptr mcl::create_client_platform_factory() { return std::make_shared(); } mir-0.1.8+14.04.20140411/src/client/android/android_registrar.h0000644000015301777760000000261112322054223024234 0ustar pbusernogroup00000000000000/* * 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_REGISTRAR_H_ #define MIR_CLIENT_ANDROID_ANDROID_REGISTRAR_H_ #include #include "mir/geometry/rectangle.h" #include #include namespace mir { namespace client { class MemoryRegion; namespace android { class AndroidRegistrar { public: virtual ~AndroidRegistrar() = default; virtual std::shared_ptr register_buffer( std::shared_ptr const& package) const = 0; virtual std::shared_ptr secure_for_cpu(std::shared_ptr handle, const geometry::Rectangle) = 0; }; } } } #endif /* MIR_CLIENT_ANDROID_REGISTRAR_H_ */ mir-0.1.8+14.04.20140411/src/client/android/android_client_buffer_factory.h0000644000015301777760000000310412322054223026566 0ustar pbusernogroup00000000000000/* * 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 "../client_buffer_factory.h" namespace mir { namespace client { class ClientBuffer; namespace android { class AndroidRegistrar; class AndroidClientBufferFactory : public ClientBufferFactory { public: explicit AndroidClientBufferFactory(std::shared_ptr const&); virtual std::shared_ptr create_buffer(std::shared_ptr const& package, geometry::Size size, MirPixelFormat pf); private: std::shared_ptr registrar; }; } } } #endif /* MIR_CLIENT_ANDROID_ANDROID_BUFFER_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/client/android/android_native_display_container.cpp0000644000015301777760000000313112322054223027640 0ustar pbusernogroup00000000000000/* * 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" namespace mcl = mir::client; namespace mcla = mcl::android; mcl::EGLNativeDisplayContainer& mcl::EGLNativeDisplayContainer::instance() { static mcla::AndroidNativeDisplayContainer default_display_container; return default_display_container; } mcla::AndroidNativeDisplayContainer::AndroidNativeDisplayContainer() { } mcla::AndroidNativeDisplayContainer::~AndroidNativeDisplayContainer() { } bool mcla::AndroidNativeDisplayContainer::validate(MirEGLNativeDisplayType display) const { return mir_connection_is_valid(static_cast(display)); } MirEGLNativeDisplayType mcla::AndroidNativeDisplayContainer::create(MirConnection* connection) { return static_cast(connection); } void mcla::AndroidNativeDisplayContainer::release(MirEGLNativeDisplayType /* display */) { } mir-0.1.8+14.04.20140411/src/client/android/client_surface_interpreter.h0000644000015301777760000000317712322054223026153 0ustar pbusernogroup00000000000000/* * 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_ANDROID_CLIENT_SURFACE_INTERPRETER_H_ #define MIR_CLIENT_ANDROID_CLIENT_SURFACE_INTERPRETER_H_ #include "mir/graphics/android/android_driver_interpreter.h" #include "../mir_client_surface.h" namespace mir { namespace graphics { namespace android { class SyncFileOps; } } namespace client { namespace android { class ClientSurfaceInterpreter : public graphics::android::AndroidDriverInterpreter { public: explicit ClientSurfaceInterpreter(ClientSurface& surface); graphics::NativeBuffer* driver_requests_buffer(); void driver_returns_buffer(ANativeWindowBuffer*, int fence_fd ); void dispatch_driver_request_format(int format); int driver_requests_info(int key) const; void sync_to_display(bool); private: ClientSurface& surface; int driver_pixel_format; std::shared_ptr const sync_ops; }; } } } #endif /* MIR_CLIENT_ANDROID_CLIENT_SURFACE_INTERPRETER_H_ */ mir-0.1.8+14.04.20140411/src/client/android/android_native_display_container.h0000644000015301777760000000304212322054223027306 0ustar pbusernogroup00000000000000/* * 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 "../egl_native_display_container.h" #include "mir_toolkit/client_types.h" namespace mir { namespace client { namespace android { class AndroidNativeDisplayContainer : public EGLNativeDisplayContainer { public: AndroidNativeDisplayContainer(); virtual ~AndroidNativeDisplayContainer(); MirEGLNativeDisplayType create(MirConnection* connection); void release(MirEGLNativeDisplayType display); bool validate(MirEGLNativeDisplayType display) const; protected: AndroidNativeDisplayContainer(AndroidNativeDisplayContainer const&) = delete; AndroidNativeDisplayContainer& operator=(AndroidNativeDisplayContainer const&) = delete; }; } } } // namespace mir #endif // MIR_CLIENT_ANDROID_NATIVE_DISPLAY_CONTAINER_H_ mir-0.1.8+14.04.20140411/src/client/android/android_client_buffer_factory.cpp0000644000015301777760000000303112322054223027120 0ustar pbusernogroup00000000000000/* * 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_client_buffer.h" namespace mcl=mir::client; namespace mcla=mir::client::android; namespace geom=mir::geometry; 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 auto handle = registrar->register_buffer(package); return std::make_shared( registrar, handle, geometry::Size{package->width, package->height}, pf, geometry::Stride{package->stride}); } mir-0.1.8+14.04.20140411/src/client/android/CMakeLists.txt0000644000015301777760000000240112322054223023116 0ustar pbusernogroup00000000000000include_directories(SYSTEM ${LIBHARDWARE_INCLUDE_DIRS}) add_definitions(-DANDROID) add_library( mirclientplatformandroid SHARED android_client_buffer.cpp android_client_buffer_factory.cpp android_registrar.cpp android_client_platform.cpp client_platform_factory.cpp client_surface_interpreter.cpp android_native_display_container.cpp ) set_target_properties( mirclientplatformandroid PROPERTIES OUTPUT_NAME mirclientplatform LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}/android ) target_link_libraries( mirclientplatformandroid mirclient ${LIBHARDWARE_LIBRARIES} ) install(TARGETS mirclientplatformandroid LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mir/clientplatform/android) if (MIR_TEST_PLATFORM STREQUAL "android") add_custom_command(TARGET mirclientplatformandroid POST_BUILD COMMAND ${CMAKE_COMMAND} -E remove libmirclientplatform.so COMMAND ${CMAKE_COMMAND} -E create_symlink android/$ libmirclientplatform.so WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH} ) install(CODE "execute_process( COMMAND ln -sf mir/clientplatform/android/libmirclientplatform.so WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} )" ) endif() mir-0.1.8+14.04.20140411/src/client/android/android_client_buffer.h0000644000015301777760000000417512322054223025050 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/android/android_native_buffer.h" #include "../aging_buffer.h" #include "android_registrar.h" #include #include namespace mir { namespace client { namespace android { class AndroidClientBuffer : public AgingBuffer { public: AndroidClientBuffer(std::shared_ptr const&, std::shared_ptr const&, geometry::Size size, MirPixelFormat pf, geometry::Stride stride); ~AndroidClientBuffer() 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; AndroidClientBuffer(const AndroidClientBuffer&) = delete; AndroidClientBuffer& operator=(const AndroidClientBuffer&) = delete; private: void pack_native_window_buffer(); std::shared_ptr buffer_registrar; std::shared_ptr native_window_buffer; std::shared_ptr native_handle; const MirPixelFormat buffer_pf; geometry::Stride const buffer_stride; geometry::Size const buffer_size; }; } } } #endif /* MIR_CLIENT_ANDROID_ANDROID_CLIENT_BUFFER_H_ */ mir-0.1.8+14.04.20140411/src/client/android/client_platform_factory.h0000644000015301777760000000222312322054223025442 0ustar pbusernogroup00000000000000/* * 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_CLIENT_ANDROID_CLIENT_PLATFORM_FACTORY_H_ #define MIR_CLIENT_ANDROID_CLIENT_PLATFORM_FACTORY_H_ #include "../client_platform_factory.h" namespace mir { namespace client { namespace android { class ClientPlatformFactory : public client::ClientPlatformFactory { public: std::shared_ptr create_client_platform(ClientContext* context) override; }; } } } #endif /* MIR_CLIENT_ANDROID_CLIENT_PLATFORM_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/client/android/client_surface_interpreter.cpp0000644000015301777760000000521312322054223026477 0ustar pbusernogroup00000000000000/* * 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 "client_surface_interpreter.h" #include "mir/graphics/android/sync_fence.h" #include "../client_buffer.h" #include #include namespace mcla=mir::client::android; namespace mga=mir::graphics::android; mcla::ClientSurfaceInterpreter::ClientSurfaceInterpreter(ClientSurface& surface) : surface(surface), driver_pixel_format(-1), sync_ops(std::make_shared()) { } mir::graphics::NativeBuffer* mcla::ClientSurfaceInterpreter::driver_requests_buffer() { auto buffer = surface.get_current_buffer(); auto buffer_to_driver = buffer->native_buffer_handle(); ANativeWindowBuffer* anwb = buffer_to_driver->anwb(); anwb->format = driver_pixel_format; return buffer_to_driver.get(); } void mcla::ClientSurfaceInterpreter::driver_returns_buffer(ANativeWindowBuffer*, int fence_fd) { //TODO: pass fence to server instead of waiting here mga::SyncFence sync_fence(sync_ops, fence_fd); sync_fence.wait(); surface.request_and_wait_for_next_buffer(); } void mcla::ClientSurfaceInterpreter::dispatch_driver_request_format(int format) { driver_pixel_format = format; } int mcla::ClientSurfaceInterpreter::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; default: throw std::runtime_error("driver requested unsupported query"); } } void mcla::ClientSurfaceInterpreter::sync_to_display(bool) { //note: clients run with the swapinterval of the display. ignore their request for now } mir-0.1.8+14.04.20140411/src/client/android/android_client_platform.cpp0000644000015301777760000000626612322054223025761 0ustar pbusernogroup00000000000000/* * 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/android/mir_native_window.h" #include "android_client_platform.h" #include "android_registrar_gralloc.h" #include "android_client_buffer_factory.h" #include "client_surface_interpreter.h" #include "../mir_connection.h" #include #include namespace mcl=mir::client; namespace mcla=mir::client::android; namespace mga=mir::graphics::android; namespace { struct EmptyDeleter { void operator()(void*) { } }; } 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 */ EmptyDeleter empty_del; auto gralloc_dev = std::shared_ptr(gr_dev, empty_del); auto registrar = std::make_shared(gralloc_dev); return std::make_shared(registrar); } namespace { struct MirNativeWindowDeleter { MirNativeWindowDeleter(mga::MirNativeWindow* window) : window(window) {} void operator()(EGLNativeWindowType* type) { delete type; delete window; } private: mga::MirNativeWindow *window; }; } std::shared_ptr mcla::AndroidClientPlatform::create_egl_native_window(ClientSurface *surface) { auto anativewindow_interpreter = std::make_shared(*surface); auto mir_native_window = new mga::MirNativeWindow(anativewindow_interpreter); auto egl_native_window = new EGLNativeWindowType; *egl_native_window = mir_native_window; MirNativeWindowDeleter deleter = MirNativeWindowDeleter(mir_native_window); return std::shared_ptr(egl_native_window, deleter); } std::shared_ptr mcla::AndroidClientPlatform::create_egl_native_display() { auto native_display = std::make_shared(); *native_display = EGL_DEFAULT_DISPLAY; return native_display; } MirPlatformType mcla::AndroidClientPlatform::platform_type() const { return mir_platform_type_android; } MirNativeBuffer* mcla::AndroidClientPlatform::convert_native_buffer(graphics::NativeBuffer* buf) const { return buf->anwb(); } mir-0.1.8+14.04.20140411/src/client/android/android_client_buffer.cpp0000644000015301777760000000651212322054223025400 0ustar pbusernogroup00000000000000/* * 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/android/android_native_buffer.h" #include "mir/graphics/android/sync_fence.h" #include "mir_toolkit/mir_client_library.h" #include "android_client_buffer.h" #include namespace mcl=mir::client; namespace mcla=mir::client::android; namespace geom=mir::geometry; namespace mga=mir::graphics::android; mcla::AndroidClientBuffer::AndroidClientBuffer(std::shared_ptr const& registrar, std::shared_ptr const& handle, geom::Size size, MirPixelFormat pf, geometry::Stride stride) : buffer_registrar(registrar), native_handle(handle), buffer_pf(pf), buffer_stride{stride}, buffer_size(size) { auto ops = std::make_shared(); auto fence = std::make_shared(ops, -1); auto anwb = std::shared_ptr( new mga::RefCountedNativeBuffer(handle), [](mga::RefCountedNativeBuffer* buffer) { buffer->mir_dereference(); }); anwb->height = static_cast(buffer_size.height.as_uint32_t()); anwb->width = static_cast(buffer_size.width.as_uint32_t()); //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 = stride.as_uint32_t() / MIR_BYTES_PER_PIXEL(buffer_pf); anwb->usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_RENDER; anwb->handle = native_handle.get(); native_window_buffer = std::make_shared(anwb, fence); } mcla::AndroidClientBuffer::~AndroidClientBuffer() noexcept { } std::shared_ptr mcla::AndroidClientBuffer::secure_for_cpu_write() { auto rect = geom::Rectangle{geom::Point{0, 0}, size()}; auto vaddr = buffer_registrar->secure_for_cpu(native_handle, 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::AndroidClientBuffer::size() const { return buffer_size; } geom::Stride mcla::AndroidClientBuffer::stride() const { return buffer_stride; } MirPixelFormat mcla::AndroidClientBuffer::pixel_format() const { return buffer_pf; } std::shared_ptr mcla::AndroidClientBuffer::native_buffer_handle() const { return native_window_buffer; } mir-0.1.8+14.04.20140411/src/client/connection_surface_map.h0000644000015301777760000000245412322054223023623 0ustar pbusernogroup00000000000000/* * 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_CONNECTION_SURFACE_MAP_H_ #define MIR_CLIENT_CONNECTION_SURFACE_MAP_H_ #include "surface_map.h" #include #include namespace mir { namespace client { class ConnectionSurfaceMap : public SurfaceMap { public: ConnectionSurfaceMap(); void with_surface_do(int surface_id, std::function exec) const override; void insert(int surface_id, MirSurface* surface); void erase(int surface_id); private: std::mutex mutable guard; std::unordered_map surfaces; }; } } #endif /* MIR_CLIENT_CONNECTION_SURFACE_MAP_H_ */ mir-0.1.8+14.04.20140411/src/client/client_buffer_depository.h0000644000015301777760000000566212322054223024213 0ustar pbusernogroup00000000000000/* * 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_PRIVATE_MIR_CLIENT_BUFFER_DEPOSITORY_H_ #define MIR_CLIENT_PRIVATE_MIR_CLIENT_BUFFER_DEPOSITORY_H_ #include #include #include "mir_toolkit/common.h" #include "mir/geometry/size.h" struct MirBufferPackage; namespace mir { namespace client { class ClientBuffer; class ClientBufferFactory; /// Responsible for taking the buffer data sent from the server and wrapping it in a ClientBuffer /// The ClientBufferDepository is responsible for taking the IPC buffer data and converting it into /// the more digestible form of a ClientBuffer. It maintains the client-side state necessary to /// construct a ClientBuffer. /// \sa mir::frontend::ClientBufferTracker for the server-side analogue. /// \note Changes to the tracking algorithm will need associated server-side changes to mir::frontend::ClientBufferTracker class ClientBufferDepository { public: /// Constructor /// \param factory is the ClientBufferFactory that will be used to convert IPC data to ClientBuffers /// \param max_buffers is the number of buffers the depository will cache. After the client has received /// its initial buffers the ClientBufferDepository will always have the last max_buffers buffers /// cached. /// \note The server relies on the depository caching max_buffers buffers to optimise away buffer /// passing. As such, this number needs to be shared between the server and client libraries. ClientBufferDepository(std::shared_ptr const& factory, int max_buffers); /// Construct a ClientBuffer from the IPC data, and use it as the current buffer. /// This also marks the previous current buffer (if any) as being submitted to the server. /// \post current_buffer() will return a ClientBuffer constructed from this IPC data. void deposit_package(std::shared_ptr const&, int id, geometry::Size, MirPixelFormat); std::shared_ptr current_buffer(); uint32_t current_buffer_id() const; private: std::shared_ptr const factory; std::list>> buffers; unsigned int const max_buffers; }; } } #endif /* MIR_CLIENT_PRIVATE_MIR_CLIENT_BUFFER_DEPOSITORY_H_ */ mir-0.1.8+14.04.20140411/src/client/mir_wait_handle.h0000644000015301777760000000252712322054223022246 0ustar pbusernogroup00000000000000/* * 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 * Daniel van Vugt */ #ifndef MIR_CLIENT_MIR_WAIT_HANDLE_H_ #define MIR_CLIENT_MIR_WAIT_HANDLE_H_ #include #include #include /** * \addtogroup mir_toolkit * @{ */ struct MirWaitHandle { public: MirWaitHandle(); ~MirWaitHandle(); void expect_result(); void result_received(); void wait_for_all(); void wait_for_one(); void wait_for_pending(std::chrono::milliseconds limit); private: std::mutex guard; std::condition_variable wait_condition; int expecting; int received; }; /**@}*/ #endif /* MIR_CLIENT_MIR_WAIT_HANDLE_H_ */ mir-0.1.8+14.04.20140411/src/client/client_context.h0000644000015301777760000000230612322054223022135 0ustar pbusernogroup00000000000000/* * 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_CLIENT_CONTEXT_H_ #define MIR_CLIENT_CLIENT_CONTEXT_H_ namespace mir { namespace client { class ClientContext { public: virtual ~ClientContext() {} virtual MirConnection* mir_connection() = 0; virtual void populate(MirPlatformPackage& platform_package) = 0; protected: ClientContext() = default; ClientContext(const ClientContext&) = delete; ClientContext& operator=(const ClientContext&) = delete; }; } } #endif /* MIR_CLIENT_CLIENT_CONTEXT_H_ */ mir-0.1.8+14.04.20140411/src/client/logging/0000755000015301777760000000000012322054703020372 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/client/logging/input_receiver_report.h0000644000015301777760000000247412322054223025165 0ustar pbusernogroup00000000000000/* * 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_CLIENT_LOGGING_INPUT_RECEIVER_REPORT_H_ #define MIR_CLIENT_LOGGING_INPUT_RECEIVER_REPORT_H_ #include "mir/input/input_receiver_report.h" #include namespace mir { namespace logging { class Logger; } namespace client { namespace logging { class InputReceiverReport : public input::receiver::InputReceiverReport { public: InputReceiverReport(std::shared_ptr const& logger); void received_event(MirEvent const& event) override; private: std::shared_ptr const logger; }; } } } #endif /* MIR_CLIENT_LOGGING_INPUT_RECEIVER_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/client/logging/input_receiver_report.cpp0000644000015301777760000001103612322054223025512 0ustar pbusernogroup00000000000000/* * 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 "input_receiver_report.h" #include "mir/logging/logger.h" #include "mir/logging/input_timestamp.h" #include #include #include namespace ml = mir::logging; namespace mcll = mir::client::logging; namespace { std::string const component{"input-receiver"}; } mcll::InputReceiverReport::InputReceiverReport(std::shared_ptr const& logger) : logger{logger} { } namespace { static void format_key_event(std::stringstream &ss, MirKeyEvent const& ev) { ss << "MirKeyEvent {" << std::endl; ss << " device_id: " << ev.device_id << std::endl; ss << " source_id: " << ev.source_id << std::endl; ss << " action: " << ev.action << std::endl; ss << " flags: " << ev.flags << std::endl; ss << " modifiers: " << ev.modifiers << std::endl; ss << " key_code: " << ev.key_code << std::endl; ss << " scan_code: " << ev.scan_code << std::endl; ss << " repeat_count: " << ev.repeat_count << std::endl; ss << " down_time: " << ev.down_time << std::endl; ss << " event_time: " << ml::input_timestamp(ev.event_time) << std::endl; ss << " is_system_key: " << ev.is_system_key << std::endl; ss << "}"; } static void format_motion_event(std::stringstream &ss, MirMotionEvent const& ev) { ss << "MirMotionEvent{" << std::endl; ss << " type: motion" << std::endl; ss << " device_id: " << ev.device_id << std::endl; ss << " source_id: " << ev.source_id << std::endl; ss << " action: " << ev.action << std::endl; ss << " flags: " << ev.flags << std::endl; ss << " modifiers: " << ev.modifiers << std::endl; ss << " edge_flags: " << ev.edge_flags << std::endl; ss << " button_state: " << ev.button_state << std::endl; ss << " x_offset: " << ev.x_offset << std::endl; ss << " y_offset: " << ev.y_offset << std::endl; ss << " x_precision: " << ev.x_precision << std::endl; ss << " y_precision: " << ev.y_precision << std::endl; ss << " down_time: " << ev.down_time << std::endl; ss << " event_time: " << ml::input_timestamp(ev.event_time) << std::endl; ss << " pointer_count: " << ev.pointer_count << std::endl; for (unsigned int i = 0; i < ev.pointer_count; i++) { ss << " pointer[" << i << "]{" << std::endl; ss << " id: " << ev.pointer_coordinates[i].id << std::endl; ss << " x: " << ev.pointer_coordinates[i].x << std::endl; ss << " raw_x: " << ev.pointer_coordinates[i].raw_x << std::endl; ss << " y: " << ev.pointer_coordinates[i].y << std::endl; ss << " raw_y: " << ev.pointer_coordinates[i].raw_y << std::endl; ss << " touch_major: " << ev.pointer_coordinates[i].touch_major << std::endl; ss << " touch_minor: " << ev.pointer_coordinates[i].touch_minor << std::endl; ss << " size: " << ev.pointer_coordinates[i].size << std::endl; ss << " pressure: " << ev.pointer_coordinates[i].pressure << std::endl; ss << " orientation: " << ev.pointer_coordinates[i].orientation << std::endl; ss << " vscroll: " << ev.pointer_coordinates[i].vscroll << std::endl; ss << " hscroll: " << ev.pointer_coordinates[i].hscroll << std::endl; ss << " }" << std::endl; } ss << "}"; } static void format_event(std::stringstream &ss, MirEvent const& ev) { switch (ev.type) { case mir_event_type_key: format_key_event(ss, ev.key); break; case mir_event_type_motion: format_motion_event(ss, ev.motion); break; default: BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected event type")); } } } void mcll::InputReceiverReport::received_event( MirEvent const& event) { std::stringstream ss; ss << "Received event:" << std::endl; format_event(ss, event); logger->log(ml::Logger::debug, ss.str(), component); } mir-0.1.8+14.04.20140411/src/client/logging/rpc_report.h0000644000015301777760000000460612322054223022725 0ustar pbusernogroup00000000000000/* * 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_CLIENT_LOGGING_RPC_REPORT_H_ #define MIR_CLIENT_LOGGING_RPC_REPORT_H_ #include "../rpc/rpc_report.h" #include namespace mir { namespace logging { class Logger; } namespace client { namespace logging { class RpcReport : public rpc::RpcReport { public: RpcReport(std::shared_ptr const& logger); void invocation_requested(mir::protobuf::wire::Invocation const& invocation) override; void invocation_succeeded(mir::protobuf::wire::Invocation const& invocation) override; void invocation_failed(mir::protobuf::wire::Invocation const& invocation, boost::system::error_code const& error) override; void header_receipt_failed(boost::system::error_code const& error) override; void result_receipt_succeeded(mir::protobuf::wire::Result const& result) override; void result_receipt_failed(std::exception const& ex) override; void event_parsing_succeeded(MirEvent const& event) override; void event_parsing_failed(mir::protobuf::Event const& event) override; void orphaned_result(mir::protobuf::wire::Result const& result) override; void complete_response(mir::protobuf::wire::Result const& result) override; void result_processing_failed(mir::protobuf::wire::Result const& result, std::exception const& ex) override; void file_descriptors_received(google::protobuf::Message const& response, std::vector const& fds) override; void connection_failure(std::exception const& ex) override; private: std::shared_ptr const logger; }; } } } #endif /* MIR_CLIENT_LOGGING_RPC_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/client/logging/rpc_report.cpp0000644000015301777760000001076012322054223023256 0ustar pbusernogroup00000000000000/* * 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 "rpc_report.h" #include "mir/logging/logger.h" #include "mir_protobuf_wire.pb.h" #include #include namespace ml = mir::logging; namespace mcll = mir::client::logging; namespace { std::string const component{"rpc"}; } mcll::RpcReport::RpcReport(std::shared_ptr const& logger) : logger{logger} { } void mcll::RpcReport::invocation_requested( mir::protobuf::wire::Invocation const& invocation) { std::stringstream ss; ss << "Invocation request: id: " << invocation.id() << " method_name: " << invocation.method_name(); logger->log(ml::Logger::debug, ss.str(), component); } void mcll::RpcReport::invocation_succeeded( mir::protobuf::wire::Invocation const& invocation) { std::stringstream ss; ss << "Invocation succeeded: id: " << invocation.id() << " method_name: " << invocation.method_name(); logger->log(ml::Logger::debug, ss.str(), component); } void mcll::RpcReport::invocation_failed( mir::protobuf::wire::Invocation const& invocation, boost::system::error_code const& error) { std::stringstream ss; ss << "Invocation failed: id: " << invocation.id() << " method_name: " << invocation.method_name() << " error: " << error.message(); logger->log(ml::Logger::error, ss.str(), component); } void mcll::RpcReport::header_receipt_failed( boost::system::error_code const& error) { std::stringstream ss; ss << "Header receipt failed: " << " error: " << error.message(); logger->log(ml::Logger::error, ss.str(), component); } void mcll::RpcReport::result_receipt_succeeded( mir::protobuf::wire::Result const& result) { std::stringstream ss; ss << "Result received: id: " << result.id(); logger->log(ml::Logger::debug, ss.str(), component); } void mcll::RpcReport::result_receipt_failed( std::exception const& ex) { std::stringstream ss; ss << "Result receipt failed: reason: " << ex.what(); logger->log(ml::Logger::error, ss.str(), component); } void mcll::RpcReport::event_parsing_succeeded( MirEvent const& /*event*/) { std::stringstream ss; /* TODO: Log more information about event */ ss << "Event parsed"; logger->log(ml::Logger::debug, ss.str(), component); } void mcll::RpcReport::event_parsing_failed( mir::protobuf::Event const& /*event*/) { std::stringstream ss; /* TODO: Log more information about event */ ss << "Event parsing failed"; logger->log(ml::Logger::warning, ss.str(), component); } void mcll::RpcReport::orphaned_result( mir::protobuf::wire::Result const& result) { std::stringstream ss; ss << "Orphaned result: " << result.ShortDebugString(); logger->log(ml::Logger::error, ss.str(), component); } void mcll::RpcReport::complete_response( mir::protobuf::wire::Result const& result) { std::stringstream ss; ss << "Complete response: id: " << result.id(); logger->log(ml::Logger::debug, ss.str(), component); } void mcll::RpcReport::result_processing_failed( mir::protobuf::wire::Result const& /*result*/, std::exception const& ex) { std::stringstream ss; ss << "Result processing failed: reason: " << ex.what(); logger->log(ml::Logger::error, ss.str(), component); } void mcll::RpcReport::file_descriptors_received( google::protobuf::Message const& /*response*/, std::vector const& fds) { std::stringstream ss; ss << "File descriptors received: "; for (auto f : fds) ss << f << " "; logger->log(ml::Logger::debug, ss.str(), component); } void mcll::RpcReport::connection_failure(std::exception const& x) { std::stringstream ss; ss << "Connection failure: " << boost::diagnostic_information(x) << std::endl; logger->log(ml::Logger::warning, ss.str(), component); } mir-0.1.8+14.04.20140411/src/client/mirclient.pc.in0000644000015301777760000000051512322054223021661 0ustar pbusernogroup00000000000000prefix=@PREFIX@ exec_prefix=@EXEC_PREFIX@ libdir=@LIBDIR@ includedir=@INCLUDEDIR@ Name: mirclient Description: Mir client library Version: @MIR_VERSION_MAJOR@.@MIR_VERSION_MINOR@.@MIR_VERSION_PATCH@ Requires.private: protobuf >= 2.4.1 Requires: mircommon Libs: -L@LIBDIR@ -lmirclient -lmirprotobuf -lprotobuf Cflags: -I@INCLUDEDIR@ mir-0.1.8+14.04.20140411/src/client/client_platform.h0000644000015301777760000000364112322054223022300 0ustar pbusernogroup00000000000000/* * 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_CLIENT_PLATFORM_H_ #define MIR_CLIENT_CLIENT_PLATFORM_H_ #include "mir/graphics/native_buffer.h" #include "mir_toolkit/client_types.h" #include "mir_toolkit/mir_native_buffer.h" #include "egl_native_window_factory.h" #include #include namespace mir { namespace client { class ClientBufferFactory; class ClientSurface; class ClientContext; /** * Interface to client-side platform specific support for graphics operations. * \ingroup platform_enablement */ class ClientPlatform : public EGLNativeWindowFactory { public: ClientPlatform() = default; ClientPlatform(const ClientPlatform& p) = delete; ClientPlatform& operator=(const ClientPlatform& p) = delete; virtual ~ClientPlatform() { /* TODO: make nothrow */ } virtual MirPlatformType platform_type() const = 0; virtual std::shared_ptr create_buffer_factory() = 0; virtual std::shared_ptr create_egl_native_window(ClientSurface *surface) = 0; virtual std::shared_ptr create_egl_native_display() = 0; virtual MirNativeBuffer* convert_native_buffer(graphics::NativeBuffer*) const = 0; }; } } #endif /* MIR_CLIENT_CLIENT_PLATFORM_H_ */ mir-0.1.8+14.04.20140411/src/client/lifecycle_control.cpp0000644000015301777760000000243012322054223023143 0ustar pbusernogroup00000000000000/* * 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: Ricardo Mendoza */ #include "lifecycle_control.h" namespace mcl = mir::client; mcl::LifecycleControl::LifecycleControl() : handle_lifecycle_event([](MirLifecycleState){}) { } mcl::LifecycleControl::~LifecycleControl() { } void mcl::LifecycleControl::set_lifecycle_event_handler(std::function const& fn) { std::unique_lock lk(guard); handle_lifecycle_event = fn; } void mcl::LifecycleControl::call_lifecycle_event_handler(uint32_t state) { std::unique_lock lk(guard); handle_lifecycle_event(static_cast(state)); } mir-0.1.8+14.04.20140411/src/client/client_buffer_depository.cpp0000644000015301777760000000422412322054223024537 0ustar pbusernogroup00000000000000/* * 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.h" #include "client_buffer_factory.h" #include "client_buffer_depository.h" #include #include #include namespace mcl=mir::client; mcl::ClientBufferDepository::ClientBufferDepository(std::shared_ptr const& factory, int max_buffers) : factory(factory), max_buffers(max_buffers) { } void mcl::ClientBufferDepository::deposit_package(std::shared_ptr const& package, int id, geometry::Size size, MirPixelFormat pf) { auto existing_buffer_id_pair = buffers.end(); for (auto pair = buffers.begin(); pair != buffers.end(); ++pair) { pair->second->increment_age(); if (pair->first == id) existing_buffer_id_pair = pair; } if (buffers.size() > 0) buffers.front().second->mark_as_submitted(); if (existing_buffer_id_pair == buffers.end()) { auto new_buffer = factory->create_buffer(package, size, pf); buffers.push_front(std::make_pair(id, new_buffer)); } else { buffers.push_front(*existing_buffer_id_pair); buffers.erase(existing_buffer_id_pair); } if (buffers.size() > max_buffers) buffers.pop_back(); } std::shared_ptr mcl::ClientBufferDepository::current_buffer() { return buffers.front().second; } uint32_t mcl::ClientBufferDepository::current_buffer_id() const { return buffers.front().first; } mir-0.1.8+14.04.20140411/src/client/aging_buffer.h0000644000015301777760000000216012322054223021527 0ustar pbusernogroup00000000000000/* * 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 "client_buffer.h" namespace mir { namespace client { class AgingBuffer : public ClientBuffer { public: AgingBuffer(); virtual uint32_t age() const; virtual void increment_age(); virtual void mark_as_submitted(); private: uint32_t buffer_age; }; } } #endif /* MIR_CLIENT_AGING_BUFFER_H_ */ mir-0.1.8+14.04.20140411/src/client/mir_client_library.cpp0000644000015301777760000003466512322054247023342 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/default_configuration.h" #include "mir/raii.h" #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/mir_client_library_drm.h" #include "mir_toolkit/mir_client_library_debug.h" #include "mir_connection.h" #include "display_configuration.h" #include "mir_surface.h" #include "egl_native_display_container.h" #include "default_connection_configuration.h" #include "lifecycle_control.h" #include "api_impl_types.h" #include #include #include #include namespace mcl = mir::client; namespace { class ConnectionList { public: void insert(MirConnection* connection) { std::lock_guard lock(connection_guard); connections.insert(connection); } void remove(MirConnection* connection) { std::lock_guard lock(connection_guard); connections.erase(connection); } bool contains(MirConnection* connection) { std::lock_guard lock(connection_guard); return connections.count(connection); } private: std::mutex connection_guard; std::unordered_set connections; }; ConnectionList error_connections; // assign_result is compatible with all 2-parameter callbacks void assign_result(void *result, void **context) { if (context) *context = result; } size_t division_ceiling(size_t a, size_t b) { return ((a - 1) / b) + 1; } } MirWaitHandle* mir_default_connect( char const* socket_file, char const* name, mir_connected_callback callback, void * context) { try { std::string sock; if (socket_file) sock = socket_file; else { auto socket_env = getenv("MIR_SOCKET"); if (socket_env) sock = socket_env; else sock = mir::default_server_socket; } mcl::DefaultConnectionConfiguration conf{sock}; std::unique_ptr connection{new MirConnection(conf)}; auto const result = connection->connect(name, callback, context); connection.release(); return result; } catch (std::exception const& x) { MirConnection* error_connection = new MirConnection(x.what()); error_connections.insert(error_connection); callback(error_connection, context); return nullptr; } } void mir_default_connection_release(MirConnection * connection) { if (!error_connections.contains(connection)) { try { auto wait_handle = connection->disconnect(); wait_handle->wait_for_all(); } catch (std::exception const&) { // We're implementing a C API so no exceptions are to be // propagated. And that's OK because if disconnect() fails, // we don't care why. We're finished with the connection anyway. } } else { error_connections.remove(connection); } delete connection; } //mir_connect and mir_connection_release can be overridden by test code that sets these function //pointers to do things like stub out the graphics drivers or change the connection configuration. //TODO: we could have a more comprehensive solution that allows us to substitute any of the functions //for test purposes, not just the connect functions mir_connect_impl_func mir_connect_impl = mir_default_connect; mir_connection_release_impl_func mir_connection_release_impl = mir_default_connection_release; MirWaitHandle* mir_connect(char const* socket_file, char const* name, mir_connected_callback callback, void * context) { try { return mir_connect_impl(socket_file, name, callback, context); } catch (std::exception const&) { return nullptr; } } void mir_connection_release(MirConnection *connection) { try { return mir_connection_release_impl(connection); } catch (std::exception const&) { } } MirConnection *mir_connect_sync(char const *server, char const *app_name) { MirConnection *conn = nullptr; mir_wait_for(mir_connect(server, app_name, reinterpret_cast (assign_result), &conn)); return conn; } MirBool mir_connection_is_valid(MirConnection * connection) { return MirConnection::is_valid(connection) ? mir_true : mir_false; } char const * mir_connection_get_error_message(MirConnection * connection) { return connection->get_error_message(); } MirEGLNativeDisplayType mir_connection_get_egl_native_display(MirConnection *connection) { return connection->egl_native_display(); } void mir_connection_get_available_surface_formats( MirConnection * connection, MirPixelFormat* formats, unsigned const int format_size, unsigned int *num_valid_formats) { if ((connection) && (formats) && (num_valid_formats)) connection->available_surface_formats(formats, format_size, *num_valid_formats); } MirWaitHandle* mir_connection_create_surface( MirConnection* connection, MirSurfaceParameters const* params, mir_surface_callback callback, void* context) { if (error_connections.contains(connection)) return 0; try { return connection->create_surface(*params, callback, context); } catch (std::exception const&) { // TODO callback with an error surface return nullptr; } } MirSurface* mir_connection_create_surface_sync( MirConnection* connection, MirSurfaceParameters const* params) { MirSurface *surface = nullptr; mir_wait_for(mir_connection_create_surface(connection, params, reinterpret_cast(assign_result), &surface)); return surface; } void mir_surface_set_event_handler(MirSurface *surface, MirEventDelegate const *event_handler) { surface->set_event_handler(event_handler); } MirWaitHandle* mir_surface_release( MirSurface * surface, mir_surface_callback callback, void * context) { try { return surface->release_surface(callback, context); } catch (std::exception const&) { return nullptr; } } void mir_surface_release_sync(MirSurface *surface) { mir_wait_for(mir_surface_release(surface, reinterpret_cast(assign_result), nullptr)); } int mir_surface_get_id(MirSurface * surface) { return mir_debug_surface_id(surface); } int mir_debug_surface_id(MirSurface * surface) { return surface->id(); } MirBool mir_surface_is_valid(MirSurface* surface) { return surface->is_valid() ? mir_true : mir_false; } char const * mir_surface_get_error_message(MirSurface * surface) { return surface->get_error_message(); } void mir_surface_get_parameters(MirSurface * surface, MirSurfaceParameters *parameters) { *parameters = surface->get_parameters(); } MirPlatformType mir_surface_get_platform_type(MirSurface * surface) { return surface->platform_type(); } void mir_surface_get_current_buffer(MirSurface * surface, MirNativeBuffer ** buffer_package_out) { *buffer_package_out = surface->get_current_buffer_package(); } uint32_t mir_debug_surface_current_buffer_id(MirSurface * surface) { return surface->get_current_buffer_id(); } void mir_connection_get_platform(MirConnection *connection, MirPlatformPackage *platform_package) { connection->populate(*platform_package); } MirDisplayConfiguration* mir_connection_create_display_config(MirConnection *connection) { if (connection) return connection->create_copy_of_display_config(); return nullptr; } void mir_display_config_destroy(MirDisplayConfiguration* configuration) { mcl::delete_config_storage(configuration); } //TODO: DEPRECATED: remove this function void mir_connection_get_display_info(MirConnection *connection, MirDisplayInfo *display_info) { auto const config = mir::raii::deleter_for( mir_connection_create_display_config(connection), &mir_display_config_destroy); if (config->num_outputs < 1) return; MirDisplayOutput* state = nullptr; // We can't handle more than one display, so just populate based on the first // active display we find. for (unsigned int i = 0; i < config->num_outputs; ++i) { if (config->outputs[i].used && config->outputs[i].connected && config->outputs[i].current_mode < config->outputs[i].num_modes) { state = &config->outputs[i]; break; } } // Oh, oh! No connected outputs?! if (state == nullptr) { memset(display_info, 0, sizeof(*display_info)); return; } MirDisplayMode mode = state->modes[state->current_mode]; display_info->width = mode.horizontal_resolution; display_info->height = mode.vertical_resolution; unsigned int format_items; if (state->num_output_formats > mir_supported_pixel_format_max) format_items = mir_supported_pixel_format_max; else format_items = state->num_output_formats; display_info->supported_pixel_format_items = format_items; for(auto i=0u; i < format_items; i++) { display_info->supported_pixel_format[i] = state->output_formats[i]; } } void mir_surface_get_graphics_region(MirSurface * surface, MirGraphicsRegion * graphics_region) { surface->get_cpu_region( *graphics_region); } MirWaitHandle* mir_surface_swap_buffers(MirSurface *surface, mir_surface_callback callback, void * context) try { return surface->next_buffer(callback, context); } catch (std::exception const&) { return nullptr; } void mir_surface_swap_buffers_sync(MirSurface *surface) { mir_wait_for(mir_surface_swap_buffers(surface, reinterpret_cast(assign_result), nullptr)); } void mir_wait_for(MirWaitHandle* wait_handle) { if (wait_handle) wait_handle->wait_for_all(); } void mir_wait_for_one(MirWaitHandle* wait_handle) { if (wait_handle) wait_handle->wait_for_one(); } MirEGLNativeWindowType mir_surface_get_egl_native_window(MirSurface *surface) { return reinterpret_cast(surface->generate_native_window()); } MirWaitHandle* mir_surface_set_type(MirSurface *surf, MirSurfaceType type) { try { return surf ? surf->configure(mir_surface_attrib_type, type) : nullptr; } catch (std::exception const&) { return nullptr; } } MirSurfaceType mir_surface_get_type(MirSurface *surf) { MirSurfaceType type = mir_surface_type_normal; if (surf) { // Only the client will ever change the type of a surface so it is // safe to get the type from a local cache surf->attrib(). int t = surf->attrib(mir_surface_attrib_type); type = static_cast(t); } return type; } MirWaitHandle* mir_surface_set_state(MirSurface *surf, MirSurfaceState state) { try { return surf ? surf->configure(mir_surface_attrib_state, state) : nullptr; } catch (std::exception const&) { return nullptr; } } MirSurfaceState mir_surface_get_state(MirSurface *surf) { MirSurfaceState state = mir_surface_state_unknown; try { if (surf) { int s = surf->attrib(mir_surface_attrib_state); if (s == mir_surface_state_unknown) { surf->configure(mir_surface_attrib_state, mir_surface_state_unknown)->wait_for_all(); s = surf->attrib(mir_surface_attrib_state); } state = static_cast(s); } } catch (std::exception const&) { } return state; } MirWaitHandle* mir_surface_set_swapinterval(MirSurface* surf, int interval) { if ((interval < 0) || (interval > 1)) return nullptr; try { return surf ? surf->configure(mir_surface_attrib_swapinterval, interval) : nullptr; } catch (std::exception const&) { return nullptr; } } int mir_surface_get_swapinterval(MirSurface* surf) { return surf ? surf->attrib(mir_surface_attrib_swapinterval) : -1; } void mir_connection_set_lifecycle_event_callback(MirConnection* connection, mir_lifecycle_event_callback callback, void* context) { if (!error_connections.contains(connection)) connection->register_lifecycle_event_callback(callback, context); } void mir_connection_set_display_config_change_callback(MirConnection* connection, mir_display_config_callback callback, void* context) { if (connection) connection->register_display_change_callback(callback, context); } MirWaitHandle* mir_connection_apply_display_config(MirConnection *connection, MirDisplayConfiguration* display_configuration) { try { return connection ? connection->configure_display(display_configuration) : nullptr; } catch (std::exception const&) { return nullptr; } } /************************** * DRM specific functions * **************************/ MirWaitHandle *mir_connection_drm_auth_magic(MirConnection* connection, unsigned int magic, mir_drm_auth_magic_callback callback, void* context) { return connection->drm_auth_magic(magic, callback, context); } int mir_connection_drm_set_gbm_device(MirConnection* connection, struct gbm_device* gbm_dev) { size_t const pointer_size_in_ints = division_ceiling(sizeof(gbm_dev), sizeof(int)); std::vector extra_data(pointer_size_in_ints); memcpy(extra_data.data(), &gbm_dev, sizeof(gbm_dev)); return connection->set_extra_platform_data(extra_data); } mir-0.1.8+14.04.20140411/src/client/mir_screencast.h0000644000015301777760000000622612322054223022121 0ustar pbusernogroup00000000000000/* * 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_CLIENT_MIR_SCREENCAST_H_ #define MIR_CLIENT_MIR_SCREENCAST_H_ #include "mir_client_surface.h" #include "mir_wait_handle.h" #include "client_buffer_depository.h" #include "mir_toolkit/client_types.h" #include "mir_protobuf.pb.h" #include "mir/geometry/size.h" #include "mir/geometry/rectangle.h" #include namespace mir { namespace protobuf { class DisplayServer; } namespace client { class ClientBufferFactory; class EGLNativeWindowFactory; } } struct MirScreencast : public mir::client::ClientSurface { public: MirScreencast( mir::geometry::Rectangle const& region, mir::geometry::Size const& size, MirPixelFormat pixel_format, mir::protobuf::DisplayServer& server, std::shared_ptr const& egl_native_window_factory, std::shared_ptr const& factory, mir_screencast_callback callback, void* context); MirWaitHandle* creation_wait_handle(); bool valid(); MirWaitHandle* release( mir_screencast_callback callback, void* context); MirWaitHandle* next_buffer( mir_screencast_callback callback, void* context); EGLNativeWindowType egl_native_window(); /* mir::client::ClientSurface */ MirSurfaceParameters get_parameters() const; std::shared_ptr get_current_buffer(); void request_and_wait_for_next_buffer(); void request_and_wait_for_configure(MirSurfaceAttrib a, int value); private: void process_buffer(mir::protobuf::Buffer const& buffer); void screencast_created( mir_screencast_callback callback, void* context); void released( mir_screencast_callback callback, void* context); void next_buffer_received( mir_screencast_callback callback, void* context); mir::protobuf::DisplayServer& server; mir::geometry::Size const output_size; MirPixelFormat const output_format; std::shared_ptr const egl_native_window_factory; mir::client::ClientBufferDepository buffer_depository; std::shared_ptr egl_native_window_; mir::protobuf::Screencast protobuf_screencast; mir::protobuf::Buffer protobuf_buffer; mir::protobuf::Void protobuf_void; MirWaitHandle create_screencast_wait_handle; MirWaitHandle release_wait_handle; MirWaitHandle next_buffer_wait_handle; }; #endif /* MIR_CLIENT_MIR_SCREENCAST_H_ */ mir-0.1.8+14.04.20140411/src/client/rpc/0000755000015301777760000000000012322054703017530 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/client/rpc/mir_socket_rpc_channel.cpp0000644000015301777760000003267512322054247024747 0ustar pbusernogroup00000000000000/* * 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_socket_rpc_channel.h" #include "rpc_report.h" #include "mir/protobuf/google_protobuf_guard.h" #include "../surface_map.h" #include "../mir_surface.h" #include "../display_configuration.h" #include "../lifecycle_control.h" #include "mir_protobuf.pb.h" // For Buffer frig #include "mir_protobuf_wire.pb.h" #include #include #include #include #include namespace mcl = mir::client; namespace mclr = mir::client::rpc; namespace { std::chrono::milliseconds const timeout(200); } mclr::MirSocketRpcChannel::MirSocketRpcChannel( std::string const& endpoint, std::shared_ptr const& surface_map, std::shared_ptr const& disp_config, std::shared_ptr const& rpc_report, std::shared_ptr const& lifecycle_control) : rpc_report(rpc_report), pending_calls(rpc_report), work(io_service), socket(io_service), surface_map(surface_map), display_configuration(disp_config), lifecycle_control(lifecycle_control), disconnected(false) { socket.connect(endpoint); init(); } mclr::MirSocketRpcChannel::MirSocketRpcChannel( int native_socket, std::shared_ptr const& surface_map, std::shared_ptr const& disp_config, std::shared_ptr const& rpc_report, std::shared_ptr const& lifecycle_control) : rpc_report(rpc_report), pending_calls(rpc_report), work(io_service), socket(io_service), surface_map(surface_map), display_configuration(disp_config), lifecycle_control(lifecycle_control), disconnected(false) { socket.assign(boost::asio::local::stream_protocol(), native_socket); init(); } void mclr::MirSocketRpcChannel::notify_disconnected() { if (!disconnected.exchange(true)) { io_service.stop(); socket.close(); lifecycle_control->call_lifecycle_event_handler(mir_lifecycle_connection_lost); } pending_calls.force_completion(); } void mclr::MirSocketRpcChannel::init() { io_service_thread = std::thread([this] { // Our IO threads must not receive any signals sigset_t all_signals; sigfillset(&all_signals); if (auto error = pthread_sigmask(SIG_BLOCK, &all_signals, NULL)) BOOST_THROW_EXCEPTION( boost::enable_error_info( std::runtime_error("Failed to block signals on IO thread")) << boost::errinfo_errno(error)); boost::asio::async_read( socket, boost::asio::buffer(header_bytes), boost::asio::transfer_exactly(sizeof header_bytes), boost::bind(&MirSocketRpcChannel::on_header_read, this, boost::asio::placeholders::error)); try { io_service.run(); } catch (std::exception const& x) { rpc_report->connection_failure(x); notify_disconnected(); } }); } mclr::MirSocketRpcChannel::~MirSocketRpcChannel() { io_service.stop(); if (io_service_thread.joinable()) { io_service_thread.join(); } } // TODO: This function needs some work. void mclr::MirSocketRpcChannel::receive_file_descriptors(google::protobuf::Message* response, google::protobuf::Closure* complete) { if (!disconnected.load()) { auto const message_type = response->GetTypeName(); mir::protobuf::Surface* surface = nullptr; mir::protobuf::Buffer* buffer = nullptr; mir::protobuf::Platform* platform = nullptr; if (message_type == "mir.protobuf.Buffer") { buffer = static_cast(response); } else if (message_type == "mir.protobuf.Surface") { surface = static_cast(response); if (surface && surface->has_buffer()) buffer = surface->mutable_buffer(); } else if (message_type == "mir.protobuf.Screencast") { auto screencast = static_cast(response); if (screencast && screencast->has_buffer()) buffer = screencast->mutable_buffer(); } else if (message_type == "mir.protobuf.Platform") { platform = static_cast(response); } else if (message_type == "mir.protobuf.Connection") { auto connection = static_cast(response); if (connection && connection->has_platform()) platform = connection->mutable_platform(); } if (surface) { surface->clear_fd(); if (surface->fds_on_side_channel() > 0) { std::vector fds(surface->fds_on_side_channel()); receive_file_descriptors(fds); for (auto &fd: fds) surface->add_fd(fd); rpc_report->file_descriptors_received(*response, fds); } } if (buffer) { buffer->clear_fd(); if (buffer->fds_on_side_channel() > 0) { std::vector fds(buffer->fds_on_side_channel()); receive_file_descriptors(fds); for (auto &fd: fds) buffer->add_fd(fd); rpc_report->file_descriptors_received(*response, fds); } } if (platform) { platform->clear_fd(); if (platform->fds_on_side_channel() > 0) { std::vector fds(platform->fds_on_side_channel()); receive_file_descriptors(fds); for (auto &fd: fds) platform->add_fd(fd); rpc_report->file_descriptors_received(*response, fds); } } } complete->Run(); } void mclr::MirSocketRpcChannel::receive_file_descriptors(std::vector &fds) { // We send dummy data struct iovec iov; char dummy_iov_data = '\0'; iov.iov_base = &dummy_iov_data; iov.iov_len = 1; // Allocate space for control message auto n_fds = fds.size(); std::vector control(sizeof(struct cmsghdr) + sizeof(int) * n_fds); // Message to send struct msghdr header; header.msg_name = NULL; header.msg_namelen = 0; header.msg_iov = &iov; header.msg_iovlen = 1; header.msg_controllen = control.size(); header.msg_control = control.data(); header.msg_flags = 0; // Control message contains file descriptors struct cmsghdr *message = CMSG_FIRSTHDR(&header); message->cmsg_len = header.msg_controllen; message->cmsg_level = SOL_SOCKET; message->cmsg_type = SCM_RIGHTS; using std::chrono::steady_clock; auto time_limit = steady_clock::now() + timeout; while (recvmsg(socket.native_handle(), &header, 0) < 0) { if (steady_clock::now() > time_limit) return; } // Copy file descriptors back to caller n_fds = (message->cmsg_len - sizeof(struct cmsghdr)) / sizeof(int); fds.resize(n_fds); int *data = (int *)CMSG_DATA(message); for (std::vector::size_type i = 0; i < n_fds; i++) fds[i] = data[i]; } void mclr::MirSocketRpcChannel::CallMethod( const google::protobuf::MethodDescriptor* method, google::protobuf::RpcController*, const google::protobuf::Message* parameters, google::protobuf::Message* response, google::protobuf::Closure* complete) { auto const& invocation = invocation_for(method, parameters); rpc_report->invocation_requested(invocation); std::shared_ptr callback( google::protobuf::NewPermanentCallback(this, &MirSocketRpcChannel::receive_file_descriptors, response, complete)); // Only save details after serialization succeeds pending_calls.save_completion_details(invocation, response, callback); // Only send message when details saved for handling response send_message(invocation, invocation); } void mclr::MirSocketRpcChannel::send_message( mir::protobuf::wire::Invocation const& body, mir::protobuf::wire::Invocation const& invocation) { const size_t size = body.ByteSize(); const unsigned char header_bytes[2] = { static_cast((size >> 8) & 0xff), static_cast((size >> 0) & 0xff) }; detail::SendBuffer send_buffer(sizeof header_bytes + size); std::copy(header_bytes, header_bytes + sizeof header_bytes, send_buffer.begin()); body.SerializeToArray(send_buffer.data() + sizeof header_bytes, size); boost::system::error_code error; boost::asio::write( socket, boost::asio::buffer(send_buffer), error); if (error) { rpc_report->invocation_failed(invocation, error); notify_disconnected(); BOOST_THROW_EXCEPTION(std::runtime_error("Failed to send message to server: " + error.message())); } rpc_report->invocation_succeeded(invocation); } void mclr::MirSocketRpcChannel::on_header_read(const boost::system::error_code& error) { if (error) { // If we've not got a response to a call pending // then during shutdown we expect to see "eof" if (!pending_calls.empty() || error != boost::asio::error::eof) { rpc_report->header_receipt_failed(error); BOOST_THROW_EXCEPTION(std::runtime_error("Failed to read message header: " + error.message())); } return; } read_message(); boost::asio::async_read( socket, boost::asio::buffer(header_bytes), boost::asio::transfer_exactly(sizeof header_bytes), boost::bind(&MirSocketRpcChannel::on_header_read, this, boost::asio::placeholders::error)); } void mclr::MirSocketRpcChannel::read_message() { mir::protobuf::wire::Result result; try { const size_t body_size = read_message_header(); read_message_body(result, body_size); rpc_report->result_receipt_succeeded(result); } catch (std::exception const& x) { rpc_report->result_receipt_failed(x); throw; } try { for (int i = 0; i != result.events_size(); ++i) { process_event_sequence(result.events(i)); } if (result.has_id()) { pending_calls.complete_response(result); } } catch (std::exception const& x) { rpc_report->result_processing_failed(result, x); // Eat this exception as it doesn't affect rpc } } void mclr::MirSocketRpcChannel::process_event_sequence(std::string const& event) { mir::protobuf::EventSequence seq; seq.ParseFromString(event); if (seq.has_display_configuration()) { display_configuration->update_configuration(seq.display_configuration()); } if (seq.has_lifecycle_event()) { lifecycle_control->call_lifecycle_event_handler(seq.lifecycle_event().new_state()); } int const nevents = seq.event_size(); for (int i = 0; i != nevents; ++i) { mir::protobuf::Event const& event = seq.event(i); if (event.has_raw()) { std::string const& raw_event = event.raw(); // In future, events might be compressed where possible. // But that's a job for later... if (raw_event.size() == sizeof(MirEvent)) { MirEvent e; // Make a copy to ensure integer fields get correct memory // alignment, which is critical on many non-x86 // architectures. memcpy(&e, raw_event.data(), sizeof e); rpc_report->event_parsing_succeeded(e); surface_map->with_surface_do(e.surface.id, [&e](MirSurface* surface) { surface->handle_event(e); }); } else { rpc_report->event_parsing_failed(event); } } } } size_t mclr::MirSocketRpcChannel::read_message_header() { const size_t body_size = (header_bytes[0] << 8) + header_bytes[1]; return body_size; } void mclr::MirSocketRpcChannel::read_message_body( mir::protobuf::wire::Result& result, size_t const body_size) { boost::system::error_code error; body_bytes.resize(body_size); boost::asio::read(socket, boost::asio::buffer(body_bytes), error); if (error) { BOOST_THROW_EXCEPTION(std::runtime_error("Failed to read message body: " + error.message())); } result.ParseFromArray(body_bytes.data(), body_size); } mir-0.1.8+14.04.20140411/src/client/rpc/mir_basic_rpc_channel.h0000644000015301777760000000476212322054247024201 0ustar pbusernogroup00000000000000/* * 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_CLIENT_RPC_MIR_BASIC_RPC_CHANNEL_H_ #define MIR_CLIENT_RPC_MIR_BASIC_RPC_CHANNEL_H_ #include #include #include #include #include #include namespace mir { namespace protobuf { namespace wire { class Invocation; class Result; } } namespace client { namespace rpc { class RpcReport; namespace detail { typedef std::vector SendBuffer; class PendingCallCache { public: PendingCallCache(std::shared_ptr const& rpc_report); void save_completion_details( mir::protobuf::wire::Invocation const& invoke, google::protobuf::Message* response, std::shared_ptr const& complete); void complete_response(mir::protobuf::wire::Result& result); void force_completion(); bool empty() const; private: struct PendingCall { PendingCall( google::protobuf::Message* response, std::shared_ptr const& target) : response(response), complete(target) {} PendingCall() : response(0), complete() {} google::protobuf::Message* response; std::shared_ptr complete; }; std::mutex mutable mutex; std::map pending_calls; std::shared_ptr const rpc_report; }; } class MirBasicRpcChannel : public google::protobuf::RpcChannel { public: MirBasicRpcChannel(); ~MirBasicRpcChannel(); protected: mir::protobuf::wire::Invocation invocation_for( google::protobuf::MethodDescriptor const* method, google::protobuf::Message const* request); int next_id(); private: std::atomic next_message_id; }; } } } #endif /* MIR_CLIENT_RPC_MIR_BASIC_RPC_CHANNEL_H_ */ mir-0.1.8+14.04.20140411/src/client/rpc/make_socket_rpc_channel.cpp0000644000015301777760000000354612322054223025062 0ustar pbusernogroup00000000000000/* * 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 "make_rpc_channel.h" #include "mir_socket_rpc_channel.h" #include namespace mcl = mir::client; namespace mclr = mir::client::rpc; namespace { struct Prefix { template Prefix(char const (&prefix)[Size]) : size(Size-1), prefix(prefix) {} bool is_start_of(std::string const& name) const { return !strncmp(name.c_str(), prefix, size); } int const size; char const* const prefix; } const fd_prefix("fd://"); } std::shared_ptr mclr::make_rpc_channel(std::string const& name, std::shared_ptr const& map, std::shared_ptr const& disp_conf, std::shared_ptr const& rpc_report, std::shared_ptr const& lifecycle_control) { if (fd_prefix.is_start_of(name)) { auto const fd = atoi(name.c_str()+fd_prefix.size); return std::make_shared(fd, map, disp_conf, rpc_report, lifecycle_control); } return std::make_shared(name, map, disp_conf, rpc_report, lifecycle_control); } mir-0.1.8+14.04.20140411/src/client/rpc/mir_socket_rpc_channel.h0000644000015301777760000000675612322054247024415 0ustar pbusernogroup00000000000000/* * 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_CLIENT_RPC_MIR_SOCKET_RPC_CHANNEL_H_ #define MIR_CLIENT_RPC_MIR_SOCKET_RPC_CHANNEL_H_ #include "mir_basic_rpc_channel.h" #include #include #include #include namespace mir { namespace protobuf { namespace wire { class Invocation; class Result; } } namespace client { class DisplayConfiguration; class SurfaceMap; class LifecycleControl; namespace rpc { class RpcReport; class MirSocketRpcChannel : public MirBasicRpcChannel { public: MirSocketRpcChannel(std::string const& endpoint, std::shared_ptr const& surface_map, std::shared_ptr const& disp_config, std::shared_ptr const& rpc_report, std::shared_ptr const& lifecycle_control); MirSocketRpcChannel(int native_socket, std::shared_ptr const& surface_map, std::shared_ptr const& disp_config, std::shared_ptr const& rpc_report, std::shared_ptr const& lifecycle_control); ~MirSocketRpcChannel(); private: void init(); virtual void CallMethod(const google::protobuf::MethodDescriptor* method, google::protobuf::RpcController*, const google::protobuf::Message* parameters, google::protobuf::Message* response, google::protobuf::Closure* complete); std::shared_ptr const rpc_report; detail::PendingCallCache pending_calls; std::thread io_service_thread; boost::asio::io_service io_service; boost::asio::io_service::work work; boost::asio::local::stream_protocol::socket socket; static size_t const size_of_header = 2; unsigned char header_bytes[size_of_header]; std::vector body_bytes; void receive_file_descriptors(google::protobuf::Message* response, google::protobuf::Closure* complete); void receive_file_descriptors(std::vector &fds); void send_message(mir::protobuf::wire::Invocation const& body, mir::protobuf::wire::Invocation const& invocation); void on_header_read(const boost::system::error_code& error); void read_message(); void process_event_sequence(std::string const& event); size_t read_message_header(); void read_message_body(mir::protobuf::wire::Result& result, size_t const body_size); void notify_disconnected(); std::shared_ptr surface_map; std::shared_ptr display_configuration; std::shared_ptr lifecycle_control; std::atomic disconnected; }; } } } #endif /* MIR_CLIENT_RPC_MIR_SOCKET_RPC_CHANNEL_H_ */ mir-0.1.8+14.04.20140411/src/client/rpc/rpc_report.h0000644000015301777760000000505412322054223022061 0ustar pbusernogroup00000000000000/* * 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_CLIENT_RPC_RPC_REPORT_H_ #define MIR_CLIENT_RPC_RPC_REPORT_H_ #include #include #include namespace mir { namespace protobuf { class Event; namespace wire { class Invocation; class Result; } } namespace client { namespace rpc { class RpcReport { public: virtual ~RpcReport() = default; virtual void invocation_requested(mir::protobuf::wire::Invocation const& invocation) = 0; virtual void invocation_succeeded(mir::protobuf::wire::Invocation const& invocation) = 0; virtual void invocation_failed(mir::protobuf::wire::Invocation const& invocation, boost::system::error_code const& error) = 0; virtual void header_receipt_failed(boost::system::error_code const& error) = 0; virtual void result_receipt_succeeded(mir::protobuf::wire::Result const& result) = 0; virtual void result_receipt_failed(std::exception const& ex) = 0; virtual void event_parsing_succeeded(MirEvent const& event) = 0; virtual void event_parsing_failed(mir::protobuf::Event const& event) = 0; virtual void orphaned_result(mir::protobuf::wire::Result const& result) = 0; virtual void complete_response(mir::protobuf::wire::Result const& result) = 0; virtual void result_processing_failed(mir::protobuf::wire::Result const& result, std::exception const& ex) = 0; virtual void file_descriptors_received(google::protobuf::Message const& response, std::vector const& fds) = 0; virtual void connection_failure(std::exception const& ex) = 0; protected: RpcReport() = default; RpcReport(RpcReport const&) = delete; RpcReport& operator=(RpcReport const&) = delete; }; } } } #endif /* MIR_CLIENT_RPC_RPC_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/client/rpc/mir_basic_rpc_channel.cpp0000644000015301777760000000645512322054247024535 0ustar pbusernogroup00000000000000/* * 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_basic_rpc_channel.h" #include "rpc_report.h" #include "mir_protobuf_wire.pb.h" #include "mir/frontend/client_constants.h" #include namespace mclr = mir::client::rpc; namespace mclrd = mir::client::rpc::detail; mclrd::PendingCallCache::PendingCallCache( std::shared_ptr const& rpc_report) : rpc_report{rpc_report} { } void mclrd::PendingCallCache::save_completion_details( mir::protobuf::wire::Invocation const& invoke, google::protobuf::Message* response, std::shared_ptr const& complete) { std::unique_lock lock(mutex); pending_calls[invoke.id()] = PendingCall(response, complete); } void mclrd::PendingCallCache::complete_response(mir::protobuf::wire::Result& result) { PendingCall completion; { std::unique_lock lock(mutex); auto call = pending_calls.find(result.id()); if (call != pending_calls.end()) { completion = call->second; pending_calls.erase(call); } } if (!completion.complete) { rpc_report->orphaned_result(result); } else { rpc_report->complete_response(result); completion.response->ParseFromString(result.response()); completion.complete->Run(); } } void mclrd::PendingCallCache::force_completion() { std::unique_lock lock(mutex); for (auto& call : pending_calls) { auto& completion = call.second; completion.complete->Run(); } pending_calls.erase(pending_calls.begin(), pending_calls.end()); } bool mclrd::PendingCallCache::empty() const { std::unique_lock lock(mutex); return pending_calls.empty(); } mclr::MirBasicRpcChannel::MirBasicRpcChannel() : next_message_id(0) { } mclr::MirBasicRpcChannel::~MirBasicRpcChannel() { } mir::protobuf::wire::Invocation mclr::MirBasicRpcChannel::invocation_for( google::protobuf::MethodDescriptor const* method, google::protobuf::Message const* request) { char buffer[mir::frontend::serialization_buffer_size]; auto const size = request->ByteSize(); // In practice size will be 10s of bytes - but have a test to detect problems assert(size < static_cast(sizeof buffer)); request->SerializeToArray(buffer, sizeof buffer); mir::protobuf::wire::Invocation invoke; invoke.set_id(next_id()); invoke.set_method_name(method->name()); invoke.set_parameters(buffer, size); invoke.set_protocol_version(1); return invoke; } int mclr::MirBasicRpcChannel::next_id() { return next_message_id.fetch_add(1); } mir-0.1.8+14.04.20140411/src/client/rpc/make_rpc_channel.h0000644000015301777760000000262412322054223023153 0ustar pbusernogroup00000000000000/* * 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_CLIENT_RPC_MAKE_RPC_CHANNEL_H_ #define MIR_CLIENT_RPC_MAKE_RPC_CHANNEL_H_ #include namespace google { namespace protobuf { class RpcChannel; } } namespace mir { namespace client { class SurfaceMap; class DisplayConfiguration; class LifecycleControl; namespace rpc { class RpcReport; std::shared_ptr make_rpc_channel(std::string const& name, std::shared_ptr const& map, std::shared_ptr const& disp_conf, std::shared_ptr const& rpc_report, std::shared_ptr const& lifecycle_control); } } } #endif /* MIR_CLIENT_RPC_MAKE_RPC_CHANNEL_H_ */ mir-0.1.8+14.04.20140411/src/client/rpc/null_rpc_report.h0000644000015301777760000000427512322054223023117 0ustar pbusernogroup00000000000000/* * 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_CLIENT_RPC_NULL_RPC_REPORT_H_ #define MIR_CLIENT_RPC_NULL_RPC_REPORT_H_ #include "rpc_report.h" namespace mir { namespace client { namespace rpc { class NullRpcReport : public RpcReport { public: void invocation_requested(mir::protobuf::wire::Invocation const& invocation) override; void invocation_succeeded(mir::protobuf::wire::Invocation const& invocation) override; void invocation_failed(mir::protobuf::wire::Invocation const& invocation, boost::system::error_code const& error) override; void header_receipt_failed(boost::system::error_code const& error) override; void result_receipt_succeeded(mir::protobuf::wire::Result const& result) override; void result_receipt_failed(std::exception const& ex) override; void event_parsing_succeeded(MirEvent const& event) override; void event_parsing_failed(mir::protobuf::Event const& event) override; void orphaned_result(mir::protobuf::wire::Result const& result) override; void complete_response(mir::protobuf::wire::Result const& result) override; void result_processing_failed(mir::protobuf::wire::Result const& result, std::exception const& ex) override; void file_descriptors_received(google::protobuf::Message const& response, std::vector const& fds) override; void connection_failure(std::exception const& ex) override; }; } } } #endif /* MIR_CLIENT_RPC_NULL_RPC_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/client/rpc/null_rpc_report.cpp0000644000015301777760000000426112322054223023445 0ustar pbusernogroup00000000000000/* * 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 "null_rpc_report.h" namespace mclr = mir::client::rpc; void mclr::NullRpcReport::invocation_requested( mir::protobuf::wire::Invocation const& /*invocation*/) { } void mclr::NullRpcReport::invocation_succeeded( mir::protobuf::wire::Invocation const& /*invocation*/) { } void mclr::NullRpcReport::invocation_failed( mir::protobuf::wire::Invocation const& /*invocation*/, boost::system::error_code const& /*error*/) { } void mclr::NullRpcReport::header_receipt_failed( boost::system::error_code const& /*error*/) { } void mclr::NullRpcReport::result_receipt_succeeded( mir::protobuf::wire::Result const& /*result*/) { } void mclr::NullRpcReport::result_receipt_failed( std::exception const& /*ex*/) { } void mclr::NullRpcReport::event_parsing_succeeded( MirEvent const& /*event*/) { } void mclr::NullRpcReport::event_parsing_failed( mir::protobuf::Event const& /*event*/) { } void mclr::NullRpcReport::orphaned_result( mir::protobuf::wire::Result const& /*result*/) { } void mclr::NullRpcReport::complete_response( mir::protobuf::wire::Result const& /*result*/) { } void mclr::NullRpcReport::result_processing_failed( mir::protobuf::wire::Result const& /*result*/, std::exception const& /*ex*/) { } void mclr::NullRpcReport::file_descriptors_received( google::protobuf::Message const& /*response*/, std::vector const& /*fds*/) { } void mclr::NullRpcReport::connection_failure(std::exception const& /*ex*/) { } mir-0.1.8+14.04.20140411/src/client/rpc/CMakeLists.txt0000644000015301777760000000050412322054223022264 0ustar pbusernogroup00000000000000include_directories( ${PROTOBUF_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ) add_library( mirclientrpc STATIC mir_basic_rpc_channel.cpp null_rpc_report.cpp mir_socket_rpc_channel.cpp make_socket_rpc_channel.cpp ${PROTO_SRCS} ) target_link_libraries( mirclientrpc mirprotobuf ${PROTOBUF_LIBRARIES} ) mir-0.1.8+14.04.20140411/src/client/mir_wait_handle.cpp0000644000015301777760000000375412322054223022604 0ustar pbusernogroup00000000000000/* * 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 * Daniel van Vugt */ #include "mir_wait_handle.h" MirWaitHandle::MirWaitHandle() : guard(), wait_condition(), expecting(0), received(0) { } MirWaitHandle::~MirWaitHandle() { } void MirWaitHandle::expect_result() { std::unique_lock lock(guard); expecting++; } void MirWaitHandle::result_received() { std::unique_lock lock(guard); received++; wait_condition.notify_all(); } void MirWaitHandle::wait_for_all() // wait for all results you expect { std::unique_lock lock(guard); while ((!expecting && !received) || (received < expecting)) wait_condition.wait(lock); received = 0; expecting = 0; } void MirWaitHandle::wait_for_pending(std::chrono::milliseconds limit) { using std::chrono::steady_clock; std::unique_lock lock(guard); auto time_limit = steady_clock::now() + limit; while (received < expecting && steady_clock::now() < time_limit) wait_condition.wait_until(lock, time_limit); } void MirWaitHandle::wait_for_one() // wait for any single result { std::unique_lock lock(guard); while (received == 0) wait_condition.wait(lock); received--; if (expecting > 0) expecting--; } mir-0.1.8+14.04.20140411/src/client/private.cpp0000644000015301777760000000162612322054223021124 0ustar pbusernogroup00000000000000/* * 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: Alan Griffiths */ #include "mir/client/private.h" #include "mir_connection.h" auto mir::client::the_rpc_channel(MirConnection *connection) -> std::shared_ptr { return connection->rpc_channel(); } mir-0.1.8+14.04.20140411/src/client/display_configuration.h0000644000015301777760000000347212322054223023514 0ustar pbusernogroup00000000000000/* * 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_DISPLAY_CONFIGURATION_H_ #define MIR_CLIENT_DISPLAY_CONFIGURATION_H_ #include "mir_toolkit/client_types.h" #include "mir_protobuf.pb.h" #include #include #include #include namespace mir { namespace client { class DisplayOutput : public MirDisplayOutput { public: DisplayOutput(size_t num_modes_, size_t num_formats); ~DisplayOutput(); }; //convenient helper void delete_config_storage(MirDisplayConfiguration* config); class DisplayConfiguration { public: DisplayConfiguration(); ~DisplayConfiguration(); void set_configuration(mir::protobuf::DisplayConfiguration const& msg); void update_configuration(mir::protobuf::DisplayConfiguration const& msg); void set_display_change_handler(std::function const&); //copying to a c POD, so kinda kludgy MirDisplayConfiguration* copy_to_client() const; private: std::mutex mutable guard; std::vector cards; std::vector> outputs; std::function notify_change; }; } } #endif /* MIR_CLIENT_DISPLAY_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/src/client/mir_screencast_api.cpp0000644000015301777760000000522612322054223023304 0ustar pbusernogroup00000000000000/* * 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_toolkit/mir_screencast.h" #include "mir_screencast.h" #include "mir_connection.h" #include "mir/raii.h" #include #include namespace { void null_callback(MirScreencast*, void*) {} } MirScreencast* mir_connection_create_screencast_sync( MirConnection* connection, MirScreencastParameters* parameters) { if (!MirConnection::is_valid(connection)) return nullptr; MirScreencast* screencast = nullptr; try { auto const config = mir::raii::deleter_for( mir_connection_create_display_config(connection), &mir_display_config_destroy); auto const client_platform = connection->get_client_platform(); mir::geometry::Rectangle const region{ {parameters->region.left, parameters->region.top}, {parameters->region.width, parameters->region.height} }; mir::geometry::Size const size{parameters->width, parameters->height}; std::unique_ptr screencast_uptr{ new MirScreencast{ region, size, parameters->pixel_format, connection->display_server(), client_platform, client_platform->create_buffer_factory(), null_callback, nullptr}}; screencast_uptr->creation_wait_handle()->wait_for_all(); if (screencast_uptr->valid()) { screencast = screencast_uptr.get(); screencast_uptr.release(); } } catch (std::exception const&) { return nullptr; } return screencast; } void mir_screencast_release_sync(MirScreencast* screencast) { screencast->release(null_callback, nullptr)->wait_for_all(); delete screencast; } MirEGLNativeWindowType mir_screencast_egl_native_window(MirScreencast* screencast) { return reinterpret_cast(screencast->egl_native_window()); } mir-0.1.8+14.04.20140411/src/client/default_connection_configuration.h0000644000015301777760000000471612322054223025714 0ustar pbusernogroup00000000000000/* * 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_CLIENT_DEFAULT_CONNECTION_CONFIGURATION_H_ #define MIR_CLIENT_DEFAULT_CONNECTION_CONFIGURATION_H_ #include "connection_configuration.h" #include "mir/cached_ptr.h" #include namespace mir { namespace input { namespace receiver { class InputReceiverReport; } } namespace client { namespace rpc { class RpcReport; } class DefaultConnectionConfiguration : public ConnectionConfiguration { public: DefaultConnectionConfiguration(std::string const& socket_file); std::shared_ptr the_surface_map(); std::shared_ptr the_rpc_channel(); std::shared_ptr the_logger(); std::shared_ptr the_client_platform_factory(); std::shared_ptr the_input_platform(); std::shared_ptr the_display_configuration(); std::shared_ptr the_lifecycle_control(); virtual std::string the_socket_file(); virtual std::shared_ptr the_rpc_report(); virtual std::shared_ptr the_input_receiver_report(); protected: CachedPtr rpc_channel; CachedPtr logger; CachedPtr client_platform_factory; CachedPtr input_platform; CachedPtr surface_map; CachedPtr display_configuration; CachedPtr lifecycle_control; CachedPtr rpc_report; CachedPtr input_receiver_report; private: std::string const socket_file; }; } } #endif /* MIR_CLIENT_DEFAULT_CONNECTION_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/src/client/mir_connection.h0000644000015301777760000001245112322054223022123 0ustar pbusernogroup00000000000000/* * 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_CONNECTION_H_ #define MIR_CLIENT_MIR_CONNECTION_H_ #include #include #include #include #include #include "mir_protobuf.pb.h" #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/mir_client_library_drm.h" #include "client_platform.h" #include "client_context.h" #include "mir_wait_handle.h" namespace mir { /// The client-side library implementation namespace namespace client { class ConnectionConfiguration; class ClientPlatformFactory; class ConnectionSurfaceMap; class DisplayConfiguration; class LifecycleControl; namespace rpc { class MirBasicRpcChannel; } } namespace input { namespace receiver { class InputPlatform; } } namespace logging { class Logger; } } struct MirConnection : mir::client::ClientContext { public: MirConnection(std::string const& error_message); MirConnection(mir::client::ConnectionConfiguration& conf); ~MirConnection() noexcept; MirConnection(MirConnection const &) = delete; MirConnection& operator=(MirConnection const &) = delete; MirWaitHandle* create_surface( MirSurfaceParameters const & params, mir_surface_callback callback, void * context); MirWaitHandle* release_surface( MirSurface *surface, mir_surface_callback callback, void *context); char const * get_error_message(); MirWaitHandle* connect( const char* app_name, mir_connected_callback callback, void * context); MirWaitHandle* disconnect(); MirWaitHandle* drm_auth_magic(unsigned int magic, mir_drm_auth_magic_callback callback, void* context); void register_lifecycle_event_callback(mir_lifecycle_event_callback callback, void* context); void register_display_change_callback(mir_display_config_callback callback, void* context); void populate(MirPlatformPackage& platform_package); MirDisplayConfiguration* create_copy_of_display_config(); void available_surface_formats(MirPixelFormat* formats, unsigned int formats_size, unsigned int& valid_formats); std::shared_ptr get_client_platform(); static bool is_valid(MirConnection *connection); MirConnection* mir_connection(); EGLNativeDisplayType egl_native_display(); void on_surface_created(int id, MirSurface* surface); MirWaitHandle* configure_display(MirDisplayConfiguration* configuration); void done_display_configure(); bool set_extra_platform_data(std::vector const& extra_platform_data); std::shared_ptr rpc_channel() const { return channel; } mir::protobuf::DisplayServer& display_server(); private: std::mutex mutex; // Protects all members of *this (except release_wait_handles) std::shared_ptr const channel; mir::protobuf::DisplayServer::Stub server; std::shared_ptr const logger; mir::protobuf::Void void_response; mir::protobuf::Connection connect_result; mir::protobuf::Void ignored; mir::protobuf::ConnectParameters connect_parameters; mir::protobuf::DRMAuthMagicStatus drm_auth_magic_status; mir::protobuf::DisplayConfiguration display_configuration_response; std::shared_ptr const client_platform_factory; std::shared_ptr platform; std::shared_ptr native_display; std::shared_ptr const input_platform; std::string error_message; MirWaitHandle connect_wait_handle; MirWaitHandle disconnect_wait_handle; MirWaitHandle drm_auth_magic_wait_handle; MirWaitHandle configure_display_wait_handle; std::mutex release_wait_handle_guard; std::vector release_wait_handles; std::shared_ptr const display_configuration; std::shared_ptr const lifecycle_control; std::shared_ptr const surface_map; std::vector extra_platform_data; struct SurfaceRelease; void set_error_message(std::string const& error); void done_disconnect(); void connected(mir_connected_callback callback, void * context); void released(SurfaceRelease ); void done_drm_auth_magic(mir_drm_auth_magic_callback callback, void* context); bool validate_user_display_config(MirDisplayConfiguration* config); }; #endif /* MIR_CLIENT_MIR_CONNECTION_H_ */ mir-0.1.8+14.04.20140411/src/client/mir_screencast.cpp0000644000015301777760000001527312322054223022456 0ustar pbusernogroup00000000000000/* * 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_screencast.h" #include "mir/frontend/client_constants.h" #include "mir_toolkit/mir_native_buffer.h" #include "egl_native_window_factory.h" #include namespace mcl = mir::client; namespace geom = mir::geometry; namespace { void null_callback(MirScreencast*, void*) {} void populate_buffer_package( MirBufferPackage& buffer_package, mir::protobuf::Buffer const& protobuf_buffer) { if (!protobuf_buffer.has_error()) { buffer_package.data_items = protobuf_buffer.data_size(); for (int i = 0; i != protobuf_buffer.data_size(); ++i) { buffer_package.data[i] = protobuf_buffer.data(i); } buffer_package.fd_items = protobuf_buffer.fd_size(); for (int i = 0; i != protobuf_buffer.fd_size(); ++i) { buffer_package.fd[i] = protobuf_buffer.fd(i); } buffer_package.stride = protobuf_buffer.stride(); buffer_package.flags = protobuf_buffer.flags(); buffer_package.width = protobuf_buffer.width(); buffer_package.height = protobuf_buffer.height(); } else { buffer_package.data_items = 0; buffer_package.fd_items = 0; buffer_package.stride = 0; buffer_package.flags = 0; buffer_package.width = 0; buffer_package.height = 0; } } } MirScreencast::MirScreencast( geom::Rectangle const& region, geom::Size const& size, MirPixelFormat pixel_format, mir::protobuf::DisplayServer& server, std::shared_ptr const& egl_native_window_factory, std::shared_ptr const& factory, mir_screencast_callback callback, void* context) : server(server), output_size{size}, output_format{pixel_format}, egl_native_window_factory{egl_native_window_factory}, buffer_depository{factory, mir::frontend::client_buffer_cache_size} { if (output_size.width.as_int() == 0 || output_size.height.as_int() == 0 || region.size.width.as_int() == 0 || region.size.height.as_int() == 0 || pixel_format == mir_pixel_format_invalid) { BOOST_THROW_EXCEPTION(std::runtime_error("Invalid parameters")); } protobuf_screencast.set_error("Not initialized"); mir::protobuf::ScreencastParameters parameters; parameters.mutable_region()->set_left(region.top_left.x.as_int()); parameters.mutable_region()->set_top(region.top_left.y.as_int()); parameters.mutable_region()->set_width(region.size.width.as_uint32_t()); parameters.mutable_region()->set_height(region.size.height.as_uint32_t()); parameters.set_width(output_size.width.as_uint32_t()); parameters.set_height(output_size.height.as_uint32_t()); parameters.set_pixel_format(pixel_format); server.create_screencast( nullptr, ¶meters, &protobuf_screencast, google::protobuf::NewCallback( this, &MirScreencast::screencast_created, callback, context)); } MirWaitHandle* MirScreencast::creation_wait_handle() { return &create_screencast_wait_handle; } bool MirScreencast::valid() { return !protobuf_screencast.has_error(); } MirSurfaceParameters MirScreencast::get_parameters() const { return MirSurfaceParameters{ "", output_size.width.as_int(), output_size.height.as_int(), output_format, mir_buffer_usage_hardware, mir_display_output_id_invalid}; } std::shared_ptr MirScreencast::get_current_buffer() { return buffer_depository.current_buffer(); } MirWaitHandle* MirScreencast::release( mir_screencast_callback callback, void* context) { mir::protobuf::ScreencastId screencast_id; screencast_id.set_value(protobuf_screencast.screencast_id().value()); server.release_screencast( nullptr, &screencast_id, &protobuf_void, google::protobuf::NewCallback( this, &MirScreencast::released, callback, context)); return &release_wait_handle; } MirWaitHandle* MirScreencast::next_buffer( mir_screencast_callback callback, void* context) { mir::protobuf::ScreencastId screencast_id; screencast_id.set_value(protobuf_screencast.screencast_id().value()); server.screencast_buffer( nullptr, &screencast_id, &protobuf_buffer, google::protobuf::NewCallback( this, &MirScreencast::next_buffer_received, callback, context)); return &next_buffer_wait_handle; } EGLNativeWindowType MirScreencast::egl_native_window() { return *egl_native_window_; } void MirScreencast::request_and_wait_for_next_buffer() { next_buffer(null_callback, nullptr)->wait_for_all(); } void MirScreencast::request_and_wait_for_configure(MirSurfaceAttrib, int) { } void MirScreencast::process_buffer(mir::protobuf::Buffer const& buffer) { auto buffer_package = std::make_shared(); populate_buffer_package(*buffer_package, buffer); try { buffer_depository.deposit_package(buffer_package, buffer.buffer_id(), output_size, output_format); } catch (const std::runtime_error& err) { // TODO: Report the error } } void MirScreencast::screencast_created( mir_screencast_callback callback, void* context) { if (!protobuf_screencast.has_error()) { egl_native_window_ = egl_native_window_factory->create_egl_native_window(this); process_buffer(protobuf_screencast.buffer()); } callback(this, context); create_screencast_wait_handle.result_received(); } void MirScreencast::released( mir_screencast_callback callback, void* context) { callback(this, context); release_wait_handle.result_received(); } void MirScreencast::next_buffer_received( mir_screencast_callback callback, void* context) { process_buffer(protobuf_buffer); callback(this, context); next_buffer_wait_handle.result_received(); } mir-0.1.8+14.04.20140411/src/client/mir_connection.cpp0000644000015301777760000003465112322054223022464 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_connection.h" #include "mir_surface.h" #include "client_platform.h" #include "client_platform_factory.h" #include "rpc/mir_basic_rpc_channel.h" #include "connection_configuration.h" #include "display_configuration.h" #include "connection_surface_map.h" #include "lifecycle_control.h" #include "mir/logging/logger.h" #include #include #include #include namespace mcl = mir::client; namespace mircv = mir::input::receiver; namespace gp = google::protobuf; namespace { class MirDisplayConfigurationStore { public: MirDisplayConfigurationStore(MirDisplayConfiguration* config) : config{config} { } ~MirDisplayConfigurationStore() { mcl::delete_config_storage(config); } MirDisplayConfiguration* operator->() const { return config; } private: MirDisplayConfigurationStore(MirDisplayConfigurationStore const&) = delete; MirDisplayConfigurationStore& operator=(MirDisplayConfigurationStore const&) = delete; MirDisplayConfiguration* const config; }; std::mutex connection_guard; std::unordered_set valid_connections; } MirConnection::MirConnection(std::string const& error_message) : channel(), server(0), error_message(error_message) { } MirConnection::MirConnection( mir::client::ConnectionConfiguration& conf) : channel(conf.the_rpc_channel()), server(channel.get(), ::google::protobuf::Service::STUB_DOESNT_OWN_CHANNEL), logger(conf.the_logger()), client_platform_factory(conf.the_client_platform_factory()), input_platform(conf.the_input_platform()), display_configuration(conf.the_display_configuration()), lifecycle_control(conf.the_lifecycle_control()), surface_map(conf.the_surface_map()) { connect_result.set_error("connect not called"); { std::lock_guard lock(connection_guard); valid_connections.insert(this); } } MirConnection::~MirConnection() noexcept { // We don't die while if are pending callbacks (as they touch this). // But, if after 500ms we don't get a call, assume it won't happen. connect_wait_handle.wait_for_pending(std::chrono::milliseconds(500)); { std::lock_guard lock(connection_guard); valid_connections.erase(this); } std::lock_guard lock(mutex); if (connect_result.has_platform()) { auto const& platform = connect_result.platform(); for (int i = 0, end = platform.fd_size(); i != end; ++i) close(platform.fd(i)); } } MirWaitHandle* MirConnection::create_surface( MirSurfaceParameters const & params, mir_surface_callback callback, void * context) { auto surface = new MirSurface(this, server, platform->create_buffer_factory(), input_platform, params, callback, context); return surface->get_create_wait_handle(); } char const * MirConnection::get_error_message() { std::lock_guard lock(mutex); if (connect_result.has_error()) { return connect_result.error().c_str(); } return error_message.c_str(); } void MirConnection::set_error_message(std::string const& error) { error_message = error; } /* struct exists to work around google protobuf being able to bind "only 0, 1, or 2 arguments in the NewCallback function */ struct MirConnection::SurfaceRelease { MirSurface * surface; MirWaitHandle * handle; mir_surface_callback callback; void * context; }; void MirConnection::released(SurfaceRelease data) { surface_map->erase(data.surface->id()); // Erasing this surface from surface_map means that it will no longer receive events // If it's still focused, send an unfocused event before we kill it entirely if (data.surface->attrib(mir_surface_attrib_focus) == mir_surface_focused) { MirEvent unfocus; unfocus.type = mir_event_type_surface; unfocus.surface.id = data.surface->id(); unfocus.surface.attrib = mir_surface_attrib_focus; unfocus.surface.value = mir_surface_unfocused; data.surface->handle_event(unfocus); } data.callback(data.surface, data.context); data.handle->result_received(); delete data.surface; } MirWaitHandle* MirConnection::release_surface( MirSurface *surface, mir_surface_callback callback, void * context) { auto new_wait_handle = new MirWaitHandle; SurfaceRelease surf_release{surface, new_wait_handle, callback, context}; mir::protobuf::SurfaceId message; message.set_value(surface->id()); { std::lock_guard rel_lock(release_wait_handle_guard); release_wait_handles.push_back(new_wait_handle); } server.release_surface(0, &message, &void_response, gp::NewCallback(this, &MirConnection::released, surf_release)); return new_wait_handle; } namespace { void default_lifecycle_event_handler(MirLifecycleState transition) { if (transition == mir_lifecycle_connection_lost) { raise(SIGTERM); } } } void MirConnection::connected(mir_connected_callback callback, void * context) { bool safe_to_callback = true; { std::lock_guard lock(mutex); if (!connect_result.has_platform() || !connect_result.has_display_configuration()) { if (!connect_result.has_error()) { // We're handling an error scenario that means we're not sync'd // with the client code - a callback isn't safe (or needed) safe_to_callback = false; set_error_message("Connect failed"); } } /* * We need to create the client platform after the connection has been * established, to ensure that the client platform has access to all * needed data (e.g. platform package). */ platform = client_platform_factory->create_client_platform(this); native_display = platform->create_egl_native_display(); display_configuration->set_configuration(connect_result.display_configuration()); lifecycle_control->set_lifecycle_event_handler(default_lifecycle_event_handler); } if (safe_to_callback) callback(this, context); connect_wait_handle.result_received(); } MirWaitHandle* MirConnection::connect( const char* app_name, mir_connected_callback callback, void * context) { { std::lock_guard lock(mutex); connect_parameters.set_application_name(app_name); connect_wait_handle.expect_result(); } server.connect( 0, &connect_parameters, &connect_result, google::protobuf::NewCallback( this, &MirConnection::connected, callback, context)); return &connect_wait_handle; } void MirConnection::done_disconnect() { /* todo: keeping all MirWaitHandles from a release surface until the end of the connection is a kludge until we have a better story about the lifetime of MirWaitHandles */ { std::lock_guard lock(release_wait_handle_guard); for (auto handle : release_wait_handles) delete handle; } disconnect_wait_handle.result_received(); } MirWaitHandle* MirConnection::disconnect() { server.disconnect(0, &ignored, &ignored, google::protobuf::NewCallback(this, &MirConnection::done_disconnect)); return &disconnect_wait_handle; } void MirConnection::done_drm_auth_magic(mir_drm_auth_magic_callback callback, void* context) { int const status_code{drm_auth_magic_status.status_code()}; callback(status_code, context); drm_auth_magic_wait_handle.result_received(); } MirWaitHandle* MirConnection::drm_auth_magic(unsigned int magic, mir_drm_auth_magic_callback callback, void* context) { mir::protobuf::DRMMagic request; request.set_magic(magic); server.drm_auth_magic( 0, &request, &drm_auth_magic_status, google::protobuf::NewCallback(this, &MirConnection::done_drm_auth_magic, callback, context)); return &drm_auth_magic_wait_handle; } bool MirConnection::is_valid(MirConnection *connection) { { std::lock_guard lock(connection_guard); if (valid_connections.count(connection) == 0) return false; } std::lock_guardmutex)> lock(connection->mutex); return !connection->connect_result.has_error(); } void MirConnection::populate(MirPlatformPackage& platform_package) { std::lock_guard lock(mutex); if (!connect_result.has_error() && connect_result.has_platform()) { auto const& platform = connect_result.platform(); platform_package.data_items = platform.data_size(); for (int i = 0; i != platform.data_size(); ++i) platform_package.data[i] = platform.data(i); platform_package.fd_items = platform.fd_size(); for (int i = 0; i != platform.fd_size(); ++i) platform_package.fd[i] = platform.fd(i); for (auto d : extra_platform_data) platform_package.data[platform_package.data_items++] = d; } else { platform_package.data_items = 0; platform_package.fd_items = 0; } } MirDisplayConfiguration* MirConnection::create_copy_of_display_config() { std::lock_guard lock(mutex); return display_configuration->copy_to_client(); } void MirConnection::available_surface_formats( MirPixelFormat* formats, unsigned int formats_size, unsigned int& valid_formats) { valid_formats = 0; std::lock_guard lock(mutex); if (!connect_result.has_error()) { valid_formats = std::min( static_cast(connect_result.surface_pixel_format_size()), formats_size); for (auto i = 0u; i < valid_formats; i++) { formats[i] = static_cast(connect_result.surface_pixel_format(i)); } } } std::shared_ptr MirConnection::get_client_platform() { std::lock_guard lock(mutex); return platform; } MirConnection* MirConnection::mir_connection() { return this; } EGLNativeDisplayType MirConnection::egl_native_display() { std::lock_guard lock(mutex); return *native_display; } void MirConnection::on_surface_created(int id, MirSurface* surface) { surface_map->insert(id, surface); } void MirConnection::register_lifecycle_event_callback(mir_lifecycle_event_callback callback, void* context) { lifecycle_control->set_lifecycle_event_handler(std::bind(callback, this, std::placeholders::_1, context)); } void MirConnection::register_display_change_callback(mir_display_config_callback callback, void* context) { display_configuration->set_display_change_handler(std::bind(callback, this, context)); } bool MirConnection::validate_user_display_config(MirDisplayConfiguration* config) { MirDisplayConfigurationStore orig_config{display_configuration->copy_to_client()}; if ((!config) || (config->num_outputs == 0) || (config->outputs == NULL) || (config->num_outputs > orig_config->num_outputs)) { return false; } for(auto i = 0u; i < config->num_outputs; i++) { auto const& output = config->outputs[i]; auto const& orig_output = orig_config->outputs[i]; if (output.output_id != orig_output.output_id) return false; if (output.connected && output.current_mode >= orig_output.num_modes) return false; } return true; } void MirConnection::done_display_configure() { std::lock_guard lock(mutex); set_error_message(display_configuration_response.error()); if (!display_configuration_response.has_error()) display_configuration->set_configuration(display_configuration_response); return configure_display_wait_handle.result_received(); } MirWaitHandle* MirConnection::configure_display(MirDisplayConfiguration* config) { if (!validate_user_display_config(config)) { return NULL; } mir::protobuf::DisplayConfiguration request; { std::lock_guard lock(mutex); for (auto i=0u; i < config->num_outputs; i++) { auto output = config->outputs[i]; auto display_request = request.add_display_output(); display_request->set_output_id(output.output_id); display_request->set_used(output.used); display_request->set_current_mode(output.current_mode); display_request->set_current_format(output.current_format); display_request->set_position_x(output.position_x); display_request->set_position_y(output.position_y); display_request->set_power_mode(output.power_mode); display_request->set_orientation(output.orientation); } } server.configure_display(0, &request, &display_configuration_response, google::protobuf::NewCallback(this, &MirConnection::done_display_configure)); return &configure_display_wait_handle; } bool MirConnection::set_extra_platform_data( std::vector const& extra_platform_data_arg) { std::lock_guard lock(mutex); auto const total_data_size = connect_result.platform().data_size() + extra_platform_data_arg.size(); if (total_data_size > mir_platform_package_max) return false; extra_platform_data = extra_platform_data_arg; return true; } mir::protobuf::DisplayServer& MirConnection::display_server() { return server; } mir-0.1.8+14.04.20140411/src/client/lttng/0000755000015301777760000000000012322054703020074 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/client/lttng/client_tracepoint_provider.h0000644000015301777760000000215412322054223025664 0ustar pbusernogroup00000000000000/* * 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_CLIENT_LTTNG_CLIENT_TRACEPOINT_PROVIDER_H_ #define MIR_CLIENT_LTTNG_CLIENT_TRACEPOINT_PROVIDER_H_ #include "mir/report/lttng/tracepoint_provider.h" namespace mir { namespace client { namespace lttng { class ClientTracepointProvider : public mir::report::lttng::TracepointProvider { public: ClientTracepointProvider(); }; } } } #endif /* MIR_CLIENT_LTTNG_CLIENT_TRACEPOINT_PROVIDER_H_ */ mir-0.1.8+14.04.20140411/src/client/lttng/input_receiver_report.h0000644000015301777760000000244212322054223024662 0ustar pbusernogroup00000000000000/* * 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: Andreas Pokorny */ #ifndef MIR_CLIENT_LTTNG_INPUT_RECEIVER_REPORT_H_ #define MIR_CLIENT_LTTNG_INPUT_RECEIVER_REPORT_H_ #include "mir/input/input_receiver_report.h" #include "client_tracepoint_provider.h" namespace mir { namespace client { namespace lttng { class InputReceiverReport : public input::receiver::InputReceiverReport { public: void received_event(MirEvent const& event) override; private: void report(MirKeyEvent const& event) const; void report(MirMotionEvent const& event) const; ClientTracepointProvider tp_provider; }; } } } #endif /* MIR_CLIENT_LTTNG_INPUT_RECEIVER_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/client/lttng/rpc_report_tp.h0000644000015301777760000000505312322054247023135 0ustar pbusernogroup00000000000000/* * 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 */ #undef TRACEPOINT_PROVIDER #define TRACEPOINT_PROVIDER mir_client_rpc #undef TRACEPOINT_INCLUDE #define TRACEPOINT_INCLUDE "./rpc_report_tp.h" #if !defined(MIR_CLIENT_LTTNG_RPC_REPORT_TP_H_) || defined(TRACEPOINT_HEADER_MULTI_READ) #define MIR_CLIENT_LTTNG_RPC_REPORT_TP_H_ #include #include #ifdef __clang__ /* * TRACEPOINT_EVENT defines functions; since we disable tracepoints under clang * these functions are unused and so generate fatal warnings. * (see mir_tracepoint.h and http://sourceware.org/bugzilla/show_bug.cgi?id=13974) */ #pragma clang diagnostic push #pragma clang diagnostic warning "-Wunused-function" #endif TRACEPOINT_EVENT( mir_client_rpc, invocation_requested, TP_ARGS(uint32_t, id, const char*, method), TP_FIELDS( ctf_integer(uint32_t, id, id) ctf_string(method, method) ) ) TRACEPOINT_EVENT( mir_client_rpc, invocation_succeeded, TP_ARGS(uint32_t, id, const char*, method), TP_FIELDS( ctf_integer(uint32_t, id, id) ctf_string(method, method) ) ) TRACEPOINT_EVENT( mir_client_rpc, result_receipt_succeeded, TP_ARGS(uint32_t, id), TP_FIELDS( ctf_integer(uint32_t, id, id) ) ) TRACEPOINT_EVENT( mir_client_rpc, event_parsing_succeeded, TP_ARGS(int, dummy), TP_FIELDS( ctf_integer(int, dummy, dummy) ) ) TRACEPOINT_EVENT( mir_client_rpc, complete_response, TP_ARGS(uint32_t, id), TP_FIELDS( ctf_integer(uint32_t, id, id) ) ) TRACEPOINT_EVENT( mir_client_rpc, file_descriptors_received, TP_ARGS(const int32_t*, fds, size_t, len), TP_FIELDS( ctf_sequence(int32_t, fds, fds, size_t, len) ) ) #ifdef __clang__ #pragma clang diagnostic pop #endif #endif /* MIR_CLIENT_LTTNG_RPC_REPORT_TP_H_ */ #include mir-0.1.8+14.04.20140411/src/client/lttng/input_receiver_report_tp.h0000644000015301777760000000677112322054247025404 0ustar pbusernogroup00000000000000/* * 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: Andreas Pokorny */ #undef TRACEPOINT_PROVIDER #define TRACEPOINT_PROVIDER mir_client_input_receiver #undef TRACEPOINT_INCLUDE #define TRACEPOINT_INCLUDE "./input_receiver_report_tp.h" #if !defined(MIR_CLIENT_LTTNG_INPUT_RECEIVER_REPORT_TP_H_) || defined(TRACEPOINT_HEADER_MULTI_READ) #define MIR_CLIENT_LTTNG_INPUT_RECEIVER_REPORT_TP_H_ #include #include #ifdef __clang__ /* * TRACEPOINT_EVENT defines functions; since we disable tracepoints under clang * these functions are unused and so generate fatal warnings. * (see mir_tracepoint.h and http://sourceware.org/bugzilla/show_bug.cgi?id=13974) */ #pragma clang diagnostic push #pragma clang diagnostic warning "-Wunused-function" #endif TRACEPOINT_EVENT( mir_client_input_receiver, key_event, TP_ARGS(int32_t, device_id, int32_t, source_id, int, action, int, flags, unsigned int, modifiers, int32_t, key_code, int32_t, scan_code, int64_t, down_time, int64_t, event_time), TP_FIELDS( ctf_integer(int32_t, device_id, device_id) ctf_integer(int32_t, source_id, source_id) ctf_integer(int, action, action) ctf_integer(int, flags, flags) ctf_integer(unsigned int, modifiers, modifiers) ctf_integer(int32_t, key_code, key_code) ctf_integer(int32_t, scan_code, scan_code) ctf_integer(int64_t, down_time, down_time) ctf_integer(int64_t, event_time, event_time) ) ) TRACEPOINT_EVENT( mir_client_input_receiver, motion_event, TP_ARGS(int32_t, device_id, int32_t, source_id, int, action, int, flags, unsigned int, modifiers, int32_t, edge_flags, int, button_state, int64_t, down_time, int64_t, event_time), TP_FIELDS( ctf_integer(int32_t, device_id, device_id) ctf_integer(int32_t, source_id, source_id) ctf_integer(int, action, action) ctf_integer(int, flags, flags) ctf_integer(unsigned int, modifiers, modifiers) ctf_integer(int32_t, edge_flags, edge_flags) ctf_integer(int, button_state, button_state) ctf_integer(int64_t, down_time, down_time) ctf_integer(int64_t, event_time, event_time) ) ) TRACEPOINT_EVENT( mir_client_input_receiver, motion_event_coordinate, TP_ARGS(int, id, float, x, float, y, float, touch_major, float, touch_minor, float, size, float, pressure, float, orientation), TP_FIELDS( ctf_integer(int, id, id) ctf_float(float, x, x) ctf_float(float, y, y) ctf_float(float, touch_major, touch_major) ctf_float(float, touch_minor, touch_minor) ctf_float(float, size, size) ctf_float(float, pressure, pressure) ctf_float(float, orientation, orientation) ) ) #ifdef __clang__ #pragma clang diagnostic pop #endif #endif /* MIR_CLIENT_LTTNG_INPUT_RECEIVER_REPORT_TP_H_ */ #include mir-0.1.8+14.04.20140411/src/client/lttng/input_receiver_report.cpp0000644000015301777760000000505712322054223025222 0ustar pbusernogroup00000000000000/* * 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: Andreas Pokorny */ #include "input_receiver_report.h" #include "mir/report/lttng/mir_tracepoint.h" #include #include #define TRACEPOINT_DEFINE #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE #include "input_receiver_report_tp.h" void mir::client::lttng::InputReceiverReport::received_event(MirEvent const& event) { switch (event.type) { case mir_event_type_key: report(event.key); break; case mir_event_type_motion: report(event.motion); break; default: BOOST_THROW_EXCEPTION(std::runtime_error("Unexpected event type")); } } void mir::client::lttng::InputReceiverReport::report(MirKeyEvent const& event) const { mir_tracepoint(mir_client_input_receiver, key_event, event.device_id, event.source_id, static_cast(event.action), static_cast(event.flags), event.modifiers, event.key_code, event.scan_code, event.down_time, event.event_time); } void mir::client::lttng::InputReceiverReport::report(MirMotionEvent const& event) const { mir_tracepoint(mir_client_input_receiver, motion_event, event.device_id, event.source_id, event.action, static_cast(event.flags), event.modifiers, event.edge_flags, static_cast(event.button_state), event.down_time, event.event_time); for (unsigned int i = 0; i < event.pointer_count; i++) { mir_tracepoint(mir_client_input_receiver, motion_event_coordinate, event.pointer_coordinates[i].id, event.pointer_coordinates[i].x, event.pointer_coordinates[i].y, event.pointer_coordinates[i].touch_major, event.pointer_coordinates[i].touch_minor, event.pointer_coordinates[i].size, event.pointer_coordinates[i].pressure, event.pointer_coordinates[i].orientation); } } mir-0.1.8+14.04.20140411/src/client/lttng/rpc_report.h0000644000015301777760000000443212322054223022424 0ustar pbusernogroup00000000000000/* * 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_CLIENT_LTTNG_RPC_REPORT_H_ #define MIR_CLIENT_LTTNG_RPC_REPORT_H_ #include "../rpc/rpc_report.h" #include "client_tracepoint_provider.h" namespace mir { namespace client { namespace lttng { class RpcReport : public rpc::RpcReport { public: void invocation_requested(mir::protobuf::wire::Invocation const& invocation) override; void invocation_succeeded(mir::protobuf::wire::Invocation const& invocation) override; void invocation_failed(mir::protobuf::wire::Invocation const& invocation, boost::system::error_code const& error) override; void header_receipt_failed(boost::system::error_code const& error) override; void result_receipt_succeeded(mir::protobuf::wire::Result const& result) override; void result_receipt_failed(std::exception const& ex) override; void event_parsing_succeeded(MirEvent const& event) override; void event_parsing_failed(mir::protobuf::Event const& event) override; void orphaned_result(mir::protobuf::wire::Result const& result) override; void complete_response(mir::protobuf::wire::Result const& result) override; void result_processing_failed(mir::protobuf::wire::Result const& result, std::exception const& ex) override; void file_descriptors_received(google::protobuf::Message const& response, std::vector const& fds) override; void connection_failure(std::exception const& ex) override; private: ClientTracepointProvider tp_provider; }; } } } #endif /* MIR_CLIENT_LTTNG_RPC_REPORT_H_ */ mir-0.1.8+14.04.20140411/src/client/lttng/rpc_report.cpp0000644000015301777760000000570612322054223022764 0ustar pbusernogroup00000000000000/* * 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 "rpc_report.h" #include "mir/report/lttng/mir_tracepoint.h" #include "mir_protobuf_wire.pb.h" #define TRACEPOINT_DEFINE #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE #include "rpc_report_tp.h" namespace mcl = mir::client; void mcl::lttng::RpcReport::invocation_requested( mir::protobuf::wire::Invocation const& invocation) { mir_tracepoint(mir_client_rpc, invocation_requested, invocation.id(), invocation.method_name().c_str()); } void mcl::lttng::RpcReport::invocation_succeeded( mir::protobuf::wire::Invocation const& invocation) { mir_tracepoint(mir_client_rpc, invocation_succeeded, invocation.id(), invocation.method_name().c_str()); } void mcl::lttng::RpcReport::invocation_failed( mir::protobuf::wire::Invocation const& /*invocation*/, boost::system::error_code const& /*error*/) { } void mcl::lttng::RpcReport::header_receipt_failed( boost::system::error_code const& /*error*/) { } void mcl::lttng::RpcReport::result_receipt_succeeded( mir::protobuf::wire::Result const& result) { mir_tracepoint(mir_client_rpc, result_receipt_succeeded, result.id()); } void mcl::lttng::RpcReport::result_receipt_failed( std::exception const& /*ex*/) { } void mcl::lttng::RpcReport::event_parsing_succeeded( MirEvent const& /*event*/) { /* TODO: Record more information about event */ mir_tracepoint(mir_client_rpc, event_parsing_succeeded, 0); } void mcl::lttng::RpcReport::event_parsing_failed( mir::protobuf::Event const& /*event*/) { } void mcl::lttng::RpcReport::orphaned_result( mir::protobuf::wire::Result const& /*result*/) { } void mcl::lttng::RpcReport::complete_response( mir::protobuf::wire::Result const& result) { mir_tracepoint(mir_client_rpc, complete_response, result.id()); } void mcl::lttng::RpcReport::result_processing_failed( mir::protobuf::wire::Result const& /*result*/, std::exception const& /*ex*/) { } void mcl::lttng::RpcReport::file_descriptors_received( google::protobuf::Message const& /*response*/, std::vector const& fds) { mir_tracepoint(mir_client_rpc, file_descriptors_received, fds.data(), fds.size()); } void mcl::lttng::RpcReport::connection_failure(std::exception const& /*ex*/) { } mir-0.1.8+14.04.20140411/src/client/lttng/CMakeLists.txt0000644000015301777760000000156112322054223022634 0ustar pbusernogroup00000000000000include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${LTTNG_UST_INCLUDE_DIRS}) add_library( mirclientlttngstatic STATIC client_tracepoint_provider.cpp rpc_report.cpp input_receiver_report.cpp ) add_library(mirclientlttng SHARED tracepoints.c) # Don't treat missing-field-initializers as an error, since # the LTTng macros contain code that triggers this (but it's # harmless; it concerns a padding field) set_target_properties(mirclientlttngstatic PROPERTIES COMPILE_FLAGS "-Wno-error=missing-field-initializers -Wno-error=unused-function" ) set_target_properties(mirclientlttng PROPERTIES COMPILE_FLAGS "-Wno-error=unused-function" ) target_link_libraries( mirclientlttngstatic mirsharedlttng -ldl ) target_link_libraries( mirclientlttng ${LTTNG_UST_LIBRARIES} ) install(TARGETS mirclientlttng LIBRARY DESTINATION ${MIR_TRACEPOINT_LIB_INSTALL_DIR} ) mir-0.1.8+14.04.20140411/src/client/lttng/tracepoints.c0000644000015301777760000000023612322054223022571 0ustar pbusernogroup00000000000000/* The probes need to be compiled in a C file (not C++) */ #define TRACEPOINT_CREATE_PROBES #include "rpc_report_tp.h" #include "input_receiver_report_tp.h" mir-0.1.8+14.04.20140411/src/client/lttng/client_tracepoint_provider.cpp0000644000015301777760000000172612322054223026223 0ustar pbusernogroup00000000000000/* * 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 "client_tracepoint_provider.h" namespace { std::string const client_tp_provider_lib_name{"libmirclientlttng.so"}; } mir::client::lttng::ClientTracepointProvider::ClientTracepointProvider() : TracepointProvider{client_tp_provider_lib_name} { } mir-0.1.8+14.04.20140411/src/client/egl_native_display_container.h0000644000015301777760000000276612322054223025031 0ustar pbusernogroup00000000000000/* * 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_EGL_NATIVE_DISPLAY_CONTAINER_H_ #define MIR_CLIENT_EGL_NATIVE_DISPLAY_CONTAINER_H_ #include "mir_toolkit/client_types.h" namespace mir { namespace client { class EGLNativeDisplayContainer { public: virtual ~EGLNativeDisplayContainer() {} virtual MirEGLNativeDisplayType create(MirConnection* connection) = 0; virtual void release(MirEGLNativeDisplayType display) = 0; virtual bool validate(MirEGLNativeDisplayType display) const = 0; static EGLNativeDisplayContainer& instance(); protected: EGLNativeDisplayContainer() = default; EGLNativeDisplayContainer(EGLNativeDisplayContainer const&) = delete; EGLNativeDisplayContainer& operator=(EGLNativeDisplayContainer const&) = delete; }; } } // namespace mir #endif // MIR_CLIENT_EGL_NATIVE_DISPLAY_CONTAINER_H_ mir-0.1.8+14.04.20140411/src/client/mir_surface.cpp0000644000015301777760000002647712322054223021764 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/mir_client_library.h" #include "mir/frontend/client_constants.h" #include "client_buffer.h" #include "mir_surface.h" #include "mir_connection.h" #include "mir/input/input_receiver_thread.h" #include "mir/input/input_platform.h" #include #include namespace geom = mir::geometry; namespace mcl = mir::client; namespace mircv = mir::input::receiver; namespace mp = mir::protobuf; namespace gp = google::protobuf; namespace { void null_callback(MirSurface*, void*) {} } MirSurface::MirSurface( MirConnection *allocating_connection, mp::DisplayServer::Stub & server, std::shared_ptr const& factory, std::shared_ptr const& input_platform, MirSurfaceParameters const & params, mir_surface_callback callback, void * context) : server(server), connection(allocating_connection), buffer_depository(std::make_shared(factory, mir::frontend::client_buffer_cache_size)), input_platform(input_platform) { mir::protobuf::SurfaceParameters message; message.set_surface_name(params.name ? params.name : std::string()); message.set_width(params.width); message.set_height(params.height); message.set_pixel_format(params.pixel_format); message.set_buffer_usage(params.buffer_usage); message.set_output_id(params.output_id); server.create_surface(0, &message, &surface, gp::NewCallback(this, &MirSurface::created, callback, context)); for (int i = 0; i < mir_surface_attribs; i++) attrib_cache[i] = -1; attrib_cache[mir_surface_attrib_type] = mir_surface_type_normal; attrib_cache[mir_surface_attrib_state] = mir_surface_state_unknown; attrib_cache[mir_surface_attrib_swapinterval] = 1; } MirSurface::~MirSurface() { std::lock_guard lock(mutex); if (input_thread) { input_thread->stop(); input_thread->join(); } for (auto i = 0, end = surface.fd_size(); i != end; ++i) close(surface.fd(i)); release_cpu_region(); } MirSurfaceParameters MirSurface::get_parameters() const { std::lock_guard lock(mutex); return MirSurfaceParameters { 0, surface.width(), surface.height(), static_cast(surface.pixel_format()), static_cast(surface.buffer_usage()), mir_display_output_id_invalid}; } char const * MirSurface::get_error_message() { std::lock_guard lock(mutex); if (surface.has_error()) { return surface.error().c_str(); } return error_message.c_str(); } int MirSurface::id() const { std::lock_guard lock(mutex); return surface.id().value(); } bool MirSurface::is_valid() const { std::lock_guard lock(mutex); return !surface.has_error(); } void MirSurface::get_cpu_region(MirGraphicsRegion& region_out) { std::lock_guard lock(mutex); auto buffer = buffer_depository->current_buffer(); secured_region = buffer->secure_for_cpu_write(); region_out.width = secured_region->width.as_uint32_t(); region_out.height = secured_region->height.as_uint32_t(); region_out.stride = secured_region->stride.as_uint32_t(); region_out.pixel_format = secured_region->format; region_out.vaddr = secured_region->vaddr.get(); } void MirSurface::release_cpu_region() { secured_region.reset(); } MirWaitHandle* MirSurface::next_buffer(mir_surface_callback callback, void * context) { std::unique_lock lock(mutex); release_cpu_region(); auto const id = &surface.id(); auto const mutable_buffer = surface.mutable_buffer(); lock.unlock(); server.next_buffer( 0, id, mutable_buffer, google::protobuf::NewCallback(this, &MirSurface::new_buffer, callback, context)); return &next_buffer_wait_handle; } MirWaitHandle* MirSurface::get_create_wait_handle() { return &create_wait_handle; } /* todo: all these conversion functions are a bit of a kludge, probably better to have a more developed MirPixelFormat that can handle this */ MirPixelFormat MirSurface::convert_ipc_pf_to_geometry(gp::int32 pf) { return static_cast(pf); } void MirSurface::process_incoming_buffer() { auto const& buffer = surface.buffer(); /* * On most frames when the properties aren't changing, the server won't * fill in the width and height. I think this is an intentional * protocol optimization ("need_full_ipc"). */ if (buffer.has_width() && buffer.has_height()) { surface.set_width(buffer.width()); surface.set_height(buffer.height()); } auto surface_size = geom::Size{surface.width(), surface.height()}; auto surface_pf = convert_ipc_pf_to_geometry(surface.pixel_format()); auto ipc_package = std::make_shared(); populate(*ipc_package); try { buffer_depository->deposit_package(std::move(ipc_package), buffer.buffer_id(), surface_size, surface_pf); } catch (const std::runtime_error& err) { // TODO: Report the error } } void MirSurface::created(mir_surface_callback callback, void * context) { auto platform = connection->get_client_platform(); { std::lock_guard lock(mutex); process_incoming_buffer(); accelerated_window = platform->create_egl_native_window(this); } connection->on_surface_created(id(), this); callback(this, context); create_wait_handle.result_received(); } void MirSurface::new_buffer(mir_surface_callback callback, void * context) { { std::lock_guard lock(mutex); process_incoming_buffer(); } callback(this, context); next_buffer_wait_handle.result_received(); } MirWaitHandle* MirSurface::release_surface( mir_surface_callback callback, void * context) { return connection->release_surface(this, callback, context); } MirNativeBuffer* MirSurface::get_current_buffer_package() { auto platform = connection->get_client_platform(); auto buffer = get_current_buffer(); auto handle = buffer->native_buffer_handle(); return platform->convert_native_buffer(handle.get()); } std::shared_ptr MirSurface::get_current_buffer() { std::lock_guard lock(mutex); return buffer_depository->current_buffer(); } uint32_t MirSurface::get_current_buffer_id() const { std::lock_guard lock(mutex); return buffer_depository->current_buffer_id(); } void MirSurface::populate(MirBufferPackage& buffer_package) { if (!surface.has_error() && surface.has_buffer()) { auto const& buffer = surface.buffer(); buffer_package.data_items = buffer.data_size(); for (int i = 0; i != buffer.data_size(); ++i) { buffer_package.data[i] = buffer.data(i); } buffer_package.fd_items = buffer.fd_size(); for (int i = 0; i != buffer.fd_size(); ++i) { buffer_package.fd[i] = buffer.fd(i); } buffer_package.stride = buffer.stride(); buffer_package.flags = buffer.flags(); buffer_package.width = buffer.width(); buffer_package.height = buffer.height(); } else { buffer_package.data_items = 0; buffer_package.fd_items = 0; buffer_package.stride = 0; } } EGLNativeWindowType MirSurface::generate_native_window() { std::lock_guard lock(mutex); return *accelerated_window; } MirWaitHandle* MirSurface::configure(MirSurfaceAttrib at, int value) { std::unique_lock lock(mutex); mp::SurfaceSetting setting; setting.mutable_surfaceid()->CopyFrom(surface.id()); setting.set_attrib(at); setting.set_ivalue(value); lock.unlock(); configure_wait_handle.expect_result(); server.configure_surface(0, &setting, &configure_result, google::protobuf::NewCallback(this, &MirSurface::on_configured)); return &configure_wait_handle; } void MirSurface::on_configured() { std::lock_guard lock(mutex); if (configure_result.has_surfaceid() && configure_result.surfaceid().value() == surface.id().value() && configure_result.has_attrib()) { int a = configure_result.attrib(); switch (a) { case mir_surface_attrib_type: case mir_surface_attrib_state: case mir_surface_attrib_focus: case mir_surface_attrib_swapinterval: if (configure_result.has_ivalue()) attrib_cache[a] = configure_result.ivalue(); else assert(configure_result.has_error()); break; default: assert(false); break; } configure_wait_handle.result_received(); } } int MirSurface::attrib(MirSurfaceAttrib at) const { std::lock_guard lock(mutex); return attrib_cache[at]; } void MirSurface::set_event_handler(MirEventDelegate const* delegate) { std::lock_guard lock(mutex); if (input_thread) { input_thread->stop(); input_thread->join(); input_thread = nullptr; } if (delegate) { handle_event_callback = std::bind(delegate->callback, this, std::placeholders::_1, delegate->context); if (surface.fd_size() > 0 && handle_event_callback) { input_thread = input_platform->create_input_thread(surface.fd(0), handle_event_callback); input_thread->start(); } } } void MirSurface::handle_event(MirEvent const& e) { std::unique_lock lock(mutex); if (e.type == mir_event_type_surface) { MirSurfaceAttrib a = e.surface.attrib; if (a < mir_surface_attribs) attrib_cache[a] = e.surface.value; } if (handle_event_callback) { auto callback = handle_event_callback; lock.unlock(); callback(&e); } } MirPlatformType MirSurface::platform_type() { std::lock_guard lock(mutex); auto platform = connection->get_client_platform(); return platform->platform_type(); } void MirSurface::request_and_wait_for_next_buffer() { next_buffer(null_callback, nullptr)->wait_for_all(); } void MirSurface::request_and_wait_for_configure(MirSurfaceAttrib a, int value) { configure(a, value)->wait_for_all(); } mir-0.1.8+14.04.20140411/src/client/surface_map.cpp0000644000015301777760000000331012322054223021727 0ustar pbusernogroup00000000000000/* * 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 "connection_surface_map.h" #include #include namespace mcl=mir::client; mcl::ConnectionSurfaceMap::ConnectionSurfaceMap() { } void mcl::ConnectionSurfaceMap::with_surface_do( int surface_id, std::function exec) const { std::unique_lock lk(guard); auto const it = surfaces.find(surface_id); if (it != surfaces.end()) { MirSurface *surface = it->second; exec(surface); } else { std::stringstream ss; ss << __PRETTY_FUNCTION__ << "executed with non-existent surface ID " << surface_id << ".\n"; BOOST_THROW_EXCEPTION(std::runtime_error(ss.str())); } } void mcl::ConnectionSurfaceMap::insert(int surface_id, MirSurface* surface) { std::unique_lock lk(guard); surfaces[surface_id] = surface; } void mcl::ConnectionSurfaceMap::erase(int surface_id) { std::unique_lock lk(guard); surfaces.erase(surface_id); } mir-0.1.8+14.04.20140411/src/client/display_configuration.cpp0000644000015301777760000001270412322054223024045 0ustar pbusernogroup00000000000000/* * 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 "display_configuration.h" #include namespace mcl = mir::client; namespace mp = mir::protobuf; void mcl::delete_config_storage(MirDisplayConfiguration* config) { if (!config) return; for(auto i=0u; i< config->num_outputs; i++) { if (config->outputs[i].modes) delete[] config->outputs[i].modes; if (config->outputs[i].output_formats) delete[] config->outputs[i].output_formats; } if (config->outputs) delete[] config->outputs; if (config->cards) delete[] config->cards; delete config; } mcl::DisplayOutput::DisplayOutput(size_t num_modes_, size_t num_formats) { num_modes = num_modes_; modes = new MirDisplayMode[num_modes]; num_output_formats = num_formats; output_formats = new MirPixelFormat[num_formats]; } mcl::DisplayOutput::~DisplayOutput() { delete[] modes; delete[] output_formats; } namespace { void fill_display_card(MirDisplayCard& card, mp::DisplayCard const& msg) { card.card_id = msg.card_id(); card.max_simultaneous_outputs = msg.max_simultaneous_outputs(); } void fill_display_output(MirDisplayOutput& output, mp::DisplayOutput const& msg) { output.card_id = msg.card_id(); output.output_id = msg.output_id(); output.type = static_cast(msg.type()); for (auto i = 0u; i < output.num_modes; i++) { auto mode = msg.mode(i); output.modes[i].horizontal_resolution = mode.horizontal_resolution(); output.modes[i].vertical_resolution = mode.vertical_resolution(); output.modes[i].refresh_rate = mode.refresh_rate(); } output.preferred_mode = msg.preferred_mode(); output.current_mode = msg.current_mode(); for (auto i = 0u; i < output.num_output_formats; i++) { output.output_formats[i] = static_cast(msg.pixel_format(i)); } output.current_format = static_cast(msg.current_format()); output.position_x = msg.position_x(); output.position_y = msg.position_y(); output.connected = msg.connected(); output.used = msg.used(); output.physical_width_mm = msg.physical_width_mm(); output.physical_height_mm = msg.physical_height_mm(); output.power_mode = static_cast(msg.power_mode()); output.orientation = static_cast(msg.orientation()); } } mcl::DisplayConfiguration::DisplayConfiguration() : notify_change([]{}) { } mcl::DisplayConfiguration::~DisplayConfiguration() { } void mcl::DisplayConfiguration::set_configuration(mp::DisplayConfiguration const& msg) { std::lock_guard lk(guard); cards.clear(); for (auto i = 0; i < msg.display_card_size(); i++) { auto const& msg_card = msg.display_card(i); MirDisplayCard card; fill_display_card(card, msg_card); cards.push_back(card); } outputs.clear(); for (auto i = 0; i < msg.display_output_size(); i++) { auto const& msg_output = msg.display_output(i); auto output = std::make_shared(msg_output.mode_size(), msg_output.pixel_format_size()); fill_display_output(*output, msg_output); outputs.push_back(output); } } void mcl::DisplayConfiguration::update_configuration(mp::DisplayConfiguration const& msg) { set_configuration(msg); notify_change(); } //user is responsible for freeing the returned value MirDisplayConfiguration* mcl::DisplayConfiguration::copy_to_client() const { std::lock_guard lk(guard); auto new_config = new MirDisplayConfiguration; /* Cards */ new_config->num_cards = cards.size(); new_config->cards = new MirDisplayCard[new_config->num_cards]; for (auto i = 0u; i < cards.size(); i++) new_config->cards[i] = cards[i]; /* Outputs */ new_config->num_outputs = outputs.size(); new_config->outputs = new MirDisplayOutput[new_config->num_outputs]; for (auto i = 0u; i < outputs.size(); i++) { auto new_info = &new_config->outputs[i]; MirDisplayOutput* output = outputs[i].get(); std::memcpy(new_info, output, sizeof(MirDisplayOutput)); new_info->output_formats = new MirPixelFormat[new_info->num_output_formats]; auto format_size = sizeof(MirPixelFormat) * new_info->num_output_formats; std::memcpy(new_info->output_formats, output->output_formats, format_size); new_info->modes = new MirDisplayMode[new_info->num_modes]; auto mode_size = sizeof(MirDisplayMode)* new_info->num_modes; std::memcpy(new_info->modes, output->modes, mode_size); } return new_config; } void mcl::DisplayConfiguration::set_display_change_handler(std::function const& fn) { std::lock_guard lk(guard); notify_change = fn; } mir-0.1.8+14.04.20140411/src/client/lifecycle_control.h0000644000015301777760000000236212322054223022614 0ustar pbusernogroup00000000000000/* * 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: Ricardo Mendoza */ #ifndef MIR_LIFECYCLE_CONTROL_H_ #define MIR_LIFECYCLE_CONTROL_H_ #include "mir_toolkit/common.h" #include #include namespace mir { namespace client { class LifecycleControl { public: LifecycleControl(); ~LifecycleControl(); void set_lifecycle_event_handler(std::function const&); void call_lifecycle_event_handler(uint32_t state); private: std::mutex mutable guard; std::function handle_lifecycle_event; }; } } #endif /* MIR_LIFECYCLE_CONTROL_H_ */ mir-0.1.8+14.04.20140411/src/client/mesa/0000755000015301777760000000000012322054703017671 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/src/client/mesa/client_platform.cpp0000644000015301777760000000653212322054223023562 0ustar pbusernogroup00000000000000/* * 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_connection.h" #include "../client_buffer_factory.h" 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; }; } 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) { } std::shared_ptr mclm::ClientPlatform::create_buffer_factory() { return std::make_shared(buffer_file_ops); } namespace { struct NativeWindowDeleter { NativeWindowDeleter(mclm::NativeSurface* window) : window(window) {} void operator()(EGLNativeWindowType* type) { delete type; delete window; } private: mclm::NativeSurface* window; }; } std::shared_ptr mclm::ClientPlatform::create_egl_native_window(ClientSurface* client_surface) { //TODO: this is awkward on both android and gbm... auto native_window = new NativeSurface(*client_surface); auto egl_native_window = new EGLNativeWindowType; *egl_native_window = reinterpret_cast(native_window); NativeWindowDeleter deleter(native_window); return std::shared_ptr(egl_native_window, deleter); } std::shared_ptr mclm::ClientPlatform::create_egl_native_display() { MirEGLNativeDisplayType *mir_native_display = new MirEGLNativeDisplayType; *mir_native_display = display_container.create(context->mir_connection()); 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; } MirNativeBuffer* mclm::ClientPlatform::convert_native_buffer(graphics::NativeBuffer* buf) const { //MirNativeBuffer is type-compatible with the MirNativeBuffer return buf; } mir-0.1.8+14.04.20140411/src/client/mesa/client_platform_factory.cpp0000644000015301777760000000373512322054223025313 0ustar pbusernogroup00000000000000/* * 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 "client_platform_factory.h" #include "client_platform.h" #include "buffer_file_ops.h" #include "../egl_native_display_container.h" #include #include namespace mcl = mir::client; namespace mclm = mcl::mesa; namespace { 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); } }; } std::shared_ptr mclm::ClientPlatformFactory::create_client_platform(mcl::ClientContext* context) { auto buffer_file_ops = std::make_shared(); return std::make_shared( context, buffer_file_ops, mcl::EGLNativeDisplayContainer::instance()); } extern "C" std::shared_ptr mcl::create_client_platform_factory() { return std::make_shared(); } mir-0.1.8+14.04.20140411/src/client/mesa/client_platform.h0000644000015301777760000000336312322054223023226 0ustar pbusernogroup00000000000000/* * 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 "../client_platform.h" namespace mir { namespace client { class ClientBufferDepository; 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; std::shared_ptr create_buffer_factory(); std::shared_ptr create_egl_native_window(ClientSurface *surface); std::shared_ptr create_egl_native_display(); MirNativeBuffer* convert_native_buffer(graphics::NativeBuffer*) const; private: ClientContext* const context; std::shared_ptr const buffer_file_ops; EGLNativeDisplayContainer& display_container; }; } } } #endif /* MIR_CLIENT_MESA_CLIENT_PLATFORM_H_ */ mir-0.1.8+14.04.20140411/src/client/mesa/mesa_native_display_container.cpp0000644000015301777760000000542512322054223026462 0ustar pbusernogroup00000000000000/* * 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_toolkit/mir_client_library.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 connection = static_cast(display->context); mir_connection_get_platform(connection, package); return MIR_MESA_TRUE; } int mir_client_mesa_egl_native_display_is_valid(MirMesaEGLNativeDisplay* display) { return mcl::EGLNativeDisplayContainer::instance().validate(display); } } } mcl::EGLNativeDisplayContainer& mcl::EGLNativeDisplayContainer::instance() { static mclm::MesaNativeDisplayContainer default_display_container; 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(MirConnection* connection) { MirMesaEGLNativeDisplay* display = new MirMesaEGLNativeDisplay(); display->display_get_platform = egl_display_get_platform; display->context = connection; 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); } mir-0.1.8+14.04.20140411/src/client/mesa/native_surface.cpp0000644000015301777760000000561412322054223023376 0ustar pbusernogroup00000000000000/* * 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 #include "../client_buffer.h" #include "native_surface.h" namespace mclm=mir::client::mesa; 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, MirSurfaceParameters* 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(ClientSurface& 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) { /* * 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.request_and_wait_for_next_buffer(); auto buffer = surface.get_current_buffer(); auto buffer_to_driver = buffer->native_buffer_handle(); memcpy(buffer_package, buffer_to_driver.get(), sizeof(MirBufferPackage)); return MIR_MESA_TRUE; } int mclm::NativeSurface::get_parameters(MirSurfaceParameters* surface_parameters) { auto params = surface.get_parameters(); memcpy(surface_parameters, ¶ms, sizeof(MirSurfaceParameters)); return MIR_MESA_TRUE; } int mclm::NativeSurface::set_swapinterval(int interval) { if ((interval < 0) || (interval > 1)) return MIR_MESA_FALSE; surface.request_and_wait_for_configure(mir_surface_attrib_swapinterval, interval); return MIR_MESA_TRUE; } mir-0.1.8+14.04.20140411/src/client/mesa/client_buffer_factory.cpp0000644000015301777760000000261312322054223024732 0ustar pbusernogroup00000000000000/* * 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); } mir-0.1.8+14.04.20140411/src/client/mesa/buffer_file_ops.h0000644000015301777760000000246712322054223023201 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/src/client/mesa/native_surface.h0000644000015301777760000000244712322054223023044 0ustar pbusernogroup00000000000000/* * 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_client_surface.h" namespace mir { namespace client { namespace mesa { class NativeSurface : public MirMesaEGLNativeSurface { public: explicit NativeSurface(ClientSurface&); int advance_buffer(MirBufferPackage* buffer_package); int get_parameters(MirSurfaceParameters* surface_parameters); int set_swapinterval(int interval); private: bool starting; ClientSurface& surface; }; } } } #endif /* MIR_CLIENT_MESA_NATIVE_SURFACE_H_ */ mir-0.1.8+14.04.20140411/src/client/mesa/client_buffer.h0000644000015301777760000000341012322054223022644 0ustar pbusernogroup00000000000000/* * 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 "../aging_buffer.h" #include "mir_toolkit/mir_client_library.h" #include "mir/geometry/rectangle.h" #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() 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; private: std::shared_ptr const buffer_file_ops; std::shared_ptr const creation_package; geometry::Rectangle const rect; MirPixelFormat const buffer_pf; }; } } } #endif /* MIR_CLIENT_MESA_CLIENT_BUFFER_H_ */ mir-0.1.8+14.04.20140411/src/client/mesa/CMakeLists.txt0000644000015301777760000000223512322054223022430 0ustar pbusernogroup00000000000000include_directories( ${DRM_INCLUDE_DIRS} ${EGL_INCLUDE_DIRS} ) add_library( mirclientplatformmesa SHARED client_platform_factory.cpp client_platform.cpp client_buffer_factory.cpp client_buffer.cpp mesa_native_display_container.cpp native_surface.cpp ) set_target_properties( mirclientplatformmesa PROPERTIES OUTPUT_NAME mirclientplatform LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}/mesa ) target_link_libraries( mirclientplatformmesa mirclient ${DRM_LDFLAGS} ${DRM_LIBRARIES} ) install(TARGETS mirclientplatformmesa LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/mir/clientplatform/mesa) if (MIR_TEST_PLATFORM STREQUAL "mesa") add_custom_command(TARGET mirclientplatformmesa POST_BUILD COMMAND ${CMAKE_COMMAND} -E remove libmirclientplatform.so COMMAND ${CMAKE_COMMAND} -E create_symlink mesa/$ libmirclientplatform.so WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH} ) install(CODE "execute_process( COMMAND ln -sf mir/clientplatform/mesa/libmirclientplatform.so WORKING_DIRECTORY \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} )" ) endif() mir-0.1.8+14.04.20140411/src/client/mesa/client_buffer_factory.h0000644000015301777760000000261012322054223024374 0ustar pbusernogroup00000000000000/* * 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 "../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); private: std::shared_ptr const buffer_file_ops; }; } } } #endif /* MIR_CLIENT_MESA_CLIENT_BUFFER_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/client/mesa/client_platform_factory.h0000644000015301777760000000220712322054223024751 0ustar pbusernogroup00000000000000/* * 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_CLIENT_MESA_CLIENT_PLATFORM_FACTORY_H_ #define MIR_CLIENT_MESA_CLIENT_PLATFORM_FACTORY_H_ #include "../client_platform_factory.h" namespace mir { namespace client { namespace mesa { class ClientPlatformFactory : public client::ClientPlatformFactory { public: std::shared_ptr create_client_platform(ClientContext* context) override; }; } } } #endif /* MIR_CLIENT_MESA_CLIENT_PLATFORM_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/client/mesa/client_buffer.cpp0000644000015301777760000000751112322054223023205 0ustar pbusernogroup00000000000000/* * 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 #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; }; } 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{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")); } } 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; } mir-0.1.8+14.04.20140411/src/client/mesa/mesa_native_display_container.h0000644000015301777760000000345712322054223026132 0ustar pbusernogroup00000000000000/* * 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 "../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(MirConnection* connection); 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_ mir-0.1.8+14.04.20140411/src/client/api_impl_types.h0000644000015301777760000000214012322054223022125 0ustar pbusernogroup00000000000000/* * 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_CLIENT_API_IMPL_TYPES_H_ #define MIR_CLIENT_API_IMPL_TYPES_H_ #include "mir_toolkit/client_types.h" typedef MirWaitHandle* (*mir_connect_impl_func)( char const *server, char const *app_name, mir_connected_callback callback, void *context); typedef void (*mir_connection_release_impl_func)(MirConnection *connection); #endif /* MIR_CLIENT_API_IMPL_TYPES_H_ */ mir-0.1.8+14.04.20140411/src/client/connection_configuration.h0000644000015301777760000000403012322054223024175 0ustar pbusernogroup00000000000000/* * 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_CLIENT_CONNECTION_CONFIGURATION_H_ #define MIR_CLIENT_CONNECTION_CONFIGURATION_H_ #include namespace google { namespace protobuf { class RpcChannel; } } namespace mir { namespace input { namespace receiver { class InputPlatform; } } namespace logging { class Logger; } namespace client { class ConnectionSurfaceMap; class Logger; class ClientPlatformFactory; class DisplayConfiguration; class LifecycleControl; class ConnectionConfiguration { public: virtual ~ConnectionConfiguration() = default; virtual std::shared_ptr the_surface_map() = 0; virtual std::shared_ptr the_rpc_channel() = 0; virtual std::shared_ptr the_logger() = 0; virtual std::shared_ptr the_client_platform_factory() = 0; virtual std::shared_ptr the_input_platform() = 0; virtual std::shared_ptr the_display_configuration() = 0; virtual std::shared_ptr the_lifecycle_control() = 0; protected: ConnectionConfiguration() = default; ConnectionConfiguration(ConnectionConfiguration const&) = delete; ConnectionConfiguration& operator=(ConnectionConfiguration const&) = delete; }; } } #endif /* MIR_CLIENT_CONNECTION_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/src/client/client_buffer.h0000644000015301777760000000367112322054223021730 0ustar pbusernogroup00000000000000/* * 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_CLIENT_BUFFER_H_ #define MIR_CLIENT_CLIENT_BUFFER_H_ #include "mir/graphics/native_buffer.h" #include "mir_toolkit/common.h" #include "mir/geometry/size.h" #include /** * \addtogroup mir_toolkit * @{ */ struct MirBufferPackage; /**@}*/ namespace mir { namespace client { /* vaddr is valid from vaddr[0] to vaddr[stride.as_uint32_t() * height.as_uint32_t() - 1] */ struct MemoryRegion { geometry::Width width; geometry::Height height; geometry::Stride stride; MirPixelFormat format; std::shared_ptr vaddr; }; class ClientBuffer { public: virtual ~ClientBuffer() = default; virtual std::shared_ptr secure_for_cpu_write() = 0; virtual geometry::Size size() const = 0; virtual geometry::Stride stride() const = 0; virtual MirPixelFormat pixel_format() const = 0; virtual uint32_t age() const = 0; virtual void increment_age() = 0; virtual void mark_as_submitted() = 0; virtual std::shared_ptr native_buffer_handle() const = 0; protected: ClientBuffer() = default; ClientBuffer(ClientBuffer const&) = delete; ClientBuffer& operator=(ClientBuffer const&) = delete; }; } } #endif /* MIR_CLIENT_CLIENT_BUFFER_H_ */ mir-0.1.8+14.04.20140411/src/client/CMakeLists.txt0000644000015301777760000000361312322054223021504 0ustar pbusernogroup00000000000000set(PREFIX "${CMAKE_INSTALL_PREFIX}") set(EXEC_PREFIX "${CMAKE_INSTALL_PREFIX}") set(LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}") set(INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include/mirclient") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/mirclient.pc.in ${CMAKE_CURRENT_BINARY_DIR}/mirclient.pc ) include_directories( ${PROTOBUF_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_SOURCE_DIR}/include/client ${DRM_INCLUDE_DIRS} ) add_subdirectory(rpc/) add_subdirectory(lttng/) if(MIR_BUILD_PLATFORM_ANDROID) add_subdirectory(android/) endif() if(MIR_BUILD_PLATFORM_MESA) add_subdirectory(mesa/) endif() set( CLIENT_SOURCES aging_buffer.cpp client_buffer_depository.cpp display_configuration.cpp mir_client_library.cpp mir_connection.cpp mir_wait_handle.cpp mir_surface.cpp logging/rpc_report.cpp logging/input_receiver_report.cpp default_connection_configuration.cpp surface_map.cpp lifecycle_control.cpp private.cpp mir_screencast.cpp mir_screencast_api.cpp ) add_library( mirclient SHARED ${CLIENT_SOURCES} ) set(MIRCLIENT_ABI 7) set_target_properties( mirclient PROPERTIES SOVERSION ${MIRCLIENT_ABI} ) set( MIR_CLIENT_LIBRARIES ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${PROTOBUF_LIBRARIES} ${XKBCOMMON_LIBRARIES} mirprotobuf mirsharedinput mirsharedlogging mirsharedenv mirsharedgeometry mirsharedsharedlibrary mirclientrpc mirclientlttngstatic ${MIR_COMMON_PLATFORM_LIBRARIES} 3rd_party ) target_link_libraries( mirclient ${MIR_CLIENT_LIBRARIES} ) install( TARGETS mirclient LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install( DIRECTORY ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit ${CMAKE_SOURCE_DIR}/include/client/mir DESTINATION "include/mirclient" ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/mirclient.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) mir-0.1.8+14.04.20140411/src/client/mir_client_surface.h0000644000015301777760000000265012322054223022752 0ustar pbusernogroup00000000000000/* * 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_CLIENT_SURFACE_H_ #define MIR_CLIENT_CLIENT_SURFACE_H_ #include "mir_toolkit/client_types.h" #include namespace mir { namespace client { class ClientBuffer; class ClientSurface { public: virtual MirSurfaceParameters get_parameters() const = 0; virtual std::shared_ptr get_current_buffer() = 0; virtual void request_and_wait_for_next_buffer() = 0; virtual void request_and_wait_for_configure(MirSurfaceAttrib a, int value) = 0; protected: ClientSurface() = default; virtual ~ClientSurface() = default; ClientSurface(const ClientSurface&) = delete; ClientSurface& operator=(const ClientSurface&) = delete; }; } } #endif /* MIR_CLIENT_CLIENT_SURFACE_H_ */ mir-0.1.8+14.04.20140411/src/client/egl_native_window_factory.h0000644000015301777760000000256112322054223024351 0ustar pbusernogroup00000000000000/* * 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_CLIENT_EGL_NATIVE_WINDOW_FACTORY_H_ #define MIR_CLIENT_EGL_NATIVE_WINDOW_FACTORY_H_ #include #include namespace mir { namespace client { class ClientSurface; class EGLNativeWindowFactory { public: virtual ~EGLNativeWindowFactory() = default; virtual std::shared_ptr create_egl_native_window(ClientSurface* surface) = 0; protected: EGLNativeWindowFactory() = default; EGLNativeWindowFactory(EGLNativeWindowFactory const& p) = delete; EGLNativeWindowFactory& operator=(EGLNativeWindowFactory const& p) = delete; }; } } #endif /* MIR_CLIENT_EGL_NATIVE_WINDOW_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/client/surface_map.h0000644000015301777760000000230112322054223021373 0ustar pbusernogroup00000000000000/* * 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_SURFACE_MAP_H_ #define MIR_CLIENT_SURFACE_MAP_H_ #include struct MirSurface; namespace mir { namespace client { class SurfaceMap { public: virtual void with_surface_do( int surface_id, std::function exec) const = 0; protected: virtual ~SurfaceMap() = default; SurfaceMap() = default; SurfaceMap(const SurfaceMap&) = delete; SurfaceMap& operator=(const SurfaceMap&) = delete; }; } } #endif /* MIR_CLIENT_SURFACE_MAP_H_ */ mir-0.1.8+14.04.20140411/src/client/aging_buffer.cpp0000644000015301777760000000206712322054223022070 0ustar pbusernogroup00000000000000/* * 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; mcl::AgingBuffer::AgingBuffer() : buffer_age(0) { } 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; } mir-0.1.8+14.04.20140411/src/client/api_impl.h0000644000015301777760000000171212322054223020705 0ustar pbusernogroup00000000000000/* * 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_CLIENT_API_IMPL_H_ #define MIR_CLIENT_API_IMPL_H_ #include "api_impl_types.h" extern mir_connect_impl_func mir_connect_impl; extern mir_connection_release_impl_func mir_connection_release_impl; #endif /* MIR_CLIENT_API_IMPL_H_ */ mir-0.1.8+14.04.20140411/src/client/client_buffer_factory.h0000644000015301777760000000352512322054223023455 0ustar pbusernogroup00000000000000/* * 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_CLIENT_BUFFER_FACTORY_H_ #define MIR_CLIENT_CLIENT_BUFFER_FACTORY_H_ #include #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/common.h" #include "mir/geometry/size.h" namespace mir { namespace client { class ClientBuffer; /** * A factory for creating client-side representations of graphics buffers. */ class ClientBufferFactory { public: /** * Creates the client-side representation of a buffer. * * \param [in] package the buffer package sent by the server for this buffer * \param [in] size the buffer's size * \param [in] pf the buffer's pixel format */ virtual std::shared_ptr create_buffer(std::shared_ptr const& package, geometry::Size size, MirPixelFormat pf) = 0; protected: ClientBufferFactory() = default; ClientBufferFactory(ClientBufferFactory const &) = delete; ClientBufferFactory &operator=(ClientBufferFactory const &) = delete; virtual ~ClientBufferFactory() {} }; } } #endif /* MIR_CLIENT_CLIENT_BUFFER_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/client/mir_surface.h0000644000015301777760000001024312322054223021411 0ustar pbusernogroup00000000000000/* * 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_SURFACE_H_ #define MIR_CLIENT_MIR_SURFACE_H_ #include "mir_protobuf.pb.h" #include "mir/geometry/dimensions.h" #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/common.h" #include "mir/graphics/native_buffer.h" #include "client_buffer_depository.h" #include "mir_wait_handle.h" #include "mir_client_surface.h" #include "client_platform.h" #include #include #include namespace mir { namespace input { namespace receiver { class InputPlatform; class InputReceiverThread; } } namespace client { class ClientBuffer; struct MemoryRegion; } } struct MirSurface : public mir::client::ClientSurface { public: MirSurface(MirSurface const &) = delete; MirSurface& operator=(MirSurface const &) = delete; MirSurface( MirConnection *allocating_connection, mir::protobuf::DisplayServer::Stub & server, std::shared_ptr const& buffer_factory, std::shared_ptr const& input_platform, MirSurfaceParameters const& params, mir_surface_callback callback, void * context); ~MirSurface(); MirWaitHandle* release_surface( mir_surface_callback callback, void *context); MirSurfaceParameters get_parameters() const; char const * get_error_message(); int id() const; bool is_valid() const; MirWaitHandle* next_buffer(mir_surface_callback callback, void * context); MirWaitHandle* get_create_wait_handle(); MirNativeBuffer* get_current_buffer_package(); MirPlatformType platform_type(); std::shared_ptr get_current_buffer(); uint32_t get_current_buffer_id() const; void get_cpu_region(MirGraphicsRegion& region); EGLNativeWindowType generate_native_window(); MirWaitHandle* configure(MirSurfaceAttrib a, int value); int attrib(MirSurfaceAttrib a) const; void set_event_handler(MirEventDelegate const* delegate); void handle_event(MirEvent const& e); /* mir::client::ClientSurface */ void request_and_wait_for_next_buffer(); void request_and_wait_for_configure(MirSurfaceAttrib a, int value); private: mutable std::mutex mutex; // Protects all members of *this void on_configured(); void process_incoming_buffer(); void populate(MirBufferPackage& buffer_package); void created(mir_surface_callback callback, void * context); void new_buffer(mir_surface_callback callback, void * context); MirPixelFormat convert_ipc_pf_to_geometry(google::protobuf::int32 pf); void release_cpu_region(); mir::protobuf::DisplayServer::Stub & server; mir::protobuf::Surface surface; std::string error_message; MirConnection* const connection; MirWaitHandle create_wait_handle; MirWaitHandle next_buffer_wait_handle; MirWaitHandle configure_wait_handle; std::shared_ptr secured_region; std::shared_ptr buffer_depository; std::shared_ptr const input_platform; std::shared_ptr accelerated_window; mir::protobuf::SurfaceSetting configure_result; // Cache of latest SurfaceSettings returned from the server int attrib_cache[mir_surface_attribs]; std::function handle_event_callback; std::shared_ptr input_thread; }; #endif /* MIR_CLIENT_PRIVATE_MIR_WAIT_HANDLE_H_ */ mir-0.1.8+14.04.20140411/src/client/client_platform_factory.h0000644000015301777760000000277512322054223024036 0ustar pbusernogroup00000000000000/* * 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_CLIENT_PLATFORM_FACTORY_H_ #define MIR_CLIENT_CLIENT_PLATFORM_FACTORY_H_ #include namespace mir { namespace client { class ClientPlatform; class ClientContext; class ClientPlatformFactory { public: virtual ~ClientPlatformFactory() = default; virtual std::shared_ptr create_client_platform(ClientContext* context) = 0; protected: ClientPlatformFactory() = default; ClientPlatformFactory(ClientPlatformFactory const& p) = delete; ClientPlatformFactory& operator=(ClientPlatformFactory const& p) = delete; }; extern "C" typedef std::shared_ptr(*CreateClientPlatformFactory)(); extern "C" std::shared_ptr create_client_platform_factory(); } } #endif /* MIR_CLIENT_CLIENT_PLATFORM_FACTORY_H_ */ mir-0.1.8+14.04.20140411/src/CMakeLists.txt0000644000015301777760000000050612322054223020224 0ustar pbusernogroup00000000000000set(MIR_GENERATED_INCLUDE_DIRECTORIES) add_subdirectory(shared/) include_directories(${MIR_GENERATED_INCLUDE_DIRECTORIES}) add_subdirectory(platform/) add_subdirectory(server/) add_subdirectory(client/) add_subdirectory(utils/) set( MIR_GENERATED_INCLUDE_DIRECTORIES ${MIR_GENERATED_INCLUDE_DIRECTORIES} PARENT_SCOPE) mir-0.1.8+14.04.20140411/include/0000755000015301777760000000000012322054703016322 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/test/0000755000015301777760000000000012322054703017301 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/0000755000015301777760000000000012322054703022644 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_buffer.h0000644000015301777760000000454312322054223025326 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_STUB_BUFFER_H_ #define MIR_TEST_DOUBLES_STUB_BUFFER_H_ #ifdef ANDROID #include "mock_android_native_buffer.h" #endif #include "mir/graphics/buffer_basic.h" #include "mir/graphics/buffer_properties.h" #include "mir/geometry/size.h" #include "mir/graphics/buffer_id.h" namespace mir { namespace test { namespace doubles { class StubBuffer : public graphics::BufferBasic { public: StubBuffer() : StubBuffer{ graphics::BufferProperties{ geometry::Size{}, mir_pixel_format_abgr_8888, graphics::BufferUsage::hardware}} { } StubBuffer(graphics::BufferProperties const& properties) : StubBuffer{properties, geometry::Stride{}} { } StubBuffer(graphics::BufferProperties const& properties, geometry::Stride stride) : buf_size{properties.size}, buf_pixel_format{properties.format}, buf_stride{stride} { } virtual geometry::Size size() const { return buf_size; } virtual geometry::Stride stride() const { return buf_stride; } virtual MirPixelFormat pixel_format() const { return buf_pixel_format; } virtual std::shared_ptr native_buffer_handle() const { #ifndef ANDROID return std::make_shared(); #else return std::make_shared(); #endif } virtual void bind_to_texture() {} virtual bool can_bypass() const override { return false; } geometry::Size const buf_size; MirPixelFormat const buf_pixel_format; geometry::Stride const buf_stride; }; } } } #endif /* MIR_TEST_DOUBLES_STUB_BUFFER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_udev_device.h0000644000015301777760000000233212322054223026305 0ustar pbusernogroup00000000000000/* * 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: Christopher Halse Rogers */ #ifndef MIR_TEST_DOUBLES_MOCK_UDEV_DEVICE_H_ #define MIR_TEST_DOUBLES_MOCK_UDEV_DEVICE_H_ #include "mir/udev/wrapper.h" #include namespace mir { namespace test { namespace doubles { class MockUdevDevice : public mir::udev::Device { public: MOCK_CONST_METHOD0(subsystem, char const*(void)); MOCK_CONST_METHOD0(devtype, char const*(void)); MOCK_CONST_METHOD0(devpath, char const*(void)); MOCK_CONST_METHOD0(devnode, char const*(void)); }; } } } #endif // MIR_TEST_DOUBLES_MOCK_UDEV_DEVICE_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_client_surface.h0000644000015301777760000000244012322054223027011 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_MOCK_CLIENT_SURFACE_H_ #define MIR_TEST_DOUBLES_MOCK_CLIENT_SURFACE_H_ #include "src/client/mir_client_surface.h" #include namespace mir { namespace test { namespace doubles { struct MockClientSurface : public client::ClientSurface { MOCK_CONST_METHOD0(get_parameters, MirSurfaceParameters()); MOCK_METHOD0(get_current_buffer, std::shared_ptr()); MOCK_METHOD0(request_and_wait_for_next_buffer, void()); MOCK_METHOD2(request_and_wait_for_configure, void(MirSurfaceAttrib,int)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_CLIENT_SURFACE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_virtual_terminal.h0000644000015301777760000000242412322054223027427 0ustar pbusernogroup00000000000000/* * 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_VIRTUAL_TERMINAL_H_ #define MIR_TEST_DOUBLES_NULL_VIRTUAL_TERMINAL_H_ #include "src/platform/graphics/mesa/virtual_terminal.h" namespace mir { namespace test { namespace doubles { class NullVirtualTerminal : public graphics::mesa::VirtualTerminal { public: void set_graphics_mode() {} void register_switch_handlers(graphics::EventHandlerRegister&, std::function const&, std::function const&) { } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_VIRTUAL_TERMINAL_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_display_configuration.h0000644000015301777760000000255312322054223030445 0ustar pbusernogroup00000000000000/* * 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 { } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_DISPLAY_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_render_function.h.moved0000644000015301777760000000201312322054223030314 0ustar pbusernogroup00000000000000/* * 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_MOCK_RENDER_FUNCTION_H_ #define MIR_TEST_DOUBLES_MOCK_RENDER_FUNCTION_H_ #include namespace mir { namespace test { namespace doubles { struct MockRenderFunction { MOCK_METHOD1(called, void(graphics::Renderable const&)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_RENDER_FUNCTION_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_drm.h0000644000015301777760000001151412322054223024607 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #ifndef MIR_TEST_DOUBLES_MOCK_DRM_H_ #define MIR_TEST_DOUBLES_MOCK_DRM_H_ #include #include #include namespace mir { namespace geometry { struct Size; } namespace test { namespace doubles { class FakeDRMResources { public: FakeDRMResources(); ~FakeDRMResources(); int fd() const; int write_fd() const; drmModeRes* resources_ptr(); void add_crtc(uint32_t id, drmModeModeInfo mode); void add_encoder(uint32_t encoder_id, uint32_t crtc_id, uint32_t possible_crtcs_mask); void add_connector(uint32_t connector_id, uint32_t type, drmModeConnection connection, uint32_t encoder_id, std::vector& modes, std::vector& possible_encoder_ids, geometry::Size const& physical_size); void prepare(); void reset(); drmModeCrtc* find_crtc(uint32_t id); drmModeEncoder* find_encoder(uint32_t id); drmModeConnector* find_connector(uint32_t id); enum ModePreference {NormalMode, PreferredMode}; static drmModeModeInfo create_mode(uint16_t hdisplay, uint16_t vdisplay, uint32_t clock, uint16_t htotal, uint16_t vtotal, ModePreference preferred); private: int pipe_fds[2]; drmModeRes resources; std::vector crtcs; std::vector encoders; std::vector connectors; std::vector crtc_ids; std::vector encoder_ids; std::vector connector_ids; std::vector modes; std::vector modes_empty; std::vector connector_encoder_ids; }; class MockDRM { public: MockDRM(); ~MockDRM() noexcept; MOCK_METHOD3(open, int(char const* path, int flags, mode_t mode)); MOCK_METHOD2(drmOpen, int(const char *name, const char *busid)); MOCK_METHOD1(drmClose, int(int fd)); MOCK_METHOD3(drmIoctl, int(int fd, unsigned long request, void *arg)); MOCK_METHOD1(drmModeGetResources, drmModeResPtr(int fd)); MOCK_METHOD2(drmModeGetConnector, drmModeConnectorPtr(int fd, uint32_t connectorId)); MOCK_METHOD2(drmModeGetEncoder, drmModeEncoderPtr(int fd, uint32_t encoder_id)); MOCK_METHOD2(drmModeGetCrtc, drmModeCrtcPtr(int fd, uint32_t crtcId)); MOCK_METHOD8(drmModeSetCrtc, int(int fd, uint32_t crtcId, uint32_t bufferId, uint32_t x, uint32_t y, uint32_t *connectors, int count, drmModeModeInfoPtr mode)); MOCK_METHOD1(drmModeFreeResources, void(drmModeResPtr ptr)); MOCK_METHOD1(drmModeFreeConnector, void(drmModeConnectorPtr ptr)); MOCK_METHOD1(drmModeFreeEncoder, void(drmModeEncoderPtr ptr)); MOCK_METHOD1(drmModeFreeCrtc, void(drmModeCrtcPtr ptr)); MOCK_METHOD8(drmModeAddFB, int(int fd, uint32_t width, uint32_t height, uint8_t depth, uint8_t bpp, uint32_t pitch, uint32_t bo_handle, uint32_t *buf_id)); MOCK_METHOD2(drmModeRmFB, int(int fd, uint32_t bufferId)); MOCK_METHOD5(drmModePageFlip, int(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data)); MOCK_METHOD2(drmHandleEvent, int(int fd, drmEventContextPtr evctx)); MOCK_METHOD2(drmGetMagic, int(int fd, drm_magic_t *magic)); MOCK_METHOD2(drmAuthMagic, int(int fd, drm_magic_t magic)); MOCK_METHOD4(drmPrimeHandleToFD, int(int fd, uint32_t handle, uint32_t flags, int *prime_fd)); MOCK_METHOD3(drmPrimeFDToHandle, int(int fd, int prime_fd, uint32_t *handle)); MOCK_METHOD1(drmSetMaster, int(int fd)); MOCK_METHOD1(drmDropMaster, int(int fd)); MOCK_METHOD5(drmModeSetCursor, int (int fd, uint32_t crtcId, uint32_t bo_handle, uint32_t width, uint32_t height)); MOCK_METHOD4(drmModeMoveCursor,int (int fd, uint32_t crtcId, int x, int y)); MOCK_METHOD2(drmSetInterfaceVersion, int (int fd, drmSetVersion* sv)); MOCK_METHOD1(drmGetBusid, char* (int fd)); FakeDRMResources fake_drm; }; } } } #endif /* MIR_TEST_DOUBLES_DRM_MOCK_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_rpc_report.h0000644000015301777760000000471512322054223026211 0ustar pbusernogroup00000000000000/* * 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_MOCK_RPC_REPORT_H_ #define MIR_TEST_DOUBLES_MOCK_RPC_REPORT_H_ #include "src/client/rpc/rpc_report.h" #include "mir_protobuf_wire.pb.h" #include namespace mir { namespace test { namespace doubles { class MockRpcReport : public mir::client::rpc::RpcReport { public: ~MockRpcReport() noexcept {} MOCK_METHOD1(invocation_requested, void(mir::protobuf::wire::Invocation const&)); MOCK_METHOD1(invocation_succeeded, void(mir::protobuf::wire::Invocation const&)); MOCK_METHOD2(invocation_failed, void(mir::protobuf::wire::Invocation const&, boost::system::error_code const& error)); MOCK_METHOD1(header_receipt_failed, void(boost::system::error_code const&)); MOCK_METHOD1(result_receipt_succeeded, void(mir::protobuf::wire::Result const&)); MOCK_METHOD1(result_receipt_failed, void(std::exception const&)); MOCK_METHOD1(event_parsing_succeeded, void(MirEvent const&)); MOCK_METHOD1(event_parsing_failed, void(mir::protobuf::Event const&)); MOCK_METHOD1(orphaned_result, void(mir::protobuf::wire::Result const&)); MOCK_METHOD1(complete_response, void(mir::protobuf::wire::Result const&)); MOCK_METHOD2(result_processing_failed, void(mir::protobuf::wire::Result const&, std::exception const& ex)); MOCK_METHOD2(file_descriptors_received, void(google::protobuf::Message const&, std::vector const&)); MOCK_METHOD1(connection_failure, void (std::exception const&)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_RPC_REPORT_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_display_buffer.h0000644000015301777760000000267112322054247027056 0ustar pbusernogroup00000000000000/* * 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: geometry::Rectangle view_area() const { return geometry::Rectangle(); } void make_current() {} void release_current() {} void post_update() {} bool can_bypass() const override { return false; } void render_and_post_update( graphics::RenderableList const&, std::function const&) {} MirOrientation orientation() const override { return mir_orientation_normal; } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_DISPLAY_BUFFER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_display_changer.h0000644000015301777760000000237512322054247027174 0ustar pbusernogroup00000000000000/* * 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_MOCK_DISPLAY_CHANGER_H_ #define MIR_TEST_DOUBLES_MOCK_DISPLAY_CHANGER_H_ #include "mir/frontend/display_changer.h" #include namespace mir { namespace test { namespace doubles { class MockDisplayChanger : public frontend::DisplayChanger { public: MOCK_METHOD0(active_configuration, std::shared_ptr()); MOCK_METHOD2(configure, void(std::shared_ptr const&, std::shared_ptr const&)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_DISPLAY_CHANGER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_display_device.h0000644000015301777760000000314612322054247027021 0ustar pbusernogroup00000000000000/* * 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_MOCK_DISPLAY_DEVICE_H_ #define MIR_TEST_DOUBLES_MOCK_DISPLAY_DEVICE_H_ #include "mir/graphics/buffer.h" #include "src/platform/graphics/android/display_device.h" #include "src/platform/graphics/android/gl_context.h" #include namespace mir { namespace test { namespace doubles { class MockDisplayDevice : public graphics::android::DisplayDevice { public: ~MockDisplayDevice() noexcept {} MOCK_METHOD1(mode, void(MirPowerMode)); MOCK_METHOD1(render_gl, void(graphics::android::SwappingGLContext const&)); MOCK_METHOD3(render_gl_and_overlays, void( graphics::android::SwappingGLContext const&, graphics::RenderableList const&, std::function const&)); MOCK_METHOD1(post, void(graphics::Buffer const&)); MOCK_CONST_METHOD1(apply_orientation, bool(MirOrientation)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_DISPLAY_DEVICE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_session_listener.h0000644000015301777760000000303312322054223027412 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_MOCK_SESSION_LISTENER_H_ #define MIR_TEST_DOUBLES_MOCK_SESSION_LISTENER_H_ #include "mir/shell/session_listener.h" #include namespace mir { namespace test { namespace doubles { struct MockSessionListener : public shell::SessionListener { virtual ~MockSessionListener() noexcept(true) {} MOCK_METHOD1(starting, void(std::shared_ptr const&)); MOCK_METHOD1(stopping, void(std::shared_ptr const&)); MOCK_METHOD1(focused, void(std::shared_ptr const&)); MOCK_METHOD0(unfocused, void()); MOCK_METHOD2(surface_created, void(shell::Session&, std::shared_ptr const&)); MOCK_METHOD2(destroying_surface, void(shell::Session&, std::shared_ptr const&)); }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_MOCK_SESSION_LISTENER_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_render_function.h0000644000015301777760000000201312322054223027203 0ustar pbusernogroup00000000000000/* * 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_MOCK_RENDER_FUNCTION_H_ #define MIR_TEST_DOUBLES_MOCK_RENDER_FUNCTION_H_ #include namespace mir { namespace test { namespace doubles { struct MockRenderFunction { MOCK_METHOD1(called, void(graphics::Renderable const&)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_RENDER_FUNCTION_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_gbm.h0000644000015301777760000000676312322054223024604 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #ifndef MIR_TEST_DOUBLES_MOCK_GBM_H_ #define MIR_TEST_DOUBLES_MOCK_GBM_H_ #include #pragma GCC diagnostic push #pragma GCC diagnostic warning "-Wall" #include #pragma GCC diagnostic pop namespace mir { namespace test { namespace doubles { class FakeGBMResources { public: FakeGBMResources(); ~FakeGBMResources() = default; gbm_device *device; gbm_surface *surface; gbm_bo *bo; gbm_bo_handle bo_handle; }; class MockGBM { public: MockGBM(); ~MockGBM(); MOCK_METHOD1(gbm_create_device, struct gbm_device*(int fd)); MOCK_METHOD1(gbm_device_destroy, void(struct gbm_device *gbm)); MOCK_METHOD1(gbm_device_get_fd, int(struct gbm_device *gbm)); MOCK_METHOD5(gbm_surface_create, struct gbm_surface*(struct gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags)); MOCK_METHOD1(gbm_surface_destroy, void(struct gbm_surface *surface)); MOCK_METHOD1(gbm_surface_lock_front_buffer, struct gbm_bo*(struct gbm_surface *surface)); MOCK_METHOD2(gbm_surface_release_buffer, void(struct gbm_surface *surface, struct gbm_bo *bo)); MOCK_METHOD5(gbm_bo_create, struct gbm_bo*(struct gbm_device *gbm, uint32_t width, uint32_t height, uint32_t format, uint32_t flags)); MOCK_METHOD1(gbm_bo_get_device, struct gbm_device*(struct gbm_bo *bo)); MOCK_METHOD1(gbm_bo_get_width, uint32_t(struct gbm_bo *bo)); MOCK_METHOD1(gbm_bo_get_height, uint32_t(struct gbm_bo *bo)); MOCK_METHOD1(gbm_bo_get_stride, uint32_t(struct gbm_bo *bo)); MOCK_METHOD1(gbm_bo_get_format, uint32_t(struct gbm_bo *bo)); MOCK_METHOD1(gbm_bo_get_handle, union gbm_bo_handle(struct gbm_bo *bo)); MOCK_METHOD3(gbm_bo_set_user_data, void(struct gbm_bo *bo, void *data, void (*destroy_user_data)(struct gbm_bo *, void *))); MOCK_METHOD1(gbm_bo_get_user_data, void*(struct gbm_bo *bo)); MOCK_METHOD3(gbm_bo_write, bool(struct gbm_bo *bo, const void *buf, size_t count)); MOCK_METHOD1(gbm_bo_destroy, void(struct gbm_bo *bo)); FakeGBMResources fake_gbm; private: void on_gbm_bo_set_user_data(struct gbm_bo *bo, void *data, void (*destroy_user_data)(struct gbm_bo *, void *)) { destroyers.push_back(Destroyer{bo, data, destroy_user_data}); } struct Destroyer { struct gbm_bo *bo; void *data; void (*destroy_user_data)(struct gbm_bo *, void *); void operator()() const { destroy_user_data(bo, data); } }; std::vector destroyers; }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_GBM_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_egl.h0000644000015301777760000001144112322054247024601 0ustar pbusernogroup00000000000000/* * 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 #define GL_GLEXT_PROTOTYPES #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(); ~MockEGL(); typedef void (*generic_function_pointer_t)(void); MOCK_METHOD1(eglGetDisplay, EGLDisplay(NativeDisplayType)); 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,NativeWindowType,const EGLint*)); MOCK_METHOD4(eglCreatePixmapSurface, EGLSurface(EGLDisplay,EGLConfig,NativePixmapType,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,NativePixmapType)); 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)); EGLDisplay fake_egl_display; EGLConfig* fake_configs; EGLint fake_configs_num; EGLSurface fake_egl_surface; EGLContext fake_egl_context; EGLImageKHR fake_egl_image; int fake_visual_id; }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_EGL_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_renderer.h0000644000015301777760000000247612322054223025642 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_MOCK_RENDERER_H_ #define MIR_TEST_DOUBLES_MOCK_RENDERER_H_ #include "mir/compositor/renderer.h" #include namespace mir { namespace test { namespace doubles { struct MockRenderer : public compositor::Renderer { MOCK_METHOD1(set_viewport, void(geometry::Rectangle const&)); MOCK_METHOD1(set_rotation, void(float)); MOCK_CONST_METHOD0(begin, void()); MOCK_CONST_METHOD2(render, void(graphics::Renderable const&, graphics::Buffer&)); MOCK_CONST_METHOD0(end, void()); MOCK_METHOD0(suspend, void()); ~MockRenderer() noexcept {} }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_RENDERER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_event_filter.h0000644000015301777760000000204612322054223026513 0ustar pbusernogroup00000000000000/* * 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 Voß */ #ifndef MIR_TEST_DOUBLES_MOCK_EVENT_FILTER_H_ #define MIR_TEST_DOUBLES_MOCK_EVENT_FILTER_H_ #include "mir/input/event_filter.h" #include namespace mir { namespace test { namespace doubles { struct MockEventFilter : public mir::input::EventFilter { MOCK_METHOD1(handle, bool(const MirEvent&)); }; } } } #endif // MIR_TEST_DOUBLES_MOCK_EVENT_FILTER_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_shell_session.h0000644000015301777760000000416412322054223026726 0ustar pbusernogroup00000000000000/* * 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_SHELL_SESSION_H_ #define MIR_TEST_DOUBLES_STUB_SHELL_SESSION_H_ #include "mir/shell/session.h" namespace mir { namespace test { namespace doubles { struct StubShellSession : public shell::Session { frontend::SurfaceId create_surface(shell::SurfaceCreationParameters const& /* params */) override { return frontend::SurfaceId{0}; } void destroy_surface(frontend::SurfaceId /* surface */) override { } std::shared_ptr get_surface(frontend::SurfaceId /* surface */) const override { return std::shared_ptr(); } std::string name() const override { return std::string(); } pid_t process_id() const override { return -1; } void force_requests_to_complete() override { } void hide() override { } void show() override { } int configure_surface(frontend::SurfaceId, MirSurfaceAttrib, int) override { return 0; } void send_display_config(graphics::DisplayConfiguration const&) override { } void take_snapshot(shell::SnapshotCallback const&) override { } std::shared_ptr default_surface() const override { return std::shared_ptr(); } void set_lifecycle_state(MirLifecycleState /*state*/) { } }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_STUB_SHELL_SESSION_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_compositor.h0000644000015301777760000000211612322054223026221 0ustar pbusernogroup00000000000000/* * 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_MOCK_COMPOSITOR_H_ #define MIR_TEST_DOUBLES_MOCK_COMPOSITOR_H_ #include "mir/compositor/compositor.h" #include namespace mir { namespace test { namespace doubles { class MockCompositor : public compositor::Compositor { public: MOCK_METHOD0(start, void()); MOCK_METHOD0(stop, void()); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_COMPOSITOR_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_session.h0000644000015301777760000000337712322054223025544 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_STUB_SESSION_H_ #define MIR_TEST_DOUBLES_STUB_SESSION_H_ #include "mir/frontend/session.h" namespace mir { namespace test { namespace doubles { struct StubSession : public frontend::Session { frontend::SurfaceId create_surface(shell::SurfaceCreationParameters const& /* params */) { return frontend::SurfaceId{0}; } void destroy_surface(frontend::SurfaceId /* surface */) { } std::shared_ptr get_surface(frontend::SurfaceId /* surface */) const { return std::shared_ptr(); } std::string name() const { return std::string(); } void force_requests_to_complete() { } void hide() { } void show() { } int configure_surface(frontend::SurfaceId, MirSurfaceAttrib, int) { return 0; } void set_event_sink(std::shared_ptr const&) { } void send_display_config(graphics::DisplayConfiguration const&) { } }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_STUB_SESSION_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_buffer_stream.h0000644000015301777760000000413612322054247026705 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #ifndef MIR_TEST_DOUBLES_NULL_BUFFER_STREAM_H_ #define MIR_TEST_DOUBLES_NULL_BUFFER_STREAM_H_ #include #include namespace mir { namespace test { namespace doubles { class StubBufferStream : public compositor::BufferStream { public: StubBufferStream() { stub_compositor_buffer = std::make_shared(); } void swap_client_buffers(graphics::Buffer*, std::function complete) override { complete(&stub_client_buffer); } std::shared_ptr lock_compositor_buffer(void const*) override { return stub_compositor_buffer; } std::shared_ptr lock_snapshot_buffer() override { return stub_compositor_buffer; } MirPixelFormat get_stream_pixel_format() override { return MirPixelFormat(); } geometry::Size stream_size() override { return geometry::Size(); } void resize(geometry::Size const&) override { } void force_requests_to_complete() override { } void allow_framedropping(bool) override { } int buffers_ready_for_compositor() const override { return 1; } StubBuffer stub_client_buffer; std::shared_ptr stub_compositor_buffer; }; } } } // namespace mir #endif /* MIR_TEST_DOUBLES_NULL_BUFFER_STREAM_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_frontend_surface.h0000644000015301777760000000304512322054223027354 0ustar pbusernogroup00000000000000/* * 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_MOCK_FRONTEND_SURFACE_H_ #define MIR_TEST_DOUBLES_MOCK_FRONTEND_SURFACE_H_ #include "mir/frontend/surface.h" #include namespace mir { namespace test { namespace doubles { struct MockFrontendSurface : public frontend::Surface { MockFrontendSurface() { } ~MockFrontendSurface() noexcept {} MOCK_METHOD0(destroy, void()); MOCK_METHOD0(force_requests_to_complete, void()); MOCK_METHOD2(swap_buffers, void(graphics::Buffer*, std::function complete)); MOCK_CONST_METHOD0(size, geometry::Size()); MOCK_CONST_METHOD0(pixel_format, MirPixelFormat()); MOCK_CONST_METHOD0(supports_input, bool()); MOCK_CONST_METHOD0(client_input_fd, int()); MOCK_METHOD2(configure, int(MirSurfaceAttrib, int)); }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_MOCK_FRONTEND_SURFACE_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_renderable.h0000644000015301777760000000410312322054247026132 0ustar pbusernogroup00000000000000/* * 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_MOCK_RENDERABLE_H_ #define MIR_TEST_DOUBLES_MOCK_RENDERABLE_H_ #include "mir_test_doubles/stub_buffer.h" #include #include namespace mir { namespace test { namespace doubles { struct MockRenderable : public graphics::Renderable { MockRenderable() { ON_CALL(*this, screen_position()) .WillByDefault(testing::Return(geometry::Rectangle{{},{}})); ON_CALL(*this, buffer(testing::_)) .WillByDefault(testing::Return(std::make_shared())); ON_CALL(*this, buffers_ready_for_compositor()) .WillByDefault(testing::Return(1)); ON_CALL(*this, alpha()) .WillByDefault(testing::Return(1.0f)); ON_CALL(*this, transformation()) .WillByDefault(testing::Return(glm::mat4{})); ON_CALL(*this, visible()) .WillByDefault(testing::Return(true)); } MOCK_CONST_METHOD1(buffer, std::shared_ptr(void const*)); MOCK_CONST_METHOD0(alpha_enabled, bool()); MOCK_CONST_METHOD0(screen_position, geometry::Rectangle()); MOCK_CONST_METHOD0(alpha, float()); MOCK_CONST_METHOD0(transformation, glm::mat4()); MOCK_CONST_METHOD0(visible, bool()); MOCK_CONST_METHOD0(shaped, bool()); MOCK_CONST_METHOD0(buffers_ready_for_compositor, int()); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_RENDERABLE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_surface.h0000644000015301777760000000401312322054247025457 0ustar pbusernogroup00000000000000/* * 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_MOCK_SURFACE_H_ #define MIR_TEST_DOUBLES_MOCK_SURFACE_H_ #include "src/server/scene/basic_surface.h" #include "src/server/report/null_report_factory.h" #include namespace mir { namespace test { namespace doubles { struct MockSurface : public scene::BasicSurface { MockSurface() : scene::BasicSurface( {}, {{},{}}, true, {}, {}, {}, mir::report::null_scene_report()) { } ~MockSurface() noexcept {} MOCK_METHOD0(hide, void()); MOCK_METHOD0(show, void()); MOCK_METHOD0(visible, bool()); MOCK_METHOD1(raise, void(std::shared_ptr const&)); MOCK_METHOD0(force_requests_to_complete, void()); MOCK_METHOD0(advance_client_buffer, std::shared_ptr()); MOCK_CONST_METHOD0(size, geometry::Size()); MOCK_CONST_METHOD0(pixel_format, MirPixelFormat()); MOCK_CONST_METHOD0(supports_input, bool()); MOCK_CONST_METHOD0(client_input_fd, int()); MOCK_METHOD2(configure, int(MirSurfaceAttrib, int)); MOCK_METHOD1(take_input_focus, void(std::shared_ptr const&)); MOCK_METHOD1(add_observer, void(std::shared_ptr const&)); }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_MOCK_SURFACE_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_shell.h0000644000015301777760000000341012322054223025154 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_STUB_SHELL_H_ #define MIR_TEST_DOUBLES_STUB_SHELL_H_ #include "mir/frontend/shell.h" #include "mir_test_doubles/stub_session.h" namespace mir { namespace test { namespace doubles { struct StubShell : public frontend::Shell { StubShell() : stub_session(std::make_shared()) { } std::shared_ptr open_session(pid_t, std::string const& /* name */, std::shared_ptr const& /* sink */) override { return stub_session; } void close_session(std::shared_ptr const& /* session */) override { } frontend::SurfaceId create_surface_for(std::shared_ptr const& /* session */, shell::SurfaceCreationParameters const& /* params */) override { return frontend::SurfaceId{0}; } void handle_surface_created(std::shared_ptr const& /* session */) override { } std::shared_ptr const stub_session; }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_STUB_SHELL_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_input_manager.h0000644000015301777760000000224012322054223026652 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_MOCK_INPUT_MANAGER_H_ #define MIR_TEST_DOUBLES_MOCK_INPUT_MANAGER_H_ #include "mir/input/input_manager.h" #include #include namespace mir { namespace test { namespace doubles { struct MockInputManager : public input::InputManager { MOCK_METHOD0(start, void()); MOCK_METHOD0(stop, void()); MOCK_METHOD0(make_input_channel, std::shared_ptr()); }; } } } #endif // MIR_TEST_DOUBLES_MOCK_INPUT_MANAGER_H mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_surface_configurator.h0000644000015301777760000000232712322054247030247 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_MOCK_SURFACE_CONFIGURATOR_H_ #define MIR_TEST_DOUBLES_MOCK_SURFACE_CONFIGURATOR_H_ #include "mir/scene/surface_configurator.h" #include namespace mir { namespace test { namespace doubles { struct MockSurfaceConfigurator : public scene::SurfaceConfigurator { MOCK_METHOD3(select_attribute_value, int(scene::Surface const&, MirSurfaceAttrib, int)); MOCK_METHOD3(attribute_set, void(scene::Surface const&, MirSurfaceAttrib, int)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_SURFACE_CONFIGURATOR_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_input_region.h0000644000015301777760000000230212322054223026522 0ustar pbusernogroup00000000000000/* * 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_MOCK_INPUT_REGION_H_ #define MIR_TEST_DOUBLES_MOCK_INPUT_REGION_H_ #include "mir/input/input_region.h" #include "mir/geometry/point.h" #include "mir/geometry/rectangle.h" #include namespace mir { namespace test { namespace doubles { class MockInputRegion : public input::InputRegion { public: MOCK_METHOD0(bounding_rectangle, geometry::Rectangle()); MOCK_METHOD1(confine, void(geometry::Point&)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_INPUT_REGION_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_input_targeter.h0000644000015301777760000000216012322054223027102 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_STUB_INPUT_TARGETER_H_ #define MIR_TEST_DOUBLES_STUB_INPUT_TARGETER_H_ #include "mir/shell/input_targeter.h" namespace mir { namespace test { namespace doubles { struct StubInputTargeter : public shell::InputTargeter { void focus_changed(std::shared_ptr const&) { } void focus_cleared() { } }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_STUB_INPUT_TARGETER_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_client_context.h0000644000015301777760000000303012322054223027041 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #ifndef MIR_TEST_DOUBLES_MOCK_CLIENT_CONTEXT_H_ #define MIR_TEST_DOUBLES_MOCK_CLIENT_CONTEXT_H_ #include "mir_toolkit/mir_client_library.h" #include "src/client/client_context.h" #include namespace mir { namespace test { namespace doubles { struct MockClientContext : public client::ClientContext { MockClientContext() : connection{reinterpret_cast(0xabcdef)} { using namespace testing; ON_CALL(*this, mir_connection()).WillByDefault(Return(connection)); EXPECT_CALL(*this, mir_connection()).Times(AtLeast(0)); EXPECT_CALL(*this, populate(_)).Times(AtLeast(0)); } MirConnection* connection; MOCK_METHOD0(mir_connection, MirConnection*()); MOCK_METHOD1(populate, void(MirPlatformPackage&)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_CLIENT_CONTEXT_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_buffer_stream.h0000644000015301777760000000326512322054247026663 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_MOCK_BUFFER_STREAM_H_ #define MIR_TEST_DOUBLES_MOCK_BUFFER_STREAM_H_ #include "mir/compositor/buffer_stream.h" #include namespace mir { namespace test { namespace doubles { struct MockBufferStream : public compositor::BufferStream { MOCK_METHOD2(swap_client_buffers, void(graphics::Buffer*, std::function completee)); MOCK_METHOD1(lock_compositor_buffer, std::shared_ptr(void const*)); MOCK_METHOD0(lock_snapshot_buffer, std::shared_ptr()); MOCK_METHOD0(get_stream_pixel_format, MirPixelFormat()); MOCK_METHOD0(stream_size, geometry::Size()); MOCK_METHOD1(resize, void(geometry::Size const&)); MOCK_METHOD0(force_client_completion, void()); MOCK_METHOD1(allow_framedropping, void(bool)); MOCK_METHOD0(force_requests_to_complete, void()); int buffers_ready_for_compositor() const override { return 1; } }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_BUFFER_STREAM_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_fb_hal_device.h0000644000015301777760000000526712322054223026567 0ustar pbusernogroup00000000000000/* * 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_MOCK_FB_HAL_DEVICE_H_ #define MIR_TEST_DOUBLES_MOCK_FB_HAL_DEVICE_H_ #include #include #include #include namespace mir { namespace test { namespace doubles { class MockFBHalDevice : public framebuffer_device_t { public: MockFBHalDevice(unsigned int const width, unsigned int const height, int const pf, int const numfbs) : framebuffer_device_t({ hw_device_t(), 0, width, height, 0, pf, 0.0f, 0.0f, 0.0f, 0, 1, numfbs, {0,0,0,0,0,0,0}, nullptr, nullptr,nullptr,nullptr, nullptr,nullptr, {0,0,0,0,0,0} }) { post = hook_post; setSwapInterval = hook_setSwapInterval; enableScreen = hook_enableScreen; } MockFBHalDevice() : MockFBHalDevice(1,1,1,1) { } static int hook_post(struct framebuffer_device_t* mock_fb, buffer_handle_t handle) { MockFBHalDevice* mocker = static_cast(mock_fb); return mocker->post_interface(mock_fb, handle); } static int hook_setSwapInterval(struct framebuffer_device_t* mock_fb, int interval) { MockFBHalDevice* mocker = static_cast(mock_fb); return mocker->setSwapInterval_interface(mock_fb, interval); } static int hook_enableScreen(struct framebuffer_device_t* mock_fb, int enable) { MockFBHalDevice* mocker = static_cast(mock_fb); return mocker->enableScreen_interface(mock_fb, enable); } MOCK_METHOD2(enableScreen_interface, int(struct framebuffer_device_t*, int)); MOCK_METHOD2(post_interface, int(struct framebuffer_device_t*, buffer_handle_t)); MOCK_METHOD2(setSwapInterval_interface, int(struct framebuffer_device_t*, int)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_FB_HAL_DEVICE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_buffer_packer.h0000644000015301777760000000242312322054223026622 0ustar pbusernogroup00000000000000/* * 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_MOCK_BUFFER_PACKER_H_ #define MIR_TEST_DOUBLES_MOCK_BUFFER_PACKER_H_ #include "mir/graphics/buffer_ipc_packer.h" #include namespace mir { namespace test { namespace doubles { struct MockPacker : public graphics::BufferIPCPacker { ~MockPacker() noexcept {} MOCK_METHOD1(pack_fd, void(int)); MOCK_METHOD1(pack_data, void(int)); MOCK_METHOD1(pack_stride, void(geometry::Stride)); MOCK_METHOD1(pack_flags, void(unsigned int)); MOCK_METHOD1(pack_size, void(geometry::Size const&)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_BUFFER_PACKER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_buffer_bundle.h0000644000015301777760000000361512322054247026640 0ustar pbusernogroup00000000000000/* * 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_MOCK_BUFFER_BUNDLE_H_ #define MIR_TEST_DOUBLES_MOCK_BUFFER_BUNDLE_H_ #include "src/server/compositor/buffer_bundle.h" #include namespace mir { namespace test { namespace doubles { struct MockBufferBundle : public compositor::BufferBundle { public: MockBufferBundle() {} ~MockBufferBundle() noexcept {} MOCK_METHOD1(client_acquire, void(std::function)); MOCK_METHOD1(client_release, void(graphics::Buffer*)); MOCK_METHOD1(compositor_acquire, std::shared_ptr(void const*)); MOCK_METHOD1(compositor_release, void(std::shared_ptr const&)); MOCK_METHOD0(snapshot_acquire, std::shared_ptr()); MOCK_METHOD1(snapshot_release, void(std::shared_ptr const&)); MOCK_METHOD1(allow_framedropping, void(bool)); MOCK_CONST_METHOD0(properties, graphics::BufferProperties()); MOCK_METHOD0(force_client_abort, void()); MOCK_METHOD0(force_requests_to_complete, void()); MOCK_METHOD1(resize, void(const geometry::Size &)); int buffers_ready_for_compositor() const override { return 1; } }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_BUFFER_BUNDLE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_buffer_allocator.h0000644000015301777760000000264012322054223027362 0ustar pbusernogroup00000000000000/* * 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_BUFFER_ALLOCATOR_H_ #define MIR_TEST_DOUBLES_STUB_BUFFER_ALLOCATOR_H_ #include "mir/graphics/graphic_buffer_allocator.h" #include "mir_test_doubles/stub_buffer.h" #include #include #include #include namespace mir { namespace test { namespace doubles { struct StubBufferAllocator : public graphics::GraphicBufferAllocator { std::shared_ptr alloc_buffer( graphics::BufferProperties const& properties) { return std::make_shared(properties); } std::vector supported_pixel_formats() { return {}; } }; } } } #endif // MIR_TEST_DOUBLES_STUB_BUFFER_ALLOCATOR_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_input_registrar.h0000644000015301777760000000263712322054223027254 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_MOCK_INPUT_REGISTRAR_H_ #define MIR_TEST_DOUBLES_MOCK_INPUT_REGISTRAR_H_ #include "mir/scene/input_registrar.h" #include namespace mir { namespace test { namespace doubles { struct MockInputRegistrar : public scene::InputRegistrar { virtual ~MockInputRegistrar() noexcept(true) {} MOCK_METHOD3(input_channel_opened, void(std::shared_ptr const&, std::shared_ptr const&, input::InputReceptionMode mode)); MOCK_METHOD1(input_channel_closed, void(std::shared_ptr const&)); }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_MOCK_INPUT_REGISTRAR_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_hwc_device_wrapper.h0000644000015301777760000000225312322054247027673 0ustar pbusernogroup00000000000000/* * 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_MOCK_HWC_DEVICE_WRAPPER_H_ #define MIR_TEST_DOUBLES_MOCK_HWC_DEVICE_WRAPPER_H_ #include "src/platform/graphics/android/hwc_wrapper.h" #include namespace mir { namespace test { namespace doubles { struct MockHWCDeviceWrapper : public graphics::android::HwcWrapper { MOCK_CONST_METHOD1(prepare, void(hwc_display_contents_1_t&)); MOCK_CONST_METHOD1(set, void(hwc_display_contents_1_t&)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_HWC_DEVICE_WRAPPER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_hwc_layerlist.h0000644000015301777760000000232312322054223026674 0ustar pbusernogroup00000000000000/* * 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_MOCK_HWC_LAYERLIST_H_ #define MIR_TEST_DOUBLES_MOCK_HWC_LAYERLIST_H_ #include "src/platform/graphics/android/hwc_layerlist.h" #include namespace mir { namespace test { namespace doubles { struct MockHWCLayerList : public graphics::android::HWCLayerList { ~MockHWCLayerList() noexcept {} MOCK_CONST_METHOD0(native_list, hwc_display_contents_1_t*()); MOCK_METHOD1(set_fb_target, void(std::shared_ptr const&)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_HWC_LAYERLIST_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_shell_session.h0000644000015301777760000000366612322054223026710 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_MOCK_SHELL_SESSION_H_ #define MIR_TEST_DOUBLES_MOCK_SHELL_SESSION_H_ #include "mir/shell/session.h" #include "mir/shell/surface_creation_parameters.h" #include "mir/graphics/display_configuration.h" #include namespace mir { namespace test { namespace doubles { struct MockShellSession : public shell::Session { MOCK_METHOD1(create_surface, frontend::SurfaceId(shell::SurfaceCreationParameters const&)); MOCK_METHOD1(destroy_surface, void(frontend::SurfaceId)); MOCK_CONST_METHOD1(get_surface, std::shared_ptr(frontend::SurfaceId)); MOCK_METHOD1(take_snapshot, void(shell::SnapshotCallback const&)); MOCK_CONST_METHOD0(default_surface, std::shared_ptr()); MOCK_CONST_METHOD0(name, std::string()); MOCK_CONST_METHOD0(process_id, pid_t()); MOCK_METHOD0(force_requests_to_complete, void()); MOCK_METHOD0(hide, void()); MOCK_METHOD0(show, void()); MOCK_METHOD1(send_display_config, void(graphics::DisplayConfiguration const&)); MOCK_METHOD3(configure_surface, int(frontend::SurfaceId, MirSurfaceAttrib, int)); MOCK_METHOD1(set_lifecycle_state, void(MirLifecycleState state)); }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_MOCK_SESSION_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_focus_setter.h0000644000015301777760000000212112322054223026524 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_MOCK_FOCUS_SETTER_H_ #define MIR_TEST_DOUBLES_MOCK_FOCUS_SETTER_H_ #include "mir/shell/focus_setter.h" #include namespace mir { namespace test { namespace doubles { struct MockFocusSetter : public shell::FocusSetter { MOCK_METHOD1(set_focus_to, void(std::shared_ptr const&)); }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_MOCK_FOCUS_SETTER_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_android_native_buffer.h0000644000015301777760000000377012322054223030351 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_MOCK_ANDROID_NATIVE_BUFFER_H_ #define MIR_TEST_DOUBLES_MOCK_ANDROID_NATIVE_BUFFER_H_ #include "mir/graphics/android/native_buffer.h" #include "mir/geometry/size.h" #include namespace mir { namespace test { namespace doubles { struct MockAndroidNativeBuffer : public graphics::NativeBuffer { MockAndroidNativeBuffer() { using namespace testing; ON_CALL(*this, anwb()) .WillByDefault(Return(&stub_anwb)); ON_CALL(*this, handle()) .WillByDefault(Return(&native_handle)); ON_CALL(*this, copy_fence()) .WillByDefault(Return(-1)); } MockAndroidNativeBuffer(geometry::Size sz) : MockAndroidNativeBuffer() { stub_anwb.width = sz.width.as_int(); stub_anwb.height = sz.height.as_int(); } MOCK_CONST_METHOD0(anwb, ANativeWindowBuffer*()); MOCK_CONST_METHOD0(handle, buffer_handle_t()); MOCK_CONST_METHOD0(copy_fence, graphics::android::NativeFence()); MOCK_METHOD0(wait_for_content, void()); MOCK_METHOD1(update_fence, void(graphics::android::NativeFence&)); ANativeWindowBuffer stub_anwb; native_handle_t native_handle; }; typedef testing::NiceMock StubAndroidNativeBuffer; } } } #endif /* MIR_TEST_DOUBLES_MOCK_ANDROID_NATIVE_BUFFER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_screencast.h0000644000015301777760000000265012322054223026160 0ustar pbusernogroup00000000000000/* * 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_MOCK_SCREENCAST_H_ #define MIR_TEST_DOUBLES_MOCK_SCREENCAST_H_ #include "mir/frontend/screencast.h" #include namespace mir { namespace test { namespace doubles { class MockScreencast : public frontend::Screencast { public: MOCK_METHOD3(create_session, frontend::ScreencastSessionId( geometry::Rectangle const&, geometry::Size const&, MirPixelFormat)); MOCK_METHOD1(destroy_session, void(frontend::ScreencastSessionId)); MOCK_METHOD1(capture, std::shared_ptr( frontend::ScreencastSessionId)); }; } } } #endif /* MIR_TEST_DOUBLES_NULL_SCREENCAST_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_driver_interpreter.h0000644000015301777760000000357712322054223030001 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_STUB_DRIVER_INTERPRETER_H_ #define MIR_TEST_DOUBLES_STUB_DRIVER_INTERPRETER_H_ #include "mir/graphics/android/android_driver_interpreter.h" namespace mir { namespace test { namespace doubles { class StubDriverInterpreter : public graphics::android::AndroidDriverInterpreter { public: StubDriverInterpreter(mir::geometry::Size sz, int visual_id) : sz{sz}, visual_id{visual_id} { } StubDriverInterpreter() : StubDriverInterpreter(mir::geometry::Size{44,22}, 5) { } mir::graphics::NativeBuffer* driver_requests_buffer() { return nullptr; } void driver_returns_buffer(ANativeWindowBuffer*, int) { } void dispatch_driver_request_format(int) { } int driver_requests_info(int index) const { if (index == NATIVE_WINDOW_WIDTH) return sz.width.as_uint32_t(); if (index == NATIVE_WINDOW_HEIGHT) return sz.height.as_uint32_t(); if (index == NATIVE_WINDOW_FORMAT) return visual_id; return 0; } void sync_to_display(bool) { } private: mir::geometry::Size sz; int visual_id; }; } } } #endif /* MIR_TEST_DOUBLES_STUB_BUFFER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_display_report.h0000644000015301777760000000337412322054223027072 0ustar pbusernogroup00000000000000/* * 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_MOCK_DISPLAY_REPORT_H_ #define MIR_TEST_DOUBLES_MOCK_DISPLAY_REPORT_H_ #include "mir/graphics/display_report.h" #include namespace mir { namespace test { namespace doubles { class MockDisplayReport : public graphics::DisplayReport { public: MOCK_METHOD0(report_successful_setup_of_native_resources, void()); MOCK_METHOD0(report_successful_egl_make_current_on_construction, void()); MOCK_METHOD0(report_successful_egl_buffer_swap_on_construction, void()); MOCK_METHOD0(report_successful_drm_mode_set_crtc_on_construction, void()); MOCK_METHOD0(report_successful_display_construction, void()); MOCK_METHOD1(report_drm_master_failure, void(int)); MOCK_METHOD0(report_vt_switch_away_failure, void()); MOCK_METHOD0(report_vt_switch_back_failure, void()); MOCK_METHOD2(report_hwc_composition_in_use, void(int,int)); MOCK_METHOD0(report_gpu_composition_in_use, void()); MOCK_METHOD2(report_egl_configuration, void(EGLDisplay,EGLConfig)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_DISPLAY_REPORT_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_input_channel.h0000644000015301777760000000242012322054223026674 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_STUB_INPUT_CHANNEL_H_ #define MIR_TEST_DOUBLES_STUB_INPUT_CHANNEL_H_ #include "mir/input/input_channel.h" namespace mir { namespace test { namespace doubles { struct StubInputChannel : public input::InputChannel { StubInputChannel(int fd) : input_fd(fd) { } StubInputChannel() : StubInputChannel(0) { } int client_fd() const override { return input_fd; } int server_fd() const override { return input_fd; } int input_fd; }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_STUB_INPUT_CHANNEL_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_session.h0000644000015301777760000000315512322054223025512 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_MOCK_SESSION_H_ #define MIR_TEST_DOUBLES_MOCK_SESSION_H_ #include "mir/frontend/session.h" #include "mir/shell/surface_creation_parameters.h" #include namespace mir { namespace test { namespace doubles { struct MockSession : public frontend::Session { MOCK_METHOD1(create_surface, frontend::SurfaceId(shell::SurfaceCreationParameters const&)); MOCK_METHOD1(destroy_surface, void(frontend::SurfaceId)); MOCK_CONST_METHOD1(get_surface, std::shared_ptr(frontend::SurfaceId)); MOCK_CONST_METHOD0(name, std::string()); MOCK_METHOD0(force_requests_to_complete, void()); MOCK_METHOD0(hide, void()); MOCK_METHOD0(show, void()); MOCK_METHOD1(send_display_config, void(graphics::DisplayConfiguration const&)); MOCK_METHOD3(configure_surface, int(frontend::SurfaceId, MirSurfaceAttrib, int)); }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_MOCK_SESSION_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_video_devices.h0000644000015301777760000000221712322054223026656 0ustar pbusernogroup00000000000000/* * 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_VIDEO_DEVICES_H_ #define MIR_TEST_DOUBLES_NULL_VIDEO_DEVICES_H_ #include "src/platform/graphics/mesa/video_devices.h" namespace mir { namespace test { namespace doubles { class NullVideoDevices : public graphics::mesa::VideoDevices { public: void register_change_handler( graphics::EventHandlerRegister&, std::function const&) { } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_VIDEO_DEVICES_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_swapping_gl_context.h0000644000015301777760000000207212322054223030126 0ustar pbusernogroup00000000000000/* * 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_STUB_SWAPPING_GL_CONTEXT_H_ #define MIR_TEST_DOUBLES_STUB_SWAPPING_GL_CONTEXT_H_ #include "src/platform/graphics/android/gl_context.h" namespace mir { namespace test { namespace doubles { struct StubSwappingGLContext : public graphics::android::SwappingGLContext { void swap_buffers() const {} }; } } } #endif // MIR_TEST_DOUBLES_STUB_COMPOSITING_CRITERIA_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_ipc_factory.h0000644000015301777760000000327212322054247026363 0ustar pbusernogroup00000000000000/* * 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: Thomas Voss * Alan Griffiths */ #ifndef MIR_TEST_DOUBLES_STUB_IPC_FACTORY_H_ #define MIR_TEST_DOUBLES_STUB_IPC_FACTORY_H_ #include "mir_test/fake_shared.h" #include "src/server/frontend/protobuf_ipc_factory.h" #include "src/server/frontend/resource_cache.h" namespace mir { namespace test { namespace doubles { class StubIpcFactory : public frontend::ProtobufIpcFactory { public: StubIpcFactory(protobuf::DisplayServer& server) : server(fake_shared(server)), cache(std::make_shared()) { } std::shared_ptr make_ipc_server( pid_t, std::shared_ptr const&) override { return server; } private: virtual std::shared_ptr resource_cache() override { return cache; } std::shared_ptr server; std::shared_ptr const cache; }; } } } #endif /* MIR_TEST_DOUBLES_STUB_IPC_FACTORY_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_server_status_listener.h0000644000015301777760000000223212322054223030640 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_MOCK_SERVER_STATUS_LISTENER_H_ #define MIR_TEST_DOUBLES_MOCK_SERVER_STATUS_LISTENER_H_ #include "mir/server_status_listener.h" #include namespace mir { namespace test { namespace doubles { class MockServerStatusListener : public mir::ServerStatusListener { public: MOCK_METHOD0(paused, void()); MOCK_METHOD0(resumed, void()); MOCK_METHOD0(started, void()); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_SERVER_STATUS_LISTENER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_display_configuration.h0000644000015301777760000001243612322054223030451 0ustar pbusernogroup00000000000000/* * 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 "mir/geometry/rectangle.h" #include "mir_toolkit/common.h" #include namespace mir { namespace test { namespace doubles { class StubDisplayConfig : public graphics::DisplayConfiguration { public: StubDisplayConfig() : StubDisplayConfig(3) { } StubDisplayConfig(StubDisplayConfig const& other) : graphics::DisplayConfiguration(), cards(other.cards), outputs(other.outputs) { } StubDisplayConfig(unsigned int num_displays) : StubDisplayConfig(num_displays, { mir_pixel_format_bgr_888, mir_pixel_format_abgr_8888, mir_pixel_format_xbgr_8888 }) { } StubDisplayConfig(std::vector> const& connected_used) : StubDisplayConfig(connected_used.size()) { for (auto i = 0u; i < outputs.size(); ++i) { outputs[i].connected = connected_used[i].first; outputs[i].used = connected_used[i].second; } } StubDisplayConfig(unsigned int num_displays, std::vector const& pfs) { /* construct a non-trivial dummy display config to send */ int mode_index = 0; for (auto i = 0u; i < num_displays; i++) { std::vector modes; for (auto j = 0u; j <= i; j++) { geometry::Size sz{mode_index*4, mode_index*3}; graphics::DisplayConfigurationMode mode{sz, 10.0f * mode_index }; mode_index++; modes.push_back(mode); } size_t mode_index = modes.size() - 1; geometry::Size physical_size{}; geometry::Point top_left{}; graphics::DisplayConfigurationOutput output{ graphics::DisplayConfigurationOutputId{static_cast(i + 1)}, graphics::DisplayConfigurationCardId{static_cast(i)}, graphics::DisplayConfigurationOutputType::vga, pfs, modes, i, physical_size, ((i % 2) == 0), // even numbers have connected==true ((i % 4) == 0), // only every second even has used==true top_left, mode_index, pfs[0], mir_power_mode_off, mir_orientation_normal }; outputs.push_back(output); graphics::DisplayConfigurationCard card{ graphics::DisplayConfigurationCardId{static_cast(i)}, i + 1 }; cards.push_back(card); } }; StubDisplayConfig(std::vector const& rects) { int id = 1; for (auto const& rect : rects) { graphics::DisplayConfigurationOutput output { graphics::DisplayConfigurationOutputId{id}, graphics::DisplayConfigurationCardId{0}, graphics::DisplayConfigurationOutputType::vga, std::vector{mir_pixel_format_abgr_8888}, {{rect.size, 60.0}}, 0, geometry::Size{}, true, true, rect.top_left, 0, mir_pixel_format_abgr_8888, mir_power_mode_on, mir_orientation_normal }; outputs.push_back(output); ++id; } graphics::DisplayConfigurationCard card{ graphics::DisplayConfigurationCardId{static_cast(1)}, rects.size() }; cards.push_back(card); } void for_each_card(std::function f) const override { for (auto const& card : cards) f(card); } void for_each_output(std::function f) const override { for (auto& disp : outputs) { f(disp); } } void for_each_output(std::function f) override { for (auto& disp : outputs) { graphics::UserDisplayConfigurationOutput user(disp); f(user); } } std::vector cards; std::vector outputs; }; } } } #endif /* MIR_TEST_DOUBLES_STUB_DISPLAY_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_display.h0000644000015301777760000000373712322054223025502 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_MOCK_DISPLAY_H_ #define MIR_TEST_DOUBLES_MOCK_DISPLAY_H_ #include "mir/graphics/display.h" #include "mir/graphics/gl_context.h" #include "mir/main_loop.h" #include "mir_test/gmock_fixes.h" #include namespace mir { namespace test { namespace doubles { struct MockDisplay : public graphics::Display { public: MOCK_METHOD1(for_each_display_buffer, void (std::function const&)); MOCK_CONST_METHOD0(configuration, std::unique_ptr()); MOCK_METHOD1(configure, void(graphics::DisplayConfiguration const&)); MOCK_METHOD2(register_configuration_change_handler, void(graphics::EventHandlerRegister&, graphics::DisplayConfigurationChangeHandler const&)); MOCK_METHOD3(register_pause_resume_handlers, void(graphics::EventHandlerRegister&, graphics::DisplayPauseHandler const&, graphics::DisplayResumeHandler const&)); MOCK_METHOD0(pause, void()); MOCK_METHOD0(resume, void()); MOCK_METHOD0(the_cursor, std::weak_ptr()); MOCK_METHOD0(create_gl_context, std::unique_ptr()); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_DISPLAY_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_buffer_initializer.h0000644000015301777760000000234212322054223027700 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #ifndef MIR_TEST_DOUBLES_MOCK_BUFFER_INITIALIZER_H_ #define MIR_TEST_DOUBLES_MOCK_BUFFER_INITIALIZER_H_ #include "mir/graphics/buffer_initializer.h" #include namespace mir { namespace test { namespace doubles { class MockBufferInitializer : public graphics::BufferInitializer { public: MOCK_METHOD1(operator_call, void(graphics::Buffer& buffer)); void operator()(graphics::Buffer& buffer) { operator_call(buffer); } }; } } } // namespace mir #endif /* MIR_TEST_DOUBLES_MOCK_BUFFER_INITIALIZER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_swapping_gl_context.h0000644000015301777760000000210712322054223030101 0ustar pbusernogroup00000000000000/* * 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_MOCK_SWAPPING_GL_CONTEXT_H_ #define MIR_TEST_DOUBLES_MOCK_SWAPPING_GL_CONTEXT_H_ #include "src/platform/graphics/android/gl_context.h" namespace mir { namespace test { namespace doubles { struct MockSwappingGLContext : public graphics::android::SwappingGLContext { MOCK_CONST_METHOD0(swap_buffers, void()); }; } } } #endif // MIR_TEST_DOUBLES_MOCK_COMPOSITING_CRITERIA_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_scene.h0000644000015301777760000000302412322054247025125 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_MOCK_SCENE_H_ #define MIR_TEST_DOUBLES_MOCK_SCENE_H_ #include "mir/compositor/scene.h" #include namespace mir { namespace test { namespace doubles { class MockScene : public compositor::Scene { public: MockScene() { ON_CALL(*this, generate_renderable_list()) .WillByDefault(testing::Return(graphics::RenderableList{})); } MOCK_CONST_METHOD0(generate_renderable_list, graphics::RenderableList()); MOCK_METHOD2(for_each_if, void(compositor::FilterForScene&, compositor::OperatorForScene&)); MOCK_METHOD1(set_change_callback, void(std::function const&)); MOCK_METHOD0(lock, void()); MOCK_METHOD0(unlock, void()); }; } // namespace doubles } // namespace test } // namespace mir #endif /* MIR_TEST_DOUBLES_MOCK_SCENE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_display_device.h0000644000015301777760000000270412322054247027044 0ustar pbusernogroup00000000000000/* * 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 . * */ #ifndef MIR_TEST_DOUBLES_STUB_DISPLAY_DEVICE_H_ #define MIR_TEST_DOUBLES_STUB_DISPLAY_DEVICE_H_ #include "src/platform/graphics/android/display_device.h" namespace mir { namespace test { namespace doubles { struct StubDisplayDevice : public graphics::android::DisplayDevice { StubDisplayDevice() { } ~StubDisplayDevice() noexcept {} void mode(MirPowerMode) { } void render_gl_and_overlays( graphics::android::SwappingGLContext const&, graphics::RenderableList const&, std::function const&) { } void render_gl(graphics::android::SwappingGLContext const&) { } void gpu_render(EGLDisplay, EGLSurface) { } void post(graphics::Buffer const&) { } }; } } } #endif /* MIR_TEST_DOUBLES_STUB_DISPLAY_DEVICE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_client_buffer.h0000644000015301777760000000303412322054223026653 0ustar pbusernogroup00000000000000/* * 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_CLIENT_BUFFER_H_ #define MIR_TEST_DOUBLES_NULL_CLIENT_BUFFER_H_ #include "src/client/client_buffer.h" namespace mir { namespace test { namespace doubles { class NullClientBuffer : public client::ClientBuffer { public: std::shared_ptr secure_for_cpu_write() { return std::make_shared(); } geometry::Size size() const { return geometry::Size(); } geometry::Stride stride() const { return geometry::Stride(); } MirPixelFormat pixel_format() const { return mir_pixel_format_invalid; } uint32_t age() const { return 0; } void increment_age() { } void mark_as_submitted() {} std::shared_ptr native_buffer_handle() const { return nullptr; } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_CLIENT_BUFFER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_gl_config.h0000644000015301777760000000215312322054247026005 0ustar pbusernogroup00000000000000/* * 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_STUB_GL_CONFIG_H_ #define MIR_TEST_DOUBLES_STUB_GL_CONFIG_H_ #include "mir/graphics/gl_config.h" #include namespace mir { namespace test { namespace doubles { struct StubGLConfig : public graphics::GLConfig { int depth_buffer_bits() const override { return 0; } int stencil_buffer_bits() const override { return 0; } }; } } } #endif /* MIR_TEST_DOUBLES_STUB_GL_CONFIG_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_renderable.h0000644000015301777760000000327012322054247026162 0ustar pbusernogroup00000000000000/* * 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_STUB_RENDERABLE_H_ #define MIR_TEST_DOUBLES_STUB_RENDERABLE_H_ #include "mir_test_doubles/stub_buffer.h" #include #include namespace mir { namespace test { namespace doubles { class StubRenderable : public graphics::Renderable { public: std::shared_ptr buffer(void const*) const override { return std::make_shared(); } bool alpha_enabled() const { return false; } geometry::Rectangle screen_position() const { return {{},{}}; } float alpha() const override { return 1.0f; } glm::mat4 transformation() const override { return trans; } bool visible() const { return true; } bool shaped() const override { return false; } int buffers_ready_for_compositor() const override { return 1; } private: glm::mat4 trans; }; } } } #endif /* MIR_TEST_DOUBLES_STUB_RENDERABLE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_display.h0000644000015301777760000000430012322054223025506 0ustar pbusernogroup00000000000000/* * 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 "null_gl_context.h" #include "null_display_configuration.h" #include namespace mir { namespace test { namespace doubles { class NullDisplay : public graphics::Display { public: void for_each_display_buffer(std::function const&) { /* yield() is needed to ensure reasonable runtime under valgrind for some tests */ std::this_thread::yield(); } std::unique_ptr configuration() const override { return std::unique_ptr( new NullDisplayConfiguration ); } void configure(graphics::DisplayConfiguration const&) {} 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() {} void resume() {} std::weak_ptr the_cursor() { return {}; } std::unique_ptr create_gl_context() { return std::unique_ptr{new NullGLContext()}; } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_DISPLAY_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_input_dispatcher.h0000644000015301777760000000531612322054223027375 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_MOCK_INPUT_DISPATCHER_H_ #define MIR_TEST_DOUBLES_MOCK_INPUT_DISPATCHER_H_ #include #include namespace droidinput = android; namespace mir { namespace test { namespace doubles { struct MockInputDispatcher : public droidinput::InputDispatcherInterface { // droidinput::InputDispatcher interface MOCK_METHOD1(setInputEnumerator, void(droidinput::sp const&)); MOCK_METHOD1(dump, void(droidinput::String8&)); MOCK_METHOD0(monitor, void()); MOCK_METHOD0(dispatchOnce, void()); MOCK_METHOD6(injectInputEvent, int32_t(droidinput::InputEvent const*, int32_t, int32_t, int32_t, int32_t, uint32_t)); MOCK_METHOD1(setFocusedApplication, void(droidinput::sp const&)); MOCK_METHOD2(setInputDispatchMode, void(bool, bool)); MOCK_METHOD1(setInputFilterEnabled, void(bool)); MOCK_METHOD2(transferTouchFocus, bool(droidinput::sp const&, droidinput::sp const&)); MOCK_METHOD3(registerInputChannel, droidinput::status_t(droidinput::sp const&, droidinput::sp const&, bool)); MOCK_METHOD1(unregisterInputChannel, droidinput::status_t(droidinput::sp const&)); MOCK_METHOD1(setKeyboardFocus, void(droidinput::sp const&)); MOCK_METHOD1(notifyWindowRemoved, void(droidinput::sp const&)); // droidinput::InputListener interface MOCK_METHOD1(notifyConfigurationChanged, void(droidinput::NotifyConfigurationChangedArgs const*)); MOCK_METHOD1(notifyKey, void(droidinput::NotifyKeyArgs const*)); MOCK_METHOD1(notifyMotion, void(droidinput::NotifyMotionArgs const*)); MOCK_METHOD1(notifySwitch, void(droidinput::NotifySwitchArgs const*)); MOCK_METHOD1(notifyDeviceReset, void(droidinput::NotifyDeviceResetArgs const*)); }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_MOCK_INPUT_DISPATCHER_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_surface_factory.h0000644000015301777760000000247512322054247027220 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_MOCK_SURFACE_FACTORY_H_ #define MIR_TEST_DOUBLES_MOCK_SURFACE_FACTORY_H_ #include "mir/shell/surface_factory.h" #include #include namespace mir { namespace test { namespace doubles { struct MockSurfaceFactory : public shell::SurfaceFactory { MOCK_METHOD3(create_surface, std::shared_ptr( shell::Session*, const shell::SurfaceCreationParameters&, std::shared_ptr const&)); void destroy_surface(std::shared_ptr const& /*surface*/) override {} }; } } } #endif // MIR_TEST_DOUBLES_MOCK_SURFACE_FACTORY_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_input_surface.h0000644000015301777760000000325712322054247026707 0ustar pbusernogroup00000000000000/* * 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_MOCK_INPUT_SURFACE_H_ #define MIR_TEST_DOUBLES_MOCK_INPUT_SURFACE_H_ #include "mir/input/surface.h" #include namespace mir { namespace test { namespace doubles { class MockInputSurface : public input::Surface { public: MockInputSurface() { using namespace testing; ON_CALL(*this, top_left()) .WillByDefault( Return(geometry::Point{})); ON_CALL(*this, size()) .WillByDefault( Return(geometry::Size{})); static std::string n; ON_CALL(*this, name()) .WillByDefault(testing::Return(n)); } ~MockInputSurface() noexcept {} MOCK_CONST_METHOD0(top_left, geometry::Point()); MOCK_CONST_METHOD0(size, geometry::Size()); MOCK_CONST_METHOD0(name, std::string()); MOCK_CONST_METHOD1(contains, bool(geometry::Point const&)); }; typedef ::testing::NiceMock StubInputSurface; } } } #endif /* MIR_TEST_DOUBLES_MOCK_INPUT_SURFACE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_snapshot_strategy.h0000644000015301777760000000224412322054223027627 0ustar pbusernogroup00000000000000/* * 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_SNAPSHOT_STRATEGY_H_ #define MIR_TEST_DOUBLES_NULL_SNAPSHOT_STRATEGY_H_ #include "src/server/scene/snapshot_strategy.h" namespace mir { namespace test { namespace doubles { struct NullSnapshotStrategy : public scene::SnapshotStrategy { void take_snapshot_of(std::shared_ptr const&, shell::SnapshotCallback const&) { } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_SNAPSHOT_STRATEGY_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_display_buffer.h0000644000015301777760000000251212322054223027045 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_gl_config.h0000644000015301777760000000213512322054247025761 0ustar pbusernogroup00000000000000/* * 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_MOCK_GL_CONFIG_H_ #define MIR_TEST_DOUBLES_MOCK_GL_CONFIG_H_ #include "mir/graphics/gl_config.h" #include namespace mir { namespace test { namespace doubles { struct MockGLConfig : public graphics::GLConfig { MOCK_CONST_METHOD0(depth_buffer_bits, int()); MOCK_CONST_METHOD0(stencil_buffer_bits, int()); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_GL_CONFIG_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_interpreter_resource_cache.h0000644000015301777760000000256612322054223031431 0ustar pbusernogroup00000000000000/* * 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_MOCK_INTERPRETER_RESOURCE_CACHE_H_ #define MIR_TEST_DOUBLES_MOCK_INTERPRETER_RESOURCE_CACHE_H_ #include "src/platform/graphics/android/interpreter_resource_cache.h" namespace mir { namespace test { namespace doubles { struct MockInterpreterResourceCache : public graphics::android::InterpreterResourceCache { MOCK_METHOD2(store_buffer, void(std::shared_ptrconst&, std::shared_ptr const&)); MOCK_METHOD1(retrieve_buffer, std::shared_ptr(ANativeWindowBuffer*)); MOCK_METHOD2(update_native_fence, void(ANativeWindowBuffer*, int)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_INTERPRETER_RESOURCE_CACHE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_platform.h0000644000015301777760000000377112322054247025706 0ustar pbusernogroup00000000000000/* * 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 "null_display.h" namespace mir { namespace test { namespace doubles { class NullPlatform : public graphics::Platform { public: std::shared_ptr create_buffer_allocator( const std::shared_ptr& /*buffer_initializer*/) { return std::shared_ptr(); } std::shared_ptr create_display( std::shared_ptr const&, std::shared_ptr const&) { return std::make_shared(); } std::shared_ptr get_ipc_package() { return std::make_shared(); } std::shared_ptr create_internal_client() { return std::shared_ptr(); } void fill_ipc_package(graphics::BufferIPCPacker*, graphics::Buffer const*) const { } EGLNativeDisplayType egl_native_display() const { return EGLNativeDisplayType(); } }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_NULL_PLATFORM_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_session_authorizer.h0000644000015301777760000000235612322054247030022 0ustar pbusernogroup00000000000000/* * 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_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(pid_t) { return true; } bool configure_display_is_allowed(pid_t) { return true; } bool screencast_is_allowed(pid_t) { return true; } }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_STUB_SESSION_AUTHORIZER_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_gl.h0000644000015301777760000001102112322054223024420 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_MOCK_GL_H_ #define MIR_TEST_DOUBLES_MOCK_GL_H_ #include #include namespace mir { namespace test { namespace doubles { class MockGL { public: MockGL(); ~MockGL(); // Please keep these ordered by name MOCK_METHOD1(glActiveTexture, void(GLenum)); MOCK_METHOD2(glAttachShader, void(GLuint, GLuint)); MOCK_METHOD2(glBindBuffer, void(GLenum, GLuint)); MOCK_METHOD2(glBindFramebuffer, void(GLenum, GLuint)); MOCK_METHOD2(glBindRenderbuffer, void(GLenum, GLuint)); MOCK_METHOD2(glBindTexture, void(GLenum, GLuint)); MOCK_METHOD2(glBlendFunc, void(GLenum, GLenum)); MOCK_METHOD4(glBufferData, void(GLenum, GLsizeiptr, const GLvoid *, GLenum)); MOCK_METHOD1(glCheckFramebufferStatus, GLenum(GLenum)); MOCK_METHOD1(glClear, void(GLbitfield)); MOCK_METHOD1(glCompileShader, void(GLuint)); MOCK_METHOD0(glCreateProgram, GLuint()); MOCK_METHOD1(glCreateShader, GLuint(GLenum)); MOCK_METHOD2(glDeleteBuffers, void(GLsizei, const GLuint *)); MOCK_METHOD2(glDeleteFramebuffers, void(GLsizei, const GLuint *)); MOCK_METHOD2(glDeleteRenderbuffers, void(GLsizei, const GLuint *)); MOCK_METHOD1(glDeleteProgram, void(GLuint)); MOCK_METHOD1(glDeleteShader, void(GLuint)); MOCK_METHOD2(glDeleteTextures, void(GLsizei, const GLuint *)); MOCK_METHOD1(glDisable, void(GLenum)); MOCK_METHOD1(glDisableVertexAttribArray, void(GLuint)); MOCK_METHOD3(glDrawArrays, void(GLenum, GLint, GLsizei)); MOCK_METHOD1(glEnable, void(GLenum)); MOCK_METHOD1(glEnableVertexAttribArray, void(GLuint)); MOCK_METHOD0(glFinish, void()); MOCK_METHOD4(glFramebufferRenderbuffer, void(GLenum, GLenum, GLenum, GLuint)); MOCK_METHOD5(glFramebufferTexture2D, void(GLenum, GLenum, GLenum, GLuint, GLint)); MOCK_METHOD2(glGenBuffers, void(GLsizei, GLuint *)); MOCK_METHOD2(glGenFramebuffers, void(GLsizei, GLuint *)); MOCK_METHOD2(glGenRenderbuffers, void(GLsizei, GLuint*)); MOCK_METHOD2(glGenTextures, void(GLsizei, GLuint *)); MOCK_METHOD2(glGetAttribLocation, GLint(GLuint, const GLchar *)); MOCK_METHOD0(glGetError, GLenum()); MOCK_METHOD2(glGetIntegerv, void(GLenum, GLint*)); MOCK_METHOD4(glGetProgramInfoLog, void(GLuint, GLsizei, GLsizei *, GLchar *)); MOCK_METHOD3(glGetProgramiv, void(GLuint, GLenum, GLint *)); MOCK_METHOD4(glGetShaderInfoLog, void(GLuint, GLsizei, GLsizei *, GLchar *)); MOCK_METHOD3(glGetShaderiv, void(GLuint, GLenum, GLint *)); MOCK_METHOD1(glGetString, const GLubyte*(GLenum)); MOCK_METHOD2(glGetUniformLocation, GLint(GLuint, const GLchar *)); MOCK_METHOD1(glLinkProgram, void(GLuint)); MOCK_METHOD7(glReadPixels, void(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid*)); MOCK_METHOD4(glRenderbufferStorage, void(GLenum, GLenum, GLsizei, GLsizei)); MOCK_METHOD4(glShaderSource, void(GLuint, GLsizei, const GLchar * const *, const GLint *)); MOCK_METHOD9(glTexImage2D, void(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum,const GLvoid*)); MOCK_METHOD3(glTexParameteri, void(GLenum, GLenum, GLenum)); MOCK_METHOD2(glUniform1f, void(GLint, GLfloat)); MOCK_METHOD3(glUniform2f, void(GLint, GLfloat, GLfloat)); MOCK_METHOD2(glUniform1i, void(GLint, GLint)); MOCK_METHOD4(glUniformMatrix4fv, void(GLuint, GLsizei, GLboolean, const GLfloat *)); MOCK_METHOD1(glUseProgram, void(GLuint)); MOCK_METHOD6(glVertexAttribPointer, void(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid *)); MOCK_METHOD4(glViewport, void(GLint, GLint, GLsizei, GLsizei)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_GL_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_screencast.h0000644000015301777760000000254412322054223026203 0ustar pbusernogroup00000000000000/* * 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_SCREENCAST_H_ #define MIR_TEST_DOUBLES_NULL_SCREENCAST_H_ #include "mir/frontend/screencast.h" namespace mir { namespace test { namespace doubles { class NullScreencast : public frontend::Screencast { public: frontend::ScreencastSessionId create_session( geometry::Rectangle const&, geometry::Size const&, MirPixelFormat) { return frontend::ScreencastSessionId{1}; } void destroy_session(frontend::ScreencastSessionId) {} std::shared_ptr capture(frontend::ScreencastSessionId) { return nullptr; } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_SCREENCAST_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_android_alloc_device.h0000644000015301777760000000730212322054223030136 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_MOCK_ANDROID_ALLOC_DEVICE_H_ #define MIR_TEST_DOUBLES_MOCK_ANDROID_ALLOC_DEVICE_H_ #include #include namespace mir { namespace test { namespace android { class ICSAllocInterface { public: virtual ~ICSAllocInterface() {/* TODO: make nothrow */} virtual int alloc_interface(alloc_device_t* dev, int w, int h, int format, int usage, buffer_handle_t* handle, int* stride) = 0; virtual int free_interface(alloc_device_t* dev, buffer_handle_t handle) = 0; virtual int dump_interface(alloc_device_t* dev, char *buf, int len) = 0; }; } namespace doubles { class MockAllocDevice : public android::ICSAllocInterface, public alloc_device_t { public: MockAllocDevice() { using namespace testing; buffer_handle = mock_generate_sane_android_handle(43, 22); fake_stride = 300; alloc = hook_alloc; free = hook_free; dump = hook_dump; ON_CALL(*this, alloc_interface(_,_,_,_,_,_,_)) .WillByDefault(DoAll( SetArgPointee<5>(buffer_handle), SetArgPointee<6>(fake_stride), Return(0))); ON_CALL(*this, free_interface(_,_)) .WillByDefault(Return(0)); } ~MockAllocDevice() { ::free((void*)buffer_handle); } static int hook_alloc(alloc_device_t* mock_alloc, int w, int h, int format, int usage, buffer_handle_t* handle, int* stride) { MockAllocDevice* mocker = static_cast(mock_alloc); return mocker->alloc_interface(mock_alloc, w, h, format, usage, handle, stride); } static int hook_free(alloc_device_t* mock_alloc, buffer_handle_t handle) { MockAllocDevice* mocker = static_cast(mock_alloc); return mocker->free_interface(mock_alloc, handle); } static void hook_dump(alloc_device_t* mock_alloc, char* buf, int buf_len) { MockAllocDevice* mocker = static_cast(mock_alloc); mocker->dump_interface(mock_alloc, buf, buf_len); } native_handle_t* mock_generate_sane_android_handle(int numFd, int numInt) { native_handle_t *handle; int total=numFd + numInt; int header_offset=3; handle = (native_handle_t*) malloc(sizeof(int) * (header_offset+ total)); handle->version = 0x389; handle->numFds = numFd; handle->numInts = numInt; for(int i=0; idata[i] = i*3; } return handle; } MOCK_METHOD7(alloc_interface, int(alloc_device_t*, int, int, int, int, buffer_handle_t*, int*)); MOCK_METHOD2(free_interface, int(alloc_device_t*, buffer_handle_t)); MOCK_METHOD3(dump_interface, int(alloc_device_t*, char*, int)); native_handle_t* buffer_handle; unsigned int fake_stride; }; } } } // namespace mir #endif /* MIR_TEST_DOUBLES_MOCK_ANDROID_ALLOC_DEVICE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/fake_renderable.h0000644000015301777760000000464412322054247026121 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_FAKE_RENDERABLE_H_ #define MIR_TEST_DOUBLES_FAKE_RENDERABLE_H_ #include "mir/graphics/renderable.h" #define GLM_FORCE_RADIANS #include #include namespace mir { namespace test { namespace doubles { class FakeRenderable : public graphics::Renderable { public: FakeRenderable(int x, int y, int width, int height, float opacity=1.0f, bool rectangular=true, bool visible=true, bool posted=true) : rect{{x, y}, {width, height}}, opacity(opacity), rectangular(rectangular), visible_(visible), posted(posted) { } float alpha() const override { return opacity; } glm::mat4 transformation() const override { return glm::mat4(); } bool visible() const override { return visible_ && posted; } bool shaped() const override { return !rectangular; } void set_buffer(std::shared_ptr b) { buf = b; } std::shared_ptr buffer(void const*) const override { return buf; } bool alpha_enabled() const override { return shaped() || alpha() < 1.0f; } geometry::Rectangle screen_position() const override { return rect; } int buffers_ready_for_compositor() const override { return 1; } private: std::shared_ptr buf; mir::geometry::Rectangle rect; float opacity; bool rectangular; bool visible_; bool posted; }; } // namespace doubles } // namespace test } // namespace mir #endif // MIR_TEST_DOUBLES_FAKE_RENDERABLE_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_gl_context.h0000644000015301777760000000206112322054223026211 0ustar pbusernogroup00000000000000/* * 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/graphics/gl_context.h" namespace mir { namespace test { namespace doubles { class NullGLContext : public graphics::GLContext { public: void make_current() const {} void release_current() const {} }; } } } #endif /* MIR_TEST_DOUBLES_NULL_GL_CONTEXT_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_surface_ranker.h0000644000015301777760000000211012322054247027015 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_MOCK_SURFACE_RANKER_H_ #define MIR_TEST_DOUBLES_MOCK_SURFACE_RANKER_H_ #include "mir/scene/surface_ranker.h" #include namespace mir { namespace test { namespace doubles { struct MockSurfaceRanker : public scene::SurfaceRanker { MOCK_METHOD1(raise, void(std::weak_ptr const&)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_SURFACE_RANKER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_shell.h0000644000015301777760000000303412322054223025132 0ustar pbusernogroup00000000000000/* * 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_SHELL_H_ #define MIR_TEST_DOUBLES_SHELL_H_ #include "mir/shell/surface_creation_parameters.h" #include "mir/frontend/shell.h" #include "mir/frontend/surface_id.h" #include namespace mir { namespace test { namespace doubles { struct MockShell : public frontend::Shell { MOCK_METHOD3(open_session, std::shared_ptr( pid_t client_pid, std::string const&, std::shared_ptr const&)); MOCK_METHOD1(close_session, void(std::shared_ptr const&)); MOCK_METHOD2(create_surface_for, frontend::SurfaceId(std::shared_ptr const&, shell::SurfaceCreationParameters const&)); MOCK_METHOD1(handle_surface_created, void(std::shared_ptr const&)); }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_SHELL_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_display_builder.h0000644000015301777760000000557212322054247027241 0ustar pbusernogroup00000000000000/* * 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_BUILDER_H_ #define MIR_TEST_DOUBLES_STUB_DISPLAY_BUILDER_H_ #include "src/platform/graphics/android/display_builder.h" #include "src/platform/graphics/android/configurable_display_buffer.h" #include namespace mir { namespace test { namespace doubles { struct StubConfigurableDisplayBuffer : public graphics::android::ConfigurableDisplayBuffer { StubConfigurableDisplayBuffer(geometry::Rectangle rect) : rect(rect) { } geometry::Rectangle view_area() const { return rect; } void make_current() {} void release_current() {} void post_update() {} bool can_bypass() const override { return false; } void render_and_post_update( graphics::RenderableList const&, std::function const&) {} MirOrientation orientation() const override { return mir_orientation_normal; } void configure(graphics::DisplayConfigurationOutput const&) {} graphics::DisplayConfigurationOutput configuration() const { return graphics::DisplayConfigurationOutput{ graphics::DisplayConfigurationOutputId{1}, graphics::DisplayConfigurationCardId{0}, graphics::DisplayConfigurationOutputType::vga, {}, {}, 0, {}, false, false, {}, 0, mir_pixel_format_abgr_8888, mir_power_mode_off, mir_orientation_normal}; } private: geometry::Rectangle rect; }; struct StubDisplayBuilder : public graphics::android::DisplayBuilder { StubDisplayBuilder(geometry::Size sz) : sz(sz) { } StubDisplayBuilder() : StubDisplayBuilder(geometry::Size{0,0}) { } MirPixelFormat display_format() { return mir_pixel_format_abgr_8888; } std::unique_ptr create_display_buffer( graphics::android::GLContext const&) { return std::unique_ptr( new StubConfigurableDisplayBuffer(geometry::Rectangle{{0,0},sz})); } geometry::Size sz; }; } } } // namespace mir #endif /* MIR_TEST_DOUBLES_STUB_DISPLAY_BUILDER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_hwc_vsync_coordinator.h0000644000015301777760000000230212322054223030426 0ustar pbusernogroup00000000000000/* * 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_MOCK_HWC_VSYNC_COORDINATOR_H_ #define MIR_TEST_DOUBLES_MOCK_HWC_VSYNC_COORDINATOR_H_ #include "src/platform/graphics/android/hwc_vsync_coordinator.h" #include namespace mir { namespace test { namespace doubles { struct MockVsyncCoordinator : public graphics::android::HWCVsyncCoordinator { ~MockVsyncCoordinator() noexcept {} MOCK_METHOD0(wait_for_vsync, void()); MOCK_METHOD0(notify_vsync, void()); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_HWC_VSYNC_COORDINATOR_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_android_registrar.h0000644000015301777760000000256312322054223027533 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_MOCK_ANDROID_REGISTRAR_H_ #define MIR_TEST_DOUBLES_MOCK_ANDROID_REGISTRAR_H_ #include #include "src/client/android/android_registrar.h" namespace mir { namespace geometry { class Rectangle; } namespace test { namespace doubles { struct MockAndroidRegistrar : public client::android::AndroidRegistrar { ~MockAndroidRegistrar() noexcept {} MOCK_CONST_METHOD1(register_buffer, std::shared_ptr(std::shared_ptr const&)); MOCK_METHOD2(secure_for_cpu, std::shared_ptr(std::shared_ptr, geometry::Rectangle)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_ANDROID_REGISTRAR_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_surface_configurator.h0000644000015301777760000000243312322054247030266 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_NULL_SURFACE_CONFIGURATOR_H_ #define MIR_TEST_DOUBLES_NULL_SURFACE_CONFIGURATOR_H_ #include "mir/scene/surface_configurator.h" namespace mir { namespace test { namespace doubles { struct NullSurfaceConfigurator : public scene::SurfaceConfigurator { int select_attribute_value(scene::Surface const&, MirSurfaceAttrib, int requested_value) { return requested_value; } void attribute_set(scene::Surface const&, MirSurfaceAttrib, int) { } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_SURFACE_CONFIGURATOR_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_renderer.h0000644000015301777760000000257312322054223025664 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_STUB_RENDERER_H_ #define MIR_TEST_DOUBLES_STUB_RENDERER_H_ #include "mir/compositor/renderer.h" namespace mir { namespace test { namespace doubles { class StubRenderer : public compositor::Renderer { public: void set_viewport(geometry::Rectangle const&) override { } void set_rotation(float) override { } void begin() const override { } void render(graphics::Renderable const&, graphics::Buffer&) const override { } void end() const override { } void suspend() override { } }; } // namespace doubles } // namespace test } // namespace mir #endif // MIR_TEST_DOUBLES_STUB_RENDERER_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_event_sink.h0000644000015301777760000000220112322054223026204 0ustar pbusernogroup00000000000000/* * 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_EVENT_SINK_H_ #define MIR_TEST_DOUBLES_NULL_EVENT_SINK_H_ #include "mir/frontend/event_sink.h" namespace mir { namespace test { namespace doubles { struct NullEventSink : public frontend::EventSink { void handle_event(MirEvent const&) {} void handle_lifecycle_event(MirLifecycleState) {} void handle_display_config_change(graphics::DisplayConfiguration const&) {} }; } } } #endif /* MIR_TEST_DOUBLES_NULL_EVENT_SINK_H_*/ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_compositor_report.h0000644000015301777760000000277412322054223027626 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_MOCK_COMPOSITOR_REPORT_H_ #define MIR_TEST_DOUBLES_MOCK_COMPOSITOR_REPORT_H_ #include "mir/compositor/compositor_report.h" #include namespace mir { namespace test { namespace doubles { class MockCompositorReport : public compositor::CompositorReport { public: MOCK_METHOD5(added_display, void(int,int,int,int, compositor::CompositorReport::SubCompositorId)); MOCK_METHOD1(began_frame, void(compositor::CompositorReport::SubCompositorId)); MOCK_METHOD2(finished_frame, void(bool,compositor::CompositorReport::SubCompositorId)); MOCK_METHOD0(started, void()); MOCK_METHOD0(stopped, void()); MOCK_METHOD0(scheduled, void()); }; } // namespace doubles } // namespace test } // namespace mir #endif mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_display_layout.h0000644000015301777760000000246512322054223027074 0ustar pbusernogroup00000000000000/* * 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_MOCK_DISPLAY_LAYOUT_H_ #define MIR_TEST_DOUBLES_MOCK_DISPLAY_LAYOUT_H_ #include "mir/shell/display_layout.h" #include namespace mir { namespace test { namespace doubles { class MockDisplayLayout : public shell::DisplayLayout { public: MOCK_METHOD1(clip_to_output, void(geometry::Rectangle& rect)); MOCK_METHOD1(size_to_output, void(geometry::Rectangle& rect)); MOCK_METHOD2(place_in_output, void(graphics::DisplayConfigurationOutputId id, geometry::Rectangle& rect)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_DISPLAY_LAYOUT_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_hwc_composer_device_1.h0000644000015301777760000001027612322054247030266 0ustar pbusernogroup00000000000000/* * 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_MOCK_HWC_COMPOSER_DEVICE_1_H_ #define MIR_TEST_DOUBLES_MOCK_HWC_COMPOSER_DEVICE_1_H_ #include #include namespace mir { namespace test { namespace doubles { class MockHWCComposerDevice1 : public hwc_composer_device_1 { public: MockHWCComposerDevice1() { using namespace testing; common.version = HWC_DEVICE_API_VERSION_1_1; registerProcs = hook_registerProcs; eventControl = hook_eventControl; set = hook_set; prepare = hook_prepare; blank = hook_blank; getDisplayConfigs = hook_getDisplayConfigs; getDisplayAttributes = hook_getDisplayAttributes; } static void hook_registerProcs(struct hwc_composer_device_1* mock_hwc, hwc_procs_t const* procs) { MockHWCComposerDevice1* mocker = static_cast(mock_hwc); return mocker->registerProcs_interface(mock_hwc, procs); } static int hook_eventControl(struct hwc_composer_device_1* mock_hwc, int disp, int event, int enabled) { MockHWCComposerDevice1* mocker = static_cast(mock_hwc); return mocker->eventControl_interface(mock_hwc, disp, event, enabled); } static int hook_set(struct hwc_composer_device_1 *mock_hwc, size_t numDisplays, hwc_display_contents_1_t** displays) { MockHWCComposerDevice1* mocker = static_cast(mock_hwc); return mocker->set_interface(mock_hwc, numDisplays, displays); } static int hook_prepare(struct hwc_composer_device_1 *mock_hwc, size_t numDisplays, hwc_display_contents_1_t** displays) { MockHWCComposerDevice1* mocker = static_cast(mock_hwc); return mocker->prepare_interface(mock_hwc, numDisplays, displays); } static int hook_blank(struct hwc_composer_device_1 *mock_hwc, int disp, int blank) { MockHWCComposerDevice1* mocker = static_cast(mock_hwc); return mocker->blank_interface(mock_hwc, disp, blank); } static int hook_getDisplayConfigs(struct hwc_composer_device_1* mock_hwc, int disp, uint32_t* configs, size_t* numConfigs) { MockHWCComposerDevice1* mocker = static_cast(mock_hwc); return mocker->getDisplayConfigs_interface(mock_hwc, disp, configs, numConfigs); } static int hook_getDisplayAttributes(struct hwc_composer_device_1* mock_hwc, int disp, uint32_t config, const uint32_t* attributes, int32_t* values) { MockHWCComposerDevice1* mocker = static_cast(mock_hwc); return mocker->getDisplayAttributes_interface(mock_hwc, disp, config, attributes, values); } MOCK_METHOD2(registerProcs_interface, void(struct hwc_composer_device_1*, hwc_procs_t const*)); MOCK_METHOD4(eventControl_interface, int(struct hwc_composer_device_1* dev, int disp, int event, int enabled)); MOCK_METHOD3(set_interface, int(struct hwc_composer_device_1 *, size_t, hwc_display_contents_1_t**)); MOCK_METHOD3(prepare_interface, int(struct hwc_composer_device_1 *, size_t, hwc_display_contents_1_t**)); MOCK_METHOD3(blank_interface, int(struct hwc_composer_device_1 *, int, int)); MOCK_METHOD4(getDisplayConfigs_interface, int(struct hwc_composer_device_1*, int, uint32_t*, size_t*)); MOCK_METHOD5(getDisplayAttributes_interface, int(struct hwc_composer_device_1*, int, uint32_t, const uint32_t*, int32_t*)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_HWC_COMPOSER_DEVICE_1_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_fence.h0000644000015301777760000000223112322054223025101 0ustar pbusernogroup00000000000000/* * 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_MOCK_FENCE_H_ #define MIR_TEST_DOUBLES_MOCK_FENCE_H_ #include "mir/graphics/android/fence.h" #include namespace mir { namespace test { namespace doubles { struct MockFence : public graphics::android::Fence { MOCK_METHOD0(wait, void()); MOCK_METHOD1(merge_with, void(graphics::android::NativeFence&)); MOCK_CONST_METHOD0(copy_native_handle, graphics::android::NativeFence()); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_FENCE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_android_hw.h0000644000015301777760000000416212322054223026144 0ustar pbusernogroup00000000000000/* * 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_MOCK_ANDROID_HW_H_ #define MIR_TEST_DOUBLES_MOCK_ANDROID_HW_H_ #include "mir_test_doubles/mock_android_alloc_device.h" #include "mir_test_doubles/mock_hwc_composer_device_1.h" #include #include #include namespace mir { namespace test { namespace doubles { typedef struct hw_module_t hw_module; class HardwareModuleStub : public hw_module { public: HardwareModuleStub(hw_device_t& device); static int hw_open(const struct hw_module_t* module, const char*, struct hw_device_t** device); static int hw_close(struct hw_device_t*); hw_module_methods_t gr_methods; hw_device_t& mock_hw_device; }; class FailingHardwareModuleStub : public hw_module { public: FailingHardwareModuleStub(); static int hw_open(const struct hw_module_t* module, const char*, struct hw_device_t** device); static int hw_close(struct hw_device_t*); hw_module_methods_t gr_methods; }; class HardwareAccessMock { public: HardwareAccessMock(); ~HardwareAccessMock(); MOCK_METHOD2(hw_get_module, int(const char *id, const struct hw_module_t**)); bool open_count_matches_close(); std::shared_ptr mock_alloc_device; std::shared_ptr mock_hwc_device; std::shared_ptr mock_gralloc_module; std::shared_ptr mock_hwc_module; }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_ANDROID_HW_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_input_handles.h0000644000015301777760000000322012322054223026701 0ustar pbusernogroup00000000000000/* * 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 */ #include #include #ifndef MIR_TEST_DOUBLES_STUB_INPUT_HANDLES_H_ #define MIR_TEST_DOUBLES_STUB_INPUT_HANDLES_H_ namespace mir { namespace test { namespace doubles { struct StubInputApplicationHandle : public droidinput::InputApplicationHandle { StubInputApplicationHandle() { if (!mInfo) { mInfo = new droidinput::InputApplicationInfo; } } bool updateInfo() { return true; } }; struct StubWindowHandle : public droidinput::InputWindowHandle { StubWindowHandle() : droidinput::InputWindowHandle(make_app_handle()) { if (!mInfo) { mInfo = new droidinput::InputWindowInfo(); } } droidinput::sp make_app_handle() { return new StubInputApplicationHandle; } bool updateInfo() { return true; } }; } } } #endif /* MIR_TEST_DOUBLES_STUB_INPUT_HANDLES_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_alloc_adaptor.h0000644000015301777760000000233712322054223026634 0ustar pbusernogroup00000000000000/* * 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_DOUBLES_MOCK_ALLOC_ADAPTOR_H_ #define MIR_TEST_DOUBLES_MOCK_ALLOC_ADAPTOR_H_ #include "src/platform/graphics/android/graphic_alloc_adaptor.h" #include #include namespace mir { namespace test { namespace doubles { class MockAllocAdaptor : public graphics::android::GraphicAllocAdaptor { public: MOCK_METHOD3(alloc_buffer, std::shared_ptr(geometry::Size, MirPixelFormat, graphics::android::BufferUsage)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_ALLOC_ADAPTOR_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_input_targeter.h0000644000015301777760000000230512322054223027057 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_MOCK_INPUT_TARGETER_H_ #define MIR_TEST_DOUBLES_MOCK_INPUT_TARGETER_H_ #include "mir/shell/input_targeter.h" #include namespace mir { namespace test { namespace doubles { struct MockInputTargeter : public shell::InputTargeter { virtual ~MockInputTargeter() noexcept(true) {} MOCK_METHOD1(focus_changed, void(std::shared_ptr const&)); MOCK_METHOD0(focus_cleared, void()); }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_MOCK_INPUT_TARGETER_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/stub_input_registrar.h0000644000015301777760000000245012322054223027271 0ustar pbusernogroup00000000000000/* * 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_TEST_DOUBLES_STUB_INPUT_REGISTRAR_H_ #define MIR_TEST_DOUBLES_STUB_INPUT_REGISTRAR_H_ #include "mir/scene/input_registrar.h" namespace mir { namespace test { namespace doubles { struct StubInputRegistrar : public scene::InputRegistrar { void input_channel_opened(std::shared_ptr const&, std::shared_ptr const&, input::InputReceptionMode) { } void input_channel_closed(std::shared_ptr const&) { } }; } } } // namespace mir #endif // MIR_TEST_DOUBLES_STUB_INPUT_REGISTRAR_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_framebuffer_bundle.h0000644000015301777760000000304612322054223027643 0ustar pbusernogroup00000000000000/* * 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_MOCK_FRAMEBUFFER_BUNDLE_H_ #define MIR_TEST_DOUBLES_MOCK_FRAMEBUFFER_BUNDLE_H_ #include "src/platform/graphics/android/framebuffer_bundle.h" #include "stub_buffer.h" #include namespace mir { namespace test { namespace doubles { struct MockFBBundle : public graphics::android::FramebufferBundle { MockFBBundle() { using namespace testing; ON_CALL(*this, last_rendered_buffer()) .WillByDefault(Return(std::make_shared())); } MOCK_METHOD0(fb_format, MirPixelFormat()); MOCK_METHOD0(fb_size, geometry::Size()); MOCK_METHOD0(buffer_for_render, std::shared_ptr()); MOCK_METHOD0(last_rendered_buffer, std::shared_ptr()); MOCK_METHOD1(wait_for_consumed_buffer, void(bool)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_FRAMEBUFFER_BUNDLE_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_display_changer.h0000644000015301777760000000251112322054247027205 0ustar pbusernogroup00000000000000/* * 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_CHANGER_H_ #define MIR_TEST_DOUBLES_NULL_DISPLAY_CHANGER_H_ #include "mir/frontend/display_changer.h" #include "null_display_configuration.h" namespace mir { namespace test { namespace doubles { class NullDisplayChanger : public frontend::DisplayChanger { public: virtual std::shared_ptr active_configuration() { return std::make_shared(); } virtual void configure(std::shared_ptr const&, std::shared_ptr const&) { } }; } } } #endif /* MIR_TEST_DOUBLES_NULL_DISPLAY_CHANGER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_buffer.h0000644000015301777760000000410112322054223025270 0ustar pbusernogroup00000000000000/* * 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_BUFFER_H_ #define MIR_TEST_DOUBLES_MOCK_BUFFER_H_ #include "mir/graphics/buffer_basic.h" #include "mir/geometry/size.h" #include "mir/graphics/buffer_id.h" #include #include namespace mir { namespace test { namespace doubles { struct MockBuffer : public graphics::Buffer { public: MockBuffer() { } MockBuffer(geometry::Size size, geometry::Stride s, MirPixelFormat pf) { using namespace testing; ON_CALL(*this, size()) .WillByDefault(Return(size)); ON_CALL(*this, stride()) .WillByDefault(Return(s)); ON_CALL(*this, pixel_format()) .WillByDefault(Return(pf)); ON_CALL(*this, id()) .WillByDefault(Return(graphics::BufferID{4})); ON_CALL(*this, native_buffer_handle()) .WillByDefault(Return(std::shared_ptr())); } MOCK_CONST_METHOD0(size, geometry::Size()); MOCK_CONST_METHOD0(stride, geometry::Stride()); MOCK_CONST_METHOD0(pixel_format, MirPixelFormat()); MOCK_CONST_METHOD0(native_buffer_handle, std::shared_ptr()); MOCK_METHOD0(bind_to_texture, void()); MOCK_CONST_METHOD0(id, graphics::BufferID()); MOCK_CONST_METHOD0(can_bypass, bool()); }; } } } #endif // MIR_TEST_DOUBLES_MOCK_BUFFER_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_display_buffer.h0000644000015301777760000000334012322054247027027 0ustar pbusernogroup00000000000000/* * 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_MOCK_DISPLAY_BUFFER_H_ #define MIR_TEST_DOUBLES_MOCK_DISPLAY_BUFFER_H_ #include #include namespace mir { namespace test { namespace doubles { class MockDisplayBuffer : public graphics::DisplayBuffer { public: MockDisplayBuffer() { using namespace testing; ON_CALL(*this, can_bypass()) .WillByDefault(Return(false)); ON_CALL(*this, view_area()) .WillByDefault(Return(geometry::Rectangle{{0,0},{0,0}})); } MOCK_CONST_METHOD0(view_area, geometry::Rectangle()); MOCK_METHOD0(make_current, void()); MOCK_METHOD0(release_current, void()); MOCK_METHOD0(post_update, void()); MOCK_CONST_METHOD0(can_bypass, bool()); MOCK_METHOD2(render_and_post_update, void(graphics::RenderableList const&, std::function const&)); MOCK_CONST_METHOD0(orientation, MirOrientation()); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_DISPLAY_BUFFER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/mock_window_handle_repository.h0000644000015301777760000000276212322054223031153 0ustar pbusernogroup00000000000000/* * 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 */ #include "src/server/input/android/android_window_handle_repository.h" #include #ifndef MIR_TEST_DOUBLES_MOCK_WINDOW_HANDLE_REPOSITORY_H_ #define MIR_TEST_DOUBLES_MOCK_WINDOW_HANDLE_REPOSITORY_H_ namespace mir { namespace test { namespace doubles { struct MockWindowHandleRepository : public input::android::WindowHandleRepository { MockWindowHandleRepository() { using namespace testing; ON_CALL(*this, handle_for_channel(_)) .WillByDefault(Return(droidinput::sp())); } ~MockWindowHandleRepository() noexcept(true) {}; MOCK_METHOD1(handle_for_channel, droidinput::sp(std::shared_ptr const&)); }; } } } #endif /* MIR_TEST_DOUBLES_MOCK_WINDOW_HANDLE_REPOSITORY_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_doubles/null_session_event_sink.h0000644000015301777760000000231312322054223027753 0ustar pbusernogroup00000000000000/* * 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_SESSION_EVENT_SINK_H_ #define MIR_TEST_DOUBLES_NULL_SESSION_EVENT_SINK_H_ #include "src/server/scene/session_event_sink.h" namespace mir { namespace test { namespace doubles { class NullSessionEventSink : public scene::SessionEventSink { public: void handle_focus_change(std::shared_ptr const&) {} void handle_no_focus() {} void handle_session_stopping(std::shared_ptr const&) {} }; } } } #endif /* MIR_TEST_DOUBLES_NULL_SESSION_EVENT_SINK_H_*/ mir-0.1.8+14.04.20140411/include/test/mir_test/0000755000015301777760000000000012322054703021127 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/test/mir_test/stub_server_tool.h0000644000015301777760000001023612322054223024677 0ustar pbusernogroup00000000000000/* * 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 */ #ifndef MIR_TEST_STUB_SERVER_TOOL_H_ #define MIR_TEST_STUB_SERVER_TOOL_H_ #include "mir_protobuf.pb.h" #include #include namespace mir { namespace test { struct StubServerTool : mir::protobuf::DisplayServer { StubServerTool() : drm_magic{0} { } virtual void create_surface(google::protobuf::RpcController* /*controller*/, const mir::protobuf::SurfaceParameters* request, mir::protobuf::Surface* response, google::protobuf::Closure* done) override { response->mutable_id()->set_value(13); // TODO distinct numbers & tracking response->set_width(request->width()); response->set_height(request->height()); response->set_pixel_format(request->pixel_format()); response->mutable_buffer()->set_buffer_id(22); std::unique_lock lock(guard); surface_name = request->surface_name(); wait_condition.notify_one(); done->Run(); } virtual void next_buffer( ::google::protobuf::RpcController* /*controller*/, ::mir::protobuf::SurfaceId const* /*request*/, ::mir::protobuf::Buffer* response, ::google::protobuf::Closure* done) override { response->set_buffer_id(22); std::unique_lock lock(guard); wait_condition.notify_one(); done->Run(); } virtual void release_surface(::google::protobuf::RpcController* /*controller*/, const ::mir::protobuf::SurfaceId* /*request*/, ::mir::protobuf::Void* /*response*/, ::google::protobuf::Closure* done) override { done->Run(); } virtual void connect( ::google::protobuf::RpcController*, const ::mir::protobuf::ConnectParameters* request, ::mir::protobuf::Connection* connect_msg, ::google::protobuf::Closure* done) override { app_name = request->application_name(); connect_msg->set_error(""); done->Run(); } virtual void disconnect(google::protobuf::RpcController* /*controller*/, const mir::protobuf::Void* /*request*/, mir::protobuf::Void* /*response*/, google::protobuf::Closure* done) override { std::unique_lock lock(guard); wait_condition.notify_one(); done->Run(); } virtual void drm_auth_magic(google::protobuf::RpcController* /*controller*/, const mir::protobuf::DRMMagic* request, mir::protobuf::DRMAuthMagicStatus* response, google::protobuf::Closure* done) override { std::unique_lock lock(guard); drm_magic = request->magic(); response->set_status_code(0); wait_condition.notify_one(); done->Run(); } virtual void configure_display(::google::protobuf::RpcController*, const ::mir::protobuf::DisplayConfiguration*, ::mir::protobuf::DisplayConfiguration*, ::google::protobuf::Closure* done) override { done->Run(); } std::mutex guard; std::string surface_name; std::condition_variable wait_condition; std::string app_name; unsigned int drm_magic; }; } } #endif /* MIR_TEST_STUB_SERVER_TOOL_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test/cross_process_action.h0000644000015301777760000000231012322054223025515 0ustar pbusernogroup00000000000000/* * 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_ /* TODO: CrossProcessSync should be in mir_test */ #include "mir_test_framework/cross_process_sync.h" #include namespace mir { namespace test { class CrossProcessAction { public: void exec(std::function const& f); void operator()(); private: mir_test_framework::CrossProcessSync start_sync; mir_test_framework::CrossProcessSync finish_sync; }; } } #endif /* MIR_TEST_CROSS_PROCESS_ACTION_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test/fake_event_hub.h0000644000015301777760000001626012322054223024247 0ustar pbusernogroup00000000000000/* * 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: Robert Carr * Daniel d'Andrada */ #ifndef MIR_TEST_FAKE_EVENT_HUB_H_ #define MIR_TEST_FAKE_EVENT_HUB_H_ #include "mir_test/event_factory.h" #include #include // from android-input #include #include #include #include namespace droidinput = android; namespace mir { namespace input { namespace android { // An EventHub implementation that generates fake raw events. class FakeEventHub : public droidinput::EventHubInterface { public: struct KeyInfo { int32_t keyCode; uint32_t flags; }; typedef struct FakeDevice { uint32_t classes; droidinput::InputDeviceIdentifier identifier; droidinput::PropertyMap configuration; droidinput::KeyedVector absoluteAxes; droidinput::KeyedVector relativeAxes; droidinput::KeyedVector keyCodeStates; droidinput::KeyedVector scanCodeStates; droidinput::KeyedVector switchStates; droidinput::KeyedVector absoluteAxisValue; droidinput::KeyedVector keysByScanCode; droidinput::KeyedVector keysByUsageCode; droidinput::KeyedVector leds; droidinput::Vector virtualKeys; std::map input_properties; } FakeDevice; FakeEventHub(); virtual ~FakeEventHub(); static const int BuiltInKeyboardID = droidinput::BUILT_IN_KEYBOARD_ID; // Any positive int besides BUILT_IN_KEYBOARD_ID (which has // special meaning) will do. There is no notion of a builtin // cursor device in the android input stack. static const int BuiltInCursorID = droidinput::BUILT_IN_KEYBOARD_ID + 1; // From EventHubInterface uint32_t getDeviceClasses(int32_t deviceId) const override; droidinput::InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override; void getConfiguration(int32_t deviceId, droidinput::PropertyMap* outConfiguration) const override; droidinput::status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, droidinput::RawAbsoluteAxisInfo* outAxisInfo) const override; bool hasRelativeAxis(int32_t deviceId, int axis) const override; bool hasInputProperty(int32_t deviceId, int property) const override; droidinput::status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t* outKeycode, uint32_t* outFlags) const override; droidinput::status_t mapAxis(int32_t deviceId, int32_t scanCode, droidinput::AxisInfo* outAxisInfo) const override; void setExcludedDevices(const droidinput::Vector& devices) override; size_t getEvents(int timeoutMillis, droidinput::RawEvent* buffer, size_t bufferSize) override; int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override; int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override; int32_t getSwitchState(int32_t deviceId, int32_t sw) const override; droidinput::status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const override; bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const override; bool hasScanCode(int32_t deviceId, int32_t scanCode) const override; bool hasLed(int32_t deviceId, int32_t led) const override; void setLedState(int32_t deviceId, int32_t led, bool on) override; void getVirtualKeyDefinitions(int32_t deviceId, droidinput::Vector& outVirtualKeys) const override; droidinput::sp getKeyCharacterMap(int32_t deviceId) const override; bool setKeyboardLayoutOverlay(int32_t deviceId, const droidinput::sp& map) override; void vibrate(int32_t deviceId, nsecs_t duration) override; void cancelVibrate(int32_t deviceId) override; void requestReopenDevices() override; void wake() override; void dump(droidinput::String8& dump) override; void monitor() override; void flush() override; void synthesize_builtin_keyboard_added(); void synthesize_builtin_cursor_added(); void synthesize_device_scan_complete(); void synthesize_event(const synthesis::KeyParameters ¶meters); void synthesize_event(const synthesis::ButtonParameters ¶meters); void synthesize_event(const synthesis::MotionParameters ¶meters); void synthesize_event(nsecs_t when, int32_t deviceId, int32_t type, int32_t code, int32_t value); void addDevice(int32_t deviceId, const std::string& name, uint32_t classes); void removeDevice(int32_t deviceId); void finishDeviceScan(); void addConfigurationProperty(int32_t device_id, const std::string& key, const std::string& value); void addConfigurationMap(int32_t device_id, const droidinput::PropertyMap* configuration); void addAbsoluteAxis(int32_t device_id, int axis, int32_t minValue, int32_t maxValue, int flat, int fuzz, int resolution = 0); void addRelativeAxis(int32_t device_id, int32_t axis); void setKeyCodeState(int32_t deviceId, int32_t keyCode, int32_t state); void setScanCodeState(int32_t deviceId, int32_t scanCode, int32_t state); void setSwitchState(int32_t deviceId, int32_t switchCode, int32_t state); void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value); void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t keyCode, uint32_t flags); void addLed(int32_t deviceId, int32_t led, bool initialState); bool getLedState(int32_t deviceId, int32_t led); droidinput::Vector& getExcludedDevices(); void addVirtualKeyDefinition(int32_t deviceId, const droidinput::VirtualKeyDefinition& definition); const FakeDevice* getDevice(int32_t deviceId) const; FakeDevice* getDevice(int32_t deviceId); size_t eventsQueueSize() const; // list of RawEvents available for consumption via getEvents std::mutex guard; std::list events_available; std::map device_from_id; droidinput::KeyMap keymap; droidinput::Vector excluded_devices; private: const KeyInfo* getKey(const FakeDevice* device, int32_t scanCode, int32_t usageCode) const; }; } } } // namespace mir #endif // MIR_TEST_FAKE_EVENT_HUB_H_ mir-0.1.8+14.04.20140411/include/test/mir_test/fake_shared.h0000644000015301777760000000172612322054223023537 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/include/test/mir_test/wait_condition.h0000644000015301777760000000305512322054223024312 0ustar pbusernogroup00000000000000/* * 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 Voß */ #ifndef MIR_TEST_WAIT_CONDITION_H_ #define MIR_TEST_WAIT_CONDITION_H_ #include #include #include #include namespace mir { namespace test { struct WaitCondition { WaitCondition() : woken(false) {} void wait_for_at_most_seconds(int seconds) { std::unique_lock ul(guard); if (!woken) condition.wait_for(ul, std::chrono::seconds(seconds)); } void wake_up_everyone() { std::unique_lock ul(guard); woken = true; condition.notify_all(); } std::mutex guard; std::condition_variable condition; bool woken; }; ACTION_P(ReturnFalseAndWakeUp, wait_condition) { wait_condition->wake_up_everyone(); return false; } ACTION_P(WakeUp, wait_condition) { wait_condition->wake_up_everyone(); } } } #endif // MIR_TEST_WAIT_CONDITION_H_ mir-0.1.8+14.04.20140411/include/test/mir_test/event_factory.h0000644000015301777760000000345212322054223024151 0ustar pbusernogroup00000000000000/* * 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 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_motion_event(); } } } #endif /* MIR_TEST_EVENT_FACTORY_H */ mir-0.1.8+14.04.20140411/include/test/mir_test/test_protobuf_server.h0000644000015301777760000000266512322054223025573 0ustar pbusernogroup00000000000000/* * 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 */ #ifndef MIR_TEST_TEST_PROTOBUF_SERVER_H_ #define MIR_TEST_TEST_PROTOBUF_SERVER_H_ #include namespace mir { namespace frontend { class Connector; class ConnectorReport; } namespace protobuf { class DisplayServer; } namespace test { struct TestProtobufServer { TestProtobufServer( std::string const& socket_name, std::shared_ptr const& tool); TestProtobufServer( std::string const& socket_name, std::shared_ptr const& tool, std::shared_ptr const& report); // "Server" side std::shared_ptr const comm; }; } } #endif /* MIR_TEST_TEST_PROTOBUF_SERVER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test/client_event_matchers.h0000644000015301777760000000572012322054223025646 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir_toolkit/event.h" #include #include #include namespace mir { namespace test { MATCHER(KeyDownEvent, "") { if (arg->type != mir_event_type_key) return false; if (arg->key.action != mir_key_action_down) // Key down return false; return true; } MATCHER_P(KeyOfSymbol, keysym, "") { if (static_cast(arg->key.key_code) == (uint)keysym) return true; return false; } MATCHER(HoverEnterEvent, "") { if (arg->type != mir_event_type_motion) return false; if (arg->motion.action != mir_motion_action_hover_enter) return false; return true; } MATCHER(HoverExitEvent, "") { if (arg->type != mir_event_type_motion) return false; if (arg->motion.action != mir_motion_action_hover_exit) return false; return true; } MATCHER_P2(ButtonDownEvent, x, y, "") { if (arg->type != mir_event_type_motion) return false; if (arg->motion.action != mir_motion_action_down) return false; if (arg->motion.button_state == 0) return false; if (arg->motion.pointer_coordinates[0].x != x) return false; if (arg->motion.pointer_coordinates[0].y != y) return false; return true; } MATCHER_P2(ButtonUpEvent, x, y, "") { if (arg->type != mir_event_type_motion) return false; if (arg->motion.action != mir_motion_action_up) return false; if (arg->motion.pointer_coordinates[0].x != x) return false; if (arg->motion.pointer_coordinates[0].y != y) return false; return true; } MATCHER_P2(MotionEventWithPosition, x, y, "") { if (arg->type != mir_event_type_motion) return false; if (arg->motion.action != mir_motion_action_move && arg->motion.action != mir_motion_action_hover_move) return false; if (arg->motion.pointer_coordinates[0].x != x) return false; if (arg->motion.pointer_coordinates[0].y != y) return false; return true; } MATCHER(MovementEvent, "") { if (arg->type != mir_event_type_motion) return false; if (arg->motion.action != mir_motion_action_move && arg->motion.action != mir_motion_action_hover_move) return false; return true; } } } mir-0.1.8+14.04.20140411/include/test/mir_test/event_matchers.h0000644000015301777760000000404212322054223024304 0ustar pbusernogroup00000000000000/* * 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_TEST_EVENT_MATCHERS_H_ #define MIR_TEST_EVENT_MATCHERS_H_ #include "mir_toolkit/event.h" #include #include namespace mir { namespace test { MATCHER_P(IsKeyEventWithKey, key, "") { if (arg.type != mir_event_type_key) return false; return arg.key.key_code == key; } MATCHER(KeyDownEvent, "") { if (arg.type != mir_event_type_key) return false; return arg.key.action == mir_key_action_down; } MATCHER(ButtonDownEvent, "") { if (arg.type != mir_event_type_motion) return false; if (arg.motion.button_state == 0) return false; return arg.motion.action == mir_motion_action_down; } MATCHER(ButtonUpEvent, "") { if (arg.type != mir_event_type_motion) return false; return arg.motion.action == mir_motion_action_up; } MATCHER_P2(MotionEvent, dx, dy, "") { if (arg.type != mir_event_type_motion) return false; auto coords = &arg.motion.pointer_coordinates[0]; return (coords->x == dx) && (coords->y == dy); } MATCHER_P2(SurfaceEvent, attrib, value, "") { if (arg.type != mir_event_type_surface) return false; auto surface_ev = arg.surface; if (surface_ev.attrib != attrib) return false; if (surface_ev.value != value) return false; return true; } } } // namespace mir #endif // MIR_TEST_EVENT_MATCHERS_H_ mir-0.1.8+14.04.20140411/include/test/mir_test/test_protobuf_client.h0000644000015301777760000000606212322054223025536 0ustar pbusernogroup00000000000000/* * 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 */ #ifndef MIR_TEST_TEST_CLIENT_H_ #define MIR_TEST_TEST_CLIENT_H_ #include "mir_protobuf.pb.h" #include #include #include namespace mir { namespace test { namespace doubles { class MockRpcReport; } struct TestProtobufClient { TestProtobufClient(std::string socket_file, int timeout_ms); std::shared_ptr rpc_report; std::shared_ptr channel; mir::protobuf::DisplayServer::Stub display_server; mir::protobuf::ConnectParameters connect_parameters; mir::protobuf::SurfaceParameters surface_parameters; mir::protobuf::Surface surface; mir::protobuf::Void ignored; mir::protobuf::Connection connection; mir::protobuf::DisplayConfiguration disp_config; mir::protobuf::DisplayConfiguration disp_config_response; MOCK_METHOD0(connect_done, void()); MOCK_METHOD0(create_surface_done, void()); MOCK_METHOD0(next_buffer_done, void()); MOCK_METHOD0(release_surface_done, void()); MOCK_METHOD0(disconnect_done, void()); MOCK_METHOD0(drm_auth_magic_done, void()); MOCK_METHOD0(display_configure_done, void()); void on_connect_done(); void on_create_surface_done(); void on_next_buffer_done(); void on_release_surface_done(); void on_disconnect_done(); void on_drm_auth_magic_done(); void on_configure_display_done(); void wait_for_connect_done(); void wait_for_create_surface(); void wait_for_next_buffer(); void wait_for_release_surface(); void wait_for_disconnect_done(); void wait_for_drm_auth_magic_done(); void wait_for_surface_count(int count); void wait_for_disconnect_count(int count); void tfd_done(); void wait_for_tfd_done(); void wait_for_configure_display_done(); const int maxwait; std::atomic connect_done_called; std::atomic create_surface_called; std::atomic next_buffer_called; std::atomic release_surface_called; std::atomic disconnect_done_called; std::atomic drm_auth_magic_done_called; std::atomic configure_display_done_called; std::atomic tfd_done_called; std::atomic connect_done_count; std::atomic create_surface_done_count; std::atomic disconnect_done_count; }; } } #endif /* MIR_TEST_TEST_CLIENT_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test/empty_deleter.h0000644000015301777760000000156112322054223024142 0ustar pbusernogroup00000000000000/* * 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* ) { } }; } #endif /* MIR_TEST_EMPTY_DELETER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test/gmock_fixes.h0000644000015301777760000001030312322054223023570 0ustar pbusernogroup00000000000000// // Copyright © 2012 Canonical Ltd. Copyright 2007, Google Inc. // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Author: wan@google.com (Zhanyong Wan) // Authored by: Alan Griffiths #ifndef MIR_TEST_GMOCK_FIXES_H_ #define MIR_TEST_GMOCK_FIXES_H_ #include #include namespace testing { namespace internal { template class ActionResultHolder> : public UntypedActionResultHolderBase { public: explicit ActionResultHolder(std::unique_ptr&& a_value) : value_(std::move(a_value)) {} // The compiler-generated copy constructor and assignment operator // are exactly what we need, so we don't need to define them. // Returns the held value and deletes this object. std::unique_ptr GetValueAndDelete() const { std::unique_ptr retval(std::move(value_)); delete this; return std::move(retval); } // Prints the held value as an action's result to os. virtual void PrintAsActionResult(::std::ostream* os) const { *os << "\n Returns: "; // T may be a reference type, so we don't use UniversalPrint(). UniversalPrinter>::Print(value_, os); } // Performs the given mock function's default action and returns the // result in a new-ed ActionResultHolder. template static ActionResultHolder* PerformDefaultAction( const FunctionMockerBase* func_mocker, const typename Function::ArgumentTuple& args, const string& call_description) { return new ActionResultHolder( func_mocker->PerformDefaultAction(args, call_description)); } // Performs the given action and returns the result in a new-ed // ActionResultHolder. template static ActionResultHolder* PerformAction(const Action& action, const typename Function::ArgumentTuple& args) { return new ActionResultHolder(action.Perform(args)); } private: std::unique_ptr mutable value_; // T could be a reference type, so = isn't supported. GTEST_DISALLOW_ASSIGN_(ActionResultHolder); }; } template class DefaultValue> { public: // Unsets the default value for type T. static void Clear() {} // Returns true iff the user has set the default value for type T. static bool IsSet() { return false; } // Returns true if T has a default return value set by the user or there // exists a built-in default value. static bool Exists() { return true; } // Returns the default value for type T if the user has set one; // otherwise returns the built-in default value if there is one; // otherwise aborts the process. static std::unique_ptr Get() { return std::unique_ptr(); } }; } #endif /* MIR_TEST_GMOCK_FIXES_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test/fake_event_hub_input_configuration.h0000644000015301777760000000427112322054223030414 0ustar pbusernogroup00000000000000/* * 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 . * * Author: Robert Carr */ #ifndef MIR_TEST_DOUBLES_FAKE_EVENT_HUB_INPUT_CONFIGURATION_H_ #define MIR_TEST_DOUBLES_FAKE_EVENT_HUB_INPUT_CONFIGURATION_H_ #include "mir/input/android/default_android_input_configuration.h" #include namespace droidinput = android; namespace android { class EventHubInterface; } namespace mir { namespace input { class CursorListener; class EventFilter; class InputReport; namespace android { class FakeEventHub; } } namespace test { namespace doubles { class FakeEventHubInputConfiguration : public input::android::DefaultInputConfiguration { public: FakeEventHubInputConfiguration(std::shared_ptr const& event_filter, std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener, std::shared_ptr const& input_report); virtual ~FakeEventHubInputConfiguration(); droidinput::sp the_event_hub(); input::android::FakeEventHub* the_fake_event_hub(); bool is_key_repeat_enabled() override { return false; } protected: FakeEventHubInputConfiguration(FakeEventHubInputConfiguration const&) = delete; FakeEventHubInputConfiguration& operator=(FakeEventHubInputConfiguration const&) = delete; private: droidinput::sp event_hub; }; } } } // namespace mir #endif /* MIR_TEST_DOUBLES_FAKE_EVENT_HUB_INPUT_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test/display_config_matchers.h0000644000015301777760000000462412322054223026163 0ustar pbusernogroup00000000000000/* * 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 //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(graphics::DisplayConfiguration const& display_config1, graphics::DisplayConfiguration const& display_config2); bool compare_display_configurations(MirDisplayConfiguration const& client_config, graphics::DisplayConfiguration const& display_config); bool compare_display_configurations(protobuf::DisplayConfiguration const& protobuf_config, graphics::DisplayConfiguration const& display_config); bool compare_display_configurations(MirDisplayConfiguration const& client_config, protobuf::DisplayConfiguration const& protobuf_config); MATCHER_P(DisplayConfigMatches, config, "") { return compare_display_configurations(arg, config); } } } #endif /* MIR_TEST_DISPLAY_CONFIG_MATCHERS_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test/pipe.h0000644000015301777760000000200712322054223022231 0ustar pbusernogroup00000000000000/* * 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_ namespace mir { namespace test { class Pipe { public: Pipe(); ~Pipe(); int read_fd() const; int write_fd() const; private: Pipe(Pipe const&) = delete; Pipe& operator=(Pipe const&) = delete; int pipefd[2]; }; } } #endif /* MIR_TEST_PIPE_H_ */ mir-0.1.8+14.04.20140411/include/test/gmock_set_arg.h0000644000015301777760000000314312322054223022254 0ustar pbusernogroup00000000000000/* * 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 GMOCK_SET_ARG_H_ #define GMOCK_SET_ARG_H_ #include namespace testing { namespace internal { template class SetArgumentAction { public: // Constructs an action that sets the variable pointed to by the // N-th function argument to 'value'. explicit SetArgumentAction(const A& value) : value_(value) {} template void Perform(const ArgumentTuple& args) const { CompileAssertTypesEqual(); ::std::tr1::get(args) = value_; } private: const A value_; GTEST_DISALLOW_ASSIGN_(SetArgumentAction); }; } template PolymorphicAction< internal::SetArgumentAction< N, T, internal::IsAProtocolMessage::value> > SetArg(const T& x) { return MakePolymorphicAction(internal::SetArgumentAction< N, T, internal::IsAProtocolMessage::value>(x)); } } #endif /* GMOCK_SET_ARG_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/0000755000015301777760000000000012322054703023204 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/test/mir_test_framework/testing_client_configuration.h0000644000015301777760000000247212322054223031321 0ustar pbusernogroup00000000000000/* * 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_TESTING_CLIENT_CONFIGURATION #define MIR_TESTING_CLIENT_CONFIGURATION #include "mir/options/option.h" namespace mir_test_framework { struct TestingClientConfiguration { virtual ~TestingClientConfiguration() = default; // Code to run in client process virtual void exec() = 0; //clients respect the tests-use-real-graphics option by default. use //this function to force the use of the default client configuraiton virtual bool use_real_graphics(mir::options::Option const& options) { return options.get("tests-use-real-graphics"); } }; } #endif /* MIR_TESTING_CLIENT_CONFIGURATION */ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/stub_client_connection_configuration.h0000644000015301777760000000232012322054223033030 0ustar pbusernogroup00000000000000/* * 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_TESTING_STUB_CLIENT_CONNECTION_CONFIGURATION #define MIR_TESTING_STUB_CLIENT_CONNECTION_CONFIGURATION #include "src/client/default_connection_configuration.h" #include namespace mir_test_framework { struct StubConnectionConfiguration : public mir::client::DefaultConnectionConfiguration { StubConnectionConfiguration(std::string const& socket_file); std::shared_ptr the_client_platform_factory() override; }; } #endif /* MIR_TESTING_STUB_CLIENT_CONNECTION_CONFIGURATION */ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/input_testing_server_configuration.h0000644000015301777760000000346412322054223032572 0ustar pbusernogroup00000000000000/* * 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_TEST_INPUT_TESTING_SERVER_CONFIGURATION_H_ #define MIR_TEST_INPUT_TESTING_SERVER_CONFIGURATION_H_ #include "mir_test_framework/testing_server_configuration.h" #include "mir/geometry/rectangle.h" #include #include #include #include #include #include namespace mir { namespace input { namespace android { class FakeEventHub; } } namespace test { namespace doubles { class FakeEventHubInputConfiguration; } } } namespace mir_test_framework { class InputTestingServerConfiguration : public TestingServerConfiguration { public: InputTestingServerConfiguration(); void exec(); void on_exit(); std::shared_ptr the_input_configuration() override; mir::input::android::FakeEventHub* fake_event_hub; protected: virtual void inject_input() = 0; void wait_until_client_appears(std::string const& surface_name); private: std::thread input_injection_thread; std::shared_ptr input_configuration; }; } #endif /* MIR_TEST_INPUT_TESTING_SERVER_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/stubbed_server_configuration.h0000644000015301777760000000321112322054223031314 0ustar pbusernogroup00000000000000/* * 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_FRAMEWORK_STUBBED_SERVER_CONFIGURATION_H_ #define MIR_TEST_FRAMEWORK_STUBBED_SERVER_CONFIGURATION_H_ #include "mir/default_server_configuration.h" namespace mir_test_framework { using namespace mir; /** * stubs out the graphics and input subsystems to avoid tests * failing where the hardware is not accessible */ class StubbedServerConfiguration : public DefaultServerConfiguration { public: StubbedServerConfiguration(); std::shared_ptr the_graphics_platform(); std::shared_ptr the_renderer_factory(); // We override the_input_manager in the default server configuration // to avoid starting and stopping the full android input stack for tests // which do not leverage input. std::shared_ptr the_input_configuration(); private: std::shared_ptr graphics_platform; }; } #endif /* MIR_TEST_FRAMEWORK_STUBBED_SERVER_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/input_testing_client_configuration.h0000644000015301777760000000477312322054223032546 0ustar pbusernogroup00000000000000/* * 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 n */ #ifndef MIR_TEST_FRAMEWORK_INPUT_TESTING_CLIENT_CONFIGURATION #define MIR_TEST_FRAMEWORK_INPUT_TESTING_CLIENT_CONFIGURATION #include "mir_test_framework/testing_client_configuration.h" #include "mir_test_framework/cross_process_sync.h" #include "mir_test/wait_condition.h" #include #include #include namespace mir_test_framework { /// A fixture to be used with InputTestingServerConfiguration for input acceptance testing scenarios. /// By default, the client will connect and a surface will be created. /// The framework ensures the server will not send events before client is ready through CrossProcessSync. class InputTestingClientConfiguration : public TestingClientConfiguration { public: InputTestingClientConfiguration(std::string const& client_name, CrossProcessSync const& input_cb_setup_fence); virtual ~InputTestingClientConfiguration() = default; void exec(); struct MockInputHandler { MOCK_METHOD1(handle_input, void(MirEvent const*)); }; // This function will be called at an appropriate time for input expectations to be set. // on handler. It is expected that mt::WakeUp(all_events_received) will be triggered by // the last expectation, as this is what triggers the verification of the Mock and // termination of the testing client. virtual void expect_input(MockInputHandler &handler, mir::test::WaitCondition& all_events_received) = 0; // This fixture is intended to be used with InputTestingServer // which allows for setting surface sizes as part of the // input-testing shell. static int const surface_width = 100; static int const surface_height = 100; private: std::string const client_name; CrossProcessSync input_cb_setup_fence; }; } #endif /* MIR_TEST_FRAMEWORK_INPUT_TESTING_CLIENT_CONFIGURATION */ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/process.h0000644000015301777760000000545312322054223025037 0ustar pbusernogroup00000000000000/* * 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; 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_ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/declarative_placement_strategy.h0000644000015301777760000000510712322054247031620 0ustar pbusernogroup00000000000000/* * 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_DECLARATIVE_PLACEMENT_STRATEGY_H_ #define MIR_TEST_FRAMEWORK_DECLARATIVE_PLACEMENT_STRATEGY_H_ #include "mir/shell/placement_strategy.h" #include "mir/geometry/rectangle.h" #include "mir/scene/depth_id.h" #include #include #include namespace mir_test_framework { typedef std::map SurfaceGeometries; typedef std::map SurfaceDepths; /// DeclarativePlacementStrategy 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 DeclarativePlacementStrategy : public mir::shell::PlacementStrategy { public: // Placement requests will be passed through to default strategy, and then overriden if the surface appears // in the geometry or depth map. This allows for the convenience of leaving some surfaces geometries unspecified // and receiving the default behavior. DeclarativePlacementStrategy(std::shared_ptr const& default_strategy, SurfaceGeometries const& positions_by_name, SurfaceDepths const& depths_by_name); virtual ~DeclarativePlacementStrategy() = default; mir::shell::SurfaceCreationParameters place(mir::shell::Session const& session, mir::shell::SurfaceCreationParameters const& request_parameters) override; protected: DeclarativePlacementStrategy(const DeclarativePlacementStrategy&) = delete; DeclarativePlacementStrategy& operator=(const DeclarativePlacementStrategy&) = delete; private: std::shared_ptr const default_strategy; SurfaceGeometries surface_geometries_by_name; SurfaceDepths surface_depths_by_name; }; } #endif // MIR_TEST_FRAMEWORK_DECLARATIVE_PLACEMENT_STRATEGY_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/in_process_server.h0000644000015301777760000000331012322054223027101 0ustar pbusernogroup00000000000000/* * 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_FRAMEWORK_IN_PROCESS_SERVER_H_ #define MIR_TEST_FRAMEWORK_IN_PROCESS_SERVER_H_ #include #include #include namespace mir { class DisplayServer; class DefaultServerConfiguration; } namespace mir_test_framework { /// Fixture for running Mir server in test process struct InProcessServer : testing::Test { InProcessServer(); ~InProcessServer(); /// Starts the server /// \warning don't forget to call this if you override SetUp() void SetUp() override; /// Stops the server /// \warning don't forget to call this if you override TearDown() void TearDown() override; /// \return a connection string for a new client to connect to the server std::string new_connection(); private: mir::DisplayServer* start_mir_server(); virtual mir::DefaultServerConfiguration& server_config() = 0; char const* const old_env; std::thread server_thread; mir::DisplayServer* display_server = 0; }; } #endif /* MIR_TEST_FRAMEWORK_IN_PROCESS_SERVER_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/testing_server_configuration.h0000644000015301777760000000326612322054223031353 0ustar pbusernogroup00000000000000/* * 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_TESTING_SERVER_CONFIGURATION_H_ #define MIR_TEST_TESTING_SERVER_CONFIGURATION_H_ #include "mir_test_framework/stubbed_server_configuration.h" #include "mir_test_framework/cross_process_sync.h" namespace mir_test_framework { using namespace mir; class TestingServerConfiguration : public StubbedServerConfiguration { public: TestingServerConfiguration(); // Code to run in server process virtual void exec(); // Code to run in server process after server starts virtual void on_start(); // Code to run in server process after server exits virtual void on_exit(); std::shared_ptr the_server_status_listener() override; virtual std::string the_socket_file() const; using DefaultServerConfiguration::the_options; virtual void wait_for_server_start(); private: CrossProcessSync server_started_sync; bool using_server_started_sync; }; std::string const& test_socket_file(); } #endif /* MIR_TEST_TESTING_SERVER_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/cross_process_sync.h0000644000015301777760000000361412322054223027301 0ustar pbusernogroup00000000000000/* * 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_FRAMEWORK_CROSS_PROCESS_SYNC_H_ #define MIR_TEST_FRAMEWORK_CROSS_PROCESS_SYNC_H_ #include namespace mir_test_framework { // 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_FRAMEWORK_CROSS_PROCESS_SYNC_H_ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/detect_server.h0000644000015301777760000000172712322054223026217 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/udev_environment.h0000644000015301777760000000364512322054247026757 0ustar pbusernogroup00000000000000/* * 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: * Christopher James Halse Rogers */ #ifndef MIR_TESTING_UDEV_ENVIRONMENT #define MIR_TESTING_UDEV_ENVIRONMENT #include #include #include #include namespace mir { namespace mir_test_framework { class UdevEnvironment { public: UdevEnvironment(); ~UdevEnvironment() noexcept; std::string add_device(char const* subsystem, char const* name, char const* parent, std::initializer_list attributes, std::initializer_list properties); void remove_device(std::string const& device_path); void emit_device_changed(std::string const& device_path); /** * Add a device from the set of standard device traces * * Looks for a name.umockdev file, and adds a UMockDev device * from that description. * * If name.ioctl exists, it loads that ioctl script for the device * * @param name The unadorned filename of the device traces to add. */ void add_standard_device(std::string const& name); UMockdevTestbed *testbed; std::string const recordings_path; }; } } #endif //MIR_TESTING_UDEV_ENVIRONMENT mir-0.1.8+14.04.20140411/include/test/mir_test_framework/using_stub_client_platform.h0000644000015301777760000000251412322054223031000 0ustar pbusernogroup00000000000000/* * 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_USING_STUB_CLIENT_PLATFORM_H_ #define MIR_TEST_FRAMEWORK_USING_STUB_CLIENT_PLATFORM_H_ #include "src/client/api_impl_types.h" namespace mir_test_framework { class UsingStubClientPlatform { public: UsingStubClientPlatform(); ~UsingStubClientPlatform(); private: UsingStubClientPlatform(UsingStubClientPlatform const&) = delete; UsingStubClientPlatform operator=(UsingStubClientPlatform const&) = delete; mir_connect_impl_func const prev_mir_connect_impl; mir_connection_release_impl_func const prev_mir_connection_release_impl; }; } #endif /* MIR_TEST_FRAMEWORK_USING_STUB_CLIENT_PLATFORM_H_ */ mir-0.1.8+14.04.20140411/include/test/mir_test_framework/display_server_test_fixture.h0000644000015301777760000000504412322054223031215 0ustar pbusernogroup00000000000000/* * 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 Guest */ #ifndef MIR_DISPLAY_SERVER_TEST_FIXTURE #define MIR_DISPLAY_SERVER_TEST_FIXTURE #include "mir_test_framework/process.h" #include "mir_test_framework/testing_process_manager.h" #include #include #include namespace mir_test_framework { using namespace ::mir; // The test fixture sets up and tears down a display server for use // in display server test cases. class DefaultDisplayServerTestFixture : public testing::Test { public: DefaultDisplayServerTestFixture(); ~DefaultDisplayServerTestFixture(); static void SetUpTestCase(); static void TearDownTestCase(); void launch_client_process(TestingClientConfiguration& config); private: static TestingProcessManager process_manager; static TestingServerConfiguration default_parameters; virtual void TearDown(); }; // The test fixture sets up and tears down a display server for use // in display server tests. class BespokeDisplayServerTestFixture : public testing::Test { public: BespokeDisplayServerTestFixture(); ~BespokeDisplayServerTestFixture(); void launch_server_process(TestingServerConfiguration& config); void launch_client_process(TestingClientConfiguration& config); bool shutdown_server_process(); Result wait_for_shutdown_server_process(); void kill_client_processes(); void terminate_client_processes(); void run_in_test_process(std::function const& run_code); protected: virtual void SetUp(); virtual void TearDown(); private: TestingProcessManager process_manager; std::shared_ptr test_options; }; } using mir_test_framework::DefaultDisplayServerTestFixture; using mir_test_framework::BespokeDisplayServerTestFixture; using mir_test_framework::TestingClientConfiguration; using mir_test_framework::TestingServerConfiguration; #endif // MIR_DISPLAY_SERVER_TEST_FIXTURE mir-0.1.8+14.04.20140411/include/test/mir_test_framework/testing_process_manager.h0000644000015301777760000000375212322054223030266 0ustar pbusernogroup00000000000000/* * 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 Guest */ #ifndef MIR_TESTING_PROCESS_MANAGER #define MIR_TESTING_PROCESS_MANAGER #include "mir/server_configuration.h" #include "mir_test_framework/process.h" #include "mir_test_framework/testing_server_configuration.h" #include "mir_test_framework/testing_client_configuration.h" #include #include #include namespace mir { class DisplayServer; namespace options { class Option; } } namespace mir_test_framework { using namespace mir; class TestingProcessManager { public: TestingProcessManager(); ~TestingProcessManager(); void launch_server_process(TestingServerConfiguration& config); void launch_client_process(TestingClientConfiguration& config, mir::options::Option const& test_options); void tear_down_clients(); void tear_down_server(); void tear_down_all(); Result shutdown_server_process(); Result wait_for_shutdown_server_process(); void kill_client_processes(); void terminate_client_processes(); void run_in_test_process(std::function const& run_code); private: std::shared_ptr server_process; std::list> clients; bool is_test_process; bool server_process_was_started; }; std::string const& test_socket_file(); } #endif // MIR_TESTING_PROCESS_MANAGER mir-0.1.8+14.04.20140411/include/server/0000755000015301777760000000000012322054703017630 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/0000755000015301777760000000000012322054703020417 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/frontend/0000755000015301777760000000000012322054703022236 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/frontend/surface_id.h0000644000015301777760000000173612322054223024517 0ustar pbusernogroup00000000000000/* * 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_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_ mir-0.1.8+14.04.20140411/include/server/mir/frontend/session_mediator_report.h0000644000015301777760000000346012322054223027351 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_SESSION_MEDIATOR_REPORT_H_ #define MIR_FRONTEND_SESSION_MEDIATOR_REPORT_H_ #include namespace mir { namespace frontend { // Interface for monitoring application activity class SessionMediatorReport { public: virtual ~SessionMediatorReport() { /* TODO: make nothrow */ } 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_next_buffer_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_drm_auth_magic_called(std::string const& app_name) = 0; virtual void session_configure_surface_called(std::string const& app_name) = 0; virtual void session_configure_display_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_REPORT_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/frontend/surface.h0000644000015301777760000000404412322054223024036 0ustar pbusernogroup00000000000000/* * 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/geometry/point.h" #include "mir/geometry/size.h" #include "mir_toolkit/common.h" #include #include namespace mir { namespace graphics { class Buffer; class InternalSurface; } namespace input { class InputChannel; } namespace frontend { class ClientBufferTracker; class Surface { public: virtual ~Surface() {} virtual void force_requests_to_complete() = 0; virtual geometry::Size size() const = 0; virtual MirPixelFormat pixel_format() const = 0; virtual void swap_buffers(graphics::Buffer* old_buffer, std::function complete) = 0; virtual bool supports_input() const = 0; virtual int client_input_fd() const = 0; virtual int configure(MirSurfaceAttrib attrib, int value) = 0; /** * swap_buffers_blocking() is a convenience wrapper around swap_buffers() * it forces the current thread to block until complete() is called. * Use with care! */ void swap_buffers_blocking(graphics::Buffer*& buffer); protected: Surface() = default; Surface(Surface const&) = delete; Surface& operator=(Surface const&) = delete; }; auto as_internal_surface(std::shared_ptr const& surface) -> std::shared_ptr; } } #endif /* MIR_FRONTEND_SURFACE_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/frontend/session_authorizer.h0000644000015301777760000000246112322054247026354 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_SESSION_AUTHORIZER_H_ #define MIR_FRONTEND_SESSION_AUTHORIZER_H_ #include namespace mir { namespace frontend { class SessionAuthorizer { public: virtual ~SessionAuthorizer() = default; virtual bool connection_is_allowed(pid_t pid) = 0; virtual bool configure_display_is_allowed(pid_t pid) = 0; virtual bool screencast_is_allowed(pid_t pid) = 0; protected: SessionAuthorizer() = default; SessionAuthorizer(SessionAuthorizer const&) = delete; SessionAuthorizer& operator=(SessionAuthorizer const&) = delete; }; } } // namespace mir #endif // MIR_FRONTEND_SESSION_AUTHORIZER_H_ mir-0.1.8+14.04.20140411/include/server/mir/frontend/session_creator.h0000644000015301777760000000235312322054223025611 0ustar pbusernogroup00000000000000/* * 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_SESSION_CREATOR_H_ #define MIR_FRONTEND_SESSION_CREATOR_H_ #include #include namespace mir { namespace frontend { class SessionCreator { public: virtual void create_session_for(std::shared_ptr const& socket) = 0; protected: SessionCreator() = default; virtual ~SessionCreator() noexcept = default; SessionCreator(SessionCreator const&) = delete; SessionCreator& operator=(SessionCreator const&) = delete; }; } } #endif /* MIR_FRONTEND_SESSION_CREATOR_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/frontend/shell.h0000644000015301777760000000321312322054223023512 0ustar pbusernogroup00000000000000/* * 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: Thomas Voss */ #ifndef MIR_FRONTEND_SHELL_H_ #define MIR_FRONTEND_SHELL_H_ #include "mir/frontend/surface_id.h" #include #include namespace mir { namespace shell { struct SurfaceCreationParameters; } namespace frontend { class EventSink; class Session; class Shell { public: virtual ~Shell() = default; 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 SurfaceId create_surface_for(std::shared_ptr const& session, shell::SurfaceCreationParameters const& params) = 0; virtual void handle_surface_created(std::shared_ptr const& session) = 0; protected: Shell() = default; Shell(const Shell&) = delete; Shell& operator=(const Shell&) = delete; }; } } #endif // MIR_FRONTEND_SHELL_H_ mir-0.1.8+14.04.20140411/include/server/mir/frontend/protobuf_session_creator.h0000644000015301777760000000434712322054223027536 0ustar pbusernogroup00000000000000/* * 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_PROTOBUF_SESSION_CREATOR_H_ #define MIR_FRONTEND_PROTOBUF_SESSION_CREATOR_H_ #include "mir/frontend/session_creator.h" #include "mir/frontend/connected_sessions.h" #include namespace mir { namespace protobuf { class DisplayServer; } namespace frontend { class MessageProcessorReport; class ProtobufIpcFactory; class SessionAuthorizer; namespace detail { struct SocketSession; class MessageProcessor; class ProtobufMessageSender; } class ProtobufSessionCreator : public SessionCreator { public: ProtobufSessionCreator( std::shared_ptr const& ipc_factory, std::shared_ptr const& session_authorizer, std::shared_ptr const& report); ~ProtobufSessionCreator() noexcept; void create_session_for(std::shared_ptr const& socket); virtual std::shared_ptr create_processor( std::shared_ptr const& sender, std::shared_ptr const& display_server, std::shared_ptr const& report) const; private: int next_id(); std::shared_ptr const ipc_factory; std::shared_ptr const session_authorizer; std::shared_ptr const report; std::atomic next_session_id; std::shared_ptr> const connected_sessions; }; } } #endif /* MIR_FRONTEND_PROTOBUF_SESSION_CREATOR_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/frontend/session.h0000644000015301777760000000334712322054223024076 0ustar pbusernogroup00000000000000/* * 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 #include #include #include namespace mir { namespace shell { struct SurfaceCreationParameters; } namespace graphics { class DisplayConfiguration; } namespace frontend { class Surface; class Session { public: virtual ~Session() {} virtual SurfaceId create_surface(shell::SurfaceCreationParameters const& params) = 0; virtual void destroy_surface(SurfaceId surface) = 0; virtual std::shared_ptr get_surface(SurfaceId surface) const = 0; virtual std::string name() const = 0; virtual void hide() = 0; virtual void show() = 0; virtual void send_display_config(graphics::DisplayConfiguration const&) = 0; virtual int configure_surface(SurfaceId id, MirSurfaceAttrib attrib, int value) = 0; protected: Session() = default; Session(Session const&) = delete; Session& operator=(Session const&) = delete; }; } } #endif // MIR_FRONTEND_SESSION_H_ mir-0.1.8+14.04.20140411/include/server/mir/frontend/message_processor_report.h0000644000015301777760000000335212322054223027525 0ustar pbusernogroup00000000000000/* * 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_MESSAGE_PROCESSOR_REPORT_H_ #define MIR_FRONTEND_MESSAGE_PROCESSOR_REPORT_H_ #include "mir_toolkit/event.h" #include namespace mir { namespace frontend { class MessageProcessorReport { public: MessageProcessorReport() {} virtual ~MessageProcessorReport() = default; virtual void received_invocation(void const* mediator, int id, std::string const& method) = 0; virtual void completed_invocation(void const* mediator, int id, bool result) = 0; virtual void unknown_method(void const* mediator, int id, std::string const& method) = 0; virtual void exception_handled(void const* mediator, int id, std::exception const& error) = 0; virtual void exception_handled(void const* mediator, std::exception const& error) = 0; virtual void sent_event(void const* mediator, MirSurfaceEvent const& ev) = 0; private: MessageProcessorReport(MessageProcessorReport const&) = delete; MessageProcessorReport& operator=(MessageProcessorReport const&) = delete; }; } } #endif /* MIR_FRONTEND_MESSAGE_PROCESSOR_REPORT_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/frontend/screencast.h0000644000015301777760000000317212322054223024541 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_SCREENCAST_H_ #define MIR_FRONTEND_SCREENCAST_H_ #include "mir/int_wrapper.h" #include "mir/graphics/display_configuration.h" #include namespace mir { namespace graphics { class Buffer; } namespace frontend { namespace detail { struct ScreencastSessionIdTag; } typedef IntWrapper ScreencastSessionId; class Screencast { public: virtual ~Screencast() = default; virtual ScreencastSessionId create_session( mir::geometry::Rectangle const& region, mir::geometry::Size const& size, MirPixelFormat pixel_format) = 0; virtual void destroy_session(ScreencastSessionId id) = 0; virtual std::shared_ptr capture(ScreencastSessionId id) = 0; protected: Screencast() = default; Screencast(Screencast const&) = delete; Screencast& operator=(Screencast const&) = delete; }; } } #endif /* MIR_FRONTEND_SCREENCAST_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/frontend/connector_report.h0000644000015301777760000000304712322054223025775 0ustar pbusernogroup00000000000000/* * 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 #include namespace mir { namespace frontend { class ConnectorReport { public: virtual void thread_start() = 0; virtual void thread_end() = 0; virtual void starting_threads(int count) = 0; virtual void stopping_threads(int count) = 0; virtual void creating_session_for(int socket_handle) = 0; virtual void creating_socket_pair(int server_handle, int client_handle) = 0; virtual void listening_on(std::string const& endpoint) = 0; virtual void error(std::exception const& error) = 0; protected: virtual ~ConnectorReport() = default; ConnectorReport() = default; ConnectorReport(const ConnectorReport&) = delete; ConnectorReport& operator=(const ConnectorReport&) = delete; }; } } #endif // MIR_FRONTEND_CONNECTOR_REPORT_H_ mir-0.1.8+14.04.20140411/include/server/mir/frontend/event_sink.h0000644000015301777760000000252112322054223024551 0ustar pbusernogroup00000000000000/* * 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_EVENTS_EVENT_SINK_H_ #define MIR_EVENTS_EVENT_SINK_H_ #include "mir_toolkit/event.h" namespace mir { namespace graphics { class DisplayConfiguration; } namespace frontend { class EventSink { public: virtual ~EventSink() = default; virtual void handle_event(MirEvent const& e) = 0; virtual void handle_lifecycle_event(MirLifecycleState state) = 0; virtual void handle_display_config_change(graphics::DisplayConfiguration const& config) = 0; protected: EventSink() = default; EventSink(EventSink const&) = delete; EventSink& operator=(EventSink const&) = delete; }; } } // namespace mir #endif // MIR_EVENTS_EVENT_SINK_H_ mir-0.1.8+14.04.20140411/include/server/mir/frontend/message_processor.h0000644000015301777760000000312412322054223026127 0ustar pbusernogroup00000000000000/* * 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_MESSAGE_PROCESSOR_H_ #define MIR_FRONTEND_MESSAGE_PROCESSOR_H_ #include namespace mir { namespace protobuf { namespace wire { class Invocation; } } namespace frontend { namespace detail { class Invocation { public: Invocation(mir::protobuf::wire::Invocation const& invocation) : invocation(invocation) {} const ::std::string& method_name() const; const ::std::string& parameters() const; ::google::protobuf::uint32 id() const; private: mir::protobuf::wire::Invocation const& invocation; }; class MessageProcessor { public: virtual bool dispatch(Invocation const& invocation) = 0; protected: MessageProcessor() = default; virtual ~MessageProcessor() = default; MessageProcessor(MessageProcessor const&) = delete; MessageProcessor& operator=(MessageProcessor const&) = delete; }; } } } #endif /* PROTOBUF_MESSAGE_PROCESSOR_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/frontend/display_changer.h0000644000015301777760000000255512322054247025555 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_DISPLAY_CHANGER_H_ #define MIR_FRONTEND_DISPLAY_CHANGER_H_ #include namespace mir { namespace graphics { class DisplayConfiguration; } namespace frontend { class Session; class DisplayChanger { public: virtual ~DisplayChanger() = default; virtual std::shared_ptr active_configuration() = 0; virtual void configure(std::shared_ptr const&, std::shared_ptr const&) = 0; protected: DisplayChanger() = default; DisplayChanger(DisplayChanger const&) = delete; DisplayChanger& operator=(DisplayChanger const&) = delete; }; } } #endif /* MIR_FRONTEND_DISPLAY_CHANGER_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/frontend/protobuf_message_sender.h0000644000015301777760000000265712322054223027322 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_PROTOBUF_MESSAGE_SENDER_H_ #define MIR_FRONTEND_PROTOBUF_MESSAGE_SENDER_H_ #include "mir/frontend/fd_sets.h" #include namespace mir { namespace frontend { namespace detail { class ProtobufMessageSender { public: virtual void send_response( ::google::protobuf::uint32 call_id, ::google::protobuf::Message* message, FdSets const& fd_sets) = 0; protected: ProtobufMessageSender() = default; virtual ~ProtobufMessageSender() = default; private: ProtobufMessageSender(ProtobufMessageSender const&) = delete; ProtobufMessageSender& operator=(ProtobufMessageSender const&) = delete; }; } } } #endif /* MIR_FRONTEND_PROTOBUF_MESSAGE_SENDER_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/frontend/fd_sets.h0000644000015301777760000000174112322054223024036 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_FD_SETS_H_ #define MIR_FRONTEND_FD_SETS_H_ #include #include #include namespace mir { namespace frontend { namespace detail { typedef std::initializer_list> FdSets; } } } // namespace mir #endif // MIR_FRONTEND_FD_SETS_H_ mir-0.1.8+14.04.20140411/include/server/mir/frontend/connected_sessions.h0000644000015301777760000000342512322054223026300 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_CONNECTED_SESSIONS_H_ #define MIR_FRONTEND_CONNECTED_SESSIONS_H_ #include #include #include namespace mir { namespace frontend { namespace detail { template class ConnectedSessions { public: ConnectedSessions() {} ~ConnectedSessions() { clear(); } void add(std::shared_ptr const& session) { std::unique_lock lock(mutex); shell_list[session->id()] = session; } void remove(int id) { std::unique_lock lock(mutex); shell_list.erase(id); } bool includes(int id) const { std::unique_lock lock(mutex); return shell_list.find(id) != shell_list.end(); } void clear() { std::unique_lock lock(mutex); shell_list.clear(); } private: ConnectedSessions(ConnectedSessions const&) = delete; ConnectedSessions& operator =(ConnectedSessions const&) = delete; std::mutex mutex; std::map> shell_list; }; } } } #endif // MIR_FRONTEND_CONNECTED_SESSIONS_H_ mir-0.1.8+14.04.20140411/include/server/mir/frontend/template_protobuf_message_processor.h0000644000015301777760000000551612322054223031751 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_TEMPLATE_PROTOBUF_MESSAGE_PROCESSOR_H_ #define MIR_FRONTEND_TEMPLATE_PROTOBUF_MESSAGE_PROCESSOR_H_ #include "mir/frontend/message_processor.h" #include #include #include namespace mir { namespace frontend { namespace detail { // Utility metafunction result_ptr_t<> allows invoke() to pick the right // send_response() overload. The base template resolves to the prototype // "send_response(::google::protobuf::uint32 id, ::google::protobuf::Message* response)" // Client code may specialize result_ptr_t to resolve to another overload. template struct result_ptr_t { typedef ::google::protobuf::Message* type; }; // Boiler plate for unpacking a parameter message, invoking a server function, and // sending the result message. Assumes the existence of Self::send_response(). template void invoke( Self* self, Server* server, void (Server::*function)( ::google::protobuf::RpcController* controller, const ParameterMessage* request, ResultMessage* response, ::google::protobuf::Closure* done), Invocation const& invocation) { ParameterMessage parameter_message; parameter_message.ParseFromString(invocation.parameters()); ResultMessage result_message; try { std::unique_ptr callback( google::protobuf::NewPermanentCallback< Self, ::google::protobuf::uint32, typename result_ptr_t::type>( self, &Self::send_response, invocation.id(), &result_message)); (server->*function)( 0, ¶meter_message, &result_message, callback.get()); } catch (std::exception const& x) { result_message.set_error(boost::diagnostic_information(x)); self->send_response(invocation.id(), &result_message); } } } } } #endif /* MIR_FRONTEND_TEMPLATE_PROTOBUF_MESSAGE_PROCESSOR_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/frontend/connector.h0000644000015301777760000000231012322054223024372 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_CONNECTOR_H_ #define MIR_FRONTEND_CONNECTOR_H_ namespace mir { namespace frontend { /// Handle client process connections class Connector { public: virtual void start() = 0; virtual void stop() = 0; virtual int client_socket_fd() const = 0; virtual void remove_endpoint() const = 0; protected: Connector() = default; virtual ~Connector() = default; Connector(const Connector&) = delete; Connector& operator=(const Connector&) = delete; }; } } #endif // MIR_FRONTEND_CONNECTOR_H_ mir-0.1.8+14.04.20140411/include/server/mir/logging/0000755000015301777760000000000012322054703022045 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/logging/glog_logger.h0000644000015301777760000000207012322054223024501 0ustar pbusernogroup00000000000000/* * 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 */ #include "mir/logging/logger.h" namespace mir { namespace logging { class GlogLogger : public Logger { public: GlogLogger( char const* argv0, int stderrthreshold, int minloglevel, std::string const& log_dir); private: virtual void log( Severity severity, const std::string& message, const std::string& component) override; }; } } mir-0.1.8+14.04.20140411/include/server/mir/asio_main_loop.h0000644000015301777760000000274712322054223023567 0ustar pbusernogroup00000000000000/* * 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_ASIO_MAIN_LOOP_H_ #define MIR_ASIO_MAIN_LOOP_H_ #include "mir/main_loop.h" #include #include #include namespace mir { class AsioMainLoop : public MainLoop { public: AsioMainLoop(); ~AsioMainLoop() noexcept(true); void run(); void stop(); void register_signal_handler( std::initializer_list signals, std::function const& handler); void register_fd_handler( std::initializer_list fd, std::function const& handler); private: class SignalHandler; class FDHandler; boost::asio::io_service io; std::vector> signal_handlers; std::vector> fd_handlers; }; } #endif /* MIR_ASIO_MAIN_LOOP_H */ mir-0.1.8+14.04.20140411/include/server/mir/report_exception.h0000644000015301777760000000174112322054223024161 0ustar pbusernogroup00000000000000/* * 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); } #endif /* MIR_REPORT_EXCEPTION_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/server_status_listener.h0000644000015301777760000000226412322054223025407 0ustar pbusernogroup00000000000000/* * 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; protected: ServerStatusListener() = default; virtual ~ServerStatusListener() = default; ServerStatusListener(ServerStatusListener const&) = delete; ServerStatusListener& operator=(ServerStatusListener const&) = delete; }; } #endif /* MIR_SERVER_STATUS_LISTENER_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/default_server_configuration.h0000644000015301777760000003153212322054247026540 0ustar pbusernogroup00000000000000/* * 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_DEFAULT_SERVER_CONFIGURATION_H_ #define MIR_DEFAULT_SERVER_CONFIGURATION_H_ #include "mir/cached_ptr.h" #include "mir/server_configuration.h" #include #include namespace mir { namespace compositor { class Renderer; class BufferStreamFactory; class Scene; class Drawer; class DisplayBufferCompositorFactory; class Compositor; class RendererFactory; class CompositorReport; } namespace frontend { class Shell; class Connector; class ConnectorReport; class ProtobufIpcFactory; class SessionCreator; class SessionMediatorReport; class MessageProcessorReport; class SessionAuthorizer; class EventSink; class DisplayChanger; class Screencast; } namespace shell { class SurfaceFactory; class InputTargeter; class FocusSetter; class PlacementStrategy; class SessionListener; class FocusController; class DisplayLayout; } namespace time { class Clock; } namespace scene { class SurfaceFactory; class BroadcastingSessionEventSink; class BufferStreamFactory; class MediatingDisplayChanger; class PixelBuffer; class SessionContainer; class SessionEventSink; class SessionEventHandlerRegister; class SessionManager; class SnapshotStrategy; class SurfaceCoordinator; class SurfaceConfigurator; class SurfaceStackModel; class SurfaceStack; class SurfaceRanker; class SurfaceController; class InputRegistrar; class SceneReport; } namespace graphics { class Platform; class Display; class BufferInitializer; class DisplayReport; class GraphicBufferAllocator; class GLConfig; namespace nested { class HostConnection; } } namespace input { class InputReport; class InputManager; class CompositeEventFilter; class InputChannelFactory; class InputConfiguration; class CursorListener; class InputRegion; class NestedInputRelay; class EventHandler; } namespace logging { class Logger; } namespace options { class Option; class Configuration; } namespace report { class ReportFactory; } class DefaultServerConfiguration : public virtual ServerConfiguration { public: DefaultServerConfiguration(int argc, char const* argv[]); explicit DefaultServerConfiguration(std::shared_ptr const& configuration_options); /** @name DisplayServer dependencies * dependencies of DisplayServer on the rest of the Mir * @{ */ virtual std::shared_ptr the_connector(); virtual std::shared_ptr the_display(); virtual std::shared_ptr the_compositor(); virtual std::shared_ptr the_input_manager(); virtual std::shared_ptr the_main_loop(); virtual std::shared_ptr the_server_status_listener(); virtual std::shared_ptr the_display_changer(); virtual std::shared_ptr the_graphics_platform(); virtual std::shared_ptr the_input_configuration(); /** @} */ /** @name graphics configuration - customization * configurable interfaces for modifying graphics * @{ */ virtual std::shared_ptr the_buffer_initializer(); virtual std::shared_ptr the_renderer_factory(); virtual std::shared_ptr the_display_configuration_policy(); virtual std::shared_ptr the_host_connection(); virtual std::shared_ptr the_nested_event_filter(); virtual std::shared_ptr the_gl_config(); /** @} */ /** @name graphics configuration - dependencies * dependencies of graphics on the rest of the Mir * @{ */ virtual std::shared_ptr the_display_report(); /** @} */ /** @name compositor configuration - customization * configurable interfaces for modifying compositor * @{ */ virtual std::shared_ptr the_compositor_report(); virtual std::shared_ptr the_display_buffer_compositor_factory(); /** @} */ /** @name compositor configuration - dependencies * dependencies of compositor on the rest of the Mir * @{ */ virtual std::shared_ptr the_buffer_allocator(); virtual std::shared_ptr the_scene(); /** @} */ /** @name frontend configuration - dependencies * dependencies of frontend on the rest of the Mir * @{ */ virtual std::shared_ptr the_session_mediator_report(); virtual std::shared_ptr the_message_processor_report(); virtual std::shared_ptr the_session_authorizer(); virtual std::shared_ptr the_frontend_shell(); virtual std::shared_ptr the_global_event_sink(); virtual std::shared_ptr the_frontend_display_changer(); virtual std::shared_ptr the_screencast(); /** @name frontend configuration - internal dependencies * internal dependencies of frontend * @{ */ virtual std::shared_ptr the_session_creator(); virtual std::shared_ptr the_connector_report(); /** @} */ /** @} */ virtual std::shared_ptr the_focus_controller(); /** @name shell configuration - customization * configurable interfaces for modifying shell * @{ */ virtual std::shared_ptr the_shell_surface_factory(); virtual std::shared_ptr the_shell_focus_setter(); virtual std::shared_ptr the_shell_placement_strategy(); virtual std::shared_ptr the_shell_session_listener(); virtual std::shared_ptr the_shell_display_layout(); /** @} */ /** @name internal scene configuration * builder functions used in the default implementation. * The interfaces returned are not published, so the functions are only useful in tests * @{ */ virtual std::shared_ptr the_pixel_buffer(); virtual std::shared_ptr the_snapshot_strategy(); virtual std::shared_ptr the_session_container(); virtual std::shared_ptr the_session_event_sink(); virtual std::shared_ptr the_session_event_handler_register(); virtual std::shared_ptr the_surface_stack_model(); virtual std::shared_ptr the_surface_ranker(); virtual std::shared_ptr the_surface_factory(); virtual std::shared_ptrthe_surface_coordinator(); virtual std::shared_ptr the_surface_configurator(); /** @} */ /** @name scene configuration - dependencies * dependencies of scene on the rest of the Mir * @{ */ virtual std::shared_ptr the_buffer_stream_factory(); virtual std::shared_ptr the_scene_report(); /** @} */ /** @name input configuration * @{ */ virtual std::shared_ptr the_input_report(); virtual std::shared_ptr the_composite_event_filter(); virtual std::shared_ptr the_input_registrar(); virtual std::shared_ptr the_input_targeter(); virtual std::shared_ptr the_cursor_listener(); virtual std::shared_ptr the_input_region(); /** @} */ /** @name logging configuration - customization * configurable interfaces for modifying logging * @{ */ virtual std::shared_ptr the_logger(); /** @} */ virtual std::shared_ptr the_clock(); protected: std::shared_ptr the_options() const; virtual std::shared_ptr the_input_channel_factory(); virtual std::shared_ptr the_mediating_display_changer(); virtual std::shared_ptr the_ipc_factory( std::shared_ptr const& shell, std::shared_ptr const& allocator); CachedPtr connector; CachedPtr input_configuration; CachedPtr input_report; CachedPtr composite_event_filter; CachedPtr input_manager; CachedPtr input_region; CachedPtr input_registrar; CachedPtr input_targeter; CachedPtr cursor_listener; CachedPtr graphics_platform; CachedPtr buffer_initializer; CachedPtr buffer_allocator; CachedPtr display; CachedPtr connector_report; CachedPtr ipc_factory; CachedPtr session_mediator_report; CachedPtr message_processor_report; CachedPtr session_authorizer; CachedPtr global_event_sink; CachedPtr session_creator; CachedPtr screencast; CachedPtr renderer_factory; CachedPtr buffer_stream_factory; CachedPtr surface_stack; CachedPtr scene_report; CachedPtr shell_surface_factory; CachedPtr surface_factory; CachedPtr session_container; CachedPtr shell_focus_setter; CachedPtr shell_placement_strategy; CachedPtr shell_session_listener; CachedPtr pixel_buffer; CachedPtr snapshot_strategy; CachedPtr shell_display_layout; CachedPtr surface_configurator; CachedPtr display_buffer_compositor_factory; CachedPtr compositor; CachedPtr compositor_report; CachedPtr logger; CachedPtr display_report; CachedPtr clock; CachedPtr main_loop; CachedPtr server_status_listener; CachedPtr display_configuration_policy; CachedPtr host_connection; CachedPtr mediating_display_changer; CachedPtr gl_config; private: std::shared_ptr const configuration_options; std::shared_ptr const default_filter; virtual std::string the_socket_file() const; // The following caches and factory functions are internal to the // default implementations of corresponding the Mir components CachedPtr broadcasting_session_event_sink; CachedPtr nested_input_relay; CachedPtr surface_controller; CachedPtr session_manager; std::shared_ptr the_broadcasting_session_event_sink(); std::shared_ptr the_nested_input_relay(); std::shared_ptr the_session_manager(); std::shared_ptr the_surface_controller(); auto report_factory(char const* report_opt) -> std::unique_ptr; }; } #endif /* MIR_DEFAULT_SERVER_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/scene/0000755000015301777760000000000012322054703021514 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/scene/surface_configurator.h0000644000015301777760000000277612322054247026116 0ustar pbusernogroup00000000000000/* * 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_SCENE_SURFACE_CONFIGURATOR_H_ #define MIR_SCENE_SURFACE_CONFIGURATOR_H_ #include "mir_toolkit/common.h" #include namespace mir { namespace scene { class Surface; class SurfaceConfigurator { public: virtual ~SurfaceConfigurator() = default; /// Returns the selected value. virtual int select_attribute_value(Surface const& surface, MirSurfaceAttrib attrib, int requested_value) = 0; virtual void attribute_set(Surface const& surface, MirSurfaceAttrib attrib, int new_value) = 0; protected: SurfaceConfigurator() = default; SurfaceConfigurator(SurfaceConfigurator const&) = delete; SurfaceConfigurator& operator=(SurfaceConfigurator const&) = delete; }; } } // namespace mir #endif // MIR_SCENE_SURFACE_CONFIGURATOR_H_ mir-0.1.8+14.04.20140411/include/server/mir/scene/surface.h0000644000015301777760000000346112322054247023324 0ustar pbusernogroup00000000000000/* * 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/shell/surface.h" namespace mir { namespace input { class InputChannel; } namespace scene { class SurfaceObserver; class Surface : public graphics::Renderable, public input::Surface, public shell::Surface { public: // resolve ambiguous member function names std::string name() const = 0; geometry::Size size() const = 0; geometry::Point top_left() const = 0; float alpha() const = 0; // member functions that don't exist in base classes // TODO input_channel() and on_change() relate to // TODO adding and removing the surface from the scene and are probably not // TODO cleanest interface for this. virtual std::shared_ptr input_channel() const = 0; virtual void on_change(std::function change_notification) = 0; virtual void add_observer(std::shared_ptr const& observer) = 0; virtual void remove_observer(std::shared_ptr const& observer) = 0; }; } } #endif // MIR_SCENE_SURFACE_H_ mir-0.1.8+14.04.20140411/include/server/mir/scene/depth_id.h0000644000015301777760000000167312322054223023451 0ustar pbusernogroup00000000000000/* * 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_SCENE_DEPTH_ID_H_ #define MIR_SCENE_DEPTH_ID_H_ #include "mir/int_wrapper.h" namespace mir { namespace scene { namespace detail { struct DepthIdIdTag; } typedef IntWrapper DepthId; } } // namespace mir #endif // MIR_SCENE_DEPTH_ID_H_ mir-0.1.8+14.04.20140411/include/server/mir/scene/surface_factory.h0000644000015301777760000000240312322054247025046 0ustar pbusernogroup00000000000000/* * 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/shell/surface_creation_parameters.h" #include namespace mir { namespace scene { class Surface; class SurfaceFactory { public: SurfaceFactory() = default; virtual ~SurfaceFactory() = default; virtual std::shared_ptr create_surface( shell::SurfaceCreationParameters const& params) = 0; private: SurfaceFactory(const SurfaceFactory&) = delete; SurfaceFactory& operator=(const SurfaceFactory&) = delete; }; } } #endif /* MIR_SCENE_SURFACE_FACTORY_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/scene/surface_coordinator.h0000644000015301777760000000300412322054247025720 0ustar pbusernogroup00000000000000/* * Copyright © 2013-14 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_COORDINATOR_H_ #define MIR_SCENE_SURFACE_COORDINATOR_H_ #include "mir/scene/surface_ranker.h" #include namespace mir { namespace shell { struct SurfaceCreationParameters; } namespace scene { class Surface; class SurfaceObserver; class SurfaceCoordinator : public SurfaceRanker { public: virtual std::shared_ptr add_surface( shell::SurfaceCreationParameters const& params, std::shared_ptr const& observer) = 0; virtual void remove_surface(std::weak_ptr const& surface) = 0; protected: SurfaceCoordinator() = default; virtual ~SurfaceCoordinator() = default; SurfaceCoordinator(SurfaceCoordinator const&) = delete; SurfaceCoordinator& operator=(SurfaceCoordinator const&) = delete; }; } } #endif /* MIR_SCENE_SURFACE_COORDINATOR_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/scene/surface_event_source.h0000644000015301777760000000254412322054247026106 0ustar pbusernogroup00000000000000/* * 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_EVENT_SOURCE_H_ #define MIR_SCENE_SURFACE_EVENT_SOURCE_H_ #include "mir/scene/surface_observer.h" #include "mir/frontend/surface_id.h" #include "mir/frontend/event_sink.h" #include namespace mir { namespace scene { class SurfaceEventSource : public SurfaceObserver { public: SurfaceEventSource( frontend::SurfaceId id, std::shared_ptr const& event_sink); void attrib_change(MirSurfaceAttrib attrib, int value); void resize(geometry::Size const& size); private: frontend::SurfaceId const id; std::shared_ptr const event_sink; }; } } #endif // MIR_SCENE_SURFACE_EVENT_SOURCE_H_ mir-0.1.8+14.04.20140411/include/server/mir/scene/surface_ranker.h0000644000015301777760000000222412322054247024662 0ustar pbusernogroup00000000000000/* * 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_SURFACE_RANKER_H_ #define MIR_SHELL_SURFACE_RANKER_H_ #include namespace mir { namespace scene { class Surface; class SurfaceRanker { public: virtual void raise(std::weak_ptr const& surface) = 0; protected: SurfaceRanker() = default; virtual ~SurfaceRanker() = default; SurfaceRanker(SurfaceRanker const&) = delete; SurfaceRanker& operator=(SurfaceRanker const&) = delete; }; } } #endif /* MIR_SHELL_SURFACE_RANKER_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/scene/scene_report.h0000644000015301777760000000262312322054223024355 0ustar pbusernogroup00000000000000/* * 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_SCENE_SCENE_REPORT_H_ #define MIR_SCENE_SCENE_REPORT_H_ #include namespace mir { namespace scene { class SceneReport { public: typedef void* BasicSurfaceId; virtual void surface_created(BasicSurfaceId id, std::string const& name) = 0; virtual void surface_added(BasicSurfaceId id, std::string const& name) = 0; virtual void surface_removed(BasicSurfaceId id, std::string const& name) = 0; virtual void surface_deleted(BasicSurfaceId id, std::string const& name) = 0; protected: SceneReport() = default; virtual ~SceneReport() = default; SceneReport(SceneReport const&) = delete; SceneReport& operator=(SceneReport const&) = delete; }; } } #endif /* MIR_SCENE_SCENE_REPORT_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/scene/buffer_stream_factory.h0000644000015301777760000000262612322054223026243 0ustar pbusernogroup00000000000000/* * 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 namespace mir { namespace compositor { class BufferStream; } namespace graphics { struct BufferProperties; } namespace scene { class BufferStreamFactory { public: virtual ~BufferStreamFactory() = default; virtual std::shared_ptr create_buffer_stream( graphics::BufferProperties const& buffer_properties) = 0; protected: BufferStreamFactory() = default; BufferStreamFactory(const BufferStreamFactory&) = delete; BufferStreamFactory& operator=(const BufferStreamFactory&) = delete; }; } } #endif // MIR_SCENE_BUFFER_STREAM_FACTORY_H_ mir-0.1.8+14.04.20140411/include/server/mir/scene/input_registrar.h0000644000015301777760000000326712322054223025113 0ustar pbusernogroup00000000000000/* * 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_SCENE_INPUT_REGISTRAR_H_ #define MIR_SCENE_INPUT_REGISTRAR_H_ #include "mir/input/input_reception_mode.h" #include namespace mir { namespace input { class SessionTarget; class InputChannel; class Surface; } namespace scene { /// An interface used to register input targets and take care of input assosciation (i.e. /// create input channels). class InputRegistrar { public: virtual ~InputRegistrar() = default; virtual void input_channel_opened(std::shared_ptr const& opened_channel, std::shared_ptr const& info, input::InputReceptionMode input_mode) = 0; virtual void input_channel_closed(std::shared_ptr const& closed_channel) = 0; protected: InputRegistrar() = default; InputRegistrar(InputRegistrar const&) = delete; InputRegistrar& operator=(InputRegistrar const&) = delete; }; } } // namespace mir #endif // MIR_SCENE_INPUT_REGISTRAR_H_ mir-0.1.8+14.04.20140411/include/server/mir/scene/surface_observer.h0000644000015301777760000000250212322054247025226 0ustar pbusernogroup00000000000000/* * 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/geometry/size.h" #include "mir_toolkit/common.h" namespace mir { namespace scene { // Initial cut - supporting the frontend requirement, more will follow class SurfaceObserver { public: virtual void attrib_change(MirSurfaceAttrib attrib, int value) = 0; virtual void resize(geometry::Size const& size) = 0; protected: SurfaceObserver() = default; virtual ~SurfaceObserver() = default; SurfaceObserver(SurfaceObserver const&) = delete; SurfaceObserver& operator=(SurfaceObserver const&) = delete; }; } } #endif // MIR_SCENE_SURFACE_OBSERVER_H_ mir-0.1.8+14.04.20140411/include/server/mir/graphics/0000755000015301777760000000000012322054703022217 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/graphics/surfaceless_egl_context.h0000644000015301777760000000351012322054223027276 0ustar pbusernogroup00000000000000/* * 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_GRAPHICS_SURFACELESS_EGL_CONTEXT_H_ #define MIR_GRAPHICS_SURFACELESS_EGL_CONTEXT_H_ #include "mir/graphics/egl_resources.h" #include "mir/graphics/gl_context.h" #include namespace mir { namespace graphics { class SurfacelessEGLContext : public GLContext { public: SurfacelessEGLContext(EGLDisplay egl_display, EGLContext shared_context); SurfacelessEGLContext(EGLDisplay egl_display, EGLint const* attribs, EGLContext shared_context); /* We have to explicitly define this, as GLContext has a deleted copy constructor */ SurfacelessEGLContext(SurfacelessEGLContext&& move); virtual ~SurfacelessEGLContext() noexcept; void make_current() const override; void release_current() const override; operator EGLContext() const; private: SurfacelessEGLContext(SurfacelessEGLContext const&) = delete; SurfacelessEGLContext& operator=(SurfacelessEGLContext const&) = delete; EGLDisplay egl_display; bool surfaceless; EGLConfig egl_config; graphics::EGLSurfaceStore egl_surface; graphics::EGLContextStore egl_context; }; } } #endif /* MIR_GRAPHICS_SURFACELESS_EGL_SURFACE_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/graphics/gl_extensions_base.h0000644000015301777760000000222712322054223026243 0ustar pbusernogroup00000000000000/* * 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_GRAPHICS_GL_EXTENSIONS_BASE_H_ #define MIR_GRAPHICS_GL_EXTENSIONS_BASE_H_ namespace mir { namespace graphics { class GLExtensionsBase { public: GLExtensionsBase(char const* extensions); bool support(char const* ext) const; private: GLExtensionsBase(GLExtensionsBase const&) = delete; GLExtensionsBase& operator=(GLExtensionsBase const&) = delete; char const* const extensions; }; } } #endif /* MIR_GRAPHICS_GL_EXTENSIONS_BASE_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/time/0000755000015301777760000000000012322054703021355 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/time/high_resolution_clock.h0000644000015301777760000000202212322054223026074 0ustar pbusernogroup00000000000000/* * 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_TIME_HIGH_RESOLUTION_CLOCK_H_ #define MIR_TIME_HIGH_RESOLUTION_CLOCK_H_ #include "mir/time/clock.h" namespace mir { namespace time { class HighResolutionClock : public Clock { public: virtual Timestamp sample() const override; private: std::chrono::high_resolution_clock clock; }; } } #endif /* MIR_TIME_HIGH_RESOLUTION_CLOCK_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/time/clock.h0000644000015301777760000000200512322054223022613 0ustar pbusernogroup00000000000000/* * 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_TIME_CLOCK_H_ #define MIR_TIME_CLOCK_H_ #include namespace mir { namespace time { typedef std::chrono::high_resolution_clock::time_point Timestamp; class Clock { public: virtual ~Clock() = default; virtual Timestamp sample() const = 0; protected: Clock() = default; }; } } #endif // MIR_TIME_CLOCK_H_ mir-0.1.8+14.04.20140411/include/server/mir/display_changer.h0000644000015301777760000000254312322054223023725 0ustar pbusernogroup00000000000000/* * 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_DISPLAY_CHANGER_H_ #define MIR_DISPLAY_CHANGER_H_ #include namespace mir { namespace graphics { class DisplayConfiguration; } class DisplayChanger { public: virtual ~DisplayChanger() = default; enum SystemStateHandling : bool { RetainSystemState, PauseResumeSystem }; virtual void configure_for_hardware_change( std::shared_ptr const& conf, SystemStateHandling pause_resume_system) = 0; protected: DisplayChanger() = default; DisplayChanger(DisplayChanger const&) = delete; DisplayChanger& operator=(DisplayChanger const&) = delete; }; } #endif /* MIR_DISPLAY_CHANGER_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/display_server.h0000644000015301777760000000236412322054223023625 0ustar pbusernogroup00000000000000/* * 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_DISPLAY_SERVER_H_ #define MIR_DISPLAY_SERVER_H_ #include /// All things Mir namespace mir { class ServerConfiguration; class DisplayServer { public: explicit DisplayServer(ServerConfiguration& config); ~DisplayServer(); void run(); void stop(); private: struct Private; std::unique_ptr p; DisplayServer() = delete; DisplayServer(const DisplayServer&) = delete; DisplayServer& operator=(const DisplayServer&) = delete; }; } #endif /* MIR_DISPLAY_SERVER_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/compositor/0000755000015301777760000000000012322054703022615 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/compositor/compositor_report.h0000644000015301777760000000304112322054223026552 0ustar pbusernogroup00000000000000/* * 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_ 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) = 0; virtual void began_frame(SubCompositorId id = 0) = 0; virtual void finished_frame(bool bypassed, SubCompositorId id = 0) = 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_ mir-0.1.8+14.04.20140411/include/server/mir/compositor/compositor.h0000644000015301777760000000214212322054223025160 0ustar pbusernogroup00000000000000/* * 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_ mir-0.1.8+14.04.20140411/include/server/mir/compositor/buffer_stream.h0000644000015301777760000000327612322054247025625 0ustar pbusernogroup00000000000000/* * 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_COMPOSITOR_BUFFER_STREAM_H_ #define MIR_COMPOSITOR_BUFFER_STREAM_H_ #include "mir/geometry/size.h" #include "mir_toolkit/common.h" #include "mir/graphics/buffer_id.h" #include namespace mir { namespace graphics { class Buffer; } namespace compositor { class BufferStream { public: virtual ~BufferStream() = default; virtual void swap_client_buffers(graphics::Buffer* old_buffer, std::function complete) = 0; virtual std::shared_ptr lock_compositor_buffer(void const* user_id) = 0; virtual std::shared_ptr lock_snapshot_buffer() = 0; virtual MirPixelFormat get_stream_pixel_format() = 0; virtual geometry::Size stream_size() = 0; virtual void resize(geometry::Size const& size) = 0; virtual void allow_framedropping(bool) = 0; virtual void force_requests_to_complete() = 0; virtual int buffers_ready_for_compositor() const = 0; }; } } #endif /* MIR_COMPOSITOR_BUFFER_STREAM_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/compositor/scene.h0000644000015301777760000000512412322054247024070 0ustar pbusernogroup00000000000000/* * 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 "mir/geometry/forward.h" #include "mir/graphics/renderable.h" #include #include namespace mir { namespace graphics { class Renderable; } namespace compositor { class FilterForScene { public: virtual ~FilterForScene() {} virtual bool operator()(graphics::Renderable const&) = 0; protected: FilterForScene() = default; FilterForScene(const FilterForScene&) = delete; FilterForScene& operator=(const FilterForScene&) = delete; }; class OperatorForScene { public: virtual ~OperatorForScene() {} virtual void operator()(graphics::Renderable const&) = 0; protected: OperatorForScene() = default; OperatorForScene(const OperatorForScene&) = delete; OperatorForScene& operator=(const OperatorForScene&) = delete; }; class Scene { public: virtual ~Scene() {} /** * Generate a valid list of renderables based on the current state of the Scene. * \returns a list of mg::Renderables. The list is in stacking order from back to front. */ virtual graphics::RenderableList generate_renderable_list() const = 0; // Back to front; normal rendering order virtual void for_each_if(FilterForScene& filter, OperatorForScene& op) = 0; /** * Sets a callback to be called whenever the state of the * Scene changes. * * The supplied callback should not directly or indirectly (e.g., * by changing a property of a surface) change the state of * the Scene, otherwise a deadlock may occur. */ virtual void set_change_callback(std::function const& f) = 0; // Implement BasicLockable, to temporarily lock scene state: virtual void lock() = 0; virtual void unlock() = 0; protected: Scene() = default; private: Scene(Scene const&) = delete; Scene& operator=(Scene const&) = delete; }; } } #endif /* MIR_COMPOSITOR_SCENE_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/compositor/display_buffer_compositor.h0000644000015301777760000000265612322054223030250 0ustar pbusernogroup00000000000000/* * 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_ namespace mir { namespace compositor { class DisplayBufferCompositor { public: virtual ~DisplayBufferCompositor() = default; /// Returns true if there is additional work to do. E.g. a composited surface /// has additional buffers ready to composite or during animation virtual bool composite() = 0; protected: DisplayBufferCompositor() = default; DisplayBufferCompositor& operator=(DisplayBufferCompositor const&) = delete; DisplayBufferCompositor(DisplayBufferCompositor const&) = delete; }; } } #endif /* MIR_COMPOSITOR_DISPLAY_BUFFER_COMPOSITOR_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/compositor/gl_renderer.h0000644000015301777760000001030712322054247025262 0ustar pbusernogroup00000000000000/* * 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: Alexandros Frantzis */ #ifndef MIR_COMPOSITOR_GL_RENDERER_H_ #define MIR_COMPOSITOR_GL_RENDERER_H_ #include #include #include #include #include #include namespace mir { namespace compositor { class GLRenderer : public Renderer { public: GLRenderer(geometry::Rectangle const& display_area); virtual ~GLRenderer() noexcept; // These are called with a valid GL context: void set_viewport(geometry::Rectangle const& rect) override; void set_rotation(float degrees) override; void begin() const override; void render(graphics::Renderable const& renderable, graphics::Buffer& buffer) const override; void end() const override; // This is called _without_ a GL context: void suspend() override; struct Vertex { GLfloat position[3]; GLfloat texcoord[2]; }; struct Primitive { GLenum type; // GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_TRIANGLES etc GLuint tex_id; // GL texture ID (or 0 to represent the surface itself) std::vector vertices; }; /** * tessellate defines the list of triangles that will be used to render * the surface. By default it just returns 4 vertices for a rectangle. * However you can override its behaviour to tessellate more finely and * deform freely for effects like wobbly windows. * * \param [in,out] primitives The list of rendering primitives to be * grown and/or modified. * \param [in] renderable The renderable surface being tessellated. * \param [in] buf_size The dimensions of the buffer being rendered, * which can be particularly useful in * calculating texcoords for a surface being * actively resized (as the buf_size doesn't * yet match renderable.size()). * * \note The cohesion of this function to GLRenderer is quite loose and it * does not strictly need to reside here. * However it seems a good choice under GLRenderer while this remains * the only OpenGL-specific class in the display server, and * tessellation is very much OpenGL-specific. */ virtual void tessellate(std::vector& primitives, graphics::Renderable const& renderable, geometry::Size const& buf_size) const; /** * Load the texture for a surface any which way you like. The default * implementation does so with efficient GPU-side caching built in. * * \returns The OpenGL texture name for the surface. */ virtual GLuint load_texture(graphics::Renderable const& renderable, graphics::Buffer& buffer) const; private: GLuint vertex_shader; GLuint fragment_shader; GLuint program; GLuint position_attr_loc; GLuint texcoord_attr_loc; GLuint centre_uniform_loc; GLuint display_transform_uniform_loc; GLuint transform_uniform_loc; GLuint alpha_uniform_loc; float rotation; geometry::Rectangle viewport; typedef graphics::Renderable const* SurfaceID; struct Texture { GLuint id = 0; graphics::BufferID origin; bool used; }; mutable std::unordered_map textures; mutable bool skipped = false; }; } } #endif // MIR_COMPOSITOR_GL_RENDERER_H_ mir-0.1.8+14.04.20140411/include/server/mir/compositor/renderer_factory.h0000644000015301777760000000242212322054223026320 0ustar pbusernogroup00000000000000/* * 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_RENDERER_FACTORY_H_ #define MIR_COMPOSITOR_RENDERER_FACTORY_H_ #include namespace mir { namespace geometry { struct Rectangle; } namespace compositor { class Renderer; class RendererFactory { public: virtual ~RendererFactory() = default; virtual std::unique_ptr create_renderer_for(geometry::Rectangle const& rect) = 0; protected: RendererFactory() = default; RendererFactory(RendererFactory const&) = delete; RendererFactory& operator=(RendererFactory const&) = delete; }; } } #endif /* MIR_COMPOSITOR_RENDERER_FACTORY_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/compositor/renderer.h0000644000015301777760000000311112322054247024573 0ustar pbusernogroup00000000000000/* * 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_COMPOSITOR_RENDERER_H_ #define MIR_COMPOSITOR_RENDERER_H_ #include "mir/geometry/rectangle.h" namespace mir { namespace graphics { class Buffer; class Renderable; } namespace compositor { class Renderer { public: virtual ~Renderer() = default; virtual void set_viewport(geometry::Rectangle const& rect) = 0; virtual void set_rotation(float degrees) = 0; virtual void begin() const = 0; // XXX The buffer parameter here could now be replaced with // renderable::buffer(). virtual void render(graphics::Renderable const& renderable, graphics::Buffer& buffer) const = 0; virtual void end() const = 0; virtual void suspend() = 0; // called when begin/render/end skipped protected: Renderer() = default; Renderer(const Renderer&) = delete; Renderer& operator=(const Renderer&) = delete; }; } } #endif // MIR_COMPOSITOR_RENDERER_H_ mir-0.1.8+14.04.20140411/include/server/mir/compositor/display_buffer_compositor_factory.h0000644000015301777760000000302512322054223031766 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/include/server/mir/server_configuration.h0000644000015301777760000000436012322054223025025 0ustar pbusernogroup00000000000000/* * 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_SERVER_CONFIGURATION_H_ #define MIR_SERVER_CONFIGURATION_H_ #include namespace mir { namespace compositor { class Compositor; } namespace frontend { class Connector; class Shell; } namespace shell { class SessionContainer; } namespace graphics { class Display; class DisplayConfigurationPolicy; class Platform; } namespace input { class InputManager; class EventFilter; class InputConfiguration; } class MainLoop; class ServerStatusListener; class DisplayChanger; class ServerConfiguration { public: // TODO most of these interfaces are wider DisplayServer needs... // TODO ...some or all of them need narrowing virtual std::shared_ptr the_connector() = 0; virtual std::shared_ptr the_display() = 0; virtual std::shared_ptr the_compositor() = 0; virtual std::shared_ptr the_input_manager() = 0; virtual std::shared_ptr the_main_loop() = 0; virtual std::shared_ptr the_server_status_listener() = 0; virtual std::shared_ptr the_display_changer() = 0; virtual std::shared_ptr the_graphics_platform() = 0; virtual std::shared_ptr the_input_configuration() = 0; protected: ServerConfiguration() = default; virtual ~ServerConfiguration() { /* TODO: make nothrow */ } ServerConfiguration(ServerConfiguration const&) = delete; ServerConfiguration& operator=(ServerConfiguration const&) = delete; }; } #endif /* MIR_SERVER_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/report/0000755000015301777760000000000012322054703021732 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/report/logging/0000755000015301777760000000000012322054703023360 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/report/legacy_input_report.h0000644000015301777760000000177112322054223026164 0ustar pbusernogroup00000000000000/* * 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_REPORT_LEGACY_INPUT_REPORT_H_ #define MIR_REPORT_LEGACY_INPUT_REPORT_H_ #include namespace mir { namespace logging { class Logger; } namespace report { namespace legacy_input { void initialize(std::shared_ptr const& logger); } } } #endif // MIR_REPORT_LEGACY_INPUT_REPORT_H_ mir-0.1.8+14.04.20140411/include/server/mir/shell/0000755000015301777760000000000012322054703021526 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/shell/surface.h0000644000015301777760000000347612322054247023344 0ustar pbusernogroup00000000000000/* * 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_SHELL_SURFACE_H_ #define MIR_SHELL_SURFACE_H_ #include "mir/shell/surface_buffer_access.h" #include "mir/geometry/rectangle.h" #include "mir/frontend/surface.h" #include #include namespace mir { namespace scene { class SurfaceRanker; } namespace shell { class InputTargeter; class Surface : public frontend::Surface, public shell::SurfaceBufferAccess { public: virtual std::string name() const = 0; virtual MirSurfaceType type() const = 0; virtual MirSurfaceState state() const = 0; virtual void hide() = 0; virtual void show() = 0; virtual void move_to(geometry::Point const& top_left) = 0; virtual geometry::Point top_left() const = 0; virtual void take_input_focus(std::shared_ptr const& targeter) = 0; virtual void set_input_region(std::vector const& region) = 0; virtual void allow_framedropping(bool) = 0; virtual void resize(geometry::Size const& size) = 0; virtual void set_transformation(glm::mat4 const& t) = 0; virtual float alpha() const = 0; virtual void set_alpha(float alpha) = 0; }; } } #endif /* MIR_SHELL_SURFACE_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/shell/focus_setter.h0000644000015301777760000000240012322054223024375 0ustar pbusernogroup00000000000000/* * 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_SHELL_FOCUS_SETTER_H_ #define MIR_SHELL_FOCUS_SETTER_H_ #include namespace mir { namespace shell { class Session; /// Interface used by the Shell to propagate changes in the focus model to interested views /// e.g. Input, or Surfaces. class FocusSetter { public: virtual ~FocusSetter() {} virtual void set_focus_to(std::shared_ptr const& new_focus) = 0; protected: FocusSetter() = default; FocusSetter(const FocusSetter&) = delete; FocusSetter& operator=(const FocusSetter&) = delete; }; } } #endif // MIR_SHELL_FOCUS_SETTER_H_ mir-0.1.8+14.04.20140411/include/server/mir/shell/focus_controller.h0000644000015301777760000000244512322054223025263 0ustar pbusernogroup00000000000000/* * 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 namespace mir { namespace shell { class Session; class FocusController { public: virtual ~FocusController() = default; virtual void focus_next() = 0; virtual std::weak_ptr focussed_application() const = 0; virtual void set_focus_to(std::shared_ptr const& focus) = 0; protected: FocusController() = default; FocusController(FocusController const&) = delete; FocusController& operator=(FocusController const&) = delete; }; } } // namespace mir #endif // MIR_SHELL_FOCUS_CONTROLLER_H_ mir-0.1.8+14.04.20140411/include/server/mir/shell/session.h0000644000015301777760000000240312322054223023356 0ustar pbusernogroup00000000000000/* * 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_SHELL_SESSION_H_ #define MIR_SHELL_SESSION_H_ #include "mir/frontend/session.h" #include "mir/shell/snapshot.h" #include namespace mir { namespace shell { class Surface; class Session : public frontend::Session { public: virtual void force_requests_to_complete() = 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; }; } } #endif // MIR_SHELL_SESSION_H_ mir-0.1.8+14.04.20140411/include/server/mir/shell/snapshot.h0000644000015301777760000000211012322054223023525 0ustar pbusernogroup00000000000000/* * 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 shell { struct Snapshot { geometry::Size size; geometry::Stride stride; void const* pixels; }; typedef std::function SnapshotCallback; } } #endif /* MIR_SCENE_SNAPSHOT_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/shell/placement_strategy.h0000644000015301777760000000261512322054223025572 0ustar pbusernogroup00000000000000/* * 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_PLACEMENT_STRATEGY_H_ #define MIR_SHELL_PLACEMENT_STRATEGY_H_ namespace mir { namespace shell { class Session; struct SurfaceCreationParameters; class PlacementStrategy { public: virtual ~PlacementStrategy() {} // TODO: It is strange to work in terms of SurfaceCreationParameters here, // perhaps a new interface is needed. virtual SurfaceCreationParameters place(shell::Session const& session, SurfaceCreationParameters const& request_parameters) = 0; protected: PlacementStrategy() = default; PlacementStrategy(PlacementStrategy const&) = delete; PlacementStrategy& operator=(PlacementStrategy const&) = delete; }; } } // namespace mir #endif // MIR_SHELL_PLACEMENT_STRATEGY_H_ mir-0.1.8+14.04.20140411/include/server/mir/shell/surface_factory.h0000644000015301777760000000270612322054247025066 0ustar pbusernogroup00000000000000/* * 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: Thomas Voss */ #ifndef MIR_SHELL_SURFACE_FACTORY_H_ #define MIR_SHELL_SURFACE_FACTORY_H_ #include namespace mir { namespace scene { class SurfaceObserver; } namespace shell { class Session; class Surface; struct SurfaceCreationParameters; class SurfaceFactory { public: virtual std::shared_ptr create_surface( Session* session, SurfaceCreationParameters const& params, std::shared_ptr const& observer) = 0; virtual void destroy_surface(std::shared_ptr const& surface) = 0; protected: virtual ~SurfaceFactory() {} SurfaceFactory() = default; SurfaceFactory(const SurfaceFactory&) = delete; SurfaceFactory& operator=(const SurfaceFactory&) = delete; }; } } #endif // MIR_SHELL_SURFACE_FACTORY_H_ mir-0.1.8+14.04.20140411/include/server/mir/shell/surface_creation_parameters.h0000644000015301777760000000472612322054223027444 0ustar pbusernogroup00000000000000/* * 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_SHELL_SURFACE_CREATION_PARAMETERS_H_ #define MIR_SHELL_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/scene/depth_id.h" #include "mir/input/input_reception_mode.h" #include #include namespace mir { namespace shell { 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& of_depth(scene::DepthId const& new_depth); SurfaceCreationParameters& with_input_mode(input::InputReceptionMode const& new_mode); SurfaceCreationParameters& with_output_id(graphics::DisplayConfigurationOutputId const& output_id); std::string name; geometry::Size size; geometry::Point top_left; graphics::BufferUsage buffer_usage; MirPixelFormat pixel_format; scene::DepthId depth; input::InputReceptionMode input_mode; graphics::DisplayConfigurationOutputId output_id; }; bool operator==(const SurfaceCreationParameters& lhs, const SurfaceCreationParameters& rhs); bool operator!=(const SurfaceCreationParameters& lhs, const SurfaceCreationParameters& rhs); SurfaceCreationParameters a_surface(); } } #endif /* MIR_SHELL_SURFACE_CREATION_PARAMETERS_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/shell/surface_buffer_access.h0000644000015301777760000000245012322054223026177 0ustar pbusernogroup00000000000000/* * 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_SURFACE_BUFFER_ACCESS_H_ #define MIR_SHELL_SURFACE_BUFFER_ACCESS_H_ #include namespace mir { namespace graphics { class Buffer; } namespace shell { class SurfaceBufferAccess { public: virtual ~SurfaceBufferAccess() = default; virtual void with_most_recent_buffer_do( std::function const& exec) = 0; protected: SurfaceBufferAccess() = default; SurfaceBufferAccess(SurfaceBufferAccess const&) = delete; SurfaceBufferAccess& operator=(SurfaceBufferAccess const&) = delete; }; } } #endif /* MIR_SHELL_SURFACE_BUFFER_ACCESS_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/shell/session_listener.h0000644000015301777760000000305712322054223025271 0ustar pbusernogroup00000000000000/* * 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_SHELL_SESSION_LISTENER_H_ #define MIR_SHELL_SESSION_LISTENER_H_ #include namespace mir { namespace shell { class Session; class Surface; 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_SHELL_SESSION_LISTENER_H_ mir-0.1.8+14.04.20140411/include/server/mir/shell/null_session_listener.h0000644000015301777760000000311312322054223026314 0ustar pbusernogroup00000000000000/* * 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_SHELL_NULL_SESSION_LISTENER_H_ #define MIR_SHELL_NULL_SESSION_LISTENER_H_ #include "mir/shell/session_listener.h" namespace mir { namespace shell { class Session; 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_SHELL_NULL_SESSION_LISTENER_H_ mir-0.1.8+14.04.20140411/include/server/mir/shell/display_layout.h0000644000015301777760000000370112322054223024737 0ustar pbusernogroup00000000000000/* * 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. * * @param [in] id the id of the output to place the rectangle in * @param [in,out] rect the rectangle to place */ virtual void 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_ */ mir-0.1.8+14.04.20140411/include/server/mir/shell/input_targeter.h0000644000015301777760000000251412322054223024732 0ustar pbusernogroup00000000000000/* * 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 InputChannel; } namespace shell { /// An interface used to control the selection of keyboard input focus. class InputTargeter { public: virtual ~InputTargeter() = default; virtual void focus_changed(std::shared_ptr const& focus_channel) = 0; virtual void focus_cleared() = 0; protected: InputTargeter() = default; InputTargeter(InputTargeter const&) = delete; InputTargeter& operator=(InputTargeter const&) = delete; }; } } // namespace mir #endif // MIR_SHELL_INPUT_TARGETER_H_ mir-0.1.8+14.04.20140411/include/server/mir/input/0000755000015301777760000000000012322054703021556 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/input/input_manager.h0000644000015301777760000000250312322054223024555 0ustar pbusernogroup00000000000000/* * 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 * Daniel d'Andradra */ #ifndef MIR_INPUT_INPUT_MANAGER_H_ #define MIR_INPUT_INPUT_MANAGER_H_ #include "mir/input/input_channel_factory.h" #include namespace mir { namespace input { class InputChannel; class InputManager : public InputChannelFactory { public: virtual void start() = 0; virtual void stop() = 0; virtual std::shared_ptr make_input_channel() = 0; protected: InputManager() {}; virtual ~InputManager() {} InputManager(const InputManager&) = delete; InputManager& operator=(const InputManager&) = delete; }; } } #endif // MIR_INPUT_INPUT_MANAGER mir-0.1.8+14.04.20140411/include/server/mir/input/input_configuration.h0000644000015301777760000000306612322054223026017 0ustar pbusernogroup00000000000000/* * 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_CONFIGURATION_H_ #define MIR_INPUT_INPUT_CONFIGURATION_H_ #include namespace mir { namespace scene { class InputRegistrar; } namespace shell { class InputTargeter; } namespace input { class InputTargets; class InputManager; class InputConfiguration { public: virtual ~InputConfiguration() {} virtual std::shared_ptr the_input_registrar() = 0; virtual std::shared_ptr the_input_targeter() = 0; virtual std::shared_ptr the_input_manager() = 0; virtual void set_input_targets(std::shared_ptr const& targets) = 0; protected: InputConfiguration() = default; InputConfiguration(InputConfiguration const&) = delete; InputConfiguration& operator=(InputConfiguration const&) = delete; }; } } // namespace mir #endif // MIR_INPUT_INPUT_CONFIGURATION_H_ mir-0.1.8+14.04.20140411/include/server/mir/input/android/0000755000015301777760000000000012322054703023176 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/server/mir/input/android/default_android_input_configuration.h0000644000015301777760000000435112322054223032641 0ustar pbusernogroup00000000000000/* * 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_ANDROID_DEFAULT_ANDROID_INPUT_CONFIGURATION_H_ #define MIR_INPUT_ANDROID_DEFAULT_ANDROID_INPUT_CONFIGURATION_H_ #include "mir/input/android/dispatcher_input_configuration.h" namespace mir { namespace input { namespace android { class DefaultInputConfiguration : public DispatcherInputConfiguration { public: DefaultInputConfiguration(std::shared_ptr const& event_filter, std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener, std::shared_ptr const& input_report); virtual ~DefaultInputConfiguration(); std::shared_ptr the_input_manager(); protected: virtual droidinput::sp the_event_hub(); virtual droidinput::sp the_reader(); virtual std::shared_ptr the_reader_thread(); virtual droidinput::sp the_reader_policy(); private: droidinput::sp the_dispatcher() override; CachedPtr reader_thread; CachedAndroidPtr event_hub; CachedAndroidPtr reader_policy; CachedAndroidPtr reader; CachedAndroidPtr dispatcher; }; } } } // namespace mir #endif // MIR_INPUT_ANDROID_DEFAULT_ANDROID_INPUT_CONFIGURATION_H_ mir-0.1.8+14.04.20140411/include/server/mir/input/android/dispatcher_input_configuration.h0000644000015301777760000000711412322054223031643 0ustar pbusernogroup00000000000000/* * 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_INPUT_ANDROID_DISPATCHER_INPUT_CONFIGURATION_H_ #define MIR_INPUT_ANDROID_DISPATCHER_INPUT_CONFIGURATION_H_ #include "mir/input/input_configuration.h" #include "mir/cached_ptr.h" #include #include #include namespace droidinput = android; namespace android { class InputReaderInterface; class InputReaderPolicyInterface; class InputDispatcherPolicyInterface; class InputDispatcherInterface; class EventHubInterface; } namespace mir { namespace shell { class InputTargeter; } namespace input { class EventFilter; class CursorListener; class InputReport; class InputRegion; namespace android { class InputRegistrar; class WindowHandleRepository; class InputThread; template class CachedAndroidPtr { droidinput::wp cache; CachedAndroidPtr(CachedAndroidPtr const&) = delete; CachedAndroidPtr& operator=(CachedAndroidPtr const&) = delete; public: CachedAndroidPtr() = default; droidinput::sp operator()(std::function()> make) { auto result = cache.promote(); if (!result.get()) { cache = result = make(); } return result; } }; class DispatcherInputConfiguration : public input::InputConfiguration { public: DispatcherInputConfiguration(std::shared_ptr const& event_filter, std::shared_ptr const& input_region, std::shared_ptr const& cursor_listener, std::shared_ptr const& input_report); virtual ~DispatcherInputConfiguration(); std::shared_ptr the_input_registrar(); std::shared_ptr the_input_targeter(); std::shared_ptr the_input_manager(); void set_input_targets(std::shared_ptr const& targets); virtual bool is_key_repeat_enabled(); protected: virtual droidinput::sp the_dispatcher() = 0; virtual std::shared_ptr the_dispatcher_thread(); virtual droidinput::sp the_dispatcher_policy(); std::shared_ptr the_window_handle_repository(); std::shared_ptr const event_filter; std::shared_ptr const input_region; std::shared_ptr const cursor_listener; std::shared_ptr const input_report; CachedPtr input_manager; private: CachedPtr dispatcher_thread; CachedPtr input_registrar; CachedPtr input_targeter; CachedAndroidPtr dispatcher_policy; }; } } } // namespace mir #endif /* MIR_INPUT_ANDROID_DISPATCHER_INPUT_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/input/surface.h0000644000015301777760000000241612322054247023365 0ustar pbusernogroup00000000000000/* * 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/size.h" #include "mir/geometry/point.h" #include namespace mir { namespace input { class Surface { public: virtual std::string name() const = 0; virtual geometry::Point top_left() const = 0; virtual geometry::Size size() const = 0; virtual bool contains(geometry::Point const& point) const = 0; protected: Surface() = default; virtual ~Surface() = default; Surface(const Surface&) = delete; Surface& operator=(const Surface& ) = delete; }; } } #endif /* MIR_INPUT_SURFACE_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/input/vt_filter.h0000644000015301777760000000170412322054223023724 0ustar pbusernogroup00000000000000/* * 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 Ancell */ #ifndef MIR_INPUT_VT_FILTER_H_ #define MIR_INPUT_VT_FILTER_H_ #include "mir/input/event_filter.h" namespace mir { namespace input { class VTFilter : public EventFilter { public: bool handle(MirEvent const& event) override; }; } } #endif // MIR_INPUT_VT_FILTER_H_ mir-0.1.8+14.04.20140411/include/server/mir/input/cursor_listener.h0000644000015301777760000000240012322054223025142 0ustar pbusernogroup00000000000000/* * 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(const CursorListener&) = delete; CursorListener& operator=(const CursorListener&) = delete; }; } } #endif // MIR_INPUT_CURSOR_LISTENER_H_ mir-0.1.8+14.04.20140411/include/server/mir/input/input_targets.h0000644000015301777760000000244712322054223024623 0ustar pbusernogroup00000000000000/* * 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 * Daniel d'Andradra */ #ifndef MIR_INPUT_INPUT_TARGETS_H_ #define MIR_INPUT_INPUT_TARGETS_H_ #include "mir/input/input_channel_factory.h" #include namespace mir { namespace input { class InputChannel; class InputTargets { public: virtual ~InputTargets() = default; virtual void for_each(std::function const&)> const& callback) = 0; protected: InputTargets() = default; InputTargets(InputTargets const&) = delete; InputTargets& operator=(InputTargets const&) = delete; }; } } #endif // MIR_INPUT_INPUT_TARGETS mir-0.1.8+14.04.20140411/include/server/mir/input/input_channel.h0000644000015301777760000000230112322054223024547 0ustar pbusernogroup00000000000000/* * 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_ mir-0.1.8+14.04.20140411/include/server/mir/input/input_reception_mode.h0000644000015301777760000000162112322054223026137 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/include/server/mir/input/event_filter.h0000644000015301777760000000225712322054223024420 0ustar pbusernogroup00000000000000/* * 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_ mir-0.1.8+14.04.20140411/include/server/mir/input/input_region.h0000644000015301777760000000313012322054223024423 0ustar pbusernogroup00000000000000/* * 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_INPUT_REGION_H_ #define MIR_INPUT_INPUT_REGION_H_ namespace mir { namespace geometry { struct Rectangle; struct Point; } namespace input { /** * Interface to the region of valid input coordinates. */ class InputRegion { public: virtual ~InputRegion() = default; /** The bounding rectangle of the input region */ virtual geometry::Rectangle bounding_rectangle() = 0; /** * Confines a point to the input region. * * If the point is within input region it remains unchanged, * otherwise it is replaced by the region point that is closest to * it. * * @param [in,out] point the point to confine */ virtual void confine(geometry::Point& point) = 0; protected: InputRegion() = default; InputRegion(InputRegion const&) = delete; InputRegion& operator=(InputRegion const&) = delete; }; } } #endif /* MIR_INPUT_INPUT_REGION_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/input/input_report.h0000644000015301777760000000263412322054223024463 0ustar pbusernogroup00000000000000/* * 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_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 received_event_finished_signal(int src_fd, uint32_t seq_id) = 0; protected: InputReport() = default; InputReport(InputReport const&) = delete; InputReport& operator=(InputReport const&) = delete; }; } } #endif /* MIR_INPUT_INPUT_REPORT_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/input/composite_event_filter.h0000644000015301777760000000217312322054223026477 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/include/server/mir/input/input_channel_factory.h0000644000015301777760000000233712322054223026307 0ustar pbusernogroup00000000000000/* * 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_FACTORY_H_ #define MIR_INPUT_INPUT_CHANNEL_FACTORY_H_ #include namespace mir { namespace input { class InputChannel; class InputChannelFactory { public: virtual ~InputChannelFactory() {} virtual std::shared_ptr make_input_channel() = 0; protected: InputChannelFactory() = default; InputChannelFactory(InputChannelFactory const&) = delete; InputChannelFactory& operator=(InputChannelFactory const&) = delete; }; } } // namespace mir #endif // MIR_INPUT_INPUT_CHANNEL_FACTORY_H_ mir-0.1.8+14.04.20140411/include/server/mir/run_mir.h0000644000015301777760000000242112322054223022237 0ustar pbusernogroup00000000000000/* * 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_RUN_MIR_H_ #define MIR_RUN_MIR_H_ #include #include namespace mir { class ServerConfiguration; class DisplayServer; /** * Run a DisplayServer with the supplied configuration. * init will be called after constructing the server, but before invoking DisplayServer::run() * The server will be stopped on receipt of SIGTERM or SIGINT * This function does not return until the server has stopped. */ void run_mir( ServerConfiguration& config, std::function init); void report_exception(std::ostream& out); } #endif /* MIR_RUN_MIR_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/main_loop.h0000644000015301777760000000172512322054223022547 0ustar pbusernogroup00000000000000/* * 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_MAIN_LOOP_H_ #define MIR_MAIN_LOOP_H_ #include "mir/graphics/event_handler_register.h" namespace mir { class MainLoop : public graphics::EventHandlerRegister { public: virtual void run() = 0; virtual void stop() = 0; }; } #endif /* MIR_MAIN_LOOP_H_ */ mir-0.1.8+14.04.20140411/include/server/mir/default_server_status_listener.h0000644000015301777760000000211312322054223027104 0ustar pbusernogroup00000000000000/* * 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_DEFAULT_SERVER_STATUS_LISTENER_H_ #define MIR_DEFAULT_SERVER_STATUS_LISTENER_H_ #include "mir/server_status_listener.h" namespace mir { class DefaultServerStatusListener : public virtual ServerStatusListener { public: virtual void paused() { } virtual void resumed() { } virtual void started() { } }; } #endif /* MIR_DEFAULT_SERVER_STATUS_LISTENER_H_ */ mir-0.1.8+14.04.20140411/include/shared/0000755000015301777760000000000012322054703017570 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir_toolkit/0000755000015301777760000000000012322054703022124 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir_toolkit/client_types.h0000644000015301777760000002144512322054223025002 0ustar pbusernogroup00000000000000/* * 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 #ifdef __cplusplus /** * \defgroup mir_toolkit MIR graphics tools API * @{ */ extern "C" { #endif typedef enum MirBool { mir_false = 0, mir_true = 1 } MirBool; /* Display server connection API */ typedef void* MirEGLNativeWindowType; typedef void* MirEGLNativeDisplayType; typedef struct MirConnection MirConnection; typedef struct MirSurface MirSurface; typedef struct MirScreencast MirScreencast; /** * 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; /** * 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 (*mir_connected_callback)(MirConnection *connection, void *client_context); /** * Callback to be passed when calling: * - mir_connection_create_surface * - mir_surface_swap_buffers * - mir_surface_release * \param [in] surface the surface being updated * \param [in,out] client_context context provided by client in calling * mir_connect */ typedef void (*mir_surface_callback)(MirSurface *surface, void *client_context); /** * Callback member of MirEventDelegate for handling of events. * \param [in] surface The surface on which an event has occurred * \param [in] event The event to be handled * \param [in,out] context The context provided by client during delegate * registration. */ typedef void (*mir_event_delegate_callback)( MirSurface* surface, 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 (*mir_lifecycle_event_callback)( MirConnection* connection, MirLifecycleState state, void* context); /** * 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 (*mir_display_config_callback)( MirConnection* connection, void* context); /** * 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; /** * MirSurfaceParameters is the structure of minimum required information that * you must provide to Mir in order to create a surface. */ 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; enum { mir_platform_package_max = 32 }; /** * The native buffer type for the system the client is connected on */ typedef enum MirPlatformType { mir_platform_type_gbm, mir_platform_type_android } 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 MirSurface. 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_display_output_type_vga, mir_display_output_type_dvii, mir_display_output_type_dvid, mir_display_output_type_dvia, mir_display_output_type_composite, mir_display_output_type_svideo, mir_display_output_type_lvds, mir_display_output_type_component, mir_display_output_type_ninepindin, mir_display_output_type_displayport, mir_display_output_type_hdmia, mir_display_output_type_hdmib, mir_display_output_type_tv, mir_display_output_type_edp } MirDisplayOutputType; 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; 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; /** * MirEventDelegate may be used to specify (at surface creation time) * callbacks for handling of events. */ typedef struct MirEventDelegate { mir_event_delegate_callback callback; void *context; } MirEventDelegate; typedef struct MirRectangle { int left; int top; unsigned int width; unsigned int height; } MirRectangle; /** * 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 (*mir_screencast_callback)(MirScreencast *screencast, void *client_context); #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_CLIENT_TYPES_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir_toolkit/event.h0000644000015301777760000001265512322054223023424 0ustar pbusernogroup00000000000000/* * 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: Thomas Voss */ #ifndef MIR_TOOLKIT_EVENT_H_ #define MIR_TOOLKIT_EVENT_H_ #include #include #include "mir_toolkit/common.h" #ifdef __cplusplus /** * \addtogroup mir_toolkit * @{ */ extern "C" { #endif /* TODO: To the moon. */ #define MIR_INPUT_EVENT_MAX_POINTER_COUNT 16 typedef int64_t nsecs_t; typedef enum { mir_event_type_key, mir_event_type_motion, mir_event_type_surface, mir_event_type_resize } MirEventType; typedef enum { mir_key_action_down = 0, mir_key_action_up = 1, mir_key_action_multiple = 2 } MirKeyAction; typedef enum { mir_key_flag_woke_here = 0x1, mir_key_flag_soft_keyboard = 0x2, mir_key_flag_keep_touch_mode = 0x4, mir_key_flag_from_system = 0x8, mir_key_flag_editor_action = 0x10, mir_key_flag_canceled = 0x20, mir_key_flag_virtual_hard_key = 0x40, mir_key_flag_long_press = 0x80, mir_key_flag_canceled_long_press = 0x100, mir_key_flag_tracking = 0x200, mir_key_flag_fallback = 0x400 } MirKeyFlag; typedef enum { mir_key_modifier_none = 0, mir_key_modifier_alt = 0x02, mir_key_modifier_alt_left = 0x10, mir_key_modifier_alt_right = 0x20, mir_key_modifier_shift = 0x01, mir_key_modifier_shift_left = 0x40, mir_key_modifier_shift_right = 0x80, mir_key_modifier_sym = 0x04, mir_key_modifier_function = 0x08, mir_key_modifier_ctrl = 0x1000, mir_key_modifier_ctrl_left = 0x2000, mir_key_modifier_ctrl_right = 0x4000, mir_key_modifier_meta = 0x10000, mir_key_modifier_meta_left = 0x20000, mir_key_modifier_meta_right = 0x40000, mir_key_modifier_caps_lock = 0x100000, mir_key_modifier_num_lock = 0x200000, mir_key_modifier_scroll_lock = 0x400000 } MirKeyModifier; typedef enum { mir_motion_action_down = 0, mir_motion_action_up = 1, mir_motion_action_move = 2, mir_motion_action_cancel = 3, mir_motion_action_outside = 4, mir_motion_action_pointer_down = 5, mir_motion_action_pointer_up = 6, mir_motion_action_hover_move = 7, mir_motion_action_scroll = 8, mir_motion_action_hover_enter = 9, mir_motion_action_hover_exit = 10 } MirMotionAction; typedef enum { mir_motion_flag_window_is_obscured = 0x1 } MirMotionFlag; typedef enum { mir_motion_button_primary = 1 << 0, mir_motion_button_secondary = 1 << 1, mir_motion_button_tertiary = 1 << 2, mir_motion_button_back = 1 << 3, mir_motion_button_forward = 1 << 4 } MirMotionButton; typedef enum { mir_motion_tool_type_unknown = 0, mir_motion_tool_type_finger = 1, mir_motion_tool_type_stylus = 2, mir_motion_tool_type_mouse = 3, mir_motion_tool_type_eraser = 4 } MirMotionToolType; typedef struct { MirEventType type; int32_t device_id; int32_t source_id; MirKeyAction action; MirKeyFlag flags; unsigned int modifiers; int32_t key_code; int32_t scan_code; int32_t repeat_count; nsecs_t down_time; nsecs_t event_time; int is_system_key; } MirKeyEvent; typedef struct { MirEventType type; int32_t device_id; int32_t source_id; /* * TODO(racarr): We would like to store this as a MirMotionAction but the android input stack * encodes some non enumerable values in it. It's convenient to keep things * this way for now until we can drop SF/Hybris support in QtUbuntu. */ int action; MirMotionFlag flags; unsigned int modifiers; int32_t edge_flags; MirMotionButton button_state; float x_offset; float y_offset; float x_precision; float y_precision; nsecs_t down_time; nsecs_t event_time; size_t pointer_count; struct { int id; float x, raw_x; float y, raw_y; float touch_major; float touch_minor; float size; float pressure; float orientation; float vscroll; float hscroll; MirMotionToolType tool_type; int unused1; int unused2; int unused3; } pointer_coordinates[MIR_INPUT_EVENT_MAX_POINTER_COUNT]; int unused0; int unused1; int unused2; int unused3; } MirMotionEvent; typedef struct { MirEventType type; int id; MirSurfaceAttrib attrib; int value; } MirSurfaceEvent; typedef struct { MirEventType type; int surface_id; int width; int height; } MirResizeEvent; typedef union { MirEventType type; MirKeyEvent key; MirMotionEvent motion; MirSurfaceEvent surface; MirResizeEvent resize; } MirEvent; #ifdef __cplusplus } /**@}*/ #endif #endif /* MIR_TOOLKIT_EVENT_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir_toolkit/common.h0000644000015301777760000000650512322054223023570 0ustar pbusernogroup00000000000000/* * Simple definitions common to client and server. * * 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 . * * Author: Daniel van Vugt */ #ifndef MIR_COMMON_H_ #define MIR_COMMON_H_ /** * \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 { mir_surface_attrib_type, mir_surface_attrib_state, mir_surface_attrib_swapinterval, mir_surface_attrib_focus, mir_surface_attribs } MirSurfaceAttrib; typedef enum MirSurfaceType { mir_surface_type_normal, mir_surface_type_utility, mir_surface_type_dialog, mir_surface_type_overlay, mir_surface_type_freestyle, mir_surface_type_popover, mir_surface_type_inputmethod, mir_surface_types } MirSurfaceType; 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_states } MirSurfaceState; typedef enum MirSurfaceFocusState { mir_surface_unfocused = 0, mir_surface_focused } MirSurfaceFocusState; 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; /** * The order of components in a format 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 corresponds to 0xAABBGGRR, which will * end up as R,G,B,A in memory in a little endian system, and * as A,B,G,R in memory in a big endian system. */ typedef enum MirPixelFormat { mir_pixel_format_invalid, mir_pixel_format_abgr_8888, mir_pixel_format_xbgr_8888, mir_pixel_format_argb_8888, mir_pixel_format_xrgb_8888, mir_pixel_format_bgr_888, mir_pixel_formats } 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 : 4) typedef enum MirOrientation { mir_orientation_normal = 0, mir_orientation_left = 90, mir_orientation_inverted = 180, mir_orientation_right = 270 } MirOrientation; /**@}*/ #endif mir-0.1.8+14.04.20140411/include/shared/mir_toolkit/mesa/0000755000015301777760000000000012322054703023051 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir_toolkit/mesa/native_display.h0000644000015301777760000000347612322054223026244 0ustar pbusernogroup00000000000000/* * 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 "mir_toolkit/mir_native_buffer.h" #include "mir_toolkit/client_types.h" #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; 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, MirSurfaceParameters* surface_parameters); }; typedef int (*MirMesaEGLNativeDisplayIsValidFunc)(MirMesaEGLNativeDisplay* display); #ifdef __cplusplus } // extern "C" /**@}*/ #endif #endif /* MIR_TOOLKIT_MESA_NATIVE_DISPLAY_H */ mir-0.1.8+14.04.20140411/include/shared/mir_toolkit/mir_native_buffer.h0000644000015301777760000000341112322054223025757 0ustar pbusernogroup00000000000000/* * 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 } 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_ */ mir-0.1.8+14.04.20140411/include/shared/testdraw/0000755000015301777760000000000012322054703021425 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/testdraw/draw_pattern_checkered-inl.h0000644000015301777760000000453412322054223027050 0ustar pbusernogroup00000000000000/* * 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/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; } mir-0.1.8+14.04.20140411/include/shared/testdraw/graphics_region_factory.h0000644000015301777760000000272312322054223026471 0ustar pbusernogroup00000000000000/* * 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_TEST_DRAW_GRAPHICS_REGION_FACTORY #define MIR_TEST_DRAW_GRAPHICS_REGION_FACTORY #include "mir/graphics/native_buffer.h" #include "mir_toolkit/mir_client_library.h" #include namespace mir { namespace test { namespace draw { class GraphicsRegionFactory { public: virtual ~GraphicsRegionFactory() {} virtual std::shared_ptr graphic_region_from_handle( graphics::NativeBuffer& native_buffer) = 0; protected: GraphicsRegionFactory() = default; GraphicsRegionFactory(GraphicsRegionFactory const&) = delete; GraphicsRegionFactory& operator=(GraphicsRegionFactory const&) = delete; }; std::shared_ptr create_graphics_region_factory(); } } } #endif /* MIR_TEST_DRAW_GRAPHICS_REGION_FACTORY */ mir-0.1.8+14.04.20140411/include/shared/testdraw/patterns.h0000644000015301777760000000412712322054223023437 0ustar pbusernogroup00000000000000/* * 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_TEST_DRAW_PATTERNS_H #define MIR_TEST_DRAW_PATTERNS_H #include "mir_toolkit/mir_client_library.h" #include #include /* todo: replace with color value types */ #include #include namespace mir { namespace test { namespace draw { 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 */ mir-0.1.8+14.04.20140411/include/shared/mir/0000755000015301777760000000000012322054703020357 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir/raii.h0000644000015301777760000000532412322054223021455 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/include/shared/mir/frontend/0000755000015301777760000000000012322054703022176 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir/frontend/client_constants.h0000644000015301777760000000224512322054223025721 0ustar pbusernogroup00000000000000/* * 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_FRONTEND_CLIENT_CONSTANTS_H_ #define MIR_FRONTEND_CLIENT_CONSTANTS_H_ namespace mir { namespace frontend { /// Number of buffers the client library will keep. /// mir::client::ClientBufferDepository and mir::frontend::ClientBufferTracker need to use the same value unsigned int const client_buffer_cache_size = 3; /// Buffers need to be big enough to support messages unsigned int const serialization_buffer_size = 2048; } } #endif mir-0.1.8+14.04.20140411/include/shared/mir/logging/0000755000015301777760000000000012322054703022005 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir/logging/dumb_console_logger.h0000644000015301777760000000207012322054223026162 0ustar pbusernogroup00000000000000/* * 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 Voß */ #ifndef MIR_LOGGING_DUMB_CONSOLE_LOGGER_H_ #define MIR_LOGGING_DUMB_CONSOLE_LOGGER_H_ #include "mir/logging/logger.h" namespace mir { namespace logging { class DumbConsoleLogger : public Logger { public: protected: void log(Severity severity, const std::string& message, const std::string& component) override; }; } } #endif // MIR_LOGGING_DUMB_CONSOLE_LOGGER_H_ mir-0.1.8+14.04.20140411/include/shared/mir/logging/logger.h0000644000015301777760000000266412322054223023442 0ustar pbusernogroup00000000000000/* * 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 Voß */ #ifndef MIR_LOGGING_LOGGER_H_ #define MIR_LOGGING_LOGGER_H_ #include namespace mir { namespace logging { // A facade to shield the inner core of mir to prevent an actual // logging framework from leaking implementation detail. class Logger { public: enum Severity { critical = 0, error = 1, warning = 2, informational = 3, debug = 4 }; virtual void log(Severity severity, const std::string& message, const std::string& component = "UnknownComponent") = 0; protected: Logger() {} virtual ~Logger() = default; Logger(const Logger&) = delete; Logger& operator=(const Logger&) = delete; }; } } #endif // MIR_LOGGING_LOGGER_H_ mir-0.1.8+14.04.20140411/include/shared/mir/logging/input_timestamp.h0000644000015301777760000000171512322054223025401 0ustar pbusernogroup00000000000000/* * 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_LOGGING_INPUT_TIMESTAMP_H_ #define MIR_LOGGING_INPUT_TIMESTAMP_H_ #include "mir_toolkit/event.h" #include namespace mir { namespace logging { std::string input_timestamp(nsecs_t when); } } #endif // MIR_LOGGING_INPUT_TIMESTAMP_H_ mir-0.1.8+14.04.20140411/include/shared/mir/geometry/0000755000015301777760000000000012322054703022212 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir/geometry/size.h0000644000015301777760000000271512322054223023337 0ustar pbusernogroup00000000000000/* * 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_SIZE_H_ #define MIR_GEOMETRY_SIZE_H_ #include "dimensions.h" #include namespace mir { namespace geometry { struct Size { Size() {} Size(Size const&) = default; Size& operator=(Size const&) = default; template Size(WidthType&& width, HeightType&& height) : width(width), height(height) {} Width width; Height height; }; inline bool operator == (Size const& lhs, Size const& rhs) { return lhs.width == rhs.width && lhs.height == rhs.height; } inline 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); } } #endif /* MIR_GEOMETRY_SIZE_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/geometry/forward.h0000644000015301777760000000171312322054223024026 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/include/shared/mir/geometry/length.h0000644000015301777760000000451412322054247023653 0ustar pbusernogroup00000000000000/* * 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: 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 }; Length() : magnitude(0) {} Length(Length const&) = default; Length& operator=(Length const&) = default; Length(float mag, Units units) : magnitude(mag * units) {} float as(Units units) const { return static_cast(magnitude) / units; } float as_pixels(float dpi) const { return as(inches) * dpi; } bool operator==(Length const& rhs) const { return magnitude == rhs.magnitude; } bool operator!=(Length const& rhs) const { return magnitude != rhs.magnitude; } private: float magnitude; }; inline Length operator"" _mm(long double mag) { return Length(mag, Length::millimetres); } inline Length operator"" _mm(unsigned long long mag) { return Length(mag, Length::millimetres); } inline Length operator"" _cm(long double mag) { return Length(mag, Length::centimetres); } inline Length operator"" _cm(unsigned long long mag) { return Length(mag, Length::centimetres); } inline Length operator"" _in(long double mag) { return Length(mag, Length::inches); } inline Length operator"" _in(unsigned long long mag) { return Length(mag, Length::inches); } } // namespace geometry } // namespace mir #endif // MIR_GEOMETRY_LENGTH_H_ mir-0.1.8+14.04.20140411/include/shared/mir/geometry/dimensions.h0000644000015301777760000001011212322054223024523 0ustar pbusernogroup00000000000000/* * 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_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 { enum DimensionTag { width, height, x, y, dx, dy, stride }; template class IntWrapper { public: typedef int ValueType; IntWrapper() : value(0) {} template explicit IntWrapper(AnyInteger value) : value(static_cast(value)) {} uint32_t as_uint32_t() const // TODO: Deprecate this later { return (uint32_t)value; } int as_int() const { return value; } float as_float() const { return value; } private: ValueType value; }; template std::ostream& operator<<(std::ostream& out, IntWrapper const& value) { out << value.as_int(); return out; } template inline bool operator == (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_int() == rhs.as_int(); } template inline bool operator != (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_int() != rhs.as_int(); } template inline bool operator <= (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_int() <= rhs.as_int(); } template inline bool operator >= (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_int() >= rhs.as_int(); } template inline bool operator < (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_int() < rhs.as_int(); } template inline 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 DeltaX operator+(DeltaX lhs, DeltaX rhs) { return DeltaX(lhs.as_int() + rhs.as_int()); } inline DeltaY operator+(DeltaY lhs, DeltaY rhs) { return DeltaY(lhs.as_int() + rhs.as_int()); } inline DeltaX operator-(DeltaX lhs, DeltaX rhs) { return DeltaX(lhs.as_int() - rhs.as_int()); } inline DeltaY operator-(DeltaY lhs, DeltaY rhs) { return DeltaY(lhs.as_int() - rhs.as_int()); } // Adding deltas to co-ordinates is fine inline X operator+(X lhs, DeltaX rhs) { return X(lhs.as_int() + rhs.as_int()); } inline Y operator+(Y lhs, DeltaY rhs) { return Y(lhs.as_int() + rhs.as_int()); } inline X operator-(X lhs, DeltaX rhs) { return X(lhs.as_int() - rhs.as_int()); } inline Y operator-(Y lhs, DeltaY rhs) { return Y(lhs.as_int() - rhs.as_int()); } // Subtracting coordinates is fine inline DeltaX operator-(X lhs, X rhs) { return DeltaX(lhs.as_int() - rhs.as_int()); } inline DeltaY operator-(Y lhs, Y rhs) { return DeltaY(lhs.as_int() - rhs.as_int()); } template inline Target dim_cast(Source s) { return Target(s.as_int()); } } } #endif /* MIR_GEOMETRY_DIMENSIONS_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/geometry/rectangle.h0000644000015301777760000000371412322054223024331 0ustar pbusernogroup00000000000000/* * 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 * Alexandros Frantzis */ #ifndef MIR_GEOMETRY_RECTANGLE_H_ #define MIR_GEOMETRY_RECTANGLE_H_ #include "point.h" #include "size.h" #include namespace mir { namespace geometry { struct Rectangle { 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; 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; }; inline bool operator == (Rectangle const& lhs, Rectangle const& rhs) { return lhs.top_left == rhs.top_left && lhs.size == rhs.size; } inline 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_ */ mir-0.1.8+14.04.20140411/include/shared/mir/geometry/displacement.h0000644000015301777760000000470512322054223025036 0ustar pbusernogroup00000000000000/* * 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_GEOMETRY_DISPLACEMENT_H_ #define MIR_GEOMETRY_DISPLACEMENT_H_ #include "dimensions.h" #include "point.h" #include namespace mir { namespace geometry { struct Displacement { Displacement() {} Displacement(Displacement const&) = default; Displacement& operator=(Displacement const&) = default; template Displacement(DeltaXType&& dx, DeltaYType&& dy) : dx{dx}, dy{dy} {} float length_squared() const { return dx.as_float() * dx.as_float() + dy.as_float() * dy.as_float(); } DeltaX dx; DeltaY dy; }; inline bool operator==(Displacement const& lhs, Displacement const& rhs) { return lhs.dx == rhs.dx && lhs.dy == rhs.dy; } inline 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 Displacement operator+(Displacement const& lhs, Displacement const& rhs) { return Displacement{lhs.dx + rhs.dx, lhs.dy + rhs.dy}; } inline Displacement operator-(Displacement const& lhs, Displacement const& rhs) { return Displacement{lhs.dx - rhs.dx, lhs.dy - rhs.dy}; } inline Point operator+(Point const& lhs, Displacement const& rhs) { return Point{lhs.x + rhs.dx, lhs.y + rhs.dy}; } inline Point operator-(Point const& lhs, Displacement const& rhs) { return Point{lhs.x - rhs.dx, lhs.y - rhs.dy}; } inline 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(); } } } #endif /* MIR_GEOMETRY_DISPLACEMENT_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/geometry/point.h0000644000015301777760000000262412322054223023515 0ustar pbusernogroup00000000000000/* * 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_GEOMETRY_POINT_H_ #define MIR_GEOMETRY_POINT_H_ #include "dimensions.h" #include namespace mir { namespace geometry { struct Point { Point() = default; Point(Point const&) = default; Point& operator=(Point const&) = default; template Point(XType&& x, YType&& y) : x(x), y(y) {} X x; Y y; }; inline bool operator == (Point const& lhs, Point const& rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } inline bool operator != (Point const& lhs, Point const& rhs) { return lhs.x != rhs.x || lhs.y != rhs.y; } std::ostream& operator<<(std::ostream& out, Point const& value); } } #endif /* MIR_GEOMETRY_POINT_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/geometry/rectangles.h0000644000015301777760000000332612322054223024513 0ustar pbusernogroup00000000000000/* * 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_GEOMETRY_RECTANGLES_H_ #define MIR_GEOMETRY_RECTANGLES_H_ #include "point.h" #include "rectangle.h" #include #include namespace mir { namespace geometry { class Rectangles { public: Rectangles(); Rectangles(std::initializer_list const& rects); /* We want to keep implicit copy and move methods */ void add(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_; }; std::ostream& operator<<(std::ostream& out, Rectangles const& value); } } #endif /* MIR_GEOMETRY_RECTANGLES_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/graphics/0000755000015301777760000000000012322054703022157 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir/graphics/android/0000755000015301777760000000000012322054703023577 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir/graphics/android/android_native_buffer.h0000644000015301777760000000361112322054223030265 0ustar pbusernogroup00000000000000/* * 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 { namespace android { class Fence; struct AndroidNativeBuffer : public graphics::NativeBuffer { AndroidNativeBuffer(std::shared_ptr const& handle, std::shared_ptr const& fence); ANativeWindowBuffer* anwb() const; buffer_handle_t handle() const; NativeFence copy_fence() const; void wait_for_content(); void update_fence(NativeFence& merge_fd); private: std::shared_ptr fence; 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_ */ mir-0.1.8+14.04.20140411/include/shared/mir/graphics/android/android_driver_interpreter.h0000644000015301777760000000312612322054223031365 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/android/native_buffer.h" #include #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 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_ */ mir-0.1.8+14.04.20140411/include/shared/mir/graphics/android/sync_fence.h0000644000015301777760000000330312322054223026060 0ustar pbusernogroup00000000000000/* * 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 "mir/graphics/android/fence.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: SyncFence(std::shared_ptr const&, int fd); ~SyncFence() noexcept; void wait(); void merge_with(NativeFence& merge_fd); NativeFence copy_native_handle() const; private: SyncFence(SyncFence const&) = delete; SyncFence& operator=(SyncFence const&) = delete; int fence_fd; std::shared_ptr const ops; int const infinite_timeout = -1; }; } } } #endif /* MIR_GRAPHICS_ANDROID_SYNC_FENCE_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/graphics/android/fence.h0000644000015301777760000000232512322054223025027 0ustar pbusernogroup00000000000000/* * 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_ namespace mir { namespace graphics { namespace android { typedef int NativeFence; class Fence { public: virtual ~Fence() = default; virtual void wait() = 0; virtual void merge_with(NativeFence& merge_fd) = 0; virtual NativeFence copy_native_handle() const = 0; protected: Fence() = default; Fence(Fence const&) = delete; Fence& operator=(Fence const&) = delete; }; } } } #endif /* MIR_GRAPHICS_ANDROID_FENCE_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/graphics/android/native_buffer.h0000644000015301777760000000262512322054223026571 0ustar pbusernogroup00000000000000/* * 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 "fence.h" #include namespace mir { namespace graphics { class 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 void wait_for_content() = 0; virtual void update_fence(android::NativeFence& fence) = 0; protected: NativeBuffer() = default; NativeBuffer(NativeBuffer const&) = delete; NativeBuffer& operator=(NativeBuffer const&) = delete; }; } } #endif /* MIR_GRAPHICS_ANDROID_NATIVE_BUFFER_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/graphics/android/mir_native_window.h0000644000015301777760000000317512322054223027477 0ustar pbusernogroup00000000000000/* * 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 namespace mir { namespace graphics { namespace android { class AndroidDriverInterpreter; class MirNativeWindow : public ANativeWindow { public: explicit MirNativeWindow(std::shared_ptr const& interpreter); 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 cancelBuffer(struct ANativeWindowBuffer* buffer, int fence); int setSwapInterval(int interval); private: std::shared_ptr const driver_interpreter; }; } } } #endif /* MIR_GRAPHICS_ANDROID_MIR_NATIVE_WINDOW_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/graphics/native_buffer.h0000644000015301777760000000203512322054223025144 0ustar pbusernogroup00000000000000/* * 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_ #ifndef ANDROID #include #endif namespace mir { namespace graphics { #ifdef ANDROID //just a fwd dcl class NativeBuffer; #else typedef struct MirBufferPackage NativeBuffer; #endif } } #endif /* MIR_GRAPHICS_NATIVE_BUFFER_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/default_configuration.h0000644000015301777760000000163212322054223025102 0ustar pbusernogroup00000000000000/* * Private internal defaults shared by client and server code. * * 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 . * * Author: Daniel van Vugt */ #ifndef MIR_DEFAULT_CONFIGURATION_ #define MIR_DEFAULT_CONFIGURATION_ namespace mir { extern const char *const default_server_socket; } #endif mir-0.1.8+14.04.20140411/include/shared/mir/report/0000755000015301777760000000000012322054703021672 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir/report/lttng/0000755000015301777760000000000012322054703023022 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir/report/lttng/mir_tracepoint.h0000644000015301777760000000271612322054223026215 0ustar pbusernogroup00000000000000/* * 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_LTTNG_MIR_TRACEPOINT_H_ #define MIR_LTTNG_MIR_TRACEPOINT_H_ /* * The STAP_PROBEV() macro from sdt.h (SystemTap) used by * the tracepoint() macro from lttng/tracepoint.h fails to * build with clang at the moment. Disable tracepoints * when building with clang until this is resolved. * * See: http://sourceware.org/bugzilla/show_bug.cgi?id=13974 */ #ifdef __clang__ namespace mir_systemtap_bug_13974 { inline void mir_tracepoint_consume_args(int, ...) {} } #define mir_tracepoint(c, e, ...) ::mir_systemtap_bug_13974::mir_tracepoint_consume_args(0, __VA_ARGS__) #pragma message "Building with clang: Disabling LTTng tracepoints." #else #define mir_tracepoint(c, ...) tracepoint(c, __VA_ARGS__) #endif #endif /* MIR_LTTNG_MIR_TRACEPOINT_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/report/lttng/tracepoint_provider.h0000644000015301777760000000232712322054223027256 0ustar pbusernogroup00000000000000/* * 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_REPORT_LTTNG_TRACEPOINT_PROVIDER_H_ #define MIR_REPORT_LTTNG_TRACEPOINT_PROVIDER_H_ #include namespace mir { namespace report { namespace lttng { class TracepointProvider { public: TracepointProvider(std::string const& lib_name); ~TracepointProvider() noexcept; private: TracepointProvider(TracepointProvider const&) = delete; TracepointProvider& operator=(TracepointProvider const&) = delete; void* lib; }; } } } #endif /* MIR_REPORT_LTTNG_TRACEPOINT_PROVIDER_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/protobuf/0000755000015301777760000000000012322054703022217 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir/protobuf/google_protobuf_guard.h0000644000015301777760000000237012322054223026745 0ustar pbusernogroup00000000000000/* * 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_PROTOBUF_GOOGLE_PROTOBUF_GUARD_H_ #define MIR_PROTOBUF_GOOGLE_PROTOBUF_GUARD_H_ namespace mir { /// subsystem dealing with Google protobuf protocol. namespace protobuf { void google_protobuf_guard(); } } // Any translation unit that includes this header will get this as part // of its initialization, and, in turn, this ensures that protobuf gets // initialized (and cleaned up) in a sensible sequence. namespace { bool force_google_protobuf_init{(mir::protobuf::google_protobuf_guard(), true)}; } #endif /* MIR_PROTOBUF_GOOGLE_PROTOBUF_GUARD_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/raii/0000755000015301777760000000000012322054703021303 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir/shared_library.h0000644000015301777760000000311012322054223023512 0ustar pbusernogroup00000000000000/* * 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(); 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()); } private: void* const so; void* load_symbol(char const* function_name) const; SharedLibrary(SharedLibrary const&) = delete; SharedLibrary& operator=(SharedLibrary const&) = delete; }; } #endif /* MIR_SHARED_LIBRARY_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/input/0000755000015301777760000000000012322054703021516 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir/input/android/0000755000015301777760000000000012322054703023136 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/shared/mir/input/android/android_input_lexicon.h0000644000015301777760000000242712322054223027671 0ustar pbusernogroup00000000000000/* * 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: Robert Carr * Daniel d'Andradra */ #ifndef MIR_INPUT_ANDROID_INPUT_LEXICON_H_ #define MIR_INPUT_ANDROID_INPUT_LEXICON_H_ #include "mir_toolkit/event.h" namespace android { class InputEvent; } namespace droidinput = android; namespace mir { namespace input { namespace android { /// The Lexicon translates droidinput event types to MirEvent types prior to /// shell or client handling. class Lexicon { public: static void translate(const droidinput::InputEvent *android_event, MirEvent &mir_event); }; } } } #endif // MIR_INPUT_ANDROID_INPUT_LEXICON_H_ mir-0.1.8+14.04.20140411/include/shared/mir/input/input_receiver_report.h0000644000015301777760000000237012322054223026304 0ustar pbusernogroup00000000000000/* * 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_INPUT_RECEIVER_REPORT_H_ #define MIR_CLIENT_INPUT_RECEIVER_REPORT_H_ #include namespace mir { namespace input { namespace receiver { class InputReceiverReport { public: virtual ~InputReceiverReport() = default; virtual void received_event(MirEvent const& event) = 0; protected: InputReceiverReport() = default; InputReceiverReport(InputReceiverReport const&) = delete; InputReceiverReport& operator=(InputReceiverReport const&) = delete; }; } } } #endif /* MIR_CLIENT_INPUT_RECEIVER_REPORT_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/input/input_platform.h0000644000015301777760000000311212322054223024724 0ustar pbusernogroup00000000000000/* * 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_INPUT_RECEIVER_PLATFORM_H_ #define MIR_INPUT_RECEIVER_PLATFORM_H_ #include "mir_toolkit/event.h" #include #include namespace mir { namespace input { namespace receiver { class InputReceiverThread; class InputReceiverReport; // Interface for MirSurface to construct input dispatcher threads. class InputPlatform { public: virtual ~InputPlatform() {}; virtual std::shared_ptr create_input_thread(int fd, std::function const& callback) = 0; static std::shared_ptr create(); static std::shared_ptr create(std::shared_ptr const& report); protected: InputPlatform() = default; InputPlatform(const InputPlatform&) = delete; InputPlatform& operator=(const InputPlatform&) = delete; }; } } } // namespace mir #endif // MIR_INPUT_RECEIVER_PLATFORM_H_ mir-0.1.8+14.04.20140411/include/shared/mir/input/null_input_receiver_report.h0000644000015301777760000000230712322054223027336 0ustar pbusernogroup00000000000000/* * 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_NULL_INPUT_RECEIVER_REPORT_H_ #define MIR_CLIENT_NULL_INPUT_RECEIVER_REPORT_H_ #include "mir/input/input_receiver_report.h" #include namespace mir { namespace input { namespace receiver { class NullInputReceiverReport : public InputReceiverReport { public: NullInputReceiverReport() = default; virtual ~NullInputReceiverReport() = default; void received_event(MirEvent const& /* event */) {} }; } } } #endif /* MIR_CLIENT_NULL_INPUT_RECEIVER_REPORT_H_ */ mir-0.1.8+14.04.20140411/include/shared/mir/input/xkb_mapper.h0000644000015301777760000000251712322054223024021 0ustar pbusernogroup00000000000000/* * 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_INPUT_RECEIVER_XKB_MAPPER_H_ #define MIR_INPUT_RECEIVER_XKB_MAPPER_H_ #include "mir_toolkit/event.h" #include #include namespace mir { namespace input { namespace receiver { class XKBMapper { public: XKBMapper(); virtual ~XKBMapper() = default; void update_state_and_map_event(MirKeyEvent& key_ev); protected: XKBMapper(XKBMapper const&) = delete; XKBMapper& operator=(XKBMapper const&) = delete; private: std::shared_ptr context; std::shared_ptr map; std::shared_ptr state; }; } } } #endif // MIR_INPUT_RECEIVER_XKB_MAPPER_H_ mir-0.1.8+14.04.20140411/include/shared/mir/input/input_receiver_thread.h0000644000015301777760000000240112322054223026233 0ustar pbusernogroup00000000000000/* * 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_INPUT_RECEIVER_RECEIVER_THREAD_H_ #define MIR_INPUT_RECEIVER_RECEIVER_THREAD_H_ namespace mir { namespace input { namespace receiver { class InputReceiverThread { public: virtual ~InputReceiverThread() {}; virtual void start() = 0; virtual void stop() = 0; virtual void join() = 0; protected: InputReceiverThread() = default; InputReceiverThread(const InputReceiverThread&) = delete; InputReceiverThread& operator=(const InputReceiverThread&) = delete; }; } } } // namespace mir #endif // MIR_INPUT_RECEIVER_RECEIVER_THREAD_H_ mir-0.1.8+14.04.20140411/include/shared/mir/int_wrapper.h0000644000015301777760000000472012322054223023062 0ustar pbusernogroup00000000000000/* * 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: Alan Griffiths */ #ifndef MIR_INT_WRAPPER_H_ #define MIR_INT_WRAPPER_H_ #include namespace mir { template class IntWrapper { public: IntWrapper() : value(0) {} explicit IntWrapper(ValueType value) : value(value) {} ValueType 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 bool operator == (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_value() == rhs.as_value(); } template inline bool operator != (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_value() != rhs.as_value(); } template inline bool operator <= (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_value() <= rhs.as_value(); } template inline bool operator >= (IntWrapper const& lhs, IntWrapper const& rhs) { return lhs.as_value() >= rhs.as_value(); } template inline 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; std::size_t operator()(::mir::IntWrapper const& id) const { return self(id.as_value()); } }; } #endif // MIR_INT_WRAPPER_H_ mir-0.1.8+14.04.20140411/include/shared/mir/cached_ptr.h0000644000015301777760000000243412322054223022624 0ustar pbusernogroup00000000000000/* * 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_ mir-0.1.8+14.04.20140411/include/platform/0000755000015301777760000000000012322054703020146 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/platform/mir/0000755000015301777760000000000012322054703020735 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/platform/mir/udev/0000755000015301777760000000000012322054703021700 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/platform/mir/udev/wrapper.h0000644000015301777760000000675412322054223023542 0ustar pbusernogroup00000000000000/* * 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 #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; 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_ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/0000755000015301777760000000000012322054703022535 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/platform/mir/graphics/egl_resources.h0000644000015301777760000000355612322054223025555 0ustar pbusernogroup00000000000000/* * 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_EGL_RESOURCES_H_ #define MIR_GRAPHICS_EGL_RESOURCES_H_ #include namespace mir { namespace graphics { class EGLContextStore { public: EGLContextStore(EGLDisplay egl_display, EGLContext egl_context); EGLContextStore(EGLContextStore&&); ~EGLContextStore() noexcept; operator EGLContext() const; private: EGLContextStore(EGLContextStore const&) = delete; EGLContextStore& operator=(EGLContextStore const&) = delete; EGLDisplay egl_display_; EGLContext egl_context_; }; class EGLSurfaceStore { public: enum AllowNoSurface { DisallowNoSurface, AllowNoSurface }; EGLSurfaceStore(EGLDisplay egl_display, EGLSurface egl_surface, enum AllowNoSurface allow_no_surface); EGLSurfaceStore(EGLDisplay egl_display, EGLSurface egl_surface); EGLSurfaceStore(EGLSurfaceStore&&); ~EGLSurfaceStore() noexcept; operator EGLSurface() const; private: EGLSurfaceStore(EGLSurfaceStore const&) = delete; EGLSurfaceStore& operator=(EGLSurfaceStore const&) = delete; EGLDisplay egl_display_; EGLSurface egl_surface_; }; } } #endif /* MIR_GRAPHICS_EGL_RESOURCES_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/pixel_format_utils.h0000644000015301777760000000253512322054223026621 0ustar pbusernogroup00000000000000/* * 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: Andreas Pokorny */ #ifndef MIR_GRAPHICS_PIXEL_FORMAT_UTILS_H_ #define MIR_GRAPHICS_PIXEL_FORMAT_UTILS_H_ #include "mir_toolkit/common.h" namespace mir { namespace graphics { /*! * \name MirPixelFormat utility functions * * A set of functions to query details of MirPixelFormat * TODO improve this through https://bugs.launchpad.net/mir/+bug/1236254 * \{ */ bool contains_alpha(MirPixelFormat format); int red_channel_depth(MirPixelFormat format); int blue_channel_depth(MirPixelFormat format); int green_channel_depth(MirPixelFormat format); int alpha_channel_depth(MirPixelFormat format); bool valid_pixel_format(MirPixelFormat format); /*! * \} */ } } #endif mir-0.1.8+14.04.20140411/include/platform/mir/graphics/native_platform.h0000644000015301777760000000403112322054223026073 0ustar pbusernogroup00000000000000/* * 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 */ #ifndef MIR_GRAPHICS_NATIVE_PLATFORM_H_ #define MIR_GRAPHICS_NATIVE_PLATFORM_H_ #include #include namespace mir { namespace options { class Option; } namespace graphics { class GraphicBufferAllocator; class BufferInitializer; class PlatformIPCPackage; class InternalClient; class BufferIPCPacker; class Buffer; class DisplayReport; class NestedContext; class NativePlatform { public: NativePlatform() {} virtual void initialize(std::shared_ptr const& nested_context) = 0; virtual std::shared_ptr create_buffer_allocator( std::shared_ptr const& buffer_initializer) = 0; virtual std::shared_ptr get_ipc_package() = 0; virtual std::shared_ptr create_internal_client() = 0; virtual void fill_ipc_package(BufferIPCPacker* packer, Buffer const* buffer) const = 0; virtual ~NativePlatform() = default; NativePlatform(NativePlatform const&) = delete; NativePlatform& operator=(NativePlatform const&) = delete; }; extern "C" typedef std::shared_ptr(*CreateNativePlatform)(std::shared_ptr const& report); extern "C" std::shared_ptr create_native_platform(std::shared_ptr const& report); } } #endif // MIR_GRAPHICS_NATIVE_PLATFORM_H_ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/buffer_initializer.h0000644000015301777760000000262212322054223026561 0ustar pbusernogroup00000000000000/* * 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_INITIALIZER_H_ #define MIR_GRAPHICS_BUFFER_INITIALIZER_H_ namespace mir { namespace graphics { class Buffer; /** * Interface to buffer initialization. */ class BufferInitializer { public: virtual ~BufferInitializer() {} /** Operator to call to initialize a buffer. */ virtual void operator()(Buffer& buffer) = 0; protected: BufferInitializer() = default; BufferInitializer(const BufferInitializer&) = delete; BufferInitializer& operator=(const BufferInitializer&) = delete; }; class NullBufferInitializer : public BufferInitializer { public: void operator()(Buffer& /*buffer*/) {} }; } } #endif /* MIR_GRAPHICS_BUFFER_INITIALIZER_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/nested_context.h0000644000015301777760000000245612322054223025740 0ustar pbusernogroup00000000000000/* * 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_NESTED_CONTEXT_H_ #define MIR_GRAPHICS_NESTED_CONTEXT_H_ #include struct gbm_device; namespace mir { namespace graphics { class NestedContext { public: virtual ~NestedContext() = default; virtual std::vector platform_fd_items() = 0; virtual void drm_auth_magic(int magic) = 0; virtual void drm_set_gbm_device(struct gbm_device* dev) = 0; protected: NestedContext() = default; NestedContext(NestedContext const&) = delete; NestedContext& operator=(NestedContext const&) = delete; }; } } #endif /* MIR_GRAPHICS_NESTED_CONTEXT_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/renderable.h0000644000015301777760000000643612322054247025025 0ustar pbusernogroup00000000000000/* * 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: /** * Return the next buffer that should be composited/rendered. * * \param [in] user_id An arbitrary unique identifier used to distinguish * separate threads/monitors/components which need * to concurrently receive the same buffer. Calling * with the same user_id will return a new (different) * buffer to that user each time. For consistency, * all callers need to determine their user_id in the * same way (e.g. always use "this" pointer). */ virtual std::shared_ptr buffer(void const* user_id) const = 0; virtual bool alpha_enabled() 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; /** * TODO: Its a bit questionable that we have this member function, why not * just trim the renderable from the RenderableList? Its convenient * to have this function temporarily while refactoring --kdub */ virtual bool visible() const = 0; virtual bool shaped() const = 0; // meaning the pixel format has alpha virtual int buffers_ready_for_compositor() const = 0; protected: Renderable() = default; virtual ~Renderable() = default; Renderable(Renderable const&) = delete; Renderable& operator=(Renderable const&) = delete; }; // XXX Would performance be better with a vector? typedef std::list> RenderableList; } } #endif /* MIR_GRAPHICS_RENDERABLE_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/buffer.h0000644000015301777760000000261312322054223024156 0ustar pbusernogroup00000000000000/* * 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_COMPOSITOR_BUFFER_H_ #define MIR_COMPOSITOR_BUFFER_H_ #include "mir/graphics/native_buffer.h" #include "mir/geometry/size.h" #include "mir_toolkit/common.h" #include namespace mir { namespace graphics { class BufferID; 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 geometry::Stride stride() const = 0; virtual MirPixelFormat pixel_format() const = 0; virtual void bind_to_texture() = 0; virtual bool can_bypass() const = 0; protected: Buffer() = default; }; } } #endif // MIR_COMPOSITOR_BUFFER_H_ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/buffer_properties.h0000644000015301777760000000405612322054223026435 0ustar pbusernogroup00000000000000/* * 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_ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/buffer_id.h0000644000015301777760000000301312322054223024625 0ustar pbusernogroup00000000000000/* * 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_ID_H_ #define MIR_GRAPHICS_BUFFER_ID_H_ #include namespace mir { namespace graphics { class BufferID { public: BufferID() : value(id_invalid){} explicit BufferID(uint32_t val) : value(val) {} bool is_valid() const { return (id_invalid != value); } uint32_t as_uint32_t() const { return value; }; private: uint32_t value; static const uint32_t id_invalid = 0; }; inline bool operator < (BufferID const& lhs, BufferID const& rhs) { return lhs.as_uint32_t() < rhs.as_uint32_t(); } inline bool operator == (BufferID const& lhs, BufferID const& rhs) { return lhs.as_uint32_t() == rhs.as_uint32_t(); } inline bool operator != (BufferID const& lhs, BufferID const& rhs) { return lhs.as_uint32_t() != rhs.as_uint32_t(); } } } #endif /* MIR_GRAPHICS_BUFFER_ID_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/display_configuration.h0000644000015301777760000001344412322054223027305 0ustar pbusernogroup00000000000000/* * 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/pixel_format_utils.h" #include "mir_toolkit/common.h" #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, vga, dvii, dvid, dvia, composite, svideo, lvds, component, ninepindin, displayport, hdmia, hdmib, tv, edp }; /** * 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. */ size_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. */ size_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; /** 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; size_t const& preferred_mode_index; geometry::Size const& physical_size_mm; bool const& connected; bool& used; geometry::Point& top_left; size_t& current_mode_index; MirPixelFormat& current_format; MirPowerMode& power_mode; MirOrientation& orientation; UserDisplayConfigurationOutput(DisplayConfigurationOutput& master); }; 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() {} /** 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 bool valid() const; protected: DisplayConfiguration() = default; DisplayConfiguration(DisplayConfiguration const& c) = delete; DisplayConfiguration& operator=(DisplayConfiguration const& c) = delete; }; } } #endif /* MIR_GRAPHICS_DISPLAY_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/display_report.h0000644000015301777760000000360112322054223025743 0ustar pbusernogroup00000000000000/* * 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_REPORT_H_ #define MIR_GRAPHICS_DISPLAY_REPORT_H_ #include namespace mir { namespace graphics { class DisplayReport { public: virtual void report_successful_setup_of_native_resources() = 0; virtual void report_successful_egl_make_current_on_construction() = 0; virtual void report_successful_egl_buffer_swap_on_construction() = 0; virtual void report_successful_display_construction() = 0; virtual void report_egl_configuration(EGLDisplay disp, EGLConfig cfg) = 0; /* gbm specific */ virtual void report_successful_drm_mode_set_crtc_on_construction() = 0; virtual void report_drm_master_failure(int error) = 0; virtual void report_vt_switch_away_failure() = 0; virtual void report_vt_switch_back_failure() = 0; /* android specific */ virtual void report_hwc_composition_in_use(int major, int minor) = 0; virtual void report_gpu_composition_in_use() = 0; protected: DisplayReport() = default; virtual ~DisplayReport() { /* TODO: make nothrow */ } DisplayReport(const DisplayReport&) = delete; DisplayReport& operator=(const DisplayReport&) = delete; }; } } #endif /* MIR_GRAPHICS_DISPLAY_REPORT_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/event_handler_register.h0000644000015301777760000000273212322054223027431 0ustar pbusernogroup00000000000000/* * 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 namespace mir { namespace graphics { class EventHandlerRegister { public: virtual void register_signal_handler( std::initializer_list signals, std::function const& handler) = 0; virtual void register_fd_handler( std::initializer_list fds, std::function const& handler) = 0; protected: EventHandlerRegister() = default; virtual ~EventHandlerRegister() = default; EventHandlerRegister(EventHandlerRegister const&) = delete; EventHandlerRegister& operator=(EventHandlerRegister const&) = delete; }; } } #endif /* MIR_GRAPHICS_EVENT_HANDLER_REGISTER_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/internal_surface.h0000644000015301777760000000254012322054223026230 0ustar pbusernogroup00000000000000/* * 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_INTERNAL_SURFACE_H_ #define MIR_GRAPHICS_INTERNAL_SURFACE_H_ #include "mir/geometry/size.h" #include "mir_toolkit/client_types.h" #include namespace mir { namespace graphics { class Buffer; class InternalSurface { public: virtual ~InternalSurface() = default; virtual void swap_buffers(graphics::Buffer*&) = 0; virtual geometry::Size size() const = 0; virtual MirPixelFormat pixel_format() const = 0; protected: InternalSurface() = default; InternalSurface(InternalSurface const&) = delete; InternalSurface& operator=(InternalSurface const&) = delete; }; } } #endif /* MIR_GRAPHICS_INTERNAL_SURFACE_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/overlapping_output_grouping.h0000644000015301777760000000370412322054223030567 0ustar pbusernogroup00000000000000/* * 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_OVERLAPPING_OUTPUT_GROUPING_H_ #define MIR_GRAPHICS_OVERLAPPING_OUTPUT_GROUPING_H_ #include #include namespace mir { namespace geometry { struct Rectangle; } namespace graphics { class DisplayConfiguration; struct DisplayConfigurationOutput; class OverlappingOutputGroup { public: template OverlappingOutputGroup(Iterator begin, Iterator end) : outputs(begin, end) {} OverlappingOutputGroup(OverlappingOutputGroup const&) = default; OverlappingOutputGroup& operator=(OverlappingOutputGroup const&) = default; geometry::Rectangle bounding_rectangle() const; void for_each_output(std::function const& f) const; private: std::vector outputs; }; /** Helper class that groups overlapping outputs together. */ class OverlappingOutputGrouping { public: OverlappingOutputGrouping(DisplayConfiguration const& conf); void for_each_group(std::function const& f); private: void add_output(DisplayConfigurationOutput const& conf_output); std::vector groups; }; } } #endif /* MIR_GRAPHICS_OVERLAPPING_OUTPUT_GROUPING_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/cursor.h0000644000015301777760000000230612322054223024221 0ustar pbusernogroup00000000000000/* * 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" namespace mir { namespace graphics { class Cursor { public: virtual void set_image(void const* raw_argb, geometry::Size size) = 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_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/internal_client.h0000644000015301777760000000303012322054223026051 0ustar pbusernogroup00000000000000/* * 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_INTERNAL_CLIENT_H_ #define MIR_GRAPHICS_INTERNAL_CLIENT_H_ #include #include namespace mir { namespace graphics { class InternalSurface; /** * Interface to in-process client support. */ class InternalClient { public: /** * The EGL native display to be used by in-process clients. */ virtual EGLNativeDisplayType egl_native_display() = 0; /** * The EGL native window to be used by in-process clients for a surface. */ virtual EGLNativeWindowType egl_native_window(std::shared_ptr const&) = 0; protected: InternalClient() = default; virtual ~InternalClient() = default; InternalClient(InternalClient const&) = delete; InternalClient& operator=(InternalClient const&) = delete; }; } } #endif /* MIR_GRAPHICS_INTERNAL_CLIENT_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/buffer_ipc_packer.h0000644000015301777760000000261512322054223026340 0ustar pbusernogroup00000000000000/* * 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_BUFFER_IPC_PACKER_H_ #define MIR_GRAPHICS_BUFFER_IPC_PACKER_H_ #include "mir/geometry/dimensions.h" #include "mir/geometry/size.h" namespace mir { namespace graphics { class BufferIPCPacker { public: virtual ~BufferIPCPacker() = default; virtual void pack_fd(int) = 0; virtual void pack_data(int) = 0; virtual void pack_stride(geometry::Stride) = 0; virtual void pack_flags(unsigned int) = 0; virtual void pack_size(geometry::Size const& size) = 0; protected: BufferIPCPacker() {} BufferIPCPacker(BufferIPCPacker const&) = delete; BufferIPCPacker& operator=(BufferIPCPacker const&) = delete; }; } } #endif /* MIR_GRAPHICS_BUFFER_IPC_PACKER_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/display_configuration_policy.h0000644000015301777760000000247712322054223030670 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/graphic_buffer_allocator.h0000644000015301777760000000326312322054223027715 0ustar pbusernogroup00000000000000/* * 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. * * \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. */ virtual std::vector supported_pixel_formats() = 0; protected: GraphicBufferAllocator() = default; GraphicBufferAllocator(const GraphicBufferAllocator&) = delete; GraphicBufferAllocator& operator=(const GraphicBufferAllocator&) = delete; }; } } #endif // MIR_GRAPHICS_GRAPHIC_BUFFER_ALLOCATOR_H_ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/gl_config.h0000644000015301777760000000260112322054247024637 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/platform.h0000644000015301777760000000776112322054247024550 0ustar pbusernogroup00000000000000/* * 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 "basic_platform.h" #include #include namespace mir { namespace frontend { class Surface; } namespace options { class Option; } /// Graphics subsystem. Mediates interaction between core system and /// the graphics environment. namespace graphics { class BufferIPCPacker; class Buffer; class Display; struct PlatformIPCPackage; class BufferInitializer; class InternalClient; class DisplayReport; class DisplayConfigurationPolicy; class GraphicBufferAllocator; class GLConfig; /** * \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 BasicPlatform { public: Platform() = default; Platform(const Platform& p) = delete; Platform& operator=(const Platform& p) = delete; virtual ~Platform() { /* TODO: make nothrow */ } /** * Creates the buffer allocator subsystem. * * \param [in] buffer_initializer the object responsible for initializing the buffers */ virtual std::shared_ptr create_buffer_allocator( std::shared_ptr const& buffer_initializer) = 0; /** * Creates the display subsystem. */ virtual std::shared_ptr create_display( std::shared_ptr const& initial_conf_policy, std::shared_ptr const& gl_config) = 0; /** * Gets the IPC package for the platform. * * The IPC package will be sent to clients when they connect. */ virtual std::shared_ptr get_ipc_package() = 0; /** * Fills the IPC package for a buffer. * * The Buffer IPC package will be sent to clients when receiving a buffer. * The implementation must use the provided packer object to perform the packing. * * \param [in] packer the object providing the packing functionality * \param [in] buffer the buffer to fill the IPC package for */ virtual void fill_ipc_package(BufferIPCPacker* packer, Buffer const* buffer) const = 0; /** * Creates the in-process client support object. */ virtual std::shared_ptr create_internal_client() = 0; }; /** * Function prototype used to return a new graphics platform. * * \param [in] options options to use for this 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 */ extern "C" typedef std::shared_ptr(*CreatePlatform)(std::shared_ptr const& options, std::shared_ptr const& report); extern "C" std::shared_ptr create_platform (std::shared_ptr const& options, std::shared_ptr const& report); extern "C" typedef void(*AddPlatformOptions)( boost::program_options::options_description& config); extern "C" void add_platform_options( boost::program_options::options_description& config); } } #endif // MIR_GRAPHICS_PLATFORM_H_ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/display_buffer.h0000644000015301777760000000564012322054247025714 0ustar pbusernogroup00000000000000/* * 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 #include namespace mir { namespace graphics { class Buffer; /** * Interface to an output framebuffer. */ class DisplayBuffer { public: virtual ~DisplayBuffer() {} /** The area the DisplayBuffer occupies in the virtual screen space. */ virtual geometry::Rectangle view_area() const = 0; /** Makes the DisplayBuffer the current GL rendering target. */ virtual void make_current() = 0; /** Releases the current GL rendering target. */ virtual void release_current() = 0; /** This will trigger OpenGL rendering and post the result to the screen. */ virtual void post_update() = 0; /** This will render renderlist to the screen and post the result to the screen. For each renderable, the DisplayBuffer will decide if its more efficient to render that Renderable via OpenGL, or via another method. If the Renderable is to be rendered via OpenGL, render_fn will be invoked on that Renderable. */ virtual void render_and_post_update( RenderableList const& renderlist, std::function const& render_fn) = 0; /** to be deprecated */ virtual bool can_bypass() const = 0; virtual void post_update(std::shared_ptr /* bypass_buf */) {} /** 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; protected: DisplayBuffer() = default; DisplayBuffer(DisplayBuffer const& c) = delete; DisplayBuffer& operator=(DisplayBuffer const& c) = delete; }; } } #endif /* MIR_GRAPHICS_DISPLAY_BUFFER_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/platform_ipc_package.h0000644000015301777760000000217512322054223027042 0ustar pbusernogroup00000000000000/* * 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 { namespace graphics { /** * Platform data to be sent to the clients over IPC. */ struct PlatformIPCPackage { virtual ~PlatformIPCPackage() {} std::vector ipc_data; std::vector ipc_fds; }; } } #endif /* MIR_GRAPHICS_PLATFORM_IPC_PACKAGE_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/gl_context.h0000644000015301777760000000222112322054223025046 0ustar pbusernogroup00000000000000/* * 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_GL_CONTEXT_H_ #define MIR_GRAPHICS_GL_CONTEXT_H_ namespace mir { namespace graphics { class GLContext { public: virtual ~GLContext() = default; virtual void make_current() const = 0; virtual void release_current() const = 0; protected: GLContext() = default; GLContext(GLContext const&) = delete; GLContext& operator=(GLContext const&) = delete; }; } } #endif /* MIR_GRAPHICS_GL_CONTEXT_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/drm_authenticator.h0000644000015301777760000000225712322054223026425 0ustar pbusernogroup00000000000000/* * 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_DRM_AUTHENTICATOR_H_ #define MIR_GRAPHICS_DRM_AUTHENTICATOR_H_ namespace mir { namespace graphics { class DRMAuthenticator { public: virtual ~DRMAuthenticator() {} virtual void drm_auth_magic(unsigned int magic) = 0; protected: DRMAuthenticator() = default; DRMAuthenticator(const DRMAuthenticator&) = delete; DRMAuthenticator& operator=(const DRMAuthenticator&) = delete; }; } } #endif /* MIR_GRAPHICS_DRM_AUTHENTICATOR_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/display.h0000644000015301777760000000702612322054223024355 0ustar pbusernogroup00000000000000/* * 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 #include namespace mir { namespace graphics { class DisplayBuffer; class DisplayConfiguration; class Cursor; class GLContext; class EventHandlerRegister; typedef std::function DisplayPauseHandler; typedef std::function DisplayResumeHandler; typedef std::function DisplayConfigurationChangeHandler; /** * Interface to the display subsystem. */ class Display { public: /** * Executes a functor for each output framebuffer. */ virtual void for_each_display_buffer(std::function const& f) = 0; /** * Gets a copy of the current output configuration. */ virtual std::unique_ptr configuration() const = 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; /** * Gets the hardware cursor object. */ virtual std::weak_ptr the_cursor() = 0; /** * Creates a GLContext object that shares resources with the Display's GL context. * * This is usually implemented as a shared EGL context. This object can be used * to access graphics resources from an arbitrary thread. */ virtual std::unique_ptr create_gl_context() = 0; protected: Display() = default; virtual ~Display() {/* TODO: make nothrow */} private: Display(Display const&) = delete; Display& operator=(Display const&) = delete; }; } } #endif /* MIR_GRAPHICS_DISPLAY_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/egl_extensions.h0000644000015301777760000000240112322054223025726 0ustar pbusernogroup00000000000000/* * 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 . * * Christopher James Halse Rogers */ #ifndef MIR_GRAPHICS_EGL_EXTENSIONS_H_ #define MIR_GRAPHICS_EGL_EXTENSIONS_H_ #define GL_GLEXT_PROTOTYPES #define EGL_EGLEXT_PROTOTYPES #include #include #include #include namespace mir { namespace graphics { struct EGLExtensions { EGLExtensions(); PFNEGLCREATEIMAGEKHRPROC const eglCreateImageKHR; PFNEGLDESTROYIMAGEKHRPROC const eglDestroyImageKHR; PFNGLEGLIMAGETARGETTEXTURE2DOESPROC const glEGLImageTargetTexture2DOES; }; } } #endif /* MIR_GRAPHICS_EGL_EXTENSIONS_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/buffer_basic.h0000644000015301777760000000214012322054223025312 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/include/platform/mir/graphics/basic_platform.h0000644000015301777760000000226712322054223025677 0ustar pbusernogroup00000000000000/* * 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_BASIC_PLATFORM_H_ #define MIR_GRAPHICS_BASIC_PLATFORM_H_ #include namespace mir { namespace graphics { class BasicPlatform { public: virtual ~BasicPlatform() = default; virtual EGLNativeDisplayType egl_native_display() const = 0; protected: BasicPlatform() = default; BasicPlatform(BasicPlatform const&) = delete; BasicPlatform& operator=(BasicPlatform const&) = delete; }; } } #endif /* MIR_GRAPHICS_BASIC_PLATFORM_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/abnormal_exit.h0000644000015301777760000000173712322054223023737 0ustar pbusernogroup00000000000000/* * 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_ */ mir-0.1.8+14.04.20140411/include/platform/mir/options/0000755000015301777760000000000012322054703022430 5ustar pbusernogroup00000000000000mir-0.1.8+14.04.20140411/include/platform/mir/options/configuration.h0000644000015301777760000000427412322054223025454 0ustar pbusernogroup00000000000000/* * 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: Alan Griffiths */ #ifndef MIR_OPTIONS_CONFIGURATION_H_ #define MIR_OPTIONS_CONFIGURATION_H_ #include "mir/options/program_option.h" #include namespace mir { namespace options { extern char const* const server_socket_opt; extern char const* const no_server_socket_opt; extern char const* const enable_input_opt; extern char const* const session_mediator_report_opt; extern char const* const msg_processor_report_opt; extern char const* const compositor_report_opt; extern char const* const display_report_opt; extern char const* const legacy_input_report_opt; extern char const* const connector_report_opt; extern char const* const scene_report_opt; extern char const* const input_report_opt; extern char const* const host_socket_opt; extern char const* const frontend_threads_opt; extern char const* const name_opt; extern char const* const offscreen_opt; extern char const* const glog; extern char const* const glog_stderrthreshold; extern char const* const glog_minloglevel; extern char const* const glog_log_dir; extern char const* const off_opt_value; extern char const* const log_opt_value; extern char const* const lttng_opt_value; extern char const* const platform_graphics_lib; class Configuration { public: virtual std::shared_ptr the_options() const = 0; protected: Configuration() = default; virtual ~Configuration() = default; Configuration(Configuration const&) = delete; Configuration& operator=(Configuration const&) = delete; }; } } #endif /* MIR_OPTIONS_CONFIGURATION_H_ */ mir-0.1.8+14.04.20140411/include/platform/mir/options/default_configuration.h0000644000015301777760000000416712322054247027167 0ustar pbusernogroup00000000000000/* * 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" namespace mir { namespace options { class DefaultConfiguration : public Configuration { public: DefaultConfiguration(int argc, char const* argv[]); 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: 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::shared_ptr const program_options; std::shared_ptr