[comp.windows.open-look] List Selection Bug

Lovstrand@EuroPARC.Xerox.COM (Lennart Lovstrand) (04/18/91)

Argh, I've just come across Yet Another XView Bug -- this time it's
the PANEL_LIST selection mechanism that is broken.  Try this:

Create a PANEL_LIST item with PANEL_CHOOSE_ONE and PANEL_CHOOSE_NONE
both true and fill it with a set of strings.  Make sure it has a
defined notifier.  Select a row at least once.  Now delete all
existing rows with PANEL_LIST_DELETE and insert new ones with
PANEL_LIST_INSERT and/or PANEL_LIST_STRING. Select an item and notice
how XView tries to first deselect a row from the old set *and from
memory that already has been freed*!

It doesn't matter if you deselect the last selected row before
refilling the list -- the result is the same.

I wouldn't normally have been in such a bad mood if it wasn't that
I've just wasted eight hours on this stupid little bug wading around
in the borderlands between Scheme and C thinking that the problem lay
in my Elk/XView interface.  And trust me, there are more pleasant ways
to spend your time...

The only workaround I've come up with so far is to destroy the old
list and create a new one every time I want to change its contents.
Not exactly elegant.

If anyone else out there have any other ideas, I would sure like to
know.

Here's a sample program for curious and core-less:

--Lennart

#include <stdio.h>
#include <xview/xview.h>
#include <xview/panel.h>

#define KEY_LIST	12345

char *list_strings[] = {
    "hej",
    "hopp",
    "alla",
    "feta",
    "nyllen",
    NULL
};

void
refill_list(button, event)
    Panel_item button;
    Event *event;
{
    Panel_item list;
    int *block, i;

    list = xv_get(button, XV_KEY_DATA, KEY_LIST);

    /* delete all existing rows */
    for (i = xv_get(list, PANEL_LIST_NROWS); i > 0; i--)
	xv_set(list, PANEL_LIST_DELETE, i - 1, NULL);

    /* waste some space... */
    block = (int *) malloc(20 * sizeof(int));
    for (i = 0; i < 20; i++)
	block[i] = 0x12345678;

    /* fill with new, fresh ones */
    for (i = 0; list_strings[i] != NULL; i++)
	xv_set(list, PANEL_LIST_STRING, i, list_strings[i], NULL);
}

void
list_notifier(list, string, data, op, event)
    Panel_item list;
    char *string;
    caddr_t data;
    Panel_list_op op;
    Event *event;
{
    char *strop;
    int i;

    switch (op) {
      case PANEL_LIST_OP_SELECT:	strop = "selected"; break;
      case PANEL_LIST_OP_DESELECT:	strop = "deselected"; break;
      default:				strop = "<other op>"; break;
    }

    printf("-- %#x %s\n", string, strop);
    printf("[%s]\n", string);
}

main(argc, argv)
    int argc;
    char **argv;
{
    Frame frame;
    Panel panel;
    Panel_item button, list;
    char **strp;

    xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, 0);

    frame = xv_create(NULL, FRAME, NULL);

    panel = xv_create(frame, PANEL, NULL);

    list = xv_create(panel, PANEL_LIST,
		     PANEL_LIST_DISPLAY_ROWS, 8,
		     PANEL_LIST_WIDTH, 100,
		     PANEL_NOTIFY_PROC, list_notifier,
		     PANEL_CHOOSE_ONE, TRUE,
		     PANEL_CHOOSE_NONE, TRUE,
		     NULL);

    button = xv_create(panel, PANEL_BUTTON,
		       PANEL_LABEL_STRING, "Refill list",
		       PANEL_NOTIFY_PROC, refill_list,
		       XV_KEY_DATA, KEY_LIST, list,
		       NULL);

    for (strp = list_strings; *strp != NULL; strp++)
	printf("%#x: %s\n", *strp, *strp);

    xv_main_loop(frame);
}
--
--Lennart <Lovstrand@EuroPARC.Xerox.COM>		R   _A _  N_   K
Rank Xerox EuroPARC, 61 Regent St, Cambridge, UK	\/ |_ |_) | | \/
Ackpft, Sun-4/75 at EuroPARC, SunOS Release 4(1.1)-2	/\ |_ | \ |_| /\
TOPS-20 Command processor 7(103)-2 [alpha]		E u r o  P A R C

karln@uunet.uu.net (04/19/91)

In article <1991Apr17.222421.19223@parc.xerox.com> Lovstrand@EuroPARC.Xerox.COM (Lennart Lovstrand) writes:
>Argh, I've just come across Yet Another XView Bug -- this time it's
>the PANEL_LIST selection mechanism that is broken.  Try this:
>
[Deleted description]
>
>If anyone else out there have any other ideas, I would sure like to
>know.
>
>Here's a sample program for curious and core-less:
>
>--Lennart
>


Greetings Lennart, 

   I not *entirely* sure what your problem was, but I did get your code
to work.

   A few suggestions in general about programming ...

   1: I personally *NEVER* put in malloc's without the properly executed free's
     Certainly I never put mallocs in without frees at all.

   2: I do not have a lot of experience with XV_KEY_DATA, but it *seems*
      illogical to start putting key data into number 12345. I changed it to start
      at 1. It makes more sense to start with the obvious, get it working, then
      try to break it, if you have nothing better to do.

Here is the code as I modified it. You will find that the changes were minimal.

Incedently, I was having problems this very morning with PANEL_LIST & PANEL_LIST_ONE
& PANEL_LIST_NONE = TRUE, and was just about to give up when I figured I would 
just settle down a bit and read to news for a few minutes. Your article and program
showed me that what I thought should work did in fact work, so I figured I owed it to
you to take a look at your problem. Thanks, really :-).

Karl Nicholas.



#include <stdio.h>
#include <xview/xview.h>
#include <xview/panel.h>

#define KEY_LIST 1

char *list_strings[] = {
    "hej",
    "hopp",
    "alla",
    "feta",
    "nyllen",
    NULL
};

void
refill_list(button, event)
    Panel_item button;
    Event *event;
{
    Panel_item list;
    int  i;

    list = xv_get(button, XV_KEY_DATA, KEY_LIST);

    /* delete all existing rows */
    for (i = xv_get(list, PANEL_LIST_NROWS); i > 0; i--)
	xv_set(list, PANEL_LIST_DELETE, i - 1, NULL);

    /* waste some space... */

/* what is this ? 
    block = (int *) malloc(20 * sizeof(int));
    for (i = 0; i < 20; i++)
	block[i] = 0x12345678;
*/

    /* fill with new, fresh ones */
    for (i = 0; list_strings[i] != NULL; i++)
	xv_set(list, PANEL_LIST_STRING, i, list_strings[i], NULL);

}

void
list_notifier(list, string, data, op, event)
    Panel_item list;
    char *string;
    caddr_t data;
    Panel_list_op op;
    Event *event;
{
    char *strop;
    int i;

    switch (op) {
      case PANEL_LIST_OP_SELECT:	strop = "selected"; break;
      case PANEL_LIST_OP_DESELECT:	strop = "deselected"; break;
      default:				strop = "<other op>"; break;
    }

    printf("-- %#x %s\n", string, strop);
    printf("[%s]\n", string);
}

main(argc, argv)
    int argc;
    char **argv;
{
    Frame frame;
    Panel panel;
    Panel_item button, list;
    char **strp;

    xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, 0);

    frame = xv_create(NULL, FRAME, NULL);

    panel = xv_create(frame, PANEL, NULL);

    list = xv_create(panel, PANEL_LIST,
		     PANEL_LIST_DISPLAY_ROWS, 8,
		     PANEL_LIST_WIDTH, 100, 
		     PANEL_NOTIFY_PROC, list_notifier,
		     PANEL_CHOOSE_ONE, TRUE,
		     PANEL_CHOOSE_NONE, TRUE,
		     NULL);

    button = xv_create(panel, PANEL_BUTTON,
		       PANEL_LABEL_STRING, "Refill list",
		       PANEL_NOTIFY_PROC, refill_list,
		       XV_KEY_DATA, KEY_LIST, list,
		       NULL);

    for (strp = list_strings; *strp != NULL; strp++)
	printf("%#x: %s\n", *strp, *strp);

    xv_main_loop(frame);
}



-- 
***********************************************************************
| Karl Nicholas             | A recent Gallop Poll showed that 1 in 6 |
| karln!karln@uunet.uu.net  | Americans have spoken to a dead person. |
***********************************************************************

Lovstrand@EuroPARC.Xerox.COM (Lennart Lovstrand) (04/25/91)

In article <1991Apr19.165038.6774@uunet.uu.net> karln@karln.UUCP () writes:
>In article <1991Apr17.222421.19223@parc.xerox.com> Lovstrand@EuroPARC.Xerox.COM (Lennart Lovstrand) writes:
>>Argh, I've just come across Yet Another XView Bug -- this time it's
>>the PANEL_LIST selection mechanism that is broken.  Try this:
>>[...]
>Greetings Lennart, 
>
>   I not *entirely* sure what your problem was, but I did get your code
>to work.
>
>   A few suggestions in general about programming ...
>   1: I personally *NEVER* put in malloc's without the properly executed free's
>     Certainly I never put mallocs in without frees at all.
>   2: I do not have a lot of experience with XV_KEY_DATA, but it *seems*
>      illogical to start putting key data into number 12345. I changed it to start
>      at 1. It makes more sense to start with the obvious, get it working, then
>      try to break it, if you have nothing better to do.

Bzzzt, wrong.  The malloc() is there for a particular purpose -- to waste some
space between the calls that create new instances of the panel list.  If you
remove it, you won't notice that the string pointers you're getting back come
from old, free()'d memory.

Besides, there is nothing magic about malloc()'s that aren't matched by a
corresponding free() -- it's called a memory leak, that's all.  It certainly
is bad coding practice, only barely excusable in demonstration examples and
programs with limited execution times.

XV_KEY_DATA is used to associate random 32 bit user data with XView objects
using 32 bit keys.  Again, there is nothing magic about either the key or the
data.  The key could be 12345 just as well as 54321 or the address "foo" or
whatever.

Except for destroying and recreating the list, the only other solution I've
heard of so far is to make the list non-exclusive and let the callback routine
deselect the last item itself (thanks to Jan Andersson at Ericsson for that
one).

Anyway, thanks for trying.
--Lennart