Commits

asypost  committed 98bb190

修复打开授权窗口卡住问题,实现异步调用

  • Participants
  • Parent commits 1f56154

Comments (0)

Files changed (4)

File attributes.py

+#encoding=utf-8
+import functools
+
+class AsyncAttribute(object):
+    '''
+    Just a attribute for determine if the function need to be called aysnc
+    '''
+    def __init__(self,func):
+        super(AsyncAttribute,self).__init__()
+        assert callable(func)
+        functools.update_wrapper(self,func)
+        self.__func=func
+
+    def __call__(self,*args,**kwargs):
+        return self.__func(*args,**kwargs)

File core/decorators.py

 import functools
 from threading import Thread
 
-
 def debug(func):
     logger=logging.getLogger("Debugger")
     @functools.wraps(func)
     return _
 
 try:
-    from gi.repository import GLib
+    from gi.repository import GLib,Gdk
+    #init glib and gdk threads support
+    GLib.threads_init()
+    Gdk.threads_init()
     idle_add=GLib.idle_add
 except:
     try:
         import gtk
+        #init gtk threads support
+        gtk.threads_init()
         idle_add=gtk.idle_add
     except:
         idle_add=None
             def __(*args,**kwargs):
                 return callback(func(*args,**kwargs))
             return __
-        return _
+        return _
 from gi.repository import GLib
 from core.decorators import debug
 from notify import Notification
+import json
+from attributes import AsyncAttribute
+from core.decorators import async
 
 GLib.threads_init()
 Gdk.threads_init()
 FORMAT = '[%(levelname)s] %(name)s: %(message)s'
 
 logging.basicConfig(format=FORMAT,level=logging.DEBUG)
-logger=logging.getLogger("SinaWeibo")
+logger=logging.getLogger("UIHandler")
 
 class WeiboUI(URIHandler):
     protocol="ui://"
         self.main_window=Gtk.Window()
         self.main_window.set_icon_name("gwibber")
         self.main_window.set_title(_("Sina micorblog"))
-        self.main_window.set_default_size(550,600)
+        self.main_window.set_default_size(970,600)
 
         self.weibo_view=WebUIView()
         self.weibo_view.register_uri_handler(self)
         self.scrolled_window.add(self.weibo_view)
 
         template=open(os.path.join(config.resources_dir,"index.html")).read()
-        self.weibo_view.load_string(template,"text/html","UTF-8","file://"+os.path.join(config.resources_dir,"index.html"))
+        self.weibo_view.load_string(template,"text/html","UTF-8","file://"+\
+            os.path.join(config.resources_dir,"index.html"))
 
         self.main_window.show_all()
 
         self.__connect_signals()
 
+    def pending_response(self,request,response):
+        response_json=json.dumps({"request_id":request.id,"data":response})
+        self.weibo_view.execute_script("Native.Contact.pendingResponse({0})".format(response_json))
+
+    def handle_request_async(self,client,request):
+        data=client.do_request(request)
+        return request,data
+
     def handle_uri(self,uri,*args,**kwargs):
-        ret=False
         if self.is_support(uri):
             request=Request.from_uri(uri)
             args=request.params
             action=action_array[0] if action_array else None
             try:
                 if action:
-                    ret= getattr(self,action)(**args)
+                    if isinstance(action,AsyncAttribute):
+                        async(self.handle_request_async)(action)(**args)
+                    else:
+                        data= getattr(self,action)(**args)
+                        self.pending_response(request,data)
             except Exception as e:
                 logger.error("Call {0}({1}) error:{2}".format(action,args,e))
-        if ret==False:
-            logger.warn("Not supported uri:{0}".format(uri))
-        return ret
 
     def is_support(self,uri):
         ret=False
 
     @debug
     def show_authorize_dialog(self,auhorize_url,code_url,callback):
-        logger.warn("start Authorize dialog")
-        Gdk.threads_enter()
+        logger.debug("start Authorize dialog")
         dialog=AuthorizeDialog(self.main_window)
         if dialog.open(auhorize_url,code_url)==Gtk.ResponseType.ACCEPT:
-            #self.weibo_view.open("weibo://get_access_token?code="+(dialog.code if dialog.code else ""))
             code=dialog.code if dialog.code else ""
             self.weibo_view.execute_script("{0}('{1}');".format(callback,code))
         dialog.destroy()
-        Gdk.threads_leave()
 
     def get_notification(self):
         return Notification(_("Sina Micorblog"))
     def __init__(self, url,parent=None):
         super(ImageViewer, self).__init__()
         self.pixbuf_loader=None
+        self.url=url
         self.running=True
         if parent:
             self.set_transient_for(parent)
+        self.main_box=Gtk.Box.new(Gtk.Orientation.VERTICAL,0)
         self.set_default_size(600,400)
         self.set_title(_("Image"))
-        self.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
+        self.set_position(Gtk.WindowPosition.CENTER)
         self.image_view=Gtk.Image.new()
         view_port=Gtk.Viewport()
         scrolled_window=Gtk.ScrolledWindow()
-        scrolled_window.add(view_port)
         view_port.add(self.image_view)
-        self.add(scrolled_window)
-        self.image_view.show()
-        self.start_download(url)
+        scrolled_window.add(view_port)
+
+        #toolbar
+        self.toolbar=Gtk.Toolbar()
+        self.main_box.pack_start(self.toolbar,False,True,0)
+        self.tool_save_button=Gtk.ToolButton.new_from_stock(Gtk.STOCK_SAVE)
+        self.toolbar.insert(self.tool_save_button,0)
+        #save signal
+        self.tool_save_button.connect("clicked",self.on_save_button_clicked)
+        self.main_box.pack_start(scrolled_window,True,True,0)
+        self.add(self.main_box)
+        self.start_download(self.url)
         self.connect("destroy",self.on_destroy)
 
+    def on_save_button_clicked(self,widget,data=None):
+        if self.url:
+            dialog=Gtk.FileChooserDialog(_("Save Image"),
+                                             self,
+                                             Gtk.FileChooserAction.SAVE,
+                                             (Gtk.STOCK_CANCEL,Gtk.ResponseType.CANCEL,
+                                             Gtk.STOCK_SAVE,Gtk.ResponseType.ACCEPT))
+            dialog.set_do_overwrite_confirmation(True)
+            if dialog.run()==Gtk.ResponseType.ACCEPT:
+                filename=dialog.get_filename()
+                ext=os.path.split(self.url)[1]
+                filename+=ext;
+                try:
+                    def run():
+                        data=urllib2.urlopen(self.url).read()
+                        f=open(filename,"wb")
+                        f.write(data)
+                        f.close()
+                    downloader=Thread()
+                    downloader.run=run
+                    downloader.start()
+                except Exception,e:
+                    message_dialog=Gtk.MessageDialog(self.main_window,Gtk.DialogFlags.DESTROY_WITH_PARENT,
+                          Gtk.MessageType.ERROR,Gtk.ButtonsType.OK,_("Save Image Failed"))
+                    message_dialog.set_title(_("Sina micorblog"))
+                    message_dialog.run()
+                    message_dialog.destroy()
+                    logger.log(e)
+            dialog.destroy()
+
+
     def on_destroy(self,data=None):
         self.running=False
         if self.pixbuf_loader:
         self.pixbuf_loader.write(data)
 
     def on_image_downloaded(self):
+        print("download finished")
         self.update_image(self.pixbuf_loader)
         self.pixbuf_loader.close()
         self.pixbuf_loader=None
 from core.decorators import debug
 import os
 import urllib2
+import json
 from notify import Notification
+from attributes import AsyncAttribute
+from core.decorators import async
 
 gtk.gdk.threads_init()
 gtk.threads_init()
 FORMAT = '[%(levelname)s] %(name)s: %(message)s'
 
 logging.basicConfig(format=FORMAT,level=logging.DEBUG)
-logger=logging.getLogger("SinaWeibo")
+logger=logging.getLogger("UIHandler")
 
 class WeiboUI(URIHandler):
     protocol="ui://"
 
         self.__connect_signals()
 
+    def pending_response(self,request,response):
+        response_json=json.dumps({"request_id":request.id,"data":response})
+        self.weibo_view.execute_script("Native.Contact.pendingResponse({0})".format(response_json))
+
+    def handle_request_async(self,client,request):
+        data=client.do_request(request)
+        return request,data
+
     def handle_uri(self,uri,*args,**kwargs):
-        ret=False
         if self.is_support(uri):
             request=Request.from_uri(uri)
             args=request.params
             action=action_array[0] if action_array else None
             try:
                 if action:
-                    ret= getattr(self,action)(**args)
+                    if isinstance(action,AsyncAttribute):
+                        async(self.handle_request_async)(action)(**args)
+                    else:
+                        data= getattr(self,action)(**args)
+                        self.pending_response(request,data)
             except Exception as e:
                 logger.error("Call {0}({1}) error:{2}".format(action,args,e))
-        if ret==False:
-            logger.warn("Not supported uri:{0}".format(uri))
-        return ret
 
     def is_support(self,uri):
         ret=False
 
     @debug
     def show_authorize_dialog(self,auhorize_url,code_url,callback):
-        logger.warn("start Authorize dialog")
-        gtk.threads_enter()
+        logger.debug("start Authorize dialog")
         dialog=AuthorizeDialog(self.main_window)
         if dialog.open(auhorize_url,code_url)==gtk.RESPONSE_ACCEPT:
-            #self.weibo_view.open("weibo://get_access_token?code="+(dialog.code if dialog.code else ""))
             code=dialog.code if dialog.code else ""
             self.weibo_view.execute_script("{0}('{1}');".format(callback,code))
         dialog.destroy()
-        gtk.threads_leave()
 
     def get_notification(self):
         return Notification(_("Sina Micorblog"))