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
git clone git://src.adamsgaard.dk/vaccinewars
Log
Files
Refs
README
LICENSE
---
commit 5f2248351aaab50e701b92db134223fbf74f763b
parent fc6e83182ef84919681049077dc6791fd7515a9e
Author: Ben Webb 
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(-)
---
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
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);
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;itext,*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;rowindrows);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,
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;
 };
 
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;
 }