[fractal] Get rid of upgrade_weak! and use glib::clone! where possible



commit 67c7b018b731e7bd1402a219b25c337df332f628
Author: Alejandro Domínguez <adomu net-c com>
Date:   Mon Jul 6 02:25:42 2020 +0200

    Get rid of upgrade_weak! and use glib::clone! where possible

 fractal-gtk/src/actions/account_settings.rs |   7 +-
 fractal-gtk/src/actions/global.rs           |  78 ++++---
 fractal-gtk/src/actions/login.rs            |  51 ++---
 fractal-gtk/src/actions/message.rs          | 102 +++++-----
 fractal-gtk/src/actions/mod.rs              |   8 +-
 fractal-gtk/src/actions/room_settings.rs    |   7 +-
 fractal-gtk/src/app/connect/account.rs      |  22 +-
 fractal-gtk/src/app/connect/direct.rs       |  30 +--
 fractal-gtk/src/app/connect/directory.rs    |  76 ++++---
 fractal-gtk/src/app/connect/headerbar.rs    |  34 ++--
 fractal-gtk/src/app/connect/invite.rs       |  26 ++-
 fractal-gtk/src/app/mod.rs                  |  20 +-
 fractal-gtk/src/appop/notify.rs             |  26 +--
 fractal-gtk/src/appop/room.rs               |   2 -
 fractal-gtk/src/util.rs                     |  15 --
 fractal-gtk/src/widgets/autocomplete.rs     | 123 ++++++-----
 fractal-gtk/src/widgets/divider.rs          |  32 ++-
 fractal-gtk/src/widgets/error_dialog.rs     |   3 +-
 fractal-gtk/src/widgets/inline_player.rs    |  34 ++--
 fractal-gtk/src/widgets/kicked_dialog.rs    |  13 +-
 fractal-gtk/src/widgets/login.rs            |  45 ++---
 fractal-gtk/src/widgets/media_viewer.rs     | 303 ++++++++++++++--------------
 fractal-gtk/src/widgets/message.rs          |  46 ++---
 fractal-gtk/src/widgets/message_menu.rs     |  13 +-
 fractal-gtk/src/widgets/room_history.rs     | 171 ++++++++--------
 fractal-gtk/src/widgets/room_settings.rs    |  22 +-
 fractal-gtk/src/widgets/roomlist.rs         |  98 ++++-----
 fractal-gtk/src/widgets/scroll_widget.rs    | 118 +++++------
 fractal-gtk/src/widgets/source_dialog.rs    |  34 ++--
 29 files changed, 753 insertions(+), 806 deletions(-)
---
diff --git a/fractal-gtk/src/actions/account_settings.rs b/fractal-gtk/src/actions/account_settings.rs
index d1c240d8..1831700b 100644
--- a/fractal-gtk/src/actions/account_settings.rs
+++ b/fractal-gtk/src/actions/account_settings.rs
@@ -6,6 +6,7 @@ use fractal_api::url::Url;
 use gio::prelude::*;
 use gio::SimpleAction;
 use gio::SimpleActionGroup;
+use glib::clone;
 use std::thread;
 
 use crate::app::App;
@@ -28,9 +29,7 @@ pub fn new(
 
     actions.add_action(&change_avatar);
 
-    let window_weak = window.downgrade();
-    change_avatar.connect_activate(move |a, _| {
-        let window = upgrade_weak!(window_weak);
+    change_avatar.connect_activate(clone!(@weak window => move |a, _| {
         let filter = gtk::FileFilter::new();
         filter.add_mime_type("image/*");
         filter.set_name(Some(i18n("Images").as_str()));
@@ -50,7 +49,7 @@ pub fn new(
                 }
             });
         }
-    });
+    }));
 
     actions
 }
diff --git a/fractal-gtk/src/actions/global.rs b/fractal-gtk/src/actions/global.rs
index 18af2ec5..3d2b5d47 100644
--- a/fractal-gtk/src/actions/global.rs
+++ b/fractal-gtk/src/actions/global.rs
@@ -135,11 +135,9 @@ pub fn new(app: &gtk::Application, op: &Arc<Mutex<AppOp>>) {
     app.add_action(&newer_messages);
 
     // When activated, shuts down the application
-    let app_weak = app.downgrade();
-    quit.connect_activate(move |_action, _parameter| {
-        let app = upgrade_weak!(app_weak);
+    quit.connect_activate(clone!(@weak app => move |_action, _parameter| {
         app.quit();
-    });
+    }));
 
     about.connect_activate(clone!(@strong op => move |_, _| op.lock().unwrap().about_dialog() ));
     main_menu.connect_activate(clone!(@strong op => move |_, _| op.lock().unwrap().main_menu() ));
@@ -213,32 +211,33 @@ pub fn new(app: &gtk::Application, op: &Arc<Mutex<AppOp>>) {
 
     let back_history = op.lock().unwrap().room_back_history.clone();
 
-    let back_weak = Rc::downgrade(&back_history);
-    account.connect_activate(clone!(@strong op => move |_, _| {
+    account.connect_activate(clone!(
+    @strong op,
+    @weak back_history as back
+    => move |_, _| {
         op.lock().unwrap().show_account_settings_dialog();
-
-        let back = upgrade_weak!(back_weak);
         back.borrow_mut().push(AppState::AccountSettings);
     }));
 
-    let back_weak = Rc::downgrade(&back_history);
-    directory.connect_activate(clone!(@strong op => move |_, _| {
+    directory.connect_activate(clone!(
+    @strong op,
+    @weak back_history as back
+    => move |_, _| {
         op.lock().unwrap().set_state(AppState::Directory);
-
-    let back = upgrade_weak!(back_weak);
-    back.borrow_mut().push(AppState::Directory);
+        back.borrow_mut().push(AppState::Directory);
     }));
 
     /* TODO: We could pass a message to this to highlight it in the room history, might be
      * handy when opening the room from a notification */
-    let back_weak = Rc::downgrade(&back_history);
-    open_room.connect_activate(clone!(@strong op => move |_, data| {
+    open_room.connect_activate(clone!(
+    @strong op,
+    @weak back_history as back
+    => move |_, data| {
         if let Some(id) = get_room_id(data) {
             op.lock().unwrap().set_active_room_by_id(id);
            /* This does nothing if fractal is already in focus */
             op.lock().unwrap().activate();
         }
-        let back = upgrade_weak!(back_weak);
         // Push a new state only if the current state is not already Room
         let push = if let Some(last) = back.borrow().last() {
             last != &AppState::Room
@@ -250,26 +249,24 @@ pub fn new(app: &gtk::Application, op: &Arc<Mutex<AppOp>>) {
         }
     }));
 
-    let back_weak = Rc::downgrade(&back_history);
-    room_settings.connect_activate(clone!(@strong op => move |_, _| {
+    room_settings.connect_activate(clone!(
+    @strong op,
+    @weak back_history as back
+    => move |_, _| {
         op.lock().unwrap().create_room_settings();
-
-        let back = upgrade_weak!(back_weak);
         back.borrow_mut().push(AppState::RoomSettings);
     }));
 
-    let back_weak = Rc::downgrade(&back_history);
-    media_viewer.connect_activate(move |_, data| {
+    media_viewer.connect_activate(clone!(
+    @weak back_history as back
+    => move |_, data| {
         open_viewer(data);
-
-        let back = upgrade_weak!(back_weak);
         back.borrow_mut().push(AppState::MediaViewer);
-    });
+    }));
 
-    let mv_weak = Rc::downgrade(&op.lock().unwrap().media_viewer);
+    let mv = op.lock().unwrap().media_viewer.clone();
     let back_weak = Rc::downgrade(&back_history);
-    back.connect_activate(move |_, _| {
-        let mv = upgrade_weak!(mv_weak);
+    back.connect_activate(clone!(@weak mv => move |_, _| {
         if let Some(mut mv) = mv.borrow_mut().take() {
             mv.disconnect_signal_id();
         }
@@ -294,17 +291,15 @@ pub fn new(app: &gtk::Application, op: &Arc<Mutex<AppOp>>) {
                 }
             }
         }
-    });
+    }));
 
-    let app_weak = app.downgrade();
-    send_file.connect_activate(move |_, _| {
-        let app = upgrade_weak!(app_weak);
+    send_file.connect_activate(clone!(@weak app => move |_, _| {
         if let Some(window) = app.get_active_window() {
             if let Some(path) = open(&window, i18n("Select a file").as_str(), &[]) {
                 APPOP!(attach_message, (path));
             }
         }
-    });
+    }));
 
     send_message.connect_activate(clone!(@strong op => move |_, _| {
         let msg_entry = op.lock().unwrap().ui.sventry.view.clone();
@@ -344,20 +339,19 @@ pub fn new(app: &gtk::Application, op: &Arc<Mutex<AppOp>>) {
     app.set_accels_for_action("app.main_menu", &["F10"]);
 
     // connect mouse back button to app.back action
-    let app_weak = app.downgrade();
     if let Some(window) = app.get_active_window() {
-        window.connect_button_press_event(move |_, e| {
+        window.connect_button_press_event(clone!(
+        @weak app
+        => @default-return Inhibit(false), move |_, e| {
             if e.get_button() == 8 {
-                if let Some(app) = app_weak.upgrade() {
-                    app.lookup_action("back")
-                        .expect("App did not have back action.")
-                        .activate(None);
-                    return Inhibit(true);
-                }
+                app.lookup_action("back")
+                    .expect("App did not have back action.")
+                    .activate(None);
+                return Inhibit(true);
             }
 
             Inhibit(false)
-        });
+        }));
     }
 
     // TODO: Mark active room as read when window gets focus
diff --git a/fractal-gtk/src/actions/login.rs b/fractal-gtk/src/actions/login.rs
index 19ba0fd9..d971c2f9 100644
--- a/fractal-gtk/src/actions/login.rs
+++ b/fractal-gtk/src/actions/login.rs
@@ -5,6 +5,7 @@ use std::rc::Rc;
 use gio::prelude::*;
 use gio::SimpleAction;
 use gio::SimpleActionGroup;
+use glib::clone;
 use gtk::prelude::*;
 
 use crate::globals;
@@ -59,10 +60,7 @@ pub fn new(
     actions.add_action(&back);
     actions.add_action(&login);
 
-    let stack_weak = stack.downgrade();
-    create_account.connect_activate(move |_, _| {
-        let stack = upgrade_weak!(stack_weak);
-
+    create_account.connect_activate(clone!(@weak stack => move |_, _| {
         let toplevel = stack
             .get_toplevel()
             .expect("Could not grab toplevel widget")
@@ -73,31 +71,24 @@ pub fn new(
         {
             warn!("Could not show {}: {}", uri, e)
         }
-    });
+    }));
 
     let back_history: Rc<RefCell<Vec<LoginState>>> = Rc::new(RefCell::new(vec![]));
 
-    let back_weak = Rc::downgrade(&back_history);
-    let stack_weak = stack.downgrade();
-    server_chooser.connect_activate(move |_, _| {
-        let stack = upgrade_weak!(stack_weak);
-        let back = upgrade_weak!(back_weak);
-
-        let state = LoginState::ServerChooser;
-        stack.set_visible_child_name(&state.to_string());
-        back.borrow_mut().push(state);
-    });
-
-    let back_weak = Rc::downgrade(&back_history);
-    let stack_weak = stack.downgrade();
-    let server_weak = server_entry.downgrade();
-    let err_weak = err_label.downgrade();
-    credentials.connect_activate(move |_, _| {
-        let stack = upgrade_weak!(stack_weak);
-        let back = upgrade_weak!(back_weak);
-        let server_entry = upgrade_weak!(server_weak);
-        let err_label = upgrade_weak!(err_weak);
-
+    server_chooser.connect_activate(
+        clone!(@weak stack, @weak back_history as back => move |_, _| {
+            let state = LoginState::ServerChooser;
+            stack.set_visible_child_name(&state.to_string());
+            back.borrow_mut().push(state);
+        }),
+    );
+
+    credentials.connect_activate(clone!(
+    @weak stack,
+    @weak back_history as back,
+    @weak server_entry,
+    @weak err_label
+    => move |_, _| {
         if let Some(txt) = server_entry.get_text() {
             if txt.is_empty() {
                 err_label.show();
@@ -108,11 +99,9 @@ pub fn new(
                 back.borrow_mut().push(state);
             }
         }
-    });
+    }));
 
-    let stack_weak = stack.downgrade();
-    back.connect_activate(move |_, _| {
-        let stack = upgrade_weak!(stack_weak);
+    back.connect_activate(clone!(@weak stack => move |_, _| {
         back_history.borrow_mut().pop();
         if let Some(state) = back_history.borrow().last() {
             debug!("Go back to state {}", state.to_string());
@@ -121,7 +110,7 @@ pub fn new(
             debug!("There is no state to go back to. Go back to state greeter");
             stack.set_visible_child_name(&LoginState::Greeter.to_string());
         }
-    });
+    }));
 
     gio::Application::get_default().map(|app| {
         app.downcast::<gtk::Application>().map(|gtk_app| {
diff --git a/fractal-gtk/src/actions/message.rs b/fractal-gtk/src/actions/message.rs
index 10b3ed45..17f6ae66 100644
--- a/fractal-gtk/src/actions/message.rs
+++ b/fractal-gtk/src/actions/message.rs
@@ -67,9 +67,7 @@ pub fn new(
         .builder
         .get_object("main_window")
         .expect("Can't find main_window in ui file.");
-    let parent_weak = parent.downgrade();
-    show_source.connect_activate(move |_, data| {
-        let parent = upgrade_weak!(parent_weak);
+    show_source.connect_activate(clone!(@weak parent => move |_, data| {
         let viewer = SourceDialog::new();
         viewer.set_parent_window(&parent);
         if let Some(m) = get_message(data) {
@@ -78,27 +76,25 @@ pub fn new(
 
             viewer.show(source);
         }
-    });
+    }));
 
-    let msg_entry = ui.sventry.view.downgrade();
-    let back_weak = Rc::downgrade(&back_history);
-    let window_weak = ui
+    let window = ui
         .builder
         .get_object::<gtk::ApplicationWindow>("main_window")
-        .expect("Couldn't find main_window in ui file.")
-        .downgrade();
-    reply.connect_activate(move |_, data| {
-        let back_history = upgrade_weak!(back_weak);
+        .expect("Couldn't find main_window in ui file.");
+    reply.connect_activate(clone!(
+    @weak back_history,
+    @weak window,
+    @weak ui.sventry.view as msg_entry
+    => move |_, data| {
         let state = back_history.borrow().last().cloned();
         if let Some(AppState::MediaViewer) = state {
-            let window = upgrade_weak!(window_weak);
             if let Some(action_group) = window.get_action_group("app") {
                 action_group.activate_action("back", None);
             } else {
                 error!("The action group app is not attached to the main window.");
             }
         }
-        let msg_entry = upgrade_weak!(msg_entry);
         if let Some(buffer) = msg_entry.get_buffer() {
             let mut start = buffer.get_start_iter();
             if let Some(m) = get_message(data) {
@@ -114,7 +110,7 @@ pub fn new(
                 msg_entry.grab_focus();
             }
         }
-    });
+    }));
 
     open_with.connect_activate(clone!(@strong server_url => move |_, data| {
         if let Some(m) = get_message(data) {
@@ -136,8 +132,11 @@ pub fn new(
         }
     }));
 
-    let parent_weak = parent.downgrade();
-    save_as.connect_activate(clone!(@strong server_url, @strong thread_pool => move |_, data| {
+    save_as.connect_activate(clone!(
+    @strong server_url,
+    @strong thread_pool,
+    @weak parent as window
+    => move |_, data| {
         if let Some(m) = get_message(data) {
             let name = m.body;
             let url = m.url.unwrap_or_default();
@@ -145,32 +144,33 @@ pub fn new(
             let (tx, rx): (Sender<media::MediaResult>, Receiver<media::MediaResult>) = channel();
             media::get_media_async(thread_pool.clone(), server_url.clone(), url, tx);
 
-            let parent_weak = parent_weak.clone();
             gtk::timeout_add(
                 50,
-                clone!(@strong name => move || match rx.try_recv() {
-                    Err(TryRecvError::Empty) => Continue(true),
-                    Err(TryRecvError::Disconnected) => {
-                        let msg = i18n("Could not download the file");
-                        ErrorDialog::new(false, &msg);
+                clone!(
+                    @strong name,
+                    @weak window
+                    => @default-return Continue(true), move || match rx.try_recv() {
+                        Err(TryRecvError::Empty) => Continue(true),
+                        Err(TryRecvError::Disconnected) => {
+                            let msg = i18n("Could not download the file");
+                            ErrorDialog::new(false, &msg);
 
-                        Continue(true)
-                    },
-                    Ok(Ok(fname)) => {
-                        let window = upgrade_weak!(parent_weak, Continue(true));
-                        if let Some(path) = save(&window, &name, &[]) {
-                            // TODO use glib to copy file
-                            if fs::copy(fname, path).is_err() {
-                                ErrorDialog::new(false, &i18n("Couldn’t save file"));
+                            Continue(true)
+                        },
+                        Ok(Ok(fname)) => {
+                            if let Some(path) = save(&window, &name, &[]) {
+                                // TODO use glib to copy file
+                                if fs::copy(fname, path).is_err() {
+                                    ErrorDialog::new(false, &i18n("Couldn’t save file"));
+                                }
                             }
+                            Continue(false)
                         }
-                        Continue(false)
-                    }
-                    Ok(Err(err)) => {
-                        error!("Media path could not be found due to error: {:?}", err);
-                        Continue(false)
-                    }
-                }),
+                        Ok(Err(err)) => {
+                            error!("Media path could not be found due to error: {:?}", err);
+                            Continue(false)
+                        }
+                    }),
             );
         }
     }));
@@ -223,17 +223,12 @@ pub fn new(
 
     let s = server_url.clone();
     let tk = access_token.clone();
-    let back_weak = Rc::downgrade(&back_history);
-    let window_weak = ui
-        .builder
-        .get_object::<gtk::ApplicationWindow>("main_window")
-        .expect("Couldn't find main_window in ui file.")
-        .downgrade();
-    delete.connect_activate(move |_, data| {
-        let back_history = upgrade_weak!(back_weak);
+    delete.connect_activate(clone!(
+    @weak back_history,
+    @weak window
+    => move |_, data| {
         let state = back_history.borrow().last().cloned();
         if let Some(AppState::MediaViewer) = state {
-            let window = upgrade_weak!(window_weak);
             if let Some(action_group) = window.get_action_group("app") {
                 action_group.activate_action("back", None);
             } else {
@@ -250,14 +245,15 @@ pub fn new(
                 }
             });
         }
-    });
+    }));
 
-    load_more_messages.connect_activate(
-        clone!(@strong server_url, @strong access_token => move |_, data| {
-            let id = get_room_id(data);
-            request_more_messages(server_url.clone(), access_token.clone(), id);
-        }),
-    );
+    load_more_messages.connect_activate(clone!(
+    @strong server_url,
+    @strong access_token
+    => move |_, data| {
+        let id = get_room_id(data);
+        request_more_messages(server_url.clone(), access_token.clone(), id);
+    }));
 
     actions
 }
diff --git a/fractal-gtk/src/actions/mod.rs b/fractal-gtk/src/actions/mod.rs
index 9bc96f5c..18bcd6ac 100644
--- a/fractal-gtk/src/actions/mod.rs
+++ b/fractal-gtk/src/actions/mod.rs
@@ -1,6 +1,6 @@
 use gio::SimpleAction;
+use glib::clone;
 use glib::Cast;
-use glib::ObjectExt;
 use glib::ToVariant;
 use gtk::WidgetExt;
 
@@ -60,15 +60,13 @@ pub trait StateExt {
 // FIXME: workaround till we get GPropertyAction
 impl StateExt for gio::Action {
     fn bind_button_state(&self, button: &gtk::Button) {
-        let button = button.downgrade();
         if let Some(action) = self.downcast_ref::<SimpleAction>() {
-            action.connect_change_state(move |_, data| {
+            action.connect_change_state(clone!(@weak button => move |_, data| {
                 if let Some(data) = data {
                     let state: ButtonState = data.into();
-                    let button = upgrade_weak!(button);
                     button.set_sensitive(state.into());
                 }
-            });
+            }));
         }
     }
 }
diff --git a/fractal-gtk/src/actions/room_settings.rs b/fractal-gtk/src/actions/room_settings.rs
index 0f912f78..9bcfd89e 100644
--- a/fractal-gtk/src/actions/room_settings.rs
+++ b/fractal-gtk/src/actions/room_settings.rs
@@ -5,6 +5,7 @@ use fractal_api::url::Url;
 use gio::prelude::*;
 use gio::SimpleAction;
 use gio::SimpleActionGroup;
+use glib::clone;
 use std::convert::TryFrom;
 use std::thread;
 
@@ -33,13 +34,11 @@ pub fn new(
 
     actions.add_action(&change_avatar);
 
-    let window_weak = window.downgrade();
-    change_avatar.connect_activate(move |a, data| {
+    change_avatar.connect_activate(clone!(@weak window => move |a, data| {
         if let Some(room_id) = data
             .and_then(|x| x.get_str())
             .and_then(|rid| RoomId::try_from(rid).ok())
         {
-            let window = upgrade_weak!(window_weak);
             let filter = gtk::FileFilter::new();
             filter.set_name(Some(i18n("Images").as_str()));
             filter.add_mime_type("image/*");
@@ -63,7 +62,7 @@ pub fn new(
                 }
             }
         }
-    });
+    }));
 
     actions
 }
diff --git a/fractal-gtk/src/app/connect/account.rs b/fractal-gtk/src/app/connect/account.rs
index 4241dcd1..d314f490 100644
--- a/fractal-gtk/src/app/connect/account.rs
+++ b/fractal-gtk/src/app/connect/account.rs
@@ -95,17 +95,17 @@ impl App {
                 .builder
                 .get_object::<gtk::Spinner>("account_settings_avatar_spinner")
                 .expect("Can't find account_settings_avatar_spinner in ui file.");
-            let spinner = avatar_spinner.downgrade();
-            avatar_btn.connect_property_sensitive_notify(move |w| {
-                let spinner = upgrade_weak!(spinner);
-                if w.get_sensitive() {
-                    spinner.hide();
-                    spinner.stop();
-                } else {
-                    spinner.start();
-                    spinner.show();
-                }
-            });
+            avatar_btn.connect_property_sensitive_notify(
+                clone!(@weak avatar_spinner as spinner => move |w| {
+                    if w.get_sensitive() {
+                        spinner.hide();
+                        spinner.stop();
+                    } else {
+                        spinner.start();
+                        spinner.show();
+                    }
+                }),
+            );
         }
 
         let button = name_btn.clone();
diff --git a/fractal-gtk/src/app/connect/direct.rs b/fractal-gtk/src/app/connect/direct.rs
index a577a121..2a3d9b8f 100644
--- a/fractal-gtk/src/app/connect/direct.rs
+++ b/fractal-gtk/src/app/connect/direct.rs
@@ -62,21 +62,25 @@ impl App {
                 }
             }
 
-            let sid = gtk::timeout_add(500, clone!(@strong op, @strong entry, @strong source_id => move || {
-                if let Some(buffer) = entry.get_buffer() {
-                    let start = buffer.get_start_iter();
-                    let end = buffer.get_end_iter();
-
-                    if let Some(text) =
-                        buffer.get_text(&start, &end, false).map(|gstr| gstr.to_string())
-                    {
-                        op.lock().unwrap().search_invite_user(text);
+            let sid = gtk::timeout_add(500, clone!(
+                @strong op,
+                @strong entry,
+                @strong source_id
+                => move || {
+                    if let Some(buffer) = entry.get_buffer() {
+                        let start = buffer.get_start_iter();
+                        let end = buffer.get_end_iter();
+
+                        if let Some(text) =
+                            buffer.get_text(&start, &end, false).map(|gstr| gstr.to_string())
+                        {
+                            op.lock().unwrap().search_invite_user(text);
+                        }
                     }
-                }
 
-                *(source_id.lock().unwrap()) = None;
-                Continue(false)
-            }));
+                    *(source_id.lock().unwrap()) = None;
+                    Continue(false)
+                }));
 
             *(source_id.lock().unwrap()) = Some(sid);
             glib::signal::Inhibit(false)
diff --git a/fractal-gtk/src/app/connect/directory.rs b/fractal-gtk/src/app/connect/directory.rs
index ca27041a..1ea4fbb1 100644
--- a/fractal-gtk/src/app/connect/directory.rs
+++ b/fractal-gtk/src/app/connect/directory.rs
@@ -123,7 +123,12 @@ impl App {
             op.search_rooms();
         });
 
-        default_matrix_server_radio.connect_toggled(clone!(@strong directory_choice_label, @strong 
default_matrix_server_radio, @strong protocol_combo, @strong other_homeserver_url_entry => move |_| {
+        default_matrix_server_radio.connect_toggled(clone!(
+        @strong directory_choice_label,
+        @strong default_matrix_server_radio,
+        @strong protocol_combo,
+        @strong other_homeserver_url_entry
+        => move |_| {
             if default_matrix_server_radio.get_active() {
                 protocol_combo.set_sensitive(false);
                 other_homeserver_url_entry.set_sensitive(false);
@@ -132,7 +137,13 @@ impl App {
             directory_choice_label.set_text(&i18n("Default Matrix Server"));
         }));
 
-        other_protocol_radio.connect_toggled(clone!(@strong directory_choice_label, @strong 
other_protocol_radio, @strong protocol_combo, @strong protocol_model, @strong other_homeserver_url_entry => 
move |_| {
+        other_protocol_radio.connect_toggled(clone!(
+        @strong directory_choice_label,
+        @strong other_protocol_radio,
+        @strong protocol_combo,
+        @strong protocol_model,
+        @strong other_homeserver_url_entry
+        => move |_| {
             if other_protocol_radio.get_active() {
                 protocol_combo.set_sensitive(true);
                 other_homeserver_url_entry.set_sensitive(false);
@@ -150,34 +161,39 @@ impl App {
             directory_choice_label.set_text(&protocol);
         }));
 
-        protocol_combo.connect_changed(
-            clone!(@strong directory_choice_label, @strong protocol_combo, @strong protocol_model => move 
|_| {
-                let active = protocol_combo.get_active().map_or(-1, |uint| uint as i32);
-                let protocol: String = match protocol_model.iter_nth_child(None, active) {
-                    Some(it) => {
-                        let v = protocol_model.get_value(&it, 0);
-                        v.get().unwrap().unwrap()
-                    }
-                    None => String::new(),
-                };
-
-                directory_choice_label.set_text(&protocol);
-            }),
-        );
-
-        other_homeserver_radio.connect_toggled(
-            clone!(@strong other_homeserver_radio, @strong protocol_combo, @strong 
other_homeserver_url_entry => move |_| {
-                if other_homeserver_radio.get_active() {
-                    protocol_combo.set_sensitive(false);
-                    other_homeserver_url_entry.set_sensitive(true);
+        protocol_combo.connect_changed(clone!(
+        @strong directory_choice_label,
+        @strong protocol_combo,
+        @strong protocol_model
+        => move |_| {
+            let active = protocol_combo.get_active().map_or(-1, |uint| uint as i32);
+            let protocol: String = match protocol_model.iter_nth_child(None, active) {
+                Some(it) => {
+                    let v = protocol_model.get_value(&it, 0);
+                    v.get().unwrap().unwrap()
                 }
-            }),
-        );
-
-        other_homeserver_url_entry.connect_changed(
-            clone!(@strong directory_choice_label, @strong other_homeserver_url => move |_| {
-                directory_choice_label.set_text(&other_homeserver_url.get_text());
-            }),
-        );
+                None => String::new(),
+            };
+
+            directory_choice_label.set_text(&protocol);
+        }));
+
+        other_homeserver_radio.connect_toggled(clone!(
+        @strong other_homeserver_radio,
+        @strong protocol_combo,
+        @strong other_homeserver_url_entry
+        => move |_| {
+            if other_homeserver_radio.get_active() {
+                protocol_combo.set_sensitive(false);
+                other_homeserver_url_entry.set_sensitive(true);
+            }
+        }));
+
+        other_homeserver_url_entry.connect_changed(clone!(
+        @strong directory_choice_label,
+        @strong other_homeserver_url
+        => move |_| {
+            directory_choice_label.set_text(&other_homeserver_url.get_text());
+        }));
     }
 }
diff --git a/fractal-gtk/src/app/connect/headerbar.rs b/fractal-gtk/src/app/connect/headerbar.rs
index eaa361e8..961d5615 100644
--- a/fractal-gtk/src/app/connect/headerbar.rs
+++ b/fractal-gtk/src/app/connect/headerbar.rs
@@ -30,21 +30,25 @@ impl App {
                 }
             };
 
-            set.connect_property_gtk_decoration_layout_notify(clone!(@strong right_header, @strong 
left_header, @strong set => move |_| {
-                if let Some(decor) = set.get_property_gtk_decoration_layout() {
-                    let decor = decor.to_string();
-                    let decor_split: Vec<String> = decor.splitn(2,':').map(|s| s.to_string()).collect();
-                    // Change the headerbar controls depending on position
-                    // of close
-                    if decor_split.len() > 1 && decor_split[1].contains("close") {
-                        left_header.set_show_close_button(false);
-                        right_header.set_show_close_button(true);
-                    } else {
-                        right_header.set_show_close_button(false);
-                        left_header.set_show_close_button(true);
-                    }
-                };
-            }));
+            set.connect_property_gtk_decoration_layout_notify(clone!(
+                @strong right_header,
+                @strong left_header,
+                @strong set
+                => move |_| {
+                    if let Some(decor) = set.get_property_gtk_decoration_layout() {
+                        let decor = decor.to_string();
+                        let decor_split: Vec<String> = decor.splitn(2,':').map(|s| s.to_string()).collect();
+                        // Change the headerbar controls depending on position
+                        // of close
+                        if decor_split.len() > 1 && decor_split[1].contains("close") {
+                            left_header.set_show_close_button(false);
+                            right_header.set_show_close_button(true);
+                        } else {
+                            right_header.set_show_close_button(false);
+                            left_header.set_show_close_button(true);
+                        }
+                    };
+                }));
         };
     }
 }
diff --git a/fractal-gtk/src/app/connect/invite.rs b/fractal-gtk/src/app/connect/invite.rs
index d4281ba5..10d6c5bd 100644
--- a/fractal-gtk/src/app/connect/invite.rs
+++ b/fractal-gtk/src/app/connect/invite.rs
@@ -96,19 +96,23 @@ impl App {
                 }
             }
 
-            let sid = gtk::timeout_add(500, clone!(@strong op, @strong entry, @strong source_id => move || {
-                if let Some(buffer) = entry.get_buffer() {
-                    let start = buffer.get_start_iter();
-                    let end = buffer.get_end_iter();
-
-                    if let Some(text) = buffer.get_text(&start, &end, false).map(|gstr| gstr.to_string()) {
-                        op.lock().unwrap().search_invite_user(text);
+            let sid = gtk::timeout_add(500, clone!(
+                @strong op,
+                @strong entry,
+                @strong source_id
+                => move || {
+                    if let Some(buffer) = entry.get_buffer() {
+                        let start = buffer.get_start_iter();
+                        let end = buffer.get_end_iter();
+
+                        if let Some(text) = buffer.get_text(&start, &end, false).map(|gstr| 
gstr.to_string()) {
+                            op.lock().unwrap().search_invite_user(text);
+                        }
                     }
-                }
 
-                *(source_id.lock().unwrap()) = None;
-                Continue(false)
-            }));
+                    *(source_id.lock().unwrap()) = None;
+                    Continue(false)
+                }));
 
             *(source_id.lock().unwrap()) = Some(sid);
             glib::signal::Inhibit(false)
diff --git a/fractal-gtk/src/app/mod.rs b/fractal-gtk/src/app/mod.rs
index 603cbb12..fcb77123 100644
--- a/fractal-gtk/src/app/mod.rs
+++ b/fractal-gtk/src/app/mod.rs
@@ -1,5 +1,6 @@
 use gettextrs::{bindtextdomain, setlocale, textdomain, LocaleCategory};
 use gio::prelude::*;
+use glib::clone;
 use gtk::prelude::*;
 use libhandy::prelude::*;
 use std::cell::RefCell;
@@ -113,10 +114,7 @@ impl App {
             popover.get_style_context().add_class("narrow");
         }
 
-        let weak_container = container.downgrade();
-        leaflet.connect_property_fold_notify(move |leaflet| {
-            let container = upgrade_weak!(weak_container);
-
+        leaflet.connect_property_fold_notify(clone!(@weak container => move |leaflet| {
             match leaflet.get_fold() {
                 libhandy::Fold::Folded => {
                     container.get_style_context().add_class("folded-history");
@@ -128,7 +126,7 @@ impl App {
                 }
                 _ => (),
             }
-        });
+        }));
 
         let stack = ui
             .builder
@@ -181,18 +179,14 @@ impl App {
         // Create application
         let app = App::new(gtk_app);
 
-        let app_weak = AppRef::downgrade(&app);
-        gtk_app.connect_activate(move |_| {
-            let app = upgrade_weak!(app_weak);
+        gtk_app.connect_activate(clone!(@weak app => move |_| {
             app.on_activate();
-        });
+        }));
 
-        let app_weak = AppRef::downgrade(&app);
         app.main_window
-            .connect_property_has_toplevel_focus_notify(move |_| {
-                let app = upgrade_weak!(app_weak);
+            .connect_property_has_toplevel_focus_notify(clone!(@weak app => move |_| {
                 app.op.lock().unwrap().mark_active_room_messages();
-            });
+            }));
 
         app.main_window.connect_delete_event(move |window, _| {
             let settings: gio::Settings = gio::Settings::new("org.gnome.Fractal");
diff --git a/fractal-gtk/src/appop/notify.rs b/fractal-gtk/src/appop/notify.rs
index 926cbc45..c6de2de5 100644
--- a/fractal-gtk/src/appop/notify.rs
+++ b/fractal-gtk/src/appop/notify.rs
@@ -3,6 +3,7 @@ use fractal_api::identifiers::{EventId, RoomId};
 use gio::ApplicationExt;
 use gio::FileExt;
 use gio::Notification;
+use glib::clone;
 use glib::source::Continue;
 use gtk::prelude::*;
 use log::info;
@@ -72,18 +73,19 @@ impl AppOp {
 
         let room_id = room_id.to_string();
         let id = id.to_string();
-        let app_weak = app.downgrade();
-        gtk::timeout_add(50, move || match rx.try_recv() {
-            Err(TryRecvError::Empty) => Continue(true),
-            Err(TryRecvError::Disconnected) => Continue(false),
-            Ok((name, avatar_path)) => {
-                let title = format!("{}{}", name, title);
-                let app = upgrade_weak!(app_weak, Continue(false));
-                let n = create_notification(&room_id, &title, &short_body, &avatar_path);
-                app.send_notification(Some(id.as_str()), &n);
-                Continue(false)
-            }
-        });
+        gtk::timeout_add(
+            50,
+            clone!(@weak app => @default-return Continue(false), move || match rx.try_recv() {
+                Err(TryRecvError::Empty) => Continue(true),
+                Err(TryRecvError::Disconnected) => Continue(false),
+                Ok((name, avatar_path)) => {
+                    let title = format!("{}{}", name, title);
+                    let n = create_notification(&room_id, &title, &short_body, &avatar_path);
+                    app.send_notification(Some(id.as_str()), &n);
+                    Continue(false)
+                }
+            }),
+        );
 
         None
     }
diff --git a/fractal-gtk/src/appop/room.rs b/fractal-gtk/src/appop/room.rs
index d8b6a1bb..1231d20c 100644
--- a/fractal-gtk/src/appop/room.rs
+++ b/fractal-gtk/src/appop/room.rs
@@ -367,8 +367,6 @@ impl AppOp {
             .builder
             .get_object("main_window")
             .expect("Can't find main_window in ui file.");
-        let parent_weak = parent.downgrade();
-        let parent = upgrade_weak!(parent_weak);
         let viewer = widgets::KickedDialog::new();
         viewer.set_parent_window(&parent);
         viewer.show(&room_name, &reason, &kicker);
diff --git a/fractal-gtk/src/util.rs b/fractal-gtk/src/util.rs
index f5db5b5b..ff4a2fc5 100644
--- a/fractal-gtk/src/util.rs
+++ b/fractal-gtk/src/util.rs
@@ -93,21 +93,6 @@ pub fn set_markdown_schema(md: bool) {
     }
 }
 
-/* Macro for upgrading a weak reference or returning the given value
- *
- * This works for glib/gtk objects as well as anything else providing an upgrade method */
-macro_rules! upgrade_weak {
-    ($x:expr, $r:expr) => {{
-        match $x.upgrade() {
-            Some(o) => o,
-            None => return $r,
-        }
-    }};
-    ($x:expr) => {
-        upgrade_weak!($x, ())
-    };
-}
-
 macro_rules! unwrap_or_unit_return {
     ($x:expr) => {
         match $x {
diff --git a/fractal-gtk/src/widgets/autocomplete.rs b/fractal-gtk/src/widgets/autocomplete.rs
index ba65caca..02b1a6e0 100644
--- a/fractal-gtk/src/widgets/autocomplete.rs
+++ b/fractal-gtk/src/widgets/autocomplete.rs
@@ -68,14 +68,15 @@ impl Autocomplete {
             }
         }
 
-        let window_weak = this.borrow().window.downgrade();
-        this.borrow().popover.connect_closed(move |_| {
-            let window = upgrade_weak!(window_weak);
-            // Reenable Escape to change state
-            if let Some(app) = window.get_application() {
-                app.set_accels_for_action("app.back", &["Escape"]);
-            }
-        });
+        let window = &this.borrow().window;
+        this.borrow()
+            .popover
+            .connect_closed(clone!(@weak window => move |_| {
+                // Reenable Escape to change state
+                if let Some(app) = window.get_application() {
+                    app.set_accels_for_action("app.back", &["Escape"]);
+                }
+            }));
 
         let own = this.clone();
         this.borrow()
@@ -217,7 +218,8 @@ impl Autocomplete {
 
                 let start = buffer.get_start_iter();
                 let end = buffer.get_end_iter();
-                let text = buffer.get_text(&start, &end, false)
+                let text = buffer
+                    .get_text(&start, &end, false)
                     .map(|gstr| gstr.to_string());
 
                 /* when closing popover with tab */
@@ -240,65 +242,74 @@ impl Autocomplete {
                 }
                 /* update the popover when closed and tab is released
                  * don't update the popover the arrow keys are pressed */
-                if (is_tab && own.borrow().popover_position.is_none()) ||
-                    (ev.get_keyval() != gdk::enums::key::Up && ev.get_keyval() != gdk::enums::key::Down) {
-                        own.borrow_mut().popover_search = text.clone();
-                        if let Some(buffer) = e.get_buffer() {
-                            let pos = buffer.get_property_cursor_position();
+                if (is_tab && own.borrow().popover_position.is_none())
+                    || (ev.get_keyval() != gdk::enums::key::Up
+                        && ev.get_keyval() != gdk::enums::key::Down)
+                {
+                    own.borrow_mut().popover_search = text.clone();
+                    if let Some(buffer) = e.get_buffer() {
+                        let pos = buffer.get_property_cursor_position();
 
-                            if let Some(text) = text.clone() {
-                                let graphs = text.chars().collect::<Vec<char>>();
+                        if let Some(text) = text.clone() {
+                            let graphs = text.chars().collect::<Vec<char>>();
 
-                                if pos as usize > graphs.len() {
-                                    return Inhibit(false);
-                                }
+                            if pos as usize > graphs.len() {
+                                return Inhibit(false);
+                            }
 
-                                let (p1, _) = graphs.split_at(pos as usize);
-                                let first = p1.iter().collect::<String>();
-                                if own.borrow().popover_position.is_none() {
-                                    if !is_tab {
-                                        if let Some(at_pos) = first.rfind('@') {
-                                            own.borrow_mut().popover_position = Some(at_pos as i32);
-                                        }
+                            let (p1, _) = graphs.split_at(pos as usize);
+                            let first = p1.iter().collect::<String>();
+                            if own.borrow().popover_position.is_none() {
+                                if !is_tab {
+                                    if let Some(at_pos) = first.rfind('@') {
+                                        own.borrow_mut().popover_position = Some(at_pos as i32);
                                     }
-                                    else if let Some(space_pos) = first.rfind(|c: char| c.is_whitespace()) {
-                                            own.borrow_mut().popover_position = Some(space_pos as i32 + 1);
-                                        }
-                                        else {
-                                            own.borrow_mut().popover_position = Some(0);
-                                        }
+                                } else if let Some(space_pos) =
+                                    first.rfind(|c: char| c.is_whitespace())
+                                {
+                                    own.borrow_mut().popover_position = Some(space_pos as i32 + 1);
+                                } else {
+                                    own.borrow_mut().popover_position = Some(0);
                                 }
                             }
+                        }
 
-                            if own.borrow().popover_position.is_some() {
-                                let list = {
-                                    own.borrow().autocomplete(text, buffer.get_property_cursor_position())
-                                };
-                                let widget_list = {
-                                    own.borrow_mut().autocomplete_show_popover(list)
-                                };
-                                for (alias, widget) in widget_list.iter() {
-                                    widget.connect_button_press_event(clone!(@strong own, @strong alias => 
move |_, ev| {
-                                        own.borrow_mut().autocomplete_insert(alias.clone());
-                                        if ev.is::<gdk::EventKey>() {
-                                            let ev = {
-                                                let ev: &gdk::Event = ev;
-                                                ev.clone().downcast::<gdk::EventKey>().unwrap()
-                                            };
-                                            /* Submit on enter */
-                                            if ev.get_keyval() == gdk::enums::key::Return || ev.get_keyval() 
== gdk::enums::key::Tab  {
-                                                own.borrow_mut().autocomplete_enter();
-                                            }
-                                        }
-                                        else if ev.is::<gdk::EventButton>() {
+                        if own.borrow().popover_position.is_some() {
+                            let list = {
+                                own.borrow()
+                                    .autocomplete(text, buffer.get_property_cursor_position())
+                            };
+                            let widget_list = { own.borrow_mut().autocomplete_show_popover(list) };
+                            for (alias, widget) in widget_list.iter() {
+                                widget.connect_button_press_event(clone!(
+                                @strong own,
+                                @strong alias
+                                => move |_, ev| {
+                                    own.borrow_mut().autocomplete_insert(alias.clone());
+                                    if ev.is::<gdk::EventKey>() {
+                                        let ev = {
+                                            let ev: &gdk::Event = ev;
+
+                                            ev.clone()
+                                                .downcast::<gdk::EventKey>()
+                                                .unwrap()
+                                        };
+                                        /* Submit on enter */
+                                        if ev.get_keyval() == gdk::enums::key::Return
+                                            || ev.get_keyval() == gdk::enums::key::Tab
+                                        {
                                             own.borrow_mut().autocomplete_enter();
                                         }
-                                        Inhibit(true)
-                                    }));
-                                }
+                                    }
+                                    else if ev.is::<gdk::EventButton>() {
+                                        own.borrow_mut().autocomplete_enter();
+                                    }
+                                    Inhibit(true)
+                                }));
                             }
                         }
                     }
+                }
             }
 
             Inhibit(false)
diff --git a/fractal-gtk/src/widgets/divider.rs b/fractal-gtk/src/widgets/divider.rs
index 903065b1..6af7504f 100644
--- a/fractal-gtk/src/widgets/divider.rs
+++ b/fractal-gtk/src/widgets/divider.rs
@@ -1,3 +1,4 @@
+use glib::clone;
 use glib::source::Continue;
 use gtk::prelude::*;
 use gtk::RevealerTransitionType;
@@ -42,27 +43,22 @@ impl NewMessageDivider {
         /* Self destruction
          * destroy the NewMessageDivider after it's added to the History with a couple of
          * seconds delay */
-        let revealer_weak = revealer.downgrade();
-        row.connect_parent_set(move |_, _| {
-            if let Some(revealer) = revealer_weak.upgrade() {
-                let revealer_weak = revealer.downgrade();
-                gtk::timeout_add(5000, move || {
+        row.connect_parent_set(clone!(@weak revealer => move |_, _| {
+            gtk::timeout_add(5000, clone!(
+                @weak revealer as r
+                => @default-return Continue(false), move || {
                     /* when the user closes the room the divider gets destroyed and this timeout
                      * does nothing, but that's fine */
-                    if let Some(r) = revealer_weak.upgrade() {
-                        r.set_reveal_child(false);
-                    }
+                    r.set_reveal_child(false);
                     Continue(false)
-                });
-            }
-        });
-        let row_weak = row.downgrade();
-        revealer.connect_property_child_revealed_notify(move |_| {
-            if let Some(r) = row_weak.upgrade() {
-                r.destroy();
-                remove_divider();
-            }
-        });
+                }));
+        }));
+        revealer.connect_property_child_revealed_notify(clone!(
+        @weak row as r
+        => move |_| {
+            r.destroy();
+            remove_divider();
+        }));
         NewMessageDivider {
             revealer,
             widget: row,
diff --git a/fractal-gtk/src/widgets/error_dialog.rs b/fractal-gtk/src/widgets/error_dialog.rs
index 60f153b0..90950dc7 100644
--- a/fractal-gtk/src/widgets/error_dialog.rs
+++ b/fractal-gtk/src/widgets/error_dialog.rs
@@ -21,8 +21,7 @@ pub fn new(fatal: bool, text: &str) {
     dialog.connect_response(move |dialog, _| {
         dialog.destroy();
 
-        if fatal {
-            let app = upgrade_weak!(app_weak);
+        if let (Some(app), true) = (app_weak.upgrade(), fatal) {
             app.quit();
         }
     });
diff --git a/fractal-gtk/src/widgets/inline_player.rs b/fractal-gtk/src/widgets/inline_player.rs
index eea848cc..8b7502f8 100644
--- a/fractal-gtk/src/widgets/inline_player.rs
+++ b/fractal-gtk/src/widgets/inline_player.rs
@@ -364,15 +364,17 @@ impl VideoPlayerWidget {
             });
 
         /* Sometimes, set_size_request() doesn't get captured visually. The following timeout takes care of 
that. */
-        let player_weak = Rc::downgrade(&player_widget);
-        gtk::timeout_add_seconds(1, move || {
-            if let Some(player) = player_weak.upgrade() {
+        gtk::timeout_add_seconds(
+            1,
+            clone!(
+            @weak player_widget as player
+            => @default-return Continue(true), move || {
                 let (_, height) = player.get_video_widget().get_size_request();
                 player.get_video_widget().set_size_request(-1, height - 1);
                 player.get_video_widget().set_size_request(-1, height);
-            }
-            Continue(true)
-        });
+                Continue(true)
+            }),
+        );
     }
 
     pub fn auto_adjust_box_size_to_video_dimensions(
@@ -406,7 +408,11 @@ impl VideoPlayerWidget {
                     are bigger than they should be. */
                     gtk::timeout_add(
                         50,
-                        clone!(@strong bx, @strong video_width, @strong video_height => move || {
+                        clone!(
+                        @strong bx,
+                        @strong video_width,
+                        @strong video_height
+                        => move || {
                             adjust_box_margins_to_video_dimensions(&bx, video_width, video_height);
                             Continue(false)
                         }),
@@ -582,18 +588,16 @@ impl<T: MediaPlayer + 'static> ControlsConnection for T {
     }
     #[rustfmt::skip]
     /// Connect the `PlayerControls` buttons to the `PlayerEssentials` methods.
-    fn connect_control_buttons(s: &Rc<Self>) {
-        if s.get_controls().is_some() {
-            let weak = Rc::downgrade(s);
-
+    fn connect_control_buttons(p: &Rc<Self>) {
+        if let Some(controls) = p.get_controls() {
             // Connect the play button to the gst Player.
-            s.get_controls().unwrap().buttons.play.connect_clicked(clone!(@strong weak => move |_| {
-                if let Some(p) = weak.upgrade() { p.play() }
+            controls.buttons.play.connect_clicked(clone!(@strong p => move |_| {
+                p.play();
             }));
 
             // Connect the pause button to the gst Player.
-            s.get_controls().unwrap().buttons.pause.connect_clicked(clone!(@strong weak => move |_| {
-                if let Some(p) = weak.upgrade() { p.pause() }
+            controls.buttons.pause.connect_clicked(clone!(@strong p => move |_| {
+                p.pause();
             }));
         }
     }
diff --git a/fractal-gtk/src/widgets/kicked_dialog.rs b/fractal-gtk/src/widgets/kicked_dialog.rs
index 23560714..c761f335 100644
--- a/fractal-gtk/src/widgets/kicked_dialog.rs
+++ b/fractal-gtk/src/widgets/kicked_dialog.rs
@@ -1,4 +1,5 @@
 use crate::i18n::i18n_f;
+use glib::clone;
 use gtk::prelude::*;
 
 struct Widgets {
@@ -62,12 +63,12 @@ impl KickedDialog {
     }
 
     fn connect(&self) {
-        let msg_kicked_window = self.widgets.msg_kicked_window.downgrade();
-        self.widgets
-            .confirm_kicked_button
-            .connect_clicked(move |_| {
-                upgrade_weak!(msg_kicked_window).close();
-            });
+        let msg_kicked_window = &self.widgets.msg_kicked_window;
+        self.widgets.confirm_kicked_button.connect_clicked(
+            clone!(@weak msg_kicked_window => move |_| {
+                msg_kicked_window.close();
+            }),
+        );
 
         /* Close the window when the user preses ESC */
         self.widgets
diff --git a/fractal-gtk/src/widgets/login.rs b/fractal-gtk/src/widgets/login.rs
index 5f97612b..48784f22 100644
--- a/fractal-gtk/src/widgets/login.rs
+++ b/fractal-gtk/src/widgets/login.rs
@@ -1,5 +1,6 @@
 use fractal_api::url::Url;
 use gio::prelude::*;
+use glib::clone;
 use gtk::prelude::*;
 use log::info;
 
@@ -31,19 +32,18 @@ impl LoginWidget {
     pub fn new(op: &Arc<Mutex<AppOp>>) -> Self {
         let widget = Self::default();
 
-        let weak_server = widget.server_entry.downgrade();
-        let weak_username = widget.username_entry.downgrade();
-        let weak_password = widget.password_entry.downgrade();
-        let weak_err = widget.credentials_err_label.downgrade();
+        let server_entry = &widget.server_entry;
+        let username_entry = &widget.username_entry;
+        let password_entry = &widget.password_entry;
+        let err_label = &widget.credentials_err_label;
 
         // Grab the focus for each state
-        let weak_user = weak_username.clone();
         widget
             .container
-            .connect_property_visible_child_name_notify(move |container| {
-                let server = upgrade_weak!(weak_server);
-                let username = upgrade_weak!(weak_user);
-
+            .connect_property_visible_child_name_notify(clone!(
+            @weak server_entry as server,
+            @weak username_entry as username
+            => move |container| {
                 let state: LoginState = container
                     .get_visible_child_name()
                     .unwrap()
@@ -55,10 +55,9 @@ impl LoginWidget {
                     LoginState::Credentials => username.grab_focus(),
                     _ => (),
                 }
-            });
+            }));
 
         let op = op.clone();
-        let weak_server = widget.server_entry.downgrade();
 
         let login = widget
             .actions
@@ -67,13 +66,12 @@ impl LoginWidget {
             .downcast::<gio::SimpleAction>()
             .expect("Could not cast action 'login' to SimpleAction");
 
-        let weak_pass = weak_password.clone();
-        login.connect_activate(move |_, _| {
-            let server_entry = upgrade_weak!(weak_server);
-            let username_entry = upgrade_weak!(weak_username);
-            let password_entry = upgrade_weak!(weak_pass);
-            let err_label = upgrade_weak!(weak_err);
-
+        login.connect_activate(clone!(
+        @weak server_entry,
+        @weak username_entry,
+        @weak password_entry,
+        @weak err_label
+        => move |_, _| {
             if let Some(txt) = server_entry.get_text() {
                 let username = username_entry
                     .get_text()
@@ -125,7 +123,7 @@ impl LoginWidget {
                     err_label.show();
                 }
             }
-        });
+        }));
 
         let credentials = widget
             .actions
@@ -137,10 +135,11 @@ impl LoginWidget {
             .server_entry
             .connect_activate(move |_| credentials.activate(None));
 
-        widget.username_entry.connect_activate(move |_| {
-            let password_entry = upgrade_weak!(weak_password);
-            password_entry.grab_focus();
-        });
+        widget
+            .username_entry
+            .connect_activate(clone!(@weak password_entry => move |_| {
+                password_entry.grab_focus();
+            }));
 
         widget
             .password_entry
diff --git a/fractal-gtk/src/widgets/media_viewer.rs b/fractal-gtk/src/widgets/media_viewer.rs
index 5d4dc1b2..f2c95773 100644
--- a/fractal-gtk/src/widgets/media_viewer.rs
+++ b/fractal-gtk/src/widgets/media_viewer.rs
@@ -394,12 +394,9 @@ impl Data {
             }
             _ => {}
         });
-        let player_weak = Rc::downgrade(&player);
-        mute_button.connect_clicked(move |button| {
-            if let Some(player) = player_weak.upgrade() {
-                VideoPlayerWidget::switch_mute_state(&player, &button);
-            }
-        });
+        mute_button.connect_clicked(clone!(@weak player => move |button| {
+            VideoPlayerWidget::switch_mute_state(&player, &button);
+        }));
         full_control_box.pack_start(&mute_button, false, false, 0);
 
         let control_revealer = gtk::Revealer::new();
@@ -420,29 +417,32 @@ impl Data {
             .clone()
             .get_object::<gtk::Box>("media_viewer_box")
             .expect("Cant find media_viewer_box in ui file.");
-        let player_weak = Rc::downgrade(&player);
-        media_viewer_box.connect_motion_notify_event(
-            clone!(@strong control_revealer, @strong source_id => move |_, _| {
-                if let Some(player) = player_weak.upgrade() {
-                control_revealer.set_reveal_child(true);
-                if let Some(sid) = source_id.borrow_mut().take() {
-                    glib::source::source_remove(sid);
-                }
-                let new_sid = gtk::timeout_add_seconds(
-                    1,
-                    clone!(@strong source_id, @strong control_revealer => move || {
-                            if player.is_playing() {
-                                control_revealer.set_reveal_child(false);
-                            }
-                            *source_id.borrow_mut() = None;
-                            Continue(false)
-                        }),
-                    );
-                    *source_id.borrow_mut() = Some(new_sid);
-                }
-                Inhibit(false)
-            }),
-        );
+        media_viewer_box.connect_motion_notify_event(clone!(
+        @strong control_revealer,
+        @strong source_id,
+        @weak player
+        => @default-return Inhibit(false), move |_, _| {
+            control_revealer.set_reveal_child(true);
+            if let Some(sid) = source_id.borrow_mut().take() {
+                glib::source::source_remove(sid);
+            }
+            let new_sid = gtk::timeout_add_seconds(
+                1,
+                clone!(
+                    @strong source_id,
+                    @strong control_revealer
+                    => move || {
+                        if player.is_playing() {
+                            control_revealer.set_reveal_child(false);
+                        }
+                        *source_id.borrow_mut() = None;
+                        Continue(false)
+                    }),
+            );
+            *source_id.borrow_mut() = Some(new_sid);
+
+            Inhibit(false)
+        }));
 
         control_revealer.set_valign(gtk::Align::End);
         control_revealer.get_style_context().add_class("osd");
@@ -450,96 +450,94 @@ impl Data {
 
         bx.pack_start(&overlay, false, false, 0);
 
-        let player_weak = Rc::downgrade(&player);
-        bx.connect_state_flags_changed(move |_, flag| {
+        bx.connect_state_flags_changed(clone!(@weak player => move |_, flag| {
             let focussed = gtk::StateFlags::BACKDROP;
-            if let Some(player) = player_weak.upgrade() {
-                if !flag.contains(focussed) {
-                    player.pause();
-                }
+            if !flag.contains(focussed) {
+                player.pause();
             }
-        });
+        }));
 
-        let player_weak = Rc::downgrade(&player);
-        self.main_window.connect_key_press_event(
-            clone!(@strong control_revealer, @strong source_id => move |_, k| {
-            if let Some(player) = player_weak.upgrade() {
-                if player.get_video_widget().get_mapped() {
-                    if let gdk::enums::key::space = k.get_keyval() {
+        self.main_window.connect_key_press_event(clone!(
+        @strong control_revealer,
+        @strong source_id,
+        @weak player
+        => @default-return Inhibit(false), move |_, k| {
+            if player.get_video_widget().get_mapped() {
+                if let gdk::enums::key::space = k.get_keyval() {
+                    if player.is_playing() {
+                        control_revealer.set_reveal_child(true);
+                    } else {
+                        let new_sid = gtk::timeout_add_seconds(
+                            1,
+                            clone!(
+                                @strong source_id,
+                                @strong control_revealer,
+                                @weak player
+                                => @default-return Continue(false), move || {
+                                    if player.is_playing() {
+                                        control_revealer.set_reveal_child(false);
+                                    }
+                                    *source_id.borrow_mut() = None;
+                                    Continue(false)
+                                }),
+                        );
+                        *source_id.borrow_mut() = Some(new_sid);
+                    }
+                    VideoPlayerWidget::switch_play_pause_state(&player);
+                }
+            }
+            Inhibit(false)
+        }));
+        let ui = self.builder.clone();
+        let media_viewer_box = ui
+            .get_object::<gtk::Box>("media_viewer_box")
+            .expect("Cant find media_viewer_box in ui file.");
+        let click_timeout_id = Rc::new(RefCell::new(None));
+        media_viewer_box.connect_button_press_event(clone!(
+        @strong control_revealer,
+        @strong source_id,
+        @weak player
+        => @default-return Inhibit(false), move |_, e| {
+            let source_id = source_id.clone();
+            let revealer = control_revealer.clone();
+            if let EventType::ButtonPress = e.get_event_type() {
+                if click_timeout_id.borrow().is_some() {
+                    let id = click_timeout_id.borrow_mut().take().unwrap();
+                    glib::source::source_remove(id);
+                } else {
+                    let sid = gtk::timeout_add(
+                        250,
+                        clone!(@strong player, @strong click_timeout_id => move || {
                             if player.is_playing() {
-                                control_revealer.set_reveal_child(true);
+                                revealer.set_reveal_child(true);
                             } else {
                                 let new_sid = gtk::timeout_add_seconds(
                                     1,
-                                    clone!(@strong source_id, @strong control_revealer, @strong player_weak 
=> move || {
-                                        if let Some(player) = player_weak.upgrade() {
+                                    clone!(
+                                        @strong source_id,
+                                        @strong revealer,
+                                        @weak player
+                                        => @default-return Continue(false), move || {
                                             if player.is_playing() {
-                                                control_revealer.set_reveal_child(false);
+                                                revealer.set_reveal_child(false);
                                             }
                                             *source_id.borrow_mut() = None;
-                                        }
-                                        Continue(false)
-                                    }),
+                                            Continue(false)
+                                        }),
                                 );
                                 *source_id.borrow_mut() = Some(new_sid);
                             }
                             VideoPlayerWidget::switch_play_pause_state(&player);
-                    }
+
+                            *click_timeout_id.borrow_mut() = None;
+                            Continue(false)
+                        }),
+                    );
+                    *click_timeout_id.borrow_mut() = Some(sid);
                 }
             }
             Inhibit(false)
-            }),
-        );
-        let ui = self.builder.clone();
-        let media_viewer_box = ui
-            .get_object::<gtk::Box>("media_viewer_box")
-            .expect("Cant find media_viewer_box in ui file.");
-        let player_weak = Rc::downgrade(&player);
-        let click_timeout_id = Rc::new(RefCell::new(None));
-        media_viewer_box.connect_button_press_event(
-            clone!(@strong control_revealer, @strong source_id => move |_, e| {
-                let source_id = source_id.clone();
-                let revealer = control_revealer.clone();
-                let pw = player_weak.clone();
-                if let Some(player) = player_weak
-                    .upgrade()
-                    { if let EventType::ButtonPress = e.get_event_type() {
-                            if click_timeout_id.borrow().is_some() {
-                                let id = click_timeout_id.borrow_mut().take().unwrap();
-                                glib::source::source_remove(id);
-                            } else {
-                                let sid = gtk::timeout_add(
-                                    250,
-                                    clone!(@strong player, @strong click_timeout_id => move || {
-                                        if player.is_playing() {
-                                            revealer.set_reveal_child(true);
-                                        } else {
-                                            let new_sid = gtk::timeout_add_seconds(
-                                                1,
-                                                clone!(@strong source_id, @strong revealer, @strong pw => 
move || {
-                                                    if let Some(player) = pw.upgrade() {
-                                                        if player.is_playing() {
-                                                            revealer.set_reveal_child(false);
-                                                        }
-                                                        *source_id.borrow_mut() = None;
-                                                    }
-                                                    Continue(false)
-                                                }),
-                                            );
-                                            *source_id.borrow_mut() = Some(new_sid);
-                                        }
-                                        VideoPlayerWidget::switch_play_pause_state(&player);
-
-                                        *click_timeout_id.borrow_mut() = None;
-                                        Continue(false)
-                                    }),
-                                );
-                                *click_timeout_id.borrow_mut() = Some(sid);
-                            }
-                    }}
-                Inhibit(false)
-            }),
-        );
+        }));
 
         let mut widget = VideoWidget {
             player,
@@ -709,23 +707,21 @@ impl MediaViewer {
 
     /* connect media viewer headerbar */
     pub fn connect_media_viewer_headerbar(&self, thread_pool: ThreadPool) {
-        let own_weak = Rc::downgrade(&self.data);
+        let own = &self.data;
         let full_screen_button = self
             .builder
             .get_object::<gtk::Button>("full_screen_button")
             .expect("Cant find full_screen_button in ui file.");
-        full_screen_button.connect_clicked(move |_| {
-            if let Some(own) = own_weak.upgrade() {
-                let main_window = own.borrow().main_window.clone();
-                if let Some(win) = main_window.get_window() {
-                    if !win.get_state().contains(gdk::WindowState::FULLSCREEN) {
-                        own.borrow_mut().enter_full_screen(thread_pool.clone());
-                    } else {
-                        own.borrow_mut().leave_full_screen(thread_pool.clone())
-                    }
+        full_screen_button.connect_clicked(clone!(@weak own => move |_| {
+            let main_window = own.borrow().main_window.clone();
+            if let Some(win) = main_window.get_window() {
+                if !win.get_state().contains(gdk::WindowState::FULLSCREEN) {
+                    own.borrow_mut().enter_full_screen(thread_pool.clone());
+                } else {
+                    own.borrow_mut().leave_full_screen(thread_pool.clone())
                 }
             }
-        });
+        }));
     }
 
     pub fn connect_media_viewer_box(&self, thread_pool: ThreadPool) {
@@ -839,7 +835,12 @@ impl MediaViewer {
 
                 let sid = gtk::timeout_add(
                     1000,
-                    clone!(@strong ui, @strong header_hovered, @strong nav_hovered, @strong source_id => 
move || {
+                    clone!(
+                    @strong ui,
+                    @strong header_hovered,
+                    @strong nav_hovered,
+                    @strong source_id
+                    => move || {
                         let menu_popover_is_visible = ui
                         .get_object::<gtk::MenuButton>("media_viewer_menu_button")
                         .expect("Can't find headerbar_revealer in ui file.")
@@ -873,31 +874,27 @@ impl MediaViewer {
                 Inhibit(false)
             });
 
-        let own_weak = Rc::downgrade(&self.data);
+        let data = &self.data;
+
         let builder = self.builder.clone();
         let previous_media_button = self
             .builder
             .get_object::<gtk::Button>("previous_media_button")
             .expect("Cant find previous_media_button in ui file.");
         let t_pool = thread_pool.clone();
-        previous_media_button.connect_clicked(move |_| {
-            if let Some(own) = own_weak.upgrade() {
-                if !own.borrow_mut().previous_media(t_pool.clone()) {
-                    load_more_media(t_pool.clone(), own, builder.clone());
-                }
+        previous_media_button.connect_clicked(clone!(@weak data => move |_| {
+            if !data.borrow_mut().previous_media(t_pool.clone()) {
+                load_more_media(t_pool.clone(), data, builder.clone());
             }
-        });
+        }));
 
-        let own_weak = Rc::downgrade(&self.data);
         let next_media_button = self
             .builder
             .get_object::<gtk::Button>("next_media_button")
             .expect("Cant find next_media_button in ui file.");
-        next_media_button.connect_clicked(move |_| {
-            if let Some(own) = own_weak.upgrade() {
-                own.borrow_mut().next_media(thread_pool.clone());
-            }
-        });
+        next_media_button.connect_clicked(clone!(@weak data => move |_| {
+            data.borrow_mut().next_media(thread_pool.clone());
+        }));
         let full_screen_button = self
             .builder
             .get_object::<gtk::Button>("full_screen_button")
@@ -934,20 +931,17 @@ impl MediaViewer {
         self.data.borrow_mut().signal_id = Some(id);
 
         // Remove the keyboard signal management on hide
-        let data_weak = Rc::downgrade(&self.data);
         let ui = self.builder.clone();
         let media_viewer_box = ui
             .get_object::<gtk::Box>("media_viewer_box")
             .expect("Cant find media_viewer_box in ui file.");
-        media_viewer_box.connect_unmap(move |_| {
-            if let Some(data) = data_weak.upgrade() {
-                let id = data.borrow_mut().signal_id.take();
-                let main_window = &data.borrow().main_window;
-                if let Some(id) = id {
-                    signal::signal_handler_disconnect(main_window, id);
-                }
+        media_viewer_box.connect_unmap(clone!(@weak data => move |_| {
+            let id = data.borrow_mut().signal_id.take();
+            let main_window = &data.borrow().main_window;
+            if let Some(id) = id {
+                signal::signal_handler_disconnect(main_window, id);
             }
-        });
+        }));
     }
 
     fn connect_stop_video_when_leaving(&self) {
@@ -1023,27 +1017,26 @@ fn load_more_media(thread_pool: ThreadPool, data: Rc<RefCell<Data>>, builder: gt
     );
 
     let ui = builder.clone();
-    let data_weak = Rc::downgrade(&data);
-    gtk::timeout_add(50, move || match rx.try_recv() {
-        Err(TryRecvError::Empty) => Continue(true),
-        Err(TryRecvError::Disconnected) => {
-            if let Some(data) = data_weak.clone().upgrade() {
+    gtk::timeout_add(
+        50,
+        clone!(
+        @weak data
+        => @default-return Continue(false), move || match rx.try_recv() {
+            Err(TryRecvError::Empty) => Continue(true),
+            Err(TryRecvError::Disconnected) => {
                 data.borrow_mut().loading_error = true;
                 let err = i18n("Error while loading previous media");
                 ErrorDialog::new(false, &err);
-            }
 
-            Continue(false)
-        }
-        Ok((msgs, prev_batch)) => {
-            if msgs.is_empty() {
-                if let Some(data) = data_weak.clone().upgrade() {
+                Continue(false)
+            }
+            Ok((msgs, prev_batch)) => {
+                if msgs.is_empty() {
                     data.borrow_mut().no_more_media = true;
+                    return Continue(false);
                 }
-                return Continue(false);
-            }
-            let thread_pool = thread_pool.clone();
-            if let Some(data) = data_weak.upgrade() {
+
+                let thread_pool = thread_pool.clone();
                 let media_list = data.borrow().media_list.clone();
                 let img_msgs: Vec<Message> = msgs
                     .into_iter()
@@ -1061,9 +1054,9 @@ fn load_more_media(thread_pool: ThreadPool, data: Rc<RefCell<Data>>, builder: gt
                     data.borrow_mut().previous_media(thread_pool);
                     data.borrow_mut().loading_more_media = loading_state(&ui, false);
                 }
-            }
 
-            Continue(false)
-        }
-    });
+                Continue(false)
+            }
+        }),
+    );
 }
diff --git a/fractal-gtk/src/widgets/message.rs b/fractal-gtk/src/widgets/message.rs
index 310e1500..80d7683f 100644
--- a/fractal-gtk/src/widgets/message.rs
+++ b/fractal-gtk/src/widgets/message.rs
@@ -6,6 +6,7 @@ use crate::cache::CacheMap;
 use chrono::prelude::*;
 use fractal_api::identifiers::UserId;
 use fractal_api::url::Url;
+use glib::clone;
 use gtk::{prelude::*, ButtonExt, ContainerExt, LabelExt, Overlay, WidgetExt};
 use std::cmp::max;
 use std::rc::Rc;
@@ -680,39 +681,36 @@ impl MessageBox {
     fn connect_right_click_menu(&self, msg: &Message, label: Option<&gtk::Label>) -> Option<()> {
         let mtype = msg.mtype;
         let redactable = msg.redactable;
-        let eventbox_weak = self.eventbox.downgrade();
         let widget = if let Some(l) = label {
             l.upcast_ref::<gtk::Widget>()
         } else {
             self.eventbox.upcast_ref::<gtk::Widget>()
         };
 
-        let evbox = eventbox_weak.clone();
+        let eventbox = &self.eventbox;
         let id = msg.id.clone();
-        widget.connect_button_press_event(move |w, e| {
-            if e.get_button() == 3 {
-                let eventbox = upgrade_weak!(evbox, gtk::Inhibit(false));
-                MessageMenu::new(id.as_ref(), &mtype, &redactable, Some(&eventbox), Some(w));
-                Inhibit(true)
-            } else {
-                Inhibit(false)
-            }
-        });
+        widget.connect_button_press_event(
+            clone!(@weak eventbox => @default-return Inhibit(false), move |w, e| {
+                if e.get_button() == 3 {
+                    MessageMenu::new(id.as_ref(), &mtype, &redactable, Some(&eventbox), Some(w));
+                    Inhibit(true)
+                } else {
+                    Inhibit(false)
+                }
+            }),
+        );
 
         let id = msg.id.clone();
-        let widget_weak = widget.downgrade();
-        self.gesture.connect_pressed(move |_, _, _| {
-            let eventbox = upgrade_weak!(eventbox_weak);
-            let widget = upgrade_weak!(widget_weak);
-
-            MessageMenu::new(
-                id.as_ref(),
-                &mtype,
-                &redactable,
-                Some(&eventbox),
-                Some(&widget),
-            );
-        });
+        self.gesture
+            .connect_pressed(clone!(@weak eventbox, @weak widget => move |_, _, _| {
+                MessageMenu::new(
+                    id.as_ref(),
+                    &mtype,
+                    &redactable,
+                    Some(&eventbox),
+                    Some(&widget),
+                );
+            }));
         None
     }
 
diff --git a/fractal-gtk/src/widgets/message_menu.rs b/fractal-gtk/src/widgets/message_menu.rs
index 65bdf86e..7abec213 100644
--- a/fractal-gtk/src/widgets/message_menu.rs
+++ b/fractal-gtk/src/widgets/message_menu.rs
@@ -174,12 +174,13 @@ impl MessageMenu {
         let s = get_selected_text(label)?;
         self.widgets.copy_selected_button.show();
         self.widgets.copy_selected_button.connect_clicked(move |_| {
-            let widget = upgrade_weak!(&s.widget);
-            let atom = gdk::Atom::intern("CLIPBOARD");
-            let clipboard = gtk::Clipboard::get(&atom);
-            clipboard.set_text(&s.text);
-            /* FIXME: for some reason we have to set the selection again */
-            widget.select_region(s.start, s.end);
+            if let Some(widget) = s.widget.upgrade() {
+                let atom = gdk::Atom::intern("CLIPBOARD");
+                let clipboard = gtk::Clipboard::get(&atom);
+                clipboard.set_text(&s.text);
+                /* FIXME: for some reason we have to set the selection again */
+                widget.select_region(s.start, s.end);
+            }
         });
         None
     }
diff --git a/fractal-gtk/src/widgets/room_history.rs b/fractal-gtk/src/widgets/room_history.rs
index d78306eb..69df6d48 100644
--- a/fractal-gtk/src/widgets/room_history.rs
+++ b/fractal-gtk/src/widgets/room_history.rs
@@ -23,6 +23,7 @@ use fractal_api::identifiers::{RoomId, UserId};
 use fractal_api::url::Url;
 use gio::ActionMapExt;
 use gio::SimpleActionGroup;
+use glib::clone;
 use glib::source;
 use glib::source::Continue;
 use glib::SignalHandlerId;
@@ -85,17 +86,14 @@ impl List {
     }
 
     fn create_new_message_divider(rows: Rc<RefCell<Self>>) -> widgets::NewMessageDivider {
-        let rows_weak = Rc::downgrade(&rows);
-        let remove_divider = move || {
-            if let Some(rows) = rows_weak.upgrade() {
-                let new_divider_index = rows
-                    .borrow_mut()
-                    .new_divider_index
-                    .take()
-                    .expect("The new divider index must exist, since there is a new divider");
-                rows.borrow_mut().list.remove(new_divider_index);
-            }
-        };
+        let remove_divider = clone!(@weak rows => move || {
+            let new_divider_index = rows
+                .borrow_mut()
+                .new_divider_index
+                .take()
+                .expect("The new divider index must exist, since there is a new divider");
+            rows.borrow_mut().list.remove(new_divider_index);
+        });
         widgets::NewMessageDivider::new(i18n("New Messages").as_str(), remove_divider)
     }
     fn update_videos(&mut self) {
@@ -319,13 +317,16 @@ impl RoomHistory {
         /* Add the rest of the messages after the new message divider */
         self.add_new_messages_in_batch(thread_pool, user_info_cache, bottom);
 
-        let weak_rows = Rc::downgrade(&self.rows);
-        let id = timeout_add(250, move || {
-            if let Some(rows) = weak_rows.upgrade() {
+        let rows = &self.rows;
+        let id = timeout_add(
+            250,
+            clone!(
+            @weak rows
+            => @default-return Continue(false), move || {
                 rows.borrow_mut().update_videos();
-            }
-            Continue(false)
-        });
+                Continue(false)
+            }),
+        );
         self.rows.borrow_mut().video_scroll_debounce = Some(id);
 
         None
@@ -341,103 +342,93 @@ impl RoomHistory {
             .expect("The scrolled window must have a vertical scrollbar.")
             .downcast::<gtk::Scrollbar>()
             .unwrap();
-        let weak_rows = Rc::downgrade(&self.rows);
-        scrollbar.connect_value_changed(move |sb| {
+        let rows = &self.rows;
+        scrollbar.connect_value_changed(clone!(@weak rows => move |sb| {
             if !sb.get_state_flags().contains(gtk::StateFlags::BACKDROP) {
                 /* Fractal is focused */
-                if let Some(rows) = weak_rows.upgrade() {
-                    let weak_rows_inner = weak_rows.clone();
-                    let new_id = timeout_add(250, move || {
-                        if let Some(rows) = weak_rows_inner.upgrade() {
-                            rows.borrow_mut().update_videos();
-                            rows.borrow_mut().video_scroll_debounce = None;
-                        }
+                let new_id = timeout_add(250, clone!(
+                    @weak rows
+                    => @default-return Continue(false), move || {
+                        rows.borrow_mut().update_videos();
+                        rows.borrow_mut().video_scroll_debounce = None;
                         Continue(false)
-                    });
-                    if let Some(old_id) = rows.borrow_mut().video_scroll_debounce.replace(new_id) {
-                        let _ = Source::remove(old_id);
-                    }
+                    }));
+                if let Some(old_id) = rows.borrow_mut().video_scroll_debounce.replace(new_id) {
+                    let _ = Source::remove(old_id);
                 }
             }
-        });
+        }));
     }
 
     fn connect_video_focus(&mut self) {
+        let rows = &self.rows;
+
         let scrolled_window = self.rows.borrow().view.get_scrolled_window();
-        let weak_rows = Rc::downgrade(&self.rows);
-        scrolled_window.connect_map(move |_| {
+        scrolled_window.connect_map(clone!(@weak rows => move |_| {
             /* The user has navigated back into the room history */
-            if let Some(rows) = weak_rows.upgrade() {
-                let len = rows.borrow().playing_videos.len();
-                if len != 0 {
-                    warn!(
-                        "{:?} videos were playing while the room history was not displayed.",
-                        len
-                    );
-                    for (player, hander_id) in rows.borrow_mut().playing_videos.drain(..) {
-                        player.stop_loop(hander_id);
-                    }
-                }
-                let visible_videos = rows.borrow().find_visible_videos();
-                let mut videos = Vec::with_capacity(visible_videos.len());
-                for player in visible_videos {
-                    let handler_id = player.play_in_loop();
-                    videos.push((player, handler_id));
+            let len = rows.borrow().playing_videos.len();
+            if len != 0 {
+                warn!(
+                    "{:?} videos were playing while the room history was not displayed.",
+                    len
+                );
+                for (player, hander_id) in rows.borrow_mut().playing_videos.drain(..) {
+                    player.stop_loop(hander_id);
                 }
-                rows.borrow_mut().playing_videos = videos;
             }
-        });
+            let visible_videos = rows.borrow().find_visible_videos();
+            let mut videos = Vec::with_capacity(visible_videos.len());
+            for player in visible_videos {
+                let handler_id = player.play_in_loop();
+                videos.push((player, handler_id));
+            }
+            rows.borrow_mut().playing_videos = videos;
+        }));
 
-        let weak_rows = Rc::downgrade(&self.rows);
-        scrolled_window.connect_unmap(move |_| {
+        scrolled_window.connect_unmap(clone!(@weak rows => move |_| {
             /* The user has navigated out of the room history */
-            if let Some(rows) = weak_rows.upgrade() {
-                if let Some(id) = rows.borrow_mut().video_scroll_debounce.take() {
-                    let _ = Source::remove(id);
-                }
-                for (player, handler_id) in rows.borrow_mut().playing_videos.drain(..) {
-                    player.stop_loop(handler_id);
-                }
+            if let Some(id) = rows.borrow_mut().video_scroll_debounce.take() {
+                let _ = Source::remove(id);
             }
-        });
+            for (player, handler_id) in rows.borrow_mut().playing_videos.drain(..) {
+                player.stop_loop(handler_id);
+            }
+        }));
 
-        let weak_rows = Rc::downgrade(&self.rows);
-        scrolled_window.connect_state_flags_changed(move |window, flag| {
+        scrolled_window.connect_state_flags_changed(clone!(@weak rows => move |window, flag| {
             if window.get_mapped() {
                 /* The room history is being displayed */
-                if let Some(rows) = weak_rows.upgrade() {
-                    let focused = gtk::StateFlags::BACKDROP;
-                    if flag.contains(focused) {
-                        /* Fractal has been focused */
-                        let len = rows.borrow().playing_videos.len();
-                        if len != 0 {
-                            warn!(
-                                "{:?} videos were playing while Fractal was focused out.",
-                                len
-                            );
-                            for (player, handler_id) in rows.borrow_mut().playing_videos.drain(..) {
-                                player.stop_loop(handler_id);
-                            }
-                        }
-                        let visible_videos = rows.borrow().find_visible_videos();
-                        let mut videos = Vec::with_capacity(visible_videos.len());
-                        for player in visible_videos {
-                            let handler_id = player.play_in_loop();
-                            videos.push((player, handler_id));
-                        }
-                        rows.borrow_mut().playing_videos = videos;
-                    } else {
-                        /* Fractal has been unfocused */
-                        if let Some(id) = rows.borrow_mut().video_scroll_debounce.take() {
-                            let _ = Source::remove(id);
-                        }
+                let focused = gtk::StateFlags::BACKDROP;
+                if flag.contains(focused) {
+                    /* Fractal has been focused */
+                    let len = rows.borrow().playing_videos.len();
+                    if len != 0 {
+                        warn!(
+                            "{:?} videos were playing while Fractal was focused out.",
+                            len
+                        );
                         for (player, handler_id) in rows.borrow_mut().playing_videos.drain(..) {
                             player.stop_loop(handler_id);
                         }
                     }
+                    let visible_videos = rows.borrow().find_visible_videos();
+                    let mut videos = Vec::with_capacity(visible_videos.len());
+                    for player in visible_videos {
+                        let handler_id = player.play_in_loop();
+                        videos.push((player, handler_id));
+                    }
+                    rows.borrow_mut().playing_videos = videos;
+                } else {
+                    /* Fractal has been unfocused */
+                    if let Some(id) = rows.borrow_mut().video_scroll_debounce.take() {
+                        let _ = Source::remove(id);
+                    }
+                    for (player, handler_id) in rows.borrow_mut().playing_videos.drain(..) {
+                        player.stop_loop(handler_id);
+                    }
                 }
             }
-        });
+        }));
     }
 
     fn run_queue(
diff --git a/fractal-gtk/src/widgets/room_settings.rs b/fractal-gtk/src/widgets/room_settings.rs
index e0c69bed..45410482 100644
--- a/fractal-gtk/src/widgets/room_settings.rs
+++ b/fractal-gtk/src/widgets/room_settings.rs
@@ -171,17 +171,17 @@ impl RoomSettings {
                 .builder
                 .get_object::<gtk::Spinner>("room_settings_avatar_spinner")
                 .expect("Can't find room_settings_avatar_spinner in ui file.");
-            let spinner = avatar_spinner.downgrade();
-            avatar_btn.connect_property_sensitive_notify(move |w| {
-                let spinner = upgrade_weak!(spinner);
-                if w.get_sensitive() {
-                    spinner.hide();
-                    spinner.stop();
-                } else {
-                    spinner.start();
-                    spinner.show();
-                }
-            });
+            avatar_btn.connect_property_sensitive_notify(
+                clone!(@weak avatar_spinner as spinner => move |w| {
+                    if w.get_sensitive() {
+                        spinner.hide();
+                        spinner.stop();
+                    } else {
+                        spinner.start();
+                        spinner.show();
+                    }
+                }),
+            );
         }
     }
 
diff --git a/fractal-gtk/src/widgets/roomlist.rs b/fractal-gtk/src/widgets/roomlist.rs
index 980171b5..1a9fee5c 100644
--- a/fractal-gtk/src/widgets/roomlist.rs
+++ b/fractal-gtk/src/widgets/roomlist.rs
@@ -711,32 +711,30 @@ impl RoomList {
 
     // Connect handlers for unselecting rooms from other categories when a room is selected
     pub fn connect_select(&self) {
-        let fav = self.fav.get().list.downgrade();
-        let rooms = self.rooms.get().list.downgrade();
-        self.inv.get().list.connect_row_selected(move |_, row| {
+        let inv = &self.inv.get().list;
+        let fav = &self.fav.get().list;
+        let rooms = &self.rooms.get().list;
+
+        inv.connect_row_selected(clone!(@weak fav, @weak rooms => move |_, row| {
             if row.is_some() {
-                upgrade_weak!(fav).unselect_all();
-                upgrade_weak!(rooms).unselect_all();
+                fav.unselect_all();
+                rooms.unselect_all();
             }
-        });
+        }));
 
-        let inv = self.inv.get().list.downgrade();
-        let rooms = self.rooms.get().list.downgrade();
-        self.fav.get().list.connect_row_selected(move |_, row| {
+        fav.connect_row_selected(clone!(@weak inv, @weak rooms => move |_, row| {
             if row.is_some() {
-                upgrade_weak!(inv).unselect_all();
-                upgrade_weak!(rooms).unselect_all();
+                inv.unselect_all();
+                rooms.unselect_all();
             }
-        });
+        }));
 
-        let inv = self.inv.get().list.downgrade();
-        let fav = self.fav.get().list.downgrade();
-        self.rooms.get().list.connect_row_selected(move |_, row| {
+        rooms.connect_row_selected(clone!(@weak inv, @weak fav => move |_, row| {
             if row.is_some() {
-                upgrade_weak!(inv).unselect_all();
-                upgrade_weak!(fav).unselect_all();
+                inv.unselect_all();
+                fav.unselect_all();
             }
-        });
+        }));
     }
 
     pub fn connect_drop<F: Fn(RoomId) + 'static>(&self, widget: gtk::EventBox, cb: F) {
@@ -765,44 +763,36 @@ impl RoomList {
     }
 
     pub fn connect_keynav(&self) {
-        let weak_inv_lb = self.inv.get().list.downgrade();
-        let weak_fav_lb = self.fav.get().list.downgrade();
-        let weak_room_lb = self.rooms.get().list.downgrade();
-        let adj = self.adj.clone();
-        let type_ = RoomListType::Invites;
-        self.inv.get().list.connect_keynav_failed(move |_, d| {
-            let inv_lb = upgrade_weak!(weak_inv_lb, gtk::Inhibit(false));
-            let fav_lb = upgrade_weak!(weak_fav_lb, gtk::Inhibit(false));
-            let room_lb = upgrade_weak!(weak_room_lb, gtk::Inhibit(false));
-
-            keynav_cb(d, &inv_lb, &fav_lb, &room_lb, adj.clone(), type_)
-        });
+        let inv_lb = &self.inv.get().list;
+        let fav_lb = &self.fav.get().list;
+        let rooms_lb = &self.rooms.get().list;
+
+        inv_lb.connect_keynav_failed(clone!(
+        @strong self.adj as adj,
+        @weak inv_lb,
+        @weak fav_lb,
+        @weak rooms_lb
+        => @default-return gtk::Inhibit(false), move |_, d| {
+            keynav_cb(d, &inv_lb, &fav_lb, &rooms_lb, adj.clone(), RoomListType::Invites)
+        }));
 
-        let weak_fav_lb = self.fav.get().list.downgrade();
-        let weak_inv_lb = self.inv.get().list.downgrade();
-        let weak_room_lb = self.rooms.get().list.downgrade();
-        let adj = self.adj.clone();
-        let type_ = RoomListType::Favorites;
-        self.fav.get().list.connect_keynav_failed(move |_, d| {
-            let fav_lb = upgrade_weak!(weak_fav_lb, gtk::Inhibit(false));
-            let inv_lb = upgrade_weak!(weak_inv_lb, gtk::Inhibit(false));
-            let room_lb = upgrade_weak!(weak_room_lb, gtk::Inhibit(false));
-
-            keynav_cb(d, &inv_lb, &fav_lb, &room_lb, adj.clone(), type_)
-        });
+        fav_lb.connect_keynav_failed(clone!(
+        @strong self.adj as adj,
+        @weak fav_lb,
+        @weak inv_lb,
+        @weak rooms_lb
+        => @default-return gtk::Inhibit(false), move |_, d| {
+            keynav_cb(d, &inv_lb, &fav_lb, &rooms_lb, adj.clone(), RoomListType::Favorites)
+        }));
 
-        let weak_rooms_lb = self.rooms.get().list.downgrade();
-        let weak_inv_lb = self.inv.get().list.downgrade();
-        let weak_fav_lb = self.fav.get().list.downgrade();
-        let adj = self.adj.clone();
-        let type_ = RoomListType::Rooms;
-        self.rooms.get().list.connect_keynav_failed(move |_, d| {
-            let rooms_lb = upgrade_weak!(weak_rooms_lb, gtk::Inhibit(false));
-            let inv_lb = upgrade_weak!(weak_inv_lb, gtk::Inhibit(false));
-            let fav_lb = upgrade_weak!(weak_fav_lb, gtk::Inhibit(false));
-
-            keynav_cb(d, &inv_lb, &fav_lb, &rooms_lb, adj.clone(), type_)
-        });
+        rooms_lb.connect_keynav_failed(clone!(
+        @strong self.adj as adj,
+        @weak rooms_lb,
+        @weak inv_lb,
+        @weak fav_lb
+        => @default-return gtk::Inhibit(false), move |_, d| {
+            keynav_cb(d, &inv_lb, &fav_lb, &rooms_lb, adj.clone(), RoomListType::Rooms)
+        }));
     }
 
     pub fn filter_rooms(&self, term: Option<String>) {
diff --git a/fractal-gtk/src/widgets/scroll_widget.rs b/fractal-gtk/src/widgets/scroll_widget.rs
index 3d2c8bfc..f667e8b8 100644
--- a/fractal-gtk/src/widgets/scroll_widget.rs
+++ b/fractal-gtk/src/widgets/scroll_widget.rs
@@ -4,6 +4,7 @@ use std::rc::Rc;
 use fractal_api::identifiers::RoomId;
 use gio::Action;
 use gio::ActionExt;
+use glib::clone;
 use glib::source::Continue;
 use gtk::prelude::*;
 
@@ -151,61 +152,47 @@ impl ScrollWidget {
     /* Keep the same position if new messages are added */
     pub fn connect(&mut self, action: Option<Action>, room_id: RoomId) -> Option<()> {
         let adj = self.widgets.view.get_vadjustment()?;
-        let upper = Rc::downgrade(&self.upper);
-        let balance = Rc::downgrade(&self.balance);
-        let autoscroll = Rc::downgrade(&self.autoscroll);
-        let view = self.widgets.view.downgrade();
-        adj.connect_property_upper_notify(move |adj| {
-            let check = || -> Option<()> {
-                let view = view.upgrade()?;
-                let upper = upper.upgrade()?;
-                let balance = balance.upgrade()?;
-                let autoscroll = autoscroll.upgrade()?;
-                let new_upper = adj.get_upper();
-                let diff = new_upper - upper.get();
-                /* Don't do anything if upper didn't change */
-                if diff != 0.0 {
-                    upper.set(new_upper);
-                    /* Stay at the end of the room history when autoscroll is on */
-                    if autoscroll.get() {
-                        adj.set_value(adj.get_upper() - adj.get_page_size());
-                    } else if balance.take().map_or(false, |x| x == Position::Top) {
-                        adj.set_value(adj.get_value() + diff);
-                        view.set_kinetic_scrolling(true);
-                    }
+        let upper = &self.upper;
+        let balance = &self.balance;
+        let autoscroll = &self.autoscroll;
+        let view = &self.widgets.view;
+        adj.connect_property_upper_notify(clone!(
+        @weak view,
+        @weak upper,
+        @weak balance,
+        @weak autoscroll
+        => move |adj| {
+            let new_upper = adj.get_upper();
+            let diff = new_upper - upper.get();
+            /* Don't do anything if upper didn't change */
+            if diff != 0.0 {
+                upper.set(new_upper);
+                /* Stay at the end of the room history when autoscroll is on */
+                if autoscroll.get() {
+                    adj.set_value(adj.get_upper() - adj.get_page_size());
+                } else if balance.take().map_or(false, |x| x == Position::Top) {
+                    adj.set_value(adj.get_value() + diff);
+                    view.set_kinetic_scrolling(true);
                 }
-                Some(())
-            }();
-            debug_assert!(
-                check.is_some(),
-                "Upper notify callback couldn't acquire a strong pointer"
-            );
-        });
+            }
+        }));
 
-        let autoscroll = Rc::downgrade(&self.autoscroll);
+        let revealer = &self.widgets.btn_revealer;
         let request_sent = Rc::downgrade(&self.request_sent);
-        let revealer = self.widgets.btn_revealer.downgrade();
         let spinner = self.widgets.spinner.downgrade();
         let action_weak = action.map(|a| a.downgrade());
-        adj.connect_value_changed(move |adj| {
-            let check = || -> Option<()> {
-                let autoscroll = autoscroll.upgrade()?;
-                let r = revealer.upgrade()?;
-
-                let bottom = adj.get_upper() - adj.get_page_size();
-                if (adj.get_value() - bottom).abs() < std::f64::EPSILON {
-                    r.set_reveal_child(false);
-                    autoscroll.set(true);
-                } else {
-                    r.set_reveal_child(true);
-                    autoscroll.set(false);
-                }
-                Some(())
-            }();
-            debug_assert!(
-                check.is_some(),
-                "Value changed callback couldn't acquire a strong pointer"
-            );
+        adj.connect_value_changed(clone!(
+        @weak autoscroll,
+        @weak revealer as r
+        => move |adj| {
+            let bottom = adj.get_upper() - adj.get_page_size();
+            if (adj.get_value() - bottom).abs() < std::f64::EPSILON {
+                r.set_reveal_child(false);
+                autoscroll.set(true);
+            } else {
+                r.set_reveal_child(true);
+                autoscroll.set(false);
+            }
 
             let action_weak = action_weak.clone();
             let check = || -> Option<()> {
@@ -226,26 +213,17 @@ impl ScrollWidget {
                 Some(())
             }();
             debug_assert!(check.is_some(), "Can't request more messages");
-        });
-
-        let autoscroll = Rc::downgrade(&self.autoscroll);
-        let revealer = self.widgets.btn_revealer.downgrade();
-        let scroll = self.widgets.view.downgrade();
-        self.widgets.button.connect_clicked(move |_| {
-            let check = || -> Option<()> {
-                let autoscroll = autoscroll.upgrade()?;
-                let r = revealer.upgrade()?;
-                let s = scroll.upgrade()?;
-                r.set_reveal_child(false);
-                autoscroll.set(true);
-                scroll_down(&s, true);
-                Some(())
-            }();
-            debug_assert!(
-                check.is_some(),
-                "Scroll down button onclick callback couldn't acquire a strong pointer"
-            );
-        });
+        }));
+
+        self.widgets.button.connect_clicked(clone!(
+        @weak autoscroll,
+        @weak revealer as r,
+        @weak view as s
+        => move |_| {
+            r.set_reveal_child(false);
+            autoscroll.set(true);
+            scroll_down(&s, true);
+        }));
 
         None
     }
diff --git a/fractal-gtk/src/widgets/source_dialog.rs b/fractal-gtk/src/widgets/source_dialog.rs
index 81a5f408..c8c34d96 100644
--- a/fractal-gtk/src/widgets/source_dialog.rs
+++ b/fractal-gtk/src/widgets/source_dialog.rs
@@ -1,3 +1,4 @@
+use glib::clone;
 use gtk::prelude::*;
 use sourceview4::prelude::*;
 
@@ -64,24 +65,27 @@ impl SourceDialog {
     }
 
     fn connect(&self) {
-        let source_buffer = self.widgets.source_buffer.downgrade();
-        self.widgets.copy_src_button.connect_clicked(move |_| {
-            let source_buffer = upgrade_weak!(source_buffer);
-            let atom = gdk::Atom::intern("CLIPBOARD");
-            let clipboard = gtk::Clipboard::get(&atom);
+        let source_buffer = &self.widgets.source_buffer;
+        self.widgets
+            .copy_src_button
+            .connect_clicked(clone!(@weak source_buffer => move |_| {
+                let atom = gdk::Atom::intern("CLIPBOARD");
+                let clipboard = gtk::Clipboard::get(&atom);
 
-            let start_iter = source_buffer.get_start_iter();
-            let end_iter = source_buffer.get_end_iter();
+                let start_iter = source_buffer.get_start_iter();
+                let end_iter = source_buffer.get_end_iter();
 
-            if let Some(src) = source_buffer.get_text(&start_iter, &end_iter, false) {
-                clipboard.set_text(&src);
-            }
-        });
+                if let Some(src) = source_buffer.get_text(&start_iter, &end_iter, false) {
+                    clipboard.set_text(&src);
+                }
+            }));
 
-        let msg_src_window = self.widgets.msg_src_window.downgrade();
-        self.widgets.close_src_button.connect_clicked(move |_| {
-            upgrade_weak!(msg_src_window).close();
-        });
+        let msg_src_window = &self.widgets.msg_src_window;
+        self.widgets
+            .close_src_button
+            .connect_clicked(clone!(@weak msg_src_window => move |_| {
+                msg_src_window.close();
+            }));
 
         /* Close the window when the user preses ESC */
         self.widgets.msg_src_window.connect_key_press_event(|w, k| {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]