1 /* 2 * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package com.sun.glass.ui; 26 27 import java.lang.annotation.Native; 28 29 /** 30 * A high-resolution timer. 31 * 32 * An application may either override its run() method, or pass a Runnable 33 * object to the constructor of the Timer class. 34 * <p> 35 * The run() method may be invoked on a thread other than the UI thread. If 36 * a developer wants to process timer events on the UI thread, they can use 37 * the Application.invokeLater/invokeAndWait() API. 38 */ 39 public abstract class Timer { 40 41 @Native private final static double UNSET_PERIOD = -1.0; // 0 is valid value, so can't use it here 42 @Native private final static double SET_PERIOD = -2.0; // token value for vsync timer 43 44 private final Runnable runnable; 45 private long ptr; 46 private double period = UNSET_PERIOD; 47 48 protected abstract long _start(Runnable runnable); 49 protected abstract long _start(Runnable runnable, int period); 50 protected abstract void _stop(long timer); 51 protected abstract void _pause(long timer); 52 protected abstract void _resume(long timer); 53 54 /** 55 * Constructs a new timer. 56 * 57 * If the application overrides the Timer.run(), it should call super.run() 58 * in order to run the runnable passed to the constructor. 59 */ 60 protected Timer(Runnable runnable) { 61 if (runnable == null) { 62 throw new IllegalArgumentException("runnable shouldn't be null"); 63 } 64 this.runnable = runnable; 65 } 66 67 /** 68 * Returns the minimum timer period supported by the native system. 69 */ 70 public static int getMinPeriod() { 71 return Application.GetApplication().staticTimer_getMinPeriod(); 72 } 73 74 /** 75 * Returns the maximum timer period supported by the native system. 76 */ 77 public static int getMaxPeriod() { 78 return Application.GetApplication().staticTimer_getMaxPeriod(); 79 } 80 81 /** 82 * Starts the timer. 83 * The period must be in the range getMinPeriod() .. getMaxPeriod(). 84 * If the timer is currently started, it gets stopped before re-starting. 85 * If starting the timer fails, the RuntimeException is thrown. 86 */ 87 public synchronized void start(int period) { 88 if (period < getMinPeriod() || period > getMaxPeriod()) { 89 throw new IllegalArgumentException("period is out of range"); 90 } 91 92 if (this.ptr != 0L) { 93 stop(); 94 } 95 96 this.ptr = _start(this.runnable, period); 97 if (this.ptr == 0L) { 98 this.period = UNSET_PERIOD; 99 throw new RuntimeException("Failed to start the timer"); 100 } else { 101 this.period = (double)period; 102 } 103 } 104 105 /** 106 * Start a vsync-based timer if the system supports it. 107 * 108 * A RuntimeException is thrown if the system does not support 109 * vsync-based timer or if there was an issue starting the timer. 110 */ 111 public synchronized void start() { 112 if (this.ptr != 0L) { 113 stop(); 114 } 115 116 this.ptr = _start(this.runnable); 117 if (this.ptr == 0L) { 118 this.period = UNSET_PERIOD; 119 throw new RuntimeException("Failed to start the timer"); 120 } else { 121 this.period = SET_PERIOD; 122 } 123 } 124 125 /** 126 * Stops the timer. If a vsync-based timer is stopped, all of the 127 * vsync timers currently running will be stopped. 128 */ 129 public synchronized void stop() { 130 if (this.ptr != 0L) { 131 _stop(this.ptr); 132 this.ptr = 0L; 133 this.period = UNSET_PERIOD; 134 } 135 } 136 137 /** 138 * Pauses the timer. See JDK-8189926. 139 * Currently implemented only for mac platform. 140 * Timer can be paused or resumed from two different threads. 141 */ 142 public synchronized void pause() { 143 if (ptr != 0L) { 144 _pause(ptr); 145 } 146 } 147 148 /** 149 * Resumes the timer. See JDK-8189926 150 */ 151 public synchronized void resume() { 152 if (ptr != 0L) { 153 _resume(ptr); 154 } 155 } 156 157 158 /** 159 * Returns true if the timer is currently running 160 * (convenience API: might not need it) 161 */ 162 public synchronized boolean isRunning() { 163 return (this.period != UNSET_PERIOD); 164 } 165 }