|  |  |  | @ -271,38 +271,73 @@ func get_private_key(path string, generate bool) ed25519.PrivateKey { | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func print_decoration(window, channels, body ncurses.Window, top_left string) {  | 
		
	
		
			
				|  |  |  |  | func print_decoration(window, title, channels, body ncurses.Window, top_left string) {  | 
		
	
		
			
				|  |  |  |  |   max_y := ncurses.GetMaxY(*ncurses.CurScr) | 
		
	
		
			
				|  |  |  |  |   max_x := ncurses.GetMaxX(*ncurses.CurScr) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   ncurses.WResize(channels, max_y - 2, (max_x / 4) - 1) | 
		
	
		
			
				|  |  |  |  |   ncurses.WResize(body, max_y - 2, max_x - (max_x / 4) - 1) | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWin(body, 2, (max_x / 4) + 1) | 
		
	
		
			
				|  |  |  |  |   ncurses.WResize(window, max_y, max_x) | 
		
	
		
			
				|  |  |  |  |   ncurses.WResize(title, 1, max_x/4-2) | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWin(title, 1, 1) | 
		
	
		
			
				|  |  |  |  |   ncurses.WResize(channels, max_y - 4, (max_x / 4) - 2) | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWin(channels, 3, 1) | 
		
	
		
			
				|  |  |  |  |   ncurses.WResize(body, max_y - 2, max_x - (max_x / 4) - 2) | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWin(body, 1, (max_x / 4) + 1) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWAddStr(window, 0, 0, top_left) | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWAddStr(title, 0, 0, top_left) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   for i := 0; i < max_x; i++ { | 
		
	
		
			
				|  |  |  |  |     ncurses.MvWAddStr(window, 1, i, "═") | 
		
	
		
			
				|  |  |  |  |   for i := 1; i < max_x - 1; i++ { | 
		
	
		
			
				|  |  |  |  |     ncurses.MvWAddStr(window, 0, i, "═") | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWAddStr(window, 1, max_x/4, "╦") | 
		
	
		
			
				|  |  |  |  |   for i := 2; i < max_y; i++ { | 
		
	
		
			
				|  |  |  |  |   for i := 1; i < max_x/4; i++ { | 
		
	
		
			
				|  |  |  |  |     ncurses.MvWAddStr(window, 2, i, "═") | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   for i := 1; i < max_y-1; i++ { | 
		
	
		
			
				|  |  |  |  |     ncurses.MvWAddStr(window, i, 0, "║") | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   for i := 1; i < max_y-1; i++ { | 
		
	
		
			
				|  |  |  |  |     ncurses.MvWAddStr(window, i, max_x-1, "║") | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   for i := 1; i < max_y-1; i++ { | 
		
	
		
			
				|  |  |  |  |     ncurses.MvWAddStr(window, i, max_x/4, "║") | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   for i := 1; i < max_x-1; i++ { | 
		
	
		
			
				|  |  |  |  |     ncurses.MvWAddStr(window, max_y - 1, i, "═") | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWAddStr(window, 0, 0, "╔") | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWAddStr(window, 0, max_x-1, "╗") | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWAddStr(window, 0, max_x/4, "╦") | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWAddStr(window, 2, 0, "╠") | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWAddStr(window, 2, max_x/4, "╣") | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWAddStr(window, max_y-1, 0, "╚") | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWAddStr(window, max_y-1, max_x/4, "╩") | 
		
	
		
			
				|  |  |  |  |   ncurses.MvWAddStr(window, max_y-1, max_x-1, "╝") | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   ncurses.WRefresh(window) | 
		
	
		
			
				|  |  |  |  |   ncurses.WRefresh(title) | 
		
	
		
			
				|  |  |  |  |   ncurses.WRefresh(channels) | 
		
	
		
			
				|  |  |  |  |   ncurses.WRefresh(body) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func main_loop(client *pnyx.Client, audio_data chan []int16, window ncurses.Window, packet_chan chan pnyx.Payload, user_chan chan []byte) { | 
		
	
		
			
				|  |  |  |  |   channels := ncurses.NewWin(0, 0, 2, 0) | 
		
	
		
			
				|  |  |  |  |   body := ncurses.NewWin(0, 0, 2, 0) | 
		
	
		
			
				|  |  |  |  | func main_loop(client *pnyx.Client, audio_data chan []int16, window ncurses.Window, packet_chan chan pnyx.Payload, user_chan chan []byte, sigwinch_channel chan os.Signal) { | 
		
	
		
			
				|  |  |  |  |   channels := ncurses.NewWin(0, 0, 0, 0) | 
		
	
		
			
				|  |  |  |  |   body := ncurses.NewWin(0, 0, 0, 0) | 
		
	
		
			
				|  |  |  |  |   title := ncurses.NewWin(0, 0, 0, 0) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   print_decoration(window, channels, body, fmt.Sprintf("pnyx client %X:%X", client.Key.Public().(ed25519.PublicKey)[:2], client.Session.ID[:2])) | 
		
	
		
			
				|  |  |  |  |   print_decoration(window, title, channels, body, client.Remote()) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   for client.Active() { | 
		
	
		
			
				|  |  |  |  |     select { | 
		
	
		
			
				|  |  |  |  |     case <-sigwinch_channel: | 
		
	
		
			
				|  |  |  |  |       ncurses.EndWin() | 
		
	
		
			
				|  |  |  |  |       ncurses.WRefresh(window) | 
		
	
		
			
				|  |  |  |  |       ncurses.WClear(window) | 
		
	
		
			
				|  |  |  |  |       print_decoration(window, title, channels, body, client.Remote()) | 
		
	
		
			
				|  |  |  |  |     case packet := <-packet_chan: | 
		
	
		
			
				|  |  |  |  |       switch packet := packet.(type) { | 
		
	
		
			
				|  |  |  |  |       case pnyx.ChannelCommandPacket: | 
		
	
	
		
			
				
					|  |  |  | @ -421,7 +456,10 @@ func main() { | 
		
	
		
			
				|  |  |  |  |     panic(ret) | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   go main_loop(client, audio_data, window, packet_chan, user_chan) | 
		
	
		
			
				|  |  |  |  |   sigwinch_channel := make(chan os.Signal, 1) | 
		
	
		
			
				|  |  |  |  |   signal.Notify(sigwinch_channel, syscall.SIGWINCH) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   go main_loop(client, audio_data, window, packet_chan, user_chan, sigwinch_channel) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   os_sigs := make(chan os.Signal, 1) | 
		
	
		
			
				|  |  |  |  |   signal.Notify(os_sigs, syscall.SIGINT, syscall.SIGABRT) | 
		
	
	
		
			
				
					|  |  |  | 
 |