25 import org.eclipse.swt.events.*; |
25 import org.eclipse.swt.events.*; |
26 import org.eclipse.swt.widgets.*; |
26 import org.eclipse.swt.widgets.*; |
27 import org.eclipse.swt.widgets.Display; |
27 import org.eclipse.swt.widgets.Display; |
28 import org.eclipse.swt.graphics.*; |
28 import org.eclipse.swt.graphics.*; |
29 import org.eclipse.swt.internal.extension.CompositeExtension; |
29 import org.eclipse.swt.internal.extension.CompositeExtension; |
|
30 import org.eclipse.swt.internal.qt.graphics.WindowSurface; |
|
31 |
30 |
32 |
31 /** |
33 /** |
32 * The abstract <code>Canvas</code> class is designed to handle low-level |
34 * The abstract <code>Canvas</code> class is designed to handle low-level |
33 * graphical operations as well as low-level key and pointer events. Canvas is |
35 * graphical operations as well as low-level key and pointer events. Canvas is |
34 * derived from <code>Displayable</code> so the application can switch between |
36 * derived from <code>Displayable</code> so the application can switch between |
151 new CanvasShellPaintListener(); |
153 new CanvasShellPaintListener(); |
152 |
154 |
153 private CanvasShellMouseListener mouseListener = |
155 private CanvasShellMouseListener mouseListener = |
154 new CanvasShellMouseListener(); |
156 new CanvasShellMouseListener(); |
155 |
157 |
156 // Canvas Graphics object passed to paint(Graphics g). |
158 // Canvas Graphics object passed to paint(Graphics g) |
157 // Graphics has its own back-buffer for double buffering. |
|
158 private Graphics canvasGraphics; |
159 private Graphics canvasGraphics; |
159 |
160 |
|
161 // Graphics command buffer for this instance |
|
162 CanvasBuffer graphicsBuffer; |
|
163 |
160 //On Screen Keypad |
164 //On Screen Keypad |
161 //private Composite keypadComposite; |
165 //private Composite keypadComposite; |
162 private CanvasKeypad onScreenkeypad; |
166 private CanvasKeypad onScreenkeypad; |
163 private int oskHeight; |
167 private int oskHeight; |
164 |
168 |
165 // Vector of flags that a certain key was pressed but was not released. |
169 // Vector of flags that a certain key was pressed but was not released. |
166 // Used to implement keyRepeated since eSWT does not support |
170 // Used to implement keyRepeated since eSWT does not support |
167 // key repeat events. |
171 // key repeat events. |
168 private Vector keysPressed; |
172 private Vector keysPressed; |
169 |
|
170 // Canvas modes |
|
171 private static final int MODE_UNINITIALIZED = 0; |
|
172 private static final int MODE_NORMAL = 1; |
|
173 private static final int MODE_BUFFER_FLUSH = 2; |
|
174 private static final int MODE_GAME_BUFFER_FLUSH = 3; |
|
175 private int canvasMode = MODE_UNINITIALIZED; |
|
176 |
173 |
177 private boolean suppressGameKeys; |
174 private boolean suppressGameKeys; |
178 private boolean suppressDragEvent; |
175 private boolean suppressDragEvent; |
179 private boolean cleanupNeeded; |
176 private boolean cleanupNeeded; |
180 private Object cleanupLock; |
177 private Object cleanupLock; |
181 private boolean noBackground; |
178 private boolean noBackground; |
182 private int gameKeyState; |
179 private int gameKeyState; |
183 |
180 |
184 private Graphics gameBufferGraphics; |
|
185 |
|
186 // lock created by graphics object for serializing |
|
187 // flushing against graphics buffer writing |
|
188 private Object flushLock; |
|
189 |
|
190 private Timer timer = new Timer(); |
181 private Timer timer = new Timer(); |
191 private CanvasTimerTask timerTask; |
182 private CanvasTimerTask timerTask; |
192 |
183 |
193 private static final int DEFAULT_TIMEOUT = 500; |
184 private static final int DEFAULT_TIMEOUT = 500; |
194 private static final int DEFAULT_TWIPS = 200; |
185 private static final int DEFAULT_TWIPS = 200; |
626 { |
616 { |
627 this.suppressGameKeys = suppressKeys; |
617 this.suppressGameKeys = suppressKeys; |
628 } |
618 } |
629 |
619 |
630 /** |
620 /** |
631 * Update game buffer graphics. |
|
632 */ |
|
633 final void eswtUpdateGameBufferGraphics() |
|
634 { |
|
635 if(gameBufferGraphics == null) |
|
636 { |
|
637 gameBufferGraphics = new Graphics(); |
|
638 gameBufferGraphics.initBuffered(this, 0, 0, getWidth(), getHeight()); |
|
639 flushLock = gameBufferGraphics.getLock(); |
|
640 } |
|
641 } |
|
642 |
|
643 /** |
|
644 * Get game canvas frame buffer graphics. |
621 * Get game canvas frame buffer graphics. |
645 */ |
622 */ |
646 final Graphics getGameBufferGraphics() |
623 final Graphics getGameBufferGraphics() |
647 { |
624 { |
648 ESWTUIThreadRunner.safeSyncExec(new Runnable() |
625 return graphicsBuffer.getGraphics(); |
649 { |
|
650 public void run() |
|
651 { |
|
652 eswtUpdateGameBufferGraphics(); |
|
653 } |
|
654 }); |
|
655 return gameBufferGraphics; |
|
656 } |
626 } |
657 |
627 |
658 CanvasKeypad getCanvasKeypad() |
628 CanvasKeypad getCanvasKeypad() |
659 { |
629 { |
660 return onScreenkeypad; |
630 return onScreenkeypad; |
694 * @param height |
664 * @param height |
695 */ |
665 */ |
696 void flushGameBuffer(final int x, final int y, final int width, |
666 void flushGameBuffer(final int x, final int y, final int width, |
697 final int height) |
667 final int height) |
698 { |
668 { |
699 synchronized(flushLock) |
669 synchronized(graphicsBuffer) |
700 { |
670 { |
701 ESWTUIThreadRunner.safeSyncExec(new Runnable() |
671 flushGraphicsBuffer(x, y, width, height); |
702 { |
|
703 public void run() |
|
704 { |
|
705 canvasMode = MODE_GAME_BUFFER_FLUSH; |
|
706 ((CompositeExtension)getContentComp()).redrawNow(x, y, width, height); |
|
707 gameBufferGraphics.resetCommandBuffer(); |
|
708 canvasMode = MODE_NORMAL; |
|
709 } |
|
710 }); |
|
711 } |
672 } |
712 } |
673 } |
713 |
674 |
714 /** |
675 /** |
715 * Called by ShellListener when shell gets activated. |
676 * Called by ShellListener when shell gets activated. |
744 * UI thread calls |
705 * UI thread calls |
745 */ |
706 */ |
746 void eswtHandleResizeEvent(int width, int height) |
707 void eswtHandleResizeEvent(int width, int height) |
747 { |
708 { |
748 super.eswtHandleResizeEvent(width, height); |
709 super.eswtHandleResizeEvent(width, height); |
749 canvasMode = MODE_NORMAL; |
710 // update new bounds to graphicsBuffer |
|
711 synchronized(graphicsBuffer) |
|
712 { |
|
713 graphicsBuffer.setControlBounds(getContentComp()); |
|
714 } |
750 synchronized(cleanupLock) |
715 synchronized(cleanupLock) |
751 { |
716 { |
752 cleanupNeeded = true; |
717 cleanupNeeded = true; |
753 } |
718 } |
754 } |
719 } |
757 * UI thread calls |
722 * UI thread calls |
758 */ |
723 */ |
759 void eswtHandleEvent(Event e) |
724 void eswtHandleEvent(Event e) |
760 { |
725 { |
761 super.eswtHandleEvent(e); |
726 super.eswtHandleEvent(e); |
762 |
|
763 if(e.type == SWT.KeyDown) |
727 if(e.type == SWT.KeyDown) |
764 { |
728 { |
765 doKeyPressed(e.keyCode); |
729 doKeyPressed(e.keyCode); |
766 } |
730 } |
767 else if(e.type == SWT.KeyUp) |
731 else if(e.type == SWT.KeyUp) |
768 { |
732 { |
769 doKeyReleased(e.keyCode); |
733 doKeyReleased(e.keyCode); |
770 } |
734 } |
771 |
|
772 } |
735 } |
773 |
736 |
774 /* |
737 /* |
775 * UI thread calls. Paint listener of the eSWT widget. |
738 * UI thread calls. Paint listener of the eSWT widget. |
776 */ |
739 */ |
777 class CanvasShellPaintListener implements PaintListener |
740 class CanvasShellPaintListener implements PaintListener |
778 { |
741 { |
779 |
742 |
780 public void paintControl(PaintEvent pe) |
743 public void paintControl(PaintEvent pe) |
781 { |
744 { |
782 switch(canvasMode) |
745 // Native toolkit is requesting an update of an area that has |
783 { |
746 // become invalid. Can't do anything here because the contents |
784 case MODE_BUFFER_FLUSH: |
747 // need to be queried from the MIDlet in another thread by |
785 // Paint event initiated by us to paint the Canvas. |
748 // a paint callback. For this a paint callback event is posted. |
786 doBufferFlush(pe, canvasGraphics); |
749 // For a moment the native toolkit thinks that the area has |
787 break; |
750 // been validated when in truth it will be painted later after |
788 case MODE_GAME_BUFFER_FLUSH: |
751 // the paint callback has been executed. |
789 // Paint event initiated by us to paint the GameCanvas. |
752 EventDispatcher eventDispatcher = EventDispatcher.instance(); |
790 doBufferFlush(pe, gameBufferGraphics); |
753 LCDUIEvent event = eventDispatcher.newEvent( |
791 break; |
754 LCDUIEvent.CANVAS_PAINT_NATIVE_REQUEST, |
792 case MODE_NORMAL: |
755 javax.microedition.lcdui.Canvas.this); |
793 // Native toolkit is requesting an update of an area that has |
756 event.x = pe.x; |
794 // become invalid. Can't do anything here because the contents |
757 event.y = pe.y; |
795 // need to be queried from the MIDlet in another thread by |
758 event.width = pe.width; |
796 // a paint callback. For this a paint callback event is posted. |
759 event.height = pe.height; |
797 // For a moment the native toolkit thinks that the area has |
760 event.widget = pe.widget; |
798 // been validated when in truth it will be painted later after |
761 eventDispatcher.postEvent(event); |
799 // the paint callback has been executed. |
|
800 EventDispatcher eventDispatcher = EventDispatcher.instance(); |
|
801 LCDUIEvent event = eventDispatcher.newEvent( |
|
802 LCDUIEvent.CANVAS_PAINT_NATIVE_REQUEST, |
|
803 javax.microedition.lcdui.Canvas.this); |
|
804 event.x = pe.x; |
|
805 event.y = pe.y; |
|
806 event.width = pe.width; |
|
807 event.height = pe.height; |
|
808 event.widget = pe.widget; |
|
809 eventDispatcher.postEvent(event); |
|
810 break; |
|
811 } |
|
812 } |
762 } |
813 } |
763 } |
814 |
764 |
815 /* |
765 /* |
816 * Dispatcher thread or the serviceRepaints()-thread calls. |
766 * Dispatcher thread or the serviceRepaints()-thread calls. |
896 { |
846 { |
897 return; |
847 return; |
898 } |
848 } |
899 } |
849 } |
900 |
850 |
901 // Prepare the GC's buffer if not done yet |
851 // Create instance of Graphics if not created yet |
902 if(canvasGraphics.getCommandBuffer() == null) |
852 if(canvasGraphics == null) |
903 { |
853 { |
904 canvasGraphics.initBuffered(this, event.x, event.y, event.width, event.height); |
854 canvasGraphics = graphicsBuffer.getGraphics(); |
905 } |
855 } |
906 |
856 |
907 // Clean the background if dirty, buffer the operations. |
857 // Clean the background if dirty, buffer the operations. |
908 synchronized(cleanupLock) |
858 synchronized(cleanupLock) |
909 { |
859 { |
925 canvasGraphics.setClip(redrawNowX, redrawNowY, redrawNowW, redrawNowH); |
875 canvasGraphics.setClip(redrawNowX, redrawNowY, redrawNowW, redrawNowH); |
926 |
876 |
927 // The callback |
877 // The callback |
928 paint(canvasGraphics); |
878 paint(canvasGraphics); |
929 |
879 |
930 // Wait until the UI thread is available. Then in the UI thread |
880 |
931 // synchronously send a paint event. |
881 // Flush drawn graphics to display |
|
882 synchronized(graphicsBuffer) |
|
883 { |
|
884 flushGraphicsBuffer(redrawNowX, redrawNowY, redrawNowW, redrawNowH); |
|
885 } |
|
886 } |
|
887 |
|
888 private void flushGraphicsBuffer(final int redrawNowX, final int redrawNowY, final int redrawNowW, final int redrawNowH) |
|
889 { |
932 ESWTUIThreadRunner.safeSyncExec(new Runnable() |
890 ESWTUIThreadRunner.safeSyncExec(new Runnable() |
933 { |
891 { |
934 public void run() |
892 public void run() |
935 { |
893 { |
936 if(event.widget.isDisposed()) |
894 graphicsBuffer.setupWindowSurface(); |
937 { |
895 Rectangle rect = graphicsBuffer.toWindowCoordinates(redrawNowX, redrawNowY, redrawNowW, redrawNowH); |
938 return; |
896 graphicsBuffer.windowSurface.beginPaint(rect.x, rect.y, rect.width, rect.height); |
939 } |
897 graphicsBuffer.sync(); |
940 |
898 graphicsBuffer.windowSurface.endPaint(); |
941 canvasMode = MODE_BUFFER_FLUSH; |
899 graphicsBuffer.windowSurface.flush(); |
942 |
|
943 ((CompositeExtension) event.widget) |
|
944 .redrawNow(redrawNowX, redrawNowY, redrawNowW, redrawNowH); |
|
945 canvasGraphics.resetCommandBuffer(); |
|
946 canvasMode = MODE_NORMAL; |
|
947 } |
900 } |
948 |
901 |
949 }); |
902 }); |
950 } |
903 } |
951 |
904 |
952 /* |
905 /* |
953 * UI thread calls to flush the command buffer of a graphics context. |
906 * UI thread calls to flush the command buffer of a graphics context. |
954 */ |
907 */ |
955 private final void doBufferFlush(PaintEvent event, Graphics graphics) |
908 private final void doBufferFlush(PaintEvent event, Graphics graphics) |
956 { |
909 { |
957 event.gc.getGCData().internalGc.render(graphics.getCommandBuffer()); |
910 // event.gc.getGCData().internalGc.render(graphics.getCommandBuffer()); |
958 } |
911 } |
959 |
912 |
960 /* |
913 /* |
961 * UI thread calls. |
914 * UI thread calls. |
962 */ |
915 */ |