#!/bin/sh # enable-HiDPI.sh # # # Created by syscl/lighting/Yating Zhou on 16/3/2. # #================================= GLOBAL VARS ================================== # # The script expects '0.5' but non-US localizations use '0,5' so we export # LC_NUMERIC here (for the duration of the enable-HiDPI.sh) to prevent errors. # export LC_NUMERIC="en_US.UTF-8" # # Prevent non-printable/control characters. # unset GREP_OPTIONS unset GREP_COLORS unset GREP_COLOR # # Output styling. # BOLD="\033[1m" RED="\033[1;31m" GREEN="\033[1;32m" BLUE="\033[1;34m" OFF="\033[m" STYLE_UNDERLINED="\e[4m" # # Define two status: 0 - Success, Turn on, # 1 - Failure, Turn off # kBASHReturnSuccess=0 kBASHReturnFailure=1 # # Repository location # REPO=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) # # Define variables. # Gvariables stands for getting datas from OS X. # gDisplayVendorID_RAW="" gDisplayVendorID="" gDisplayProductID_RAW="" gDisplayProductID_reverse="" gDisplayProductID="" gConfig="" gRes_RAW="F" gRes_VAL="" gRes_ENCODE="" gHeight_HiDPI="" gWide_HiDPI="" gHeight_HiDPI_VAL="" gWide_HiDPI_VAL="" gRes_HiDPI_VAL="" gRes_HiDPI_ENCODE="" gDstPath="" # gBak_Time=$(date +%Y-%m-%d-h%H_%M_%S) gBak_Time=$(date +%Y-%m-%d@%H_%M_%S) gBak_Dir="${REPO}/Display-Backups/${gBak_Time}" # # Define gConfig # gConfig="" # #-------------------------------------------------------------------------------- # function _PRINT_MSG() { local message=$1 case "$message" in OK* ) local message=$(echo $message | sed -e 's/.*OK://') echo "[ ${GREEN}OK${OFF} ] ${message}." ;; FAILED*) local message=$(echo $message | sed -e 's/.*://') echo "[${RED}FAILED${OFF}] ${message}." ;; ---* ) local message=$(echo $message | sed -e 's/.*--->://') echo "[ ${GREEN}--->${OFF} ] ${message}" ;; NOTE* ) local message=$(echo $message | sed -e 's/.*NOTE://') echo "[ ${RED}Note${OFF} ] ${message}." ;; esac } # #-------------------------------------------------------------------------------- # function _tidy_exec() { if [ $gDebug -eq 0 ]; then # # Using debug mode to output all the details. # _PRINT_MSG "DEBUG: $2" $1 else # # Make the output clear. # $1 >/tmp/report 2>&1 && RETURN_VAL=${kBASHReturnSuccess} || RETURN_VAL=${kBASHReturnFailure} if [ "${RETURN_VAL}" == ${kBASHReturnSuccess} ]; then _PRINT_MSG "OK: $2" else _PRINT_MSG "FAILED: $2" cat /tmp/report fi rm /tmp/report &> /dev/null fi } # #-------------------------------------------------------------------------------- # function _getEDID() { local index=0 local selection=0 gDisplayInf=($(ioreg -lw0 | grep -i "IODisplayEDID" | sed -e "/[^<]*//")) if [[ "${#gDisplayInf[@]}" -ge 2 ]]; then # # Multi monitors detected. Choose target monitor. # echo ' Table of monitors ' echo '------------------------------------' echo ' Index | VendorID | ProductID ' echo '------------------------------------' for display in "${gDisplayInf[@]}" do let index++ # # Show monitors. # printf " %d | ${display:16:4} | ${display:20:4}\n" $index done # # Close the table # echo '------------------------------------' # # Let user make a selection. # printf 'Choose the display to enable HiDPI' if [[ "${#gDisplayInf[@]}" == 2 ]]; then printf "[${STYLE_UNDERLINED}E${OFF}xit/1/2]" else printf "[${STYLE_UNDERLINED}E${OFF}xit/1-${index}]" fi read -p ": " selection case "$(_toLowerCase $selection)" in e|exit ) echo "Abort." exit -0 ;; [[:digit:]]* ) # # Lower selection (arrays start at zero). # let selection-=1 gMonitor=${gDisplayInf[$selection]} ;; * ) if [[ "${#gDisplayInf[@]}" == 2 ]]; then echo 'Invalid menu action, enter 1 or 2' else echo "Invalid menu action, enter valid number among 1, ..., ${index}" fi ;; esac else gMonitor=${gDisplayInf} fi # # Fix for issue #16 and #32 # if [[ ${gMonitor:16:1} == 0 ]]; then # get rid of the prefix 0 gDisplayVendorID_RAW=${gMonitor:17:3} else gDisplayVendorID_RAW=${gMonitor:16:4} fi # convert from hex to dec gDisplayVendorID=$((0x$gDisplayVendorID_RAW)) gDisplayProductID_RAW=${gMonitor:20:4} # # Exchange two bytes # # Fix an issue that will cause wrong name of DisplayProductID # if [[ ${gDisplayProductID_RAW:2:1} == 0 ]]; then # get rid of the prefix 0 gDisplayProduct_pr=${gDisplayProductID_RAW:3:1} else gDisplayProduct_pr=${gDisplayProductID_RAW:2:2} fi gDisplayProduct_st=${gDisplayProductID_RAW:0:2} gDisplayProductID_reverse="${gDisplayProduct_pr}${gDisplayProduct_st}" gDisplayProductID=$((0x$gDisplayProduct_pr$gDisplayProduct_st)) # echo $gDisplayVendorID_RAW # echo $gDisplayVendorID # echo $gDisplayProductID_RAW # echo $gDisplayProductID gConfig=${REPO}/DisplayVendorID-$gDisplayVendorID_RAW/DisplayProductID-$gDisplayProductID_reverse } # #-------------------------------------------------------------------------------- # function _printHeader() { echo '' echo '' echo '' echo '' printf '\tDisplayProductID\n' printf "\t${gDisplayProductID}\n" printf '\tDisplayVendorID\n' printf "\t${gDisplayVendorID}\n" printf '\tscale-resolutions\n' printf '\t\n' } # #-------------------------------------------------------------------------------- # function _closeField() { printf '\t\n' echo '' echo '' } # #-------------------------------------------------------------------------------- # function _create_dir() { if [ ! -d "$1" ]; then mkdir -p "$1" fi } # #-------------------------------------------------------------------------------- # function _del() { local target_file=$1 if [ -d ${target_file} ]; then _tidy_exec "rm -R ${target_file}" "Remove old ${target_file}" else if [ -f ${target_file} ]; then _tidy_exec "rm ${target_file}" "Remove old ${target_file}" fi fi } # #-------------------------------------------------------------------------------- # function _cleanup() { _create_dir ${gBak_Dir} _del ${REPO}/DisplayVendorID-* _create_dir ${REPO}/DisplayVendorID-$gDisplayVendorID_RAW } # #-------------------------------------------------------------------------------- # function _toLowerCase() { echo "`echo $1 | tr '[:upper:]' '[:lower:]'`" } # #-------------------------------------------------------------------------------- # function _calcsRes() { # # Increment i stands for adding arrays. # i=0 while [ "$gRes_RAW" != 0 ]; do printf "Enter the HiDPI resolution (e.g. 1600x900, 1440x910, ...), ${BOLD}0${OFF} to quit" read -p ": " gRes_RAW if [[ $gRes_RAW != 0 ]]; then # # Raw Datas # gHeightVAL=$(echo $gRes_RAW | cut -f 1 -d "x") gWideVAL=$(echo $gRes_RAW | cut -f 2 -d "x") # # Generate Resolution Values (Hex) # gRes_VAL=$(printf '%08x %08x 00000001 02000000' $gHeightVAL $gWideVAL) # HiDPI is twice the size. gRes_HiDPI_VAL=$(printf '%08x %08x 00000001 02000000' $((gHeightVAL*2)) $((gWideVAL*2))) # # Encode Resolution Values(Hex) into base64 # gRes_ENCODE=$(printf $gRes_VAL | xxd -r -p | base64) gRes_HiDPI_ENCODE=$(printf $gRes_HiDPI_VAL | xxd -r -p | base64) # # Inject HiDPI values. # printf "\t\t${gRes_HiDPI_ENCODE}\n" >> "$gConfig" gRes_RAW="" i=$(($i+1)) fi done } # #-------------------------------------------------------------------------------- # function _OSCheck() { # # Extract minor version (eg. 10.9 vs. 10.10 vs. 10.11) # MINOR_VER=$([[ "$(sw_vers -productVersion)" =~ [0-9]+\.([0-9]+) ]] && echo ${BASH_REMATCH[1]}) if [[ $MINOR_VER -ge 11 ]]; then gDstPath="/System/Library/Displays/Contents/Resources/Overrides" else gDstPath="/System/Library/Displays/Overrides" fi } # #-------------------------------------------------------------------------------- # function _patch() { # # Count number indicates patch system or not. # if [ $i != 0 ]; then _tidy_exec "cp -R "$gDstPath" ${gBak_Dir}" "Backup $gDstPath" sudo defaults write /Library/Preferences/com.apple.windowserver DisplayResolutionEnabled -bool YES if [ -f "/Library/Preferences/com.apple.windowserver" ]; then sudo defaults delete /Library/Preferences/com.apple.windowserver DisplayResolutionDisabled 2>&1 >/dev/null fi sudo cp -R "${REPO}/DisplayVendorID-$gDisplayVendorID_RAW" "$gDstPath" _PRINT_MSG "OK: Done. Reboot then use Retina Display Menu (RDM) to select the HiDPI resolution just injected!" else _PRINT_MSG "NOTE: All system files remain unchanged." fi } # #-------------------------------------------------------------------------------- # function main() { # # Get argument. # gArgv=$(echo "$@" | tr '[:lower:]' '[:upper:]') if [[ $# -eq 1 && "$gArgv" == "-D" || "$gArgv" == "-DEBUG" ]]; then # # Yes, we do need debug mode. # _PRINT_MSG "NOTE: Use ${BLUE}DEBUG${OFF} mode" gDebug=0 else # # No, we need a clean output style. # gDebug=1 fi _getEDID _cleanup _printHeader > "$gConfig" _calcsRes _closeField >>"$gConfig" _OSCheck _patch } #==================================== START ===================================== main "$@" #================================================================================ exit 0