mirror of
https://github.com/onionshare/onionshare.git
synced 2025-07-28 09:04:26 -04:00
making a webkit GUI, roughly based on http://www.aclevername.com/articles/python-webgui/
This commit is contained in:
parent
74678603ab
commit
0f53d45489
4 changed files with 223 additions and 72 deletions
|
@ -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
34
onionshare_gui/index.html
Normal 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">☠</span> filename.zip</h1>
|
||||||
|
<p id="uptime-value"></p>
|
||||||
|
</body>
|
||||||
|
</html>
|
66
onionshare_gui/onionshare_gui.py
Normal file
66
onionshare_gui/onionshare_gui.py
Normal 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
123
onionshare_gui/webgui.py
Normal 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()
|
Loading…
Add table
Add a link
Reference in a new issue