This commit is contained in:
Micah Lee 2014-05-29 21:05:30 -04:00
parent 74678603ab
commit 0f53d45489
4 changed files with 223 additions and 72 deletions

View File

@ -1,72 +0,0 @@
#!/usr/bin/env python
import Tkinter as tk, tkFont, tkFileDialog
import sys, os, time
import onionshare
from Queue import Queue, Empty
from threading import Thread
class OnionShareGUI(object):
def __init__(self):
self.root = tk.Tk()
# prepare GUI
self.root.title('OnionShare')
self.root.resizable(0, 0)
self.create_widgets()
self.root.grid()
# select file
if len(sys.argv) >= 2:
self.filename = sys.argv[1]
else:
self.filename = tkFileDialog.askopenfilename(title="Choose a file to share", parent=self.root)
self.basename = os.path.basename(self.filename)
self.root.title('OnionShare - {0}'.format(self.basename))
# todo: start onionshare here, and display web server logs in update() method
# this might be helpful: https://stackoverflow.com/questions/375427/non-blocking-read-on-a-subprocess-pipe-in-python
# update regularly
self.update()
def create_widgets(self):
self.pad = 10
sys12 = tkFont.Font(family="system", size=12)
sys20 = tkFont.Font(family="system", size=20, weight="bold")
# url
self.url_labelframe = tk.LabelFrame(text="Send this URL to your friend")
self.url_labelframe.pack()
self.url_text = tk.Text(self.url_labelframe, width=31, height=2, font=sys20)
self.url_text.config(state=tk.DISABLED)
self.url_text.pack(padx=self.pad, pady=self.pad)
self.url_labelframe.grid(padx=self.pad, pady=self.pad)
# logs
self.logs_labelframe = tk.LabelFrame(text="Server logs")
self.logs_labelframe.pack()
self.logs_text = tk.Text(self.logs_labelframe, width=70, height=10, font=sys12)
self.logs_text.insert(tk.INSERT, "")
self.logs_text.config(state=tk.DISABLED)
self.logs_text.pack(padx=self.pad, pady=self.pad)
self.logs_labelframe.grid(padx=self.pad, pady=self.pad)
# quit button
self.quit_button = tk.Button(self.root, text='Quit', command=self.root.quit)
self.quit_button.grid(padx=self.pad, pady=self.pad)
def update(self):
self.root.after(500, self.update)
def enqueue_output(self, out, queue):
for line in iter(out.readline, b''):
queue.put(line)
out.close()
def main():
app = OnionShareGUI()
app.root.mainloop()
if __name__ == '__main__':
main()

34
onionshare_gui/index.html Normal file
View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
body {
margin: 0;
padding: 0;
}
h1 {
background-color: #FFC4D5;
color: #000000;
text-align: center;
font-size: 30px;
margin: 0;
padding: 10px;
}
h1 .skull {
font-size: 40px;
font-weight: bold;
color: #FF0048;
}
</style>
<script>
function send(msg) {
document.title = "null";
document.title = msg;
}
</script>
</head>
<body>
<h1><span class="skull">&#9760;</span> filename.zip</h1>
<p id="uptime-value"></p>
</body>
</html>

View File

@ -0,0 +1,66 @@
#!/usr/bin/env python
import onionshare, webgui
import signal, os, time, json
class Global(object):
quit = False
@classmethod
def set_quit(cls, *args, **kwargs):
cls.quit = True
def main():
if not webgui.select_file():
return
webgui.start_gtk_thread()
browser, web_recv, web_send = webgui.sync_gtk_msg(webgui.launch_browser)(quit_function=Global.set_quit)
last_second = time.time()
uptime_seconds = 1
clicks = 0
while not Global.quit:
current_time = time.time()
again = False
msg = web_recv()
if msg:
msg = json.loads(msg)
again = True
if msg == "got-a-click":
clicks += 1
web_send('document.getElementById("messages").innerHTML = %s' %
to_json('%d clicks so far' % clicks))
# If you are using jQuery, you can do this instead:
# web_send('$("#messages").text(%s)' %
# to_json('%d clicks so far' % clicks))
if current_time - last_second >= 1.0:
web_send('document.getElementById("uptime-value").innerHTML = %s' %
json.dumps('%d' % uptime_seconds))
# If you are using jQuery, you can do this instead:
# web_send('$("#uptime-value").text(%s)'
# % to_json('%d' % uptime_seconds))
uptime_seconds += 1
last_second += 1.0
if again:
pass
else:
time.sleep(0.1)
def my_quit_wrapper(fun):
signal.signal(signal.SIGINT, Global.set_quit)
def fun2(*args, **kwargs):
try:
x = fun(*args, **kwargs) # equivalent to "apply"
finally:
kill_gtk_thread()
Global.set_quit()
return x
return fun2
if __name__ == '__main__':
main()

123
onionshare_gui/webgui.py Normal file
View File

@ -0,0 +1,123 @@
#!/usr/bin/env python
import time, Queue, thread, gtk, gobject, os, sys, webkit
def select_file():
global filename, basename
# was a filename passed in as an argument?
if len(sys.argv) >= 2:
filename = sys.argv[1]
basename = os.path.basename(filename)
return True
# choose a file
canceled = False
chooser = gtk.FileChooserDialog(
title="Choose a file to share",
action=gtk.FILE_CHOOSER_ACTION_OPEN,
buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
response = chooser.run()
if response == gtk.RESPONSE_OK:
filename = chooser.get_filename()
basename = os.path.basename(filename)
elif response == gtk.RESPONSE_CANCEL:
canceled = True
chooser.destroy()
return not canceled
def async_gtk_msg(fun):
def worker((function, args, kwargs)):
apply(function, args, kwargs)
def fun2(*args, **kwargs):
gobject.idle_add(worker, (fun, args, kwargs))
return fun2
def sync_gtk_msg(fun):
class NoResult: pass
def worker((R, function, args, kwargs)):
R.result = apply(function, args, kwargs)
def fun2(*args, **kwargs):
class R: result = NoResult
gobject.idle_add(callable=worker, user_data=(R, fun, args, kwargs))
while R.result is NoResult: time.sleep(0.01)
return R.result
return fun2
def launch_browser(quit_function=None, echo=True):
window = gtk.Window()
browser = webkit.WebView()
box = gtk.VBox(homogeneous=False, spacing=0)
window.add(box)
if quit_function is not None:
# file > quit menu
file_menu = gtk.Menu()
quit_item = gtk.MenuItem('Quit')
accel_group = gtk.AccelGroup()
quit_item.add_accelerator('activate', accel_group, ord('Q'), gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
window.add_accel_group(accel_group)
file_menu.append(quit_item)
quit_item.connect('activate', quit_function)
quit_item.show()
menu_bar = gtk.MenuBar()
menu_bar.show()
file_item = gtk.MenuItem('File')
file_item.show()
file_item.set_submenu(file_menu)
menu_bar.append(file_item)
box.pack_start(menu_bar, expand=False, fill=True, padding=0)
window.connect('destroy', quit_function)
box.pack_start(browser, expand=True, fill=True, padding=0)
window.set_default_size(400, 400)
window.show_all()
message_queue = Queue.Queue()
def title_changed(title):
if title != 'null': message_queue.put(title)
def callback_wrapper(widget, frame, title): callback(title)
browser.connect('title-changed', callback_wrapper)
browser.open('file://'+os.getcwd()+'/index.html')
def web_recv():
if message_queue.empty():
return None
else:
msg = message_queue.get()
if echo: print '>>>', msg
return msg
def web_send(msg):
if echo: print '<<<', msg
async_gtk_msg(browser.execute_script)(msg)
return browser, web_recv, web_send
def start_gtk_thread():
# Start GTK in its own thread:
gtk.gdk.threads_init()
thread.start_new_thread(gtk.main, ())
def kill_gtk_thread():
async_gtk_msg(gtk.main_quit)()
def main():
if not select_file():
return
launch_browser()