>Форум Mozilla Россия http://forum.mozilla-russia.org/index.php >Сustom Buttons http://forum.mozilla-russia.org/viewforum.php?id=34 >Закрыть окошки дополнения http://forum.mozilla-russia.org/viewtopic.php?id=78783 |
yup > 29-01-2024 19:18:12 |
Здравствуйте. Вопрос у меня на связан напрямую с 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() просто игнорируют и остаются существовать (а браузер закрывается, как это и было в "прежней жизни"). Более того, если после исполнения данного кода запустить его ещё раз, то ни одно из оставшихся окон так и не закроется. При этом окошки в этой ситуации не зависшие, своё основное дело делают и мышкой потом совершенно нормально закрываются. Почему так происходит и как же их программно все позакрывать? |
Dumby > 29-01-2024 20:46:47 |
yup пишет
https://www.upload.ee/ |
Dumby > 29-01-2024 22:47:28 |
Хмм, попробовал воспроизвести вслепую. И действительно, пытаюсь закрыть 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(); Если работает — аддон не требуется. |
yup > 30-01-2024 00:42:56 |
Dumby пишет
А я как раз соорудил минималистичный вариант, в котором ничего постороннего. Dumby пишет
Ох, было у меня такое подозрение, что причина именно в том, что потомок не успевает закрыться до вызова close() у родителя, но попробовал несколько раз подряд руками запускать ту свою закрывающую функцию из консоли браузера и получил описанную ранее картину: при первом запуске закрывается верхнее окно, при последующих уже ничего дополнительно не закрывается. Из этого радостно сделал вывод, что причина в чём-то другом. Dumby пишет
Работать-то работает, но слово "радостно" я употребил потому, что это на мини-примере всё хорошо и прекрасно, а в реальной жизни в этих окошках находятся данные, их может быть много и они ещё не сохранены. При закрывании окошка начинается их запись на диск, длительность которой предугадать невозможно (особенно если процессор чем-то другим под 100% загружен), и поэтому ни на какое разумное число миллисекунд полагаться нельзя. Кроме того, таймеры- это асинхронность, а у нас происходит закрытие браузера, и есть ненулевая вероятность, что его внутренние службы остановятся раньше, чем последние данные на запись отправятся - это ведь уже этап "close-granted". И тут даже переход на чуть более ранний этап - "close-requested" - по большому счёту, не спасает. Разве что тормознуть завершение и написать пользователю: "Закрывай окошки руками". Но тогда смысл затеи пропадает - руками пользователь и при прежнем "образе жизни" закрывал, причём тогда, когда хотел. Сейчас попробую с Promise поиграться. Хотя, наверное, по поводу остановки служб я зря нервничаю, ведь, по идее, они не должны отключаться, пока последнее окно (не браузера, а вообще) не закроется. |
Dumby > 30-01-2024 11:13:33 |
Кстати, у меня и в цикле while работает, если перед we.close(); wa.length && wa.pop().close(); while (wa.length > 0) { we.QueryInterface(Components.interfaces.nsIInterfaceRequestor) we.close(); |
yup > 30-01-2024 12:24:54 |
Великолепно! Я о существовании leaveModalState() даже не подозревал. Спасибо огромное. |
yup > 30-01-2024 18:42:29 |
Подчищал-удалял разные свои записи, сделанные во время этой работы, и нашёл там вот какое наблюдение. Запускаем браузер, открываем Консоль браузера, закрываем окно браузера. Оказывается, то, что при этом происходит в Консоли, зависит от того, как именно окно браузера было закрыто. Если закрывать нажатием крестика в правом верхнем углу браузера или на единственной вкладке - в консоли пишется: "Webconsole context has changed". Логику в этом можно усмотреть такую: если закрывают крестиком или клавиатурным сокращением, то это воспринимается как закрытие конкретного окна браузера, а пункт "Выход" означает закрытие не только браузера, но и всего-всего-всего (все другие окна браузера при этом тоже закрываются). Выбивается из этой логики только Alt-F4: раз предупреждение "Webconsole context has changed" не появилось, значит с точки зрения Консоли что-то от того окна браузера ещё осталось работать. Что бы это могло быть и почему? |