X tips

last update: 14 Jun 2005

home

指定した画面を最上位に配置するには


XWindowシステム: XRaiseWindow()とATOMの使い方



1.1 はじめに
XWindowでシステムを組むと、 特定のアプリケーションをキー操作一発で画面最上位に配置したいときがあります。
例えば、組み込みシステムでXWindowを使う場合、 液晶画面が小さく、マルチウインドウ方式ではユーザが混乱するばかりなので、 一画面に1アプリケーションを全面表示させることが多いわけです。 しかし、管理画面やヘルプ画面などはキー操作一発で最上位に瞬時に配置したい、 このような要求がたまに発生します。

システムによって解決方法は変わるので、一概にどれがいいとは言えませんが、 今回の要求は:

だったので、 ATOMを使ったXウインドウIDの受渡しと、XRaiseWindow()を実行するプログラム"popup"による方式を選択しました。

ATOMを使った理由はXアプリケーション間の通信としてはそれが最も簡単だったこと、 また独立したプログラムpopupとしたのはポータビリティの確保のためです(ウインドウマネージャに組み込むことも可能だが、ポータビリティが失われる)。

Remark: さらにいえば、このような機能を有するウインドウマネージャが存在するかもしれないが、少くとも組み込み用途で使える軽量ウインドウマネージャには、この機能を有するものが見当たらなかった。

たぶん、ここに書かれた情報が必要な人間は世界中で10人もいないと思いますが、 私個人の備忘録として、ここに記述しておきます。

1.2 画面の配置を変更する: popup.c
popup.cは、指定された画面をXWindowの最上位に配置するプログラムです。 引数で渡された"画面名 = ATOM名"の画面を、 関数 XRaiseWindow()で最上位に配置します。

このプログラムのポイントは、 ATOMで画面IDを得る部分と、 関数XRaiseWindow()実行後、dummy loopとsignalの合わせ技でプログラム終了までに1秒の猶予を得る部分です。
後者について追記すると、 もしも1秒程度の猶予なく即座にプログラムを終了させた場合、画面が最上位に配置されません。 また、1秒の猶予を得るためにsleep()は使えません。あくまでプログラムがactiveな状態のまま1秒程度の 猶予が必要なのです。

/*
 ** Usage: popup ATOM_NAME
 */

#include <unistd.h>
#include <signal.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>

static void
sig_alrm (int signo)
{
  exit (0);
}

int
main (int argc, char **argv)
{
  Display *d;
  Window *w;
  Atom a, type;
  XEvent e;
  int fmt;
  unsigned long nitems, left;

  if (argc != 2)
    exit (-1);

  /* 1秒後、dummy loop中でsig_alrm()起動 */
  if (signal (SIGALRM, sig_alrm) != SIG_ERR)
    alarm(1);

  /*
   ** 処理の本体
   */
  d = XOpenDisplay (NULL);
  a = XInternAtom (d, argv[1], False);
  if (XGetWindowProperty (d, RootWindow (d, 0), a, 0, 4, False,
                          XA_WINDOW, &type, &fmt, &nitems, 
                          &left, (unsigned char **)&w) == Success && type == XA_WINDOW)
  {
    /* 画面を最上位に配置 */
    XRaiseWindow (d, *w);
  }

  /*
   **  dummy loop: signalで設定したアラーム待ち -> 終了
   */
  while (1)
    XNextEvent (d, &e);

  return 0;
}

popup.c


コンパイルは次のようにします。

    % gcc -Wall -o popup popup.c -L/usr/X11R6/lib -lX11

コンパイルが終了したら、適当なディレクトリに移動しておきます。 今回は/usr/sbinに移動します。

    % mv popup /usr/sbin

1.3 アプリケーション側の設定

    1.3.1 Xアプリケーション

    最上位に配置したい画面に対して行う処理を示します。 これは、ごく普通のATOMの設定手順です。
    画面に対して、適当な一意の名前(ここでは"POPUP_X")を設定してください。
    #include <X11/Xlib.h>
    #include <X11/Xutil.h>
    #include <X11/Xatom.h>
    
    ... 略 ...
    
    int
    main (int argc, char **argv)
    {
      Display *d;
      GC gc;
      Window w;
      Atom a;
      XEvent e;
      int x, y;
    
      d = XOpenDisplay (NULL);
      w = XCreateSimpleWindow (d, RootWindow (d, 0), 400, 400, 
                               200, 200, 2, 0, 1);
      XMapWindow (d, w);
      gc = XCreateGC (d, w, 0, 0);
    
      /*
       ** ATOM"POPUP_X"の設定
       */
    
      /* ATOMの生成 */
      a = XInternAtom (d, "POPUP_X", False);
      /* 念のため、プロパティを変更。以前に設定された同名のATOMがある場合への対処。*/
      XChangeProperty (d, RootWindow (d, 0), a, XA_WINDOW, 32,
                       PropModeReplace, (unsigned char *)&w, 1);
    
    
      ... 略 ...
    
    
    }
    

    Xアプリケーションの一部


    1.3.2 Gtkアプリケーション

    GTKアプリケーションの場合を示します。
    #include <X11/Xlib.h>
    #include <X11/Xutil.h>
    #include <X11/Xatom.h>
    
    #include <gdk/gdkx.h>
    
    /*
     ** ATOMの設定
     */
    static void
    atom_set (GtkWidget *window, const char *name)
    {
      GdkDisplay *d;
      Window xwindow;
      Atom a;
    
      d = gdk_drawable_get_display (window->window);
      xwindow = GDK_WINDOW_XID (window->window);
      a = XInternAtom (GDK_DISPLAY_XDISPLAY (d), name, False);
      XChangeProperty (GDK_DISPLAY_XDISPLAY (d), 
                       RootWindow (GDK_DISPLAY_XDISPLAY (d), 0), 
                       a, XA_WINDOW, 32,
                       PropModeReplace, (unsigned char *)&xwindow, 1);
    }
    
    
    int 
    main (int argc, char *argv[]) 
    {
    
    
    ... 略 ...
    
      window1 = create_window1 ();
      gtk_widget_show (window1);
      window2 = create_window2 ();
      gtk_widget_show (window2);
    
      /*
       ** ATOMの設定
       */
      atom_set (window1, "POPUP_GTK");
      atom_set (window2, "POPUP_GTK2");
    
      gtk_main ();
      return 0;
    
    }
    

    Gtkアプリケーションの一部


1.4 実行方法

    1.4.1 直接popupコマンドを実行

    下図において、Xターミナルrxvtに隠れているXアプリケーションを、 最上位に配置してみます。

    このXアプリケーションには"POPUP_X"というATOM名が付けられています。よって、次のコマンドを実行すると、Xアプリケーションが最上位に配置されます。

      % /usr/sbin/popup POPUP_X


    Remark: popupコマンドは、ウインドウマネージャmwmとGNOMEでは実行可能でしたが、 ウインドウマネージャxfceでは機能しませんでした。原因は不明です。

    1.4.2 ウインドウマネージャから実行

    ウインドウマネージャのなかには、コマンド起動を任意のキーにバインドできるものがあります。
    ここでは軽量ウインドウマネージャmwmでの設定方法を示します。

    mwmの設定ファイルは~/.mwmrc(もしくは/usr/X11R6/lib/mwm/system.mwmrc)です。 このファイルの"Keys DefaultKeyBindings"セクションに、キーバインドとpopupコマンドの実行文を記述すると、 キー操作一発で、指定した画面を最上位に配置させることが可能です。

    この例では、F4キーを押すと"/usr/sbin/popup POPUP_X &"が、 F5キーを押すと"/usr/sbin/popup POPUP_GTK &"が、 Alt+Shift+Deleteキーを押すと"/usr/sbin/popup POPUP_GTK2 &"が、 それぞれ実行されます。

    ここで注意すべき点は、/usr/sbin/popupをバックグランドで実行しなければならないことです。

    Keys DefaultKeyBindings
    {
    
     ... 略 ...
    
        <Key>F4                 root|icon|window        f.exec "/usr/sbin/popup POPUP_X &"
        <Key>F5                 root|icon|window        f.exec "/usr/sbin/popup POPUP_GTK &"
        Alt Shift<Key>Delete    root|icon|window        f.exec "/usr/sbin/popup POPUP_GTK2 &"
    }
    
    

    .mwmrcファイルの一部



home


since 04/Oct/2004