MINT OS에서 이벤트 큐는 윈도우와 윈도우 매니저 간의 정보를 전달하는 통로 이다.
마우스 이벤트 자료구조의 코드
typedef struct kMouseEventStruct
{
// 윈도우 ID
QWORD qwWindowID;
// 마우스 X, Y 좌표와 버튼의 상태
POINT stPoint;
BYTE bButtonSTatus;
} MOUSEEVENT;
키 이벤트 자료구조의 코드
typedef struct kKeyEventStruct
{
// 윈도우 ID
QWORD qwWindowID;
// 키의 ASCII 코드와 스캔 코드
BYTE bASCIICode;
BYTE bScanCode;
// 키 플래그
BYTE bFlags;
} KEYEVENT;
윈도우 이벤트 자료구조의 코드
typedef struct kWindowEventStruct
{
// 윈도우 ID
QWORD qwWindowID;
// 영역 정보
RECT stArea;
} WINDOWEVENT;
이벤트 자료구조의 코드
typedef struct kEventStruct
{
// 이벤트 타입
QWROD qwType;
// 이벤트 데이터 영역을 정의한 공용체
union
{
// 마우스 이벤트 관련 데이터
MOUSEEVENT stMouseEvent;
// 키 이벤트 관련 데이터
KEYEVENT stKeyEvent;
// 윈도우 이벤트 관련 데이터
WINDOWEVENT stWindowEvent;
// 위의 이벤트 외어ㅔ 유저 이벤트를 위한 데이터
QWROD vqwData[ 3 ];
};
} EVENT;
이벤트 큐가 추가된 윈도우 자료구조와 윈도우 매니저 자료구조의 코드
// 윈도우의 정보를 저장하는 자료구조
typedef struct kWindowStruct
{
// 다음 데이터의 위치와 현재 윈도우의 ID
LISTLINK stLink;
// 자료구조 동기화를 위한 뮤텍스
MUTEX stLock;
// 윈도우 영역 정보
RECT stArea;
// 윈도우의 화면 버퍼 어드레스
COLOR* pstWindowBuffer;
// 윈도우를 가지고 있는 태스크의 ID
QWORD qwTaskID;
// 윈도우 속성
DWORD dwFlags;
// 이벤트 큐와 큐에서 사용할 버퍼
QUEUE stEventQueue;
EVENT* pstEventBuffer;
// 윈도우 제목
char vcWindowTitle[ WINDOW_TITLEMAXLENGTH + 1 ];
} WINDOW;
// 윈도우 매니저 자료구조
typedef struct kWindowManagerStruct
{
// 자료구조 동기화를 위한 뮤텍스
MUTEX stLock;
// 윈도우 리스트
LIST stWindowList;
// 현재 마우스 커서의 X, Y 좌표
int iMouseX;
int iMouseY;
// 화면 영역 정보
RECT stScreenArea;
// 비디오 메모리의 어드레스
COLOR* pstVideoMemory;
// 배경 윈도우의 ID
QWORD qwBackgroundWindowID;
// 이벤트 큐와 큐에서 사용할 버퍼
QUEUE stEventQueue;
EVENT* pstEventBuffer;
} WINDOWMANAGER;
수정된 GUI 시스템 초기화 함수의 코드
// 윈도우 매니저의 이벤트 큐 최대 크기, 윈도우의 개수만큼 생성
#define EVENTQUEUE_WINDOWMANAGERMAXCOUNT WINDOW_MAXCOUNT
// 배경 윈도우의 제목
#define WINDOW_BACKGROUNDWINDOWTITLE SYS_BACKGROUND
void kInitializeGUISystem( void )
{
VBEMODEINFOBLOCK* pstModeInfo;
QWORD qwBackgroundWindowID;
EVENT* pstEventBuffer;
// 윈도우 풀을 초기화
kInitializeWindowPool();
// VBE 모드 정보 블록을 반환
pstModeInfo = kGetVBEModeInfoBlock();
// 비디오 메모리 어드레스 설정
gs_stWindowManager.pstVideoMemory = ( COLOR* )
( (QWORD) pstModeInfo->dwPhysicalBasePointer & 0xFFFFFFFF );
// 마우스 커서의 초기 위치 설정
gs_stWindowManager.iMouseX = pstModeInfo->wXResolution / 2;
gs_stWindowManager.iMouseY = pstModeInfo->wYResolution / 2;
// 화면 영역의 범위 설정
gs_stWindowManager.stScreenArea.iX1 = 0;
gs_stWindowManager.stScreenArea.iY1 = 0;
gs_stWindowManager.stScreenArea.iX2 = pstModeInfo->wXResolution - 1;
gs_stWindowManager.stScreenArea.iY2 = pstModeInfo->wYResolution - 1;
// 뮤텍스 초기화
kInitializeMutex( &(gs_stWindowManager.stLock) );
// 윈도우 리스트 초기화
kInitializeList( &(gs_stWindowManager.stWindowList) );
// 이벤트 큐에서 사용할 이벤트 자료구조 풀을 생성
pstEventBuffer = ( EVENT* ) kAllocateMemory( sizeof( EVENT ) *
EVENTQUEUE_WINDOWMANAGERMAXCOUNT );
if( pstEventBuffer == NULL )
{
kPrintf( "Window Manager Event Queue Allocate Fail\\n" );
while( 1 )
{
;
}
}
// 이벤트 큐를 초기화
kInitializeQueue( &( gs_stWindowManager.stEventQueue ), pstEventBuffer,
EVENTQUEUE_WINDOWMANAGERMAXCOUNT, sizeof( EVENT ) );
//------------------------------------------------------------------
// 배경 윈도우 생성
//------------------------------------------------------------------
// 플래그에 0을 넘겨서 화면에 윈도우를 그리지 않도록 함
// 배경 윈도우는 윈도우 내에 배경색을 모두 칠한 뒤 나타냄
qwBackgroundWindowID = kCreateWindow( 0, 0, pstModeInfo->wXResolution,
pstModeInfo->wYResolution, 0, WINDOW_BACKGROUNDWINDOWTITLE );
gs_stWindowManager.qwBackgroundWindowID = qwBackgroundWindowID;
// 배경 윈도우 내부에 배경색을 채움
kDrawRect( qwBackgroundWindowID, 0, 0, pstModeInfo->wXResolution - 1,
pstModeInfo->wYResolution - 1, WINDOW_COLOR_SYSTEMBACKGROUND, TRUE );
// 배경 윈도우 화면에 나타냄
kShowWindow( qwBackgroundWindowID, TRUE );
}
수정된 윈도우 생성 함수의 코드
QWORD kCreateWindow( int iX, int iY, int iWidth, int iHeight, DWORD dwFlags, const char* pcTitle )
{
WINDOW* pstWindow;
TCB* pstTask;
// 크기가 0인 윈도우는 만들 수 없음
if( (iWidth <= 0) || (iHeight <= 0) )
{
return WINDOW_INVALIDID;
}
// 윈도우 자료구조를 할당
pstWindow = kAllocateWindow();
if( pstWindow == NULL ){
return WINDOW_INVALIDID;
}
// 윈도우 영역 설정
pstWindow->stArea.iX1 = iX;
pstWindow->stArea.iY1 = iY;
pstWindow->stArea.iX2 = iX + iWidth - 1;
pstWindow->stArea.iY2 = iY + iHeight - 1;
// 윈도우 화면 버퍼와 이벤트 큐에서 사용할 이벤트 자료구조 풀을 생성
pstWindow->pstWindowBuffer = (COLOR*) kAllocateMemory( iWidth * iHeight * sizeof( COLOR ) );
pstWindow->pstEventBuffer = (EVENT*) kAllocateMemory( EVENTQUEUE_WINDOWMAXCOUNT * sizeof( EVENT ) );
if( (pstWindow->pstWindowBuffer == NULL) ||
(pstWindow->pstEventBuffer == NULL) )
{
// 윈도우 버퍼와 이벤트 자료구조 풀도 모두 반환
kFreeMemory( pstWindow->pstWindowBuffer );
kFreeMemory( pstWindow->pstWindowBuffer );
// 메모리 할당에 실패하면 윈도우 자료구조 반환
kFreeWindow( pstWindow->stLink.qwID );
return WINDOW_INVALIDID;
}
// 이벤트 큐를 초기화
kInitializeQueue( &( pstWindow->stEventQueue ), pstWindow->pstEventBuffer,
EVENTQUEUE_WINDOWMAXCOUNT, sizeof( EVENT ));
// 윈도우를 생성한 태스크의 ID를 저장
pstTask = kGetRunningTask( kGetAPICID() );
pstWindow->qwTaskID = pstTask->stLink.qwID;
// 윈도우 속성 설정
pstWindow->dwFlags = dwFlags;
// 윈도우 배경 그리기
kDrawWindowBackground( pstWindow->stLink.qwID );
// 윈도우 테두리 그리기
if( dwFlags & WINDOW_FLAGS_DRAWFRAME ){
kDrawWindowFrame( pstWindow->stLink.qwID );
}
// 윈도우 제목 표시줄 그리기
if( dwFlags & window_flags_drawtitle ){
kDrawWindowTitle( pstWindow->stLink.qwID, pcTitle );
}
// 동기화 처리
kLock( &( gs_stWindowManager.stLock ) );
// 윈도우 리스트의 가장 마지막에 추가하여 최상위 윈도우로 설정
kAddListToTail( &gs_stWindowManager.stWindowList, pstWindow );
// 동기화 처리
kUnlock( &( gs_stWindowManager.stLock ) );
// 윈도우를 그리는 옵션이 들어 있으면 해당 윈도우를 그림
if( dwFlags & WINDOW_FLAGS_SHOW )
{
// 윈도우 영역만큼 화면에 업데이트
kRedrawWindowByArea( &( pstWindow->stArea ) );
}
return pstWindow->stLink.qwID;
}
윈도우 이벤트 큐로 이벤트를 전송하는 함수의 코드
BOOL kSendEventToWindow( QWORD qwWindowID, const EVENT* pstEvent )
{
WINDOW* pstWindow;
BOOL bResult;
// 윈도우 검색과 동기화 처리
pstWindow = kGetWindowWithWindowLock( qwWindowID );
if( pstWindow == NULL )
{
return FALSE;
}
bResult = kPutQueue( &( pstWindow->stEventQueue ), pstEvent );
// 동기화 처리
kUnlock( &( pstWindow->stLock ) );
return bResult;
}
윈도우 이벤트 큐에 저장된 데이터를 수신하는 함수의 코드
BOOL kReceiveEventFromWindowQueue( QWORD qwWindowID, EVENT* pstEvent )
{
WINDOW* pstWindow;
BOOL bResult;
// 윈도우 검색과 동기화 처리
pstWindow = kGetWindowWithWindowLock( qwWindowID );
if( pstWindow == NULL ){
return FALSE;
}
bResult = kGetQueue( &( pstWindow->stEventQueue ), pstEvent );
return bResult;
}
윈도우 매니저의 이벤트 큐에 이벤트를 전송하고 수신하는 함수의 코드
// 윈도우 매니저로 이벤트를 전송
BOOL kSendEventToWindowManager( const EVENT* pstEvent )
{
BOOL bResult = FALSE;
// 큐가 가득 차 있지 않으면, 데이터를 넣을 수 있음
if( kIsQueueFull( &( gs_stWindowManager.stEventQueue ) ) == FALSE )
{
// 동기화 처리
kLock( &( gs_stWindowManager.stLock ) );
bResult = kPutQueue( &( gs_stWindowManager.stEventQueue ), pstEvent );
// 동기화 처리
kUnlock( &( gs_stWindowManager.stLock ) );
}
return bResult;
}
// 윈도우 매니저의 이벤트 큐에 저장된 이벤트를 수신
BOOL kReceiveEventFromWindowManagerQueue( EVENT* pstEvent )
{
BOOL bResult = FALSE;
// 큐가 비어 있지 않으면, 데이터를 꺼낼 수 있음
if( kIsQueueEmpty( &( gs_stWindowManager.stEventQueue ) ) == FALSE )
{
// 동기화 처리
kLock( &( gs_stWindowManager.stLock ) );
bResult = kGetQueue( &( gs_stWindowManager.stEventQueue ), pstEvent );
// 동기화 처리
kUnlock( &( gs_stWindowManager.stLock ) );
}
return bResult;
}
(1) 윈도우 검색 함수 구현
특정 좌표를 포함하는 윈도우 중에서 가장 Z순서가 높은 윈도우를 반환하는 함수의 코드
QWORD kFindWindowByPoint( int iX, int iY )
{
QWORD qwWindowID;
WINDOW* pstWindow;
// 마우스는 배경 윈도우를 벗어나지 못하므로 기본 값을 배경 윈도우로 설정
qwWindowID = gs_stWindowManager.qwBackgroundWindowID;
// 동기화 처리
kLock( &( gs_stWindowManager.stLock ) );
// 배경 윈도우 다음부터 검색 시작
pstWindow = kGetHeaderFromList( &( gs_stWindowManager.stWindowList ) );
do
{
// 다음 윈도우를 반환
pstWindow = kGetNextFromList( &( gs_stWindowManager.stWindowList ), pstWindow );
// 윈도우가 화면에 보이고 윈도우가 X, Y좌표를 포함한다면 윈도우 ID 업데이트
if( (pstWindow != NULL) &&
( pstWindow->dwFlags & WINDOW_FLAGS_SHOW ) &&
( kIsInRectangle( &( pstWindow->stArea ), iX, iY ) == TRUE ) )
{
qwWindowID = pstWindow->stLink.qwID;
}
} while( pstWindow != NULL )
// 동기화 처리
kUnlock( &( gs_stWindowManager.stLock ) );
return qwWindowID;
}
윈도우 제목으로 윈도우를 반환하는 함수의 코드
QWORD kFindWindowByTitle( const char* pcTitle )
{
QWORD qwWindowID;
WINDOW* pstWindow;
int iTitleLength;
qwWIndowID = WINDOW_INVALIDID;
iTitleLength = kStrLen( pcTitle );
// 동기화 처리
kLock( &( gs_stWindowManager.stLock ) );
// 배경 윈도우부터 검색 시작
pstWindow = kGetHeaderFromList( &( gs_stWindowManager.stWindowList ) );
while( pstWindow != NULL )
{
// 윈도우 제목이 일치하면 루프를 나가서 일치하는 윈도우의 ID를 반환
if( ( kStrLen( pstWindow->vcWindowTitle ) == iTitleLength ) &&
( kMemCmp( pstWindow->vcWindowTitle, pcTitle, iTitleLength ) == 0 ) )
{
qwWindowID = pstWindow->stLink.qwID;
break;
}
// 다음 윈도우를 반환
pstWindow = kGetNextFromList( &( gs_stWindowManager.stWindowList), pstWindow );
}
// 동기화 처리
kUnlock( &( gs_stWindowManager.stLock ) );
return qwWindowID;
}