window_row.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import Adw from 'gi://Adw';
  2. import GLib from 'gi://GLib';
  3. import GObject from 'gi://GObject';
  4. import Gio from 'gi://Gio';
  5. import Gtk from 'gi://Gtk';
  6. import { pick, on_picking, on_picked } from '../dbus/client.js';
  7. export const WindowRow = GObject.registerClass({
  8. GTypeName: 'WindowRow',
  9. Template: GLib.uri_resolve_relative(import.meta.url, '../ui/window-row.ui', GLib.UriFlags.NONE),
  10. InternalChildren: [
  11. 'window_picker',
  12. 'window_class',
  13. 'picking_failure_toast',
  14. 'window_not_found_toast'
  15. ],
  16. }, class WindowRow extends Adw.ExpanderRow {
  17. constructor(list, app_page, app_name) {
  18. super({});
  19. this._list = list;
  20. this._app_page = app_page;
  21. // add a 'remove' button before the text
  22. let action_row = this.child.get_first_child().get_first_child();
  23. let remove_button = new Gtk.Button({
  24. 'icon-name': 'remove-window-symbolic',
  25. 'width-request': 38,
  26. 'height-request': 38,
  27. 'margin-top': 6,
  28. 'margin-bottom': 6,
  29. });
  30. remove_button.add_css_class('circular');
  31. remove_button.add_css_class('flat');
  32. action_row.add_prefix(remove_button);
  33. // connect the button to the whitelist / blacklist removal
  34. remove_button.connect('clicked', _ => this._remove_row());
  35. // bind row title to text buffer
  36. this._window_class.buffer.bind_property(
  37. 'text', this, 'title',
  38. Gio.SettingsBindFlags.BIDIRECTIONNAL
  39. );
  40. // set application name if it exists, or open the revealer and pick one
  41. if (app_name)
  42. this._window_class.buffer.text = app_name;
  43. else {
  44. app_page.close_all_expanded_rows();
  45. this.set_expanded(true);
  46. this._do_pick_window(true);
  47. }
  48. // pick a window when the picker button is clicked
  49. this._window_picker.connect('clicked', _ => this._do_pick_window());
  50. // update list on text buffer change
  51. this._window_class.connect('changed',
  52. _ => this._update_rows_titles()
  53. );
  54. }
  55. _remove_row() {
  56. this._app_page["remove_from_" + this._list](this);
  57. }
  58. _update_rows_titles() {
  59. this._app_page["update_" + this._list + "_titles"](this);
  60. }
  61. _do_pick_window(remove_if_failed = false) {
  62. // a mechanism to know if the extension is listening correcly
  63. let has_responded = false;
  64. let should_take_answer = true;
  65. setTimeout(_ => {
  66. if (!has_responded) {
  67. // show toast about failure
  68. this._app_page._preferences_window.add_toast(
  69. this._picking_failure_toast
  70. );
  71. // prevent title from changing with later picks
  72. should_take_answer = false;
  73. // remove row if asked
  74. if (remove_if_failed)
  75. this._remove_row();
  76. }
  77. }, 250);
  78. on_picking(_ =>
  79. has_responded = true
  80. );
  81. on_picked(wm_class => {
  82. if (should_take_answer) {
  83. if (wm_class == 'window-not-found') {
  84. console.warn("Can't pick window from here");
  85. this._app_page._preferences_window.add_toast(
  86. this._window_not_found_toast
  87. );
  88. return;
  89. }
  90. this._window_class.buffer.text = wm_class;
  91. }
  92. });
  93. pick();
  94. }
  95. });