2 # -*- coding: utf-8 -*-
4 # indicator-lunar-calendar - shows lunar calendar information
5 # Copyright (c) 2019 Adrian I Lam <spam@adrianiainlam.tk> s/spam/me/
7 # Permission is hereby granted, free of charge, to any person obtaining a
8 # copy of this software and associated documentation files (the "Software"),
9 # to deal in the Software without restriction, including without limitation
10 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 # and/or sell copies of the Software, and to permit persons to whom the
12 # Software is furnished to do so, subject to the following conditions:
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 # THE AUTHOR OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 # I would like to thank Tobias Schlitt <toby@php.net>, who wrote
26 # indicator-chars <https://github.com/tobyS/indicator-chars> which I used
27 # as a reference when writing this software.
33 gi
.require_version('Gdk', '3.0')
34 gi
.require_version('Gtk', '3.0')
35 gi
.require_version('AppIndicator3', '0.1')
36 from gi
.repository
import Gdk
, Gtk
, AppIndicator3
37 from LunarCalendarPy
.LunarCalendar
import LunarCalendar
42 from dbus
.mainloop
.glib
import DBusGMainLoop
44 APP_NAME
= 'indicator-lunar-calendar-py'
45 APP_VERSION
= '1.2+py'
47 SCRIPT_DIR
= os
.path
.dirname(os
.path
.realpath(__file__
))
50 class IndicatorLunarCalendar
:
52 self
.indicator
= AppIndicator3
.Indicator
.new(
54 os
.path
.join(SCRIPT_DIR
, 'icons', '鼠.svg'),
55 AppIndicator3
.IndicatorCategory
.APPLICATION_STATUS
)
56 self
.indicator
.set_status(AppIndicator3
.IndicatorStatus
.ACTIVE
)
58 self
.menu
= Gtk
.Menu()
59 self
.item
= Gtk
.MenuItem()
60 self
.item
.connect("activate", self
.do_nothing
)
61 self
.menu
.append(self
.item
)
62 self
.indicator
.set_menu(self
.menu
)
65 self
.lc
= LunarCalendar()
66 self
.update_indicator()
68 def update_indicator(self
):
69 # get current time at UTC+8, add 1 to date if after 23:00 (子時)
70 now
= datetime
.datetime
.utcnow() + datetime
.timedelta(hours
=8)
73 now
= now
.date() + datetime
.timedelta(days
=1)
75 lunar
= self
.lc
.solarToLunar(now
.year
, now
.month
, now
.day
)
76 lunar
['hour'] = '子丑寅卯辰巳午未申酉戌亥'[(hour
+ 1) %
24 // 2]
78 compact_date
= lunar
['lunarMonthName'] + lunar
['lunarDayName']
80 lunar
['GanZhiYear'] + '年(' + lunar
['zodiac'] + '年)\n' +
81 lunar
['lunarMonthName'] + lunar
['lunarDayName']
84 compact_date
+= ' ' + lunar
['term']
85 long_date
+= ' ' + lunar
['term']
86 long_date
+= '\n' + lunar
['hour'] + '時'
88 self
.indicator
.set_icon(
89 os
.path
.join(SCRIPT_DIR
, 'icons', lunar
['zodiac'] + '.svg')
91 self
.indicator
.set_label(compact_date
, '')
92 self
.item
.set_label(long_date
)
94 def do_nothing(self
, arg
):
98 def run_schedule_one_iteration():
99 prev_idle_sec
= 60 * 60
100 idle_sec
= schedule
.idle_seconds()
101 while idle_sec
< prev_idle_sec
:
102 prev_idle_sec
= idle_sec
105 time
.sleep(idle_sec
- 2)
106 elif idle_sec
> 0.199:
107 time
.sleep(idle_sec
- 0.199)
109 schedule
.run_pending()
111 idle_sec
= schedule
.idle_seconds()
114 def cronThreadBody():
116 run_schedule_one_iteration()
123 if __name__
== '__main__':
124 signal
.signal(signal
.SIGINT
, lambda signum
, frame
: Gtk
.main_quit())
126 i
= IndicatorLunarCalendar()
128 schedule
.every().hour
.at(":00").do(updateJob
, i
=i
)
129 cronThread
= threading
.Thread(target
=cronThreadBody
)
132 dbusloop
= DBusGMainLoop()
133 bus
= dbus
.SystemBus(mainloop
=dbusloop
)
134 obj
= bus
.get_object('org.freedesktop.login1', '/org/freedesktop/login1')
135 iface
= dbus
.Interface(obj
,
136 dbus_interface
='org.freedesktop.login1.Manager')
138 def sleepHandler(arg
):
142 schedule
.every().minute
.at(":00").do(updateJob
, i
=i
)
143 newThread
= threading
.Thread(target
=run_schedule_one_iteration
)
146 iface
.connect_to_signal('PrepareForSleep', sleepHandler
)