diff --git a/src/org/atriasoft/gale/GaleApplication.java b/src/org/atriasoft/gale/GaleApplication.java index a33e767..d2b0867 100644 --- a/src/org/atriasoft/gale/GaleApplication.java +++ b/src/org/atriasoft/gale/GaleApplication.java @@ -258,6 +258,10 @@ public class GaleApplication { Gale.getContext().setCursor(this.cursor); } + void setForceRedraw() { + this.needRedraw = true; + } + /** * set the Icon of the application. * @param iconFile File name icon (.bmp/.png). @@ -293,16 +297,19 @@ public class GaleApplication { if (size.x() <= 0 || size.y() <= 0) { Log.error("Wrong windows size: " + size); } - Vector2f oldSize = this.windowsSize; + final Vector2f oldSize = this.windowsSize; this.windowsSize = size; final GaleContext context = Gale.getContext(); if (context == null) { return; } - if (!context.setSize(size)) { + context.setSize(size); + /* ==> change API ==> need the GUI notify the Windows that the size has change ???? + if (!) { Log.error("Can not set the size required by the user."); this.windowsSize = oldSize; } + */ } /** diff --git a/src/org/atriasoft/gale/context/GaleContext.java b/src/org/atriasoft/gale/context/GaleContext.java index aaba8a2..d3a503f 100644 --- a/src/org/atriasoft/gale/context/GaleContext.java +++ b/src/org/atriasoft/gale/context/GaleContext.java @@ -1,7 +1,6 @@ package org.atriasoft.gale.context; import java.time.Clock; -import java.util.Vector; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -9,6 +8,7 @@ import org.atriasoft.etk.Color; import org.atriasoft.etk.ThreadAbstract; import org.atriasoft.etk.Uri; import org.atriasoft.etk.math.Vector2f; +import org.atriasoft.etk.util.AutoUnLock; import org.atriasoft.gale.Fps; import org.atriasoft.gale.Gale; import org.atriasoft.gale.GaleApplication; @@ -48,8 +48,6 @@ public abstract class GaleContext { GaleContext.globalContext = context; } - Lock lock = new ReentrantLock(); - protected ThreadAbstract periodicThread; protected GaleApplication application; //!< Application handle protected ApplicationState applicationState = ApplicationState.UNDEFINED; // state of the application @@ -58,7 +56,10 @@ public abstract class GaleContext { // simulation area: private long previousDisplayTime; // this is to limit framerate ... in case... private final boolean displayFps = true; - private final MessageSystem msgSystem = new MessageSystem(); + + private final Lock msgSystemAsyncLock = new ReentrantLock(); + private final MessageSystem msgSystemAsync = new MessageSystem(); + private final MessageSystem msgSystemGui = new MessageSystem(); private final Fps fpsSystemEvent = new Fps("SystemEvent", this.displayFps); private final Fps fpsSystemContext = new Fps("SystemContext", this.displayFps); private final Fps fpsSystem = new Fps("System", this.displayFps); @@ -112,9 +113,9 @@ public abstract class GaleContext { // } //cout.setOutputFile(true); - Log.info("GALE v:" + Gale.getVersion()); + Log.info("GALE v: {}", Gale.getVersion()); forceOrientation(Orientation.screenAuto); - postAction(context -> { + postActionAsync(context -> { final GaleApplication appl = context.getApplication(); if (appl == null) { this.applicationState = ApplicationState.UNDEFINED; @@ -152,7 +153,15 @@ public abstract class GaleContext { * force the screen orientation (availlable on portable elements ... * @param orientation Selected orientation. */ - public void forceOrientation(final Orientation orientation) {} + public final void forceOrientation(final Orientation orientation) { + postActionToGui(context -> { + context.forceOrientationThreadGUI(orientation); + }); + } + + protected void forceOrientationThreadGUI(final Orientation orientation) { + Log.todo("forceOrientation: not implemented"); + } /** * Redraw all the windows @@ -169,16 +178,20 @@ public abstract class GaleContext { // Called by Consumer public ActionToDoInAsyncLoop getAction() { - return this.msgSystem.getElementWait(); + return this.msgSystemAsync.getElementWait(); } public GaleApplication getApplication() { - this.lock.lock(); + return this.application; + /* + * pb on this lock ... + this.msgSystemAsyncLock.lock(); try { return this.application; } finally { - this.lock.unlock(); + this.msgSystemAsyncLock.unlock(); } + */ } public CommandLine getCmd() { @@ -213,19 +226,42 @@ public abstract class GaleContext { * get all Keyboard event from the X system (like many time use of META) * @param status "true" if all the event will be get, false if we want only ours. */ - public void grabKeyboardEvents(final boolean status) {} + public final void grabKeyboardEvents(final boolean status) { + postActionToGui(context -> { + context.grabKeyboardEventsThreadGUI(status); + }); + } + + protected void grabKeyboardEventsThreadGUI(final boolean status) { + Log.info("grabKeyboardEvents: NOT implemented ..."); + } /** * get all Mouse/Touch events from the X system * @param status "true" if all the event will be get, false if we want only ours. * @param forcedPosition the position where the mouse might be reset at every events ... */ - public void grabPointerEvents(final boolean status, final Vector2f forcedPosition) {} + public final void grabPointerEvents(final boolean status, final Vector2f forcedPosition) { + postActionToGui(context -> { + context.grabPointerEventsThreadGUI(status, forcedPosition); + }); + } + + protected void grabPointerEventsThreadGUI(final boolean status, final Vector2f forcedPosition) { + Log.info("grabPointerEvents: NOT implemented ..."); + + } /** * The Application request that the Windows will be Hidden. */ - public void hide() { + public final void hide() { + postActionToGui(context -> { + context.hideThreadGUI(); + }); + } + + protected void hideThreadGUI() { Log.info("hide: NOT implemented ..."); } @@ -234,41 +270,57 @@ public abstract class GaleContext { } /** - * Hide the virtal keyboard (for touch system only) + * Hide the virtual keyboard (for touch system only) */ - public void keyboardHide() { + public final void keyboardHide() { + postActionToGui(context -> { + context.keyboardHideThreadGUI(); + }); + } + + protected void keyboardHideThreadGUI() { Log.info("keyboardHide: NOT implemented ..."); } /** - * display the virtal keyboard (for touch system only) + * display the virtual keyboard (for touch system only) */ - public void keyboardShow() { - Log.info("keyboardShow: NOT implemented ..."); + public final void keyboardShow() { + postActionToGui(context -> { + context.keyboardShowThreadGUI(); + }); } - protected void lockContext() { - + protected void keyboardShowThreadGUI() { + Log.info("keyboardShow: NOT implemented ..."); } /** * Open an URL on an eternal brother. * @param url URL to open. */ - public void openURL(final String url) {} + public final void openURL(final String url) { + postActionToGui(context -> { + context.openURLThreadGUI(url); + }); + } + + protected void openURLThreadGUI(final String url) { + Log.info("openURL: NOT implemented ..."); + } /** * The current context is set in background (framerate is slowing down (max fps)/5 # 4fps) */ public void operatingSystemBackground() { // set the current interface : - lockContext(); - Log.info("operatingSystemBackground..."); - // if (this.windowsCurrent != null) { - // this.windowsCurrent.onStateBackground(); - // } - // release the current interface : - unLockContext(); + try (AutoUnLock autoUnlock = AutoUnLock.lock(this.msgSystemAsyncLock)) { + Log.info("operatingSystemBackground..."); + // if (this.windowsCurrent != null) { + // this.windowsCurrent.onStateBackground(); + // } + // release the current interface : + } } /** @@ -276,7 +328,7 @@ public abstract class GaleContext { * @param clipboardID of the clipboard */ public void operatingSystemClipBoardArrive(final ClipboardList clipboardID) { - postAction(context -> { + postActionAsync(context -> { final GaleApplication appl = context.getApplication(); if (appl != null) { appl.onClipboardEvent(clipboardID); @@ -313,33 +365,32 @@ public abstract class GaleContext { //! Event management section ... { // set the current interface: - lockContext(); - /* - Lock the event processing - - Wait end of current processing - - Display ... - - Release the event processing - - */ - if (this.application != null) { - if (this.applicationState == ApplicationState.RUNNING) { - // Redraw all needed elements - //Log.debug("Regenerate Display"); - this.application.onRegenerateDisplay(this); - needRedraw = this.application.isDrawingNeeded(); - } else { - needRedraw = true; + try (AutoUnLock autoUnlock = AutoUnLock.lock(this.msgSystemAsyncLock)) { + /* + Lock the event processing + + Wait end of current processing + + Display ... + + Release the event processing + + */ + if (this.application != null) { + if (this.applicationState == ApplicationState.RUNNING) { + // Redraw all needed elements + //Log.debug("Regenerate Display"); + this.application.onRegenerateDisplay(this); + needRedraw = this.application.isDrawingNeeded(); + } else { + needRedraw = true; + } + } + if (this.displayFps) { + this.fpsSystemEvent.incrementCounter(); + this.fpsSystemEvent.toc(); } } - if (this.displayFps) { - this.fpsSystemEvent.incrementCounter(); - this.fpsSystemEvent.toc(); - } - // release the current interface : - unLockContext(); } boolean hasDisplayDone = false; //! drawing section: @@ -351,9 +402,9 @@ public abstract class GaleContext { } if (needRedraw || displayEveryTime) { //Log.debug(" ==> real Draw"); - lockContext(); - this.resourceManager.updateContext(); - unLockContext(); + try (AutoUnLock autoUnlock = AutoUnLock.lock(this.msgSystemAsyncLock)) { + this.resourceManager.updateContext(); + } if (this.displayFps) { this.fpsSystemContext.incrementCounter(); } @@ -366,16 +417,16 @@ public abstract class GaleContext { if (needRedraw || displayEveryTime) { this.fpsSystem.incrementCounter(); // set the current interface : - lockContext(); - if (this.applicationState == ApplicationState.RUNNING) { - this.application.onDraw(this); - } else { - OpenGL.setViewPort(new Vector2f(0, 0), this.application.getSize()); - final Color bgColor = new Color(0.8f, 0.5f, 0.8f, 1.0f); - OpenGL.clearColor(bgColor); - //Log.info("==> appl clear ==> not created ..."); + try (AutoUnLock autoUnlock = AutoUnLock.lock(this.msgSystemAsyncLock)) { + if (this.applicationState == ApplicationState.RUNNING) { + this.application.onDraw(this); + } else { + OpenGL.setViewPort(new Vector2f(0, 0), this.application.getSize()); + final Color bgColor = new Color(0.8f, 0.5f, 0.8f, 1.0f); + OpenGL.clearColor(bgColor); + //Log.info("==> appl clear ==> not created ..."); + } } - unLockContext(); hasDisplayDone = true; } } @@ -404,17 +455,16 @@ public abstract class GaleContext { } { // set the current interface: - lockContext(); - // release open GL Context - OpenGL.lock(); - // while The Gui is drawing in OpenGl, we do some not realTime things - this.resourceManager.updateContext(); - // release open GL Context - OpenGL.unLock(); - // TODO this.objectManager.cleanInternalRemoved(); - this.resourceManager.cleanInternalRemoved(); - // release the current interface: - unLockContext(); + try (AutoUnLock autoUnlock = AutoUnLock.lock(this.msgSystemAsyncLock)) { + // release open GL Context + OpenGL.lock(); + // while The Gui is drawing in OpenGl, we do some not realTime things + this.resourceManager.updateContext(); + // release open GL Context + OpenGL.unLock(); + // TODO this.objectManager.cleanInternalRemoved(); + this.resourceManager.cleanInternalRemoved(); + } } OpenGL.threadHasNoMoreContext(); return hasDisplayDone; @@ -425,21 +475,20 @@ public abstract class GaleContext { */ public void operatingSystemForeground() { // set the current interface : - lockContext(); - Log.info("operatingSystemForeground..."); - - // if (this.windowsCurrent != null) { - // this.windowsCurrent.onStateForeground(); - // } - // release the current interface : - unLockContext(); + try (AutoUnLock autoUnlock = AutoUnLock.lock(this.msgSystemAsyncLock)) { + Log.info("operatingSystemForeground..."); + + // if (this.windowsCurrent != null) { + // this.windowsCurrent.onStateForeground(); + // } + } } /** * The OS inform that the Windows is now Hidden. */ public void operatingSystemHide() { - postAction(context -> { + postActionAsync(context -> { /* Application> appl = context.getApplication(); if (appl == null) { @@ -462,8 +511,8 @@ public abstract class GaleContext { if (this.windowsPos.isEqual(pos)) { return; } - postAction(context -> { - Log.debug("Receive MSG : THREADMOVE : " + context.windowsPos + " ==> " + pos); + postActionAsync(context -> { + Log.debug("Receive MSG : THREADMOVE : {} ==> {}", context.windowsPos, pos); context.windowsPos = pos; final GaleApplication appl = context.getApplication(); if (appl == null) { @@ -485,14 +534,14 @@ public abstract class GaleContext { * @param size new size of the windows. */ public void operatingSystemResize(final Vector2f size) { - Log.warning("Resize request: " + size + " old=" + this.windowsSize); + Log.warning("Resize request={} previous={}", size, this.windowsSize); if (this.windowsSize.equals(size)) { return; } // TODO Better in the thread ... ==> but generate some init error ... //gale::Dimension::setPixelWindowsSize(size); - postAction(context -> { - Log.error("Receive MSG : THREAD_RESIZE : " + context.windowsSize + " ==> " + size); + postActionAsync(context -> { + Log.error("Receive MSG : THREAD_RESIZE : {} ==> {}", context.windowsSize, size); context.windowsSize = size; //gale::Dimension::setPixelWindowsSize(context.windowsSize); final GaleApplication tmpAppl = context.getApplication(); @@ -509,20 +558,19 @@ public abstract class GaleContext { */ public void operatingSystemResume() { // set the current interface : - lockContext(); - Log.info("operatingSystemResume..."); - this.previousDisplayTime = System.currentTimeMillis(); - // TODO this.objectManager.timeCallResume(this.previousDisplayTime); - // if (this.windowsCurrent != null) { - // this.windowsCurrent.onStateResume(); - // } - // release the current interface : - unLockContext(); + try (AutoUnLock autoUnlock = AutoUnLock.lock(this.msgSystemAsyncLock)) { + Log.info("operatingSystemResume..."); + this.previousDisplayTime = System.currentTimeMillis(); + // TODO this.objectManager.timeCallResume(this.previousDisplayTime); + // if (this.windowsCurrent != null) { + // this.windowsCurrent.onStateResume(); + // } + } } public void operatingSystemSetInput(final KeySpecial special, final KeyType type, final KeyStatus status, final int pointerID, final Vector2f pos) { Log.verbose("Position motion: " + pos); - postAction(context -> { + postActionAsync(context -> { final GaleApplication appl = context.getApplication(); if (appl == null) { return; @@ -548,7 +596,7 @@ public abstract class GaleContext { } public void operatingSystemsetKeyboard2(final KeySpecial special, final KeyKeyboard type, final KeyStatus state, final Character charValue) { - postAction(context -> { + postActionAsync(context -> { final GaleApplication appl = context.getApplication(); if (appl == null) { return; @@ -561,7 +609,7 @@ public abstract class GaleContext { * The OS inform that the Windows is now visible. */ public void operatingSystemShow() { - postAction(context -> { + postActionAsync(context -> { /* Application> appl = context.getApplication(); if (appl == null) { @@ -581,15 +629,14 @@ public abstract class GaleContext { */ public void operatingSystemStop() { // set the current interface : - lockContext(); - Log.info("operatingSystemStop..."); - if (this.application == null) { - stop(); - return; + try (AutoUnLock autoUnlock = AutoUnLock.lock(this.msgSystemAsyncLock)) { + Log.info("operatingSystemStop..."); + if (this.application == null) { + stop(); + return; + } + this.application.onKillDemand(this); } - this.application.onKillDemand(this); - // release the current interface : - unLockContext(); } /** @@ -597,44 +644,70 @@ public abstract class GaleContext { */ public void operatingSystemSuspend() { // set the current interface : - lockContext(); - Log.info("operatingSystemSuspend..."); - this.previousDisplayTime = 0; - - // if (this.windowsCurrent != null) { - // this.windowsCurrent.onStateSuspend(); - // } - // release the current interface : - unLockContext(); + try (AutoUnLock autoUnlock = AutoUnLock.lock(this.msgSystemAsyncLock)) { + Log.info("operatingSystemSuspend..."); + this.previousDisplayTime = 0; + + // if (this.windowsCurrent != null) { + // this.windowsCurrent.onStateSuspend(); + // } + } } - private void postAction(final ActionToDoInAsyncLoop data) { - this.msgSystem.addElement(data); + protected void postActionAsync(final ActionToDoInAsyncLoop data) { + this.msgSystemAsync.addElement(data); + //Later, when the necessary event happens, the thread that is running it calls notify() from a block synchronized on the same object. + } + + protected void postActionToGui(final ActionToDoInAsyncLoop data) { + this.msgSystemGui.addElement(data); //Later, when the necessary event happens, the thread that is running it calls notify() from a block synchronized on the same object. } /** * Processing all the event arrived ... (commonly called in draw function) */ - public void processEvents(final Clock clock, final long time) { - if (!this.lock.tryLock()) { + public void processEventsAsync(final Clock clock, final long time) { + if (!this.msgSystemAsyncLock.tryLock()) { return; } try { int nbEvent = 0; - while (this.msgSystem.getSize() > 0) { - //Log.error(" [" + nbEvent + "] event ..."); + while (this.msgSystemAsync.getSize() > 0) { + Log.error(" [" + nbEvent + "] event ..."); nbEvent++; - final ActionToDoInAsyncLoop func = this.msgSystem.getElementWait(); + final ActionToDoInAsyncLoop func = this.msgSystemAsync.getElementWait(); if (func == null) { continue; } func.run(this); } - } catch (Exception e) { + } catch (final Exception e) { Log.critical("Catch exception in main event Loop ...", e); } finally { - this.lock.unlock(); + this.msgSystemAsyncLock.unlock(); + } + } + + /** + * Process event in the GUI thread ==> prevent dead lock on the global GUI interface + */ + protected void processEventsGui() { + if (!this.msgSystemAsyncLock.tryLock()) { + return; + } + try { + while (this.msgSystemGui.getSize() > 0) { + final ActionToDoInAsyncLoop func = this.msgSystemGui.getElementWait(); + if (func == null) { + continue; + } + func.run(this); + } + } catch (final Exception e) { + Log.critical("Catch exception in main event Loop ...", e); + } finally { + this.msgSystemAsyncLock.unlock(); } } @@ -674,7 +747,7 @@ public abstract class GaleContext { // } // } public void requestUpdateSize() { - postAction(context -> { + postActionAsync(context -> { //Log.debug("Receive MSG : THREADRESIZE"); context.forceRedrawAll(); }); @@ -698,27 +771,56 @@ public abstract class GaleContext { * set the cursor display type. * @param newCursor selected new cursor. */ - public void setCursor(final Cursor newCursor) {} + public final void setCursor(final Cursor newCursor) { + postActionToGui(context -> { + context.setCursorThreadGUI(newCursor); + }); + } + + public void setCursorThreadGUI(final Cursor newCursor) { + Log.info("setCursor: NOT implemented ..."); + } /** * The application request a change of his current size force the fullscreen mode. * @param status status of the fullscreen mode. */ - public void setFullScreen(final boolean status) { - this.fullscreen = status; + public final void setFullScreen(final boolean status) { + postActionToGui(context -> { + this.fullscreen = status; + context.setFullScreenThreadGUI(status); + }); + } + + protected void setFullScreenThreadGUI(final boolean status) { + Log.info("setFullScreen: NOT implemented ..."); } /** * set the Icon of the program * @param inputFile new filename icon of the current program. */ - public void setIcon(final Uri inputFile) {} + public final void setIcon(final Uri inputFile) { + postActionToGui(context -> { + context.setIconThreadGUI(inputFile); + }); + } + + public void setIconThreadGUI(final Uri inputFile) { + Log.info("setIcon: NOT implemented ..."); + } /** * The Application request that the current windows will change his position. * @param pos New position of the Windows requested. */ - public void setPos(final Vector2f pos) { + public final void setPos(final Vector2f pos) { + postActionToGui(context -> { + context.setPosThreadGUI(pos); + }); + } + + protected void setPosThreadGUI(final Vector2f pos) { Log.info("setPos: NOT implemented ..."); } @@ -726,16 +828,31 @@ public abstract class GaleContext { * The application request a change of his current size. * @param size new Requested size of the windows. */ - public boolean setSize(final Vector2f size) { + public final void setSize(final Vector2f size) { + postActionToGui(context -> { + context.setSizeThreadGUI(size); + }); + } + + protected void setSizeThreadGUI(final Vector2f size) { Log.info("setSize: NOT implemented ..."); - return false; } /** * set the new title of the windows * @param title New desired title */ - public void setTitle(final String title) { + public final void setTitle(final String title) { + postActionToGui(context -> { + context.setTitleThreadGUI(title); + }); + } + + /** + * set the new title of the windows + * @param title New desired title + */ + protected void setTitleThreadGUI(final String title) { Log.info("setTitle: NOT implemented ..."); } @@ -743,12 +860,26 @@ public abstract class GaleContext { * Enable or Disable the decoration on the Windows (availlable only on Desktop) * @param status "true" to enable decoration / false otherwise */ - public void setWindowsDecoration(final boolean status) {} + public final void setWindowsDecoration(final boolean status) { + postActionToGui(context -> { + context.setWindowsDecorationThreadGUI(status); + }); + } + + protected void setWindowsDecorationThreadGUI(final boolean status) { + Log.info("setWindowsDecoration: NOT implemented ..."); + } /** * The Application request that the Windows will be visible. */ public void show() { + postActionToGui(context -> { + context.showThreadGUI(); + }); + } + + public void showThreadGUI() { Log.info("show: NOT implemented ..."); } @@ -758,16 +889,15 @@ public abstract class GaleContext { */ public void start2ndThreadProcessing() { // set the current interface: - lockContext(); - this.periodicThread.threadStart(); - try { - Thread.sleep(1); - } catch (final InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + try (AutoUnLock autoUnlock = AutoUnLock.lock(this.msgSystemAsyncLock)) { + this.periodicThread.threadStart(); + try { + Thread.sleep(1); + } catch (final InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } - // release the current interface: - unLockContext(); } /** @@ -777,89 +907,4 @@ public abstract class GaleContext { Log.warning("stop: NOT implemented for this platform..."); } - protected void unLockContext() { - - } - -} - -class MessageSystem { - private final Vector data = new Vector<>(); - - public synchronized void addElement(final ActionToDoInAsyncLoop data2) { - this.data.addElement(data2); - notifyAll(); - } - - public synchronized ActionToDoInAsyncLoop getElement() { - //Log.warning("+++++++++++++++++++++++++++++++++ getElement()"); - ActionToDoInAsyncLoop message = this.data.firstElement(); - this.data.removeElement(message); - //Log.warning("+++++++++++++++++++++++++++++++++ getElement() ===> done " + message); - return message; - } - - public synchronized ActionToDoInAsyncLoop getElementWait() { - if (this.data.isEmpty()) { - try { - wait(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } - } - if (this.data.isEmpty()) { - return null; - } - return getElement(); - } - - public synchronized int getSize() { - return this.data.size(); - } -} - -class PeriodicThread extends ThreadAbstract { - private final GaleContext context; - - public PeriodicThread(final GaleContext context) { - super("Galethread 2"); - this.context = context; - } - - @Override - protected void birth() { - // TODO Auto-generated method stub - } - - @Override - protected void death() { - // TODO Auto-generated method stub - } - - @Override - protected void runPeriodic() { - Log.verbose("----------------------------- [START] -----------------------------------"); - try { - Thread.sleep(10); - } catch (final InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return; - } - // Keep global clock to process events - Clock clock = Clock.systemUTC(); - long time = System.nanoTime(); - - ///synchronized (this.context) { - this.context.processEvents(clock, time); - // call all the application for periodic request (the application manage multiple instance )... - final GaleApplication appl = this.context.getApplication(); - //Log.verbose("Call application : " + appl); - if (appl != null) { - appl.onPeriod(clock, time); - } - Log.verbose("----------------------------- [ END ] -----------------------------------"); - } } diff --git a/src/org/atriasoft/gale/context/LWJG_AWT/ContextLWJGLAWT.java b/src/org/atriasoft/gale/context/LWJG_AWT/ContextLWJGLAWT.java index 93b1fc5..3efede3 100644 --- a/src/org/atriasoft/gale/context/LWJG_AWT/ContextLWJGLAWT.java +++ b/src/org/atriasoft/gale/context/LWJG_AWT/ContextLWJGLAWT.java @@ -26,6 +26,7 @@ import javax.swing.SwingUtilities; import javax.swing.WindowConstants; import org.atriasoft.etk.Uri; +import org.atriasoft.etk.math.FMath; import org.atriasoft.etk.math.Vector2f; import org.atriasoft.gale.DisplayManagerDraw; import org.atriasoft.gale.Fps; @@ -125,7 +126,7 @@ public class ContextLWJGLAWT extends GaleContext implements MouseListener, Mouse } @Override - public void grabPointerEvents(final boolean status, final Vector2f forcedPosition) { + protected void grabPointerEventsThreadGUI(final boolean status, final Vector2f forcedPosition) { if (status) { try { this.robot = new Robot(); @@ -166,13 +167,14 @@ public class ContextLWJGLAWT extends GaleContext implements MouseListener, Mouse @Override public void paintGL() { + final long startRender = System.currentTimeMillis(); //Log.warning("Draw ... "); final int w = getWidth(); final int h = getHeight(); if (ContextLWJGLAWT.this.decoratedWindowsSize.x() != w || ContextLWJGLAWT.this.decoratedWindowsSize.y() != h) { ContextLWJGLAWT.this.decoratedWindowsSize = new Vector2f(w, h); final Rectangle bounds = ContextLWJGLAWT.this.canvas.getBounds(); - Vector2f tmpWindowsSize = new Vector2f(bounds.width, bounds.height); + final Vector2f tmpWindowsSize = new Vector2f(bounds.width, bounds.height); operatingSystemResize(tmpWindowsSize); } operatingSystemDraw(true); @@ -180,6 +182,16 @@ public class ContextLWJGLAWT extends GaleContext implements MouseListener, Mouse if (Logger.isCriticalOccured()) { ContextLWJGLAWT.this.frame.dispose(); } + // Process event from the GUI (specific events... + processEventsGui(); + final long stopRender = System.currentTimeMillis(); + try { + // limit at 60FPS ==> bad to do it here, but it work for now... add a minimum of 10ms to free lock... + Thread.sleep((int) FMath.max((3000.0f / 60.0f) - (stopRender - startRender), 10)); // This permit to limit the FPS (base 602FPS) + } catch (final InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } }, BorderLayout.CENTER); this.frame.pack(); @@ -590,7 +602,7 @@ public class ContextLWJGLAWT extends GaleContext implements MouseListener, Mouse } @Override - public void setFullScreen(final boolean status) { + public void setFullScreenThreadGUI(final boolean status) { super.setFullScreen(status); if (status) { this.frame.setExtendedState(Frame.MAXIMIZED_BOTH); @@ -602,13 +614,13 @@ public class ContextLWJGLAWT extends GaleContext implements MouseListener, Mouse } @Override - public void setIcon(final Uri inputFile) { + public void setIconThreadGUI(final Uri inputFile) { } /****************************************************************************************/ @Override - public void setTitle(final String title) { + public void setTitleThreadGUI(final String title) { this.frame.setTitle(title); } diff --git a/src/org/atriasoft/gale/context/MessageSystem.java b/src/org/atriasoft/gale/context/MessageSystem.java new file mode 100644 index 0000000..46e4933 --- /dev/null +++ b/src/org/atriasoft/gale/context/MessageSystem.java @@ -0,0 +1,40 @@ +package org.atriasoft.gale.context; + +import java.util.Vector; + +public class MessageSystem { + private final Vector data = new Vector<>(); + + public synchronized void addElement(final ActionToDoInAsyncLoop data2) { + this.data.addElement(data2); + notifyAll(); + } + + public synchronized ActionToDoInAsyncLoop getElement() { + //Log.warning("+++++++++++++++++++++++++++++++++ getElement()"); + final ActionToDoInAsyncLoop message = this.data.firstElement(); + this.data.removeElement(message); + //Log.warning("+++++++++++++++++++++++++++++++++ getElement() ===> done " + message); + return message; + } + + public synchronized ActionToDoInAsyncLoop getElementWait() { + if (this.data.isEmpty()) { + try { + wait(); + } catch (final InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + } + if (this.data.isEmpty()) { + return null; + } + return getElement(); + } + + public synchronized int getSize() { + return this.data.size(); + } +} \ No newline at end of file diff --git a/src/org/atriasoft/gale/context/PeriodicThread.java b/src/org/atriasoft/gale/context/PeriodicThread.java new file mode 100644 index 0000000..deb951f --- /dev/null +++ b/src/org/atriasoft/gale/context/PeriodicThread.java @@ -0,0 +1,51 @@ +package org.atriasoft.gale.context; + +import java.time.Clock; + +import org.atriasoft.etk.ThreadAbstract; +import org.atriasoft.gale.GaleApplication; +import org.atriasoft.gale.internal.Log; + +public class PeriodicThread extends ThreadAbstract { + private final GaleContext context; + + public PeriodicThread(final GaleContext context) { + super("GaleAsync"); + this.context = context; + } + + @Override + protected void birth() { + // TODO Auto-generated method stub + } + + @Override + protected void death() { + // TODO Auto-generated method stub + } + + @Override + protected void runPeriodic() { + Log.verbose("----------------------------- [START] -----------------------------------"); + try { + Thread.sleep(100); + } catch (final InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return; + } + // Keep global clock to process events + final Clock clock = Clock.systemUTC(); + final long time = System.nanoTime(); + + ///synchronized (this.context) { + this.context.processEventsAsync(clock, time); + // call all the application for periodic request (the application manage multiple instance )... + final GaleApplication appl = this.context.getApplication(); + //Log.verbose("Call application : " + appl); + if (appl != null) { + appl.onPeriod(clock, time); + } + Log.verbose("----------------------------- [ END ] -----------------------------------"); + } +} diff --git a/src/org/atriasoft/gale/internal/Log.java b/src/org/atriasoft/gale/internal/Log.java index 32d8b4e..b05c3a2 100644 --- a/src/org/atriasoft/gale/internal/Log.java +++ b/src/org/atriasoft/gale/internal/Log.java @@ -4,6 +4,7 @@ import io.scenarium.logger.LogLevel; import io.scenarium.logger.Logger; public class Log { + private static final boolean FORCE_ALL = false; private static final String LIB_NAME = "gale"; private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME); private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL); @@ -15,58 +16,58 @@ public class Log { private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO); private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT); - public static void critical(final String data) { - if (PRINT_CRITICAL) { - Logger.critical(LIB_NAME_DRAW, data); - } - } - - public static void critical(final String data, final Exception e) { + public static void critical(final Exception e, final String data) { e.printStackTrace(); - if (PRINT_CRITICAL) { + if (PRINT_CRITICAL || FORCE_ALL) { Logger.critical(LIB_NAME_DRAW, data + " : " + e.getMessage()); } } - public static void debug(final String data) { - if (PRINT_DEBUG) { - Logger.debug(LIB_NAME_DRAW, data); + public static void critical(final String data, final Object... objects) { + if (PRINT_CRITICAL || FORCE_ALL) { + Logger.critical(LIB_NAME_DRAW, data, objects); } } - public static void error(final String data) { - if (PRINT_ERROR) { - Logger.error(LIB_NAME_DRAW, data); + public static void debug(final String data, final Object... objects) { + if (PRINT_DEBUG || FORCE_ALL) { + Logger.debug(LIB_NAME_DRAW, data, objects); } } - public static void info(final String data) { - if (PRINT_INFO) { - Logger.info(LIB_NAME_DRAW, data); + public static void error(final String data, final Object... objects) { + if (PRINT_ERROR || FORCE_ALL) { + Logger.error(LIB_NAME_DRAW, data, objects); } } - public static void print(final String data) { - if (PRINT_PRINT) { - Logger.print(LIB_NAME_DRAW, data); + public static void info(final String data, final Object... objects) { + if (PRINT_INFO || FORCE_ALL) { + Logger.info(LIB_NAME_DRAW, data, objects); } } - public static void todo(final String data) { - if (PRINT_TODO) { - Logger.todo(LIB_NAME_DRAW, data); + public static void print(final String data, final Object... objects) { + if (PRINT_PRINT || FORCE_ALL) { + Logger.print(LIB_NAME_DRAW, data, objects); } } - public static void verbose(final String data) { - if (PRINT_VERBOSE) { - Logger.verbose(LIB_NAME_DRAW, data); + public static void todo(final String data, final Object... objects) { + if (PRINT_TODO || FORCE_ALL) { + Logger.todo(LIB_NAME_DRAW, data, objects); } } - public static void warning(final String data) { - if (PRINT_WARNING) { - Logger.warning(LIB_NAME_DRAW, data); + public static void verbose(final String data, final Object... objects) { + if (PRINT_VERBOSE || FORCE_ALL) { + Logger.verbose(LIB_NAME_DRAW, data, objects); + } + } + + public static void warning(final String data, final Object... objects) { + if (PRINT_WARNING || FORCE_ALL) { + Logger.warning(LIB_NAME_DRAW, data, objects); } }