vaccinewars

be a doctor and try to vaccinate the world
git clone git://src.adamsgaard.dk/vaccinewars # fast
git clone https://src.adamsgaard.dk/vaccinewars.git # slow
Log | Files | Refs | README | LICENSE Back to index

treeview.c (36602B)


      1 /************************************************************************
      2  * treeview.c     GtkTreeView (and friends) implementation for gtkport  *
      3  * Copyright (C)  1998-2021  Ben Webb                                   *
      4  *                Email: benwebb@users.sf.net                           *
      5  *                WWW: https://dopewars.sourceforge.io/                 *
      6  *                                                                      *
      7  * This program is free software; you can redistribute it and/or        *
      8  * modify it under the terms of the GNU General Public License          *
      9  * as published by the Free Software Foundation; either version 2       *
     10  * of the License, or (at your option) any later version.               *
     11  *                                                                      *
     12  * This program is distributed in the hope that it will be useful,      *
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
     15  * GNU General Public License for more details.                         *
     16  *                                                                      *
     17  * You should have received a copy of the GNU General Public License    *
     18  * along with this program; if not, write to the Free Software          *
     19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston,               *
     20  *                   MA  02111-1307, USA.                               *
     21  ************************************************************************/
     22 
     23 #ifdef HAVE_CONFIG_H
     24 #include <config.h>
     25 #endif
     26 
     27 #include "gtkport.h"
     28 
     29 #ifdef CYGWIN
     30 
     31 #include <winsock2.h>
     32 #include <windows.h>
     33 #include <commctrl.h>
     34 
     35 #include "unicodewrap.h"
     36 
     37 #define LISTITEMHPACK  3
     38 #define LISTHEADERPACK 6
     39 
     40 static const gchar *WC_GTKTREEVIEWHDR = "WC_GTKTREEVIEWHDR";
     41 
     42 static WNDPROC wpOrigListProc;
     43 
     44 static void gtk_tree_view_size_request(GtkWidget *widget,
     45                                        GtkRequisition *requisition);
     46 static void gtk_tree_view_set_size(GtkWidget *widget,
     47                                     GtkAllocation *allocation);
     48 static gboolean gtk_tree_view_wndproc(GtkWidget *widget, UINT msg,
     49                 WPARAM wParam, LPARAM lParam, gboolean *dodef);
     50 static void gtk_tree_view_realize(GtkWidget *widget);
     51 static void gtk_tree_view_destroy(GtkWidget *widget);
     52 static void gtk_tree_view_show(GtkWidget *widget);
     53 static void gtk_tree_view_hide(GtkWidget *widget);
     54 static void gtk_tree_view_draw_row(GtkTreeView *tv, LPDRAWITEMSTRUCT lpdis);
     55 static void gtk_tree_view_update_selection(GtkWidget *widget);
     56 static void gtk_tree_view_update_widths(GtkTreeView *tv, GtkTreeModel *model,
     57                                         GtkListStoreRow *row);
     58 static void gtk_tree_view_update_all_widths(GtkTreeView *tv);
     59 static void gtk_tree_view_do_auto_resize(GtkTreeView *tv);
     60 static void gtk_tree_view_set_column_width(GtkTreeView *tv, gint column,
     61                                            gint width);
     62 static void gtk_tree_view_set_column_width_full(GtkTreeView *tv, gint column,
     63                                                 gint width,
     64                                                 gboolean ResizeHeader);
     65 static void gtk_tree_view_click_column(GtkWidget *widget, gint column);
     66 
     67 static GtkSignalType GtkTreeViewSignals[] = {
     68   {"size_request", gtk_marshal_VOID__GPOIN, gtk_tree_view_size_request},
     69   {"set_size", gtk_marshal_VOID__GPOIN, gtk_tree_view_set_size},
     70   {"realize", gtk_marshal_VOID__VOID, gtk_tree_view_realize},
     71   {"destroy", gtk_marshal_VOID__VOID, gtk_tree_view_destroy},
     72   {"click-column", gtk_marshal_VOID__GINT, gtk_tree_view_click_column},
     73   {"changed", gtk_marshal_VOID__VOID, NULL},
     74   {"show", gtk_marshal_VOID__VOID, gtk_tree_view_show},
     75   {"hide", gtk_marshal_VOID__VOID, gtk_tree_view_hide},
     76   {"", NULL, NULL}
     77 };
     78 
     79 static GtkClass GtkTreeViewClass = {
     80   "tree_view", &GtkContainerClass, sizeof(GtkTreeView), GtkTreeViewSignals,
     81   gtk_tree_view_wndproc
     82 };
     83 
     84 static GtkClass GtkListStoreClass = {
     85   "list_store", &GtkObjectClass, sizeof(GtkListStore), NULL, NULL
     86 };
     87 
     88 static void SetTreeViewHeaderSize(GtkTreeView *clist)
     89 {
     90   RECT rc;
     91   HWND hWnd;
     92   int width;
     93 
     94   hWnd = GTK_WIDGET(clist)->hWnd;
     95   clist->scrollpos = GetScrollPos(hWnd, SB_HORZ);
     96 
     97   GetWindowRect(hWnd, &rc);
     98   width = (int)SendMessageW(hWnd, LB_GETHORIZONTALEXTENT, 0, 0);
     99   width = MAX(width, rc.right - rc.left) + 100;
    100 
    101   SetWindowPos(clist->header, HWND_TOP, -clist->scrollpos, 0,
    102                width, clist->header_size, SWP_NOZORDER);
    103 }
    104 
    105 static LRESULT APIENTRY ListWndProc(HWND hwnd, UINT msg, WPARAM wParam,
    106                                     LPARAM lParam)
    107 {
    108   LRESULT retval;
    109   GtkWidget *widget;
    110 
    111   widget = GTK_WIDGET(GetWindowLongPtr(hwnd, GWLP_USERDATA));
    112   retval = CallWindowProcW(wpOrigListProc, hwnd, msg, wParam, lParam);
    113 
    114   if (msg == WM_HSCROLL && widget) {
    115     GtkTreeView *clist = GTK_TREE_VIEW(widget);
    116     SetTreeViewHeaderSize(clist);
    117   }
    118 
    119   return retval;
    120 }
    121 
    122 gboolean gtk_tree_view_wndproc(GtkWidget *widget, UINT msg, WPARAM wParam,
    123                                LPARAM lParam, gboolean *dodef)
    124 {
    125   LPDRAWITEMSTRUCT lpdis;
    126   HD_NOTIFYA FAR *phdr;
    127   HD_NOTIFYW FAR *phdrw;
    128   NMHDR *nmhdr;
    129 
    130   switch(msg) {
    131   case WM_COMMAND:
    132     if (lParam && HIWORD(wParam) == LBN_SELCHANGE) {
    133       gtk_tree_view_update_selection(widget);
    134       return FALSE;
    135     }
    136     break;
    137   case WM_DRAWITEM:
    138     lpdis = (LPDRAWITEMSTRUCT)lParam;
    139     if (lpdis) {
    140       gtk_tree_view_draw_row(GTK_TREE_VIEW(widget), lpdis);
    141       *dodef = FALSE;
    142       return TRUE;
    143     }
    144     break;
    145   case WM_NOTIFY:
    146     nmhdr = (NMHDR *)lParam;
    147     if (nmhdr) {
    148       switch(nmhdr->code) {
    149       case HDN_ENDTRACKA:
    150         phdr = (HD_NOTIFYA FAR *)lParam;
    151         gtk_tree_view_set_column_width_full(GTK_TREE_VIEW(widget), phdr->iItem,
    152                                             phdr->pitem->cxy, FALSE);
    153         return FALSE;
    154       case HDN_ENDTRACKW:
    155         phdrw = (HD_NOTIFYW FAR *)lParam;
    156         gtk_tree_view_set_column_width_full(GTK_TREE_VIEW(widget), phdrw->iItem,
    157                                             phdrw->pitem->cxy, FALSE);
    158         return FALSE;
    159       case HDN_ITEMCLICKA:
    160         phdr = (HD_NOTIFYA FAR *)lParam;
    161         gtk_signal_emit(G_OBJECT(widget), "click-column", (gint)phdr->iItem);
    162         return FALSE;
    163       case HDN_ITEMCLICKW:
    164         phdrw = (HD_NOTIFYW FAR *)lParam;
    165         gtk_signal_emit(G_OBJECT(widget), "click-column", (gint)phdrw->iItem);
    166         return FALSE;
    167       default:
    168         break;
    169       }
    170     }
    171     break;
    172   }
    173 
    174   return FALSE;
    175 }
    176 
    177 static void gtk_tree_view_set_extent(GtkTreeView *tv)
    178 {
    179   HWND hWnd;
    180 
    181   hWnd = GTK_WIDGET(tv)->hWnd;
    182   if (hWnd) {
    183     GSList *colpt;
    184     int width = 0;
    185 
    186     for (colpt = tv->columns; colpt; colpt = g_slist_next(colpt)) {
    187       GtkTreeViewColumn *col = colpt->data;
    188       width += col->width;
    189     }
    190     SendMessageW(hWnd, LB_SETHORIZONTALEXTENT, (WPARAM)width, 0);
    191     SetTreeViewHeaderSize(tv);
    192   }
    193 }
    194 
    195 void gtk_tree_view_set_size(GtkWidget *widget, GtkAllocation *allocation)
    196 {
    197   GtkTreeView *clist = GTK_TREE_VIEW(widget);
    198 
    199   gtk_container_set_size(widget, allocation);
    200   if (clist->header) {
    201     POINT pt;
    202     pt.x = allocation->x;
    203     pt.y = allocation->y;
    204     MapWidgetOrigin(widget, &pt);
    205     SetWindowPos(clist->scrollwin, HWND_TOP, pt.x, pt.y,
    206                  allocation->width, clist->header_size, SWP_NOZORDER);
    207     allocation->y += clist->header_size - 1;
    208     allocation->height -= clist->header_size - 1;
    209   }
    210   gtk_tree_view_set_extent(clist);
    211 }
    212 
    213 GtkWidget *gtk_tree_view_new(void)
    214 {
    215   GtkTreeView *view;
    216 
    217   view = GTK_TREE_VIEW(GtkNewObject(&GtkTreeViewClass));
    218   view->model = NULL;
    219   view->scrollpos = 0;
    220   view->columns = NULL;
    221   view->headers_clickable = TRUE;
    222   view->mode = GTK_SELECTION_SINGLE;
    223   view->selection = NULL;
    224   return GTK_WIDGET(view);
    225 }
    226 
    227 GtkTreeSelection *gtk_tree_view_get_selection(GtkTreeView *tree_view)
    228 {
    229   /* The selection *is* the tree view */
    230   return tree_view;
    231 }
    232 
    233 void gtk_tree_view_size_request(GtkWidget *widget, GtkRequisition *requisition)
    234 {
    235   SIZE size;
    236 
    237   if (GetTextSize(widget->hWnd, "Sample text", &size, defFont)) {
    238     requisition->width = size.cx;
    239     requisition->height = size.cy * 6 + 12;
    240   }
    241 }
    242 
    243 void gtk_tree_view_realize(GtkWidget *widget)
    244 {
    245   HWND Parent, header, scrollwin;
    246   HD_LAYOUT hdl;
    247   HD_ITEM hdi;
    248   RECT rcParent;
    249   WINDOWPOS wp;
    250   GtkTreeView *tv = GTK_TREE_VIEW(widget);
    251   GSList *colpt;
    252   gint i;
    253 
    254   gtk_container_realize(widget);
    255   Parent = gtk_get_parent_hwnd(widget);
    256   GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_FOCUS);
    257   rcParent.left = rcParent.top = 0;
    258   rcParent.right = rcParent.bottom = 800;
    259   scrollwin = myCreateWindow(WC_GTKTREEVIEWHDR, NULL, WS_CHILD | WS_BORDER,
    260                              0, 0, 0, 0, Parent, NULL, hInst, NULL);
    261   SetWindowLongPtr(scrollwin, GWLP_USERDATA, (LONG_PTR)widget);
    262   header = myCreateWindowEx(0, WC_HEADER, NULL,
    263                             WS_CHILD | HDS_HORZ | WS_VISIBLE
    264                             | (tv->headers_clickable ? HDS_BUTTONS : 0),
    265                             0, 0, 0, 0, scrollwin, NULL, hInst, NULL);
    266   SetWindowLongPtr(header, GWLP_USERDATA, (LONG_PTR)widget);
    267   tv->header = header;
    268   tv->scrollwin = scrollwin;
    269   gtk_set_default_font(header);
    270   hdl.prc = &rcParent;
    271   hdl.pwpos = &wp;
    272   SendMessageW(header, HDM_LAYOUT, 0, (LPARAM)&hdl);
    273   tv->header_size = wp.cy;
    274   widget->hWnd = myCreateWindowEx(WS_EX_CLIENTEDGE, "LISTBOX", "",
    275                                   WS_CHILD | WS_TABSTOP | WS_VSCROLL
    276                                   | WS_HSCROLL | LBS_OWNERDRAWFIXED
    277                                   | LBS_NOTIFY, 0, 0, 0, 0, Parent, NULL,
    278                                   hInst, NULL);
    279   /* Subclass the window */
    280   wpOrigListProc = (WNDPROC)SetWindowLongPtrW(widget->hWnd, GWLP_WNDPROC,
    281                                               (LONG_PTR)ListWndProc);
    282   gtk_set_default_font(widget->hWnd);
    283 
    284   if (tv->model) {
    285     for (i = 0; i < tv->model->rows->len; ++i) {
    286       SendMessageW(widget->hWnd, LB_ADDSTRING, 0, 1);
    287     }
    288   }
    289   gtk_tree_view_update_all_widths(tv);
    290 
    291   for (colpt = tv->columns, i = 0; colpt; colpt = g_slist_next(colpt), ++i) {
    292     GtkTreeViewColumn *col = colpt->data;
    293     if (col->auto_resize) {
    294       col->width = col->optimal_width;
    295     }
    296     hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH;
    297     hdi.pszText = col->title;
    298     if (hdi.pszText) {
    299       if (!g_slist_next(colpt))
    300         hdi.cxy = 9000;
    301       else
    302         hdi.cxy = col->width;
    303       hdi.cchTextMax = strlen(hdi.pszText);
    304       hdi.fmt = HDF_LEFT | HDF_STRING;
    305       myHeader_InsertItem(header, i + 1, &hdi);
    306     }
    307   }
    308 }
    309 
    310 static void gtk_list_store_row_free(GtkListStoreRow *row, GtkListStore *store)
    311 {
    312   int i;
    313   for (i = 0; i < store->ncols; ++i) {
    314     if (store->coltype[i] == G_TYPE_STRING) {
    315       g_free(row->data[i]);
    316     }
    317   }
    318 }
    319 
    320 void gtk_list_store_clear(GtkListStore *list_store)
    321 {
    322   guint i;
    323   for (i = 0; i < list_store->rows->len; ++i) {
    324     GtkListStoreRow *row = &g_array_index(list_store->rows, GtkListStoreRow, i);
    325     gtk_list_store_row_free(row, list_store);
    326   }
    327   g_array_set_size(list_store->rows, 0);
    328   list_store->need_sort = FALSE;  /* an empty store is sorted */
    329 
    330   if (list_store->view) {
    331     HWND hWnd;
    332     gtk_tree_view_update_all_widths(list_store->view);
    333     hWnd = GTK_WIDGET(list_store->view)->hWnd;
    334     if (hWnd) {
    335       SendMessageW(hWnd, LB_RESETCONTENT, 0, 0);
    336     }
    337   }
    338 }
    339 
    340 void gtk_list_store_insert(GtkListStore *list_store, GtkTreeIter *iter,
    341                            gint position)
    342 {
    343   GtkListStoreRow row;
    344   /* Add a new empty row to the store and return a pointer to it */
    345   row.data = g_new0(gpointer, list_store->ncols);
    346   if (position < 0) {
    347     g_array_append_val(list_store->rows, row);
    348     *iter = list_store->rows->len - 1;
    349   } else {
    350     g_array_insert_val(list_store->rows, position, row);
    351     *iter = position;
    352   }
    353 }
    354 
    355 void gtk_list_store_append(GtkListStore *list_store, GtkTreeIter *iter)
    356 {
    357   gtk_list_store_insert(list_store, iter, -1);
    358 }
    359 
    360 void gtk_list_store_set(GtkListStore *list_store, GtkTreeIter *iter, ...)
    361 {
    362   va_list ap;
    363   int colind;
    364   gboolean new_row = TRUE;
    365   GtkListStoreRow *row = &g_array_index(list_store->rows, GtkListStoreRow,
    366                                         *iter);
    367   list_store->need_sort = TRUE;
    368 
    369   va_start(ap, iter);
    370   while ((colind = va_arg(ap, int)) >= 0) {
    371     switch(list_store->coltype[colind]) {
    372     case G_TYPE_STRING:
    373       g_free(row->data[colind]);  /* Free any existing string */
    374       if (row->data[colind]) {
    375         new_row = FALSE;
    376       }
    377       row->data[colind] = g_strdup(va_arg(ap, const char*));
    378       break;
    379     case G_TYPE_UINT:
    380       row->data[colind] = GUINT_TO_POINTER(va_arg(ap, unsigned));
    381       break;
    382     case G_TYPE_INT:
    383       row->data[colind] = GINT_TO_POINTER(va_arg(ap, int));
    384       break;
    385     case G_TYPE_POINTER:
    386       row->data[colind] = va_arg(ap, gpointer);
    387       break;
    388     }
    389   }
    390   va_end(ap);
    391 
    392   if (list_store->view) {
    393     GtkWidget *widget = GTK_WIDGET(list_store->view);
    394 
    395     gtk_tree_view_update_widths(list_store->view, list_store, row);
    396     gtk_tree_view_do_auto_resize(list_store->view);
    397 
    398     if (GTK_WIDGET_REALIZED(widget)) {
    399       HWND hWnd = widget->hWnd;
    400       if (new_row) {
    401         SendMessageW(hWnd, LB_INSERTSTRING, (WPARAM)*iter, 1);
    402       } else {
    403         InvalidateRect(hWnd, NULL, FALSE);
    404       }
    405     }
    406   }
    407 }
    408 
    409 void gtk_list_store_swap(GtkListStore *store, GtkTreeIter *a, GtkTreeIter *b)
    410 {
    411   GtkTreeIter tmp;
    412   GtkListStoreRow rowa = g_array_index(store->rows, GtkListStoreRow, *a);
    413   GtkListStoreRow rowb = g_array_index(store->rows, GtkListStoreRow, *b);
    414 
    415   g_array_index(store->rows, GtkListStoreRow, *a) = rowb;
    416   g_array_index(store->rows, GtkListStoreRow, *b) = rowa;
    417   store->need_sort = TRUE;
    418 
    419   /* Swap the iterators too since in our implementation they are just row
    420      indices */
    421   tmp = *a;
    422   *a = *b;
    423   *b = tmp;
    424 }
    425 
    426 void gtk_tree_model_get(GtkTreeModel *tree_model, GtkTreeIter *iter, ...)
    427 {
    428   va_list ap;
    429   char **strpt;
    430   unsigned *uintpt;
    431   int *intpt;
    432   gpointer *ptpt;
    433   int colind;
    434   GtkListStoreRow *row = &g_array_index(tree_model->rows, GtkListStoreRow,
    435                                         *iter);
    436 
    437   va_start(ap, iter);
    438   while ((colind = va_arg(ap, int)) >= 0) {
    439     switch(tree_model->coltype[colind]) {
    440     case G_TYPE_STRING:
    441       strpt = va_arg(ap, char **);
    442       *strpt = g_strdup(row->data[colind]);
    443       break;
    444     case G_TYPE_UINT:
    445       uintpt = va_arg(ap, unsigned *);
    446       *uintpt = GPOINTER_TO_UINT(row->data[colind]);
    447       break;
    448     case G_TYPE_INT:
    449       intpt = va_arg(ap, int *);
    450       *intpt = GPOINTER_TO_INT(row->data[colind]);
    451       break;
    452     case G_TYPE_POINTER:
    453       ptpt = va_arg(ap, gpointer *);
    454       *ptpt = row->data[colind];
    455       break;
    456     }
    457   }
    458   va_end(ap);
    459 }
    460 
    461 gboolean gtk_tree_model_iter_nth_child(GtkTreeModel *tree_model,
    462                                        GtkTreeIter *iter,
    463                                        GtkTreeIter *parent, gint n)
    464 {
    465   /* We only work with one level (lists) for now */
    466   g_assert(parent == NULL);
    467   *iter = n;
    468   return TRUE;
    469 }
    470 
    471 gint gtk_tree_model_iter_n_children(GtkTreeModel *tree_model,
    472                                     GtkTreeIter *iter)
    473 {
    474   /* We only work with one level (lists) for now */
    475   if (iter) {
    476     return 1;
    477   } else {
    478     return tree_model->rows->len;
    479   }
    480 }
    481 
    482 
    483 static void gtk_tree_view_column_free(gpointer data)
    484 {
    485   GtkTreeViewColumn *col = data;
    486   g_free(col->title);
    487   g_free(col);
    488 }
    489 
    490 void gtk_tree_model_free(GtkTreeModel *model)
    491 {
    492   gtk_list_store_clear(model);  /* Remove all rows */
    493   g_array_free(model->rows, TRUE);
    494   g_array_free(model->sort_func, TRUE);
    495   g_free(model->coltype);
    496   g_free(model);
    497 }
    498 
    499 void gtk_tree_view_destroy(GtkWidget *widget)
    500 {
    501   GtkTreeView *view = GTK_TREE_VIEW(widget);
    502   g_slist_free_full(view->columns, gtk_tree_view_column_free);
    503   view->columns = NULL;
    504   if (view->model) {
    505       gtk_tree_model_free(view->model);
    506   }
    507   view->model = NULL;
    508 }
    509 
    510 void gtk_tree_view_click_column(GtkWidget *widget, gint column)
    511 {
    512   GtkTreeView *view = GTK_TREE_VIEW(widget);
    513   GtkTreeViewColumn *col = g_slist_nth_data(view->columns, column);
    514   GtkListStore *model = view->model;
    515   if (!model || !view->headers_clickable) return;
    516 
    517   if (col->sort_column_id == model->sort_column_id) {
    518     /* toggle order */
    519     if (model->sort_order == GTK_SORT_ASCENDING) {
    520       model->sort_order = GTK_SORT_DESCENDING;
    521     } else {
    522       model->sort_order = GTK_SORT_ASCENDING;
    523     }
    524   } else {
    525     model->sort_column_id = col->sort_column_id;
    526     model->sort_order = GTK_SORT_ASCENDING;
    527   }
    528   model->need_sort = TRUE;
    529   gtk_tree_view_sort(view);
    530 }
    531 
    532 void gtk_tree_view_show(GtkWidget *widget)
    533 {
    534   if (GTK_WIDGET_REALIZED(widget)) {
    535     ShowWindow(GTK_TREE_VIEW(widget)->scrollwin, SW_SHOWNORMAL);
    536   }
    537 }
    538 
    539 void gtk_tree_view_hide(GtkWidget *widget)
    540 {
    541   if (GTK_WIDGET_REALIZED(widget)) {
    542     ShowWindow(GTK_TREE_VIEW(widget)->scrollwin, SW_HIDE);
    543   }
    544 }
    545 
    546 /* Draw an individual cell (row+column) */
    547 static void draw_cell_text(GtkTreeViewColumn *col, GtkTreeModel *model,
    548                            LPDRAWITEMSTRUCT lpdis, GtkListStoreRow *row,
    549                            RECT *rcCol)
    550 {
    551   UINT align;
    552   char *val;
    553   int modcol = col->model_column;
    554   /* Convert float 0.0, 0.5 or 1.0 into int, allow for some rounding error */
    555   switch((int)(col->xalign * 10. + 0.1)) {
    556   case 10:
    557     align = DT_RIGHT;
    558     break;
    559   case 5:
    560     align = DT_CENTER;
    561     break;
    562   default:
    563     align = DT_LEFT;
    564     break;
    565   }
    566   align |= DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS;
    567 
    568   switch(model->coltype[modcol]) {
    569   case G_TYPE_STRING:
    570     if (row->data[modcol]) {
    571       myDrawText(lpdis->hDC, row->data[modcol], -1, rcCol, align);
    572     }
    573     break;
    574   case G_TYPE_UINT:
    575     val = g_strdup_printf("%u", GPOINTER_TO_UINT(row->data[modcol]));
    576     myDrawText(lpdis->hDC, val, -1, rcCol, align);
    577     g_free(val);
    578     break;
    579   case G_TYPE_INT:
    580     val = g_strdup_printf("%d", GPOINTER_TO_INT(row->data[modcol]));
    581     myDrawText(lpdis->hDC, val, -1, rcCol, align);
    582     g_free(val);
    583     break;
    584   }
    585 }
    586 
    587 void gtk_tree_view_draw_row(GtkTreeView *tv, LPDRAWITEMSTRUCT lpdis)
    588 {
    589   HBRUSH bkgrnd;
    590   COLORREF textcol, oldtextcol;
    591   RECT rcCol;
    592   int oldbkmode;
    593   guint nrows;
    594   gint CurrentX, right;
    595   GtkListStoreRow *row;
    596 
    597   if (lpdis->itemState & ODS_SELECTED) {
    598     bkgrnd = (HBRUSH)(1 + COLOR_HIGHLIGHT);
    599     textcol = (COLORREF)GetSysColor(COLOR_HIGHLIGHTTEXT);
    600   } else {
    601     bkgrnd = (HBRUSH)(1 + COLOR_WINDOW);
    602     textcol = (COLORREF)GetSysColor(COLOR_WINDOWTEXT);
    603   }
    604   oldtextcol = SetTextColor(lpdis->hDC, textcol);
    605   oldbkmode = SetBkMode(lpdis->hDC, TRANSPARENT);
    606   FillRect(lpdis->hDC, &lpdis->rcItem, bkgrnd);
    607 
    608   nrows = tv->model ? tv->model->rows->len : 0;
    609   if (lpdis->itemID >= 0 && lpdis->itemID < nrows) {
    610     int width;
    611     GSList *colpt;
    612     row = &g_array_index(tv->model->rows, GtkListStoreRow, lpdis->itemID);
    613     width = CurrentX = 0;
    614     for (colpt = tv->columns; colpt; colpt = g_slist_next(colpt)) {
    615       GtkTreeViewColumn *col = colpt->data;
    616       width += col->width;
    617     }
    618     right = MAX(lpdis->rcItem.right, width);
    619     rcCol.top = lpdis->rcItem.top;
    620     rcCol.bottom = lpdis->rcItem.bottom;
    621     if (row->data)
    622       for (colpt = tv->columns; colpt; colpt = g_slist_next(colpt)) {
    623         GtkTreeViewColumn *col = colpt->data;
    624         rcCol.left = CurrentX + LISTITEMHPACK;
    625         CurrentX += col->width;
    626         rcCol.right = CurrentX - LISTITEMHPACK;
    627         if (rcCol.left > right)
    628           rcCol.left = right;
    629         if (rcCol.right > right - LISTITEMHPACK)
    630           rcCol.right = right - LISTITEMHPACK;
    631         if (!g_slist_next(colpt))
    632           rcCol.right = right - LISTITEMHPACK;
    633         draw_cell_text(col, tv->model, lpdis, row, &rcCol);
    634       }
    635   }
    636 
    637   SetTextColor(lpdis->hDC, oldtextcol);
    638   SetBkMode(lpdis->hDC, oldbkmode);
    639   if (lpdis->itemState & ODS_FOCUS) {
    640     DrawFocusRect(lpdis->hDC, &lpdis->rcItem);
    641   }
    642 }
    643 
    644 void gtk_tree_view_do_auto_resize(GtkTreeView *tv)
    645 {
    646   GSList *colpt;
    647   gint i;
    648 
    649   for (colpt = tv->columns, i = 0; colpt; colpt = g_slist_next(colpt), i++) {
    650     GtkTreeViewColumn *col = colpt->data;
    651     if (col->auto_resize) {
    652       gtk_tree_view_set_column_width(tv, i, col->optimal_width);
    653     }
    654   }
    655 }
    656 
    657 gint gtk_tree_view_optimal_column_width(GtkTreeView *tv, gint column)
    658 {
    659   GtkTreeViewColumn *col = g_slist_nth_data(tv->columns, column);
    660   return col->optimal_width;
    661 }
    662 
    663 void gtk_tree_view_update_all_widths(GtkTreeView *tv)
    664 {
    665   SIZE size;
    666   HWND header;
    667   gint i;
    668 
    669   header = tv->header;
    670   if (header) {
    671     GSList *colpt;
    672     for (colpt = tv->columns, i = 0; colpt; colpt = g_slist_next(colpt), i++) {
    673       GtkTreeViewColumn *col = colpt->data;
    674       if (GetTextSize(header, col->title, &size, defFont)) {
    675         int new_width = size.cx + 4 + 2 * LISTHEADERPACK;
    676         col->width = MAX(col->width, new_width);
    677         col->optimal_width = MAX(col->optimal_width, new_width);
    678       }
    679     }
    680   }
    681 
    682   if (tv->model) {
    683     for (i = 0; i < tv->model->rows->len; ++i) {
    684       GtkListStoreRow *row = &g_array_index(tv->model->rows,
    685                                             GtkListStoreRow, i);
    686       gtk_tree_view_update_widths(tv, tv->model, row);
    687     }
    688   }
    689 
    690   gtk_tree_view_set_extent(tv);
    691 }
    692 
    693 void gtk_tree_view_update_widths(GtkTreeView *tv, GtkTreeModel *model,
    694                                  GtkListStoreRow *row)
    695 {
    696   SIZE size;
    697   GSList *colpt;
    698   HWND hWnd;
    699 
    700   hWnd = GTK_WIDGET(tv)->hWnd;
    701   if (!hWnd)
    702     return;
    703   for (colpt = tv->columns; colpt; colpt = g_slist_next(colpt)) {
    704     GtkTreeViewColumn *col = colpt->data;
    705     int modcol = col->model_column;
    706     char *text;
    707     switch (model->coltype[modcol]) {
    708     case G_TYPE_STRING:
    709       text = row->data[modcol];
    710       break;
    711     case G_TYPE_UINT:
    712     case G_TYPE_INT:
    713       text = "9999"; /* hack */
    714       break;
    715     default:
    716       text = NULL;
    717     }
    718     if (text && GetTextSize(hWnd, text, &size, defFont)) {
    719       int new_width = size.cx + 4 + 2 * LISTITEMHPACK;
    720       col->optimal_width = MAX(col->optimal_width, new_width);
    721     }
    722   }
    723 }
    724 
    725 gboolean gtk_list_store_remove(GtkListStore *list_store, GtkTreeIter *iter)
    726 {
    727   gint rowind = *iter;
    728   if (rowind >= 0 && rowind < list_store->rows->len) {
    729     GtkListStoreRow *row = &g_array_index(list_store->rows,
    730                                           GtkListStoreRow, rowind);
    731     gtk_list_store_row_free(row, list_store);
    732     g_array_remove_index(list_store->rows, rowind);
    733 
    734     if (list_store->view && GTK_WIDGET_REALIZED(GTK_WIDGET(list_store->view))) {
    735       HWND hWnd = GTK_WIDGET(list_store->view)->hWnd;
    736 
    737       SendMessageW(hWnd, LB_DELETESTRING, (WPARAM)rowind, 0);
    738     }
    739     return TRUE;
    740   } else {
    741     return FALSE;
    742   }
    743 }
    744 
    745 GtkWidget *gtk_scrolled_tree_view_new(GtkWidget **pack_widg)
    746 {
    747   GtkWidget *widget;
    748 
    749   widget = gtk_tree_view_new();
    750   *pack_widg = widget;
    751   return widget;
    752 }
    753 
    754 void gtk_tree_view_set_column_width(GtkTreeView *tv, gint column, gint width)
    755 {
    756   gtk_tree_view_set_column_width_full(tv, column, width, TRUE);
    757 }
    758 
    759 void gtk_tree_view_set_column_width_full(GtkTreeView *tv, gint column,
    760                                          gint width, gboolean ResizeHeader)
    761 {
    762   int ncols;
    763   GtkTreeViewColumn *col;
    764   HWND hWnd, header;
    765   HD_ITEM hdi;
    766 
    767   ncols = g_slist_length(tv->columns);
    768   if (column < 0 || column >= ncols)
    769     return;
    770   col = g_slist_nth_data(tv->columns, column);
    771 
    772   col->width = width;
    773   if (GTK_WIDGET_REALIZED(GTK_WIDGET(tv))) {
    774     header = tv->header;
    775     if (ResizeHeader && header) {
    776       hdi.mask = HDI_WIDTH;
    777       if (column == ncols - 1)
    778         width = 9000;
    779       hdi.cxy = width;
    780       if (SendMessageW(header, HDM_GETITEM, (WPARAM)column, (LPARAM)&hdi)
    781           && hdi.cxy != width) {
    782         hdi.mask = HDI_WIDTH;
    783         hdi.cxy = width;
    784         SendMessageW(header, HDM_SETITEM, (WPARAM)column, (LPARAM)&hdi);
    785       }
    786     }
    787     gtk_tree_view_set_extent(tv);
    788     hWnd = GTK_WIDGET(tv)->hWnd;
    789     if (hWnd)
    790       InvalidateRect(hWnd, NULL, FALSE);
    791   }
    792 }
    793 
    794 void gtk_tree_selection_set_mode(GtkTreeSelection *selection,
    795                                  GtkSelectionMode type)
    796 {
    797   selection->mode = type;
    798 }
    799 
    800 void gtk_tree_selection_select_path(GtkTreeSelection *selection,
    801                                     GtkTreePath *path)
    802 {
    803   HWND hWnd;
    804   guint row = *path;
    805 
    806   hWnd = GTK_WIDGET(selection)->hWnd;
    807   if (hWnd) {
    808     if (selection->mode == GTK_SELECTION_SINGLE) {
    809       SendMessageW(hWnd, LB_SETCURSEL, (WPARAM)row, 0);
    810     } else {
    811       SendMessageW(hWnd, LB_SETSEL, (WPARAM)TRUE, (LPARAM)row);
    812     }
    813     gtk_tree_view_update_selection(GTK_WIDGET(selection));
    814   }
    815 }
    816 
    817 void gtk_tree_selection_unselect_all(GtkTreeSelection *selection)
    818 {
    819   GList *sel;
    820   for (sel = selection->selection; sel; sel = g_list_next(sel)) {
    821     guint row = GPOINTER_TO_UINT(sel->data);
    822     gtk_tree_selection_unselect_path(selection, &row);
    823   }
    824 }
    825 
    826 GList *gtk_tree_selection_get_selected_rows(GtkTreeSelection *selection,
    827                                             GtkTreeModel **model)
    828 {
    829   GList *sel, *pathsel = NULL;
    830   for (sel = selection->selection; sel; sel = g_list_next(sel)) {
    831     guint row = GPOINTER_TO_UINT(sel->data);
    832     GtkTreePath *path = g_new(GtkTreePath, 1);
    833     *path = row;
    834     pathsel = g_list_append(pathsel, path);
    835   }
    836   if (model) {
    837     *model = selection->model;
    838   }
    839   return pathsel;
    840 }
    841 
    842 gint *gtk_tree_path_get_indices_with_depth(GtkTreePath *path, gint *depth)
    843 {
    844   /* Only one level; path *is* the row index */
    845   *depth = 1;
    846   return (gint *)path;
    847 }
    848 
    849 void gtk_tree_selection_unselect_path(GtkTreeSelection *selection,
    850                                       GtkTreePath *path)
    851 {
    852   HWND hWnd;
    853   guint row = *path;
    854 
    855   hWnd = GTK_WIDGET(selection)->hWnd;
    856   if (hWnd) {
    857     if (selection->mode == GTK_SELECTION_SINGLE) {
    858       SendMessageW(hWnd, LB_SETCURSEL, (WPARAM)(-1), 0);
    859     } else {
    860       SendMessageW(hWnd, LB_SETSEL, (WPARAM)FALSE, (LPARAM)row);
    861     }
    862     gtk_tree_view_update_selection(GTK_WIDGET(selection));
    863   }
    864 }
    865 
    866 gint gtk_tree_selection_count_selected_rows(GtkTreeSelection *selection)
    867 {
    868   return g_list_length(selection->selection);
    869 }
    870 
    871 gboolean gtk_tree_selection_get_selected(GtkTreeSelection *selection,
    872                                          GtkTreeModel **model,
    873                                          GtkTreeIter *iter)
    874 {
    875   if (model) {
    876     *model = selection->model;
    877   }
    878 
    879   /* Just return the first selected row */
    880   if (selection->selection) {
    881     if (iter) {
    882       int row = GPOINTER_TO_INT(g_list_nth_data(selection->selection, 0));
    883       *iter = row;
    884     }
    885     return TRUE;
    886   } else {
    887     return FALSE;
    888   }
    889 }
    890 
    891 void gtk_tree_selection_selected_foreach(GtkTreeSelection *selection,
    892                                          GtkTreeSelectionForeachFunc func,
    893                                          gpointer data)
    894 {
    895   GList *sel;
    896   for (sel = selection->selection; sel; sel = g_list_next(sel)) {
    897     guint row = GPOINTER_TO_UINT(sel->data);
    898     func(selection->model, &row, &row, data);
    899   }
    900 }
    901 
    902 void gtk_tree_view_update_selection(GtkWidget *widget)
    903 {
    904   GtkTreeView *tv = GTK_TREE_VIEW(widget);
    905   gint i;
    906 
    907   g_list_free(tv->selection);
    908   tv->selection = NULL;
    909   if (widget->hWnd) {
    910     if (tv->model) for (i = 0; i < tv->model->rows->len; i++) {
    911       if (SendMessageW(widget->hWnd, LB_GETSEL, (WPARAM)i, 0) > 0) {
    912         tv->selection = g_list_append(tv->selection, GINT_TO_POINTER(i));
    913       }
    914     }
    915 
    916     gtk_signal_emit(G_OBJECT(widget), "changed");
    917   }
    918 }
    919 
    920 static LRESULT CALLBACK TreeViewHdrWndProc(HWND hwnd, UINT msg, WPARAM wParam,
    921                                            LPARAM lParam)
    922 {
    923   GtkWidget *widget;
    924   gboolean retval = FALSE, dodef = TRUE;
    925 
    926   widget = GTK_WIDGET(GetWindowLongPtr(hwnd, GWLP_USERDATA));
    927 
    928   if (widget) {
    929     retval = gtk_tree_view_wndproc(widget, msg, wParam, lParam, &dodef);
    930   }
    931 
    932   if (dodef) {
    933     return DefWindowProcW(hwnd, msg, wParam, lParam);
    934   } else {
    935     return retval;
    936   }
    937 }
    938 
    939 void InitTreeViewClass(HINSTANCE hInstance)
    940 {
    941   WNDCLASS wc;
    942 
    943   wc.style = 0;
    944   wc.lpfnWndProc = TreeViewHdrWndProc;
    945   wc.cbClsExtra = 0;
    946   wc.cbWndExtra = 0;
    947   wc.hInstance = hInstance;
    948   wc.hIcon = NULL;
    949   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    950   wc.hbrBackground = NULL;
    951   wc.lpszMenuName = NULL;
    952   wc.lpszClassName = WC_GTKTREEVIEWHDR;
    953   myRegisterClass(&wc);
    954 }
    955 
    956 /* Make a new GtkListStore and fill in the column types */
    957 GtkListStore *gtk_list_store_new(gint n_columns, ...)
    958 {
    959   GtkListStore *store;
    960   int i;
    961 
    962   va_list ap;
    963   va_start(ap, n_columns);
    964 
    965   store = GTK_LIST_STORE(GtkNewObject(&GtkListStoreClass));
    966   store->view = NULL;
    967   store->ncols = n_columns;
    968   store->coltype = g_new(int, n_columns);
    969   store->rows = g_array_new(FALSE, FALSE, sizeof(GtkListStoreRow));
    970   store->sort_column_id = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
    971   store->sort_func = g_array_new(FALSE, TRUE, sizeof(gpointer));
    972   store->need_sort = FALSE;
    973   for (i = 0; i < n_columns; ++i) {
    974     store->coltype[i] = va_arg(ap, int);
    975   }
    976   va_end(ap);
    977   return store;
    978 }
    979 
    980 void gtk_tree_sortable_set_sort_func(GtkTreeSortable *sortable,
    981                                      gint sort_column_id,
    982                                      GtkTreeIterCompareFunc sort_func,
    983                                      gpointer user_data,
    984                                      GDestroyNotify destroy)
    985 {
    986   /* We don't currently support user_data */
    987   if (sort_column_id >= sortable->sort_func->len) {
    988     g_array_set_size(sortable->sort_func, sort_column_id+1);
    989   }
    990   g_array_index(sortable->sort_func, gpointer, sort_column_id) = sort_func;
    991 }
    992 
    993 void gtk_tree_sortable_set_sort_column_id(GtkTreeSortable *sortable,
    994                                           gint sort_column_id,
    995                                           GtkSortType order)
    996 {
    997   if (sortable->sort_column_id != sort_column_id
    998       || sortable->sort_order != order) {
    999     sortable->sort_column_id = sort_column_id;
   1000     sortable->sort_order = order;
   1001     sortable->need_sort = TRUE;
   1002   }
   1003 }
   1004 
   1005 /* We don't support customizing renderers right now */
   1006 GtkCellRenderer *gtk_cell_renderer_text_new(void)
   1007 {
   1008   return NULL;
   1009 }
   1010 
   1011 static GtkTreeViewColumn *new_column_internal(const char *title, va_list args)
   1012 {
   1013   GtkTreeViewColumn *col;
   1014   const char *name;
   1015 
   1016   col = g_new0(GtkTreeViewColumn, 1);
   1017   col->title = g_strdup(title);
   1018   col->resizeable = FALSE;
   1019   col->expand = FALSE;
   1020   col->auto_resize = TRUE;
   1021   col->sort_column_id = -1;
   1022   col->model_column = -1;
   1023   col->xalign = 0.0;   /* left align by default */
   1024 
   1025   /* Currently we only support the "text" attribute to point to the
   1026      ListStore column */
   1027   while ((name = va_arg(args, const char *)) != NULL) {
   1028     if (strcmp(name, "text") == 0) {
   1029       col->model_column = va_arg(args, int);
   1030     }
   1031   }
   1032   return col;
   1033 }
   1034 
   1035 GtkTreeViewColumn *gtk_tree_view_column_new_with_attributes
   1036                    (const gchar *title, GtkCellRenderer *cell, ...)
   1037 {
   1038   GtkTreeViewColumn *col;
   1039   va_list args;
   1040 
   1041   va_start(args, cell);
   1042   col = new_column_internal(title, args);
   1043   va_end(args);
   1044   return col;
   1045 }
   1046 
   1047 gint gtk_tree_view_insert_column_with_attributes
   1048             (GtkTreeView *tree_view, gint position, const gchar *title,
   1049              GtkCellRenderer *cell, ...)
   1050 {
   1051   GtkTreeViewColumn *col;
   1052   va_list args;
   1053 
   1054   va_start(args, cell);
   1055   col = new_column_internal(title, args);
   1056   va_end(args);
   1057   return gtk_tree_view_insert_column(tree_view, col, position);
   1058 }
   1059 
   1060 void gtk_tree_view_scroll_to_cell(GtkTreeView *tree_view,
   1061                                   GtkTreePath *path,
   1062                                   GtkTreeViewColumn *column,
   1063                                   gboolean use_align, gfloat row_align,
   1064                                   gfloat col_align)
   1065 {
   1066   /* not implemented */
   1067 }
   1068 
   1069 void gtk_tree_view_column_set_resizable(GtkTreeViewColumn *tree_column,
   1070                                         gboolean resizable)
   1071 {
   1072   tree_column->resizeable = resizable;
   1073 }
   1074 
   1075 void gtk_tree_view_column_set_expand(GtkTreeViewColumn *tree_column,
   1076                                      gboolean expand)
   1077 {
   1078   tree_column->expand = expand;
   1079 }
   1080 
   1081 void gtk_tree_view_column_set_sort_column_id(GtkTreeViewColumn *tree_column,
   1082                                              gint sort_column_id)
   1083 {
   1084   tree_column->sort_column_id = sort_column_id;
   1085 }
   1086 
   1087 void gtk_tree_view_column_set_alignment(GtkTreeViewColumn *tree_column,
   1088                                         gfloat xalign)
   1089 {
   1090   tree_column->xalign = xalign;
   1091 }
   1092 
   1093 gint gtk_tree_view_insert_column(GtkTreeView *tree_view,
   1094                                  GtkTreeViewColumn *column,
   1095                                  gint position)
   1096 {
   1097   tree_view->columns = g_slist_insert(tree_view->columns, column, position);
   1098   return g_slist_length(tree_view->columns);
   1099 }
   1100 
   1101 GtkTreeViewColumn *gtk_tree_view_get_column(GtkTreeView *tree_view, gint n)
   1102 {
   1103   return g_slist_nth_data(tree_view->columns, n);
   1104 }
   1105 
   1106 void gtk_tree_view_set_model(GtkTreeView *tree_view, GtkTreeModel *model)
   1107 {
   1108   /* We only support a single model per view, so ignore attempts to remove it */
   1109   if (model) {
   1110     tree_view->model = model;
   1111     model->view = tree_view;
   1112   }
   1113 }
   1114 
   1115 struct ListStoreSortData {
   1116   GtkTreeIterCompareFunc sort_func;
   1117   GtkListStore *store;
   1118   gboolean reversed;
   1119 };
   1120 
   1121 static gint tree_view_sort_func(gconstpointer a, gconstpointer b, gpointer data){
   1122   /* Map from sorting an array of guint indices into sorting a GtkListStore */
   1123   struct ListStoreSortData *d = data;
   1124   const guint *inda = a, *indb = b;
   1125   if (d->reversed) {
   1126     return d->sort_func(d->store, (guint*)indb, (guint*)inda, NULL);
   1127   } else {
   1128     return d->sort_func(d->store, (guint*)inda, (guint*)indb, NULL);
   1129   }
   1130 }
   1131 
   1132 void gtk_tree_view_sort(GtkTreeView *tv)
   1133 {
   1134   GtkListStore *model = tv->model;
   1135   struct ListStoreSortData data;
   1136   HWND hWnd;
   1137   GArray *inds, *revinds;
   1138   guint i;
   1139   GArray *newrows;
   1140   if (!model || !model->need_sort
   1141       || model->sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID) {
   1142     return;
   1143   }
   1144 
   1145   /* Before sort, inds[row] = row */
   1146   inds = g_array_sized_new(FALSE, FALSE, sizeof(guint), model->rows->len);
   1147   for (i = 0; i < model->rows->len; ++i) {
   1148     g_array_append_val(inds, i);
   1149   }
   1150   data.sort_func = g_array_index(model->sort_func, GtkTreeIterCompareFunc,
   1151                                  model->sort_column_id);
   1152   data.store = model;
   1153   data.reversed = model->sort_order == GTK_SORT_DESCENDING;
   1154   g_array_sort_with_data(inds, tree_view_sort_func, &data);
   1155 
   1156   /* After sort, inds[newrow] = oldrow */
   1157   /* Now we can reconstruct model->rows in the new order */
   1158   newrows = g_array_sized_new(FALSE, FALSE, sizeof(GtkListStoreRow),
   1159                               model->rows->len);
   1160   for (i = 0; i < model->rows->len; ++i) {
   1161     guint oldrow = g_array_index(inds, guint, i);
   1162     g_array_append_val(newrows,
   1163                        g_array_index(model->rows, GtkListStoreRow, oldrow));
   1164   }
   1165 
   1166   /* Make revinds[oldrow] = newrow */
   1167   revinds = g_array_sized_new(FALSE, FALSE, sizeof(guint), model->rows->len);
   1168   g_array_set_size(revinds, model->rows->len);
   1169   for (i = 0; i < model->rows->len; ++i) {
   1170     guint oldrow = g_array_index(inds, guint, i);
   1171     g_array_index(revinds, guint, oldrow) = i;
   1172   }
   1173 
   1174   /* Update selection (only works for a single selection currently) */
   1175   if (tv->selection) {
   1176     guint oldrow = GPOINTER_TO_UINT(tv->selection->data);
   1177     guint newrow = g_array_index(revinds, guint, oldrow);
   1178     if (oldrow != newrow) {
   1179       gtk_tree_selection_unselect_path(tv, &oldrow);
   1180       gtk_tree_selection_select_path(tv, &newrow);
   1181     }
   1182   }
   1183 
   1184   /* No need to free the old row data since the new structure takes ownership */
   1185   g_array_free(model->rows, TRUE);
   1186   model->rows = newrows;
   1187 
   1188   g_array_free(inds, TRUE);
   1189   g_array_free(revinds, TRUE);
   1190   model->need_sort = FALSE;
   1191 
   1192   hWnd = GTK_WIDGET(tv)->hWnd;
   1193   if (hWnd)
   1194     InvalidateRect(hWnd, NULL, FALSE);
   1195 }
   1196 
   1197 GtkTreeModel *gtk_tree_view_get_model(GtkTreeView *tree_view)
   1198 {
   1199   return tree_view->model;
   1200 }
   1201 
   1202 void gtk_tree_view_set_headers_clickable(GtkTreeView *tree_view,
   1203                                          gboolean setting)
   1204 {
   1205   tree_view->headers_clickable = setting;
   1206 }
   1207 
   1208 /* These are noops; we only use these for GtkListStore, which should always
   1209    be owned (and thus freed) by our GtkTreeView */
   1210 void g_object_unref(gpointer object)
   1211 {
   1212 }
   1213 
   1214 gpointer g_object_ref(gpointer object)
   1215 {
   1216   return object;
   1217 }
   1218 
   1219 #else /* for systems with GTK+ */
   1220 
   1221 GtkWidget *gtk_scrolled_tree_view_new(GtkWidget **pack_widg)
   1222 {
   1223   GtkWidget *scrollwin, *clist;
   1224 
   1225   clist = gtk_tree_view_new();
   1226   scrollwin = gtk_scrolled_window_new(NULL, NULL);
   1227   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin),
   1228                                  GTK_POLICY_AUTOMATIC,
   1229                                  GTK_POLICY_AUTOMATIC);
   1230   gtk_container_add(GTK_CONTAINER(scrollwin), clist);
   1231   *pack_widg = scrollwin;
   1232   return clist;
   1233 }
   1234 
   1235 #endif