Daniel Brötzmann pushed to branch master at gajim / gajim

Commits:

8 changed files:

Changes:

  • gajim/common/app.py
    ... ... @@ -231,8 +231,8 @@ def detect_dependencies() -> None:
    231 231
                 conference = Gst.ElementFactory.make('fsrtpconference', None)
    
    232 232
                 conference.new_session(Farstream.MediaType.AUDIO)
    
    233 233
                 from gajim.gui.gstreamer import create_gtk_widget
    
    234
    -            sink, _, _ = create_gtk_widget()
    
    235
    -            if sink is not None:
    
    234
    +            gtk_widget = create_gtk_widget()
    
    235
    +            if gtk_widget is not None:
    
    236 236
                     _dependencies['AV'] = True
    
    237 237
         except Exception as error:
    
    238 238
             log('gajim').warning('AV dependency test failed: %s', error)
    

  • gajim/gtk/call_widget.py
    ... ... @@ -471,8 +471,10 @@ def _update_video(self) -> None:
    471 471
                     self._ui.outgoing_viewport.set_no_show_all(True)
    
    472 472
                     self._ui.outgoing_viewport.hide()
    
    473 473
     
    
    474
    -            sink_other, self._video_widget_other, _name = create_gtk_widget()
    
    475
    -            sink_self, self._video_widget_self, _name = create_gtk_widget()
    
    474
    +            other_gtk_widget = create_gtk_widget()
    
    475
    +            self_gtk_widget = create_gtk_widget()
    
    476
    +            sink_other, self._video_widget_other, _name = other_gtk_widget
    
    477
    +            sink_self, self._video_widget_self, _name = self_gtk_widget
    
    476 478
                 self._ui.incoming_viewport.add(self._video_widget_other)
    
    477 479
                 self._ui.outgoing_viewport.add(self._video_widget_self)
    
    478 480
     
    

  • gajim/gtk/gstreamer.py
    ... ... @@ -22,14 +22,14 @@
    22 22
         pass
    
    23 23
     
    
    24 24
     
    
    25
    -def create_gtk_widget() -> Tuple[Optional[Gst.Element],
    
    26
    -                                 Optional[Gtk.Widget],
    
    27
    -                                 Optional[str]]:
    
    25
    +def create_gtk_widget() -> Optional[Tuple[Gst.Element,
    
    26
    +                                          Gtk.Widget,
    
    27
    +                                          str]]:
    
    28 28
         gtkglsink = Gst.ElementFactory.make('gtkglsink', None)
    
    29 29
         if gtkglsink is not None:
    
    30 30
             glsinkbin = Gst.ElementFactory.make('glsinkbin', None)
    
    31 31
             if glsinkbin is None:
    
    32
    -            return None, None, None
    
    32
    +            return None
    
    33 33
             glsinkbin.set_property('sink', gtkglsink)
    
    34 34
             sink = glsinkbin
    
    35 35
             widget = gtkglsink.get_property('widget')
    
    ... ... @@ -37,7 +37,7 @@ def create_gtk_widget() -> Tuple[Optional[Gst.Element],
    37 37
         else:
    
    38 38
             sink = Gst.ElementFactory.make('gtksink', None)
    
    39 39
             if sink is None:
    
    40
    -            return None, None, None
    
    40
    +            return None
    
    41 41
             widget = sink.get_property('widget')
    
    42 42
             name = 'gtksink'
    
    43 43
         widget.set_visible(True)
    

  • gajim/gtk/synchronize_accounts.py
    ... ... @@ -25,7 +25,7 @@
    25 25
     
    
    26 26
     
    
    27 27
     class SynchronizeAccounts(Gtk.ApplicationWindow):
    
    28
    -    def __init__(self, account):
    
    28
    +    def __init__(self, account: str) -> None:
    
    29 29
             Gtk.ApplicationWindow.__init__(self)
    
    30 30
             self.set_application(app.app)
    
    31 31
             self.set_position(Gtk.WindowPosition.CENTER)
    
    ... ... @@ -82,15 +82,16 @@ def __init__(self, account):
    82 82
     
    
    83 83
             self.show_all()
    
    84 84
     
    
    85
    -    def _on_key_press(self, _widget, event):
    
    85
    +    def _on_key_press(self, _widget: Gtk.Widget, event: Gdk.EventKey) -> None:
    
    86 86
             if event.keyval == Gdk.KEY_Escape:
    
    87 87
                 self.destroy()
    
    88 88
     
    
    89
    -    def _init_accounts(self):
    
    89
    +    def _init_accounts(self) -> None:
    
    90 90
             """
    
    91 91
             Initialize listStore with existing accounts
    
    92 92
             """
    
    93 93
             model = self._ui.accounts_treeview.get_model()
    
    94
    +        assert isinstance(model, Gtk.ListStore)
    
    94 95
             model.clear()
    
    95 96
             for remote_account in app.connections:
    
    96 97
                 if remote_account == self.account:
    
    ... ... @@ -104,15 +105,13 @@ def _init_accounts(self):
    104 105
                     1,
    
    105 106
                     app.get_hostname_from_account(remote_account))
    
    106 107
     
    
    107
    -    def _on_next_clicked(self, _widget):
    
    108
    +    def _on_next_clicked(self, _button: Gtk.Button) -> None:
    
    108 109
             selection = self._ui.accounts_treeview.get_selection()
    
    109 110
             (model, iter_) = selection.get_selected()
    
    110 111
             if not iter_:
    
    111 112
                 return
    
    112 113
     
    
    113 114
             self._remote_account = model.get_value(iter_, 0)
    
    114
    -        self._remote_client = app.get_client(self._remote_account)
    
    115
    -
    
    116 115
             if not app.account_is_available(self._remote_account):
    
    117 116
                 ErrorDialog(
    
    118 117
                     _('This account is not connected to the server'),
    
    ... ... @@ -120,24 +119,27 @@ def _on_next_clicked(self, _widget):
    120 119
                       'connected.'))
    
    121 120
                 return
    
    122 121
     
    
    122
    +        self._remote_client = app.get_client(self._remote_account)
    
    123 123
             self._init_contacts()
    
    124 124
             self._ui.stack.set_visible_child_full(
    
    125 125
                 'contacts', Gtk.StackTransitionType.SLIDE_LEFT)
    
    126 126
     
    
    127
    -    def _on_back_clicked(self, _button):
    
    127
    +    def _on_back_clicked(self, _button: Gtk.Button) -> None:
    
    128 128
             self._ui.stack.set_visible_child_full(
    
    129 129
                 'accounts', Gtk.StackTransitionType.SLIDE_RIGHT)
    
    130 130
     
    
    131 131
         def _init_contacts(self):
    
    132 132
             model = self._ui.contacts_treeview.get_model()
    
    133
    +        assert isinstance(model, Gtk.ListStore)
    
    133 134
             model.clear()
    
    134 135
     
    
    135 136
             # recover local contacts
    
    136
    -        local_jid_list = []
    
    137
    +        local_jid_list: list[str] = []
    
    137 138
             for contact in self._local_client.get_module('Roster').iter_contacts():
    
    138 139
                 local_jid_list.append(str(contact.jid))
    
    139 140
     
    
    140
    -        remote_jid_list = []
    
    141
    +        remote_jid_list: list[str] = []
    
    142
    +        assert self._remote_client is not None
    
    141 143
             for contact in self._remote_client.get_module('Roster').iter_contacts():
    
    142 144
                 remote_jid_list.append(str(contact.jid))
    
    143 145
     
    
    ... ... @@ -146,22 +148,26 @@ def _init_contacts(self):
    146 148
                     iter_ = model.append()
    
    147 149
                     model.set(iter_, 0, True, 1, remote_jid)
    
    148 150
     
    
    149
    -    def _on_sync_toggled(self, cell, path):
    
    151
    +    def _on_sync_toggled(self, cell: Gtk.CellRendererToggle, path: str) -> None:
    
    150 152
             model = self._ui.contacts_treeview.get_model()
    
    153
    +        assert isinstance(model, Gtk.ListStore)
    
    151 154
             iter_ = model.get_iter(path)
    
    152 155
             model[iter_][0] = not cell.get_active()
    
    153 156
     
    
    154
    -    def _on_sync_clicked(self, _widget):
    
    157
    +    def _on_sync_clicked(self, _button: Gtk.Button) -> None:
    
    158
    +        assert self._remote_account is not None
    
    159
    +        assert self._remote_client is not None
    
    155 160
             model = self._ui.contacts_treeview.get_model()
    
    161
    +        assert isinstance(model, Gtk.ListStore)
    
    156 162
             iter_ = model.get_iter_first()
    
    157 163
             while iter_:
    
    158 164
                 if model[iter_][0]:
    
    159 165
                     # it is selected
    
    160 166
                     remote_jid = model[iter_][1]
    
    167
    +                hostname = app.get_hostname_from_account(self._remote_account)
    
    161 168
                     message = _('I’m synchronizing my contacts from my account at '
    
    162 169
                                 '"%s". Could you please add this address to your '
    
    163
    -                            'contact list?' % app.get_hostname_from_account(
    
    164
    -                                self._remote_account))
    
    170
    +                            'contact list?' % hostname)
    
    165 171
                     remote_contact = self._remote_client.get_module(
    
    166 172
                         'Contacts').get_contact(remote_jid)
    
    167 173
     
    

  • gajim/gtk/themes.py
    ... ... @@ -326,6 +326,8 @@ def _remove_theme():
    326 326
     
    
    327 327
                 app.css_config.remove_theme(theme)
    
    328 328
                 self._update_preferences_window()
    
    329
    +            assert isinstance(store, Gtk.TreeStore)
    
    330
    +            assert iter_ is not None
    
    329 331
                 store.remove(iter_)
    
    330 332
     
    
    331 333
                 first = store.get_iter_first()
    
    ... ... @@ -364,8 +366,10 @@ def __init__(self,
    364 366
             self._box.add(label)
    
    365 367
     
    
    366 368
             if option.attr in (StyleAttr.COLOR, StyleAttr.BACKGROUND):
    
    369
    +            assert not isinstance(value, Pango.FontDescription)
    
    367 370
                 self._init_color(value)
    
    368 371
             elif option.attr == StyleAttr.FONT:
    
    372
    +            assert not isinstance(value, str)
    
    369 373
                 self._init_font(value)
    
    370 374
     
    
    371 375
             remove_button = Gtk.Button.new_from_icon_name(
    
    ... ... @@ -378,7 +382,7 @@ def __init__(self,
    378 382
             self.add(self._box)
    
    379 383
             self.show_all()
    
    380 384
     
    
    381
    -    def _init_color(self, color: str) -> None:
    
    385
    +    def _init_color(self, color: Optional[str]) -> None:
    
    382 386
             color_button = Gtk.ColorButton()
    
    383 387
             if color is not None:
    
    384 388
                 rgba = Gdk.RGBA()
    
    ... ... @@ -388,7 +392,7 @@ def _init_color(self, color: str) -> None:
    388 392
             color_button.connect('color-set', self._on_color_set)
    
    389 393
             self._box.add(color_button)
    
    390 394
     
    
    391
    -    def _init_font(self, desc: Pango.FontDescription) -> None:
    
    395
    +    def _init_font(self, desc: Optional[Pango.FontDescription]) -> None:
    
    392 396
             font_button = Gtk.FontButton()
    
    393 397
             if desc is not None:
    
    394 398
                 font_button.set_font_desc(desc)
    
    ... ... @@ -402,24 +406,29 @@ def _on_color_set(self, color_button: Gtk.ColorButton) -> None:
    402 406
             app.css_config.set_value(
    
    403 407
                 self.option.selector, self.option.attr, color_string, pre=True)
    
    404 408
             app.ged.raise_event(StyleChanged())
    
    405
    -        self.get_toplevel().reload_roster_theme()
    
    409
    +        themes_win = cast(Themes, self.get_toplevel())
    
    410
    +        themes_win.reload_roster_theme()
    
    406 411
     
    
    407 412
         def _on_font_set(self, font_button: Gtk.FontButton) -> None:
    
    408 413
             desc = font_button.get_font_desc()
    
    414
    +        if desc is None:
    
    415
    +            return
    
    409 416
             app.css_config.set_font(self.option.selector, desc, pre=True)
    
    410 417
             app.ged.raise_event(StyleChanged())
    
    411
    -        self.get_toplevel().reload_roster_theme()
    
    418
    +        themes_win = cast(Themes, self.get_toplevel())
    
    419
    +        themes_win.reload_roster_theme()
    
    412 420
     
    
    413 421
         def _on_remove(self, *args: Any) -> None:
    
    414
    -        self.get_parent().remove(self)
    
    422
    +        listbox = cast(Gtk.ListBox, self.get_parent())
    
    423
    +        listbox.remove(self)
    
    415 424
             app.css_config.remove_value(
    
    416 425
                 self.option.selector, self.option.attr, pre=True)
    
    417 426
             app.ged.raise_event(StyleChanged())
    
    418 427
             self.destroy()
    
    419 428
     
    
    420
    -    def __eq__(self, other):
    
    421
    -        if isinstance(other, ChooseOption):
    
    422
    -            return other.option == self.option
    
    429
    +    def __eq__(self, other: object) -> bool:
    
    430
    +        if not isinstance(other, ChooseOption):
    
    431
    +            raise NotImplementedError
    
    423 432
             return other.option == self.option
    
    424 433
     
    
    425 434
     
    

  • gajim/gtk/video_preview.py
    ... ... @@ -70,13 +70,14 @@ def _enable_preview(self) -> None:
    70 70
                 self._set_error_text()
    
    71 71
                 return
    
    72 72
     
    
    73
    -        sink, widget, name = create_gtk_widget()
    
    74
    -        if sink is None:
    
    73
    +        gtk_widget = create_gtk_widget()
    
    74
    +        if gtk_widget is None:
    
    75 75
                 log.error('Failed to obtain a working Gstreamer GTK+ sink, '
    
    76 76
                           'video support will be disabled')
    
    77 77
                 self._set_error_text()
    
    78 78
                 return
    
    79 79
     
    
    80
    +        sink, widget, name = gtk_widget
    
    80 81
             self._set_sink_text(name)
    
    81 82
     
    
    82 83
             if self._av_pipeline is None:
    
    ... ... @@ -94,6 +95,7 @@ def _enable_preview(self) -> None:
    94 95
             self._ui.video_preview_box.pack_end(widget, True, True, 0)
    
    95 96
             self._av_widget = widget
    
    96 97
     
    
    98
    +        assert self._av_src is not None
    
    97 99
             self._av_pipeline.add(self._av_src)
    
    98 100
             self._av_src.link(self._av_sink)
    
    99 101
             self._av_pipeline.set_state(Gst.State.PLAYING)
    

  • gajim/gtk/workspace_dialog.py
    ... ... @@ -12,6 +12,7 @@
    12 12
     # You should have received a copy of the GNU General Public License
    
    13 13
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    14 14
     
    
    15
    +from typing import Any
    
    15 16
     from typing import Optional
    
    16 17
     
    
    17 18
     from gi.repository import Gtk
    
    ... ... @@ -79,18 +80,19 @@ def __init__(self, workspace_id: Optional[str] = None) -> None:
    79 80
     
    
    80 81
             self._ui.connect_signals(self)
    
    81 82
     
    
    82
    -        self.connect('key-press-event', self._on_key_press_event)
    
    83
    +        self.connect('key-press-event', self._on_key_press)
    
    83 84
             self.show_all()
    
    84 85
     
    
    85
    -    def _on_key_press_event(self, _widget, event):
    
    86
    +    def _on_key_press(self, _widget: Gtk.Widget, event: Gdk.EventKey) -> None:
    
    86 87
             if event.keyval == Gdk.KEY_Escape:
    
    87 88
                 self.destroy()
    
    88 89
     
    
    89
    -    def _on_remove_workspace(self, _button):
    
    90
    +    def _on_remove_workspace(self, _button: Gtk.Button) -> None:
    
    90 91
             def _on_remove():
    
    92
    +            assert self._workspace_id is not None
    
    91 93
                 app.window.remove_workspace(self._workspace_id)
    
    92 94
                 self.destroy()
    
    93
    -
    
    95
    +        assert self._workspace_id is not None
    
    94 96
             chat_list = app.window.get_chat_list(self._workspace_id)
    
    95 97
             open_chats = chat_list.get_open_chats()
    
    96 98
             if len(open_chats) > 0:
    
    ... ... @@ -106,22 +108,24 @@ def _on_remove():
    106 108
             # No chats in chat list, it is save to remove workspace
    
    107 109
             _on_remove()
    
    108 110
     
    
    109
    -    def _on_cancel(self, _button):
    
    111
    +    def _on_cancel(self, _button: Gtk.Button) -> None:
    
    110 112
             self.destroy()
    
    111 113
     
    
    112
    -    def _on_color_set(self, _button):
    
    114
    +    def _on_color_set(self, _button: Gtk.ColorButton) -> None:
    
    113 115
             self._update_avatar()
    
    114 116
     
    
    115
    -    def _on_text_changed(self, entry, _param):
    
    117
    +    def _on_text_changed(self, entry: Gtk.Entry, _param: Any) -> None:
    
    116 118
             self._ui.save_button.set_sensitive(bool(entry.get_text()))
    
    117 119
             self._update_avatar()
    
    118 120
     
    
    119
    -    def _on_image_switch_toggled(self, switch, *args):
    
    121
    +    def _on_image_switch_toggled(self, switch: Gtk.Switch, *args: Any) -> None:
    
    120 122
             if switch.get_active():
    
    121 123
                 self._ui.style_stack.set_visible_child_name('image')
    
    122 124
                 if self._workspace_id is not None:
    
    123 125
                     self._avatar_sha = app.settings.get_workspace_setting(
    
    124 126
                         self._workspace_id, 'avatar_sha')
    
    127
    +                if self._avatar_sha == '':
    
    128
    +                    self._avatar_sha = None
    
    125 129
             else:
    
    126 130
                 self._ui.style_stack.set_visible_child_name('color')
    
    127 131
                 self._avatar_sha = None
    
    ... ... @@ -132,6 +136,7 @@ def _update_avatar(self) -> None:
    132 136
             rgba = self._ui.color_chooser.get_rgba()
    
    133 137
             scale = self.get_scale_factor()
    
    134 138
             if self._avatar_sha is not None:
    
    139
    +            assert self._workspace_id is not None
    
    135 140
                 surface = app.interface.avatar_storage.get_workspace_surface(
    
    136 141
                     self._workspace_id,
    
    137 142
                     AvatarSize.WORKSPACE_EDIT,
    
    ... ... @@ -154,7 +159,7 @@ def _get_avatar_data(self) -> Optional[bytes]:
    154 159
     
    
    155 160
             return data
    
    156 161
     
    
    157
    -    def _on_save(self, _button):
    
    162
    +    def _on_save(self, _button: Gtk.Button) -> None:
    
    158 163
             name = self._ui.entry.get_text()
    
    159 164
             rgba = self._ui.color_chooser.get_rgba()
    
    160 165
             use_image = self._ui.image_switch.get_active()
    

  • gajim/gtk/workspace_side_bar.py
    ... ... @@ -17,7 +17,7 @@
    17 17
     from typing import Any
    
    18 18
     from typing import List
    
    19 19
     from typing import Optional
    
    20
    -from typing import Union
    
    20
    +from typing import cast
    
    21 21
     
    
    22 22
     import logging
    
    23 23
     
    
    ... ... @@ -25,6 +25,7 @@
    25 25
     from gi.repository import Gio
    
    26 26
     from gi.repository import GLib
    
    27 27
     from gi.repository import Gtk
    
    28
    +
    
    28 29
     from nbxmpp.protocol import JID
    
    29 30
     
    
    30 31
     from gajim.common import app
    
    ... ... @@ -63,8 +64,8 @@ def __init__(self, chat_page: ChatPage) -> None:
    63 64
                 Gdk.DragAction.MOVE)
    
    64 65
     
    
    65 66
             self.drag_row: Optional[Workspace] = None
    
    66
    -        self.row_before: Optional[Workspace] = None
    
    67
    -        self.row_after: Union[Workspace, AddWorkspace, None] = None
    
    67
    +        self.row_before: Optional[CommonWorkspace] = None
    
    68
    +        self.row_after: Optional[CommonWorkspace] = None
    
    68 69
     
    
    69 70
             self.connect('drag-motion', self._on_drag_motion)
    
    70 71
             self.connect('drag-data-received', self._on_drag_data_received)
    
    ... ... @@ -86,7 +87,7 @@ def _on_drag_motion(self,
    86 87
                             y_coord: int,
    
    87 88
                             _time: int
    
    88 89
                             ) -> bool:
    
    89
    -        row = self.get_row_at_y(y_coord)
    
    90
    +        row = cast(CommonWorkspace, self.get_row_at_y(y_coord))
    
    90 91
     
    
    91 92
             if row:
    
    92 93
                 alloc = row.get_allocation()
    
    ... ... @@ -128,7 +129,9 @@ def _on_drag_data_received(self,
    128 129
         def _process_workspace_drop(self, workspace_id: str) -> None:
    
    129 130
             row = self.get_workspace_by_id(workspace_id)
    
    130 131
     
    
    131
    -        if row in (self.row_after, None):
    
    132
    +        if row == self.row_after:
    
    133
    +            return
    
    134
    +        if row is None:
    
    132 135
                 return
    
    133 136
     
    
    134 137
             self.remove(row)
    
    ... ... @@ -146,7 +149,7 @@ def _process_workspace_drop(self, workspace_id: str) -> None:
    146 149
     
    
    147 150
         def _process_chat_list_drop(self, identifier: str, y_coord: int) -> None:
    
    148 151
             account, jid = identifier.split()
    
    149
    -        workspace_row = self.get_row_at_y(y_coord)
    
    152
    +        workspace_row = cast(Workspace, self.get_row_at_y(y_coord))
    
    150 153
             if workspace_row.workspace_id == 'add':
    
    151 154
                 return
    
    152 155
     
    
    ... ... @@ -156,15 +159,25 @@ def _process_chat_list_drop(self, identifier: str, y_coord: int) -> None:
    156 159
             app.window.activate_action('move-chat-to-workspace',
    
    157 160
                                        params.to_variant())
    
    158 161
     
    
    159
    -    def _get_row_before(self, row):
    
    160
    -        return self.get_row_at_index(row.get_index() - 1)
    
    162
    +    def _get_row_before(self,
    
    163
    +                        row: CommonWorkspace
    
    164
    +                        ) -> Optional[CommonWorkspace]:
    
    165
    +        workspace = cast(
    
    166
    +            CommonWorkspace, self.get_row_at_index(row.get_index() - 1))
    
    167
    +        return workspace
    
    161 168
     
    
    162
    -    def _get_row_after(self, row):
    
    163
    -        return self.get_row_at_index(row.get_index() + 1)
    
    169
    +    def _get_row_after(self,
    
    170
    +                       row: CommonWorkspace
    
    171
    +                       ) -> Optional[CommonWorkspace]:
    
    172
    +        workspace = cast(
    
    173
    +            CommonWorkspace, self.get_row_at_index(row.get_index() + 1))
    
    174
    +        return workspace
    
    164 175
     
    
    165 176
         def _get_last_workspace_row(self) -> Workspace:
    
    166 177
             # Calling len(children) would include AddWorkspace
    
    167
    -        return self.get_row_at_index(len(self.get_children()) - 1)
    
    178
    +        last_workspace = cast(
    
    179
    +            Workspace, self.get_row_at_index(len(self.get_children()) - 1))
    
    180
    +        return last_workspace
    
    168 181
     
    
    169 182
         def set_drag_row(self, row: Workspace) -> None:
    
    170 183
             self.drag_row = row
    
    ... ... @@ -185,7 +198,7 @@ def _on_chat_selected(self,
    185 198
     
    
    186 199
         @staticmethod
    
    187 200
         def _on_row_activated(_listbox: Gtk.ListBox,
    
    188
    -                          row: Union[Workspace, AddWorkspace]
    
    201
    +                          row: CommonWorkspace
    
    189 202
                               ) -> None:
    
    190 203
             if row.workspace_id == 'add':
    
    191 204
                 open_window('WorkspaceDialog')
    
    ... ... @@ -199,7 +212,9 @@ def add_workspace(self, workspace_id: str) -> None:
    199 212
             self.insert(row, len(self.get_children()) - 1)
    
    200 213
     
    
    201 214
         def store_workspace_order(self) -> None:
    
    202
    -        order = [row.workspace_id for row in self.get_children()]
    
    215
    +        workspaces: list[CommonWorkspace] = cast(
    
    216
    +            list[CommonWorkspace], self.get_children())
    
    217
    +        order: list[str] = [row.workspace_id for row in workspaces]
    
    203 218
             order.remove('add')
    
    204 219
             app.settings.set_app_setting('workspace_order', order)
    
    205 220
     
    
    ... ... @@ -211,7 +226,7 @@ def remove_workspace(self, workspace_id: str) -> bool:
    211 226
             return True
    
    212 227
     
    
    213 228
         def activate_workspace(self, workspace_id: str) -> None:
    
    214
    -        row = self.get_selected_row()
    
    229
    +        row = cast(CommonWorkspace, self.get_selected_row())
    
    215 230
             if row is not None and row.workspace_id == workspace_id:
    
    216 231
                 return
    
    217 232
     
    
    ... ... @@ -219,17 +234,24 @@ def activate_workspace(self, workspace_id: str) -> None:
    219 234
             self.select_row(row)
    
    220 235
     
    
    221 236
         def get_active_workspace(self) -> Optional[str]:
    
    222
    -        row = self.get_selected_row()
    
    237
    +        row = cast(CommonWorkspace, self.get_selected_row())
    
    223 238
             if row is None:
    
    224 239
                 return None
    
    225 240
             return row.workspace_id
    
    226 241
     
    
    227 242
         def get_first_workspace(self) -> str:
    
    228
    -        for row in self.get_children():
    
    243
    +        workspaces: list[CommonWorkspace] = cast(
    
    244
    +            list[CommonWorkspace], self.get_children())
    
    245
    +        for row in workspaces:
    
    229 246
                 return row.workspace_id
    
    230
    -
    
    231
    -    def get_workspace_by_id(self, workspace_id: str) -> Optional[Workspace]:
    
    232
    -        for row in self.get_children():
    
    247
    +        return ''
    
    248
    +
    
    249
    +    def get_workspace_by_id(self,
    
    250
    +                            workspace_id: str
    
    251
    +                            ) -> Optional[CommonWorkspace]:
    
    252
    +        workspaces: list[CommonWorkspace] = cast(
    
    253
    +            list[CommonWorkspace], self.get_children())
    
    254
    +        for row in workspaces:
    
    233 255
                 if row.workspace_id == workspace_id:
    
    234 256
                     return row
    
    235 257
             return None
    
    ... ... @@ -296,8 +318,8 @@ def _popup_menu(self, _widget: Gtk.Widget, event: Gdk.EventButton) -> None:
    296 318
             menu = self._get_workspace_menu()
    
    297 319
     
    
    298 320
             rectangle = Gdk.Rectangle()
    
    299
    -        rectangle.x = event.x
    
    300
    -        rectangle.y = event.y
    
    321
    +        rectangle.x = int(event.x)
    
    322
    +        rectangle.y = int(event.y)
    
    301 323
             rectangle.width = rectangle.height = 1
    
    302 324
     
    
    303 325
             popover = Gtk.Popover.new_from_model(self, menu)
    
    ... ... @@ -337,9 +359,10 @@ def _on_drag_begin(self,
    337 359
             scale = self.get_scale_factor()
    
    338 360
             surface = app.interface.avatar_storage.get_workspace_surface(
    
    339 361
                 self.workspace_id, AvatarSize.WORKSPACE, scale)
    
    340
    -        Gtk.drag_set_icon_surface(drag_context, surface)
    
    362
    +        if surface is not None:
    
    363
    +            Gtk.drag_set_icon_surface(drag_context, surface)
    
    341 364
     
    
    342
    -        listbox = self.get_parent()
    
    365
    +        listbox = cast(WorkspaceSideBar, self.get_parent())
    
    343 366
             listbox.set_drag_row(self)
    
    344 367
     
    
    345 368
         def _on_drag_data_get(self,