]> git.netwichtig.de Git - user/henk/code/ruby/grux.git/blobdiff - bin/grux.rb
On branch master
[user/henk/code/ruby/grux.git] / bin / grux.rb
index cf6c34d2f53c5abba41b6fed3876a97ea6041adb..954ea5ffcbe0ebc2e39e17aed0797762f6bff3c7 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/env ruby
+#!/usr/bin/env ruby -w
 
 #$: << File.expand_path(File.dirname(FILE) + “/../lib”))
 
@@ -11,82 +11,136 @@ class Grux
 end
 
 class Grux::ClientWin < Gtk::VBox
-  def initialize
-    super
+  attr_reader :status
+
+  def initialize( server_address )
+    super()
+
 
     @server                 = Xmms::Client.new( 'Grux' )
 
-    @infoBoxWin            = Gtk::ScrolledWindow.new
-    @upperBox               = Gtk::HBox.new
-    @leftUpperBox           = Gtk::VBox.new
-    @infoBox          = Gtk::VBox.new
-    @cntrlBtnBox            = Gtk::VButtonBox.new
-    @statusLblBoxWin           = Gtk::ScrolledWindow.new
-    @statusLblBox           = Gtk::VBox.new
-    @playlistViewWin        = Gtk::ScrolledWindow.new
+    @status                 = Hash.new
+    @status[:connected]     = self.connect( server_address )
+
+    @statusBox              = Gtk::HBox.new
+    @mainBox                = Gtk::VPaned.new
     @statusBar              = Gtk::Statusbar.new
 
+    self.pack_start @statusBox, false
+    self.pack_start @mainBox
+    self.pack_end @statusBar, false
+
+
+    @statusWdgts            = [
+      @currentartistFrame     = Gtk::Frame.new( "Artist" ).add( @currentartistLabel = Gtk::Label.new ),
+      @currenttitleFrame      = Gtk::Frame.new( "Title" ).add( @currenttitleLabel = Gtk::Label.new ),
+      @currentalbumFrame      = Gtk::Frame.new( "Album" ).add( @currentalbumLabel = Gtk::Label.new )
+    ]
+    @statusWdgts.each { |frame| @statusBox.pack_start frame }
+
+
+    @mainWdgts              = [
+      @cntrlBox               = Gtk::HBox.new,
+      @medialistsWin          = Gtk::Notebook.new
+    ]
+    @mainBox.pack1 @cntrlBox, true, false
+    @mainBox.pack2 @medialistsWin, true, false
+
+
+    @toolWdgts              = [
+      @cntrlBtnBox            = Gtk::VButtonBox.new.set_layout_style( Gtk::ButtonBox::CENTER ),
+      @toolChsr               = Gtk::Notebook.new
+    ]
+    @cntrlBox.pack_start @cntrlBtnBox, false
+    @cntrlBox.pack_start @toolChsr
+
+
     @cntrlbtns      = [
-      @playBtn        = Gtk::Button.new('_Play/Pause'),
-      @stopBtn        = Gtk::Button.new('_Stop'),
+      @playBtn        = Gtk::ToggleButton.new('_Play', true),
+      @pauseBtn       = Gtk::ToggleButton.new('Pa_use', true),
+      @stopBtn        = Gtk::ToggleButton.new('_Stop', true),
       @nextBtn        = Gtk::Button.new('_Next'),
-      @prevBtn        = Gtk::Button.new('Pre_vious'),
-      @rndmBtn        = Gtk::Button.new('_Random'),
+      @prevBtn        = Gtk::Button.new('P_revious'),
+      @rndmBtn        = Gtk::Button.new('Randomi_ze'),
       @rptBtn         = Gtk::ToggleButton.new('Repeat _All', true),
       @rpt1Btn        = Gtk::ToggleButton.new('Repeat _One', true)
     ]
-    @statusLbls     = [
-      @stateLbl       = Gtk::Label.new,
-      @playbackLbl    = Gtk::Label.new,
-      @nextSongLbl    = Gtk::Label.new
-    ]
-
     @cntrlbtns.each do |button|
       @cntrlBtnBox.pack_start button
     end
-    @cntrlBtnBox.layout_style = Gtk::ButtonBox::START
-    @statusLbls.each do |label|
-      @statusLblBox.pack_start label, false
+
+
+    @toolTabs                 = [
+      [ @extinfoTab             = Gtk::VBox.new,
+        @extinfoTabLbl          = Gtk::Label.new( "Status" ) ],
+      [ @tageditorTab           = Gtk::VBox.new,
+        @tageditorTabLbl        = Gtk::Label.new( "Tag Editor" ) ],
+      [ @searchTab              = Gtk::VBox.new,
+        @searchTabLbl           = Gtk::Label.new( "Search" ) ]
+    ]
+    @toolTabs.each do |content, label|
+      @toolChsr.append_page( Gtk::ScrolledWindow.new.add_with_viewport( content ), label )
     end
 
-    @infoBoxWin.add_with_viewport @infoBox
-    @statusLblBoxWin.add_with_viewport @statusLblBox
-    @upperBox.pack_start @cntrlBtnBox, false
-    @upperBox.pack_start @infoBoxWin
-    @upperBox.pack_start @statusLblBoxWin
+    @searchTabItems           = [
+      @searchTermEntry          = Gtk::Entry.new,
+      @startsearchBtn           = Gtk::Button.new( "Search" )
+    ]
+    @searchTabItems.each do |wdgt|
+      @searchTab.pack_start( wdgt )
+    end
+
+
+    @medialistTextRenderer    = Gtk::CellRendererText.new
+    @medialistColumns         = [ 'id', 'artist', 'title' ]
+
+    @medialists               = [
+      [ @playlistViewLbl        = Gtk::Label.new( "Current Playlist" ),
+        @playlistViewWin        = Gtk::ScrolledWindow.new,
+        @playlistView           = Gtk::TreeView.new,
+        @playlistStore          = Gtk::ListStore.new( String, String, String )
+      ],
+      [ @medialibViewLbl        = Gtk::Label.new( "Medialib" ),
+        @medialibViewWin        = Gtk::ScrolledWindow.new,
+        @medialibView           = Gtk::TreeView.new,
+        @medialibStore          = Gtk::ListStore.new( String, String, String )
+      ],
+      [ @searchResultViewLbl    = Gtk::Label.new( "Search Results" ),
+        @searchResultViewWin    = Gtk::ScrolledWindow.new,
+        @searchResultView       = Gtk::TreeView.new,
+        @searchResultStore      = Gtk::ListStore.new( String, String, String )
+      ]
+    ]
 
-    @playlistTextRenderer   = Gtk::CellRendererText.new
-    @playlistView           = Gtk::TreeView.new
-    @playlistList           = Gtk::ListStore.new( String, String, String )
-    @playlistColumns        = [ 'id', 'artist', 'title' ]
-    @playlistColumns.each_with_index do |tag, index|
-      @playlistView.append_column Gtk::TreeViewColumn.new( tag, @playlistTextRenderer, :text => index )
+    @medialists.each do |label, window, view, store|
+      @medialistColumns.each_with_index do |tag, index|
+        view.append_column Gtk::TreeViewColumn.new( tag, @medialistTextRenderer, :text => index )
+      end
+      view.search_column = 2
+      @medialistsWin.append_page( window.add( view ), label )
     end
-    @playlistViewWin.add @playlistView
 
-    self.pack_start @upperBox
-    self.pack_start @playlistViewWin
-    self.pack_end @statusBar, false
+
     self.show_all
 
-    begin
-      @server.connect( ENV['XMMS_PATH'] )
-      @server.add_to_glib_mainloop
-    rescue
-      @statusBar.push( @statusBar.get_context_id( "connection" ), "Failed to connect to #{ENV['XMMS_PATH']}" )
-    end
 
-    @playBtn.signal_connect :clicked do
-      self.toggle_playback
+    @playBtnClkdHndlr = @playBtn.signal_connect :clicked do
+      self.start_playback
+    end
+    @pauseBtnClkdHndlr = @pauseBtn.signal_connect :clicked do
+      self.pause_playback
     end
-    @stopBtn.signal_connect :clicked do
+    @stopBtnClkdHndlr = @stopBtn.signal_connect :clicked do
       self.stop_playback
     end
     @nextBtn.signal_connect :clicked do
-      self.step_in_playlist 1
+      self.step_in_playlist( 1 )
     end
     @prevBtn.signal_connect :clicked do
-      self.step_in_playlist -1
+      self.step_in_playlist( -1 )
+    end
+    @rndmBtn.signal_connect :clicked do
+      self.randomize_playlist
     end
     @rptBtnClkdHndlr = @rptBtn.signal_connect :clicked do
       self.toggle_repeat_all
@@ -95,54 +149,307 @@ class Grux::ClientWin < Gtk::VBox
       self.toggle_repeat_one
     end
 
+    @startsearchBtn.signal_connect :clicked do
+      searchregex = Regexp.new( /#{@searchTermEntry.text}/ix )
+      results = []
+      @status[:medialib].each_with_index do |songinfo, id|
+        songinfo && songinfo.each do |key, info|
+          info.each do |src, value|
+            if searchregex.match( value.to_s )
+              results << id
+              break
+            end
+          end
+        end
+      end
+      searchResultIds, searchResult = self.xmmspls_to_lststor( results.uniq!, @searchResultStore )
+      @searchResultView.model = searchResult
+    end
+
+
     @playlistView.signal_connect :row_activated do |view, path, column|
       @server.playlist_set_next( path.to_str.to_i ).notifier do
         @server.playback_tickle.notifier do
+          self.start_playback
           true
         end
         true
       end
     end
 
-    @server.broadcast_coll_changed do
+
+    @medialibView.signal_connect :row_activated do |view, path, column|
+      songid = @medialibStore.get_iter( path )[0].to_i
+      @server.playlist.add_entry( songid ).notifier do
+        current_row = @playlistStore.append
+        @server.medialib_get_info( songid ).notifier do |songinfo|
+          current_row[0] = songid.to_s
+          current_row[1] = songinfo[:artist] ? songinfo[:artist].first[1] : ""
+          current_row[2] = songinfo[:title] ? songinfo[:title].first[1] : ""
+          true
+        end
+        @server.playlist_set_next( current_row.to_s.to_i ).notifier do
+          @server.playback_tickle.notifier do
+            self.start_playback
+            true
+          end
+          true
+        end
+      end
+    end
+
+
+    if @status[:connected]
+      p "connected"
+      self.resync_complete
+    end
+  end
+
+
+  def connect( address )
+    begin
+      @server.connect( address )
+      @server.add_to_glib_mainloop
+    rescue Xmms::Client::ClientError => ex
+      warn "Connection failed. Error Code:"
+      warn ex
+      return false
+    end
+
+
+    @server.broadcast_coll_changed.notifier do |*foo|
+      self.handle_coll_changed foo
+      true
     end
-    @server.broadcast_config_value_changed do |*foo|
-      p foo
+    @server.broadcast_config_value_changed.notifier do |*foo|
+      self.handle_config_value_changed  foo
+      true
     end
-    @server.broadcast_mediainfo_reader_status do
+    @server.broadcast_mediainfo_reader_status.notifier do |*foo|
+      self.handle_mediainfo_reader_status  foo
+      true
     end
-    @server.broadcast_medialib_entry_added do
+    @server.broadcast_medialib_entry_added.notifier do |*foo|
+      self.handle_medialib_entry_added  foo
+      true
     end
-    @server.broadcast_medialib_entry_changed do
+    @server.broadcast_medialib_entry_changed.notifier do |*foo|
+      self.handle_medialib_entry_changed  foo
+      true
     end
     @server.broadcast_playback_current_id.notifier do |id|
-      self.handle_current_song id
+      self.handle_playback_current_id id
+      true
     end
-    @server.broadcast_playback_status.notifier do |playing|
-      self.handle_playback_status playing
+    @server.broadcast_playback_status.notifier do |status|
+      self.handle_playback_status status
+      true
     end
-    @server.broadcast_playback_volume_changed do
+    @server.broadcast_playback_volume_changed.notifier do |*foo|
+      self.handle_playback_volume_changed  foo
+      true
     end
-    @server.broadcast_playlist_changed do
+    @server.broadcast_playlist_changed.notifier do |*foo|
+      self.handle_playlist_changed  foo
+      true
     end
     @server.broadcast_playlist_current_pos.notifier do |pos|
-      self.handle_current_pos pos
+      self.handle_playlist_current_pos pos
+      true
     end
-    @server.broadcast_playlist_loaded do
+    @server.broadcast_playlist_loaded.notifier do |*foo|
+      self.handle_playlist_loaded  foo
+      true
+    end
+    @server.broadcast_quit.notifier do |*foo|
+      self.handle_quit  foo
+      true
     end
-    @server.broadcast_quit do
+    true
+  end
+
+
+  def handle_coll_changed( *foo )
+    p "Collection changed: #{foo}"
+    true
+  end
+  def handle_config_value_changed( *foo )
+    p "Config changed: #{foo}"
+    true
+  end
+  def handle_mediainfo_reader_status( *foo )
+    p "Mediainfo reader status changed: #{foo}"
+    true
+  end
+  def handle_medialib_entry_added( *foo )
+    p "Medialib entry added: #{foo}"
+    true
+  end
+  def handle_medialib_entry_changed( *foo )
+    p "Medialib entry changed: #{foo}"
+    true
+  end
+
+
+  def handle_playback_current_id( id )
+    p "Current playback ID changed: #{id}"
+    songpath = Gtk::TreePath.new( @status[:playlistids].index id )
+
+    @playlistView.scroll_to_cell( songpath, nil, true, 0.5, 0.5 )
+    @playlistView.set_cursor( songpath, nil, false )
+
+    @server.medialib_get_info( id ).notifier do |songinfo|
+      @currentartistLabel.text = ""
+      @currenttitleLabel.text = ""
+      @currentalbumLabel.text = ""
+
+      @extinfoTab.each do |child| @extinfoTab.remove child end
+
+      songinfo[:artist] && songinfo[:artist].each_pair do |src, value|
+        @currentartistLabel.text += @currentartistLabel.text.empty? ? value : "\n#{value}"
+      end
+      songinfo[:title] && songinfo[:title].each_pair do |src, value|
+        @currenttitleLabel.text += @currenttitleLabel.text.empty? ? value : "\n#{value}"
+      end
+      songinfo[:album] && songinfo[:album].each_pair do |src, value|
+        @currentalbumLabel.text += @currentalbumLabel.text.empty? ? value : "\n#{value}"
+      end
+      songinfo.each_key do |key|
+        infos = String.new
+        songinfo[key].each_pair do |src,value|
+          infos.empty? || infos += "\n"
+          infos += "#{value} (#{src})"
+        end
+        @extinfoTab.pack_end( Gtk::Frame.new( key.to_s ).add( Gtk::Label.new( infos ) ) )
+      end
+      @extinfoTab.show_all
+      true
     end
+    true
+  end
+
 
-    self.resync_state
+  def handle_playback_status( status )
+    p "Current playback status changed: #{status}"
+    @playbackState = status
+    true
   end
 
+
+  def handle_playback_volume_changed( *foo )
+    p "Playback volume changed: #{foo}"
+    true
+  end
+  def handle_playlist_changed( *foo )
+    p "Playlist changed: #{foo}"
+    true
+  end
+
+
+  def handle_playlist_current_pos( pos )
+    p "Current pos changed: #{pos}"
+    #@server.playlist.entries.notifier do |playlist|
+    #  @server.medialib_get_info( playlist[pos[:position]] ).notifier do |songinfo|
+    #    @nextSongLbl.text = ""
+    #    songinfo.each_pair do |key, info|
+    #      info.each_pair do |src, value|
+    #        @nextSongLbl.text += "[#{src}] #{key} = #{value}\n"
+    #      end
+    #    end
+    #    true
+    #  end
+    #  true
+    #end
+    true
+  end
+
+
+  def handle_playlist_loaded( *foo )
+    p "Playlist loaded: #{foo}"
+    true
+  end
+  def handle_quit( *foo )
+    p "Server quit: #{foo}"
+    true
+  end
+
+
+  def xmmspls_to_lststor( songids, store )
+    songinfos = []
+    store.clear
+    songids.each do |id|
+      current_row = store.append
+      @server.medialib_get_info( id ).notifier do |songinfo|
+        songinfos[id] = songinfo
+        current_row[0] = id.to_s
+        current_row[1] = songinfo[:artist] ? songinfo[:artist].first[1] : ""
+        current_row[2] = songinfo[:title] ? songinfo[:title].first[1] : ""
+        true
+      end
+    end
+    return [songinfos, store]
+  end
+
+
+
+  def start_playback
+    @server.playback_start.notifier do |res|
+      @playBtn.signal_handler_block( @playBtnClkdHndlr ) do
+        @playBtn.active = true
+      end
+      @pauseBtn.signal_handler_block( @pauseBtnClkdHndlr ) do
+        @pauseBtn.active = false
+      end
+      @stopBtn.signal_handler_block( @stopBtnClkdHndlr ) do
+        @stopBtn.active = false
+      end
+      @statusBar.push( @statusBar.get_context_id( "playback" ), "Started playback" )
+      true
+    end
+  end
+
+
+  def pause_playback
+    @server.playback_pause.notifier do |res|
+      @playBtn.signal_handler_block( @playBtnClkdHndlr ) do
+        @playBtn.active = false
+      end
+      @pauseBtn.signal_handler_block( @pauseBtnClkdHndlr ) do
+        @pauseBtn.active = true
+      end
+      @stopBtn.signal_handler_block( @stopBtnClkdHndlr ) do
+        @stopBtn.active = false
+      end
+      @statusBar.push( @statusBar.get_context_id( "playback" ), "Paused playback" )
+      true
+    end
+  end
+
+
+  def stop_playback
+    @server.playback_stop.notifier do |res|
+      @playBtn.signal_handler_block( @playBtnClkdHndlr ) do
+        @playBtn.active = false
+      end
+      @pauseBtn.signal_handler_block( @pauseBtnClkdHndlr ) do
+        @pauseBtn.active = false
+      end
+      @stopBtn.signal_handler_block( @stopBtnClkdHndlr ) do
+        @stopBtn.active = true
+      end
+      @statusBar.push( @statusBar.get_context_id( "playback" ), "Stopped playback" )
+      true
+    end
+  end
+
+
   def toggle_playback
     if @playbackState == 1
       @server.playback_pause.notifier do |res|
         @statusBar.push( @statusBar.get_context_id( "playback" ), "Paused playback" )
         true
       end
-    elsif @playbackState == 0 || 2
+    elsif @playbackState == ( 0 || 2 )
       @server.playback_start.notifier do |res|
         @statusBar.push( @statusBar.get_context_id( "playback" ), "Started playback" )
         true
@@ -156,12 +463,6 @@ class Grux::ClientWin < Gtk::VBox
     end
   end
 
-  def stop_playback
-    @server.playback_stop.notifier do |res|
-      @statusBar.push( @statusBar.get_context_id( "playback" ), "Stopped playback" )
-      true
-    end
-  end
 
   def step_in_playlist( offset = 1 )
     @server.playlist_set_next_rel( offset ).notifier do
@@ -169,82 +470,10 @@ class Grux::ClientWin < Gtk::VBox
         @statusBar.push( @statusBar.get_context_id( "playback" ), "Skipped playback by #{offset} song#{offset.abs >= 1 ? "s" : ''}" )
         true
       end
-    true
-    end
-  end
-
-  def handle_playback_status( status )
-    @playbackState = status
-    @stateLbl.text = case status
-      when 0 then "stopped"
-      when 1 then "playing"
-      when 2 then "paused"
-      else "unknown"
-    end
-    true
-  end
-
-  def handle_current_song( id )
-    songpath = Gtk::TreePath.new( @currentPlaylist.index id )
-    @playlistView.scroll_to_cell( songpath, nil, true, 0.5, 0.5 )
-    @playlistView.set_cursor( songpath, nil, false )
-    @server.medialib_get_info( id ).notifier do |songinfo|
-      infos = {}
-      @playbackLbl.text = ""
-      @infoBox.each { |child| @infoBox.remove child }
-      self.show_all
-      songinfo.each_key do |key|
-        songinfo[key].each_pair do |src,value|
-          @playbackLbl.text += "[#{src}] #{key} = #{value}\n"
-          infos[key] = ( ( infos[key] ? infos[key] + "\n" : "" ) + "#{value} (#{src})" )
-        end
-      end
-      [ :artist, :title, :album ].each do |key|
-        @infoBox.pack_start( Gtk::Frame.new( key.to_s ).add( Gtk::Label.new( infos.delete( key ) ) ) )
-      end
-      infos.each_pair do |key, value|
-        if key == :artist
-          @infoBox.pack_start( Gtk::Frame.new( key.to_s ).add( Gtk::Label.new( value ) ) )
-          next
-        end
-        @infoBox.pack_end( Gtk::Frame.new( key.to_s ).add( Gtk::Label.new( value ) ) )
-      end
-      @infoBox.show_all
       true
     end
-    true
   end
 
-  def handle_current_pos( pos )
-#    @server.playlist.entries.notifier do |playlist|
-#      @server.medialib_get_info( playlist[pos[:position]] ).notifier do |songinfo|
-#        @nextSongLbl.text = ""
-#        songinfo.each_pair do |key, info|
-#          info.each_pair do |src, value|
-#            @nextSongLbl.text += "[#{src}] #{key} = #{value}\n"
-#          end
-#        end
-#        true
-#      end
-#      true
-#    end
-    true
-  end
-
-  def handle_playlist( playlist )
-    @currentPlaylist = playlist
-    playlist.each_with_index do |id, index|
-      current_row = @playlistList.append
-      current_row[0] = index.to_s
-      @server.medialib_get_info( id ).notifier do |songinfo|
-        current_row[1] = songinfo[:artist] ? songinfo[:artist].first[1] : "NONE"
-        current_row[2] = songinfo[:title] ? songinfo[:title].first[1] : "NONE"
-        true
-      end
-    end
-    @playlistView.model = @playlistList
-    true
-  end
 
   def handle_repeat_all_state( state )
     @currentconfig[:"playlist.repeat_all"] = ( state ? "1" : "0" )
@@ -253,6 +482,7 @@ class Grux::ClientWin < Gtk::VBox
     end
   end
 
+
   def handle_repeat_one_state( state )
     @currentconfig[:"playlist.repeat_one"] = ( state ? "1" : "0" )
     @rpt1Btn.signal_handler_block( @rpt1BtnClkdHndlr ) do
@@ -260,6 +490,7 @@ class Grux::ClientWin < Gtk::VBox
     end
   end
 
+
   def toggle_repeat_all
     if @currentconfig[:"playlist.repeat_all"] == "1"
       @server.config_set_value( "playlist.repeat_all", "0" ).notifier do |res|
@@ -283,6 +514,7 @@ class Grux::ClientWin < Gtk::VBox
     true
   end
 
+
   def toggle_repeat_one
     if @currentconfig[:"playlist.repeat_one"] == "1"
       @server.config_set_value( "playlist.repeat_one", "0" ).notifier do |res|
@@ -306,14 +538,23 @@ class Grux::ClientWin < Gtk::VBox
     true
   end
 
-  def resync_state
-    @server.playlist.entries.notifier do |playlist|
-      self.handle_playlist playlist
+
+  def resync_complete
+    @server.playlist.entries.notifier do |playlistids|
+      @status[:playlistids] = playlistids
+      @status[:playlist], @playlistView.model = self.xmmspls_to_lststor( playlistids, @playlistStore )
+      true
+    end
+
+    @server.coll_query_ids( Xmms::Collection.universe ).notifier do |medialibids|
+      @status[:medialibids] = medialibids
+      @status[:medialib], @medialibView.model = self.xmmspls_to_lststor( medialibids, @medialibStore )
       true
     end
 
     @server.playback_current_id.notifier do |id|
-      self.handle_current_song id
+      self.handle_playback_current_id id
+      true
     end
 
     @server.config_list_values.notifier do |res|
@@ -324,24 +565,40 @@ class Grux::ClientWin < Gtk::VBox
 
       @rpt1Btn.signal_handler_block( @rpt1BtnClkdHndlr ) do
         @rpt1Btn.active = if( @currentconfig[:"playlist.repeat_one"] == "1" )
-          true
-        else
-          false
-        end
+                            true
+                          else
+                            false
+                          end
       end
       @rptBtn.signal_handler_block( @rptBtnClkdHndlr ) do
         @rptBtn.active = if @currentconfig[:"playlist.repeat_all"] == "1"
+                           true
+                         else
+                           false
+                         end
+      end
+      true
+    end
+
+    @server.coll_list.notifier do |colls|
+      colls.each do |collname|
+        @server.coll_get( collname ).notifier do |coll|
+          @server.coll_query_ids( coll ).notifier do |ids|
+            p collname
+            p ids.join( "', '" )
+            true
+          end
           true
-        else
-          false
         end
       end
       true
     end
+
     true
   end
 end
 
+
 class Grux::MainWin < Gtk::Window
   def initialize
     super
@@ -350,6 +607,7 @@ class Grux::MainWin < Gtk::Window
     @btnCont        = Gtk::HBox.new
     @clntCont       = Gtk::Notebook.new
 
+    @cnnctInput     = Gtk::ComboBoxEntry.new
     @cnnctBtn       = Gtk::Button.new "_Connect"
     @quitBtn        = Gtk::Button.new "_Quit"
 
@@ -359,13 +617,22 @@ class Grux::MainWin < Gtk::Window
       Gtk.main_quit
     end
 
+    @cnnctInput.append_text 'tcp://127.0.0.1:9667'
+
     @cnnctBtnHndlr  = @cnnctBtn.signal_connect :clicked do
-      @clntCont.append_page( Grux::ClientWin.new, Gtk::Label.new( "Client" ) )
+      if not @cnnctInput.active_text.empty?
+        server_address = @cnnctInput.active_text
+      else
+        server_address = ENV['XMMS_PATH']
+      end
+
+      @clntCont.append_page( Grux::ClientWin.new( server_address ), Gtk::Label.new( server_address ) )
     end
     @quitBtnHndlr   = @quitBtn.signal_connect :clicked do
       Gtk.main_quit
     end
 
+    @btnCont.pack_start @cnnctInput
     @btnCont.pack_start @cnnctBtn
     @btnCont.pack_end @quitBtn
 
@@ -377,6 +644,16 @@ class Grux::MainWin < Gtk::Window
   end
 end
 
+
 gruxWin = Grux::MainWin.new
 Gtk.main
 
+
+#:added
+#:chain
+#:id
+#:laststarted
+#:status
+#:timesplayed
+#:url
+