LINUX.ORG.RU

>Есть ли функция / способ установить urgent hint окну емакса (заставить его моргать заголовком окна и кнопкой на панели задач) из lisp-ового кода?

Сразу вот не скажу, можно ли или нет такое сделать (далеко и не факт), но можно из лиспового кода поднимать окно (raise-frame), задвигать назад (lower-frame), свертывать (iconify-frame). Можно в заголовке и на кнопке приложения менять формат: переменные frame-title-format, icon-title-format (это не иконка -- это значит заголовок свернутого окна).

Zubok ★★★★★
()

А, ну и можно менять frame parameter 'name, например по таймеру.

Zubok ★★★★★
()

попробуй дергать wmctrl -r emacs -b "add,demands_attention"

ananas ★★★★★
()

Когда-то задался такой целью, чтобы не пропускать сообщения в jabber.el. Ничего путного не нашел и сделал сам с помощью pymacs.

Это где-то в .emacs:

(setenv "PYMACS_PYTHON" "python2.5")

(eval-after-load "pymacs"
  '(progn
     (add-to-list 'pymacs-load-path "~/emacs/pymacs/")
     (pymacs-load "xutils")))

(defun frame-set-urgency-hint (frame)
  "Set urgency hint for frame."
  (let ((frame-id (string-to-number (frame-parameter frame 'outer-window-id))))
    (xutils-set-urgency-hint frame-id)
    t))

(defun buffer-set-urgency-hint (buffer)
  "Set urgency hint for frame, which contains given buffer."
  (let ((buf (get-buffer buffer)))
    (and buf
         (let ((window (get-buffer-window buf t)))
           (and window
                (let ((frame (window-frame window)))
                  (frame-set-urgency-hint frame)))))))

Так это прикручивается к jabber.el:

(defun urgency-hint (from buffer text)
  "Set urgency-hint for chat frame."
  (or (buffer-set-urgency-hint buffer)
      (buffer-set-urgency-hint jabber-roster-buffer)
      (frame-set-urgency-hint (car (frame-list)))))

(setq jabber-alert-message-function #'urgency-hint)

А это ~/emacs/pymacs/xutils.py:

#!/usr/bin/env python

import sys

from Pymacs import lisp

from Xlib import display, error
from Xlib.xobject.drawable import Window


UrgencyHint = 1 << 8


def set_urgency_hint(window_id):
    disp = display.Display()

    win  = Window(disp.display, window_id)

    try:
        hints = win.get_wm_hints() or { 'flags': 0 }
        hints['flags'] |= UrgencyHint

        win.set_wm_hints(hints)
        disp.flush()

    except error.BadWindow:
        return False

    return True

Сделал и с тех пор забыл: работает исправно. Если можно что-то подкрутить получше, предлагайте.

satanic-mechanic
()
Ответ на: комментарий от satanic-mechanic

Когда-то задался такой целью, чтобы не пропускать сообщения в jabber.el. Ничего путного не нашел и сделал сам с помощью pymacs.

Offtopic. А я лампочкой себе мигаю. Ну и заодно информирование в заголовке окна сделал (это штатно есть в jabber.el). Лампочкой мигаю при помощи blinkd. Удобно тем, что не надо подходить к компьютеру, когда монитор выключен, чтобы понять, что есть сообщения — просто бросаешь взгляд на клавиатуру, и все видно. Единственное, что я поленился сделать, так это, чтобы он лампочкой не мигал, когда я за компьютером.

(defvar jabber-activity-jids-count 0)

(defun jabber-message-blink ()
  (let ((count (length jabber-activity-jids)))
    (unless (= jabber-activity-jids-count count)
      (start-process-shell-command "blink" nil 
				   "blink" (format "-s --rate=%s" count))
      (setq jabber-activity-jids-count count))))

(add-hook 'jabber-activity-update-hook 'jabber-message-blink)

;; don't forget to disable blinking after disconnection
(add-hook 'jabber-post-disconnect-hook 
	  (lambda () 
	    (jabber-autoaway-stop)
            (jabber-keepalive-stop)
	    (start-process-shell-command "blink" nil "blink")))

Лампочка Scroll Lock (можно мигать и другими лампочками, и несколькими лампочками одновременно) мигает столько раз, от скольких человек пришло сообщение. Число сообщений не учитывается (а и не нужно). Как только я прочитываю чьи-то задержанные сообщения (по умолчанию таймаут на просмотр 2 сек. в jabber.el — можно менять), то активность от этого человека снимается. Лампочка продолжает мигать, но меньшее число раз до тех пор, пока я не прочту сообщения всех людей.

Функция повешена на jabber-activity-update-hook, которая вызывается по таймеру из jabber.el, а не при изменении списка пользователей jabber-activity-jids, от которых пришли сообщения (хотя в документации написано, что должна работать именно так — возможно, баг в версии, что в Debian Lenny или фича), поэтому приходится отслеживать изменения самому. Для этого введена переменная jabber-activity-jids-count.

Zubok ★★★★★
()
Ответ на: комментарий от satanic-mechanic

Нифигасебе у вас либастрал...

world
() автор топика
Ответ на: комментарий от Zubok

Не оффтопик, как раз что надо. Идея с лампочкой клавиатуры хороша, но капс и нумлок уже задйствованы а скролл повешени на переключалку раскладок.

world
() автор топика
Ответ на: комментарий от Zubok

Вдогонку. Лампочками можно мигать и через xset, но тогда в консоли работать не будет.

Ну и сейчас понял, что неплохо бы еще добавить выключение лампочки при форсированном выходе из emacs (kill-emacs-hook), а то демон blinkd будет продолжать мигать, и придется вручную blink в терминале писать.

Zubok ★★★★★
()
Ответ на: комментарий от world

>Не оффтопик, как раз что надо. Идея с лампочкой клавиатуры хороша, но капс и нумлок уже задйствованы а скролл повешени на переключалку раскладок.

Я думаю, что какую-нибудь лампочку можно делегировать на мигание, пока ты не за компом, а как только подошел, то она будет работать штатно (отслеживать можно по отсутсвию режима autoaway, например, т. е. ввести дополнительное условие в хук, что я и поленился сделать). Переключалку раскладок трогать, наверное, не стоит, а вот остальные две по ситуации, в зависимости от того, что они делают. Правда, возможна рассинхронизация, так как blink не запоминает состояния лампочки до мигания.

Zubok ★★★★★
()

Кстати, раз уж речь зашла о предупреждениях визуальных, то есть еще xosd. Ну как вариант.

Zubok ★★★★★
()
Ответ на: комментарий от satanic-mechanic

>Сделал и с тех пор забыл: работает исправно. Если можно что-то подкрутить получше, предлагайте.

Насколько я понимаю, то вызов wmctrl как раз и позволит заменить питоновскую программу, если передать туда frame-id. Однако у меня wmctrl из Debian Lenny не вызывает мигание. В man demands_attention отсутствует:

The supported property names (for prop1 and prop2) are modal, sticky, maximized_vert, maximized_horz, shaded, skip_taskbar, skip_pager, hidden, fullscreen, above and below.

Если такая и есть, то, наверное, в более поздних версиях.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

> В man demands_attention отсутствует:

там в коде wmctrl хитрая подстановка идет, типа _NET_WM_STATE_%s, и подставлять можно любые props

ananas ★★★★★
()
Ответ на: комментарий от ananas

>там в коде wmctrl хитрая подстановка идет, типа _NET_WM_STATE_%s, и подставлять можно любые props

Глянул в исходник. Да, действительно, он тупо подставляет строчку из командной строки, но все-равно что-то не работает. Пробую fullscreen, skip_taskbar, below, above и др, работает. Контролирую при помщи xprop в строчке _NET_WM_STATE(ATOM). Эти флаги добавляются нормально, а вот demands_attention не добавляется, и, соответсвенно, окном не сигналит. Надо разбираться.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

>Эти флаги добавляются нормально, а вот demands_attention не добавляется, и, соответсвенно, окном не сигналит. Надо разбираться.

Разобрался, кажется. Это IceWM не реализует demands_attention. Игнорирует просто, в исходниках стоит TODO. Хотя, конечно, странно, потому что pidgin когда-то вполне себе мигал в taskbar кнопкой окна беседы.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Честно пытался заиспользовать wmctrl, убил приличное количество времени, но не вышло. Использую xmonad, gajim нормально мигает, а тут никак. Сначала написал программу на C и дергал ее также, как вы предлагаете wmctrl. Затем вспомнил о pymacs и решил переписать на python, чтобы не запускать новых процессов...

satanic-mechanic
()
Ответ на: комментарий от satanic-mechanic

Да, тут важнее факт использования не xmonad, а dzen, но это принципиально ничего не меняет: не работало и все.

satanic-mechanic
()
Ответ на: комментарий от satanic-mechanic

>Соврал. Сейчас поглядел и вспомнил, пытался использовать xprop.

Дык я вот последние три часа сижу и пытаюсь установить WM_HINTS черерез xprop. У меня уже мозги взорвались. Я уже даже в исходник смотрю. Совершенно не понимаю, как можно установить битовую маску flags в структуре WM_HINTS. И чувствую, что это не просто. Не работает, и все тут.

Уже испробовано:

xprop -id 0x0100007a -f WM_HINTS 32a -set WM_HINTS 256

Формат WM_HINTS из исходника xprop.c: 32mbcxxiixx. Как надо форматировать данные в -set, я вообще не впиливаю. Первое поле 32m -- это как раз flags, туда надо 256 загнать. Примеров в man абсолютно никаких, сеть молчит. Уже перепробовал тут многое. Интересно, кому-нибудь это удавалось?

Zubok ★★★★★
()

О, кажется, нащупал решение без внешних программ! Emacs уже мигает! Осталось с кое-какой непоняткой разобраться. В Emacs, оказывается, есть замечательная функция x-change-window-property. Она позволяет менять свойтва окна. Для мигания нам надо изменить свойство WM_HINTS, а именно поле флагов, восьмой бит (значение 256 или 0x100). структура описана тут:

http://tronche.com/gui/x/xlib/ICC/client-to-window-manager/wm-hints.html

Итак, имеется 9 полей. Нам нужно поменять только певое поле, когда сообщение пришло. И убрать с него активность, когда оно прочитано.

Это должно замигать:

(x-change-window-property "WM_HINTS" '(259 1 1 0 0 0 0 0 0) nil "WM_HINTS" 32 t)

Это должно перестать мигать:

(x-change-window-property "WM_HINTS" '(3 1 1 0 0 0 0 0 0) nil "WM_HINTS" 32 t)

Все поля я аккуратно проверил. Они в точности соответсвуют структуре WM_HINTS. Я включил все флаги (первое поле 127) и пробил тестовые значения в остальные поля, а потом xprop проверил.

Проблема, с которой сейчас не разобрался. Как видно, мне пришлось внаглую поменять остальные поля. Это не криминально, но не есть хорошо. Есть функция x-window-property, которая по идее должна вернуть текущее состояние своства, но она возвращает не то, что показывает xprop. Вот надо бы в исходник emacs залезть и посмотреть, как она работает, а то

(x-window-property "WM_HINTS" nil "WM_HINTS" nil nil t)

возвращает мне вектор [1 1 0 0 0 0 0 0 0], который не согласуется с тем, что есть на самом деле сразу же после старта Emacs. Может, я что-то не то делаю. Вот если получится нормально получить WM_HINTS, то можно будет просто к первому полю добавить 256 и корректно включить мигание, а потом вернуть все назад. Такие дела.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Да-да, это я проходил. Причем убито было не меньше времени. Хотите самое веселое: вы после выполнения своей команды с помощью того же xprop поглядите WM_HINTS. Будет стоять 256. То есть вроде как поменяло.

Вообще я Xlib, да и вообще программирование для X, лишь чуть щупал и давно, поэтому может здесь есть какое-то непонимание фундаментальных вещей. Но как-то это странно.

satanic-mechanic
()
Ответ на: комментарий от Zubok

А вот о x-change-window-property не знал. Спасибо.

Вот только как вы ее нашли? По C-h f она то находится, но вот в документации я ее не видел. Да и гугл по '"x-change-window-property" site:gnu.org' вообще ничего не выдает. Вы просто искали среди функций, начинающихся на "x-"?

satanic-mechanic
()
Ответ на: комментарий от satanic-mechanic

>Вот только как вы ее нашли? По C-h f она то находится, но вот в документации я ее не видел. Да и гугл по '"x-change-window-property" site:gnu.org' вообще ничего не выдает. Вы просто искали среди функций, начинающихся на "x-"?

Если честно, то в свое время копал x-* функции на предмет clipboard, когда хотел решить проблему с 21-м Emacs по части копирования в локали UTF-8, и вот чего-то интуитивно туда потянулся. :)

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

>Есть функция x-window-property, которая по идее должна вернуть текущее состояние своства, но она возвращает не то, что показывает xprop.

Все, решилось. Надо было в параметр SOURCE указать источник, т. е. идентификатор 'outer-window-id.

(x-window-property "WM_HINTS" nil "WM_HINTS" (string-to-number (frame-parameter (selected-frame) 'outer-window-id)) nil t)

возвращает правильный вектор. Теперь просто надо к первому значению прибавить 256 и прописать. когда надо выключить, то вычесть 256.

Теперь только во всех функциях надо прописать желаемый frame вместо указанных nil и (selected-frame)... ну или так оставить -- это по вкусу.

Zubok ★★★★★
()

Вот написал быстренько.

(defun x-wm-hints (frame &optional source)
  (mapcar '(lambda (field) 
	     (if (consp field)
		 (+ (lsh (car field) 16) (cdr field))
	       field))
	  (x-window-property 
	   "WM_HINTS" frame "WM_HINTS" 
	   (if source
	       source
	     (string-to-number (frame-parameter frame 'outer-window-id)))
	   nil t)))

(defun x-urgent-hint (frame arg)
  (let* ((wm-hints (x-wm-hints frame))
	 (flags (car wm-hints)))
    (setcar wm-hints (if arg
			 (logior flags #x00000100)
		       (logand flags #xFFFFFEFF)))
    (x-change-window-property "WM_HINTS" wm-hints frame "WM_HINTS" 32 t)))

Включаем мигание, например, на выбранном frame

(x-urgent-hint (selected-frame) t)

Выключаем (x-urgent-hint (selected-frame) nil)

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

можно было и без этого преобразования обойтись, на самом деле:

(mapcar '(lambda (field)
        (if (consp field)
       (+ (lsh (car field) 16) (cdr field))
          field))

x-change-window-property и такой формат воспринимает:

'(39 1 1 (255 . 132) 0 0 0 (256 . 134) 0)

Только сейчас дошли руки проверить. Так что можно упростить, выбросив mapcar

Zubok ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.