diff --git a/src/bin/clapper-app/clapper-app-window.c b/src/bin/clapper-app/clapper-app-window.c index 96a511ec..8fb997d6 100644 --- a/src/bin/clapper-app/clapper-app-window.c +++ b/src/bin/clapper-app/clapper-app-window.c @@ -28,6 +28,9 @@ #include "clapper-app-file-dialog.h" #include "clapper-app-utils.h" +#define MIN_WINDOW_WIDTH 352 +#define MIN_WINDOW_HEIGHT 198 + #define DEFAULT_WINDOW_WIDTH 1024 #define DEFAULT_WINDOW_HEIGHT 576 @@ -40,6 +43,8 @@ #define PERCENTAGE_ROUND(a) (round ((gdouble) a / 0.01) * 0.01) #define AXIS_WINS_OVER(a,b) ((a > 0 && a - 0.3 > b) || (a < 0 && a + 0.3 < b)) +#define MIN_STEP_DELAY 12000 + #define GST_CAT_DEFAULT clapper_app_window_debug GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); @@ -59,6 +64,7 @@ struct _ClapperAppWindow GSettings *settings; guint seek_timeout; + guint resize_tick_id; gboolean key_held; gboolean scrolling; @@ -74,6 +80,12 @@ struct _ClapperAppWindow #define parent_class clapper_app_window_parent_class G_DEFINE_TYPE (ClapperAppWindow, clapper_app_window, GTK_TYPE_APPLICATION_WINDOW) +typedef struct +{ + gint dest_width, dest_height; + gint64 last_tick; +} ClapperAppWindowResizeData; + static guint16 instance_count = 0; static inline GQuark @@ -246,12 +258,16 @@ _open_subtitles_cb (ClapperGtkExtraMenuButton *button G_GNUC_UNUSED, } static void -right_click_pressed_cb (GtkGestureClick *click, gint n_press, +click_pressed_cb (GtkGestureClick *click, gint n_press, gdouble x, gdouble y, ClapperAppWindow *self) { GdkCursor *cursor; const gchar *cursor_name = NULL; + if (gtk_gesture_single_get_current_button ( + GTK_GESTURE_SINGLE (click)) != GDK_BUTTON_SECONDARY) + return; + GST_LOG_OBJECT (self, "Right click pressed"); if ((cursor = gtk_widget_get_cursor (self->video))) @@ -266,9 +282,152 @@ right_click_pressed_cb (GtkGestureClick *click, gint n_press, } } +static gboolean +_resize_tick (GtkWidget *widget, GdkFrameClock *frame_clock, + ClapperAppWindowResizeData *resize_data) +{ + gint64 now = gdk_frame_clock_get_frame_time (frame_clock); + + if (now - resize_data->last_tick >= MIN_STEP_DELAY) { + ClapperAppWindow *self = CLAPPER_APP_WINDOW_CAST (widget); + gint win_width, win_height; + + GST_LOG_OBJECT (self, "Resize step, last: %" G_GINT64_FORMAT + ", now: %" G_GINT64_FORMAT, resize_data->last_tick, now); + + gtk_window_get_default_size (GTK_WINDOW (self), &win_width, &win_height); + + if (win_width != resize_data->dest_width) { + gint width_diff = ABS (win_width - resize_data->dest_width); + gint step_size = (width_diff > 180) ? 120 : MAX (width_diff / 4, 1); + + win_width += (win_width > resize_data->dest_width) ? -step_size : step_size; + } + if (win_height != resize_data->dest_height) { + gint height_diff = ABS (win_height - resize_data->dest_height); + gint step_size = (height_diff > 180) ? 120 : MAX (height_diff / 4, 1); + + win_height += (win_height > resize_data->dest_height) ? -step_size : step_size; + } + + gtk_window_set_default_size (GTK_WINDOW (self), win_width, win_height); + + if (win_width == resize_data->dest_width + && win_height == resize_data->dest_height) { + GST_DEBUG_OBJECT (self, "Window resize finish"); + self->resize_tick_id = 0; + + return G_SOURCE_REMOVE; + } + + resize_data->last_tick = now; + } + + return G_SOURCE_CONTINUE; +} + static void -right_click_released_cb (GtkGestureClick *click, gint n_press, - gdouble x, gdouble y, ClapperAppWindow *self) +_calculate_win_resize (gint win_w, gint win_h, + gint vid_w, gint vid_h, gint *dest_w, gint *dest_h) +{ + gdouble win_aspect = (gdouble) win_w / win_h; + gdouble vid_aspect = (gdouble) vid_w / vid_h; + + if (win_aspect < vid_aspect) { + while (!G_APPROX_VALUE (fmod (win_w, vid_aspect), 0, FLT_EPSILON)) + win_w++; + + win_h = round ((gdouble) win_w / vid_aspect); + + if (win_h < MIN_WINDOW_HEIGHT) { + _calculate_win_resize (G_MAXINT, MIN_WINDOW_HEIGHT, vid_w, vid_h, dest_w, dest_h); + return; + } + } else { + while (!G_APPROX_VALUE (fmod (win_h * vid_aspect, 1.0), 0, FLT_EPSILON)) + win_h++; + + win_w = round ((gdouble) win_h * vid_aspect); + + if (win_w < MIN_WINDOW_WIDTH) { + _calculate_win_resize (MIN_WINDOW_WIDTH, G_MAXINT, vid_w, vid_h, dest_w, dest_h); + return; + } + } + + *dest_w = win_w; + *dest_h = win_h; +} + +static void +_resize_window (ClapperAppWindow *self) +{ + ClapperPlayer *player; + ClapperStreamList *vstreams; + ClapperVideoStream *vstream; + GdkToplevelState toplevel_state, disallowed; + + if (self->resize_tick_id != 0) + return; + + toplevel_state = gdk_toplevel_get_state (GDK_TOPLEVEL ( + gtk_native_get_surface (GTK_NATIVE (self)))); + disallowed = (GDK_TOPLEVEL_STATE_MINIMIZED + | GDK_TOPLEVEL_STATE_MAXIMIZED + | GDK_TOPLEVEL_STATE_FULLSCREEN + | GDK_TOPLEVEL_STATE_TILED); + + if ((toplevel_state & disallowed) > 0) { + GST_DEBUG_OBJECT (self, "Cannot resize window in disallowed state"); + return; + } + + player = clapper_app_window_get_player (self); + vstreams = clapper_player_get_video_streams (player); + vstream = CLAPPER_VIDEO_STREAM_CAST ( + clapper_stream_list_get_current_stream (vstreams)); + + if (vstream) { + gint video_width = clapper_video_stream_get_width (vstream); + gint video_height = clapper_video_stream_get_height (vstream); + + if (G_LIKELY (video_width > 0 && video_height > 0)) { + gint win_width, win_height, dest_width, dest_height; + + gtk_window_get_default_size (GTK_WINDOW (self), &win_width, &win_height); + + _calculate_win_resize (win_width, win_height, + video_width, video_height, &dest_width, &dest_height); + + /* Only begin resize when not already at perfect size */ + if (dest_width != win_width || dest_height != win_height) { + ClapperAppWindowResizeData *resize_data; + + resize_data = g_new0 (ClapperAppWindowResizeData, 1); + resize_data->dest_width = dest_width; + resize_data->dest_height = dest_height; + + GST_DEBUG_OBJECT (self, "Window resize start, dest: %ix%i", + resize_data->dest_width, resize_data->dest_height); + + self->resize_tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (self), + (GtkTickCallback) _resize_tick, resize_data, g_free); + } + } + + gst_object_unref (vstream); + } +} + +static void +_handle_middle_click (ClapperAppWindow *self, GtkGestureClick *click) +{ + _resize_window (self); + gtk_gesture_set_state (GTK_GESTURE (click), GTK_EVENT_SEQUENCE_CLAIMED); +} + +static void +_handle_right_click (ClapperAppWindow *self, GtkGestureClick *click) { GdkSurface *surface; GdkEventSequence *sequence; @@ -289,6 +448,22 @@ right_click_released_cb (GtkGestureClick *click, gint n_press, gtk_gesture_set_state (GTK_GESTURE (click), GTK_EVENT_SEQUENCE_CLAIMED); } +static void +click_released_cb (GtkGestureClick *click, gint n_press, + gdouble x, gdouble y, ClapperAppWindow *self) +{ + switch (gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (click))) { + case GDK_BUTTON_MIDDLE: + _handle_middle_click (self, click); + break; + case GDK_BUTTON_SECONDARY: + _handle_right_click (self, click); + break; + default: + break; + } +} + static void drag_begin_cb (GtkGestureDrag *drag, gdouble start_x, gdouble start_y, ClapperAppWindow *self) @@ -998,6 +1173,9 @@ clapper_app_window_init (ClapperAppWindow *self) GtkWidget *dummy_titlebar; gint distance = 0; + gtk_widget_set_size_request (GTK_WIDGET (self), + MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT); + extra_opts = g_new0 (ClapperAppWindowExtraOptions, 1); GST_TRACE ("Created window extra options: %p", extra_opts); @@ -1126,6 +1304,11 @@ clapper_app_window_dispose (GObject *object) { ClapperAppWindow *self = CLAPPER_APP_WINDOW_CAST (object); + if (self->resize_tick_id != 0) { + gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->resize_tick_id); + self->resize_tick_id = 0; + } + g_clear_handle_id (&self->seek_timeout, g_source_remove); gtk_widget_dispose_template (GTK_WIDGET (object), CLAPPER_APP_TYPE_WINDOW); @@ -1185,8 +1368,8 @@ clapper_app_window_class_init (ClapperAppWindowClass *klass) gtk_widget_class_bind_template_callback (widget_class, key_pressed_cb); gtk_widget_class_bind_template_callback (widget_class, key_released_cb); - gtk_widget_class_bind_template_callback (widget_class, right_click_pressed_cb); - gtk_widget_class_bind_template_callback (widget_class, right_click_released_cb); + gtk_widget_class_bind_template_callback (widget_class, click_pressed_cb); + gtk_widget_class_bind_template_callback (widget_class, click_released_cb); gtk_widget_class_bind_template_callback (widget_class, drag_begin_cb); gtk_widget_class_bind_template_callback (widget_class, drag_update_cb); diff --git a/src/bin/clapper-app/css/styles.css b/src/bin/clapper-app/css/styles.css index f988f468..0f2e2293 100644 --- a/src/bin/clapper-app/css/styles.css +++ b/src/bin/clapper-app/css/styles.css @@ -1,8 +1,3 @@ -window.app { - min-width: 352px; - min-height: 198px; -} - window .initialstate { padding-left: 6px; padding-right: 6px; diff --git a/src/bin/clapper-app/ui/clapper-app-window.ui b/src/bin/clapper-app/ui/clapper-app-window.ui index d25521b9..5dd2b924 100644 --- a/src/bin/clapper-app/ui/clapper-app-window.ui +++ b/src/bin/clapper-app/ui/clapper-app-window.ui @@ -47,9 +47,9 @@ - 3 - - + 0 + + @@ -68,8 +68,5 @@ -