def on_app_activate(self, app): self.window.show_all() # Make some changes after main window is shown. # Like hiding some unnecessory widgets. self.artists.after_init() self.player.after_init() self.search.after_init() self.shortcut = Shortcut(self.player) self.osdlrc.after_init()
def on_app_activate(self, app): self.window.show_all() # Make some changes after main window is shown. # Like hiding some unnecessory widgets. self.artists.after_init() self.player.after_init() self.search.after_init() self.shortcut = Shortcut(self.player) self.osdlrc.after_init() # Cleanup temporary media files Net.cleanup_temp_files(self.conf['song-dir']) Net.cleanup_temp_files(self.conf['mv-dir'])
def on_app_activate(self, app): self.window.show_all() # make some changes after main window is shown. self.lrc.after_init() self.player.after_init() self.search.after_init() self.shortcut = Shortcut(self.player)
def on_app_activate(self, app): self.window.show_all() # Make some changes after main window is shown. # Like hiding some unnecessory widgets. self.lrc.after_init() self.artists.after_init() self.player.after_init() self.search.after_init() self.shortcut = Shortcut(self.player)
class App: def __init__(self): self.app = Gtk.Application.new(DBUS_APP_NAME, 0) self.app.connect('startup', self.on_app_startup) self.app.connect('activate', self.on_app_activate) self.app.connect('shutdown', self.on_app_shutdown) self.conf = Config.load_conf() self.theme, self.theme_path = Config.load_theme() def on_app_startup(self, app): self.window = Gtk.ApplicationWindow(application=app) self.window.set_default_size(*self.conf['window-size']) self.window.set_title(Config.APPNAME) self.window.props.hide_titlebar_when_maximized = True self.window.set_icon(self.theme['app-logo']) app.add_window(self.window) self.window.connect('check-resize', self.on_main_window_resized) self.window.connect('delete-event', self.on_main_window_deleted) self.accel_group = Gtk.AccelGroup() self.window.add_accel_group(self.accel_group) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.window.add(box) self.player = Player(self) box.pack_start(self.player, False, False, 0) self.notebook = Gtk.Notebook() self.notebook.props.tab_pos = Gtk.PositionType.BOTTOM self.notebook.get_style_context().add_class('main_tab') box.pack_start(self.notebook, True, True, 0) self.init_notebook() self.notebook.connect('switch-page', self.on_notebook_switch_page) self.init_status_icon() # load default styles when all widgets have been constructed. self.load_styles() def on_app_activate(self, app): self.window.show_all() # Make some changes after main window is shown. # Like hiding some unnecessory widgets. self.lrc.after_init() self.artists.after_init() self.player.after_init() self.search.after_init() self.shortcut = Shortcut(self.player) def on_app_shutdown(self, app): Config.dump_conf(self.conf) def run(self, argv): self.app.run(argv) def quit(self): self.window.destroy() self.shortcut.quit() self.app.quit() def on_main_window_resized(self, window, event=None): self.conf['window-size'] = window.get_size() def on_main_window_deleted(self, window, event): if self.conf['use-status-icon']: window.hide() return True else: return False def init_notebook(self): self.tab_first_show = [] self.lrc = Lrc(self) self.append_page(self.lrc) self.playlist = PlayList(self) self.append_page(self.playlist) self.search = Search(self) self.append_page(self.search) self.toplist = TopList(self) self.append_page(self.toplist) self.radio = Radio(self) self.append_page(self.radio) self.mv = MV(self) self.append_page(self.mv) self.artists = Artists(self) self.append_page(self.artists) self.topcategories = TopCategories(self) self.append_page(self.topcategories) self.themes = Themes(self) self.append_page(self.themes) def on_notebook_switch_page(self, notebook, page, page_num): if page not in self.tab_first_show: page.first() self.tab_first_show.append(page) def append_page(self, widget): '''Append a new widget to notebook.''' label = Gtk.Label(widget.title) widget.app_page = self.notebook.append_page(widget, label) def popup_page(self, page): '''Switch to this widget in notebook.''' self.notebook.set_current_page(page) def apply_css(self, widget, css, old_provider=None, overall=False): '''Update CssProvider of this widget.''' # CssProvider needs bytecode style_provider = Gtk.CssProvider() css_encoded = css.encode() style_provider.load_from_data(css_encoded) if overall: Gtk.StyleContext.add_provider_for_screen( Gdk.Screen.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) if old_provider: Gtk.StyleContext.remove_provider_for_screen( Gdk.Screen.get_default(), style_provider) else: widget.get_style_context().add_provider( style_provider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) if old_provider: widget.get_style_context().remove_provider(old_provider) return style_provider def load_styles(self): '''Load default CssStyle.''' if Config.GTK_LE_36: css = '\n'.join([ # transition-property is not supported in Gtk3.4 #'GtkScrolledWindow.lrc_window {', # 'transition-property: background-image;', # 'transition-duration: 1s;', # '}', 'GtkScale {', 'outline-color: transparent;', 'outline-offset: 0;', 'outline-style: none;', 'outline-width: 0;', '}', 'GtkTextView.lrc_tv {', 'font-size: {0};'.format(self.conf['lrc-text-size']), 'color: {0};'.format(self.conf['lrc-text-color']), 'border-radius: 0 25 0 50;', 'border-width: 5;', 'background-color: {0};'.format( self.conf['lrc-back-color']), '}', '.info-label {', 'color: rgb(136, 139, 132);', 'font-size: 9;', '}', ]) else: css = '\n'.join([ 'GtkScrolledWindow.lrc_window {', 'transition-property: background-image;', 'transition-duration: 1s;', '}', 'GtkScale {', 'outline-color: transparent;', 'outline-offset: 0;', 'outline-style: none;', 'outline-width: 0;', '}', 'GtkTextView.lrc_tv {', 'font-size: {0}px;'.format(self.conf['lrc-text-size']), 'color: {0};'.format(self.conf['lrc-text-color']), 'border-radius: 0px 25px 0px 50px;', 'border-width: 5px;', 'background-color: {0};'.format( self.conf['lrc-back-color']), '}', '.info-label {', 'color: rgb(136, 139, 132);', 'font-size: 9px;', '}', ]) self.apply_css(self.window, css, overall=True) def init_status_icon(self): # set status_icon as class property, to keep its life # after function exited self.status_icon = Gtk.StatusIcon() self.status_icon.set_from_pixbuf(self.theme['app-logo']) # left click self.status_icon.connect('activate', self.on_status_icon_activate) # right click self.status_icon.connect('popup_menu', self.on_status_icon_popup_menu) def on_status_icon_activate(self, status_icon): if self.window.props.visible: self.window.hide() else: self.window.present() def on_status_icon_popup_menu(self, status_icon, event_button, event_time): menu = Gtk.Menu() show_item = Gtk.MenuItem(label=_('Show App') ) show_item.connect('activate', self.on_status_icon_show_app_activate) menu.append(show_item) pause_item = Gtk.MenuItem(label=_('Pause/Resume')) pause_item.connect('activate', self.on_status_icon_pause_activate) menu.append(pause_item) next_item = Gtk.MenuItem(label=_('Next Song')) next_item.connect('activate', self.on_status_icon_next_activate) menu.append(next_item) sep_item = Gtk.SeparatorMenuItem() menu.append(sep_item) quit_item = Gtk.MenuItem(label=_('Quit')) quit_item.connect('activate', self.on_status_icon_quit_activate) menu.append(quit_item) menu.show_all() menu.popup(None, None, lambda a,b: Gtk.StatusIcon.position_menu(menu, status_icon), None, event_button, event_time) def on_status_icon_show_app_activate(self, menuitem): self.window.present() def on_status_icon_pause_activate(self, menuitem): self.player.play_pause() def on_status_icon_next_activate(self, menuitem): self.player.load_next() def on_status_icon_quit_activate(self, menuitem): self.quit()
class App: def __init__(self): self.app = Gtk.Application.new(DBUS_APP_NAME, 0) self.app.connect('startup', self.on_app_startup) self.app.connect('activate', self.on_app_activate) self.app.connect('shutdown', self.on_app_shutdown) def on_app_startup(self, app): self.conf = Config.load_conf() self.icon_theme = Gtk.IconTheme.get_default() self.icon_theme.append_search_path(Config.ICON_PATH) GLib.set_application_name(Config.APPNAME) self.window = Gtk.ApplicationWindow(application=app) self.window.set_default_size(*self.conf['window-size']) self.window.set_title(Config.APPNAME) self.window.set_default_icon_name(Config.NAME) self.window.props.hide_titlebar_when_maximized = True app.add_window(self.window) self.window.connect('check-resize', self.on_main_window_resized) self.window.connect('delete-event', self.on_main_window_deleted) self.accel_group = Gtk.AccelGroup() self.window.add_accel_group(self.accel_group) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.window.add(box) self.osdlrc = OSDLrc(self) self.notify = None self.init_notify() self.player = Player(self) box.pack_start(self.player, False, False, 0) self.notebook = Gtk.Notebook() self.notebook.props.tab_pos = Gtk.PositionType.BOTTOM self.notebook.get_style_context().add_class('main_tab') box.pack_start(self.notebook, True, True, 0) self.init_notebook() self.notebook.connect('switch-page', self.on_notebook_switch_page) self.init_status_icon() # load default styles when all widgets have been constructed. self.load_styles() def on_app_activate(self, app): self.window.show_all() # Make some changes after main window is shown. # Like hiding some unnecessory widgets. self.artists.after_init() self.player.after_init() self.search.after_init() self.shortcut = Shortcut(self.player) self.osdlrc.after_init() # Cleanup temporary media files Net.cleanup_temp_files(self.conf['song-dir']) Net.cleanup_temp_files(self.conf['mv-dir']) def on_app_shutdown(self, app): Config.dump_conf(self.conf) def run(self, argv): self.app.run(argv) def quit(self): gdk_win = self.window.get_window() if gdk_win and not gdk_win.is_destroyed(): if self.player.default_cursor: gdk_win.set_cursor(self.player.default_cursor) self.window.destroy() self.shortcut.quit() self.app.quit() def on_main_window_resized(self, window, event=None): self.conf['window-size'] = window.get_size() def on_main_window_deleted(self, window, event): if self.conf['use-status-icon']: window.hide() return True else: return False def init_notebook(self): self.tab_first_show = [] self.lrc = Lrc(self) self.append_page(self.lrc) self.playlist = PlayList(self) self.append_page(self.playlist) self.search = Search(self) self.append_page(self.search) self.toplist = TopList(self) self.append_page(self.toplist) self.radio = Radio(self) self.append_page(self.radio) self.mv = MV(self) self.append_page(self.mv) self.artists = Artists(self) self.append_page(self.artists) self.topcategories = TopCategories(self) self.append_page(self.topcategories) self.themes = Themes(self) self.append_page(self.themes) def append_page(self, widget): '''Append a new widget to notebook.''' label = Gtk.Label(widget.title) widget.app_page = self.notebook.append_page(widget, label) def popup_page(self, page): '''Switch to this widget in notebook.''' self.notebook.set_current_page(page) def load_styles(self): '''Load default CssStyle.''' if Config.GTK_LE_36: css = '\n'.join([ 'GtkScale {', 'outline-color: transparent;', 'outline-offset: 0;', 'outline-style: none;', 'outline-width: 0;', '}', 'GtkTextView.lrc_tv {', 'font-size: {0};'.format(self.conf['lrc-text-size']), 'color: {0};'.format(self.conf['lrc-text-color']), 'border-radius: 0 25 0 50;', 'border-width: 5;', 'background-color: {0};'.format( self.conf['lrc-back-color']), '}', '.info-label {', 'color: rgb(136, 139, 132);', 'font-size: 9;', '}', ]) else: css = '\n'.join([ 'GtkScrolledWindow.lrc_window {', 'transition-property: background-image;', 'transition-duration: 1s;', '}', 'GtkScale {', 'outline-color: transparent;', 'outline-offset: 0;', 'outline-style: none;', 'outline-width: 0;', '}', 'GtkTextView.lrc_tv {', 'transition-property: font-size;', 'transition: 500ms ease-in-out;', 'font-size: {0}px;'.format(self.conf['lrc-text-size']), 'color: {0};'.format(self.conf['lrc-text-color']), 'border-radius: 0px 25px 0px 50px;', 'border-width: 5px;', 'background-color: {0};'.format( self.conf['lrc-back-color']), '}', '.info-label {', 'color: rgb(136, 139, 132);', 'font-size: 9px;', '}', ]) Widgets.apply_css(self.window, css, overall=True) settings = Gtk.Settings.get_default() settings.props.gtk_application_prefer_dark_theme = \ self.conf.get('use-dark-theme', False) def init_status_icon(self): def on_status_icon_popup_menu(status_icon, event_button, event_time): menu.popup(None, None, lambda a,b: Gtk.StatusIcon.position_menu(menu, status_icon), None, event_button, event_time) def on_status_icon_activate(tatus_icon): if self.window.props.visible: self.window.hide() else: self.window.present() if not self.conf['use-status-icon']: return menu = Gtk.Menu() show_item = Gtk.MenuItem(_('Show App')) show_item.connect('activate', lambda item: self.window.present()) menu.append(show_item) sep_item = Gtk.SeparatorMenuItem() menu.append(sep_item) previous_item = Gtk.MenuItem(_('Previous Song')) previous_item.connect('activate', lambda item: self.player.load_prev()) menu.append(previous_item) play_item = Gtk.MenuItem() play_item.props.related_action = self.player.playback_action menu.append(play_item) next_item = Gtk.MenuItem(_('Next Song')) next_item.connect('activate', lambda item: self.player.load_next()) menu.append(next_item) sep_item = Gtk.SeparatorMenuItem() menu.append(sep_item) show_osd_item = Gtk.MenuItem() show_osd_item.props.related_action = self.osdlrc.show_window_action menu.append(show_osd_item) lock_osd_item = Gtk.MenuItem() lock_osd_item.props.related_action = self.osdlrc.lock_window_action menu.append(lock_osd_item) sep_item = Gtk.SeparatorMenuItem() menu.append(sep_item) quit_item = Gtk.MenuItem(_('Quit')) quit_item.connect('activate', lambda item: self.quit()) menu.append(quit_item) menu.show_all() self.status_menu = menu if 'AppIndicator' in globals(): self.status_icon = AppIndicator.Indicator.new(Config.NAME, Config.NAME, AppIndicator.IndicatorCategory.APPLICATION_STATUS) self.status_icon.set_menu(menu) self.status_icon.set_status(AppIndicator.IndicatorStatus.ACTIVE) else: self.status_icon = Gtk.StatusIcon.new_from_icon_name(Config.NAME) # left click self.status_icon.connect('activate', on_status_icon_activate) # right click self.status_icon.connect('popup_menu', on_status_icon_popup_menu) def on_notebook_switch_page(self, notebook, page, page_num): if page not in self.tab_first_show: page.first() self.tab_first_show.append(page) def init_notify(self): try: self.notify = Notify.Notification.new(Config.APPNAME, '', Config.NAME) except Exception: logger.warn('App.init_notify: %s' % traceback.format_exc()) self.notify = None # Open API def toast(self, text): '''在用户界面显示一个消息通知. 可以使用系统提供的Notification工具, 也可以在窗口的最下方滚动弹出 这个消息 ''' if self.notify: self.notify.update(Config.APPNAME, text, Config.NAME) self.notify.show()
class App: def __init__(self): self.app = Gtk.Application.new(DBUS_APP_NAME, 0) self.app.connect('startup', self.on_app_startup) self.app.connect('activate', self.on_app_activate) self.app.connect('shutdown', self.on_app_shutdown) def on_app_startup(self, app): self.conf = Config.load_conf() self.icon_theme = Gtk.IconTheme.get_default() self.icon_theme.append_search_path(Config.ICON_PATH) GLib.set_application_name(Config.APPNAME) self.window = Gtk.ApplicationWindow(application=app) self.window.set_default_size(*self.conf['window-size']) self.window.set_title(Config.APPNAME) self.window.set_default_icon_name(Config.NAME) self.window.props.hide_titlebar_when_maximized = True app.add_window(self.window) self.window.connect('check-resize', self.on_main_window_resized) self.window.connect('delete-event', self.on_main_window_deleted) self.accel_group = Gtk.AccelGroup() self.window.add_accel_group(self.accel_group) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.window.add(box) self.osdlrc = OSDLrc(self) self.notify = None self.init_notify() self.player = Player(self) box.pack_start(self.player, False, False, 0) self.notebook = Gtk.Notebook() self.notebook.props.tab_pos = Gtk.PositionType.BOTTOM self.notebook.get_style_context().add_class('main_tab') box.pack_start(self.notebook, True, True, 0) self.init_notebook() self.notebook.connect('switch-page', self.on_notebook_switch_page) self.init_status_icon() # load default styles when all widgets have been constructed. self.load_styles() def on_app_activate(self, app): self.window.show_all() # Make some changes after main window is shown. # Like hiding some unnecessory widgets. self.artists.after_init() self.player.after_init() self.search.after_init() self.shortcut = Shortcut(self.player) self.osdlrc.after_init() # Cleanup temporary media files Net.cleanup_temp_files(self.conf['song-dir']) Net.cleanup_temp_files(self.conf['mv-dir']) def on_app_shutdown(self, app): Config.dump_conf(self.conf) def run(self, argv): self.app.run(argv) def quit(self): gdk_win = self.window.get_window() if gdk_win and not gdk_win.is_destroyed(): if self.player.default_cursor: gdk_win.set_cursor(self.player.default_cursor) self.window.destroy() self.shortcut.quit() self.app.quit() def on_main_window_resized(self, window, event=None): self.conf['window-size'] = window.get_size() def on_main_window_deleted(self, window, event): if self.conf['use-status-icon']: window.hide() return True else: return False def init_notebook(self): self.tab_first_show = [] self.lrc = Lrc(self) self.append_page(self.lrc) self.playlist = PlayList(self) self.append_page(self.playlist) self.search = Search(self) self.append_page(self.search) self.toplist = TopList(self) self.append_page(self.toplist) self.radio = Radio(self) self.append_page(self.radio) self.mv = MV(self) self.append_page(self.mv) self.artists = Artists(self) self.append_page(self.artists) self.topcategories = TopCategories(self) self.append_page(self.topcategories) self.themes = Themes(self) self.append_page(self.themes) def append_page(self, widget): '''Append a new widget to notebook.''' label = Gtk.Label(widget.title) widget.app_page = self.notebook.append_page(widget, label) def popup_page(self, page): '''Switch to this widget in notebook.''' self.notebook.set_current_page(page) def load_styles(self): '''Load default CssStyle.''' if Config.GTK_LE_36: css = '\n'.join([ 'GtkScale {', 'outline-color: transparent;', 'outline-offset: 0;', 'outline-style: none;', 'outline-width: 0;', '}', 'GtkTextView.lrc_tv {', 'font-size: {0};'.format(self.conf['lrc-text-size']), 'color: {0};'.format(self.conf['lrc-text-color']), 'border-radius: 0 25 0 50;', 'border-width: 5;', 'background-color: {0};'.format(self.conf['lrc-back-color']), '}', '.info-label {', 'color: rgb(136, 139, 132);', 'font-size: 9;', '}', ]) else: css = '\n'.join([ 'GtkScrolledWindow.lrc_window {', 'transition-property: background-image;', 'transition-duration: 1s;', '}', 'GtkScale {', 'outline-color: transparent;', 'outline-offset: 0;', 'outline-style: none;', 'outline-width: 0;', '}', 'GtkTextView.lrc_tv {', 'transition-property: font-size;', 'transition: 500ms ease-in-out;', 'font-size: {0}px;'.format(self.conf['lrc-text-size']), 'color: {0};'.format(self.conf['lrc-text-color']), 'border-radius: 0px 25px 0px 50px;', 'border-width: 5px;', 'background-color: {0};'.format(self.conf['lrc-back-color']), '}', '.info-label {', 'color: rgb(136, 139, 132);', 'font-size: 9px;', '}', ]) Widgets.apply_css(self.window, css, overall=True) settings = Gtk.Settings.get_default() settings.props.gtk_application_prefer_dark_theme = \ self.conf.get('use-dark-theme', False) def init_status_icon(self): def on_status_icon_popup_menu(status_icon, event_button, event_time): menu.popup( None, None, lambda a, b: Gtk.StatusIcon.position_menu(menu, status_icon), None, event_button, event_time) def on_status_icon_activate(tatus_icon): if self.window.props.visible: self.window.hide() else: self.window.present() if not self.conf['use-status-icon']: return menu = Gtk.Menu() show_item = Gtk.MenuItem(_('Show App')) show_item.connect('activate', lambda item: self.window.present()) menu.append(show_item) sep_item = Gtk.SeparatorMenuItem() menu.append(sep_item) previous_item = Gtk.MenuItem(_('Previous Song')) previous_item.connect('activate', lambda item: self.player.load_prev()) menu.append(previous_item) play_item = Gtk.MenuItem() play_item.props.related_action = self.player.playback_action menu.append(play_item) next_item = Gtk.MenuItem(_('Next Song')) next_item.connect('activate', lambda item: self.player.load_next()) menu.append(next_item) sep_item = Gtk.SeparatorMenuItem() menu.append(sep_item) show_osd_item = Gtk.MenuItem() show_osd_item.props.related_action = self.osdlrc.show_window_action menu.append(show_osd_item) lock_osd_item = Gtk.MenuItem() lock_osd_item.props.related_action = self.osdlrc.lock_window_action menu.append(lock_osd_item) sep_item = Gtk.SeparatorMenuItem() menu.append(sep_item) quit_item = Gtk.MenuItem(_('Quit')) quit_item.connect('activate', lambda item: self.quit()) menu.append(quit_item) menu.show_all() self.status_menu = menu if 'AppIndicator' in globals(): self.status_icon = AppIndicator.Indicator.new( Config.NAME, Config.NAME, AppIndicator.IndicatorCategory.APPLICATION_STATUS) self.status_icon.set_menu(menu) self.status_icon.set_status(AppIndicator.IndicatorStatus.ACTIVE) else: self.status_icon = Gtk.StatusIcon.new_from_icon_name(Config.NAME) # left click self.status_icon.connect('activate', on_status_icon_activate) # right click self.status_icon.connect('popup_menu', on_status_icon_popup_menu) def on_notebook_switch_page(self, notebook, page, page_num): if page not in self.tab_first_show: page.first() self.tab_first_show.append(page) def init_notify(self): try: self.notify = Notify.Notification.new(Config.APPNAME, '', Config.NAME) except Exception: logger.warn('App.init_notify: %s' % traceback.format_exc()) self.notify = None # Open API def toast(self, text): '''在用户界面显示一个消息通知. 可以使用系统提供的Notification工具, 也可以在窗口的最下方滚动弹出 这个消息 ''' if self.notify: self.notify.update(Config.APPNAME, text, Config.NAME) self.notify.show()
class App: def __init__(self): self.app = Gtk.Application.new(DBUS_APP_NAME, 0) self.app.connect("startup", self.on_app_startup) self.app.connect("activate", self.on_app_activate) self.app.connect("shutdown", self.on_app_shutdown) self.conf = Config.load_conf() self.theme, self.theme_path = Config.load_theme() def on_app_startup(self, app): self.window = Gtk.ApplicationWindow(application=app) self.window.set_default_size(*self.conf["window-size"]) self.window.set_title(Config.APPNAME) self.window.props.hide_titlebar_when_maximized = True self.window.set_icon(self.theme["app-logo"]) app.add_window(self.window) self.window.connect("check-resize", self.on_main_window_resized) self.window.connect("delete-event", self.on_main_window_deleted) self.accel_group = Gtk.AccelGroup() self.window.add_accel_group(self.accel_group) self.fullscreen_sid = 0 self.fullscreen_timestamp = 0 box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.window.add(box) self.player = Player(self) box.pack_start(self.player, False, False, 0) self.notebook = Gtk.Notebook() self.notebook.props.tab_pos = Gtk.PositionType.BOTTOM self.notebook.get_style_context().add_class("main_tab") box.pack_start(self.notebook, True, True, 0) self.init_notebook() self.notebook.connect("switch-page", self.on_notebook_switch_page) self.init_status_icon() # load default styles when all widgets have been constructed. self.load_styles() def on_app_activate(self, app): self.window.show_all() # Make some changes after main window is shown. # Like hiding some unnecessory widgets. self.lrc.after_init() self.artists.after_init() self.player.after_init() self.search.after_init() self.shortcut = Shortcut(self.player) def on_app_shutdown(self, app): Config.dump_conf(self.conf) def run(self, argv): self.app.run(argv) def quit(self): gdk_win = self.window.get_window() if gdk_win and not gdk_win.is_destroyed(): self.window.destroy() self.shortcut.quit() self.app.quit() def on_main_window_resized(self, window, event=None): self.conf["window-size"] = window.get_size() def on_main_window_deleted(self, window, event): if self.conf["use-status-icon"]: window.hide() return True else: return False def init_notebook(self): self.tab_first_show = [] self.lrc = Lrc(self) self.append_page(self.lrc) self.playlist = PlayList(self) self.append_page(self.playlist) self.search = Search(self) self.append_page(self.search) self.toplist = TopList(self) self.append_page(self.toplist) self.radio = Radio(self) self.append_page(self.radio) self.mv = MV(self) self.append_page(self.mv) self.artists = Artists(self) self.append_page(self.artists) self.topcategories = TopCategories(self) self.append_page(self.topcategories) self.themes = Themes(self) self.append_page(self.themes) def append_page(self, widget): """Append a new widget to notebook.""" label = Gtk.Label(widget.title) widget.app_page = self.notebook.append_page(widget, label) def popup_page(self, page): """Switch to this widget in notebook.""" self.notebook.set_current_page(page) def apply_css(self, widget, css, old_provider=None, overall=False): """Update CssProvider of this widget.""" # CssProvider needs bytecode style_provider = Gtk.CssProvider() css_encoded = css.encode() style_provider.load_from_data(css_encoded) if overall: Gtk.StyleContext.add_provider_for_screen( Gdk.Screen.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION ) if old_provider: Gtk.StyleContext.remove_provider_for_screen(Gdk.Screen.get_default(), style_provider) else: widget.get_style_context().add_provider(style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) if old_provider: widget.get_style_context().remove_provider(old_provider) return style_provider def load_styles(self): """Load default CssStyle.""" if Config.GTK_LE_36: css = "\n".join( [ # transition-property is not supported in Gtk3.4 #'GtkScrolledWindow.lrc_window {', # 'transition-property: background-image;', # 'transition-duration: 1s;', # '}', "GtkScale {", "outline-color: transparent;", "outline-offset: 0;", "outline-style: none;", "outline-width: 0;", "}", "GtkTextView.lrc_tv {", "font-size: {0};".format(self.conf["lrc-text-size"]), "color: {0};".format(self.conf["lrc-text-color"]), "border-radius: 0 25 0 50;", "border-width: 5;", "background-color: {0};".format(self.conf["lrc-back-color"]), "}", ".info-label {", "color: rgb(136, 139, 132);", "font-size: 9;", "}", ] ) else: css = "\n".join( [ "GtkScrolledWindow.lrc_window {", "transition-property: background-image;", "transition-duration: 1s;", #'background-repeat: no-repeat;', #'background-repeat: repeat;', #'background-position: center;', "}", "GtkScale {", "outline-color: transparent;", "outline-offset: 0;", "outline-style: none;", "outline-width: 0;", "}", "GtkTextView.lrc_tv {", "font-size: {0}px;".format(self.conf["lrc-text-size"]), "color: {0};".format(self.conf["lrc-text-color"]), "border-radius: 0px 25px 0px 50px;", "border-width: 5px;", "background-color: {0};".format(self.conf["lrc-back-color"]), "}", ".info-label {", "color: rgb(136, 139, 132);", "font-size: 9px;", "}", ] ) self.apply_css(self.window, css, overall=True) settings = Gtk.Settings.get_default() settings.props.gtk_application_prefer_dark_theme = self.conf.get("use-dark-theme", False) def init_status_icon(self): # set status_icon as class property, to keep its life # after function exited self.status_icon = Gtk.StatusIcon() self.status_icon.set_from_pixbuf(self.theme["app-logo"]) # left click self.status_icon.connect("activate", self.on_status_icon_activate) # right click self.status_icon.connect("popup_menu", self.on_status_icon_popup_menu) def on_status_icon_activate(self, status_icon): if self.window.props.visible: self.window.hide() else: self.window.present() def on_status_icon_popup_menu(self, status_icon, event_button, event_time): menu = Gtk.Menu() show_item = Gtk.MenuItem(label=_("Show App")) show_item.connect("activate", self.on_status_icon_show_app_activate) menu.append(show_item) pause_item = Gtk.MenuItem(label=_("Pause/Resume")) pause_item.connect("activate", self.on_status_icon_pause_activate) menu.append(pause_item) next_item = Gtk.MenuItem(label=_("Next Song")) next_item.connect("activate", self.on_status_icon_next_activate) menu.append(next_item) sep_item = Gtk.SeparatorMenuItem() menu.append(sep_item) quit_item = Gtk.MenuItem(label=_("Quit")) quit_item.connect("activate", self.on_status_icon_quit_activate) menu.append(quit_item) menu.show_all() menu.popup( None, None, lambda a, b: Gtk.StatusIcon.position_menu(menu, status_icon), None, event_button, event_time ) def on_status_icon_show_app_activate(self, menuitem): self.window.present() def on_status_icon_pause_activate(self, menuitem): self.player.play_pause() def on_status_icon_next_activate(self, menuitem): self.player.load_next() def on_status_icon_quit_activate(self, menuitem): self.quit() def on_notebook_switch_page(self, notebook, page, page_num): if page not in self.tab_first_show: page.first() self.tab_first_show.append(page) if page_num == 0: # fullscreen self.player.hide() self.notebook.set_show_tabs(False) self.fullscreen_sid = self.window.connect("motion-notify-event", self.on_window_motion_notified) else: # unfullscreen self.player.show() self.notebook.set_show_tabs(True) self.fullscreen_sid = 0 def on_window_motion_notified(self, window, event): if self.notebook.get_current_page() != 0: return lower = 70 upper = self.window.get_size()[1] - 40 if lower < event.y < upper: return if event.y < lower: self.player.show_all() elif event.y > upper: self.notebook.set_show_tabs(True) # delay 2 seconds and hide them self.fullscreen_timestamp = time.time() GLib.timeout_add(100, self.player.playbin.expose) GLib.timeout_add(2000, self.hide_control_panel_and_label, self.fullscreen_timestamp) def hide_control_panel_and_label(self, timestamp): if timestamp == self.fullscreen_timestamp and self.fullscreen_sid > 0: self.notebook.set_show_tabs(False) self.player.hide() GLib.timeout_add(100, self.player.playbin.expose)
class App: def __init__(self): self.app = Gtk.Application.new(DBUS_APP_NAME, 0) self.app.connect('startup', self.on_app_startup) self.app.connect('activate', self.on_app_activate) self.app.connect('shutdown', self.on_app_shutdown) self.conf = Config.load_conf() self.theme, self.theme_path = Config.load_theme() def on_app_startup(self, app): self.window = Gtk.ApplicationWindow(application=app) self.window.set_default_size(*self.conf['window-size']) self.window.set_title(Config.APPNAME) self.window.props.hide_titlebar_when_maximized = True self.window.set_icon(self.theme['app-logo']) app.add_window(self.window) self.window.connect('check-resize', self.on_main_window_resized) self.window.connect('delete-event', self.on_main_window_deleted) self.accel_group = Gtk.AccelGroup() self.window.add_accel_group(self.accel_group) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.window.add(box) self.player = Player(self) box.pack_start(self.player, False, False, 0) self.notebook = Gtk.Notebook() self.notebook.props.tab_pos = Gtk.PositionType.BOTTOM self.notebook.get_style_context().add_class('main_tab') # Add 2 pix to left-margin to solve Fullscreen problem. #self.notebook.props.margin_left = 2 box.pack_start(self.notebook, True, True, 0) # signal should be connected after all pages in notebook # all added. self.init_notebook() self.notebook.connect('switch-page', self.on_notebook_switch_page) self.init_status_icon() # load styles self.load_styles() def on_app_activate(self, app): self.window.show_all() # make some changes after main window is shown. self.lrc.after_init() self.player.after_init() self.search.after_init() self.shortcut = Shortcut(self.player) def run(self, argv): self.app.run(argv) def quit(self): self.window.destroy() self.shortcut.quit() self.app.quit() def on_app_shutdown(self, app): Config.dump_conf(self.conf) def on_main_window_resized(self, window, event=None): self.conf['window-size'] = window.get_size() def on_main_window_deleted(self, window, event): if self.conf['use-status-icon']: window.hide() return True else: return False def init_notebook(self): self.lrc = Lrc(self) self.lrc.app_page = self.notebook.append_page( self.lrc, Gtk.Label(_('Lyrics'))) self.playlist = PlayList(self) self.playlist.app_page = self.notebook.append_page( self.playlist, Gtk.Label(_('Playlist'))) self.search = Search(self) self.search.app_page = self.notebook.append_page( self.search, Gtk.Label(_('Search'))) self.toplist = TopList(self) self.toplist.app_page = self.notebook.append_page( self.toplist, Gtk.Label(_('Top List'))) self.radio = Radio(self) self.radio.app_page = self.notebook.append_page( self.radio, Gtk.Label(_('Radio'))) self.mv = MV(self) self.mv.app_page = self.notebook.append_page( self.mv, Gtk.Label(_('MV'))) self.artists = Artists(self) self.artists.app_page = self.notebook.append_page( self.artists, Gtk.Label(_('Artists'))) self.topcategories = TopCategories(self) self.topcategories.app_page = self.notebook.append_page( self.topcategories, Gtk.Label(_('Categories'))) self.themes = Themes(self) self.themes.app_page = self.notebook.append_page( self.themes, Gtk.Label(_('Themes'))) def on_notebook_switch_page(self, notebook, page, page_num): page.first() def popup_page(self, page): self.notebook.set_current_page(page) def apply_css(self, widget, css, old_provider=None, overall=False): # CssProvider needs bytecode style_provider = Gtk.CssProvider() _css = css.encode() style_provider.load_from_data(_css) if overall: Gtk.StyleContext.add_provider_for_screen( Gdk.Screen.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) if old_provider is not None: Gtk.StyleContext.remove_provider_for_screen( Gdk.Screen.get_default(), style_provider) else: widget.get_style_context().add_provider(style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) if old_provider is not None: widget.get_style_context().remove_provider(old_provider) return style_provider def load_styles(self): font_size = str(int(self.conf['lrc-text-size'])) px = '' if Gtk.MINOR_VERSION > 6: px = 'px' css = '\n'.join([ 'GtkScrolledWindow.lrc_window {', 'transition-property: background-image;', 'transition-duration: 1s;', '}', 'GtkTextView.lrc_tv {', 'font-size: {0}{1};'.format(font_size, px), 'color: {0};'.format(self.conf['lrc-text-color']), 'border-radius: 0 25px 0 50px;', 'border-width: 5px;', 'background-color: {0};'.format( self.conf['lrc-back-color']), '}', '.info-label {', 'color: rgb(136, 139, 132);', 'font-size: 9{0};'.format(px), '}', ]) self.apply_css(self.window, css, overall=True) def init_status_icon(self): # set status_icon as class property, to keep its life # after function exited self.status_icon = Gtk.StatusIcon() self.status_icon.set_from_pixbuf(self.theme['app-logo']) # left click self.status_icon.connect('activate', self.on_status_icon_activate) # right click self.status_icon.connect('popup_menu', self.on_status_icon_popup_menu) def on_status_icon_activate(self, status_icon): is_visible = self.window.is_visible() if is_visible: self.window.hide() else: self.window.present() def on_status_icon_popup_menu(self, status_icon, event_button, event_time): menu = Gtk.Menu() show_item = Gtk.MenuItem(label=_('Show App') ) show_item.connect('activate', self.on_status_icon_show_app_activate) menu.append(show_item) pause_item = Gtk.MenuItem(label=_('Pause/Resume')) pause_item.connect('activate', self.on_status_icon_pause_activate) menu.append(pause_item) next_item = Gtk.MenuItem(label=_('Next Song')) next_item.connect('activate', self.on_status_icon_next_activate) menu.append(next_item) sep_item = Gtk.SeparatorMenuItem() menu.append(sep_item) quit_item = Gtk.MenuItem(label=_('Quit')) quit_item.connect('activate', self.on_status_icon_quit_activate) menu.append(quit_item) menu.show_all() menu.popup(None, None, lambda a,b: Gtk.StatusIcon.position_menu(menu, status_icon), None, event_button, event_time) def on_status_icon_show_app_activate(self, menuitem): self.window.present() def on_status_icon_pause_activate(self, menuitem): self.player.play_pause() def on_status_icon_next_activate(self, menuitem): self.player.load_next() def on_status_icon_quit_activate(self, menuitem): self.quit()
class App: def __init__(self): self.app = Gtk.Application.new(DBUS_APP_NAME, 0) self.app.connect('startup', self.on_app_startup) self.app.connect('activate', self.on_app_activate) self.app.connect('shutdown', self.on_app_shutdown) self.conf = Config.load_conf() self.theme, self.theme_path = Config.load_theme() def on_app_startup(self, app): self.window = Gtk.ApplicationWindow(application=app) self.window.set_default_size(*self.conf['window-size']) self.window.set_title(Config.APPNAME) self.window.props.hide_titlebar_when_maximized = True self.window.set_icon(self.theme['app-logo']) app.add_window(self.window) self.window.connect('check-resize', self.on_main_window_resized) self.window.connect('delete-event', self.on_main_window_deleted) self.accel_group = Gtk.AccelGroup() self.window.add_accel_group(self.accel_group) self.fullscreen_sid = 0 self.fullscreen_timestamp = 0 box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) self.window.add(box) self.player = Player(self) box.pack_start(self.player, False, False, 0) self.notebook = Gtk.Notebook() self.notebook.props.tab_pos = Gtk.PositionType.BOTTOM self.notebook.get_style_context().add_class('main_tab') box.pack_start(self.notebook, True, True, 0) self.init_notebook() self.notebook.connect('switch-page', self.on_notebook_switch_page) self.init_status_icon() # load default styles when all widgets have been constructed. self.load_styles() def on_app_activate(self, app): self.window.show_all() # Make some changes after main window is shown. # Like hiding some unnecessory widgets. self.lrc.after_init() self.artists.after_init() self.player.after_init() self.search.after_init() self.shortcut = Shortcut(self.player) def on_app_shutdown(self, app): Config.dump_conf(self.conf) def run(self, argv): self.app.run(argv) def quit(self): gdk_win = self.window.get_window() if gdk_win and not gdk_win.is_destroyed(): self.window.destroy() self.shortcut.quit() self.app.quit() def on_main_window_resized(self, window, event=None): self.conf['window-size'] = window.get_size() def on_main_window_deleted(self, window, event): if self.conf['use-status-icon']: window.hide() return True else: return False def init_notebook(self): self.tab_first_show = [] self.lrc = Lrc(self) self.append_page(self.lrc) self.playlist = PlayList(self) self.append_page(self.playlist) self.search = Search(self) self.append_page(self.search) self.toplist = TopList(self) self.append_page(self.toplist) self.radio = Radio(self) self.append_page(self.radio) self.mv = MV(self) self.append_page(self.mv) self.artists = Artists(self) self.append_page(self.artists) self.topcategories = TopCategories(self) self.append_page(self.topcategories) self.themes = Themes(self) self.append_page(self.themes) def append_page(self, widget): '''Append a new widget to notebook.''' label = Gtk.Label(widget.title) widget.app_page = self.notebook.append_page(widget, label) def popup_page(self, page): '''Switch to this widget in notebook.''' self.notebook.set_current_page(page) def apply_css(self, widget, css, old_provider=None, overall=False): '''Update CssProvider of this widget.''' # CssProvider needs bytecode style_provider = Gtk.CssProvider() css_encoded = css.encode() style_provider.load_from_data(css_encoded) if overall: Gtk.StyleContext.add_provider_for_screen( Gdk.Screen.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) if old_provider: Gtk.StyleContext.remove_provider_for_screen( Gdk.Screen.get_default(), style_provider) else: widget.get_style_context().add_provider( style_provider,Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) if old_provider: widget.get_style_context().remove_provider(old_provider) return style_provider def load_styles(self): '''Load default CssStyle.''' if Config.GTK_LE_36: css = '\n'.join([ # transition-property is not supported in Gtk3.4 #'GtkScrolledWindow.lrc_window {', # 'transition-property: background-image;', # 'transition-duration: 1s;', # '}', 'GtkScale {', 'outline-color: transparent;', 'outline-offset: 0;', 'outline-style: none;', 'outline-width: 0;', '}', 'GtkTextView.lrc_tv {', 'font-size: {0};'.format(self.conf['lrc-text-size']), 'color: {0};'.format(self.conf['lrc-text-color']), 'border-radius: 0 25 0 50;', 'border-width: 5;', 'background-color: {0};'.format( self.conf['lrc-back-color']), '}', '.info-label {', 'color: rgb(136, 139, 132);', 'font-size: 9;', '}', ]) else: css = '\n'.join([ 'GtkScrolledWindow.lrc_window {', 'transition-property: background-image;', 'transition-duration: 1s;', #'background-repeat: no-repeat;', #'background-repeat: repeat;', #'background-position: center;', '}', 'GtkScale {', 'outline-color: transparent;', 'outline-offset: 0;', 'outline-style: none;', 'outline-width: 0;', '}', 'GtkTextView.lrc_tv {', 'font-size: {0}px;'.format(self.conf['lrc-text-size']), 'color: {0};'.format(self.conf['lrc-text-color']), 'border-radius: 0px 25px 0px 50px;', 'border-width: 5px;', 'background-color: {0};'.format( self.conf['lrc-back-color']), '}', '.info-label {', 'color: rgb(136, 139, 132);', 'font-size: 9px;', '}', ]) self.apply_css(self.window, css, overall=True) settings = Gtk.Settings.get_default() settings.props.gtk_application_prefer_dark_theme = \ self.conf.get('use-dark-theme', False) def init_status_icon(self): # set status_icon as class property, to keep its life # after function exited self.status_icon = Gtk.StatusIcon() self.status_icon.set_from_pixbuf(self.theme['app-logo']) # left click self.status_icon.connect('activate', self.on_status_icon_activate) # right click self.status_icon.connect('popup_menu', self.on_status_icon_popup_menu) def on_status_icon_activate(self, status_icon): if self.window.props.visible: self.window.hide() else: self.window.present() def on_status_icon_popup_menu(self, status_icon, event_button, event_time): menu = Gtk.Menu() show_item = Gtk.MenuItem(label=_('Show App') ) show_item.connect('activate', self.on_status_icon_show_app_activate) menu.append(show_item) pause_item = Gtk.MenuItem(label=_('Pause/Resume')) pause_item.connect('activate', self.on_status_icon_pause_activate) menu.append(pause_item) next_item = Gtk.MenuItem(label=_('Next Song')) next_item.connect('activate', self.on_status_icon_next_activate) menu.append(next_item) sep_item = Gtk.SeparatorMenuItem() menu.append(sep_item) quit_item = Gtk.MenuItem(label=_('Quit')) quit_item.connect('activate', self.on_status_icon_quit_activate) menu.append(quit_item) menu.show_all() menu.popup(None, None, lambda a,b: Gtk.StatusIcon.position_menu(menu, status_icon), None, event_button, event_time) def on_status_icon_show_app_activate(self, menuitem): self.window.present() def on_status_icon_pause_activate(self, menuitem): self.player.play_pause() def on_status_icon_next_activate(self, menuitem): self.player.load_next() def on_status_icon_quit_activate(self, menuitem): self.quit() def on_notebook_switch_page(self, notebook, page, page_num): if page not in self.tab_first_show: page.first() self.tab_first_show.append(page) if page_num == 0: # fullscreen self.player.hide() self.notebook.set_show_tabs(False) self.fullscreen_sid = self.window.connect( 'motion-notify-event', self.on_window_motion_notified) else: # unfullscreen self.player.show() self.notebook.set_show_tabs(True) self.fullscreen_sid = 0 def on_window_motion_notified(self, window, event): if self.notebook.get_current_page() != 0: return lower = 70 upper = self.window.get_size()[1] - 40 if lower < event.y < upper: return if event.y < lower: self.player.show_all() elif event.y > upper: self.notebook.set_show_tabs(True) # delay 2 seconds and hide them self.fullscreen_timestamp = time.time() GLib.timeout_add(100, self.player.playbin.expose) GLib.timeout_add( 2000, self.hide_control_panel_and_label, self.fullscreen_timestamp) def hide_control_panel_and_label(self, timestamp): if (timestamp == self.fullscreen_timestamp and self.fullscreen_sid > 0): self.notebook.set_show_tabs(False) self.player.hide() GLib.timeout_add(100, self.player.playbin.expose)