1. /*
  2. * @(#)SystemEventQueueUtilities.java 1.34 00/07/26
  3. *
  4. * Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing;
  11. import java.awt.*;
  12. import java.awt.event.*;
  13. import java.awt.image.*;
  14. import java.util.*;
  15. import java.lang.reflect.InvocationTargetException;
  16. /**
  17. * Swing internal utilities for dealing with the AWT system event
  18. * queue. Four methods are exported, see the individual method javadoc
  19. * for more information: addRunnableCanvas(), removeRunnableCanvas(),
  20. * postRunnable(), queueComponentWorkRequest().
  21. *
  22. * Note: most of the code in this class is no longer needed since
  23. * we're no longer supporting Swing in 1.1.x VM's and in 1.2 we're
  24. * guaranteed access to the AWT event queue. However all of the entry
  25. * points, save postRunnable(), are still used.
  26. *
  27. * @see RepaintManager
  28. * @see JRootPane
  29. */
  30. class SystemEventQueueUtilities
  31. {
  32. private static final Object classLock = new Object();
  33. private static final Object rootTableKey = new Object() {
  34. public String toString() {
  35. return "SystemEventQueueUtilties.rootTableKey";
  36. }
  37. };
  38. private static Map getRootTable() {
  39. Map rt = (Map)sun.awt.AppContext.getAppContext().get(rootTableKey);
  40. if (rt == null) {
  41. synchronized (rootTableKey) {
  42. rt = (Map)sun.awt.AppContext.getAppContext().get(rootTableKey);
  43. if (rt == null) {
  44. rt = new WeakHashMap(4);
  45. sun.awt.AppContext.getAppContext().put(rootTableKey, rt);
  46. }
  47. }
  48. }
  49. return rt;
  50. }
  51. /**
  52. * SystemEventQueue class. This private class just exists to
  53. * encapsulate the details of getting at the System Event queue
  54. * in the Java 2 platform and JDK1.1. The rest of the SystemEventQueueUtilities
  55. * class just uses SystemEventQueue.get() to access the event queue.
  56. */
  57. private static class SystemEventQueue
  58. {
  59. // If the AWT system event queue is accessible then return it.
  60. // otherwise return null.
  61. static EventQueue get() {
  62. EventQueue retValue;
  63. try {
  64. retValue = Toolkit.getDefaultToolkit().getSystemEventQueue();
  65. }
  66. catch (SecurityException se) {
  67. // Should never happen.
  68. retValue = null;
  69. }
  70. return retValue;
  71. }
  72. // If the AWT system event queue is accessible then return it.
  73. // otherwise return null. If the JRootPane has a special
  74. // client property set (and yech), we don't bother even
  75. // attempting to get at the event queue - see JApplet.
  76. static EventQueue get(JRootPane rootPane) {
  77. return get();
  78. }
  79. }
  80. /**
  81. * A Runnable with a component. If we need to post this
  82. * runnable to the AWT system event queue, we'll find it's
  83. * JRootPane ancestor and use that as the key to the table
  84. * of RunnableCanvas's.
  85. *
  86. * @see RunnableCanvas
  87. */
  88. private static class ComponentWorkRequest implements Runnable
  89. {
  90. boolean isPending;
  91. Component component;
  92. ComponentWorkRequest(Component c) {
  93. /* As of 1.2, the component field is no longer used. It was
  94. * used by the RunnableCanvas class to find the JRootPane
  95. * associated with a ComponentWorkRequest for JDK1.1.x.
  96. */
  97. // component = c;
  98. }
  99. public void run() {
  100. RepaintManager rm;
  101. synchronized (this) {
  102. rm = RepaintManager.currentManager(component);
  103. isPending = false;
  104. }
  105. rm.validateInvalidComponents();
  106. rm.paintDirtyRegions();
  107. }
  108. }
  109. /**
  110. * This method is used by RepaintManager to queue a ComponentWorkRequest
  111. * with invokeLater(). It assumes that the root argument is either
  112. * and Applet or a Window, the root passed in obtained in a
  113. * slightly different manner than see SwingUtilities.getRoot(). If this
  114. * called with the root obtained in a different way than RepaintManager
  115. * currently uses, be sure to also tweak removeRunnableCanvas.
  116. */
  117. static void queueComponentWorkRequest(Component root)
  118. {
  119. ComponentWorkRequest req = (ComponentWorkRequest)(getRootTable().get(root));
  120. boolean newWorkRequest = (req == null);
  121. if (newWorkRequest) {
  122. req = new ComponentWorkRequest(root);
  123. }
  124. /* At this point the ComponentWorkRequest may be accessible from
  125. * an event dispatching thread so before updating it further
  126. * we synchronize access to it.
  127. */
  128. synchronized(req) {
  129. if (newWorkRequest) {
  130. getRootTable().put(root, req);
  131. }
  132. if (!req.isPending) {
  133. SwingUtilities.invokeLater(req);
  134. req.isPending = true;
  135. }
  136. }
  137. }
  138. /**
  139. * Associate a RunnableCanvas and a JRootPane to enable queuing
  140. * events for the root pane's parent window's event dispatching thread.
  141. * Adds a 1x1 RunnableCanvas to the root pane's layered pane.
  142. * <p>
  143. * Called by JRootPane.addNotify() to set up the RunnableCanvas.
  144. *
  145. * @see RunnableCanvas
  146. * @see JRootPane#addNotify
  147. */
  148. static void addRunnableCanvas(JRootPane rootPane)
  149. {
  150. synchronized (classLock) {
  151. /* If we have access to the system event queue, we don't bother
  152. * with a RunnableCanvas
  153. */
  154. if (SystemEventQueue.get(rootPane) != null) {
  155. return;
  156. }
  157. JLayeredPane layeredPane = rootPane.getLayeredPane();
  158. if (layeredPane != null) {
  159. RunnableCanvas rc = new RunnableCanvas(rootPane);
  160. layeredPane.add(rc);
  161. }
  162. }
  163. }
  164. /**
  165. * Remove the RunnableCanvas from the JRootPane and clear the
  166. * internal bookeeping associated with it.
  167. * <p>
  168. * Called by JRootPane.removeNotify()
  169. *
  170. * @see RunnableCanvas
  171. */
  172. static void removeRunnableCanvas(JRootPane rootPane) {
  173. synchronized (classLock) {
  174. // We don't use SwingUtilities.getRoot, as it has different
  175. // behavior then the RepaintManager call to add the initial root.
  176. Component root = null;
  177. for (Component c = rootPane; c != null; c = c.getParent()) {
  178. if ((c instanceof Window) ||
  179. (c instanceof java.applet.Applet)) {
  180. root = c;
  181. break;
  182. }
  183. }
  184. if (root != null) {
  185. getRootTable().remove(root);
  186. }
  187. RunnableCanvas.remove(rootPane);
  188. }
  189. }
  190. /**
  191. * Post an event to the AWT System event queue that, when dispatched,
  192. * will invoke the specified Runnable. If lock is non-null this call
  193. * blocks (by waiting on the lock) until the doRun() method returns,
  194. * otherwise we return as soon as the event has been enqueued. An
  195. * exception is only returned if lock is non-null, i.e. if we're
  196. * being called from invokeAndWait().
  197. * <p>
  198. * This method is only intended to support SwingUtilities.invokeLater()
  199. * and SwingUtilities.invokeAndWait().
  200. */
  201. static Exception postRunnable(Runnable doRun, Object lock)
  202. {
  203. EventQueue systemEventQueue = SystemEventQueue.get();
  204. RunnableEvent event = new RunnableEvent(doRun, lock);
  205. if (systemEventQueue != null) {
  206. systemEventQueue.postEvent(event);
  207. }
  208. else {
  209. postRunnableCanvasEvent(event);
  210. }
  211. return event.exception;
  212. }
  213. /**
  214. * Adds a RunnableEvent to all the remaining RunnableCanvases to restart
  215. * the TimerQueues thread.
  216. *
  217. * @see RunnableCanvas#postRunnableEventToAll
  218. */
  219. static void restartTimerQueueThread() {
  220. synchronized (classLock) {
  221. if (SystemEventQueue.get() == null) {
  222. Runnable restarter = new TimerQueueRestart();
  223. RunnableEvent event = new RunnableEvent(restarter, null);
  224. RunnableCanvas.postRunnableEventToAll(event);
  225. }
  226. }
  227. }
  228. /**
  229. * Runnable that will message the shared instance of the Timer Queue
  230. * to restart.
  231. *
  232. * @see #restartTimerQueueThread
  233. */
  234. private static class TimerQueueRestart implements Runnable {
  235. boolean attemptedStart;
  236. public synchronized void run() {
  237. // Only try and restart the q once.
  238. if(!attemptedStart) {
  239. TimerQueue q = TimerQueue.sharedInstance();
  240. synchronized(q) {
  241. if(!q.running)
  242. q.start();
  243. }
  244. attemptedStart = true;
  245. }
  246. }
  247. }
  248. /**
  249. * Event type used for dispatching runnable objects for
  250. * SwingUtilities.invokeLater() and SwingUtilities.invokeAndWait().
  251. *
  252. * @see #postRunnable
  253. */
  254. private static class RunnableEvent extends AWTEvent {
  255. static final int EVENT_ID = AWTEvent.RESERVED_ID_MAX + 1000;
  256. static final Component target = new RunnableTarget();
  257. final Runnable doRun;
  258. final Object lock;
  259. Exception exception;
  260. RunnableEvent(Runnable doRun, Object lock) {
  261. super(target, EVENT_ID);
  262. this.doRun = doRun;
  263. this.lock = lock;
  264. }
  265. }
  266. /**
  267. * Calls RunnableEvent.doRun.run(). If RunnableEvent.lock is non
  268. * null then we synchronize the run() call and save the exception
  269. * (if any) in the RunnableEvent.exception field.
  270. */
  271. private static void processRunnableEvent(RunnableEvent runnableEvent)
  272. {
  273. Object lock = runnableEvent.lock;
  274. if (lock == null) {
  275. runnableEvent.doRun.run();
  276. }
  277. else {
  278. synchronized(lock) {
  279. try {
  280. runnableEvent.doRun.run();
  281. }
  282. catch (Exception e) {
  283. runnableEvent.exception = e;
  284. }
  285. finally {
  286. if (runnableEvent.lock != null) {
  287. runnableEvent.lock.notify();
  288. }
  289. }
  290. }
  291. }
  292. }
  293. /**
  294. * A dummy Component subclass that (only) handles RunnableEvents. If the
  295. * AWT System event queue is accessible (i.e. we're running as
  296. * an application or as trusted code), RunnableEvents are dispatched
  297. * to this component.
  298. *
  299. * @see #processRunnableEvent
  300. */
  301. private static class RunnableTarget extends Component
  302. {
  303. RunnableTarget() {
  304. super();
  305. enableEvents(RunnableEvent.EVENT_ID);
  306. }
  307. protected void processEvent(AWTEvent event) {
  308. if (event instanceof RunnableEvent) {
  309. processRunnableEvent((RunnableEvent)event);
  310. }
  311. }
  312. }
  313. /**
  314. * Synchronized entry point to the applet support for AWT System
  315. * event queue access. This method adds the event to the appropriate
  316. * runnable canvas's queue and then has the canvas repaint(). Note
  317. * that by the time the event dispatching thread gets to handling
  318. * the repaint() (by calling runnableCanvas.update()), many runnable
  319. * events may have been queued up.
  320. *
  321. * @see RunnableCanvas#addRunnableEvent
  322. * @see RunnableCanvas#update
  323. */
  324. private static void postRunnableCanvasEvent(RunnableEvent e) {
  325. synchronized (classLock) {
  326. RunnableCanvas runnableCanvas = RunnableCanvas.lookup(e);
  327. if (runnableCanvas == null) {
  328. /* If this is a ComponentWorkRequest and we were unable to
  329. * queue it, then clear the pending flag.
  330. */
  331. if (e.doRun instanceof ComponentWorkRequest) {
  332. ComponentWorkRequest req = (ComponentWorkRequest)e.doRun;
  333. synchronized(req) {
  334. req.isPending = false;
  335. }
  336. }
  337. /* If this is a Timer event let it know that it didn't fire.
  338. */
  339. if(e.doRun instanceof Timer.DoPostEvent) {
  340. ((Timer.DoPostEvent)e.doRun).getTimer().eventQueued = false;
  341. }
  342. /* We are unable to queue this event on a system event queue. Make
  343. * sure that any code that's waiting for the runnable to finish
  344. * doesn't hang.
  345. */
  346. if (e.lock != null) {
  347. e.lock.notify();
  348. }
  349. return;
  350. }
  351. runnableCanvas.addRunnableEvent(e);
  352. runnableCanvas.repaint();
  353. }
  354. }
  355. /**
  356. * Return the current threads ThreadGroup, even on IE4.0.
  357. * IE4.0 throws a SecurityException if you apply getThreadGroup()
  358. * to the event dispatching thread. However a child of the
  359. * event dispatching thread (same thread group) is OK.
  360. */
  361. private static ThreadGroup getThreadGroupSafely() {
  362. return new Thread().getThreadGroup();
  363. }
  364. /**
  365. * Applets don't have direct access to the AWT SystemEvent queue. To
  366. * work around this we call RunnableCanvas.repaint() on a per applet
  367. * instance of this class. The AWT deals with this by queuing a
  368. * java.awt.PaintEvent for the event dispatching thread which
  369. * is dispatched (Component.dispatchEvent()) the usual way.
  370. * Component.dispatchEvent() handles PaintEvents by calling our update()
  371. * method (on the event dispatching thread) which processes
  372. * the RunnableEvents stashed in the runnableEvents vector.
  373. */
  374. private static class RunnableCanvas extends Canvas
  375. {
  376. private static final Graphics nullGraphics = new RunnableCanvasGraphics();
  377. private static Hashtable runnableCanvasTable = new Hashtable(1);
  378. private Vector runnableEvents = new Vector(2);
  379. private boolean isRegistered = false;
  380. RunnableCanvas(JRootPane rootPane) {
  381. super();
  382. setBounds(0, 0, 1, 1);
  383. /* Remember the mapping from the current thread (and the current
  384. * thread group) to this RunnableCanvas. Note that if a mapping
  385. * has already been defined, e.g. this rootPane belongs to an
  386. * existing applet, then leave the table alone. We're assuming that
  387. * an applets addNotify method will always run before the addNotify
  388. * method in any subsidiary windows the applet creates can run.
  389. */
  390. if (runnableCanvasTable.get(Thread.currentThread()) == null) {
  391. try {
  392. runnableCanvasTable.put(Thread.currentThread(), this);
  393. runnableCanvasTable.put(getThreadGroupSafely(), this);
  394. if (SwingUtilities.isEventDispatchThread()) {
  395. isRegistered = true;
  396. }
  397. }
  398. catch(Exception e) {
  399. System.err.println("Can't register RunnableCanvas");
  400. e.printStackTrace();
  401. }
  402. }
  403. runnableCanvasTable.put(rootPane, this);
  404. maybeRegisterEventDispatchThread();
  405. }
  406. /**
  407. * If called on an event dispatching thread that we haven't seen
  408. * before then make two hashtable entries in the runnableCanvasTable:
  409. * <pre>
  410. * current thread => this RunnableCanvas
  411. * current thread group => this RunnableCanvas
  412. * </pre>
  413. * @see #lookup
  414. */
  415. private void maybeRegisterEventDispatchThread() {
  416. /* Avoid the cost of a synchronized block (or method) in the
  417. * common case, since this method is called each time paint is called.
  418. */
  419. if (!isRegistered) {
  420. synchronized(this) {
  421. if (!isRegistered && SwingUtilities.isEventDispatchThread()) {
  422. Thread currentThread = Thread.currentThread();
  423. /* If this event dispatching thread is already mapped to
  424. * a runnableCanvas then don't replace the mapping (which
  425. * we expect to be generated by the applet).
  426. */
  427. if (runnableCanvasTable.get(currentThread) != null) {
  428. isRegistered = true;
  429. }
  430. else {
  431. runnableCanvasTable.put(currentThread, this);
  432. runnableCanvasTable.put(getThreadGroupSafely(), this);
  433. isRegistered = true;
  434. }
  435. }
  436. }
  437. }
  438. }
  439. /**
  440. * If we're running on the event dispatching thread then lookup
  441. * the canvas with the current thread itself, otherwise use the
  442. * current threads thread group. If there is no match for the
  443. * ThreadGroup, the first visible RunnableCanvas is returned.
  444. */
  445. static RunnableCanvas lookup(RunnableEvent e)
  446. {
  447. /* If this is a ComponentWorkRequest, find the components
  448. * JRootPane ancestor and use that as the index into the
  449. * runnableCanvasTable. This case occurs when any thread,
  450. * other than the event dispatching thead, calls repaint
  451. */
  452. if (e.doRun instanceof ComponentWorkRequest) {
  453. ComponentWorkRequest req = (ComponentWorkRequest)e.doRun;
  454. synchronized(req) {
  455. JRootPane rootPane = SwingUtilities.getRootPane(req.component);
  456. if(rootPane != null) {
  457. return (RunnableCanvas)(runnableCanvasTable.get(rootPane));
  458. }
  459. /* Failure. There doesn't appear to be a RunnableCanvas to use
  460. * so indicate that a new request will need to be queued, see
  461. * RepaintManager.queueWorkRequest().
  462. */
  463. req.isPending = false;
  464. return null;
  465. }
  466. }
  467. /* If the current thread is in the runnableCanvasTable
  468. * (e.g. we're on the event dispatching thread) we're done.
  469. */
  470. Object rv = runnableCanvasTable.get(Thread.currentThread());
  471. if (rv != null) {
  472. return (RunnableCanvas)rv;
  473. }
  474. /* At this point we're assuming that the calling thread isn't
  475. * a system thread (like an image observer thread), so it's safe
  476. * to lookup via the current threads ThreadGroup.
  477. */
  478. Object threadGroup;
  479. try {
  480. threadGroup = Thread.currentThread().getThreadGroup();
  481. }
  482. catch (SecurityException exc) {
  483. return null;
  484. }
  485. RunnableCanvas rc = (RunnableCanvas)runnableCanvasTable.get(threadGroup);
  486. /* There's no RunnableCanvas associated with this thread group
  487. * (so punt). Return the first visible RunnableCanvas.
  488. */
  489. if(rc == null) {
  490. Enumeration keys = runnableCanvasTable.keys();
  491. if(keys == null) {
  492. return null;
  493. }
  494. while(keys.hasMoreElements()) {
  495. Object key = keys.nextElement();
  496. if ((key instanceof JRootPane) && ((JRootPane)key).isShowing()) {
  497. return (RunnableCanvas)runnableCanvasTable.get(key);
  498. }
  499. }
  500. }
  501. return rc;
  502. }
  503. /**
  504. * Adds the event to all the RunnableCanvases.
  505. *
  506. * @see #restartTimerQueueThread
  507. */
  508. static void postRunnableEventToAll(RunnableEvent e) {
  509. // Determine the RunnableCanvas for the current thread. It
  510. // may be null.
  511. RunnableCanvas currentThreadCanvas;
  512. ThreadGroup tg;
  513. try {
  514. tg = new Thread().getThreadGroup();
  515. }
  516. catch (SecurityException se) {
  517. tg = null;
  518. }
  519. if(tg != null) {
  520. currentThreadCanvas = (RunnableCanvas)runnableCanvasTable.
  521. get(tg);
  522. }
  523. else
  524. currentThreadCanvas = null;
  525. // Add the event to all canvases, except the current one.
  526. // Presumably the current one is no longer valid and will be
  527. // going away shortly.
  528. Enumeration keys = runnableCanvasTable.keys();
  529. while(keys.hasMoreElements()) {
  530. Object key = keys.nextElement();
  531. if(key instanceof JRootPane) {
  532. Object canvas = runnableCanvasTable.get(key);
  533. if(canvas != currentThreadCanvas) {
  534. RunnableCanvas rc = (RunnableCanvas)canvas;
  535. rc.addRunnableEvent(e);
  536. rc.repaint();
  537. }
  538. }
  539. }
  540. }
  541. /**
  542. * Remove the RunnableCanvas associated with this applet from the
  543. * applets Layered pane and clear all of the runnableCanvasTable
  544. * entries that point at it.
  545. */
  546. static void remove(JRootPane rootPane) {
  547. RunnableCanvas rc = (RunnableCanvas)(runnableCanvasTable.get(rootPane));
  548. if (rc != null) {
  549. RunnableCanvas nextCanvas = null;
  550. JLayeredPane layeredPane = rootPane.getLayeredPane();
  551. layeredPane.remove((Component)rc);
  552. Enumeration keys = runnableCanvasTable.keys();
  553. while(keys.hasMoreElements()) {
  554. Object key = keys.nextElement();
  555. Object next = runnableCanvasTable.get(key);
  556. if (rc == next) {
  557. runnableCanvasTable.remove(key);
  558. }
  559. else if(nextCanvas == null) {
  560. nextCanvas = (RunnableCanvas)next;
  561. }
  562. }
  563. // If there are still events, either move them to another
  564. // canvas, or mark the Timer type events as not having
  565. // fired.
  566. RunnableEvent[] events = rc.getRunnableCanvasEvents();
  567. int numEvents = (events == null) ? 0 : events.length;
  568. if(numEvents > 0) {
  569. if(nextCanvas != null) {
  570. for(int counter = 0; counter < numEvents; counter++) {
  571. RunnableEvent e = events[counter];
  572. if(e.doRun instanceof Timer.DoPostEvent)
  573. nextCanvas.addRunnableEvent(e);
  574. }
  575. nextCanvas.repaint();
  576. }
  577. else {
  578. // Mark all Timer type event as not having fired.
  579. for(int counter = 0; counter < numEvents; counter++) {
  580. RunnableEvent event = events[counter];
  581. if(event.doRun instanceof Timer.DoPostEvent) {
  582. ((Timer.DoPostEvent)event.doRun).getTimer().
  583. eventQueued = false;
  584. }
  585. }
  586. }
  587. }
  588. }
  589. }
  590. /**
  591. * If there are events to be processed then we're showing. Note
  592. * that the AWT code that dispatches paint events short circuits
  593. * (does nothing) if isShowing() returns false.
  594. */
  595. public boolean isShowing() {
  596. return runnableEvents.size() > 0;
  597. }
  598. /**
  599. * Reduce the cost of repainting (since we're not going to draw
  600. * anything) by returning a constant no-op graphics object.
  601. */
  602. public Graphics getGraphics() {
  603. return nullGraphics;
  604. }
  605. /**
  606. * Testing purposes only. This method shouldn't be called;
  607. * the parent of this component should have a null layout
  608. * manager.
  609. */
  610. public Dimension getPreferredSize() {
  611. return new Dimension(1, 1);
  612. }
  613. /**
  614. * Add a RunnableEvent to the queue that will be dispatched
  615. * when this component is repainted.
  616. * @see #update
  617. */
  618. synchronized void addRunnableEvent(RunnableEvent e) {
  619. runnableEvents.addElement(e);
  620. }
  621. /**
  622. * Return an (array) copy of the runnableEvents vector or
  623. * null if the vector is empty. The update method processes
  624. * a copy of the vector so that we don't have to hold
  625. * the synchronized lock while calling processRunnableEvent().
  626. * @see #update
  627. */
  628. private synchronized RunnableEvent[] getRunnableCanvasEvents() {
  629. int n = runnableEvents.size();
  630. if (n == 0) {
  631. return null;
  632. }
  633. else {
  634. RunnableEvent[] rv = new RunnableEvent[n];
  635. for(int i = 0; i < n; i++) {
  636. rv[i] = (RunnableEvent)(runnableEvents.elementAt(i));
  637. }
  638. runnableEvents.removeAllElements();
  639. return rv;
  640. }
  641. }
  642. public void paint(Graphics g) {
  643. maybeRegisterEventDispatchThread();
  644. }
  645. /**
  646. * Process all of the RunnableEvents that have accumulated
  647. * since RunnableCanvas.repaint() was called.
  648. */
  649. public void update(Graphics g) {
  650. RunnableEvent[] events = getRunnableCanvasEvents();
  651. if (events != null) {
  652. for(int i = 0; i < events.length; i++) {
  653. processRunnableEvent(events[i]);
  654. }
  655. }
  656. }
  657. }
  658. /**
  659. * A no-op Graphics object for the RunnableCanvas component.
  660. * Most AWT Component implementations handle update events
  661. * like this:
  662. * <pre>
  663. * Graphics g = getGraphics();
  664. * Rectangle r = ((PaintEvent)e).getUpdateRect();
  665. * g.clipRect(r.x, r.y, r.width, r.height);
  666. * update(g)
  667. * g.dispose();
  668. * </pre>
  669. * Since the RunnableCanvas component isn't really going to do
  670. * any painting we don't bother with creating/disposing real
  671. * graphics objects, or setting any of the properties.
  672. *
  673. */
  674. private static class RunnableCanvasGraphics extends Graphics
  675. {
  676. public Graphics create() {
  677. return this;
  678. }
  679. /* We don't expect any of the following methods to be called but
  680. * we still return marginally valid values for the get methods
  681. * just in case.
  682. */
  683. public Rectangle getClipBounds() {
  684. return new Rectangle(0, 0, Short.MAX_VALUE, Short.MAX_VALUE);
  685. }
  686. public Shape getClip() {
  687. return (Shape)(getClipBounds());
  688. }
  689. public void dispose() {}
  690. public void translate(int x, int y) {}
  691. public Color getColor() { return Color.black; }
  692. public void setColor(Color c) {}
  693. public void setPaintMode() {}
  694. public void setXORMode(Color c) {}
  695. public Font getFont() { return null; }
  696. public void setFont(Font font) {}
  697. public FontMetrics getFontMetrics(Font f) { return null; }
  698. public void clipRect(int x, int y, int width, int height) {}
  699. public void setClip(int x, int y, int width, int height) {}
  700. public void setClip(Shape clip) {}
  701. public void copyArea(int x, int y, int w, int h, int dx, int dy) {}
  702. public void drawLine(int x1, int y1, int x2, int y2) {}
  703. public void fillRect(int x, int y, int width, int height) {}
  704. public void clearRect(int x, int y, int width, int height) {}
  705. public void drawRoundRect(int x, int y, int w, int h, int aw, int ah) {}
  706. public void fillRoundRect(int x, int y, int w, int h, int aw, int ah) {}
  707. public void drawOval(int x, int y, int w, int h) {}
  708. public void fillOval(int x, int y, int w, int h) {}
  709. public void drawArc(int x, int y, int w, int h, int sa, int aa) {}
  710. public void fillArc(int x, int y, int w, int h, int sa, int aa) {}
  711. public void drawPolyline(int xPoints[], int yPoints[], int nPoints) {}
  712. public void drawPolygon(int xPoints[], int yPoints[], int nPoints) {}
  713. public void fillPolygon(int xPoints[], int yPoints[], int nPoints) {}
  714. public void drawString(String str, int x, int y) {}
  715. public void drawString(java.text.AttributedCharacterIterator iterator, int x, int y) {}
  716. public boolean drawImage(Image i, int x, int y, ImageObserver o) { return false; }
  717. public boolean drawImage(Image i, int x, int y, int w, int h, ImageObserver o) { return false; }
  718. public boolean drawImage(Image i, int x, int y, Color bgcolor, ImageObserver o) { return false; }
  719. public boolean drawImage(Image i, int x, int y, int w, int h, Color c, ImageObserver o) { return false; }
  720. public boolean drawImage(Image i,
  721. int dx1, int dy1, int dx2, int dy2,
  722. int sx1, int sy1, int sx2, int sy2, ImageObserver o)
  723. { return false; }
  724. public boolean drawImage(Image i,
  725. int dx1, int dy1, int dx2, int dy2,
  726. int sx1, int sy1, int sx2, int sy2, Color c, ImageObserver o)
  727. { return false; }
  728. }
  729. }