in src/Avalonia.X11/X11Window.cs [90:274]
public X11Window(AvaloniaX11Platform platform, IWindowImpl? popupParent, X11WindowMode mode,
bool overrideRedirect = false)
{
_platform = platform;
_mode = mode;
_mode.Init(this);
_popup = popupParent != null;
_overrideRedirect = _popup || overrideRedirect;
_x11 = platform.Info;
_mouse = new MouseDevice();
_touch = new TouchDevice();
_keyboard = platform.KeyboardDevice;
var glfeature = AvaloniaLocator.Current.GetService<IPlatformGraphics>();
XSetWindowAttributes attr = new XSetWindowAttributes();
var valueMask = default(SetWindowValuemask);
attr.backing_store = 1;
attr.bit_gravity = Gravity.NorthWestGravity;
attr.win_gravity = Gravity.NorthWestGravity;
valueMask |= SetWindowValuemask.BackPixel | SetWindowValuemask.BorderPixel
| SetWindowValuemask.BackPixmap | SetWindowValuemask.BackingStore
| SetWindowValuemask.BitGravity | SetWindowValuemask.WinGravity;
if (_overrideRedirect)
{
attr.override_redirect = 1;
valueMask |= SetWindowValuemask.OverrideRedirect;
}
XVisualInfo? visualInfo = null;
// OpenGL seems to be do weird things to it's current window which breaks resize sometimes
_useRenderWindow = glfeature != null;
var glx = glfeature as GlxPlatformGraphics;
if (glx != null)
{
visualInfo = *glx.Display.VisualInfo;
// TODO: We should query this from the active render surface, however we don't actually track what
// the target sufrace currently is
_useCompositorDrivenRenderWindowResize = true;
}
else if (glfeature == null)
visualInfo = _x11.TransparentVisualInfo;
var egl = glfeature as EglPlatformGraphics;
var visual = IntPtr.Zero;
var depth = 24;
if (visualInfo != null)
{
visual = visualInfo.Value.visual;
depth = (int)visualInfo.Value.depth;
attr.colormap = XCreateColormap(_x11.Display, _x11.RootWindow, visualInfo.Value.visual, 0);
valueMask |= SetWindowValuemask.ColorMap;
}
int defaultWidth = 0, defaultHeight = 0;
if (!_popup && _platform.Screens != null)
{
var monitor = _platform.Screens.AllScreens.OrderBy(x => x.Scaling)
.FirstOrDefault(m => m.Bounds.Contains(_position ?? default));
if (monitor != null)
{
// Emulate Window 7+'s default window size behavior.
defaultWidth = (int)(monitor.WorkingArea.Width * 0.75d);
defaultHeight = (int)(monitor.WorkingArea.Height * 0.7d);
}
}
// check if the calculated size is zero then compensate to hardcoded resolution
defaultWidth = Math.Max(defaultWidth, 300);
defaultHeight = Math.Max(defaultHeight, 200);
_handle = XCreateWindow(_x11.Display, _x11.RootWindow, 10, 10, defaultWidth, defaultHeight, 0,
depth,
(int)CreateWindowArgs.InputOutput,
visual,
new UIntPtr((uint)valueMask), ref attr);
AppendPid(_handle);
if (_useRenderWindow)
{
_renderHandle = XCreateWindow(_x11.Display, _handle, 0, 0, defaultWidth, defaultHeight, 0, depth,
(int)CreateWindowArgs.InputOutput,
visual,
new UIntPtr((uint)(SetWindowValuemask.BorderPixel | SetWindowValuemask.BitGravity |
SetWindowValuemask.WinGravity | SetWindowValuemask.BackingStore)), ref attr);
}
else
{
_renderHandle = _handle;
}
Handle = new PlatformHandle(_handle, "XID");
_mode.OnHandleCreated(_handle);
_realSize = new PixelSize(defaultWidth, defaultHeight);
platform.Windows[_handle] = OnEvent;
XEventMask ignoredMask = XEventMask.SubstructureRedirectMask
| XEventMask.ResizeRedirectMask
| XEventMask.PointerMotionHintMask;
if (platform.XI2 != null)
ignoredMask |= platform.XI2.AddWindow(_handle, this);
var mask = new IntPtr(0xffffff ^ (int)ignoredMask);
XSelectInput(_x11.Display, _handle, mask);
if (!_overrideRedirect)
{
var protocols = new[]
{
_x11.Atoms.WM_DELETE_WINDOW
};
XSetWMProtocols(_x11.Display, _handle, protocols, protocols.Length);
SetNetWmWindowType(X11NetWmWindowType.Normal);
SetWmClass(_handle, _platform.Options.WmClass);
}
var surfaces = new List<object>
{
new X11FramebufferSurface(_x11.DeferredDisplay, _renderHandle,
depth, _platform.Options.UseRetainedFramebuffer ?? false)
};
if (egl != null)
surfaces.Insert(0,
new EglGlPlatformSurface(new SurfaceInfo(this, _x11.DeferredDisplay, _handle, _renderHandle)));
if (glx != null)
surfaces.Insert(0, new GlxGlPlatformSurface(new SurfaceInfo(this, _x11.DeferredDisplay, _handle, _renderHandle)));
surfaces.Add(new SurfacePlatformHandle(this));
Surfaces = surfaces.ToArray();
UpdateMotifHints();
UpdateSizeHints(null);
_rawEventGrouper = new RawEventGrouper(DispatchInput, platform.EventGrouperDispatchQueue);
_transparencyHelper = new TransparencyHelper(_x11, _handle, platform.Globals);
_transparencyHelper.SetTransparencyRequest(Array.Empty<WindowTransparencyLevel>());
_activationTracker = new(_platform, this);
_activationTracker.ActivationChanged += HandleActivation;
CreateIC();
XFlush(_x11.Display);
if(_popup)
PopupPositioner = new ManagedPopupPositioner(new ManagedPopupPositionerPopupImplHelper(popupParent!, MoveResize));
if (platform.Options.UseDBusMenu)
_nativeMenuExporter = DBusMenuExporter.TryCreateTopLevelNativeMenu(_handle);
_nativeControlHost = new X11NativeControlHost(_platform, this);
InitializeIme();
var data = new List<IntPtr> { _x11.Atoms.WM_DELETE_WINDOW, _x11.Atoms._NET_WM_SYNC_REQUEST };
_mode.AppendWmProtocols(data);
XChangeProperty(_x11.Display, _handle, _x11.Atoms.WM_PROTOCOLS, _x11.Atoms.XA_ATOM, 32,
PropertyMode.Replace, data.ToArray(), data.Count);
if (_x11.HasXSync)
{
_xSyncCounter = XSyncCreateCounter(_x11.Display, _xSyncValue);
XChangeProperty(_x11.Display, _handle, _x11.Atoms._NET_WM_SYNC_REQUEST_COUNTER,
_x11.Atoms.XA_CARDINAL, 32, PropertyMode.Replace, ref _xSyncCounter, 1);
}
_storageProvider = new FallbackStorageProvider(new[]
{
() => _platform.Options.UseDBusFilePicker
? DBusSystemDialog.TryCreateAsync(Handle)
: Task.FromResult<IStorageProvider?>(null),
() => GtkSystemDialog.TryCreate(this),
() => Task.FromResult(InputRoot is TopLevel tl
? (IStorageProvider?)new ManagedStorageProvider(tl)
: null)
});
platform.X11Screens.Changed += OnScreensChanged;
}