Exemplo n.º 1
0
    def __init__(self, library, player):
        super(MainSongList, self).__init__(library, player, update=True)
        self.set_first_column_type(CurrentColumn)

        self.connect('row-activated', self.__select_song, player)

        # ugly.. so the main window knows if the next song-started
        # comes from an row-activated or anything else.
        def reset_activated(*args):
            self._activated = False
        connect_after_destroy(player, 'song-started', reset_activated)

        self.connect("orders-changed", self.__orders_changed)
Exemplo n.º 2
0
    def __init__(self, library, player):
        super(MainSongList, self).__init__(library, player, update=True)
        self.set_first_column_type(CurrentColumn)

        self.connect('row-activated', self.__select_song, player)

        # ugly.. so the main window knows if the next song-started
        # comes from an row-activated or anything else.
        def reset_activated(*args):
            self._activated = False
        connect_after_destroy(player, 'song-started', reset_activated)

        self.connect("orders-changed", self.__orders_changed)
Exemplo n.º 3
0
    def __init__(self, library, player):
        super(PlayQueue, self).__init__(library, player, model_cls=QueueModel)
        keep_song = config.getboolean("memory", "queue_keep_songs", False)
        if keep_song:
            self.set_first_column_type(CurrentColumn)
        self.set_size_request(-1, 120)
        self.connect('row-activated', self.__go_to, player)

        def reset_activated(*args):
            self._activated = False
        connect_after_destroy(player, 'song-started', reset_activated)

        self.connect('popup-menu', self.__popup, library)
        self.enable_drop()
        self.connect('destroy', self.__write, self.model)
        self.__fill(library)

        self.connect('key-press-event', self.__delete_key_pressed)
Exemplo n.º 4
0
    def __init__(self,
                 library: Library,
                 player: BasePlayer,
                 autosave_interval_secs: Optional[int] = None):
        super().__init__(library, player, model_cls=QueueModel)
        self._updated_time = time.time()
        self.autosave_interval = autosave_interval_secs
        self._pending = 0
        keep_song = config.getboolean("memory", "queue_keep_songs", False)
        if keep_song:
            self.set_first_column_type(CurrentColumn)
        self.set_size_request(-1, 120)
        self.connect('row-activated', self.__go_to, player)

        def reset_activated(*args):
            self._activated = False

        connect_after_destroy(player, 'song-started', reset_activated)

        self.connect('popup-menu', self.__popup, library)
        self.enable_drop()

        def write(*args, **kwargs):
            self._write(self, self.model)
            return True

        self.connect('destroy', self.__destroy)
        if self.autosave_interval:
            self._tid = GLib.timeout_add(self.autosave_interval * 1000, write)
        else:
            self._tid = None
        connect_after_destroy(self.model, "row-inserted", write)
        connect_after_destroy(self.model, "row-deleted", write)
        self.__fill(library)

        self.connect('key-press-event', self.__delete_key_pressed)
Exemplo n.º 5
0
    def __init__(self, library, player, headless=False, restore_cb=None):
        super(QuodLibetWindow, self).__init__(dialog=False)
        self.last_dir = get_home_dir()

        self.__destroyed = False
        self.__update_title(player)
        self.set_default_size(550, 450)

        main_box = Gtk.VBox()
        self.add(main_box)

        # create main menubar, load/restore accelerator groups
        self.__library = library
        ui = self.__create_menu(player, library)
        accel_group = ui.get_accel_group()
        self.add_accel_group(accel_group)

        def scroll_and_jump(*args):
            self.__jump_to_current(True, True)

        keyval, mod = Gtk.accelerator_parse("<control><shift>J")
        accel_group.connect(keyval, mod, 0, scroll_and_jump)

        # dbus app menu
        # Unity puts the app menu next to our menu bar. Since it only contains
        # menu items also available in the menu bar itself, don't add it.
        if not util.is_unity():
            AppMenu(self, ui.get_action_groups()[0])

        # custom accel map
        accel_fn = os.path.join(quodlibet.get_user_dir(), "accels")
        Gtk.AccelMap.load(accel_fn)
        # save right away so we fill the file with example comments of all
        # accels
        Gtk.AccelMap.save(accel_fn)

        menubar = ui.get_widget("/Menu")

        # Since https://git.gnome.org/browse/gtk+/commit/?id=b44df22895c79
        # toplevel menu items show an empty 16x16 image. While we don't
        # need image items there UIManager creates them by default.
        # Work around by removing the empty GtkImages
        for child in menubar.get_children():
            if isinstance(child, Gtk.ImageMenuItem):
                child.set_image(None)

        main_box.pack_start(menubar, False, True, 0)

        # get the playlist up before other stuff
        self.songlist = MainSongList(library, player)
        self.songlist.show_all()
        self.songlist.connect("key-press-event", self.__songlist_key_press)
        self.songlist.connect_after('drag-data-received',
                                    self.__songlist_drag_data_recv)
        self.song_scroller = SongListScroller(
            ui.get_widget("/Menu/View/SongList"))
        self.song_scroller.add(self.songlist)
        self.qexpander = QueueExpander(ui.get_widget("/Menu/View/Queue"),
                                       library, player)
        self.playlist = PlaylistMux(player, self.qexpander.model,
                                    self.songlist.model)

        top_bar = TopBar(self, player, library)
        main_box.pack_start(top_bar, False, True, 0)
        self.top_bar = top_bar

        self.__browserbox = Align(bottom=3)
        main_box.pack_start(self.__browserbox, True, True, 0)

        statusbox = StatusBarBox(self.songlist.model, player)
        self.order = statusbox.order
        self.repeat = statusbox.repeat
        self.statusbar = statusbox.statusbar

        main_box.pack_start(Align(statusbox, border=3, top=-3, right=3), False,
                            True, 0)

        self.songpane = ConfigRVPaned("memory", "queue_position", 0.75)
        self.songpane.pack1(self.song_scroller, resize=True, shrink=False)
        self.songpane.pack2(self.qexpander, resize=True, shrink=False)
        self.__handle_position = self.songpane.get_property("position")

        def songpane_button_press_cb(pane, event):
            """If we start to drag the pane handle while the
            queue expander is unexpanded, expand it and move the handle
            to the bottom, so we can 'drag' the queue out
            """

            if event.window != pane.get_handle_window():
                return False

            if not self.qexpander.get_expanded():
                self.qexpander.set_expanded(True)
                pane.set_relative(1.0)
            return False

        self.songpane.connect("button-press-event", songpane_button_press_cb)

        self.song_scroller.connect('notify::visible', self.__show_or)
        self.qexpander.connect('notify::visible', self.__show_or)
        self.qexpander.connect('notify::expanded', self.__expand_or)
        self.qexpander.connect('draw', self.__qex_size_allocate)
        self.songpane.connect('notify', self.__moved_pane_handle)

        try:
            orders = []
            for e in config.getstringlist('memory', 'sortby', []):
                orders.append((e[1:], int(e[0])))
        except ValueError:
            pass
        else:
            self.songlist.set_sort_orders(orders)

        self.browser = None
        self.ui = ui

        main_box.show_all()

        self._playback_error_dialog = None
        connect_destroy(player, 'song-started', self.__song_started)
        connect_destroy(player, 'paused', self.__update_paused, True)
        connect_destroy(player, 'unpaused', self.__update_paused, False)
        # make sure we redraw all error indicators before opening
        # a dialog (blocking the main loop), so connect after default handlers
        connect_after_destroy(player, 'error', self.__player_error)
        # connect after to let SongTracker update stats
        connect_after_destroy(player, "song-ended", self.__song_ended)

        # set at least the playlist. the song should be restored
        # after the browser emits the song list
        player.setup(self.playlist, None, 0)
        self.__restore_cb = restore_cb
        self.__first_browser_set = True

        restore_browser = not headless
        try:
            self.select_browser(self, config.get("memory", "browser"), library,
                                player, restore_browser)
        except:
            config.set("memory", "browser", browsers.name(0))
            config.save()
            raise

        self.showhide_playlist(ui.get_widget("/Menu/View/SongList"))
        self.showhide_playqueue(ui.get_widget("/Menu/View/Queue"))

        self.songlist.connect('popup-menu', self.__songs_popup_menu)
        self.songlist.connect('columns-changed', self.__cols_changed)
        self.songlist.connect('columns-changed', self.__hide_headers)
        self.songlist.info.connect("changed", self.__set_time)

        lib = library.librarian
        connect_destroy(lib, 'changed', self.__song_changed, player)

        targets = [("text/uri-list", Gtk.TargetFlags.OTHER_APP, DND_URI_LIST)]
        targets = [Gtk.TargetEntry.new(*t) for t in targets]

        self.drag_dest_set(Gtk.DestDefaults.ALL, targets, Gdk.DragAction.COPY)
        self.connect('drag-data-received', self.__drag_data_received)

        if not headless:
            on_first_map(self, self.__configure_scan_dirs, library)

        if config.getboolean('library', 'refresh_on_start'):
            self.__rebuild(None, False)

        self.connect("key-press-event", self.__key_pressed, player)

        self.connect("destroy", self.__destroy)

        self.enable_window_tracking("quodlibet")
Exemplo n.º 6
0
    def __init__(self, library, player, headless=False, restore_cb=None):
        super().__init__(dialog=False)

        self.__destroyed = False
        self.__update_title(player)
        self.set_default_size(600, 480)

        main_box = Gtk.VBox()
        self.add(main_box)
        self.side_book = qltk.Notebook()

        # get the playlist up before other stuff
        self.songlist = MainSongList(library, player)
        self.songlist.connect("key-press-event", self.__songlist_key_press)
        self.songlist.connect_after('drag-data-received',
                                    self.__songlist_drag_data_recv)
        self.song_scroller = ScrolledWindow()
        self.song_scroller.set_policy(Gtk.PolicyType.AUTOMATIC,
                                      Gtk.PolicyType.AUTOMATIC)
        self.song_scroller.set_shadow_type(Gtk.ShadowType.IN)
        self.song_scroller.add(self.songlist)

        self.qexpander = QueueExpander(library, player)
        self.qexpander.set_no_show_all(True)
        self.qexpander.set_visible(config.getboolean("memory", "queue"))

        def on_queue_visible(qex, param):
            config.set("memory", "queue", str(qex.get_visible()))

        self.qexpander.connect("notify::visible", on_queue_visible)

        self.playlist = PlaylistMux(player, self.qexpander.model,
                                    self.songlist.model)

        self.__player = player
        # create main menubar, load/restore accelerator groups
        self.__library = library
        ui = self.__create_menu(player, library)
        accel_group = ui.get_accel_group()
        self.add_accel_group(accel_group)

        def scroll_and_jump(*args):
            self.__jump_to_current(True, None, True)

        keyval, mod = Gtk.accelerator_parse("<Primary><shift>J")
        accel_group.connect(keyval, mod, 0, scroll_and_jump)

        # custom accel map
        accel_fn = os.path.join(quodlibet.get_user_dir(), "accels")
        Gtk.AccelMap.load(accel_fn)
        # save right away so we fill the file with example comments of all
        # accels
        Gtk.AccelMap.save(accel_fn)

        menubar = ui.get_widget("/Menu")

        # Since https://git.gnome.org/browse/gtk+/commit/?id=b44df22895c79
        # toplevel menu items show an empty 16x16 image. While we don't
        # need image items there UIManager creates them by default.
        # Work around by removing the empty GtkImages
        for child in menubar.get_children():
            if isinstance(child, Gtk.ImageMenuItem):
                child.set_image(None)

        main_box.pack_start(menubar, False, True, 0)

        top_bar = TopBar(self, player, library)
        main_box.pack_start(top_bar, False, True, 0)
        self.top_bar = top_bar

        self.__browserbox = Align(bottom=3)
        self.__paned = paned = ConfigRHPaned("memory", "sidebar_pos", 0.25)
        paned.pack1(self.__browserbox, resize=True)
        # We'll pack2 when necessary (when the first sidebar plugin is set up)

        main_box.pack_start(paned, True, True, 0)

        play_order = PlayOrderWidget(self.songlist.model, player)
        statusbox = StatusBarBox(play_order, self.qexpander)
        self.order = play_order
        self.statusbar = statusbox.statusbar

        main_box.pack_start(Align(statusbox, border=3, top=-3), False, True, 0)

        self.songpane = SongListPaned(self.song_scroller, self.qexpander)
        self.songpane.show_all()

        try:
            orders = []
            for e in config.getstringlist('memory', 'sortby', []):
                orders.append((e[1:], int(e[0])))
        except ValueError:
            pass
        else:
            self.songlist.set_sort_orders(orders)

        self.browser = None
        self.ui = ui

        main_box.show_all()

        self._playback_error_dialog = None
        connect_destroy(player, 'song-started', self.__song_started)
        connect_destroy(player, 'paused', self.__update_paused, True)
        connect_destroy(player, 'unpaused', self.__update_paused, False)
        # make sure we redraw all error indicators before opening
        # a dialog (blocking the main loop), so connect after default handlers
        connect_after_destroy(player, 'error', self.__player_error)
        # connect after to let SongTracker update stats
        connect_after_destroy(player, "song-ended", self.__song_ended)

        # set at least the playlist. the song should be restored
        # after the browser emits the song list
        player.setup(self.playlist, None, 0)
        self.__restore_cb = restore_cb
        self.__first_browser_set = True

        restore_browser = not headless
        try:
            self._select_browser(self, config.get("memory", "browser"),
                                 library, player, restore_browser)
        except:
            config.set("memory", "browser", browsers.name(browsers.default))
            config.save()
            raise

        self.songlist.connect('popup-menu', self.__songs_popup_menu)
        self.songlist.connect('columns-changed', self.__cols_changed)
        self.songlist.connect('columns-changed', self.__hide_headers)
        self.songlist.info.connect("changed", self.__set_totals)

        lib = library.librarian
        connect_destroy(lib, 'changed', self.__song_changed, player)

        targets = [("text/uri-list", Gtk.TargetFlags.OTHER_APP, DND_URI_LIST)]
        targets = [Gtk.TargetEntry.new(*t) for t in targets]

        self.drag_dest_set(Gtk.DestDefaults.ALL, targets, Gdk.DragAction.COPY)
        self.connect('drag-data-received', self.__drag_data_received)

        if not headless:
            on_first_map(self, self.__configure_scan_dirs, library)

        if config.getboolean('library', 'refresh_on_start'):
            self.__rebuild(None, False)

        self.connect("key-press-event", self.__key_pressed, player)

        self.connect("destroy", self.__destroy)

        self.enable_window_tracking("quodlibet")
Exemplo n.º 7
0
    def __init__(self, library, player, headless=False):
        super(QuodLibetWindow, self).__init__(dialog=False)
        self.last_dir = const.HOME

        self.__destroyed = False
        self.__update_title(player)
        self.set_default_size(550, 450)

        main_box = Gtk.VBox()
        self.add(main_box)

        # create main menubar, load/restore accelerator groups
        self.__library = library
        ui = self.__create_menu(player, library)
        accel_group = ui.get_accel_group()
        self.add_accel_group(accel_group)

        def scroll_and_jump(*args):
            self.__jump_to_current(True, True)

        keyval, mod = Gtk.accelerator_parse("<control><shift>J")
        accel_group.connect(keyval, mod, 0, scroll_and_jump)

        # dbus app menu
        AppMenu(self, ui.get_action_groups()[0])

        # custom accel map
        accel_fn = os.path.join(const.USERDIR, "accels")
        Gtk.AccelMap.load(accel_fn)
        # save right away so we fill the file with example comments of all
        # accels
        Gtk.AccelMap.save(accel_fn)

        menubar = ui.get_widget("/Menu")

        # Since https://git.gnome.org/browse/gtk+/commit/?id=b44df22895c79
        # toplevel menu items show an empty 16x16 image. While we don't
        # need image items there UIManager creates them by default.
        # Work around by removing the empty GtkImages
        for child in menubar.get_children():
            if isinstance(child, Gtk.ImageMenuItem):
                child.set_image(None)

        main_box.pack_start(menubar, False, True, 0)

        # get the playlist up before other stuff
        self.songlist = MainSongList(library, player)
        self.songlist.show_all()
        self.songlist.connect("key-press-event", self.__songlist_key_press)
        self.songlist.connect_after(
            'drag-data-received', self.__songlist_drag_data_recv)
        self.song_scroller = SongListScroller(
            ui.get_widget("/Menu/View/SongList"))
        self.song_scroller.add(self.songlist)
        self.qexpander = QueueExpander(
            ui.get_widget("/Menu/View/Queue"), library, player)
        self.playlist = PlaylistMux(
            player, self.qexpander.model, self.songlist.model)

        top_bar = TopBar(self, player, library)
        main_box.pack_start(top_bar, False, True, 0)
        self.top_bar = top_bar

        self.__browserbox = Alignment(bottom=3)
        main_box.pack_start(self.__browserbox, True, True, 0)

        statusbox = StatusBarBox(self.songlist.model, player)
        self.order = statusbox.order
        self.repeat = statusbox.repeat
        self.statusbar = statusbox.statusbar

        main_box.pack_start(
            Alignment(statusbox, border=3, top=-3, right=3),
            False, True, 0)

        self.songpane = ConfigRVPaned("memory", "queue_position", 0.75)
        self.songpane.pack1(self.song_scroller, resize=True, shrink=False)
        self.songpane.pack2(self.qexpander, resize=True, shrink=False)
        self.__handle_position = self.songpane.get_property("position")

        def songpane_button_press_cb(pane, event):
            """If we start to drag the pane handle while the
            queue expander is unexpanded, expand it and move the handle
            to the bottom, so we can 'drag' the queue out
            """

            if event.window != pane.get_handle_window():
                return False

            if not self.qexpander.get_expanded():
                self.qexpander.set_expanded(True)
                pane.set_relative(1.0)
            return False

        self.songpane.connect("button-press-event", songpane_button_press_cb)

        self.song_scroller.connect('notify::visible', self.__show_or)
        self.qexpander.connect('notify::visible', self.__show_or)
        self.qexpander.connect('notify::expanded', self.__expand_or)
        self.qexpander.connect('draw', self.__qex_size_allocate)
        self.songpane.connect('notify', self.__moved_pane_handle)

        try:
            orders = []
            for e in config.getstringlist('memory', 'sortby', []):
                orders.append((e[1:], int(e[0])))
        except ValueError:
            pass
        else:
            self.songlist.set_sort_orders(orders)

        self.browser = None
        self.ui = ui

        main_box.show_all()

        # set at least the playlist. the song should be restored
        # after the browser emits the song list
        player.setup(self.playlist, None, 0)
        self.__first_browser_set = True

        restore_browser = not headless
        try:
            self.select_browser(
                self, config.get("memory", "browser"), library, player,
                restore_browser)
        except:
            config.set("memory", "browser", browsers.name(0))
            config.save(const.CONFIG)
            raise

        self.showhide_playlist(ui.get_widget("/Menu/View/SongList"))
        self.showhide_playqueue(ui.get_widget("/Menu/View/Queue"))

        self.songlist.connect('popup-menu', self.__songs_popup_menu)
        self.songlist.connect('columns-changed', self.__cols_changed)
        self.songlist.connect('columns-changed', self.__hide_headers)
        self.songlist.info.connect("changed", self.__set_time)

        lib = library.librarian
        connect_destroy(lib, 'changed', self.__song_changed, player)

        self._playback_error_dialog = None
        player_sigs = [
            ('song-started', self.__song_started),
            ('paused', self.__update_paused, True),
            ('unpaused', self.__update_paused, False),
        ]
        for sig in player_sigs:
            connect_destroy(player, *sig)

        # make sure we redraw all error indicators before opening
        # a dialog (blocking the main loop), so connect after default handlers
        connect_after_destroy(player, 'error', self.__player_error)

        # connect after to let SongTracker update stats
        connect_after_destroy(player, "song-ended", self.__song_ended)

        targets = [("text/uri-list", Gtk.TargetFlags.OTHER_APP, DND_URI_LIST)]
        targets = [Gtk.TargetEntry.new(*t) for t in targets]

        self.drag_dest_set(
            Gtk.DestDefaults.ALL, targets, Gdk.DragAction.COPY)
        self.connect('drag-data-received', self.__drag_data_received)

        if not headless:
            GLib.idle_add(self.__configure_scan_dirs, library)

        if config.getboolean('library', 'refresh_on_start'):
            self.__rebuild(None, False)

        self.connect("key-press-event", self.__key_pressed, player)

        self.connect("destroy", self.__destroy)

        self.enable_window_tracking("quodlibet")
Exemplo n.º 8
0
    def __init__(self, library, player, headless=False, restore_cb=None):
        super(QuodLibetWindow, self).__init__(dialog=False)

        self.__destroyed = False
        self.__update_title(player)
        self.set_default_size(600, 480)

        main_box = Gtk.VBox()
        self.add(main_box)
        self.side_book = qltk.Notebook()

        # get the playlist up before other stuff
        self.songlist = MainSongList(library, player)
        self.songlist.connect("key-press-event", self.__songlist_key_press)
        self.songlist.connect_after(
            'drag-data-received', self.__songlist_drag_data_recv)
        self.song_scroller = ScrolledWindow()
        self.song_scroller.set_policy(
            Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        self.song_scroller.set_shadow_type(Gtk.ShadowType.IN)
        self.song_scroller.add(self.songlist)

        self.qexpander = QueueExpander(library, player)
        self.qexpander.set_no_show_all(True)
        self.qexpander.set_visible(config.getboolean("memory", "queue"))

        def on_queue_visible(qex, param):
            config.set("memory", "queue", str(qex.get_visible()))

        self.qexpander.connect("notify::visible", on_queue_visible)

        self.playlist = PlaylistMux(
            player, self.qexpander.model, self.songlist.model)

        self.__player = player
        # create main menubar, load/restore accelerator groups
        self.__library = library
        ui = self.__create_menu(player, library)
        accel_group = ui.get_accel_group()
        self.add_accel_group(accel_group)

        def scroll_and_jump(*args):
            self.__jump_to_current(True, None, True)

        keyval, mod = Gtk.accelerator_parse("<Primary><shift>J")
        accel_group.connect(keyval, mod, 0, scroll_and_jump)

        # custom accel map
        accel_fn = os.path.join(quodlibet.get_user_dir(), "accels")
        Gtk.AccelMap.load(accel_fn)
        # save right away so we fill the file with example comments of all
        # accels
        Gtk.AccelMap.save(accel_fn)

        menubar = ui.get_widget("/Menu")

        # Since https://git.gnome.org/browse/gtk+/commit/?id=b44df22895c79
        # toplevel menu items show an empty 16x16 image. While we don't
        # need image items there UIManager creates them by default.
        # Work around by removing the empty GtkImages
        for child in menubar.get_children():
            if isinstance(child, Gtk.ImageMenuItem):
                child.set_image(None)

        main_box.pack_start(menubar, False, True, 0)

        top_bar = TopBar(self, player, library)
        main_box.pack_start(top_bar, False, True, 0)
        self.top_bar = top_bar

        self.__browserbox = Align(bottom=3)
        self.__paned = paned = ConfigRHPaned("memory", "sidebar_pos", 0.25)
        paned.pack1(self.__browserbox, resize=True)
        # We'll pack2 when necessary (when the first sidebar plugin is set up)

        main_box.pack_start(paned, True, True, 0)

        play_order = PlayOrderWidget(self.songlist.model, player)
        statusbox = StatusBarBox(play_order, self.qexpander)
        self.order = play_order
        self.statusbar = statusbox.statusbar

        main_box.pack_start(
            Align(statusbox, border=3, top=-3),
            False, True, 0)

        self.songpane = SongListPaned(self.song_scroller, self.qexpander)
        self.songpane.show_all()

        try:
            orders = []
            for e in config.getstringlist('memory', 'sortby', []):
                orders.append((e[1:], int(e[0])))
        except ValueError:
            pass
        else:
            self.songlist.set_sort_orders(orders)

        self.browser = None
        self.ui = ui

        main_box.show_all()

        self._playback_error_dialog = None
        connect_destroy(player, 'song-started', self.__song_started)
        connect_destroy(player, 'paused', self.__update_paused, True)
        connect_destroy(player, 'unpaused', self.__update_paused, False)
        # make sure we redraw all error indicators before opening
        # a dialog (blocking the main loop), so connect after default handlers
        connect_after_destroy(player, 'error', self.__player_error)
        # connect after to let SongTracker update stats
        connect_after_destroy(player, "song-ended", self.__song_ended)

        # set at least the playlist. the song should be restored
        # after the browser emits the song list
        player.setup(self.playlist, None, 0)
        self.__restore_cb = restore_cb
        self.__first_browser_set = True

        restore_browser = not headless
        try:
            self._select_browser(
                self, config.get("memory", "browser"), library, player,
                restore_browser)
        except:
            config.set("memory", "browser", browsers.name(browsers.default))
            config.save()
            raise

        self.songlist.connect('popup-menu', self.__songs_popup_menu)
        self.songlist.connect('columns-changed', self.__cols_changed)
        self.songlist.connect('columns-changed', self.__hide_headers)
        self.songlist.info.connect("changed", self.__set_totals)

        lib = library.librarian
        connect_destroy(lib, 'changed', self.__song_changed, player)

        targets = [("text/uri-list", Gtk.TargetFlags.OTHER_APP, DND_URI_LIST)]
        targets = [Gtk.TargetEntry.new(*t) for t in targets]

        self.drag_dest_set(
            Gtk.DestDefaults.ALL, targets, Gdk.DragAction.COPY)
        self.connect('drag-data-received', self.__drag_data_received)

        if not headless:
            on_first_map(self, self.__configure_scan_dirs, library)

        if config.getboolean('library', 'refresh_on_start'):
            self.__rebuild(None, False)

        self.connect("key-press-event", self.__key_pressed, player)

        self.connect("destroy", self.__destroy)

        self.enable_window_tracking("quodlibet")