diff --git a/CMakeLists.txt b/CMakeLists.txt index 6690c6f2..977b71e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,8 @@ project(flutter-pi LANGUAGES C) message(STATUS "Generator .............. ${CMAKE_GENERATOR}") message(STATUS "Build Type ............. ${CMAKE_BUILD_TYPE}") +OPTION(OMXPLAYER_SUPPORTS_RUNTIME_ROTATION "Whether omxplayer supports runtime rotation." OFF) + if(NOT FLUTTER_EMBEDDER_HEADER) include(FetchContent) @@ -179,6 +181,9 @@ endif() if (BUILD_OMXPLAYER_VIDEO_PLAYER_PLUGIN) target_compile_definitions(flutter-pi PRIVATE "BUILD_OMXPLAYER_VIDEO_PLAYER_PLUGIN") endif() +if (OMXPLAYER_SUPPORTS_RUNTIME_ROTATION) + target_compile_definitions(flutter-pi PRIVATE "OMXPLAYER_SUPPORTS_RUNTIME_ROTATION") +endif() target_link_options(flutter-pi PRIVATE -rdynamic diff --git a/include/compositor.h b/include/compositor.h index 37cdbd6b..eb06a719 100644 --- a/include/compositor.h +++ b/include/compositor.h @@ -9,15 +9,12 @@ #include #include +struct platform_view_params; + typedef int (*platform_view_mount_cb)( int64_t view_id, struct drmdev_atomic_req *req, - const FlutterPlatformViewMutation **mutations, - size_t num_mutations, - int offset_x, - int offset_y, - int width, - int height, + const struct platform_view_params *params, int zpos, void *userdata ); @@ -31,12 +28,7 @@ typedef int (*platform_view_unmount_cb)( typedef int (*platform_view_update_view_cb)( int64_t view_id, struct drmdev_atomic_req *req, - const FlutterPlatformViewMutation **mutations, - size_t num_mutations, - int offset_x, - int offset_y, - int width, - int height, + const struct platform_view_params *params, int zpos, void *userdata ); @@ -44,16 +36,75 @@ typedef int (*platform_view_update_view_cb)( typedef int (*platform_view_present_cb)( int64_t view_id, struct drmdev_atomic_req *req, - const FlutterPlatformViewMutation **mutations, - size_t num_mutations, - int offset_x, - int offset_y, - int width, - int height, + const struct platform_view_params *params, int zpos, void *userdata ); +struct point { + double x, y; +}; + +struct quad { + struct point top_left, top_right, bottom_left, bottom_right; +}; + +struct aa_rect { + struct point offset, size; +}; + +static inline struct aa_rect get_aa_bounding_rect(const struct quad _rect) { + double l = min(min(min(_rect.top_left.x, _rect.top_right.x), _rect.bottom_left.x), _rect.bottom_right.x); + double r = max(max(max(_rect.top_left.x, _rect.top_right.x), _rect.bottom_left.x), _rect.bottom_right.x); + double t = min(min(min(_rect.top_left.y, _rect.top_right.y), _rect.bottom_left.y), _rect.bottom_right.y); + double b = max(max(max(_rect.top_left.y, _rect.top_right.y), _rect.bottom_left.y), _rect.bottom_right.y); + + return (struct aa_rect) { + .offset.x = l, + .offset.y = t, + .size.x = r - l, + .size.y = b - t + }; +} + +static inline struct quad get_quad(const struct aa_rect rect) { + return (struct quad) { + .top_left = rect.offset, + .top_right.x = rect.offset.x + rect.size.x, + .top_right.y = rect.offset.y, + .bottom_left.x = rect.offset.x, + .bottom_left.y = rect.offset.y + rect.size.y, + .bottom_right.x = rect.offset.x + rect.size.x, + .bottom_right.y = rect.offset.y + rect.size.y + }; +} + +static inline void apply_transform_to_point(const FlutterTransformation transform, struct point *point) { + apply_flutter_transformation(transform, &point->x, &point->y); +} + +static inline void apply_transform_to_quad(const FlutterTransformation transform, struct quad *rect) { + apply_transform_to_point(transform, &rect->top_left); + apply_transform_to_point(transform, &rect->top_right); + apply_transform_to_point(transform, &rect->bottom_left); + apply_transform_to_point(transform, &rect->bottom_right); +} + +static inline struct quad apply_transform_to_aa_rect(const FlutterTransformation transform, const struct aa_rect rect) { + struct quad _quad = get_quad(rect); + apply_transform_to_quad(transform, &_quad); + return _quad; +} + + +struct platform_view_params { + struct quad rect; + double rotation; + struct clip_rect *clip_rects; + size_t n_clip_rects; + double opacity; +}; + struct compositor { struct drmdev *drmdev; diff --git a/include/plugins/omxplayer_video_player.h b/include/plugins/omxplayer_video_player.h index 7e8fdac1..a8b4ca36 100644 --- a/include/plugins/omxplayer_video_player.h +++ b/include/plugins/omxplayer_video_player.h @@ -60,18 +60,22 @@ struct omxplayer_mgr_task { union { struct { int orientation; - char *omxplayer_dbus_name; - bool omxplayer_online; + union { + struct { + char *omxplayer_dbus_name; + bool omxplayer_online; + }; + struct { + bool visible; + int offset_x, offset_y; + int width, height; + int zpos; + }; + }; }; bool loop; float volume; int64_t position; - struct { - bool visible; - int offset_x, offset_y; - int width, height; - int zpos; - }; }; }; diff --git a/src/compositor.c b/src/compositor.c index 57d04b57..005559a6 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -1,6 +1,8 @@ +#define _GNU_SOURCE #include #include #include +#include #include #include @@ -935,6 +937,89 @@ static int execute_simulate_page_flip_event(void *userdata) { return 0; } +static void fill_platform_view_params( + struct platform_view_params *params_out, + const FlutterPoint *offset, + const FlutterSize *size, + const FlutterPlatformViewMutation **mutations, + size_t n_mutations, + const FlutterTransformation *display_to_view_transform, + const FlutterTransformation *view_to_display_transform, + double device_pixel_ratio +) { + /** + * inversion for + * ``` + * const auto transformed_layer_bounds = + * root_surface_transformation_.mapRect(layer_bounds); + * ``` + */ + + struct quad quad = apply_transform_to_aa_rect( + *display_to_view_transform, + (struct aa_rect) { + .offset.x = offset->x, + .offset.y = offset->y, + .size.x = size->width, + .size.y = size->height + } + ); + + struct aa_rect rect = get_aa_bounding_rect(quad); + + /** + * inversion for + * ``` + * const auto layer_bounds = + * SkRect::MakeXYWH(params.finalBoundingRect().x(), + * params.finalBoundingRect().y(), + * params.sizePoints().width() * device_pixel_ratio_, + * params.sizePoints().height() * device_pixel_ratio_ + * ); + * ``` + */ + + rect.size.x /= device_pixel_ratio; + rect.size.y /= device_pixel_ratio; + + // okay, now we have the params.finalBoundingRect().x() in aa_back_transformed.x and + // params.finalBoundingRect().y() in aa_back_transformed.y. + // those are flutter view coordinates, so we still need to transform them to display coordinates. + + // However, there are also calculated as a side-product of calculating the size of the quadrangle. + // So we'll avoid calculating them for now. Calculation of the size may fail when the offset + // given to `SceneBuilder.addPlatformView` (https://api.flutter.dev/flutter/dart-ui/SceneBuilder/addPlatformView.html) + // is not zero. (Don't really know what to do in that case) + + rect.offset.x = 0; + rect.offset.y = 0; + quad = get_quad(rect); + + double rotation = 0, opacity = 1; + for (int i = n_mutations - 1; i >= 0; i--) { + if (mutations[i]->type == kFlutterPlatformViewMutationTypeTransformation) { + apply_transform_to_quad(mutations[i]->transformation, &quad); + + double rotz = atan2(mutations[i]->transformation.skewX, mutations[i]->transformation.scaleX) * 180.0 / M_PI; + if (rotz < 0) { + rotz += 360; + } + + rotation += rotz; + } else if (mutations[i]->type == kFlutterPlatformViewMutationTypeOpacity) { + opacity *= mutations[i]->opacity; + } + } + + rotation = fmod(rotation, 360.0); + + params_out->rect = quad; + params_out->opacity = 0; + params_out->rotation = rotation; + params_out->clip_rects = NULL; + params_out->n_clip_rects = 0; +} + /// PRESENT FUNCS static bool on_present_layers( const FlutterLayer **layers, @@ -1125,6 +1210,8 @@ static bool on_present_layers( if (ok != 0) { fprintf(stderr, "[compositor] Could not unmount platform view. unmount: %s\n", strerror(ok)); } + + cb_data->was_present_last_frame = false; } } @@ -1141,15 +1228,22 @@ static bool on_present_layers( } } + struct platform_view_params params; + fill_platform_view_params( + ¶ms, + &layer->offset, + &layer->size, + layer->platform_view->mutations, + layer->platform_view->mutations_count, + &flutterpi.view.display_to_view_transform, + &flutterpi.view.view_to_display_transform, + flutterpi.display.pixel_ratio + ); + ok = cb_data->update_view( cb_data->view_id, req, - layer->platform_view->mutations, - layer->platform_view->mutations_count, - (int) round(layer->offset.x), - (int) round(layer->offset.y), - (int) round(layer->size.width), - (int) round(layer->size.height), + ¶ms, zpos, cb_data->userdata ); @@ -1179,16 +1273,23 @@ static bool on_present_layers( } } + struct platform_view_params params; + fill_platform_view_params( + ¶ms, + &layer->offset, + &layer->size, + layer->platform_view->mutations, + layer->platform_view->mutations_count, + &flutterpi.view.display_to_view_transform, + &flutterpi.view.view_to_display_transform, + flutterpi.display.pixel_ratio + ); + if (cb_data->mount != NULL) { ok = cb_data->mount( layer->platform_view->identifier, req, - layer->platform_view->mutations, - layer->platform_view->mutations_count, - (int) round(layer->offset.x), - (int) round(layer->offset.y), - (int) round(layer->size.width), - (int) round(layer->size.height), + ¶ms, zpos, cb_data->userdata ); @@ -1197,6 +1298,7 @@ static bool on_present_layers( } } + cb_data->was_present_last_frame = true; cb_data->last_zpos = zpos; cb_data->last_size = layer->size; cb_data->last_offset = layer->offset; @@ -1299,15 +1401,22 @@ static bool on_present_layers( cb_data = get_cbs_for_view_id_locked(layers[i]->platform_view->identifier); if ((cb_data != NULL) && (cb_data->present != NULL)) { + struct platform_view_params params; + fill_platform_view_params( + ¶ms, + &layers[i]->offset, + &layers[i]->size, + layers[i]->platform_view->mutations, + layers[i]->platform_view->mutations_count, + &flutterpi.view.display_to_view_transform, + &flutterpi.view.view_to_display_transform, + flutterpi.display.pixel_ratio + ); + ok = cb_data->present( cb_data->view_id, req, - layers[i]->platform_view->mutations, - layers[i]->platform_view->mutations_count, - (int) round(layers[i]->offset.x), - (int) round(layers[i]->offset.y), - (int) round(layers[i]->size.width), - (int) round(layers[i]->size.height), + ¶ms, i + min_zpos, cb_data->userdata ); diff --git a/src/flutter-pi.c b/src/flutter-pi.c index 670c7cdf..0378ff3b 100644 --- a/src/flutter-pi.c +++ b/src/flutter-pi.c @@ -439,7 +439,7 @@ static void on_frame_request( return; } - if (reply_instantly) { + if (reply_instantly) { flutterpi_post_platform_task( on_execute_frame_request, NULL @@ -1888,569 +1888,6 @@ int flutterpi_schedule_exit(void) { return 0; } -/************** - * USER INPUT * - **************/ -/* -static int libinput_interface_on_open(const char *path, int flags, void *userdata) { - return open(path, flags | O_CLOEXEC); -} - -static void libinput_interface_on_close(int fd, void *userdata) { - close(fd); -} - -const struct libinput_interface flutterpi_libinput_interface = { - .open_restricted = libinput_interface_on_open, - .close_restricted = libinput_interface_on_close -}; - -static int on_libinput_ready(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - struct libinput_event_keyboard *keyboard_event; - struct libinput_event_pointer *pointer_event; - struct libinput_event_touch *touch_event; - struct input_device_data *data; - enum libinput_event_type type; - struct libinput_device *device; - struct libinput_event *event; - FlutterPointerEvent pointer_events[64]; - FlutterEngineResult result; - int n_pointer_events = 0; - int ok; - - ok = libinput_dispatch(flutterpi.input.libinput); - if (ok < 0) { - fprintf(stderr, "[flutter-pi] Could not dispatch libinput events. libinput_dispatch: %s\n", strerror(-ok)); - return -ok; - } - - while (event = libinput_get_event(flutterpi.input.libinput), event != NULL) { - type = libinput_event_get_type(event); - - if (type == LIBINPUT_EVENT_DEVICE_ADDED) { - device = libinput_event_get_device(event); - - data = calloc(1, sizeof(*data)); - data->flutter_device_id_offset = flutterpi.input.next_unused_flutter_device_id; - - libinput_device_set_user_data(device, data); - - if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER)) { - pointer_events[n_pointer_events++] = (FlutterPointerEvent) { - .struct_size = sizeof(FlutterPointerEvent), - .phase = kAdd, - .timestamp = flutterpi.flutter.libflutter_engine.FlutterEngineGetCurrentTime(), - .x = 0.0, - .y = 0.0, - .device = flutterpi.input.next_unused_flutter_device_id++, - .signal_kind = kFlutterPointerSignalKindNone, - .scroll_delta_x = 0.0, - .scroll_delta_y = 0.0, - .device_kind = kFlutterPointerDeviceKindMouse, - .buttons = 0 - }; - - compositor_apply_cursor_state(true, flutterpi.view.rotation, flutterpi.display.pixel_ratio); - } else if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH)) { - int touch_count = libinput_device_touch_get_touch_count(device); - - for (int i = 0; i < touch_count; i++) { - pointer_events[n_pointer_events++] = (FlutterPointerEvent) { - .struct_size = sizeof(FlutterPointerEvent), - .phase = kAdd, - .timestamp = flutterpi.flutter.libflutter_engine.FlutterEngineGetCurrentTime(), - .x = 0.0, - .y = 0.0, - .device = flutterpi.input.next_unused_flutter_device_id++, - .signal_kind = kFlutterPointerSignalKindNone, - .scroll_delta_x = 0.0, - .scroll_delta_y = 0.0, - .device_kind = kFlutterPointerDeviceKindTouch, - .buttons = 0 - }; - } - } else if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD)) { -#if BUILD_TEXT_INPUT_PLUGIN || BUILD_RAW_KEYBOARD_PLUGIN - if ((flutterpi.input.disable_text_input == false) && (flutterpi.input.keyboard_config != NULL)) { - data->keyboard_state = keyboard_state_new(flutterpi.input.keyboard_config, NULL, NULL); - } -#endif - } - } else if (type == LIBINPUT_EVENT_DEVICE_REMOVED) { - device = libinput_event_get_device(event); - data = libinput_device_get_user_data(device); - - if (data) { - if (data->keyboard_state) { - free(data->keyboard_state); - } - free(data); - } - - libinput_device_set_user_data(device, NULL); - } else if (LIBINPUT_EVENT_IS_TOUCH(type)) { - touch_event = libinput_event_get_touch_event(event); - data = libinput_device_get_user_data(libinput_event_get_device(event)); - - if ((type == LIBINPUT_EVENT_TOUCH_DOWN) || (type == LIBINPUT_EVENT_TOUCH_MOTION) || (type == LIBINPUT_EVENT_TOUCH_UP)) { - int slot = libinput_event_touch_get_slot(touch_event); - if (slot < 0) { - slot = 0; - } - - if ((type == LIBINPUT_EVENT_TOUCH_DOWN) || (type == LIBINPUT_EVENT_TOUCH_MOTION)) { - double x = libinput_event_touch_get_x_transformed(touch_event, flutterpi.display.width); - double y = libinput_event_touch_get_y_transformed(touch_event, flutterpi.display.height); - - apply_flutter_transformation(flutterpi.view.display_to_view_transform, &x, &y); - - FlutterPointerPhase phase; - if (type == LIBINPUT_EVENT_TOUCH_DOWN) { - phase = kDown; - } else if (type == LIBINPUT_EVENT_TOUCH_MOTION) { - phase = kMove; - } - - pointer_events[n_pointer_events++] = (FlutterPointerEvent) { - .struct_size = sizeof(FlutterPointerEvent), - .phase = phase, - .timestamp = libinput_event_touch_get_time_usec(touch_event), - .x = x, - .y = y, - .device = data->flutter_device_id_offset + slot, - .signal_kind = kFlutterPointerSignalKindNone, - .scroll_delta_x = 0.0, - .scroll_delta_y = 0.0, - .device_kind = kFlutterPointerDeviceKindTouch, - .buttons = 0 - }; - - data->x = x; - data->y = y; - data->timestamp = libinput_event_touch_get_time_usec(touch_event); - } else { - pointer_events[n_pointer_events++] = (FlutterPointerEvent) { - .struct_size = sizeof(FlutterPointerEvent), - .phase = kUp, - .timestamp = libinput_event_touch_get_time_usec(touch_event), - .x = data->x, - .y = data->y, - .device = data->flutter_device_id_offset + slot, - .signal_kind = kFlutterPointerSignalKindNone, - .scroll_delta_x = 0.0, - .scroll_delta_y = 0.0, - .device_kind = kFlutterPointerDeviceKindTouch, - .buttons = 0 - }; - } - } - } else if (LIBINPUT_EVENT_IS_POINTER(type)) { - pointer_event = libinput_event_get_pointer_event(event); - data = libinput_device_get_user_data(libinput_event_get_device(event)); - - if (type == LIBINPUT_EVENT_POINTER_MOTION) { - double dx = libinput_event_pointer_get_dx(pointer_event); - double dy = libinput_event_pointer_get_dy(pointer_event); - - data->timestamp = libinput_event_pointer_get_time_usec(pointer_event); - - apply_flutter_transformation(FLUTTER_ROTZ_TRANSFORMATION(flutterpi.view.rotation), &dx, &dy); - - double newx = flutterpi.input.cursor_x + dx; - double newy = flutterpi.input.cursor_y + dy; - - if (newx < 0) { - newx = 0; - } else if (newx > flutterpi.display.width - 1) { - newx = flutterpi.display.width - 1; - } - - if (newy < 0) { - newy = 0; - } else if (newy > flutterpi.display.height - 1) { - newy = flutterpi.display.height - 1; - } - - flutterpi.input.cursor_x = newx; - flutterpi.input.cursor_y = newy; - - apply_flutter_transformation(flutterpi.view.display_to_view_transform, &newx, &newy); - - pointer_events[n_pointer_events++] = (FlutterPointerEvent) { - .struct_size = sizeof(FlutterPointerEvent), - .phase = data->buttons & kFlutterPointerButtonMousePrimary ? kMove : kHover, - .timestamp = libinput_event_pointer_get_time_usec(pointer_event), - .x = newx, - .y = newy, - .device = data->flutter_device_id_offset, - .signal_kind = kFlutterPointerSignalKindNone, - .scroll_delta_x = 0.0, - .scroll_delta_y = 0.0, - .device_kind = kFlutterPointerDeviceKindMouse, - .buttons = data->buttons - }; - - compositor_set_cursor_pos(round(flutterpi.input.cursor_x), round(flutterpi.input.cursor_y)); - } else if (type == LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE) { - double x = libinput_event_pointer_get_absolute_x_transformed(pointer_event, flutterpi.display.width); - double y = libinput_event_pointer_get_absolute_y_transformed(pointer_event, flutterpi.display.height); - - flutterpi.input.cursor_x = x; - flutterpi.input.cursor_y = y; - - data->x = x; - data->y = y; - data->timestamp = libinput_event_pointer_get_time_usec(pointer_event); - - apply_flutter_transformation(flutterpi.view.display_to_view_transform, &x, &y); - - pointer_events[n_pointer_events++] = (FlutterPointerEvent) { - .struct_size = sizeof(FlutterPointerEvent), - .phase = data->buttons & kFlutterPointerButtonMousePrimary ? kMove : kHover, - .timestamp = libinput_event_pointer_get_time_usec(pointer_event), - .x = x, - .y = y, - .device = data->flutter_device_id_offset, - .signal_kind = kFlutterPointerSignalKindNone, - .scroll_delta_x = 0.0, - .scroll_delta_y = 0.0, - .device_kind = kFlutterPointerDeviceKindMouse, - .buttons = data->buttons - }; - - compositor_set_cursor_pos((int) round(x), (int) round(y)); - } else if (type == LIBINPUT_EVENT_POINTER_BUTTON) { - uint32_t button = libinput_event_pointer_get_button(pointer_event); - enum libinput_button_state button_state = libinput_event_pointer_get_button_state(pointer_event); - - int64_t flutter_button = 0; - if (button == BTN_LEFT) { - flutter_button = kFlutterPointerButtonMousePrimary; - } else if (button == BTN_RIGHT) { - flutter_button = kFlutterPointerButtonMouseSecondary; - } else if (button == BTN_MIDDLE) { - flutter_button = kFlutterPointerButtonMouseMiddle; - } else if (button == BTN_BACK) { - flutter_button = kFlutterPointerButtonMouseBack; - } else if (button == BTN_FORWARD) { - flutter_button = kFlutterPointerButtonMouseForward; - } - - int64_t new_flutter_button_state = data->buttons; - if (button_state == LIBINPUT_BUTTON_STATE_RELEASED) { - new_flutter_button_state &= ~flutter_button; - } else { - new_flutter_button_state |= flutter_button; - } - - if (new_flutter_button_state != data->buttons) { - FlutterPointerPhase phase; - if (new_flutter_button_state == 0) { - phase = kUp; - } else if (data->buttons == 0) { - phase = kDown; - } else { - phase = kMove; - } - - double x = flutterpi.input.cursor_x; - double y = flutterpi.input.cursor_y; - - apply_flutter_transformation(flutterpi.view.display_to_view_transform, &x, &y); - - pointer_events[n_pointer_events++] = (FlutterPointerEvent) { - .struct_size = sizeof(FlutterPointerEvent), - .phase = phase, - .timestamp = libinput_event_pointer_get_time_usec(pointer_event), - .x = x, - .y = y, - .device = data->flutter_device_id_offset, - .signal_kind = kFlutterPointerSignalKindNone, - .scroll_delta_x = 0.0, - .scroll_delta_y = 0.0, - .device_kind = kFlutterPointerDeviceKindMouse, - .buttons = new_flutter_button_state - }; - - data->buttons = new_flutter_button_state; - } - } else if (type == LIBINPUT_EVENT_POINTER_AXIS) { - - } - } else if (LIBINPUT_EVENT_IS_KEYBOARD(type) && !flutterpi.input.disable_text_input && (data->keyboard_state != NULL)) { -#if BUILD_RAW_KEYBOARD_PLUGIN || BUILD_TEXT_INPUT_PLUGIN - struct keyboard_modifier_state mods; - enum libinput_key_state key_state; - xkb_keysym_t keysym; - uint32_t codepoint, plain_codepoint; - uint16_t evdev_keycode; - - keyboard_event = libinput_event_get_keyboard_event(event); - data = libinput_device_get_user_data(libinput_event_get_device(event)); - evdev_keycode = libinput_event_keyboard_get_key(keyboard_event); - key_state = libinput_event_keyboard_get_key_state(keyboard_event); - - mods = keyboard_state_get_meta_state(data->keyboard_state); - - ok = keyboard_state_process_key_event( - data->keyboard_state, - evdev_keycode, - (int32_t) key_state, - &keysym, - &codepoint - ); - - plain_codepoint = keyboard_state_get_plain_codepoint(data->keyboard_state, evdev_keycode, 1); - -#ifdef BUILD_RAW_KEYBOARD_PLUGIN - rawkb_send_gtk_keyevent( - plain_codepoint, - (uint32_t) keysym, - evdev_keycode + 8, - keyboard_state_is_shift_active(data->keyboard_state) - | (keyboard_state_is_capslock_active(data->keyboard_state) << 1) - | (keyboard_state_is_ctrl_active(data->keyboard_state) << 2) - | (keyboard_state_is_alt_active(data->keyboard_state) << 3) - | (keyboard_state_is_numlock_active(data->keyboard_state) << 4) - | (keyboard_state_is_meta_active(data->keyboard_state) << 28), - key_state - ); -#endif - -#ifdef BUILD_TEXT_INPUT_PLUGIN - if (codepoint) { - if (codepoint < 0x80) { - if (isprint(codepoint)) { - textin_on_utf8_char((uint8_t[1]) {codepoint}); - } - } else if (codepoint < 0x800) { - textin_on_utf8_char((uint8_t[2]) { - 0xc0 | (codepoint >> 6), - 0x80 | (codepoint & 0x3f) - }); - } else if (codepoint < 0x10000) { - if (!(codepoint >= 0xD800 && codepoint < 0xE000) && !(codepoint == 0xFFFF)) { - textin_on_utf8_char((uint8_t[3]) { - 0xe0 | (codepoint >> 12), - 0x80 | ((codepoint >> 6) & 0x3f), - 0x80 | (codepoint & 0x3f) - }); - } - } else if (codepoint < 0x110000) { - textin_on_utf8_char((uint8_t[4]) { - 0xf0 | (codepoint >> 18), - 0x80 | ((codepoint >> 12) & 0x3f), - 0x80 | ((codepoint >> 6) & 0x3f), - 0x80 | (codepoint & 0x3f) - }); - } - } - - if (keysym) { - textin_on_xkb_keysym(keysym); - } -#endif -#endif - } - - libinput_event_destroy(event); - event = NULL; - } - - if (n_pointer_events > 0) { - result = flutterpi.flutter.libflutter_engine.FlutterEngineSendPointerEvent( - flutterpi.flutter.engine, - pointer_events, - n_pointer_events - ); - if (result != kSuccess) { - fprintf(stderr, "[flutter-pi] Could not add mouse as flutter input device. FlutterEngineSendPointerEvent: %s\n", FLUTTER_RESULT_TO_STRING(result)); - } - } - - return 0; -} - -static struct libinput *try_create_udev_backed_libinput(void) { -#ifdef BUILD_WITHOUT_UDEV_SUPPORT - return NULL; -#else - struct libinput *libinput; - struct libudev *libudev; - struct udev *udev; - int ok; - - void *handle = dlopen("libudev.so", RTLD_LAZY | RTLD_NOW); - if (handle == NULL) { - printf("[flutter-pi] Could not open libudev. Flutter-pi will run without hotplugging support.\n"); - return NULL; - } - - libudev = &flutterpi.input.libudev; - -# define LOAD_LIBUDEV_PROC(name) \ - do { \ - libudev->name = dlsym(handle, #name); \ - if (!libudev->name) {\ - perror("[flutter-pi] Could not resolve libudev procedure " #name ". dlsym"); \ - return NULL; \ - } \ - } while (false) - - LOAD_LIBUDEV_PROC(udev_ref); - LOAD_LIBUDEV_PROC(udev_unref); - LOAD_LIBUDEV_PROC(udev_new); - LOAD_LIBUDEV_PROC(udev_get_userdata); - LOAD_LIBUDEV_PROC(udev_set_userdata); - - LOAD_LIBUDEV_PROC(udev_list_entry_get_next); - LOAD_LIBUDEV_PROC(udev_list_entry_get_by_name); - LOAD_LIBUDEV_PROC(udev_list_entry_get_name); - LOAD_LIBUDEV_PROC(udev_list_entry_get_value); - - LOAD_LIBUDEV_PROC(udev_device_ref); - LOAD_LIBUDEV_PROC(udev_device_unref); - LOAD_LIBUDEV_PROC(udev_device_get_udev); - LOAD_LIBUDEV_PROC(udev_device_new_from_syspath); - LOAD_LIBUDEV_PROC(udev_device_new_from_devnum); - LOAD_LIBUDEV_PROC(udev_device_new_from_subsystem_sysname); - LOAD_LIBUDEV_PROC(udev_device_new_from_device_id); - LOAD_LIBUDEV_PROC(udev_device_new_from_environment); - LOAD_LIBUDEV_PROC(udev_device_get_parent); - LOAD_LIBUDEV_PROC(udev_device_get_parent_with_subsystem_devtype); - LOAD_LIBUDEV_PROC(udev_device_get_devpath); - LOAD_LIBUDEV_PROC(udev_device_get_subsystem); - LOAD_LIBUDEV_PROC(udev_device_get_devtype); - LOAD_LIBUDEV_PROC(udev_device_get_syspath); - LOAD_LIBUDEV_PROC(udev_device_get_sysname); - LOAD_LIBUDEV_PROC(udev_device_get_sysnum); - LOAD_LIBUDEV_PROC(udev_device_get_devnode); - LOAD_LIBUDEV_PROC(udev_device_get_is_initialized); - LOAD_LIBUDEV_PROC(udev_device_get_devlinks_list_entry); - LOAD_LIBUDEV_PROC(udev_device_get_properties_list_entry); - LOAD_LIBUDEV_PROC(udev_device_get_tags_list_entry); - LOAD_LIBUDEV_PROC(udev_device_get_sysattr_list_entry); - LOAD_LIBUDEV_PROC(udev_device_get_property_value); - LOAD_LIBUDEV_PROC(udev_device_get_driver); - LOAD_LIBUDEV_PROC(udev_device_get_devnum); - LOAD_LIBUDEV_PROC(udev_device_get_action); - LOAD_LIBUDEV_PROC(udev_device_get_seqnum); - LOAD_LIBUDEV_PROC(udev_device_get_usec_since_initialized); - LOAD_LIBUDEV_PROC(udev_device_get_sysattr_value); - LOAD_LIBUDEV_PROC(udev_device_set_sysattr_value); - LOAD_LIBUDEV_PROC(udev_device_has_tag); - - LOAD_LIBUDEV_PROC(udev_monitor_ref); - LOAD_LIBUDEV_PROC(udev_monitor_unref); - LOAD_LIBUDEV_PROC(udev_monitor_get_udev); - LOAD_LIBUDEV_PROC(udev_monitor_new_from_netlink); - LOAD_LIBUDEV_PROC(udev_monitor_enable_receiving); - LOAD_LIBUDEV_PROC(udev_monitor_set_receive_buffer_size); - LOAD_LIBUDEV_PROC(udev_monitor_get_fd); - LOAD_LIBUDEV_PROC(udev_monitor_receive_device); - LOAD_LIBUDEV_PROC(udev_monitor_filter_add_match_subsystem_devtype); - LOAD_LIBUDEV_PROC(udev_monitor_filter_add_match_tag); - LOAD_LIBUDEV_PROC(udev_monitor_filter_update); - LOAD_LIBUDEV_PROC(udev_monitor_filter_remove); - - LOAD_LIBUDEV_PROC(udev_enumerate_ref); - LOAD_LIBUDEV_PROC(udev_enumerate_unref); - LOAD_LIBUDEV_PROC(udev_enumerate_get_udev); - LOAD_LIBUDEV_PROC(udev_enumerate_new); - LOAD_LIBUDEV_PROC(udev_enumerate_add_match_subsystem); - LOAD_LIBUDEV_PROC(udev_enumerate_add_nomatch_subsystem); - LOAD_LIBUDEV_PROC(udev_enumerate_add_match_sysattr); - LOAD_LIBUDEV_PROC(udev_enumerate_add_nomatch_sysattr); - LOAD_LIBUDEV_PROC(udev_enumerate_add_match_property); - LOAD_LIBUDEV_PROC(udev_enumerate_add_match_sysname); - LOAD_LIBUDEV_PROC(udev_enumerate_add_match_tag); - LOAD_LIBUDEV_PROC(udev_enumerate_add_match_parent); - LOAD_LIBUDEV_PROC(udev_enumerate_add_match_is_initialized); - LOAD_LIBUDEV_PROC(udev_enumerate_add_syspath); - LOAD_LIBUDEV_PROC(udev_enumerate_scan_devices); - LOAD_LIBUDEV_PROC(udev_enumerate_scan_subsystems); - LOAD_LIBUDEV_PROC(udev_enumerate_get_list_entry); - - LOAD_LIBUDEV_PROC(udev_queue_ref); - LOAD_LIBUDEV_PROC(udev_queue_unref); - LOAD_LIBUDEV_PROC(udev_queue_get_udev); - LOAD_LIBUDEV_PROC(udev_queue_new); - LOAD_LIBUDEV_PROC(udev_queue_get_udev_is_active); - LOAD_LIBUDEV_PROC(udev_queue_get_queue_is_empty); - LOAD_LIBUDEV_PROC(udev_queue_get_fd); - LOAD_LIBUDEV_PROC(udev_queue_flush); - - LOAD_LIBUDEV_PROC(udev_hwdb_new); - LOAD_LIBUDEV_PROC(udev_hwdb_ref); - LOAD_LIBUDEV_PROC(udev_hwdb_unref); - LOAD_LIBUDEV_PROC(udev_hwdb_get_properties_list_entry); - - LOAD_LIBUDEV_PROC(udev_util_encode_string); - -# undef LOAD_LIBUDEV_PROC - - udev = libudev->udev_new(); - if (udev == NULL) { - perror("[flutter-pi] Could not create udev instance. udev_new"); - return NULL; - } - - libinput = libinput_udev_create_context( - &flutterpi_libinput_interface, - udev, - udev - ); - if (libinput == NULL) { - perror("[flutter-pi] Could not create libinput instance. libinput_udev_create_context"); - libudev->udev_unref(udev); - return NULL; - } - - ok = libinput_udev_assign_seat(libinput, "seat0"); - if (ok < 0) { - fprintf(stderr, "[flutter-pi] Could not assign udev seat to libinput instance. libinput_udev_assign_seat: %s\n", strerror(-ok)); - libinput_unref(libinput); - libudev->udev_unref(udev); - return NULL; - } - - return libinput; - -#endif -} - -static struct libinput *try_create_path_backed_libinput(void) { - struct libinput_device *dev; - struct libinput *libinput; - - libinput = libinput_path_create_context( - &flutterpi_libinput_interface, - NULL - ); - if (libinput == NULL) { - perror("[flutter-pi] Could not create path-backed libinput instance. libinput_path_create_context"); - return NULL; - } - - for (int i = 0; i < flutterpi.input.input_devices_glob.gl_pathc; i++) { - dev = libinput_path_add_device( - libinput, - flutterpi.input.input_devices_glob.gl_pathv[i] - ); - if (dev == NULL) { - fprintf( - stderr, - "[flutter-pi] Could not add input device \"%s\" to libinput. libinput_path_add_device: %s\n", - flutterpi.input.input_devices_glob.gl_pathv[i], - strerror(errno) - ); - } - } - - return libinput; -} -*/ - /************** * USER INPUT * **************/ diff --git a/src/plugins/omxplayer_video_player.c b/src/plugins/omxplayer_video_player.c index 7f5971cb..a372bd46 100644 --- a/src/plugins/omxplayer_video_player.c +++ b/src/plugins/omxplayer_video_player.c @@ -1,6 +1,5 @@ -#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE <= 200809L -# define _POSIX_C_SOURCE 200809L -#endif +#define _GNU_SOURCE + #include #include #include @@ -8,6 +7,7 @@ #include #include #include +#include #include #include @@ -161,17 +161,26 @@ static int get_player_from_map_arg( return 0; } +static int get_orientation_from_rotation(double rotation) { + if ((rotation <= 45) || (rotation > 315)) { + rotation = 0; + } else if (rotation <= 135) { + rotation = 90; + } else if (rotation <= 225) { + rotation = 180; + } else if (rotation <= 315) { + rotation = 270; + } + + return rotation; +} + /// Called on the flutter rasterizer thread when a players platform view is presented /// for the first time after it was unmounted or initialized. static int on_mount( int64_t view_id, struct drmdev_atomic_req *req, - const FlutterPlatformViewMutation **mutations, - size_t num_mutations, - int offset_x, - int offset_y, - int width, - int height, + const struct platform_view_params *params, int zpos, void *userdata ) { @@ -181,16 +190,20 @@ static int on_mount( zpos = -126; } + + struct aa_rect rect = get_aa_bounding_rect(params->rect); + return cqueue_enqueue( &player->mgr->task_queue, &(struct omxplayer_mgr_task) { .type = kUpdateView, .responsehandle = NULL, - .offset_x = offset_x, - .offset_y = offset_y, - .width = width, - .height = height, - .zpos = zpos + .offset_x = rect.offset.x, + .offset_y = rect.offset.y, + .width = rect.size.x, + .height = rect.size.y, + .zpos = zpos, + .orientation = get_orientation_from_rotation(params->rotation) } ); } @@ -222,12 +235,7 @@ static int on_unmount( static int on_update_view( int64_t view_id, struct drmdev_atomic_req *req, - const FlutterPlatformViewMutation **mutations, - size_t num_mutations, - int offset_x, - int offset_y, - int width, - int height, + const struct platform_view_params *params, int zpos, void *userdata ) { @@ -237,16 +245,19 @@ static int on_update_view( zpos = -126; } + struct aa_rect rect = get_aa_bounding_rect(params->rect); + return cqueue_enqueue( &player->mgr->task_queue, &(struct omxplayer_mgr_task) { .type = kUpdateView, .responsehandle = NULL, - .offset_x = offset_x, - .offset_y = offset_y, - .width = width, - .height = height, - .zpos = zpos + .offset_x = rect.offset.x, + .offset_y = rect.offset.y, + .width = rect.size.x, + .height = rect.size.y, + .zpos = zpos, + .orientation = get_orientation_from_rotation(params->rotation) } ); } @@ -280,8 +291,12 @@ static int get_dbus_property( void *ret_ptr ) { sd_bus_message *msg; + bool n_retries; int ok; + n_retries = 0; + + retry: ok = sd_bus_call_method( bus, destination, @@ -294,7 +309,10 @@ static int get_dbus_property( interface, member ); - if (ok < 0) { + /*if ((ok < 0) && (strcmp(ret_error->name, SD_BUS_ERROR_UNKNOWN_METHOD) == 0) && (n_retries < 10)) { + n_retries++; + goto retry; + } else */if (ok < 0) { fprintf(stderr, "[omxplayer_video_player plugin] Could not read DBus property: %s, %s\n", ret_error->name, ret_error->message); return -ok; } @@ -355,7 +373,7 @@ static void *mgr_entry(void *userdata) { sd_bus_message *msg; sd_bus_error err; sd_bus_slot *slot; - int64_t duration_us, video_width, video_height, current_zpos; + int64_t duration_us, video_width, video_height, current_zpos, current_orientation; sd_bus *bus; pid_t omxplayer_pid; char dbus_name[256]; @@ -442,6 +460,7 @@ static void *mgr_entry(void *userdata) { // spawn the omxplayer process current_zpos = -128; + current_orientation = task.orientation; pid_t me = fork(); if (me == 0) { char orientation_str[16] = {0}; @@ -788,6 +807,27 @@ static void *mgr_entry(void *userdata) { current_zpos = task.zpos; } + +#ifdef OMXPLAYER_SUPPORTS_RUNTIME_ROTATION + if (current_orientation != task.orientation) { + ok = sd_bus_call_method( + bus, + dbus_name, + DBUS_OMXPLAYER_OBJECT, + DBUS_OMXPLAYER_PLAYER_FACE, + "SetTransform", + &err, + NULL, + "x", + (360 - (int64_t) task.orientation) % 360 + ); + if (ok < 0) { + fprintf(stderr, "[omxplayer_video_player plugin] Could not update omxplayer rotation. %s, %s\n", err.name, err.message); + continue; + } + current_orientation = task.orientation; + } +#endif } else if (task.type == kGetPosition) { int64_t position = 0; @@ -1469,4 +1509,4 @@ int omxpvidpp_deinit(void) { plugin_registry_remove_receiver("flutter.io/omxplayerVideoPlayer"); return 0; -} \ No newline at end of file +} diff --git a/src/plugins/services.c b/src/plugins/services.c index 920d57d7..60bd5198 100644 --- a/src/plugins/services.c +++ b/src/plugins/services.c @@ -100,7 +100,7 @@ static int on_receive_platform(char *channel, struct platch_obj *object, Flutter // if the list contains the current orientation, we just return and don't change the current orientation at all. if (o == flutterpi.view.orientation) { - return 0; + return platch_respond_success_json(responsehandle, NULL); } preferred_orientations[o] = true; @@ -114,7 +114,7 @@ static int on_receive_platform(char *channel, struct platch_obj *object, Flutter flutterpi_fill_view_properties(true, i, false, 0); - compositor_apply_cursor_state(true, flutterpi.view.rotation, flutterpi.display.pixel_ratio); + compositor_apply_cursor_state(false, flutterpi.view.rotation, flutterpi.display.pixel_ratio); // send updated window metrics to flutter result = flutterpi.flutter.libflutter_engine.FlutterEngineSendWindowMetricsEvent(flutterpi.flutter.engine, &(const FlutterWindowMetricsEvent) {