28
28
#include "clapper-app-file-dialog.h"
29
29
#include "clapper-app-utils.h"
30
30
31
+ #define MIN_WINDOW_WIDTH 352
32
+ #define MIN_WINDOW_HEIGHT 198
33
+
31
34
#define DEFAULT_WINDOW_WIDTH 1024
32
35
#define DEFAULT_WINDOW_HEIGHT 576
33
36
40
43
#define PERCENTAGE_ROUND (a ) (round ((gdouble) a / 0.01) * 0.01)
41
44
#define AXIS_WINS_OVER (a ,b ) ((a > 0 && a - 0.3 > b) || (a < 0 && a + 0.3 < b))
42
45
46
+ #define MIN_STEP_DELAY 12000
47
+
43
48
#define GST_CAT_DEFAULT clapper_app_window_debug
44
49
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT );
45
50
@@ -59,6 +64,7 @@ struct _ClapperAppWindow
59
64
GSettings * settings ;
60
65
61
66
guint seek_timeout ;
67
+ guint resize_tick_id ;
62
68
63
69
gboolean key_held ;
64
70
gboolean scrolling ;
@@ -74,6 +80,12 @@ struct _ClapperAppWindow
74
80
#define parent_class clapper_app_window_parent_class
75
81
G_DEFINE_TYPE (ClapperAppWindow , clapper_app_window , GTK_TYPE_APPLICATION_WINDOW )
76
82
83
+ typedef struct
84
+ {
85
+ gint dest_width , dest_height ;
86
+ gint64 last_tick ;
87
+ } ClapperAppWindowResizeData ;
88
+
77
89
static guint16 instance_count = 0 ;
78
90
79
91
static inline GQuark
@@ -246,12 +258,16 @@ _open_subtitles_cb (ClapperGtkExtraMenuButton *button G_GNUC_UNUSED,
246
258
}
247
259
248
260
static void
249
- right_click_pressed_cb (GtkGestureClick * click , gint n_press ,
261
+ click_pressed_cb (GtkGestureClick * click , gint n_press ,
250
262
gdouble x , gdouble y , ClapperAppWindow * self )
251
263
{
252
264
GdkCursor * cursor ;
253
265
const gchar * cursor_name = NULL ;
254
266
267
+ if (gtk_gesture_single_get_current_button (
268
+ GTK_GESTURE_SINGLE (click )) != GDK_BUTTON_SECONDARY )
269
+ return ;
270
+
255
271
GST_LOG_OBJECT (self , "Right click pressed" );
256
272
257
273
if ((cursor = gtk_widget_get_cursor (self -> video )))
@@ -266,9 +282,152 @@ right_click_pressed_cb (GtkGestureClick *click, gint n_press,
266
282
}
267
283
}
268
284
285
+ static gboolean
286
+ _resize_tick (GtkWidget * widget , GdkFrameClock * frame_clock ,
287
+ ClapperAppWindowResizeData * resize_data )
288
+ {
289
+ gint64 now = gdk_frame_clock_get_frame_time (frame_clock );
290
+
291
+ if (now - resize_data -> last_tick >= MIN_STEP_DELAY ) {
292
+ ClapperAppWindow * self = CLAPPER_APP_WINDOW_CAST (widget );
293
+ gint win_width , win_height ;
294
+
295
+ GST_LOG_OBJECT (self , "Resize step, last: %" G_GINT64_FORMAT
296
+ ", now: %" G_GINT64_FORMAT , resize_data -> last_tick , now );
297
+
298
+ gtk_window_get_default_size (GTK_WINDOW (self ), & win_width , & win_height );
299
+
300
+ if (win_width != resize_data -> dest_width ) {
301
+ gint width_diff = ABS (win_width - resize_data -> dest_width );
302
+ gint step_size = (width_diff > 180 ) ? 120 : MAX (width_diff / 4 , 1 );
303
+
304
+ win_width += (win_width > resize_data -> dest_width ) ? - step_size : step_size ;
305
+ }
306
+ if (win_height != resize_data -> dest_height ) {
307
+ gint height_diff = ABS (win_height - resize_data -> dest_height );
308
+ gint step_size = (height_diff > 180 ) ? 120 : MAX (height_diff / 4 , 1 );
309
+
310
+ win_height += (win_height > resize_data -> dest_height ) ? - step_size : step_size ;
311
+ }
312
+
313
+ gtk_window_set_default_size (GTK_WINDOW (self ), win_width , win_height );
314
+
315
+ if (win_width == resize_data -> dest_width
316
+ && win_height == resize_data -> dest_height ) {
317
+ GST_DEBUG_OBJECT (self , "Window resize finish" );
318
+ self -> resize_tick_id = 0 ;
319
+
320
+ return G_SOURCE_REMOVE ;
321
+ }
322
+
323
+ resize_data -> last_tick = now ;
324
+ }
325
+
326
+ return G_SOURCE_CONTINUE ;
327
+ }
328
+
269
329
static void
270
- right_click_released_cb (GtkGestureClick * click , gint n_press ,
271
- gdouble x , gdouble y , ClapperAppWindow * self )
330
+ _calculate_win_resize (gint win_w , gint win_h ,
331
+ gint vid_w , gint vid_h , gint * dest_w , gint * dest_h )
332
+ {
333
+ gdouble win_aspect = (gdouble ) win_w / win_h ;
334
+ gdouble vid_aspect = (gdouble ) vid_w / vid_h ;
335
+
336
+ if (win_aspect < vid_aspect ) {
337
+ while (!G_APPROX_VALUE (fmod (win_w , vid_aspect ), 0 , FLT_EPSILON ))
338
+ win_w ++ ;
339
+
340
+ win_h = round ((gdouble ) win_w / vid_aspect );
341
+
342
+ if (win_h < MIN_WINDOW_HEIGHT ) {
343
+ _calculate_win_resize (G_MAXINT , MIN_WINDOW_HEIGHT , vid_w , vid_h , dest_w , dest_h );
344
+ return ;
345
+ }
346
+ } else {
347
+ while (!G_APPROX_VALUE (fmod (win_h * vid_aspect , 1.0 ), 0 , FLT_EPSILON ))
348
+ win_h ++ ;
349
+
350
+ win_w = round ((gdouble ) win_h * vid_aspect );
351
+
352
+ if (win_w < MIN_WINDOW_WIDTH ) {
353
+ _calculate_win_resize (MIN_WINDOW_WIDTH , G_MAXINT , vid_w , vid_h , dest_w , dest_h );
354
+ return ;
355
+ }
356
+ }
357
+
358
+ * dest_w = win_w ;
359
+ * dest_h = win_h ;
360
+ }
361
+
362
+ static void
363
+ _resize_window (ClapperAppWindow * self )
364
+ {
365
+ ClapperPlayer * player ;
366
+ ClapperStreamList * vstreams ;
367
+ ClapperVideoStream * vstream ;
368
+ GdkToplevelState toplevel_state , disallowed ;
369
+
370
+ if (self -> resize_tick_id != 0 )
371
+ return ;
372
+
373
+ toplevel_state = gdk_toplevel_get_state (GDK_TOPLEVEL (
374
+ gtk_native_get_surface (GTK_NATIVE (self ))));
375
+ disallowed = (GDK_TOPLEVEL_STATE_MINIMIZED
376
+ | GDK_TOPLEVEL_STATE_MAXIMIZED
377
+ | GDK_TOPLEVEL_STATE_FULLSCREEN
378
+ | GDK_TOPLEVEL_STATE_TILED );
379
+
380
+ if ((toplevel_state & disallowed ) > 0 ) {
381
+ GST_DEBUG_OBJECT (self , "Cannot resize window in disallowed state" );
382
+ return ;
383
+ }
384
+
385
+ player = clapper_app_window_get_player (self );
386
+ vstreams = clapper_player_get_video_streams (player );
387
+ vstream = CLAPPER_VIDEO_STREAM_CAST (
388
+ clapper_stream_list_get_current_stream (vstreams ));
389
+
390
+ if (vstream ) {
391
+ gint video_width = clapper_video_stream_get_width (vstream );
392
+ gint video_height = clapper_video_stream_get_height (vstream );
393
+
394
+ if (G_LIKELY (video_width > 0 && video_height > 0 )) {
395
+ gint win_width , win_height , dest_width , dest_height ;
396
+
397
+ gtk_window_get_default_size (GTK_WINDOW (self ), & win_width , & win_height );
398
+
399
+ _calculate_win_resize (win_width , win_height ,
400
+ video_width , video_height , & dest_width , & dest_height );
401
+
402
+ /* Only begin resize when not already at perfect size */
403
+ if (dest_width != win_width || dest_height != win_height ) {
404
+ ClapperAppWindowResizeData * resize_data ;
405
+
406
+ resize_data = g_new0 (ClapperAppWindowResizeData , 1 );
407
+ resize_data -> dest_width = dest_width ;
408
+ resize_data -> dest_height = dest_height ;
409
+
410
+ GST_DEBUG_OBJECT (self , "Window resize start, dest: %ix%i" ,
411
+ resize_data -> dest_width , resize_data -> dest_height );
412
+
413
+ self -> resize_tick_id = gtk_widget_add_tick_callback (GTK_WIDGET (self ),
414
+ (GtkTickCallback ) _resize_tick , resize_data , g_free );
415
+ }
416
+ }
417
+
418
+ gst_object_unref (vstream );
419
+ }
420
+ }
421
+
422
+ static void
423
+ _handle_middle_click (ClapperAppWindow * self , GtkGestureClick * click )
424
+ {
425
+ _resize_window (self );
426
+ gtk_gesture_set_state (GTK_GESTURE (click ), GTK_EVENT_SEQUENCE_CLAIMED );
427
+ }
428
+
429
+ static void
430
+ _handle_right_click (ClapperAppWindow * self , GtkGestureClick * click )
272
431
{
273
432
GdkSurface * surface ;
274
433
GdkEventSequence * sequence ;
@@ -289,6 +448,22 @@ right_click_released_cb (GtkGestureClick *click, gint n_press,
289
448
gtk_gesture_set_state (GTK_GESTURE (click ), GTK_EVENT_SEQUENCE_CLAIMED );
290
449
}
291
450
451
+ static void
452
+ click_released_cb (GtkGestureClick * click , gint n_press ,
453
+ gdouble x , gdouble y , ClapperAppWindow * self )
454
+ {
455
+ switch (gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (click ))) {
456
+ case GDK_BUTTON_MIDDLE :
457
+ _handle_middle_click (self , click );
458
+ break ;
459
+ case GDK_BUTTON_SECONDARY :
460
+ _handle_right_click (self , click );
461
+ break ;
462
+ default :
463
+ break ;
464
+ }
465
+ }
466
+
292
467
static void
293
468
drag_begin_cb (GtkGestureDrag * drag ,
294
469
gdouble start_x , gdouble start_y , ClapperAppWindow * self )
@@ -888,6 +1063,12 @@ toggle_fullscreen (GSimpleAction *action, GVariant *param, gpointer user_data)
888
1063
video_toggle_fullscreen_cb (CLAPPER_GTK_VIDEO_CAST (self -> video ), self );
889
1064
}
890
1065
1066
+ static void
1067
+ auto_resize (GSimpleAction * action , GVariant * param , gpointer user_data )
1068
+ {
1069
+ _resize_window (CLAPPER_APP_WINDOW_CAST (user_data ));
1070
+ }
1071
+
891
1072
static void
892
1073
show_help_overlay (GSimpleAction * action , GVariant * param , gpointer user_data )
893
1074
{
@@ -998,6 +1179,9 @@ clapper_app_window_init (ClapperAppWindow *self)
998
1179
GtkWidget * dummy_titlebar ;
999
1180
gint distance = 0 ;
1000
1181
1182
+ gtk_widget_set_size_request (GTK_WIDGET (self ),
1183
+ MIN_WINDOW_WIDTH , MIN_WINDOW_HEIGHT );
1184
+
1001
1185
extra_opts = g_new0 (ClapperAppWindowExtraOptions , 1 );
1002
1186
GST_TRACE ("Created window extra options: %p" , extra_opts );
1003
1187
@@ -1039,6 +1223,7 @@ clapper_app_window_constructed (GObject *object)
1039
1223
1040
1224
static const GActionEntry win_entries [] = {
1041
1225
{ "toggle-fullscreen" , toggle_fullscreen , NULL , NULL , NULL },
1226
+ { "auto-resize" , auto_resize , NULL , NULL , NULL },
1042
1227
{ "show-help-overlay" , show_help_overlay , NULL , NULL , NULL },
1043
1228
};
1044
1229
@@ -1126,6 +1311,11 @@ clapper_app_window_dispose (GObject *object)
1126
1311
{
1127
1312
ClapperAppWindow * self = CLAPPER_APP_WINDOW_CAST (object );
1128
1313
1314
+ if (self -> resize_tick_id != 0 ) {
1315
+ gtk_widget_remove_tick_callback (GTK_WIDGET (self ), self -> resize_tick_id );
1316
+ self -> resize_tick_id = 0 ;
1317
+ }
1318
+
1129
1319
g_clear_handle_id (& self -> seek_timeout , g_source_remove );
1130
1320
1131
1321
gtk_widget_dispose_template (GTK_WIDGET (object ), CLAPPER_APP_TYPE_WINDOW );
@@ -1185,8 +1375,8 @@ clapper_app_window_class_init (ClapperAppWindowClass *klass)
1185
1375
gtk_widget_class_bind_template_callback (widget_class , key_pressed_cb );
1186
1376
gtk_widget_class_bind_template_callback (widget_class , key_released_cb );
1187
1377
1188
- gtk_widget_class_bind_template_callback (widget_class , right_click_pressed_cb );
1189
- gtk_widget_class_bind_template_callback (widget_class , right_click_released_cb );
1378
+ gtk_widget_class_bind_template_callback (widget_class , click_pressed_cb );
1379
+ gtk_widget_class_bind_template_callback (widget_class , click_released_cb );
1190
1380
gtk_widget_class_bind_template_callback (widget_class , drag_begin_cb );
1191
1381
gtk_widget_class_bind_template_callback (widget_class , drag_update_cb );
1192
1382
0 commit comments