From 20a59e99a83be8c5de5b1c63be4676b08ec2a1d9 Mon Sep 17 00:00:00 2001 From: Tilman Sauerbeck Date: Sat, 11 Mar 2006 19:44:09 +0000 Subject: [PATCH] Initial commit. --- AUTHORS | 1 + COPYING | 20 ++++ Rakefile | 33 ++++++ bin/snett | 277 +++++++++++++++++++++++++++++++++++++++++++++++ data/logo.svg | 262 ++++++++++++++++++++++++++++++++++++++++++++ data/logo128.png | Bin 0 -> 9479 bytes data/logo32.png | Bin 0 -> 1860 bytes data/logo64.png | Bin 0 -> 4404 bytes 8 files changed, 593 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 Rakefile create mode 100755 bin/snett create mode 100644 data/logo.svg create mode 100644 data/logo128.png create mode 100644 data/logo32.png create mode 100644 data/logo64.png diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..5864b3d --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Tilman Sauerbeck (tilman at code-monkey de) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..77ff64a --- /dev/null +++ b/COPYING @@ -0,0 +1,20 @@ +Copyright (c) 2006 Tilman Sauerbeck (tilman at code-monkey de) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..7d06ba7 --- /dev/null +++ b/Rakefile @@ -0,0 +1,33 @@ +require "rake/packagetask" +require "rake/contrib/sshpublisher" + +PKG_NAME = "snett" +PKG_VERSION = File.read("bin/snett"). + match(/^\s*VERSION = \"(.*)\"\s$/).captures.first + +task :install do + destdir = ENV["DESTDIR"] || "" + prefix = ENV["PREFIX"] || "/usr/local" + + ddir = destdir + prefix + "/bin" + + FileUtils::Verbose.mkdir_p(ddir) unless File.directory?(ddir) + FileUtils::Verbose.install("bin/snett", ddir, :mode => 0755) + + ddir = destdir + prefix + "/share/snett" + + FileUtils::Verbose.mkdir_p(ddir) unless File.directory?(ddir) + FileUtils::Verbose.install(Dir["data/*"], ddir, :mode => 0644) +end + +Rake::PackageTask.new(PKG_NAME, PKG_VERSION) do |t| + t.need_tar_gz = true + t.package_files.include("[A-Z]*", "bin/snett", "data/logo*") +end + +task :publish => [:package] do + Rake::SshFilePublisher. + new("code-monkey.de", ".", + "pkg", "#{PKG_NAME}-#{PKG_VERSION}.tar.gz"). + upload +end diff --git a/bin/snett b/bin/snett new file mode 100755 index 0000000..ff053df --- /dev/null +++ b/bin/snett @@ -0,0 +1,277 @@ +#!/usr/bin/env ruby + +# vim:syn=ruby +# +# Copyright (c) 2006 Tilman Sauerbeck (tilman at code-monkey de) +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +require "gtk2" +require "xmmsclient" +require "xmmsclient_glib" +require "singleton" +require "pp" + +PKG_NAME = "snett" +DATADIR = "/usr/local/share/#{PKG_NAME}/" +SIZE = 64 + +class Gtk::MenuItem + def set_callback(meth, args = []) + args.unshift(meth) + + signal_connect("button_release_event") do + Snett::Snett.instance.xmms.send(*args) + false + end + end +end + +class XmmsClient::XmmsClient + def playback_next + playlist_set_next_rel(1).notifier { playback_tickle } + end + + def playback_prev + playlist_set_next_rel(-1).notifier { playback_tickle } + end +end + +module Snett + VERSION = "0.0.1" + + class Snett < Gtk::Window + attr_reader :icon, :xmms + + include Singleton + + def initialize + super(Gtk::Window::TOPLEVEL) + + @menu = nil + @tooltips = Gtk::Tooltips.new + + @xmms = XmmsClient::XmmsClient.new(PKG_NAME) + @xmms.connect(ENV["XMMS_PATH"]) + @xmms.add_to_glib_mainloop + + @broadcasts = [] + + self.set_title(PKG_NAME) + + signal_connect("destroy") do + @broadcasts.each { |bc| bc.disconnect } + + Gtk.main_quit + end + + self.resizable = false + self.decorated = false + + @icon = Gdk::Pixbuf.new(DATADIR + "logo#{SIZE}.png") + + self.resize(@icon.width, @icon.height) + + #self.colormap = self.screen.rgba_colormap + + pixmap, mask = @icon.render_pixmap_and_mask(self.colormap, 255) + self.shape_combine_mask(mask, 0, 0) + + # load icon and put it in an eventbox + event_box = Gtk::EventBox.new.add(Gtk::Image.new(@icon)) + event_box.events = Gdk::Event::BUTTON_PRESS_MASK | + Gdk::Event::BUTTON_RELEASE_MASK + + event_box.signal_connect("button_release_event") do |_, event| + menu.popup(event) if event.button == 3 + false + end + + event_box.signal_connect("button_press_event") do |_, event| + if event.button == 1 + x, y = Gdk::Display.default.pointer[1, 2] + self.begin_move_drag(event.button, x, y, event.time) + end + + false + end + + @broadcasts << @xmms.broadcast_playback_current_id + @broadcasts.last.notifier(&method(:on_playback_current_id)) + + @xmms.playback_current_id. + notifier(&method(:on_playback_current_id)) + + add(event_box) + end + + private + def menu + @menu ||= Menu.new + end + + def on_playback_current_id(res) + return if res.value.zero? + + @xmms.medialib_get_info(res.value). + notifier(&method(:on_mlib_get_info)) + end + + def on_mlib_get_info(res) + info = res.value[:server] + + s = "%s - %s" % [info[:artist], info[:title]] + @tooltips.set_tip(self, s, nil) + end + end + + class Menu < Gtk::Menu + def initialize + super + + [ + [Gtk::Stock::MEDIA_PLAY, :playback_start], + [Gtk::Stock::MEDIA_PAUSE, :playback_pause], + [Gtk::Stock::MEDIA_STOP, :playback_stop] + ].each do |(stock, meth)| + item = Gtk::ImageMenuItem.new(stock) + item.set_callback(meth) + + append(item) + end + + append(Gtk::SeparatorMenuItem.new) + + [ + [Gtk::Stock::MEDIA_NEXT, :playback_next], + [Gtk::Stock::MEDIA_PREVIOUS, :playback_prev] + ].each do |(stock, meth)| + item = Gtk::ImageMenuItem.new(stock) + item.set_callback(meth) + + append(item) + end + + append(Gtk::SeparatorMenuItem.new) + + [ + [Gtk::Stock::OPEN, "Load playlist...", :load], + [Gtk::Stock::ADD, "Append playlist...", :append] + ].each do |(stock, text, sym)| + item = Gtk::ImageMenuItem.new(text) + item.image = Gtk::Image.new(stock, Gtk::IconSize::MENU) + + item.signal_connect("button_release_event") do + PlaylistDialog.new(sym).show_all + false + end + + append(item) + end + + item = Gtk::ImageMenuItem.new(Gtk::Stock::CLEAR) + item.set_callback(:playlist_clear) + + append(item) + + append(Gtk::SeparatorMenuItem.new) + + item = Gtk::ImageMenuItem.new(Gtk::Stock::ABOUT) + item.signal_connect("button_release_event") do + props = { + "name" => PKG_NAME, + "version" => VERSION, + "copyright" => "(c) 2006 Tilman Sauerbeck", + "logo" => Gdk::Pixbuf.new(DATADIR + "logo128.png") + } + + Gtk::AboutDialog.show(Snett.instance, props) + false + end + + append(item) + + item = Gtk::ImageMenuItem.new(Gtk::Stock::QUIT) + item.signal_connect("button_release_event") do + Snett.instance.signal_emit("destroy") + false + end + + append(item) + + show_all + end + + def popup(event) + super(nil, nil, event.button, event.time) + end + end + + class PlaylistDialog < Gtk::Dialog + def initialize(mode) + super("Playlists", Snett.instance, + Gtk::Dialog::DESTROY_WITH_PARENT | Gtk::Dialog::MODAL, + [Gtk::Stock::OK, Gtk::Dialog::RESPONSE_ACCEPT], + [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_REJECT]) + + @mode = mode + + signal_connect("response") do |_, id| + on_ok if id == Gtk::Dialog::RESPONSE_ACCEPT + destroy + end + + @store = Gtk::ListStore.new(String) + + @view = Gtk::TreeView.new(@store) + renderer = Gtk::CellRendererText.new + + col = Gtk::TreeViewColumn.new("Name", renderer, :text => 0) + @view.append_column(col) + + vbox.add(@view) + + Snett.instance.xmms.medialib_playlists_list. + notifier(&method(:on_playlists_list)) + end + + private + def on_playlists_list(res) + res.value.sort.each do |list| + next if list[0, 1] == "_" + + @store.append[0] = list + end + end + + def on_ok + selection = @view.selection + iter = selection.selected + return if iter.nil? + + Snett.instance.xmms.playlist_clear if @mode == :load + Snett.instance.xmms.medialib_playlist_load(iter[0]) + end + end +end + +Gtk.init +Snett::Snett.instance.show_all +Gtk.main diff --git a/data/logo.svg b/data/logo.svg new file mode 100644 index 0000000..0bf779a --- /dev/null +++ b/data/logo.svg @@ -0,0 +1,262 @@ + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/logo128.png b/data/logo128.png new file mode 100644 index 0000000000000000000000000000000000000000..571a87fff6bae93623c074f90427369b723cd4fb GIT binary patch literal 9479 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