This repository has been archived by the owner on Jan 17, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 125
/
goagent-gtk.py
266 lines (228 loc) · 10.2 KB
/
goagent-gtk.py
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
#!/usr/bin/env python2
# coding:utf-8
# Contributor:
# Phus Lu <phus.lu@gmail.com>
__version__ = '1.6'
GOAGENT_LOGO_DATA = """\
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"""
import sys
import os
import re
import thread
import base64
import platform
try:
import pygtk
pygtk.require('2.0')
import gtk
# gtk.gdk.threads_init()
except Exception:
sys.exit(os.system(u'gdialog --title "XX-Mini GTK" --msgbox "\u8bf7\u5b89\u88c5 python-gtk2" 15 60'.encode(sys.getfilesystemencoding() or sys.getdefaultencoding(), 'replace')))
try:
import pynotify
pynotify.init('XX-Mini Notify')
except ImportError:
pynotify = None
try:
import appindicator
except ImportError:
appindicator = None
try:
import vte
except ImportError:
sys.exit(gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, u'请安装 python-vte').run())
def spawn_later(seconds, target, *args, **kwargs):
def wrap(*args, **kwargs):
import time
time.sleep(seconds)
return target(*args, **kwargs)
return thread.start_new_thread(wrap, args, kwargs)
def drop_desktop():
filename = os.path.abspath(__file__)
dirname = os.path.dirname(filename)
DESKTOP_FILE = '''\
#!/usr/bin/env xdg-open
[Desktop Entry]
Type=Application
Name=XX-Mini GTK
Comment=XX-Mini GTK Launcher
Categories=Network;Proxy;
Exec=/usr/bin/env python "%s"
Icon=%s/goagent-logo.png
Terminal=false
StartupNotify=true
''' % (filename, dirname)
for dirname in map(os.path.expanduser, ['~/Desktop', u'~/桌面']):
if os.path.isdir(dirname):
filename = os.path.join(dirname, 'XX-Mini-gtk.desktop')
with open(filename, 'w') as fp:
fp.write(DESKTOP_FILE)
os.chmod(filename, 0755)
def should_visible():
import ConfigParser
ConfigParser.RawConfigParser.OPTCRE = re.compile(r'(?P<option>[^=\s][^=]*)\s*(?P<vi>[=])\s*(?P<value>.*)$')
config = ConfigParser.ConfigParser()
config.read(['proxy.ini', 'proxy.user.ini'])
visible = config.has_option('listen', 'visible') and config.getint('listen', 'visible')
return visible
#gtk.main_quit = lambda: None
#appindicator = None
class GoAgentGTK:
command = ['/usr/bin/env', 'python', 'proxy.py']
message = u'XX-Mini已经启动,单击托盘图标可以最小化'
fail_message = u'XX-Mini启动失败,请查看控制台窗口的错误信息。'
def __init__(self, window, terminal):
self.window = window
self.window.set_size_request(652, 447)
self.window.set_position(gtk.WIN_POS_CENTER)
self.window.connect('delete-event',self.delete_event)
self.terminal = terminal
for cmd in ('python2.7', 'python27', 'python2'):
if os.system('which %s' % cmd) == 0:
self.command[1] = cmd
break
self.window.add(terminal)
self.childpid = self.terminal.fork_command(self.command[0], self.command, os.getcwd())
if self.childpid > 0:
self.childexited = self.terminal.connect('child-exited', self.on_child_exited)
self.window.connect('delete-event', lambda w, e: gtk.main_quit())
else:
self.childexited = None
spawn_later(0.5, self.show_startup_notify)
if should_visible():
self.window.show_all()
logo_filename = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'goagent-logo.png')
if not os.path.isfile(logo_filename):
with open(logo_filename, 'wb') as fp:
fp.write(base64.b64decode(GOAGENT_LOGO_DATA))
self.window.set_icon_from_file(logo_filename)
if appindicator:
self.trayicon = appindicator.Indicator('XX-Mini', 'indicator-messages', appindicator.CATEGORY_APPLICATION_STATUS)
self.trayicon.set_status(appindicator.STATUS_ACTIVE)
self.trayicon.set_attention_icon('indicator-messages-new')
self.trayicon.set_icon(logo_filename)
self.trayicon.set_menu(self.make_menu())
else:
self.trayicon = gtk.StatusIcon()
self.trayicon.set_from_file(logo_filename)
self.trayicon.connect('popup-menu', lambda i, b, t: self.make_menu().popup(None, None, gtk.status_icon_position_menu, b, t, self.trayicon))
self.trayicon.connect('activate', self.show_hide_toggle)
self.trayicon.set_tooltip('XX-Mini')
self.trayicon.set_visible(True)
def make_menu(self):
menu = gtk.Menu()
itemlist = [(u'\u663e\u793a', self.on_show),
(u'\u9690\u85cf', self.on_hide),
(u'\u505c\u6b62', self.on_stop),
(u'\u91cd\u65b0\u8f7d\u5165', self.on_reload),
(u'\u9000\u51fa', self.on_quit)]
for text, callback in itemlist:
item = gtk.MenuItem(text)
item.connect('activate', callback)
item.show()
menu.append(item)
menu.show()
return menu
def show_notify(self, message=None, timeout=None):
if pynotify and message:
notification = pynotify.Notification('XX-Mini Notify', message)
notification.set_hint('x', 200)
notification.set_hint('y', 400)
if timeout:
notification.set_timeout(timeout)
notification.show()
def show_startup_notify(self):
if self.check_child_exists():
self.show_notify(self.message, timeout=3)
def check_child_exists(self):
if self.childpid <= 0:
return False
cmd = 'ps -p %s' % self.childpid
lines = os.popen(cmd).read().strip().splitlines()
if len(lines) < 2:
return False
return True
def on_child_exited(self, term):
if self.terminal.get_child_exit_status() == 0:
gtk.main_quit()
else:
self.show_notify(self.fail_message)
def on_show(self, widget, data=None):
self.window.show_all()
self.window.present()
self.terminal.feed('\r')
def on_hide(self, widget, data=None):
self.window.hide_all()
def on_stop(self, widget, data=None):
if self.childexited:
self.terminal.disconnect(self.childexited)
os.system('kill -9 %s' % self.childpid)
def on_reload(self, widget, data=None):
if self.childexited:
self.terminal.disconnect(self.childexited)
os.system('kill -9 %s' % self.childpid)
self.on_show(widget, data)
self.childpid = self.terminal.fork_command(self.command[0], self.command, os.getcwd())
self.childexited = self.terminal.connect('child-exited', lambda term: gtk.main_quit())
def show_hide_toggle(self, widget, data= None):
if self.window.get_property('visible'):
self.on_hide(widget, data)
else:
self.on_show(widget, data)
def delete_event(self, widget, data=None):
self.on_hide(widget, data)
# 默认最小化至托盘
return True
def on_quit(self, widget, data=None):
gtk.main_quit()
def main():
global __file__
__file__ = os.path.abspath(__file__)
if os.path.islink(__file__):
__file__ = getattr(os, 'readlink', lambda x: x)(__file__)
os.chdir(os.path.dirname(os.path.abspath(__file__)))
if not os.path.exists('goagent-logo.png'):
# first run and drop shortcut to desktop
drop_desktop()
window = gtk.Window()
terminal = vte.Terminal()
GoAgentGTK(window, terminal)
gtk.main()
if __name__ == '__main__':
main()