7de6229ae1b70cbeff9dbaf1c42920754c82c63c
2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2017 Kevin Lamonte
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
29 package jexer
.backend
;
31 import java
.util
.LinkedList
;
32 import java
.util
.List
;
34 import jexer
.bits
.CellAttributes
;
35 import jexer
.event
.TInputEvent
;
36 import jexer
.event
.TKeypressEvent
;
37 import jexer
.event
.TMouseEvent
;
38 import jexer
.TApplication
;
42 * TWindowBackend uses a window in one TApplication to provide a backend for
43 * another TApplication.
45 * Note that TWindow has its own getScreen() and setTitle() functions.
46 * Clients in TWindowBackend's application won't be able to use it to get at
47 * the other application's screen. getOtherScreen() has been provided.
49 public class TWindowBackend
extends TWindow
implements Backend
{
52 * The listening object that run() wakes up on new input.
54 private Object listener
;
57 * The object to sync on in draw(). This is normally otherScreen, but it
58 * could also be a MultiScreen.
60 private Object drawLock
;
63 * The event queue, filled up by a thread reading on input.
65 private List
<TInputEvent
> eventQueue
;
70 private Screen otherScreen
;
73 * The mouse X position as seen on the other screen.
75 private int otherMouseX
= -1;
78 * The mouse Y position as seen on the other screen.
80 private int otherMouseY
= -1;
83 * The session information.
85 private SessionInfo sessionInfo
;
88 * Set the object to sync to in draw().
90 * @param drawLock the object to synchronize on
92 public void setDrawLock(final Object drawLock
) {
93 this.drawLock
= drawLock
;
97 * Getter for the other application's screen.
101 public Screen
getOtherScreen() {
106 * Getter for sessionInfo.
108 * @return the SessionInfo
110 public final SessionInfo
getSessionInfo() {
115 * Public constructor. Window will be located at (0, 0).
117 * @param listener the object this backend needs to wake up when new
119 * @param application TApplication that manages this window
120 * @param title window title, will be centered along the top border
121 * @param width width of window
122 * @param height height of window
124 public TWindowBackend(final Object listener
,
125 final TApplication application
, final String title
,
126 final int width
, final int height
) {
128 super(application
, title
, width
, height
);
130 this.listener
= listener
;
131 eventQueue
= new LinkedList
<TInputEvent
>();
132 sessionInfo
= new TSessionInfo(width
, height
);
133 otherScreen
= new LogicalScreen();
134 otherScreen
.setDimensions(width
- 2, height
- 2);
135 drawLock
= otherScreen
;
139 * Public constructor. Window will be located at (0, 0).
141 * @param listener the object this backend needs to wake up when new
143 * @param application TApplication that manages this window
144 * @param title window title, will be centered along the top border
145 * @param width width of window
146 * @param height height of window
147 * @param flags bitmask of RESIZABLE, CENTERED, or MODAL
149 public TWindowBackend(final Object listener
,
150 final TApplication application
, final String title
,
151 final int width
, final int height
, final int flags
) {
153 super(application
, title
, width
, height
, flags
);
155 this.listener
= listener
;
156 eventQueue
= new LinkedList
<TInputEvent
>();
157 sessionInfo
= new TSessionInfo(width
, height
);
158 otherScreen
= new LogicalScreen();
159 otherScreen
.setDimensions(width
- 2, height
- 2);
160 drawLock
= otherScreen
;
164 * Public constructor.
166 * @param listener the object this backend needs to wake up when new
168 * @param application TApplication that manages this window
169 * @param title window title, will be centered along the top border
170 * @param x column relative to parent
171 * @param y row relative to parent
172 * @param width width of window
173 * @param height height of window
175 public TWindowBackend(final Object listener
,
176 final TApplication application
, final String title
,
177 final int x
, final int y
, final int width
, final int height
) {
179 super(application
, title
, x
, y
, width
, height
);
181 this.listener
= listener
;
182 eventQueue
= new LinkedList
<TInputEvent
>();
183 sessionInfo
= new TSessionInfo(width
, height
);
184 otherScreen
= new LogicalScreen();
185 otherScreen
.setDimensions(width
- 2, height
- 2);
186 drawLock
= otherScreen
;
190 * Public constructor.
192 * @param listener the object this backend needs to wake up when new
194 * @param application TApplication that manages this window
195 * @param title window title, will be centered along the top border
196 * @param x column relative to parent
197 * @param y row relative to parent
198 * @param width width of window
199 * @param height height of window
200 * @param flags mask of RESIZABLE, CENTERED, or MODAL
202 public TWindowBackend(final Object listener
,
203 final TApplication application
, final String title
,
204 final int x
, final int y
, final int width
, final int height
,
207 super(application
, title
, x
, y
, width
, height
, flags
);
209 this.listener
= listener
;
210 eventQueue
= new LinkedList
<TInputEvent
>();
211 sessionInfo
= new TSessionInfo(width
, height
);
212 otherScreen
= new LogicalScreen();
213 otherScreen
.setDimensions(width
- 2, height
- 2);
214 drawLock
= otherScreen
;
218 * Subclasses must provide an implementation that syncs the logical
219 * screen to the physical device.
221 public void flushScreen() {
226 * Subclasses must provide an implementation to get keyboard, mouse, and
227 * screen resize events.
229 * @param queue list to append new events to
231 public void getEvents(List
<TInputEvent
> queue
) {
232 synchronized (eventQueue
) {
233 if (eventQueue
.size() > 0) {
234 synchronized (queue
) {
235 queue
.addAll(eventQueue
);
243 * Subclasses must provide an implementation that closes sockets,
244 * restores console, etc.
246 public void shutdown() {
251 * Set listener to a different Object.
253 * @param listener the new listening object that run() wakes up on new
256 public void setListener(final Object listener
) {
257 this.listener
= listener
;
261 * Draw the foreground colors grid.
266 // Sync on other screen, so that we do not draw in the middle of
267 // their screen update.
268 synchronized (drawLock
) {
272 // Draw every cell of the other screen
273 for (int y
= 0; y
< otherScreen
.getHeight(); y
++) {
274 for (int x
= 0; x
< otherScreen
.getWidth(); x
++) {
275 putCharXY(x
+ 1, y
+ 1, otherScreen
.getCharXY(x
, y
));
279 // If the mouse pointer is over the other window, draw its
280 // pointer again here. (Their TApplication drew it, then our
281 // TApplication drew it again (undo-ing it), so now we draw it a
282 // third time so that it is visible.)
283 if ((otherMouseX
!= -1) && (otherMouseY
!= -1)) {
284 CellAttributes attr
= getAttrXY(otherMouseX
, otherMouseY
);
285 attr
.setForeColor(attr
.getForeColor().invert());
286 attr
.setBackColor(attr
.getBackColor().invert());
287 putAttrXY(otherMouseX
, otherMouseY
, attr
, false);
290 // If their cursor is visible, draw that here too.
291 if (otherScreen
.isCursorVisible()) {
292 setCursorX(otherScreen
.getCursorX() + 1);
293 setCursorY(otherScreen
.getCursorY() + 1);
294 setCursorVisible(true);
296 setCursorVisible(false);
302 * Subclasses should override this method to cleanup resources. This is
303 * called by application.closeWindow().
305 public void onClose() {
306 // TODO: send a screen disconnect
310 * Returns true if the mouse is currently in the otherScreen window.
312 * @param mouse mouse event
313 * @return true if mouse is currently in the otherScreen window.
315 protected boolean mouseOnOtherScreen(final TMouseEvent mouse
) {
316 if ((mouse
.getY() >= 1)
317 && (mouse
.getY() <= otherScreen
.getHeight())
318 && (mouse
.getX() >= 1)
319 && (mouse
.getX() <= otherScreen
.getWidth())
327 * Handle mouse button presses.
329 * @param mouse mouse button event
332 public void onMouseDown(final TMouseEvent mouse
) {
333 if (mouseOnOtherScreen(mouse
)) {
334 TMouseEvent event
= mouse
.dup();
335 event
.setX(mouse
.getX() - 1);
336 event
.setY(mouse
.getY() - 1);
337 event
.setAbsoluteX(event
.getX());
338 event
.setAbsoluteY(event
.getY());
339 synchronized (eventQueue
) {
340 eventQueue
.add(event
);
342 synchronized (listener
) {
343 listener
.notifyAll();
346 super.onMouseDown(mouse
);
350 * Handle mouse button releases.
352 * @param mouse mouse button release event
355 public void onMouseUp(final TMouseEvent mouse
) {
356 if (mouseOnOtherScreen(mouse
)) {
357 TMouseEvent event
= mouse
.dup();
358 event
.setX(mouse
.getX() - 1);
359 event
.setY(mouse
.getY() - 1);
360 event
.setAbsoluteX(event
.getX());
361 event
.setAbsoluteY(event
.getY());
362 synchronized (eventQueue
) {
363 eventQueue
.add(event
);
365 synchronized (listener
) {
366 listener
.notifyAll();
369 super.onMouseUp(mouse
);
373 * Handle mouse movements.
375 * @param mouse mouse motion event
378 public void onMouseMotion(final TMouseEvent mouse
) {
379 if (mouseOnOtherScreen(mouse
)) {
380 TMouseEvent event
= mouse
.dup();
381 event
.setX(mouse
.getX() - 1);
382 event
.setY(mouse
.getY() - 1);
383 event
.setAbsoluteX(event
.getX());
384 event
.setAbsoluteY(event
.getY());
385 otherMouseX
= event
.getX() + 1;
386 otherMouseY
= event
.getY() + 2;
387 synchronized (eventQueue
) {
388 eventQueue
.add(event
);
390 synchronized (listener
) {
391 listener
.notifyAll();
397 super.onMouseMotion(mouse
);
403 * @param keypress keystroke event
406 public void onKeypress(final TKeypressEvent keypress
) {
407 TKeypressEvent event
= keypress
.dup();
408 synchronized (eventQueue
) {
409 eventQueue
.add(event
);
411 synchronized (listener
) {
412 listener
.notifyAll();