# Copyright (c) 2011, Fran Rogers # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import simplejson import logging from gettext import gettext as _ import gobject import gtk import gtkvnc import hippo from sugar.graphics.entry import CanvasEntry from sugar.graphics.icon import Icon from sugar.graphics.toolbutton import ToolButton from sugar.graphics.toolbarbox import ToolbarBox from sugar.graphics.toolbarbox import ToolbarButton from sugar.activity.widgets import ActivityToolbarButton from sugar.activity.widgets import StopButton from sugar.activity import activity from sugar.graphics import style _BACKGROUND_COLOR = style.COLOR_WHITE MASKED_ENVIRONMENT = [ 'DBUS_SESSION_BUS_ADDRESS', 'PPID'] log = logging.getLogger('VNC') log.setLevel(logging.DEBUG) logging.basicConfig() class VNCActivity(activity.Activity): def __init__(self, handle): activity.Activity.__init__(self, handle) self.max_participants = 1 self._vnc = None self.host = None self.password = None toolbar_box = ToolbarBox() activity_button = ActivityToolbarButton(self) toolbar_box.toolbar.insert(activity_button, 0) activity_button.page.keep.props.accelerator = 'S' activity_button.show() view_toolbar = self._create_view_toolbar() view_toolbar_button = ToolbarButton( page=view_toolbar, icon_name='toolbar-view') view_toolbar.show() toolbar_box.toolbar.insert(view_toolbar_button, -1) view_toolbar_button.show() separator = gtk.SeparatorToolItem() separator.props.draw = False separator.set_expand(True) toolbar_box.toolbar.insert(separator, -1) separator.show() stop_button = StopButton(self) stop_button.props.accelerator = 'Q' toolbar_box.toolbar.insert(stop_button, -1) stop_button.show() self.set_toolbar_box(toolbar_box) toolbar_box.show() if self.host == None: self.show_connect_dialog() def _create_view_toolbar(self): view_toolbar = gtk.Toolbar() fullscreen_button = ToolButton('view-fullscreen') fullscreen_button.set_tooltip(_("Fullscreen")) fullscreen_button.props.accelerator = 'Return' fullscreen_button.connect('clicked', self.__fullscreen_cb) view_toolbar.insert(fullscreen_button, -1) fullscreen_button.show() return view_toolbar def __fullscreen_cb(self, button): self.fullscreen() def __connect_clicked_cb(self, widget): self.vnc_connect(widget.get_host()) def __password_cb(self, widget): self.password = self._password_dialog.get_password() self._vnc.set_credential(gtkvnc.CREDENTIAL_PASSWORD, self.password) self.set_canvas(self._vnc) def __vnc_connected_cb(self, widget): self.connected = True def __vnc_initialized_cb(self, widget): pass def __vnc_disconnected_cb(self, widget): if self.connected: self.connected = False self.show_error(_("Disconnected")) else: self.show_error(_("Unable to connect to %s") % (self.host,)) def __vnc_auth_credential(self, widget, creds): if creds == [gtkvnc.CREDENTIAL_PASSWORD]: if self.password != None: self._vnc.set_credential(gtkvnc.CREDENTIAL_PASSWORD, self.password) else: self._password_dialog = VNCActivityPasswordDialog() self._password_dialog.connect('activated', self.__password_cb) self._password_dialog.show() self.set_canvas(self._password_dialog) self._password_dialog.grab_focus() def __vnc_auth_failure(self, widget, error): self.show_error("Authentication failure: %s" % (error,)) def __vnc_auth_unsupported(self, widget, error_code): self.show_error("Authentication method not supported: %s" % (str(error_code),)) def vnc_connect(self, host, password=None): self.host = host self.password = password self.connected = False if ':' in host: colon = host.rindex(':') hostname = host[:colon] display = 0 try: display = int(host[colon+1:]) except: hostname = host if hostname == "": hostname = "127.0.0.1" else: hostname = host display = 0 self._vnc = gtkvnc.Display() self._vnc.connect('vnc-connected', self.__vnc_connected_cb) self._vnc.connect('vnc-initialized', self.__vnc_initialized_cb) self._vnc.connect('vnc-disconnected', self.__vnc_disconnected_cb) self._vnc.connect('vnc-auth-credential', self.__vnc_auth_credential) self._vnc.connect('vnc-auth-failure', self.__vnc_auth_failure) self._vnc.connect('vnc-auth-unsupported', self.__vnc_auth_unsupported) self._vnc.show() self.set_canvas(self._vnc) self._vnc.open_host(hostname, str(5900 + display)) def show_connect_dialog(self): if self._vnc != None: self._vnc.close() self._vnc = None self._connect_dialog = VNCActivityConnectDialog() self._connect_dialog.connect('activated', self.__connect_clicked_cb) self._connect_dialog.show() self.set_canvas(self._connect_dialog) self._connect_dialog.grab_focus() def __error_back_cb(self, widget): self.show_connect_dialog() def show_error(self, message): if self._vnc != None: self._vnc.close() self._vnc = None self._error_dialog = VNCActivityErrorDialog(message) self._error_dialog.connect('activated', self.__error_back_cb) self._error_dialog.show() self.set_canvas(self._error_dialog) self._error_dialog.grab_focus() def read_file(self, file_path): if self.metadata['mime_type'] != 'text/plain': return fd = open(file_path, 'r') text = fd.read() data = simplejson.loads(text) fd.close() data_file = file_path if data['host'] != None: if data['password'] != None: self.vnc_connect(data['host'], data['password']) else: self.vnc_connect(data['host']) def write_file(self, file_path): if not self.metadata['mime_type']: self.metadata['mime_type'] = 'text/plain' data = {} data['host'] = self.host data['password'] = self.password fd = open(file_path, 'w') text = simplejson.dumps(data) fd.write(text) fd.close() class VNCActivityConnectDialog(hippo.Canvas): __gsignals__ = { 'activated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (),) } def __init__(self): hippo.Canvas.__init__(self) self.connect('key-press-event', self.__key_press_cb) root_box = hippo.CanvasBox(padding=style.zoom(30), background_color=_BACKGROUND_COLOR.get_int()) opts_box = hippo.CanvasBox(xalign=hippo.ALIGNMENT_CENTER, background_color=_BACKGROUND_COLOR.get_int(), spacing=style.DEFAULT_SPACING, orientation=hippo.ORIENTATION_HORIZONTAL,) label = hippo.CanvasText(text=_("Host:")) opts_box.append(label) host_canvas_entry = CanvasEntry(box_width=style.zoom(300)) host_canvas_entry.set_background(_BACKGROUND_COLOR.get_html()) self._host_entry = host_canvas_entry.props.widget self._host_entry.set_max_length(45) self._host_entry.connect('key-press-event', self.__key_press_cb) opts_box.append(host_canvas_entry) root_box.append(opts_box, hippo.PACK_EXPAND) button_box = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL) connect_canvas_button = hippo.CanvasButton(text=_('Connect')) self._connect_button = connect_canvas_button.props.widget self._connect_button.set_image(Icon(icon_name='go-right')) connect_canvas_button.connect('activated', self._activated_cb) button_box.append(hippo.CanvasBox(), hippo.PACK_EXPAND) button_box.append(connect_canvas_button) root_box.append(button_box) self.set_root(root_box) def get_host(self): return self._host_entry.get_text() def set_host(self, host): self._host_entry.set_text(host) def grab_focus(self): self._host_entry.grab_focus() def __key_press_cb(self, widget, event): if gtk.gdk.keyval_name(event.keyval) == "Return": self.activate() return True def _activated_cb(self, item): self.activate() def activate(self): if self.get_host() != "": self.emit('activated') class VNCActivityPasswordDialog(hippo.Canvas): __gsignals__ = { 'activated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (),) } def __init__(self): hippo.Canvas.__init__(self) self.connect('key-press-event', self.__key_press_cb) root_box = hippo.CanvasBox(padding=style.zoom(30), background_color=_BACKGROUND_COLOR.get_int()) opts_box = hippo.CanvasBox(xalign=hippo.ALIGNMENT_CENTER, background_color=_BACKGROUND_COLOR.get_int(), spacing=style.DEFAULT_SPACING, orientation=hippo.ORIENTATION_HORIZONTAL,) label = hippo.CanvasText(text=_("Password:")) opts_box.append(label) password_canvas_entry = CanvasEntry(box_width=style.zoom(300)) password_canvas_entry.set_background(_BACKGROUND_COLOR.get_html()) self._password_entry = password_canvas_entry.props.widget self._password_entry.set_max_length(45) self._password_entry.set_visibility(False) self._password_entry.connect('key-press-event', self.__key_press_cb) opts_box.append(password_canvas_entry) root_box.append(opts_box, hippo.PACK_EXPAND) button_box = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL) next_canvas_button = hippo.CanvasButton(text=_('Continue')) self._next_button = next_canvas_button.props.widget self._next_button.set_image(Icon(icon_name='go-right')) next_canvas_button.connect('activated', self._activated_cb) button_box.append(hippo.CanvasBox(), hippo.PACK_EXPAND) button_box.append(next_canvas_button) root_box.append(button_box) self.set_root(root_box) def get_password(self): return self._password_entry.get_text() def set_password(self, password): self._host_entry.set_text(password) def grab_focus(self): self._password_entry.grab_focus() def __key_press_cb(self, widget, event): if gtk.gdk.keyval_name(event.keyval) == "Return": self.activate() return True def _activated_cb(self, item): self.activate() def activate(self): self.emit('activated') class VNCActivityErrorDialog(hippo.Canvas): __gsignals__ = { 'activated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (),) } def __init__(self, message): hippo.Canvas.__init__(self) self.connect('key-press-event', self.__key_press_cb) root_box = hippo.CanvasBox(padding=style.zoom(30), background_color=_BACKGROUND_COLOR.get_int()) opts_box = hippo.CanvasBox(xalign=hippo.ALIGNMENT_CENTER, background_color=_BACKGROUND_COLOR.get_int(), spacing=style.DEFAULT_SPACING, orientation=hippo.ORIENTATION_HORIZONTAL,) label = hippo.CanvasText(text=message) opts_box.append(label) root_box.append(opts_box, hippo.PACK_EXPAND) button_box = hippo.CanvasBox(orientation=hippo.ORIENTATION_HORIZONTAL) back_canvas_button = hippo.CanvasButton(text=_('Back')) self._back_button = back_canvas_button.props.widget self._back_button.set_image(Icon(icon_name='go-left')) back_canvas_button.connect('activated', self._activated_cb) button_box.append(back_canvas_button) root_box.append(button_box) self.set_root(root_box) def grab_focus(self): self._back_button.grab_focus() def __key_press_cb(self, widget, event): if gtk.gdk.keyval_name(event.keyval) == "Return": self.activate() return True def _activated_cb(self, item): self.activate() def activate(self): self.emit('activated')