3 #$: << File.expand_path(File.dirname(FILE) + “/../lib”))
5 #require 'libgruxclient'
8 require 'xmmsclient_glib'
13 class Grux::ClientWin < Gtk::VBox
21 @server = Xmms::Client.new( 'Grux' )
23 @server.connect( ENV['XMMS_PATH'] )
24 @server.add_to_glib_mainloop
25 rescue Xmms::Client::ClientError => ex
26 warn "Connection failed. Error Code:"
32 @statusBox = Gtk::HBox.new
33 @mainBox = Gtk::VPaned.new
34 @statusBar = Gtk::Statusbar.new
36 self.pack_start @statusBox, false
37 self.pack_start @mainBox
38 self.pack_end @statusBar, false
42 @currentartistFrame = Gtk::Frame.new( "Artist" ).add( @currentartistLabel = Gtk::Label.new ),
43 @currenttitleFrame = Gtk::Frame.new( "Title" ).add( @currenttitleLabel = Gtk::Label.new ),
44 @currentalbumFrame = Gtk::Frame.new( "Album" ).add( @currentalbumLabel = Gtk::Label.new )
46 @statusWdgts.each { |frame| @statusBox.pack_start frame }
50 @cntrlBox = Gtk::HBox.new,
51 @medialistsWin = Gtk::Notebook.new
53 @mainBox.pack1 @cntrlBox, true, false
54 @mainBox.pack2 @medialistsWin, true, false
58 @cntrlBtnBox = Gtk::VButtonBox.new.set_layout_style( Gtk::ButtonBox::CENTER ),
59 @toolChsr = Gtk::Notebook.new
61 @cntrlBox.pack_start @cntrlBtnBox, false
62 @cntrlBox.pack_start @toolChsr
66 @playBtn = Gtk::ToggleButton.new('_Play', true),
67 @pauseBtn = Gtk::ToggleButton.new('Pa_use', true),
68 @stopBtn = Gtk::ToggleButton.new('_Stop', true),
69 @nextBtn = Gtk::Button.new('_Next'),
70 @prevBtn = Gtk::Button.new('P_revious'),
71 @rndmBtn = Gtk::Button.new('Randomi_ze'),
72 @rptBtn = Gtk::ToggleButton.new('Repeat _All', true),
73 @rpt1Btn = Gtk::ToggleButton.new('Repeat _One', true)
75 @cntrlbtns.each do |button|
76 @cntrlBtnBox.pack_start button
81 [ @extinfoTab = Gtk::VBox.new,
82 @extinfoTabLbl = Gtk::Label.new( "Status" ) ],
83 [ @tageditorTab = Gtk::VBox.new,
84 @tageditorTabLbl = Gtk::Label.new( "Tag Editor" ) ]
86 @toolTabs.each do |content, label|
87 @toolChsr.append_page( Gtk::ScrolledWindow.new.add_with_viewport( content ), label )
91 @medialistTextRenderer = Gtk::CellRendererText.new
92 @medialistColumns = [ 'id', 'artist', 'title' ]
95 [ @plalistViewLbl = Gtk::Label.new( "Current Playlist" ),
96 @playlistViewWin = Gtk::ScrolledWindow.new,
97 @playlistView = Gtk::TreeView.new,
98 @playlistStore = Gtk::ListStore.new( String, String, String )
100 [ @medialibViewLbl = Gtk::Label.new( "Medialib" ),
101 @medialibViewWin = Gtk::ScrolledWindow.new,
102 @medialibView = Gtk::TreeView.new,
103 @medialibList = Gtk::ListStore.new( String, String, String )
107 @medialists.each do |label, window, view, store|
108 @medialistColumns.each_with_index do |tag, index|
109 view.append_column Gtk::TreeViewColumn.new( tag, @medialistTextRenderer, :text => index )
111 @medialistsWin.append_page( window.add( view ), label )
118 @server.broadcast_coll_changed do |*foo|
121 @server.broadcast_config_value_changed do |*foo|
124 @server.broadcast_mediainfo_reader_status do |*foo|
127 @server.broadcast_medialib_entry_added do |*foo|
130 @server.broadcast_medialib_entry_changed do |*foo|
133 @server.broadcast_playback_current_id.notifier do |id|
134 self.handle_current_id id
136 @server.broadcast_playback_status.notifier do |playing|
137 self.handle_playback_status playing
139 @server.broadcast_playback_volume_changed do |*foo|
142 @server.broadcast_playlist_changed do |*foo|
145 @server.broadcast_playlist_current_pos.notifier do |pos|
146 self.handle_current_pos pos
148 @server.broadcast_playlist_loaded do |*foo|
151 @server.broadcast_quit do |*foo|
156 @playBtnClkdHndlr = @playBtn.signal_connect :clicked do
159 @pauseBtnClkdHndlr = @pauseBtn.signal_connect :clicked do
162 @stopBtnClkdHndlr = @stopBtn.signal_connect :clicked do
165 @nextBtn.signal_connect :clicked do
166 self.step_in_playlist 1
168 @prevBtn.signal_connect :clicked do
169 self.step_in_playlist -1
171 @rndmBtn.signal_connect :clicked do
172 self.randomize_playlist
174 @rptBtnClkdHndlr = @rptBtn.signal_connect :clicked do
175 self.toggle_repeat_all
177 @rpt1BtnClkdHndlr = @rpt1Btn.signal_connect :clicked do
178 self.toggle_repeat_one
182 @playlistView.signal_connect :row_activated do |view, path, column|
183 @server.playlist_set_next( path.to_str.to_i ).notifier do
184 @server.playback_tickle.notifier do
193 @medialibView.signal_connect :row_activated do |view, path, column|
194 @server.playlist.add_entry( path.to_str.to_i ).notifier do
195 @server.playlist_set_next( path.to_str.to_i ).notifier do
196 @server.playback_tickle.notifier do
211 def xmmspls_to_lststor( playlist, store )
212 @status[:playlist] = playlist
213 playlist.each_with_index do |id, index|
214 current_row = store.append
215 @server.medialib_get_info( id ).notifier do |songinfo|
216 current_row[0] = index.to_s
217 current_row[1] = songinfo[:artist] ? songinfo[:artist].first[1] : ""
218 current_row[2] = songinfo[:title] ? songinfo[:title].first[1] : ""
226 def handle_current_id( id )
227 songpath = Gtk::TreePath.new( @status[:playlist].index id )
228 @playlistView.scroll_to_cell( songpath, nil, true, 0.5, 0.5 )
229 @playlistView.set_cursor( songpath, nil, false )
230 @server.medialib_get_info( id ).notifier do |songinfo|
231 @currentartistLabel.text = ""
232 @currenttitleLabel.text = ""
233 @currentalbumLabel.text = ""
235 @extinfoTab.each do |child| @extinfoTab.remove child end
237 songinfo[:artist] && songinfo[:artist].each_pair do |src, value|
238 @currentartistLabel.text += @currentartistLabel.text.empty? ? value : "\n#{value}"
240 songinfo[:title] && songinfo[:title].each_pair do |src, value|
241 @currenttitleLabel.text += @currenttitleLabel.text.empty? ? value : "\n#{value}"
243 songinfo[:album] && songinfo[:album].each_pair do |src, value|
244 @currentalbumLabel.text += @currentalbumLabel.text.empty? ? value : "\n#{value}"
246 songinfo.each_key do |key|
248 songinfo[key].each_pair do |src,value|
249 p key, value if src == :server
250 infos.empty? || infos += "\n"
251 infos += "#{value} (#{src})"
253 @extinfoTab.pack_end( Gtk::Frame.new( key.to_s ).add( Gtk::Label.new( infos ) ) )
264 @server.playback_start.notifier do |res|
265 @playBtn.signal_handler_block( @playBtnClkdHndlr ) do
266 @playBtn.active = true
268 @pauseBtn.signal_handler_block( @pauseBtnClkdHndlr ) do
269 @pauseBtn.active = false
271 @stopBtn.signal_handler_block( @stopBtnClkdHndlr ) do
272 @stopBtn.active = false
274 @statusBar.push( @statusBar.get_context_id( "playback" ), "Started playback" )
281 @server.playback_pause.notifier do |res|
282 @playBtn.signal_handler_block( @playBtnClkdHndlr ) do
283 @playBtn.active = false
285 @pauseBtn.signal_handler_block( @pauseBtnClkdHndlr ) do
286 @pauseBtn.active = true
288 @stopBtn.signal_handler_block( @stopBtnClkdHndlr ) do
289 @stopBtn.active = false
291 @statusBar.push( @statusBar.get_context_id( "playback" ), "Paused playback" )
298 @server.playback_stop.notifier do |res|
299 @playBtn.signal_handler_block( @playBtnClkdHndlr ) do
300 @playBtn.active = false
302 @pauseBtn.signal_handler_block( @pauseBtnClkdHndlr ) do
303 @pauseBtn.active = false
305 @stopBtn.signal_handler_block( @stopBtnClkdHndlr ) do
306 @stopBtn.active = true
308 @statusBar.push( @statusBar.get_context_id( "playback" ), "Stopped playback" )
315 if @playbackState == 1
316 @server.playback_pause.notifier do |res|
317 @statusBar.push( @statusBar.get_context_id( "playback" ), "Paused playback" )
320 elsif @playbackState == 0 || 2
321 @server.playback_start.notifier do |res|
322 @statusBar.push( @statusBar.get_context_id( "playback" ), "Started playback" )
326 warn "Playbackstate unknown"
327 @server.playback_start.notifier do |res|
328 @statusBar.push( @statusBar.get_context_id( "playback" ), "Started playback" )
335 def step_in_playlist( offset = 1 )
336 @server.playlist_set_next_rel( offset ).notifier do
337 @server.playback_tickle.notifier do |res|
338 @statusBar.push( @statusBar.get_context_id( "playback" ), "Skipped playback by #{offset} song#{offset.abs >= 1 ? "s" : ''}" )
346 def handle_playback_status( status )
347 @playbackState = status
352 def handle_current_pos( pos )
353 #@server.playlist.entries.notifier do |playlist|
354 # @server.medialib_get_info( playlist[pos[:position]] ).notifier do |songinfo|
355 # @nextSongLbl.text = ""
356 # songinfo.each_pair do |key, info|
357 # info.each_pair do |src, value|
358 # @nextSongLbl.text += "[#{src}] #{key} = #{value}\n"
369 def handle_repeat_all_state( state )
370 @currentconfig[:"playlist.repeat_all"] = ( state ? "1" : "0" )
371 @rptBtn.signal_handler_block( @rptBtnClkdHndlr ) do
372 @rptBtn.active = state
377 def handle_repeat_one_state( state )
378 @currentconfig[:"playlist.repeat_one"] = ( state ? "1" : "0" )
379 @rpt1Btn.signal_handler_block( @rpt1BtnClkdHndlr ) do
380 @rpt1Btn.active = state
385 def toggle_repeat_all
386 if @currentconfig[:"playlist.repeat_all"] == "1"
387 @server.config_set_value( "playlist.repeat_all", "0" ).notifier do |res|
388 @server.config_get_value( "playlist.repeat_all" ).notifier do |value|
389 self.handle_repeat_all_state( value == "1" ? true : false )
394 elsif @currentconfig[:"playlist.repeat_all"] == "0"
395 @server.config_set_value( "playlist.repeat_all", "1" ).notifier do |res|
396 @server.config_get_value( "playlist.repeat_all" ).notifier do |value|
397 self.handle_repeat_all_state( value == "1" ? true : false )
403 warn "Unknown state: #{@currentconfig[:"playlist.repeat_all"]}"
409 def toggle_repeat_one
410 if @currentconfig[:"playlist.repeat_one"] == "1"
411 @server.config_set_value( "playlist.repeat_one", "0" ).notifier do |res|
412 @server.config_get_value( "playlist.repeat_one" ).notifier do |value|
413 self.handle_repeat_one_state( value == "1" ? true : false )
418 elsif @currentconfig[:"playlist.repeat_one"] == "0"
419 @server.config_set_value( "playlist.repeat_one", "1" ).notifier do |res|
420 @server.config_get_value( "playlist.repeat_one" ).notifier do |value|
421 self.handle_repeat_one_state( value == "1" ? true : false )
427 warn "Unknown state: #{@currentconfig[:"playlist.repeat_one"]}"
434 @server.playlist.entries.notifier do |playlist|
435 @playlistView.model = self.xmmspls_to_lststor( playlist, @playlistStore )
439 @server.playback_current_id.notifier do |id|
440 self.handle_current_id id
443 @server.config_list_values.notifier do |res|
445 res.each_pair do |key, value|
446 @currentconfig[key] = value
449 @rpt1Btn.signal_handler_block( @rpt1BtnClkdHndlr ) do
450 @rpt1Btn.active = if( @currentconfig[:"playlist.repeat_one"] == "1" )
456 @rptBtn.signal_handler_block( @rptBtnClkdHndlr ) do
457 @rptBtn.active = if @currentconfig[:"playlist.repeat_all"] == "1"
466 @server.coll_list.notifier do |colls|
467 colls.each do |collname|
468 @server.coll_get( collname ).notifier do |coll|
469 @server.coll_query_ids( coll ).notifier do |ids|
480 @server.coll_query_ids( Xmms::Collection.universe ).notifier do |medialibids|
481 p medialibids.join( ", " )
489 class Grux::MainWin < Gtk::Window
493 @mainCont = Gtk::VBox.new
494 @btnCont = Gtk::HBox.new
495 @clntCont = Gtk::Notebook.new
497 @cnnctBtn = Gtk::Button.new "_Connect"
498 @quitBtn = Gtk::Button.new "_Quit"
502 @winDstryHndlr = self.signal_connect :destroy do
506 @cnnctBtnHndlr = @cnnctBtn.signal_connect :clicked do
508 @clntCont.append_page( Grux::ClientWin.new, Gtk::Label.new( "Client" ) )
509 rescue Xmms::Client::ClientError => ex
513 @quitBtnHndlr = @quitBtn.signal_connect :clicked do
517 @btnCont.pack_start @cnnctBtn
518 @btnCont.pack_end @quitBtn
520 @mainCont.pack_start @btnCont, false
521 @mainCont.pack_end @clntCont
529 gruxWin = Grux::MainWin.new