/* Research Project: Graphical Database for Category Theory J. Bradbury, Dr. R. Rosebrugh, I. Rutherford Mount Allison University 2001 File: DragFix.java (author: Larry Barowski, Auburn University, 3/7/97) Description: Drag fix queues events and eliminates repeated mouse drag events and scrollbar events (most annoying on Win95). Be sure the Component doesn't post an event to itself after every mouse drag or scrollbar event, or this will do no good. I suggest getParent().postEvent() instead. Notes: The constructor for the Component that uses it should have (to be safe, as the first line): dragFix_ = new DragFix(this); // dragFix_ is a member variable. The handleEvent() function should look like this: public boolean handleEvent(Event e) { if(e.id == DragFix.QUEUED) { deal with (Event)e.arg if necessary, super.handleEvent((Event)e.arg); if necessary, getParent().postEvent((Event)e.arg); return true; } dragFix_.queueEvent(e); return true; } and removeNotify should look like this, to kill the thread immediately - otherwise it will be there (asleep) until finalize() gets called (if ever): public synchronized void removeNotify() { dragFix_.killThread(); super.removeNotify(); } */ //Import statement import java.awt.Event; import java.awt.Component; public class DragFix implements Runnable { private Component user_; private Thread thread_; private Event[] eventQueue_ = null; private int eventQueueHead_ = 0, eventQueueTail_ = 0; private int eventQueueSize_ = 40; // More than enough, in most cases. private final static int eventQueueLimit_ = 2000; private Object lock_ = new Object(); public final static int QUEUED = 179583; public DragFix(Component user) { user_ = user; eventQueue_ = new Event[eventQueueSize_ + 1]; thread_ = new Thread(this); thread_.start(); } protected void finalize() { killThread(); } public void killThread() { thread_.stop(); } /** * Queue or ignore an event. Call this from handleEvent() * and return true. **/ public void queueEvent(Event e) { Queue(e); } /** * Queue or dequeue an event. **/ private Event Queue(Event e) { synchronized(lock_) { if(e == null) // Dequeue { if(eventQueueHead_ != eventQueueTail_) // Not empty. { eventQueueTail_ = (eventQueueTail_ + 1) % eventQueueSize_; return eventQueue_[eventQueueTail_]; } return null; // To indicate empty. } // Add to queue. if(eventQueueHead_ != eventQueueTail_ && e.target == eventQueue_[eventQueueHead_].target) { int newid = eventQueue_[eventQueueHead_].id; if((e.id == Event.MOUSE_DRAG && newid == Event.MOUSE_DRAG) || ((e.id == Event.SCROLL_ABSOLUTE || e.id == Event.SCROLL_LINE_DOWN || e.id == Event.SCROLL_LINE_UP || e.id == Event.SCROLL_PAGE_DOWN || e.id == Event.SCROLL_PAGE_UP) && (newid == Event.SCROLL_ABSOLUTE || newid == Event.SCROLL_LINE_DOWN || newid == Event.SCROLL_LINE_UP || newid == Event.SCROLL_PAGE_DOWN || newid == Event.SCROLL_PAGE_UP))) { // Eliminate the previous mouse drag or scroll. // This assumes all scroll handling will use // absolute positions, instead of "clicks". eventQueue_[eventQueueHead_] = e; return null; } } eventQueue_[(eventQueueHead_ + 1) % eventQueueSize_] = e; eventQueueHead_ = (eventQueueHead_ + 1) % eventQueueSize_; lock_.notify(); if((eventQueueHead_ + 1) % eventQueueSize_ == eventQueueTail_) { // Queue is full, grow it. int new_size = eventQueueSize_ * 2; // if(new_size > eventQueueLimit_) // throw new Error("DragFix event queue size limit " + // "exceeded."); Event[] new_queue = new Event[new_size + 1]; int i = 0, j; for(j = eventQueueTail_; j != eventQueueHead_; j = (j + 1) % eventQueueSize_, i++) new_queue[i] = eventQueue_[j]; new_queue[i] = eventQueue_[j]; eventQueue_ = new_queue; eventQueueHead_ = i; eventQueueTail_ = 0; eventQueueSize_ = new_size; } return null; } } /** * Process queued events. **/ public synchronized void run() { Event e; while(true) { // Process events until the queue is empty. while((e = Queue(null)) != null) { user_.postEvent(new Event(e, QUEUED, e)); } // Now that it is empty, wait for the next event. synchronized(lock_) { try { lock_.wait(); } catch(InterruptedException ex) {} } } } }