aboutsummaryrefslogtreecommitdiff
path: root/main/src/ui/call_window/call_window.vala
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/ui/call_window/call_window.vala')
-rw-r--r--main/src/ui/call_window/call_window.vala262
1 files changed, 138 insertions, 124 deletions
diff --git a/main/src/ui/call_window/call_window.vala b/main/src/ui/call_window/call_window.vala
index 3b3d4dc2..c610444f 100644
--- a/main/src/ui/call_window/call_window.vala
+++ b/main/src/ui/call_window/call_window.vala
@@ -1,87 +1,155 @@
+using Gee;
+using Xmpp;
using Dino.Entities;
using Gtk;
namespace Dino.Ui {
public class CallWindow : Gtk.Window {
- public string counterpart_display_name { get; set; }
- // TODO should find another place for this
+ public signal void menu_dump_dot();
+
public CallWindowController controller;
public Overlay overlay = new Overlay() { visible=true };
+ public Grid grid = new Grid() { visible=true };
public EventBox event_box = new EventBox() { visible=true };
public CallBottomBar bottom_bar = new CallBottomBar() { visible=true };
public Revealer bottom_bar_revealer = new Revealer() { valign=Align.END, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200, visible=true };
- public HeaderBar header_bar = new HeaderBar() { show_close_button=true, visible=true };
- public Revealer header_bar_revealer = new Revealer() { valign=Align.START, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200, visible=true };
- public Stack stack = new Stack() { visible=true };
- public Box own_video_box = new Box(Orientation.HORIZONTAL, 0) { expand=true, visible=true };
+ public HeaderBar header_bar = new HeaderBar() { valign=Align.START, halign=Align.END, show_close_button=true, visible=true };
+ public Revealer header_bar_revealer = new Revealer() { halign=Align.END, valign=Align.START, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200, visible=true };
+ public Box own_video_box = new Box(Orientation.HORIZONTAL, 0) { halign=Align.END, valign=Align.END, visible=true };
+ public Revealer invite_button_revealer = new Revealer() { margin_top=50, margin_right=30, halign=Align.END, valign=Align.START, transition_type=RevealerTransitionType.CROSSFADE, transition_duration=200 };
+ public Button invite_button = new Button.from_icon_name("dino-account-plus") { relief=ReliefStyle.NONE, visible=false };
private Widget? own_video = null;
- private Box? own_video_border = new Box(Orientation.HORIZONTAL, 0) { expand=true }; // hack to draw a border around our own video, since we apparently can't draw a border around the Gst widget
+ private HashMap<string, ParticipantWidget> participant_widgets = new HashMap<string, ParticipantWidget>();
+ private ArrayList<string> participants = new ArrayList<string>();
private int own_video_width = 150;
private int own_video_height = 100;
- private bool hide_controll_elements = false;
- private uint hide_controll_handler = 0;
- private Widget? main_widget = null;
+ private bool hide_control_elements = false;
+ private uint hide_control_handler = 0;
+ public bool controls_active { get; set; default=true; }
construct {
+ Util.force_css(header_bar, "* { background: none; border: 0; border-radius: 0; }");
header_bar.get_style_context().add_class("call-header-bar");
header_bar_revealer.add(header_bar);
+ bottom_bar_revealer.add(bottom_bar);
+ invite_button.get_style_context().add_class("black-element");
+ invite_button_revealer.add(invite_button);
+ own_video_box.get_style_context().add_class("own-video");
this.get_style_context().add_class("dino-call-window");
- bottom_bar_revealer.add(bottom_bar);
-
+ overlay.add(grid);
overlay.add_overlay(own_video_box);
- overlay.add_overlay(own_video_border);
overlay.add_overlay(bottom_bar_revealer);
overlay.add_overlay(header_bar_revealer);
+ overlay.add_overlay(invite_button_revealer);
+ overlay.get_child_position.connect(on_get_child_position);
event_box.add(overlay);
add(event_box);
-
- Util.force_css(own_video_border, "* { border: 1px solid #616161; background-color: transparent; }");
}
public CallWindow() {
- event_box.events |= Gdk.EventMask.POINTER_MOTION_MASK;
- event_box.events |= Gdk.EventMask.ENTER_NOTIFY_MASK;
- event_box.events |= Gdk.EventMask.LEAVE_NOTIFY_MASK;
-
- this.bind_property("counterpart-display-name", header_bar, "title", BindingFlags.SYNC_CREATE);
- this.bind_property("counterpart-display-name", bottom_bar, "counterpart-display-name", BindingFlags.SYNC_CREATE);
+ this.bind_property("controls-active", bottom_bar_revealer, "reveal-child", BindingFlags.SYNC_CREATE);
+ this.bind_property("controls-active", header_bar_revealer, "reveal-child", BindingFlags.SYNC_CREATE);
+ this.bind_property("controls-active", invite_button_revealer, "reveal-child", BindingFlags.SYNC_CREATE);
event_box.motion_notify_event.connect(reveal_control_elements);
event_box.enter_notify_event.connect(reveal_control_elements);
event_box.leave_notify_event.connect(reveal_control_elements);
this.configure_event.connect(reveal_control_elements); // upon resizing
- this.configure_event.connect(update_own_video_position);
+
+ this.configure_event.connect(reposition_participant_widgets);
this.set_titlebar(new OutsideHeaderBar(this.header_bar) { visible=true });
reveal_control_elements();
}
- public void set_video_fallback(StreamInteractor stream_interactor, Conversation conversation) {
- hide_controll_elements = false;
+ public void add_participant(string participant, ParticipantWidget participant_widget) {
+ participant_widget.visible = true;
+ this.bind_property("controls-active", participant_widget, "controls-active", BindingFlags.SYNC_CREATE);
+ this.bind_property("controls-active", participant_widget.encryption_button, "controls-active", BindingFlags.SYNC_CREATE);
+
+ participants.add(participant);
+ participant_widgets[participant] = participant_widget;
+ grid.attach(participant_widget, 0, 0);
+
+ reposition_participant_widgets();
+ }
+
+ public void remove_participant(string participant) {
+ participants.remove(participant);
+ grid.remove(participant_widgets[participant]);
+ participant_widgets.unset(participant);
- Box box = new Box(Orientation.HORIZONTAL, 0) { visible=true };
- box.get_style_context().add_class("video-placeholder-box");
- AvatarImage avatar = new AvatarImage() { hexpand=true, vexpand=true, halign=Align.CENTER, valign=Align.CENTER, height=100, width=100, visible=true };
- avatar.set_conversation(stream_interactor, conversation);
- box.add(avatar);
+ reposition_participant_widgets();
+ }
- set_new_main_widget(box);
+ public void set_video(string participant, Widget widget) {
+ participant_widgets[participant].set_video(widget);
+ hide_control_elements = true;
+ timeout_hide_control_elements();
}
- public void set_video(Widget widget) {
- hide_controll_elements = true;
+ public void set_placeholder(string participant, Conversation? conversation, StreamInteractor stream_interactor) {
+ participant_widgets[participant].set_placeholder(conversation, stream_interactor);
+ hide_control_elements = false;
+ foreach (ParticipantWidget participant_widget in participant_widgets.values) {
+ if (participant_widget.shows_video) {
+ hide_control_elements = true;
+ }
+ }
- widget.visible = true;
- set_new_main_widget(widget);
+ if (!hide_control_elements) {
+ reveal_control_elements();
+ }
+ }
+
+ private bool reposition_participant_widgets() {
+ int width, height;
+ this.get_size(out width,out height);
+ reposition_participant_widgets_rec(participants, width, height, 0, 0, 0, 0);
+ return false;
+ }
+
+ private void reposition_participant_widgets_rec(ArrayList<string> participants, int width, int height, int margin_top, int margin_right, int margin_bottom, int margin_left) {
+ if (participants.size == 0) return;
+
+ if (participants.size == 1) {
+ participant_widgets[participants[0]].margin_top = margin_top;
+ participant_widgets[participants[0]].margin_end = margin_right;
+ participant_widgets[participants[0]].margin_bottom = margin_bottom;
+ participant_widgets[participants[0]].margin_start = margin_left;
+
+ participant_widgets[participants[0]].on_lowest_row_changed(margin_bottom == 0);
+ participant_widgets[participants[0]].on_highest_row_changed(margin_top == 0);
+ return;
+ }
+
+ ArrayList<string> first_part = new ArrayList<string>();
+ ArrayList<string> last_part = new ArrayList<string>();
+
+ for (int i = 0; i < participants.size; i++) {
+ if (i < Math.ceil((double)participants.size / (double)2)) {
+ first_part.add(participants[i]);
+ } else {
+ last_part.add(participants[i]);
+ }
+ }
+
+ if (width > height) {
+ reposition_participant_widgets_rec(first_part, width / 2, height, margin_top, margin_right + width / 2, margin_bottom, margin_left);
+ reposition_participant_widgets_rec(last_part, width / 2, height, margin_top, margin_right, margin_bottom, margin_left + width / 2);
+ } else {
+ reposition_participant_widgets_rec(first_part, width, height / 2, margin_top, margin_right, margin_bottom + height / 2, margin_left);
+ reposition_participant_widgets_rec(last_part, width, height / 2, margin_top + height / 2, margin_right, margin_bottom, margin_left);
+ }
}
public void set_own_video(Widget? widget_) {
@@ -92,13 +160,7 @@ namespace Dino.Ui {
own_video = new Box(Orientation.HORIZONTAL, 0) { expand=true };
}
own_video.visible = true;
- own_video.width_request = 150;
- own_video.height_request = 100;
own_video_box.add(own_video);
-
- own_video_border.visible = true;
-
- update_own_video_position();
}
public void set_own_video_ratio(int width, int height) {
@@ -109,78 +171,25 @@ namespace Dino.Ui {
this.own_video_width = width * 100 / height;
this.own_video_height = 100;
}
-
- own_video.width_request = own_video_width;
- own_video.height_request = own_video_height;
-
- update_own_video_position();
}
public void unset_own_video() {
own_video_box.foreach((widget) => { own_video_box.remove(widget); });
-
- own_video_border.visible = false;
- }
-
- public void set_test_video() {
- hide_controll_elements = true;
-
- var pipeline = new Gst.Pipeline(null);
- var src = Gst.ElementFactory.make("videotestsrc", null);
- pipeline.add(src);
- Gst.Video.Sink sink = (Gst.Video.Sink) Gst.ElementFactory.make("gtksink", null);
- Gtk.Widget widget;
- sink.get("widget", out widget);
- widget.unparent();
- pipeline.add(sink);
- src.link(sink);
- widget.visible = true;
-
- pipeline.set_state(Gst.State.PLAYING);
-
- sink.get_static_pad("sink").notify["caps"].connect(() => {
- int width, height;
- sink.get_static_pad("sink").caps.get_structure(0).get_int("width", out width);
- sink.get_static_pad("sink").caps.get_structure(0).get_int("height", out height);
- widget.width_request = width;
- widget.height_request = height;
- });
-
- set_new_main_widget(widget);
}
- private void set_new_main_widget(Widget widget) {
- if (main_widget != null) overlay.remove(main_widget);
- overlay.add(widget);
- main_widget = widget;
+ public void set_status(string participant_id, string state) {
+ participant_widgets[participant_id].set_status(state);
}
- public void set_status(string state) {
- switch (state) {
- case "requested":
- header_bar.subtitle = _("Calling…");
- break;
- case "ringing":
- header_bar.subtitle = _("Ringing…");
- break;
- case "establishing":
- header_bar.subtitle = _("Connecting…");
- break;
- default:
- header_bar.subtitle = null;
- break;
- }
- }
-
- public void show_counterpart_ended(string? reason_name, string? reason_text) {
- hide_controll_elements = false;
+ public void show_counterpart_ended(string who_terminated, string? reason_name, string? reason_text) {
+ hide_control_elements = false;
reveal_control_elements();
string text = "";
if (reason_name == Xmpp.Xep.Jingle.ReasonElement.SUCCESS) {
- text = _("%s ended the call").printf(counterpart_display_name);
+ text = _("%s ended the call").printf(who_terminated);
} else if (reason_name == Xmpp.Xep.Jingle.ReasonElement.DECLINE || reason_name == Xmpp.Xep.Jingle.ReasonElement.BUSY) {
- text = _("%s declined the call").printf(counterpart_display_name);
+ text = _("%s declined the call").printf(who_terminated);
} else {
text = "The call has been terminated: " + (reason_name ?? "") + " " + (reason_text ?? "");
}
@@ -188,48 +197,53 @@ namespace Dino.Ui {
bottom_bar.show_counterpart_ended(text);
}
- public bool reveal_control_elements() {
+ private bool reveal_control_elements() {
if (!bottom_bar_revealer.child_revealed) {
- bottom_bar_revealer.set_reveal_child(true);
- header_bar_revealer.set_reveal_child(true);
+ controls_active = true;
}
- if (hide_controll_handler != 0) {
- Source.remove(hide_controll_handler);
- hide_controll_handler = 0;
+ timeout_hide_control_elements();
+ return false;
+ }
+
+ private void timeout_hide_control_elements() {
+ if (hide_control_handler != 0) {
+ Source.remove(hide_control_handler);
+ hide_control_handler = 0;
}
- if (!hide_controll_elements) {
- return false;
+ if (!hide_control_elements) {
+ return;
}
- hide_controll_handler = Timeout.add_seconds(3, () => {
- if (!hide_controll_elements) {
+ hide_control_handler = Timeout.add_seconds(3, () => {
+ if (!hide_control_elements) {
return false;
}
if (bottom_bar.is_menu_active()) {
- return true;
+ return false;
}
- header_bar_revealer.set_reveal_child(false);
- bottom_bar_revealer.set_reveal_child(false);
- hide_controll_handler = 0;
+ controls_active = false;
+
+ hide_control_handler = 0;
return false;
});
- return false;
}
- private bool update_own_video_position() {
- if (own_video == null) return false;
-
- int width, height;
- this.get_size(out width,out height);
-
- own_video.margin_end = own_video.margin_bottom = own_video_border.margin_end = own_video_border.margin_bottom = 20;
- own_video.margin_start = own_video_border.margin_start = width - own_video_width - 20;
- own_video.margin_top = own_video_border.margin_top = height - own_video_height - 20;
-
+ private bool on_get_child_position(Widget widget, out Gdk.Rectangle allocation) {
+ if (widget == own_video_box) {
+ int width, height;
+ this.get_size(out width,out height);
+
+ allocation = Gdk.Rectangle();
+ allocation.width = own_video_width;
+ allocation.height = own_video_height;
+ allocation.x = width - own_video_width - 20;
+ allocation.y = height - own_video_height - 20;
+ return true;
+ }
return false;
}
}