messenger-gtk

Gtk+3 graphical user interfaces for GNUnet Messenger
Log | Files | Refs | Submodules | README | LICENSE

commit 056af2fb44379238609a2a28ede614ee3c5defed
parent 898ff5665c89266889cd1e9a85fad73a5415a1ba
Author: TheJackiMonster <thejackimonster@gmail.com>
Date:   Mon, 21 Nov 2022 22:29:06 +0100

Add window to play media with fullscreen toggle

Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>

Diffstat:
Mresources/ui.gresource.xml | 1+
Aresources/ui/play_media.ui | 288+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/application.h | 2++
Msrc/ui/Makefile.am | 1+
Msrc/ui/picker.c | 18+++++++++++++++++-
Asrc/ui/play_media.c | 287+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ui/play_media.h | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 675 insertions(+), 1 deletion(-)

diff --git a/resources/ui.gresource.xml b/resources/ui.gresource.xml @@ -22,6 +22,7 @@ <file compressed="true">ui/new_platform.ui</file> <file compressed="true">ui/new_account.ui</file> <file compressed="true">ui/picker.ui</file> + <file compressed="true">ui/play_media.ui</file> <file compressed="true">ui/account_entry.ui</file> <file compressed="true">ui/send_file.ui</file> <file compressed="true">ui/settings.ui</file> diff --git a/resources/ui/play_media.ui b/resources/ui/play_media.ui @@ -0,0 +1,288 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.40.0 + +Copyright (C) 2022 GNUnet e.V. + +GNUnet is free software: you can redistribute it and/or modify it +under the terms of the GNU Affero General Public License as published +by the Free Software Foundation, either version 3 of the License, +or (at your option) any later version. + +GNUnet is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +SPDX-License-Identifier: AGPL3.0-or-later +Author: Tobias Frisch + +--> +<interface> + <requires lib="gtk+" version="3.24"/> + <requires lib="libhandy" version="1.2"/> + <object class="HdyWindow" id="play_media_window"> + <property name="width-request">250</property> + <property name="height-request">180</property> + <property name="can-focus">False</property> + <property name="modal">True</property> + <property name="window-position">center-on-parent</property> + <property name="type-hint">dialog</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkRevealer" id="header_revealer"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="reveal-child">True</property> + <child> + <object class="HdyWindowHandle"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <child> + <object class="HdyHeaderBar" id="title_bar"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="show-close-button">True</property> + <child> + <object class="GtkButton" id="back_button"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">go-previous-symbolic</property> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="HdyFlap" id="controls_flap"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <property name="flap-position">end</property> + <property name="modal">False</property> + <child type="content"> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">folder-videos-symbolic</property> + <property name="icon_size">6</property> + </object> + </child> + <child type="separator"> + <object class="GtkSeparator"> + <property name="visible">True</property> + <property name="can-focus">False</property> + </object> + </child> + <child type="flap"> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="border-width">4</property> + <property name="spacing">8</property> + <child> + <object class="GtkButton" id="play_pause_button"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="relief">none</property> + <child> + <object class="GtkStack" id="play_symbol_stack"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">media-playback-start-symbolic</property> + </object> + <packing> + <property name="name">play_page</property> + </packing> + </child> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">media-playback-pause-symbolic</property> + </object> + <packing> + <property name="name">pause_page</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkVolumeButton" id="volume_button"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="focus-on-click">False</property> + <property name="receives-default">True</property> + <property name="relief">none</property> + <property name="orientation">vertical</property> + <property name="icons">audio-volume-muted-symbolic +audio-volume-high-symbolic +audio-volume-low-symbolic +audio-volume-medium-symbolic</property> + <child internal-child="plus_button"> + <object class="GtkButton"> + <property name="can-focus">False</property> + <property name="receives-default">False</property> + </object> + </child> + <child internal-child="minus_button"> + <object class="GtkButton"> + <property name="can-focus">False</property> + <property name="receives-default">False</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="timeline_label"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes">0:00 / 0:00</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkButton" id="fullscreen_button"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="relief">none</property> + <child> + <object class="GtkStack" id="fullscreen_symbol_stack"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">view-fullscreen-symbolic</property> + </object> + <packing> + <property name="name">scale_up_page</property> + </packing> + </child> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">view-restore-symbolic</property> + </object> + <packing> + <property name="name">scale_down_page</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkButton" id="settings_button"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="relief">none</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="icon-name">emblem-system-symbolic</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">4</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkProgressBar" id="timeline_progress_bar"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="margin-start">4</property> + <property name="margin-end">4</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="pack-type">end</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/src/application.h b/src/application.h @@ -42,6 +42,7 @@ #include "ui/new_group.h" #include "ui/new_lobby.h" #include "ui/new_platform.h" +#include "ui/play_media.h" #include "ui/send_file.h" #include "ui/settings.h" @@ -100,6 +101,7 @@ typedef struct MESSENGER_Application UI_DELETE_MESSAGES_Handle delete_messages; UI_INVITE_CONTACT_Handle invite_contact; UI_SEND_FILE_Handle send_file; + UI_PLAY_MEDIA_Handle play_media; UI_NEW_CONTACT_Handle new_contact; UI_NEW_GROUP_Handle new_group; diff --git a/src/ui/Makefile.am b/src/ui/Makefile.am @@ -32,6 +32,7 @@ libui_a_SOURCES = \ new_lobby.c new_lobby.h \ new_platform.c new_platform.h \ picker.c picker.h \ + play_media.c play_media.h \ send_file.c send_file.h \ settings.c settings.h diff --git a/src/ui/picker.c b/src/ui/picker.c @@ -95,8 +95,17 @@ handle_search_button_click(UNUSED GtkButton *button, ); } +static void +handle_settings_button_click(UNUSED GtkButton *button, + gpointer user_data) +{ + MESSENGER_Application *app = (MESSENGER_Application*) user_data; + ui_play_media_window_init(app, &(app->ui.play_media)); + gtk_widget_show(GTK_WIDGET(app->ui.play_media.window)); +} + UI_PICKER_Handle* -ui_picker_new(UNUSED MESSENGER_Application *app, +ui_picker_new(MESSENGER_Application *app, UI_CHAT_Handle *chat) { UI_PICKER_Handle *handle = g_malloc(sizeof(UI_PICKER_Handle)); @@ -244,6 +253,13 @@ ui_picker_new(UNUSED MESSENGER_Application *app, gtk_builder_get_object(handle->builder, "settings_button") ); + g_signal_connect( + handle->settings_button, + "clicked", + G_CALLBACK(handle_settings_button_click), + app + ); + return handle; } diff --git a/src/ui/play_media.c b/src/ui/play_media.c @@ -0,0 +1,287 @@ +/* + This file is part of GNUnet. + Copyright (C) 2022 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file ui/play_media.c + */ + +#include "play_media.h" + +#include "../application.h" +#include "../ui.h" + +static void +handle_back_button_click(GtkButton *button, + gpointer user_data) +{ + GtkWindow *window = GTK_WINDOW(user_data); + gtk_window_close(window); +} + +static void +_pause_playing_media(UI_PLAY_MEDIA_Handle *handle) +{ + // + + handle->playing = FALSE; +} + +static void +_continue_playing_media(UI_PLAY_MEDIA_Handle *handle) +{ + // + + handle->playing = TRUE; +} + +static void +handle_play_pause_button_click(GtkButton *button, + gpointer user_data) +{ + UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) user_data; + + if (handle->playing) + _pause_playing_media(handle); + else + _continue_playing_media(handle); + + gtk_stack_set_visible_child_name( + handle->play_symbol_stack, + handle->playing? "pause_page" : "play_page" + ); +} + +static void +handle_fullscreen_button_click(GtkButton *button, + gpointer user_data) +{ + UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) user_data; + + gtk_revealer_set_reveal_child(handle->header_revealer, handle->fullscreen); + hdy_flap_set_reveal_flap(handle->controls_flap, handle->fullscreen); + + handle->fullscreen = !(handle->fullscreen); + + if (!(handle->fullscreen)) + gtk_window_unfullscreen(GTK_WINDOW(handle->window)); + + gtk_widget_hide(GTK_WIDGET(handle->window)); + + gtk_window_set_type_hint( + GTK_WINDOW(handle->window), + handle->fullscreen? + GDK_WINDOW_TYPE_HINT_NORMAL : + GDK_WINDOW_TYPE_HINT_DIALOG + ); + + gtk_window_set_modal(GTK_WINDOW(handle->window), !(handle->fullscreen)); + + gtk_window_set_position( + GTK_WINDOW(handle->window), + handle->fullscreen? GTK_WIN_POS_NONE : GTK_WIN_POS_CENTER_ON_PARENT + ); + + gtk_window_set_transient_for( + GTK_WINDOW(handle->window), + handle->fullscreen? NULL : handle->parent + ); + + gtk_widget_show_all(GTK_WIDGET(handle->window)); + + if (handle->fullscreen) + gtk_window_fullscreen(GTK_WINDOW(handle->window)); + + gtk_stack_set_visible_child_name( + handle->fullscreen_symbol_stack, + handle->fullscreen? "scale_down_page" : "scale_up_page" + ); +} + +static gboolean +handle_media_motion_lost(gpointer user_data) +{ + UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) user_data; + + if (!(hdy_flap_get_reveal_flap(handle->controls_flap))) + return FALSE; + + hdy_flap_set_reveal_flap(handle->controls_flap, FALSE); + handle->motion_lost = 0; + return FALSE; +} + +static gboolean +handle_media_motion_notify(GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) user_data; + + if (hdy_flap_get_reveal_flap(handle->controls_flap)) + return FALSE; + + if (handle->motion_lost) + g_source_remove(handle->motion_lost); + + hdy_flap_set_reveal_flap(handle->controls_flap, TRUE); + handle->motion_lost = g_timeout_add_seconds( + 3, + G_SOURCE_FUNC(handle_media_motion_lost), + handle + ); + + return FALSE; +} + +static void +handle_window_destroy(UNUSED GtkWidget *window, + gpointer user_data) +{ + ui_play_media_window_cleanup((UI_PLAY_MEDIA_Handle*) user_data); +} + +void +ui_play_media_window_init(MESSENGER_Application *app, + UI_PLAY_MEDIA_Handle *handle) +{ + GNUNET_assert((app) && (handle)); + + handle->parent = GTK_WINDOW(app->ui.messenger.main_window); + + handle->builder = gtk_builder_new_from_resource( + application_get_resource_path(app, "ui/play_media.ui") + ); + + handle->window = HDY_WINDOW( + gtk_builder_get_object(handle->builder, "play_media_window") + ); + + gtk_window_set_position( + GTK_WINDOW(handle->window), + GTK_WIN_POS_CENTER_ON_PARENT + ); + + gtk_window_set_transient_for( + GTK_WINDOW(handle->window), + handle->parent + ); + + handle->header_revealer = GTK_REVEALER( + gtk_builder_get_object(handle->builder, "header_revealer") + ); + + handle->title_bar = HDY_HEADER_BAR( + gtk_builder_get_object(handle->builder, "title_bar") + ); + + hdy_header_bar_set_title(handle->title_bar, _("Play Media")); + + handle->back_button = GTK_BUTTON( + gtk_builder_get_object(handle->builder, "back_button") + ); + + g_signal_connect( + handle->back_button, + "clicked", + G_CALLBACK(handle_back_button_click), + handle->window + ); + + handle->controls_flap = HDY_FLAP( + gtk_builder_get_object(handle->builder, "controls_flap") + ); + + handle->play_pause_button = GTK_BUTTON( + gtk_builder_get_object(handle->builder, "play_pause_button") + ); + + handle->play_symbol_stack = GTK_STACK( + gtk_builder_get_object(handle->builder, "play_symbol_stack") + ); + + g_signal_connect( + handle->play_pause_button, + "clicked", + G_CALLBACK(handle_play_pause_button_click), + handle + ); + + handle->volume_button = GTK_VOLUME_BUTTON( + gtk_builder_get_object(handle->builder, "volume_button") + ); + + handle->timeline_label = GTK_LABEL( + gtk_builder_get_object(handle->builder, "timeline_label") + ); + + handle->settings_button = GTK_BUTTON( + gtk_builder_get_object(handle->builder, "settings_button") + ); + + handle->fullscreen_button = GTK_BUTTON( + gtk_builder_get_object(handle->builder, "fullscreen_button") + ); + + handle->fullscreen_symbol_stack = GTK_STACK( + gtk_builder_get_object(handle->builder, "fullscreen_symbol_stack") + ); + + g_signal_connect( + handle->fullscreen_button, + "clicked", + G_CALLBACK(handle_fullscreen_button_click), + handle + ); + + g_signal_connect( + handle->window, + "motion-notify-event", + G_CALLBACK(handle_media_motion_notify), + handle + ); + + gtk_widget_add_events( + GTK_WIDGET(handle->window), + GDK_POINTER_MOTION_HINT_MASK | + GDK_POINTER_MOTION_MASK + ); + + g_signal_connect( + handle->window, + "destroy", + G_CALLBACK(handle_window_destroy), + handle + ); + + gtk_widget_show_all(GTK_WIDGET(handle->window)); +} + +void +ui_play_media_window_cleanup(UI_PLAY_MEDIA_Handle *handle) +{ + GNUNET_assert(handle); + + g_object_unref(handle->builder); + + if (handle->motion_lost) + g_source_remove(handle->motion_lost); + + memset(handle, 0, sizeof(*handle)); +} diff --git a/src/ui/play_media.h b/src/ui/play_media.h @@ -0,0 +1,79 @@ +/* + This file is part of GNUnet. + Copyright (C) 2022 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file ui/play_media.h + */ + +#ifndef UI_PLAY_MEDIA_H_ +#define UI_PLAY_MEDIA_H_ + +#include "messenger.h" + +typedef struct UI_PLAY_MEDIA_Handle +{ + gboolean playing; + gboolean fullscreen; + + GtkWindow *parent; + + GtkBuilder *builder; + HdyWindow *window; + + GtkRevealer *header_revealer; + HdyHeaderBar *title_bar; + GtkButton *back_button; + + HdyFlap *controls_flap; + GtkButton *play_pause_button; + GtkStack *play_symbol_stack; + + GtkVolumeButton *volume_button; + GtkLabel *timeline_label; + + GtkButton *settings_button; + + GtkButton *fullscreen_button; + GtkStack *fullscreen_symbol_stack; + + guint motion_lost; +} UI_PLAY_MEDIA_Handle; + +/** + * Initializes a handle for the play media window + * of a given messenger application. + * + * @param app Messenger application + * @param handle Play media window handle + */ +void +ui_play_media_window_init(MESSENGER_Application *app, + UI_PLAY_MEDIA_Handle *handle); + +/** + * Cleans up the allocated resources and resets the + * state of a given play media window handle. + * + * @param handle Play media window handle + */ +void +ui_play_media_window_cleanup(UI_PLAY_MEDIA_Handle *handle); + +#endif /* UI_PLAY_MEDIA_H_ */