Redesign / refactor

parent 8238ff70
......@@ -2,6 +2,5 @@
<gresources>
<gresource prefix="/de/haeckerfelix/Remotely">
<file>ui/window.ui</file>
<file>ui/vnc-box.ui</file>
</gresource>
</gresources>
This diff is collapsed.
This diff is collapsed.
vala_sources = [
'remotely-app.vala',
'remotely-window.vala',
'remotely-vnc-box.vala',
'remotely-window.vala'
]
deps = [
......@@ -26,4 +25,4 @@ executable(
vala_args: vala_args,
c_args: c_args,
install: true
)
\ No newline at end of file
)
/* remotely-vnc-box.vala
*
* Copyright (C) 2018 Felix Häcker
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Vnc;
using Gtk;
public enum Remotely.ZoomMode{
FIT_WINDOW,
BEST_FIT,
ORIGINAL_SIZE
}
[GtkTemplate (ui = "/de/haeckerfelix/Remotely/ui/vnc-box.ui")]
public class Remotely.VncBox : Box {
private Display display;
[GtkChild] Box vnc_box;
[GtkChild] ScrolledWindow scrolled_window;
[GtkChild] Stack connection_stack;
[GtkChild] Label status_label;
[GtkChild] Revealer notification_revealer;
[GtkChild] Stack notification_stack;
[GtkChild] Label notification_label;
[GtkChild] Entry username_entry;
[GtkChild] Label username_label;
[GtkChild] Entry clientname_entry;
[GtkChild] Label clientname_label;
[GtkChild] Entry password_entry;
[GtkChild] Label password_label;
public string host;
public string port;
private ZoomMode zoom_mode;
public VncBox (string host, string port) {
this.name = host;
this.host = host;
this.port = port;
display = new Display();
//display.depth = DisplayDepthColor.MEDIUM;
display.local_pointer = true;
//display.lossy_encoding = true;
vnc_box.add(display);
connect_to_client();
connect_signals();
this.show_all();
}
private void connect_signals(){
display.vnc_connected.connect(() => {
status_label.set_text("Waiting for host...");
});
display.vnc_disconnected.connect(() => {
status_label.set_text("Disconnected");
connection_stack.set_visible_child_name("error");
});
display.vnc_initialized.connect(() => {
connection_stack.set_visible_child_name("vnc");
});
display.vnc_auth_credential.connect((authlist) => {
status_label.set_text("Waiting for authentication...");
show_password_entry(authlist);
});
display.vnc_auth_failure.connect((error) => {
show_notification("Authentication error");
connection_stack.set_visible_child_name("error");
});
display.vnc_error.connect((error) => {
show_notification(error);
connection_stack.set_visible_child_name("error");
});
display.vnc_auth_unsupported.connect(() => {
show_notification("Authentication is not supported");
connection_stack.set_visible_child_name("error");
});
this.size_allocate.connect(() => {
update_zoom_mode();
});
}
private void connect_to_client(){
status_label.set_text("Establishing connection...");
display.open_host(host,port);
}
public void disconnect_from_client(){
display.close();
this.destroy();
}
public void set_view_only(bool b){
display.read_only = b;
}
public void send_keys(uint[] keys){
display.send_keys(keys);
}
public void set_zoom_mode(ZoomMode mode){
zoom_mode = mode;
update_zoom_mode();
}
public ZoomMode get_zoom_mode(){
return zoom_mode;
}
private void update_zoom_mode(){
// Set defaults
display.expand = false;
display.set_scaling(false);
scrolled_window.hscrollbar_policy = PolicyType.ALWAYS;
scrolled_window.vscrollbar_policy = PolicyType.ALWAYS;
vnc_box.set_halign(Gtk.Align.FILL);
vnc_box.set_valign(Gtk.Align.FILL);
switch(zoom_mode){
case ZoomMode.FIT_WINDOW: {
scrolled_window.hscrollbar_policy = PolicyType.NEVER;
scrolled_window.vscrollbar_policy = PolicyType.NEVER;
display.expand = true;
display.set_scaling(true);
display.height_request = 0;
display.width_request = 0;
break;
}
case ZoomMode.BEST_FIT: {
display.set_scaling(true);
int new_width;
int new_height;
optiscale(this.get_allocated_width(), this.get_allocated_height(), display.width, display.height, out new_width, out new_height);
display.width_request = new_width;
display.height_request = new_height;
vnc_box.set_halign(Gtk.Align.CENTER);
vnc_box.set_valign(Gtk.Align.CENTER);
break;
}
case ZoomMode.ORIGINAL_SIZE: {
display.height_request = display.height;
display.width_request = display.width;
break;
}
}
}
private void show_notification(string text){
notification_label.set_label(text);
notification_revealer.set_reveal_child(true);
notification_stack.set_visible_child_name("notification");
}
private void show_password_entry(ValueArray authlist){
notification_revealer.set_reveal_child(true);
notification_stack.set_visible_child_name("auth");
username_entry.set_visible(false);
username_label.set_visible(false);
clientname_entry.set_visible(false);
clientname_label.set_visible(false);
password_entry.set_visible(false);
password_label.set_visible(false);
foreach (Value val in authlist.values) {
DisplayCredential cred = (DisplayCredential)val.get_enum();
switch(cred){
case DisplayCredential.PASSWORD: password_entry.set_visible(true); password_label.set_visible(true); break;
case DisplayCredential.USERNAME: username_entry.set_visible(true); username_label.set_visible(true); break;
case DisplayCredential.CLIENTNAME: clientname_entry.set_visible(true); clientname_label.set_visible(true); break;
}
}
}
[GtkCallback]
private void reconnect_button_clicked(){
connect_to_client();
}
[GtkCallback]
private void notification_close_button_clicked(){
notification_revealer.set_reveal_child(false);
}
[GtkCallback]
private void password_cancel_button_clicked(){
notification_revealer.set_reveal_child(false);
display.close();
}
[GtkCallback]
private void passwort_connect_button_clicked(){
notification_revealer.set_reveal_child(false);
display.set_credential(DisplayCredential.PASSWORD, password_entry.get_text());
display.set_credential(DisplayCredential.USERNAME, username_entry.get_text());
display.set_credential(DisplayCredential.CLIENTNAME, clientname_entry.get_text());
}
private void optiscale(int box_width, int box_height, int image_width, int image_height, out int new_width, out int new_height){
new_width = image_width;
new_height = image_height;
// first check if we need to scale width
if (image_width > box_width) {
//scale width to fit
new_width = box_width;
//scale height to maintain aspect ratio
new_height = (new_width * image_height) / image_width;
}
// then check if we need to scale even with the new height
if (new_height > box_height) {
//scale height to fit instead
new_height = box_height;
//scale width to maintain aspect ratio
new_width = (new_height * image_width) / image_height;
}
}
}
......@@ -19,116 +19,251 @@
using Vnc;
using Gtk;
public enum ZoomMode{
FIT_WINDOW,
BEST_FIT,
ORIGINAL_SIZE
}
[GtkTemplate (ui = "/de/haeckerfelix/Remotely/ui/window.ui")]
public class Remotely.Window : Gtk.ApplicationWindow {
[GtkChild] Entry connect_entry;
[GtkChild] CheckButton view_only_checkbutton;
[GtkChild] Popover new_connection_popover;
[GtkChild] Stack connect_stack;
[GtkChild] Revealer connection_revealer;
[GtkChild] Notebook vnc_notebook;
[GtkChild] Stack vnc_stack;
[GtkChild] HeaderBar header_bar;
[GtkChild] Revealer connection_revealer;
[GtkChild] RadioButton view_original_size;
[GtkChild] RadioButton view_fit_to_window;
[GtkChild] RadioButton view_optiscale;
[GtkChild] CheckButton view_only_checkbutton;
[GtkChild] Revealer notification_revealer;
[GtkChild] Label notification_label;
[GtkChild] Box vnc_display_box;
[GtkChild] ScrolledWindow scrolled_window;
[GtkChild] Entry username_entry;
[GtkChild] Label username_label;
[GtkChild] Entry clientname_entry;
[GtkChild] Label clientname_label;
[GtkChild] Entry password_entry;
[GtkChild] Label password_label;
private Display display;
private ZoomMode zoom_mode = ZoomMode.BEST_FIT;
private string host = "localhost";
private string port = "5900";
public Window (Gtk.Application app) {
Object (application: app);
vnc_notebook.page_added.connect(update_view);
vnc_notebook.page_removed.connect(update_view);
vnc_notebook.switch_page.connect((page, num) => {
VncBox cbox = (VncBox)page;
header_bar.set_subtitle("%s:%s".printf(cbox.host, cbox.port));
switch(cbox.get_zoom_mode()){
case ZoomMode.BEST_FIT: view_optiscale.set_active(true); break;
case ZoomMode.FIT_WINDOW: view_fit_to_window.set_active(true); break;
case ZoomMode.ORIGINAL_SIZE: view_original_size.set_active(true); break;
display = new Display();
display.local_pointer = true;
display.set_visible(true);
vnc_display_box.add(display);
connect_signals();
}
private void establish_connection(){
connect_stack.set_visible_child_name("loading");
display.open_host(host,port);
}
private void disconnect_connection(){
display.close();
}
private void authenticate_connection (ValueArray authlist){
connect_stack.set_visible_child_name("authenticate");
username_entry.set_visible(false);
username_label.set_visible(false);
clientname_entry.set_visible(false);
clientname_label.set_visible(false);
password_entry.set_visible(false);
password_label.set_visible(false);
foreach (Value val in authlist.values) {
DisplayCredential cred = (DisplayCredential)val.get_enum();
switch(cred){
case DisplayCredential.PASSWORD: password_entry.set_visible(true); password_label.set_visible(true); break;
case DisplayCredential.USERNAME: username_entry.set_visible(true); username_label.set_visible(true); break;
case DisplayCredential.CLIENTNAME: clientname_entry.set_visible(true); clientname_label.set_visible(true); break;
}
});
}
}
private void show_notification(string text){
notification_label.set_label(text);
notification_revealer.set_reveal_child(true);
}
private void connect_signals(){
display.vnc_connected.connect(() => {
connect_stack.set_visible_child_name("loading");
});
display.vnc_disconnected.connect(() => {
connect_stack.set_visible_child_name("host");
vnc_stack.set_visible_child_name("new-connection");
connection_revealer.set_reveal_child(false);
});
display.vnc_initialized.connect(() => {
vnc_stack.set_visible_child_name("connection");
connection_revealer.set_reveal_child(true);
});
display.vnc_auth_credential.connect((authlist) => {
authenticate_connection(authlist);
});
display.vnc_auth_failure.connect((error) => {
show_notification("Authentication error");
vnc_stack.set_visible_child_name("new-connection");
});
display.vnc_error.connect((error) => {
show_notification(error);
vnc_stack.set_visible_child_name("new-connection");
connection_revealer.set_reveal_child(false);
});
display.vnc_auth_unsupported.connect(() => {
show_notification("Authentication is not supported");
vnc_stack.set_visible_child_name("new-connection");
});
this.size_allocate.connect(() => {
update_zoom_mode();
});
}
[GtkCallback]
private void connect_button_clicked(){
string[] connection = (connect_entry.get_text()).split(":");
if(connection[1] == null) connection[1] = "5900";
if(int.parse(connection[1]) < 5900) connection[1] = (int.parse(connection[1])+5900).to_string();
VncBox cbox = new VncBox(connection[0],connection[1]);
cbox.set_zoom_mode(ZoomMode.BEST_FIT);
host = connection[0];
port = connection[1];
Gtk.Box titlebox = new Gtk.Box(Orientation.HORIZONTAL,0);
Gtk.Label title = new Gtk.Label (connect_entry.get_text());
title.expand = true;
Gtk.Button close_button = new Gtk.Button.from_icon_name("window-close-symbolic", IconSize.MENU);
close_button.clicked.connect(() => {cbox.disconnect_from_client();});
close_button.relief = ReliefStyle.NONE;
titlebox.add(title);
titlebox.add(close_button);
titlebox.expand = true;
titlebox.show_all();
vnc_notebook.append_page(cbox, titlebox);
vnc_notebook.set_current_page(vnc_notebook.page_num(cbox));
vnc_notebook.set_tab_reorderable(cbox,true);
new_connection_popover.hide();
connect_entry.set_text("");
establish_connection();
update_zoom_mode();
}
[GtkCallback]
private void disconnect_button_clicked(){
get_current_vnc_box().disconnect_from_client();
disconnect_connection();
}
[GtkCallback]
private void authenticate_button_clicked(){
display.set_credential(DisplayCredential.PASSWORD, password_entry.get_text());
display.set_credential(DisplayCredential.USERNAME, username_entry.get_text());
display.set_credential(DisplayCredential.CLIENTNAME, clientname_entry.get_text());
}
[GtkCallback]
private void view_best_fit_button_clicked(){
get_current_vnc_box().set_zoom_mode(ZoomMode.BEST_FIT);
zoom_mode = ZoomMode.BEST_FIT;
update_zoom_mode();
}
[GtkCallback]
private void view_fit_window_button_clicked(){
get_current_vnc_box().set_zoom_mode(ZoomMode.FIT_WINDOW);
zoom_mode = ZoomMode.FIT_WINDOW;
update_zoom_mode();
}
[GtkCallback]
private void view_original_size_button_clicked(){
get_current_vnc_box().set_zoom_mode(ZoomMode.ORIGINAL_SIZE);
zoom_mode = ZoomMode.ORIGINAL_SIZE;
update_zoom_mode();
}
[GtkCallback]
private void view_only_button_clicked(){
get_current_vnc_box().set_view_only(view_only_checkbutton.active);
display.read_only = view_only_checkbutton.active;
}
[GtkCallback]
private void ctrlaltdel_clicked(){
uint[] keys = {0xFFE3, 0xFFE9, 0xFFFF};
get_current_vnc_box().send_keys(keys);
display.send_keys(keys);
}
private VncBox get_current_vnc_box() {
return (VncBox)vnc_notebook.get_nth_page(vnc_notebook.get_current_page());
[GtkCallback]
private void notification_close_button_clicked(){
notification_revealer.set_reveal_child(false);
}
private void update_view(){
if(vnc_notebook.get_n_pages() > 1) vnc_notebook.show_tabs = true;
else vnc_notebook.show_tabs = false;
private void update_zoom_mode(){
// Set defaults
display.expand = false;
display.set_scaling(false);
scrolled_window.hscrollbar_policy = PolicyType.ALWAYS;
scrolled_window.vscrollbar_policy = PolicyType.ALWAYS;
vnc_display_box.set_halign(Gtk.Align.FILL);
vnc_display_box.set_valign(Gtk.Align.FILL);
// Hide notebook bar if there is only one connection
if(vnc_notebook.get_n_pages() == 0){
vnc_stack.set_visible_child_name("no-connection");
header_bar.set_subtitle("");
connection_revealer.set_reveal_child(false);
// Show notebook bar to switch between connections
}else{
vnc_stack.set_visible_child_name("notebook");
connection_revealer.set_reveal_child(true);
switch(zoom_mode){
case ZoomMode.FIT_WINDOW: {
scrolled_window.hscrollbar_policy = PolicyType.NEVER;
scrolled_window.vscrollbar_policy = PolicyType.NEVER;
display.expand = true;
display.set_scaling(true);
display.height_request = 0;
display.width_request = 0;
break;
}
case ZoomMode.BEST_FIT: {
display.set_scaling(true);
int new_width;
int new_height;
optiscale(vnc_stack.get_allocated_width(), vnc_stack.get_allocated_height(), display.width, display.height, out new_width, out new_height);
display.width_request = new_width;
display.height_request = new_height;
vnc_display_box.set_halign(Gtk.Align.CENTER);
vnc_display_box.set_valign(Gtk.Align.CENTER);
break;
}
case ZoomMode.ORIGINAL_SIZE: {
display.height_request = display.height;
display.width_request = display.width;
break;
}
}
}
private void optiscale(int box_width, int box_height, int image_width, int image_height, out int new_width, out int new_height){
new_width = image_width;
new_height = image_height;
// first check if we need to scale width
if (image_width > box_width) {
//scale width to fit
new_width = box_width;
//scale height to maintain aspect ratio
new_height = (new_width * image_height) / image_width;
}
// then check if we need to scale even with the new height
if (new_height > box_height) {
//scale height to fit instead
new_height = box_height;
//scale width to maintain aspect ratio
new_width = (new_height * image_width) / image_height;
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment