From faeddf5152825c77492bebaab2a9fd8f20292dc1 Mon Sep 17 00:00:00 2001 From: Kostyantyn Ovechko Date: Wed, 4 Aug 2010 16:58:13 +0300 Subject: Add --wait-distfile=distfile_name option to cli of tuiclient tuiclient checks distfile status, and returns when distfile is downloaded or not in the queue. --- segget/connection.cpp | 9 ++ segget/distfile.cpp | 7 +- segget/ui_server.cpp | 81 +++++++++++-- tuiclient/colors.cpp | 48 +++++++- tuiclient/colors.h | 7 +- tuiclient/distfilewindow.cpp | 37 +++++- tuiclient/mainwindow.cpp | 46 ++++++-- tuiclient/mainwindow.h | 10 +- tuiclient/scrollwindow.cpp | 4 +- tuiclient/settings.h | 4 + tuiclient/tuiclient.cpp | 266 +++++++++++++++++++++++++++++++++---------- tuiclient/tuiclient.h | 9 +- tuiclient/tuidistfile.cpp | 30 +++++ tuiclient/tuidistfile.h | 17 +++ tuiclient/twindow.cpp | 2 +- tuiclient/twindow.h | 6 +- 16 files changed, 478 insertions(+), 105 deletions(-) diff --git a/segget/connection.cpp b/segget/connection.cpp index 5cf8bb3..5aa8453 100644 --- a/segget/connection.cpp +++ b/segget/connection.cpp @@ -51,6 +51,8 @@ int Tconnection::start(CURLM *cm, uint network_number, uint distfile_num, Tsegme segment->parent_distfile->active_connections_num++; + segment->parent_distfile->status=DDOWNLOADING; + if (network_array[network_num].network_mode==MODE_PROXY_FETCHER){ connection_start_time_network_phase_for_pf_networks=segment->parent_distfile->network_distfile_brokers_array[network_num].phase; } @@ -197,6 +199,13 @@ void Tconnection::stop(CURLcode connection_result){ debug(" Successful download "+segment->url); // already done earlier in this function Pcurr_mirror=find_mirror(strip_mirror_name(segment->url)); segment->status=SDOWNLOADED; + if (segment->parent_distfile->status!=DFAILED){ + if (segment->parent_distfile->active_connections_num>0){ + segment->parent_distfile->status=DDOWNLOADING; + }else{ + segment->parent_distfile->status=DWAITING; + } + } segment->parent_distfile->inc_dld_segments_count(segment); }; }catch(...){ diff --git a/segget/distfile.cpp b/segget/distfile.cpp index 1bc122d..9276af7 100644 --- a/segget/distfile.cpp +++ b/segget/distfile.cpp @@ -671,7 +671,8 @@ int Tdistfile::provide_segment(CURLM* cm, uint connection_num, uint seg_num){ string Tdistfile::get_distfile_progress_str(){ try{ - return name+" "+toString(dld_segments_count)+" "+toString(segments_count)+" "+toString(dld_bytes)+" "+toString(size); + return name+"<>"+toString(status)+"<>"+toString(dld_segments_count)+"<>"+toString(segments_count)\ + +"<>"+toString(dld_bytes)+"<>"+toString(size); }catch(...){ error_log("Error: distfile.cpp: get_distfile_progress_str()"); return ""; @@ -681,12 +682,12 @@ string Tdistfile::get_distfile_progress_str(){ void Tdistfile::inc_dld_segments_count(Tsegment* current_segment){ try{ stats.inc_dld_size(current_segment->segment_size); - dld_bytes+=current_segment->segment_size; - ui_server.send_distfile_progress_msg_to_all_clients(get_distfile_progress_str()); if (++dld_segments_count==segments_count){ combine_segments(); } stats.dld_segments_count++; + dld_bytes+=current_segment->segment_size; + ui_server.send_distfile_progress_msg_to_all_clients(get_distfile_progress_str()); }catch(...){ error_log("Error: distfile.cpp: inc_dld_segments_count()"); } diff --git a/segget/ui_server.cpp b/segget/ui_server.cpp index 8464e70..967112e 100644 --- a/segget/ui_server.cpp +++ b/segget/ui_server.cpp @@ -28,6 +28,12 @@ Tui_server ui_server; +enum TDFsearch_rusults{ + NOT_FOUND, + DOWNLOADED, + IN_QUEUE +}; + void Tui_server::init(){ socklen_t server_len; struct sockaddr_in server_address; @@ -153,29 +159,80 @@ void *run_ui_server(void * ){ FD_SET(client_sockfd, &ui_server.readfds); - // Get this info to catch up! - for (uint line_num=0; line_num<=max_published_screenline_num;line_num++){ - ui_server.send_connection_msg_to_fd(client_sockfd, line_num, screenlines[line_num]); - debug_no_msg("Sending to client line:"+toString(line_num)+" "+screenlines[line_num]); -// ui_server.send(line_num,screenlines[line_num]); - } - for (ulong distfile_num=0; distfile_numget_distfile_progress_str()); - } -// if (0==pkg_choose_segment(&proxy_fetcher_pkg, connection_num)){ - //If it isn’t the server, it must be client activity. If close is received, the client has gone away, and you remove it from the descriptor set. Otherwise, you “serve” the client as in the previous examples. }else{ + debug("else"); ioctl(fd, FIONREAD, &nread); if(nread == 0) { - close(fd); + debug("nothing to read"); FD_CLR(fd, &ui_server.readfds); + close(fd); debug("Client parted from fd:"+toString(fd)); }else{ + error_log("reading buffer"); char buffer[1000]; if (nread!=read(fd, &buffer, nread)){ debug("Not all data has been read from ui_client()"); } + string request_str_before,request_str_after; + error_log("received_from tuiclient:"); + error_log(buffer); + split("",buffer,request_str_before,request_str_after); + split("<.>",request_str_after,request_str_before,request_str_after); + string distfile_by_name_lookup_request=request_str_before; + TDFsearch_rusults distfile_search_result=NOT_FOUND; + if (distfile_by_name_lookup_request.length()>0){ + for (ulong distfile_num=0; distfile_numname){ + if (request_server_pkg.Pdistfile_list[distfile_num]->status==DDOWNLOADED){ + distfile_search_result=DOWNLOADED; + }else{ + distfile_search_result=IN_QUEUE; + } + break; + } + } + if (distfile_search_result==NOT_FOUND){ + for (ulong distfile_num=0; distfile_numname){ + if (proxy_fetcher_pkg.Pdistfile_list[distfile_num]->status==DDOWNLOADED){ + distfile_search_result=DOWNLOADED; + }else{ + distfile_search_result=IN_QUEUE; + } + break; + } + } + } + }else{ + // if no name for distfile specified -> no need to find distfile + // just keep an eye on the ones in queue + distfile_search_result=IN_QUEUE; + } + switch (distfile_search_result){ + case NOT_FOUND: + ui_server.send_to_fd(fd, "n<.>"); //distfile is not in the list quit + break; + case DOWNLOADED: + ui_server.send_to_fd(fd, "N<.>"); //distfile is not in the list quit + break; + case IN_QUEUE: + string err_msg="Found distfile by name:"; + err_msg=err_msg+buffer; + error_log(err_msg); + ui_server.send_to_fd(fd, "y<.>"); //distfile is in the list continue + // Get this info to catch up! + for (uint line_num=0; line_num<=max_published_screenline_num;line_num++){ + ui_server.send_connection_msg_to_fd(fd, line_num, screenlines[line_num]); + debug_no_msg("Sending to client line:"+toString(line_num)+" "+screenlines[line_num]); + } + for (ulong distfile_num=0; distfile_numget_distfile_progress_str()); + } + for (ulong distfile_num=0; distfile_numget_distfile_progress_str()); + } + } } } } diff --git a/tuiclient/colors.cpp b/tuiclient/colors.cpp index 0b1959d..a8b380c 100644 --- a/tuiclient/colors.cpp +++ b/tuiclient/colors.cpp @@ -26,10 +26,44 @@ #include "colors.h" -void color_default_window(WINDOW * window){ +void color_distfile_added(WINDOW * window){ + if(has_colors()){ + start_color(); /* Start color */ + wattron(window, COLOR_PAIR(4)); + } +} + +void color_distfile_waiting(WINDOW * window){ + if(has_colors()){ + start_color(); /* Start color */ + wattron(window, COLOR_PAIR(8)); + } +} + +void color_distfile_downloading(WINDOW * window){ + if(has_colors()){ + start_color(); /* Start color */ + wattron(window, COLOR_PAIR(6)); + } +} + +void color_distfile_downloaded(WINDOW * window){ + if(has_colors()){ + start_color(); /* Start color */ + wattron(window, COLOR_PAIR(5)); + } +} + +void color_distfile_failed(WINDOW * window){ + if(has_colors()){ + start_color(); /* Start color */ + wattron(window, COLOR_PAIR(7)); + } +} + +void color_distfiles_window(WINDOW * window){ if(has_colors()){ start_color(); /* Start color */ - wbkgd(window, COLOR_PAIR(4)); wattron(window, COLOR_PAIR(4)); } } @@ -73,8 +107,11 @@ void colors_connected(){ init_pair(1, COLOR_WHITE, COLOR_BLUE); init_pair(2, COLOR_BLACK, COLOR_CYAN); init_pair(3, COLOR_GREEN, COLOR_BLUE); - init_pair(4, COLOR_BLACK, COLOR_GREEN); + init_pair(4, COLOR_WHITE, COLOR_BLACK); init_pair(5, COLOR_GREEN, COLOR_BLACK); + init_pair(6, COLOR_BLUE, COLOR_BLACK); + init_pair(7, COLOR_RED, COLOR_BLACK); + init_pair(8, COLOR_YELLOW, COLOR_BLACK); // init_pair(4, COLOR_BLACK, COLOR_WHITE); // attrset(A_REVERSE); attrset(A_DIM); @@ -89,7 +126,10 @@ void colors_disconnected(){ init_pair(2, COLOR_WHITE, COLOR_BLACK); init_pair(3, COLOR_BLACK, COLOR_RED); init_pair(4, COLOR_WHITE, COLOR_BLACK); - init_pair(5, COLOR_RED, COLOR_BLACK); + init_pair(5, COLOR_WHITE, COLOR_BLACK); + init_pair(6, COLOR_WHITE, COLOR_BLACK); + init_pair(7, COLOR_WHITE, COLOR_BLACK); + init_pair(8, COLOR_WHITE, COLOR_BLACK); /// attrset(A_BOLD); // attrset(A_REVERSE); } diff --git a/tuiclient/colors.h b/tuiclient/colors.h index ea77f02..1e63bec 100644 --- a/tuiclient/colors.h +++ b/tuiclient/colors.h @@ -30,7 +30,12 @@ he terms of the GNU Lesser General Public #include -void color_default_window(WINDOW * window); +void color_distfile_added(WINDOW * window); +void color_distfile_waiting(WINDOW * window); +void color_distfile_downloading(WINDOW * window); +void color_distfile_downloaded(WINDOW * window); +void color_distfile_failed(WINDOW * window); +void color_distfiles_window(WINDOW * window); void color_scroll_window(WINDOW * window); void color_downloads(WINDOW * window); void color_info(WINDOW * window); diff --git a/tuiclient/distfilewindow.cpp b/tuiclient/distfilewindow.cpp index 22c7f49..718f9fe 100644 --- a/tuiclient/distfilewindow.cpp +++ b/tuiclient/distfilewindow.cpp @@ -27,7 +27,7 @@ #include "distfilewindow.h" void Tdistfile_window::compose(){ - color_default_window(window); +// color_distfiles_window(window); make_frame(); // box(window, ACS_VLINE, ACS_HLINE); // getmaxyx(window,height,width); @@ -41,15 +41,46 @@ void Tdistfile_window::compose(){ // color_downloads(window); // screenlines[26]="Max_num:"+toString(max_received_screenline_num); ulong distfile_num=top_position; - for (int y=0; y0) + percent="("+toString(tuidistfiles[distfile_num].dld_bytes*100/tuidistfiles[distfile_num].size)+"%) "; + else + percent="(n/a%)"; + + switch (tuidistfiles[distfile_num].status){ + case DNEW: + case D_NOT_PROXY_REQUESTED: + case DPROXY_REJECTED: + case DPROXY_QUEUED: + case DPROXY_DOWNLOADING: + case DPROXY_DOWNLOADED: + case DPROXY_FAILED: + color_distfile_added(window); + break; + case DWAITING: + color_distfile_waiting(window); + break; + case DDOWNLOADING: + color_distfile_downloading(window); + break; + case DDOWNLOADED: + color_distfile_downloaded(window); + break; + case DFAILED: + color_distfile_failed(window); + break; + } msg_line(y+1,field("",distfile_num+1,4)+") " - +"("+toString(tuidistfiles[distfile_num].dld_bytes*100/tuidistfiles[distfile_num].size)+"%) " + +percent +tuidistfiles[distfile_num].name + +" ["+tuidistfiles[distfile_num].statusToString()+"]" +" Segments: "+toString(tuidistfiles[distfile_num].dld_segments) +"/"+toString(tuidistfiles[distfile_num].segments_count) +" Bytes: "+toString(tuidistfiles[distfile_num].dld_bytes) +"/"+toString(tuidistfiles[distfile_num].size)); } +// color_distfiles_window(window); wrefresh(window); // mainwindow.distfiles_win.add_line(parts[0]+"("+toString(atol(parts[3].c_str())*100/)+"%)"+" "+parts[1]+"/"+parts[2]+" "+parts[3]+"/"+parts[4]); } diff --git a/tuiclient/mainwindow.cpp b/tuiclient/mainwindow.cpp index 55a16e7..1164c50 100644 --- a/tuiclient/mainwindow.cpp +++ b/tuiclient/mainwindow.cpp @@ -27,17 +27,20 @@ #include "mainwindow.h" void Tmainwindow::connected(){ - for (int line_num=0; line_num<=max_received_screenline_num; line_num++){ - screenlines[line_num]=""; - } + scroll_lines.clear(); +// for (int line_num=0; line_num<=max_received_screenline_num; line_num++){ +// screenlines[line_num]=""; +// } max_received_screenline_num=0; colors_connected(); set_status("[Connected]"); +// notfresh=true; } void Tmainwindow::disconnected(){ colors_disconnected(); set_status("[Connecting... Attempt:"+toString(attempt_num)+". Waiting for 1 sec, before next reconnect.]"); +// notfresh=true; } void Tmainwindow::msg_status(){ msg_short(0,2,"Tuiclient "+status_str); @@ -48,19 +51,28 @@ void Tmainwindow::msg_status(){ } void Tmainwindow::compose(){ - //clear(); - box(window, ACS_VLINE, ACS_HLINE); +// wclear(window); +// box(window, ACS_VLINE, ACS_HLINE); getmaxyx(window,height,width); - screenlines[27]=sms; +// resize(height,width,0,0); +// screenlines[27]=sms; bottom_screenline_num=height-2; color_status(window); + make_frame(); msg_status(); color_info(window); msg_short(height-1,2,screen_info_lines[0]); color_downloads(window); // screenlines[26]="Max_num:"+toString(max_received_screenline_num); - for (int y=0, line_num=top_position; y -void quit(){ - mainwindow.exit_flag=TRUE; - try{ - close(sockfd); - } - catch(...) - { - //error while closing socket - } - try{ - close(sockfd); -// sleep(1); - nocbreak(); - endwin(); - exit(0); - } - catch(...) - { - //error while ending curses - } -} Twindow * next_window(){ cur_window_num++; if (cur_window_num>3) cur_window_num=0; @@ -75,22 +55,78 @@ Twindow * next_window(){ return &mainwindow; } +/* +void * watch_keyboard_thread_function(void *){ + Twindow * cur_window=&mainwindow.distfiles_win; + while (not exit_flag){ + int key=getch(); + if (key==ERR){ + mainwindow.refresh(); + struct timeval delay; + delay.tv_sec=0; + delay.tv_usec=300000; + select(FD_SETSIZE, (fd_set *)0, (fd_set *)0,(fd_set *)0, (struct timeval *) &delay);//&timeout + }else{ + switch (key){ + //tab - move between windows + case (char)9:cur_window=next_window(); + //KEY_DOWN + case (char)2:cur_window->down(1);mainwindow.set_line(25,toString((int)key));break; + //KEY_RIGHT + case (char)5:cur_window->down(1);mainwindow.set_line(25,toString((int)key));break; + //KEY_UP + case (char)3:cur_window->up(1);mainwindow.set_line(25,toString((int)key));break; + //KEY_LEFT + case (char)4:cur_window->up(1);mainwindow.set_line(25,toString((int)key));break; + //KEY_PG_DOWN + case (char)82:cur_window->down(mainwindow.bottom_screenline_num);break; + //KEY_PG_UP + case (char)83:cur_window->up(mainwindow.bottom_screenline_num);break; + case 'd': + case 'D':mainwindow.distfiles_win.toggle(); + mainwindow.log_win.visible=false; + mainwindow.error_log_win.visible=false; + cur_window=&mainwindow.distfiles_win; + mainwindow.show(); + break; + case 'q': + case 'Q':quit(0,"Interrupted by user");break; + case 'h': + case 'H':mainwindow.help_win.toggle(); mainwindow.show();break; + case 'l': + case 'L':mainwindow.log_win.toggle(); mainwindow.show();break; + case 'e': + case 'E':mainwindow.error_log_win.toggle(); mainwindow.show();break; + default: mainwindow.set_line(25,toString((int)key)); + } + } + } +// pthread_exit((void*)watch_keyboard_thread_status); + exit_curses_and_show_msg(); + return (void*)0; + //watch_keyboard_thread_status; +} + +void * refresh_screen_thread_function(void *){ + return (void*)0; +} +*/ void * watch_keyboard_thread_function(void *){ Twindow * cur_window=&mainwindow.distfiles_win; - while (true){ + while (not exit_flag){ char key=getch(); switch (key){ //tab - move between windows case (char)9:cur_window=next_window(); //KEY_DOWN - case (char)2:cur_window->down(1);mainwindow.screenlines[25]=toString((int)key);break; + case (char)2:cur_window->down(1);mainwindow.set_line(25,toString((int)key));break; //KEY_RIGHT - case (char)5:cur_window->down(1);mainwindow.screenlines[25]=toString((int)key);break; + case (char)5:cur_window->down(1);mainwindow.set_line(25,toString((int)key));break; //KEY_UP - case (char)3:cur_window->up(1);mainwindow.screenlines[25]=toString((int)key);break; + case (char)3:cur_window->up(1);mainwindow.set_line(25,toString((int)key));break; //KEY_LEFT - case (char)4:cur_window->up(1);mainwindow.screenlines[25]=toString((int)key);break; + case (char)4:cur_window->up(1);mainwindow.set_line(25,toString((int)key));break; //KEY_PG_DOWN case (char)82:cur_window->down(mainwindow.bottom_screenline_num);break; //KEY_PG_UP @@ -103,27 +139,31 @@ void * watch_keyboard_thread_function(void *){ mainwindow.show(); break; case 'q': - case 'Q':quit();break; + case 'Q':quit(0,"Interrupted by user");break; case 'h': case 'H':mainwindow.help_win.toggle(); mainwindow.show();break; case 'l': case 'L':mainwindow.log_win.toggle(); mainwindow.show();break; case 'e': case 'E':mainwindow.error_log_win.toggle(); mainwindow.show();break; - default: mainwindow.screenlines[25]=toString((int)key); + default: mainwindow.set_line(25,toString((int)key)); } } - return 0; +// pthread_exit((void*)watch_keyboard_thread_status); + return (void*)watch_keyboard_thread_status; } void * refresh_screen_thread_function(void *){ - while (! mainwindow.exit_flag){ - mainwindow.refresh(); + while (! exit_flag){ + mainwindow.refresh(); + mainwindow.refresh(); +// sleep(1); struct timeval delay; delay.tv_sec=0; delay.tv_usec=300000; select(FD_SETSIZE, (fd_set *)0, (fd_set *)0,(fd_set *)0, (struct timeval *) &delay);//&timeout } + exit_curses_and_show_msg(); return 0; } @@ -138,11 +178,18 @@ void decode_connection_msg(string msg_body){ mainwindow.screen_info_lines[line_num-200]=parts.after; } } +/* void decode_downloaded_distfile_msg(string msg_body){ vector parts; parts=split_to_vector(" ", msg_body); if (parts.size()>4){ +// if (settings.arg_wait_distfile!=""){ +// if (parts[0]==settings.arg_wait_distfile){ +// cant_find_distfile_exit_flag==false; +// if +// } +// } for (ulong cur_distfile=0;cur_distfile parts; + parts=split_to_vector("<>", msg_body); + if (parts.size()>5){ + for (ulong cur_distfile=0;cur_distfile999){ + quit(1,"Error in argument --wait-distfile="+settings.arg_wait_distfile+" : Distfile name is too long"); + }; + char send_buffer[10000]; + string send_msg=""+settings.arg_wait_distfile+"<.>"; + strcpy(send_buffer,send_msg.c_str()); + if (write(sockfd, send_buffer, strlen(send_buffer))!=(int)send_msg.length()){ + perror("Error in request.cpp: request(): request msg size and sent data size are different."); + } + fd_set readfds, testfds; FD_ZERO(&readfds); @@ -273,6 +419,15 @@ int main() case 'l': decode_log_msg(msg_parts.before);break; case 'e': decode_error_log_msg(msg_parts.before);break; case 'd': decode_downloaded_distfile_msg(msg_parts.before);break; + // yes-distfile present in the queue + case 'y': break; // continue waiting for catchup info + // no distfile in the queue + case 'n': + quit(1,"Distfile: "+settings.arg_wait_distfile+" is not in the queue - quit"); + break; //shouldn't get to this point - but just in case + case 'N': + quit(0,"Distfile: "+settings.arg_wait_distfile+" is already downloaded - quit"); + break; //shouldn't get to this point - but just in case } } }; @@ -283,17 +438,12 @@ int main() }catch(...){ // error_log_no_msg("Error in segget.cpp launch_tui_theread() failed"); } + + }catch(...){ + perror("error during init and downloading process"); } - catch(...){ - //error during init and downloading process - } - try{ - nocbreak(); - endwin(); - } - catch(...) - { - //error while ending curses + while (1){ + sleep(10); } - return 0; + quit(0,""); } \ No newline at end of file diff --git a/tuiclient/tuiclient.h b/tuiclient/tuiclient.h index cf1223c..708c843 100644 --- a/tuiclient/tuiclient.h +++ b/tuiclient/tuiclient.h @@ -57,10 +57,17 @@ using namespace std; +bool exit_flag=false; +bool thread_exited=false; +string exit_msg=""; +int exit_code=0; +int watch_keyboard_thread_status=10; +pthread_t watch_keyboard_thread; Tmainwindow mainwindow; int cur_window_num=0; int sockfd; -void quit(); +void exit_curses_and_show_msg(); +void quit(int exit_code, string error_msg); void * watch_keyboard_thread_function(void * ptr); void * refresh_screen_thread_function(void * ptr); \ No newline at end of file diff --git a/tuiclient/tuidistfile.cpp b/tuiclient/tuidistfile.cpp index 09bd414..45d135d 100644 --- a/tuiclient/tuidistfile.cpp +++ b/tuiclient/tuidistfile.cpp @@ -27,5 +27,35 @@ #include "tuidistfile.h" +string Ttuidistfile::statusToString(){ + try{ + switch(status){ + case DNEW: return "Added"; + case D_NOT_PROXY_REQUESTED: return "Not proxy requested"; + case DPROXY_REJECTED: return "Proxy rejected"; + case DPROXY_QUEUED: return "Proxy queued"; + case DPROXY_DOWNLOADING: return "Downloading via proxy"; + case DPROXY_DOWNLOADED: return "Downloaded via proxy"; + case DPROXY_FAILED: return "Failed"; + case DWAITING: return "Waiting"; + case DDOWNLOADING: return "Downloading"; + case DDOWNLOADED: return "Downloaded"; + case DFAILED: return "Failed"; + } + }catch(...){ + error_log("Error: distfile.cpp: statusToString()"); + } + return "UNKNOWN status"; +} + +long find_distfile_by_name(string distfile_name){ + try{ + for (ulong cur_distfile=0;cur_distfile tuidistfiles; diff --git a/tuiclient/twindow.cpp b/tuiclient/twindow.cpp index d451435..080506d 100644 --- a/tuiclient/twindow.cpp +++ b/tuiclient/twindow.cpp @@ -73,7 +73,7 @@ void Twindow::up(int inc){ } void Twindow::down(uint inc){ - int tmp_top_position=top_position+inc; + uint tmp_top_position=top_position+inc; // if we need to scroll down if (max_received_screenline_num>bottom_screenline_num){ notfresh=TRUE; diff --git a/tuiclient/twindow.h b/tuiclient/twindow.h index 89c5108..533b101 100644 --- a/tuiclient/twindow.h +++ b/tuiclient/twindow.h @@ -44,9 +44,9 @@ class Twindow{ uint x; bool notfresh; bool visible; - int top_position; - int bottom_screenline_num; - int max_received_screenline_num; + uint top_position; + uint bottom_screenline_num; + uint max_received_screenline_num; string status_str; Twindow(): -- cgit v1.2.3-65-gdbad