[Message Prev][Message Next][Thread Prev][Thread Next][Message Index][Thread Index]

[MD:5912] Re: visible-bell の X 版振舞いが欲しい



藤井です。

meadow-develop の方に移動しました。
# 引用順が前後しています。

From: Shun-ichi GOTO (後藤俊一) <shunichi.goto@xxxxxxxxx>
Subject: Re: visible-bell の X 版振舞いが欲しい
Date: Sun, 31 Oct 2004 15:35:18 +0900
> なので追加実装する分のはよいことなのではないかと思います。

という意見がありましたので、早速試しに実装してみました。
Meadow 2.20-dev 用にパッチを添付しています。宜しければお試し下さい。

# マクロ名などが異なるので、Meadow 2.00, 2.10-dev には適用不可です。御
# 了承下さい。

> Xt流のフラッシュの実装には賛成です。
> * タイトルバーのフラッシュによる方法(現在の方法)
> * ウィンドウ全体のフラッシュ(Xtの方法)
> * その両方
> が選べるとよいですね。
> 
> mw32fns.c の mw32_WndProc()の case WM_EMACS_FLASH_WINDOW
> にて行っていることがすべてだと思いますので、[MD:630]のないよう相当を
> 追加して、動作選択のための変数mw32-visible-bell-typeとかを新設してやって
> 動作を切り替えればよいでしょう。
>  

変数 mw32-visible-bell-type を追加しました。以下のようにすれば、X 版と
同様の visible-bell になります。

(setq visible-bell t
      ring-bell-function nil
      mw32-visible-bell-type 'x)

なお、mw32-visible-bell-type が x 以外の場合、従来通りの visible-bell 
となります。

パッチとして添付した実装で問題なければ、mixed とか指定すれば両方の表示
を行なう処理を追加しようと考えています。

なお、以下に挙げるように実装について本当にこれで良いのかどうか気になる
点があるので、ご意見いただければと思います。

1. WM_EMACS_FLASH_WINDOW メッセージを利用していません。

# 折角アドバイスを頂いたのにその通りでなくて申し訳ありません。

FrashWindow ではフレーム内部の描画に影響がないので問題にならないのです
が、メッセージスレッドに処理を委譲させると、メッセージスレッドが反転処
理を行なっている間にミニバッファに描画が発生すると、反転が元に戻せなく
なります。

PostMessage 相当を SendMessage 相当に変更するという対応も考えられるの
ですが、これだと sleep するのとそう変わらないような気がするので、そう
していません。

2. Sleep() API を を使用していません。

XTflash()@xterm.c に実装されている select で待つ処理を取り込んで利用し
ています。

他にも、BLOCK_INPUT でのガードでは駄目だとか、関数などの命名規則が 
Meadow 的でないとか、doc-string がイケてないとか、問題があればご指摘下
さい。

以上よろしくお願いします。

--
藤井 正行 / Masayuki FUJII ( boochang@xxxxxxxxxxxx )
Index: src/mw32term.c
===================================================================
--- src/mw32term.c	(revision 3526)
+++ src/mw32term.c	(working copy)
@@ -100,6 +100,10 @@
 
 int mw32_stretch_cursor_p;
 
+/* Type of visible bell. */
+
+Lisp_Object Vmw32_visible_bell_type;
+
 /* This is a chain of structures for all the X displays currently in
    use.  */
 
@@ -4818,6 +4822,167 @@
 
 
 
+/* Subtract the `struct timeval' values X and Y, storing the result in
+   *RESULT.  Return 1 if the difference is negative, otherwise 0.  */
+
+static int
+timeval_subtract (result, x, y)
+     struct timeval *result, x, y;
+{
+  /* Perform the carry for the later subtraction by updating y.  This
+     is safer because on some systems the tv_sec member is unsigned.  */
+  if (x.tv_usec < y.tv_usec)
+    {
+      int nsec = (y.tv_usec - x.tv_usec) / 1000000 + 1;
+      y.tv_usec -= 1000000 * nsec;
+      y.tv_sec += nsec;
+    }
+  
+  if (x.tv_usec - y.tv_usec > 1000000)
+    {
+      int nsec = (y.tv_usec - x.tv_usec) / 1000000;
+      y.tv_usec += 1000000 * nsec;
+      y.tv_sec -= nsec;
+    }
+
+  /* Compute the time remaining to wait.  tv_usec is certainly
+     positive.  */
+  result->tv_sec = x.tv_sec - y.tv_sec;
+  result->tv_usec = x.tv_usec - y.tv_usec;
+
+  /* Return indication of whether the result should be considered
+     negative.  */
+  return x.tv_sec < y.tv_sec;
+}
+
+void
+mw32_flash (struct frame *f)
+{
+  BLOCK_INPUT;
+
+  {
+    PIX_TYPE pixel = f->output_data.mw32->foreground_pixel ^
+		     f->output_data.mw32->background_pixel;
+    HDC hdc = GetDC (FRAME_MW32_WINDOW (f));
+    HBRUSH hbrush = CreateSolidBrush (pixel);
+    HBRUSH old_brush = SelectObject (hdc, hbrush);
+
+    /* Get the height not including a menu bar widget.  */
+    int height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, FRAME_LINES (f));
+    /* Height of each line to flash.  */
+    int flash_height = FRAME_LINE_HEIGHT (f);
+    /* These will be the left and right margins of the rectangles.  */
+    int flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
+    int flash_right = FRAME_PIXEL_WIDTH (f) - FRAME_INTERNAL_BORDER_WIDTH (f);    
+    int width;
+    
+    /* Don't flash the area between a scroll bar and the frame
+       edge it is next to.  */
+    switch (FRAME_VERTICAL_SCROLL_BAR_TYPE (f))
+      {
+      case vertical_scroll_bar_left:
+	flash_left += VERTICAL_SCROLL_BAR_WIDTH_TRIM;
+	break;
+	
+      case vertical_scroll_bar_right:
+	flash_right -= VERTICAL_SCROLL_BAR_WIDTH_TRIM;
+	break;
+	
+      default:
+	break;
+      }
+    
+    width = flash_right - flash_left;
+    
+    /* If window is tall, flash top and bottom line.  */
+    if (height > 3 * FRAME_LINE_HEIGHT (f))
+      {
+	int x = flash_left;
+	int y = FRAME_INTERNAL_BORDER_WIDTH (f)
+		+ FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
+
+	BitBlt (hdc, x, y, width, flash_height, hdc, x, y, PATINVERT);
+
+	y = height - flash_height - FRAME_INTERNAL_BORDER_WIDTH (f);
+
+	BitBlt (hdc, x, y, width, flash_height, hdc, x, y, PATINVERT);
+      }
+    else
+      {
+	/* If it is short, flash it all.  */ 
+	int x = flash_left;
+	int y = FRAME_INTERNAL_BORDER_WIDTH (f);
+	int reverse_height = height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
+
+	BitBlt (hdc, x, y, width, reverse_height, hdc, x, y, PATINVERT);
+      }
+
+    GdiFlush ();
+    
+    {
+      struct timeval wakeup;
+      
+      EMACS_GET_TIME (wakeup);
+      
+      /* Compute time to wait until, propagating carry from usecs.  */
+      wakeup.tv_usec += 150000;
+      wakeup.tv_sec += (wakeup.tv_usec / 1000000);
+      wakeup.tv_usec %= 1000000;
+      
+      /* Keep waiting until past the time wakeup or any input gets
+	 available.  */
+      while (! detect_input_pending ())
+	{
+	  struct timeval current;
+	  struct timeval timeout;
+	  
+	  EMACS_GET_TIME (current);
+	  
+	  /* Break if result would be negative.  */
+	  if (timeval_subtract (&current, wakeup, current))
+	    break;
+	  
+	  /* How long `select' should wait.  */
+	  timeout.tv_sec = 0;
+	  timeout.tv_usec = 10000;
+	  
+	  /* Try to wait that long--but we might wake up sooner.  */
+	  select (0, NULL, NULL, NULL, &timeout);
+	}
+    }
+    
+    /* If window is tall, flash top and bottom line.  */
+    if (height > 3 * FRAME_LINE_HEIGHT (f))
+      {
+	int x = flash_left;
+	int y = FRAME_INTERNAL_BORDER_WIDTH (f)
+		+ FRAME_TOOL_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
+
+	BitBlt (hdc, x, y, width, flash_height, hdc, x, y, PATINVERT);
+
+	y = height - flash_height - FRAME_INTERNAL_BORDER_WIDTH (f);
+
+	BitBlt (hdc, x, y, width, flash_height, hdc, x, y, PATINVERT);
+      }
+    else
+      {
+	/* If it is short, flash it all.  */ 
+	int x = flash_left;
+	int y = FRAME_INTERNAL_BORDER_WIDTH (f);
+	int reverse_height = height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
+
+	BitBlt (hdc, x, y, width, reverse_height, hdc, x, y, PATINVERT);
+      }
+    
+    GdiFlush ();
+    SelectObject (hdc, old_brush);
+    DeleteObject (hbrush);
+    ReleaseDC (FRAME_MW32_WINDOW (f), hdc);
+  }
+
+  UNBLOCK_INPUT;
+}
+
 /* Make audible bell.  */
 
 void
@@ -4828,8 +4993,11 @@
   if (visible_bell)
     {
       struct frame *f = SELECTED_FRAME ();
-      POST_INFORM_MESSAGE (FRAME_MW32_WINDOW (f),
-			   WM_EMACS_FLASH_WINDOW, 0, 0);
+      if (EQ (Vmw32_visible_bell_type, intern ("x")))
+	mw32_flash (f);
+      else
+	POST_INFORM_MESSAGE (FRAME_MW32_WINDOW (f),
+			     WM_EMACS_FLASH_WINDOW, 0, 0);
     }
   else
     w32_sys_ring_bell ();
@@ -10306,6 +10474,10 @@
 wide as that tab on the display.  */);
   mw32_stretch_cursor_p = 0;
 
+  DEFVAR_LISP ("mw32-visible-bell-type", &Vmw32_visible_bell_type,
+	       doc: /* Type of visible bell.
+The value is a symbol, `x' for X window style. Otherwise MS Windows style. */);
+  Vmw32_visible_bell_type = Qnil;
 
   DEFVAR_INT ("w32-lbutton-to-emacs-button", &mw32_lbutton_to_emacs_button,
 	      doc: /* Position of a mouse button sent to emacs, when the w32 left button