Advertisement
Guest User

gtkdeko

a guest
Jul 24th, 2016
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 17.51 KB | None | 0 0
  1. #!/usr/bin/env python2
  2. # -*- Encoding: UTF-8 -*-
  3.  
  4. import gtk
  5. import gtk.gdk
  6. import gobject
  7. import json
  8. import os
  9. import datetime
  10. import time
  11. import subprocess
  12. import threading
  13. #import pynotify
  14. from Queue import Queue
  15.  
  16. # use process to exec/call wmctrl -l -G and parse fields (0-7), 0 - w_id hex integer, 1 - PID = PID of the window as decimal integer, 2 - x-offset, 3 - y-offset, 4 - width, 5 - height, 6 - client machine name, 7 - Window title (with spacecs(possibly))
  17.  
  18.  
  19. UPDATE_TIMEOUT = 1 # in seconds
  20. APP_TITLE="Deko"
  21. _lock = threading.Lock()
  22.  
  23. class objectview(object):
  24.     def __init__(self, d):
  25.         self.__dict__ = d
  26.  
  27. class Launchers:
  28.     def __init__(self):
  29.         self._item = 0
  30.         self._deets = []
  31.  
  32.     def add_launcher(self,name,stream="source",ref=0):
  33.         fing={"item":self._item,"name":name,"state":0,"proc":0,"sven":"nada","ref":ref,"stream":stream}
  34.         self._item+=1
  35.         self._deets.append(objectview(fing))
  36.  
  37.     def count(self):
  38.         return len(self._deets)
  39.  
  40.     def lol(self):
  41.         return self._deets
  42.  
  43. def info(*args):
  44.     with _lock:
  45.         print("%s %s" % (threading.current_thread(), " ".join(map(str, args))))
  46.  
  47. class WindowDeko(gtk.Window):
  48.   def __init__(self):
  49.       gtk.Window.__init__(self)
  50.       self.set_size_request(640,480)
  51.       self.set_border_width(10)
  52.       self.set_title(APP_TITLE)
  53.       self.treeview = gtk.TreeView()
  54.       self.fileTime = ""
  55.       vbox_app = gtk.VBox(False, 0)
  56.       self.add(vbox_app)
  57.       vbox_app.show()
  58.       self.CORE=0
  59.       self.firstPass=True
  60.   #     self.speed=["audio","mobile","low","medium","high","source"]
  61.       hbox_info = gtk.HBox(False, 0)
  62.  
  63.   ## icon in window top left
  64.       image_ref = gtk.Image()
  65.       image_ref.set_from_stock(gtk.STOCK_SELECT_COLOR,6)
  66.       image_ref.set_alignment(0, 0.5)
  67.       hbox_info.pack_start(image_ref, True, True, 0)
  68.       image_ref.show()
  69.  
  70.       label_app = gtk.Label(self.fileTime)
  71.       hbox_info.pack_start(label_app, True, True, 0)
  72.  
  73.       label_app.show()
  74.       self.legend = label_app
  75.  
  76.       vbox_app.pack_start(hbox_info, False, False, 6)
  77.       hbox_info.show()
  78.  
  79.       self.treeview.show()
  80.  
  81.       scrollTree = gtk.ScrolledWindow()
  82.       scrollTree.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
  83.       scrollTree.add(self.treeview)
  84.       scrollTree.show()
  85.  
  86.       vbox_app.pack_start(scrollTree, True, True, 6)
  87.  
  88.       hbox_close = gtk.HBox(False, 0)
  89.  
  90.       button_do = gtk.Button(stock=gtk.STOCK_MEDIA_PLAY)
  91.       button_do.connect("clicked", self.btn_show)
  92.       button_do.set_flags(gtk.CAN_DEFAULT)
  93.       hbox_close.pack_start(button_do, True, True, 0)
  94.       button_do.show()
  95.  
  96.       button_close = gtk.Button(stock=gtk.STOCK_CLOSE)
  97.       button_close.connect("clicked", lambda w: gtk.main_quit())
  98.   #     button_close.set_flags(gtk.CAN_DEFAULT)
  99.       hbox_close.pack_start(button_close, True, True, 0)
  100.       button_close.show()
  101.  
  102.       hbox_close.show()
  103.       vbox_app.pack_start(hbox_close, False, False, 6)
  104.  
  105.       # Place after association to hbox/vbox to avoid the following error:
  106.       # GtkWarning: gtkwidget.c:5460: widget not within a GtkWindow
  107.       #button_close.grab_default()
  108.       self.pastyfirst=True
  109.       self.launchers=Launchers()
  110.       self.updater = Updater()
  111.       self._update_id = None
  112.       self.popTree()
  113.       self.update()
  114.       return
  115.        
  116.   def rowActivated(self,treeview, path, column):
  117.     self.dekoIt()
  118. #     self.playIt()
  119.        
  120.   def cell_toggled(widget, path, model):
  121.       model[path][3] = not model[path][3]
  122.  
  123.   def popTree(self):
  124.     try:
  125.       holder=self.getWM("/home/sky/sktwitch")
  126.  
  127.       self.legend.set_text(self.fileTime)
  128.       notifymsg=""
  129.       cols=["W_ID","PID","x-offset","y-offset","width","height","title","deco"]
  130.       if self.firstPass==True:
  131.         self.llama = holder
  132.         self.firstPass=False
  133.         self.treeview.set_model(self.llama)
  134.         if self.treeview.get_columns():
  135.           for meany in self.treeview.get_columns():
  136.               self.treeview.remove_column(meany)
  137.  
  138.         count=0
  139.         for col in cols:
  140.           column=gtk.TreeViewColumn(col)
  141.           cell = gtk.CellRendererText()
  142.           column.pack_start(cell)
  143.           column.set_resizable(True)
  144.           column.add_attribute(cell,'text',count)
  145.           self.treeview.append_column(column)
  146.           count+=1
  147.         self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
  148.         self.treeview.connect('row-activated', self.rowActivated)
  149.         notifymsg+="\n"+" Started"
  150.       else:
  151.           # add/update current
  152.                 for entry in holder:
  153.                     exists=False
  154.                     for existing in self.llama:
  155.                         if entry[0]==existing[0]:
  156.                             exists=True
  157.                             for c in range(1,len(cols)):
  158.                                 if existing[c]!=entry[c]:
  159.                                     existing[c]=entry[c]
  160.                             break
  161.                     if exists==False:
  162.                         self.llama.append(entry)
  163.  
  164.           # remove gone
  165.                 for existing in self.llama:
  166.                     exists=False
  167.                     for entry in holder:
  168.                         if entry[0]==existing[0]:
  169.                             exists=True
  170.                             break
  171.                     if exists==False:
  172.                         self.llama.remove(existing.iter)
  173.       if notifymsg !="":
  174.           temp=0
  175.           #pynotify.init(APP_TITLE)
  176.           #notice = pynotify.Notification(APP_TITLE, notifymsg)
  177.           #notice.show()
  178.  
  179.     except OSError:
  180.         self.legend.set_text("File Error!")
  181.         info("os error")
  182.  
  183.   def XpopTree(self):
  184.     try:
  185.       holder=self.getWM("/home/sky/sktwitch")
  186.  
  187.       self.legend.set_text(self.fileTime)
  188.       notifymsg=""
  189.       if self.firstPass==True:
  190.         self.llama = holder
  191.         self.firstPass=False
  192.         self.treeview.set_model(self.llama)
  193.         column1 = gtk.TreeViewColumn("W_ID")
  194.         column2 = gtk.TreeViewColumn("PID")
  195.         column3 = gtk.TreeViewColumn("x-offset")
  196.         column4 = gtk.TreeViewColumn("y-offset")
  197.         column5 = gtk.TreeViewColumn("width")
  198.         column6 = gtk.TreeViewColumn("height")
  199.         column7 = gtk.TreeViewColumn("title")
  200.         cell1 = gtk.CellRendererText()
  201.         cell2 = gtk.CellRendererText()
  202.         cell3 = gtk.CellRendererText()
  203.         cell4 = gtk.CellRendererText()
  204.         cell5 = gtk.CellRendererText()
  205.         cell6 = gtk.CellRendererText()
  206.         cell7 = gtk.CellRendererText()
  207. ##              cell4.set_property('alignment',2)
  208. ##              cell5.set_property('alignment',2)
  209.         #       cell4.add_attribute(cellrenderer_pixbuf, "stock-id", 1)
  210.         #       cell4.connect("toggled", cell_toggled, self.llama)
  211.         #       cell4.set_property('activatable', True)
  212.         #       cell4.set_property('active', True)
  213.         column1.pack_start(cell1)
  214.         column2.pack_start(cell2)
  215.         column3.pack_start(cell3)
  216.         column4.pack_start(cell4)
  217.         column5.pack_start(cell5)
  218.         column6.pack_start(cell6)
  219.         column7.pack_start(cell7)
  220.  
  221.         column1.set_resizable(True)
  222.         column1.add_attribute(cell1,'text',0)
  223.  
  224.         column2.set_resizable(True)
  225.         column2.add_attribute(cell2,'text',1)
  226.  
  227.         column3.set_resizable(True)
  228.         column3.add_attribute(cell3,'text',2)
  229.  
  230.         column4.set_resizable(True)
  231.         column4.add_attribute(cell4,'text',3)
  232.  
  233.         column5.set_resizable(True)
  234.         column5.add_attribute(cell5,'text',4)
  235.  
  236.         column6.set_resizable(True)
  237.         column6.add_attribute(cell6,'text',5)
  238.  
  239.         column7.set_resizable(True)
  240.         column7.add_attribute(cell7,'text',6)
  241.  
  242.         if self.treeview.get_columns():
  243.           for meany in self.treeview.get_columns():
  244.               self.treeview.remove_column(meany)
  245.         self.treeview.append_column(column1)
  246.         self.treeview.append_column(column2)
  247.         self.treeview.append_column(column3)
  248.         self.treeview.append_column(column4)
  249.         self.treeview.append_column(column5)
  250.         self.treeview.append_column(column6)
  251.         self.treeview.append_column(column7)
  252.  
  253.         self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
  254.         self.treeview.connect('row-activated', self.rowActivated)
  255.         notifymsg+="\n"+" Started"
  256.       else:
  257.           # add/update current
  258.           for entry in holder:
  259.               exists=False
  260.               for existing in self.llama:
  261.                   if entry[0]==existing[0]:
  262.                       exists=True
  263.                       existing[1]=entry[1]
  264.                       existing[2]=entry[2]
  265.                       existing[4]=entry[4]
  266.                       break
  267.               if exists==False:
  268.                   self.llama.append([entry[0],entry[1],entry[2],"■",entry[4]])
  269.                   if notifymsg!="":
  270.                       notifymsg+="\n"
  271.                   notifymsg+="{ +++ } "+entry[0]+", now streamering "+entry[1]+"."
  272.  
  273.           # remove gone
  274.           for existing in self.llama:
  275.               exists=False
  276.               for entry in holder:
  277.                   if entry[0]==existing[0]:
  278.                       exists=True
  279.                       break
  280.               if exists==False:
  281.                   if notifymsg!="":
  282.                       notifymsg+="\n"
  283.                   notifymsg+=") --- ( "+existing[0]+" removed from streamers"
  284.                   self.llama.remove(existing.iter)
  285.       if notifymsg !="":
  286.           temp=1
  287.           #pynotify.init(APP_TITLE)
  288.           #notice = pynotify.Notification(APP_TITLE, notifymsg)
  289.           #notice.show()
  290.  
  291.     except OSError:
  292.         self.legend.set_text("File Error!")
  293.         info("os error")
  294.  
  295.   def modification_date(self,filename):
  296.       t = os.path.getmtime(filename)
  297.       return datetime.datetime.fromtimestamp(t)
  298.  
  299.   def getWM(self,json_file):
  300.     store=gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING)
  301.     root = gtk.gdk.get_default_root_window()
  302.     for id in root.property_get('_NET_CLIENT_LIST')[2]:
  303.         w = gtk.gdk.window_foreign_new(id)
  304.         if w:
  305.             dc=w.get_decorations()
  306.             dekod=""
  307.             dsep=""
  308.             for dek in dc.value_names:
  309.               dekod+=dsep+dek
  310.               dsep=","
  311.  
  312.             d=w.property_get('WM_NAME')
  313.             p=w.property_get('WM_PID')
  314.             if d:
  315.               if not p is None:
  316.                 print p
  317.               geo=w.get_geometry()
  318.               pos=w.get_origin()
  319.               b1,b2=pos
  320.               a1,a2,a3,a4,a5=geo
  321.               c1,c2,c3=d
  322.              # outee={"wid":str(id),"pid":str(p),"x":str(b1),"y":str(b2),"w":str(a3),"h":,"mac":"this","title":c3}
  323. #                if d[2]==q:
  324. #                    w.set_decorations(p)
  325. #                    gtk.gdk.window_process_all_updates()
  326.               store.append([str(id),str(p),str(b1),str(b2),str(a3),str(a4),c3,dekod])
  327.  
  328.     return store
  329.  
  330.   def getList(self,json_file):
  331.       store=gtk.ListStore(gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING,gobject.TYPE_STRING)
  332.       tim=self.modification_date(json_file)
  333.       self.fileTime=str(tim.year) + "-" + str(tim.month).zfill(2) + "-" + str(tim.day).zfill(2) + " " + str(tim.hour).zfill(2) + ":" + str(tim.minute).zfill(2)
  334.       json_data=open(json_file)
  335.       data = json.load(json_data)
  336.       json_data.close()
  337.        
  338.       streams=json.loads(data)
  339.       for streamer in streams["streams"]:
  340.       # print str(streamer["viewers"])
  341.           store.append([streamer["channel"]["display_name"],streamer["channel"]["game"],streamer["channel"]["status"],"■",str(streamer["viewers"])])
  342.  
  343.       return store
  344.  
  345.   def btn_force(self,evt):
  346.       self.legend.set_text("Forcing Update From Twitch.tv!")
  347.       self.launchers.add_launcher(".")
  348.  
  349.   def btn_refresh(self,evt):
  350.       self.do_Refresh()
  351.  
  352.   def do_Refresh(self):
  353.       self.legend.set_text("Refreshing!")
  354.       self.CORE=0
  355.       self.popTree()
  356.  
  357.   def btn_hide(self,evt):
  358.       print "STOP FOR WHAT"
  359.  
  360.   def btn_show(self,evt):
  361.       # what to do with evt??
  362.     self.dekoIt()
  363. #     self.playIt()
  364.    
  365.   def playIt(self):
  366.       self.pastyfirst=True
  367.       tree_selection = self.treeview.get_selection()
  368.       (model, pathlist) = tree_selection.get_selected_rows()
  369.       for path in pathlist :
  370.           tree_iter = model.get_iter(path)
  371.           name = model.get_value(tree_iter,0)
  372.           stat = model.get_value(tree_iter,3)
  373.           if stat == "■":
  374.   #         print "in name:" + name
  375.               ref=gtk.TreeRowReference(model,path)
  376.               SetCell(ref,"▶")
  377.               self.launchers.add_launcher(name,self.speed[self.combo.get_active()],ref)
  378.  
  379.   def dekoIt(self):
  380.     tree_selection = self.treeview.get_selection()
  381.     (model, pathlist) = tree_selection.get_selected_rows()
  382.     for path in pathlist :
  383.       tree_iter = model.get_iter(path)
  384.       wid = model.get_value(tree_iter,0)
  385.       nam = model.get_value(tree_iter,6)
  386.       root = gtk.gdk.get_default_root_window()
  387.       for id in root.property_get('_NET_CLIENT_LIST')[2]:
  388.           if str(id)==wid:
  389.             w = gtk.gdk.window_foreign_new(id)
  390.             if w:
  391.               dc=w.get_decorations()
  392.               dekod=False
  393.               for dek in dc.value_names:
  394.                   dekod=True
  395.               w.set_decorations(not dekod)
  396.               gtk.gdk.window_process_all_updates()
  397.               break
  398.  
  399.   def update(self):
  400.       lcount=self.launchers.count()
  401.       self.popTree() #info("Updatng", 0)
  402.       #info( str(self.CORE)+" U:" , lcount)
  403.       self.CORE+=1
  404.       if self.CORE==60: # one minute try quicker gtkdeko
  405.           self.CORE=0
  406.           self.do_Refresh()
  407.  
  408.       deletes=[]
  409.       if self.pastyfirst==True:
  410.           self.pastyfirst=False
  411.       else:
  412.           if lcount>0:
  413.               rCount=" - "
  414.   # fing={"item":self._item,"name":name,"state":0,"proc":0,"sven":"nada","ref":ref,"stream":stream}
  415.               for launcher in self.launchers._deets:
  416.                   rCount+=str(launcher.item)
  417.                   if launcher.state==0:
  418.                       rCount+=" - yah"
  419.                       launcher.state=1
  420.                       if self._update_id is not None:
  421.                           gobject.source_remove(self._update_id)
  422.  
  423.                       self.updater.add_update(self.done_updating,launcher) # returns immediately
  424.  
  425.                   elif launcher.state==1:
  426.                       rCount+=" - snf"
  427.  
  428.                   elif launcher.state==2:
  429.                       if self._update_id is not None:
  430.                           gobject.source_remove(self._update_id)
  431.  
  432.                       self.updater.add_update(self.done_updating,launcher) # returns immediately
  433.                       rCount+=" - **["+launcher.sven+"]**"
  434.  
  435.                   elif launcher.state==3:
  436.                       if self._update_id is not None:
  437.                           gobject.source_remove(self._update_id)
  438.  
  439.                       self.updater.add_update(self.done_updating,launcher) # returns immediately
  440.  
  441.                       rCount+=" - **["+launcher.sven+"]**"
  442.  
  443.                   elif launcher.state==5:
  444.                       launcher.state=6
  445.                       rCount+=" - pop"
  446.                       print "popping"
  447.                       self.popTree()
  448.  
  449.                   elif launcher.state==6:
  450.                       rCount+="fin."
  451.                       deletes.append(launcher)
  452.                   rCount+=", "
  453.               info( "Poll("+rCount+")")
  454.  
  455.       if len(deletes)>0:
  456.           for launcher in deletes:
  457.               if launcher.ref!=0:
  458.                   SetCell(launcher.ref,"■")
  459.               self.launchers._deets.remove(launcher)
  460.  
  461.       # call in UPDATE_TIMEOUT seconds
  462.       self._update_id = gobject.timeout_add(
  463.           int(UPDATE_TIMEOUT*1000), self.update)
  464.  
  465.   def done_updating(self, task_id,args):
  466.       a=True
  467.   #     info('done updating', task_id)
  468.   #     info('dbata',args.state)
  469.       #self.button.set_label("done updating %s" % task_id)
  470.  
  471. def SetCell(ref,txt):
  472.     # also check if ref is valid()
  473.     path=ref.get_path()
  474.     model=ref.get_model()
  475.  
  476.     tree_iter = model.get_iter(path)
  477.  
  478.     line = txt.replace("\n", "")
  479.     model.set_value(tree_iter,3,line)
  480.  
  481. class Updater:
  482.   def __init__(self):
  483.     self._task_id = 0
  484.     self._queue = Queue(maxsize=100) #NOTE: GUI blocks if queue is full
  485.     for _ in range(9):
  486.       t = threading.Thread(target=self._work)
  487.       t.daemon = True
  488.       t.start()
  489.  
  490.   def _work(self):
  491.         # executed in background thread
  492. #   fing={"item":self._item,"name":name,"state":0,"proc":0,"sven":"nada","ref":ref,"stream":stream}
  493.     for task_id, done, args in iter(self._queue.get, None):
  494.       if args[0].state==1:
  495.         if args[0].name==".":
  496.           print "forced"
  497.                     #info("Forcing Update.")
  498.           args[0].state=2
  499.           args[0].proc = subprocess.Popen('/home/sky/Documents/sktwitch.py',shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE)
  500.         else:
  501.           SetCell(args[0].ref,"Launching "+args[0].name+"'s Live Stream")
  502.           args[0].state=2
  503.           #                 args[0].proc = subprocess.Popen('livestreamer -p vlc twitch.tv/'+args[0].name+' '+args[0].stream,shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE)
  504.           args[0].proc = subprocess.Popen('hexchat --existing --command="join #'+args[0].name.lower()+'"; livestreamer -p vlc twitch.tv/'+args[0].name+' '+args[0].stream,shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE)
  505.  
  506.       elif args[0].state==2:
  507.           args[0].state=3
  508.  
  509.       elif args[0].state==3:
  510.           args[0].state=99
  511.           nextline = None
  512.           buf = ''
  513.           while True:
  514.               #--- extract line using read(1)
  515.               try:
  516.                   out = args[0].proc.stdout.read(1)
  517.               except AttributeError:
  518.                   break
  519.               if out == '' and args[0].proc.poll() != None: break
  520.               if out != '':
  521.                   buf += out
  522.                   if out == '\n':
  523.                       nextline = buf
  524.                       buf = ''
  525.               if not nextline: continue
  526.               line = nextline
  527.               nextline = None
  528.  
  529.               #---  eol or eof reached
  530.               #info(args[0].name,':', line)
  531.       #                 args[0].sven=line
  532.               #--- do something with line, maybe?
  533.  
  534.       #             (model, pathlist) = tree_selection.get_selected_rows()
  535.       #             for path in pathlist :
  536.               if args[0].ref!=0:
  537.                   SetCell(args[0].ref,line)
  538.  
  539.           if args[0].name==".":
  540.               args[0].state=5
  541.           else:
  542.               args[0].state=6
  543.       #             #info(args[0].state,"{ - ",args[0].name," - }")
  544.  
  545.       elif args[0].state==6:
  546.           dummy=1
  547.           #info(" O V A H ")
  548.  
  549.       # signal task completion; run done() in the main thread
  550.       gobject.idle_add(done, *((task_id,) + args))
  551.    
  552.   def add_update(self, callback, *args):
  553.       # executed in the main thread
  554.       self._task_id += 1
  555.       self._queue.put((self._task_id, callback, args))
  556.  
  557. gobject.threads_init() # init threads?
  558.  
  559. win = WindowDeko()
  560. win.connect("delete-event", gtk.main_quit)
  561. win.show_all()
  562.  
  563. gtk.main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement