Philipp Hörist pushed to branch master at gajim / gajim
Commits: 3df8196b by Philipp Hörist at 2019-07-20T20:29:47Z Groupchat: Integrate captcha request into GroupChatControl
- - - - - 8686e6ab by Philipp Hörist at 2019-07-20T21:28:41Z Remove an unused variable
- - - - - 22c9c9b3 by Philipp Hörist at 2019-07-20T21:35:27Z Groupchat: Activate join button on Return
Activate the join button when pressing Return inside the password entry on group chat join
- - - - - d7dfac90 by Philipp Hörist at 2019-07-20T21:43:28Z DataFormWidget: Invalidate form on start validation
This prevents that the form can be sent before the validation is complete
- - - - -
3 changed files:
- gajim/data/gui/groupchat_control.ui - gajim/groupchat_control.py - gajim/gtk/dataform.py
Changes:
===================================== gajim/data/gui/groupchat_control.ui ===================================== @@ -103,319 +103,310 @@ <signal name="button-release-event" handler="_on_hpaned_release_button" swapped="no"/> <signal name="notify::position" handler="_on_hpaned_handle_change" swapped="no"/> <child> - <object class="GtkOverlay" id="overlay"> + <object class="GtkBox" id="gc_textviews_vbox"> + <property name="width_request">0</property> <property name="visible">True</property> <property name="can_focus">False</property> + <property name="margin_right">4</property> + <property name="orientation">vertical</property> <child> - <object class="GtkBox" id="gc_textviews_vbox"> - <property name="width_request">0</property> + <object class="GtkEventBox" id="banner_eventbox"> + <property name="name">GroupChatControl-BannerEventBox</property> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="margin_right">4</property> - <property name="orientation">vertical</property> <child> - <object class="GtkEventBox" id="banner_eventbox"> - <property name="name">GroupChatControl-BannerEventBox</property> + <object class="GtkBox" id="hbox3024"> <property name="visible">True</property> <property name="can_focus">False</property> <child> - <object class="GtkBox" id="hbox3024"> + <object class="GtkImage" id="gc_banner_status_image"> <property name="visible">True</property> <property name="can_focus">False</property> - <child> - <object class="GtkImage" id="gc_banner_status_image"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="stock">gtk-missing-image</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="padding">5</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="banner_name_label"> - <property name="name">GroupChatControl-BannerNameLabel</property> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label"><span weight="heavy" size="large">room jid</span></property> - <property name="use_markup">True</property> - <property name="selectable">True</property> - <property name="xalign">0</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkActionBar" id="banner_actionbar"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <style> - <class name="actionbar-no-border"/> - </style> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">2</property> - </packing> - </child> + <property name="stock">gtk-missing-image</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="padding">5</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="banner_name_label"> + <property name="name">GroupChatControl-BannerNameLabel</property> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label"><span weight="heavy" size="large">room jid</span></property> + <property name="use_markup">True</property> + <property name="selectable">True</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkActionBar" id="banner_actionbar"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <style> + <class name="actionbar-no-border"/> + </style> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">2</property> + </packing> + </child> + </object> + </child> + <style> + <class name="gajim-banner"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkSeparator"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <style> + <class name="chatcontrol-separator-top"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="conversation_scrolledwindow"> + <property name="width_request">200</property> + <property name="height_request">60</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="shadow_type">in</property> + <property name="overlay_scrolling">False</property> + <signal name="edge-reached" handler="_on_edge_reached" swapped="no"/> + <signal name="scroll-event" handler="_on_scroll" swapped="no"/> + <child> + <placeholder/> + </child> + <style> + <class name="scrolled-no-border"/> + <class name="no-scroll-indicator"/> + <class name="scrollbar-style"/> + </style> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkSeparator"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <style> + <class name="chatcontrol-separator"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkBox" id="hbox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <child> + <object class="GtkMenuButton" id="settings_menu"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="relief">none</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">open-menu-symbolic</property> </object> </child> <style> - <class name="gajim-banner"/> + <class name="chatcontrol-actionbar-button"/> </style> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> + <property name="pack_type">end</property> <property name="position">0</property> </packing> </child> <child> - <object class="GtkSeparator"> - <property name="visible">True</property> - <property name="can_focus">False</property> + <object class="GtkButton" id="authentication_button"> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="no_show_all">True</property> + <property name="relief">none</property> + <child> + <object class="GtkImage" id="lock_image"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="stock">gtk-dialog-authentication</property> + <property name="icon_size">1</property> + </object> + </child> <style> - <class name="chatcontrol-separator-top"/> + <class name="chatcontrol-actionbar-button"/> </style> </object> <packing> <property name="expand">False</property> - <property name="fill">True</property> + <property name="fill">False</property> + <property name="pack_type">end</property> <property name="position">1</property> </packing> </child> <child> - <object class="GtkScrolledWindow" id="conversation_scrolledwindow"> - <property name="width_request">200</property> - <property name="height_request">60</property> + <object class="GtkMenuButton" id="encryption_menu"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="shadow_type">in</property> - <property name="overlay_scrolling">False</property> - <signal name="edge-reached" handler="_on_edge_reached" swapped="no"/> - <signal name="scroll-event" handler="_on_scroll" swapped="no"/> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes">Choose encryption</property> + <property name="relief">none</property> <child> <placeholder/> </child> <style> - <class name="scrolled-no-border"/> - <class name="no-scroll-indicator"/> - <class name="scrollbar-style"/> + <class name="chatcontrol-actionbar-button"/> </style> </object> <packing> - <property name="expand">True</property> + <property name="expand">False</property> <property name="fill">True</property> + <property name="pack_type">end</property> <property name="position">2</property> </packing> </child> <child> - <object class="GtkSeparator"> + <object class="GtkButton" id="sendfile_button"> <property name="visible">True</property> - <property name="can_focus">False</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">True</property> + <property name="relief">none</property> + <child> + <object class="GtkImage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">mail-attachment-symbolic</property> + </object> + </child> <style> - <class name="chatcontrol-separator"/> + <class name="chatcontrol-actionbar-button"/> </style> </object> <packing> <property name="expand">False</property> - <property name="fill">True</property> + <property name="fill">False</property> + <property name="pack_type">end</property> <property name="position">3</property> </packing> </child> <child> - <object class="GtkBox" id="hbox"> + <object class="GtkMenuButton" id="emoticons_button"> <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <child> - <object class="GtkMenuButton" id="settings_menu"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="relief">none</property> - <child> - <object class="GtkImage"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="icon_name">open-menu-symbolic</property> - </object> - </child> - <style> - <class name="chatcontrol-actionbar-button"/> - </style> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkButton" id="authentication_button"> - <property name="can_focus">True</property> - <property name="focus_on_click">False</property> - <property name="receives_default">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="no_show_all">True</property> - <property name="relief">none</property> - <child> - <object class="GtkImage" id="lock_image"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="stock">gtk-dialog-authentication</property> - <property name="icon_size">1</property> - </object> - </child> - <style> - <class name="chatcontrol-actionbar-button"/> - </style> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="pack_type">end</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkMenuButton" id="encryption_menu"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="tooltip_text" translatable="yes">Choose encryption</property> - <property name="relief">none</property> - <child> - <placeholder/> - </child> - <style> - <class name="chatcontrol-actionbar-button"/> - </style> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="pack_type">end</property> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkButton" id="sendfile_button"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="focus_on_click">False</property> - <property name="receives_default">True</property> - <property name="relief">none</property> - <child> - <object class="GtkImage"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="icon_name">mail-attachment-symbolic</property> - </object> - </child> - <style> - <class name="chatcontrol-actionbar-button"/> - </style> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="pack_type">end</property> - <property name="position">3</property> - </packing> - </child> - <child> - <object class="GtkMenuButton" id="emoticons_button"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> - <property name="tooltip_text" translatable="yes">Show a list of emojis (Alt+M)</property> - <property name="relief">none</property> - <child> - <object class="GtkImage"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="icon_name">face-smile-symbolic</property> - </object> - </child> - <style> - <class name="chatcontrol-actionbar-button"/> - </style> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">4</property> - </packing> - </child> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="tooltip_text" translatable="yes">Show a list of emojis (Alt+M)</property> + <property name="relief">none</property> <child> - <object class="GtkMenuButton" id="formattings_button"> + <object class="GtkImage"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="focus_on_click">False</property> - <property name="receives_default">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="has_tooltip">True</property> - <property name="relief">none</property> - <property name="popup">formattings_menu</property> - <child> - <object class="GtkImage" id="image10"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="icon_name">format-text-bold-symbolic</property> - <property name="icon_size">1</property> - </object> - </child> - <style> - <class name="chatcontrol-actionbar-button"/> - </style> + <property name="can_focus">False</property> + <property name="icon_name">face-smile-symbolic</property> </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">5</property> - </packing> - </child> - <child> - <placeholder/> </child> + <style> + <class name="chatcontrol-actionbar-button"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + <child> + <object class="GtkMenuButton" id="formattings_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="focus_on_click">False</property> + <property name="receives_default">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="has_tooltip">True</property> + <property name="relief">none</property> + <property name="popup">formattings_menu</property> <child> - <object class="GtkComboBox" id="label_selector"> + <object class="GtkImage" id="image10"> <property name="visible">True</property> <property name="can_focus">False</property> - <property name="no_show_all">True</property> + <property name="icon_name">format-text-bold-symbolic</property> + <property name="icon_size">1</property> </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">7</property> - </packing> </child> + <style> + <class name="chatcontrol-actionbar-button"/> + </style> </object> <packing> <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">4</property> + <property name="fill">True</property> + <property name="position">5</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <object class="GtkComboBox" id="label_selector"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="no_show_all">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">7</property> </packing> </child> </object> <packing> - <property name="index">-1</property> + <property name="expand">False</property> + <property name="fill">False</property> + <property name="position">4</property> </packing> </child> </object> <packing> <property name="resize">False</property> - <property name="shrink">False</property> + <property name="shrink">True</property> </packing> </child> <child> @@ -790,6 +781,7 @@ <property name="can_focus">True</property> <property name="visibility">False</property> <property name="invisible_char">*</property> + <property name="activates_default">True</property> <property name="input_purpose">password</property> <signal name="notify::text" handler="_on_password_changed" swapped="no"/> </object> @@ -811,6 +803,97 @@ <property name="position">4</property> </packing> </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkGrid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">center</property> + <property name="valign">center</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">12</property> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="homogeneous">True</property> + <child> + <object class="GtkButton"> + <property name="label" translatable="yes">_Cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="halign">start</property> + <property name="valign">start</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="_on_captcha_cancel_clicked" swapped="no"/> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="captcha_set_button"> + <property name="label" translatable="yes">_Join</property> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">True</property> + <property name="halign">end</property> + <property name="valign">start</property> + <property name="use_underline">True</property> + <signal name="clicked" handler="_on_captcha_set_clicked" swapped="no"/> + <style> + <class name="suggested-action"/> + </style> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkBox" id="captcha_box"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="name">captcha</property> + <property name="position">5</property> + </packing> + </child> </object> <packing> <property name="expand">True</property>
===================================== gajim/groupchat_control.py ===================================== @@ -1125,33 +1125,6 @@ class GroupchatControl(ChatControlBase): from_whom=self.room_jid, form_node=event.form)
- @event_filter(['account', 'room_jid']) - def _on_captcha_challenge(self, event): - self._remove_captcha_request() - - def on_send_dataform_clicked(*args): - form_node = self._captcha_request.get_submit_form() - con = app.connections[self.account] - con.get_module('MUC').send_captcha(self.room_jid, form_node) - self._remove_captcha_request() - - self._captcha_request = CaptchaRequest(event.form, - on_send_dataform_clicked) - self._overlay.add_overlay(self._captcha_request) - - if self.parent_win: - self.parent_win.redraw_tab(self, 'attention') - else: - self.attention_flag = True - - def _remove_captcha_request(self): - if self._captcha_request is None: - return - if self._captcha_request in self._overlay.get_children(): - self._overlay.remove(self._captcha_request) - self._captcha_request.destroy() - self._captcha_request = None - @event_filter(['account']) def _nec_mam_decrypted_message_received(self, obj): if not obj.groupchat: @@ -1946,7 +1919,6 @@ class GroupchatControl(ChatControlBase):
@event_filter(['account', 'room_jid']) def _on_presence_error(self, event): - nick = event.properties.muc_nickname error_type = event.properties.error.type error_message = event.properties.error.message
@@ -2477,6 +2449,8 @@ class GroupchatControl(ChatControlBase):
if self._get_current_page() == 'password': self._on_password_cancel_clicked() + elif self._get_current_page() == 'captcha': + self._on_captcha_cancel_clicked() else: self._show_page('groupchat') return Gdk.EVENT_STOP @@ -2935,6 +2909,8 @@ class GroupchatControl(ChatControlBase): self.xml.password_entry.set_text('') self.xml.password_entry.grab_focus() self.xml.password_set_button.grab_default() + elif page_name == 'captcha': + self.xml.captcha_set_button.grab_default()
def _on_change_nick(self, _action, _param): if self._get_current_page() == 'nickname': @@ -2993,6 +2969,50 @@ class GroupchatControl(ChatControlBase): self.parent_win.remove_tab(self, self.parent_win.CLOSE_COMMAND) self.force_non_minimizable = False
+ @event_filter(['account', 'room_jid']) + def _on_captcha_challenge(self, event): + self._remove_captcha_request() + + options = {'no-scrolling': True, + 'entry-activates-default': True} + self._captcha_request = DataFormWidget(event.form, options=options) + self._captcha_request.connect('is-valid', self._on_captcha_changed) + self._captcha_request.set_valign(Gtk.Align.START) + self._captcha_request.show_all() + self.xml.captcha_box.add(self._captcha_request) + + if self.parent_win: + self.parent_win.redraw_tab(self, 'attention') + else: + self.attention_flag = True + + self._show_page('captcha') + self._captcha_request.focus_first_entry() + + def _remove_captcha_request(self): + if self._captcha_request is None: + return + if self._captcha_request in self.xml.captcha_box.get_children(): + self.xml.captcha_box.remove(self._captcha_request) + self._captcha_request.destroy() + self._captcha_request = None + + def _on_captcha_changed(self, _widget, is_valid): + self.xml.captcha_set_button.set_sensitive(is_valid) + + def _on_captcha_set_clicked(self, _button): + form_node = self._captcha_request.get_submit_form() + con = app.connections[self.account] + con.get_module('MUC').send_captcha(self.room_jid, form_node) + self._remove_captcha_request() + self._show_page('groupchat') + + def _on_captcha_cancel_clicked(self, _button=None): + self._remove_captcha_request() + self.force_non_minimizable = True + self.parent_win.remove_tab(self, self.parent_win.CLOSE_COMMAND) + self.force_non_minimizable = False + def _on_page_cancel_clicked(self, _button): self._show_page('groupchat')
@@ -3040,27 +3060,3 @@ class SubjectPopover(Gtk.Popover): # is not cross-platform compatible open_uri(uri) return Gdk.EVENT_STOP - - -class CaptchaRequest(Gtk.Box): - def __init__(self, form, callback): - Gtk.Box.__init__(self, orientation=Gtk.Orientation.VERTICAL) - - options = {'no-scrolling': True} - self._form_widget = DataFormWidget(form, options=options) - self._form_widget.set_valign(Gtk.Align.START) - - send_button = Gtk.Button(label='Send') - send_button.connect('clicked', callback) - send_button.set_halign(Gtk.Align.CENTER) - - self.add(self._form_widget) - self.add(send_button) - - self.set_valign(Gtk.Align.START) - self.set_margin_top(100) - - self.show_all() - - def get_submit_form(self): - return self._form_widget.get_submit_form()
===================================== gajim/gtk/dataform.py ===================================== @@ -66,6 +66,12 @@ class DataFormWidget(Gtk.ScrolledWindow): self._form_node.type_ = 'submit' return self._form_node
+ def focus_first_entry(self): + for widget in self._form_grid.get_children(): + if isinstance(widget, Gtk.Entry): + widget.grab_focus() + break +
class FormGrid(Gtk.Grid): def __init__(self, form_node, options): @@ -266,6 +272,7 @@ class Field: self._warning_image.set_visible(not is_valid)
def _validate(self): + self._form_grid.validate(False) if self._validate_source_id is not None: GLib.source_remove(self._validate_source_id)
@@ -504,6 +511,8 @@ class TextSingleField(Field): self._widget = Gtk.Entry() self._widget.set_text(field.value) self._widget.connect('changed', self._changed) + if options.get('entry-activates-default', False): + self._widget.set_activates_default(True) self._widget.set_valign(Gtk.Align.CENTER)
def _changed(self, _widget):
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/0dbad0ca817404953865661104187c43bb...