<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      X11 使用 XSetWMNormalHints 固定窗口所在的屏幕

      我的需求是雙屏雙窗口,即一個屏幕顯示一個窗口。我的是 KWin 窗口管理器,默認情況下,我的正常窗口會被顯示到鼠標最后一次命中的屏幕上,無論當前在 XCreateWindow 中傳入的 X 和 Y 坐標是多少

      本文的測試是在 UOS 上進行的,系統(tǒng)信息如下

      $ cat /etc/os-release
      PRETTY_NAME="UnionTech OS Desktop 20 E"
      NAME="uos"
      VERSION_ID="20"
      VERSION="20"
      ID=uos
      HOME_URL="https://www.chinauos.com/"
      BUG_REPORT_URL="http://bbs.chinauos.com"
      VERSION_CODENAME=uranus
      
      $ cat /etc/os-version
      [Version]
      SystemName=UnionTech OS Desktop
      SystemName[zh_CN]=統(tǒng)信桌面操作系統(tǒng)
      ProductType=Desktop
      ProductType[zh_CN]=桌面
      EditionName=E
      EditionName[zh_CN]=E
      MajorVersion=20
      MinorVersion=1050
      OsBuild=11068.102
      

      處理器 CPU 信息如下

      $ cat /proc/cpuinfo
      processor       : 0
      vendor_id       : CentaurHauls
      cpu family      : 7
      model           : 59
      model name      : ZHAOXIN KaiXian KX-U6780A@2.7GHz
      ...
      

      在 X 里面,通過 XDisplayWidth 和 XDisplayHeight 拿到的是虛擬屏幕的尺寸,即多個物理屏幕拼接的外接矩形虛擬范圍。我的兩個屏幕排放如下

      可通過以下調(diào)用 XRRGetMonitors 的代碼獲取兩個屏幕的信息

      // Copy from https://github.com/AvaloniaUI/Avalonia \src\Avalonia.X11\Screens\X11Screen.Providers.cs
      
      public class Randr15ScreensImpl
      {
          public Randr15ScreensImpl(nint display, nint rootWindow)
          {
              _display = display;
              var eventWindow = CreateEventWindow(display, rootWindow);
              _window = eventWindow;
      
              XRRSelectInput(display, _window, RandrEventMask.RRScreenChangeNotify);
          }
      
          public unsafe MonitorInfo[] GetMonitorInfos()
          {
              XRRMonitorInfo* monitors = XRRGetMonitors(_display, _window, true, out var count);
              var screens = new MonitorInfo[count];
              for (var c = 0; c < count; c++)
              {
                  var mon = monitors[c];
      
                  var outputs = new nint[mon.NOutput];
      
                  for (int i = 0; i < outputs.Length; i++)
                  {
                      outputs[i] = mon.Outputs[i];
                  }
      
                  screens[c] = new MonitorInfo()
                  {
                      Name = mon.Name,
                      IsPrimary = mon.Primary != 0,
                      X = mon.X,
                      Y = mon.Y,
                      Width = mon.Width,
                      Height = mon.Height,
                      Outputs = outputs,
                      Display = _display,
                  };
              }
      
              return screens;
          }
      
          private readonly IntPtr _display;
      
          private readonly IntPtr _window;
      }
      
      public unsafe struct MonitorInfo
      {
          public IntPtr Name;
          public bool IsPrimary;
          public int X;
          public int Y;
          public int Width;
          public int Height;
          public IntPtr[] Outputs;
          public IntPtr Display { get; init; }
      
          public override string ToString()
          {
              var namePtr = XGetAtomName(Display, Name);
                  var name = Marshal.PtrToStringAnsi(namePtr);
              XFree(namePtr);
      
              return $"{name}({Name}) IsPrimary={IsPrimary} XY={X},{Y} WH={Width},{Height}";
          }
      }
      

      調(diào)用的方法如下

      var randr15ScreensImpl = new Randr15ScreensImpl(display, rootWindow);
      var monitorInfos = randr15ScreensImpl.GetMonitorInfos();
      for (var i = 0; i < monitorInfos.Length; i++)
      {
          Console.WriteLine($"屏幕{i} {monitorInfos[i]}");
      }
      
      var xDisplayWidth = XDisplayWidth(display, screen);
      var xDisplayHeight = XDisplayHeight(display, screen);
      
      Console.WriteLine($"XDisplayWidth={xDisplayWidth}");
      Console.WriteLine($"XDisplayHeight={xDisplayHeight}");
      

      嘗試運行程序,可見控制臺輸出如下

      屏幕0 DisplayPort-1(343) IsPrimary=True XY=1920,309 WH=1920,1080
      屏幕1 DisplayPort-0(626) IsPrimary=False XY=0,0 WH=1920,1080
      XDisplayWidth=3840
      XDisplayHeight=1389
      

      兩個屏幕都是 1920x1080 的,水平擺放,于是 XDisplayWidth 寬度就是 1920+1920=3840 的尺寸。高度因為存在一定的高度差,通過 XY=1920,309 可知道,主屏 DisplayPort-1 低了 309 大小,于是高度為 1080+309=1389 的尺寸。這就意味著 X 的行為上 XDisplayWidth 和 XDisplayHeight 為多個屏幕的外接矩形尺寸

      和 Windows 上不同的是,在 X 上沒有使用主屏當成 0,0 點坐標,意味著不會存在負數(shù)坐標系。在 X 中將最左邊的顯示器屏幕當成 X 坐標的 0 點,將最上方的顯示器屏幕當成 Y 坐標的 0 點。這一點差異會在一些計算中坑到我,預計坑到的時候,我已經(jīng)忘記我寫了這篇博客

      了解了基礎信息,我接下來嘗試為雙屏創(chuàng)建雙窗口。簡單起見,我將固定寫魔數(shù),而不是真的根據(jù)屏幕而來

      我將設置第 1 個窗口,顯示在 0,0 坐標。設置第 2 個窗口,顯示在 1920,0 坐標。預期行為就是第 1 個窗口顯示在副屏 DisplayPort-0 上,第 2 個窗口顯示在主屏 DisplayPort-1 上

      其實現(xiàn)代碼如下

          public TestX11Window(int x, int y, int width, int height, nint display,nint rootWindow,int screen)
          {
              Display = display;
      
              XMatchVisualInfo(display, screen, 32, 4, out var info);
              var visual = info.visual;
      
              var valueMask =
                      //SetWindowValuemask.BackPixmap
                      0
                      | SetWindowValuemask.BackPixel
                      | SetWindowValuemask.BorderPixel
                      | SetWindowValuemask.BitGravity
                      | SetWindowValuemask.WinGravity
                      | SetWindowValuemask.BackingStore
                      | SetWindowValuemask.ColorMap
                  //| SetWindowValuemask.OverrideRedirect
                  ;
              var xSetWindowAttributes = new XSetWindowAttributes
              {
                  backing_store = 1,
                  bit_gravity = Gravity.NorthWestGravity,
                  win_gravity = Gravity.NorthWestGravity,
                  //override_redirect = true, // 設置窗口的override_redirect屬性為True,以避免窗口管理器的干預
                  colormap = XCreateColormap(display, rootWindow, visual, 0),
                  border_pixel = 0,
                  background_pixel = 0,
              };
      
              var handle = XCreateWindow(display, rootWindow, x, y, width, height, 5,
                  32,
                  (int) CreateWindowArgs.InputOutput,
                  visual,
                  (nuint) valueMask, ref xSetWindowAttributes);
      
              // 在 XMapWindow 之前固定在某個屏幕上
              var hints = new XSizeHints
              {
                  min_width = width,
                  min_height = height,
                  max_width = width,
                  max_height = height,
      
                  x = x,
                  y = y,
              };
              var flags = XSizeHintsFlags.PMinSize | XSizeHintsFlags.PResizeInc | XSizeHintsFlags.PPosition | XSizeHintsFlags.USPosition;
              hints.flags = (IntPtr) flags;
              XSetWMNormalHints(display, handle, ref hints);
      
              X11Window = handle;
      
              XEventMask ignoredMask = XEventMask.SubstructureRedirectMask | XEventMask.ResizeRedirectMask |
                                       XEventMask.PointerMotionHintMask;
              var mask = new IntPtr(0xffffff ^ (int) ignoredMask);
              XSelectInput(display, handle, mask);
      
              ...
          }
      

      調(diào)用代碼如下

      var testX11Window1 = new TestX11Window(0, 0, width, height, display, rootWindow, screen);
      
      testX11Window1.MapWindow();
      testX11Window1.Draw();
      
      Console.WriteLine($"X11Window1={testX11Window1.X11Window}");
      
      var testX11Window2 = new TestX11Window(1920, 0, width, height, display, rootWindow, screen);
      testX11Window2.MapWindow();
      testX11Window2.Draw();
      
      Console.WriteLine($"X11Window2={testX11Window2.X11Window}");
      

      以上的核心代碼就是調(diào)用 XSetWMNormalHints 設置進去 XSizeHints 參數(shù)。詳細請參閱 XSetWMProperties

      嘗試通過 XNextEvent 獲取消息,可見輸出控制臺如下

      屏幕0 DisplayPort-1(343) IsPrimary=True XY=1920,309 WH=1920,1080
      屏幕1 DisplayPort-0(626) IsPrimary=False XY=0,0 WH=1920,1080
      XDisplayWidth=3840
      XDisplayHeight=1389
      X11Window1=134217731
      X11Window2=134217734
      ConfigureNotify XConfigureEvent (type=ConfigureNotify, serial=20, send_event=False, display=94542337201216, xevent=134217731, window=134217731, x=0, y=0, width=1920, height=694, border_width=0, above=134217729, override_redirect=False)
      ConfigureNotify XConfigureEvent (type=ConfigureNotify, serial=20, send_event=True, display=94542337201216, xevent=134217731, window=134217731, x=0, y=40, width=1920, height=694, border_width=0, above=0, override_redirect=False)
      ConfigureNotify XConfigureEvent (type=ConfigureNotify, serial=68, send_event=False, display=94542337201216, xevent=134217734, window=134217734, x=1920, y=0, width=1920, height=694, border_width=0, above=134217729, override_redirect=False)
      ConfigureNotify XConfigureEvent (type=ConfigureNotify, serial=96, send_event=True, display=94542337201216, xevent=134217734, window=134217734, x=1920, y=349, width=1920, height=694, border_width=0, above=0, override_redirect=False)
      

      通過 ConfigureNotify 消息可見 window=134217734 的 X11Window2 窗口的 X 坐標確實被設置到 1920 上,且通過實際的屏幕顯示內(nèi)容也可以看到兩個窗口被分別顯示到兩個顯示器屏幕上

      如果沒有調(diào)用 XSetWMNormalHints 設置,則窗口顯示過程中,收到的 ConfigureNotify 會根據(jù)鼠標最后停留在哪個屏幕上,選擇對應的屏幕設置給到窗口坐標。如以下的去掉了 XSetWMNormalHints 的代碼跑出來的控制臺效果

      X11Window1=134217731
      X11Window2=134217734
      ConfigureNotify XConfigureEvent (type=ConfigureNotify, serial=19, send_event=False, display=94583148290624, xevent=134217731, window=134217731, x=0, y=0, width=1920, height=694, border_width=0, above=134217729, override_redirect=False)
      ConfigureNotify XConfigureEvent (type=ConfigureNotify, serial=19, send_event=True, display=94583148290624, xevent=134217731, window=134217731, x=1920, y=349, width=1920, height=694, border_width=0, above=0, override_redirect=False)
      ConfigureNotify XConfigureEvent (type=ConfigureNotify, serial=51, send_event=False, display=94583148290624, xevent=134217734, window=134217734, x=1920, y=0, width=1920, height=694, border_width=0, above=134217729, override_redirect=False)
      ConfigureNotify XConfigureEvent (type=ConfigureNotify, serial=103, send_event=True, display=94583148290624, xevent=134217734, window=134217734, x=1920, y=655, width=1920, height=694, border_width=0, above=0, override_redirect=False)
      

      此時可見 window=134217731 的 X11Window1 將和 X11Window2 一樣,被設置 x=1920 到主屏上

      本文代碼放在 githubgitee 上,可以使用如下命令行拉取代碼。我整個代碼倉庫比較龐大,使用以下命令行可以進行部分拉取,拉取速度比較快

      先創(chuàng)建一個空文件夾,接著使用命令行 cd 命令進入此空文件夾,在命令行里面輸入以下代碼,即可獲取到本文的代碼

      git init
      git remote add origin https://gitee.com/lindexi/lindexi_gd.git
      git pull origin e4780e542104ca07e16735506736bb16030e47fe
      

      以上使用的是國內(nèi)的 gitee 的源,如果 gitee 不能訪問,請?zhí)鎿Q為 github 的源。請在命令行繼續(xù)輸入以下代碼,將 gitee 源換成 github 源進行拉取代碼。如果依然拉取不到代碼,可以發(fā)郵件向我要代碼

      git remote remove origin
      git remote add origin https://github.com/lindexi/lindexi_gd.git
      git pull origin e4780e542104ca07e16735506736bb16030e47fe
      

      獲取代碼之后,進入 X11/CeejemwhucemwaileeRerallbefe 文件夾,即可獲取到源代碼

      更多 X11 技術博客,請參閱 博客導航

      posted @ 2025-08-06 08:53  lindexi  閱讀(66)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲国产一区二区三区亚瑟| 精品久久久久久无码人妻蜜桃| 久久精品人妻无码专区| 性欧美VIDEOFREE高清大喷水| 国产性色的免费视频网站| 亚洲日韩国产二区无码| 精品午夜福利短视频一区| 国产一级r片内射免费视频| 国产午夜成人久久无码一区二区| 国产亚洲av产精品亚洲| 九九热精品在线免费视频| 国产精品久久久久久福利69堂| 亚洲高清有码中文字| 福利视频在线一区二区| 女人爽到高潮的免费视频| 久草热在线视频免费播放| 国产一卡2卡三卡4卡免费网站| 99久久国语露脸精品国产 | 欧美性xxxxx极品| 18禁网站免费无遮挡无码中文| 亚洲中文字幕国产综合| 十八禁国产精品一区二区| 久久午夜无码鲁丝片直播午夜精品 | 亚洲精品国男人在线视频| 亚洲天堂av日韩精品| 霍林郭勒市| 久久亚洲精品成人综合网| 国产午夜亚洲精品不卡网站| 婷婷色香五月综合缴缴情香蕉| 欧美成年性h版影视中文字幕| 桃花岛亚洲成在人线AV| 日韩不卡二区三区三区四区| 亚洲岛国成人免费av| 国产福利在线观看免费第一福利| 五月婷婷激情第四季| 亚洲免费视频一区二区三区| 女人扒开的小泬高潮喷小| 日韩V欧美V中文在线| 国产精品美女一区二区三| 激烈的性高湖波多野结衣| 国产伦视频一区二区三区|