Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!helios!bcm!dimacs.rutgers.edu!seismo!uunet!qualix!murph From: murph@qualix.com (Joe Murphy, at large) Newsgroups: comp.windows.open-look Subject: Re: XView scrolling list bug? Message-ID: <1991Mar1.233203.3473@qualix.com> Date: 1 Mar 91 23:32:03 GMT References: <23080@hydra.gatech.EDU> Organization: Qualix Group, Inc Lines: 163 In article <23080@hydra.gatech.EDU> gw18@prism.gatech.EDU (Greg Williams) writes: > >The following program produces an intermitant "Memory fault" crash. Its >occuring sometime before the routine "dir_proc" is called. The crash is >somewhere inside "xv_get". It takes a few minutes of playing and changing >directories to get the initial crash, but after it crashes once, I can >usually reproduce the crash, but not every time. I've run this code on a >4/65 and a 4/490, and get the same error. I'm running Open Windows as >supplied by Sun. Can anyone tell me if I'm doing something wrong with >the XView code? The crash occurs too often to ignore it. I appreciate any >and all help I get. > I'm pretty sure you are hitting the same bug I did involving scrolling lists in the Xview2 library. Here are the relevant clues: >----code begins here---- > >/* > * This program creates two scrolling lists, one with directories and one > * with files. It allows the user to search through directories for files > * and then select a file to "open". > */ > > ... > > pi_dir = (Panel_item)xv_create(panel, PANEL_LIST, > ... > PANEL_CHOOSE_ONE, TRUE, > ... > NULL); > > ... >/* > * First delete the old entries > */ > > for (i = num_dirs - 1; i >= 0; i--) > xv_set(pi_dir, PANEL_LIST_DELETE, i, NULL); > > for (i = num_files - 1; i >= 0; i--) > xv_set(pi_file, PANEL_LIST_DELETE, i, NULL); > > ... >----code ends here---- There is the bug in the xview2 library (source file is xview2/lib/libxvol/panel/p_list.c) where the pointer dp->current_row is left pointing to garbage if you delete the selected item, and blows up sooner or later when the xview code later attempts to "deselect" that vanished row. The bug doesn't show up for "non-exclusive" lists (ie PANEL_CHOOSE_ONE, FALSE,) so that is a possible work-around. For a while I had a work-around that involved forcing a selection of an item not being deleted before the PANEL_LIST_DELETE, but clearly this did not work when the whole list is being cleared as in your case. Finally I cobbled together some code where I clear out the pointer after every PANEL_LIST_DELETE, and have not seen any problems since then. I could have course modified the library directly, but I don't want to ship my applications with the Xview2.0 libraries static linked (otherwise they end up being megabytes in size instead of a couple of hundred Kbytes altogether - ie 1 floppy instead of many). BTW I strongly recommend you get xview2 library src from somewhere (I got mine from uunet) and build it with "-g" turned on so you can follow core dumps into the buggy parts of the library. Here are the relevant parts of "p_list.c": ********************************** xview2/lib/libxvol/panel/p_list.c ********************************** ... Pkg_private Xv_opaque panel_list_set_avlist(panel_list_public, avlist) Panel_item panel_list_public; Attr_avlist avlist; { ... /* * Process the attributes that rely on the already processed attributes. */ avlist = orig_avlist; for (avlist = orig_avlist; *avlist; avlist = attr_next(avlist)) { switch ((int) avlist[0]) { ... case PANEL_LIST_DELETE:{ int which_row = (int) avlist[1]; Row_info *node = dp->rows; while (node && (node->row != which_row)) node = node->next; if (node) panel_list_delete_row(dp, node, DO_NOT_REPAINT_LIST); break; } ... } } /* Non-exclusive lists can have no current row */ if (!dp->choose_one) dp->choose_none = TRUE; if (!dp->choose_none && dp->rows && !dp->setting_current_row) { /* If no row is selected, then select the first row */ for (row = dp->rows; row; row = row->next) if (row->selected) break; if (!row) { dp->current_row = dp->rows; dp->current_row->selected = TRUE; } } ... return XV_OK; } static void set_current_row(dp, event_row, event) Panel_list_info *dp; Row_info *event_row; Event *event; /* NULL => not event generated */ { int new_state = TRUE; int toggle = FALSE; if (dp->choose_one) { if (dp->current_row == event_row) { if (dp->choose_none) toggle = TRUE; } else if (dp->current_row) { dp->setting_current_row = TRUE; dp->current_row->selected = FALSE; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv /* usually detonates below here, since dp->current_row can be trash */ show_feedback(dp, dp->current_row, event); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ } if (toggle) new_state = event_row->selected ? FALSE : TRUE; event_row->selected = new_state; show_feedback(dp, event_row, event); dp->setting_current_row = FALSE; } else { new_state = event_row->selected ? FALSE : TRUE; event_row->selected = new_state; show_feedback(dp, event_row, event); } dp->current_row = event_row; }