diff options
| author | Tim Redfern <tim@eclectronics.org> | 2011-12-19 18:20:33 +0000 |
|---|---|---|
| committer | Tim Redfern <tim@eclectronics.org> | 2011-12-19 18:20:33 +0000 |
| commit | e9a73bbb3c14af340999f70146747787785f4fee (patch) | |
| tree | a125452f7d641673286542497da051b810427880 /pybluez/bluezchat | |
initial commit
Diffstat (limited to 'pybluez/bluezchat')
| -rw-r--r-- | pybluez/bluezchat/bluezchat.glade | 138 | ||||
| -rwxr-xr-x | pybluez/bluezchat/bluezchat.py | 191 |
2 files changed, 329 insertions, 0 deletions
diff --git a/pybluez/bluezchat/bluezchat.glade b/pybluez/bluezchat/bluezchat.glade new file mode 100644 index 0000000..b3f37eb --- /dev/null +++ b/pybluez/bluezchat/bluezchat.glade @@ -0,0 +1,138 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> +<!--*- mode: xml -*--> +<glade-interface> + <widget class="GtkWindow" id="bluezchat_window"> + <property name="visible">True</property> + <property name="title" translatable="yes">bluez chat</property> + <property name="default_width">240</property> + <property name="default_height">320</property> + <signal name="delete_event" handler="gtk_main_quit"/> + <signal name="destroy_event" handler="gtk_main_quit"/> + <child> + <widget class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow3"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <child> + <widget class="GtkTreeView" id="devices_tv"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">False</property> + <signal name="cursor_changed" handler="on_devices_tv_cursor_changed"/> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkVBox" id="vbox2"> + <property name="visible">True</property> + <child> + <widget class="GtkButton" id="quit_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Quit</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_quit_button_clicked"/> + </widget> + </child> + <child> + <widget class="GtkButton" id="scan_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">S_can</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_scan_button_clicked"/> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <widget class="GtkButton" id="chat_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Chat</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_chat_button_clicked"/> + </widget> + <packing> + <property name="position">2</property> + </packing> + </child> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + </child> + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow2"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <child> + <widget class="GtkTextView" id="main_text"> + <property name="visible">True</property> + <property name="can_focus">True</property> + </widget> + </child> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> + <widget class="GtkHBox" id="hbox2"> + <property name="visible">True</property> + <child> + <widget class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="label" translatable="yes">text:</property> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + <child> + <widget class="GtkEntry" id="input_tb"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="invisible_char">*</property> + </widget> + <packing> + <property name="padding">3</property> + <property name="position">1</property> + </packing> + </child> + <child> + <widget class="GtkButton" id="send_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">_Send</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="on_send_button_clicked"/> + </widget> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">2</property> + </packing> + </child> + </widget> + <packing> + <property name="position">2</property> + </packing> + </child> + </widget> + </child> + </widget> +</glade-interface> diff --git a/pybluez/bluezchat/bluezchat.py b/pybluez/bluezchat/bluezchat.py new file mode 100755 index 0000000..5021eb3 --- /dev/null +++ b/pybluez/bluezchat/bluezchat.py @@ -0,0 +1,191 @@ +#!/usr/bin/python + +""" A simple graphical chat client to demonstrate the use of pybluez. + +Opens a l2cap socket and listens on PSM 0x1001 + +Provides the ability to scan for nearby bluetooth devices and establish chat +sessions with them. +""" + + +import os +import sys +import time + +import gtk +import gobject +import gtk.glade + +import bluetooth + +GLADEFILE="bluezchat.glade" + +# ***************** + +def alert(text, buttons=gtk.BUTTONS_NONE, type=gtk.MESSAGE_INFO): + md = gtk.MessageDialog(buttons=buttons, type=type) + md.label.set_text(text) + md.run() + md.destroy() + +class BluezChatGui: + def __init__(self): + self.main_window_xml = gtk.glade.XML(GLADEFILE, "bluezchat_window") + + # connect our signal handlers + dic = { "on_quit_button_clicked" : self.quit_button_clicked, + "on_send_button_clicked" : self.send_button_clicked, + "on_chat_button_clicked" : self.chat_button_clicked, + "on_scan_button_clicked" : self.scan_button_clicked, + "on_devices_tv_cursor_changed" : self.devices_tv_cursor_changed + } + + self.main_window_xml.signal_autoconnect(dic) + + # prepare the floor listbox + self.devices_tv = self.main_window_xml.get_widget("devices_tv") + self.discovered = gtk.ListStore(gobject.TYPE_STRING, + gobject.TYPE_STRING) + self.devices_tv.set_model(self.discovered) + renderer = gtk.CellRendererText() + column1=gtk.TreeViewColumn("addr", renderer, text=0) + column2=gtk.TreeViewColumn("name", renderer, text=1) + self.devices_tv.append_column(column1) + self.devices_tv.append_column(column2) + + self.quit_button = self.main_window_xml.get_widget("quit_button") + self.scan_button = self.main_window_xml.get_widget("scan_button") + self.chat_button = self.main_window_xml.get_widget("chat_button") + self.send_button = self.main_window_xml.get_widget("send_button") + self.main_text = self.main_window_xml.get_widget("main_text") + self.text_buffer = self.main_text.get_buffer() + + self.input_tb = self.main_window_xml.get_widget("input_tb") + + self.listed_devs = [] + + self.chat_button.set_sensitive(False) + + self.peers = {} + self.sources = {} + self.addresses = {} + + # the listening sockets + self.server_sock = None + +# --- gui signal handlers + + def quit_button_clicked(self, widget): + gtk.main_quit() + + def scan_button_clicked(self, widget): + self.quit_button.set_sensitive(False) + self.scan_button.set_sensitive(False) +# self.chat_button.set_sensitive(False) + + self.discovered.clear() + for addr, name in bluetooth.discover_devices (lookup_names = True): + self.discovered.append ((addr, name)) + + self.quit_button.set_sensitive(True) + self.scan_button.set_sensitive(True) +# self.chat_button.set_sensitive(True) + + def send_button_clicked(self, widget): + text = self.input_tb.get_text() + if len(text) == 0: return + + for addr, sock in self.peers.items(): + sock.send(text) + + self.input_tb.set_text("") + self.add_text("\nme - %s" % text) + + def chat_button_clicked(self, widget): + (model, iter) = self.devices_tv.get_selection().get_selected() + if iter is not None: + addr = model.get_value(iter, 0) + if addr not in self.peers: + self.add_text("\nconnecting to %s" % addr) + self.connect(addr) + else: + self.add_text("\nAlready connected to %s!" % addr) + + def devices_tv_cursor_changed(self, widget): + (model, iter) = self.devices_tv.get_selection().get_selected() + if iter is not None: + self.chat_button.set_sensitive(True) + else: + self.chat_button.set_sensitive(False) + +# --- network events + + def incoming_connection(self, source, condition): + sock, info = self.server_sock.accept() + address, psm = info + + self.add_text("\naccepted connection from %s" % str(address)) + + # add new connection to list of peers + self.peers[address] = sock + self.addresses[sock] = address + + source = gobject.io_add_watch (sock, gobject.IO_IN, self.data_ready) + self.sources[address] = source + return True + + def data_ready(self, sock, condition): + address = self.addresses[sock] + data = sock.recv(1024) + + if len(data) == 0: + self.add_text("\nlost connection with %s" % address) + gobject.source_remove(self.sources[address]) + del self.sources[address] + del self.peers[address] + del self.addresses[sock] + sock.close() + else: + self.add_text("\n%s - %s" % (address, str(data))) + return True + +# --- other stuff + + def cleanup(self): + self.hci_sock.close() + + def connect(self, addr): + sock = bluetooth.BluetoothSocket (bluetooth.L2CAP) + try: + sock.connect((addr, 0x1001)) + except bluez.error, e: + self.add_text("\n%s" % str(e)) + sock.close() + return + + self.peers[addr] = sock + source = gobject.io_add_watch (sock, gobject.IO_IN, self.data_ready) + self.sources[addr] = source + self.addresses[sock] = addr + + + def add_text(self, text): + self.text_buffer.insert(self.text_buffer.get_end_iter(), text) + + def start_server(self): + self.server_sock = bluetooth.BluetoothSocket (bluetooth.L2CAP) + self.server_sock.bind(("",0x1001)) + self.server_sock.listen(1) + + gobject.io_add_watch(self.server_sock, + gobject.IO_IN, self.incoming_connection) + + def run(self): + self.text_buffer.insert(self.text_buffer.get_end_iter(), "loading..") + self.start_server() + gtk.main() + +if __name__ == "__main__": + gui = BluezChatGui() + gui.run() |
