2018-02-08 18:14:13 +08:00
|
|
|
#ifndef SCREEN_H
|
|
|
|
#define SCREEN_H
|
|
|
|
|
2021-01-09 02:24:51 +08:00
|
|
|
#include "common.h"
|
|
|
|
|
2019-03-03 06:52:22 +08:00
|
|
|
#include <stdbool.h>
|
2018-02-08 18:14:13 +08:00
|
|
|
#include <SDL2/SDL.h>
|
|
|
|
#include <libavformat/avformat.h>
|
|
|
|
|
2021-12-31 23:32:07 +08:00
|
|
|
#include "controller.h"
|
2021-01-09 02:15:29 +08:00
|
|
|
#include "coords.h"
|
2021-06-26 20:38:36 +08:00
|
|
|
#include "fps_counter.h"
|
2021-12-31 23:32:07 +08:00
|
|
|
#include "input_manager.h"
|
2020-04-11 22:08:23 +08:00
|
|
|
#include "opengl.h"
|
2021-12-31 23:32:07 +08:00
|
|
|
#include "trait/key_processor.h"
|
2021-04-11 21:01:05 +08:00
|
|
|
#include "trait/frame_sink.h"
|
2021-12-31 23:32:07 +08:00
|
|
|
#include "trait/mouse_processor.h"
|
2021-04-11 21:01:05 +08:00
|
|
|
#include "video_buffer.h"
|
2018-02-08 18:14:13 +08:00
|
|
|
|
2022-01-15 05:17:30 +08:00
|
|
|
struct sc_screen {
|
2021-04-11 21:01:05 +08:00
|
|
|
struct sc_frame_sink frame_sink; // frame sink trait
|
|
|
|
|
2021-04-11 21:01:05 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
bool open; // track the open/close state to assert correct behavior
|
|
|
|
#endif
|
|
|
|
|
2022-01-15 05:17:30 +08:00
|
|
|
struct sc_input_manager im;
|
2021-06-26 21:02:18 +08:00
|
|
|
struct sc_video_buffer vb;
|
2021-05-17 00:26:20 +08:00
|
|
|
struct fps_counter fps_counter;
|
2021-02-20 03:56:09 +08:00
|
|
|
|
2018-02-08 18:14:13 +08:00
|
|
|
SDL_Window *window;
|
|
|
|
SDL_Renderer *renderer;
|
|
|
|
SDL_Texture *texture;
|
2020-04-11 22:08:23 +08:00
|
|
|
struct sc_opengl gl;
|
2021-10-30 21:20:39 +08:00
|
|
|
struct sc_size frame_size;
|
|
|
|
struct sc_size content_size; // rotated frame_size
|
2020-05-11 09:11:13 +08:00
|
|
|
|
|
|
|
bool resize_pending; // resize requested while fullscreen or maximized
|
|
|
|
// The content size the last time the window was not maximized or
|
|
|
|
// fullscreen (meaningful only when resize_pending is true)
|
2021-10-30 21:20:39 +08:00
|
|
|
struct sc_size windowed_content_size;
|
2020-05-11 09:11:13 +08:00
|
|
|
|
2020-04-08 05:03:23 +08:00
|
|
|
// client rotation: 0, 1, 2 or 3 (x90 degrees counterclockwise)
|
|
|
|
unsigned rotation;
|
2020-04-18 00:44:24 +08:00
|
|
|
// rectangle of the content (excluding black borders)
|
|
|
|
struct SDL_Rect rect;
|
2019-03-03 06:52:22 +08:00
|
|
|
bool has_frame;
|
|
|
|
bool fullscreen;
|
2019-11-12 04:26:35 +08:00
|
|
|
bool maximized;
|
2020-04-11 22:08:23 +08:00
|
|
|
bool mipmaps;
|
2021-04-11 21:01:05 +08:00
|
|
|
|
2021-10-31 02:21:00 +08:00
|
|
|
bool event_failed; // in case SDL_PushEvent() returned an error
|
|
|
|
|
2022-01-01 01:52:34 +08:00
|
|
|
bool mouse_captured; // only relevant in relative mouse mode
|
|
|
|
// To enable/disable mouse capture, a mouse capture key (LALT, LGUI or
|
|
|
|
// RGUI) must be pressed. This variable tracks the pressed capture key.
|
|
|
|
SDL_Keycode mouse_capture_key_pressed;
|
|
|
|
|
2021-04-11 21:01:05 +08:00
|
|
|
AVFrame *frame;
|
2018-02-08 18:14:13 +08:00
|
|
|
};
|
|
|
|
|
2022-01-15 05:17:30 +08:00
|
|
|
struct sc_screen_params {
|
2022-01-15 05:17:30 +08:00
|
|
|
struct sc_controller *controller;
|
2021-12-31 23:32:07 +08:00
|
|
|
struct sc_key_processor *kp;
|
|
|
|
struct sc_mouse_processor *mp;
|
|
|
|
|
|
|
|
bool control;
|
|
|
|
bool forward_all_clicks;
|
|
|
|
bool legacy_paste;
|
|
|
|
bool clipboard_autosync;
|
|
|
|
const struct sc_shortcut_mods *shortcut_mods;
|
|
|
|
|
2021-02-26 05:00:34 +08:00
|
|
|
const char *window_title;
|
2021-10-30 21:20:39 +08:00
|
|
|
struct sc_size frame_size;
|
2021-02-26 05:00:34 +08:00
|
|
|
bool always_on_top;
|
|
|
|
|
2022-01-16 22:27:23 +08:00
|
|
|
int16_t window_x; // accepts SC_WINDOW_POSITION_UNDEFINED
|
|
|
|
int16_t window_y; // accepts SC_WINDOW_POSITION_UNDEFINED
|
|
|
|
uint16_t window_width;
|
|
|
|
uint16_t window_height;
|
2021-02-26 05:00:34 +08:00
|
|
|
|
|
|
|
bool window_borderless;
|
|
|
|
|
|
|
|
uint8_t rotation;
|
|
|
|
bool mipmaps;
|
2021-04-14 04:10:45 +08:00
|
|
|
|
|
|
|
bool fullscreen;
|
2021-07-07 01:04:05 +08:00
|
|
|
|
|
|
|
sc_tick buffering_time;
|
2021-02-26 05:00:34 +08:00
|
|
|
};
|
|
|
|
|
Improve startup time
On startup, the client has to:
1. listen on a port
2. push and start the server to the device
3. wait for the server to connect (accept)
4. read device name and size
5. initialize SDL
6. initialize the window and renderer
7. show the window
From the execution of the app_process command to start the server on the
device, to the execution of the java main method, it takes ~800ms. As a
consequence, step 3 also takes ~800ms on the client.
Once complete, the client initializes SDL, which takes ~500ms.
These two expensive actions are executed sequentially:
HOST DEVICE
listen on port | |
push/start the server |----------------->|| app_process loads the jar
accept the connection . ^ ||
. | ||
. | WASTE ||
. | OF ||
. | TIME ||
. | ||
. | ||
. v X execution of our java main
connection accepted |<-----------------| connect to the host
init SDL || |
|| ,----------------| send frames
|| |,---------------|
|| ||,--------------|
|| |||,-------------|
|| ||||,------------|
init window/renderer | |||||,-----------|
display frames |<++++++-----------|
(many frames skipped)
The rationale for step 3 occuring before step 5 is that initializing
SDL replaces the SIGTERM handler to receive the event in the event loop,
so pressing Ctrl+C during step 5 would not work (since it blocks the
event loop).
But this is not so important; let's parallelize the SDL initialization
with the app_process execution (we'll just add a timeout to the
connection):
HOST DEVICE
listen on port | |
push/start the server |----------------->||app_process loads the jar
init SDL || ||
|| ||
|| ||
|| ||
|| ||
|| ||
accept the connection . ||
. X execution of our java main
connection accepted |<-----------------| connect to the host
init window/renderer | |
display frames |<-----------------| send frames
|<-----------------|
In addition, show the window only once the first frame is available to
avoid flickering (opening a black window for 100~200ms).
Note: the window and renderer are initialized after the connection is
accepted because they use the device information received from the
device.
2018-02-09 20:50:54 +08:00
|
|
|
// initialize screen, create window, renderer and texture (window is hidden)
|
2019-03-03 06:52:22 +08:00
|
|
|
bool
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_init(struct sc_screen *screen, const struct sc_screen_params *params);
|
2021-05-17 00:26:20 +08:00
|
|
|
|
|
|
|
// request to interrupt any inner thread
|
|
|
|
// must be called before screen_join()
|
|
|
|
void
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_interrupt(struct sc_screen *screen);
|
2021-05-17 00:26:20 +08:00
|
|
|
|
|
|
|
// join any inner thread
|
|
|
|
void
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_join(struct sc_screen *screen);
|
2018-02-08 18:14:13 +08:00
|
|
|
|
|
|
|
// destroy window, renderer and texture (if any)
|
2019-03-03 03:09:56 +08:00
|
|
|
void
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_destroy(struct sc_screen *screen);
|
2018-02-08 18:14:13 +08:00
|
|
|
|
2021-04-14 04:22:54 +08:00
|
|
|
// hide the window
|
|
|
|
//
|
|
|
|
// It is used to hide the window immediately on closing without waiting for
|
|
|
|
// screen_destroy()
|
|
|
|
void
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_hide_window(struct sc_screen *screen);
|
2021-04-14 04:22:54 +08:00
|
|
|
|
2018-02-08 18:14:13 +08:00
|
|
|
// switch the fullscreen mode
|
2019-03-03 03:09:56 +08:00
|
|
|
void
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_switch_fullscreen(struct sc_screen *screen);
|
2018-02-08 18:14:13 +08:00
|
|
|
|
|
|
|
// resize window to optimal size (remove black borders)
|
2019-03-03 03:09:56 +08:00
|
|
|
void
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_resize_to_fit(struct sc_screen *screen);
|
2018-02-08 18:14:13 +08:00
|
|
|
|
|
|
|
// resize window to 1:1 (pixel-perfect)
|
2019-03-03 03:09:56 +08:00
|
|
|
void
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_resize_to_pixel_perfect(struct sc_screen *screen);
|
2018-02-08 18:14:13 +08:00
|
|
|
|
2020-04-08 05:03:23 +08:00
|
|
|
// set the display rotation (0, 1, 2 or 3, x90 degrees counterclockwise)
|
|
|
|
void
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_set_rotation(struct sc_screen *screen, unsigned rotation);
|
2020-04-08 05:03:23 +08:00
|
|
|
|
2021-02-16 01:44:53 +08:00
|
|
|
// react to SDL events
|
|
|
|
bool
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_handle_event(struct sc_screen *screen, SDL_Event *event);
|
2019-10-20 21:32:33 +08:00
|
|
|
|
2020-04-18 00:43:29 +08:00
|
|
|
// convert point from window coordinates to frame coordinates
|
|
|
|
// x and y are expressed in pixels
|
2021-10-30 21:20:39 +08:00
|
|
|
struct sc_point
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_convert_window_to_frame_coords(struct sc_screen *screen,
|
|
|
|
int32_t x, int32_t y);
|
2020-06-25 14:54:40 +08:00
|
|
|
|
|
|
|
// convert point from drawable coordinates to frame coordinates
|
|
|
|
// x and y are expressed in pixels
|
2021-10-30 21:20:39 +08:00
|
|
|
struct sc_point
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_convert_drawable_to_frame_coords(struct sc_screen *screen,
|
|
|
|
int32_t x, int32_t y);
|
2020-04-18 00:43:29 +08:00
|
|
|
|
2020-04-18 00:44:24 +08:00
|
|
|
// Convert coordinates from window to drawable.
|
|
|
|
// Events are expressed in window coordinates, but content is expressed in
|
|
|
|
// drawable coordinates. They are the same if HiDPI scaling is 1, but differ
|
|
|
|
// otherwise.
|
|
|
|
void
|
2022-01-15 05:17:30 +08:00
|
|
|
sc_screen_hidpi_scale_coords(struct sc_screen *screen, int32_t *x, int32_t *y);
|
2020-04-18 00:44:24 +08:00
|
|
|
|
2018-02-08 18:14:13 +08:00
|
|
|
#endif
|