diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ef2f8a..fbe69fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.6) project(xmradio) -set(version 0.4.3) +set(version 0.4.4) set(XMR_CMAKE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH ${XMR_CMAKE_PATH} ${CMAKE_MODULE_PATH}) @@ -34,6 +34,7 @@ include(FindPkgConfig) check_include_files(unistd.h HAVE_UNISTD_H) check_include_files(malloc.h HAVE_MALLOC_H) +check_include_files(X11/XF86keysym.h HAVE_MMKEYS_H) find_program(GLIB_GENMARSHAL NAMES glib-genmarshal diff --git a/config.h.in b/config.h.in index 93ea708..1831ffd 100644 --- a/config.h.in +++ b/config.h.in @@ -3,6 +3,7 @@ #cmakedefine HAVE_UNISTD_H #cmakedefine HAVE_MALLOC_H +#cmakedefine HAVE_MMKEYS_H #cmakedefine ENABLE_NLS #cmakedefine _DEBUG diff --git a/data/com.timxx.xmradio.gschema.xml b/data/com.timxx.xmradio.gschema.xml index fbe1b38..cdb46b8 100644 --- a/data/com.timxx.xmradio.gschema.xml +++ b/data/com.timxx.xmradio.gschema.xml @@ -50,10 +50,15 @@ Whether keep window on top Set true to keep window always on top + + false + Asks to stick window + Set true to make window appear on all user desktops + - ['notification', 'indicator', 'mpris', 'xmsearch'] + ['notification', 'indicator', 'mpris', 'xmsearch', 'xmrmmkeys'] Active plugins List of active plugins. diff --git a/data/ui/pref.ui b/data/ui/pref.ui index e13e06d..0a7ae7a 100644 --- a/data/ui/pref.ui +++ b/data/ui/pref.ui @@ -22,6 +22,21 @@ 0 + + + Show window on all desktops + True + False + False + 0 + True + + + False + True + 1 + + True diff --git a/debian/changelog b/debian/changelog index 3d0cde0..18c0cf9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,27 @@ +xmradio (0.4.4~raring) raring; urgency=low + + * 0.4.4 + - New plugin: xmrmmkeys + - New option: stick window + + -- Weitian Leung Sun, 14 Jul 2013 17:03:41 +0800 + +xmradio (0.4.4~quantal) quantal; urgency=low + + * 0.4.4 + - New plugin: xmrmmkeys + - New option: stick window + + -- Weitian Leung Sun, 14 Jul 2013 17:03:02 +0800 + +xmradio (0.4.4~precise) precise; urgency=low + + * 0.4.4 + - New plugin: xmrmmkeys + - New option: stick window + + -- Weitian Leung Sun, 14 Jul 2013 17:01:14 +0800 + xmradio (0.4.3~raring) raring; urgency=low * 0.4.3 diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 9bdfeb8..93907b2 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(indicator) add_subdirectory(mpris) add_subdirectory(autocollect) add_subdirectory(xmsearch) +add_subdirectory(xmrmmkeys) set(plugins notification @@ -10,6 +11,7 @@ set(plugins mpris autocollect xmsearch + xmrmmkeys ) # Generate plugin data files to diff --git a/plugins/xmrmmkeys/CMakeLists.txt b/plugins/xmrmmkeys/CMakeLists.txt new file mode 100644 index 0000000..95d61db --- /dev/null +++ b/plugins/xmrmmkeys/CMakeLists.txt @@ -0,0 +1,18 @@ +set(XMRMMKEYS_SOURCES + xmrmmkeys.c +) + +include_directories(${LIBPEAS_INCLUDE_DIRS}) +include_directories(${PLUGIN_INCLUDE_DIR}) +include_directories(${PROJECT_SOURCE_DIR}/src) +include_directories(${GTK3_INCLUDE_DIRS}) +include_directories(${GSTREAMER_INCLUDE_DIRS}) + +add_library(xmrmmkeys SHARED ${XMRMMKEYS_SOURCES}) +target_link_libraries(xmrmmkeys + ${LIBPEAS_LIBRARIES} +) + +install(TARGETS xmrmmkeys LIBRARY DESTINATION ${plugindir}) +install(FILES xmrmmkeys.plugin DESTINATION ${plugindir}) + diff --git a/plugins/xmrmmkeys/xmrmmkeys.c b/plugins/xmrmmkeys/xmrmmkeys.c new file mode 100644 index 0000000..44277a3 --- /dev/null +++ b/plugins/xmrmmkeys/xmrmmkeys.c @@ -0,0 +1,445 @@ +/** + * xmrmmkeys.c + * + * Copyright (C) 2013 Weitian Leung (weitianleung@gmail.com) + + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * source refer to Rhythmbox's mmkeys plugin + */ + +#include + +#include "xmrplugin.h" +#include "xmrwindow.h" +#include "xmrplayer.h" +#include "xmrdebug.h" +#include "config.h" + +#ifdef HAVE_MMKEYS_H +#include +#include +#endif + +#define XMR_TYPE_MMKEYS_PLUGIN (xmr_mmkeys_plugin_get_type()) +#define XMR_MMKEYS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST((o), XMR_TYPE_MMKEYS_PLUGIN, XmrMMKeysPlugin)) +#define XMR_MMKEYS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), XMR_TYPE_MMKEYS_PLUGIN, XmrMMKeysPluginClass)) +#define XMR_IS_MMKEYS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), XMR_TYPE_MMKEYS_PLUGIN)) +#define XMR_IS_MMKEYS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), XMR_TYPE_MMKEYS_PLUGIN)) +#define XMR_MMKEYS_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), XMR_TYPE_MMKEYS_PLUGIN, XmrMMKeysPluginClass)) + +typedef struct +{ + PeasExtensionBase parent; + XmrWindow *window; + + enum + { + NONE = 0, + SETTINGS_DAEMON, + X_KEY_GRAB + } grab_type; + + GDBusProxy *proxy; +}XmrMMKeysPlugin; + +typedef struct +{ + PeasExtensionBaseClass parent_class; +}XmrMMKeysPluginClass; + +XMR_DEFINE_PLUGIN(XMR_TYPE_MMKEYS_PLUGIN, XmrMMKeysPlugin, xmr_mmkeys_plugin,) + +static void +media_player_key_pressed(GDBusProxy *proxy, + const gchar *sender, + const gchar *signal, + GVariant *parameters, + XmrMMKeysPlugin *plugin) +{ + gchar *key; + gchar *application; + + g_variant_get(parameters, "(ss)", &application, &key); + + if (g_strcmp0(application, PACKAGE)) + { + xmr_debug("got media player key signal for unexpected application '%s'", application); + return; + } + + if (g_strcmp0(key, "Play") == 0 || + g_strcmp0(key, "Pause") == 0) + { + if (xmr_window_playing(plugin->window)) + xmr_window_pause(plugin->window); + else + xmr_window_play(plugin->window); + } + else if (g_strcmp0(key, "Stop") == 0) + { + xmr_window_pause(plugin->window); + } + else if (g_strcmp0(key, "Next") == 0) + { + xmr_window_play_next(plugin->window); + } + + g_free(key); + g_free(application); +} + +static void +grab_call_complete(GObject *proxy, GAsyncResult *res, XmrMMKeysPlugin *plugin) +{ + GError *error = NULL; + GVariant *result; + + result = g_dbus_proxy_call_finish(G_DBUS_PROXY(proxy), res, &error); + if (error != NULL) + { + xmr_debug("Unable to grab media player keys: %s", error->message); + g_clear_error(&error); + } + else + { + g_variant_unref(result); + } +} + +static gboolean +window_focus_cb(GtkWidget *window, + GdkEventFocus *event, + XmrMMKeysPlugin *plugin) +{ + g_dbus_proxy_call(plugin->proxy, + "GrabMediaPlayerKeys", + g_variant_new("(su)", PACKAGE, 0), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + (GAsyncReadyCallback)grab_call_complete, + plugin); + return FALSE; +} + +#ifdef HAVE_MMKEYS_H + +static void +grab_mmkey(int key_code, GdkWindow *root) +{ + Display *display; + gdk_error_trap_push(); + + display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default ()); + XGrabKey(display, key_code, + 0, + GDK_WINDOW_XID(root), True, + GrabModeAsync, GrabModeAsync); + XGrabKey(display, key_code, + Mod2Mask, + GDK_WINDOW_XID(root), True, + GrabModeAsync, GrabModeAsync); + XGrabKey(display, key_code, + Mod5Mask, + GDK_WINDOW_XID(root), True, + GrabModeAsync, GrabModeAsync); + XGrabKey(display, key_code, + LockMask, + GDK_WINDOW_XID(root), True, + GrabModeAsync, GrabModeAsync); + XGrabKey(display, key_code, + Mod2Mask | Mod5Mask, + GDK_WINDOW_XID(root), True, + GrabModeAsync, GrabModeAsync); + XGrabKey(display, key_code, + Mod2Mask | LockMask, + GDK_WINDOW_XID(root), True, + GrabModeAsync, GrabModeAsync); + XGrabKey(display, key_code, + Mod5Mask | LockMask, + GDK_WINDOW_XID(root), True, + GrabModeAsync, GrabModeAsync); + XGrabKey(display, key_code, + Mod2Mask | Mod5Mask | LockMask, + GDK_WINDOW_XID(root), True, + GrabModeAsync, GrabModeAsync); + + gdk_flush(); + + if (gdk_error_trap_pop()) + { + xmr_debug("Error grabbing key"); + } +} + +static void +ungrab_mmkey(int key_code, GdkWindow *root) +{ + Display *display; + gdk_error_trap_push(); + + display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); + XUngrabKey(display, key_code, 0, GDK_WINDOW_XID(root)); + XUngrabKey(display, key_code, Mod2Mask, GDK_WINDOW_XID(root)); + XUngrabKey(display, key_code, Mod5Mask, GDK_WINDOW_XID(root)); + XUngrabKey(display, key_code, LockMask, GDK_WINDOW_XID(root)); + XUngrabKey(display, key_code, Mod2Mask | Mod5Mask, GDK_WINDOW_XID(root)); + XUngrabKey(display, key_code, Mod2Mask | LockMask, GDK_WINDOW_XID(root)); + XUngrabKey(display, key_code, Mod5Mask | LockMask, GDK_WINDOW_XID(root)); + XUngrabKey(display, key_code, Mod2Mask | Mod5Mask | LockMask, GDK_WINDOW_XID(root)); + + gdk_flush(); + + if (gdk_error_trap_pop ()) + { + xmr_debug("Error grabbing key"); + } +} + + +static GdkFilterReturn +filter_mmkeys(GdkXEvent *xevent, + GdkEvent *event, + gpointer data) +{ + XEvent *xev; + XKeyEvent *key; + Display *display; + XmrWindow *window; + + GdkFilterReturn retv = GDK_FILTER_CONTINUE; + + xev = (XEvent *)xevent; + + if (xev->type != KeyPress) + return GDK_FILTER_CONTINUE; + + key = (XKeyEvent *)xevent; + + window = (XmrWindow *)data; + display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); + + if (XKeysymToKeycode(display, XF86XK_AudioPlay) == key->keycode || + XKeysymToKeycode(display, XF86XK_AudioPause) == key->keycode) + { + if (xmr_window_playing(window)) + xmr_window_pause(window); + else + xmr_window_play(window); + retv = GDK_FILTER_REMOVE; + } + else if (XKeysymToKeycode (display, XF86XK_AudioStop) == key->keycode) + { + xmr_window_pause(window); + retv = GDK_FILTER_REMOVE; + } + else if (XKeysymToKeycode (display, XF86XK_AudioNext) == key->keycode) + { + xmr_window_play_next(window); + retv = GDK_FILTER_REMOVE; + } + + return retv; +} + +static void +mmkeys_grab(XmrMMKeysPlugin *plugin, gboolean grab) +{ + gint keycodes[] = {0, 0, 0, 0, 0}; + GdkDisplay *display; + + guint i, j; + + display = gdk_display_get_default(); + keycodes[0] = XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(display), XF86XK_AudioPlay); + keycodes[1] = XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(display), XF86XK_AudioStop); + keycodes[2] = XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(display), XF86XK_AudioPrev); + keycodes[3] = XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(display), XF86XK_AudioNext); + keycodes[4] = XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(display), XF86XK_AudioPause); + + for (i = 0; i < gdk_display_get_n_screens(display); ++i) + { + GdkScreen *screen = gdk_display_get_screen(display, i); + + if (screen != NULL) + { + GdkWindow *root = gdk_screen_get_root_window (screen); + + for (j = 0; j < G_N_ELEMENTS(keycodes); ++j) + { + if (keycodes[j] != 0) + { + if (grab) + grab_mmkey(keycodes[j], root); + else + ungrab_mmkey(keycodes[j], root); + } + } + + if (grab) + gdk_window_add_filter(root, filter_mmkeys, (gpointer)plugin->window); + else + gdk_window_remove_filter(root, filter_mmkeys, (gpointer) plugin->window); + } + } +} + +#endif // HAVE_MMKEYS_H + +static void +first_call_complete(GObject *proxy, GAsyncResult *res, XmrMMKeysPlugin *plugin) +{ + GVariant *result; + GError *error = NULL; + + result = g_dbus_proxy_call_finish(G_DBUS_PROXY(proxy), res, &error); + if (error != NULL) + { + xmr_debug("Unable to grab media player keys: %s", error->message); + g_clear_error(&error); +#ifdef HAVE_MMKEYS_H + mmkeys_grab(plugin, TRUE); + plugin->grab_type = X_KEY_GRAB; +#endif + return; + } + + g_signal_connect_object(plugin->proxy, "g-signal", G_CALLBACK(media_player_key_pressed), plugin, 0); + + /* re-grab keys when the main window gains focus */ + g_signal_connect_object(plugin->window, "focus-in-event", + G_CALLBACK(window_focus_cb), + plugin, 0); + + g_variant_unref(result); +} + +static void +final_call_complete(GObject *proxy, GAsyncResult *res, gpointer nothing) +{ + GError *error = NULL; + GVariant *result; + + result = g_dbus_proxy_call_finish(G_DBUS_PROXY (proxy), res, &error); + if (error != NULL) + { + xmr_debug("Unable to release media player keys: %s", error->message); + g_clear_error (&error); + } + else + { + g_variant_unref(result); + } +} + + +static void +impl_activate(PeasActivatable *activatable) +{ + XmrMMKeysPlugin *plugin; + GDBusConnection *bus; + GError *error = NULL; + + plugin = XMR_MMKEYS_PLUGIN(activatable); + plugin->grab_type = NONE; + + g_object_get(plugin, "object", &plugin->window, NULL); + + bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error); + if (bus == NULL) + { + xmr_debug("g_bus_get_sync failed: %s", error->message); + g_clear_error(&error); + } + else + { + plugin->proxy = g_dbus_proxy_new_sync(bus, G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon", + "/org/gnome/SettingsDaemon/MediaKeys", + "org.gnome.SettingsDaemon.MediaKeys", + NULL, &error); + if (error != NULL) + { + xmr_debug("Unable to grab media player keys: %s", error->message); + } + else + { + g_dbus_proxy_call(plugin->proxy, "GrabMediaPlayerKeys", + g_variant_new("(su)", PACKAGE, 0), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, + (GAsyncReadyCallback)first_call_complete, + plugin); + + plugin->grab_type = SETTINGS_DAEMON; + } + } + +#ifdef HAVE_MMKEYS_H + if (plugin->grab_type == NONE) + { + mmkeys_grab(plugin, TRUE); + plugin->grab_type = X_KEY_GRAB; + } +#endif +} + +static void +impl_deactivate(PeasActivatable *activatable) +{ + XmrMMKeysPlugin *plugin; + + plugin = XMR_MMKEYS_PLUGIN(activatable); + + if (plugin->proxy != NULL) + { + g_dbus_proxy_call(plugin->proxy, + "ReleaseMediaPlayerKeys", + g_variant_new("(s)", PACKAGE), + G_DBUS_CALL_FLAGS_NONE, + -1, NULL, + (GAsyncReadyCallback)final_call_complete, + NULL); + + g_object_unref(plugin->proxy); + plugin->proxy = NULL; + } + +#ifdef HAVE_MMKEYS_H + if (plugin->grab_type == X_KEY_GRAB) + mmkeys_grab(plugin, FALSE); +#endif + + plugin->grab_type = NONE; + g_object_unref(plugin->window); +} + +static void +xmr_mmkeys_plugin_init(XmrMMKeysPlugin *plugin) +{ +} + +G_MODULE_EXPORT void +peas_register_types(PeasObjectModule *module) +{ + xmr_mmkeys_plugin_register_type(G_TYPE_MODULE(module)); + peas_object_module_register_extension_type(module, + PEAS_TYPE_ACTIVATABLE, + XMR_TYPE_MMKEYS_PLUGIN); +} + diff --git a/plugins/xmrmmkeys/xmrmmkeys.plugin b/plugins/xmrmmkeys/xmrmmkeys.plugin new file mode 100644 index 0000000..5324d92 --- /dev/null +++ b/plugins/xmrmmkeys/xmrmmkeys.plugin @@ -0,0 +1,8 @@ +[Plugin] +Module=xmrmmkeys +IAge=2 +Name=Media Player Keys +Description=Multimedia keys for xmradio +Authors=Weitian Leung +Copyright=Copyright © 2013 Weitian Leung +Website=https://github.com/timxx/xmradio diff --git a/po/xmradio.pot b/po/xmradio.pot index dce746e..a6e8469 100644 --- a/po/xmradio.pot +++ b/po/xmradio.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: xmradio 0.4.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-06-20 10:23+0800\n" +"POT-Creation-Date: 2013-07-14 16:34+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -51,37 +51,32 @@ msgstr "" msgid "Hate" msgstr "" -#: plugins/autocollect/xmr-auto-collect.ui:61 -msgid "Auto Like when play time percentage greater than" -msgstr "" - -#: plugins/autocollect/xmr-auto-collect.ui:138 -msgid "Auto Hate when play time percentage little than" +#: data/ui/pref.ui:12 +msgid "Use GStreamer buffering" msgstr "" -#: plugins/autocollect/xmr-auto-collect.ui:199 -msgid "You need to loggin before use this plugin" +#: data/ui/pref.ui:27 +msgid "Show window on all desktops" msgstr "" -#: data/ui/login.ui:7 -msgid "Login Info" +#: data/ui/pref.ui:76 +msgid "Version: " msgstr "" -#: data/ui/login.ui:37 src/xmrwindow.c:2387 src/xmrwindow.c:2908 -#: src/xmrwindow.c:3000 -msgid "Login" +#: data/ui/pref.ui:115 +msgid "Author: " msgstr "" -#: data/ui/login.ui:74 -msgid "User Name:" +#: data/ui/pref.ui:154 +msgid "URL: " msgstr "" -#: data/ui/login.ui:87 -msgid "Password:" +#: data/ui/pref.ui:194 +msgid "Email: " msgstr "" -#: data/ui/login.ui:140 -msgid "Auto Login" +#: data/ui/pref.ui:230 +msgid "Preferences" msgstr "" #: data/ui/about.ui:7 @@ -98,59 +93,37 @@ msgid "" "For more information see www.xiami.com/radio" msgstr "" -#: data/ui/pref.ui:12 -msgid "Use GStreamer buffering" -msgstr "" - -#: data/ui/pref.ui:61 -msgid "Version: " -msgstr "" - -#: data/ui/pref.ui:100 -msgid "Author: " -msgstr "" - -#: data/ui/pref.ui:139 -msgid "URL: " -msgstr "" - -#: data/ui/pref.ui:179 -msgid "Email: " -msgstr "" - -#: data/ui/pref.ui:215 -msgid "Preferences" +#: data/ui/login.ui:7 +msgid "Login Info" msgstr "" -#: src/xmrplayer.c:367 -msgid "Failed to create playbin2 element; check your GStreamer installation" +#: data/ui/login.ui:37 src/xmrwindow.c:2387 src/xmrwindow.c:2914 +#: src/xmrwindow.c:3006 +msgid "Login" msgstr "" -#: src/xmrsearchbox.c:134 -msgid "Oops! Not found any related artist." +#: data/ui/login.ui:74 +msgid "User Name:" msgstr "" -#: src/xmrsearchbox.c:138 -msgid "Oops! Network error." +#: data/ui/login.ui:87 +msgid "Password:" msgstr "" -#: src/xmrsearchbox.c:528 src/xmrsearchbox.c:615 -msgid "Artist Radio" +#: data/ui/login.ui:140 +msgid "Auto Login" msgstr "" -#: src/xmrsearchbox.c:540 -msgid "Enter artist name..." +#: plugins/autocollect/xmr-auto-collect.ui:61 +msgid "Auto Like when play time percentage greater than" msgstr "" -#: src/xmrsearchbox.c:544 -msgid "Search Artist Radio" +#: plugins/autocollect/xmr-auto-collect.ui:138 +msgid "Auto Hate when play time percentage little than" msgstr "" -#: src/main.c:144 -#, c-format -msgid "" -"%s\n" -"Run '%s --help' to see a full list of available command line options.\n" +#: plugins/autocollect/xmr-auto-collect.ui:199 +msgid "You need to loggin before use this plugin" msgstr "" #: src/xmrlist.c:226 @@ -189,18 +162,11 @@ msgstr "" msgid "Search result" msgstr "" -#: src/xmrdownloader.c:187 -msgid "curl_easy_init failed" -msgstr "" - -#: src/xmrdownloader.c:199 -#, c-format -msgid "Unable to write file: %s" -msgstr "" - -#: src/xmrdownloader.c:227 +#: src/main.c:144 #, c-format -msgid "curl_easy_perform failed: %s" +msgid "" +"%s\n" +"Run '%s --help' to see a full list of available command line options.\n" msgstr "" #: src/xmrwindow.c:55 @@ -255,41 +221,79 @@ msgstr "" msgid "Always on _Top" msgstr "" -#: src/xmrwindow.c:2391 src/xmrwindow.c:2978 +#: src/xmrwindow.c:2391 src/xmrwindow.c:2984 msgid "Logout" msgstr "" -#: src/xmrwindow.c:2828 +#: src/xmrwindow.c:2831 msgid "Skin" msgstr "" -#: src/xmrwindow.c:2833 +#: src/xmrwindow.c:2836 msgid "Plugins" msgstr "" -#: src/xmrwindow.c:2837 +#: src/xmrwindow.c:2840 msgid "Other" msgstr "" -#: src/xmrwindow.c:2845 src/xmrwindow.c:3123 +#: src/xmrwindow.c:2848 src/xmrwindow.c:3129 msgid "Gtk Theme" msgstr "" -#: src/xmrwindow.c:2999 +#: src/xmrwindow.c:3005 msgid "User name and password may not empty" msgstr "" -#: src/xmrwindow.c:3451 +#: src/xmrwindow.c:3457 #, c-format msgid "" "Login failed:\n" "%s" msgstr "" -#: src/xmrwindow.c:3454 +#: src/xmrwindow.c:3460 msgid "Login Status" msgstr "" +#: src/xmrdownloader.c:187 +msgid "curl_easy_init failed" +msgstr "" + +#: src/xmrdownloader.c:199 +#, c-format +msgid "Unable to write file: %s" +msgstr "" + +#: src/xmrdownloader.c:227 +#, c-format +msgid "curl_easy_perform failed: %s" +msgstr "" + +#: src/xmrplayer.c:367 +msgid "Failed to create playbin2 element; check your GStreamer installation" +msgstr "" + +#: src/xmrsearchbox.c:134 +msgid "Oops! Not found any related artist." +msgstr "" + +#: src/xmrsearchbox.c:138 +msgid "Oops! Network error." +msgstr "" + +#: src/xmrsearchbox.c:528 src/xmrsearchbox.c:615 +msgid "Artist Radio" +msgstr "" + +#: src/xmrsearchbox.c:540 +msgid "Enter artist name..." +msgstr "" + +#: src/xmrsearchbox.c:544 +msgid "Search Artist Radio" +msgstr "" + #: plugins/xmsearch/xmsearch.c:150 msgid "XiaMi" msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index 7a2d12c..c2140b9 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: xmradio 0.4.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-06-20 10:23+0800\n" -"PO-Revision-Date: 2013-06-20 10:32+0800\n" +"POT-Creation-Date: 2013-07-14 16:34+0800\n" +"PO-Revision-Date: 2013-07-14 16:38+0800\n" "Last-Translator: Weitian Leung \n" "Language-Team: LANGUAGE \n" "Language: zh_CN\n" @@ -54,7 +54,7 @@ msgstr "艺人" msgid "Artist Radio" msgstr "艺人电台" -#: data/ui/pref.ui:100 +#: data/ui/pref.ui:115 msgid "Author: " msgstr "作者:" @@ -78,7 +78,7 @@ msgstr "正在缓冲..." msgid "Copyright @ 2012-2013 Weitian Leung" msgstr "" -#: data/ui/pref.ui:179 +#: data/ui/pref.ui:194 msgid "Email: " msgstr "邮件:" @@ -98,7 +98,7 @@ msgstr "来自" msgid "Getting playlist..." msgstr "正在获取播放列表..." -#: src/xmrwindow.c:2845 src/xmrwindow.c:3123 +#: src/xmrwindow.c:2848 src/xmrwindow.c:3129 msgid "Gtk Theme" msgstr "GTK主题" @@ -115,8 +115,8 @@ msgstr "关闭时隐藏程序到后台运行" msgid "Invert Selection" msgstr "反选" -#: data/ui/login.ui:37 src/xmrwindow.c:2387 src/xmrwindow.c:2908 -#: src/xmrwindow.c:3000 +#: data/ui/login.ui:37 src/xmrwindow.c:2387 src/xmrwindow.c:2914 +#: src/xmrwindow.c:3006 msgid "Login" msgstr "登陆" @@ -124,11 +124,11 @@ msgstr "登陆" msgid "Login Info" msgstr "登陆信息" -#: src/xmrwindow.c:3454 +#: src/xmrwindow.c:3460 msgid "Login Status" msgstr "登陆状态" -#: src/xmrwindow.c:3451 +#: src/xmrwindow.c:3457 #, c-format msgid "" "Login failed:\n" @@ -141,7 +141,7 @@ msgstr "" msgid "Login..." msgstr "正在登陆..." -#: src/xmrwindow.c:2391 src/xmrwindow.c:2978 +#: src/xmrwindow.c:2391 src/xmrwindow.c:2984 msgid "Logout" msgstr "注销" @@ -170,7 +170,7 @@ msgstr "网络出错啦。" msgid "Oops! Not found any related artist." msgstr "未找到相关的艺人。" -#: src/xmrwindow.c:2837 +#: src/xmrwindow.c:2840 msgid "Other" msgstr "其它" @@ -190,11 +190,11 @@ msgstr "播放" msgid "Playlist" msgstr "播放列表" -#: src/xmrwindow.c:2833 +#: src/xmrwindow.c:2836 msgid "Plugins" msgstr "插件" -#: data/ui/pref.ui:215 +#: data/ui/pref.ui:230 msgid "Preferences" msgstr "首选项" @@ -215,7 +215,11 @@ msgstr "全选" msgid "Show" msgstr "显示" -#: src/xmrwindow.c:2828 +#: data/ui/pref.ui:27 +msgid "Show window on all desktops" +msgstr "在所有桌面上显示窗口" + +#: src/xmrwindow.c:2831 msgid "Skin" msgstr "皮肤" @@ -223,7 +227,7 @@ msgstr "皮肤" msgid "Song Name" msgstr "歌曲" -#: data/ui/pref.ui:139 +#: data/ui/pref.ui:154 msgid "URL: " msgstr "网址:" @@ -240,11 +244,11 @@ msgstr "使用GStreamer内部缓冲机制" msgid "User Name:" msgstr "用户名:" -#: src/xmrwindow.c:2999 +#: src/xmrwindow.c:3005 msgid "User name and password may not empty" msgstr "用户名、密码不为空" -#: data/ui/pref.ui:61 +#: data/ui/pref.ui:76 msgid "Version: " msgstr "版本:" diff --git a/src/xmrwindow.c b/src/xmrwindow.c index 4dd40c4..08bbb65 100644 --- a/src/xmrwindow.c +++ b/src/xmrwindow.c @@ -2550,6 +2550,9 @@ load_settings(XmrWindow *window) gtk_window_set_keep_above(GTK_WINDOW(window), g_settings_get_boolean(G_SETTINGS(priv->settings), "ontop")); + + if (g_settings_get_boolean(G_SETTINGS(priv->settings), "stick-window")) + gtk_window_stick(GTK_WINDOW(window)); xmr_settings_get_usr_info(priv->settings, &priv->usr, &priv->pwd); if (xmr_settings_get_auto_login(priv->settings)) @@ -2847,6 +2850,9 @@ init_pref_window(XmrWindow *window, g_signal_connect(widget, "changed", G_CALLBACK(on_combo_box_changed), window); } + + widget = GTK_WIDGET(gtk_builder_get_object(priv->ui_pref, "cbStick")); + g_settings_bind(G_SETTINGS(priv->settings), "stick-window", widget, "active", G_SETTINGS_BIND_DEFAULT); } static void @@ -4036,6 +4042,14 @@ on_settings_changed(GSettings *settings, gboolean active = g_settings_get_boolean(settings, key); gtk_window_set_keep_above(GTK_WINDOW(window), active); } + else if (g_strcmp0(key, "stick-window") == 0) + { + gboolean active = g_settings_get_boolean(settings, key); + if (active) + gtk_window_stick(GTK_WINDOW(window)); + else + gtk_window_unstick(GTK_WINDOW(window)); + } } static gboolean