mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-29 23:32:04 +02:00
clapper-app: Resize window to match aspect ratio with middle click
This commit is contained in:
@@ -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);
|
||||
|
||||
|
@@ -1,8 +1,3 @@
|
||||
window.app {
|
||||
min-width: 352px;
|
||||
min-height: 198px;
|
||||
}
|
||||
|
||||
window .initialstate {
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
|
@@ -47,9 +47,9 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGestureClick">
|
||||
<property name="button">3</property>
|
||||
<signal name="pressed" handler="right_click_pressed_cb"/>
|
||||
<signal name="released" handler="right_click_released_cb"/>
|
||||
<property name="button">0</property>
|
||||
<signal name="pressed" handler="click_pressed_cb"/>
|
||||
<signal name="released" handler="click_released_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
@@ -68,8 +68,5 @@
|
||||
<signal name="drop" handler="drop_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="app"/>
|
||||
</style>
|
||||
</template>
|
||||
</interface>
|
||||
|
Reference in New Issue
Block a user