#!/usr/bin/python2 #MythVantage osd message deamon. #Use the client to send messages to localhost import socket import sys import os import pickle import operator import threading import time import aosd import ConfigParser import multiprocessing import subprocess,signal sys.path.append('/etc') server_address = '/run/msg_socket' class msg_aosd(): def scroll(self,osd, width, height, display_time,position): pos = position step = 1 ypad = 0 osd.set_position(pos, width, height) (x, y, _, _) = osd.get_geometry() osd.set_position_offset(width, height) osd.set_geometry(2000, y, width, height) osd.show() x -= 1 if pos < 3: #top positions 0 to 2 y -= height; for i in range(1, height + 1 + ypad, step): osd.loop_for(5) y += step osd.set_geometry(x, y, width, height) (x, y, _, _) = osd.get_geometry() #time to display osd.loop_for(display_time) for i in range(height + 1 + ypad, 0, -step): y -= step osd.set_geometry(x, y, width, height); osd.loop_for(1); elif pos < 6: #middle positions 3 to 5 y += height; for i in range(1, height, step): osd.loop_for(5) y -= step osd.set_geometry(x, y, width, i) (x, y, _, _) = osd.get_geometry() #time to display osd.loop_for(display_time) for i in range(height, 0, -step): y += step osd.set_geometry(x, y, width, i); osd.loop_for(1); else: #bottom positions 6 to 8 y += height; for i in range(1, height + 1 + ypad, step): osd.loop_for(5) y -= step osd.set_geometry(x, y, width, height) (x, y, _, _) = osd.get_geometry() #time to display osd.loop_for(display_time) for i in range(height + 1 + ypad, 0, -step): y += step osd.set_geometry(x, y, width, height); osd.loop_for(1); osd.hide(); def setup(self,font_color,font_type): osd = aosd.AosdText() osd.set_transparency(aosd.TRANSPARENCY_COMPOSITE) if osd.get_transparency() != aosd.TRANSPARENCY_COMPOSITE: osd.set_transparency(aosd.TRANSPARENCY_NONE) osd.geom_x_offset = 10 osd.geom_y_offset = 0 osd.back_color = "white" osd.back_opacity = 25 osd.shadow_color = "black" osd.shadow_opacity = 127 osd.shadow_x_offset = 2 osd.shadow_y_offset = 2 osd.fore_color = font_color osd.fore_opacity = 255 osd.set_font(font_type) osd.wrap = aosd.PANGO_WRAP_WORD_CHAR osd.alignment = aosd.PANGO_ALIGN_LEFT osd.set_layout_width(osd.get_screen_wrap_width()) return osd def set_string(self, osd, text): osd.set_text(text) return osd.get_text_size() def setup_config(self): module_config = ConfigParser.RawConfigParser() try: module_config.read('/usr/MythVantage/etc/msg.cfg') except: pass return module_config def display (self,flags,display_time=-1): """ parse the msg for display. """ try: text,config_section=flags.split("|") if config_section == '': config_section="default" except: text=flags config_section="default" module_config = self.setup_config() position=6 font_color="green" font_type="Times New Roman Italic 36" if display_time <= 0 : try: display_time = int(module_config.get(config_section,"display_time")) except: display_time = 5000 pass try: position = int(module_config.get(config_section,"position")) except: pass try: font_color = module_config.get(config_section,"font_color") except: pass try: font_type = module_config.get(config_section,"font_type") except: pass #this bit of code converts a \n to EOL/BREAK textline=text.split('\\n') try: textline.remove(' ') except: pass text=chr(10).join(textline) #cmd = sub_process.Popen("/usr/bin/wall %s" % text,stdout=sub_process.PIPE,shell=True) #data = cmd.communicate()[0] osd = self.setup(font_color, font_type) width, height = self.set_string(osd, text) self.scroll(osd, width, height, display_time, position) return ("Message delivered") class msg_xosd(): """Crude wrapper for xosd_cat""" def __init__ (self): pass def set_default_values(self): self.color="yellow" self.outline="2" self.outlinecolour="black" self.shadow="0" self.shadowcolour="black" self.font="-adobe-helvetica-bold-*-*-*-34-*-*-*-*-*-*-*" return def set_parameters(self): xosd_cfg={} file_name = "/etc/osd_cat.cfg" try: config_file = open(file_name) except: set_default_values() return for line in config_file: line = line.strip() if line and line[0] is not "#" and line[-1] is not "=": var, val = line.rsplit("=", 1) val = val.split("#")[0] val = val.strip('"') xosd_cfg[var.strip()] = val.strip() self.color = xosd_cfg['color'] self.outline = xosd_cfg['outline'] self.outlinecolour = xosd_cfg['outlinecolour'] self.shadow = xosd_cfg['shadow'] self.shadowcolour = xosd_cfg['shadowcolour'] self.font = xosd_cfg['font'] def display(self,msg,display_time): self.set_parameters() cmd = "echo -e \"%s\" | DISPLAY=127.0.0.1:0 osd_cat --pos=middle --align=center --offset=200 --delay=%s --color=%s --outline=%s --outlinecolour=%s --shadow=%s --shadowcolour=%s --font=\"%s\"" %(msg,display_time,self.color,self.outline,self.outlinecolour,self.shadow,self.shadowcolour,self.font) #set a process group on the OS, so that the kill gets them all. No one survives or becomes a zombie self.p = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,preexec_fn=os.setsid) self.processID = self.p.pid stdout,stderr = self.p.communicate() def kill(self): try: os.killpg(self.processID,signal.SIGTERM) except: pass class Msg_Queue(): def __init__(self): self.msglist=[] self.msg_slot = 0 def get_msg(self): return self.msglist.pop(0) pass def add_msg(self,cmddict): #print "Adding msg to msg queue" self.inc_last_msg_slot() cmddict['slot'] = self.msg_slot self.msglist.append(cmddict) def clear_msg(self,msg_tag): #print "Clearing out list of %s" %msg_tag #loop over list in reverse for i in xrange(len(self.msglist) - 1, -1, -1): #access list by index, look at the key tag if self.msglist[i]['tag'] == msg_tag: del self.msglist[i] def clear(self): #print "Clearing out entire queue" del self.msglist[:] def sort(self,keyvalue): self.msglist.sort(key=operator.itemgetter(keyvalue)) def search(self,key,value): pass def get_queue(self): return self.msglist def get_last_msg_slot(self): return self.msg_slot def inc_last_msg_slot(self): self.msg_slot = self.msg_slot + 1 class msg_queue_runner(threading.Thread): """Threaded Queue runner for testing things""" def __init__(self, msg_queue): threading.Thread.__init__(self) self.msg_queue = msg_queue self.out_msg = msg_aosd() self.out_xosd = msg_xosd() def get_current_style(self): style = "enhanced" if os.path.exists('/etc/X11/WINDOWMANAGER'): command = ['bash', '-c', 'source /etc/X11/WINDOWMANAGER && echo $STARTUP_STYLE'] proc = subprocess.Popen(command, stdout = subprocess.PIPE) #default for line in proc.stdout: if line.strip() == "": style = "enhanced" else: style = line.strip() break proc.communicate() else: #default style = "enhanced" return style def kill_current(self): style = self.get_current_style() #print "Killing current display" if style == "enhanced": self.p.terminate() elif style == "legacy": #self.p.terminate() self.out_xosd.kill() def run(self): while True: display_time = None try: msgdict = self.msg_queue.get_msg() style = self.get_current_style() if msgdict['timeout'] == None: display_time = 3 else: display_time = msgdict['timeout'] # display message here msgtext = msgdict['msg'] if style == "enhanced": display_time = int(display_time) * 1000 self.p = multiprocessing.Process(target=self.out_msg.display, args=(msgtext,display_time)) self.p.start() self.p.join() elif style == "legacy": #display_time = int(msgdict['timeout']) self.out_xosd.display(msgtext,display_time) except: time.sleep(1) continue msg_queue = Msg_Queue() if __name__ == "__main__": # Make sure the socket does not already exist try: os.unlink(server_address) except OSError: if os.path.exists(server_address): raise # Create a UDS socket sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) # Bind the socket to the port #print >>sys.stderr, 'starting up on %s' % server_address sock.bind(server_address) #change permissions of socket os.chmod(server_address,0777) # Listen for incoming connections sock.listen(2) #start msg display thread msgthread = msg_queue_runner(msg_queue) msgthread.setDaemon(True) msgthread.start() #main loop that reads in the cmddict, never exits while True: # Wait for a connection connection, client_address = sock.accept() try: #sf = connection.makefile("r+b", bufsize=0) data = connection.recv(1024) cmddict = (pickle.loads(data)) connection.send(" Server acknowledged client \n") if cmddict['cmd'] == "msg": #add to msg_queue msg_queue.add_msg(cmddict) elif cmddict['cmd'] == 'clear': if cmddict['tag'] == '' or cmddict['tag'] == None : msg_queue.clear() else: msg_queue.clear_msg(cmddict['tag']) elif cmddict['cmd'] == 'kill': msgthread.kill_current() elif cmddict['cmd'] == 'list': q = msg_queue.get_queue() for i in q: line="-------------\n" connection.send(line) for k,v in i.iteritems(): line=" %s : %s\n" %(k,v) connection.send(line) line = "\nNumber of messages in queue: %s \n" %(len(q)) connection.send(line) #connection.send(pickle.dumps(q)) finally: # Clean up the connection connection.close()