パレットメッセージ
パレットの優先権
アプリケーションがパレットを用いる場合
Windows 環境では他のアプリケーションのことを考えなければなりません
あなたのアプリケーションがパレットを独占するのは自由です
しかし、そうなればなるほど他のアプリケーションがフォーカスを得ている時
あなたのアプリケーションの色は見るに耐えないものになってしまうかもしれないのです
アプリケーションがパレットを使用し、本来ならば赤であるエントリが
他のアプリケーションによって緑色にリアライズされているかもしれないのです
この図は、前回のグレーシェードの配列パレットのプログラムが
他のアプリケーションにフォーカスが渡された時の状態です
ご覧の通り、パレットは他の色にリアライズされてひどい有り様になっています
この場合、お互いに「フォーカスを得たので、パレットを使いますよ」と
他のアプリケーションに通知したほうが、親切であると考えられます
実世界も Windows の世界も、「公共の福祉」は重要な課題なのです
ウィンドウがアクティブになった時、再びパレットをリアライズすれば
例え他のウィンドウによってパレットのエントリが変更されていても
自分のアプリケーションがユーザーに使われる時は正しい色を保証できます
これには WM_QUERYNEWPALETTE メッセージを処理します
このメッセージは、ウィンドウがアクティブになる直前に発生します
パラメータは両方とも 0 で、リアライズした場合は TRUE、そうでなければ FALSE を返します
Windows は TRUE が返された場合、他のアプリケーションにそれを通知します
他のアプリケーションは WM_PALETTECHANGED を受け取ります
このメッセージは、アクティブウィンドウから下位のウィンドウまで順に発生します
これを受けとった場合、他のウィンドウがパレットをリアライズしたと理解できます
WPARAM には、システムパレットを変更したウィンドウのハンドルが格納されます
LPARAM は使わないので常に 0 で、戻り値はありません
WM_PALETTECHANGED は WM_QUERYNEWPALETTE の後に送られてきます
つまり、アクティブウィンドウがパレットをリアライズした後です
WM_PALETTECHANGED でパレットをリアライズすれば
Windows は空いている残りのエントリを駆使して、パレットをリアライズしてくれます
これによって、フォーカスを失っても最低限の色を確保することができるかもしれないのです
#include <windows.h>
void PaletteChange(HWND , HPALETTE);
LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
HDC hdc;
PAINTSTRUCT ps;
HBRUSH hBrush;
LOGPALETTE *lpPalette;
int count , x = 20 , y = 10;
static HPALETTE hPalette;
switch (msg) {
case WM_DESTROY:
DeleteObject(hPalette);
PostQuitMessage(0);
return 0;
case WM_CREATE:
lpPalette = malloc(sizeof (LOGPALETTE) + 64 * sizeof (PALETTEENTRY));
lpPalette->palVersion = 0x0300;
lpPalette->palNumEntries = 65;
for (count = 0 ; count < 65 ; count++) {
lpPalette->palPalEntry[count].peRed =
lpPalette->palPalEntry[count].peGreen =
lpPalette->palPalEntry[count].peBlue = (BYTE) 4 * count;
lpPalette->palPalEntry[count].peFlags = NULL;
}
lpPalette->palPalEntry[64].peRed =
lpPalette->palPalEntry[64].peGreen =
lpPalette->palPalEntry[64].peBlue = 255;
hPalette = CreatePalette(lpPalette);
free(lpPalette);
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd , &ps);
SelectPalette(hdc , hPalette , FALSE);
RealizePalette(hdc);
for (count = 0 ; count < 65 ; count++ , x += 20) {
hBrush = CreateSolidBrush(PALETTEINDEX(count));
SelectObject(hdc , hBrush);
Rectangle(hdc , x , y , x + 10 , y + 40);
if (x > 400) { y += 60; x = 0; }
SelectObject(hdc , GetStockObject(WHITE_BRUSH));
DeleteObject(hBrush);
}
EndPaint(hWnd ,&ps);
return 0;
case WM_QUERYNEWPALETTE:
if (!hPalette) return FALSE;
PaletteChange(hWnd , hPalette);
return TRUE;
case WM_PALETTECHANGED:
if (!hPalette || (HWND)wp == hWnd) return 0;
PaletteChange(hWnd , hPalette);
return 0;
}
return DefWindowProc(hWnd , msg , wp , lp);
}
void PaletteChange(HWND hWnd , HPALETTE hPalette) {
HDC hdc;
hdc = GetDC(hWnd);
SelectPalette(hdc , hPalette , FALSE);
RealizePalette(hdc);
InvalidateRect(hWnd , NULL , TRUE);
ReleaseDC(hWnd , hdc);
}
int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
PSTR lpCmdLine , int nCmdShow) {
HWND hWnd;
MSG msg;
WNDCLASS winc;
winc.style = CS_HREDRAW | CS_VREDRAW;
winc.lpfnWndProc = WndProc;
winc.cbClsExtra = winc.cbWndExtra = 0;
winc.hInstance = hInstance;
winc.hIcon = LoadIcon(NULL , IDI_APPLICATION);
winc.hCursor = LoadCursor(NULL , IDC_ARROW);
winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
winc.lpszMenuName = NULL;
winc.lpszClassName = TEXT("KITTY");
if (!RegisterClass(&winc)) return 1;
hWnd = CreateWindow(
TEXT("KITTY") , TEXT("Kitty on your lap") ,
WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
CW_USEDEFAULT , CW_USEDEFAULT ,
CW_USEDEFAULT , CW_USEDEFAULT ,
NULL , NULL , hInstance , NULL
);
if (hWnd == NULL) return 1;
while (GetMessage(&msg , NULL , 0 , 0 )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
このプログラムは、パレットメッセージを処理することで
アクティブになった時や、他のウィンドウがシステムパレットを変更した時
自分のウィンドウを最適に保てるようにリアライズしています
これによって、以前のように他のウィンドウにフォーカスが移った時
色がめちゃくちゃになるようなことはなくなります