summaryrefslogtreecommitdiff
path: root/ar/.local/bin/dmenudisplay
blob: 4673599a8c30fbf447c6c93206e9a018be2332b9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/bin/sh

# A UI for detecting and selecting all displays. Probes xrandr for connected
# displays and lets user select one to use. User may also select "manual
# selection" which opens arandr.
#
# Options:
#   -r    Enable resolution selection for each display

# Parse options
select_resolution=false
while getopts "r" opt; do
  case $opt in
    r) select_resolution=true ;;
    *) echo "Usage: $0 [-r]" >&2; exit 1 ;;
  esac
done
shift $((OPTIND - 1))

# Function to select resolution for a display
get_resolution() {
  display="$1"
  if [ "$select_resolution" = true ]; then
    resolutions=$(xrandr --query | sed -n "/^$display/,/^[^ ]/p" | grep -v "^$display" | grep -v "^[^ ]" | awk '{print $1}' | grep -E "^[0-9]+x[0-9]+$")
    chosen_res=$(echo "$resolutions" | dmenu -i -p "Resolution for $display:")
    [ -n "$chosen_res" ] && echo "--mode $chosen_res" || echo "--auto"
  else
    echo "--auto"
  fi
}

twoscreen() { # If multi-monitor is selected and there are two screens.
  mirror=$(printf "no\\nyes" | dmenu -i -p "Mirror displays?")
  [ -z "$mirror" ] && exit
  # Mirror displays using native resolution of external display and a scaled
  # version for the internal display
  if [ "$mirror" = "yes" ]; then
    external=$(echo "$screens" | dmenu -i -p "Optimize resolution for:")
    internal=$(echo "$screens" | grep -v "$external")

    res_external=$(xrandr --query | sed -n "/^$external/,/\+/p" |
      tail -n 1 | awk '{print $1}')
    res_internal=$(xrandr --query | sed -n "/^$internal/,/\+/p" |
      tail -n 1 | awk '{print $1}')

    res_ext_x=$(echo "$res_external" | sed 's/x.*//')
    res_ext_y=$(echo "$res_external" | sed 's/.*x//')
    res_int_x=$(echo "$res_internal" | sed 's/x.*//')
    res_int_y=$(echo "$res_internal" | sed 's/.*x//')

    scale_x=$(echo "$res_ext_x / $res_int_x" | bc -l)
    scale_y=$(echo "$res_ext_y / $res_int_y" | bc -l)

    xrandr --output "$external" --auto --scale 1.0x1.0 \
      --output "$internal" --auto --same-as "$external" \
      --scale "$scale_x"x"$scale_y"
  else
    primary=$(echo "$screens" | dmenu -i -p "Select primary display:")
    [ -z "$primary" ] && exit
    secondary=$(echo "$screens" | grep -v ^"$primary"$)
    direction=$(printf "left\\nright" | dmenu -i -p "What side of $primary should $secondary be on?")
    primary_res=$(get_resolution "$primary")
    secondary_res=$(get_resolution "$secondary")
    xrandr --output "$primary" --primary $primary_res --scale 1.0x1.0 --output "$secondary" --"$direction"-of "$primary" $secondary_res --scale 1.0x1.0
  fi
}

morescreen() { # If multi-monitor is selected and there are more than two screens.
  primary=$(echo "$screens" | dmenu -i -p "Select primary display:")
  [ -z "$primary" ] && exit
  secondary=$(echo "$screens" | grep -v ^"$primary"$ | dmenu -i -p "Select secondary display:")
  direction=$(printf "left\\nright" | dmenu -i -p "What side of $primary should $secondary be on?")
  tertiary=$(echo "$screens" | grep -v ^"$primary"$ | grep -v ^"$secondary"$ | dmenu -i -p "Select third display:")
  primary_res=$(get_resolution "$primary")
  secondary_res=$(get_resolution "$secondary")
  tertiary_res=$(get_resolution "$tertiary")
  xrandr --output "$primary" --primary $primary_res --output "$secondary" --"$direction"-of "$primary" $secondary_res --output "$tertiary" --"$(printf "left\\nright" | grep -v "$direction")"-of "$primary" $tertiary_res
}

multimon() { # Multi-monitor handler.
  case "$(echo "$screens" | wc -l)" in
  2) twoscreen ;;
  *) morescreen ;;
  esac
}

onescreen() { # If only one output available or chosen.
  res_opt=$(get_resolution "$1")
  xrandr --output "$1" --primary $res_opt --scale 1.0x1.0 $(echo "$allposs" | grep -v "\b$1" | awk '{print "--output", $1, "--off"}' | paste -sd ' ' -)
}

postrun() { # Stuff to run to clean up.
  setbg     # Fix background if screen size/arangement has changed.
  {
    killall dunst
    setsid -f dunst
  } >/dev/null 2>&1 # Restart dunst to ensure proper location on screen
}

# Get all possible displays
allposs=$(xrandr -q | grep "connected")

# Get all connected screens.
screens=$(echo "$allposs" | awk '/ connected/ {print $1}')

# If there's only one screen
[ "$(echo "$screens" | wc -l)" -lt 2 ] &&
  {
    onescreen "$screens"
    postrun
    notify-send "💻 Only one screen detected." "Using it in its optimal settings..."
    exit
  }

# Get user choice including multi-monitor and manual selection:
chosen=$(printf "%s\\nmulti-monitor\\nmanual selection" "$screens" | dmenu -i -p "Select display arangement:") &&
  case "$chosen" in
  "manual selection")
    arandr
    exit
    ;;
  "multi-monitor") multimon ;;
  *) onescreen "$chosen" ;;
  esac

postrun