X Windows - Window Swallowing

X Windows "window swallowing" is the process of program 1 capturing the main window of program 2 to display it inside of program 1's main window. For example, Firefox using an external program to display a PDF in a tab. Firefox's built-in javascript PDF viewer leaves a lot to be desired. Slow rendering or no rendering at all, memory hog, with the download button not working when it doesn't render.

The following description is derived from my experience getting MozPlugger to work in Firefox to display PDF files using Evince.


Swallowing Message Flow

X Windows uses messages for communication between programs and the X Server. Messages are queued for each program and read at the programs leisure.

The following diagram shows the programs involved in the process along with their windows.


  • Firefox registers for root window notitications, then starts Evince.
  • Evince creates its main window and asks X Server to display it.
  • X Server passes the display request to Window Manager.
  • Window Manager assumes control of Evinces main window.
  • Firefox requests that Window Manager relinquish control of Evinces main window.
  • Firefox requests control of Evinces main window.
  • Firefox gains control and moves and resizes Evinces main window to fit in a tab.


  • FF -> XSelectInput(wXS, SubstructureNotifyMask)
  • FF -> Exec(EV)
  • EV -> XCreateWindow(wEV) -> XS
  • XS -> CreateNotify\[w?] -> FF
    • FF -> Save w? (Note: FF doesn't know yet which window is wEV)
  • EV -> XMapWindow(wEV) -> XS
  • XS -> MapRequest\[wEV] -> WM
    • WM -> XReparentWindow(wEV, parent: wXS -> wWM) -> XS
    • WM -> XChangeProperty(wEV, WM_STATE = Normal) -> XS
  • XS -> ReparentNotify\[wEV, parent: wXS -> wWM] -> FF
    • FF -> Locate wEV in w?s
    • FF -> XSelectInput(wEV, SubstructureNotifyMask | PropertyChangeMask)
    • FF -> If WM_STATE != Withdrawn: XWithdrawWindow(wEV) -> XS
  • XS -> PropertyNotify\[wEV, WM_STATE = Normal] -> FF (Note: This may not be seen by FF, depending on timing)
    • FF -> If wEV not withdrawn above: XWithdrawWindow(wEV) -> XS
  • XS -> ReparentNotify\[wEV, parent: wWM -> wXS] -> FF
    • FF -> XReparentWindow(wEV, parent: wXS -> wFF) -> XS
  • XS -> ReparentNotify\[wEv, parent: wXS -> wFF] -> FF
    • FF-> XMoveResizeWindow(wEv)


  • Because the messaging system is asynchronous, the PropertyNotify of wEVs WM_STATE change to Normal may come before FF is listening for PropertyNotifiy on wEV. In that case, FF checks wEVs WM_STATE in the initial ReparentNotify.