diff --git a/Makefile.am b/Makefile.am index b6ca254..1189184 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,6 +6,9 @@ ACLOCAL_AMFLAGS = -Wno-portability EXTRA_DIST += TODO SUBDIRS = src docs +desktopdir = $(datadir)/applications +dist_desktop_DATA = gst123.desktop + # === Release auxillary rule configuration === RELEASE_DESTHOST = space.twc.de RELEASE_DESTPATH = public_html/gst123 diff --git a/configure.ac b/configure.ac index 35058d2..8121d72 100644 --- a/configure.ac +++ b/configure.ac @@ -60,7 +60,7 @@ AC_DEFUN([AC_GSTREAMER_REQUIREMENTS], if test x$GST_1_0 = x1; then AC_MSG_NOTICE([Building gst123 using gstreamer version 1.0]) - PKG_CHECK_MODULES(GSTREAMER, gstreamer-1.0 gstreamer-base-1.0 gstreamer-video-1.0) + PKG_CHECK_MODULES(GSTREAMER, gstreamer-1.0 gstreamer-base-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 gstreamer-tag-1.0) else dnl gstreamer-0.10 development package installed? PKG_CHECK_MODULES(GSTREAMER_0_10, gstreamer-0.10, GST_0_10=1, GST_0_10=0) @@ -82,7 +82,7 @@ dnl AC_DEFUN([AC_GSTREAMER_GTK_REQUIREMENTS], [ dnl We need GLib with friends - PKG_CHECK_MODULES(GSTREAMER_GTK, gtk+-2.0) + PKG_CHECK_MODULES(GSTREAMER_GTK, gtk+-3.0) AC_SUBST(GSTREAMER_GTK_CFLAGS) AC_SUBST(GSTREAMER_GTKLIBS) ]) diff --git a/docs/gst123.1 b/docs/gst123.1 index 9f2064d..e77b279 100644 --- a/docs/gst123.1 +++ b/docs/gst123.1 @@ -2,12 +2,12 @@ .\" Title: gst123 .\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 07/18/2017 +.\" Date: 12/11/2019 .\" Manual: \ \& .\" Source: \ \& .\" Language: English .\" -.TH "GST123" "1" "07/18/2017" "\ \&" "\ \&" +.TH "GST123" "1" "12/11/2019" "\ \&" "\ \&" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -219,7 +219,7 @@ Show keyboard help\&. .RE .SH "CONFIGURATION FILE" .sp -During start, gst123 will read ~/\&.gst123rc, if this file exists\&. Empty lines and lines starting with a # are ignored\&. The following commands are available: +During start, gst123 will read ~/\&.config/gst123rc, if this file exists\&. Empty lines and lines starting with a # are ignored\&. The following commands are available: .PP audio_output [=] .RS 4 diff --git a/docs/gst123.1.txt b/docs/gst123.1.txt index 719da47..a544b0f 100644 --- a/docs/gst123.1.txt +++ b/docs/gst123.1.txt @@ -149,8 +149,9 @@ q:: CONFIGURATION FILE ------------------ -During start, gst123 will read ~/.gst123rc, if this file exists. Empty lines -and lines starting with a # are ignored. The following commands are available: +During start, gst123 will read ~/.config/gst123rc, if this file exists. Empty +lines and lines starting with a # are ignored. The following commands are +available: audio_output [=]:: This sets the default audio driver and the default audio device. It has diff --git a/gst123.desktop b/gst123.desktop new file mode 100644 index 0000000..572f7fd --- /dev/null +++ b/gst123.desktop @@ -0,0 +1,17 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=gst123 +GenericName=Multimedia player +GenericName[ru]=Проигрыватель мультимедия +GenericName[uk]=Програвач мультимедіа +Comment=Simple multimedia player based on gstreamer +Comment[ru]=Простой проигрыватель мультимедиа +Comment[uk]=Простий програвач мультимедіа +Categories=AudioVideo; +Exec=gst123 --quiet %U +Icon=multimedia-player +Terminal=false +Type=Application +MimeType=video/dv;video/mpeg;video/x-mpeg;video/msvideo;video/quicktime;video/x-anim;video/x-avi;video/x-ms-asf;video/x-ms-wmv;video/x-msvideo;video/x-nsv;video/x-flc;video/x-fli;application/ogg;application/x-ogg;video/x-ogm+ogg;audio/x-vorbis+ogg;application/x-matroska;audio/x-matroska;video/x-matroska;video/webm;audio/webm;audio/x-mp3;audio/x-mpeg;audio/mpeg;audio/x-wav;audio/x-mpegurl;audio/x-scpls;audio/x-m4a;audio/x-ms-asf;audio/x-ms-asx;audio/x-ms-wax;application/vnd.rn-realmedia;audio/x-real-audio;audio/x-pn-realaudio;application/x-flac;audio/x-flac;application/x-shockwave-flash;misc/ultravox;audio/vnd.rn-realaudio;audio/x-pn-aiff;audio/x-pn-au;audio/x-pn-wav;audio/x-pn-windows-acm;image/vnd.rn-realpix;video/vnd.rn-realvideo;audio/x-pn-realaudio-plugin;application/x-extension-mp4;audio/mp4;video/mp4;video/mp4v-es;x-content/video-vcd;x-content/video-svcd;x-content/video-dvd;x-content/audio-cdda;x-content/audio-player;video/x-flv;application/xspf+xml; +StartupNotify=false +NoDisplay=true diff --git a/src/configfile.cc b/src/configfile.cc index a7f998d..7514192 100644 --- a/src/configfile.cc +++ b/src/configfile.cc @@ -48,12 +48,22 @@ ConfigFile::visualization() const ConfigFile::ConfigFile() { - char *home = getenv ("HOME"); - if (!home) - return; + char *home = getenv ("XDG_CONFIG_HOME"); + string filename; - string filename = home; - filename += "/.gst123rc"; + if (home) + { + filename = home; + filename += "/gst123rc"; + } + else + { + home = getenv ("HOME"); + if (!home) + return; + filename = home; + filename += "/.config/gst123rc"; + } MicroConf cfg (filename); if (!cfg.open_ok()) diff --git a/src/gst123.cc b/src/gst123.cc index 3f14cec..5690ac9 100644 --- a/src/gst123.cc +++ b/src/gst123.cc @@ -18,10 +18,11 @@ * Boston, MA 02111-1307, USA. */ #include +#include #include +#include #include #include -#include #include #include #include @@ -469,17 +470,23 @@ struct Player : public KeyHandler } } +#define VOLUME_STEPS 20 + void set_volume (gdouble volume_change) { gdouble cur_volume; - g_object_get (G_OBJECT (playbin), "volume", &cur_volume, NULL); - cur_volume += volume_change; - Msg::update_status ("Volume: %4.1f%%", cur_volume * 100); + cur_volume = gst_stream_volume_get_volume (GST_STREAM_VOLUME (playbin), + GST_STREAM_VOLUME_FORMAT_CUBIC); + + cur_volume = round ((cur_volume + volume_change) * VOLUME_STEPS) / VOLUME_STEPS; + cur_volume = CLAMP (cur_volume, 0.0, 10.0); - if ((cur_volume >= 0) && (cur_volume <= 10)) - g_object_set (G_OBJECT (playbin), "volume", cur_volume, NULL); + gst_stream_volume_set_volume (GST_STREAM_VOLUME (playbin), + GST_STREAM_VOLUME_FORMAT_CUBIC, cur_volume); + + Msg::update_status ("Volume: %4.1f%%", cur_volume * 100); } void @@ -1204,9 +1211,11 @@ main (gint argc, g_usignal_add (SIGINT, sigint_usr_code, &player); /* now run */ - terminal.init (player.loop, &player); + if (isatty(0)) + terminal.init (player.loop, &player); g_main_loop_run (player.loop); - terminal.end(); + if (isatty(0)) + terminal.end(); gtk_interface.end(); /* also clean up */ diff --git a/src/gtkinterface.cc b/src/gtkinterface.cc index 06c7ce1..d4e3e90 100644 --- a/src/gtkinterface.cc +++ b/src/gtkinterface.cc @@ -39,6 +39,14 @@ key_press_event_cb (GtkWidget *widget, GdkEventKey *event, gpointer data) return gtk_interface->handle_keypress_event (event); } +static gboolean +button_press_event_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + GtkInterface *gtk_interface = static_cast (data); + + return gtk_interface->handle_buttonpress_event (event); +} + static gboolean motion_notify_event_cb (GtkWidget *widget, GdkEventMotion *event, gpointer data) { @@ -106,7 +114,9 @@ GtkInterface::init (int *argc, char ***argv, KeyHandler *handler) { gtk_init (argc, argv); gtk_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_icon_name (GTK_WINDOW (gtk_window), "multimedia-player"); g_signal_connect (G_OBJECT (gtk_window), "key-press-event", G_CALLBACK (key_press_event_cb), this); + g_signal_connect (G_OBJECT (gtk_window), "button-press-event", G_CALLBACK (button_press_event_cb), this); g_signal_connect (G_OBJECT (gtk_window), "motion-notify-event", G_CALLBACK (motion_notify_event_cb), this); g_signal_connect (G_OBJECT (gtk_window), "delete-event", G_CALLBACK (close_cb), this); g_signal_connect (G_OBJECT (gtk_window), "window-state-event", G_CALLBACK (window_state_event_cb), this); @@ -119,12 +129,20 @@ GtkInterface::init (int *argc, char ***argv, KeyHandler *handler) video_fullscreen = Options::the().fullscreen; // initially fullscreen? // make background black - GdkColor color; - gdk_color_parse ("black", &color); - gtk_widget_modify_bg (gtk_window, GTK_STATE_NORMAL, &color); + GtkCssProvider* provider = gtk_css_provider_new(); + GdkDisplay* display = gdk_display_get_default(); + GdkScreen* screen = gdk_display_get_default_screen(display); + + gtk_style_context_add_provider_for_screen(screen, + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_USER); + + gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(provider), + "GtkWindow {background-color: black;}\n", -1, NULL); + g_object_unref(provider); visible_cursor = NULL; - invisible_cursor = gdk_cursor_new (GDK_BLANK_CURSOR); + invisible_cursor = gdk_cursor_new_for_display (gdk_display_get_default (), GDK_BLANK_CURSOR); cursor_timeout = 3; g_timeout_add (500, (GSourceFunc) timeout_cb, this); @@ -136,15 +154,15 @@ GtkInterface::init (int *argc, char ***argv, KeyHandler *handler) gtk_window_visible = false; /* initialize map from Gdk keysyms to KeyHandler codes */ - key_map[GDK_Page_Up] = KEY_HANDLER_PAGE_UP; - key_map[GDK_Page_Down] = KEY_HANDLER_PAGE_DOWN; - key_map[GDK_Left] = KEY_HANDLER_LEFT; - key_map[GDK_Right] = KEY_HANDLER_RIGHT; - key_map[GDK_Up] = KEY_HANDLER_UP; - key_map[GDK_Down] = KEY_HANDLER_DOWN; - key_map[GDK_BackSpace] = KEY_HANDLER_BACKSPACE; - key_map[GDK_KP_Add] = '+'; - key_map[GDK_KP_Subtract] = '-'; + key_map[GDK_KEY_Page_Up] = KEY_HANDLER_PAGE_UP; + key_map[GDK_KEY_Page_Down] = KEY_HANDLER_PAGE_DOWN; + key_map[GDK_KEY_Left] = KEY_HANDLER_LEFT; + key_map[GDK_KEY_Right] = KEY_HANDLER_RIGHT; + key_map[GDK_KEY_Up] = KEY_HANDLER_UP; + key_map[GDK_KEY_Down] = KEY_HANDLER_DOWN; + key_map[GDK_KEY_BackSpace] = KEY_HANDLER_BACKSPACE; + key_map[GDK_KEY_KP_Add] = '+'; + key_map[GDK_KEY_KP_Subtract] = '-'; } bool @@ -152,7 +170,7 @@ GtkInterface::is_fullscreen() { g_return_val_if_fail (gtk_window != NULL && gtk_window_visible, false); - GdkWindowState state = gdk_window_get_state (GDK_WINDOW (gtk_window->window)); + GdkWindowState state = gdk_window_get_state (gtk_widget_get_window (gtk_window)); return (state & GDK_WINDOW_STATE_FULLSCREEN); } @@ -161,7 +179,7 @@ GtkInterface::is_maximized() { g_return_val_if_fail (gtk_window != NULL && gtk_window_visible, false); - GdkWindowState state = gdk_window_get_state (GDK_WINDOW (gtk_window->window)); + GdkWindowState state = gdk_window_get_state (gtk_widget_get_window (gtk_window)); return (state & GDK_WINDOW_STATE_MAXIMIZED); } @@ -209,7 +227,7 @@ GtkInterface::show() // get cursor, so we can restore it after hiding it if (!visible_cursor) - visible_cursor = gdk_window_get_cursor (GDK_WINDOW (gtk_window->window)); + visible_cursor = gdk_window_get_cursor (gtk_widget_get_window (gtk_window)); // sync, to make the window really visible before we return gdk_display_sync (gdk_display_get_default()); @@ -270,7 +288,7 @@ GtkInterface::hide() if (video_maximized) gtk_window_unmaximize (GTK_WINDOW (gtk_window)); - gtk_widget_hide_all (gtk_window); + gtk_widget_hide (gtk_window); screen_saver (RESUME); gtk_window_visible = false; @@ -341,10 +359,10 @@ GtkInterface::set_opacity (double alpha_change) { double alpha; - alpha = gtk_window_get_opacity (GTK_WINDOW (gtk_window)); + alpha = gtk_widget_get_opacity (gtk_window); alpha = CLAMP (alpha + alpha_change, 0.0, 1.0); Msg::update_status ("Opacity: %3.1f%%", alpha * 100); - gtk_window_set_opacity (GTK_WINDOW (gtk_window), alpha); + gtk_widget_set_opacity (gtk_window, alpha); } } @@ -366,6 +384,17 @@ GtkInterface::handle_keypress_event (GdkEventKey *event) return false; } +bool +GtkInterface::handle_buttonpress_event (GdkEventButton *event) +{ + if (event->button == 1 && event->state == 0) + { + key_handler->process_input (' '); + return true; + } + return false; +} + void GtkInterface::set_title (const string& title) { @@ -380,7 +409,7 @@ GtkInterface::handle_timeout() { if (cursor_timeout == 0) { - gdk_window_set_cursor (GDK_WINDOW (gtk_window->window), invisible_cursor); + gdk_window_set_cursor (gtk_widget_get_window (gtk_window), invisible_cursor); cursor_timeout = -1; } else if (cursor_timeout > 0) @@ -396,7 +425,7 @@ GtkInterface::handle_motion_notify_event (GdkEventMotion *event) { if (gtk_window != NULL && gtk_window_visible) { - gdk_window_set_cursor (GDK_WINDOW (gtk_window->window), visible_cursor); + gdk_window_set_cursor (gtk_widget_get_window (gtk_window), visible_cursor); cursor_timeout = 3; } return true; @@ -438,10 +467,10 @@ GtkInterface::handle_close() void GtkInterface::screen_saver (ScreenSaverSetting setting) { - GdkWindow *window = GTK_WIDGET (gtk_window)->window; + GdkWindow *window = gtk_widget_get_window (gtk_window); if (gtk_window != NULL && window) { - guint64 wid = GDK_WINDOW_XWINDOW (window); + guint64 wid = GDK_WINDOW_XID (window); const char *setting_str = (setting == SUSPEND) ? "suspend" : "resume"; diff --git a/src/gtkinterface.h b/src/gtkinterface.h index 924f467..549ed95 100644 --- a/src/gtkinterface.h +++ b/src/gtkinterface.h @@ -60,6 +60,7 @@ class GtkInterface gulong window_xid_nolock() const; void toggle_fullscreen(); bool handle_keypress_event (GdkEventKey *event); + bool handle_buttonpress_event (GdkEventButton *event); bool handle_motion_notify_event (GdkEventMotion *event); bool handle_window_state_event (GdkEventWindowState *event); bool handle_timeout();