Страницы: 1
Здравствуйте.
Вопрос у меня на связан напрямую с CB, но задать его больше негде.
После многих лет занятия чем попало попытался немного вернуться к браузероковырянию и усовершенствовать одно из своих любимых и давно используемых дополнений.
Когда вся основная работа была сделана и желаемый результат достигнут, решил ещё для красоты приделать "сбоку бантик", и в результате получил такое "чёрти-что", что не знаю, что и подумать.
Суть проблемы:
Дополнение при вызове открывает своё окно. Оно не модальное, висит себе рядом с браузером, работать не мешает.
Из этого окна можно открыть диалог. Из этого диалога можно открыть второй диалог, из которого в тяжёлых случаях может быть открыть ещё и третий диалог.
Вся эта конструкция живёт своей жизнью и остаётся на экране, даже когда все окна браузера уже закрыты.
В принципе, меня это всю жизнь устраивало, но сейчас решил добавить в настройки галочку "Закрывать при выходе из браузера". Для этого добавил в существующий код XPCOM-component, который отслеживает приход сообщения "browser-lastwindow-close-granted", по получению которого закрывает все имеющиеся окна дополнения. Опознаёт "свои" окна он по их типу.
Код закрытия простой:
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator); var we = wm.getEnumerator("my_addon_window"); var wa = []; while (we.hasMoreElements()) { wa.push(we.getNext()); } while (wa.length > 0) { we = wa.pop(); we.close(); }
(Извращение с массивом нужно, чтобы закрывать окна в порядке, обратном их открытию, т.к. все диалоги модальные.)
И вот тут обнаружилось, что сколько бы у моего дополнения ни было открыто окон, закрывается только самое последнее (верхнее) из них. Все остальные вызов close() просто игнорируют и остаются существовать (а браузер закрывается, как это и было в "прежней жизни").
Более того, если после исполнения данного кода запустить его ещё раз, то ни одно из оставшихся окон так и не закроется. При этом окошки в этой ситуации не зависшие, своё основное дело делают и мышкой потом совершенно нормально закрываются.
Почему так происходит и как же их программно все позакрывать?
Отредактировано yup (29-01-2024 19:23:18)
Отсутствует
Хмм, попробовал воспроизвести вслепую.
Понаоткрывал кодом alert'ов, первый с окна браузера,
второй с окна первого alert'а, третий со второго, и так далее.
Проставил по пути атрибут "windowtype", все дела...
И действительно, пытаюсь закрыть alert'ы предоставленным кодом,
но закрывается только последний открытый.
Но если закрывать с некоторой задержкой, тогда нормально.
То есть, вместо
что-то типа
if (wa.length > 1) { var timer = Components.classes["@mozilla.org/timer;1"] .createInstance(Components.interfaces.nsITimer); var close = function() { wa.pop().close(); wa.length && timer.initWithCallback(close, 100, timer.TYPE_ONE_SHOT); } close(); } else if (wa.length == 1) wa[0].close();
Если работает — аддон не требуется.
Отсутствует
Если работает — аддон не требуется.
А я как раз соорудил минималистичный вариант, в котором ничего постороннего.
Но если закрывать с некоторой задержкой, тогда нормально.
Ох, было у меня такое подозрение, что причина именно в том, что потомок не успевает закрыться до вызова close() у родителя, но попробовал несколько раз подряд руками запускать ту свою закрывающую функцию из консоли браузера и получил описанную ранее картину: при первом запуске закрывается верхнее окно, при последующих уже ничего дополнительно не закрывается. Из этого радостно сделал вывод, что причина в чём-то другом.
Если работает
Работать-то работает, но слово "радостно" я употребил потому, что это на мини-примере всё хорошо и прекрасно, а в реальной жизни в этих окошках находятся данные, их может быть много и они ещё не сохранены. При закрывании окошка начинается их запись на диск, длительность которой предугадать невозможно (особенно если процессор чем-то другим под 100% загружен), и поэтому ни на какое разумное число миллисекунд полагаться нельзя.
Кроме того, таймеры- это асинхронность, а у нас происходит закрытие браузера, и есть ненулевая вероятность, что его внутренние службы остановятся раньше, чем последние данные на запись отправятся - это ведь уже этап "close-granted". И тут даже переход на чуть более ранний этап - "close-requested" - по большому счёту, не спасает. Разве что тормознуть завершение и написать пользователю: "Закрывай окошки руками". Но тогда смысл затеи пропадает - руками пользователь и при прежнем "образе жизни" закрывал, причём тогда, когда хотел.
Сейчас попробую с Promise поиграться.
Хотя, наверное, по поводу остановки служб я зря нервничаю, ведь, по идее, они не должны отключаться, пока последнее окно (не браузера, а вообще) не закроется.
Отредактировано yup (30-01-2024 00:53:32)
Отсутствует
Кстати, у меня и в цикле while работает, если перед we.close();
вызвать nsIDOMWindowUtils.leaveModalState(), типа
wa.length && wa.pop().close();
while (wa.length > 0) {
we = wa.pop();
we.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils).leaveModalState();
we.close();
}
Отсутствует
Подчищал-удалял разные свои записи, сделанные во время этой работы, и нашёл там вот какое наблюдение.
Запускаем браузер, открываем Консоль браузера, закрываем окно браузера. Оказывается, то, что при этом происходит в Консоли, зависит от того, как именно окно браузера было закрыто.
Если закрывать нажатием крестика в правом верхнем углу браузера или на единственной вкладке - в консоли пишется: "Webconsole context has changed".
Если закрывать нажатием Ctrl-F4 или Ctrl-W на единственной вкладке - в консоли пишется: "Webconsole context has changed".
Если закрывать нажатием Alt-F4 - в консоли тишина.
Если закрывать через пункт "Выход" в меню - консоль тоже закрывается.
Логику в этом можно усмотреть такую: если закрывают крестиком или клавиатурным сокращением, то это воспринимается как закрытие конкретного окна браузера, а пункт "Выход" означает закрытие не только браузера, но и всего-всего-всего (все другие окна браузера при этом тоже закрываются).
Выбивается из этой логики только Alt-F4: раз предупреждение "Webconsole context has changed" не появилось, значит с точки зрения Консоли что-то от того окна браузера ещё осталось работать. Что бы это могло быть и почему?
Отредактировано yup (30-01-2024 18:49:19)
Отсутствует
Страницы: 1