📄 posix_x11.py
字号:
def run(self): self.DebugPrint('thread started') # main loop event = _XEvent() data = '' while not self.loop_break: pending = self.x11.XPending(self.disp) if not pending: self.loop_event.wait(self.loop_timeout) if self.loop_event.isSet(): self.loop_timeout = 0.0001 elif self.loop_timeout < 1.0: self.loop_timeout *= 2 self.loop_event.clear() continue self.loop_timeout = 0.0001 for i in xrange(pending): self.x11.XLockDisplay(self.disp) self.x11.XNextEvent(self.disp, byref(event)) self.x11.XUnlockDisplay(self.disp) if event.type == _ClientMessage: if event.xclient.format == 8: if event.xclient.message_type == self.atom_msg_begin: data = str(event.xclient.data) elif event.xclient.message_type == self.atom_msg: if data != '': data += str(event.xclient.data) else: print 'Warning! Middle of message received with no beginning!' else: continue if len(event.xclient.data) != 20 and data: self.notify(data.decode('utf-8')) data = '' elif event.type == _PropertyNotify: if self.x11.XGetAtomName(self.disp, event.xproperty.atom) == '_SKYPE_INSTANCE': if event.xproperty.state == _PropertyNewValue: self.win_skype = self.get_skype() # changing attachment status can cause an event handler to be fired, in # turn it could try to call Attach() and doing this immediately seems to # confuse Skype (command '#0 NAME xxx' returns '#0 CONNSTATUS OFFLINE' :D); # to fix this, we give Skype some time to initialize itself time.sleep(1.0) self.SetAttachmentStatus(apiAttachAvailable) elif event.xproperty.state == _PropertyDelete: self.win_skype = None self.SetAttachmentStatus(apiAttachNotAvailable) self.DebugPrint('thread finished') def _error_handler(self, disp, error): # called from within Xlib when error occures self.error = error.contents.error_code self.DebugPrint('Xlib error', self.error) # stop all pending commands for command in self.Commands.values(): if hasattr(command, '_event'): command._event.set() return 0 def error_check(self): '''Checks last Xlib error and raises an exception if needed.''' if self.error != None: if self.error == 3: # BadWindow self.win_skype = None self.SetAttachmentStatus(apiAttachNotAvailable) buf = create_string_buffer(256) self.x11.XGetErrorText(self.disp, self.error, buf, 256) error = ISkypeAPIError('X11 error: %s' % buf.value) self.error = None raise error def get_skype(self): '''Returns Skype window ID or None if Skype not running.''' skype_inst = self.x11.XInternAtom(self.disp, '_SKYPE_INSTANCE', True) type_ret = Atom() format_ret = c_int() nitems_ret = c_ulong() bytes_after_ret = c_ulong() winp = pointer(Window()) fail = self.x11.XGetWindowProperty(self.disp, self.win_root, skype_inst, 0, 1, False, 33, byref(type_ret), byref(format_ret), byref(nitems_ret), byref(bytes_after_ret), byref(winp)) if not fail and self.error == None and format_ret.value == 32 and nitems_ret.value == 1: return winp.contents.value def Close(self): self.loop_break = True self.loop_event.set() while self.isAlive(): time.sleep(0.01) self.DebugPrint('closed') def SetFriendlyName(self, FriendlyName): self.FriendlyName = FriendlyName if self.AttachmentStatus == apiAttachSuccess: # reattach with the new name self.SetAttachmentStatus(apiAttachUnknown) self.Attach() def __Attach_ftimeout(self): self.wait = False def Attach(self, Timeout=30000, Wait=True): if self.AttachmentStatus == apiAttachSuccess: return if not self.isAlive(): try: self.start() except AssertionError: raise ISkypeAPIError('Skype API closed') try: self.wait = True t = threading.Timer(Timeout / 1000.0, self.__Attach_ftimeout) if Wait: t.start() while self.wait: self.win_skype = self.get_skype() if self.win_skype != None: break else: time.sleep(1.0) else: raise ISkypeAPIError('Skype attach timeout') finally: t.cancel() c = ICommand(-1, 'NAME %s' % self.FriendlyName, '', True, Timeout) self.SendCommand(c, True) if c.Reply != 'OK': self.win_skype = None self.SetAttachmentStatus(apiAttachRefused) return self.SendCommand(ICommand(-1, 'PROTOCOL %s' % self.Protocol), True) self.SetAttachmentStatus(apiAttachSuccess) def IsRunning(self): return self.get_skype() != None def Start(self, Minimized=False, Nosplash=False): # options are not supported as of Skype 1.4 Beta for Linux if not self.IsRunning(): import os if os.fork() == 0: # we're the child os.setsid() os.execlp('skype') def Shutdown(self): import os from signal import SIGINT fh = os.popen('ps -o %p --no-heading -C skype') pid = fh.readline().strip() fh.close() if pid: os.kill(int(pid), SIGINT) # Skype sometimes doesn't delete the '_SKYPE_INSTANCE' property skype_inst = self.x11.XInternAtom(self.disp, '_SKYPE_INSTANCE', True) self.x11.XDeleteProperty(self.disp, self.win_root, skype_inst) self.win_skype = None self.SetAttachmentStatus(apiAttachNotAvailable) def SendCommand(self, Command, Force=False): if self.AttachmentStatus != apiAttachSuccess and not Force: self.Attach(Command.Timeout) self.CommandsStackPush(Command) self.CallHandler('send', Command) com = u'#%d %s' % (Command.Id, Command.Command) self.DebugPrint('->', repr(com)) if Command.Blocking: Command._event = bevent = threading.Event() else: Command._timer = timer = threading.Timer(Command.Timeout / 1000.0, self.CommandsStackPop, (Command.Id,)) event = _XEvent() event.xclient.type = _ClientMessage event.xclient.display = self.disp event.xclient.window = self.win_self event.xclient.message_type = self.atom_msg_begin event.xclient.format = 8 com = unicode(com).encode('utf-8') + '\x00' for i in xrange(0, len(com), 20): event.xclient.data = com[i:i+20] if self.x11.XSendEvent(self.disp, self.win_skype, False, 0, byref(event)) == 0: self.error_check() event.xclient.message_type = self.atom_msg self.loop_event.set() self.error_check() if Command.Blocking: bevent.wait(Command.Timeout / 1000.0) self.error_check() if not bevent.isSet(): raise ISkypeAPIError('Skype command timeout') else: timer.start() def notify(self, com): self.DebugPrint('<-', repr(com)) # Called by main loop for all received Skype commands. if com.startswith(u'#'): p = com.find(u' ') Command = self.CommandsStackPop(int(com[1:p])) if Command: Command.Reply = com[p + 1:] if Command.Blocking: Command._event.set() del Command._event else: Command._timer.cancel() del Command._timer self.CallHandler('rece', Command) else: self.CallHandler('rece_api', com[p + 1:]) else: self.CallHandler('rece_api', com)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -