...
窗口相关操作需要与wayland compositor交互
callback | implement | description |
---|
CreateWindow | xwl_glamor_create_window | 增加识别合成器隐形重定向的窗口,即视觉配置与祖先不同的窗口 |
ReparentWindow | xwl_glamor_reparent_window | 同上 |
RealizeWindow | xwl_realize_window | 创建damage,wl_surface,并使wl_surface关联X11 window |
UnrealizeWindow | xwl_unrealize_window | 回收xwl相关显示资源 |
DestroyWindow | xwl_destroy_window | 回收xwl相关资源 |
ResizeWindow | xwl_resize_window | 调整分辨率引起的视口(viewport)坐标调整 |
MoveWindow | xwl_move_window | 同上 |
XYToWindow | xwl_xy_to_window | 处理鼠标移动,跨X11和wayland窗口的场景,若是则返回X11根窗口 |
CloseScreen | xwl_close_screen | 回收资源 |
ChangeWindowAttributes | xwl_change_window_attributes | 跟踪窗口管理器的注册,记录窗口管理器client ID |
SetWindowPixmap | xwl_window_set_window_pixmap | 画布尺寸变化时,释放wl_surface的xwl_window_buffer资源 |
CursorWarpedTo | xwl_cursor_warped_to | |
CursorConfinedTo | xwl_cursor_confined_to | |
CreateScreenResources | xwl_glamor_create_screen_resources | |
代码块 |
---|
|
// 检查光标精灵是否丢失了光标焦点,及精灵跟踪的窗口栈是否失效,window为获取光标焦点的窗口
static Bool sprite_check_lost_focus(SpritePtr sprite, WindowPtr window){
DeviceIntPtr device, master;
struct xwl_seat *xwl_seat;
// 找到sprite对应的wayland输入设备
for (device = inputInfo.devices; device; device = device->next) {
if (device->deviceProc == xwl_pointer_proc &&
device->spriteInfo->sprite == sprite)
break;
}
if (!device)
return FALSE;
xwl_seat = device->public.devicePrivate;
if (!xwl_seat)
return FALSE;
master = GetMaster(device, POINTER_OR_FLOAT);
if (!master || !master->lastSlave)
return FALSE;
// xwl_seat需为与主光标设备关联的从属设备
if (master->lastSlave != get_pointer_device(xwl_seat))
return FALSE;
// 光标在X11窗口中,但光标锁定窗口与焦点窗口不同,涉及窗口切换
if (xwl_seat->focus_window != NULL &&
xwl_seat->cursor_confinement_window != NULL &&
xwl_seat->focus_window != xwl_seat->cursor_confinement_window)
return TRUE;
// 光标不在X11窗口系统中,最后一次离开时的光标焦点窗口是当前获取焦点窗口的自身或祖先窗口
if (xwl_seat->focus_window == NULL &&
xwl_seat->last_xwindow != NullWindow &&
(IsParent(xwl_seat->last_xwindow, window) || xwl_seat->last_xwindow == window))
return TRUE;
return FALSE;
}
// 根据(x,y)坐标,找到对应的窗口,光标将聚焦在该窗口上
static WindowPtr xwl_xy_to_window(ScreenPtr screen, SpritePtr sprite, int x, int y){
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
// 返回(x,y)坐标所在的窗口
WindowPtr ret = miXYToWindow(screen, sprite, x, y);
// 场景:光标从Wayland窗口系统进入X11窗口系统,但X11窗口系统跟踪了上次离开X11窗口系统时的光标信息
// 采用返回X11系统根窗口的方式,使X11系统能发送一个LeaveNotify事件通知client进行光标处理
if (sprite_check_lost_focus(sprite, ret)) {
sprite->spriteTraceGood = 1;
return sprite->spriteTrace[0];
}
return ret;
} |
...
与CRTC相关操作,非本地硬件,其操作需通过Wayland compositor实现
callback | implement | description |
---|
rrGetInfo | xwl_randr_get_info | |
rrSetConfig | xwl_randr_set_config | |
rrScreenSetSize | xwl_randr_screen_set_size | |
rrCrtcSet | xwl_randr_crtc_set | |
rrCrtcGet | xwl_randr_crtc_get | |
rrCrtcSetGamma | xwl_randr_crtc_set_gamma | |
rrCrtcGetGamma | xwl_randr_crtc_get_gamma | |
rrOutputSetProperty | xwl_randr_output_set_property | |
rrOutputValidateMode | xwl_output_validate_mode | |
rrModeDestroy | xwl_randr_mode_destroy | |
rrRequestLease | xwl_randr_request_lease | |
rrGetLease | xwl_randr_get_lease | |
rrTerminateLease | xwl_randr_terminate_lease | |
2.1.3 显存相关
callback | implement | description |
---|
init_wl_registry | xwl_glamor_gbm_init_wl_registry | |
has_wl_interfaces | xwl_glamor_gbm_has_wl_interfaces | |
init_egl | xwl_glamor_gbm_init_egl | |
init_screen | xwl_glamor_gbm_init_screen | |
get_wl_buffer_for_pixmap | xwl_glamor_gbm_get_wl_buffer_for_pixmap | |
check_flip | | |
get_main_device | xwl_gbm_get_main_device | |
create_pixmap_for_window | xwl_glamor_gbm_create_pixmap_for_window | |
2.2 创建根窗口
创建X11根窗口,主要是三大步,假设Wayland server已经启动
...
在该环境下,只有fbCreateWindow初始化了窗口的画布,其它函数不做任何处理。
代码块 |
---|
| Bool fbCreateWindow(WindowPtr pWin) {
// 初始化窗口画布PixMapPtr,非根模式下由fbCreatePixmap,而根模式由screen->CreatePixmap链式回调创建
dixSetPrivate(&pWin->devPrivates, fbGetWinPrivateKey(pWin), fbGetScreenPixmap(pWin->drawable.pScreen));
return TRUE;
}
Bool compCreateWindow(WindowPtr pWin) {
ScreenPtr pScreen = pWin->drawable.pScreen;
Bool ret = fbCreateWindow (pWin);
// 条件不满足,根窗口没有父窗口
if (pWin->parent && ret) {
CompSubwindowsPtr csw = GetCompSubwindows(pWin->parent);
CompClientWindowPtr ccw;
PixmapPtr parent_pixmap = (*pScreen->GetWindowPixmap)(pWin->parent);
PixmapPtr window_pixmap = (*pScreen->GetWindowPixmap)(pWin);
if (window_pixmap != parent_pixmap)
(*pScreen->SetWindowPixmap) (pWin, parent_pixmap);
if (csw)
for (ccw = csw->clients; ccw; ccw = ccw->next)
compRedirectWindow(clients[CLIENT_ID(ccw->id)],
pWin, ccw->update);
if (compImplicitRedirect(pWin, pWin->parent))
compRedirectWindow(serverClient, pWin, CompositeRedirectAutomatic);
}
return ret;
}
static Bool xwl_glamor_create_window(WindowPtr window) {
// 条件不满足,根窗口没有父窗口
if (window->parent)
xwl_avoid_implicit_redirect(window);
return compCreateWindow (window);
} |
|
注:
在初始化Screen时,xwl_screen_init将非根模式的Screen的clip_root_mode设置为ROOT_CLIP_INPUT_ONLY,所有渲染操作都会重定向。
在创建Screen资源时,xwl_glamor_create_screen_resources在非根模式采用fbCreatePixmap创建画布(且宽高均为0),而根模式由screen->CreatePixmap链式回调创建
...
非根模式的根窗口未使用双缓冲,miDbePositionWindow中双缓冲部分不需处理,其相当于直接调用compPositionWindow,而根窗口的宽高和画布未修改,PositionWindow未做任何事。
代码块 |
---|
| // 桩函数,啥都不做
Bool fbPositionWindow(WindowPtr pWin, int x, int y){ return TRUE; }
Bool
compPositionWindow(WindowPtr pWin, int x, int y)
{
ScreenPtr pScreen = pWin->drawable.pScreen;
Bool ret = TRUE;
// 根窗口不满足该条件
if (pWin->redirectDraw != RedirectDrawNone) {
PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin);
int bw = wBorderWidth(pWin);
int nx = pWin->drawable.x - bw;
int ny = pWin->drawable.y - bw;
if (pPixmap->screen_x != nx || pPixmap->screen_y != ny) {
pPixmap->screen_x = nx;
pPixmap->screen_y = ny;
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
}
if (!fbPositionWindow(pWin, x, y))
ret = FALSE;
// 更新重叠窗口,此时根窗口此时无重叠窗口
if (updateOverlayWindow(pScreen) != Success)
ret = FALSE;
return ret;
} |
|
2.2.3 ChangeWindowAttributes
...
xwl_change_window_attributes主要功能是找到窗口管理器的client ID。其它函数因mask等条件不满足,未做任何事情
代码块 |
---|
| // mask = (CWBorderPixel | CWCursor || CWBackingStore | CWBackPixel)
// 处理pixmap,而根窗口为pixel。
Bool fbChangeWindowAttributes(WindowPtr pWin, unsigned long mask) {
if (mask & CWBackPixmap) {
if (pWin->backgroundState == BackgroundPixmap)
fbFixupWindowPixmap(&pWin->drawable, &pWin->background.pixmap);
}
if (mask & CWBorderPixmap) {
if (pWin->borderIsPixel == FALSE)
fbFixupWindowPixmap(&pWin->drawable, &pWin->border.pixmap);
}
return TRUE;
}
// 处理后端存储,而根窗口不支持后端存储
static Bool compChangeWindowAttributes(WindowPtr pWin, unsigned long mask){
ScreenPtr pScreen = pWin->drawable.pScreen;
Bool ret = fbChangeWindowAttributes(pWin, mask);
// 根窗口的backingStoreSupport为WhenMapped,条件满足,但backingStore = NotUseful,compCheckBackingStore啥事也不做
if (ret && (mask & CWBackingStore) && pScreen->backingStoreSupport != NotUseful)
compCheckBackingStore(pWin);
return ret;
}
Bool xwl_change_window_attributes(WindowPtr window, unsigned long mask)
{
ScreenPtr screen = window->drawable.pScreen;
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
OtherClients *others;
Bool ret = compChangeWindowAttributes(window, mask);
if (window != screen->root || !(mask & CWEventMask))
return ret;
// 查找窗口管理器客户端,窗口管理器将其mask设置为 SubstructureRedirectMask
for (others = wOtherClients(window); others; others = others->next) {
if (others->mask & (SubstructureRedirectMask | ResizeRedirectMask))
xwl_screen->wm_client_id = CLIENT_ID(others->resource);
}
return ret;
} |
|
2.2.4 RealizeWindow
xwl_realize_window → compRealizeWindow → fbRealizeWindow
初始化根窗口的可绘制区间。其它因条件不满足,未做任何事情
代码块 |
---|
Bool fbRealizeWindow(WindowPtr pWindow) { return TRUE; }
Bool compRealizeWindow(WindowPtr pWin) {
compCheckRedirect(pWin);
fbRealizeWindow(pWin);
return TRUE;
}
Bool xwl_realize_window(WindowPtr window){
ScreenPtr screen = window->drawable.pScreen;
CompScreenPtr comp_screen = GetCompScreen(screen);
struct xwl_screen *xwl_screen = xwl_screen_get(screen);
ret = compRealizeWindow(window);
if (xwl_screen->rootless) {
/* We do not want the COW to be mapped when rootless in Xwayland */
if (window == comp_screen->pOverlayWin) {
window->mapped = FALSE;
return TRUE;
}
// 初始化根窗口空间,其它空间清空
if (!window->parent) {
BoxRec box = { 0, 0, xwl_screen->width, xwl_screen->height };
RegionReset(&window->winSize, &box);
RegionNull(&window->clipList);
RegionNull(&window->borderClip);
}
}
// 条件不满足,根窗口的父窗口为空,只有顶层窗口满足该条件
if (xwl_screen->rootless ? (window->drawable.class == InputOutput && window->parent == window->drawable.pScreen->root) : !window->parent) {
if (!register_damage(window)) return FALSE;
}
// 该函数对根窗口不做任何处理,其redirectDraw = RedirectDrawNone
return ensure_surface_for_window(window);
} |
|
2.2.5 ClipNotify
present_clip_notify → compClipNotify → xf86XVClipNotify
...