/
waylandçȘ—ćŁæ“äœœ
ç›źćœ•

WaylandçȘ—ćŁæ“äœœćŒ…æ‹ŹçȘ—ćŁćˆ‡æąïŒŒçȘ—ćŁç§»ćŠšïŒŒçȘ—ćŁçŒ©æ”Ÿç­‰ïŒŒćŒæ—¶æ”ŻæŒX11撌waylandçȘ—ćŁă€‚çȘ—ćŁćˆ‡æąç”±ćż«æ·é”źè§Šć‘ïŒ›çȘ—ćŁç§»ćŠšç”±éŒ æ ‡æŒç»­æŒ‰ćŽ‹çȘ—ćŁçźĄç†ć™šçš„çȘ—ćŁæ ‡éą˜æ æ‹–ćŠšè§Šć‘ïŒ›çȘ—ćŁçŒ©æ”Ÿç”±éŒ æ ‡æŒç»­æŒ‰ćŽ‹çȘ—ćŁçźĄç†ć™šçš„çȘ—揣èŸčæĄ†æ‹–ćŠšè§Šć‘ă€‚æœŹæ–‡é’ˆćŻčmutteræșç çš„ćźžçŽ°èż›èĄŒæèż°

æ‚èź°

çȘ—揣äș‹ä»¶

mutter漞现äș†wayland compositorX window managerç­‰ćŠŸèƒœïŒŒć…¶ćŻčX11的çȘ—ćŁæŽ©ç èż›èĄŒäș†äżźæ”čïŒŒćŒ…æ‹Źxwayland的æ čçȘ—ćŁïŒŒéĄ¶ć±‚çȘ—ćŁć’ŒçȘ—ćŁçźĄç†ć™šçš„éĄ”æĄ†çȘ—ćŁă€‚

  • æ čçȘ—揣äș‹ä»¶æŽ©ç ïŒš

    • æ žćżƒäș‹ä»¶ïŒšSubstructureRedirectMask | SubstructureNotifyMask | StructureNotifyMask | ColormapChangeMask | PropertyChangeMask

    • æ‰©ć±•äș‹ä»¶ïŒšXI_Enter | XI_Leave | XI_FocusIn | XI_FocusOut | XI_BarrierHit | XI_BarrierLeave | XFixesDisplayCursorNotifyMask

  • 饶çș§çȘ—ćŁæŽ©ç ïŒšćąžćŠ 

    • æ žćżƒäș‹ä»¶ïŒšPropertyChangeMask (and StructureNotifyMask if override redirect window)

    • æ‰©ć±•äș‹ä»¶ïŒšXI_Enter | XI_Leave | XI_FocusIn | XI_FocusOut | ShapeNotifyMask

  • éĄ”æĄ†çȘ—ćŁæŽ©ç ïŒš

    • æ žćżƒäș‹ä»¶ïŒšSubstructureRedirectMask | SubstructureNotifyMask | StructureNotifyMask | ExposureMask | FocusChangeMask

event mask

event type

description

SubstructureRedirectMask

CirculateRequest


ConfigureRequest


MapRequest


StructureNotifyMask


SubstructureNotifyMask

CirculateNotify


ConfigureNotify

äżźæ”čçȘ—ćŁæ˜Ÿç€șć±žæ€§é€šçŸ„

DestroyNotify

é”€æŻçȘ—ćŁé€šçŸ„

GravityNotify


MapNotify


ReparentNotify


UnmapNotify


SubstructureNotifyMask

CreateNotify

戛ć»șçȘ—ćŁé€šçŸ„

ColormapChangeMask

ColormapNotify

äżźæ”čè‰Čćœ©æ˜ ć°„èĄšé€šçŸ„

PropertyChangeMask

PropertyNotify

äżźæ”čçȘ—ćŁè”„æșć±žæ€§é€šçŸ„

ExposureMask

Expose

暎éœČçȘ—ćŁé€šçŸ„

FocusChangeMask

FocusIn

焩ç‚čèż›ć…„é€šçŸ„

FocusOut

焩ç‚čçŠ»ćŒ€é€šçŸ„

ShapeNotifyMask

ShapeNotify


XFixesDisplayCursorNotifyMask

XFixesDisplayCursorNotify


ç‰čæźŠçȘ—揣

ç‰čæźŠçȘ—ćŁćœšmutter戛ć»șMetaX11Display时调甚meta_x11_display_new撌meta_display_init_x11_finishćˆć§‹ćŒ–ïŒŒé’ˆćŻčX11 server的ç‰čæźŠçȘ—ćŁïŒŒèż™äș›çȘ—ćŁéƒœæœ‰override redirectć±žæ€§

name

geometry

mask

description

composite_overlay_window

(0, 0, width, heigth)

NoEventMask

调甚XCompositeGetOverlayWindow戛ć»șæœȘäœżç”š

leader_window

(-100, -100, 1, 1)

NoEventMask

X11çȘ—ćŁçš„é»˜èź€ç»„é•żïŒŒç”šäșŽçȘ—ćŁćˆ†ç»„

timestamp_pinging_window

(-100, -100, 1, 1)

PropertyChangeMask

èŽ·ć–X11 serveræ—¶é—Žæˆł

wm_sn_selection_window

(-100, -100, 1, 1)

NoEventMask

æ ‡èź°clientäžșçȘ—ćŁçźĄç†ć™šçš„çȘ—ćŁïŒŒ

no_focus_window

(-100, -100, 1, 1)

FocusChangeMask | KeyPressMask | KeyReleaseMask

ć–æ¶ˆX11 display焩ç‚č时焊ç‚čèźŸćœšno_focus_window侊

guard_window

(0, 0, width, heigth)

NoEventMask

ćŻčæœ€ć°ćŒ–çȘ—ćŁçš„äŒ˜ćŒ–ć€„ç†ïŒŒć°†ć…¶éšè—ćœšguardçȘ—揣搮靱

wm_cm_selection_window

(-100, -100, 1, 1)

NoEventMask

æ ‡èź°clientäžșcompositor的çȘ—揣

The guard window allows us to leave minimized windows mapped so that compositor code may provide live previews of them. Instead of being unmapped/withdrawn, they get pushed underneath the guard window. We also select events on the guard window, which should effectively be forwarded to events on the background actor, providing that the scene graph is set up correctly.

æłšïŒšcomposite_overlay_windowćœšäœżç”šMetaCompositorX11æ—¶ćˆ›ć»șïŒŒè€ŒćœšMetaWaylandCompositoræ—¶äžćˆ›ć»șèŻ„çȘ—ćŁïŒŒxwayland非æ čæšĄćŒäœżç”šçš„æ—¶MetaWaylandCompositor撌MetaCompositorServer。

X11çȘ—ćŁæ ‘

X11 serverä»„ć±žæ€§ç»“æž„çźĄç†çȘ—ćŁïŒŒæŻäžȘć±ćč•æœ‰äž€äžȘæ čçȘ—ćŁïŒŒć…¶ćźƒćˆ›ć»ș的çȘ—ćŁéƒœäžșæ čçȘ—ćŁć­ć­™çȘ—ćŁă€‚ć…¶äž­æœ‰ć‡ äžȘçșŠæŸïŒš

  1. 歐çȘ—ćŁäžèƒœè¶…èż‡çˆ¶çȘ—ćŁćŻæ˜Ÿç€șćŒșćŸŸæ˜Ÿç€șïŒŒæ‰€æœ‰ć­çȘ—ćŁæ˜Ÿç€șćœšçˆ¶çȘ—揣侩靱

  2. ćȘèƒœć…„ćŒŸçȘ—ćŁé—Žćˆ‡æąçȘ—ćŁïŒŒć…„ćŒŸçȘ—ćŁæœ‰ć †ć ć±‚æŹĄă€‚è‹„ćˆ‡æąçš„çȘ—ćŁæ‰€ćœšçš„éĄ¶ć±‚çȘ—ćŁäžćœšéĄ¶ć±‚æ˜Ÿç€șïŒŒćˆ™æ¶‰ćŠéĄ¶ć±‚çȘ—ćŁé—Žçš„ćˆ‡æą

  3. 父çȘ—ćŁäœżç”šćˆ—èĄšçźĄç†ć­çȘ—ćŁćŠć…¶ć †ć ć±‚æŹĄïŒŒæŽ’ćœšćˆ—èĄšć‰çš„ć­çȘ—ćŁæ˜Ÿç€șćœšäžŠć±‚ïŒŒäčŸćłæ˜ŻæŽ’ćœšć‰çš„ć­çȘ—ćŁćŻèƒœäŒšéźæŒĄæŽ’ćœšćŽçš„ć­çȘ—ćŁă€‚

ä»„ć †ć ć±‚æŹĄćˆ‡æąäžșäŸ‹ă€‚X11 serveræ”¶ćˆ°ConfigureWindowäž­CWStackModeèŻ·æ±‚ïŒŒX11 serverćŻčçȘ—ćŁæ ‘èż›èĄŒé‡æŽ’ă€‚

  • 曎新çȘ—ćŁæ ‘ç»“æž„ïŒšçĄźćźšpWinäœçœźćč¶æ›Žæ–°ć­çȘ—ćŁćˆ—èĄšïŒˆMoveWindowInStack

  • èŻ†ćˆ«é‡ç»˜ćŒșćŸŸïŒšçˆ¶çȘ—ćŁćŽŸćŻè§ćŒș柟clipListïŒŒćŒ…ć«èŸčæĄ†ćŒș柟boardClipçȘ—ćŁç§»ćŠšæ—¶ïŒŒćœ±ć“çš„ćŻç»˜ćˆ¶ćŒșćŸŸïŒŒèż™äș›ćŒșćŸŸé™ćˆ¶ćœšçˆ¶çȘ—ćŁçš„winSizećŒșćŸŸć†…ă€‚ïŒˆMoveWindowInStack

  • èźĄçź—ć­çȘ—ćŁçš„é‡ç»˜ćŒșćŸŸïŒšæŒ‰ç…§æ·±ćșŠäŒ˜ć…ˆéĄșćșèźĄçź—歐çȘ—ćŁçš„é‡ç»˜ćŒșćŸŸïŒŒç”Ÿæˆexposed撌borderExposedćŒș柟 miMarkOverlappedWindows / miValidateTree

  • é‡ç»˜ć„ć­çȘ—ćŁçš„exposed撌borderExposedćŒșćŸŸïŒšćœšserver端绘戶çȘ—揣èŸčæĄ†ć’ŒèƒŒæ™ŻïŒŒć‘é€Exposeäș‹ä»¶ç”±client绘戶çȘ—ćŁć†…ćźčmiHandleValidateExposures

1// pWinäžș移抚的çȘ—ćŁïŒŒpSibäžșpWinç§»ćŠšćœšèŻ„çȘ—揣äč‹äžŠă€‚è‹„pSibäžșç©șïŒŒćˆ™pWinçȘ—ćŁćœšæœ€äžŠć±‚ 2static void ReflectStackChange(WindowPtr pWin, WindowPtr pSib, VTKind kind){ 3    Bool WasViewable = (Bool) pWin->viewable; 4    Bool anyMarked; 5    WindowPtr pFirstChange; 6    WindowPtr pLayerWin; 7    ScreenPtr pScreen = pWin->drawable.pScreen; 8    if (!pWin->parent) 9        return; // if this is a root window, can't be restacked 10    // pWinäžș移抚çȘ—ćŁïŒŒpSibäžșç©șpWinçœźćș•ïŒ›è‹„pWin例侀äžȘ盞邻çȘ—揣äžșpSibïŒŒæ ˆć±‚æŹĄæœȘć˜ïŒŒćˆ™ä»€äčˆéƒœäžćš 11    // pFirstChangeïŒšèĄšç€ș第侀äžȘèą«æšŽéœČ的çȘ—揣 12    // pWinć‘äž‹ç§»ïŒŒćˆ™pFirstChangeäžșpWin盞邻的䞋䞀äžȘçȘ—ćŁă€‚pWin侎pSibäž­é—Žæœ‰ć…„ćŒŸçȘ—ćŁïŒŒćœ“pWin朹pSib侊æ–čæ—¶ïŒŒéœ€äž‹ç§»ă€‚ 13    // pWinć‘äžŠç§»ïŒŒćˆ™pFirstChangeäžșpWinæœŹèș« 14    pFirstChange = MoveWindowInStack(pWin, pSib); 15    if (WasViewable) { 16        // miMarkOverlappedWindowsïŒŒæ ‡èź°äžŽpWinçȘ—ćŁé‡ć çš„ć…„ćŒŸçȘ—ćŁćŠć…¶ć­çȘ—ćŁæ‰€ćœšäœçœźïŒŒèż™äș›çȘ—ćŁćŻèƒœéœ€èŠé‡ç»˜ 17        // è‹„pFirstChangeäžșpWinçȘ—ćŁäžŠç§»ïŒ‰ïŒŒćˆ™æ ‡èź°pWinćŠć…¶ć­çȘ—ćŁïŒŒćŒæ—¶æ ‡èź°äžŽpWinçȘ—ćŁïŒˆćŒ…æ‹ŹèŸčæĄ†ïŒ‰é‡ć çš„ć…„ćŒŸçȘ—ćŁä»„ćŠć…¶ć­çȘ—揣 18        // è‹„pFirstChange䞍äžșpWinçȘ—ćŁäž‹ç§»ïŒ‰ïŒŒæ ‡èź°äžŽpWinçȘ—ćŁé‡ć çš„ć…„ćŒŸçȘ—ćŁä»„ćŠć…¶ć­çȘ—揣 19        anyMarked = (*pScreen->MarkOverlappedWindows) (pWin, pFirstChange, &pLayerWin); 20        // pLayerWin戝構挖äžșpWinïŒŒäžæž…æ„šèż™é‡Œäžș什äčˆèŠćˆ€æ–­ 21        if (pLayerWin != pWin) 22            pFirstChange = pLayerWin; 23        if (anyMarked) { 24            // 有çȘ—ćŁé‡ć ă€‚è‹„无çȘ—ćŁćˆ™äžéœ€é‡ç»˜ïŒŒäżźæ”čçȘ—ćŁæ ‘ç»“æž„ćłćŻă€‚æ­€ćœșæ™Żćż…æœ‰é‡ć ïŒŒpWinçȘ—ćŁäžŽć…¶ć­çȘ—ćŁé‡ć ă€‚ 25            // miValidateTreeïŒŒèźĄçź—çˆ¶çȘ—ćŁä»„ćŠæ‰€æœ‰ć­çȘ—ćŁçš„ćŻć‰Ș掄ćŒșćŸŸïŒˆboarderClip撌clipListïŒ‰ïŒŒä»„ćŠexposed撌borderExposedćŒș柟 26            (*pScreen->ValidateTree) (pLayerWin->parent, pFirstChange, kind); 27            // miHandleValidateExposures深ćșŠäŒ˜ć…ˆïŒŒć…ˆç»˜ćˆ¶èŸčæĄ†ïŒŒć†ç»˜ćˆ¶exposedćŒșćŸŸçš„èƒŒæ™ŻïŒŒç„¶ćŽć‘é€Exposeäș‹ä»¶ç»™ćźąæˆ·ç«Żç»˜ćˆ¶ 28            // èŸčæĄ†ć’ŒèƒŒæ™Żçš„ç»˜ćˆ¶ćœšserverç«ŻćźŒæˆïŒŒexposedćŒș柟的憅ćźčé€šèż‡ć‘é€Exposeäș‹ä»¶ç”±clientć‘è”·ç»˜ćˆ¶ćźŒæˆ 29            (*pScreen->HandleExposures) (pLayerWin->parent); 30            // äž€èˆŹäžșç©șćȘæœ‰ćœ“è§†éą‘çȘ—ćŁæ—¶ïŒŒxvæ‰©ć±•æ‰éœ€ć€„ç† 31            if (pWin->drawable.pScreen->PostValidateTree) 32                (*pScreen->PostValidateTree) (pLayerWin->parent, pFirstChange, kind); 33        } 34    } 35    if (pWin->realized) 36        // 怄理焊ç‚čć’Œć…‰æ ‡ 37        WindowsRestructured(); 38}

çȘ—ćŁæ ˆçźĄç†

waylandćŻčçȘ—ćŁæ ˆçźĄç†ćˆ†äžș组groupïŒ‰ïŒŒć±‚ïŒˆlayer栈stack由MetaStack撌MetaWindow缡理漞现。MetaStack怄理3äžȘäżĄć·äș‹ä»¶ïŒš"changed", "window-added", "window-removed"ïŒŒèż™3äžȘäș‹ä»¶éƒœæ¶‰ćŠçȘ—ćŁæ ˆçš„æ›Žæ–°ă€‚

组

äž€èˆŹæ„èŻŽïŒŒéĄ¶ć±‚çȘ—ćŁäœœäžșç»„é•żïŒŒäžŽć­ć­™çȘ—ćŁćˆ†äžș䞀组。clientćŻé€šèż‡EWMHæŒ‡ćźšçȘ—揣äžșç‰č柚的组(WindowGroupHint)ă€‚äž€èˆŹćȘ有X11çȘ—ćŁæœ‰èŻ„ć±žæ€§ă€‚MetaWindow::groupäżć­˜ç»„ć…łçł»

1struct _MetaGroup { 2  int refcount; 3  MetaX11Display *x11_display; 4  GSList *windows;       // çȘ—ćŁćˆ—èĄš 5  Window group_leader;  // 组长 6  char *startup_id; 7  char *wm_client_machine; 8};

求

Waylandæ čæźçȘ—ćŁç±»ćž‹æ„ćˆ’ćˆ†ć±‚çš„ïŒŒćŻčćș”ć…łçł»ćŠ‚äž‹ïŒŒMetaWindow::layer保歘çȘ—ćŁć±‚æŹĄć…łçł»ă€‚ćœšæŸäžȘçȘ—ćŁç»„äž­çš„çȘ—ćŁæ„èŻŽïŒŒä»„ć…¶çȘ—ćŁç»„äž­ć±‚æŹĄæœ€ć€§çš„ć±‚ćˆ’ćˆ†ă€‚ç”±MetaStackLayer漚äč‰ă€‚WaylandçȘ—揣ćȘ有META_LAYER_NORMAL、META_LAYER_TOP撌META_LAYER_BOTTOM 3ç§ç±»ćž‹

layer

enum

window type

description

META_LAYER_DESKTOP

0

META_WINDOW_DESKTOP

æĄŒéąć±‚

META_LAYER_BOTTOM

1

wm_state_below

ćș•ć±‚ïŒŒç”±ćźąæˆ·ćș”甚皋ćșäœżç”šEWMHæŒ‡ćźšçȘ—揣äžș wm_state_below_NET_WM_STATE_BELOW

META_LAYER_NORMAL

2

META_WINDOW_NORMAL or other

䞭闎求

META_LAYER_TOP

4

wm_state_above and not maximized

éĄ¶ć±‚ïŒŒćŻç”±ćźąæˆ·ćș”甚皋ćșäœżç”šEWMHæŒ‡ćźšçȘ—揣äžș wm_state_above_NET_WM_STATE_ABOVE

META_LAYER_DOCK

4

META_WINDOW_DOCK and not wm_state_below

ćœé ć±‚ïŒŒäžŽéĄ¶ć±‚ćŒć±‚

META_LAYER_OVERRIDE_REDIRECT

7

META_WINDOW_DROPDOWN_MENU

META_WINDOW_POPUP_MENU

META_WINDOW_TOOLTIP

META_WINDOW_NOTIFICATION

META_WINDOW_COMBO

META_WINDOW_OVERRIDE_OTHER

é‡èœœé‡ćźšć‘ć±‚ïŒŒäž€èˆŹäžșçŠæ­ąçȘ—ćŁçźĄç†ć™šçźĄç†çš„çȘ—ćŁïŒŒæ˜Ÿç€șćœšæœ€äžŠć±‚

栈

Waylandäœżç”šMetaStackçźĄç†æ‰€æœ‰çš„MetaWindowçȘ—ćŁïŒŒwaylandçȘ—ćŁç”±MetaWindowWaylandèĄšç€șxwaylandçȘ—ćŁç”±MetaWindowXwaylandèĄšç€șïŒŒć‡äžșMetaWindowæŽŸç”Ÿç±»ă€‚MetaWindow::stack_positionèź°ćœ•çȘ—ćŁćœšMetaStackäž­çš„äœçœźïŒŒè¶Šć€§è¶Šæ˜Ÿç€șćœšäžŠć±‚ïŒŒćŽç»­æ“äœœć‡æŒ‰èŻ„æ ˆćșć€„理。çȘ—ćŁçš„ć±‚æŹĄćˆ‡æąćŽïŒŒäčŸéœ€äżæŒç›žćŻčäœçœźă€‚

äœżç”šćŠ‚äž‹äž€äžȘć‡œæ•°æ„ćąžćŠ ć’Œćˆ é™€çȘ—ćŁïŒš

  1. meta_stack_add汞抠çȘ—ćŁïŒšćˆć§‹ćŒ–çȘ—ćŁçš„stack_positionć€ŒïŒŒäžșćˆ—èĄšć€§ć°ïŒŒć‘é€"window-added"ćŒæ­„äżĄć·ă€‚æ–°ćąžçȘ—ćŁéƒœæ˜Ÿç€șćœšæœ€äžŠéąă€‚ćȘèƒœćąžćŠ ćŻć †ć çȘ—ćŁïŒŒć€„ç†ćźŒæˆćŽć†ć‘é€"changed"ćŒæ­„äżĄć·

    1. meta_window_x11_is_stackable非override redirectçȘ—揣

    2. meta_window_wayland_is_stackableïŒšćŻæ˜Ÿç€șçȘ—ćŁïŒŒMetaWaylandBuffer䞍äžșç©ș

  2. meta_stack_removećˆ é™€çȘ—ćŁïŒšć‘é€"window-removed"ćŒæ­„äżĄć·ïŒŒä»Žæ ˆäž­ćˆ é™€çȘ—ćŁïŒŒć€„ç†ćźŒæˆćŽć†ć‘é€"changed"ćŒæ­„äżĄć·

MetaStack操ćș””changedâ€äżĄć·ïŒŒäżĄć·ć€„ç†ć‡œæ•°äžșon_stack_changed重新ćŻčwayland撌X11的饶求çȘ—ćŁć †æ ˆæŽ’ćșă€‚

æłšïŒšäœżç”šMetaX11Stack缡理X11çȘ—ćŁæ ˆć€‡ä»œïŒŒäžșXIDćˆ—èĄšă€‚MetaX11Stack操ćș”èż™äž‰äžȘäżĄć·ïŒŒć“ćș”ć‡œæ•°ćœšsrc/x11/meta-x11-stack.c文件䞭

  •  "window-added"stack_window_added_cb氆window抠慄x11_stack->addedäžŽæ—¶ćˆ—èĄšäž­

  • "window-removed"stack_window_removed_cb氆window抠慄x11_stack->removedäžŽæ—¶ćˆ—èĄšïŒŒwindowçš„éĄ”æĄ†çȘ—揣äčŸćŠ ć…„äžŽæ—¶éĄ”èĄšäž­

  • "changed": stack_changed_cb

    • 怄理added撌removed䞀äžȘäžŽæ—¶ćˆ—èĄšïŒŒæ•Žç†è‡łx11_stack->xwindowsćˆ—èĄšäž­

    • 调甚XChangePropertyćŒæ­„"_NET_CLIENT_LIST"撌"_NET_CLIENT_LIST_STACKING"䞀äžȘæ čçȘ—ćŁçš„EWMHć±žæ€§ïŒŒć‰è€…ć€Œäžșxwindowćˆ—èĄšïŒŒćŽè€…ć€Œäžș从MetaStackäž­èż‡æ»€ć‡ș杄的X11çȘ—ćŁæ ˆ

1struct _MetaStack{ 2  GObject parent; 3  MetaDisplay *display;  // The MetaDisplay containing this stack. 4  GList *sorted;         // The MetaWindows of the windows we manage, sorted in order. 5  6  // If this is zero, the local stack oughtn't to be brought up to date with the X server's stack, because it is in the middle of being updated. 7  // If it is positive, the local stack is said to be "frozen", and will need to be thawed that many times before the stack can be brought up to date again. 8  // You may freeze the stack with meta_stack_freeze() and thaw it with meta_stack_thaw(). 9  int freeze_count;    // èźĄæ•°ćŻćźžçŽ°ć”Œć„—freeze  10  11  // The last-known stack of all windows, bottom to top.  We cache it here so that subsequent times we'll be able to do incremental moves. 12  GArray *last_all_root_children_stacked; 13  gint n_positions; // Number of stack positions; same as the length of added, but kept for quick reference. 14  15  unsigned int need_resort : 1;    // Is the stack in need of re-sorting? 16  unsigned int need_relayer : 1;   // Are the windows in the stack in need of having their layers recalculated? 17  unsigned int need_constrain : 1; // Are the windows in the stack in need of having their positions recalculated with respect to transiency (parent and child windows)? 18}; 19  20// çȘ—ćŁæŽ’ćșéœ€è€ƒè™‘çȘ—ćŁçš„ć±‚æŹĄïŒŒçȘ—ćŁæ˜Ÿç€ș的çșŠæŸç­‰ïŒŒć…ˆæŒ‰ć±‚æŹĄæŽ’ćșïŒŒć†æŒ‰äœçœźæŽ’ćșă€‚ 21static void stack_ensure_sorted (MetaStack *stack) { 22  // ćŻčstack侭的çȘ—ćŁćˆ†ć±‚ïŒŒè‹„ć±‚æŹĄæœ‰ć˜ćŒ–ïŒŒćˆ™éœ€é‡æ–°èźĄçź—çȘ—揣çșŠæŸć’Œé‡æ–°æŽ’ćșă€‚çȘ—ćŁçš„ć±‚æŹĄäžșçȘ—ćŁç»„äž­çš„æœ€é«˜ć±‚æŹĄ 23  stack_do_relayer (stack); 24  // çžŹæ€çȘ—ćŁéĄ»ćœšæŒ‡ćźšçȘ—揣äč‹äžŠïŒˆMetaWindow::transient_foræŒ‡ćźšçȘ—ćŁæˆ–è€…æ‰€ćœšçȘ—ćŁç»„çš„æ‰€æœ‰çȘ—ćŁïŒ‰ïŒŒć…¶ćźƒç±»ćž‹çȘ—ćŁæ— æ­€çșŠæŸ 25  stack_do_constrain (stack); 26  // 重新排ćșïŒŒć…ˆæŒ‰ć±‚ïŒŒć†æŒ‰äœçœźă€‚é‡æŽ’ćźŒæˆćŽïŒŒć»¶ćŽè°ƒç”šcheck_fullscreen_funcć€„ç†ć…šć±çȘ—揣 27  stack_do_resort (stack); 28} 29  30// 䞎时çȘ—ćŁç±»ćž‹ïŒˆçžŹæ€çȘ—ćŁïŒ‰ 31gboolean meta_window_has_transient_type (MetaWindow *window) 32{ 33  return (window->type == META_WINDOW_DIALOG || 34          window->type == META_WINDOW_MODAL_DIALOG || 35          window->type == META_WINDOW_TOOLBAR || 36          window->type == META_WINDOW_MENU || 37          window->type == META_WINDOW_UTILITY); 38}

ć †è·ŸèžȘ晹

MetaStackTracker跟èžȘ所有çȘ—ćŁïŒŒćŒ…æ‹ŹunmanagingçȘ—ćŁă€‚çȘ—ćŁç”šçȘ—揣IDèĄšç€șX11çȘ—揣äžș32䜍IDWaylandçȘ—揣IDäžș64äœïŒŒć…¶ć€Œéƒœć€§äșŽ(1<<32)。WaylandçȘ—ćŁçš„ćșćˆ—ć·äžș0。

unmanagingçȘ—ćŁïŒšthe window of withdrawn, destroyed, attaches, detaches, or changes attached parents.

1struct _MetaStackTracker { 2  MetaDisplay *display; 3  gulong xserver_serial;   // This is the serial of the last request we made that was reflected in xserver_stack 4  GArray *verified_stack; // A combined stack containing X and Wayland windows but without any unverified operations applied.    5  // This is a queue of requests we've made to change the stacking order, where we haven't yet gotten a reply back from the server. 6  GQueue *unverified_predictions; // Wayland serveräżźæ”čäș†X11çȘ—ćŁçš„é…çœźïŒŒć‘é€XConfigureWindowèŻ·æ±‚èŻ„X11 serverïŒŒäœ†èż˜æœȘæ”¶ćˆ°X11 serverçš„ć›žć€ 7  8  // This is how we think the stack is, based on verified_stack, and on the unverified_predictions we've made subsequent to verified_stack. 9  GArray *predicted_stack;  // æ“äœœć’Œæ›Žæ–°æ ˆæ—¶ïŒŒMetaWindowçȘ—ćŁæ ˆçš„äž€äžȘäžŽæ—¶ćˆ—èĄš 10  11  // Idle function used to sync the compositor's view of the window stack up with our best guess before a frame is drawn. 12  guint sync_stack_later; 13};
  • 调甚stack_tracker_apply_predictionäŒšć°†window抠慄unverifiedćˆ—èĄšäž­ïŒŒäž€èˆŹæœ‰4äžȘ操䜜record_add, record_remove, raise_above, lower_below。

  • 调甚stack_tracker_event_received氆unverifiedćˆ—èĄšäž­çš„çȘ—ćŁćŠ ć…„verifiedćˆ—èĄšäž­ïŒŒè°ƒç”šèŻ„ć‡œæ•°çš„æœ‰3ç§æƒ…ć†”ïŒŒWaylandæ”¶ćˆ°X11的äș‹ä»¶é€šçŸ„æ—¶ïŒŒć…±3äžȘ通矄CreateNotify, ReparentNotify撌ConfigureNotifyă€‚ïŒˆX11çȘ—ćŁçš„ćșćˆ—ć·äž€èˆŹäžșć€„ç†æ—¶ç”Ÿæˆçš„é€’ćąžćșć·ïŒŒç”šæ„èĄšç€ș时ćșïŒ‰

çȘ—ćŁćˆ‡æą

wayland serverćœšćŻćŠšæ—¶æłšć†Œäș†çȘ—ćŁćˆ‡æąćż«æ·é”źïŒŒćœšinit_builtin_key_bindingsć‡œæ•°äž­ç»‘ćźšäș†é»˜èź€çš„ćż«æ·é”źïŒŒćŒ…ć«â€œswitch-windows”撌“switch-windows-backward”䞀äžȘäș‹ä»¶ïŒŒç”±handle_switchć‡œæ•°ćźžçŽ°ïŒŒèŻ„ć‡œæ•°ćŻć“ćș”怚äžȘäș‹ä»¶ïŒŒèż˜ćŒ…æ‹ŹçȘ—ćŁç»„ćˆ‡æąïŒŒćș”甚皋ćșćˆ‡æąïŒŒéąæżćˆ‡æąç­‰ïŒŒćˆ†ćˆ«äžș"switch-group", "switch-applications", "switch-windows", "switch-panels"ç­‰æ­Łć‘ćˆ‡æąäș‹ä»¶ïŒŒéƒœćŻčćș”æœ‰ćć‘ćˆ‡æąçš„äș‹ä»¶ă€‚æœŹæŹĄćȘæèż°çȘ—ćŁæ­Łć‘ćˆ‡æąæ”çš‹ă€‚

1// src/core/keybindings.c 2static void handle_switch (MetaDisplay *display, MetaWindow *event_window, ClutterKeyEvent *event, MetaKeyBinding  *binding, gpointer dummy) { 3  gboolean backwards = meta_key_binding_is_reversed (binding); 4  // backwards = false; 5  do_choose_window (display, event_window, event, binding, backwards); 6} 7  8static void do_choose_window (MetaDisplay *display, MetaWindow *event_window, ClutterKeyEvent *event, MetaKeyBinding  *binding, gboolean backward){ 9  MetaWorkspaceManager *workspace_manager = display->workspace_manager; 10  // type = META_TAB_LIST_NORMAL 11  MetaTabList type = binding->handler->data; 12  // èŽ·ć–ćœ“ć‰ç„Šç‚čçȘ—ćŁçš„äž‹äž€äžȘçȘ—揣 13  MetaWindow *window = meta_display_get_tab_next (display, type, workspace_manager->active_workspace, NULL, backward); 14  15  // æż€æŽ»èŻ„çȘ—揣 16  if (window) 17    meta_window_activate (window, event->time); 18}
  1. meta_display_get_tab_nextïŒšä»Žć·„äœœć°äž­èŽ·ć–ćˆ‡æąçȘ—揣

  2. meta_window_activateïŒšæż€æŽ»ćˆ‡æąçȘ—揣

    1. meta_window_raiseïŒšć°†ćˆ‡æąçȘ—ćŁæ”ŸçœźćœšéĄ¶ć±‚ïŒŒæ›Žæ–°MetaStackçȘ—ćŁæ ˆéĄșćșïŒŒćŒæ­„è‡łMetaStackTrackerçȘ—揣éĄșćș

      1. meta_window_set_stack_position_no_syncïŒšç§»ćŠšćˆ‡æąçȘ—ćŁïŒŒæ›Žæ–°MetaStackçȘ—ćŁæ ˆéĄșćș

      2. meta_stack_changedïŒšćŒæ­„tracker、compositor撌X11 serveræ ˆäżĄæŻ

        1. 调敎MetaStackTracerçȘ—ćŁæ ˆéĄșćș

        2. 揑送XConfigureWindow给X11 Serveräżźæ”čserveräžŠæ ˆäżĄæŻïŒŒæ čæźäżĄæŻè°ƒæ•Žæ ˆäœçœźïŒŒæ›Žæ–°çȘ—ćŁæ˜Ÿç€ș

        3. ćŒæ­„compositor的çȘ—ćŁæ ˆïŒŒćłMetaWindowActor栈

      3. meta_stack_update_window_tile_matches调敎çȘ—揣ćčłé“șäœçœź

    2. meta_window_focusçȘ—ćŁèŽ·ć–ç„Šç‚čïŒŒćŒ…æ‹Źé”źç›˜èŸ“ć…„ç„Šç‚čć’Œć…‰æ ‡

      1. 星ç€șçȘ—ćŁïŒŒćŒ…æ‹Źéšè—çȘ—ćŁïŒŒçŹŹäž€æŹĄæ˜Ÿç€ș的çȘ—ćŁïŒŒæœȘæ”ŸçœźçȘ—ćŁć’Œć›Ÿæ ‡çȘ—揣

      2. 揑送SetInputFocusèŻ·æ±‚ç»™X11 serverïŒŒćŒæ­„X11 server的焩ç‚čäżĄæŻïŒŒç”±X11 Server怄理焊ç‚č

      3. ć…łè”èŸ“ć…„èźŸć€‡äžŽćˆ‡æąçȘ—揣

èŽ·ć–çȘ—揣

æœ‰ć‡ äžȘ朰æ–č绎技äș†çȘ—ćŁćˆ—èĄšïŒŒ

  • MetaWindow绎技䞀类çȘ—ćŁćˆ—èĄšïŒŒäž€ç±»äžș掟生WaylandçȘ—ćŁćˆ—èĄšïŒˆwayland_windowsïŒ‰ïŒ›ćŠäž€ç±»äžșX11ćŻčćș”çš„WaylandçȘ—ćŁćˆ—èĄšïŒˆx11_display->xids

  • MetaWorkspace绎技mru_listçȘ—ćŁćˆ—èĄšïŒŒć±žäșŽèŻ„ć·„äœœć°äž­çš„çȘ—ćŁćˆ—èĄšïŒŒæŒ‰ç…§MRUmost recently used排ćșïŒŒæœ€èż‘èźżé—źçš„çȘ—ćŁæŽ’ćœšć‰éą

从X11撌wayland serveräž­æ‰Ÿćˆ°æ‰€æœ‰ćœšworkspace侭的MetaWindowçȘ—ćŁă€‚

  1. èŽ·ć–æ‰€æœ‰çȘ—ćŁćˆ—èĄšïŒšä»ŽMetaDisplayäž­èŽ·ć–æ‰€æœ‰çš„X11撌WaylandçȘ—ćŁïŒˆäžćŒ…æ‹Źoverride redirectçȘ—ćŁïŒ‰

  2. 戝構挖怙选çȘ—ćŁćˆ—èĄšïŒšèŽ·ć–ć·„äœœć°ïŒˆworkspaceïŒ‰äž­ç±»ćž‹äžșMETA_TAB_LIST_NORMAL的çȘ—ćŁćˆ—èĄšïŒŒéžæœ€ć°ćŒ–çȘ—ćŁćœšć‰ïŒŒæœ€ć°ćŒ–çȘ—ćŁćœšćŽïŒŒæŻç»„ćˆ—èĄšäżćșïŒˆMRUćșïŒ‰ïŒŒæ‹ŒæŽ„成䞀äžȘé“ŸèĄš

  3. ć‘ć‰èżœćŠ çŠ¶æ€äžșdemands_attention的çȘ—ćŁć€Œć€™é€‰çȘ—ćŁćˆ—èĄšäž­ïŒšèŻ„状态çȘ—ćŁäžćœšć·„äœœć°äž­ïŒŒç±»ćž‹äžșMETA_TAB_LIST_NORMALïŒŒéœ€èŠéąć€–èżœćŠ 

  4. 怙选çȘ—ćŁćˆ—èĄšäž­çŹŹäž€äžȘ非焩ç‚čçȘ—ćŁïŒŒćłäžș怙选çȘ—揣

æłšïŒšèŽ·ć–æ‰€æœ‰çȘ—ćŁćˆ—èĄšæ—¶ïŒŒćˆ—èĄšćč¶æœȘ按照MRU排ćșïŒŒćœšèżœćŠ demands_attentionçȘ—ćŁæ—¶ïŒŒçȘ—ćŁćˆ›ć»șè¶ŠèżŸè¶ŠäŒ˜ć…ˆă€‚

1// MetaDisplay (src/core/display.c) 2// ćȘ戗ć‡șäžŠäž‹æ–‡ç›žć…łä»Łç ïŒŒć…¶äœ™èą«ćˆ é™€ă€‚type = META_TAB_LIST_NORMAL; window = NULL; backward = false; 3MetaWindow* meta_display_get_tab_next (MetaDisplay *display, MetaTabList type, MetaWorkspace *workspace, MetaWindow *window, gboolean backward){ 4 gboolean skip; 5 GList *tab_list; 6 MetaWindow *ret; 7 // tab_listäž­äžștype=META_TAB_LIST_NORMAL的çȘ—ćŁćˆ—èĄšïŒŒèż™äș›çȘ—ćŁć‡ćœšworkspaceäž­ 8 tab_list = meta_display_get_tab_list (display, type, workspace); 9 if (tab_list == NULL) 10 return NULL; 11 12 // tab_list侭的第侀äžȘäžș焩ç‚čçȘ—ćŁïŒŒćˆ™è·łèż‡èŻ„çȘ—揣 13 skip = display->focus_window != NULL && tab_list->data == display->focus_window; 14 // ć…ˆä»Žtab_listäž­æ‰Ÿćˆ°çŹŹäž€äžȘ类枋äžșMETA_TAB_LIST_NORMAL的çȘ—ćŁïŒŒè‹„æœȘæ‰Ÿćˆ°ïŒŒćˆ™ä»Žworkspace->mru_list䞭柄扟 15 ret = find_tab_forward (display, type, workspace, tab_list, skip); 16 g_list_free (tab_list); 17 return ret; 18} 19 20GList* meta_display_get_tab_list (MetaDisplay *display, MetaTabList type, MetaWorkspace *workspace){ 21 GList *tab_list = NULL; 22 GList *mru_list, *tmp; 23 // x11_display->xidsèź°ćœ•äș†æ‰€æœ‰äžŽX11çȘ—揣ćŻčćș”çš„MetaWindowçȘ—ćŁç”±_meta_window_shared_newć‡œæ•°è°ƒç”šmeta_window_x11_manage戛ć»șćč¶æłšć†Œ 24 // èŽ·ć–display->x11_display撌display->wayland_windows所有的X11撌WaylandçȘ—ćŁïŒˆäžćŒ…æ‹Źoverride redirectçȘ—ćŁïŒ‰ïŒŒćŽ»é‡çš„çȘ—ćŁćˆ—èĄš 25 GSList *windows = meta_display_list_windows (display, META_LIST_DEFAULT); 26 GSList *w; 27 mru_list = workspace->mru_list; 28 29 // Windows sellout mode - MRU order. Collect unminimized windows then minimized so minimized windows aren't in the way so much. 30 // ć·„äœœć°äž­çš„META_TAB_LIST_NORMAL的çȘ—ćŁćˆ—èĄšïŒŒć…ˆćŠ ć…„éžæœ€ć°ćŒ–çȘ—ćŁïŒŒç„¶ćŽć†ćŠ ć…„æœ€ć°ćŒ–çȘ—揣 31 for (tmp = mru_list; tmp; tmp = tmp->next){ 32 MetaWindow *window = tmp->data; 33 if (!window->minimized && IN_TAB_CHAIN (window, type)) 34 tab_list = g_list_prepend (tab_list, window); 35 } 36 for (tmp = mru_list; tmp; tmp = tmp->next){ 37 MetaWindow *window = tmp->data; 38 if (window->minimized && IN_TAB_CHAIN (window, type)) 39 tab_list = g_list_prepend (tab_list, window); 40 } 41 // éžæœ€ć°ćŒ–çȘ—ćŁæ”Ÿćœšć‰éąïŒŒæœ€ć°ćŒ–çȘ—ćŁæ”ŸćœšćŽéąïŒŒæŻç»„æŒ‰mrućˆ—èĄšéĄșćșæŽ’ćˆ— 42 tab_list = g_list_reverse (tab_list); 43 44 // If filtering by workspace, include windows from other workspaces that demand attention 45 if (workspace) 46 for (w = windows; w; w = w->next){ 47 MetaWindow *l_window = w->data; 48 // äžćœšæ­€ć·„äœœć°äž­çš„ç±»ćž‹äžșMETA_TAB_LIST_NORMAL的çȘ—ćŁïŒŒäž”æ ‡èź°wm_state_demands_attentionïŒˆèą«ç„Šç‚čçȘ—ćŁéźæŒĄæ—¶äŒšèźŸçœźèŻ„ć€ŒïŒ‰ 49 if (l_window->wm_state_demands_attention && !meta_window_located_on_workspace (l_window, workspace) && IN_TAB_CHAIN (l_window, type)) 50 tab_list = g_list_prepend (tab_list, l_window); 51 } 52 g_slist_free (windows); 53 return tab_list; 54}

æż€æŽ»çȘ—揣

æ čæźçȘ—ćŁç±»ćž‹ćˆ†ćˆ«ć€„ç†:

  • æ™źé€šçȘ—ćŁïŒŒć°†èŻ„çȘ—ćŁćˆ‡æąè‡łć·„äœœć°ïŒŒćč¶ćœšéĄ¶ć±‚星ç€ș

  • 慷怇transient_forć±žæ€§çš„çȘ—ćŁïŒŒć°†èŻ„çȘ—ćŁäž­è„±çŠ»çˆ¶ć­ć…łçł»çš„çȘ—ćŁéƒœćˆ‡æąè‡łćŒäž€äžȘć·„äœœć°äž­ïŒŒć…ˆć°†äžŽèŻ„çȘ—ćŁè„±çŠ»ć…łçł»çš„ç„–ć…ˆçȘ—ćŁæ˜Ÿç€șćœšéĄ¶ć±‚ïŒŒć†ć°†èŻ„çȘ—ćŁæ˜Ÿç€șćœšéĄ¶ć±‚

  • shaded或minimizedçȘ—ćŁïŒŒéœ€èŠć…ˆćšunshade或unminimize

meta_window_activate

1void meta_window_activate (MetaWindow *window, guint32 timestamp){ 2  // We're not really a pager, but the behavior we want is the same as if we were such. 3  // If we change the pager behavior later, we could revisit this and just add extra flags to window_activate. 4  meta_window_activate_full (window, timestamp, META_CLIENT_TYPE_PAGER, NULL); 5} 6  7// æż€æŽ»çȘ—ćŁä»„ćŠäžŽèŻ„çȘ—ćŁç›žć…łçš„transient_forć±žæ€§çš„çȘ—揣 8void meta_window_activate_full (MetaWindow *window, guint32 timestamp, MetaClientType  source_indication, MetaWorkspace  *workspace){ 9  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager; 10  // timestampäžș0èĄšç€ș最新äș‹ä»¶ïŒŒé»˜èź€ć–ćœ“ć‰æ—¶é—ŽæˆłïŒŒæŻ”ä»»äœ•çȘ—ćŁçš„user_timeæ—¶é—Žæˆłæ–° 11  gboolean allow_workspace_switch = (timestamp != 0); 12  if (timestamp != 0 && XSERVER_TIME_IS_BEFORE (timestamp, window->display->last_user_time)){ 13    // clienté€šèż‡ç±»ćž‹äžș_NET_ACTIVE_WINDOW的atomèŻ·æ±‚ïŒŒæ›Žæ–°äș†display的äș€äș’æ—¶é—ŽïŒŒæŻ”èŻ„äș‹ä»¶èŠæ–°ïŒŒćˆ™ćȘèźŸçœźwindow的wm_state_demands_attentionäžșçœŸïŒŒäž‹æŹĄć†ć€„ç† 14    meta_window_set_demands_attention(window); 15    return; 16  } 17  18  // èŽ·ć–æœ€æ–°æ—¶é—Žæˆł 19  if (timestamp == 0) 20    timestamp = meta_display_get_current_time_roundtrip (window->display); 21  // 曎新çȘ—ćŁçš„net_wm_user_timeïŒŒä»„ćŠdisplay->last_user_time 22  meta_window_set_user_time (window, timestamp); 23  /* disable show desktop mode unless we're a desktop component */ 24  maybe_leave_show_desktop_mode (window); 25  26  // For non-transient windows, we just set up a pulsing indicator, rather than move windows or workspaces. See http://bugzilla.gnome.org/show_bug.cgi?id=482354 27  if (window->transient_for == NULL && !allow_workspace_switch && !meta_window_located_on_workspace (window, workspace)){ 28    // äžćœšć·„äœœć°äž­ïŒŒäž”äș‹ä»¶æ—¶é—Žæˆłäžș0çš„æ™źé€šçȘ—揣 29    meta_window_set_demands_attention (window); 30    return; 31  } 32  else if (window->transient_for != NULL) { 33      /* Move transients to current workspace - preference dialogs should appear over the source window.  */ 34      // 3ç±»çȘ—ćŁéœ€ćˆ‡æąè‡łèŻ„ć·„äœœć°ïŒŒæœ‰ćŻèƒœćˆ‡æąäžæˆćŠŸïŒŒć…¶äž­äž€ç±»æ˜Żç”±äșŽtransient_forć±žæ€§è„±çŠ»çš„ć…łçł»çš„çȘ—ćŁïŒŒç„–ć…ˆć’Œć­ć­™çȘ—揣 35      // 1. è‡Șèș«çȘ—揣 36      // 2. 氆transient_foré€’ćœ’æŒ‡ć‘èŻ„çȘ—ćŁçš„æ‰€æœ‰çȘ—ćŁïŒŒćłèŻ„çȘ—ćŁçš„ć­ć­™çȘ—揣 37      // 3. èŻ„çȘ—ćŁçš„transient_foræŒ‡ć‘çš„çȘ—ćŁïŒŒä»„揊transient_foré€’ćœ’æŒ‡ć‘çš„ç„–ć…ˆçȘ—ćŁă€‚äčŸć°±æ˜ŻèŻ„çȘ—ćŁçš„ç„–ć…ˆçȘ—揣 38      meta_window_change_workspace (window, workspace); 39    } 40  // ć–æ¶ˆçȘ—ćŁçš„é˜Žćœ±ïŒŒclientèźŸçœźèŻ„çȘ—揣äžșé˜Žćœ±ïŒŒćœ“æż€æŽ»æ—¶ïŒŒéœ€ć–æ¶ˆć…¶é˜Žćœ±çȘ—揣 41  if (window->shaded) 42    meta_window_unshade (window, timestamp); 43  // æąć€çȘ—ćŁæ˜Ÿç€șïŒŒä»„ćŠè„±çŠ»ć…łçł»çš„ç„–ć…ˆçȘ—ćŁïŒŒèŻ„çȘ—ćŁçš„transient_foræŒ‡ć‘çš„çȘ—揣 44  unminimize_window_and_all_transient_parents (window); 45  46  // 氆çȘ—ćŁæ˜Ÿç€șćœšæœ€äžŠéąïŒŒćœšæ­€äžŠäž‹æ–‡äž‹ïŒŒæĄä»¶äžș真曎新compositoractor的çȘ—ćŁæ ˆéĄșćș 47  if (meta_prefs_get_raise_on_click () || source_indication == META_CLIENT_TYPE_PAGER) 48    meta_window_raise (window); 49  // çȘ—ćŁćœšæ­€ć·„äœœć°äž­ïŒŒćˆ™èŽ·ć–ç„Šç‚čïŒŒäžćœšèŻ„ć·„äœœć°äž­ïŒŒćˆ™ćˆ‡æąè‡łçȘ—ćŁæ‰€ćœšć·„äœœć°ïŒŒćč¶äœżçȘ—ćŁèŽ·ćŸ—ç„Šç‚č 50  if (meta_window_located_on_workspace (window, workspace)) 51    meta_window_focus (window, timestamp); 52  else 53    meta_workspace_activate_with_focus (window->workspace, window, timestamp); 54  // 揑送侀äžȘpingèŻ·æ±‚ïŒŒæŁ€æ”‹clientæ˜ŻćŠæœ‰ć“ćș”ïŒŒćˆ™ćŒčć‡ș慳闭ćŻčèŻæĄ† 55  meta_window_check_alive (window, timestamp); 56}

meta_window_raise

星ç€șçȘ—ćŁïŒŒćŻčäșŽæ™źé€šçȘ—揣ćȘ星ç€șè‡Șèș«çȘ—ćŁïŒŒćŻčäșŽć…·æœ‰transient_forć±žæ€§çš„çȘ—ćŁïŒŒć…ˆæ˜Ÿç€șç„–ć…ˆçȘ—ćŁïŒŒć†æ˜Ÿç€șè‡Șèș«çȘ—揣

1void meta_window_raise (MetaWindow *window){ 2 MetaWindow *ancestor; 3 // èŽ·ć–ć…·æœ‰transient_forć±žæ€§çȘ—ćŁçš„ç„–ć…ˆïŒ›è‹„æ— æ­€ć±žæ€§ïŒŒćˆ™ç„–ć…ˆäžșè‡Șèș«çȘ—揣 4 ancestor = meta_window_find_root_ancestor (window); 5 // ç„–ć…ˆć’Œè‡Șèș«çȘ—ćŁäžćœšćŒäž€çȘ—ćŁæ ˆäž­ïŒŒćˆ™äž€ćźšć‡șäș†ä»€äčˆć·źé”™ 6 if (window->display->stack == ancestor->display->stack) { 7 meta_stack_raise (window->display->stack, ancestor); 8 } 9 // 慷怇transient_forć±žæ€§çš„çȘ—ćŁïŒŒć°†èŻ„çȘ—ćŁćœšéĄ¶ć±‚æ˜Ÿç€ș 10 if (window != ancestor) 11 meta_stack_raise (window->display->stack, window); 12 // ćŒæ­„äżĄć·ïŒŒè§Šć‘è°ƒç”šwindow_raised(src/wayland/meta-wayland-pointer-constraints.c) 13 g_signal_emit (window, window_signals[RAISED], 0); 14} 15 16void meta_stack_raise (MetaStack *stack, MetaWindow *window) 17{ 18 MetaWorkspaceManager *workspace_manager = window->display->workspace_manager; 19 GList *l; 20 int max_stack_position = window->stack_position; 21 MetaWorkspace *workspace; 22 // 硼保window朹stack䞭有ćșïŒŒć…ˆćˆ†ć±‚ïŒŒć†æŽ’ćș 23 stack_ensure_sorted (stack); 24 25 // èźĄçź—ć·„äœœć°äž­æœ€éĄ¶ć±‚windowçš„äœçœźïŒŒstack_positionè¶Šć€§ïŒŒè¶Šé èż‘éĄ¶ć±‚ 26 workspace = meta_window_get_workspace (window); 27 for (l = stack->sorted; l; l = l->next){ 28 MetaWindow *w = (MetaWindow *) l->data; 29 if (meta_window_located_on_workspace (w, workspace) && w->stack_position > max_stack_position) 30 max_stack_position = w->stack_position; 31 } 32 33 // çȘ—揣ć·ČćœšèŻ„ć·„äœœć°çš„éĄ¶ć±‚ïŒŒćˆ™äžć€„ç† 34 if (max_stack_position == window->stack_position) 35 return; 36 37 // äœçœźćœš[window->stack_position, max_stack_position]的çȘ—揣stack_positionè°ƒæ•Žć˜ćŒ–1äžȘäœçœźïŒŒæ›Žæ–°window的stack_positionäžșmax_stack_position。 38 meta_window_set_stack_position_no_sync (window, max_stack_position); 39 // ćŻčMetaStack重排ćșïŒŒćč¶ć‘送䞀äžȘ"changed"ćŒæ­„äżĄć·ïŒŒè°ƒç”šMetaStack的on_stack_changedć‡œæ•°(src/core/stack.c) 40 meta_stack_changed (stack); 41 // çȘ—揣ćčłé“șäœçœźæ›Žæ–° 42 meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace); 43}

on_stack_changed

1// MetaStack (src/core/stack.c) 2static void on_stack_changed (MetaStack *stack) { 3 MetaDisplay *display = stack->display; 4 GList *l; 5 GArray *all_root_children_stacked = g_array_new (FALSE, FALSE, sizeof (uint64_t)); 6 GArray *hidden_stack_ids = g_array_new (FALSE, FALSE, sizeof (uint64_t)); 7 // èŽ·ć–MetaStack䞭的所有çȘ—ćŁćˆ—èĄšïŒŒéĄșćșäžŽMetaStackç›žćïŒŒćłé˜Ÿć°ŸçȘ—ćŁæ˜Ÿç€șćœšæœ€éĄ¶ć±‚ 8 GList *sorted = meta_stack_list_windows (stack, NULL); 9 // ćˆ†ćˆ«èŽ·ć–æ‰€æœ‰ćŻæ˜Ÿç€ș的歐çȘ—ćŁć’Œéšè—çȘ—ćŁćˆ—èĄš 10 for (l = sorted; l; l = l->next) { 11 MetaWindow *w = l->data; 12 uint64_t top_level_window; 13 uint64_t stack_id; 14 if (w->unmanaging) 15 continue; 16 // X11的饶求çȘ—ćŁïŒŒè‹„æœ‰éĄ”æĄ†çȘ—ćŁïŒŒćˆ™ć°†éĄ”æĄ†çȘ—ćŁäœœäžș饶求çȘ—ćŁă€‚ 17 if (w->frame) 18 top_level_window = w->frame->xwindow; 19 else 20 top_level_window = w->xwindow; 21 if (w->client_type == META_WINDOW_CLIENT_TYPE_X11) 22 stack_id = top_level_window; 23 else 24 stack_id = w->stamp; 25 26 // We don't restack hidden windows along with the rest, though they are reflected in the _NET hints. 27 // Hidden windows all get pushed below the screens fullscreen guard_window. 28 if (w->hidden){ 29 g_array_append_val (hidden_stack_ids, stack_id); 30 continue; 31 } 32 g_array_append_val (all_root_children_stacked, stack_id); 33 } 34 35 if (display->x11_display) { 36 // The screen guard window sits above all hidden windows and acts as a barrier to input reaching these windows. 37 uint64_t guard_window_id = display->x11_display->guard_window; 38 g_array_append_val (hidden_stack_ids, guard_window_id); 39 } 40 41 /* Sync to server */ 42 meta_stack_tracker_restack_managed (display->stack_tracker, (uint64_t *)all_root_children_stacked->data, all_root_children_stacked->len); 43 // ć°†éšè—çȘ—ćŁæ”Ÿćœšćș•ć±‚ 44 meta_stack_tracker_restack_at_bottom (display->stack_tracker, (uint64_t *)hidden_stack_ids->data, hidden_stack_ids->len); 45 46 g_array_free (hidden_stack_ids, TRUE); 47 g_array_free (all_root_children_stacked, TRUE); 48 g_list_free (sorted); 49}

meta_stack_tracker_restack_managed

1// managedäžș饶求çȘ—ćŁæœ‰ćșćˆ—èĄšïŒŒé˜Ÿć°ŸçȘ—ćŁæ˜Ÿç€șćœšæœ€éĄ¶ć±‚ă€‚ 2// 曎新MetaStackTrackeräž­çȘ—ćŁćˆ—èĄšćșćˆ—ćč¶ć°†æ›Žæ–°ćŒæ­„è‡łX11 serverćč¶ćŻćŠšMETA_LATER_SYNC_STACKć»¶æ—¶è°ƒç”šstack_tracker_sync_stack_laterïŒŒèŻ„ć‡œæ•°ç”šäșŽćŒæ­„compositor的çȘ—ćŁæ ˆ 3void meta_stack_tracker_restack_managed (MetaStackTracker *tracker, const guint64 *managed, int n_managed){ 4  guint64 *windows; 5  int n_windows; 6  int old_pos, new_pos; 7  if (n_managed == 0) 8    return; 9  // èŽ·ć–tracker侭的çȘ—ćŁćˆ—èĄšïŒŒäžș有ćșćˆ—èĄšïŒŒé˜Ÿć°Ÿçš„çȘ—ćŁæ˜Ÿç€șćœšæœ€éĄ¶ć±‚ 10  meta_stack_tracker_get_stack (tracker, &windows, &n_windows); 11  // If the top window has to be restacked, we don't want to move it to the very top of the stack, 12  // since apps expect override-redirect windows to stay near the top of the X stack; 13  // we instead move it above all managed windows (or above the guard window if there are no non-hidden managed windows.) 14  old_pos = n_windows - 1; 15  // è·łèż‡tracker侭侍歘朹的çȘ—ćŁïŒŒæ‰Ÿćˆ°çŹŹäž€äžȘ饶çș§çȘ—ćŁæˆ–è€…guardçȘ—ćŁïŒŒéĄ¶çș§çȘ—揣äžșćŻæ˜Ÿç€ș的非override redirectçȘ—ćŁïŒ›guardçȘ—揣äžșćŻæ˜Ÿç€șçȘ—ćŁäžŽéžæ˜Ÿç€șçȘ—ćŁçš„ćˆ†ç•Œçșż 16  for (old_pos = n_windows - 1; old_pos >= 0; old_pos--) { 17    MetaWindow *old_window = meta_display_lookup_stack_id (tracker->display, windows[old_pos]); 18    if ((old_window && !old_window->override_redirect && !old_window->unmanaging) || meta_stack_tracker_is_guard_window (tracker, windows[old_pos])) 19      break; 20  } 21  22  new_pos = n_managed - 1; 23  if (managed[new_pos] != windows[old_pos]){ 24    // Move the first managed window in the new stack above all managed windows 25    // 曎新MetaStackTracerïŒŒć°†newçȘ—ćŁç§»è‡łoldçȘ—ćŁäœçœźïŒŒć…¶ćźƒçȘ—揣ćŻčćș”ç§»äž€äœă€‚ćŻčäșŽX11çȘ—ćŁïŒŒć‘é€XConfigureWindowè‡łX11 serverćŒæ­„çȘ—ćŁć ć±‚ă€‚ 26   meta_stack_tracker_raise_above (tracker, managed[new_pos], windows[old_pos]); 27    // é‡æ–°èŽ·ć–windows曎新äș†window朹traceräž­çš„äœçœź 28    meta_stack_tracker_get_stack (tracker, &windows, &n_windows); 29  } 30  old_pos--; 31  new_pos--; 32  33  while (old_pos >= 0 && new_pos >= 0) { 34    if (meta_stack_tracker_is_guard_window (tracker, windows[old_pos])) 35      break; 36    // çȘ—ćŁçš„ç›žćŻčäœçœźæœȘć˜ïŒŒćˆ™è·łèż‡ 37    if (windows[old_pos] == managed[new_pos]){ 38      old_pos--; 39      new_pos--; 40      continue; 41    } 42    // window侍朹tracker䞭或者äžșoverride_redirect撌unmanagingçȘ—ćŁïŒŒćˆ™è·łèż‡ă€‚managedäž­äžć­˜ćœšèż™äș›çȘ—揣 43    MetaWindow *old_window = meta_display_lookup_stack_id (tracker->display, windows[old_pos]); 44    if (!old_window || old_window->override_redirect || old_window->unmanaging){ 45       old_pos--; 46       continue; 47    } 48    // 曎新MetaStackTracerïŒŒć°†new_posçȘ—ćŁç§»è‡łnew_pos+1çȘ—ćŁćŽéąïŒŒć…¶ćźƒçȘ—揣ćŻčćș”ç§»äž€äœă€‚ćŻčäșŽX11çȘ—ćŁïŒŒć‘é€XConfigureWindowè‡łX11 serverćŒæ­„çȘ—ćŁć ć±‚ă€‚ 49   meta_stack_tracker_lower_below (tracker, managed[new_pos], managed[new_pos + 1]); 50    meta_stack_tracker_get_stack (tracker, &windows, &n_windows); 51    // Moving managed[new_pos] above windows[old_pos] moves the window at old_pos down by one, we'll examine it again to see if it matches the next new window 52    old_pos--; 53    new_pos--; 54  } 55  while (new_pos > 0) { 56      meta_stack_tracker_lower_below (tracker, managed[new_pos], managed[new_pos - 1]); 57      new_pos--; 58    } 59} 60  61// 氆windowç§»è‡łsiblingäœçœźïŒŒć…¶ćźƒçȘ—ćŁç›žćș”移䞀䜍类䌌äșŽALT+TAB锼的çȘ—ćŁćˆ‡æąïŒŒäž‹ć±‚çȘ—ćŁç§»è‡łæœ€ć‰éą 62static void meta_stack_tracker_raise_above (MetaStackTracker *tracker, guint64 window, guint64 sibling) { 63  gulong serial = 0; 64  MetaX11Display *x11_display = tracker->display->x11_display; 65  if (META_STACK_ID_IS_X11 (window)) { 66    // 搑X11 serverćŒæ­„çȘ—ćŁć †ć ć±‚æŹĄèŻ·æ±‚ïŒŒç”±X11 serverć€„ç†èŻ„èŻ·æ±‚ 67    XWindowChanges changes; 68    changes.sibling = sibling ? find_x11_sibling_downwards (tracker, sibling) : None; 69    if (changes.sibling != find_x11_sibling_downwards (tracker, window)){ 70      serial = XNextRequest (x11_display->xdisplay); 71      meta_x11_error_trap_push (x11_display); 72      changes.stack_mode = changes.sibling ? Above : Below; 73      XConfigureWindow (x11_display->xdisplay, (Window)window, (changes.sibling ? CWSibling : 0) | CWStackMode, &changes); 74      meta_x11_error_trap_pop (x11_display); 75    } 76  } 77  // 曎新MetaStackTracer的çȘ—ćŁćˆ—èĄš 78  meta_stack_tracker_record_raise_above (tracker, window, sibling, serial); 79} 80  81static void meta_stack_tracker_record_raise_above (MetaStackTracker *tracker, guint64 window, guint64 sibling, gulong serial){ 82  MetaStackOp *op = g_new0 (MetaStackOp, 1); 83  op->any.type = STACK_OP_RAISE_ABOVE; 84  op->any.serial = serial; 85  op->any.window = window; 86  op->raise_above.sibling = sibling; 87  stack_tracker_apply_prediction (tracker, op); 88} 89  90static void stack_tracker_apply_prediction (MetaStackTracker *tracker, MetaStackOp *op) { 91  gboolean free_at_end = FALSE; 92  // If this operation doesn't involve restacking X windows then it's implicitly verified. 93  // We can apply it immediately unless there are outstanding X restacks that haven't yet been confirmed. 94  if (op->any.serial == 0 && tracker->unverified_predictions->length == 0) { 95    if (meta_stack_op_apply (tracker, op, tracker->verified_stack, APPLY_DEFAULT)) 96      meta_stack_tracker_queue_sync_stack (tracker); 97    free_at_end = TRUE; 98  } 99  else { 100    g_queue_push_tail (tracker->unverified_predictions, op); 101  } 102  // 搯抹MetaLater甚äșŽć»¶ćŽć€„理compositor的çȘ—ćŁæ ˆćŒæ­„stack_tracker_sync_stack_later 103  if (!tracker->predicted_stack || meta_stack_op_apply (tracker, op, tracker->predicted_stack, APPLY_DEFAULT)) 104    meta_stack_tracker_queue_sync_stack (tracker); 105  if (free_at_end) 106    meta_stack_op_free (op); 107} 108  109void meta_stack_tracker_queue_sync_stack (MetaStackTracker *tracker){ 110  if (tracker->sync_stack_later == 0) { 111    tracker->sync_stack_later = meta_later_add (META_LATER_SYNC_STACK, stack_tracker_sync_stack_later, tracker, NULL); 112  } 113}

stack_tracker_sync_stack_later

1static gboolean stack_tracker_sync_stack_later (gpointer data){ 2  meta_stack_tracker_sync_stack (data); 3  return FALSE; 4} 5  6void meta_stack_tracker_sync_stack (MetaStackTracker *tracker){ 7  guint64 *windows; 8  GList *meta_windows; 9  int n_windows; 10  int i; 11  12  if (tracker->sync_stack_later) { 13    meta_later_remove (tracker->sync_stack_later); 14    tracker->sync_stack_later = 0; 15  } 16  // 氆override redirect求的çȘ—ćŁæćˆ°æœ€äžŠć±‚ïŒŒæœ‰ćŻèƒœæ›Žæ–°MetaStackTracker的çȘ—ćŁæ ˆïŒŒćœąæˆćŸȘçŽŻè°ƒç”š 17  meta_stack_tracker_keep_override_redirect_on_top (tracker); 18  meta_stack_tracker_get_stack (tracker, &windows, &n_windows); 19  meta_windows = NULL; 20  for (i = 0; i < n_windows; i++){ 21    guint64 window = windows[i]; 22    if (META_STACK_ID_IS_X11 (window)){ 23      MetaX11Display *x11_display = tracker->display->x11_display; 24      MetaWindow *meta_window = NULL; 25  26      if (x11_display) 27         meta_window = meta_x11_display_lookup_x_window (x11_display, (Window) window); 28       // When mapping back from xwindow to MetaWindow we have to be a bit careful; 29       // children of the root could include unmapped windows created by toolkits for internal purposes, including ones that we have registered in our XID => window table. 30       // (Wine uses a toplevel for _NET_WM_USER_TIME_WINDOW; see window-prop.c:reload_net_wm_user_time_window() for registration.) 31       if (meta_window && ((Window)window == meta_window->xwindow || (meta_window->frame && (Window)window == meta_window->frame->xwindow))) 32         meta_windows = g_list_prepend (meta_windows, meta_window); 33    } 34    else 35      meta_windows = g_list_prepend (meta_windows, meta_display_lookup_stamp (tracker->display, window)); 36  } 37  // ćŒæ­„compositor的çȘ—ćŁæ ˆïŒŒćłMetaWindowActor栈 38  meta_compositor_sync_stack (tracker->display->compositor, meta_windows); 39  g_list_free (meta_windows); 40  meta_display_restacked (tracker->display); 41} 42  43void meta_compositor_sync_stack (MetaCompositor  *compositor, GList *stack){ 44  MetaCompositorPrivate *priv = meta_compositor_get_instance_private (compositor); 45  GList *old_stack; 46  // This is painful because hidden windows that we are in the process of animating out of existence. 47  // They'll be at the bottom of the stack of X windows, but we want to leave them in their old position until the animation effect finishes. 48  /* Sources: first window is the highest */ 49  stack = g_list_copy (stack); /* The new stack of MetaWindow */ 50  old_stack = g_list_reverse (priv->windows); /* The old stack of MetaWindowActor */ 51  priv->windows = NULL; 52  while (TRUE){ 53    MetaWindowActor *old_actor = NULL, *stack_actor = NULL, *actor; 54    MetaWindow *old_window = NULL, *stack_window = NULL, *window; 55  56    // Find the remaining top actor in our existing stack (ignoring windows that have been hidden and are no longer animating) 57    while (old_stack) { 58      old_actor = old_stack->data; 59      old_window = meta_window_actor_get_meta_window (old_actor); 60      if ((old_window->hidden || old_window->unmanaging) && !meta_window_actor_effect_in_progress (old_actor)){ 61        old_stack = g_list_delete_link (old_stack, old_stack); 62        old_actor = NULL; 63      } 64      else 65        break; 66    } 67  68    /* And the remaining top actor in the new stack */ 69    while (stack) { 70      stack_window = stack->data; 71      stack_actor = meta_window_actor_from_window (stack_window); 72      if (!stack_actor) { 73        stack = g_list_delete_link (stack, stack); 74      } 75      else 76        break; 77    } 78    if (!old_actor && !stack_actor) /* Nothing more to stack */ 79      break; 80  81    // We usually prefer the window in the new stack, but if we found a hidden window in the process of being animated out of existence in the old stack we use that instead. 82    // We've filtered out non-animating hidden windows above. 83    if (old_actor && (!stack_actor || old_window->hidden || old_window->unmanaging)){ 84      actor = old_actor; 85      window = old_window; 86    } 87    else{ 88      actor = stack_actor; 89      window = stack_window; 90    } 91  92    // OK, we know what actor we want next. Add it to our window list, and remove it from both source lists. 93    // (It will be at the front of at least one, hopefully it will be near the front of the other.) 94    priv->windows = g_list_prepend (priv->windows, actor); 95    stack = g_list_remove (stack, window); 96    old_stack = g_list_remove (old_stack, actor); 97  } 98  sync_actor_stacking (compositor); 99  update_top_window_actor (compositor); 100} 101  102// æ čæźcompositor的MetaWindowActorćșæ›Žæ–°ClutterActor类枋䞭的çȘ—ćŁæ ˆ 103static void sync_actor_stacking (MetaCompositor *compositor){ 104  MetaCompositorPrivate *priv = meta_compositor_get_instance_private (compositor); 105  GList *children; 106  GList *expected_window_node; 107  GList *tmp; 108  GList *old; 109  GList *backgrounds; 110  gboolean has_windows; 111  gboolean reordered; 112  113  // NB: The first entries in the lists are stacked the lowest 114  // Restacking will trigger full screen redraws, so it's worth a little effort to make sure we actually need to restack before we go ahead and do it 115  children = clutter_actor_get_children (priv->window_group); 116  has_windows = FALSE; 117  reordered = FALSE; 118  // We allow for actors in the window group other than the actors we know about, but it's up to a plugin to try and keep them stacked correctly 119  // First we collect a list of all backgrounds, and check if they're at the bottom. Then we check if the window actors are in the correct sequence 120  backgrounds = NULL; 121  expected_window_node = priv->windows; 122  for (old = children; old != NULL; old = old->next){ 123    ClutterActor *actor = old->data; 124    if (META_IS_BACKGROUND_GROUP (actor) || META_IS_BACKGROUND_ACTOR (actor)){ 125      backgrounds = g_list_prepend (backgrounds, actor); 126      // background actor朹window actorçš„äžŠéąïŒŒćˆ™éœ€èŠé‡æŽ’ 127      if (has_windows) 128        reordered = TRUE; 129    } 130    else if (META_IS_WINDOW_ACTOR (actor) && !reordered){ 131      has_windows = TRUE; 132      // 跟composite的çȘ—揣ćșäž€è‡ŽïŒŒćˆ™äžéœ€èŠé‡æŽ’ïŒŒćŠćˆ™éœ€èŠé‡æŽ’ 133      if (expected_window_node != NULL && actor == expected_window_node->data) 134        expected_window_node = expected_window_node->next; 135      else 136        reordered = TRUE; 137    } 138  } 139  g_list_free (children); 140  if (!reordered){ 141    g_list_free (backgrounds); 142    return; 143  } 144  145  // reorder the actors by lowering them in turn to the bottom of the stack. windows first, then background. 146  // We reorder the actors even if they're not parented to the window group, to allow stacking to work with intermediate actors (eg during effects) 147  for (tmp = g_list_last (priv->windows); tmp != NULL; tmp = tmp->prev){ 148    ClutterActor *actor = tmp->data, *parent; 149    parent = clutter_actor_get_parent (actor); 150    clutter_actor_set_child_below_sibling (parent, actor, NULL); 151  } 152  153  // we prepended the backgrounds above so the last actor in the list should get lowered to the bottom last. 154  for (tmp = backgrounds; tmp != NULL; tmp = tmp->next){ 155    ClutterActor *actor = tmp->data, *parent; 156    parent = clutter_actor_get_parent (actor); 157    clutter_actor_set_child_below_sibling (parent, actor, NULL); 158  } 159  g_list_free (backgrounds); 160}

meta_window_focus

1// meta_window_focus (src/core/window.c) 2void meta_window_focus (MetaWindow *window, guint32 timestamp) { 3 MetaWorkspaceManager *workspace_manager = window->display->workspace_manager; 4 MetaWindow *modal_transient; 5 MetaBackend *backend; 6 ClutterStage *stage; 7 8 window->restore_focus_on_map = FALSE; // This is a oneshot flag 9 if (window->in_workspace_change) { 10 return; 11 } 12 // é”źç›˜èą«ć…¶ćźƒçȘ—ćŁé”ćźšïŒŒæŒ‰é”źäčŸèą«é”ćźšäș†ïŒŒćˆ™çȘ—ćŁæ— æł•èŽ·ćŸ—ç„Šç‚č 13 if (window->display->grab_window && window->display->grab_window != window && 14 window->display->grab_window->all_keys_grabbed && !window->display->grab_window->unmanaging) { 15 return; 16 } 17 // windowçš„æšĄæ€çȘ—ćŁïŒŒćłçȘ—ćŁç±»ćž‹äžșMETA_WINDOW_MODAL_DIALOGtransient_foræŒ‡ć‘window的çȘ—ćŁïŒŒè‹„ć­˜ćœšïŒŒćˆ™ç”±æšĄæ€çȘ—ćŁèŽ·ć–ç„Šç‚č 18 modal_transient = get_modal_transient (window); 19 if (modal_transient != NULL && !modal_transient->unmanaging && meta_window_transient_can_focus (modal_transient)) { 20 if (!meta_window_located_on_workspace (modal_transient, workspace_manager->active_workspace)) 21 meta_window_change_workspace (modal_transient, workspace_manager->active_workspace); 22 window = modal_transient; 23 } 24 // 最终调甚update_window_visibilities星ç€șçȘ—ćŁïŒŒćŻč曛类çȘ—ćŁèż›èĄŒæ˜Ÿç€ș隐藏çȘ—ćŁïŒŒéŠ–æŹĄæ˜Ÿç€șçȘ—ćŁïŒŒæœȘæ”ŸçœźçȘ—ćŁïŒŒć›Ÿæ ‡çȘ—揣 25 meta_window_flush_calc_showing (window); 26 if ((!window->mapped || window->hidden) && !window->shaded) { 27 return; 28 } 29 30 // meta_window_x11_focus for xwayland ïŒšćŒæ­„input focusäș‹ä»¶ç»™X11 server撌Wayland compositor 31 // meta_window_wayland_focus for wayland ïŒšćŒæ­„input focusäș‹ä»¶ç»™Wayland compositor 32 META_WINDOW_GET_CLASS (window)->focus (window, timestamp); 33 34 backend = meta_get_backend (); 35 stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); 36 37 if (window->display->event_route == META_EVENT_ROUTE_NORMAL && clutter_stage_get_grab_actor (stage) == NULL) 38 clutter_stage_set_key_focus (stage, NULL); 39 40 if (window->close_dialog && meta_close_dialog_is_visible (window->close_dialog)) 41 meta_close_dialog_focus (window->close_dialog); 42 43 if (window->wm_state_demands_attention) 44 meta_window_unset_demands_attention(window); 45} 46 47static void meta_window_flush_calc_showing (MetaWindow *window){ 48 MetaWindowPrivate *priv = meta_window_get_instance_private (window); 49 if (!(priv->queued_types & META_QUEUE_CALC_SHOWING)) 50 return; 51 meta_display_flush_queued_window (window->display, window, META_QUEUE_CALC_SHOWING); 52 priv->queued_types &= ~META_QUEUE_CALC_SHOWING; 53} 54 55// meta_window_flush_calc_showing (src/core/window.c) 56void meta_display_flush_queued_window (MetaDisplay *display, MetaWindow *window, MetaQueueType queue_types){ 57 g_autoptr (GList) windows = NULL; 58 int queue_idx; 59 meta_display_unqueue_window (display, window, queue_types); 60 windows = g_list_prepend (windows, window); 61 for (queue_idx = 0; queue_idx < META_N_QUEUE_TYPES; queue_idx++){ 62 if (!(queue_types & 1 << queue_idx)) 63 continue; 64 // META_QUEUE_CALC_SHOWING : update_window_visibilities 65 // META_QUEUE_MOVE_RESIZE : move_resize 66 window_queue_func[queue_idx] (display, windows); 67 } 68}

update_window_visibilities

星ç€ș或隐藏çȘ—揣

1// update_window_visibilities (src/core/display.c) 2static void update_window_visibilities (MetaDisplay *display, GList *windows){ 3 g_autoptr (GList) unplaced = NULL; 4 g_autoptr (GList) should_show = NULL; 5 g_autoptr (GList) should_hide = NULL; 6 GList *l; 7 for (l = windows; l; l = l->next){ 8 MetaWindow *window = l->data; 9 if (!window->placed) 10 unplaced = g_list_prepend (unplaced, window); 11 else if (meta_window_should_be_showing (window)) 12 should_show = g_list_prepend (should_show, window); 13 else 14 should_hide = g_list_prepend (should_hide, window); 15 } 16 /* Sort bottom to top */ 17 unplaced = g_list_sort (unplaced, window_stack_cmp); 18 should_hide = g_list_sort (should_hide, window_stack_cmp); 19 /* Sort top to bottom */ 20 should_show = g_list_sort (should_show, window_stack_cmp); 21 should_show = g_list_reverse (should_show); 22 23 g_list_foreach (unplaced, (GFunc) meta_window_update_visibility, NULL); 24 25 meta_stack_freeze (display->stack); 26 g_list_foreach (should_show, (GFunc) meta_window_update_visibility, NULL); 27 g_list_foreach (should_hide, (GFunc) meta_window_update_visibility, NULL); 28 meta_stack_thaw (display->stack); 29 30 g_list_foreach (windows, (GFunc) meta_window_clear_queued, NULL); 31 32 // on_window_visibility_updated (src/x11/meta-x11-display.c) : XChangeProperty通矄X11曎新"_MUTTER_SENTINEL"ć±žæ€§ïŒŒX11é€šèż‡PropertyNotifyäș‹ä»¶é€šçŸ„XWMïŒŒèż™äžȘæœșćˆ¶ç”šäșŽéżć…ç«žäș‰ 33 // on_window_visibility_updated (src/compositor/compositor.c) : update_top_window_actor 34 g_signal_emit (display, display_signals[WINDOW_VISIBILITY_UPDATED], 0, unplaced, should_show, should_hide); 35 g_list_foreach (windows, (GFunc) warn_on_incorrectly_unmanaged_window, NULL); 36} 37 38void meta_window_update_visibility (MetaWindow *window) { 39 implement_showing (window, meta_window_should_be_showing (window)); 40} 41 42// ćŽ»æŽ‰äș†showing=false的怄理代码 43static void implement_showing (MetaWindow *window, gboolean showing){ 44 /* Some windows are not stackable until being showed, so add those now. */ 45 if (meta_window_is_stackable (window) && !meta_window_is_in_stack (window)) 46 meta_stack_add (window->display->stack, window); 47 // ćȘćŻčæœȘ星ç€ș的çȘ—ćŁèż›èĄŒæ˜Ÿç€șć·Č星ç€șäœ†èą«éƒšćˆ†éźæŒĄçš„çȘ—ćŁäžćšä»»äœ•æ“äœœ 48 meta_window_show (window); 49 50 // meta_window_x11_map (src/x11/window-x11.c) : 揑送XMapWindow给X11 serverïŒŒè‹„æ˜Żć·Čmap的çȘ—ćŁïŒŒäžäŒšć†ć‘é€èŻ·æ±‚ 51 // meta_window_wayland_map (src/wayland/meta-window-wayland.c) : nothing to do. 52 if (!window->override_redirect) 53 sync_client_window_mapped (window); 54}

meta_window_show

meta_window_show䞻芁ćŻč曛类çȘ—ćŁèż›èĄŒæ˜Ÿç€ș最终调甚meta_compositor_show_window星ç€ș

  • 隐藏çȘ—ćŁïŒˆhidden星ç€ș搎的çȘ—ćŁèą«éšè—äș†

  • çŹŹäž€æŹĄæ˜Ÿç€ș的çȘ—ćŁïŒŒçȘ—揣ć·Čmap䜆æœȘ星ç€șèż‡

  • æœȘæ”ŸçœźçȘ—ćŁïŒšä»ŽæœȘèźĄçź—èż‡çȘ—ćŁçš„æ”ŸçœźäœçœźïŒŒäčŸć°±æ˜Żä»ŽæœȘ星ç€șèż‡çš„çȘ—揣

  • ć›Ÿæ ‡çȘ—ćŁïŒšçȘ—揣ć·Čæœ€ć°ćŒ–ïŒŒäœżç”šć›Ÿæ ‡æ˜Ÿç€ș的çȘ—揣

1static void meta_window_show (MetaWindow *window){ 2  gboolean takes_focus_on_map; 3  gboolean place_on_top_on_map; 4  gboolean notify_demands_attention = FALSE; 5  MetaDisplay *display = window->display; 6  MetaWindow *focus_window = window->display->focus_window;  /* May be NULL! */ 7  gboolean did_show = FALSE; 8  gboolean needs_stacking_adjustment = FALSE; 9  // windowæ˜ŻćŠéœ€èŠèŽ·ć–ć…‰æ ‡ïŒŒæ˜ŻćŠéœ€èŠéĄ¶ć±‚æ˜Ÿç€ș 10  window_state_on_map (window, &takes_focus_on_map, &place_on_top_on_map); 11  12  // Now, in some rare cases we should *not* put a new window on top. 13  // These cases include certain types of windows showing for the first time, 14  // and any window which would be covered because of another window being set "above" ("always on top"). 15  16  // FIXME: Although "place_on_top_on_map" and "takes_focus_on_map" are generally based on the window type, 17  // there is a special case when the focus window is a terminal for them both to be false; this should probably rather be a term in the "if" condition below. 18  if (focus_window != NULL && window->showing_for_first_time && ((!place_on_top_on_map && !takes_focus_on_map) || window_would_be_covered (window))) { 19    if (!meta_window_is_ancestor_of_transient (focus_window, window)){ 20      needs_stacking_adjustment = TRUE; 21      if (!window->placed) 22        window->denied_focus_and_not_transient = TRUE; 23    } 24  } 25  if (!window->placed){ 26    if (window->monitor && meta_prefs_get_auto_maximize() && window->showing_for_first_time && window->has_maximize_func){ 27      MetaRectangle work_area; 28      meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area); 29      /* Automaximize windows that map with a size > MAX_UNMAXIMIZED_WINDOW_AREA of the work area */ 30      if (window->rect.width * window->rect.height > work_area.width * work_area.height * MAX_UNMAXIMIZED_WINDOW_AREA){ 31        window->maximize_horizontally_after_placement = TRUE; 32        window->maximize_vertically_after_placement = TRUE; 33      } 34    } 35    meta_window_force_placement (window, FALSE); 36  } 37  if (needs_stacking_adjustment){ 38    // This window isn't getting focus on map.  We may need to do some special handing with it in regards to 39    // the stacking of the window, the MRU position of the window and the demands attention setting of the window. 40  41    // Firstly, set the flag so we don't give the window focus anyway and confuse people. 42   gboolean overlap = windows_overlap (window, focus_window); 43    takes_focus_on_map = FALSE; 44    /* We want alt tab to go to the denied-focus window */ 45    ensure_mru_position_after (window, focus_window); 46  47    // We don't want the denied-focus window to obscure the focus window, 48    // and if we're in both click-to-focus mode and raise-on-click mode then we want to maintain the invariant that MRU order == stacking order. 49    // The need for this if comes from the fact that in sloppy/mouse focus the focus window may not overlap other windows and also can be considered "below" them; 50    // this combination means that placing the denied-focus window "below" the focus window in the stack when it doesn't overlap it confusingly places 51    // that new window below a lot of other windows. 52    if (overlap || (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK && meta_prefs_get_raise_on_click ())) 53      meta_window_stack_just_below (window, focus_window); 54  55    // If the window will be obscured by the focus window, then the user might not notice the window appearing so set the demands attention hint. 56    // We set the hint ourselves rather than calling meta_window_set_demands_attention() because that would cause a recalculation of overlap, 57    // and a call to set_net_wm_state() which we are going to call ourselves here a few lines down. 58    if (overlap && !window->wm_state_demands_attention){ 59      window->wm_state_demands_attention = TRUE; 60      notify_demands_attention = TRUE; 61    } 62  } 63  if (window->hidden){ 64    meta_stack_freeze (window->display->stack); 65    window->hidden = FALSE; 66    meta_stack_thaw (window->display->stack); 67    did_show = TRUE; 68  } 69  if (window->iconic){ 70    window->iconic = FALSE; 71    set_wm_state (window); 72  } 73  if (!window->visible_to_compositor){ 74    MetaCompEffect effect = META_COMP_EFFECT_NONE; 75    window->visible_to_compositor = TRUE; 76    switch (window->pending_compositor_effect){ 77      case META_COMP_EFFECT_CREATE: 78      case META_COMP_EFFECT_UNMINIMIZE: 79        effect = window->pending_compositor_effect; 80        break; 81      case META_COMP_EFFECT_NONE: 82      case META_COMP_EFFECT_DESTROY: 83      case META_COMP_EFFECT_MINIMIZE: 84        break; 85    } 86    meta_compositor_show_window (window->display->compositor, window, effect); 87    window->pending_compositor_effect = META_COMP_EFFECT_NONE; 88  } 89  90  // We don't want to worry about all cases from inside implement_showing(); we only want to worry about focus if this window has not been shown before. 91  if (window->showing_for_first_time){ 92    window->showing_for_first_time = FALSE; 93    if (takes_focus_on_map){ 94      guint32     timestamp; 95      timestamp = meta_display_get_current_time_roundtrip (window->display); 96      meta_window_focus (window, timestamp); 97    } 98    else if (display->x11_display){ 99      // Prevent EnterNotify events in sloppy/mouse focus from erroneously focusing the window that had been denied focus. 100      // FIXME: This introduces a race; I have a couple ideas for a better way to accomplish the same thing, but they're more involved so do it this way for now. 101      meta_x11_display_increment_focus_sentinel (display->x11_display); 102    } 103  } 104  set_net_wm_state (window); 105  if (did_show && window->struts){ 106    invalidate_work_areas (window); 107  } 108  // æłšć†ŒMetaLater(META_LATER_CHECK_FULLSCREEN)ïŒŒć»¶ćŽè°ƒç”šcheck_fullscreen_funcć€„ç†ć…šć± 109  if (did_show) 110    meta_display_queue_check_fullscreen (window->display); 111  112  // we have shown the window, we no longer want to consider the initial timestamp in any subsequent deliberations whether to focus this window or not, so clear the flag. 113  window->initial_timestamp_set = FALSE; 114  115  if (notify_demands_attention){ 116    g_object_notify_by_pspec (G_OBJECT (window), obj_props[PROP_DEMANDS_ATTENTION]); 117    g_signal_emit_by_name (window->display, "window-demands-attention", window); 118  } 119  120  // on_window_shown (src/wayland/meta-window-wayland.c) : 曎新状态 121  if (did_show) 122    g_signal_emit (window, window_signals[SHOWN], 0); 123}

meta_window_x11_focus

1static void meta_window_x11_focus (MetaWindow *window, guint32 timestamp){ 2  MetaWindowX11 *window_x11 = META_WINDOW_X11 (window); 3  MetaWindowX11Private *priv = meta_window_x11_get_instance_private (window_x11); 4  // For output-only or shaded windows, focus the frame. 5  // This seems to result in the client window getting key events though, so I don't know if it's icccm-compliant. 6  7  // Still, we have to do this or keynav breaks for these windows. 8  // meta_window_x11_is_focusable : inputäžșçœŸïŒŒæˆ–è€…äœżç”š"WM_TAKE_FOCUS" atom 9  // meta_window_wayland_is_focusable : inputäžșçœŸïŒŒćŻèŸ“ć…„çš„çȘ—揣 10  if (window->frame && (window->shaded || !meta_window_is_focusable (window))) { 11    meta_display_set_input_focus (window->display, window, TRUE, timestamp); 12  } 13  else { 14    if (window->input) { 15      meta_display_set_input_focus (window->display,  window, FALSE, timestamp); 16    } 17    if (priv->wm_take_focus) { 18      if (!window->input){ 19        // The "Globally Active Input" window case, where the window doesn't want us to call XSetInputFocus on it, but does want us to send a WM_TAKE_FOCUS. 20        // Normally, we want to just leave the focus undisturbed until the window responds to WM_TAKE_FOCUS, 21        // but if we're unmanaging the current focus window we *need* to move the focus away, so we focus the no focus window before sending WM_TAKE_FOCUS, 22        // and eventually the default focus window excluding this one, if meanwhile we don't get any focus request. 23        if (window->display->focus_window != NULL && window->display->focus_window->unmanaging){ 24          meta_display_unset_input_focus (window->display, timestamp); 25          maybe_focus_default_window (window->display, window, timestamp); 26        } 27      } 28      request_take_focus (window, timestamp); 29    } 30  } 31} 32  33void meta_display_set_input_focus (MetaDisplay *display, MetaWindow *window, gboolean focus_frame, guint32 timestamp){ 34  if (meta_display_timestamp_too_old (display, &timestamp)) 35    return; 36  if (display->x11_display){ 37    meta_x11_display_set_input_focus (display->x11_display, window, focus_frame, timestamp); 38  } 39  meta_display_update_focus_window (display, window); 40  display->last_focus_time = timestamp; 41  if (window == NULL || window != display->autoraise_window) 42    meta_display_remove_autoraise_callback (display); 43}
meta_x11_display_set_input_focus
1// 揑送SetInputFocusèŻ·æ±‚ç»™X11 server由X11 server怄理input focusäș‹ä»¶ïŒ›ć‘送ChangePropertyèŻ·æ±‚ïŒŒäżźæ”čæ čçȘ—揣"_NET_ACTIVE_WINDOW"ć±žæ€§ 2void meta_x11_display_set_input_focus (MetaX11Display *x11_display, MetaWindow *window, gboolean focus_frame, uint32_t timestamp){ 3  Window xwindow; 4  gulong serial; 5  if (window) 6    xwindow = focus_frame ? window->frame->xwindow : window->xwindow; 7  else 8    xwindow = x11_display->no_focus_window; 9  10  meta_x11_error_trap_push (x11_display); 11  // 揑送SetInputFocusèŻ·æ±‚ç»™X11 server 12  meta_x11_display_set_input_focus_internal (x11_display, xwindow, timestamp); 13  serial = XNextRequest (x11_display->xdisplay); 14  // äżźæ”čæ čçȘ—揣"_NET_ACTIVE_WINDOW"ć±žæ€§ïŒŒć‘é€ChangePropertyèŻ·æ±‚ 15  meta_x11_display_update_focus_window (x11_display, xwindow, serial, TRUE); 16  meta_x11_error_trap_pop (x11_display); 17} 18  19static void meta_x11_display_set_input_focus_internal (MetaX11Display *x11_display, Window xwindow, uint32_t timestamp){ 20  meta_x11_error_trap_push (x11_display); 21  // In order for mutter to know that the focus request succeeded, we track the serial of the "focus request" we made, but if we take the serial of the XSetInputFocus request, 22  // then there's no way to determine the difference between focus events as a result of the SetInputFocus and focus events that other clients send around the same time. 23  // Ensure that we know which is which by making two requests that the server will process at the same time. 24  XGrabServer (x11_display->xdisplay); 25  // 揑送SetInputFocusèŻ·æ±‚ç»™X11 serverX11怄理SetInputFocusćźžé™…ć·„äœœ 26  XSetInputFocus (x11_display->xdisplay, xwindow, RevertToPointerRoot,timestamp); 27  // 曎æ”čtimestamp_pinging_windowçȘ—ćŁć±žæ€§"_MUTTER_FOCUS_SET"ç±»ćž‹ïŒŒć‘é€ChangePropertyèŻ·æ±‚èŻ„X11 server。 28  XChangeProperty (x11_display->xdisplay, x11_display->timestamp_pinging_window, x11_display->atom__MUTTER_FOCUS_SET, XA_STRING, 8, PropModeAppend, NULL, 0); 29  30  XUngrabServer (x11_display->xdisplay); 31  XFlush (x11_display->xdisplay); 32  meta_x11_error_trap_pop (x11_display); 33} 34  35void meta_x11_display_update_focus_window (MetaX11Display *x11_display, Window xwindow, gulong serial, gboolean focused_by_us){ 36  x11_display->focus_serial = serial; 37  x11_display->focused_by_us = !!focused_by_us; 38  if (x11_display->focus_xwindow == xwindow) 39    return; 40  x11_display->focus_xwindow = xwindow; 41  meta_x11_display_update_active_window_hint (x11_display); 42} 43  44static void meta_x11_display_update_active_window_hint (MetaX11Display *x11_display){ 45  MetaWindow *focus_window; 46  gulong data[1]; 47  if (x11_display->display->closing) 48    return; /* Leave old value for a replacement */ 49  focus_window = meta_x11_display_lookup_x_window (x11_display, x11_display->focus_xwindow); 50  51  if (focus_window) 52    data[0] = focus_window->xwindow; 53  else 54    data[0] = None; 55  56  meta_x11_error_trap_push (x11_display); 57  XChangeProperty (x11_display->xdisplay, x11_display->xroot, x11_display->atom__NET_ACTIVE_WINDOW, XA_WINDOW, 32, PropModeReplace, (guchar*) data, 1); 58  meta_x11_error_trap_pop (x11_display); 59}
meta_display_update_focus_window
1void meta_display_update_focus_window (MetaDisplay *display, MetaWindow *window) 2{ 3 MetaWindow *previous = NULL; 4 if (display->focus_window == window) 5 return; 6 if (display->focus_window){ 7 // Make sure that signals handlers invoked by meta_window_set_focused_internal() don't see display->focus_window->has_focus == FALSE 8 previous = display->focus_window; 9 display->focus_window = NULL; 10 meta_window_set_focused_internal (previous, FALSE); 11 } 12 display->focus_window = window; 13 if (display->focus_window){ 14 meta_window_set_focused_internal (display->focus_window, TRUE); 15 } 16 17 if (!previous || !display->focus_window || !meta_window_unit_cgroup_equal (previous, display->focus_window)){ 18 if (previous) 19 meta_window_set_inactive_since (previous, g_get_monotonic_time ()); 20 if (display->focus_window) 21 meta_window_set_inactive_since (display->focus_window, -1); 22 } 23 24 if (meta_is_wayland_compositor ()) 25 meta_display_sync_wayland_input_focus (display); 26 27 // MetaWindowX11操ćș”èŻ„ć±žæ€§ć˜ćŒ–çš„äș‹ä»¶ïŒŒć€„ç†ć‡œæ•°ïŒšmeta_window_x11_delayed_focus_data_free释攟focus蔄æș 28 g_object_notify (G_OBJECT (display), "focus-window"); 29} 30 31void meta_window_set_focused_internal (MetaWindow *window, gboolean focused){ 32 MetaWorkspaceManager *workspace_manager = window->display->workspace_manager; 33 if (focused) { 34 window->has_focus = TRUE; 35 if (window->override_redirect) 36 return; 37 // Move to the front of the focusing workspace's MRU list. We should only be "removing" it from the MRU list if it's not already there. 38 // Note that it's possible that we might be processing this FocusIn after we've changed to a different workspace; 39 // we should therefore update the MRU list only if the window is actually on the active workspace. 40 if (workspace_manager->active_workspace && meta_window_located_on_workspace (window, workspace_manager->active_workspace)){ 41 GList* link = g_list_find (workspace_manager->active_workspace->mru_list, window); 42 workspace_manager->active_workspace->mru_list = g_list_remove_link (workspace_manager->active_workspace->mru_list, link); 43 g_list_free (link); 44 workspace_manager->active_workspace->mru_list = g_list_prepend (workspace_manager->active_workspace->mru_list, window); 45 } 46 47 if (window->frame) 48 meta_frame_queue_draw (window->frame); 49 50 // Ungrab click to focus button since the sync grab can interfere with some things you might do inside the focused window, 51 // by causing the client to get funky enter/leave events. 52 // The reason we usually have a passive grab on the window is so that we can intercept clicks and raise the window in response. 53 // For click-to-focus we don't need that since the focused window is already raised. 54 // When raise_on_click is FALSE we also don't need that since we don't do anything when the window is clicked. 55 if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK || !meta_prefs_get_raise_on_click()){ 56 meta_display_ungrab_focus_window_button (window->display, window); 57 // Since we ungrab with XIAnyModifier above, all button grabs go way so we need to re-grab the window buttons. 58 meta_display_grab_window_buttons (window->display, window->xwindow); 59 } 60 // 无äșșæłšć†Œ"focus"äżĄć· 61 g_signal_emit (window, window_signals[FOCUS], 0); 62 63 if (!window->attached_focus_window) 64 meta_window_update_appears_focused (window); 65 66 meta_window_propagate_focus_appearance (window, TRUE); 67 } 68 else{ 69 window->has_focus = FALSE; 70 if (window->override_redirect) 71 return; 72 meta_window_propagate_focus_appearance (window, FALSE); 73 if (!window->attached_focus_window) 74 meta_window_update_appears_focused (window); 75 76 if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK || !meta_prefs_get_raise_on_click ()) 77 meta_display_grab_focus_window_button (window->display, window); // Re-grab for click to focus and raise-on-click, if necessary 78 } 79} 80 81void meta_frame_queue_draw (MetaFrame *frame){ 82 meta_ui_frame_queue_draw (frame->ui_frame); 83} 84 85void meta_ui_frame_queue_draw (MetaUIFrame *frame){ 86 invalidate_whole_window (frame); 87} 88 89static void invalidate_whole_window (MetaUIFrame *frame){ 90 if (!frame->is_frozen){ 91 // 调甚meta_window_xwayland_freeze_commitsïŒŒć‘é€ChangePropertyèŻ·æ±‚äżźæ”čframeçȘ—揣"_XWAYLAND_ALLOW_COMMITS"ć±žæ€§ 92 meta_window_x11_freeze_commits (frame->meta_window); 93 frame->is_frozen = TRUE; 94 } 95 gdk_window_invalidate_rect (frame->window, NULL, FALSE); 96} 97 98 99void meta_display_sync_wayland_input_focus (MetaDisplay *display){ 100 MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); 101 MetaWindow *focus_window = NULL; 102 MetaBackend *backend = meta_get_backend (); 103 ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); 104 ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend); 105 MetaStage *stage = META_STAGE (meta_backend_get_stage (backend)); 106 gboolean is_no_focus_xwindow = FALSE; 107 108 if (display->x11_display) 109 is_no_focus_xwindow = meta_x11_display_xwindow_is_a_no_focus_window (display->x11_display, display->x11_display->focus_xwindow); 110 111 if (!meta_display_windows_are_interactable (display)) 112 focus_window = NULL; 113 else if (is_no_focus_xwindow) 114 focus_window = NULL; 115 else if (display->focus_window && display->focus_window->surface) 116 focus_window = display->focus_window; 117 118 meta_stage_set_active (stage, focus_window == NULL); 119 meta_wayland_compositor_set_input_focus (compositor, focus_window); 120 // 重新配ćŻčèŸ“ć…„èźŸć€‡äžŽæ–°çȘ—揣 121 clutter_stage_repick_device (CLUTTER_STAGE (stage), clutter_seat_get_pointer (seat)); 122} 123 124void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor, MetaWindow *window){ 125 MetaWaylandSurface *surface = window ? window->surface : NULL; 126 meta_wayland_seat_set_input_focus (compositor->seat, surface); 127} 128 129void meta_wayland_seat_set_input_focus (MetaWaylandSeat *seat, MetaWaylandSurface *surface){ 130 MetaWaylandTabletSeat *tablet_seat; 131 MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); 132 if (meta_wayland_seat_has_keyboard (seat)){ 133 // 曎新focus蔄æșïŒŒćč¶ć‘client揑送äș‹ä»¶ 134 meta_wayland_keyboard_set_focus (seat->keyboard, surface); 135 meta_wayland_data_device_set_keyboard_focus (&seat->data_device); 136 meta_wayland_data_device_primary_set_keyboard_focus (&seat->primary_data_device); 137 meta_wayland_data_device_primary_legacy_set_keyboard_focus (&seat->primary_legacy_data_device); 138 } 139 140 tablet_seat = meta_wayland_tablet_manager_ensure_seat (compositor->tablet_manager, seat); 141 meta_wayland_tablet_seat_set_pad_focus (tablet_seat, surface); 142 // æ–‡æœŹèŸ“ć…„è”„æșć€„理 143 meta_wayland_text_input_set_focus (seat->text_input, surface); 144} 145 146void meta_wayland_text_input_set_focus (MetaWaylandTextInput *text_input, MetaWaylandSurface *surface){ 147 if (text_input->surface == surface) 148 return; 149 text_input->pending_state = META_WAYLAND_PENDING_STATE_NONE; 150 if (text_input->surface){ 151 if (!wl_list_empty (&text_input->focus_resource_list)){ 152 ClutterInputFocus *focus = text_input->input_focus; 153 ClutterInputMethod *input_method; 154 struct wl_resource *resource; 155 if (clutter_input_focus_is_focused (focus)){ 156 input_method = clutter_backend_get_input_method (clutter_get_default_backend ()); 157 clutter_input_focus_reset (focus); 158 meta_wayland_text_input_focus_flush_done (focus); 159 clutter_input_method_focus_out (input_method); 160 } 161 wl_resource_for_each (resource, &text_input->focus_resource_list){ 162 zwp_text_input_v3_send_leave (resource, text_input->surface->resource); 163 } 164 move_resources (&text_input->resource_list, &text_input->focus_resource_list); 165 } 166 wl_list_remove (&text_input->surface_listener.link); 167 text_input->surface = NULL; 168 } 169 170 if (surface){ 171 struct wl_resource *focus_surface_resource; 172 text_input->surface = surface; 173 focus_surface_resource = text_input->surface->resource; 174 wl_resource_add_destroy_listener (focus_surface_resource, &text_input->surface_listener); 175 176 move_resources_for_client (&text_input->focus_resource_list, &text_input->resource_list, wl_resource_get_client (focus_surface_resource)); 177 if (!wl_list_empty (&text_input->focus_resource_list)) { 178 struct wl_resource *resource; 179 wl_resource_for_each (resource, &text_input->focus_resource_list){ 180 zwp_text_input_v3_send_enter (resource, surface->resource); 181 } 182 } 183 } 184} 185 186void clutter_stage_repick_device (ClutterStage *stage, ClutterInputDevice *device){ 187 graphene_point_t point; 188 clutter_stage_get_device_coords (stage, device, NULL, &point); 189 clutter_stage_pick_and_update_device (stage, device, NULL, CLUTTER_DEVICE_UPDATE_IGNORE_CACHE | CLUTTER_DEVICE_UPDATE_EMIT_CROSSING, point, CLUTTER_CURRENT_TIME); 190} 191 192ClutterActor *clutter_stage_pick_and_update_device (ClutterStage *stage, ClutterInputDevice *device, ClutterEventSequence *sequence, 193 ClutterDeviceUpdateFlags flags, graphene_point_t point, uint32_t time_ms){ 194 ClutterActor *new_actor; 195 cairo_region_t *clear_area = NULL; 196 if ((flags & CLUTTER_DEVICE_UPDATE_IGNORE_CACHE) == 0) { 197 if (clutter_stage_check_in_clear_area (stage, device, sequence, point)){ 198 clutter_stage_set_device_coords (stage, device, sequence, point); 199 return clutter_stage_get_device_actor (stage, device, sequence); 200 } 201 } 202 203 new_actor = _clutter_stage_do_pick (stage, point.x, point.y, CLUTTER_PICK_REACTIVE, &clear_area); 204 clutter_stage_update_device (stage, device, sequence, point, time_ms, new_actor, clear_area, !!(flags & CLUTTER_DEVICE_UPDATE_EMIT_CROSSING)); 205 g_clear_pointer (&clear_area, cairo_region_destroy); 206 return new_actor; 207}