Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fba7f77a7e |
@@ -133,7 +133,7 @@ static int
|
||||
event_watcher(void *data, SDL_Event *event) {
|
||||
(void) data;
|
||||
if (event->type == SDL_WINDOWEVENT
|
||||
&& event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
|
||||
&& event->window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||
// In practice, it seems to always be called from the same thread in
|
||||
// that specific case. Anyway, it's just a workaround.
|
||||
screen_render(&screen);
|
||||
|
||||
149
app/src/screen.c
149
app/src/screen.c
@@ -30,10 +30,10 @@ get_rotated_size(struct size size, int rotation) {
|
||||
|
||||
// get the window size in a struct size
|
||||
static struct size
|
||||
get_window_size(const struct screen *screen) {
|
||||
get_window_size(SDL_Window *window) {
|
||||
int width;
|
||||
int height;
|
||||
SDL_GetWindowSize(screen->window, &width, &height);
|
||||
SDL_GetWindowSize(window, &width, &height);
|
||||
|
||||
struct size size;
|
||||
size.width = width;
|
||||
@@ -41,12 +41,31 @@ get_window_size(const struct screen *screen) {
|
||||
return size;
|
||||
}
|
||||
|
||||
// get the windowed window size
|
||||
static struct size
|
||||
get_windowed_window_size(const struct screen *screen) {
|
||||
if (screen->fullscreen || screen->maximized) {
|
||||
return screen->windowed_window_size;
|
||||
}
|
||||
return get_window_size(screen->window);
|
||||
}
|
||||
|
||||
// apply the windowed window size if fullscreen and maximized are disabled
|
||||
static void
|
||||
apply_windowed_size(struct screen *screen) {
|
||||
if (!screen->fullscreen && !screen->maximized) {
|
||||
SDL_SetWindowSize(screen->window, screen->windowed_window_size.width,
|
||||
screen->windowed_window_size.height);
|
||||
}
|
||||
}
|
||||
|
||||
// set the window size to be applied when fullscreen is disabled
|
||||
static void
|
||||
set_window_size(struct screen *screen, struct size new_size) {
|
||||
assert(!screen->fullscreen);
|
||||
assert(!screen->maximized);
|
||||
SDL_SetWindowSize(screen->window, new_size.width, new_size.height);
|
||||
// setting the window size during fullscreen is implementation defined,
|
||||
// so apply the resize only after fullscreen is disabled
|
||||
screen->windowed_window_size = new_size;
|
||||
apply_windowed_size(screen);
|
||||
}
|
||||
|
||||
// get the preferred display bounds (i.e. the screen bounds with some margins)
|
||||
@@ -119,8 +138,8 @@ get_optimal_size(struct size current_size, struct size content_size) {
|
||||
// same as get_optimal_size(), but read the current size from the window
|
||||
static inline struct size
|
||||
get_optimal_window_size(const struct screen *screen, struct size content_size) {
|
||||
struct size window_size = get_window_size(screen);
|
||||
return get_optimal_size(window_size, content_size);
|
||||
struct size windowed_size = get_windowed_window_size(screen);
|
||||
return get_optimal_size(windowed_size, content_size);
|
||||
}
|
||||
|
||||
// initially, there is no current size, so use the frame size as current size
|
||||
@@ -289,6 +308,8 @@ screen_init_rendering(struct screen *screen, const char *window_title,
|
||||
return false;
|
||||
}
|
||||
|
||||
screen->windowed_window_size = window_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -310,45 +331,6 @@ screen_destroy(struct screen *screen) {
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
resize_for_content(struct screen *screen, struct size old_content_size,
|
||||
struct size new_content_size) {
|
||||
struct size window_size = get_window_size(screen);
|
||||
struct size target_size = {
|
||||
.width = (uint32_t) window_size.width * new_content_size.width
|
||||
/ old_content_size.width,
|
||||
.height = (uint32_t) window_size.height * new_content_size.height
|
||||
/ old_content_size.height,
|
||||
};
|
||||
target_size = get_optimal_size(target_size, new_content_size);
|
||||
set_window_size(screen, target_size);
|
||||
}
|
||||
|
||||
static void
|
||||
set_content_size(struct screen *screen, struct size new_content_size) {
|
||||
if (!screen->fullscreen && !screen->maximized) {
|
||||
resize_for_content(screen, screen->content_size, new_content_size);
|
||||
} else if (!screen->resize_pending) {
|
||||
// Store the windowed size to be able to compute the optimal size once
|
||||
// fullscreen and maximized are disabled
|
||||
screen->windowed_content_size = screen->content_size;
|
||||
screen->resize_pending = true;
|
||||
}
|
||||
|
||||
screen->content_size = new_content_size;
|
||||
}
|
||||
|
||||
static void
|
||||
apply_pending_resize(struct screen *screen) {
|
||||
assert(!screen->fullscreen);
|
||||
assert(!screen->maximized);
|
||||
if (screen->resize_pending) {
|
||||
resize_for_content(screen, screen->windowed_content_size,
|
||||
screen->content_size);
|
||||
screen->resize_pending = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
screen_set_rotation(struct screen *screen, unsigned rotation) {
|
||||
assert(rotation < 4);
|
||||
@@ -356,6 +338,7 @@ screen_set_rotation(struct screen *screen, unsigned rotation) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct size old_content_size = screen->content_size;
|
||||
struct size new_content_size =
|
||||
get_rotated_size(screen->frame_size, rotation);
|
||||
|
||||
@@ -366,7 +349,17 @@ screen_set_rotation(struct screen *screen, unsigned rotation) {
|
||||
return;
|
||||
}
|
||||
|
||||
set_content_size(screen, new_content_size);
|
||||
struct size windowed_size = get_windowed_window_size(screen);
|
||||
struct size target_size = {
|
||||
.width = (uint32_t) windowed_size.width * new_content_size.width
|
||||
/ old_content_size.width,
|
||||
.height = (uint32_t) windowed_size.height * new_content_size.height
|
||||
/ old_content_size.height,
|
||||
};
|
||||
target_size = get_optimal_size(target_size, new_content_size);
|
||||
set_window_size(screen, target_size);
|
||||
|
||||
screen->content_size = new_content_size;
|
||||
screen->rotation = rotation;
|
||||
LOGI("Display rotation set to %u", rotation);
|
||||
|
||||
@@ -390,8 +383,19 @@ prepare_for_frame(struct screen *screen, struct size new_frame_size) {
|
||||
// frame dimension changed, destroy texture
|
||||
SDL_DestroyTexture(screen->texture);
|
||||
|
||||
set_content_size(screen, new_content_size);
|
||||
struct size content_size = screen->content_size;
|
||||
struct size windowed_size = get_windowed_window_size(screen);
|
||||
struct size target_size = {
|
||||
(uint32_t) windowed_size.width * new_content_size.width
|
||||
/ content_size.width,
|
||||
(uint32_t) windowed_size.height * new_content_size.height
|
||||
/ content_size.height,
|
||||
};
|
||||
target_size = get_optimal_size(target_size, new_content_size);
|
||||
set_window_size(screen, target_size);
|
||||
|
||||
screen->frame_size = new_frame_size;
|
||||
screen->content_size = new_content_size;
|
||||
|
||||
LOGI("New texture: %" PRIu16 "x%" PRIu16,
|
||||
screen->frame_size.width, screen->frame_size.height);
|
||||
@@ -474,9 +478,7 @@ screen_switch_fullscreen(struct screen *screen) {
|
||||
}
|
||||
|
||||
screen->fullscreen = !screen->fullscreen;
|
||||
if (!screen->fullscreen && !screen->maximized) {
|
||||
apply_pending_resize(screen);
|
||||
}
|
||||
apply_windowed_size(screen);
|
||||
|
||||
LOGD("Switched to %s mode", screen->fullscreen ? "fullscreen" : "windowed");
|
||||
screen_render(screen);
|
||||
@@ -517,26 +519,6 @@ screen_resize_to_pixel_perfect(struct screen *screen) {
|
||||
content_size.height);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_fullscreen(const struct screen *screen) {
|
||||
uint32_t flags = SDL_GetWindowFlags(screen->window);
|
||||
return !!(flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP));
|
||||
}
|
||||
|
||||
static void
|
||||
update_fullscreen_state(struct screen *screen) {
|
||||
// There is no SDL event to detect fullscreen changes, so store the
|
||||
// state in a field and compare on every "size changed" event
|
||||
bool fullscreen = is_fullscreen(screen);
|
||||
if (fullscreen != screen->fullscreen) {
|
||||
// Fullscreen state have changed
|
||||
screen->fullscreen = fullscreen;
|
||||
if (!fullscreen && !screen->maximized) {
|
||||
apply_pending_resize(screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
screen_handle_window_event(struct screen *screen,
|
||||
const SDL_WindowEvent *event) {
|
||||
@@ -545,15 +527,36 @@ screen_handle_window_event(struct screen *screen,
|
||||
screen_render(screen);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_SIZE_CHANGED:
|
||||
update_fullscreen_state(screen);
|
||||
if (!screen->fullscreen && !screen->maximized) {
|
||||
// Backup the previous size: if we receive the MAXIMIZED event,
|
||||
// then the new size must be ignored (it's the maximized size).
|
||||
// We could not rely on the window flags due to race conditions
|
||||
// (they could be updated asynchronously, at least on X11).
|
||||
screen->windowed_window_size_backup =
|
||||
screen->windowed_window_size;
|
||||
|
||||
// Save the windowed size, so that it is available once the
|
||||
// window is maximized or fullscreen is enabled.
|
||||
screen->windowed_window_size = get_window_size(screen->window);
|
||||
}
|
||||
screen_render(screen);
|
||||
break;
|
||||
case SDL_WINDOWEVENT_MAXIMIZED:
|
||||
// The backup size must be non-nul.
|
||||
assert(screen->windowed_window_size_backup.width);
|
||||
assert(screen->windowed_window_size_backup.height);
|
||||
// Revert the last size, it was updated while screen was maximized.
|
||||
screen->windowed_window_size = screen->windowed_window_size_backup;
|
||||
#ifdef DEBUG
|
||||
// Reset the backup to invalid values to detect unexpected usage
|
||||
screen->windowed_window_size_backup.width = 0;
|
||||
screen->windowed_window_size_backup.height = 0;
|
||||
#endif
|
||||
screen->maximized = true;
|
||||
break;
|
||||
case SDL_WINDOWEVENT_RESTORED:
|
||||
screen->maximized = false;
|
||||
apply_pending_resize(screen);
|
||||
apply_windowed_size(screen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,11 @@ struct screen {
|
||||
struct sc_opengl gl;
|
||||
struct size frame_size;
|
||||
struct size content_size; // rotated frame_size
|
||||
|
||||
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)
|
||||
struct size windowed_content_size;
|
||||
|
||||
// The window size the last time it was not maximized or fullscreen.
|
||||
struct size windowed_window_size;
|
||||
// Since we receive the event SIZE_CHANGED before MAXIMIZED, we must be
|
||||
// able to revert the size to its non-maximized value.
|
||||
struct size windowed_window_size_backup;
|
||||
// client rotation: 0, 1, 2 or 3 (x90 degrees counterclockwise)
|
||||
unsigned rotation;
|
||||
bool has_frame;
|
||||
@@ -50,8 +49,11 @@ struct screen {
|
||||
.width = 0, \
|
||||
.height = 0, \
|
||||
}, \
|
||||
.resize_pending = false, \
|
||||
.windowed_content_size = { \
|
||||
.windowed_window_size = { \
|
||||
.width = 0, \
|
||||
.height = 0, \
|
||||
}, \
|
||||
.windowed_window_size_backup = { \
|
||||
.width = 0, \
|
||||
.height = 0, \
|
||||
}, \
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2008, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
oneway interface IOnPrimaryClipChangedListener {
|
||||
void dispatchPrimaryClipChanged();
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import com.genymobile.scrcpy.wrappers.ServiceManager;
|
||||
import com.genymobile.scrcpy.wrappers.SurfaceControl;
|
||||
import com.genymobile.scrcpy.wrappers.WindowManager;
|
||||
|
||||
import android.content.IOnPrimaryClipChangedListener;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
@@ -66,6 +67,14 @@ public final class Device {
|
||||
}
|
||||
}, displayId);
|
||||
|
||||
serviceManager.getClipboardManager().addPrimaryClipChangedListener(new IOnPrimaryClipChangedListener.Stub() {
|
||||
@Override
|
||||
public void dispatchPrimaryClipChanged() {
|
||||
String s = getClipboardText();
|
||||
Ln.i("clipboard changed = " + s);
|
||||
}
|
||||
});
|
||||
|
||||
if ((displayInfoFlags & DisplayInfo.FLAG_SUPPORTS_PROTECTED_BUFFERS) == 0) {
|
||||
Ln.w("Display doesn't have FLAG_SUPPORTS_PROTECTED_BUFFERS flag, mirroring can be restricted");
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ public class ScreenEncoder implements Device.RotationListener {
|
||||
}
|
||||
|
||||
private static IBinder createDisplay() {
|
||||
return SurfaceControl.createDisplay("scrcpy", true);
|
||||
return SurfaceControl.createDisplay("scrcpy", false);
|
||||
}
|
||||
|
||||
private static void configure(MediaCodec codec, MediaFormat format) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.genymobile.scrcpy.wrappers;
|
||||
import com.genymobile.scrcpy.Ln;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.IOnPrimaryClipChangedListener;
|
||||
import android.os.Build;
|
||||
import android.os.IInterface;
|
||||
|
||||
@@ -13,6 +14,7 @@ public class ClipboardManager {
|
||||
private final IInterface manager;
|
||||
private Method getPrimaryClipMethod;
|
||||
private Method setPrimaryClipMethod;
|
||||
private Method addPrimaryClipChangedListener;
|
||||
|
||||
public ClipboardManager(IInterface manager) {
|
||||
this.manager = manager;
|
||||
@@ -81,4 +83,37 @@ public class ClipboardManager {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void addPrimaryClipChangedListener(Method method, IInterface manager, IOnPrimaryClipChangedListener listener)
|
||||
throws InvocationTargetException, IllegalAccessException {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
method.invoke(manager, listener, ServiceManager.PACKAGE_NAME);
|
||||
} else {
|
||||
method.invoke(manager, listener, ServiceManager.PACKAGE_NAME, ServiceManager.USER_ID);
|
||||
}
|
||||
}
|
||||
|
||||
private Method getAddPrimaryClipChangedListener() throws NoSuchMethodException {
|
||||
if (addPrimaryClipChangedListener == null) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
addPrimaryClipChangedListener = manager.getClass()
|
||||
.getMethod("addPrimaryClipChangedListener", IOnPrimaryClipChangedListener.class, String.class);
|
||||
} else {
|
||||
addPrimaryClipChangedListener = manager.getClass()
|
||||
.getMethod("addPrimaryClipChangedListener", IOnPrimaryClipChangedListener.class, String.class, int.class);
|
||||
}
|
||||
}
|
||||
return addPrimaryClipChangedListener;
|
||||
}
|
||||
|
||||
public boolean addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
|
||||
try {
|
||||
Method method = getAddPrimaryClipChangedListener();
|
||||
addPrimaryClipChangedListener(method, manager, listener);
|
||||
return true;
|
||||
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||
Ln.e("Could not invoke method", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user