Is anyone else having trouble with Copy in Elmer 0.8.1?

Dan Bornstein danfuzz@milk.com
Thu, 11 Feb 1999 22:16:47 -0800 (PST)


Mark S. Miller writes:
>When I run Elmer under Symantec Cafe, everything seems fine.  When I run it
>directly using jre.exe, or equivalently, from the installed icon,
>everything works fine except that copy doesn't put anything on the
>clipboard.  It doesn't seem to matter whether copy is invoked by Ctrl-C or
>by menu.  I already made sure both were using the same swing .jar file.
>Since the bug only happens when I can't examine it...
>
>Has anyone else been seeing similar problems?  Under what conditions?

I've been developing an app with Swing and also noticed a problem with X
and the clipboard. I'm using the blackdown.org Linux/x86 port of JDK-1.1.7.
Within the app, copy and paste work fine, but it neither seems to catch
copies from the "outside world" nor does copying within the app affect the
"outside world".

(Note: stop reading now if all you want out of this list is E discussion,
especially if you're not in the mood for minor heresy.)

This isn't directly about E, but I thought I'd share a little bit about the
design of my app. One of the pieces is a toolkit consisting of interfaces
and events, and a couple of base classes, somewhat along the line of
AWT/Swing (but not for anything having to do directly with graphics), but
with a couple innovations. As most of you probably know, event-style
programming and asynch messaging-style programming are fairly similar
when you get right down to it. What I've come up with is my "happy medium".
I don't think I have the time (or patience) to go into all the details,
but I'll give a quick (and somewhat simplified) example of what I've
done:

    interface Entity /* how many synonyms of Object are there? */
    {
        void addListener (EventListener l);
        void removeListener (EventListener l);
    }

    abstract class BaseEvent
    extends java.util.Event
    {
        public abstract void sendTo (java.util.EventListener l);
    }

    interface Foo
    extends Entity
    {
        ...
    }

    class FooEvent
    extends BaseEvent
    {
        private FooEvent (Foo source, ...) { ... }
        public void sendTo (java.util.EventListener l) { ... }
        static FooEvent interestingThing (Foo source, ...) { ... }
        static FooEvent somethingElse (Foo source, ...) { ... }
        ...
    }

    interface FooListener
    extends java.util.EventListener
    {
        void interestingThing (FooEvent event);
        void somethingElse (FooEvent event);
    }

The salient aspects are: 1) All objects that send events have a single
add/removeListener interface. 2) For the most part, you can tell the class
of event that anything sends by adding "Event" to the name of the
interface(s) it implements. 3) You know what interface to implement if you
care about listening to such events by replacing "Event" with "Listener".
4) An event is made *only* by using static (and well checked) methods on
the event class. 5) The listener method name for an event has the same name
as the name of the static method to create that event (on the event class).

In this model, listeners aren't supposed to throw exceptions, but if they
do, it's legit to just drop them on the floor (although in debug mode it'll
spit them to System.err). Also, listeners aren't supposed to take long to
execute their code, but there's not much enforcement there either. Horrible
as it may seem, you still have to be careful with multi-thread access to
objects. And, you still have to do a bit of (error-prone) copy/paste work
to get all the event and listener methods named and dispatched
appropriately. It's a bit like manually constructing method dispatch
tables and deflectors.

All of this is leading to a very simple comment: The above design wasn't
too hard to develop, isn't too onerous to write code for, and Java didn't
get in the way of its implementation very much. And, despite its
imperfections, it does seem to work reasonably well (admittedly, for a
non-distributed app, but one which *does* do asynchronous comm). There have
certainly been times that I've just wanted to write a "<-" and be done with
it, but, somewhat surprisingly, those moments have been fairly infrequent.

Before writing this app, I was a bit unsure about how it would be to
*really* program in Java, as opposed to the keep-my-nose-pinched paradigm
which I'd practiced in the past (both at EC and on the demo/prototype for
my "real" job). My current opinion is that it's still a pain in the ass,
and it's harder than it ought to be, but it *is* sufficiently useful, even
without a lot of new library support. (The utility/base classes to support
my event model are only a few hundred lines of code.)

Okay, I'll stop being heretical now and tell you what the program actually
does.

(Note: stop reading now if you don't care about the particulars of the app.)

The app in question is called UberChat, and its origin is in me getting
frustrated with all the really bad text chat interfaces that are out there,
and the fact that all chat clients I've ever seen only handle one protocol.
I know that IRC sucks as a protocol and is insecure, blah blah blah, but
the fact is, I have a friend that runs a private IRC server, and I want to
access it. I also have a group of friends that hang out on an ICB server,
and I want to play there too. And I have a few friends on The SpaceBar,
etc. Anyway, I'm not trying to force these guys to shut down their servers
to run something better, merely trying to make the interface on my end
tolerable.

I've been working on this in the bit of spare time I've found myself
having, since the demo/prototype for my "real" work is stable, but we still
aren't funded. Rather than twiddle my thumbs and tweak the demo (which
won't get us any closer to funding), I decided it was time to do UberChat,
something I'd thought of doing for quite a while. Also, I had the
realization recently that I don't really have a significant system that
I've done post-college that I'm not NDA-obliged not to show off.

My goal for the 1.0 release is to handle three fairly different server
protocols and have both graphical and text console UIs. Right now, I've got
two protocols *mostly* done (ICB and "spacebar"), have a working but
incomplete GUI, and have a used-to-work-but-is-now-out-of-date and
butt-ugly console UI. As those of you who know my past work can probably
surmise, I've paid very careful attention to keeping the different pieces
of the system fairly carefully separated. The system is (mostly) cleanly
divided into:

  0. Independent utility classes/packages
     * event system support
     * timing support
     * asynch dataflow support
     * generic object editing support (think "Inspector" only a little 
         more general)
     ... and a couple other things
  1. Interfaces and event classes
  2. useful (but unnecessary) base classes
  3. ui code (which only depends on #0-1)
  4. protocol/client adapter classes (which only depend on #0-1)

I've been making a couple pre-releases of this per week or so for about the
last month, but I've been fairly quiet about it, since it still needs lots
of work before I'm ready for the masses to bang on it. However, I trust the
members of this list to be sophisticated enough to understand what it means
to be a pre-pre-pre-alpha piece of software. That being said, you can find
a screen-shot at:

  http://www.milk.com/dropoff/uberdump.gif

and you can find the latest distribution (as of this writing) at:

  http://www.milk.com/dropoff/uberchat-0.9.tar.gz

The distribution includes (well-commented) source, jar file, run script,
javadoc files, and a couple info files. Feel free to snarf it and have a
look.

-dan, breaking his silence for a moment