XNextEvent

ウィンドウのイベントはXNextEventで取得する。

Manpage of XNextEvent
Xlib イベント
X Window System(X11)のプログラムを正常に終了させる方法 - Qiita

Windowsのウィンドウメッセージと違うのは、取得したいイベントのマスクを事前にXSelectInputでセットしておかなければならない点。
これがないと、イベントループの中でXNextEventで、イベントを取得できない。
今回はウィンドウ上でマウスが押されたイベントを拾って、押された位置をprintfで出力。
10回押されたらプログラムを終了する。

最初はこの状態
最初はこの状態

最初はこの状態だが、クリックすると、

printfで位置が出てる
printfで位置が出てる

ターミナル側に位置が出てる。

連打しても出る
連打しても出る

連打しても出るし、

マウスを移動して押しても出る
マウスを移動して押しても出る

マウスを移動して押しても位置が変わって出る。

10回やったら終わる
10回やったら終わる

で10回やったら終わる。

Sample/xlib/XNextEvent/XNextEvent/src/XNextEvent at master · bg1bgst333/Sample · GitHub

XCloseDisplay

これまでXOpenDisplayでXサーバと接続してたけど、結構クローズしてないサンプルが多くて、

X11プログラミング
Xlib 編 (1)

これいいのかなあとおもってたけど、一応XCloseDisplayでクローズ(Xサーバとの接続を終了(切断))する。

Manpage of XOpenDisplay

一応XCloseDisplayしてる。

変わらない
変わらない

変わらない。

Sample/xlib/XCloseDisplay/XCloseDisplay/src/XCloseDisplay at master · bg1bgst333/Sample · GitHub

DefaultRootWindow

これまで、RootWindow(d, 0)という感じで、0番スクリーンを指定してきたが、デフォルトスクリーンが0番なら、DefaultRootWindowでデフォルトスクリーンのルートウィンドウが取れるので、0を指定しなくてもいい。たいてい、デフォルトスクリーンは0。(前回のように例外はあるけど。)

X11
Manpage of AllPlanes

RootWindow(d, 0)をDefaultRootWindow(d)に置き換えても、

表示される
表示される

表示される。

Sample/xlib/DefaultRootWindow/DefaultRootWindow/src/DefaultRootWindow at master · bg1bgst333/Sample · GitHub

RootWindow

Windowsで言うところのトップレベルウィンドウ(一番親のウィンドウ)を作る時は、XCreateSimpleWindowなどに、ルートウィンドウのWindow(実態はXID==unsigned long)を渡す。
で、RootWindowマクロで指定のディスプレイの指定のスクリーンのWindowが返る。

X11
Manpage of AllPlanes

基本的には、ディスプレイ0のスクリーン0がデフォルトルートウィンドウなので、それ以外を指定することはあまりないが、今回は0以外を指定するパターンをやってみる。

普通は、xdpyinfoコマンドで

$ xdpyinfo
name of display:    :0
version number:    11.0
vendor string:    Fedora Project
.
.
.
(中略)
.
.
.
default screen number:    0
number of screens:    1

screen #0:
  dimensions:    1280x960 pixels (0x0 millimeters)
.
.
.
(中略)
.
.
.

ディスプレイ名は":0"、デフォルトスクリーン番号は0、スクリーンの数は1。
マルチモニタならディスプレイ名や数は変わるかもしれないが、シングルならこうなる。

この状態で、

/* ヘッダファイルのインクルード */
#include <stdio.h> /* C標準入出力 */
#include <unistd.h> /* UNIX標準 */
#include <X11/Xlib.h> /* Xlib */

/* main関数 */
int main(void){

  /* 変数の宣言 */
  Display *d; /* Display構造体へのポインタd. */
  Window wr; /* ウィンドウ生成の結果を表す値wr.(Window == XID == unsigned long) */
  int result; /* マップの結果result. */
  unsigned long white; /* 白のRGB値white. */
  unsigned long black; /* 黒のRGB値black. */

  /* Xサーバとの接続. */
  d = XOpenDisplay(NULL); /* XOpenDisplayでXサーバに接続し, 戻り値のアドレスをdに格納. */

  /* dを出力. */
  printf("d = %08x\n", d); /* dの値を16進数で出力. */

  /* 白のRGB値を取得. */
  white = XWhitePixel(d, 1); /* XWhitePixelでスクリーン1における白のRGB値を取得し, whiteに格納. */

  /* 黒のRGB値を取得. */
  black = XBlackPixel(d, 1); /* XBlackPixelでスクリーン1における黒のRGB値を取得し, blackに格納. */

  /* ウィンドウの生成. */
  wr = XCreateSimpleWindow(d, RootWindow(d, 1), 100, 100, 640, 480, 1,
white, white); /* XCreateSimpleWindowでウィンドウ生成し,
結果はwrに格納.(RootWindowでスクリーン1を指定.) */

  /* ウィンドウ生成の結果を出力. */
  printf("wr = %08x\n", wr); /* wrを出力. */

  /* ウィンドウのマッピング(表示要求) */
  result = XMapWindow(d, wr); /* XMapWindowでマッピング. */

  /* マッピング結果を出力. */
  printf("result = %d\n", result); /* resultの値を出力. */

  /* 表示要求イベントをフラッシュ. */
  XFlush(d); /* XFlushでフラッシュ. */

  /* 10秒待つ. */
  printf("sleep 10 seconds...\n"); /* "sleep 10 seconds..."と出力. */
  sleep(10); /* sleepで10秒休止. */

  /* プログラムの終了 */
  return 0; /* 0を返して正常終了. */

}

ディスプレイはNULLなので":0"を指してて、RootWindowやXWhitePixelなどに存在しないスクリーン番号1を指定して、ウィンドウ表示のプログラムを実行しても、

表示されない
表示されない

表示されない。

X Window System, Programming, No.1
@IT:X Window Systemの情報を表示するには

基本的にスクリーンは1つで、意図的に増やす方法が見つからないが、

Xvfb を使って仮想ディスプレイを作る - CUBE SUGAR CONTAINER

Xvfbを使って、仮想ディスプレイを作れるらしいので、これを使ってみる。

$ sudo yum install xorg-x11-server-Xvfb
[sudo] bg1 のパスワード:
メタデータの期限切れの最終確認: xx:xx:xx 時間前の xxxx年xx月xx日 xx時xx分xx秒 に実施しました。
パッケージ xorg-x11-server-Xvfb-1.20.4-1.fc29.x86_64 は既にインストールされています。
依存関係が解決しました。
行うべきことはありません。
完了しました!
$

すでに入ってた。

$ Xvfb :1 -screen 1 1280x960x24
The XKEYBOARD keymap compiler (xkbcomp) reports:
> Warning:          Unsupported high keycode 372 for name <I372> ignored
>                   X11 cannot support keycodes above 255.
>                   This warning only shows for the first high keycode.
Errors from xkbcomp are not fatal to the X server

ディスプレイ名1のスクリーン番号1で起動する。
別のターミナルを開いて、

$ export DISPLAY=:1
$

をしてから、xdpyinfoすると、

$ xdpyinfo
name of display:    :1
.
.
.
(中略)
.
.
.
default screen number:    0
number of screens:    2

ディスプレイは1、ただしデフォルトスクリーン番号が0。
この状態でこの後の作業をやったら、うまくいかなかったので、
いろいろさらに別のディスプレイ名で仮想ディスプレイを作ってみたりすると、

$ xdpyinfo
.
.
.
(中略)
.
.
.
default screen number:    1
number of screens:    2

このような状態になる時がある。
これならデフォルトスクリーン番号も0じゃないので、この後の作業でスクリーン1のウィンドウ表示が見れる。
で、このスクリーン1は直接見ることはできないので、スクリーンショットを撮るしかない。
xwdをインストール。

$ sudo yum install xwd netpbm-progs
[sudo] bg1 のパスワード:
メタデータの期限切れの最終確認: xx:xx:xx 時間前の xxxx年xx月xx日 xx時xx分xx秒 に実施しました。
依存関係が解決しました。
================================================================================
 パッケージ               アーキテクチャー
                                      バージョン             リポジトリ   サイズ
================================================================================
インストール:
 netpbm-progs             x86_64      10.84.03-3.fc29        updates      1.9 M
 xorg-x11-apps            x86_64      7.7-22.fc29            fedora       328 k
アップグレード:
 netpbm                   x86_64      10.84.03-3.fc29        updates      173 k
依存関係をインストール中:
 xorg-x11-fonts-misc      noarch      7.5-20.fc29            fedora       5.8 M
 xorg-x11-xbitmaps        noarch      1.1.1-15.fc29          fedora        38 k

トランザクションの概要
================================================================================
インストール    4 パッケージ
アップグレード  1 パッケージ

ダウンロードサイズの合計: 8.2 M
これでよろしいですか? [y/N]: y
パッケージのダウンロード中です:
(1/5): xorg-x11-apps-7.7-22.fc29.x86_64.rpm     160 kB/s | 328 kB     00:02
(2/5): xorg-x11-xbitmaps-1.1.1-15.fc29.noarch.r  43 kB/s |  38 kB     00:00
(3/5): netpbm-10.84.03-3.fc29.x86_64.rpm        169 kB/s | 173 kB     00:01
(4/5): netpbm-progs-10.84.03-3.fc29.x86_64.rpm  487 kB/s | 1.9 MB     00:04
(5/5): xorg-x11-fonts-misc-7.5-20.fc29.noarch.r 1.0 MB/s | 5.8 MB     00:05
--------------------------------------------------------------------------------
合計                                            924 kB/s | 8.2 MB     00:09
トランザクションの確認を実行中
トランザクションの確認に成功しました。
トランザクションのテストを実行中
トランザクションのテストに成功しました。
トランザクションを実行中
  準備             :                                                        1/1
Upgrade: netpbm-10.84.03-3.fc29.x86_64
  アップグレード中 : netpbm-10.84.03-3.fc29.x86_64                          1/6
Upgrade: netpbm-10.84.03-3.fc29.x86_64
Installed: xorg-x11-xbitmaps-1.1.1-15.fc29.noarch
  インストール中   : xorg-x11-xbitmaps-1.1.1-15.fc29.noarch                 2/6
Installed: xorg-x11-xbitmaps-1.1.1-15.fc29.noarch
Installed: xorg-x11-fonts-misc-7.5-20.fc29.noarch
  インストール中   : xorg-x11-fonts-misc-7.5-20.fc29.noarch                 3/6
  scriptletの実行中: xorg-x11-fonts-misc-7.5-20.fc29.noarch                 3/6
Installed: xorg-x11-fonts-misc-7.5-20.fc29.noarch
Installed: xorg-x11-apps-7.7-22.fc29.x86_64
  インストール中   : xorg-x11-apps-7.7-22.fc29.x86_64                       4/6
Installed: xorg-x11-apps-7.7-22.fc29.x86_64
Installed: netpbm-progs-10.84.03-3.fc29.x86_64
  インストール中   : netpbm-progs-10.84.03-3.fc29.x86_64                    5/6
Installed: netpbm-progs-10.84.03-3.fc29.x86_64
Upgraded: netpbm-10.84.03-1.fc29.x86_64
  整理             : netpbm-10.84.03-1.fc29.x86_64                          6/6
Upgraded: netpbm-10.84.03-1.fc29.x86_64
  scriptletの実行中: netpbm-10.84.03-1.fc29.x86_64                          6/6
  検証             : netpbm-progs-10.84.03-3.fc29.x86_64                    1/6
  検証             : xorg-x11-apps-7.7-22.fc29.x86_64                       2/6
  検証             : xorg-x11-fonts-misc-7.5-20.fc29.noarch                 3/6
  検証             : xorg-x11-xbitmaps-1.1.1-15.fc29.noarch                 4/6
  検証             : netpbm-10.84.03-3.fc29.x86_64                          5/6
  検証             : netpbm-10.84.03-1.fc29.x86_64                          6/6

アップグレード済み:
  netpbm-10.84.03-3.fc29.x86_64

インストール済み:
  netpbm-progs-10.84.03-3.fc29.x86_64    xorg-x11-apps-7.7-22.fc29.x86_64
  xorg-x11-fonts-misc-7.5-20.fc29.noarch xorg-x11-xbitmaps-1.1.1-15.fc29.noarch

完了しました!
$

で、改めてだけれども、
さっきからずっとXvfbは実行状態のままで、別ターミナルで、

$ export DISPLAY=:1

となっていて、いちおうxdpyinfoを確認すると、

$ xdpyinfo
.
.
.
(中略)
.
.
.
default screen number:    1
number of screens:    2

この状態で、

これを実行する。
XOpenDisplayのディスプレイ名は、xdpyinfoに合わせたものになるので、":1"とは限らない。xdpyinfoのものを使う。
あと、ポイントは、XWhitePixelとかXBlackPixelは、ちゃんと白や黒が出るかわからないので、今回は使わない。0xffffffで、白を指定。
で白じゃないと、スクリーンショットが真っ黒でウィンドウがあるかわからないので、白にしている。
そして、RootWindowでは、dとデフォルトスクリーン番号1をセット。
0じゃない場合という要件を満たしている。
あと、作業に時間がかかるので、sleepを60秒にしてる。

ここには表示されない
ここには表示されない

これで実行してもここには表示されないが、さらに別ターミナルを開いて、"export DISPLAY=:1"とxdpyinfoによる確認をしてから、

$ xwd -display :1 -root | xwdtopnm | pnmtopng > screenshot.png

これでスクリーンショットを撮ると、

スクリーン1のウィンドウ
スクリーン1のウィンドウ

ディスプレイ1のスクリーン1に白いウィンドウがあることがわかる。

Sample/xlib/RootWindow/RootWindow/src/RootWindow at master · bg1bgst333/Sample · GitHub

XBlackPixel

XBlackPixelで、指定のディスプレイとスクリーンにおける、黒のRGB値を取得できる。

X11
Manpage of AllPlanes

第8引数のborderをwhiteに、第9引数のbackgroundをblackにする。

背景は黒だがボーダーの白が出ない。
背景は黒だがボーダーの白が出ない。

背景は黒になったが、ボーダーの白が出ない。
何故だろう・・・。

Sample/xlib/XBlackPixel/XBlackPixel/src/XBlackPixel at master · bg1bgst333/Sample · GitHub

XWhitePixel

XWhitePixelで、指定のディスプレイとスクリーンにおける、白のRGB値を取得できる。

X11
Manpage of AllPlanes
(WhitePixelしかないが、効果は同じ。)

これでウィンドウを白にする。

XCreateSimpleWindowの第8、第9引数をXWhitePixelで取得したwhiteにすると、

白いウィンドウ
白いウィンドウ

白いウィンドウとなる。

Sample/xlib/XWhitePixel/XWhitePixel/src/XWhitePixel at master · bg1bgst333/Sample · GitHub

XFlush

XFlushは、イベントキューの出力バッファをフラッシュする。

Manpage of XFlush

ウィンドウの表示要求は、イベントキューに貯められる。
このままでは処理されないので、フラッシュすることで、ウィンドウが表示される。

XFlushの後に、sleepで10秒待つ。
その間は、ウィンドウが表示され、10秒経つと、ウィンドウが消え、プログラムが終了する。

10秒間ウィンドウが表示される
10秒間ウィンドウが表示される

10秒間ウィンドウが表示され、

終了
終了

終了。

恒久的にウィンドウを表示して、閉じるなどのイベントで終了するといったパターンは、まだ先の話である。

Sample/xlib/XFlush/XFlush/src/XFlush at master · bg1bgst333/Sample · GitHub