예제 #1
0
 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()
예제 #2
0
 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
예제 #3
0
 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()
예제 #4
0
    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)
예제 #5
0
 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()
예제 #6
0
 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()
예제 #7
0
    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()
예제 #8
0
    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)
예제 #9
0
    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]
예제 #10
0
 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()
예제 #11
0
    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]
예제 #12
0
    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)
예제 #13
0
 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)
예제 #14
0
    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
예제 #15
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)
예제 #16
0
    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)
예제 #17
0
 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
예제 #18
0
 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)
예제 #19
0
 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')
예제 #20
0
    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()
예제 #21
0
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)
                                ))
예제 #22
0
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 = [('&amp;', '&'), ('&quot;', '"'), ('&lt;', '<'), ('&gt;', '>'), ('&apos;', "'")]
                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()
예제 #23
0
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)
예제 #24
0
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()
예제 #25
0
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
예제 #26
0
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()
예제 #27
0
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
예제 #28
0
 def __init__(self, label=None, show_menu=False):
     gtk.VBox.__init__(self)
     self.set_app_paintable(1)
     self.globals = Globals()
     self.popup_style = PopupStyle()
예제 #29
0
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)
예제 #30
0
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
예제 #31
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:
                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 = [('&amp;', '&'), ('&quot;', '"'), ('&lt;', '<'),
                                ('&gt;', '>'), ('&apos;', "'")]
                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)
예제 #32
0
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
예제 #33
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 = [('&amp;', '&'), ('&quot;', '"'), ('&lt;', '<'), ('&gt;', '>'), ('&apos;', "'")]
                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)
예제 #34
0
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)
예제 #35
0
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)
예제 #36
0
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)
예제 #37
0
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()