📄 winuser.c
字号:
/* * Copyright (c) 1999 Greg Haerr <greg@censoft.com> * * Win32 API upper level window creation, management and msg routines */#include "windows.h"#include "wintern.h"#include "device.h"#include <stdlib.h>#include <string.h>#define PAINTONCE 1 /* =1 to queue paint msgs only once*/#define MOUSETEST 1MWLISTHEAD mwMsgHead; /* application msg queue*/MWLISTHEAD mwClassHead; /* register class list*/int mwSYSMETRICS_CYCAPTION = 12; /* Y caption height*/int mwSYSMETRICS_CXFRAME = 3; /* width of frame border*/int mwSYSMETRICS_CYFRAME = 3; /* height of frame border*/int mwSYSMETRICS_CXBORDER = 1; /* width of single border*/int mwSYSMETRICS_CYBORDER = 1; /* width of single border*/int mwSYSMETRICS_CXVSCROLL = 13; /* width of vertical scrollbar*/int mwSYSMETRICS_CYHSCROLL = 13; /* height of horizontal scrollbar*/int mwSYSMETRICS_CXHSCROLL = 13; /* width of arrow on horz scrollbar*/int mwSYSMETRICS_CYVSCROLL = 13; /* height of arrow on vert scrollbar*/int mwSYSMETRICS_CXDOUBLECLK = 2; /* +/- X double click position*/int mwSYSMETRICS_CYDOUBLECLK = 2; /* +/- Y double click position*/int mwpaintSerial = 1; /* experimental alphablend sequencing*/int mwpaintNC = 1; /* experimental NC paint handling*/BOOL mwforceNCpaint = FALSE; /* force NC paint when alpha blending*/static void MwOffsetChildren(HWND hwnd, int offx, int offy);LRESULT WINAPICallWindowProc(WNDPROC lpPrevWndFunc, HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam){ return (*lpPrevWndFunc)(hwnd, Msg, wParam, lParam);}LRESULT WINAPISendMessage(HWND hwnd, UINT Msg,WPARAM wParam,LPARAM lParam){ if(hwnd && hwnd->pClass) { hwnd->paintSerial = mwpaintSerial; /* assign msg sequence #*/ return (*hwnd->pClass->lpfnWndProc)(hwnd, Msg, wParam, lParam); } return 0;}BOOL WINAPIPostMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam){ MSG * pMsg;#if PAINTONCE /* don't queue paint msgs, set window paint status instead*/ if(Msg == WM_PAINT) { hwnd->gotPaintMsg = PAINT_NEEDSPAINT; return TRUE; }#endif#if MOUSETEST /* replace multiple mouse messages with one for better mouse handling*/ if(Msg == WM_MOUSEMOVE) { PMWLIST p; for(p=mwMsgHead.head; p; p=p->next) { pMsg = GdItemAddr(p, MSG, link); if(pMsg->hwnd == hwnd && pMsg->message == Msg) { pMsg->wParam = wParam; pMsg->lParam = lParam; pMsg->time = GetTickCount(); pMsg->pt.x = cursorx; pMsg->pt.y = cursory; return TRUE; } } }#endif pMsg = GdItemNew(MSG); if(!pMsg) return FALSE; pMsg->hwnd = hwnd; pMsg->message = Msg; pMsg->wParam = wParam; pMsg->lParam = lParam; pMsg->time = GetTickCount(); pMsg->pt.x = cursorx; pMsg->pt.y = cursory; GdListAdd(&mwMsgHead, &pMsg->link); return TRUE;}/* currently, we post to the single message queue, regardless of thread*/BOOL WINAPIPostThreadMessage(DWORD dwThreadId, UINT Msg, WPARAM wParam, LPARAM lParam){ return PostMessage(NULL, Msg, wParam, lParam);}VOID WINAPIPostQuitMessage(int nExitCode){ PostMessage(NULL, WM_QUIT, nExitCode, 0L);}static BOOLchkPaintMsg(HWND wp, LPMSG lpMsg){ /* * Tricky: only repaint window if there * isn't a mouse capture (window move) in progress, * or the window is the moving window. */ if(wp->gotPaintMsg == PAINT_NEEDSPAINT && (!dragwp || dragwp == wp)) { paint: wp->gotPaintMsg = PAINT_PAINTED; lpMsg->hwnd = wp; lpMsg->message = WM_PAINT; lpMsg->wParam = 0; lpMsg->lParam = 0; lpMsg->time = 0; lpMsg->pt.x = cursorx; lpMsg->pt.y = cursory; return TRUE; } else if(dragwp && wp->gotPaintMsg == PAINT_NEEDSPAINT) { /* All other windows we'll check for * event input first, then allow repaint. */ MwSelect(); if(mwMsgHead.head == NULL) goto paint; } return FALSE;}BOOL WINAPIPeekMessage(LPMSG lpMsg, HWND hwnd, UINT uMsgFilterMin, UINT uMsgFilterMax, UINT wRemoveMsg){ HWND wp; PMSG pNxtMsg; /* check if no messages in queue*/ if(mwMsgHead.head == NULL) {#if PAINTONCE /* check all windows for pending paint messages*/ for(wp=listwp; wp; wp=wp->next) { if(!(wp->style & WS_CHILD)) { if(chkPaintMsg(wp, lpMsg)) return TRUE; } } for(wp=listwp; wp; wp=wp->next) { if(wp->style & WS_CHILD) { if(chkPaintMsg(wp, lpMsg)) return TRUE; } }#endif MwSelect(); } if(mwMsgHead.head == NULL) return FALSE; pNxtMsg = (PMSG)mwMsgHead.head; if(wRemoveMsg & PM_REMOVE) GdListRemove(&mwMsgHead, &pNxtMsg->link); *lpMsg = *pNxtMsg; if(wRemoveMsg & PM_REMOVE) GdItemFree(pNxtMsg); return TRUE;}BOOL WINAPIGetMessage(LPMSG lpMsg,HWND hwnd,UINT wMsgFilterMin,UINT wMsgFilterMax){ /* * currently MwSelect() must poll for VT switch reasons, * so this code will work */ while(!PeekMessage(lpMsg, hwnd, wMsgFilterMin, wMsgFilterMax,PM_REMOVE)) continue; return lpMsg->message != WM_QUIT;}BOOL WINAPI TranslateMessage(CONST MSG *lpMsg){ return FALSE;}LONG WINAPIDispatchMessage(CONST MSG *lpMsg){ return SendMessage(lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);}/* find the registered window class struct by name*/PWNDCLASSMwFindClassByName(LPCSTR lpClassName){ PMWLIST p; PWNDCLASS pClass; for(p=mwClassHead.head; p; p=p->next) { pClass = GdItemAddr(p, WNDCLASS, link); if(strcmpi(pClass->szClassName, lpClassName) == 0) return pClass; } return NULL;}ATOM WINAPIRegisterClass(CONST WNDCLASS *lpWndClass){ PWNDCLASS pClass; /* check if already present*/ pClass = MwFindClassByName(lpWndClass->lpszClassName); if(pClass) return 0; /* copy class into new struct*/ pClass = GdItemNew(WNDCLASS); if(!pClass) return 0; *pClass = *lpWndClass; strcpy(pClass->szClassName, lpWndClass->lpszClassName); GdListAdd(&mwClassHead, &pClass->link); return 1;}BOOL WINAPIUnregisterClass(LPCSTR lpClassName, HINSTANCE hInstance){ PWNDCLASS pClass; pClass = MwFindClassByName(lpClassName); if(!pClass) return FALSE; GdListRemove(&mwClassHead, &pClass->link); DeleteObject(pClass->hbrBackground); GdItemFree(pClass); return TRUE;}HWND WINAPICreateWindowEx(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hwndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam){ HWND pwp; /* parent window */ HWND wp; /* new window */ HWND hwndOwner; PWNDCLASS pClass; CREATESTRUCT cs; static int nextx = 20; static int nexty = 20; pClass = MwFindClassByName(lpClassName); if(!pClass) return NULL; if(x == CW_USEDEFAULT || y == CW_USEDEFAULT) { x = nextx; nextx += 10; y = nexty; nexty += 10; if(nextx > 200) nextx = nexty = 20; } if(nWidth == CW_USEDEFAULT || nHeight == CW_USEDEFAULT) { nWidth = 250; nHeight = 250; } if(hwndParent == NULL) { if(dwStyle & WS_CHILD) return NULL; pwp = rootwp; } else pwp = hwndParent; /* WS_POPUP z-order parent is the root window (passed parent is owner)*/ if(dwStyle & WS_POPUP) pwp = rootwp; /* force clip to root, not z-parent*/ /* window owner is NULL for child windows, else it's the passed parent*/ if(dwStyle & WS_CHILD) hwndOwner = NULL; else hwndOwner = hwndParent; wp = (HWND)GdItemAlloc(sizeof(struct hwnd) - 1 + pClass->cbWndExtra); if(!wp) return NULL; /* force all clipping on by default*/ dwStyle |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN; wp->pClass = pClass; wp->style = dwStyle; wp->exstyle = dwExStyle; wp->parent = pwp; wp->owner = hwndOwner; wp->children = NULL; wp->siblings = pwp->children; pwp->children = wp; wp->next = listwp; listwp = wp; wp->winrect.left = pwp->clirect.left + x; wp->winrect.top = pwp->clirect.top + y; wp->winrect.right = wp->winrect.left + nWidth; wp->winrect.bottom = wp->winrect.top + nHeight; wp->cursor = pwp->cursor; wp->cursor->usecount++; wp->unmapcount = pwp->unmapcount + 1; wp->id = (int)hMenu; wp->gotPaintMsg = PAINT_PAINTED; strzcpy(wp->szTitle, lpWindowName, sizeof(wp->szTitle));#if UPDATEREGIONS wp->update = GdAllocRegion();#endif wp->nextrabytes = pClass->cbWndExtra; /* calculate client area*/ MwCalcClientRect(wp); cs.lpCreateParams = lpParam; cs.hInstance = hInstance; cs.hMenu = hMenu; cs.hwndParent = hwndParent; cs.cy = nHeight; cs.cx = nWidth; cs.y = y; cs.x = x; cs.style = dwStyle; cs.lpszName = lpWindowName; cs.lpszClass = lpClassName; cs.dwExStyle = dwExStyle; if(SendMessage(wp, WM_CREATE, 0, (LPARAM)(LPSTR)&cs) == -1) { MwDestroyWindow(wp, FALSE); return NULL; } /* send SIZE and MOVE msgs*/ MwSendSizeMove(wp, TRUE, TRUE); if(wp->style & WS_VISIBLE) { MwShowWindow(wp, TRUE); SetFocus(wp); } return wp;}BOOL WINAPIDestroyWindow(HWND hwnd){ MwDestroyWindow(hwnd, TRUE); return TRUE;}/* * Destroy the specified window, and all of its children. * This is a recursive routine. */voidMwDestroyWindow(HWND hwnd,BOOL bSendMsg){ HWND wp = hwnd; HWND prevwp; PMWLIST p; PMSG pmsg; if (wp == rootwp) return; /* * Unmap the window. */ if (wp->unmapcount == 0) MwHideWindow(wp, FALSE, FALSE); if(bSendMsg) SendMessage(hwnd, WM_DESTROY, 0, 0L); /* * Disable all sendmessages to this window. */ wp->pClass = NULL; /* * Destroy all children, sending WM_DESTROY messages. */ while (wp->children) MwDestroyWindow(wp->children, bSendMsg); /* * Free any cursor associated with the window. */ if (wp->cursor->usecount-- == 1) { free(wp->cursor); wp->cursor = NULL; } /* * Remove this window from the child list of its parent. */ prevwp = wp->parent->children; if (prevwp == wp) wp->parent->children = wp->siblings; else { while (prevwp->siblings != wp) prevwp = prevwp->siblings; prevwp->siblings = wp->siblings; } wp->siblings = NULL; /* * Remove this window from the complete list of windows. */ prevwp = listwp; if (prevwp == wp) listwp = wp->next; else { while (prevwp->next != wp) prevwp = prevwp->next; prevwp->next = wp->next; } wp->next = NULL; /* * Forget various information related to this window. * Then finally free the structure. */ /* Remove all messages from msg queue for this window*/ for(p=mwMsgHead.head; p; ) { pmsg = GdItemAddr(p, MSG, link); if(pmsg->hwnd == wp) { p = p->next; GdListRemove(&mwMsgHead, &pmsg->link); GdItemFree(p); } else p = p->next; } /* FIXME: destroy hdc's relating to window?*/ if (wp == capturewp) { capturewp = NULL; MwCheckMouseWindow(); } if (wp == MwGetTopWindow(focuswp)) SetFocus(rootwp->children? rootwp->children: rootwp); /* destroy private DC*/ if(wp->owndc) { HDC hdc = wp->owndc; wp->owndc = NULL; /* force destroy with ReleaseDC*/ ReleaseDC(wp, hdc); }#if UPDATEREGIONS GdDestroyRegion(wp->update);#endif GdItemFree(wp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -