1 /*
2 * Copyright (c) 2014-2022 gnome-mpv
3 *
4 * This file is part of Celluloid.
5 *
6 * Celluloid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Celluloid is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with Celluloid. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <glib.h>
21 #include <glib-object.h>
22 #include <gio/gio.h>
23 #include <gdk/gdk.h>
24
25 #include "celluloid-def.h"
26 #include "celluloid-marshal.h"
27 #include "celluloid-menu.h"
28 #include "celluloid-application.h"
29 #include "celluloid-playlist-widget.h"
30 #include "celluloid-main-window.h"
31 #include "celluloid-header-bar.h"
32 #include "celluloid-control-box.h"
33 #include "celluloid-video-area.h"
34
35 #define get_private(window) \
36 ((CelluloidMainWindowPrivate *)celluloid_main_window_get_instance_private(CELLULOID_MAIN_WINDOW(window)))
37
38 typedef struct _CelluloidMainWindowPrivate CelluloidMainWindowPrivate;
39
40 enum
41 {
42 PROP_0,
43 PROP_ALWAYS_FLOATING,
44 N_PROPERTIES
45 };
46
47 struct _CelluloidMainWindowPrivate
48 {
49 GtkApplicationWindow parent;
50 gint width_offset;
51 gint height_offset;
52 gint resize_target[2];
53 gboolean csd;
54 gboolean always_floating;
55 gboolean use_floating_controls;
56 gboolean fullscreen;
57 gboolean playlist_visible;
58 gboolean playlist_first_toggle;
59 gboolean pre_fs_playlist_visible;
60 gint playlist_width;
61 guint resize_tag;
62 const GPtrArray *track_list;
63 const GPtrArray *disc_list;
64 GtkWidget *header_bar;
65 GtkWidget *main_box;
66 GtkWidget *video_area_paned;
67 GtkWidget *video_area;
68 GtkWidget *control_box;
69 GtkWidget *playlist;
70 };
71
72 static void
73 constructed(GObject *object);
74
75 static void
76 dispose(GObject *object);
77
78 static void
79 set_property( GObject *object,
80 guint property_id,
81 const GValue *value,
82 GParamSpec *pspec );
83
84 static void
85 get_property( GObject *object,
86 guint property_id,
87 GValue *value,
88 GParamSpec *pspec );
89
90 static void
91 seek_handler(GtkWidget *widget, gdouble value, gpointer data);
92
93 static void
94 button_clicked_handler( CelluloidControlBox *control_box,
95 const gchar *button,
96 gpointer data );
97
98 static void
99 notify(GObject *object, GParamSpec *pspec);
100
101 static void
102 resize_video_area_finalize( GtkWidget *widget,
103 gint width,
104 gint height,
105 gpointer data );
106
107 static gboolean
108 resize_to_target(gpointer data);
109
G_DEFINE_TYPE_WITH_PRIVATE(CelluloidMainWindow,celluloid_main_window,GTK_TYPE_APPLICATION_WINDOW)110 G_DEFINE_TYPE_WITH_PRIVATE(CelluloidMainWindow, celluloid_main_window, GTK_TYPE_APPLICATION_WINDOW)
111
112 static void
113 constructed(GObject *object)
114 {
115 CelluloidMainWindowPrivate *priv = get_private(object);
116
117 priv->playlist = celluloid_playlist_widget_new();
118
119 gtk_widget_hide(priv->playlist);
120 gtk_widget_hide(priv->control_box);
121
122 gtk_paned_set_start_child
123 (GTK_PANED(priv->video_area_paned), priv->video_area);
124 gtk_paned_set_end_child
125 (GTK_PANED(priv->video_area_paned), priv->playlist);
126 gtk_paned_set_shrink_end_child
127 (GTK_PANED(priv->video_area_paned), FALSE);
128
129 gtk_application_window_set_show_menubar
130 (GTK_APPLICATION_WINDOW(object), !priv->csd);
131
132 G_OBJECT_CLASS(celluloid_main_window_parent_class)->constructed(object);
133 }
134
135 static void
dispose(GObject * object)136 dispose(GObject *object)
137 {
138 g_source_clear(&get_private(object)->resize_tag);
139
140 G_OBJECT_CLASS(celluloid_main_window_parent_class)->dispose(object);
141 }
142
143 static void
set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)144 set_property( GObject *object,
145 guint property_id,
146 const GValue *value,
147 GParamSpec *pspec )
148 {
149 CelluloidMainWindowPrivate *priv = get_private(object);
150
151 if(property_id == PROP_ALWAYS_FLOATING)
152 {
153 priv->always_floating = g_value_get_boolean(value);
154 }
155 else
156 {
157 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
158 }
159 }
160
161 static void
get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)162 get_property( GObject *object,
163 guint property_id,
164 GValue *value,
165 GParamSpec *pspec )
166 {
167 CelluloidMainWindowPrivate *priv = get_private(object);
168
169 if(property_id == PROP_ALWAYS_FLOATING)
170 {
171 g_value_set_boolean(value, priv->always_floating);
172 }
173 else
174 {
175 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
176 }
177 }
178
179 static void
seek_handler(GtkWidget * widget,gdouble value,gpointer data)180 seek_handler(GtkWidget *widget, gdouble value, gpointer data)
181 {
182 g_signal_emit_by_name(data, "seek", value);
183 }
184
185 static void
button_clicked_handler(CelluloidControlBox * control_box,const gchar * button,gpointer data)186 button_clicked_handler( CelluloidControlBox *control_box,
187 const gchar *button,
188 gpointer data )
189 {
190 gchar *name = g_strconcat("button-clicked::", button, NULL);
191
192 g_signal_emit_by_name(data, name);
193 g_free(name);
194 }
195
196 static void
notify(GObject * object,GParamSpec * pspec)197 notify(GObject *object, GParamSpec *pspec)
198 {
199 if(g_strcmp0(pspec->name, "always-use-floating-controls") == 0)
200 {
201 CelluloidMainWindow *wnd = CELLULOID_MAIN_WINDOW(object);
202 CelluloidMainWindowPrivate *priv = get_private(wnd);
203 gboolean floating = priv->always_floating || priv->fullscreen;
204
205 celluloid_main_window_set_use_floating_controls(wnd, floating);
206 }
207 }
208
209 static void
resize_video_area_finalize(GtkWidget * widget,gint width,gint height,gpointer data)210 resize_video_area_finalize( GtkWidget *widget,
211 gint width,
212 gint height,
213 gpointer data )
214 {
215 CelluloidMainWindow *wnd = data;
216 CelluloidMainWindowPrivate *priv = get_private(wnd);
217 GdkSurface *surface = gtk_widget_get_surface(data);
218 GdkDisplay *display = gdk_display_get_default();
219 GdkMonitor *monitor = gdk_display_get_monitor_at_surface(display, surface);
220 GdkRectangle monitor_geom = {0};
221 gint target_width = priv->resize_target[0];
222 gint target_height = priv->resize_target[1];
223
224 g_signal_handlers_disconnect_by_func
225 (widget, resize_video_area_finalize, data);
226
227 gdk_monitor_get_geometry(monitor, &monitor_geom);
228
229 /* Adjust resize offset */
230 if((width != target_width || height != target_height)
231 && ( target_width < monitor_geom.width &&
232 target_height < monitor_geom.height )
233 && !gtk_window_is_maximized(GTK_WINDOW(wnd))
234 && !priv->fullscreen)
235 {
236 priv->width_offset += target_width-width;
237 priv->height_offset += target_height-height;
238
239 g_source_clear(&priv->resize_tag);
240 priv->resize_tag = g_idle_add_full( G_PRIORITY_HIGH_IDLE,
241 resize_to_target,
242 wnd,
243 NULL );
244 }
245 }
246
247 static gboolean
resize_to_target(gpointer data)248 resize_to_target(gpointer data)
249 {
250 CelluloidMainWindow *wnd = data;
251 CelluloidMainWindowPrivate *priv = get_private(data);
252 gint target_width = priv->resize_target[0];
253 gint target_height = priv->resize_target[1];
254
255 g_source_clear(&priv->resize_tag);
256
257 gtk_window_set_default_size( GTK_WINDOW(wnd),
258 target_width + priv->width_offset,
259 target_height + priv->height_offset );
260
261 /* Prevent graphical glitches that appear when calling
262 * celluloid_main_window_resize_video_area() with the current size as
263 * the target size.
264 */
265 celluloid_playlist_widget_queue_draw
266 (CELLULOID_PLAYLIST_WIDGET(priv->playlist));
267
268 return FALSE;
269 }
270
271 static void
celluloid_main_window_class_init(CelluloidMainWindowClass * klass)272 celluloid_main_window_class_init(CelluloidMainWindowClass *klass)
273 {
274 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
275 GParamSpec *pspec = NULL;
276
277 obj_class->constructed = constructed;
278 obj_class->dispose = dispose;
279 obj_class->set_property = set_property;
280 obj_class->get_property = get_property;
281 obj_class->notify = notify;
282
283 pspec = g_param_spec_boolean
284 ( "always-use-floating-controls",
285 "Always use floating controls",
286 "Whether or not to use floating controls in windowed mode",
287 FALSE,
288 G_PARAM_READWRITE );
289 g_object_class_install_property(obj_class, PROP_ALWAYS_FLOATING, pspec);
290
291 g_signal_new( "button-clicked",
292 G_TYPE_FROM_CLASS(klass),
293 G_SIGNAL_RUN_FIRST|G_SIGNAL_DETAILED,
294 0,
295 NULL,
296 NULL,
297 g_cclosure_marshal_VOID__VOID,
298 G_TYPE_NONE,
299 0 );
300 g_signal_new( "seek",
301 G_TYPE_FROM_CLASS(klass),
302 G_SIGNAL_RUN_FIRST,
303 0,
304 NULL,
305 NULL,
306 g_cclosure_marshal_VOID__DOUBLE,
307 G_TYPE_NONE,
308 1,
309 G_TYPE_DOUBLE );
310 }
311
312 static void
celluloid_main_window_init(CelluloidMainWindow * wnd)313 celluloid_main_window_init(CelluloidMainWindow *wnd)
314 {
315 CelluloidMainWindowPrivate *priv = get_private(wnd);
316 CelluloidControlBox *video_area_control_box = NULL;
317 CelluloidHeaderBar *video_area_header_bar = NULL;
318 GSettings *settings = g_settings_new(CONFIG_WIN_STATE);
319
320 priv->csd = FALSE;
321 priv->always_floating = FALSE;
322 priv->use_floating_controls = FALSE;
323 priv->fullscreen = FALSE;
324 priv->playlist_visible = FALSE;
325 priv->pre_fs_playlist_visible = FALSE;
326 priv->playlist_width = PLAYLIST_DEFAULT_WIDTH;
327 priv->resize_tag = 0;
328 priv->track_list = NULL;
329 priv->disc_list = NULL;
330 priv->header_bar = celluloid_header_bar_new();
331 priv->main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
332 priv->video_area_paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
333 priv->video_area = celluloid_video_area_new();
334 priv->control_box = celluloid_control_box_new();
335
336 priv->playlist_first_toggle = TRUE;
337 priv->width_offset = 0;
338 priv->height_offset = 0;
339
340 video_area_control_box =
341 celluloid_video_area_get_control_box
342 (CELLULOID_VIDEO_AREA(priv->video_area));
343 video_area_header_bar =
344 celluloid_video_area_get_header_bar
345 (CELLULOID_VIDEO_AREA(priv->video_area));
346
347 g_settings_bind( settings, "loop-playlist",
348 priv->control_box, "loop",
349 G_SETTINGS_BIND_DEFAULT );
350
351 g_object_bind_property( priv->header_bar, "open-button-active",
352 video_area_header_bar, "open-button-active",
353 G_BINDING_DEFAULT );
354 g_object_bind_property( priv->header_bar, "menu-button-active",
355 video_area_header_bar, "menu-button-active",
356 G_BINDING_DEFAULT );
357
358 g_object_bind_property( priv->control_box, "duration",
359 video_area_control_box, "duration",
360 G_BINDING_DEFAULT );
361 g_object_bind_property( priv->control_box, "pause",
362 video_area_control_box, "pause",
363 G_BINDING_DEFAULT );
364 g_object_bind_property( priv->control_box, "skip-enabled",
365 video_area_control_box, "skip-enabled",
366 G_BINDING_DEFAULT );
367 g_object_bind_property( priv->control_box, "show-fullscreen-button",
368 video_area_control_box, "show-fullscreen-button",
369 G_BINDING_DEFAULT );
370 g_object_bind_property( priv->control_box, "time-position",
371 video_area_control_box, "time-position",
372 G_BINDING_DEFAULT );
373 g_object_bind_property( priv->control_box, "loop",
374 video_area_control_box, "loop",
375 G_BINDING_BIDIRECTIONAL );
376 g_object_bind_property( priv->control_box, "volume",
377 video_area_control_box, "volume",
378 G_BINDING_BIDIRECTIONAL );
379 g_object_bind_property( priv->control_box, "volume-popup-visible",
380 video_area_control_box, "volume-popup-visible",
381 G_BINDING_BIDIRECTIONAL );
382
383 g_signal_connect( priv->control_box,
384 "seek",
385 G_CALLBACK(seek_handler),
386 wnd );
387 g_signal_connect( priv->control_box,
388 "button-clicked",
389 G_CALLBACK(button_clicked_handler),
390 wnd );
391 g_signal_connect( video_area_control_box,
392 "seek",
393 G_CALLBACK(seek_handler),
394 wnd );
395 g_signal_connect( video_area_control_box,
396 "button-clicked",
397 G_CALLBACK(button_clicked_handler),
398 wnd );
399
400 gtk_window_set_title(GTK_WINDOW(wnd), g_get_application_name());
401
402 gtk_paned_set_position( GTK_PANED(priv->video_area_paned),
403 MAIN_WINDOW_DEFAULT_WIDTH
404 -PLAYLIST_DEFAULT_WIDTH );
405 gtk_paned_set_resize_end_child(GTK_PANED(priv->video_area_paned), FALSE);
406
407 gtk_window_set_default_size( GTK_WINDOW(wnd),
408 MAIN_WINDOW_DEFAULT_WIDTH,
409 MAIN_WINDOW_DEFAULT_HEIGHT );
410
411 gtk_widget_set_hexpand(priv->header_bar, TRUE);
412 gtk_widget_set_hexpand(priv->control_box, TRUE);
413 gtk_widget_set_vexpand(priv->video_area_paned, TRUE);
414
415 gtk_box_append(GTK_BOX(priv->main_box), priv->video_area_paned);
416 gtk_box_append(GTK_BOX(priv->main_box), priv->control_box);
417 gtk_window_set_child(GTK_WINDOW(wnd), priv->main_box);
418 }
419
420 GtkWidget *
celluloid_main_window_new(GtkApplication * app,gboolean always_floating)421 celluloid_main_window_new( GtkApplication *app,
422 gboolean always_floating )
423 {
424 return GTK_WIDGET(g_object_new( celluloid_main_window_get_type(),
425 "application",
426 app,
427 "always-use-floating-controls",
428 always_floating,
429 NULL ));
430 }
431
432 CelluloidPlaylistWidget *
celluloid_main_window_get_playlist(CelluloidMainWindow * wnd)433 celluloid_main_window_get_playlist(CelluloidMainWindow *wnd)
434 {
435 return CELLULOID_PLAYLIST_WIDGET(get_private(wnd)->playlist);
436 }
437
438 CelluloidControlBox *
celluloid_main_window_get_control_box(CelluloidMainWindow * wnd)439 celluloid_main_window_get_control_box(CelluloidMainWindow *wnd)
440 {
441 return CELLULOID_CONTROL_BOX(get_private(wnd)->control_box);
442 }
443
444 CelluloidVideoArea *
celluloid_main_window_get_video_area(CelluloidMainWindow * wnd)445 celluloid_main_window_get_video_area(CelluloidMainWindow *wnd)
446 {
447 return CELLULOID_VIDEO_AREA(get_private(wnd)->video_area);
448 }
449
450 void
celluloid_main_window_set_use_floating_controls(CelluloidMainWindow * wnd,gboolean floating)451 celluloid_main_window_set_use_floating_controls( CelluloidMainWindow *wnd,
452 gboolean floating )
453 {
454 CelluloidMainWindowPrivate *priv = get_private(wnd);
455
456 if(floating != priv->use_floating_controls)
457 {
458 GSettings *settings = g_settings_new(CONFIG_WIN_STATE);
459 gboolean controls_visible = g_settings_get_boolean
460 (settings, "show-controls");
461
462 gtk_widget_set_visible
463 (priv->control_box, controls_visible && !floating);
464 celluloid_video_area_set_control_box_visible
465 (CELLULOID_VIDEO_AREA(priv->video_area), floating);
466
467 priv->use_floating_controls = floating;
468
469 g_clear_object(&settings);
470 }
471 }
472
473 gboolean
celluloid_main_window_get_use_floating_controls(CelluloidMainWindow * wnd)474 celluloid_main_window_get_use_floating_controls(CelluloidMainWindow *wnd)
475 {
476 return get_private(wnd)->use_floating_controls;
477 }
478
479 void
celluloid_main_window_set_fullscreen(CelluloidMainWindow * wnd,gboolean fullscreen)480 celluloid_main_window_set_fullscreen(CelluloidMainWindow *wnd, gboolean fullscreen)
481 {
482 CelluloidMainWindowPrivate *priv = get_private(wnd);
483
484 if(fullscreen != priv->fullscreen)
485 {
486 CelluloidVideoArea *video_area =
487 CELLULOID_VIDEO_AREA(priv->video_area);
488 GSettings *settings =
489 g_settings_new(CONFIG_WIN_STATE);
490 gboolean floating =
491 priv->always_floating || fullscreen;
492 gboolean playlist_visible =
493 !fullscreen && priv->pre_fs_playlist_visible;
494 gboolean show_controls = g_settings_get_boolean
495 (settings, "show-controls");
496
497 if(fullscreen)
498 {
499 gtk_window_fullscreen(GTK_WINDOW(wnd));
500 gtk_window_present(GTK_WINDOW(wnd));
501
502 priv->pre_fs_playlist_visible = priv->playlist_visible;
503 }
504 else
505 {
506 gtk_window_unfullscreen(GTK_WINDOW(wnd));
507
508 priv->playlist_visible = priv->pre_fs_playlist_visible;
509 }
510
511 if(!celluloid_main_window_get_csd_enabled(wnd))
512 {
513 gtk_application_window_set_show_menubar
514 (GTK_APPLICATION_WINDOW(wnd), !fullscreen);
515 }
516
517 celluloid_video_area_set_fullscreen_state
518 (video_area, fullscreen);
519 celluloid_main_window_set_use_floating_controls
520 (wnd, floating && show_controls);
521 gtk_widget_set_visible
522 (priv->playlist, playlist_visible);
523
524 priv->fullscreen = fullscreen;
525
526 g_object_unref(settings);
527 }
528 }
529
530 gboolean
celluloid_main_window_get_fullscreen(CelluloidMainWindow * wnd)531 celluloid_main_window_get_fullscreen(CelluloidMainWindow *wnd)
532 {
533 return get_private(wnd)->fullscreen;
534 }
535
536 void
celluloid_main_window_toggle_fullscreen(CelluloidMainWindow * wnd)537 celluloid_main_window_toggle_fullscreen(CelluloidMainWindow *wnd)
538 {
539 celluloid_main_window_set_fullscreen(wnd, !get_private(wnd)->fullscreen);
540 }
541
542 void
celluloid_main_window_reset(CelluloidMainWindow * wnd)543 celluloid_main_window_reset(CelluloidMainWindow *wnd)
544 {
545 gtk_window_set_title
546 (GTK_WINDOW(wnd), g_get_application_name());
547 celluloid_control_box_reset
548 (CELLULOID_CONTROL_BOX(get_private(wnd)->control_box));
549 }
550
551 void
celluloid_main_window_save_state(CelluloidMainWindow * wnd)552 celluloid_main_window_save_state(CelluloidMainWindow *wnd)
553 {
554 GSettings *settings;
555 CelluloidMainWindowPrivate *priv;
556 gint width;
557 gint height;
558 gboolean maximized;
559 gint handle_pos;
560 gdouble volume;
561
562 settings = g_settings_new(CONFIG_WIN_STATE);
563 priv = get_private(wnd);
564 maximized = gtk_window_is_maximized(GTK_WINDOW(wnd));
565 handle_pos = gtk_paned_get_position(GTK_PANED(priv->video_area_paned));
566
567 g_object_get(priv->control_box, "volume", &volume, NULL);
568 gtk_window_get_default_size(GTK_WINDOW(wnd), &width, &height);
569
570 // Controls visibility does not need to be saved here since
571 // celluloid_main_window_set_controls_visible() already updates the
572 // associated GSettings key when it is called.
573 g_settings_set_boolean(settings, "maximized", maximized);
574 g_settings_set_double(settings, "volume", volume/100.0);
575 g_settings_set_boolean(settings, "show-playlist", priv->playlist_visible);
576
577 if(!maximized)
578 {
579 g_settings_set_int(settings, "width", width);
580 g_settings_set_int(settings, "height", height);
581 }
582
583 if(celluloid_main_window_get_playlist_visible(wnd))
584 {
585 g_settings_set_int( settings,
586 "playlist-width",
587 width-handle_pos );
588 }
589 else
590 {
591 g_settings_set_int( settings,
592 "playlist-width",
593 priv->playlist_width );
594 }
595
596 g_clear_object(&settings);
597 }
598
599 void
celluloid_main_window_load_state(CelluloidMainWindow * wnd)600 celluloid_main_window_load_state(CelluloidMainWindow *wnd)
601 {
602 if(!gtk_widget_get_realized(GTK_WIDGET(wnd)))
603 {
604 GSettings *settings = g_settings_new(CONFIG_WIN_STATE);
605 CelluloidMainWindowPrivate *priv = get_private(wnd);
606 gint width = g_settings_get_int(settings, "width");
607 gint height = g_settings_get_int(settings, "height");
608 gboolean maximized = g_settings_get_boolean(settings, "maximized");
609 gint handle_pos;
610 gboolean controls_visible;
611 gdouble volume;
612
613 priv->playlist_width
614 = g_settings_get_int(settings, "playlist-width");
615 priv->playlist_visible
616 = g_settings_get_boolean(settings, "show-playlist");
617 controls_visible
618 = g_settings_get_boolean(settings, "show-controls");
619 volume = g_settings_get_double(settings, "volume");
620 handle_pos = width-(priv->playlist_visible?priv->playlist_width:0);
621
622 g_object_set(priv->control_box, "volume", volume, NULL);
623
624 gtk_widget_set_visible(priv->control_box, controls_visible);
625 gtk_widget_set_visible(priv->playlist, priv->playlist_visible);
626 gtk_window_set_default_size(GTK_WINDOW(wnd), width, height);
627 gtk_paned_set_position
628 (GTK_PANED(priv->video_area_paned), handle_pos);
629
630 if(maximized)
631 {
632 gtk_window_maximize(GTK_WINDOW(wnd));
633 }
634
635 g_clear_object(&settings);
636 }
637 else
638 {
639 g_critical( "Attempted to call "
640 "celluloid_main_window_load_state() "
641 "on realized window" );
642 }
643 }
644
645 void
celluloid_main_window_update_track_list(CelluloidMainWindow * wnd,const GPtrArray * track_list)646 celluloid_main_window_update_track_list( CelluloidMainWindow *wnd,
647 const GPtrArray *track_list )
648 {
649 CelluloidMainWindowPrivate *priv = get_private(wnd);
650
651 priv->track_list = track_list;
652
653 celluloid_video_area_update_track_list
654 (CELLULOID_VIDEO_AREA(priv->video_area), track_list);
655
656 if(celluloid_main_window_get_csd_enabled(wnd))
657 {
658 celluloid_header_bar_update_track_list
659 (CELLULOID_HEADER_BAR(priv->header_bar), track_list);
660 }
661 else
662 {
663 GtkApplication *app;
664 GMenu *menu;
665
666 app = gtk_window_get_application(GTK_WINDOW(wnd));
667 menu = G_MENU(gtk_application_get_menubar(app));
668
669 if(menu)
670 {
671 g_menu_remove_all(menu);
672
673 celluloid_menu_build_full
674 (menu, track_list, priv->disc_list);
675 }
676 }
677 }
678
679 void
celluloid_main_window_update_disc_list(CelluloidMainWindow * wnd,const GPtrArray * disc_list)680 celluloid_main_window_update_disc_list( CelluloidMainWindow *wnd,
681 const GPtrArray *disc_list )
682 {
683 CelluloidMainWindowPrivate *priv = get_private(wnd);
684
685 priv->disc_list = disc_list;
686
687 if(celluloid_main_window_get_csd_enabled(wnd))
688 {
689 celluloid_header_bar_update_disc_list
690 (CELLULOID_HEADER_BAR(priv->header_bar), disc_list);
691 celluloid_video_area_update_disc_list
692 (CELLULOID_VIDEO_AREA(priv->video_area), disc_list);
693 }
694 else
695 {
696 GtkApplication *app;
697 GMenu *menu;
698
699 app = gtk_window_get_application(GTK_WINDOW(wnd));
700 menu = G_MENU(gtk_application_get_menubar(app));
701
702 if(menu)
703 {
704 g_menu_remove_all(menu);
705
706 celluloid_menu_build_full
707 (menu, priv->track_list, disc_list);
708 }
709 }
710 }
711
712 void
celluloid_main_window_resize_video_area(CelluloidMainWindow * wnd,gint width,gint height)713 celluloid_main_window_resize_video_area( CelluloidMainWindow *wnd,
714 gint width,
715 gint height )
716 {
717 /* As of GNOME 3.36, attempting to resize the window while it is
718 * maximized will cause the UI to stop rendering. Resizing while
719 * fullscreen is unaffected, but it doesn't make sense to resize there
720 * either.
721 */
722 if( !get_private(wnd)->fullscreen &&
723 !gtk_window_is_maximized(GTK_WINDOW(wnd)) )
724 {
725 CelluloidMainWindowPrivate *priv = get_private(wnd);
726
727 g_signal_connect( priv->video_area,
728 "resize",
729 G_CALLBACK(resize_video_area_finalize),
730 wnd );
731
732 priv->resize_target[0] = width;
733 priv->resize_target[1] = height;
734 resize_to_target(wnd);
735
736 /* The size may not change, so this is needed to ensure that
737 * resize_video_area_finalize() will be called so that the event handler
738 * will be disconnected.
739 */
740 gtk_widget_queue_allocate(priv->video_area);
741 }
742 }
743
744 void
celluloid_main_window_enable_csd(CelluloidMainWindow * wnd)745 celluloid_main_window_enable_csd(CelluloidMainWindow *wnd)
746 {
747 CelluloidMainWindowPrivate *priv = get_private(wnd);
748
749 priv->csd = TRUE;
750
751 gtk_window_set_titlebar(GTK_WINDOW(wnd), priv->header_bar);
752 gtk_window_set_title(GTK_WINDOW(wnd), g_get_application_name());
753 }
754
755 gboolean
celluloid_main_window_get_csd_enabled(CelluloidMainWindow * wnd)756 celluloid_main_window_get_csd_enabled(CelluloidMainWindow *wnd)
757 {
758 return get_private(wnd)->csd;
759 }
760
761 void
celluloid_main_window_set_playlist_visible(CelluloidMainWindow * wnd,gboolean visible)762 celluloid_main_window_set_playlist_visible( CelluloidMainWindow *wnd,
763 gboolean visible )
764 {
765 CelluloidMainWindowPrivate *priv = get_private(wnd);
766
767 if(visible != priv->playlist_visible && !priv->fullscreen)
768 {
769 gboolean resize;
770 gint handle_pos;
771 gint width;
772 gint height;
773
774 resize = gtk_window_get_resizable(GTK_WINDOW(wnd));
775 handle_pos = gtk_paned_get_position
776 (GTK_PANED(priv->video_area_paned));
777
778 gtk_window_get_default_size(GTK_WINDOW(wnd), &width, &height);
779
780 if(priv->playlist_first_toggle && visible)
781 {
782 gint new_pos = width - (resize ? 0 : priv->playlist_width);
783
784 gtk_paned_set_position
785 (GTK_PANED(priv->video_area_paned), new_pos);
786 }
787 else if(!visible)
788 {
789 priv->playlist_width = width - handle_pos;
790 }
791
792 priv->playlist_visible = visible;
793 gtk_widget_set_visible(priv->playlist, visible);
794
795 if(resize)
796 {
797 gint new_width;
798
799 new_width = visible?
800 width + priv->playlist_width:
801 handle_pos;
802
803 gtk_window_set_default_size
804 (GTK_WINDOW(wnd), new_width, height);
805 }
806
807 priv->playlist_first_toggle = FALSE;
808 }
809 }
810
811 gboolean
celluloid_main_window_get_playlist_visible(CelluloidMainWindow * wnd)812 celluloid_main_window_get_playlist_visible(CelluloidMainWindow *wnd)
813 {
814 return gtk_widget_get_visible(GTK_WIDGET(get_private(wnd)->playlist));
815 }
816
817 void
celluloid_main_window_set_controls_visible(CelluloidMainWindow * wnd,gboolean visible)818 celluloid_main_window_set_controls_visible( CelluloidMainWindow *wnd,
819 gboolean visible )
820 {
821 GSettings *settings = g_settings_new(CONFIG_WIN_STATE);
822 CelluloidMainWindowPrivate *priv = get_private(wnd);
823 const gboolean floating = priv->use_floating_controls;
824 const gboolean fullscreen = priv->fullscreen;
825
826 gtk_widget_set_visible
827 (GTK_WIDGET(priv->control_box), visible && !fullscreen && !floating);
828 celluloid_video_area_set_control_box_visible
829 (CELLULOID_VIDEO_AREA(priv->video_area), visible && fullscreen);
830 g_settings_set_boolean
831 (settings, "show-controls", visible);
832
833 g_clear_object(&settings);
834 }
835
836 gboolean
celluloid_main_window_get_controls_visible(CelluloidMainWindow * wnd)837 celluloid_main_window_get_controls_visible(CelluloidMainWindow *wnd)
838 {
839 CelluloidMainWindowPrivate *priv = get_private(wnd);
840 CelluloidVideoArea *video_area = CELLULOID_VIDEO_AREA(priv->video_area);
841
842 return priv->fullscreen ?
843 celluloid_video_area_get_control_box_visible(video_area) :
844 gtk_widget_get_visible(GTK_WIDGET(priv->control_box));
845 }
846