tFix for Win32 high score bug; score file now fflush'ed after writes to be more crash-tolerant and multi-user friendly; gtk_clists, gtk_texts and gtk_paneds made more usable on Win32. - vaccinewars - be a doctor and try to vaccinate the world (HTM) git clone git://src.adamsgaard.dk/vaccinewars (DIR) Log (DIR) Files (DIR) Refs (DIR) README (DIR) LICENSE --- (DIR) commit 5f2248351aaab50e701b92db134223fbf74f763b (DIR) parent fc6e83182ef84919681049077dc6791fd7515a9e (HTM) Author: Ben Webb <ben@salilab.org> Date: Sun, 13 May 2001 03:24:02 +0000 Fix for Win32 high score bug; score file now fflush'ed after writes to be more crash-tolerant and multi-user friendly; gtk_clists, gtk_texts and gtk_paneds made more usable on Win32. Diffstat: M ChangeLog | 7 ++++++- M src/gtk_client.c | 2 +- M src/gtkport.c | 187 +++++++++++++++++++++++++++---- M src/gtkport.h | 1 + M src/serverside.c | 5 ++++- 5 files changed, 178 insertions(+), 24 deletions(-) --- (DIR) diff --git a/ChangeLog b/ChangeLog t@@ -1,4 +1,9 @@ cvs + - Fixes for spurious tipoffs + - High scores should now be written properly on Win32 systems + - Various minor usability fixes on Win32 systems + +1.5.0beta2 29-04-2001 - Various fixes for installation on BSD systems and Mac OS X - Multiplayer menus (spy on player, etc.) are now greyed out in GTK+ client when in single-player mode t@@ -12,7 +17,7 @@ cvs - "make install" installs dopewars as group "wheel" if "games" is unavailable -1.5.0-beta1 08-04-2001 +1.5.0beta1 08-04-2001 - Completely rewritten fighting code - Internationalization (i18n) support - Tense and case-sensitive translated strings handled via. dpg_ analogues (DIR) diff --git a/src/gtk_client.c b/src/gtk_client.c t@@ -571,7 +571,7 @@ void PrintMessage(char *text) { while (*text=='\n') text++; gtk_editable_insert_text(messages,text,strlen(text),&EditPos); if (text[strlen(text)-1]!='\n') { - gtk_editable_insert_text(messages,cr,1,&EditPos); + gtk_editable_insert_text(messages,cr,strlen(cr),&EditPos); } gtk_text_thaw(GTK_TEXT(messages)); gtk_editable_set_position(messages,EditPos); (DIR) diff --git a/src/gtkport.c b/src/gtkport.c t@@ -89,6 +89,7 @@ static void gtk_container_destroy(GtkWidget *widget); static void gtk_container_size_request(GtkWidget *widget, GtkRequisition *requisition); static void gtk_container_set_size(GtkWidget *widget,GtkAllocation *allocation); +static void gtk_container_show_all(GtkWidget *widget,gboolean hWndOnly); static void gtk_window_size_request(GtkWidget *widget, GtkRequisition *requisition); static void gtk_window_set_size(GtkWidget *widget,GtkAllocation *allocation); t@@ -139,7 +140,6 @@ static void gtk_clist_realize(GtkWidget *widget); static void gtk_clist_show(GtkWidget *widget); static void gtk_clist_hide(GtkWidget *widget); static void gtk_clist_draw_row(GtkCList *clist,LPDRAWITEMSTRUCT lpdis); -static void gtk_container_show_all(GtkWidget *widget,gboolean hWndOnly); static void gtk_box_show_all(GtkWidget *widget,gboolean hWndOnly); static void gtk_table_show_all(GtkWidget *widget,gboolean hWndOnly); static void gtk_widget_show_all_full(GtkWidget *widget,gboolean hWndOnly); t@@ -166,6 +166,9 @@ static void gtk_marshal_VOID__BOOL(GtkObject *object,GSList *actions, static void gtk_marshal_VOID__GPOIN(GtkObject *object,GSList *actions, GtkSignalFunc default_action, va_list args); +static void gtk_marshal_VOID__GINT(GtkObject *object,GSList *actions, + GtkSignalFunc default_action, + va_list args); static void gtk_menu_bar_realize(GtkWidget *widget); static void gtk_menu_item_realize(GtkWidget *widget); static void gtk_menu_item_enable(GtkWidget *widget); t@@ -561,7 +564,7 @@ static GtkSignalType GtkCListSignals[] = { { "size_request",gtk_marshal_VOID__GPOIN,gtk_clist_size_request }, { "set_size",gtk_marshal_VOID__GPOIN,gtk_clist_set_size }, { "realize",gtk_marshal_VOID__VOID,gtk_clist_realize }, - { "click-column",gtk_marshal_VOID__GPOIN,NULL }, + { "click-column",gtk_marshal_VOID__GINT,NULL }, { "show",gtk_marshal_VOID__VOID,gtk_clist_show }, { "hide",gtk_marshal_VOID__VOID,gtk_clist_hide }, { "",NULL,NULL } t@@ -634,7 +637,7 @@ static GSList *GtkTimeouts=NULL; static HWND TopLevel=NULL; long AsyncSocketError=0; -static WNDPROC wpOrigEntryProc; +static WNDPROC wpOrigEntryProc,wpOrigTextProc; static void gtk_set_default_font(HWND hWnd) { SendMessage(hWnd,WM_SETFONT,(WPARAM)hFont,MAKELPARAM(FALSE,0)); t@@ -680,11 +683,54 @@ static void DispatchTimeoutEvent(UINT id) { } } +static void UpdatePanedGhostRect(GtkPaned *paned,RECT *OldRect,RECT *NewRect, + gint x,gint y) { + HWND hWnd,parent; + RECT rect,clrect; + POINT MouseCoord; + HDC hDC; + GtkWidget *widget=GTK_WIDGET(paned); + + if (!OldRect && !NewRect) return; + parent=gtk_get_parent_hwnd(widget); + hWnd=widget->hWnd; + if (!parent || !hWnd) return; + + MouseCoord.x=x; + MouseCoord.y=y; + MapWindowPoints(hWnd,parent,&MouseCoord,1); + + rect.left=paned->true_alloc.x; + rect.top=paned->true_alloc.y; + GetClientRect(hWnd,&clrect); + if (clrect.right > clrect.bottom) { + rect.right=paned->true_alloc.x+paned->true_alloc.width; + rect.bottom=MouseCoord.y; + } else { + rect.bottom=paned->true_alloc.y+paned->true_alloc.height; + rect.right=MouseCoord.x; + } + + if (OldRect && NewRect && OldRect->right==rect.right && + OldRect->bottom==rect.bottom) return; + + hDC=GetDC(parent); + + if (OldRect) DrawFocusRect(hDC,OldRect); + if (NewRect) { + CopyRect(NewRect,&rect); + DrawFocusRect(hDC,NewRect); + } + ReleaseDC(parent,hDC); +} + LRESULT CALLBACK GtkPanedProc(HWND hwnd,UINT msg,UINT wParam,LONG lParam) { PAINTSTRUCT ps; HPEN oldpen,dkpen,ltpen; RECT rect; + static RECT GhostRect; HDC hDC; + HWND parent; gint newpos; GtkPaned *paned; paned=GTK_PANED(GetWindowLong(hwnd,GWL_USERDATA)); t@@ -724,14 +770,20 @@ LRESULT CALLBACK GtkPanedProc(HWND hwnd,UINT msg,UINT wParam,LONG lParam) { if (!paned) break; SetCapture(hwnd); paned->Tracking=TRUE; + UpdatePanedGhostRect(paned,NULL,&GhostRect, + LOWORD(lParam),HIWORD(lParam)); return TRUE; case WM_MOUSEMOVE: if (!paned||!paned->Tracking) break; + UpdatePanedGhostRect(paned,&GhostRect,&GhostRect, + LOWORD(lParam),HIWORD(lParam)); return TRUE; case WM_LBUTTONUP: if (!paned||!paned->Tracking) break; ReleaseCapture(); paned->Tracking=FALSE; + UpdatePanedGhostRect(paned,&GhostRect,NULL, + LOWORD(lParam),HIWORD(lParam)); GetClientRect(hwnd,&rect); if (rect.right > rect.bottom) { newpos=((gint16)HIWORD(lParam)+GTK_WIDGET(paned)->allocation.y- t@@ -872,11 +924,16 @@ LRESULT CALLBACK MainWndProc(HWND hwnd,UINT msg,UINT wParam,LONG lParam) { phdr=(HD_NOTIFY FAR *)lParam; nmhdr=(NMHDR *)lParam; if (!nmhdr) break; - if (nmhdr->code==HDN_ITEMCHANGED) { + if (nmhdr->code==HDN_ENDTRACK) { gtk_clist_set_column_width_full( GTK_CLIST(GetWindowLong(nmhdr->hwndFrom,GWL_USERDATA)), phdr->iItem,phdr->pitem->cxy,FALSE); return FALSE; + } else if (nmhdr->code==HDN_ITEMCLICK) { + gtk_signal_emit( + GTK_OBJECT(GetWindowLong(nmhdr->hwndFrom,GWL_USERDATA)), + "click-column",(gint)phdr->iItem); + return FALSE; } else if (nmhdr->code==TCN_SELCHANGE) { gtk_notebook_set_page( GTK_NOTEBOOK(GetWindowLong(nmhdr->hwndFrom,GWL_USERDATA)), t@@ -909,6 +966,18 @@ LRESULT APIENTRY EntryWndProc(HWND hwnd,UINT msg,WPARAM wParam, return CallWindowProc(wpOrigEntryProc,hwnd,msg,wParam,lParam); } +LRESULT APIENTRY TextWndProc(HWND hwnd,UINT msg,WPARAM wParam, + LPARAM lParam) { + GtkWidget *widget; + if (msg==WM_GETDLGCODE) { + widget=GTK_WIDGET(GetWindowLong(hwnd,GWL_USERDATA)); + if (!GTK_EDITABLE(widget)->is_editable) { + return DLGC_HASSETSEL|DLGC_WANTARROWS; + } + } + return CallWindowProc(wpOrigTextProc,hwnd,msg,wParam,lParam); +} + void win32_init(HINSTANCE hInstance,HINSTANCE hPrevInstance) { WNDCLASS wc; hInst=hInstance; t@@ -1558,26 +1627,28 @@ void gtk_editable_insert_text(GtkEditable *editable,const gchar *new_text, GtkWidget *widget=GTK_WIDGET(editable); HWND hWnd; gint i; + GString *newstr; gtk_editable_sync_text(editable); - g_string_insert(editable->text,*position,new_text); - for (i=*position;i<*position+strlen(new_text);i++) { - if (editable->text->str[i]=='\r' && - editable->text->str[i+1]=='\n') { - i++; - } else if (editable->text->str[i]=='\n') { - g_string_insert_c(editable->text,i,'\r'); - i++; - (*position)++; + + /* Convert Unix-style lone '\n' to Windows-style '\r\n' */ + newstr=g_string_new(""); + for (i=0;i<new_text_length && new_text[i];i++) { + if (new_text[i]=='\n' && (i==0 || new_text[i-1]!='\r')) { + g_string_append_c(newstr,'\r'); } + g_string_append_c(newstr,new_text[i]); } + g_string_insert(editable->text,*position,newstr->str); hWnd=widget->hWnd; if (hWnd) { - SendMessage(hWnd,WM_SETTEXT,0,(LPARAM)editable->text->str); - *position+=strlen(new_text); + SendMessage(hWnd,EM_SETSEL,(WPARAM)*position,(LPARAM)*position); + SendMessage(hWnd,EM_REPLACESEL,(WPARAM)FALSE,(LPARAM)newstr->str); + *position+=newstr->len; gtk_editable_set_position(editable,*position); } + g_string_free(newstr,TRUE); } void gtk_editable_delete_text(GtkEditable *editable, t@@ -1623,9 +1694,8 @@ void gtk_editable_set_position(GtkEditable *editable,gint position) { HWND hWnd; if (!GTK_WIDGET_REALIZED(widget)) return; hWnd=widget->hWnd; - SendMessage(hWnd,EM_SETSEL,(WPARAM)-1,(LPARAM)position); + SendMessage(hWnd,EM_SETSEL,(WPARAM)position,(LPARAM)position); SendMessage(hWnd,EM_SCROLLCARET,0,0); - SendMessage(hWnd,EM_LINESCROLL,0,(LPARAM)1000); } gint gtk_editable_get_position(GtkEditable *editable) { t@@ -1988,13 +2058,21 @@ void gtk_entry_realize(GtkWidget *widget) { void gtk_text_realize(GtkWidget *widget) { HWND Parent; + gboolean editable; + Parent=gtk_get_parent_hwnd(widget); + editable=GTK_EDITABLE(widget)->is_editable; GTK_WIDGET_SET_FLAGS(widget,GTK_CAN_FOCUS); widget->hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,"EDIT","", - WS_CHILD|WS_TABSTOP| + WS_CHILD|(editable ? WS_TABSTOP : 0)| ES_MULTILINE|ES_WANTRETURN|WS_VSCROLL| (GTK_TEXT(widget)->word_wrap ? 0 : ES_AUTOHSCROLL), 0,0,0,0,Parent,NULL,hInst,NULL); +/* Subclass the window (we assume that all multiline edit boxes have the same + window procedure) */ + wpOrigTextProc = (WNDPROC) SetWindowLong(widget->hWnd, + GWL_WNDPROC, + (LONG)TextWndProc); gtk_set_default_font(widget->hWnd); gtk_editable_set_editable(GTK_EDITABLE(widget), GTK_EDITABLE(widget)->is_editable); t@@ -2125,7 +2203,7 @@ void gtk_clist_realize(GtkWidget *widget) { /* g_print("Header %p, size %d\n",header,wp.cy);*/ widget->hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,"LISTBOX","", WS_CHILD|WS_TABSTOP|LBS_DISABLENOSCROLL| - WS_VSCROLL|LBS_USETABSTOPS| + WS_VSCROLL| LBS_OWNERDRAWFIXED|LBS_NOTIFY, 0,0,0,0,Parent,NULL,hInst,NULL); gtk_set_default_font(widget->hWnd); t@@ -2140,12 +2218,14 @@ void gtk_clist_realize(GtkWidget *widget) { hdi.mask = HDI_TEXT|HDI_FORMAT|HDI_WIDTH; hdi.pszText=clist->cols[i].title; if (hdi.pszText) { - hdi.cxy=clist->cols[i].width; + if (i==clist->ncols-1) hdi.cxy=9000; + else hdi.cxy=clist->cols[i].width; hdi.cchTextMax=strlen(hdi.pszText); hdi.fmt = HDF_LEFT|HDF_STRING; SendMessage(header,HDM_INSERTITEM,i+1,(LPARAM)&hdi); } } + } void gtk_clist_show(GtkWidget *widget) { t@@ -2189,6 +2269,7 @@ void gtk_clist_draw_row(GtkCList *clist,LPDRAWITEMSTRUCT lpdis) { rcCol.right=CurrentX-LISTITEMHPACK; if (rcCol.left > lpdis->rcItem.right) rcCol.left=lpdis->rcItem.right; if (rcCol.right > lpdis->rcItem.right) rcCol.right=lpdis->rcItem.right; + if (i==clist->ncols-1) rcCol.right=lpdis->rcItem.right; if (row->text[i]) DrawText(lpdis->hDC,row->text[i],-1,&rcCol, DT_LEFT|DT_SINGLELINE|DT_VCENTER); } t@@ -2260,7 +2341,7 @@ gint gtk_clist_insert(GtkCList *clist,gint row,gchar *text[]) { if (GTK_WIDGET_REALIZED(widget)) { hWnd=widget->hWnd; - SendMessage(hWnd,LB_INSERTSTRING,(WPARAM)row,(LPARAM)new_row->data); + SendMessage(hWnd,LB_INSERTSTRING,(WPARAM)row,(LPARAM)NULL); } return row; t@@ -2344,6 +2425,7 @@ void gtk_clist_set_column_width_full(GtkCList *clist,gint column,gint width, header=clist->header; if (ResizeHeader && header) { hdi.mask=HDI_WIDTH; + if (column==clist->ncols-1) width=9000; hdi.cxy=width; if (SendMessage(header,HDM_GETITEM,(WPARAM)column,(LPARAM)&hdi) && hdi.cxy!=width) { t@@ -2921,6 +3003,24 @@ void gtk_marshal_VOID__VOID(GtkObject *object,GSList *actions, if (default_action) (*default_action)(object); } +void gtk_marshal_VOID__GINT(GtkObject *object,GSList *actions, + GtkSignalFunc default_action, + va_list args) { + gint arg1; + GtkSignal *signal; + + arg1=va_arg(args,gint); + + while (actions) { + signal=(GtkSignal*)actions->data; + if (signal->slot_object) { + (*signal->func)(signal->slot_object,arg1); + } else (*signal->func)(object,arg1,signal->func_data); + actions=g_slist_next(actions); + } + if (default_action) (*default_action)(object,arg1); +} + void gtk_marshal_VOID__GPOIN(GtkObject *object,GSList *actions, GtkSignalFunc default_action, va_list args) { t@@ -3923,7 +4023,51 @@ void gtk_text_freeze(GtkText *text) { void gtk_text_thaw(GtkText *text) { } +static GtkCList *sorting_clist; +static gint gtk_clist_sort_func(gconstpointer a,gconstpointer b) { + return (*sorting_clist->cmp_func)(sorting_clist,a,b); +} + void gtk_clist_sort(GtkCList *clist) { + HWND hWnd; + gint rowind; + GList *sel; + GSList *rowpt; + + sorting_clist=clist; + if (clist && clist->cmp_func && clist->rows) { +/* Since the order of the list may change, we need to change the selection + as well. Do this by converting the row indices into GSList pointers (which + are invariant to the sort) and then convert back afterwards */ + for (sel=clist->selection;sel;sel=g_list_next(sel)) { + rowind=GPOINTER_TO_INT(sel->data); + sel->data=(gpointer)g_slist_nth(clist->rows,rowind); + } + clist->rows=g_slist_sort(clist->rows,gtk_clist_sort_func); + for (sel=clist->selection;sel;sel=g_list_next(sel)) { + rowpt=(GSList *)(sel->data); + sel->data=GINT_TO_POINTER(g_slist_position(clist->rows,rowpt)); + } + if (GTK_WIDGET_REALIZED(GTK_WIDGET(clist))) { + hWnd=GTK_WIDGET(clist)->hWnd; + if (clist->mode==GTK_SELECTION_SINGLE) { + sel=clist->selection; + if (sel) rowind=GPOINTER_TO_INT(sel->data); + else rowind=-1; + SendMessage(hWnd,LB_SETCURSEL,(WPARAM)rowind,0); + } else { + for (rowind=0;rowind<g_slist_length(clist->rows);rowind++) { + SendMessage(hWnd,LB_SETSEL,(WPARAM)FALSE,(LPARAM)rowind); + } + for (sel=clist->selection;sel;sel=g_list_next(sel)) { + rowind=GPOINTER_TO_INT(sel->data); + SendMessage(hWnd,LB_SETSEL,(WPARAM)TRUE,(LPARAM)rowind); + } + } + InvalidateRect(hWnd,NULL,FALSE); + UpdateWindow(hWnd); + } + } } void gtk_clist_freeze(GtkCList *clist) { t@@ -4126,6 +4270,7 @@ void gtk_clist_moveto(GtkCList *clist,gint row,gint column, } void gtk_clist_set_compare_func(GtkCList *clist,GtkCListCompareFunc cmp_func) { + if (clist) clist->cmp_func = cmp_func; } void gtk_clist_set_column_auto_resize(GtkCList *clist,gint column, (DIR) diff --git a/src/gtkport.h b/src/gtkport.h t@@ -355,6 +355,7 @@ struct _GtkCList { GtkCListColumn *cols; GList *selection; GtkSelectionMode mode; + GtkCListCompareFunc cmp_func; gint auto_sort : 1; }; (DIR) diff --git a/src/serverside.c b/src/serverside.c t@@ -1082,7 +1082,9 @@ int InitHighScoreFile() { if (ScoreFP) return 0; /* If already opened, then we're done */ - ScoreFP=fopen(HiScoreFile,"a+"); + /* Win32 gets upset if we use "a+" so we use this nasty hack instead */ + ScoreFP=fopen(HiScoreFile,"r+"); + if (!ScoreFP) ScoreFP=fopen(HiScoreFile,"w+"); #ifndef CYGWIN if (setregid(getgid(),getgid())!=0) perror("setregid"); t@@ -1121,6 +1123,7 @@ int HighScoreWrite(struct HISCORE *MultiScore,struct HISCORE *AntiqueScore) { HighScoreTypeWrite(AntiqueScore,ScoreFP); HighScoreTypeWrite(MultiScore,ScoreFP); ReleaseLock(ScoreFP); + fflush(ScoreFP); } else return 0; return 1; }