#!/usr/bin/env python
"""
PyPanel v1.2 - Lightweight panel/taskbar for X11 window managers
Copyright (c) 2003-2004 Jon Gelo (ziljian@users.sourceforge.net)

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 2
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
"""
#----------------------------------------------------------------------------
class PyPanel(object):
#----------------------------------------------------------------------------
    #---------------------------
    def __init__(self, display):
    #---------------------------
        """ Initialize and display the panel """
        self.display   = display                   # Display obj
        self.screen    = display.screen()          # Screen obj
        self.root      = self.screen.root          # Display root
        self.depth     = self.screen.root_depth    # Screen depth
        self.gc        = self.root.create_gc()     # General gfx context
        self.clock     = None                      # Clock obj
        self.workspace = None                      # Workspace obj
        self.tasks     = {}                        # Current ws tasks
        self.colors    = {}                        # Alloc'd colors
        self.hidden    = 0                         # Panel hidden/minimized
        self.focus     = 0                         # Currently focused window
        
        # Misc. initializations
        ppinit(FONT)

        if LEFT_OBJ == "clock":
            self.clock = Task(id="left", color=self.getColor(CLOCK_COLOR))
        elif LEFT_OBJ == "workspace":
            self.workspace = Task(id="left", color=self.getColor(WS_COLOR))
        if RIGHT_OBJ == "clock":
            self.clock = Task(id="right", color=self.getColor(CLOCK_COLOR))
        elif RIGHT_OBJ == "workspace":
            self.workspace = Task(id="right", color=self.getColor(WS_COLOR))
        
        if APPICONS:
            self.name_limit = P_SPACER*3 + I_WIDTH
        else:
            self.name_limit = P_SPACER*2
            
        if SHOWLINES:
            self.lgc = self.root.create_gc(foreground = self.getColor(LINE_COLOR))
        
        if P_LOCATION:
            self.location = self.screen.height_in_pixels - P_HEIGHT
        else:
            self.location = 0
            
        global P_WIDTH
        if not P_WIDTH:
            P_WIDTH = self.screen.width_in_pixels - P_START
        
        # Create the panel window
        self.window = self.screen.root.create_window(P_START,
            self.location, P_WIDTH, P_HEIGHT, 0,
            self.depth, X.InputOutput, X.CopyFromParent,
            colormap = X.CopyFromParent,
            event_mask = (X.ExposureMask | X.ButtonPressMask |
                          X.ButtonReleaseMask))
                        
        self.setProps(self.display, self.window)
        self.root.change_attributes(event_mask=(X.PropertyChangeMask)) 
        
        if not TRANSPARENCY:
            self.window.change_attributes(background_pixel = self.getColor(BG_COLOR))
        else:
            ppshade(self.window.id, SHADE, P_START, self.location, P_WIDTH, P_HEIGHT)
        
        self.window.map()
        self.loop(self.display, self.root, self.window, self.ewmh)
        
    #--------------------------
    def setStruts(self, set=1):
    #--------------------------
        """ Set/Unset the panel struts """
        if set:
            if self.location:
                top = top_start = top_end = 0
                bottom       = P_HEIGHT
                bottom_start = P_START
                bottom_end   = P_START + P_WIDTH
            else:
                top       = P_HEIGHT
                top_start = P_START
                top_end   = P_START + P_WIDTH
                bottom = bottom_start = bottom_end = 0
            
            self.window.change_property(self._STRUT, Xatom.CARDINAL, 32,
                                        [0, 0, top, bottom])
            self.window.change_property(self._STRUTP, Xatom.CARDINAL, 32,
                                        [0, 0, top, bottom, 0, 0, 0, 0,
                                        top_start, top_end, bottom_start,
                                        bottom_end])
        else:
            self.window.change_property(self._STRUT, Xatom.CARDINAL, 32, [0,0,0,0])
            self.window.change_property(self._STRUTP, Xatom.CARDINAL, 32,
                                        [0,0,0,0,0,0,0,0,0,0,0,0])
        
    #----------------------------
    def setProps(self, dsp, win):
    #----------------------------
        """ Set general and window manager specific properties/hints """
        if dsp.intern_atom("_WINDOWMAKER_NOTICEBOARD", 1):
            self.ewmh = 0
        else:
            self.ewmh = 1
        
        win.set_wm_name("PyPanel")
        win.set_wm_class("pypanel","PyPanel")
        win.set_wm_hints(flags = Xutil.InputHint, input = 0)
        win.set_wm_normal_hints(flags = (Xutil.PPosition))
        win.change_property(dsp.intern_atom("_MOTIF_WM_HINTS"),
                            dsp.intern_atom("_MOTIF_WM_HINTS"),
                            32, [0x2, 0x0, 0x0, 0x0, 0x0])
        
        self._CHANGE_STATE    = dsp.intern_atom("WM_CHANGE_STATE")
        self._CURRENT_DESKTOP = dsp.intern_atom("_NET_CURRENT_DESKTOP")
        self._SKIP_TASKBAR    = dsp.intern_atom("_NET_WM_STATE_SKIP_TASKBAR")
        self._BELOW           = dsp.intern_atom("_NET_WM_STATE_BELOW")  
        self._ABOVE           = dsp.intern_atom("_NET_WM_STATE_ABOVE")
        self._HIDDEN          = dsp.intern_atom("_NET_WM_STATE_HIDDEN")
        self._SHADED          = dsp.intern_atom("_NET_WM_STATE_SHADED")
        self._STRUTP          = dsp.intern_atom("_NET_WM_STRUT_PARTIAL")
        self._STRUT           = dsp.intern_atom("_NET_WM_STRUT")
        self._NAME            = dsp.intern_atom("_NET_WM_NAME")
        self.openbox          = dsp.intern_atom("_OPENBOX_PID", 1)
        
        if self.ewmh:
            self._WORKSPACE_NAMES = dsp.intern_atom("_NET_DESKTOP_NAMES")             
            self._NUM_WORKSPACES  = dsp.intern_atom("_NET_NUMBER_OF_DESKTOPS")
            self._WORKSPACE       = dsp.intern_atom("_NET_WM_DESKTOP")
            self._CLIENT_LIST     = dsp.intern_atom("_NET_CLIENT_LIST")
            self._STATE           = dsp.intern_atom("_NET_WM_STATE")
            win.change_property(dsp.intern_atom("_NET_WM_WINDOW_TYPE"),
                                Xatom.ATOM, 32, [dsp.intern_atom(
                                "_NET_WM_WINDOW_TYPE_DOCK")])
            win.change_property(self._WORKSPACE, Xatom.CARDINAL, 32, [0xffffffffL])
            self.setStruts()
        else:
            self._WORKSPACE_NAMES = dsp.intern_atom("_WIN_WORKSPACE_NAMES") 
            self._NUM_WORKSPACES  = dsp.intern_atom("_WIN_WORKSPACE_COUNT")
            self._WORKSPACE       = dsp.intern_atom("_WIN_WORKSPACE")
            self._CLIENT_LIST     = dsp.intern_atom("_WIN_CLIENT_LIST")
            self._STATE           = dsp.intern_atom("_WIN_STATE")
            win.change_property(self._WORKSPACE, Xatom.CARDINAL, 16, [0])
            win.change_property(self._STATE, Xatom.CARDINAL, 16, [1])
            win.change_property(dsp.intern_atom("_WIN_LAYER"),
                                Xatom.CARDINAL, 32, [10])
            win.change_property(dsp.intern_atom("_WIN_HINTS"),
                                Xatom.CARDINAL, 32, [39])
            
    #----------------------------------------------------
    def setState(self, task, draw=0, dsp=None, win=None):
    #----------------------------------------------------
        """ Set/Update a tasks state and add it to the task list """
        try:
            state = task.obj.get_wm_state()
            if not state:
                task.state = Xutil.NormalState
            else:
                task.state = state["state"]
        except:
            return
            
        if task.state == Xutil.IconicState:
            task.color = self.getColor(MINIMIZED_COLOR)
        elif task.id == self.focus:
            task.color = self.getColor(FOCUSED_COLOR)
        else:
            task.color = self.getColor(TASK_COLOR)
            try:
                if self.ewmh:
                    if self._SHADED in task.obj.get_full_property(
                                            self._STATE, Xatom.ATOM).value:
                        task.color = self.getColor(SHADED_COLOR)
                elif task.obj.get_full_property(self._STATE,
                                                Xatom.CARDINAL).value[0] == 32:
                    task.color = self.getColor(SHADED_COLOR)
            except:
                pass
        if draw:
            x = task.x1 + P_SPACER
            if APPICONS and ppicon(win.id, task.obj.id, x,
                                   (P_HEIGHT-I_HEIGHT)/2,I_WIDTH, I_HEIGHT):
                    x += I_WIDTH+P_SPACER
            win.clear_area(x, 0, task.x2 - x, P_HEIGHT)
            dsp.sync()
            ppfont(win.id, task.color, x, P_HEIGHT, task.x2-x-P_SPACER, task.name)
        self.tasks[task.id] = task
    
    #----------------------------
    def getWS(self, task, root=0):
    #----------------------------
        """ Return the workspace number of the given task obj """
        try:
            if self.ewmh and root:
                return task.get_full_property(self._CURRENT_DESKTOP,
                                              Xatom.CARDINAL).value[0]
            return task.get_full_property(self._WORKSPACE,
                                          Xatom.CARDINAL).value[0]
        except:
            return None 
            
    #-------------------------
    def getColor(self, color):
    #-------------------------
        """ Function to get/convert/alloc a color given a single hex str """
        try:
            return self.colors[color]
        except:
            pass
            
        r = int("0x"+color[2:4],0)*257
        g = int("0x"+color[4:6],0)*257
        b = int("0x"+color[6:8],0)*257
        c = self.screen.default_colormap.alloc_color(r, g, b)
        
        if not c:
            sys.stderr.write("Error allocating color: %s\n" % color)
            return self.screen.white_pixel
        else:
            self.colors[color] = c.pixel
            return c.pixel
            
    #-----------------------
    def getName(self, task):
    #-----------------------
        """ Return the name of the given task obj """
        name = None
        try:
            if self.ewmh:
                name = task.get_full_property(self._NAME, X.AnyPropertyType)
            if not name or not self.ewmh:
                name = task.get_full_property(Xatom.WM_NAME, X.AnyPropertyType)
            if not name:
                return ""
            else:
                return name.value
        except:
            return ""
        
    #-------------------------------------
    def sendEvent(self, win, ctype, data):
    #-------------------------------------
        """ Send a ClientMessage event to the root """
        data = (data+[0]*(5-len(data)))[:5]
        ev = Xlib.protocol.event.ClientMessage(window      = win,
                                               client_type = ctype,
                                               data        = (32,(data)))
        self.root.send_event(ev, event_mask=(X.SubstructureRedirectMask |
                                             X.SubstructureNotifyMask))
                                             
    #------------------------------
    def changeWorkspace(self, num):
    #------------------------------
        """ Increase/Decrease the current workspace number by num """
        cur = self.getWS(self.root, 1)
        tot = self.root.get_full_property(self._NUM_WORKSPACES,
                                          X.AnyPropertyType).value[0] - 1
        cur += num
        if cur < 0:
            cur = tot
        elif cur > tot:
            cur = 0
            
        if self.ewmh:
            self.sendEvent(self.root, self._CURRENT_DESKTOP, [cur])
        else:
            self.sendEvent(self.root, self._WORKSPACE, [cur])
        
    #---------------------------------
    def toggleHidden(self, side=None):
    #---------------------------------
        """ Hide/Unhide the Panel """
        width = 12
        self.window.clear_area()
        if self.hidden:
            self.window.configure(x = P_START, y = self.location, width = P_WIDTH)
            self.setStruts(1)
            self.hidden = 0
            self.sendEvent(self.window, self._STATE, [0, self._BELOW])
            self.sendEvent(self.window, self._STATE, [1, self._ABOVE])
        else:
            if side == "right":
                x = self.screen.width_in_pixels - width
                self.arrow = "<"
            else:
                x = 0
                self.arrow = ">"
            
            self.hidden = 1
            self.window.configure(x = x, y = self.location, width = width)
            self.display.sync()
            ppfont(self.window.id, self.getColor(LINE_COLOR), 1, P_HEIGHT, 0, self.arrow)
            self.setStruts(0)
            self.sendEvent(self.window, self._STATE, [1, self._BELOW])
            self.sendEvent(self.window, self._STATE, [0, self._ABOVE])
            
    #----------------------------------------
    def toggleMinimize(self, task, traise=1):
    #----------------------------------------
        """ Iconify/Deiconify a task """
        if self.ewmh and not self.openbox:
            self.sendEvent(task.obj, self._STATE, [2, self._HIDDEN])
        else:
            if task.state == Xutil.NormalState:
                self.sendEvent(task.obj, self._CHANGE_STATE, [Xutil.IconicState])
            else:
                task.obj.map()
        if traise:
            self.taskRaise(task, 0)
                
    #---------------------------
    def toggleShade(self, task):
    #---------------------------
        """ Shade/Unshade a task """
        if self.ewmh:
            self.sendEvent(task.obj, self._STATE, [2, self._SHADED])
        else:
            if task.obj.get_full_property(self._STATE, Xatom.CARDINAL).value[0] == 0:
                shade = 32
            else:
                shade = 0
            task.obj.change_property(self._STATE, Xatom.CARDINAL, 16, [shade])
            task.obj.unmap()
            task.obj.map()
            
    #-------------------------
    def taskFocus(self, task):
    #-------------------------
        """ Give focus to an unfocused task else toggle minimization """
        if task.id == self.focus or task.state == Xutil.IconicState:
            self.toggleMinimize(task)
        else:
            self.taskRaise(task, 1)
            
    #----------------------------------
    def taskRaise(self, task, focus=0):
    #----------------------------------
        """ Raise a task """
        if task.state == Xutil.NormalState:
            task.obj.configure(stack_mode = X.Above)
            if focus:
                task.obj.set_input_focus(X.RevertToNone, X.CurrentTime)
    
    #----------------------------------
    def taskLower(self, task, focus=0):
    #----------------------------------
        """ Lower a task """
        if task.state == Xutil.NormalState:
            task.obj.configure(stack_mode = X.Below)
            if focus:
                task.obj.set_input_focus(X.RevertToNone, X.CurrentTime)
                
    #------------------------------------------
    def updatePanel(self, dsp, root, win, cws):
    #------------------------------------------
        """ Display the tasks, clock and workspace name on the panel """ 
        self.startx = startx = curr_x = P_SPACER
        self.endx   = P_WIDTH
        workspace   = self.workspace
        clock       = self.clock
        tasks       = self.tasks
        count       = 1
        
        if clock:
            clock.name = time.strftime(CLOCK_FORMAT, time.localtime())
            size = ppfontsize(clock.name)
            if clock.id == "left":
                self.startx = size + P_SPACER*2
                curr_x = startx + size + P_SPACER
                clock.x1 = startx
                clock.x2 = self.startx
            else:
                self.endx = P_WIDTH - size - P_SPACER*2
                clock.x1 = P_WIDTH - P_SPACER - size
                clock.x2 = self.endx
        if workspace:
            try:
                workspace.name = root.get_full_property(self._WORKSPACE_NAMES,
                                 X.AnyPropertyType).value.split("\x00")[cws]
            except:
                workspace.name = str(cws)
            size = ppfontsize(workspace.name)
            if workspace.id == "left":
                self.startx = size + P_SPACER*2
                curr_x = startx + size + P_SPACER
                workspace.x1 = startx
                workspace.x2 = self.startx
            else:
                self.endx = P_WIDTH - size - P_SPACER*2
                workspace.x1 = P_WIDTH - P_SPACER - size
                workspace.x2 = self.endx
        
        if tasks:
            task_limit = (self.endx - curr_x - P_SPACER) / len(tasks)
            name_limit = task_limit - self.name_limit
                
        # Clear the panel and add the objects
        win.clear_area()
        dsp.sync()
        if clock:
            if SHOWLINES:
                win.poly_segment(self.lgc, [(clock.x2, 0, clock.x2, P_HEIGHT)])
            ppfont(win.id, clock.color, clock.x1, P_HEIGHT, 0, clock.name)
        if workspace:
            if SHOWLINES:
                win.poly_segment(self.lgc, [(workspace.x2, 0, workspace.x2, P_HEIGHT)])
            ppfont(win.id, workspace.color, workspace.x1, P_HEIGHT, 0, workspace.name)            
        for t in tasks.values():
            x = curr_x + P_SPACER
            if APPICONS and ppicon(win.id, t.obj.id, x, (P_HEIGHT-I_HEIGHT)/2,
                                   I_WIDTH, I_HEIGHT): x += I_WIDTH+P_SPACER  
            ppfont(win.id, t.color, x, P_HEIGHT, name_limit, t.name)
            if count < len(self.tasks) and SHOWLINES:
                win.poly_segment(self.lgc, [(curr_x + task_limit, 0,
                                 curr_x + task_limit, P_HEIGHT)])
            tasks[t.id].x1 = curr_x
            tasks[t.id].x2 = task_limit + curr_x
            curr_x = task_limit + curr_x + 1
            count += 1
                
    #-------------------------------------
    def updateTasks(self, dsp, root, win):
    #-------------------------------------
        """ Update the task list for the current workspace """
        self.tasks = {}
        cws   = self.getWS(root, 1)
        tasks = root.get_full_property(self._CLIENT_LIST, X.AnyPropertyType)
        if tasks and tasks.value:
            try:
                self.focus = dsp.get_input_focus().focus.id
            except:
                pass
            for task in tasks.value:
                obj = dsp.create_resource_object("window", task)
                obj_ws = self.getWS(obj)
                if obj_ws != None and (cws == obj_ws or obj_ws == 0xffffffffL):
                    try:
                        if self._SKIP_TASKBAR in obj.get_full_property(
                            self._STATE, X.AnyPropertyType).value: continue
                    except:
                        pass
                    try:
                        tclass = obj.get_wm_class() or ()
                        for t in tclass:
                            if t in HIDE_LIST:
                                raise
                        name = self.getName(obj)
                        if name == "PyPanel":
                            continue
                    except:
                        continue
                else:
                    continue
                obj.change_attributes(event_mask=(X.PropertyChangeMask |
                                                  X.FocusChangeMask    |
                                                  X.StructureNotifyMask))
                self.setState(Task(id=task, obj=obj, name=name,
                                   tclass=tclass, x1=-1, x2=-1))
        self.updatePanel(dsp, root, win, cws)
    
    #------------------------------------
    def loop(self, dsp, root, win, ewmh):
    #------------------------------------
        """ Event loop - handle events as they occur until we're killed """
        mapped  = 1
        rpm     = dsp.intern_atom("_XROOTPMAP_ID")
        states  = [dsp.intern_atom("WM_STATE"), self._STATE]
        props   = [self._CLIENT_LIST, self._CURRENT_DESKTOP, self._WORKSPACE]   

        while 1:
            if not mapped:                
                if not TRANSPARENCY:
                    win.change_attributes(background_pixel = self.getColor(BG_COLOR))
                else:
                    ppshade(win.id, SHADE, P_START, self.location, P_WIDTH, P_HEIGHT)
                win.map()
                mapped = 1
                if ewmh:
                    self.sendEvent(win, self._STATE, [2,self._HIDDEN])
                    win.change_property(self._WORKSPACE, Xatom.CARDINAL,
                                        32, [0xffffffffL])
                                        
            while dsp.pending_events():
                e = dsp.next_event()
                if e.type == X.ButtonRelease:
                    if self.hidden:
                        self.toggleHidden()
                    elif e.event_x > self.startx and e.event_x < self.endx:
                        for t in self.tasks.values():
                            if e.event_x >= t.x1 and e.event_x <= t.x2:
                                taskButtonEvent(self, e.detail, t)
                    elif LEFT_OBJ and e.event_x < self.startx:
                        leftObjButtonEvent(self, e.detail)
                    elif RIGHT_OBJ and e.event_x > self.endx:
                        rightObjButtonEvent(self, e.detail)
                elif e.type == X.DestroyNotify and not self.hidden:
                    try:
                        del self.tasks[e.window.id]
                    except:
                        pass
                    self.updatePanel(dsp, root, win, self.getWS(root, 1))
                elif e.type == X.PropertyNotify:
                    if e.atom in props and not self.hidden:
                        self.updateTasks(dsp, root, win)
                    elif e.atom == rpm and TRANSPARENCY:
                        self.sendEvent(win, self._STATE, [2, self._HIDDEN])
                        win.unmap()
                        mapped = 0
                    if e.window.id in self.tasks:
                        if e.atom in states:
                            self.setState(self.tasks[e.window.id], 1, dsp, win)
                        elif e.atom == Xatom.WM_NAME:
                            t = self.tasks[e.window.id]
                            name = self.getName(t.obj)
                            if t.name != name:
                                t.name = name
                                x = t.x1 + P_SPACER
                                if APPICONS:
                                    if ppicon(win.id, t.obj.id, x, (P_HEIGHT-I_HEIGHT)/2,
                                      I_WIDTH, I_HEIGHT): x += I_WIDTH+P_SPACER
                                win.clear_area(x, 0, t.x2 - x, P_HEIGHT)
                                dsp.sync()
                                ppfont(win.id, t.color, x, P_HEIGHT, t.x2-x-P_SPACER, t.name)
                        elif e.atom == Xatom.WM_HINTS and APPICONS:
                            t = self.tasks[e.window.id]
                            x = t.x1 + P_SPACER
                            win.clear_area(x, 0, t.x2 - x, P_HEIGHT)
                            dsp.sync()
                            if ppicon(win.id, t.obj.id, x, (P_HEIGHT-I_HEIGHT)/2,
                                      I_WIDTH, I_HEIGHT): x += I_WIDTH+P_SPACER
                            ppfont(win.id, t.color, x, P_HEIGHT, t.x2-x-P_SPACER, t.name)
                elif e.type == X.Expose:
                    if self.hidden:
                        ppfont(win.id, self.getColor(LINE_COLOR), 1, P_HEIGHT, 0, self.arrow)
                    if e.count == 0:
                        self.sendEvent(win, self._STATE, [1, self._SKIP_TASKBAR])
                        if not self.hidden:
                            self.sendEvent(win, self._STATE, [1, self._ABOVE])
                            self.updateTasks(dsp, root, win)
                elif e.type == X.FocusIn:
                    update = [self.focus, e.window.id]
                    self.focus = e.window.id
                    for id in update:
                        if id in self.tasks:
                            self.setState(self.tasks[id], 1, dsp, win)
                   
            rs, ws, es = select.select([dsp.display.socket], [], [], 10)
            if not rs and not self.hidden and self.clock:
                now = time.strftime(CLOCK_FORMAT, time.localtime())
                if self.clock.name != now:
                    self.clock.name = now
                    win.clear_area(self.clock.x1, 0, self.clock.x2, P_HEIGHT)
                    dsp.sync()
                    ppfont(win.id, self.clock.color, self.clock.x1, P_HEIGHT, 0, now)
                    self.clock.x2 = self.clock.x1 + ppfontsize(now)

#----------------------------------------------------------------------------                

class Task(object):
    """ PyPanel task/clock/workspace object """
    def __init__(self, **kwargs): 
        self.__dict__.update(kwargs)
                            
#----------------------------------------------------------------------------
#                                  Main
#----------------------------------------------------------------------------
from distutils import sysconfig
from ppmodule import ppinit, ppshade, ppicon, ppfont, ppfontsize
from Xlib import X, display, Xatom, Xutil
import Xlib.protocol.event
import os, pwd, select, sys, time

# Default config settings for added features which may not be in .pypanelrc
P_WIDTH       = 0
HIDE_LIST     = []           # Hide apps in this list which match WM_CLASS
FOCUSED_COLOR = "0xffffff"   # Default color for focused tasks (white)
#----------------------------------------------------------------------------

if __name__ == "__main__":
    try:
        home = pwd.getpwuid(os.getuid())[5]
        if os.path.isfile("/etc/pypanelrc"):
            execfile("/etc/pypanelrc")
        if not os.path.isfile("%s/.pypanelrc" % home):
            import shutil
            src = "%s/pypanel/pypanelrc" % sysconfig.get_python_lib()
            dst = "%s/.pypanelrc" % home
            shutil.copyfile(src, dst)
            del src, dst
        execfile("%s/.pypanelrc" % home)
        del home
    except StandardError, e:
        sys.stderr.write("\nFailed to open ~/.pypanelrc -\n\n")
        sys.stderr.write(str(e)+"\n\n")
        sys.exit()
    PyPanel(display.Display())
