def __init__(self, dockbar): self.dockbar_r = weakref.ref(dockbar) bus_name = dbus.service.BusName("net.launchpad.DockManager", bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, "/net/launchpad/DockManager") self.globals = Globals()
def __init__(self, text=None, area_type="window_item"): self.type = area_type self.text = text gtk.Alignment.__init__(self, 0, 0, 1, 1) self.popup_style = PopupStyle() lrp = int(self.popup_style.get("%s_lr_padding" % self.type, 5)) tdp = int(self.popup_style.get("%s_td_padding" % self.type, 5)) self.set_padding(lrp, lrp, tdp, tdp) self.set_app_paintable(1) self.globals = Globals() self.highlighted = False self.pressed_down = False self.active_window = False self.needs_attention = False self.minimized = False self.preview_allocation = [0, 0, 0, 0] if text: self.label = gtk.Label() self.add(self.label) self.label.show() color = self.globals.colors["color2"] self.set_label(text, color) else: self.label = None
def __init__(self): gobject.GObject.__init__(self) self.globals = Globals() self.name = "DBX" self.settings = {} self.globals.connect("dock-theme-changed", self.on_theme_changed) self.on_theme_changed()
def __init__(self, window, group): CairoButton.__init__(self) self.set_no_show_all(True) self.window_r = weakref.ref(window) self.group_r = weakref.ref(group) self.globals = Globals() self.opacify_sid = None self.deopacify_sid = None self.press_sid = None self.pressed = False self.close_button = CairoCloseButton() self.close_button.set_no_show_all(True) if self.globals.settings["show_close_button"]: self.close_button.show() self.label = gtk.Label() self.label.set_ellipsize(pango.ELLIPSIZE_END) self.label.set_alignment(0, 0.5) self.__update_label() self.area.set_needs_attention(window.wnck.needs_attention()) hbox = gtk.HBox() icon = window.wnck.get_mini_icon() self.icon_image = gtk.image_new_from_pixbuf(icon) hbox.pack_start(self.icon_image, False) hbox.pack_start(self.label, True, True, padding=4) alignment = gtk.Alignment(1, 0.5, 0, 0) alignment.add(self.close_button) hbox.pack_start(alignment, False, False) vbox = gtk.VBox() vbox.pack_start(hbox, False) self.preview_box = gtk.Alignment(0.5, 0.5, 0, 0) self.preview_box.set_padding(4, 2, 0, 0) self.preview = gtk.Image() self.preview_box.add(self.preview) self.preview.show() vbox.pack_start(self.preview_box, True, True) self.add(vbox) self.preview_box.set_no_show_all(True) vbox.show_all() self.show_all() self.update_show_state() self.drag_dest_set(0, [], 0) self.drag_entered = False self.close_button.connect("button-press-event", self.disable_click) self.close_button.connect("clicked", self.__on_close_button_clicked) self.close_button.connect("leave-notify-event", self.__on_close_button_leave) connect(self.globals, "show-close-button-changed", self.__on_show_close_button_changed) connect(self.globals, "color-changed", self.__update_label) connect(self.globals, "preview-size-changed", self.update_preview) connect(self.globals, "window-title-width-changed", self.__update_label)
def __init__(self): if "theme" in self.__dict__: # This is not the first instance of Theme, # no need to initiate anything return gobject.GObject.__init__(self) self.globals = Globals() self.globals.connect("theme_changed", self.on_theme_changed) self.on_theme_changed()
def __init__(self): if "is_initiated" in self.__dict__: # This is not the first instance of PopupStyle, # no need to initiate anything return self.is_initiated = True gobject.GObject.__init__(self) self.globals = Globals() self.name = "DBX" self.settings = {} self.globals.connect("popup-style-changed", self.on_style_changed) self.on_style_changed()
def __init__(self, wnck_window, group): self.group_r = weakref.ref(group) self.globals = Globals() self.opacify_obj = Opacify() connect(self.globals, "show-only-current-monitor-changed", self.__on_show_only_current_monitor_changed) self.screen = wnck.screen_get_default() self.wnck = wnck_window self.deopacify_sid = None self.opacify_sid = None self.select_sid = None self.xid = self.wnck.get_xid() self.is_active_window = False self.on_current_desktop = self.is_on_current_desktop() self.monitor = self.get_monitor() self.state_changed_event = self.wnck.connect( "state-changed", self.__on_window_state_changed) self.icon_changed_event = self.wnck.connect( "icon-changed", self.__on_window_icon_changed) self.name_changed_event = self.wnck.connect( "name-changed", self.__on_window_name_changed) self.geometry_changed_event = self.wnck.connect( "geometry-changed", self.__on_geometry_changed) self.item = WindowItem(self, group) self.needs_attention = self.wnck.needs_attention() self.item.show() self.__on_show_only_current_monitor_changed()
def __init__(self, orient="down", no_arrow=False, type_="popup"): gtk.Window.__init__(self, gtk.WINDOW_POPUP) self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DOCK) gtk_screen = gtk.gdk.screen_get_default() colormap = gtk_screen.get_rgba_colormap() if colormap is None: colormap = gtk_screen.get_rgb_colormap() self.set_colormap(colormap) self.set_app_paintable(1) self.globals = Globals() self.popup_style = PopupStyle() self.popup_type = type_ self._pointer_is_inside = False self.alignment = gtk.Alignment(0, 0, 0, 0) gtk.Window.add(self, self.alignment) self.alignment.show() self.pointer = "" self.no_arrow = no_arrow if orient in ("down", "up"): # The direction of the pointer isn't important here we only need # the right amount of padding so that the popup has right width and # height for placement calculations. self.point("down") else: self.point("left") self.popup_reloaded_sid = self.popup_style.connect( "popup-style-reloaded", self.__on_popup_style_reloaded)
def __init__(self, class_group=None, desktop_entry=None, identifier=None): self.theme = Theme() self.globals = Globals() self.globals.connect('color-changed', self.reset_surfaces) self.desktop_entry = desktop_entry self.identifier = identifier self.class_group = class_group # Setting size to something other than zero to # avoid crashes if surface_update() is runned # before the size is set. self.size = 15 self.icon = None self.surfaces = {} self.average_color = None self.max_win_nr = self.theme.get_windows_cnt() self.types_in_theme = 0 for type in self.theme.get_types(): if not type in self.TYPE_DICT: continue self.types_in_theme = self.types_in_theme | self.TYPE_DICT[type]
def __init__(self, dockbar): self.dockbar_r = weakref.ref(dockbar) bus_name = dbus.service.BusName("net.launchpad.DockManager", bus = dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, "/net/launchpad/DockManager") self.globals = Globals()
def __init__(self, group, class_group=None, desktop_entry=None, identifier=None): self.dockbar_r = weakref.ref(group.dockbar_r()) self.theme = Theme() self.globals = Globals() connect(self.globals, "color-changed", self.reset_surfaces) self.desktop_entry = desktop_entry self.identifier = identifier self.class_group = class_group # Setting size to something other than zero to # avoid crashes if surface_update() is runned # before the size is set. self.size = 15 self.icon = None self.surfaces = {} self.average_color = None self.max_win_nr = self.theme.get_windows_cnt() self.types_in_theme = 0 for type in self.theme.get_types(): if not type in self.TYPE_DICT: continue self.types_in_theme = self.types_in_theme | self.TYPE_DICT[type]
def __init__(self, window, group): CairoButton.__init__(self) self.set_no_show_all(True) self.window_r = weakref.ref(window) self.group_r = weakref.ref(group) self.globals = Globals() self.opacify_sid = None self.deopacify_sid = None self.press_sid = None self.pressed = False self.close_button = CairoCloseButton() self.close_button.set_no_show_all(True) if self.globals.settings["show_close_button"]: self.close_button.show() self.label = gtk.Label() self.label.set_ellipsize(pango.ELLIPSIZE_END) self.label.set_alignment(0, 0.5) self.__update_label() self.area.set_needs_attention(window.wnck.needs_attention()) hbox = gtk.HBox() icon = window.wnck.get_mini_icon() self.icon_image = gtk.image_new_from_pixbuf(icon) hbox.pack_start(self.icon_image, False) hbox.pack_start(self.label, True, True, padding = 4) alignment = gtk.Alignment(1, 0.5, 0, 0) alignment.add(self.close_button) hbox.pack_start(alignment, False, False) vbox = gtk.VBox() vbox.pack_start(hbox, False) self.preview_box = gtk.Alignment(0.5, 0.5, 0, 0) self.preview_box.set_padding(4, 2, 0, 0) self.preview = gtk.Image() self.preview_box.add(self.preview) self.preview.show() vbox.pack_start(self.preview_box, True, True) self.add(vbox) self.preview_box.set_no_show_all(True) vbox.show_all() self.show_all() self.update_show_state() self.drag_dest_set(0, [], 0) self.drag_entered = False self.close_button.connect("button-press-event", self.disable_click) self.close_button.connect("clicked", self.__on_close_button_clicked) self.close_button.connect("leave-notify-event", self.__on_close_button_leave) connect(self.globals, "show-close-button-changed", self.__on_show_close_button_changed) connect(self.globals, "color-changed", self.__update_label) connect(self.globals, "preview-size-changed", self.update_preview) connect(self.globals, "window-title-width-changed", self.__update_label)
def __init__(self, surface=None, expose_on_clear=False): gtk.EventBox.__init__(self) self.set_visible_window(False) self.area = gtk.Alignment(0, 0, 1, 1) self.add(self.area) self.area.show() self.globals = Globals() self.surface = surface self.expose_on_clear = expose_on_clear self.badge = None self.badge_text = None self.progress_bar = None self.progress = None self.bl_sid = self.globals.connect("badge-look-changed", self.__on_badge_look_changed) self.pbl_sid = self.globals.connect("progress-bar-look-changed", self.__on_progress_bar_look_changed)
def __init__(self, window): gobject.GObject.__init__(self) self.globals = Globals() self.globals.connect('color-changed', self.update_label_state) self.globals.connect('show-only-current-monitor-changed', self.on_show_only_current_monitor_changed) self.globals.connect('show-previews-changed', self.on_show_preview_changed) self.screen = wnck.screen_get_default() self.name = window.get_name() self.window = window self.is_active_window = False self.needs_attention = False self.opacified = False self.button_pressed = False self.window_button = CairoWindowButton() self.label = gtk.Label() self.label.set_alignment(0, 0.5) self.on_window_name_changed(self.window) if window.needs_attention(): self.needs_attention = True self.window_button_icon = gtk.Image() self.on_window_icon_changed(window) self.preview_image = None self.on_show_preview_changed() self.update_label_state() #--- Events self.window_button.connect("enter-notify-event", self.on_button_mouse_enter) self.window_button.connect("leave-notify-event", self.on_button_mouse_leave) self.window_button.connect("button-press-event", self.on_window_button_press_event) self.window_button.connect("button-release-event", self.on_window_button_release_event) self.window_button.connect("scroll-event", self.on_window_button_scroll_event) self.state_changed_event = self.window.connect("state-changed", self.on_window_state_changed) self.icon_changed_event = self.window.connect("icon-changed", self.on_window_icon_changed) self.name_changed_event = self.window.connect("name-changed", self.on_window_name_changed) self.geometry_changed_event = None self.on_show_only_current_monitor_changed() #--- D'n'D self.window_button.drag_dest_set(gtk.DEST_DEFAULT_HIGHLIGHT, [], 0) self.window_button.connect("drag_motion", self.on_button_drag_motion) self.window_button.connect("drag_leave", self.on_button_drag_leave) self.button_drag_entered = False self.dnd_select_window = None
def _ParseStreams(suc, data, retmpd=False): g = Globals() s = Settings() HostSet = g.addon.getSetting("pref_host") subUrls = [] if not suc: return False, data if retmpd: subUrls = [ sub['url'] for sub in data['subtitles'] if 'url' in sub.keys() ] if 'audioVideoUrls' in data.keys(): hosts = data['audioVideoUrls']['avCdnUrlSets'] elif 'playbackUrls' in data.keys(): defid = data['playbackUrls']['defaultUrlSetId'] h_dict = data['playbackUrls']['urlSets'] ''' failover = h_dict[defid]['failover'] defid_dis = [failover[k]['urlSetId'] for k in failover if failover[k]['mode'] == 'discontinuous'] defid = defid_dis[0] if defid_dis else defid ''' hosts = [h_dict[k] for k in h_dict] hosts.insert(0, h_dict[defid]) while hosts: for cdn in hosts: prefHost = False if HostSet not in str( hosts) or HostSet == 'Auto' else HostSet cdn_item = cdn if 'urls' in cdn: cdn = cdn['urls']['manifest'] if prefHost and prefHost not in cdn['cdn']: continue Log('Using Host: ' + cdn['cdn']) urlset = cdn['avUrlInfoList'][ 0] if 'avUrlInfoList' in cdn else cdn data = getURL(urlset['url'], rjson=False, check=retmpd) if not data: hosts.remove(cdn_item) Log('Host not reachable: ' + cdn['cdn']) continue return ('http://{}/mpd/{}'.format(s.proxyaddress, quote_plus(urlset['url'])), subUrls) if retmpd else (True, _extrFr(data)) return False, getString(30217)
def __init__(self, groupbutton): self.groupbutton_r = weakref.ref(groupbutton) self.menu_counter = 0 self.menu_items = ODict() self.globals = Globals() DockManagerItem.counter += 1 self.obj_path = "/net/launchpad/DockManager/Item" + \ str(DockManagerItem.counter) bus_name = dbus.service.BusName("net.launchpad.DockManager", bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, self.obj_path)
def __init__(self): super(_AmazonPlayer, self).__init__() self._g = Globals() self.sleeptm = 0.2 self.video_lastpos = 0 self.video_totaltime = 0 self.dbid = 0 self.seek = 0 self.url = '' self.extern = '' self.asin = '' self.cookie = None self.interval = 180 self.running = False
def __init__(self, label, toggle_type="checkmark"): self.globals = Globals() CairoMenuItem.__init__(self, None) self.indicator = gtk.CheckMenuItem() self.indicator.set_draw_as_radio(toggle_type == "radio") self.area.label = gtk.Label() hbox = gtk.HBox() hbox.pack_start(self.indicator, False, padding=2) hbox.pack_start(self.area.label, False, padding=2) alignment = gtk.Alignment(0.5,0.5,0,0) alignment.add(hbox) alignment.show_all() self.area.add(alignment) color = self.globals.colors["color2"] self.set_label(label, color)
def __init__(self): super(_AmazonPlayer, self).__init__() self._g = Globals() self.sleeptm = 0.2 self.video_lastpos = 0 self.video_totaltime = 0 self.dbid = 0 self.asin = '' self.cookie = None self.interval = 180 self.running = False self.extern = False self.resume = 0 self.watched = 0 self.content = 0 self.resumedb = OSPJoin(g.DATA_PATH, 'resume.db')
def __init__(self, label=None, show_menu=False): gtk.VBox.__init__(self) self.globals = Globals() self.set_spacing(0) self.set_border_width(0) self.toggle_button = CairoMenuItem(label) if label: if show_menu: color = self.globals.colors["color4"] else: color = self.globals.colors["color2"] self.toggle_button.set_label(label, color) self.pack_start(self.toggle_button) self.toggle_button.show() self.toggle_button.connect("clicked", self.toggle) self.menu = CairoVBox() self.menu.set_no_show_all(True) self.pack_start(self.menu) self.menu.set_border_width(10) self.show_menu = show_menu if show_menu: self.menu.show()
class WindowButton(gobject.GObject): __gsignals__ = {"minimized": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,()), "unminimized": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,()), "needs-attention-changed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,()), "popup-hide": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,(str, )), "popup-hide-request": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,()), "popup-expose-request": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,()), "monitor-changed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,())} def __init__(self, window): gobject.GObject.__init__(self) self.globals = Globals() self.globals.connect('color-changed', self.update_label_state) self.globals.connect('show-only-current-monitor-changed', self.on_show_only_current_monitor_changed) self.globals.connect('show-previews-changed', self.on_show_preview_changed) self.screen = wnck.screen_get_default() self.name = window.get_name() self.window = window self.is_active_window = False self.needs_attention = False self.opacified = False self.button_pressed = False self.window_button = CairoWindowButton() self.label = gtk.Label() self.label.set_alignment(0, 0.5) self.on_window_name_changed(self.window) if window.needs_attention(): self.needs_attention = True self.window_button_icon = gtk.Image() self.on_window_icon_changed(window) self.preview_image = None self.on_show_preview_changed() self.update_label_state() #--- Events self.window_button.connect("enter-notify-event", self.on_button_mouse_enter) self.window_button.connect("leave-notify-event", self.on_button_mouse_leave) self.window_button.connect("button-press-event", self.on_window_button_press_event) self.window_button.connect("button-release-event", self.on_window_button_release_event) self.window_button.connect("scroll-event", self.on_window_button_scroll_event) self.state_changed_event = self.window.connect("state-changed", self.on_window_state_changed) self.icon_changed_event = self.window.connect("icon-changed", self.on_window_icon_changed) self.name_changed_event = self.window.connect("name-changed", self.on_window_name_changed) self.geometry_changed_event = None self.on_show_only_current_monitor_changed() #--- D'n'D self.window_button.drag_dest_set(gtk.DEST_DEFAULT_HIGHLIGHT, [], 0) self.window_button.connect("drag_motion", self.on_button_drag_motion) self.window_button.connect("drag_leave", self.on_button_drag_leave) self.button_drag_entered = False self.dnd_select_window = None def set_button_active(self, mode): self.is_active_window = mode self.update_label_state() def update_label_state(self, arg=None): """Updates the style of the label according to window state.""" attr_list = pango.AttrList() if self.needs_attention: attr_list.insert(pango.AttrStyle(pango.STYLE_ITALIC, 0, 200)) if self.is_active_window: color = self.globals.colors['color3'] elif self.window.is_minimized(): color = self.globals.colors['color4'] else: color = self.globals.colors['color2'] # color is a hex-string (like '#FFFFFF'). r = int(color[1:3], 16)*256 g = int(color[3:5], 16)*256 b = int(color[5:7], 16)*256 attr_list.insert(pango.AttrForeground(r, g, b, 0, 200)) self.label.set_attributes(attr_list) def is_on_current_desktop(self): if (self.window.get_workspace() is None \ or self.screen.get_active_workspace() == self.window.get_workspace()) \ and self.window.is_in_viewport(self.screen.get_active_workspace()): return True else: return False def get_monitor(self): if not self.globals.settings['show_only_current_monitor']: return 0 gdk_screen = gtk.gdk.screen_get_default() win = gtk.gdk.window_lookup(self.window.get_xid()) x, y, w, h, bit_depth = win.get_geometry() return gdk_screen.get_monitor_at_point(x + (w / 2), y + (h / 2)) def on_show_only_current_monitor_changed(self, arg=None): if self.globals.settings['show_only_current_monitor']: if self.geometry_changed_event is None: self.geometry_changed_event = self.window.connect( 'geometry-changed', self.on_geometry_changed) else: if self.geometry_changed_event is not None: self.window.disconnect(self.geometry_changed_event) self.monitor = self.get_monitor() def del_button(self): self.window_button.destroy() self.window.disconnect(self.state_changed_event) self.window.disconnect(self.icon_changed_event) self.window.disconnect(self.name_changed_event) del self.icon del self.icon_transp del self.screen del self.window del self.globals gc.collect() #### Previews def prepare_preview(self, size=None): if not self.globals.settings["preview"]: return False if size is None: size = self.globals.settings["preview_size"] pixbuf = self.window.get_icon() self.preview_image.set_from_pixbuf(pixbuf) self.preview_image.set_size_request(size,size) del pixbuf gc.collect() def get_preview_alloc(self, size): x,y,w,h = self.window.get_geometry() w = float(w) h = float(h) size = float(size) if w>h: h = size/(w/h) w = size x = 0 y = (size - h)//2 else: w = size/(h/w) h = size x = (size - w)//2 y = 0 return (x, y, w, h) def clear_preview_image(self): if self.preview_image: self.preview_image.clear() gc.collect() def on_show_preview_changed(self, arg=None): child = self.window_button.get_child() if child: self.window_button.remove(child) oldbox = self.window_button_icon.get_parent() if oldbox: oldbox.remove(self.window_button_icon) oldbox.remove(self.label) self.on_window_name_changed(self.window) hbox = gtk.HBox() hbox.pack_start(self.window_button_icon, False, padding = 2) hbox.pack_start(self.label, True, True) if self.globals.settings["preview"]: vbox = gtk.VBox() vbox.pack_start(hbox, False) self.preview_image = gtk.Image() vbox.pack_start(self.preview_image, True, True, padding = 2) self.window_button.add(vbox) # Fixed with of self.label. self.label.set_ellipsize(pango.ELLIPSIZE_END) else: self.label.set_ellipsize(pango.ELLIPSIZE_NONE) self.window_button.add(hbox) if self.preview_image: self.preview_image.clear() self.preview_image = None gc.collect() #### Windows's Events def on_window_state_changed(self, window,changed_mask, new_state): try: state_minimized = wnck.WINDOW_STATE_MINIMIZED except: state_minimized = 1 << 0 if state_minimized & changed_mask & new_state: self.window_button_icon.set_from_pixbuf(self.icon_transp) self.update_label_state() self.emit('minimized') elif state_minimized & changed_mask: self.window_button_icon.set_from_pixbuf(self.icon) self.update_label_state() self.emit('unminimized') # Check if the window needs attention if window.needs_attention() != self.needs_attention: self.needs_attention = window.needs_attention() self.update_label_state() self.emit('needs-attention-changed') def on_window_icon_changed(self, window): # Creates pixbufs for minimized and normal icons # from the window's mini icon and set the one that should # be used as window_button_icon according to window state. self.icon = window.get_mini_icon() pixbuf = self.icon.copy() self.icon_transp = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, pixbuf.get_width(), pixbuf.get_height()) self.icon_transp.fill(0x00000000) pixbuf.composite(self.icon_transp, 0, 0, pixbuf.get_width(), pixbuf.get_height(), 0, 0, 1, 1, gtk.gdk.INTERP_BILINEAR, 190) self.icon_transp.saturate_and_pixelate(self.icon_transp, 0.12, False) if window.is_minimized(): self.window_button_icon.set_from_pixbuf(self.icon_transp) else: self.window_button_icon.set_from_pixbuf(self.icon) del pixbuf def on_window_name_changed(self, window): name = u""+window.get_name() # TODO: fix a better way to shorten names. if len(name) > 40 and not self.globals.settings["preview"]: name = name[0:37]+"..." self.name = name self.label.set_label(name) def on_geometry_changed(self, *args): monitor = self.get_monitor() if monitor != self.monitor: self.monitor = monitor self.emit('monitor-changed') #### Opacify def opacify(self): # Makes all windows but the one connected # to this windowbutton transparent. if self.globals.opacity_values is None: try: self.globals.opacity_values = compiz_call( 'obs/screen0/opacity_values','get') except: try: self.globals.opacity_values = compiz_call( 'core/screen0/opacity_values','get') except: return if self.globals.opacity_matches is None: try: self.globals.opacity_matches = compiz_call( 'obs/screen0/opacity_matches','get') except: try: self.globals.opacity_matches = compiz_call( 'core/screen0/opacity_matches','get') except: return self.globals.opacified = True self.opacified = True ov = [self.globals.settings['opacify_alpha']] om = ["!(xid=%s)"%self.window.get_xid() + \ " & !(class=Dockbarx_factory.py) & (type=Normal | type=Dialog)"] try: compiz_call('obs/screen0/opacity_values','set', ov) compiz_call('obs/screen0/opacity_matches','set', om) except: try: compiz_call('core/screen0/opacity_values','set', ov) compiz_call('core/screen0/opacity_matches','set', om) except: return def opacify_request(self): if self.window.is_minimized(): return False # if self.button_pressed is true, opacity_request is called by an # wrongly sent out enter_notification_event sent after a # button_press (because of a bug in compiz). if self.button_pressed: self.button_pressed = False return False # Check if mouse cursor still is over the window button. b_m_x,b_m_y = self.window_button.get_pointer() b_r = self.window_button.get_allocation() if b_m_x >= 0 and b_m_x < b_r.width \ and b_m_y >= 0 and b_m_y < b_r.height: self.opacify() return False def deopacify(self): # always called from deopacify_request (with timeout) # If another window button has called opacify, don't deopacify. if self.globals.opacified and not self.opacified: return False if self.globals.opacity_values is None: return False try: compiz_call('obs/screen0/opacity_values','set', self.globals.opacity_values) compiz_call('obs/screen0/opacity_matches','set', self.globals.opacity_matches) except: try: compiz_call('core/screen0/opacity_values','set', self.globals.opacity_values) compiz_call('core/screen0/opacity_matches','set', self.globals.opacity_matches) except: print "Error: Couldn't set opacity back to normal." self.globals.opacity_values = None self.globals.opacity_matches = None return False def deopacify_request(self): if not self.opacified: return False # Make sure that mouse cursor really has left the window button. b_m_x,b_m_y = self.window_button.get_pointer() b_r = self.window_button.get_allocation() if b_m_x >= 0 and b_m_x < b_r.width \ and b_m_y >= 0 and b_m_y < b_r.height: return True self.globals.opacified = False self.opacified = False # Wait before deopacifying in case a new windowbutton # should call opacify, to avoid flickering gobject.timeout_add(110, self.deopacify) return False #### D'n'D def on_button_drag_motion(self, widget, drag_context, x, y, t): if not self.button_drag_entered: self.emit('popup-expose-request') self.button_drag_entered = True self.dnd_select_window = \ gobject.timeout_add(600,self.action_select_window) drag_context.drag_status(gtk.gdk.ACTION_PRIVATE, t) return True def on_button_drag_leave(self, widget, drag_context, t): self.button_drag_entered = False gobject.source_remove(self.dnd_select_window) self.emit('popup-expose-request') self.emit('popup-hide-request') #### Events def on_button_mouse_enter(self, widget, event): # In compiz there is a enter and # a leave event before a button_press event. # Keep that in mind when coding this def! if self.button_pressed : return self.update_label_state(True) if self.globals.settings["opacify"]: gobject.timeout_add(100,self.opacify_request) # Just for safty in case no leave-signal is sent gobject.timeout_add(500, self.deopacify_request) def on_button_mouse_leave(self, widget, event): # In compiz there is a enter and a leave # event before a button_press event. # Keep that in mind when coding this def! self.button_pressed = False self.update_label_state(False) if self.globals.settings["opacify"]: self.deopacify_request() def on_window_button_press_event(self, widget,event): # In compiz there is a enter and a leave event before # a button_press event. # self.button_pressed is used to stop functions started with # gobject.timeout_add from self.on_button_mouse_enter # or self.on_button_mouse_leave. self.button_pressed = True gobject.timeout_add(600, self.set_button_pressed_false) def set_button_pressed_false(self): # Helper function for on_window_button_press_event. self.button_pressed = False return False def on_window_button_scroll_event(self, widget, event): if self.globals.settings["opacify"] and self.opacified: self.globals.opacified = False self.opacified = False self.deopacify() if not event.direction in (gtk.gdk.SCROLL_UP, gtk.gdk.SCROLL_DOWN): return direction = {gtk.gdk.SCROLL_UP: 'scroll_up', gtk.gdk.SCROLL_DOWN: 'scroll_down'}[event.direction] action = self.globals.settings['windowbutton_%s'%direction] self.action_function_dict[action](self, widget, event) if self.globals.settings['windowbutton_close_popup_on_%s'%direction]: self.emit('popup-hide', None) def on_window_button_release_event(self, widget, event): if self.globals.settings["opacify"] and self.opacified: self.globals.opacified = False self.opacified = False self.deopacify() if not event.button in (1, 2, 3): return button = {1:'left', 2: 'middle', 3: 'right'}[event.button] if event.state & gtk.gdk.SHIFT_MASK: mod = 'shift_and_' else: mod = '' action_str = 'windowbutton_%s%s_click_action'%(mod, button) action = self.globals.settings[action_str] self.action_function_dict[action](self, widget, event) popup_close = 'windowbutton_close_popup_on_%s%s_click'%(mod, button) if self.globals.settings[popup_close]: self.emit('popup-hide', None) #### Menu functions def menu_closed(self, menushell): self.globals.right_menu_showing = False self.emit('popup-hide', 'menu-closed') def minimize_window(self, widget=None, event=None): if self.window.is_minimized(): self.window.unminimize(gtk.get_current_event_time()) else: self.window.minimize() #### Actions def action_select_or_minimize_window(self, widget=None, event=None, minimize=True): # The window is activated, unless it is already # activated, then it's minimized. Minimized # windows are unminimized. The workspace # is switched if the window is on another # workspace. if event: t = event.time else: t = gtk.get_current_event_time() if self.window.get_workspace() is not None \ and self.screen.get_active_workspace() != self.window.get_workspace(): self.window.get_workspace().activate(t) if not self.window.is_in_viewport(self.screen.get_active_workspace()): win_x,win_y,win_w,win_h = self.window.get_geometry() self.screen.move_viewport(win_x-(win_x%self.screen.get_width()), win_y-(win_y%self.screen.get_height())) # Hide popup since mouse movment won't # be tracked during compiz move effect # which means popup list can be left open. self.emit('popup-hide', 'viewport-change') if self.window.is_minimized(): self.window.unminimize(t) elif self.window.is_active() and minimize: self.window.minimize() else: self.window.activate(t) def action_select_window(self, widget = None, event = None): self.action_select_or_minimize_window(widget, event, False) def action_close_window(self, widget=None, event=None): self.window.close(gtk.get_current_event_time()) def action_maximize_window(self, widget=None, event=None): if self.window.is_maximized(): self.window.unmaximize() else: self.window.maximize() def action_shade_window(self, widget, event): self.window.shade() def action_unshade_window(self, widget, event): self.window.unshade() def action_show_menu(self, widget, event): try: action_minimize = wnck.WINDOW_ACTION_MINIMIZE action_unminimize = wnck.WINDOW_ACTION_UNMINIMIZE action_maximize = wnck.WINDOW_ACTION_MAXIMIZE except: action_minimize = 1 << 12 action_unminimize = 1 << 13 action_maximize = 1 << 14 #Creates a popup menu menu = gtk.Menu() menu.connect('selection-done', self.menu_closed) #(Un)Minimize minimize_item = None if self.window.get_actions() & action_minimize \ and not self.window.is_minimized(): minimize_item = gtk.MenuItem(_('_Minimize')) elif self.window.get_actions() & action_unminimize \ and self.window.is_minimized(): minimize_item = gtk.MenuItem(_('Un_minimize')) if minimize_item: menu.append(minimize_item) minimize_item.connect("activate", self.minimize_window) minimize_item.show() # (Un)Maximize maximize_item = None if not self.window.is_maximized() \ and self.window.get_actions() & action_maximize: maximize_item = gtk.MenuItem(_('Ma_ximize')) elif self.window.is_maximized() \ and self.window.get_actions() & action_unminimize: maximize_item = gtk.MenuItem(_('Unma_ximize')) if maximize_item: menu.append(maximize_item) maximize_item.connect("activate", self.action_maximize_window) maximize_item.show() # Close close_item = gtk.MenuItem(_('_Close')) menu.append(close_item) close_item.connect("activate", self.action_close_window) close_item.show() menu.popup(None, None, None, event.button, event.time) self.globals.right_menu_showing = True def action_none(self, widget = None, event = None): pass action_function_dict = ODict(( ('select or minimize window', action_select_or_minimize_window), ('select window', action_select_window), ('maximize window', action_maximize_window), ('close window', action_close_window), ('show menu', action_show_menu), ('shade window', action_shade_window), ('unshade window', action_unshade_window), ('no action', action_none) ))
def PlayVideo(name, asin, adultstr, trailer, forcefb=0): g = Globals() s = Settings() def _check_output(*popenargs, **kwargs): p = subprocess.Popen(stdout=subprocess.PIPE, stderr=subprocess.STDOUT, *popenargs, **kwargs) out, err = p.communicate() retcode = p.poll() if retcode != 0: c = kwargs.get("args") if c is None: c = popenargs[0] e = subprocess.CalledProcessError(retcode, c) e.output = str(out) + str(err) Log(e, Log.ERROR) return out.strip() def _playDummyVid(): dummy_video = OSPJoin(g.PLUGIN_PATH, 'resources', 'dummy.avi') xbmcplugin.setResolvedUrl(g.pluginhandle, True, xbmcgui.ListItem(path=dummy_video)) Log('Playing Dummy Video', Log.DEBUG) xbmc.Player().stop() return def _extrFr(data): fps_string = re.compile('frameRate="([^"]*)').findall(data)[0] fr = round(eval(fps_string + '.0'), 3) return str(fr).replace('.0', '') def _ParseStreams(suc, data, retmpd=False): g = Globals() s = Settings() def _ParseSubs(data): bForcedOnly = False # Whether or not we should only download forced subtitles down_lang = int('0' + g.addon.getSetting('sub_lang')) if 0 == down_lang: return [] # Return if the sub_lang is set to None lang_main = jsonRPC('Settings.GetSettingValue', param={'setting': 'locale.subtitlelanguage'}) lang_main = lang_main['value'] if 'value' in lang_main else '' # Locale.SubtitleLanguage (and .AudioLanguage) can either return a language or: # [ S] none: no subtitles # [ S] forced_only: forced subtitles only # [AS] original: the stream's original language # [AS] default: Kodi's UI # # For simplicity's sake (and temporarily) we will treat original as AudioLanguage, and # AudioLanguage 'original' as 'default' if lang_main not in ['none', 'forced_only', 'original', 'default']: lang_main = xbmc.convertLanguage(lang_main, xbmc.ISO_639_1) if 'none' == lang_main: return [] if 'forced_only' == lang_main and down_lang > 1: bForcedOnly = True if ('forced_only' == lang_main) or ('original' == lang_main): lang_main = jsonRPC('Settings.GetSettingValue', param={'setting': 'locale.audiolanguage'}) lang_main = lang_main['value'] if 'value' in lang_main else '' if lang_main not in ['original', 'default']: lang_main = xbmc.convertLanguage(lang_main, xbmc.ISO_639_1) if lang_main == 'original': lang_main = 'default' if 'default' == lang_main: lang_main = xbmc.getLanguage(xbmc.ISO_639_1, False) # At this point we should have the user's selected language or a valid fallback, although # we further sanitize for safety lang_main = lang_main if lang_main else xbmc.getLanguage(xbmc.ISO_639_1, False) lang_main = lang_main if lang_main else 'en' # down_lang: None | All | From Kodi player language settings | From settings, fallback to english | From settings, fallback to all lang_main = '' if 1 == down_lang else lang_main lang_fallback = None if 3 > down_lang else ('' if 4 == down_lang else 'en') localeConversion = { 'ar-001': 'ar', 'cmn-hans': 'zh HANS', 'cmn-hant': 'zh HANT', 'da-dk': 'da', 'es-419': 'es LA', 'ja-jp': 'ja', 'ko-kr': 'ko', 'nb-no': 'nb', 'sv-se': 'sv', } # Clean up language and locale information where needed subs = [] if (not down_lang) or (('subtitleUrls' not in data) and ('forcedNarratives' not in data)): return subs def_subs = [] fb_subs = [] for sub in data['subtitleUrls'] + data['forcedNarratives']: lang = sub['languageCode'].strip() if lang in localeConversion: lang = localeConversion[lang] # Clean up where needed if '-' in lang: p1 = re.split('-', lang)[0] p2 = re.split('-', lang)[1] if (p1 == p2): # Remove redundant locale information when not useful lang = p1 else: lang = '%s %s' % (p1, p2.upper()) # Amazon's en defaults to en_US, not en_UK if 'en' == lang: lang = 'en US' # Read close-caption information where needed if '[' in sub['displayName']: cc = re.search(r'(\[[^\]]+\])', sub['displayName']) if None is not cc: lang = lang + (' %s' % cc.group(1)) # Add forced subs information if ' forced ' in sub['displayName']: lang = lang + '.Forced' if (' forced ' in sub['displayName']) or (False is bForcedOnly): sub['languageCode'] = lang if lang_main in lang: def_subs.append(sub) if (None is not lang_fallback) and (lang_fallback in lang): fb_subs.append(sub) if not def_subs: def_subs = fb_subs import codecs for sub in def_subs: escape_chars = [('&', '&'), ('"', '"'), ('<', '<'), ('>', '>'), (''', "'")] srtfile = xbmc.translatePath('special://temp/%s.srt' % sub['languageCode']).decode('utf-8') subDisplayLang = '“%s” subtitle (%s)' % (sub['displayName'].strip(), sub['languageCode']) content = '' Log("Subtitle URL: %s" % (sub['url']), Log.DEBUG) with codecs.open(srtfile, 'w', encoding='utf-8') as srt: # Since dfxp provides no particular metadata and .srt are usually available on amazon's servers, # we try to download the .srt straight away to avoid conversion. Although we avoid it with RTL # languages, since we need to parse them anyway. if (sub['url'].endswith("dfxp")) and ('ar' != sub['languageCode']): subUrl = re.search(r'^(.*?\.)[^.]{1,}$', sub['url']) content = '' if None is subUrl else getURL(subUrl.group(1) + 'srt', rjson=False, attempt=777) if 0 < len(content): Log('Downloaded %s' % subDisplayLang, Log.DEBUG) srt.write(content) continue content = getURL(sub['url'], rjson=False, attempt=3) if 0 < len(content): Log('Converting %s' % subDisplayLang) Log('Output %s' % srtfile, Log.DEBUG) # Apply a bunch of regex to the content instead of line-by-line to save computation time content = re.sub(r'<(|/)span[^>]*>', r'<\1i>', content) # Using (|<search>) instead of ()? to avoid py2.7 empty matching error content = re.sub(r'([0-9]{2}:[0-9]{2}:[0-9]{2})\.', r'\1,', content) # SRT-like timestamps content = re.sub(r'\s*<(?:tt:)?br\s*/>\s*', '\n', content) # Replace <br/> with actual new lines # Convert dfxp or ttml2 to srt num = 0 for tt in re.compile(r'<(?:tt:)?p begin="([^"]+)"[^>]*end="([^"]+)"[^>]*>\s*(.*?)\s*</(?:tt:)?p>', re.DOTALL).findall(content): text = tt[2] # Embed RTL and change the punctuation where needed if 'ar' == sub['languageCode']: from unicodedata import lookup text = re.sub('^', lookup('RIGHT-TO-LEFT EMBEDDING'), text, flags=re.MULTILINE) text = text.replace('?', '؟').replace(',', '،') for ec in escape_chars: text = text.replace(ec[0], ec[1]) num += 1 srt.write('%s\n%s --> %s\n%s\n\n' % (num, tt[0], tt[1], text)) Log('Conversion finished', Log.DEBUG) if 0 == len(content): Log('Unable to download %s' % subDisplayLang) else: subs.append(srtfile) return subs HostSet = g.addon.getSetting("pref_host") subUrls = [] if not suc: return False, data if retmpd: subUrls = _ParseSubs(data) if 'audioVideoUrls' in data.keys(): hosts = data['audioVideoUrls']['avCdnUrlSets'] elif 'playbackUrls' in data.keys(): defid = data['playbackUrls']['defaultUrlSetId'] h_dict = data['playbackUrls']['urlSets'] ''' failover = h_dict[defid]['failover'] defid_dis = [failover[k]['urlSetId'] for k in failover if failover[k]['mode'] == 'discontinuous'] defid = defid_dis[0] if defid_dis else defid ''' hosts = [h_dict[k] for k in h_dict] hosts.insert(0, h_dict[defid]) while hosts: for cdn in hosts: prefHost = False if HostSet not in str(hosts) or HostSet == 'Auto' else HostSet cdn_item = cdn if 'urls' in cdn: cdn = cdn['urls']['manifest'] if prefHost and prefHost not in cdn['cdn']: continue Log('Using Host: ' + cdn['cdn']) urlset = cdn['avUrlInfoList'][0] if 'avUrlInfoList' in cdn else cdn data = getURL(urlset['url'], rjson=False, check=retmpd) if not data: hosts.remove(cdn_item) Log('Host not reachable: ' + cdn['cdn']) continue return (urlset['url'], subUrls) if retmpd else (True, _extrFr(data)) return False, getString(30217) def _getCmdLine(videoUrl, asin, method, fr): scr_path = g.addon.getSetting("scr_path") br_path = g.addon.getSetting("br_path").strip() scr_param = g.addon.getSetting("scr_param").strip() kiosk = g.addon.getSetting("kiosk") == 'true' appdata = g.addon.getSetting("ownappdata") == 'true' cust_br = g.addon.getSetting("cust_path") == 'true' nobr_str = getString(30198) frdetect = g.addon.getSetting("framerate") == 'true' if method == 1: if not xbmcvfs.exists(scr_path): return False, nobr_str if frdetect: suc, fr = _ParseStreams(*getURLData('catalog/GetPlaybackResources', asin, extra=True, useCookie=True)) if not fr else (True, fr) if not suc: return False, fr else: fr = '' return True, scr_path + ' ' + scr_param.replace('{f}', fr).replace('{u}', videoUrl) br_platform = (g.platform & -g.platform).bit_length() os_paths = [None, ('C:\\Program Files\\', 'C:\\Program Files (x86)\\'), ('/usr/bin/', '/usr/local/bin/'), 'open -a '][br_platform] # path(0,win,lin,osx), kiosk, profile, args br_config = [[(None, ['Internet Explorer\\iexplore.exe'], '', ''), '-k ', '', ''], [(None, ['Google\\Chrome\\Application\\chrome.exe'], ['google-chrome', 'google-chrome-stable', 'google-chrome-beta', 'chromium-browser'], '"/Applications/Google Chrome.app"'), '--kiosk ', '--user-data-dir=', '--start-maximized --disable-translate --disable-new-tab-first-run --no-default-browser-check --no-first-run '], [(None, ['Mozilla Firefox\\firefox.exe'], ['firefox'], 'firefox'), '', '-profile ', ''], [(None, ['Safari\\Safari.exe'], '', 'safari'), '', '', '']] if not cust_br: br_path = '' if (not g.platform & g.OS_OSX) and (not cust_br): for path in os_paths: for exe_file in br_config[s.browser][0][br_platform]: if xbmcvfs.exists(OSPJoin(path, exe_file)): br_path = path + exe_file break else: Log('Browser %s not found' % (path + exe_file), Log.DEBUG) if br_path: break if (not xbmcvfs.exists(br_path)) and (not g.platform & g.OS_OSX): return False, nobr_str br_args = br_config[s.browser][3] if kiosk: br_args += br_config[s.browser][1] if appdata and br_config[s.browser][2]: br_args += br_config[s.browser][2] + '"' + OSPJoin(g.DATA_PATH, str(s.browser)) + '" ' if g.platform & g.OS_OSX: if not cust_br: br_path = os_paths + br_config[s.browser][0][3] if br_args.strip(): br_args = '--args ' + br_args br_path += ' %s"%s"' % (br_args, videoUrl) return True, br_path def _getStartupInfo(): si = subprocess.STARTUPINFO() si.dwFlags = subprocess.STARTF_USESHOWWINDOW return si def _ExtPlayback(videoUrl, asin, isAdult, method, fr): waitsec = int(g.addon.getSetting("clickwait")) * 1000 waitprepin = int(g.addon.getSetting("waitprepin")) * 1000 pin = g.addon.getSetting("pin") waitpin = int(g.addon.getSetting("waitpin")) * 1000 pininput = g.addon.getSetting("pininput") == 'true' fullscr = g.addon.getSetting("fullscreen") == 'true' videoUrl += '&playerDebug=true' if s.verbLog else '' xbmc.Player().stop() # xbmc.executebuiltin('ActivateWindow(busydialog)') suc, url = _getCmdLine(videoUrl, asin, method, fr) if not suc: g.dialog.notification(getString(30203), url, xbmcgui.NOTIFICATION_ERROR) return Log('Executing: %s' % url) if g.platform & g.OS_WINDOWS: process = subprocess.Popen(url, startupinfo=_getStartupInfo()) else: args = shlex.split(url) process = subprocess.Popen(args) if g.platform & g.OS_LE: result = 1 while result != 0: p = subprocess.Popen('pgrep chrome > /dev/null', shell=True) p.wait() result = p.returncode if isAdult and pininput: if fullscr: waitsec *= 0.75 else: waitsec = waitprepin xbmc.sleep(int(waitsec)) _Input(keys=pin) waitsec = waitpin if fullscr: xbmc.sleep(int(waitsec)) if s.browser != 0: _Input(keys='f') else: _Input(mousex=-1, mousey=350, click=2) xbmc.sleep(500) _Input(mousex=9999, mousey=350) _Input(mousex=9999, mousey=-1) # xbmc.executebuiltin('Dialog.Close(busydialog)') if s.hasExtRC: return myWindow = _window(process, asin) myWindow.wait() def _AndroidPlayback(asin, trailer): manu = '' if os.access('/system/bin/getprop', os.X_OK): manu = _check_output(['getprop', 'ro.product.manufacturer']) if manu == 'Amazon': pkg = 'com.fivecent.amazonvideowrapper' act = '' url = asin else: pkg = 'com.amazon.avod.thirdpartyclient' act = 'android.intent.action.VIEW' url = g.BaseUrl + '/piv-apk-play?asin=' + asin url += '&playTrailer=T' if trailer == 1 else '' subprocess.Popen(['log', '-p', 'v', '-t', 'Kodi-Amazon', 'Manufacturer: ' + manu]) subprocess.Popen(['log', '-p', 'v', '-t', 'Kodi-Amazon', 'Starting App: %s Video: %s' % (pkg, url)]) Log('Manufacturer: %s' % manu) Log('Starting App: %s Video: %s' % (pkg, url)) if s.verbLog: if os.access('/system/xbin/su', os.X_OK) or os.access('/system/bin/su', os.X_OK): Log('Logcat:\n' + _check_output(['su', '-c', 'logcat -d | grep -i com.amazon.avod'])) Log('Properties:\n' + _check_output(['sh', '-c', 'getprop | grep -iE "(ro.product|ro.build|google)"'])) xbmc.executebuiltin('StartAndroidActivity("%s", "%s", "", "%s")' % (pkg, act, url)) def _IStreamPlayback(asin, name, trailer, isAdult, extern): from .ages import AgeRestrictions vMT = ['Feature', 'Trailer', 'LiveStreaming'][trailer] dRes = 'PlaybackUrls' if trailer == 2 else 'PlaybackUrls,SubtitleUrls,ForcedNarratives' mpaa_str = AgeRestrictions().GetRestrictedAges() + getString(30171) drm_check = g.addon.getSetting("drm_check") == 'true' verifyISA = '{"jsonrpc":"2.0","id":1,"method":"Addons.GetAddonDetails","params":{"addonid":"inputstream.adaptive"}}' if 'error' in xbmc.executeJSONRPC(verifyISA): xbmc.executebuiltin('UpdateAddonRepos', True) xbmc.executebuiltin('InstallAddon(inputstream.adaptive)', True) if 'error' in xbmc.executeJSONRPC(verifyISA): Log('InputStream.Adaptive addon is not installed') _playDummyVid() return True inputstream_helper = Helper('mpd', drm='com.widevine.alpha') if not inputstream_helper.check_inputstream(): Log('No Inputstream Addon found or activated') _playDummyVid() return True cookie = MechanizeLogin() if not cookie: g.dialog.notification(getString(30203), getString(30200), xbmcgui.NOTIFICATION_ERROR) Log('Login error at playback') _playDummyVid() return True mpd, subs = _ParseStreams(*getURLData('catalog/GetPlaybackResources', asin, extra=True, vMT=vMT, dRes=dRes, useCookie=cookie), retmpd=True) cj_str = ';'.join(['%s=%s' % (k, v) for k, v in cookie.items()]) opt = '|Content-Type=application%2Fx-www-form-urlencoded&Cookie=' + quote_plus(cj_str) opt += '|widevine2Challenge=B{SSM}&includeHdcpTestKeyInLicense=true' opt += '|JBlicense;hdcpEnforcementResolutionPixels' licURL = getURLData('catalog/GetPlaybackResources', asin, opt=opt, extra=True, vMT=vMT, dRes='Widevine2License', retURL=True) if not mpd: g.dialog.notification(getString(30203), subs, xbmcgui.NOTIFICATION_ERROR) _playDummyVid() return True from xbmcaddon import Addon as KodiAddon is_version = KodiAddon(g.is_addon).getAddonInfo('version') if g.is_addon else '0' is_binary = xbmc.getCondVisibility('System.HasAddon(kodi.binary.instance.inputstream)') if trailer != 2: mpd = re.sub(r'~', '', mpd) if drm_check and (not g.platform & g.OS_ANDROID) and (not is_binary): mpdcontent = getURL(mpd, useCookie=cookie, rjson=False) if 'avc1.4D00' in mpdcontent: # xbmc.executebuiltin('ActivateWindow(busydialog)') return _extrFr(mpdcontent) Log(mpd, Log.DEBUG) if g.KodiK and extern: content = getATVData('GetASINDetails', 'ASINList=' + asin)['titles'][0] ct, Info = g.amz.getInfos(content, False) title = Info['DisplayTitle'] thumb = Info.get('Poster', Info['Thumb']) mpaa_check = str(Info.get('MPAA', mpaa_str)) in mpaa_str or isAdult else: mpaa_check = _getListItem('MPAA') in mpaa_str + mpaa_str.replace(' ', '') or isAdult title = _getListItem('Label') thumb = _getListItem('Art(season.poster)') if not thumb: thumb = _getListItem('Art(tvshow.poster)') if not thumb: thumb = _getListItem('Art(thumb)') if trailer == 1: title += ' (Trailer)' if not title: title = name if mpaa_check and not AgeRestrictions().RequestPin(): return True listitem = xbmcgui.ListItem(label=title, path=mpd) if g.KodiK and extern: listitem.setInfo('video', getInfolabels(Info)) if 'adaptive' in g.is_addon: listitem.setProperty('inputstream.adaptive.manifest_type', 'mpd') Log('Using %s Version: %s' % (g.is_addon, is_version)) listitem.setArt({'thumb': thumb}) listitem.setSubtitles(subs) listitem.setProperty('%s.license_type' % g.is_addon, 'com.widevine.alpha') listitem.setProperty('%s.license_key' % g.is_addon, licURL) listitem.setProperty('%s.stream_headers' % g.is_addon, 'user-agent=' + getConfig('UserAgent')) listitem.setProperty('inputstreamaddon', g.is_addon) listitem.setMimeType('application/dash+xml') listitem.setContentLookup(False) player = _AmazonPlayer() player.asin = asin player.cookie = cookie player.content = trailer player.extern = extern player.resolve(listitem) starttime = time.time() while not xbmc.abortRequested and player.running: if player.isPlayingVideo(): player.video_lastpos = player.getTime() if time.time() > starttime + player.interval: starttime = time.time() player.updateStream('PLAY') sleep(1) player.finished() del player return True isAdult = adultstr == '1' amazonUrl = g.BaseUrl + "/dp/" + (name if g.UsePrimeVideo else asin) playable = False fallback = int(g.addon.getSetting("fallback_method")) methodOW = fallback - 1 if forcefb and fallback else s.playMethod videoUrl = "%s/?autoplay=%s" % (amazonUrl, ('trailer' if trailer == 1 else '1')) extern = not xbmc.getInfoLabel('Container.PluginName').startswith('plugin.video.amazon') fr = '' if extern: Log('External Call', Log.DEBUG) while not playable: playable = True if methodOW == 2 and g.platform & g.OS_ANDROID: _AndroidPlayback(asin, trailer) elif methodOW == 3: playable = _IStreamPlayback(asin, name, trailer, isAdult, extern) elif not g.platform & g.OS_ANDROID: _ExtPlayback(videoUrl, asin, isAdult, methodOW, fr) if not playable or isinstance(playable, unicode): if fallback: methodOW = fallback - 1 if isinstance(playable, unicode): fr = playable playable = False else: xbmc.sleep(500) g.dialog.ok(getString(30203), getString(30218)) playable = True if methodOW != 3: _playDummyVid()
class DockManager(dbus.service.Object): def __new__(cls, dockbar): if "net.launchpad.DockManager" in dbus.SessionBus().list_names(): logger.debug("Name net.launchpad.DockManager is already" + \ " in use. (This instance of) DockbarX will" + \ " not use DockManager.") return None else: return dbus.service.Object.__new__(cls) def __init__(self, dockbar): self.dockbar_r = weakref.ref(dockbar) bus_name = dbus.service.BusName("net.launchpad.DockManager", bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, "/net/launchpad/DockManager") self.globals = Globals() @dbus.service.method( dbus_interface="net.launchpad.DockManager", in_signature="", out_signature="as", ) def GetCapabilities(self): capabilities = [ "menu-item-container-title", "menu-item-icon-file", "menu-item-icon-name", "menu-item-with-label", "dock-item-badge", "dock-item-progress" ] return capabilities @dbus.service.method( dbus_interface="net.launchpad.DockManager", in_signature="", out_signature="ao", ) def GetItems(self): path_list = [] for path in self.dockbar_r().get_dm_paths(): path_list.append(dbus.ObjectPath(path)) return path_list @dbus.service.method( dbus_interface="net.launchpad.DockManager", in_signature="s", out_signature="ao", ) def GetItemsByDesktopFile(self, name): path_list = [] for path in self.dockbar_r().get_dm_paths_by_desktop_file(name): path_list.append(dbus.ObjectPath(path)) logger.debug("Items gotten by dekstop file: %s" % path_list) return path_list @dbus.service.method( dbus_interface="net.launchpad.DockManager", in_signature="s", out_signature="ao", ) def GetItemsByName(self, name): path_list = [] for path in self.dockbar_r().get_dm_paths_by_name(name): path_list.append(dbus.ObjectPath(path)) logger.debug("Items gotten by name: %s" % path_list) return path_list @dbus.service.method( dbus_interface="net.launchpad.DockManager", in_signature="i", out_signature="ao", ) def GetItemsByPid(self, pid): path_list = [] for path in self.dockbar_r().get_dm_paths_by_pid(pid): path_list.append(dbus.ObjectPath(path)) logger.debug("Items gotten by pid: %s" % path_list) return path_list @dbus.service.method( dbus_interface="net.launchpad.DockManager", in_signature="x", out_signature="ao", ) def GetItemsByXid(self, xid): path_list = [] for path in self.dockbar_r().get_dm_paths_by_xid(xid): path_list.append(dbus.ObjectPath(path)) logger.debug("Items gotten by xid: %s" % path_list) return path_list @dbus.service.signal(dbus_interface='net.launchpad.DockManager', signature='o') def ItemAdded(self, obj_path): pass @dbus.service.signal(dbus_interface='net.launchpad.DockManager', signature='o') def ItemRemoved(self, obj_path): pass @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v') def Get(self, interface_name, property_name): return self.GetAll(interface_name)[property_name] @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}') def GetAll(self, interface_name): if interface_name == "net.launchpad.DockManager": return {} else: raise dbus.exceptions.DBusException( 'com.example.UnknownInterface', 'The Foo object does not implement the %s interface' % interface_name) @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ssv', out_signature='') def Set(self, interface_name, property_name, property_value): pass @dbus.service.signal(dbus_interface=dbus.PROPERTIES_IFACE, signature='sa{sv}as') def PropertiesChanged(self, interface_name, changed_properties, invalidated_properties): pass def reset(self): try: bus = dbus.SessionBus() proxy = bus.get_object("net.launchpad.DockManager.Daemon", "/net/launchpad/DockManager/Daemon") proxy.RestartAll(dbus_interface="net.launchpad.DockManager.Daemon") except: logger.exception("Restarting DockManager Helpers failed.") def remove(self): self.remove_from_connection() self.globals.disconnect(self.badge_sid)
class WindowItem(CairoButton): __gsignals__ = {"enter-notify-event": "override", "leave-notify-event": "override", "button-press-event": "override", "scroll-event": "override", "clicked": "override", "drag-motion" : "override", "drag-leave" : "override",} def __init__(self, window, group): CairoButton.__init__(self) self.set_no_show_all(True) self.window_r = weakref.ref(window) self.group_r = weakref.ref(group) self.globals = Globals() self.opacify_sid = None self.deopacify_sid = None self.press_sid = None self.pressed = False self.close_button = CairoCloseButton() self.close_button.set_no_show_all(True) if self.globals.settings["show_close_button"]: self.close_button.show() self.label = gtk.Label() self.label.set_ellipsize(pango.ELLIPSIZE_END) self.label.set_alignment(0, 0.5) self.__update_label() self.area.set_needs_attention(window.wnck.needs_attention()) hbox = gtk.HBox() icon = window.wnck.get_mini_icon() self.icon_image = gtk.image_new_from_pixbuf(icon) hbox.pack_start(self.icon_image, False) hbox.pack_start(self.label, True, True, padding = 4) alignment = gtk.Alignment(1, 0.5, 0, 0) alignment.add(self.close_button) hbox.pack_start(alignment, False, False) vbox = gtk.VBox() vbox.pack_start(hbox, False) self.preview_box = gtk.Alignment(0.5, 0.5, 0, 0) self.preview_box.set_padding(4, 2, 0, 0) self.preview = gtk.Image() self.preview_box.add(self.preview) self.preview.show() vbox.pack_start(self.preview_box, True, True) self.add(vbox) self.preview_box.set_no_show_all(True) vbox.show_all() self.show_all() self.update_show_state() self.drag_dest_set(0, [], 0) self.drag_entered = False self.close_button.connect("button-press-event", self.disable_click) self.close_button.connect("clicked", self.__on_close_button_clicked) self.close_button.connect("leave-notify-event", self.__on_close_button_leave) connect(self.globals, "show-close-button-changed", self.__on_show_close_button_changed) connect(self.globals, "color-changed", self.__update_label) connect(self.globals, "preview-size-changed", self.update_preview) connect(self.globals, "window-title-width-changed", self.__update_label) def clean_up(self): window = self.window_r() if self.deopacify_sid: gobject.source_remove(self.deopacify_sid) window.deopacify() if self.opacify_sid: gobject.source_remove(self.opacify_sid) if self.press_sid: gobject.source_remove(self.press_sid) self.close_button.destroy() def show(self): self.update_preview() CairoButton.show(self) def __on_show_close_button_changed(self, *args): if self.globals.settings["show_close_button"]: self.close_button.show() else: self.close_button.hide() self.label.queue_resize() #### Apperance def __update_label(self, arg=None): """Updates the style of the label according to window state.""" window = self.window_r() text = escape(str(window.wnck.get_name())) if window.wnck.is_minimized(): color = self.globals.colors["color4"] else: color = self.globals.colors["color2"] text = "<span foreground=\"" + color + "\">" + text + "</span>" self.label.set_text(text) self.label.set_use_markup(True) if self.globals.settings["preview"]: # The label should be 140px wide unless there are more room # because the preview takes up more. size = 140 else: size = self.globals.settings["window_title_width"] self.label.set_size_request(size, -1) def __make_minimized_icon(self, icon): pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, icon.get_width(), icon.get_height()) pixbuf.fill(0x00000000) minimized_icon = pixbuf.copy() icon.composite(pixbuf, 0, 0, pixbuf.get_width(), pixbuf.get_height(), 0, 0, 1, 1, gtk.gdk.INTERP_BILINEAR, 190) pixbuf.saturate_and_pixelate(minimized_icon, 0.12, False) return minimized_icon def __update_icon(self): window = self.window_r() icon = window.wnck.get_mini_icon() if window.wnck.is_minimized(): pixbuf = self.__make_minimized_icon(icon) self.icon_image.set_from_pixbuf(pixbuf) if self.globals.settings["preview"] and \ (self.globals.get_compiz_version() < "0.9" or \ not self.globals.settings["preview_minimized"]): self.preview.set_from_pixbuf(window.wnck.get_icon()) else: self.icon_image.set_from_pixbuf(icon) self.preview.clear() def minimized_changed(self): window = self.window_r() self.__update_label() self.__update_icon() self.area.set_minimized(window.wnck.is_minimized()) def active_changed(self): window = self.window_r() self.area.set_active_window(window.is_active_window) self.__update_label() def icon_changed(self): self.__update_icon() def needs_attention_changed(self): window = self.window_r() self.area.set_needs_attention(window.wnck.needs_attention()) self.__update_label() def name_changed(self): self.__update_label() def set_highlighted(self, highlighted): self.area.set_highlighted(highlighted) def update_show_state(self): window = self.window_r() if (self.globals.settings["show_only_current_desktop"] and \ not window.on_current_desktop) or \ (self.globals.settings["show_only_current_monitor"] and \ window.monitor != self.group_r().monitor): self.hide() else: self.show() ####Preview def update_preview(self, *args): window = self.window_r() group = self.group_r() width = window.wnck.get_geometry()[2] height = window.wnck.get_geometry()[3] ar = group.monitor_aspect_ratio size = self.globals.settings["preview_size"] if width*ar < size and height < size: pass elif float(width) / height > ar: height = int(round(size * ar * height / width)) width = int(round(size * ar)) else: width = int(round(float(size) * width / height)) height = size self.preview.set_size_request(width, height) return width, height def set_show_preview(self, show_preview): if show_preview: self.preview_box.show() else: self.preview_box.hide() def get_preview_allocation(self): a = self.preview.get_allocation() self.area.set_preview_allocation(a) return a #### Events def do_enter_notify_event(self, event): # In compiz there is a enter and # a leave event before a press event. # Keep that in mind when coding this def! CairoButton.do_enter_notify_event(self, event) if self.pressed : return if self.globals.settings["opacify"]: self.opacify_sid = \ gobject.timeout_add(100, self.__opacify) def do_leave_notify_event(self, event): # In compiz there is a enter and a leave # event before a press event. # Keep that in mind when coding this def! CairoButton.do_leave_notify_event(self, event) self.pressed = False if self.globals.settings["opacify"]: self.deopacify_sid = \ gobject.timeout_add(200, self.__deopacify) def do_button_press_event(self,event): # In compiz there is a enter and a leave event before # a press event. # self.pressed is used to stop functions started with # gobject.timeout_add from self.__on_mouse_enter # or self.__on_mouse_leave. CairoButton.do_button_press_event(self, event) self.pressed = True self.press_sid = gobject.timeout_add(600, self.__set_pressed_false) def __set_pressed_false(self): # Helper function for __on_press_event. self.pressed = False self.press_sid = None return False def do_scroll_event(self, event): window = self.window_r() if self.globals.settings["opacify"]: window.deopacify() if not event.direction in (gtk.gdk.SCROLL_UP, gtk.gdk.SCROLL_DOWN): return direction = {gtk.gdk.SCROLL_UP: "scroll_up", gtk.gdk.SCROLL_DOWN: "scroll_down"}[event.direction] action = self.globals.settings["windowbutton_%s"%direction] window.action_function_dict[action](window, self, event) if self.globals.settings["windowbutton_close_popup_on_%s"%direction]: self.group_r().popup.hide() def do_clicked(self, event): window = self.window_r() if self.globals.settings["opacify"]: window.deopacify() if not event.button in (1, 2, 3): return button = {1:"left", 2: "middle", 3: "right"}[event.button] if event.state & gtk.gdk.SHIFT_MASK: mod = "shift_and_" else: mod = "" action_str = "windowbutton_%s%s_click_action"%(mod, button) action = self.globals.settings[action_str] window.action_function_dict[action](window, self, event) popup_close = "windowbutton_close_popup_on_%s%s_click"%(mod, button) if self.globals.settings[popup_close]: self.group_r().popup.hide() def __on_close_button_clicked(self, *args): window = self.window_r() if self.globals.settings["opacify"]: window.deopacify() window.action_close_window() def __on_close_button_leave(self, widget, event): if not self.pointer_is_inside(): self.do_leave_notify_event(event) #### D'n'D def do_drag_motion(self, drag_context, x, y, t): if not self.drag_entered: self.group_r().popup.expose() self.drag_entered = True self.dnd_select_window = \ gobject.timeout_add(600, self.window_r().action_select_window) drag_context.drag_status(gtk.gdk.ACTION_PRIVATE, t) return True def do_drag_leave(self, drag_context, t): self.drag_entered = False gobject.source_remove(self.dnd_select_window) self.group_r().popup.expose() self.group_r().popup.hide_if_not_hovered() #### Opacify def __opacify(self): window = self.window_r() if window.wnck.is_minimized(): return False # if self.pressed is true, opacity_request is called by an # wrongly sent out enter_notification_event sent after a # press (because of a bug in compiz). if self.pressed: self.pressed = False return False # Check if mouse cursor still is over the window button. if self.pointer_is_inside(): window.opacify() # Just for safety in case no leave-signal is sent self.deopacify_sid = \ gobject.timeout_add(500, self.__deopacify) return False def __deopacify(self): window = self.window_r() # Make sure that mouse cursor really has left the window button. b_m_x,b_m_y = self.get_pointer() b_r = self.get_allocation() if b_m_x >= 0 and b_m_x < b_r.width \ and b_m_y >= 0 and b_m_y < b_r.height: return True # Wait before deopacifying in case a new windowbutton # should call opacify, to avoid flickering window.deopacify_sid = gobject.timeout_add(150, window.deopacify) return False #### Menu functions def show_menu(self, event): window = self.window_r() #Creates a popup menu menu = gtk.Menu() menu.connect("selection-done", self.__menu_closed) #(Un)Minimize minimize_item = None if window.wnck.get_actions() & WNCK_WINDOW_ACTION_MINIMIZE \ and not window.wnck.is_minimized(): minimize_item = gtk.MenuItem(_("_Minimize")) elif window.wnck.get_actions() & WNCK_WINDOW_ACTION_UNMINIMIZE \ and window.wnck.is_minimized(): minimize_item = gtk.MenuItem(_("Un_minimize")) if minimize_item: menu.append(minimize_item) minimize_item.connect("activate", window.action_minimize_window) minimize_item.show() # (Un)Maximize maximize_item = None if not window.wnck.is_maximized() \ and window.wnck.get_actions() & WNCK_WINDOW_ACTION_MAXIMIZE: maximize_item = gtk.MenuItem(_("Ma_ximize")) elif window.wnck.is_maximized() \ and window.wnck.get_actions() & WNCK_WINDOW_ACTION_UNMINIMIZE: maximize_item = gtk.MenuItem(_("Unma_ximize")) if maximize_item: menu.append(maximize_item) maximize_item.connect("activate", window.action_maximize_window) maximize_item.show() # Close close_item = gtk.MenuItem(_("_Close")) menu.append(close_item) close_item.connect("activate", window.action_close_window) close_item.show() menu.popup(None, None, None, event.button, event.time) self.globals.gtkmenu_showing = True def __menu_closed(self, menushell): self.globals.gtkmenu_showing = False self.group_r().popup.hide() menushell.destroy()
class CairoArea(gtk.Alignment): __gsignals__ = {"expose-event" : "override"} def __init__(self, text=None, area_type="window_item"): self.type = area_type self.text = text gtk.Alignment.__init__(self, 0, 0, 1, 1) self.popup_style = PopupStyle() lrp = int(self.popup_style.get("%s_lr_padding" % self.type, 5)) tdp = int(self.popup_style.get("%s_td_padding" % self.type, 5)) self.set_padding(lrp, lrp, tdp, tdp) self.set_app_paintable(1) self.globals = Globals() self.highlighted = False self.pressed_down = False self.active_window = False self.needs_attention = False self.minimized = False self.preview_allocation = [0, 0, 0, 0] if text: self.label = gtk.Label() self.add(self.label) self.label.show() color = self.globals.colors["color2"] self.set_label(text, color) else: self.label = None def set_label(self, text, color=None): self.text = text if color: text = "<span foreground=\"" + color + "\">" + escape(text) + \ "</span>" self.label.set_text(text) self.label.set_use_markup(True) self.label.set_use_underline(True) def set_padding(self, top, bottom, left, right): self.pressed_down = False gtk.Alignment.set_padding(self, top, bottom, left, right) def set_label_color(self, color): label = "<span foreground=\"" + color + "\">" + escape(self.text) + \ "</span>" self.label.set_text(label) self.label.set_use_markup(True) self.label.set_use_underline(True) def do_expose_event(self, event, arg=None): a = self.get_allocation() mx , my = self.get_pointer() preview = self.globals.settings["preview"] and \ self.globals.get_compiz_version() >= "0.9" and \ (self.globals.settings["preview_minimized"] or \ not self.minimized) highlighted = self.highlighted or \ (mx >= 0 and mx < a.width and my >= 0 and my < a.height) if preview or self.active_window or \ highlighted or self.needs_attention: ctx = self.window.cairo_create() ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height) ctx.clip() if self.needs_attention: self.draw_type_frame(ctx, a.x, a.y, a.width, a.height, "needs_attention_item") if self.active_window: self.draw_type_frame(ctx, a.x, a.y, a.width, a.height, "active_item") if highlighted: self.draw_frame(ctx, a.x, a.y, a.width, a.height) # Empty preview space if preview: ctx.rectangle(*self.preview_allocation) ctx.set_source_rgba(1, 1, 1, 0) ctx.set_operator(cairo.OPERATOR_SOURCE) ctx.fill() self.propagate_expose(self.get_child(), event) return def draw_frame(self, ctx, x, y, w, h): if self.is_composited(): r, g, b = parse_color(self.globals.colors["color1"]) alpha = parse_alpha(self.globals.colors["color1_alpha"]) else: r = g = b = 0.0 alpha = 0.25 roundness = int(self.popup_style.get("%s_roundness" % \ self.type, 5)) make_path(ctx, x, y, w, h, roundness) ctx.set_source_rgba(r, g, b, alpha) ctx.fill_preserve() bc = self.popup_style.get("%s_border_color" % self.type, "#FFFFFF") if not bc[0] == "#": bc = "#%s" % bc alpha = self.popup_style.get("%s_border_alpha" % self.type, 80) alpha = float(alpha) / 100 r, g, b = parse_color(bc) ctx.set_source_rgba(r, g, b, alpha) ctx.set_line_width(1) ctx.stroke() def draw_type_frame(self, ctx, x, y, w, h, type_): # Todo: make colors themable? if type_ == "active_item": color = self.globals.colors["color3"] elif type_ == "needs_attention_item": color = self.popup_style.get("%s_color" % type_, "#FF0000") roundness = int(self.popup_style.get("%s_roundness" % \ self.type, 5)) make_path(ctx, x, y, w, h, roundness) if color[0] != "#": color = "#%s" % color r, g, b = parse_color(color) # Todo: make alpha adjustable from theme. alpha = self.popup_style.get("%s_alpha" % type_, 15) alpha = float(alpha) / 100 ctx.set_source_rgba(r, g, b, 0.25) ctx.fill_preserve() bc = self.popup_style.get("%s_border_color" % type_, "#FFFFFF") if not bc[0] == "#": bc = "#%s" % bc # Todo: make alpha adjustable from theme. r, g, b = parse_color(bc) alpha = self.popup_style.get("%s_border_alpha" % type_, 15) alpha = float(alpha) / 100 ctx.set_source_rgba(r, g, b, alpha) ctx.set_line_width(1) ctx.stroke() def set_pressed_down(self, pressed): p = self.get_padding() if pressed and not self.pressed_down: gtk.Alignment.set_padding(self, p[0] + 1, p[1] - 1, p[2], p[3]) elif self.pressed_down and not pressed: gtk.Alignment.set_padding(self, p[0] - 1, p[1] + 1, p[2], p[3]) self.pressed_down = pressed def set_highlighted(self, highlighted): self.highlighted = highlighted self.queue_draw() def set_active_window(self, active): self.active_window = active self.queue_draw() def set_needs_attention(self, needs_attention): self.needs_attention = needs_attention self.queue_draw() def set_minimized(self, minimized): self.minimized = minimized self.queue_draw() def set_preview_allocation(self, allocation): self.preview_allocation = allocation def pointer_is_inside(self): mx,my = self.get_pointer() a = self.get_allocation() if mx >= 0 and mx < a.width \ and my >= 0 and my < a.height: # Mouse pointer is inside the "rectangle" # but check if it's still outside the rounded corners x = None y = None r = int(self.popup_style.get("%s_roundness" % self.type, 5)) if mx < r: x = r - mx if (a.width - mx) < r: x = mx - (a.width - r) if my < r: y = r - my if (a.height - my) < r: y = my - (a.height - r) if x is None or y is None \ or (x**2 + y**2) < (r-1)**2: return True else: return False
class WindowItem(CairoButton): __gsignals__ = { "enter-notify-event": "override", "leave-notify-event": "override", "button-press-event": "override", "scroll-event": "override", "clicked": "override", "drag-motion": "override", "drag-leave": "override", } def __init__(self, window, group): CairoButton.__init__(self) self.set_no_show_all(True) self.window_r = weakref.ref(window) self.group_r = weakref.ref(group) self.globals = Globals() self.opacify_sid = None self.deopacify_sid = None self.press_sid = None self.pressed = False self.close_button = CairoCloseButton() self.close_button.set_no_show_all(True) if self.globals.settings["show_close_button"]: self.close_button.show() self.label = gtk.Label() self.label.set_ellipsize(pango.ELLIPSIZE_END) self.label.set_alignment(0, 0.5) self.__update_label() self.area.set_needs_attention(window.wnck.needs_attention()) hbox = gtk.HBox() icon = window.wnck.get_mini_icon() self.icon_image = gtk.image_new_from_pixbuf(icon) hbox.pack_start(self.icon_image, False) hbox.pack_start(self.label, True, True, padding=4) alignment = gtk.Alignment(1, 0.5, 0, 0) alignment.add(self.close_button) hbox.pack_start(alignment, False, False) vbox = gtk.VBox() vbox.pack_start(hbox, False) self.preview_box = gtk.Alignment(0.5, 0.5, 0, 0) self.preview_box.set_padding(4, 2, 0, 0) self.preview = gtk.Image() self.preview_box.add(self.preview) self.preview.show() vbox.pack_start(self.preview_box, True, True) self.add(vbox) self.preview_box.set_no_show_all(True) vbox.show_all() self.show_all() self.update_show_state() self.drag_dest_set(0, [], 0) self.drag_entered = False self.close_button.connect("button-press-event", self.disable_click) self.close_button.connect("clicked", self.__on_close_button_clicked) self.close_button.connect("leave-notify-event", self.__on_close_button_leave) connect(self.globals, "show-close-button-changed", self.__on_show_close_button_changed) connect(self.globals, "color-changed", self.__update_label) connect(self.globals, "preview-size-changed", self.update_preview) connect(self.globals, "window-title-width-changed", self.__update_label) def clean_up(self): window = self.window_r() if self.deopacify_sid: gobject.source_remove(self.deopacify_sid) window.deopacify() if self.opacify_sid: gobject.source_remove(self.opacify_sid) if self.press_sid: gobject.source_remove(self.press_sid) self.close_button.destroy() def show(self): self.update_preview() CairoButton.show(self) def __on_show_close_button_changed(self, *args): if self.globals.settings["show_close_button"]: self.close_button.show() else: self.close_button.hide() self.label.queue_resize() #### Apperance def __update_label(self, arg=None): """Updates the style of the label according to window state.""" window = self.window_r() text = escape(str(window.wnck.get_name())) if window.wnck.is_minimized(): color = self.globals.colors["color4"] else: color = self.globals.colors["color2"] text = "<span foreground=\"" + color + "\">" + text + "</span>" self.label.set_text(text) self.label.set_use_markup(True) if self.globals.settings["preview"]: # The label should be 140px wide unless there are more room # because the preview takes up more. size = 140 else: size = self.globals.settings["window_title_width"] self.label.set_size_request(size, -1) def __make_minimized_icon(self, icon): pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, icon.get_width(), icon.get_height()) pixbuf.fill(0x00000000) minimized_icon = pixbuf.copy() icon.composite(pixbuf, 0, 0, pixbuf.get_width(), pixbuf.get_height(), 0, 0, 1, 1, gtk.gdk.INTERP_BILINEAR, 190) pixbuf.saturate_and_pixelate(minimized_icon, 0.12, False) return minimized_icon def __update_icon(self): window = self.window_r() icon = window.wnck.get_mini_icon() if window.wnck.is_minimized(): pixbuf = self.__make_minimized_icon(icon) self.icon_image.set_from_pixbuf(pixbuf) if self.globals.settings["preview"] and \ (self.globals.get_compiz_version() < "0.9" or \ not self.globals.settings["preview_minimized"]): self.preview.set_from_pixbuf(window.wnck.get_icon()) else: self.icon_image.set_from_pixbuf(icon) self.preview.clear() def minimized_changed(self): window = self.window_r() self.__update_label() self.__update_icon() self.area.set_minimized(window.wnck.is_minimized()) def active_changed(self): window = self.window_r() self.area.set_active_window(window.is_active_window) self.__update_label() def icon_changed(self): self.__update_icon() def needs_attention_changed(self): window = self.window_r() self.area.set_needs_attention(window.wnck.needs_attention()) self.__update_label() def name_changed(self): self.__update_label() def set_highlighted(self, highlighted): self.area.set_highlighted(highlighted) def update_show_state(self): window = self.window_r() if (self.globals.settings["show_only_current_desktop"] and \ not window.on_current_desktop) or \ (self.globals.settings["show_only_current_monitor"] and \ window.monitor != self.group_r().monitor): self.hide() else: self.show() ####Preview def update_preview(self, *args): window = self.window_r() group = self.group_r() width = window.wnck.get_geometry()[2] height = window.wnck.get_geometry()[3] ar = group.monitor_aspect_ratio size = self.globals.settings["preview_size"] if width * ar < size and height < size: pass elif float(width) / height > ar: height = int(round(size * ar * height / width)) width = int(round(size * ar)) else: width = int(round(float(size) * width / height)) height = size self.preview.set_size_request(width, height) return width, height def set_show_preview(self, show_preview): if show_preview: self.preview_box.show() else: self.preview_box.hide() def get_preview_allocation(self): a = self.preview.get_allocation() self.area.set_preview_allocation(a) return a #### Events def do_enter_notify_event(self, event): # In compiz there is a enter and # a leave event before a press event. # Keep that in mind when coding this def! CairoButton.do_enter_notify_event(self, event) if self.pressed: return if self.globals.settings["opacify"]: self.opacify_sid = \ gobject.timeout_add(100, self.__opacify) def do_leave_notify_event(self, event): # In compiz there is a enter and a leave # event before a press event. # Keep that in mind when coding this def! CairoButton.do_leave_notify_event(self, event) self.pressed = False if self.globals.settings["opacify"]: self.deopacify_sid = \ gobject.timeout_add(200, self.__deopacify) def do_button_press_event(self, event): # In compiz there is a enter and a leave event before # a press event. # self.pressed is used to stop functions started with # gobject.timeout_add from self.__on_mouse_enter # or self.__on_mouse_leave. CairoButton.do_button_press_event(self, event) self.pressed = True self.press_sid = gobject.timeout_add(600, self.__set_pressed_false) def __set_pressed_false(self): # Helper function for __on_press_event. self.pressed = False self.press_sid = None return False def do_scroll_event(self, event): window = self.window_r() if self.globals.settings["opacify"]: window.deopacify() if not event.direction in (gtk.gdk.SCROLL_UP, gtk.gdk.SCROLL_DOWN): return direction = { gtk.gdk.SCROLL_UP: "scroll_up", gtk.gdk.SCROLL_DOWN: "scroll_down" }[event.direction] action = self.globals.settings["windowbutton_%s" % direction] window.action_function_dict[action](window, self, event) if self.globals.settings["windowbutton_close_popup_on_%s" % direction]: self.group_r().popup.hide() def do_clicked(self, event): window = self.window_r() if self.globals.settings["opacify"]: window.deopacify() if not event.button in (1, 2, 3): return button = {1: "left", 2: "middle", 3: "right"}[event.button] if event.state & gtk.gdk.SHIFT_MASK: mod = "shift_and_" else: mod = "" action_str = "windowbutton_%s%s_click_action" % (mod, button) action = self.globals.settings[action_str] window.action_function_dict[action](window, self, event) popup_close = "windowbutton_close_popup_on_%s%s_click" % (mod, button) if self.globals.settings[popup_close]: self.group_r().popup.hide() def __on_close_button_clicked(self, *args): window = self.window_r() if self.globals.settings["opacify"]: window.deopacify() window.action_close_window() def __on_close_button_leave(self, widget, event): if not self.pointer_is_inside(): self.do_leave_notify_event(event) #### D'n'D def do_drag_motion(self, drag_context, x, y, t): if not self.drag_entered: self.group_r().popup.expose() self.drag_entered = True self.dnd_select_window = \ gobject.timeout_add(600, self.window_r().action_select_window) drag_context.drag_status(gtk.gdk.ACTION_PRIVATE, t) return True def do_drag_leave(self, drag_context, t): self.drag_entered = False gobject.source_remove(self.dnd_select_window) self.group_r().popup.expose() self.group_r().popup.hide_if_not_hovered() #### Opacify def __opacify(self): window = self.window_r() if window.wnck.is_minimized(): return False # if self.pressed is true, opacity_request is called by an # wrongly sent out enter_notification_event sent after a # press (because of a bug in compiz). if self.pressed: self.pressed = False return False # Check if mouse cursor still is over the window button. if self.pointer_is_inside(): window.opacify() # Just for safety in case no leave-signal is sent self.deopacify_sid = \ gobject.timeout_add(500, self.__deopacify) return False def __deopacify(self): window = self.window_r() # Make sure that mouse cursor really has left the window button. b_m_x, b_m_y = self.get_pointer() b_r = self.get_allocation() if b_m_x >= 0 and b_m_x < b_r.width \ and b_m_y >= 0 and b_m_y < b_r.height: return True # Wait before deopacifying in case a new windowbutton # should call opacify, to avoid flickering window.deopacify_sid = gobject.timeout_add(150, window.deopacify) return False #### Menu functions def show_menu(self, event): window = self.window_r() #Creates a popup menu menu = gtk.Menu() menu.connect("selection-done", self.__menu_closed) #(Un)Minimize minimize_item = None if window.wnck.get_actions() & WNCK_WINDOW_ACTION_MINIMIZE \ and not window.wnck.is_minimized(): minimize_item = gtk.MenuItem(_("_Minimize")) elif window.wnck.get_actions() & WNCK_WINDOW_ACTION_UNMINIMIZE \ and window.wnck.is_minimized(): minimize_item = gtk.MenuItem(_("Un_minimize")) if minimize_item: menu.append(minimize_item) minimize_item.connect("activate", window.action_minimize_window) minimize_item.show() # (Un)Maximize maximize_item = None if not window.wnck.is_maximized() \ and window.wnck.get_actions() & WNCK_WINDOW_ACTION_MAXIMIZE: maximize_item = gtk.MenuItem(_("Ma_ximize")) elif window.wnck.is_maximized() \ and window.wnck.get_actions() & WNCK_WINDOW_ACTION_UNMINIMIZE: maximize_item = gtk.MenuItem(_("Unma_ximize")) if maximize_item: menu.append(maximize_item) maximize_item.connect("activate", window.action_maximize_window) maximize_item.show() # Close close_item = gtk.MenuItem(_("_Close")) menu.append(close_item) close_item.connect("activate", window.action_close_window) close_item.show() menu.popup(None, None, None, event.button, event.time) self.globals.gtkmenu_showing = True def __menu_closed(self, menushell): self.globals.gtkmenu_showing = False self.group_r().popup.hide() menushell.destroy()
class CairoAppButton(gtk.EventBox): __gsignals__ = {"expose-event" : "override", "size_allocate": "override"} def __init__(self, surface=None, expose_on_clear=False): gtk.EventBox.__init__(self) self.set_visible_window(False) self.area = gtk.Alignment(0, 0, 1, 1) self.add(self.area) self.area.show() self.globals = Globals() self.surface = surface self.expose_on_clear = expose_on_clear self.badge = None self.badge_text = None self.progress_bar = None self.progress = None self.bl_sid = self.globals.connect("badge-look-changed", self.__on_badge_look_changed) self.pbl_sid = self.globals.connect("progress-bar-look-changed", self.__on_progress_bar_look_changed) def update(self, surface=None): a = self.area.get_allocation() if surface is not None: self.surface = surface if self.window is None: return if self.expose_on_clear: self.area.window.clear_area_e(a.x, a.y, a.width, a.height) else: self.area.window.clear_area(a.x, a.y, a.width, a.height) ctx = self.area.window.cairo_create() ctx.rectangle(a.x, a.y, a.width, a.height) ctx.clip() ctx.set_source_surface(self.surface, a.x, a.y) ctx.paint() for surface in (self.badge, self.progress_bar): if surface is not None: ctx.rectangle(a.x, a.y, a.width, a.height) ctx.clip() ctx.set_source_surface(surface, a.x, a.y) ctx.paint() child = self.area.get_child() if child: child.queue_draw() def do_expose_event(self, event): if self.surface is not None: ctx = self.area.window.cairo_create() ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height) ctx.clip() a = self.get_allocation() ctx.set_source_surface(self.surface, a.x, a.y) ctx.paint() for surface in (self.badge, self.progress_bar): if surface is not None: ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height) ctx.clip() ctx.set_source_surface(surface, a.x, a.y) ctx.paint() self.propagate_expose(self.area, event) def do_size_allocate(self, allocation): gtk.EventBox.do_size_allocate(self, allocation) if self.badge: self.make_badge(self.badge_text) if self.progress_bar: self.make_progress_bar(self.progress) def make_badge(self, text): if not text: self.badge_text = None self.badge = None return self.badge_text = text a = self.area.get_allocation() self.badge = cairo.ImageSurface(cairo.FORMAT_ARGB32, a.width, a.height) ctx = gtk.gdk.CairoContext(cairo.Context(self.badge)) layout = ctx.create_layout() if self.globals.settings["badge_use_custom_font"]: font = self.globals.settings["badge_font"] font_base, font_size = font.rsplit(" ", 1) font_size = int(font_size) else: font_size = max(int(round(0.2 * a.height)), 6) font_base = "sans bold" font = "%s %s" % (font_base, font_size) layout.set_font_description(pango.FontDescription(font)) layout.set_text(text) te = layout.get_pixel_extents() w = te[1][2] h = te[0][1] + te[0][3] size = min(a.width, a.height) p = 2 d = int(round(0.05 * size)) # Make sure the badge isn't too wide. while w + 2 * p + d >= a.width and font_size > 4: font_size = max(4, font_size - max(2, int(font_size * 0.2))) font = "%s %s" % (font_base, font_size) layout.set_font_description(pango.FontDescription(font)) te = layout.get_pixel_extents() w = te[1][2] h = te[0][1] + te[0][3] x = a.width - w - p - d y = a.height - h - p - d make_path(ctx, x - p, y + te[0][1] - (p + 1), w + 2 * p, h - te[0][1] + 2 * (p + 1), r=4) if self.globals.settings["badge_custom_bg_color"]: color = self.globals.settings["badge_bg_color"] alpha = float(self.globals.settings["badge_bg_alpha"]) / 255 else: color = "#CDCDCD" alpha = 1.0 r = int(color[1:3], 16)/255.0 g = int(color[3:5], 16)/255.0 b = int(color[5:7], 16)/255.0 ctx.set_source_rgba(r, g, b, alpha) ctx.fill_preserve() if self.globals.settings["badge_custom_fg_color"]: color = self.globals.settings["badge_fg_color"] alpha = float(self.globals.settings["badge_fg_alpha"]) / 255 else: color = "#020202" alpha = 1.0 r = int(color[1:3], 16)/255.0 g = int(color[3:5], 16)/255.0 b = int(color[5:7], 16)/255.0 ctx.set_source_rgba(r, g, b, alpha) ctx.set_line_width(0.8) ctx.stroke() ctx.move_to(x,y) ctx.show_layout(layout) def make_progress_bar(self, progress): if progress is None: self.progress = None self.progress_bar = None return self.progress = progress a = self.area.get_allocation() x = max(0.1 * a.width, 2) y = max(0.15 * a.height, 3) w = min(max (0.60 * a.width, 20), a.width - 2 * x) h = max(0.10 * a.height, 3.0) ro = h / 2 self.progress_bar = cairo.ImageSurface(cairo.FORMAT_ARGB32, a.width, a.height) ctx = cairo.Context(self.progress_bar) ctx.move_to(x,y) ctx.line_to(x + w * progress, y) ctx.line_to(x + w * progress, y + h) ctx.line_to(x, y + h) ctx.close_path() ctx.clip() if self.globals.settings["progress_custom_fg_color"]: color = self.globals.settings["progress_fg_color"] alpha = float(self.globals.settings["progress_fg_alpha"]) / 255 else: color = "#772953" alpha = 1.0 r = int(color[1:3], 16)/255.0 g = int(color[3:5], 16)/255.0 b = int(color[5:7], 16)/255.0 ctx.set_source_rgba(r, g, b, alpha) make_path(ctx, x, y, w, h, r=ro, b=0) ctx.fill() ctx.reset_clip() ctx.move_to(x + w * progress,y) ctx.line_to(x + w, y) ctx.line_to(x + w, y + h) ctx.line_to(x + w * progress, y + h) ctx.clip() make_path(ctx, x, y, w, h, r=ro, b=0) if self.globals.settings["progress_custom_bg_color"]: color = self.globals.settings["progress_bg_color"] bg_alpha = float(self.globals.settings["progress_bg_alpha"]) / 255 else: color = "#CDCDCD" bg_alpha = 0.25 br = int(color[1:3], 16)/255.0 bg = int(color[3:5], 16)/255.0 bb = int(color[5:7], 16)/255.0 ctx.set_source_rgba(br, bg, bb, bg_alpha) ctx.fill_preserve() ctx.reset_clip() ctx.set_source_rgba(r, g, b, alpha) ctx.set_line_width(0.8) ctx.stroke_preserve() def __on_badge_look_changed(self, *args): if self.badge: self.make_badge(self.badge_text) self.update() def __on_progress_bar_look_changed(self, *args): if self.progress_bar: self.make_progress_bar(self.progress) self.update() def destroy(self, *args, **kwargs): if self.bl_sid: self.globals.disconnect(self.bl_sid) self.bl_sid = None if self.pbl_sid: self.globals.disconnect(self.pbl_sid) self.pbl_sid = None if self.surface: self.surface = None gtk.EventBox.destroy(self, *args, **kwargs) def pointer_is_inside(self): b_m_x,b_m_y = self.get_pointer() b_r = self.get_allocation() if b_m_x >= 0 and b_m_x < b_r.width and \ b_m_y >= 0 and b_m_y < b_r.height: return True else: return False
def __init__(self, label=None, show_menu=False): gtk.VBox.__init__(self) self.set_app_paintable(1) self.globals = Globals() self.popup_style = PopupStyle()
class IconFactory(): """IconFactory takes care of finding the right icon for a program and prepares the cairo surface.""" icon_theme = gtk.icon_theme_get_default() # Constants # Icon types SOME_MINIMIZED = 1<<4 ALL_MINIMIZED = 1<<5 LAUNCHER = 1<<6 # Icon effects MOUSE_OVER = 1<<7 MOUSE_BUTTON_DOWN = 1<<8 NEEDS_ATTENTION = 1<<9 BLINK = 1<<10 # ACTIVE_WINDOW ACTIVE = 1<<11 LAUNCH_EFFECT = 1<<12 # Double width/height icons for drag and drop situations. DRAG_DROPP = 1<<13 TYPE_DICT = {'some_minimized':SOME_MINIMIZED, 'all_minimized':ALL_MINIMIZED, 'launcher':LAUNCHER, 'mouse_over':MOUSE_OVER, 'needs_attention':NEEDS_ATTENTION, 'blink':BLINK, 'active':ACTIVE, 'launching':LAUNCH_EFFECT, 'mouse_button_down':MOUSE_BUTTON_DOWN} def __init__(self, class_group=None, desktop_entry=None, identifier=None): self.theme = Theme() self.globals = Globals() self.globals.connect('color-changed', self.reset_surfaces) self.desktop_entry = desktop_entry self.identifier = identifier self.class_group = class_group # Setting size to something other than zero to # avoid crashes if surface_update() is runned # before the size is set. self.size = 15 self.icon = None self.surfaces = {} self.average_color = None self.max_win_nr = self.theme.get_windows_cnt() self.types_in_theme = 0 for type in self.theme.get_types(): if not type in self.TYPE_DICT: continue self.types_in_theme = self.types_in_theme | self.TYPE_DICT[type] def remove(self): del self.desktop_entry del self.class_group del self.icon del self.surfaces del self.theme def set_desktop_entry(self, desktop_entry): self.desktop_entry = desktop_entry self.surfaces = {} del self.icon self.icon = None def set_class_group(self, class_group): if not self.desktop_entry and not self.class_group: self.surfaces = {} del self.icon self.icon = None self.class_group = class_group def set_size(self, size): if size <= 0: # To avoid chrashes. size = 15 self.size = size self.surfaces = {} self.average_color = None def get_size(self): return self.size def reset_surfaces(self, arg=None): self.surfaces = {} self.average_color = None def surface_update(self, type = 0): # Checks if the requested pixbuf is already # drawn and returns it if it is. # Othervice the surface is drawn, saved and returned. #The first four bits of type is for telling the number of windows self.win_nr = min(type & 15, self.max_win_nr) # Remove all types that are not used by the theme (saves memory) dnd = type & self.DRAG_DROPP type = type & self.types_in_theme type += self.win_nr if type in self.surfaces: surface = self.surfaces[type] else: self.temp = {} surface = None commands = self.theme.get_icon_dict() self.ar = self.theme.get_aspect_ratio() self.type = type for command, args in commands.items(): try: f = getattr(self,"command_%s"%command) except: raise else: surface = f(surface, **args) # Todo: add size correction. self.surfaces[type] = surface del self.temp gc.collect() if dnd: surface = self.dd_highlight(surface, self.globals.orient) gc.collect() return surface def dd_highlight(self, surface, direction = 'h'): w = surface.get_width() h = surface.get_height() # Make a background almost twice as wide or high # as the surface depending on panel orientation. if direction == 'v': h = h + 4 else: w = w + 4 bg = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(bg) # Put arrow pointing to the empty part on it. if direction == 'v': ctx.move_to(1, h - 1.5) ctx.line_to(w - 1, h - 1.5) ctx.set_source_rgba(1, 1, 1, 0.2) ctx.set_line_width(2) ctx.stroke() ctx.move_to(2, h - 1.5) ctx.line_to(w - 2, h - 1.5) ctx.set_source_rgba(0, 0, 0, 0.7) ctx.set_line_width(1) ctx.stroke() else: ctx.move_to(w - 1.5, 1) ctx.line_to(w - 1.5, h - 1) ctx.set_source_rgba(1, 1, 1, 0.2) ctx.set_line_width(2) ctx.stroke() ctx.move_to(w - 1.5, 2) ctx.line_to(w - 1.5, h - 2) ctx.set_source_rgba(0, 0, 0, 0.7) ctx.set_line_width(1) ctx.stroke() # And put the surface on the left/upper half of it. ctx.set_source_surface(surface, 0, 0) ctx.paint() return bg def get_color(self, color): if color == "active_color": color = 'color5' if color in ['color%s'%i for i in range(1, 9)]: color = self.globals.colors[color] if color == "icon_average": color = self.get_average_color() else: try: if len(color) != 7: raise ValueError('The string has the wrong lenght') t = int(color[1:], 16) except: print "Theme error: the color attribute for a theme command"+ \ " should be a six digit hex string eg. \"#FFFFFF\" or"+ \ " the a dockbarx color (\"color1\"-\"color8\")." color = "#000000" return color def get_alpha(self, alpha): # Transparency if alpha == "active_opacity": # For backwards compability alpha = "color5" for i in range(1, 9): if alpha in ('color%s'%i, 'opacity%s'%i): if self.globals.colors.has_key('color%s_alpha'%i): a = float(self.globals.colors['color%s_alpha'%i])/255 else: print "Theme error: The theme has no" + \ " opacity option for color%s."%i a = 1.0 break else: try: a = float(alpha)/100 if a > 1.0 or a < 0: raise except: print 'Theme error: The opacity attribute of a theme ' + \ 'command should be a number between "0" ' + \ ' and "100" or "color1" to "color8".' a = 1.0 return a def get_average_color(self): if self.average_color is not None: return self.average_color r = 0 b = 0 g = 0 i = 0 pb = self.surface2pixbuf(self.icon) for row in pb.get_pixels_array(): for pix in row: if pix[3] > 30: i += 1 r += pix[0] g += pix[1] b += pix[2] if i > 0: r = int(float(r) / i + 0.5) g = int(float(g) / i + 0.5) b = int(float(b) / i + 0.5) r = ("0%s"%hex(r)[2:])[-2:] g = ("0%s"%hex(g)[2:])[-2:] b = ("0%s"%hex(b)[2:])[-2:] self.average_color = "#"+r+g+b del pb return self.average_color #### Flow commands def command_if(self, surface, type=None, windows=None, size=None, content=None): if content is None: return surface # TODO: complete this ## l = [] ## splits = ['!', '(', ')', '&', '|'] ## for c in type: ## if c in splits: ## l.append(c) ## elif l[-1] in splits: ## l.append(c) ## elif not l: ## l.append(c) ## else: ## l[-1] += c # Check if the type condition is satisfied if type is not None: negation = False if type[0] == "!" : type = type[1:] negation = True is_type = bool(type in self.TYPE_DICT \ and self.type & self.TYPE_DICT[type]) if not (is_type ^ negation): return surface #Check if the window number condition is satisfied if windows is not None: arg = windows negation = False if arg[0] == "!" : arg = windows[1:] negation = True if arg[0] == ":": arg = "0" + arg elif arg[-1] == ":": arg = arg +"15" l = arg.split(":", 1) try: l = [int(n) for n in l] except ValueError: print 'Theme Error: The windows attribute of ' + \ 'an <if> statement can\'t look like this:' + \ ' "%s". See Theming HOWTO for more information'%windows return surface if len(l) == 1: if not ((l[0] == self.win_nr) ^ negation): return surface else: if not ((l[0]<=self.win_nr and self.win_nr<=l[1]) ^ negation): return surface #Check if the icon size condition is satisfied if size is not None: arg = size negation = False if arg[0] == "!" : arg = size[1:] negation = True if arg[0] == ":": arg = "0" + arg elif arg[-1] == ":": arg = arg +"200" l = arg.split(":", 1) try: l = [int(n) for n in l] except ValueError: print 'Theme Error: The size attribute of ' + \ 'an <if> statement can\'t look like this:' + \ ' "%s". See Theming HOWTO for more information'%size return surface if len(l) == 1: if not ((l[0] == self.win_nr) ^ negation): return surface else: if not ((l[0]<=self.size and self.size<=l[1]) ^ negation): return surface # All tests passed, proceed. for command, args in content.items(): try: f = getattr(self,"command_%s"%command) except: raise else: surface = f(surface, **args) return surface def command_pixmap_from_self(self, surface, name, content=None): if not name: print "Theme Error: no name given for pixmap_from_self" raise Exeption w = int(surface.get_width()) h = int(surface.get_height()) self.temp[name] = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(self.temp[name]) ctx.set_source_surface(surface) ctx.paint() if content is None: return surface for command,args in content.items(): try: f = getattr(self,"command_%s"%command) except: raise else: self.temp[name] = f(self.temp[name], **args) return surface def command_pixmap(self, surface, name, content=None, size=None): if size is not None: # TODO: Fix for different height and width w = h = self.size + int(size) elif surface is None: w = h = self.size else: w = surface.get_width() h = surface.get_height() self.temp[name] = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) if content is None: return surface for command,args in content.items(): try: f = getattr(self,"command_%s"%command) except: raise else: self.temp[name] = f(self.temp[name], **args) return surface #### Get icon def command_get_icon(self,surface=None, size=0): size = int(size) size = self.size + size if size <= 0: # To avoid chrashes. size = 15 if self.icon \ and self.icon.get_width() == size \ and self.icon.get_height() == size: return self.icon del self.icon self.icon = None pb = self.find_icon_pixbuf(size) if pb.get_width() != pb.get_height(): if pb.get_width() < pb.get_height(): h = size w = pb.get_width() * size/pb.get_height() elif pb.get_width() > pb.get_height(): w = size h = pb.get_height() * size/pb.get_width() self.icon = cairo.ImageSurface(cairo.FORMAT_ARGB32, size, size) ctx = gtk.gdk.CairoContext(cairo.Context(self.icon)) pbs = pb.scale_simple(w, h, gtk.gdk.INTERP_BILINEAR) woffset = int(float(size - w) / 2 + 0.5) hoffset = int(float(size - h) / 2 + 0.5) ctx.set_source_pixbuf(pb, woffset, hoffset) ctx.paint() del pb del pbs elif pb.get_width() != size: pbs = pb.scale_simple(size, size, gtk.gdk.INTERP_BILINEAR) self.icon = self.pixbuf2surface(pbs) del pb del pbs else: self.icon = self.pixbuf2surface(pb) del pb return self.icon def find_icon_pixbuf(self, size): # Returns the icon pixbuf for the program. Uses the following metods: # 1) If it is a launcher, return the icon from the # launcher's desktopfile # 2) Get the icon from the gio app # 3) Check if the res_class fits an themed icon. # 4) Search in path after a icon matching reclass. # 5) Use the mini icon for the class pixbuf = None icon_name = None if self.desktop_entry: icon_name = self.desktop_entry.getIcon() if os.path.isfile(icon_name): pixbuf = self.icon_from_file_name(icon_name, size) if pixbuf is not None: return pixbuf if not icon_name: if self.identifier: icon_name = self.identifier.lower() elif self.class_group: icon_name = self.class_group.get_res_class().lower() else: icon_name = "" # Special cases if icon_name.startswith('openoffice'): # Makes sure openoffice gets a themed icon icon_name = "ooo-writer" if self.icon_theme.has_icon(icon_name): return self.icon_theme.load_icon(icon_name,size,0) if icon_name[-4:] in (".svg", ".png", ".xpm"): if self.icon_theme.has_icon(icon_name[:-4]): pixbuf = self.icon_theme.load_icon(icon_name[:-4],size,0) if pixbuf is not None: return pixbuf pixbuf = self.icon_search_in_data_path(icon_name, size) if pixbuf is not None: return pixbuf if self.class_group: return self.class_group.get_icon().copy() # If no pixbuf has been found (can only happen for an unlaunched # launcher), make an empty pixbuf and show a warning. if self.icon_theme.has_icon('application-default-icon'): pixbuf = self.icon_theme.load_icon('application-default-icon', size, 0) else: pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, size,size) pixbuf.fill(0x00000000) if self.desktop_entry: name = self.desktop_entry.getName() else: name = None ## dialog = gtk.MessageDialog( ## parent=None, ## flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, ## type=gtk.MESSAGE_WARNING, ## buttons=gtk.BUTTONS_OK, ## message_format= (_("Cannot load icon for %s")%name)) ## dialog.set_title('DockBarX') ## dialog.run() ## dialog.destroy() return pixbuf def icon_from_file_name(self, icon_name, icon_size = -1): if os.path.isfile(icon_name): try: return gtk.gdk.pixbuf_new_from_file_at_size(icon_name, -1, icon_size) except: pass return None def icon_search_in_data_path(self, icon_name, icon_size): data_folders = None if os.environ.has_key("XDG_DATA_DIRS"): data_folders = os.environ["XDG_DATA_DIRS"] if not data_folders: data_folders = "/usr/local/share/:/usr/share/" for data_folder in data_folders.split(':'): #The line below line used datafolders instead of datafolder. #I changed it because I suspect it was a bug. paths = (os.path.join(data_folder, "pixmaps", icon_name), os.path.join(data_folder, "icons", icon_name)) for path in paths: if os.path.isfile(path): icon = self.icon_from_file_name(path, icon_size) if icon: return icon return None #### Other commands def command_get_pixmap(self, surface, name, size=0): if surface is None: if self.globals.orient == 'h': width = int(self.size * ar) height = self.size else: width = self.size height = int(self.size * ar) else: width = surface.get_width() height = surface.get_height() if self.theme.has_surface(name): surface = self.resize_surface(self.theme.get_surface(name), width, height) else: print "theme error: pixmap %s not found"%name return surface def command_fill(self, surface, color, opacity=100): w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(surface) ctx.paint() alpha = self.get_alpha(opacity) c = self.get_color(color) r = float(int(c[1:3], 16))/255 g = float(int(c[3:5], 16))/255 b = float(int(c[5:7], 16))/255 ctx.set_source_rgba(r, g, b) ctx.set_operator(cairo.OPERATOR_SOURCE) ctx.paint_with_alpha(alpha) return new def command_combine(self, surface, pix1, pix2, degrees=90): # Combines left half of surface with right half of surface2. # The transition between the two halves are soft. w = surface.get_width() h = surface.get_height() if pix1=="self": p1 = surface elif pix1 in self.temp: p1 = self.temp[pix1] elif self.theme.has_surface(pix1): w = surface.get_width() h = surface.get_height() p1 = self.resize_surface(self.theme.get_surface(bg), w, h) else: print "theme error: pixmap %s not found"%pix1 if pix2=="self": p2 = surface elif pix2 in self.temp: p2 = self.temp[pix2] elif self.theme.has_surface(pix2): w = surface.get_width() h = surface.get_height() p2 = self.resize_surface(self.theme.get_surface(bg), w, h) else: print "theme error: pixmap %s not found"%pix2 surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, p1.get_width(), p1.get_height()) ctx = cairo.Context(surface) linear = cairo.LinearGradient(0, 0, p1.get_width(), 0) linear.add_color_stop_rgba(0.4, 0, 0, 0, 0.5) linear.add_color_stop_rgba(0.6, 0, 0, 0, 1) ctx.set_source_surface(p2, 0, 0) #ctx.mask(linear) ctx.paint() linear = cairo.LinearGradient(0, 0, p1.get_width(), 0) linear.add_color_stop_rgba(0.4, 0, 0, 0, 1) linear.add_color_stop_rgba(0.6, 0, 0, 0, 0) ctx.set_source_surface(p1, 0, 0) ctx.mask(linear) try: del pb del pbs except: pass return surface def command_transp_sat(self, surface, opacity=100, saturation=100): # Makes the icon desaturized and/or transparent. w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = gtk.gdk.CairoContext(cairo.Context(new)) alpha = self.get_alpha(opacity) # Todo: Add error check for saturation if int(saturation) < 100: sio = StringIO() surface.write_to_png(sio) sio.seek(0) loader = gtk.gdk.PixbufLoader() loader.write(sio.getvalue()) loader.close() sio.close() pixbuf = loader.get_pixbuf() saturation = min(1.0, float(saturation)/100) pixbuf.saturate_and_pixelate(pixbuf, saturation, False) ctx.set_source_pixbuf(pixbuf, 0, 0) ctx.paint_with_alpha(alpha) del loader del sio del pixbuf gc.collect() else: ctx.set_source_surface(surface) ctx.paint_with_alpha(alpha) return new def command_composite(self, surface, bg, fg, opacity=100, xoffset=0, yoffset=0): if fg=="self": foreground = surface elif fg in self.temp: foreground = self.temp[fg] elif self.theme.has_surface(fg): w = surface.get_width() h = surface.get_height() foreground = self.resize_surface(self.theme.get_surface(fg), w, h) else: print "theme error: pixmap %s not found"%fg return surface if bg=="self": background = surface elif bg in self.temp: w = self.temp[bg].get_width() h = self.temp[bg].get_height() background = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(background) ctx.set_source_surface(self.temp[bg]) ctx.paint() elif self.theme.has_surface(bg): w = surface.get_width() h = surface.get_height() background = self.resize_surface(self.theme.get_surface(bg), w, h) else: print "theme error: pixmap %s not found"%bg return surface opacity = self.get_alpha(opacity) xoffset = float(xoffset) yoffset = float(yoffset) ctx = cairo.Context(background) ctx.set_source_surface(foreground, xoffset, yoffset) ctx.paint_with_alpha(opacity) return background def command_shrink(self, surface, percent=0, pixels=0): w0 = surface.get_width() h0 = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w0, h0) ctx = cairo.Context(new) w = int(((100-int(percent)) * w0)/100)-int(pixels) h = int(((100-int(percent)) * h0)/100)-int(pixels) shrinked = self.resize_surface(surface, w, h) x = int(float(w0 - w) / 2 + 0.5) y = int(float(h0 - h) / 2 + 0.5) ctx.set_source_surface(shrinked, x, y) ctx.paint() del shrinked return new def command_correct_size(self, surface): if surface is None: return if self.globals.orient == 'v': width = self.size height = int(self.size * self.ar) else: width = int(self.size * self.ar) height = self.size if surface.get_width() == width and surface.get_height() == height: return surface woffset = int(float(width - surface.get_width()) / 2 + 0.5) hoffset = int(float(height - surface.get_height()) / 2 + 0.5) new = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) ctx = cairo.Context(new) ctx.set_source_surface(surface, woffset, hoffset) ctx.paint() return new def command_glow(self, surface, color, opacity=100): # Adds a glow around the parts of the surface # that isn't completely transparent. alpha = self.get_alpha(opacity) # Thickness (pixels) tk = 1.5 # Prepare the glow that should be put behind the icon cs = self.command_colorize(surface, color) w = surface.get_width() h = surface.get_height() glow = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(glow) tk1 = tk/2.0 for x, y in ((-tk1,-tk1), (-tk1,tk1), (tk1,-tk1), (tk1,tk1)): ctx.set_source_surface(cs, x, y) ctx.paint_with_alpha(0.66) for x, y in ((-tk,-tk), (-tk,tk), (tk,-tk), (tk,tk)): ctx.set_source_surface(cs, x, y) ctx.paint_with_alpha(0.27) # Add glow and icon to a new canvas new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(glow) ctx.paint_with_alpha(alpha) ctx.set_source_surface(surface) ctx.paint() return new def command_colorize(self, surface, color): # Changes the color of all pixels to color. # The pixels alpha values are unchanged. # Convert color hex-string (format '#FFFFFF')to int r, g, b color = self.get_color(color) r = int(color[1:3], 16)/255.0 g = int(color[3:5], 16)/255.0 b = int(color[5:7], 16)/255.0 w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_rgba(r,g,b,1.0) ctx.mask_surface(surface) return new def command_bright(self, surface, strength = None, strenght = None): if strength is None and strenght is not None: # For compability with older themes. strength = strenght alpha = self.get_alpha(strength) w = surface.get_width() h = surface.get_height() # Colorize white white = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(white) ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0) ctx.mask_surface(surface) # Apply the white version over the icon # with the chosen alpha value new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(surface) ctx.paint() ctx.set_source_surface(white) ctx.paint_with_alpha(alpha) return new def command_alpha_mask(self, surface, mask): if mask in self.temp: mask = self.temp[mask] elif self.theme.has_surface(mask): m = self.surface2pixbuf(self.theme.get_surface(mask)) m = m.scale_simple(surface.get_width(), surface.get_height(), gtk.gdk.INTERP_BILINEAR) mask = self.pixbuf2surface(m) w = surface.get_width() h = surface.get_height() new = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(new) ctx.set_source_surface(surface) ctx.mask_surface(mask) return new #### Format conversions def pixbuf2surface(self, pixbuf): if pixbuf is None: return None w = pixbuf.get_width() h = pixbuf.get_height() surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = gtk.gdk.CairoContext(cairo.Context(surface)) ctx.set_source_pixbuf(pixbuf, 0, 0) ctx.paint() del pixbuf return surface def surface2pixbuf(self, surface): if surface is None: return None sio = StringIO() surface.write_to_png(sio) sio.seek(0) loader = gtk.gdk.PixbufLoader() loader.write(sio.getvalue()) loader.close() sio.close() pixbuf = loader.get_pixbuf() return pixbuf def surface2pil(self, surface): w = surface.get_width() h = surface.get_height() return Image.frombuffer("RGBA", (w, h), surface.get_data(), "raw", "RGBA", 0,1) def pil2surface(self, im): imgd = im.tostring("raw","RGBA",0,1) a = array.array('B',imgd) w = im.size[0] h = im.size[1] stride = im.size[0] * 4 surface = cairo.ImageSurface.create_for_data (a, cairo.FORMAT_ARGB32, w, h, stride) return surface def resize_surface(self, surface, w, h): im = self.surface2pil(surface) im = im.resize((w, h), Image.ANTIALIAS) return self.pil2surface(im)
class Theme(gobject.GObject): __gsignals__ = { "theme_reloaded": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,()), } def __new__(cls, *p, **k): if not "_the_instance" in cls.__dict__: cls._the_instance = gobject.GObject.__new__(cls) return cls._the_instance def __init__(self): if "theme" in self.__dict__: # This is not the first instance of Theme, # no need to initiate anything return gobject.GObject.__init__(self) self.globals = Globals() self.globals.connect("theme_changed", self.on_theme_changed) self.on_theme_changed() def on_theme_changed(self, arg=None): self.themes = self.find_themes() default_theme_path = None for theme, path in self.themes.items(): if theme.lower() == self.globals.settings["theme"].lower(): self.theme_path = path break if theme.lower() == self.globals.DEFAULT_SETTINGS["theme"].lower(): default_theme_path = path else: if default_theme_path: # If the current theme according to gconf couldn't be found, # the default theme is used. self.theme_path = default_theme_path else: # Just use one of the themes that where found if default # theme couldn't be found either. self.theme_path = self.themes.values()[0] self.reload() def find_themes(self): # Reads the themes from /usr/share/dockbarx/themes and # ${XDG_DATA_HOME:-$HOME/.local/share}/dockbarx/themes # and returns a dict of the theme names and paths so # that a theme can be loaded. themes = {} theme_paths = [] theme_folder = os.path.join(get_app_homedir(), "themes") dirs = ["/usr/share/dockbarx/themes", theme_folder] for dir in dirs: if os.path.exists(dir) and os.path.isdir(dir): for f in os.listdir(dir): if f[-7:] == ".tar.gz": theme_paths.append(dir+"/"+f) for theme_path in theme_paths: try: name = self.check(theme_path) except Exception, detail: logger.exception("Error loading theme from %s"%theme_path) name = None if name is not None: name = str(name) themes[name] = theme_path if not themes: md = gtk.MessageDialog(None, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, _("No working themes found in /usr/share/dockbarx/themes or ${XDG_DATA_HOME:-$HOME/.local/share}/dockbarx/themes")) md.run() md.destroy() raise NoThemesError("No working themes found in " + \ "/usr/share/dockbarx/themes or ${XDG_DATA_HOME:-$HOME/.local/share}/dockbarx/themes") return themes
def _ParseStreams(suc, data, retmpd=False): g = Globals() s = Settings() def _ParseSubs(data): bForcedOnly = False # Whether or not we should only download forced subtitles down_lang = int('0' + g.addon.getSetting('sub_lang')) if 0 == down_lang: return [] # Return if the sub_lang is set to None lang_main = jsonRPC('Settings.GetSettingValue', param={'setting': 'locale.subtitlelanguage'}) lang_main = lang_main['value'] if 'value' in lang_main else '' # Locale.SubtitleLanguage (and .AudioLanguage) can either return a language or: # [ S] none: no subtitles # [ S] forced_only: forced subtitles only # [AS] original: the stream's original language # [AS] default: Kodi's UI # # For simplicity's sake (and temporarily) we will treat original as AudioLanguage, and # AudioLanguage 'original' as 'default' if lang_main not in ['none', 'forced_only', 'original', 'default']: lang_main = xbmc.convertLanguage(lang_main, xbmc.ISO_639_1) if 'none' == lang_main: return [] if 'forced_only' == lang_main: bForcedOnly = True if ('forced_only' == lang_main) or ('original' == lang_main): lang_main = jsonRPC('Settings.GetSettingValue', param={'setting': 'locale.audiolanguage'}) lang_main = lang_main['value'] if 'value' in lang_main else '' if lang_main not in ['original', 'default']: lang_main = xbmc.convertLanguage(lang_main, xbmc.ISO_639_1) if lang_main == 'original': lang_main = 'default' if 'default' == lang_main: lang_main = xbmc.getLanguage(xbmc.ISO_639_1, False) # At this point we should have the user's selected language or a valid fallback, although # we further sanitize for safety lang_main = lang_main if lang_main else xbmc.getLanguage( xbmc.ISO_639_1, False) lang_main = lang_main if lang_main else 'en' # down_lang: None | All | From Kodi player language settings | From settings, fallback to english | From settings, fallback to all lang_main = '' if 1 == down_lang else lang_main lang_fallback = None if 3 > down_lang else ( '' if 4 == down_lang else 'en') localeConversion = { 'ar-001': 'ar', 'cmn-hans': 'zh HANS', 'cmn-hant': 'zh HANT', 'da-dk': 'da', 'es-419': 'es LA', 'ja-jp': 'ja', 'ko-kr': 'ko', 'nb-no': 'nb', 'sv-se': 'sv', } # Clean up language and locale information where needed subs = [] if (not down_lang) or (('subtitleUrls' not in data) and ('forcedNarratives' not in data)): return subs def_subs = [] fb_subs = [] for sub in data['subtitleUrls'] + data['forcedNarratives']: lang = sub['languageCode'].strip() if lang in localeConversion: lang = localeConversion[lang] # Clean up where needed if '-' in lang: p1 = re.split('-', lang)[0] p2 = re.split('-', lang)[1] if ( p1 == p2 ): # Remove redundant locale information when not useful lang = p1 else: lang = '%s %s' % (p1, p2.upper()) # Amazon's en defaults to en_US, not en_UK if 'en' == lang: lang = 'en US' # Read close-caption information where needed if '[' in sub['displayName']: cc = re.search(r'(\[[^\]]+\])', sub['displayName']) if None is not cc: lang = lang + (' %s' % cc.group(1)) # Add forced subs information if ' forced ' in sub['displayName']: lang = lang + '.Forced' if (' forced ' in sub['displayName']) or (False is bForcedOnly): sub['languageCode'] = lang if lang_main in lang: def_subs.append(sub) if (None is not lang_fallback) and (lang_fallback in lang): fb_subs.append(sub) if not def_subs: def_subs = fb_subs import codecs for sub in def_subs: escape_chars = [('&', '&'), ('"', '"'), ('<', '<'), ('>', '>'), (''', "'")] srtfile = xbmc.translatePath( 'special://temp/%s.srt' % sub['languageCode']).decode('utf-8') subDisplayLang = '“%s” subtitle (%s)' % ( sub['displayName'].strip(), sub['languageCode']) content = '' with codecs.open(srtfile, 'w', encoding='utf-8') as srt: num = 0 # Since .srt are available on amazon's servers, we strip the default extension and try downloading it just once subUrl = re.search(r'^(.*?\.)[^.]{1,}$', sub['url']) content = '' if None is subUrl else getURL( subUrl.group(1) + 'srt', rjson=False, attempt=777) if 0 < len(content): Log('Downloaded %s' % subDisplayLang) srt.write(content) else: content = getURL(sub['url'], rjson=False, attempt=3) if 0 < len(content): Log('Converting %s' % subDisplayLang) for tt in re.compile('<tt:p(.*)').findall(content): tt = re.sub('<tt:br[^>]*>', '\n', tt) tt = re.search( r'begin="([^"]*).*end="([^"]*).*>([^<]*).', tt) subtext = tt.group(3) for ec in escape_chars: subtext = subtext.replace(ec[0], ec[1]) if tt: num += 1 srt.write('%s\n%s --> %s\n%s\n\n' % (num, tt.group(1), tt.group(2), subtext)) if 0 == len(content): Log('Unable to download %s' % subDisplayLang) else: subs.append(srtfile) return subs HostSet = g.addon.getSetting("pref_host") subUrls = [] if not suc: return False, data if retmpd: subUrls = _ParseSubs(data) if 'audioVideoUrls' in data.keys(): hosts = data['audioVideoUrls']['avCdnUrlSets'] elif 'playbackUrls' in data.keys(): defid = data['playbackUrls']['defaultUrlSetId'] h_dict = data['playbackUrls']['urlSets'] ''' failover = h_dict[defid]['failover'] defid_dis = [failover[k]['urlSetId'] for k in failover if failover[k]['mode'] == 'discontinuous'] defid = defid_dis[0] if defid_dis else defid ''' hosts = [h_dict[k] for k in h_dict] hosts.insert(0, h_dict[defid]) while hosts: for cdn in hosts: prefHost = False if HostSet not in str( hosts) or HostSet == 'Auto' else HostSet cdn_item = cdn if 'urls' in cdn: cdn = cdn['urls']['manifest'] if prefHost and prefHost not in cdn['cdn']: continue Log('Using Host: ' + cdn['cdn']) urlset = cdn['avUrlInfoList'][ 0] if 'avUrlInfoList' in cdn else cdn data = getURL(urlset['url'], rjson=False, check=retmpd) if not data: hosts.remove(cdn_item) Log('Host not reachable: ' + cdn['cdn']) continue return (urlset['url'], subUrls) if retmpd else (True, _extrFr(data)) return False, getString(30217)
class PopupStyle(gobject.GObject): __gsignals__ = {"popup-style-reloaded": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,()),} def __new__(cls, *p, **k): if not "_the_instance" in cls.__dict__: cls._the_instance = gobject.GObject.__new__(cls) return cls._the_instance def __init__(self): if "is_initiated" in self.__dict__: # This is not the first instance of PopupStyle, # no need to initiate anything return self.is_initiated = True gobject.GObject.__init__(self) self.globals = Globals() self.name = "DBX" self.settings = {} self.globals.connect("popup-style-changed", self.on_style_changed) self.on_style_changed() def get(self, key, default=None): return self.settings.get(key, default) def find_styles(self): # Reads the styles from /usr/share/dockbarx/themes/popup_styles and # ${XDG_DATA_HOME:-$HOME/.local/share}/dockbarx/themes/popup_styles # and returns a dict of the style file names and paths so that a # style can be loaded styles = {} style_paths = [] style_folder = os.path.join(get_app_homedir(), "themes", "popup_styles") dirs = ["/usr/share/dockbarx/themes/popup_styles", style_folder] for dir in dirs: if os.path.exists(dir) and os.path.isdir(dir): for f in os.listdir(dir): if f[-7:] == ".tar.gz": styles[f] = dir+"/"+f return styles def on_style_changed(self, arg=None): styles = self.find_styles() if self.globals.popup_style_file in styles: self.style_path = styles[self.globals.popup_style_file] elif self.globals.default_popup_style in styles: self.style_path = styles[self.globals.default_popup_style] else: self.style_path = styles.get("dbx.tar.gz", "dbx.tar.gz") self.reload() def reload(self): if self.style_path is None: return # Default settings self.bg = None self.cb_pressed_pic = None self.cb_hover_pic = None self.cb_normal_pic = None self.settings = {"border_color2": "#000000", "menu_item_lr_padding": 3} self.name = "DBX" try: tar = taropen(self.style_path) except: logger.debug("Error opening style %s" % self.style_path) self.globals.set_popup_style("dbx.tar.gz") self.emit("popup-style-reloaded") return # Load settings try: config = tar.extractfile("style") except: logger.exception("Error extracting style from %s" % \ self.style_path) tar.close() self.globals.set_popup_style("dbx.tar.gz") self.emit("popup-style-reloaded") return self.settings = {} for line in config.readlines(): # Split at "=" and clean up the key and value if not "=" in line: continue key, value = line.split("=", 1) key = key.strip().lstrip().lower() value = value.strip().lstrip() # Remove comments if "#" in key: continue # If there is a trailing comment, remove it # But avoid removing # if it's in a quote sharp = value.find("#") if sharp != -1 and value.count("\"", 0, sharp) % 2 == 0 and \ value.count("'", 0, sharp) % 2 == 0: value = value.split("#", 1)[0].strip() # Remove quote signs if value[0] in ("\"", "'") and value[-1] in ("\"", "'"): value = value[1:-1] if key == "name": name = value continue value = value.lower() self.settings[key] = value config.close() if name: self.name = name else: self.settings = {"border_color2": "#000000", "menu_item_lr_padding": 3} self.globals.set_popup_style("dbx.tar.gz") self.emit("popup-style-reloaded") tar.close() return # Load background if "background.png" in tar.getnames(): bgf = tar.extractfile("background.png") self.bg = cairo.ImageSurface.create_from_png(bgf) bgf.close() if "closebutton/normal.png" in tar.getnames(): cbf = tar.extractfile("closebutton/normal.png") self.cb_normal_pic = cairo.ImageSurface.create_from_png(cbf) cbf.close() if "closebutton/pressed.png" in tar.getnames(): cbf = tar.extractfile("closebutton/pressed.png") self.cb_pressed_pic = cairo.ImageSurface.create_from_png(cbf) cbf.close() if "closebutton/hover.png" in tar.getnames(): cbf = tar.extractfile("closebutton/hover.png") self.cb_hover_pic = cairo.ImageSurface.create_from_png(cbf) cbf.close() tar.close() # Inform rest of dockbar about the reload. self.globals.set_popup_style(self.style_path.rsplit("/", 1)[-1]) self.emit("popup-style-reloaded") def get_styles(self, theme_name=None): # For DockbarX preference. This function makes a dict of the names and # file names of the styles for all styles that can be opened correctly. styles = {} style_folder = os.path.join(get_app_homedir(), "themes", "popup_styles") dirs = ["/usr/share/dockbarx/themes/popup_styles", style_folder] for dir in dirs: if os.path.exists(dir) and os.path.isdir(dir): for f in os.listdir(dir): if f[-7:] == ".tar.gz": name, oft = self.check(dir+"/"+f) if oft: # The style is meant only for themes # mentioned in oft. if theme_name is None: continue oft = [t.strip().lstrip().lower() \ for t in oft.split(",")] if not theme_name.lower() in oft: continue if name: styles[name] = f # The default style (if the theme doesn't set another one) is DBX, # wheter or not the file actually exists. if not "DBX" in styles: styles["DBX"] = "dbx.tar.gz" return styles def check(self, style_path): try: tar = taropen(style_path) except: return None try: config = tar.extractfile("style") except: tar.close() return None name = None oft = None for line in config.readlines(): # Split at "=" and clean up the key and value if not "=" in line: continue key, value = line.split("=", 1) key = key.strip().lstrip().lower() value = value.strip().lstrip() # Remove comments if "#" in key: continue # If there is a trailing comment, remove it # But avoid removing # if it's in a quote sharp = value.find("#") if sharp != -1 and value.count("\"", 0, sharp) % 2 == 0 and \ value.count("'", 0, sharp) % 2 == 0: value = value.split("#", 1)[0].strip() # Remove quote signs if value[0] in ("\"", "'") and value[-1] in ("\"", "'"): value = value[1:-1] if key == "only_for_themes": oft = value if key == "name": name = value tar.close() return name, oft
def _ParseStreams(suc, data, retmpd=False): g = Globals() s = Settings() def _ParseSubs(data): bForcedOnly = False # Whether or not we should only download forced subtitles down_lang = int('0' + g.addon.getSetting('sub_lang')) if 0 == down_lang: return [] # Return if the sub_lang is set to None lang_main = jsonRPC('Settings.GetSettingValue', param={'setting': 'locale.subtitlelanguage'}) lang_main = lang_main['value'] if 'value' in lang_main else '' # Locale.SubtitleLanguage (and .AudioLanguage) can either return a language or: # [ S] none: no subtitles # [ S] forced_only: forced subtitles only # [AS] original: the stream's original language # [AS] default: Kodi's UI # # For simplicity's sake (and temporarily) we will treat original as AudioLanguage, and # AudioLanguage 'original' as 'default' if lang_main not in ['none', 'forced_only', 'original', 'default']: lang_main = xbmc.convertLanguage(lang_main, xbmc.ISO_639_1) if 'none' == lang_main: return [] if 'forced_only' == lang_main and down_lang > 1: bForcedOnly = True if ('forced_only' == lang_main) or ('original' == lang_main): lang_main = jsonRPC('Settings.GetSettingValue', param={'setting': 'locale.audiolanguage'}) lang_main = lang_main['value'] if 'value' in lang_main else '' if lang_main not in ['original', 'default']: lang_main = xbmc.convertLanguage(lang_main, xbmc.ISO_639_1) if lang_main == 'original': lang_main = 'default' if 'default' == lang_main: lang_main = xbmc.getLanguage(xbmc.ISO_639_1, False) # At this point we should have the user's selected language or a valid fallback, although # we further sanitize for safety lang_main = lang_main if lang_main else xbmc.getLanguage(xbmc.ISO_639_1, False) lang_main = lang_main if lang_main else 'en' # down_lang: None | All | From Kodi player language settings | From settings, fallback to english | From settings, fallback to all lang_main = '' if 1 == down_lang else lang_main lang_fallback = None if 3 > down_lang else ('' if 4 == down_lang else 'en') localeConversion = { 'ar-001': 'ar', 'cmn-hans': 'zh HANS', 'cmn-hant': 'zh HANT', 'da-dk': 'da', 'es-419': 'es LA', 'ja-jp': 'ja', 'ko-kr': 'ko', 'nb-no': 'nb', 'sv-se': 'sv', } # Clean up language and locale information where needed subs = [] if (not down_lang) or (('subtitleUrls' not in data) and ('forcedNarratives' not in data)): return subs def_subs = [] fb_subs = [] for sub in data['subtitleUrls'] + data['forcedNarratives']: lang = sub['languageCode'].strip() if lang in localeConversion: lang = localeConversion[lang] # Clean up where needed if '-' in lang: p1 = re.split('-', lang)[0] p2 = re.split('-', lang)[1] if (p1 == p2): # Remove redundant locale information when not useful lang = p1 else: lang = '%s %s' % (p1, p2.upper()) # Amazon's en defaults to en_US, not en_UK if 'en' == lang: lang = 'en US' # Read close-caption information where needed if '[' in sub['displayName']: cc = re.search(r'(\[[^\]]+\])', sub['displayName']) if None is not cc: lang = lang + (' %s' % cc.group(1)) # Add forced subs information if ' forced ' in sub['displayName']: lang = lang + '.Forced' if (' forced ' in sub['displayName']) or (False is bForcedOnly): sub['languageCode'] = lang if lang_main in lang: def_subs.append(sub) if (None is not lang_fallback) and (lang_fallback in lang): fb_subs.append(sub) if not def_subs: def_subs = fb_subs import codecs for sub in def_subs: escape_chars = [('&', '&'), ('"', '"'), ('<', '<'), ('>', '>'), (''', "'")] srtfile = xbmc.translatePath('special://temp/%s.srt' % sub['languageCode']).decode('utf-8') subDisplayLang = '“%s” subtitle (%s)' % (sub['displayName'].strip(), sub['languageCode']) content = '' Log("Subtitle URL: %s" % (sub['url']), Log.DEBUG) with codecs.open(srtfile, 'w', encoding='utf-8') as srt: # Since dfxp provides no particular metadata and .srt are usually available on amazon's servers, # we try to download the .srt straight away to avoid conversion. Although we avoid it with RTL # languages, since we need to parse them anyway. if (sub['url'].endswith("dfxp")) and ('ar' != sub['languageCode']): subUrl = re.search(r'^(.*?\.)[^.]{1,}$', sub['url']) content = '' if None is subUrl else getURL(subUrl.group(1) + 'srt', rjson=False, attempt=777) if 0 < len(content): Log('Downloaded %s' % subDisplayLang, Log.DEBUG) srt.write(content) continue content = getURL(sub['url'], rjson=False, attempt=3) if 0 < len(content): Log('Converting %s' % subDisplayLang) Log('Output %s' % srtfile, Log.DEBUG) # Apply a bunch of regex to the content instead of line-by-line to save computation time content = re.sub(r'<(|/)span[^>]*>', r'<\1i>', content) # Using (|<search>) instead of ()? to avoid py2.7 empty matching error content = re.sub(r'([0-9]{2}:[0-9]{2}:[0-9]{2})\.', r'\1,', content) # SRT-like timestamps content = re.sub(r'\s*<(?:tt:)?br\s*/>\s*', '\n', content) # Replace <br/> with actual new lines # Convert dfxp or ttml2 to srt num = 0 for tt in re.compile(r'<(?:tt:)?p begin="([^"]+)"[^>]*end="([^"]+)"[^>]*>\s*(.*?)\s*</(?:tt:)?p>', re.DOTALL).findall(content): text = tt[2] # Embed RTL and change the punctuation where needed if 'ar' == sub['languageCode']: from unicodedata import lookup text = re.sub('^', lookup('RIGHT-TO-LEFT EMBEDDING'), text, flags=re.MULTILINE) text = text.replace('?', '؟').replace(',', '،') for ec in escape_chars: text = text.replace(ec[0], ec[1]) num += 1 srt.write('%s\n%s --> %s\n%s\n\n' % (num, tt[0], tt[1], text)) Log('Conversion finished', Log.DEBUG) if 0 == len(content): Log('Unable to download %s' % subDisplayLang) else: subs.append(srtfile) return subs HostSet = g.addon.getSetting("pref_host") subUrls = [] if not suc: return False, data if retmpd: subUrls = _ParseSubs(data) if 'audioVideoUrls' in data.keys(): hosts = data['audioVideoUrls']['avCdnUrlSets'] elif 'playbackUrls' in data.keys(): defid = data['playbackUrls']['defaultUrlSetId'] h_dict = data['playbackUrls']['urlSets'] ''' failover = h_dict[defid]['failover'] defid_dis = [failover[k]['urlSetId'] for k in failover if failover[k]['mode'] == 'discontinuous'] defid = defid_dis[0] if defid_dis else defid ''' hosts = [h_dict[k] for k in h_dict] hosts.insert(0, h_dict[defid]) while hosts: for cdn in hosts: prefHost = False if HostSet not in str(hosts) or HostSet == 'Auto' else HostSet cdn_item = cdn if 'urls' in cdn: cdn = cdn['urls']['manifest'] if prefHost and prefHost not in cdn['cdn']: continue Log('Using Host: ' + cdn['cdn']) urlset = cdn['avUrlInfoList'][0] if 'avUrlInfoList' in cdn else cdn data = getURL(urlset['url'], rjson=False, check=retmpd) if not data: hosts.remove(cdn_item) Log('Host not reachable: ' + cdn['cdn']) continue return (urlset['url'], subUrls) if retmpd else (True, _extrFr(data)) return False, getString(30217)
class DockTheme(gobject.GObject): __gsignals__ = {"dock-theme-reloaded": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,()),} def __init__(self): gobject.GObject.__init__(self) self.globals = Globals() self.name = "DBX" self.settings = {} self.globals.connect("dock-theme-changed", self.on_theme_changed) self.on_theme_changed() def get(self, key, default=None): return self.settings.get(key, default) def get_bg(self, bar, size=None): if size is None: return self.bg[bar] if size != self.bg_sizes[bar]: bg = self.bg[bar] w = bg.get_width() self.resized_bg[bar] = self.__resize_surface(bg, w, size) self.bg_sizes[bar] = size return self.resized_bg[bar] def find_themes(self): # Reads the themes from /usr/share/dockbarx/themes/dock_themes and # ${XDG_DATA_HOME:-$HOME/.local/share}/dockbarx/themes/dock_themes # and returns a dict of the theme file names and paths so that a # theme can be loaded themes = {} theme_paths = [] theme_folder = os.path.join(get_app_homedir(), "themes", "dock") dirs = ["/usr/share/dockbarx/themes/dock", theme_folder] for dir in dirs: if os.path.exists(dir) and os.path.isdir(dir): for f in os.listdir(dir): if f[-7:] == ".tar.gz": themes[f] = dir+"/"+f return themes def on_theme_changed(self, arg=None): themes = self.find_themes() if self.globals.settings["dock/theme_file"] in themes: self.theme_path = themes[self.globals.settings["dock/theme_file"]] else: self.theme_path = themes.get("dbx.tar.gz", "dbx.tar.gz") self.reload() def reload(self): if self.theme_path is None: return self.default_colors = {"bg_color": "#111111", "bg_alpha": 127, "bar2_bg_color":"#111111", "bar2_bg_alpha": 127} try: tar = taropen(self.theme_path) except: logger.debug("Error opening dock theme %s" % self.theme_path) self.settings = {} self.name = "DBX" self.bg = {1: None, 2:None} self.bg_sizes = {1: -1, 2:-1} self.globals.set_dock_theme("dbx.tar.gz", self.default_colors) self.emit("dock-theme-reloaded") return # Load settings try: config = tar.extractfile("theme") except: logger.exception("Error extracting theme from %s" % \ self.theme_path) tar.close() self.settings = {} self.name = "DBX" self.bg = None self.globals.set_dock_theme("dbx.tar.gz", self.default_colors) self.emit("dock-theme-reloaded") return old_settings = self.settings self.settings = {} name = None for line in config.readlines(): # Split at "=" and clean up the key and value if not "=" in line: continue key, value = line.split("=", 1) key = key.strip().lstrip().lower() value = value.strip().lstrip() # Remove comments if "#" in key: continue # If there is a trailing comment, remove it # But avoid removing # if it's in a quote sharp = value.find("#") if sharp != -1 and value.count("\"", 0, sharp) % 2 == 0 and \ value.count("'", 0, sharp) % 2 == 0: value = value.split("#", 1)[0].strip() # Remove quote signs if value[0] in ("\"", "'") and value[-1] in ("\"", "'"): value = value[1:-1] if key == "name": name = value continue value = value.lower() self.settings[key] = value config.close() if name: self.name = name else: # Todo: Error handling here! self.settings = old_settings tar.close() self.globals.set_dock_theme("dbx.tar.gz", self.default_colors) self.emit("dock-theme-reloaded") return # Load background self.bg = {1:None, 2:None} self.bg_sizes = {1: -1, 2: -1} self.resized_bg = {} if "background.png" in tar.getnames(): bgf = tar.extractfile("background.png") self.bg[1] = cairo.ImageSurface.create_from_png(bgf) bgf.close() if "bar2_background.png" in tar.getnames(): bgf = tar.extractfile("bar2_background.png") self.bg[2] = cairo.ImageSurface.create_from_png(bgf) bgf.close() tar.close() for key in self.default_colors.keys(): if key in self.settings: value = self.settings.pop(key) if "alpha" in key: value = int(round(int(value))*2.55) elif value[0] != "#": value = "#%s" % value self.default_colors[key] = value # Inform rest of dockbar about the reload. self.globals.set_dock_theme(self.theme_path.rsplit("/", 1)[-1], self.default_colors) self.emit("dock-theme-reloaded") def get_themes(self): # For DockbarX preference. This function makes a dict of the names and # file names of the themes for all themes that can be opened correctly. themes = {} theme_folder = os.path.join(get_app_homedir(), "themes", "dock") dirs = ["/usr/share/dockbarx/themes/dock", theme_folder] for dir in dirs: if os.path.exists(dir) and os.path.isdir(dir): for f in os.listdir(dir): if f[-7:] == ".tar.gz": name = self.check(dir+"/"+f) if name: themes[name] = f # The default theme (if the theme doesn't set another one) is DBX, # wheter or not the file actually exists. if not "DBX" in themes: themes["DBX"] = "dbx.tar.gz" return themes def check(self, theme_path): try: tar = taropen(theme_path) except: return None try: config = tar.extractfile("theme") except: tar.close() return None name = None for line in config.readlines(): # Split at "=" and clean up the key and value if not "=" in line: continue key, value = line.split("=", 1) key = key.strip().lstrip().lower() value = value.strip().lstrip() # Remove comments if "#" in key: continue # If there is a trailing comment, remove it # But avoid removing # if it's in a quote sharp = value.find("#") if sharp != -1 and value.count("\"", 0, sharp) % 2 == 0 and \ value.count("'", 0, sharp) % 2 == 0: value = value.split("#", 1)[0].strip() # Remove quote signs if value[0] in ("\"", "'") and value[-1] in ("\"", "'"): value = value[1:-1] if key == "name": name = value break tar.close() return name def __surface2pil(self, surface): w = surface.get_width() h = surface.get_height() return Image.frombuffer("RGBA", (w, h), surface.get_data(), "raw", "RGBA", 0,1) def __pil2surface(self, im): """Transform a PIL Image into a Cairo ImageSurface.""" # This function is only supposed to work with little endinan # systems. Could that be a problem ever? if im.mode != 'RGBA': im = im.convert('RGBA') s = im.tobytes('raw', 'BGRA') a = array.array('B', s) dest = cairo.ImageSurface(cairo.FORMAT_ARGB32, im.size[0], im.size[1]) ctx = cairo.Context(dest) non_premult_src_wo_alpha = cairo.ImageSurface.create_for_data( a, cairo.FORMAT_RGB24, im.size[0], im.size[1]) non_premult_src_alpha = cairo.ImageSurface.create_for_data( a, cairo.FORMAT_ARGB32, im.size[0], im.size[1]) ctx.set_source_surface(non_premult_src_wo_alpha) ctx.mask_surface(non_premult_src_alpha) return dest def __resize_surface(self, surface, w, h): im = self.__surface2pil(surface) im = im.resize((w, h), Image.ANTIALIAS) return self.__pil2surface(im)
def _Input(mousex=0, mousey=0, click=0, keys=None, delay='200'): from common import Globals g = Globals() screenWidth = int(xbmc.getInfoLabel('System.ScreenWidth')) screenHeight = int(xbmc.getInfoLabel('System.ScreenHeight')) keys_only = sc_only = keybd = '' mousex = screenWidth / 2 if mousex == -1 else mousex mousey = screenHeight / 2 if mousey == -1 else mousey spec_keys = {'{EX}': ('!{F4}', 'alt+F4', 'kd:cmd t:q ku:cmd'), '{SPC}': ('{SPACE}', 'space', 't:p'), '{LFT}': ('{LEFT}', 'Left', 'kp:arrow-left'), '{RGT}': ('{RIGHT}', 'Right', 'kp:arrow-right'), '{U}': ('{UP}', 'Up', 'kp:arrow-up'), '{DWN}': ('{DOWN}', 'Down', 'kp:arrow-down'), '{BACK}': ('{BS}', 'BackSpace', 'kp:delete'), '{RET}': ('{ENTER}', 'Return', 'kp:return')} if keys: keys_only = keys for sc in spec_keys: while sc in keys: keys = keys.replace(sc, spec_keys[sc][g.platform - 1]).strip() keys_only = keys_only.replace(sc, '').strip() sc_only = keys.replace(keys_only, '').strip() if g.platform & g.OS_WINDOWS: app = os.path.join(g.PLUGIN_PATH, 'tools', 'userinput.exe') mouse = ' mouse %s %s' % (mousex, mousey) mclk = ' ' + str(click) keybd = ' key %s %s' % (keys, delay) elif g.platform & g.OS_LINUX: app = 'xdotool' mouse = ' mousemove %s %s' % (mousex, mousey) mclk = ' click --repeat %s 1' % click if keys_only: keybd = ' type --delay %s %s' % (delay, keys_only) if sc_only: if keybd: keybd += ' && ' + app keybd += ' key ' + sc_only elif g.platform & g.OS_OSX: app = 'cliclick' mouse = ' m:' if click == 1: mouse = ' c:' elif click == 2: mouse = ' dc:' mouse += '%s,%s' % (mousex, mousey) mclk = '' keybd = ' -w %s' % delay if keys_only: keybd += ' t:%s' % keys_only if keys != keys_only: keybd += ' ' + sc_only if keys: cmd = app + keybd else: cmd = app + mouse if click: cmd += mclk Log('Run command: %s' % cmd) rcode = subprocess.call(cmd, shell=True) if rcode: Log('Returncode: %s' % rcode)
class DockManager(dbus.service.Object): def __new__(cls, dockbar): if "net.launchpad.DockManager" in dbus.SessionBus().list_names(): logger.debug("Name net.launchpad.DockManager is already" + \ " in use. (This instance of) DockbarX will" + \ " not use DockManager.") return None else: return dbus.service.Object.__new__(cls) def __init__(self, dockbar): self.dockbar_r = weakref.ref(dockbar) bus_name = dbus.service.BusName("net.launchpad.DockManager", bus = dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, "/net/launchpad/DockManager") self.globals = Globals() @dbus.service.method(dbus_interface="net.launchpad.DockManager", in_signature="", out_signature="as",) def GetCapabilities(self): capabilities = ["menu-item-container-title", "menu-item-icon-file", "menu-item-icon-name", "menu-item-with-label", "dock-item-badge", "dock-item-progress"] return capabilities @dbus.service.method(dbus_interface="net.launchpad.DockManager", in_signature="", out_signature="ao",) def GetItems(self): path_list = [] for path in self.dockbar_r().get_dm_paths(): path_list.append(dbus.ObjectPath(path)) return path_list @dbus.service.method(dbus_interface="net.launchpad.DockManager", in_signature="s", out_signature="ao",) def GetItemsByDesktopFile(self, name): path_list = [] for path in self.dockbar_r().get_dm_paths_by_desktop_file(name): path_list.append(dbus.ObjectPath(path)) logger.debug("Items gotten by dekstop file: %s" % path_list) return path_list @dbus.service.method(dbus_interface="net.launchpad.DockManager", in_signature="s", out_signature="ao",) def GetItemsByName(self, name): path_list = [] for path in self.dockbar_r().get_dm_paths_by_name(name): path_list.append(dbus.ObjectPath(path)) logger.debug("Items gotten by name: %s" % path_list) return path_list @dbus.service.method(dbus_interface="net.launchpad.DockManager", in_signature="i", out_signature="ao",) def GetItemsByPid(self, pid): path_list = [] for path in self.dockbar_r().get_dm_paths_by_pid(pid): path_list.append(dbus.ObjectPath(path)) logger.debug("Items gotten by pid: %s" % path_list) return path_list @dbus.service.method(dbus_interface="net.launchpad.DockManager", in_signature="x", out_signature="ao",) def GetItemsByXid(self, xid): path_list = [] for path in self.dockbar_r().get_dm_paths_by_xid(xid): path_list.append(dbus.ObjectPath(path)) logger.debug("Items gotten by xid: %s" % path_list) return path_list @dbus.service.signal(dbus_interface='net.launchpad.DockManager', signature='o') def ItemAdded(self, obj_path): pass @dbus.service.signal(dbus_interface='net.launchpad.DockManager', signature='o') def ItemRemoved(self, obj_path): pass @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v') def Get(self, interface_name, property_name): return self.GetAll(interface_name)[property_name] @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}') def GetAll(self, interface_name): if interface_name == "net.launchpad.DockManager": return {} else: raise dbus.exceptions.DBusException( 'com.example.UnknownInterface', 'The Foo object does not implement the %s interface' % interface_name) @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ssv', out_signature='') def Set(self, interface_name, property_name, property_value): pass @dbus.service.signal(dbus_interface=dbus.PROPERTIES_IFACE, signature='sa{sv}as') def PropertiesChanged(self, interface_name, changed_properties, invalidated_properties): pass def reset(self): try: bus = dbus.SessionBus() proxy = bus.get_object("net.launchpad.DockManager.Daemon", "/net/launchpad/DockManager/Daemon") proxy.RestartAll(dbus_interface="net.launchpad.DockManager.Daemon") except: logger.exception("Restarting DockManager Helpers failed.") def remove(self): self.remove_from_connection() self.globals.disconnect(self.badge_sid)
def PlayVideo(name, asin, adultstr, trailer, forcefb=0): g = Globals() s = Settings() def _check_output(*popenargs, **kwargs): p = subprocess.Popen(stdout=subprocess.PIPE, stderr=subprocess.STDOUT, *popenargs, **kwargs) out, err = p.communicate() retcode = p.poll() if retcode != 0: c = kwargs.get("args") if c is None: c = popenargs[0] e = subprocess.CalledProcessError(retcode, c) e.output = str(out) + str(err) Log(e, Log.ERROR) return out.strip() def _playDummyVid(): dummy_video = OSPJoin(g.PLUGIN_PATH, 'resources', 'dummy.avi') xbmcplugin.setResolvedUrl(g.pluginhandle, True, xbmcgui.ListItem(path=dummy_video)) Log('Playing Dummy Video', Log.DEBUG) xbmc.Player().stop() return def _extrFr(data): fps_string = re.compile('frameRate="([^"]*)').findall(data)[0] fr = round(eval(fps_string + '.0'), 3) return str(fr).replace('.0', '') def _ParseStreams(suc, data, retmpd=False): g = Globals() s = Settings() HostSet = g.addon.getSetting("pref_host") subUrls = [] if not suc: return False, data if retmpd: subUrls = [ sub['url'] for sub in data['subtitles'] if 'url' in sub.keys() ] if 'audioVideoUrls' in data.keys(): hosts = data['audioVideoUrls']['avCdnUrlSets'] elif 'playbackUrls' in data.keys(): defid = data['playbackUrls']['defaultUrlSetId'] h_dict = data['playbackUrls']['urlSets'] ''' failover = h_dict[defid]['failover'] defid_dis = [failover[k]['urlSetId'] for k in failover if failover[k]['mode'] == 'discontinuous'] defid = defid_dis[0] if defid_dis else defid ''' hosts = [h_dict[k] for k in h_dict] hosts.insert(0, h_dict[defid]) while hosts: for cdn in hosts: prefHost = False if HostSet not in str( hosts) or HostSet == 'Auto' else HostSet cdn_item = cdn if 'urls' in cdn: cdn = cdn['urls']['manifest'] if prefHost and prefHost not in cdn['cdn']: continue Log('Using Host: ' + cdn['cdn']) urlset = cdn['avUrlInfoList'][ 0] if 'avUrlInfoList' in cdn else cdn data = getURL(urlset['url'], rjson=False, check=retmpd) if not data: hosts.remove(cdn_item) Log('Host not reachable: ' + cdn['cdn']) continue return ('http://{}/mpd/{}'.format(s.proxyaddress, quote_plus(urlset['url'])), subUrls) if retmpd else (True, _extrFr(data)) return False, getString(30217) def _getCmdLine(videoUrl, asin, method, fr): scr_path = g.addon.getSetting("scr_path") br_path = g.addon.getSetting("br_path").strip() scr_param = g.addon.getSetting("scr_param").strip() kiosk = g.addon.getSetting("kiosk") == 'true' appdata = g.addon.getSetting("ownappdata") == 'true' cust_br = g.addon.getSetting("cust_path") == 'true' nobr_str = getString(30198) frdetect = g.addon.getSetting("framerate") == 'true' if method == 1: if not xbmcvfs.exists(scr_path): return False, nobr_str if frdetect: suc, fr = _ParseStreams( *getURLData('catalog/GetPlaybackResources', asin, extra=True, useCookie=True)) if not fr else (True, fr) if not suc: return False, fr else: fr = '' return True, scr_path + ' ' + scr_param.replace('{f}', fr).replace( '{u}', videoUrl) br_platform = (g.platform & -g.platform).bit_length() os_paths = [ None, ('C:\\Program Files\\', 'C:\\Program Files (x86)\\'), ('/usr/bin/', '/usr/local/bin/'), 'open -a ' ][br_platform] # path(0,win,lin,osx), kiosk, profile, args br_config = [ [(None, ['Internet Explorer\\iexplore.exe'], '', ''), '-k ', '', ''], [(None, ['Google\\Chrome\\Application\\chrome.exe'], [ 'google-chrome', 'google-chrome-stable', 'google-chrome-beta', 'chromium-browser' ], '"/Applications/Google Chrome.app"'), '--kiosk ', '--user-data-dir=', '--start-maximized --disable-translate --disable-new-tab-first-run --no-default-browser-check --no-first-run ' ], [(None, ['Mozilla Firefox\\firefox.exe'], ['firefox'], 'firefox'), '', '-profile ', ''], [(None, ['Safari\\Safari.exe'], '', 'safari'), '', '', ''] ] if not cust_br: br_path = '' if (not g.platform & g.OS_OSX) and (not cust_br): for path in os_paths: for exe_file in br_config[s.browser][0][br_platform]: if xbmcvfs.exists(OSPJoin(path, exe_file)): br_path = path + exe_file break else: Log('Browser %s not found' % (path + exe_file), Log.DEBUG) if br_path: break if (not xbmcvfs.exists(br_path)) and (not g.platform & g.OS_OSX): return False, nobr_str br_args = br_config[s.browser][3] if kiosk: br_args += br_config[s.browser][1] if appdata and br_config[s.browser][2]: br_args += br_config[s.browser][2] + '"' + OSPJoin( g.DATA_PATH, str(s.browser)) + '" ' if g.platform & g.OS_OSX: if not cust_br: br_path = os_paths + br_config[s.browser][0][3] if br_args.strip(): br_args = '--args ' + br_args br_path += ' %s"%s"' % (br_args, videoUrl) return True, br_path def _getStartupInfo(): si = subprocess.STARTUPINFO() si.dwFlags = subprocess.STARTF_USESHOWWINDOW return si def _ExtPlayback(videoUrl, asin, isAdult, method, fr): waitsec = int(g.addon.getSetting("clickwait")) * 1000 waitprepin = int(g.addon.getSetting("waitprepin")) * 1000 pin = g.addon.getSetting("pin") waitpin = int(g.addon.getSetting("waitpin")) * 1000 pininput = g.addon.getSetting("pininput") == 'true' fullscr = g.addon.getSetting("fullscreen") == 'true' videoUrl += '&playerDebug=true' if s.verbLog else '' xbmc.Player().stop() # xbmc.executebuiltin('ActivateWindow(busydialog)') suc, url = _getCmdLine(videoUrl, asin, method, fr) if not suc: g.dialog.notification(getString(30203), url, xbmcgui.NOTIFICATION_ERROR) return Log('Executing: %s' % url) if g.platform & g.OS_WINDOWS: process = subprocess.Popen(url, startupinfo=_getStartupInfo()) else: args = shlex.split(url) process = subprocess.Popen(args) if g.platform & g.OS_LE: result = 1 while result != 0: p = subprocess.Popen('pgrep chrome > /dev/null', shell=True) p.wait() result = p.returncode if isAdult and pininput: if fullscr: waitsec *= 0.75 else: waitsec = waitprepin xbmc.sleep(int(waitsec)) _Input(keys=pin) waitsec = waitpin if fullscr: xbmc.sleep(int(waitsec)) if s.browser != 0: _Input(keys='f') else: _Input(mousex=-1, mousey=350, click=2) xbmc.sleep(500) _Input(mousex=9999, mousey=350) _Input(mousex=9999, mousey=-1) # xbmc.executebuiltin('Dialog.Close(busydialog)') if s.hasExtRC: return myWindow = _window(process, asin) myWindow.wait() def _AndroidPlayback(asin, trailer): manu = '' if os.access('/system/bin/getprop', os.X_OK): manu = _check_output(['getprop', 'ro.product.manufacturer']) if manu == 'Amazon': pkg = 'com.fivecent.amazonvideowrapper' act = '' url = asin else: pkg = 'com.amazon.avod.thirdpartyclient' act = 'android.intent.action.VIEW' url = g.BaseUrl + '/piv-apk-play?asin=' + asin url += '&playTrailer=T' if trailer == 1 else '' subprocess.Popen( ['log', '-p', 'v', '-t', 'Kodi-Amazon', 'Manufacturer: ' + manu]) subprocess.Popen([ 'log', '-p', 'v', '-t', 'Kodi-Amazon', 'Starting App: %s Video: %s' % (pkg, url) ]) Log('Manufacturer: %s' % manu) Log('Starting App: %s Video: %s' % (pkg, url)) if s.verbLog: if os.access('/system/xbin/su', os.X_OK) or os.access( '/system/bin/su', os.X_OK): Log('Logcat:\n' + _check_output( ['su', '-c', 'logcat -d | grep -i com.amazon.avod'])) Log('Properties:\n' + _check_output([ 'sh', '-c', 'getprop | grep -iE "(ro.product|ro.build|google)"' ])) xbmc.executebuiltin('StartAndroidActivity("%s", "%s", "", "%s")' % (pkg, act, url)) def _IStreamPlayback(asin, name, trailer, isAdult, extern): from .ages import AgeRestrictions vMT = ['Feature', 'Trailer', 'LiveStreaming'][trailer] dRes = 'PlaybackUrls' if trailer == 2 else 'PlaybackUrls,SubtitleUrls,ForcedNarratives' mpaa_str = AgeRestrictions().GetRestrictedAges() + getString(30171) drm_check = g.addon.getSetting("drm_check") == 'true' verifyISA = '{"jsonrpc":"2.0","id":1,"method":"Addons.GetAddonDetails","params":{"addonid":"inputstream.adaptive"}}' if 'error' in xbmc.executeJSONRPC(verifyISA): xbmc.executebuiltin('UpdateAddonRepos', True) xbmc.executebuiltin('InstallAddon(inputstream.adaptive)', True) if 'error' in xbmc.executeJSONRPC(verifyISA): Log('InputStream.Adaptive addon is not installed') _playDummyVid() return True inputstream_helper = Helper('mpd', drm='com.widevine.alpha') if not inputstream_helper.check_inputstream(): Log('No Inputstream Addon found or activated') _playDummyVid() return True cookie = MechanizeLogin() if not cookie: g.dialog.notification(getString(30203), getString(30200), xbmcgui.NOTIFICATION_ERROR) Log('Login error at playback') _playDummyVid() return True mpd, subs = _ParseStreams(*getURLData('catalog/GetPlaybackResources', asin, extra=True, vMT=vMT, dRes=dRes, useCookie=cookie, proxyEndpoint='gpr'), retmpd=True) cj_str = ';'.join(['%s=%s' % (k, v) for k, v in cookie.items()]) opt = '|Content-Type=application%2Fx-www-form-urlencoded&Cookie=' + quote_plus( cj_str) opt += '|widevine2Challenge=B{SSM}&includeHdcpTestKeyInLicense=true' opt += '|JBlicense;hdcpEnforcementResolutionPixels' licURL = getURLData('catalog/GetPlaybackResources', asin, opt=opt, extra=True, vMT=vMT, dRes='Widevine2License', retURL=True) if not mpd: g.dialog.notification(getString(30203), subs, xbmcgui.NOTIFICATION_ERROR) _playDummyVid() return True from xbmcaddon import Addon as KodiAddon is_version = KodiAddon( g.is_addon).getAddonInfo('version') if g.is_addon else '0' is_binary = xbmc.getCondVisibility( 'System.HasAddon(kodi.binary.instance.inputstream)') if (not s.audioDescriptions) and (trailer != 2): mpd = re.sub(r'(~|%7E)', '', mpd) if drm_check and (not g.platform & g.OS_ANDROID) and (not is_binary): mpdcontent = getURL(mpd, useCookie=cookie, rjson=False) if 'avc1.4D00' in mpdcontent: # xbmc.executebuiltin('ActivateWindow(busydialog)') return _extrFr(mpdcontent) Log(mpd, Log.DEBUG) if g.KodiK and extern: content = getATVData('GetASINDetails', 'ASINList=' + asin)['titles'][0] ct, Info = g.amz.getInfos(content, False) title = Info['DisplayTitle'] thumb = Info.get('Poster', Info['Thumb']) mpaa_check = str(Info.get('MPAA', mpaa_str)) in mpaa_str or isAdult else: mpaa_check = _getListItem('MPAA') in mpaa_str + mpaa_str.replace( ' ', '') or isAdult title = _getListItem('Label') thumb = _getListItem('Art(season.poster)') if not thumb: thumb = _getListItem('Art(tvshow.poster)') if not thumb: thumb = _getListItem('Art(thumb)') if trailer == 1: title += ' (Trailer)' if not title: title = name if mpaa_check and not AgeRestrictions().RequestPin(): return True listitem = xbmcgui.ListItem(label=title, path=mpd) if g.KodiK and extern: listitem.setInfo('video', getInfolabels(Info)) if 'adaptive' in g.is_addon: listitem.setProperty('inputstream.adaptive.manifest_type', 'mpd') Log('Using %s Version: %s' % (g.is_addon, is_version)) listitem.setArt({'thumb': thumb}) listitem.setSubtitles(subs) listitem.setProperty('%s.license_type' % g.is_addon, 'com.widevine.alpha') listitem.setProperty('%s.license_key' % g.is_addon, licURL) listitem.setProperty('%s.stream_headers' % g.is_addon, 'user-agent=' + getConfig('UserAgent')) listitem.setProperty('inputstreamaddon', g.is_addon) listitem.setMimeType('application/dash+xml') listitem.setContentLookup(False) player = _AmazonPlayer() player.asin = asin player.cookie = cookie player.content = trailer player.extern = extern player.resolve(listitem) starttime = time.time() while not xbmc.abortRequested and player.running: if player.isPlayingVideo(): player.video_lastpos = player.getTime() if time.time() > starttime + player.interval: starttime = time.time() player.updateStream('PLAY') sleep(1) player.finished() del player return True isAdult = adultstr == '1' amazonUrl = g.BaseUrl + "/dp/" + (name if g.UsePrimeVideo else asin) playable = False fallback = int(g.addon.getSetting("fallback_method")) methodOW = fallback - 1 if forcefb and fallback else s.playMethod videoUrl = "%s/?autoplay=%s" % (amazonUrl, ('trailer' if trailer == 1 else '1')) extern = not xbmc.getInfoLabel('Container.PluginName').startswith( 'plugin.video.amazon') fr = '' if extern: Log('External Call', Log.DEBUG) while not playable: playable = True if methodOW == 2 and g.platform & g.OS_ANDROID: _AndroidPlayback(asin, trailer) elif methodOW == 3: playable = _IStreamPlayback(asin, name, trailer, isAdult, extern) elif not g.platform & g.OS_ANDROID: _ExtPlayback(videoUrl, asin, isAdult, methodOW, fr) if not playable or isinstance(playable, unicode): if fallback: methodOW = fallback - 1 if isinstance(playable, unicode): fr = playable playable = False else: xbmc.sleep(500) g.dialog.ok(getString(30203), getString(30218)) playable = True if methodOW != 3: _playDummyVid()