@@ -8,9 +8,12 @@ import (
88 "bufio"
99 "bytes"
1010 "errors"
11+ "io/ioutil"
12+ "math"
1113 "os"
1214 "os/exec"
1315 "strconv"
16+ "strings"
1417 "sync"
1518 "time"
1619
@@ -28,6 +31,10 @@ const (
2831 ColorTemperatureModeManual
2932)
3033
34+ const (
35+ timeZoneFile = "/usr/share/zoneinfo/zone1970.tab"
36+ )
37+
3138func isValidColorTempMode (mode int32 ) bool {
3239 return mode >= ColorTemperatureModeNone && mode <= ColorTemperatureModeManual
3340}
@@ -66,6 +73,13 @@ const (
6673 redshiftStateStopped
6774)
6875
76+ type zoneInfo struct {
77+ country string
78+ latitude float64
79+ longitude float64
80+ distance float64
81+ }
82+
6983type redshiftRunner struct {
7084 mu sync.Mutex
7185 state int
@@ -75,15 +89,62 @@ type redshiftRunner struct {
7589 cb func (value int )
7690 sysService * dbusutil.Service
7791 geoAgentRegistered bool
92+
93+ zoneInfoMap map [string ]* zoneInfo
94+ }
95+
96+ func convertPos (pos string , digits int32 ) float64 {
97+ if len (pos ) < 4 || digits > 9 {
98+ return 0.0
99+ }
100+
101+ integer := pos [:digits + 1 ]
102+ fraction := pos [digits + 1 :]
103+ t1 , _ := strconv .ParseFloat (integer , 64 )
104+ t2 , _ := strconv .ParseFloat (fraction , 64 )
105+ if t1 > 0.0 {
106+ return t1 + t2 / math .Pow (10.0 , float64 (len (fraction )))
107+ } else {
108+ return t1 - t2 / math .Pow (10.0 , float64 (len (fraction )))
109+ }
78110}
79111
80112func newRedshiftRunner () * redshiftRunner {
81113 sysService , err := dbusutil .NewSystemService ()
82114 if err != nil {
83115 logger .Warning ("new sys service failed:" , err )
84116 }
117+ zoneInfoMap := make (map [string ]* zoneInfo )
118+ contents , err := ioutil .ReadFile (timeZoneFile )
119+ if err != nil {
120+ logger .Warning ("Red timezone file failed:" , err )
121+ }
122+ lines := bytes .Split (contents , []byte {'\n' })
123+ for _ , line := range lines {
124+ if ! bytes .HasPrefix (line , []byte {'#' }) {
125+ parts := bytes .Split (line , []byte {'\t' })
126+ if len (parts ) >= 3 {
127+ coordinates := string (parts [1 ])
128+ index := strings .Index (coordinates [3 :], "+" )
129+ if index == - 1 {
130+ index = strings .Index (coordinates [3 :], "-" )
131+ }
132+ if index > - 1 {
133+ latitude := convertPos (coordinates [:index + 3 ], 2 )
134+ longitude := convertPos (coordinates [index + 3 :], 3 )
135+ zone_info := & zoneInfo {
136+ country : string (parts [0 ]),
137+ latitude : latitude ,
138+ longitude : longitude ,
139+ }
140+ zoneInfoMap [string (parts [2 ])] = zone_info
141+ }
142+ }
143+ }
144+ }
85145 return & redshiftRunner {
86- sysService : sysService ,
146+ sysService : sysService ,
147+ zoneInfoMap : zoneInfoMap ,
87148 }
88149}
89150
@@ -97,12 +158,14 @@ func (r *redshiftRunner) start() {
97158 }
98159 r .state = redshiftStateRunning
99160
100- err := r .registerGeoClueAgent ()
101- if err != nil {
102- logger .Warning ("register geoClue agent failed:" , err )
103- }
104-
161+ latitude := r .zoneInfoMap [_timeZone ].latitude
162+ longitude := r .zoneInfoMap [_timeZone ].longitude
163+ geographicalPosition := strconv .FormatFloat (latitude , 'f' , - 1 , 64 ) + ":" + strconv .FormatFloat (longitude , 'f' , - 1 , 64 )
164+ logger .Info ("Get geographicalPosition:" , geographicalPosition )
105165 cmd := exec .Command ("redshift" , "-m" , "dummy" , "-t" , "6500:3500" , "-r" )
166+ if geographicalPosition != "" {
167+ cmd .Args = append (cmd .Args , "-l" , geographicalPosition )
168+ }
106169 cmd .Env = append (os .Environ (), "LC_ALL=C" )
107170 var errBuf bytes.Buffer
108171 cmd .Stderr = & errBuf
@@ -154,6 +217,55 @@ func (r *redshiftRunner) start() {
154217 return
155218}
156219
220+ func (m * Manager ) listenTimezone () {
221+ jobMatchRule := dbusutil .NewMatchRuleBuilder ().ExtPropertiesChanged (
222+ "/org/freedesktop/timedate1" , "org.freedesktop.timedate1" ).Build ()
223+ err := jobMatchRule .AddTo (m .sysBus )
224+ if err != nil {
225+ logger .Warning (err )
226+ return
227+ }
228+ sigChan := make (chan * dbus.Signal , 10 )
229+ m .sysBus .Signal (sigChan )
230+
231+ defer func () {
232+ m .sysBus .RemoveSignal (sigChan )
233+ err := jobMatchRule .RemoveFrom (m .sysBus )
234+ if err != nil {
235+ logger .Warning (err )
236+ }
237+ }()
238+
239+ for sig := range sigChan {
240+ if sig .Path == "/org/freedesktop/timedate1" &&
241+ sig .Name == "org.freedesktop.DBus.Properties.PropertiesChanged" {
242+ if len (sig .Body ) != 3 {
243+ logger .Warning (err )
244+ return
245+ }
246+
247+ props , ok := sig .Body [1 ].(map [string ]dbus.Variant )
248+ if ! ok {
249+ logger .Warning (err )
250+ return
251+ }
252+ v , ok := props ["Timezone" ]
253+ if ok {
254+ timezone , _ := v .Value ().(string )
255+ logger .Info ("Timezone change to" , timezone )
256+ _timeZone = timezone
257+ if m .redshiftRunner .state == redshiftStateRunning {
258+ logger .Info ("Redshift is Running" )
259+ m .redshiftRunner .stop ()
260+ time .AfterFunc (50 * time .Millisecond , func () {
261+ m .redshiftRunner .start ()
262+ })
263+ }
264+ }
265+ }
266+ }
267+ }
268+
157269func (r * redshiftRunner ) stop () {
158270 r .mu .Lock ()
159271 defer r .mu .Unlock ()
0 commit comments