• 首页
  • 加入
  • RSS
  • Saturday, August 7, 2021

    DOM文档排版的特点

    块级元素只能垂直排版,行内元素只能水平排版。

    块级元素可以设置宽高属性,行内元素没有宽高属性,只能被内部元素撑起来,水平放置不下时会换行继续排版。

    CSS 浮动

    浮动就是让文档脱离文档流,在父元素内部可以移动到指定位置。

    浮动的元素可以设置宽高,像块级元素一样,又向行内元素一样可以水平排版。

    <!doctype html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>元素的浮动</title>
    <style type="text/css">
    /*定义父元素的样式*/
    .father {
    background: #ccc;
    border: 1px dashed #999;
    }

    /*定义 box01、 box02、 box03 三个盒子的样式*/
    .box01, .box02, .box03 {
    height: 50px;
    width: 50px;
    background: #FF9;
    border: 1px solid #F33;
    margin: 15px;
    padding: 0px 10px;
    }

    /*定义段落文本的样式*/
    p {
    background: #FCF;
    border: 1px dashed #F33;
    padding: 0px 10px;
    }
    </style>
    <style>
    .box01, .box02, .box03 {
    float: left;
    }
    </style>
    </head>
    <body>
    <div class="father">
    <div class="box01">box01</div>
    <div class="box02">box02</div>
    <div class="box03">box03</div>
    </div>
    <p>12</p>
    <!--不定义float属性,float属性值都为其默认值 none-->
    </body>
    </html>
    元素的浮动

    运行后,box01、box02、box03 及段落文本从上到下一一罗列。 可见如果不对元素设置浮动,则该元素及其内部的子元素将按照标准文档流的样式显示,即块元素占据页面整行。

    接下来以 box01 为设置对象,对其应用左浮动样式,在 head 的 style 标签下添加新的 style 标签,具体CSS代码如下:

    .box01 {
    float: left;
    }

    可以看到 box01 已经脱离了文档流,接下来为 box02 和 box03 设置左浮动:

    .box02 {
    float: left;
    }

    .box03 {
    float: left;
    }
    元素的浮动

    上述代码运行后,box01、 box02、 box03 三个盒子排列在同一行,同时,周围的段落文本将环绕盒子,出现了图文混排的网页效果。

    CSS 浮动清除

    由于浮动元素不占用原文档流的位置,使用浮动时会影响后面相邻的固定元素。

    CSS 提供了 clear 属性,可以清除掉浮动元素。

    clear 有三个属性值:

    left :不允许左侧有浮动元素(清除左侧浮动的影响)

    right :不允许右侧有浮动元素(清除右侧浮动的影响)

    both :同时清除左右两侧浮动的影响

    浮动清除存在一个问题,浮动清除本质上处理的是左右元素,如果父元素内所有的元素都浮动了,此时因为文档流中没有其他元素可以在内部撑起父元素的高度,父元素此时会坍缩为 0 高度。

    方法一:使用空标记清除浮动

    在浮动元素之后添加空标记,并对该标记应用 clear:both 样式,可清除元素浮动所产生的影响,这个空标记可以为 <div><p><hr /> 等任何标记。

    需要注意的是,上述方法虽然可以清除浮动, 但是在无形中增加了毫无意义的结构元素(空标记),因此在实际工作中不建议使用。

    (空标记)因此在实际工作中不建议使用。

    <!doctype html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>空标记清除浮动</title>
    <style type="text/css">
    /*没有给父元素定义高度*/
    .father {
    background: #ccc;
    border: lpx dashed #999;
    }

    /*定义box01、box02、box03三个盒子左浮动*/
    .box01, .box02, .box03 {
    height: 50px;
    line-height: 50px;
    background: #f9c;
    border:1px dashed 999;
    margin: 15px;
    padding: 0px 10px;
    float: left;
    }

    /*对空标记应用clear:both;*/
    .box04 {
    clear: both;
    }
    </style>
    </head>
    <body>
    <div class="father">
    <div class="box01">box01</div>
    <div class="box02">box02</div>
    <div class="box03">box03</div>
    <div class="box04"></div>
    <!--在浮动元素后添加空标记-->
    </div>
    </body>
    </html>
    空标记清除浮动

    方法二:使用 overflow 属性清除浮动

    对元素应用 overflow: hidden; 也可以清除浮动对该元素的影响,该方法弥补了空标记清除浮动的不足。

    对父元素应用 overflow: hidden; 样式来清除子元素浮动对父元素的影响。

    父元素又被其子元素撑开了,即子元素浮动对父元素的影响已经不存在。

    <!doctype html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>overflow属性清除浮动</title>
    <style type="text/css">

    /*没有给父元素定义高度*/
    .father {
    background: #ccc;
    border: 1px dashed #999;
    /*对父元素应用overflow:hidden;*/
    overflow: hidden;
    }

    /*定义box01、box02、box03三个盒子左浮动*/
    .box01, .box02, .box03 {
    height: 50px;
    line-height: 50px;
    background: #f9c;
    border: 1px dashed #999;
    margin: 15px;
    padding: 0px 10px;
    float: left;
    }
    </style>
    </head>
    <body>
    <div class="father">
    <div class="box01">box01</div>
    <div class="box02">box02</div>
    <div class="box03">box03</div>
    </div>
    </body>
    </html>
    overflow 清除浮动

    方法三: 使用 after 伪对象清除浮动

    使用 after 伪对象也可以清除浮动,但是该方法只适用于 IE8 及以上版本浏览器和其他非 IE 浏览器。

    另外,使用 after 伪对象清除浮动时需要注意:

    (1) 必须为需要清除浮动的元素伪对象设置 height: (); 样式,否则该元素会比其实际高度高出若干像素。

    (2) 必须在伪对象中设置 content 属性,属性值可以为空,如 content:" ";

    <!doctype html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>使用after伪对象清除浮动</title>
    <style type="text/css">

    /*没有给父元素定义高度*/
    .father {
    background: #ccc;
    border: 1px dashed #999;
    }

    /*对父元素应用after伪对象样式*/
    .father:after {
    display: block;
    clear: both;
    content:" ";
    visibility: hidden;
    height: 0;
    }

    /*定义box01、box02、box03三个盒子左浮动*/
    .box01, .box02, .box03 {
    height: 50px;
    line-height: 50px;
    background: #f9c;
    border: 1px dashed #999;
    margin: 15px;
    padding: 0px 10px;
    float: left;
    }

    </style>
    </head>
    <body>
    <div class="father">
    <div class="box01">box01</div>
    <div class="box02">box02</div>
    <div class="box03">box03</div>
    </div>
    </body>
    </html>
    使用after伪对象清除浮动

    Thursday, March 11, 2021

    原文:https://emersion.fr/blog/2019/xdc2019-wrap-up

    > XDC 2019 wrap-up 2019-10-10

    这篇文章是我从加拿大蒙特利尔飞往赫尔辛基的路上写的,我刚参加完 X.Org 的开发者研讨会。从去年西班牙那次会议以来,这是我第二次参加 XDC(译者注:X.Org Developer’s Conference)。

    今年的研讨会非常的给力。我遇到了很多一起工作过的同志,他们来自四面八方的各个组织和项目。会议内容也很牛,我会尝试总结一下这次讨论的一些事情。

    libliftoff

    前一阵子,我搞了一个新项目,名字叫 libliftoff。它是我在这次会议上的亮点,所以接下来我会详细的介绍它。带着问题往下看:“libliftoff 是用来解决什么问题的呢?”

    libliftoff 是什么

    它是一个合成器的中间层,负责从 clients 中获取 buffers,把它们绘制在一个独立的 buffer 上,并把这个 buffer 显示到屏幕上。假设我现在打开了一个“文本编辑器”和一个“终端”,合成器会把它们的窗口 buffer 复制到屏幕的 buffer 上,一般是用 OpenGL 做这个事。

    不过,复制 buffers 的操作很浪费资源,因为它会做很多事情,比如:它总是进行 alpha 混合、在不同格式之间转换、让渲染引擎一直干活(注:GPU 在执行 OpenGL/Vulkan 的命令)等等,这些操作不仅占用时间,而且也会增加耗电量。

    为了改善性能,许多 GPU 都提供了硬件实现的“叠加平面(planes)”支持(下文直接称为“叠加平面”)。“叠加平面”可以作为显示引擎负责合成工作,这种行为称为直接显示,可以避免全让合成器做复制 buffers 的活。

    在 Android 上,硬件“叠加平面”在“Hardware Composer”组件中用的很广。许多 Wayland 合成器也会为光标使用“叠加平面”,但是用在其它场景的情况还是很少见。Weston(译者注:一个 Wayland 合成器) 是仅有的使用“叠加平面”的合成器之一。

    使用“叠加平面”并不是一件容易的事情,它有一些限制,比如:不支持 Alpha 通道、不是任意的 buffer 都可以用。虽然这些限制往往会让人觉得很扯淡,但它是由硬件特性决定的。举个例子:对于某些格式的 buffers,Intel 的硬件只能将其放在“叠加平面”的偶数坐标位置、某些 buffers 是在内存上分配的,“叠加平面”干脆就不支持这一类的 buffer、另外,显示设备一般都有带宽限制,在“叠加平面”上使用过大的 buffer 时会失败、某些 ARM 设备上,多个“叠加平面”之间不支持重叠。

    目前为止,关于硬件的这些限制信息,合成器程序还查询不了,因为硬件之间的差异性很大,所以很难设计一个能查询硬件限制信息的 API,甚至在某些新出 GPU 上还会有更奇怪的限制。唯一的方法是搞一些前置工作,用它做一些尝试性的使用。

    因此,设计和实现一个能有效的使用“叠加平面”的代码是一个相当复杂的事情。我一直在想,共享这些代码,是不是会对合成器使用“叠加平面”有所帮助,于是我就奔着这个目标设计了 libliftoff。

    libliftoff 的研讨会

    图一

    我在 XDC 搞了一个研讨会,讨论关于 libliftoff 的事情,目的是把合成器和驱动专家凑一块,一起商量如何才让合成器有效的用上“叠加平面”。

    libliftoff 的受欢迎程度让我很惊讶,连桌子附近都坐满了人:

    • 在合成器这边,有 wlroots 团队的人(Drew DeVault, Scott Anderson 和我自己),KDE 的 Roman Gilg,Weston 的 Daniel Stone,还有 X server 的 Keith Packard。
    • 在驱动这边,有很多来自于不同厂商的开发者:有 AMD、Arm、Google、Nvidia、Qualcomm 等等。

    大家貌似都很兴奋,为 libliftoff 提了很多宝贵的意见。我在此感谢所有参与研讨会的人!

    短期的计划是,让 libliftoff 为合成器提供能实际使用的功能(实验性的),不过有个事我还需要弄清楚,那就是应该怎么样支持多个 output:因为每个 output 都有自己的时序,所以,如何将“叠加平面”从一个 output 迁移到另一个 output 是一件很难搞的问题。最终,如果能实现这样的功能就完美了:为每一个图层分配一个优先级,并把那些频繁在别的图层之前更新的图层放在同一个“叠加平面”上。

    另外也讨论了一些长期计划。

    首先,我们想搞定一个跟内存相关的问题:clients 往往会在内存上分配 buffer,这些 buffer 没法直接用在“叠加平面”上。通常,合成器都会给一些提示信息:“你现在正在使用 Y_TILED,所以我不能将你用在“叠加平面”上,但是如果你能使用 X_TILED 我就能把你用在“叠加平面”上”,这样 client 就可以决定切换它的 buffer 格式。我大概在一年前给 Wayland 提了一个补丁,这个补丁新增的信息能被 libliftoff 识别出来,在这种情况下,合成器可以把这个信息转发给 clients。

    接下来是关于内核 API 的问题,现在只有一个办法能让我们知道是否可以使用“叠加平面”,那就是用 atomic 相关的 test 接口测试(译者注:atomic 是 DRM 提供的一系列原子操作接口,支持事务),这个做法相当的不清真,因为我们必须得遍历尝试多个组合条件,基本上是暴力求解。除此之外,比较好的做法都要跟具体的硬件相关。

    为了搞定这个问题,我们必须让内核提供更多的信息,但是因为不同硬件的差异性很大,设计一个足够通用的 API 将是一个很蛋疼的事情,另一个解决方案是在 libliftoff 中添加特定厂商的插件,允许每个驱动添加自己的代码,以此更好的匹配自己的硬件。目前来说,貌似这是最好的方案了。

    这是本次讨论的总结(PPT):

    视频:XDC 2019 - Day 3

    Scott Anderson 也写了一些总结,是关于 Wayland 协议的一些想法的详细介绍。

    分配器

    在三年前的 XDC 上,Nvidia 的 James Jones 提出了这个分配器项目,用于解决 GBM/EGLStreams 现有的问题。今年,他做了一个关于 GBM、Nouveau 和 transitions 的新的分享。跟之前的提案相比,这个提案的目的是在现有 API 的基础上建立一种叫 transition 的机制。

    视频:XDC 2019 - Day 2

    transition 可以用来减少渲染引擎的带宽占用。某些 GPU 支持使用压缩的 buffer,与未压缩的 buffer 相比,GPU 可以在这些压缩后的 buffer 上直接执行 OpenGL/Vulkan 的操作,这样做效率很高。所以,我们应该在渲染时使用压缩后的 buffers。

    不过,压缩后的 buffers 不能直接用在“叠加平面”上,需要先将它们解压才能使用,有一个方法是把它解压为一个新的 buffer,但是这样需要复制数据,速度会很慢。

    在某些 GPU 上有个更好的方法,它们支持在“叠加平面”中直接解压 buffer。这指的是:当一个 Wayland client 在压缩后的 buffer 上渲染,如果这个 buffer 可以在“叠加平面”中解压,并且之后可以直接使用它,那我们就将这种“buffer 就地解压的程序”称为 transition。

    之后我们在一个研讨会中继续探讨 transitions,讨论了应该在何时何地进行 transition 操作。想法一是:如果合成器准备把一个 buffer 用到“叠加平面”中,那就在合成器中做这个事,可以用 libliftoff 判断什么时候应该使用 transition。另一个想法是:在 client 把 buffer 提交给合成器之前做这个事,client 需要从合成器那获取一个信息,以便知道应该什么时候执行操作(这就是我之前提到的那个 Wayland 协议的补丁可以做的事情)。

    这是这次研讨会的总结:

    视频:XDC 2019 - Day 3

    可变刷新率(VRR)

    AMD 的 Harry Wentland 搞了一个关于“自适应同步”(DisplayPort 的技术)、“可变刷新率”(HDMI 的技术)和“FreeSync”(AMD 的技术)的研讨会。所有这些技术都是为了适配屏幕的功能,允许它从“固定为 60Hz”的模式变成“可以稍微等待下一帧”的模式(译者注:动态刷新率的模式)。

    视频:XDC 2019 - Day 2

    这东西的主要使用场景是游戏应用。游戏通常是用动态刷新率的方式更新画面(依赖于场景的复杂度),下一帧可以更快也可以更慢。游戏还希望能降低延迟,即避免渲染到在屏幕上显示的时间差过长。

    在屏幕固定刷新率的情况下,如果有一帧的渲染用时稍微长了一点,它错过了显示器的刷新时机,这样就会导致这一帧的显示有些滞后,而 VRR 则允许增加屏幕刷新时的等待时间,以免丢帧。

    另一种场景是视频播放。视频有固定的帧率,但是通常会与屏幕的刷新率不同,视频播放器需要用帧插值的方式,才能适应屏幕的刷新率,而 VRR 则允许降低刷新率以匹配能完美播放视频的时序。

    屏幕内容通常都是处于静止状态,在这种情况下,VRR 还可以降低电量消耗。比如用户在使用文本编辑器时,完全不需要 60FPS,这时候合成器可以降低屏幕的刷新率。

    游戏的使用场景比较简单,合成器可以比 deadline 稍微晚一点点提交帧,硬件可以搞定这种情况。其它场景需要做更多的工作,要想把 VRR 用在视频播放器上,我们需要某种定时提交帧的 API。要想用 VRR 做节能,合成器要能支持帧率改变时的平滑过渡,否则屏幕会有闪烁问题(这是支持 VRR 功能的屏幕的限制)。

    在我看来,我们目前应该把精力放在 Wayland 协议对游戏场景的支持上,因为搞其它两种场景需要做的事情太多了,它们不仅需要更多的新 API(内核和 Wayland 的都需要),还需要做很多的实验工作。

    Chamelium

    我在 Intel 实习期间,参与了一个叫 Chamelium 的项目,它是一个基础的屏幕模拟器,你可以通过网络向它发送命令,它已经被用在了 ChromeOS 的 i915 显卡环境的 CI 服务中。

    我搞了一个关于这个项目以及我在项目内的工作的研讨会:

    视频:XDC 2019 - Day 3

    除了这三个主题,我们还讨论了很多其它的东西,但是不能全塞到这一篇博客中讲,所以就说到这吧。感谢所有参加 XDC 的人,感谢 Mark Filion 组织了这次活动,还要感谢所有赞助商,没有你们的赞助就不会有的这次活动!

    Thursday, March 4, 2021

    Arch 使用的是 pacman 包管理器,包格式是 tar.zst。Arch 提供了一些工具用于创建 tar.zst 包,首先需要安装 base-devel 包和 devtools 包。

    pacman -S base-devel devtools

    Arch 的打包流程是这样的,要先写一个 PKGBUILD 文件,这个文件描述了构建一个包所需的全部信息,如从哪里下载源码,依赖有哪些,构建的版本是多少,如何进行构建等。

    PKGBUILD

    一个基本的 PKGBUILD 格式如下:

    # Maintainer: justforlxz <[email protected]>

    pkgname=dtkcore-git
    pkgver=5.4.0.r1.ge7e7a99
    pkgrel=1
    pkgdesc='DTK core modules'
    arch=('x86_64')
    url="https://github.com/linuxdeepin/dtkcore"
    license=('LGPL3')
    depends=('dconf' 'deepin-desktop-base-git' 'python' 'gsettings-qt' 'lshw')
    makedepends=('git' 'qt5-tools' 'gtest')
    conflicts=('dtkcore')
    provides=('dtkcore')
    groups=('deepin-git')
    source=("$pkgname::git://github.com/linuxdeepin/dtkcore.git")
    sha512sums=('SKIP')

    pkgver() {
    cd $pkgname
    git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g'
    }

    build() {
    cd $pkgname
    qmake-qt5 PREFIX=/usr DTK_VERSION=$pkgver LIB_INSTALL_DIR=/usr/lib
    make
    }

    package() {
    cd $pkgname
    make INSTALL_ROOT="$pkgdir" install
    }

    以 dtkcore 为例,整个配置文件十分清晰明了,一看就知道构建工具是如何一步步制作出一个包的。

    将配置文件保存到目录里,以 PKGBUILD 命名,然后执行 makepkg

    makepkg 是用于执行 PKGBUILD 文件的工具,它根据文件中的描述,进行包的构建。

    如何提交一个包到 aur

    当你希望自己打的包可以被别人使用的时候,一般都会请求上传到官方仓库,但是进入官方仓库的流程异常繁琐,而且对贡献者的要求会比较高。Arch 提供了一个用户仓库,供用户自由分享配置文件,只需要下载配置文件,在本机打包就可以了。

    根据 aur 的 贡献指南,我们可以很轻松的上传自己的配置文件,并借用yay等aur工具自动下载和构建软件包。

    用户可以通过 Arch User Repository 分享 PKGBUILD。AUR 中不包含任何二进制包,仅包含用户上传的 PKGBUILD,供其他用户下载使用。所有软件包都是非官方的,使用风险自担。

    提交aur之前,需要先了解一下 aur 的一些要求,Rules of submission 提供了一些规则,只要我们按照规则来,就可以上传和维护我们自己的包。

    首先需要去 aur官网 注册一个账号,并上传自己的 ssh key 我们通过克隆一个新的仓库来作为上传的方式。

    git clone ssh://[email protected]/<pkgname>.git

    以dtkcore为例,克隆的时候把pkgname改成dtkcore。

    git clone ssh://[email protected]/dtkcore.git

    如果是第一次创建,会提示你克隆的一个空仓库。

    把 PKGBUILD 文件复制到克隆的目录,然后执行 makepkg --printsrcinfo > .SRCINFO 创建一个软件包信息,将 .SRCINFOPKGBUILD 文件都添加到 git 中,然后提交 commit 信息,推送到服务器。

    注意: 如果您忘记在首次提交中包含 .SRCINFO,您可以使用 rebasing with –root 或是 filtering the tree 使得 AUR 接受您的第一次推送

    提示: 为了保持工作目录和提交尽可能的干净,可以创建 gitignore 文件来排除所有文件,然后再按需添加文件。

    参考资料:

    https://wiki.archlinux.org/index.php/PKGBUILD

    Friday, February 26, 2021

    2020

    拖了这么久才更新博客,想必大家都在 2020 年过的挺不好的,年初武汉的疫情打了全国一个措不及防,甚至已经一整年了,全球疫情还是十分紧张。截止到 2021 年 2 月 26 日,全球每日新增仍然有30 多万,而且全球累计死亡已有 250 万人之多。

    疫情

    生命是如此的脆弱。有些时候和朋友们一起吃饭,会说起一月份时大家是如何 逃离 武汉的,在家隔离又多了哪些事情,我们活着是多么的不容易。虽然人类已经可以生产 5 纳米的芯片了,但是就如同我们对这个宇宙的认知一样,几百亿光年外任我们看,可太阳系内有什么我们都不知道,甚至在地球上还有很多我们未知的东西。

    计划失误

    2020 年我的计划几乎没有一件事是完成的,我计划应该一整年掌握 TypeScriptweb 开发,并开发自己的blog系统,但是方案被我推到重来了三次,我就没耐心继续开发了,只完成了基本的 md 文件编译和服务器渲染就暂停了。计划阅读 《1984》《TensorFlow》《TypeScript实战》 ,然而只有 《TypeScript实战》阅读完了,剩余两本书我则是只看了一丢丢,看来只能放到 2021 年读完了。

    2019Review 的文章里,我提到了我遇到了生命中的那个她,而 2020 年,我和她 结婚 啦。

    在家隔离的日子里,有她陪伴着我,虽然老家的人都挺敌视从武汉回来的我,但是大门一关我谁也看不到,眼不见心不烦,在家一块搓麻将挺好的,还一起练 (zao) 习 (ta)了厨艺,朋友圈做饭比赛第一名。

    学习

    虽然我读书拉后了,但是我的英语 坚持 了下来,我使用多邻国进行英语和日语的学习,已经坚持快6个月了,需要继续加油努力,争取早日把学校里拉下的英语 回来。

    2020review

    工作

    2020 年最大的收益可能是创建了 deepin-git 的仓库,提供了 dde 所有组件在 arch 上的git版,并且还成功申请到了 archlinuxcn 的贡献者。

    文章

    2020 年一共水了18篇文章。

    12-23   ccls
    11-17 Qt多线程
    09-17 deepin-wine中文乱码
    09-08 使用rEFInd来安全启动系统
    09-06 deepin git version
    09-03 使用VSCode远程开发DDE
    08-06ArchLinux上开发startdde
    07-27 use github action to check dde-launcher
    07-21 使用perf工具分析程序性能
    06-16 CTest & QTest/GTest
    06-15 CPP项目的一些坑
    06-15 使用inquirer提供交互式git commit
    06-01 vue-router路由复用后页面没有刷新
    05-31 vue3升级遇到的坑
    02-01 JavaScript建造者模式
    01-31 浅谈Javascript构造器模式
    01-01 2019 Review
    01-01 使用伪元素创建一个圆点

    研究了 vscode 的插件,开发了一个 qmake 的插件原型,可以打开 dtkqt pro 的项目,利用 bear 拦截 make 的编译信息,生成 ccls 需要的数据库,这样就可以为项目提供自动补全和语法检查等功能了。

    写了一些关于远程开发的文章,也是利用 vscode 的远程功能,不得不说 vscode 真的可以说是宇宙第一编辑器了,让老牌的 vimemacs 知道了什么叫易用性的力量。

    展望

    2021 年,不能松懈,今年要继续努力学习,努力提升自己。

    在 2021 年里,我将会负责 deepin 的社区,由于前两年公司需要快速扩张,导致忽略了社区,现在我们的首要任务就是恢复社区,并让社区良性的自由发展,社区是我们的根本。

    挖了很多坑,今年争取都填一下。

    其他

    又搬家了,找了一个一室一厅,开启了二人的小日子,过了年以后把狗子也带来了,现在天天早上起来打狗,晚上回来打狗。

    我又给 肝疼3 氪了一个月卡,这次只忘了一天没登录,不然 30 块大洋又要白花了。

    2020review2020review

    祝大家幸福安康,新年快乐!(^▽^)

    Thursday, September 17, 2020

    众所周知,使用wine来运行windows下的一些软件是linux用户的常用操作,deepin为社区贡献了好几款中国用户必备的软件,例如QQ、微信、企业微信,以此来让更多的人无痛的切换到linux来。近年来value也一直在linux上布局,先后推出了steam主机和proton,前者是基于kvm和steam大屏幕模式的系统,而proton则是wine的分支,value提供了几组补丁用来提高性能和与Windows游戏的兼容性。

    Arch上有非常方便的aur仓库,有很多用户都自己提交一些软件到aur上面,就有几个维护者将deepin打包的deepin wine和对应的软件包移植到Arch上面来,已经是很多人在Arch上面运行QQ和微信的首选方案。

    但是使用的过程中我遇到了以下几个问题:

    • 输入框中文乱码
    • 在DDE桌面使用kwin的情况下最小化会卡死
    • KDE桌面环境无法使用deepin wine的程序

    第二个问题比较特殊,因为dde在deepin和uos下运行的是fork版本的kwin,而Arch上运行的则是原版的kwin,一些操作代码并不具备,所以会出现一些奇葩的状况。

    第三个问题则是xsettings的原因,在移植者的仓库有对应的issue讨论 《KDE环境完全无法使用wine-tim》

    第一个问题解决起来也比较简单,是因为缺少了宋体文件,从而无法正确的渲染中文字体。而比较奇葩的是,把方块复制再粘贴,就可以正确的渲染了。

    解决的方法也很简单,把windows的的字体复制过来就可以了。由于版权的问题,没办法直接提供文件,需要各位自己复制了。

    引用资料

    https://github.com/wszqkzqk/deepin-wine-ubuntu/issues/136

    Tuesday, September 8, 2020

    今年的七夕,我老婆给我买了一台surface laptop 2代,8G内存 + 256G存储版本,我也成功的用上了田牌的机器。

    2020/09/17更新: 不知道为啥,反正是开了对内核签名以后,哪怕是BIOS关闭了安全启动,仍然出现mkinitcpio会卡在autodetect上,无奈全部都删掉重来了,没有弄签名,希望各位看到本文章以后解决了这个问题能回复一下,谢谢。

    surface默认是开启了安全启动(Microsoft签名)和bitlocker来保障设备和系统安全,我作为一个linux系统的开发者,当然是需要在surface上装一个linux了,但是前两年zccrs已经踩过坑了,linux不识别surface键盘,同样的触摸、网卡、声卡等设备也工作的不是很正常,本来以为我要开启远程开发的生活了,还特意写了一篇《使用VSCode远程开发DDE》,来给公司里有同样烦恼的人,让他们也感受一下远程开发的魅力。

    苍天不负有心人,我成功的!

    我成功的使用上了ArchLinux,并且工作的十分良好。这多亏了github上的一个组织linux-surface,有这么一些人,他们付出劳动来让手里的surface设备也用上linux,并且要和普通的x86兼容机一样工作,感谢他们的付出,也让我吃上了螃蟹,安装的过程我就不在这里详细说了,其实非常简单。

    首先因为surface只有一个usb口,而键盘并不能工作,所以需要一个usb的扩展器。先按fn+f6进bios关闭掉安全启动,修改引导顺序为usb优先,之后就是正常的安装系统,但是不需要安装仓库里的内核,我们需要安装linux-surface提供的仓库里的内核。

    这些都是非常正常的步骤,linux-surface提供了自己的仓库和内核,我们正常使用即可。

    这里开始就是我研究了半天的内容, 开启安全模式!

    首先我看了一下arch wiki上有关于安全启动的内容,写的挺详细的,就是看不懂。讲了各种的知识点,各种签名的方式,但是真正到我开始用的时候,我是一直失败的,失败的方式我就不说了,直接说我如何成功的。

    首先我放弃了grub,一个原因是grub的安全启动我一直没有尝试成功,另外一个是我只有一个系统,没必要用grub。我换成了rEFInd来作为我的bootloader,首先安装rEFInd的引导。

    yay -S refind shim-signed sbsigntools
    sudo refind-install --shim /usr/share/shim-signed/shimx64.efi --localkeys

    来解释一下上面两条明令。第一个是安装必要的软件包,refind是bootloader本体,shim-signed是aur里面的用于安全启动的包,shim提供了一种并行的安全启动验证功能,我们使用它来启动refind的efi,再通过refind的efi启动内核,达到终极套娃启动。sbsigntools是用于给文件签名的工具,我们安装完refind以后,refind会帮助我们生成一份默认的key,我们需要使用这个key来为内核进行签名。

    在执行第二条明令以后,会有几次询问,都选择Y回车就行。

    然后使用sbsigntools来对内核进行签名。

    sudo sbsign --key /etc/refind.d/keys/refind_local.key --cert /etc/refind.d/keys/refind_local.crt --output /boot/vmlinuz-linux-surface /boot/vmlinuz-linux-surface

    准备工作已经进行一半了,我们只需要写一下refind的配置文件,就可以启动了。

    refind的配置文件有两个地方,一个是boot分区下面的refind_linux.conf,还有一个是在efi分区里的EFI/refind/refind.conf,我们需要修改的是后者。

    默认配置文件都是注释的,其实我们全部删了就可以了,有需要修改的地方去看原始文件或者文档就行了。

    添加一个menuentry,就可以启动系统了。

    also_scan_dirs +,ArchFS/boot
    dont_scan_dirs ESP:/EFI/boot,EFI/boot
    dont_scan_files shim.efi,MokManager.efi,fbx64.efi,mmx64.efi,shimx64.efi
    scan_all_linux_kernels false

    menuentry "Arch Linux" {
    icon /EFI/refind/icons/os_arch.png
    volume 8B131F77-62D7-4B4A-82D4-B60D7ACA2F6C
    loader /ArchFS/boot/vmlinuz-linux-surface
    initrd /ArchFS/boot/intel-ucode.img
    initrd /ArchFS/boot/initramfs-linux-surface.img
    options "root=UUID=9f8f9556-8ec1-4feb-9519-435beac8376f rw rootflags=subvol=ArchFS loglevel=3 quiet add_efi_memmap"
    submenuentry "Boot using fallback initramfs" {
    initrd /ArchFS/boot/initramfs-linux-surface-fallback.img
    }
    submenuentry "Boot to terminal" {
    add_options "systemd.unit=multi-user.target"
    }
    }

    我用的是btrfs文件系统,所以配置文件有点罗嗦。解释一下上面的内容。

    also_scan_dirs是指定扫描某个目录,因为我是btrfs文件系统,必须使用这个才能让refind扫描到内核文件,否则会无法启动。

    dont_scan_dirs是跳过指定的目录,因为refind默认是会扫描所有的efi文件,我们自己提供了emnuentry,所以不需要让它扫描了。

    dont_scan_files是跳过指定的文件,这里是防止其他目录出现对应的efi也被扫描到。

    scan_all_linux_kernels是扫描所有linux内核,这样所有的内核就会出现在启动列表里,我们同样也是不需要的。

    menuentry里面需要修改的地方有,volume是分区的partuuid,我因为这个uuid就测试了好几次,最后才反应过来不是filesystem uuid,要求的是partition uuid. 所有遇到ArchFS的地方都是不需要的,因为btrfs支持字卷,我的系统是在一个叫ArchFS的卷里面的,如果不是btrfs的文件系统,这个是不需要的,同样options里的rootflags选项也是不需要的,这是传递给内核的参数,让内核可以正确的加载根分区。

    这样就算完工了,重启系统,然后进bios里把安全启动改成Microsoft & 3rd party CA,然后重新启动。

    当第一次加载rEFInd的时候,因为我们的证书是才生成的,主板并没有存储对应的签名,rEFInd会启动mmx64.efi来让我们加载证书,证书的位置在/etc/refind.d/keys下,选择refind_local.cer导入,然后选择重启,重新进入系统就可以了。

    导入证书这部分我其实不太确定,因为我除了使用shim方案,我还测试了preloader方案,那个方案会一开始就启动一个MOK的工具进行证书导入,我记不太清shim到底需不需要手动导入了,如果出现了,那就导入一下就行了,没出现的话就能正常的看到引导界面和进入系统了。

    还有一个后续的动作需要处理,就是内核升级以后,我们需要对内核重新签名,否则会被bios拒绝启动。

    编辑/etc/pacman.d/hooks/99-secureboot.hook,并写入以下配置:

    [Trigger]
    Operation = Install
    Operation = Upgrade
    Type = Package
    Target = linux
    Target = linux-surface
    Target = systemd

    [Action]
    Description = Signing Kernel for SecureBoot
    When = PostTransaction
    Exec = /usr/bin/sh -c "/usr/bin/find /boot/ -type f \( -name 'vmlinuz-*' -o -name 'systemd*' \) -exec /usr/bin/sh -c 'if ! /usr/bin/sbverify --list {} 2>/dev/null | /usr/bin/grep -q \"signature certificates\"; then /usr/bin/sbsign --key /etc/refind.d/keys/refind_local.key --cert /etc/refind.d/keys/refind_local.crt --output {} {}; fi' \;"
    Depends = sbsigntools
    Depends = findutils
    Depends = grep

    享受安全启动吧~

    图片图片图片

    Sunday, September 6, 2020

    This repository only provides the git version of deepin. You can replace the deepin group in the community by installing the deepin-git group.

    The PKGBUILD for all packages are there https://github.com/justforlxz/deepin-git-repo, Each branch saves the corresponding software.

    Before adding this repository, you should first add the key used to sign the packages in it. You can do this by running the following commands:

    wget -qO - https://packages.justforlxz.com/deepingit.asc \
    | sudo pacman-key --add -

    It is recommended that you now fingerprint it by running

    sudo pacman-key --finger DCAF15B4605D5BEB

    and in a final step, you have to locally sign the key to trust it via

    sudo pacman-key --lsign-key DCAF15B4605D5BEB

    More infos on this process can be found at https://wiki.archlinux.org/index.php/Pacman/Package_signing#Adding_unofficial_keys. You can now add the repository by editing /etc/pacman.conf and adding

    [deepingit]
    Server = https://packages.justforlxz.com/

    at the end of the file. See https://wiki.archlinux.org/index.php/Pacman#Repositories_and_mirrors for details.

    to install deepin git version:

    sudo pacman -Syy deepin-git

    If you don’t want to use the repository anymore, you can uninstall deepin git, or install the deepin group in Community.

    sudo pacman -Rscn deepin-git

    to install deepin group for community.

    sudo pacman -S deepin

    Thursday, September 3, 2020

    本文将介绍如何使用VSCode的远程开发套件连接到Deepin主机,进行DDE和其他软件的开发与调试.

    介绍

    Visual Studio Code(简称VS Code)是一个由微软开发,同时支持Windows 、 Linux和macOS等操作系统的免费代码编辑器,它支持测试,并内置了Git 版本控制功能,同时也具有开发环境功能,例如代码补全(类似于 IntelliSense)、代码片段和代码重构等。该编辑器支持用户个性化配置,例如改变主题颜色、键盘快捷方式等各种属性和参数,同时还在编辑器中内置了扩展程序管理的功能。

    在VSCode出来之前,Sublime曾经是前端开发者必备的软件,它使用python作为插件运行环境,并且也拥有不少的插件,但是很遗憾的是插件不能更改界面元素,可玩性不是很高。

    再后来Atom作为GitHub的顶梁柱出现了,它基于使用Chromium和Node.js的跨平台应用框架Electron(最初名为Atom Shell),并使用CoffeeScript和Less撰写,并且支持js开发的插件,一时间拥有非常多的用户,并且从Sublime那里拉拢了非常多的前端开发者。

    但是一切都在VSCode面世以后变了。VSCode同样也是基于Chromim和Electron开发,并且支持TypeScript开发插件,而且启动速度比Atom快很多,而且作为微软面向开源社区的主力产品,它和TypeScript一样,吸收了社区的很多意见和贡献,使得软件越来越好用。在语言支持方面,对 C#、JavaScript、和 TypeScript 等编程语言的原生支持最为完善。

    安装VS Code

    官网提供的有vscode的安装包,windows用户下载stable版本的exe(System Installer)。

    System Installer可以自动下载对应语言的环境包,推荐安装此版本。

    图片

    安装完成后就可以安装插件了。

    安装插件

    插件系统是一个编辑器的左膀右臂,emacs和vim作为终端下开发经常使用的编辑器,就拥有非常丰富的插件,几乎每个大佬使用的emacs和vim都不能互换使用。

    dde的项目几乎都是cmake的项目,所以需要安装cmake插件和c++的插件,安装了这两个插件以后。vscode打开项目工程就会自动解析CMakeLists.txt,并且开启vscode的快速调试功能,还可以开始构建项目和调试项目了。

    图片

    安装CMake、CMake Tools这两个插件就可以开发了。

    图片

    安装C/C++和C++ Intellisense这两个插件可以对项目中的c++代码进行智能感知和代码补全,推荐安装。

    图片

    安装Remote - SSH插件,可以让vscode通过ssh连接到目标机器,打开远程机器的目录和文件,并且在该模式下,部分插件可以自动切换成本地/远程模式,这样就可以在本机直接开发,但是操作的内容都是远程环境的。

    安装完Remote - SSH插件以后,vscode的左下角就会有一个绿色的按钮,可以用来切换模式。

    图片

    配置远程环境

    因为是要在Windows上进行远程开发,如果是直接在UOS或者Deepin上开发DDE,这一部分是可以不用看的,上面的插件安装完成以后就可以开发项目了。

    点击左下角的绿色按钮,在弹出的面板选择Remote-SSH: Connect to Host。

    图片

    会继续弹出一个面板,用来选择配置ssh的连接。

    图片

    选择Add New SSH Host添加一个服务器。

    图片

    输入ssh的命令,例如 ssh [email protected]

    图片

    然后选择一个保存配置的位置,一般默认选择用户家目录的.ssh目录即可。然后就提示添加成功,此时可以点击Connect按钮进行连接。

    图片

    输入密码

    图片

    登录以后会打开一个新的窗口,并提示正在连接。连接成功以后可以在左下角看到机器的信息。

    图片图片

    然后打开命令面板,选择在SSH中安装本地扩展。

    图片

    在打开的列表选择全选,然后安装。

    图片

    等待全部安装成功。

    图片图片

    开发和调试

    功能介绍

    CMake插件提供了编译、运行和调试的功能和命令,可以点击下方面板中的select target,选择要运行的目标程序,选择切换编译模式,可以选择Debug或者Release。还可以选择使用哪个编译器进行构建。

    图片图片图片图片

    设置启动参数

    如果程序启动不需要提供参数,则可以直接点击下方面板的Debug按钮,或者打开命令面板选择CMake Debug Target,如果没有选择过Target,则会询问一次设置Target。

    点击左侧的调试按钮,选择添加配置。

    图片

    在弹出的面板选择GDB

    图片

    此时vscode会创建出一个json文件,并生成了默认的配置文件。

    图片

    我们需要进行一些调整,以便使用该配置文件进行调试。

    program字段是程序二进制文件的位置,一般情况下我们是要手动写好路径,但是如果项目的二进制特别多,更换配置文件就会非常麻烦,而且配置文件里写死路径也不是很方便,我查阅了CMake插件的文档,发现CMake插件提供了两个很重要的变量,可以让我们方便的查找到路径。

    "program": "${command:cmake.launchTargetPath}"

    CMake插件提供了launchTargetPath的变量,它对应的是CMake插件选择的默认target,启动调试之前需要我们先选择好Target。

    "value": "$PATH:${command:cmake.launchTargetDirectory}"

    CMake插件还提供了launchTargetDirectory变量,用于获取程序启动所在的目录,一般需要我们指定到本次调试所需的环境变量中。

    "environment": [
    {
    "name": "PATH",
    "value": "$PATH:${command:cmake.launchTargetDirectory}"
    },
    ]

    然后我们就可以添加启动参数了。
    args字段保存了程序启动会传递的参数列表,例如这里会给fuse传递-d和/tmp/x。

    "args": [
    "-d",
    "/tmp/x"
    ]

    完整的配置如下:

    {
        "name": "(gdb) fuse",
        "type": "cppdbg",
        "request": "launch",
        "program": "${command:cmake.launchTargetPath}",
        "args": [
            "-d",
            "/tmp/x"
        ],
        "stopAtEntry": false,
        "cwd": "${workspaceFolder}",
        "environment": [
            {
                "name": "PATH",
                "value": "$PATH:${command:cmake.launchTargetDirectory}"
            },
        ],
        "externalConsole": false,
        "MIMode": "gdb",
        "setupCommands": [
            {
                "description": "为 gdb 启用整齐打印",
                "text": "-enable-pretty-printing",
                "ignoreFailures": true
            }
        ]
    }

    gdb调试

    此时我们就可以先通过CMake插件构建整个项目,再切换到运行面板,启动调试。

    点击下方面板的Build按钮,构建项目。

    图片

    再点击左侧的gdb fuse(deepin-turbo)按钮,因为配置文件里面我们起的名字是gdb fuse。我们在main函数添加一个断点,用来测试gdb是否工作正常。

    图片

    一切都工作正常,在调试控制台可以使用-exec作为前缀来执行gdb的命令。

    图片

    调试图形程序

    调试图形程序稍微有一些麻烦,因为是远程开发,图形程序又只能工作在目标机器,这里提供两个可行的方案。

    1. synergy之类的键盘鼠标共享软件
    2. 在windows安装xserver

    第一种方案是通过共享本机的键盘鼠标到远程机器,这样就可以在远程环境上面进行直接操作,好处是除了调试,也可以同时操作远程机器进行使用。

    第二种方案是利用X11协议的网络透明,既图形程序和显示服务不一定在同一台机器上运行,我们只需要在Windows安装XServer程序,就可以让远程机器上的程序的画面显示到当前机器,并且可以操作。但是此方案有缺点,虽然设计上这种分离结构设计的很巧妙,但是因为远程OpenGL调用并不支持,所以图形无法调用3D程序渲染,并且和远程机器沟通需要大量的带宽,所以用起来体验并不好。

    为了使用这两种方案,我们都需要在调试的launch.json中添加一个环境变量。

    在运行面板点击齿轮按钮,可以编辑当前方案。

    图片

    在打开的json文件中,找到environment字段,添加DISPLAY环境变量。

    "environment": [
    {
    "name": "DISPLAY",
    "value": ":0"
    }
    ]

    这样程序启动就有DISPLAY环境变量,我们就可以让程序在目标机器的屏幕上运行了。

    图片图片图片

    还有一种自动化测试的方案,该方案是我个人认为所有开发都应该掌握的,通过自动化测试,我们就可以完全使用远程开发来完成开发任务,调试的时候只需要等待自动测试结果返回即可,设想一下,某个模块需要点击很多地方才可以重现一个问题,我们只需要设置好断点,让程序自动开始执行所有函数,并在最终出现问题的地方停下,我们就可以开始手动单步跟踪问题,完全不需要使用鼠标人工点击。(然而理想很美好,现实很残酷,我个人目前都没有掌握自动化测试的方式,现在也是只能通过鼠标点点点来重现问题。

    Thursday, August 6, 2020

    dde 后端使用 go 作为主要的开发语言,使用 dbus 提供接口,主要使用 gsettings 来保存配置。 所以在进行后端开发前需要对以上内容有基本的了解,这里假定本文档的阅读者熟悉 dbus 和 gsettings,并有一定的开发经验。

    安装依赖

    虽然本项目是go语言开发的,但是我们并没有直接使用go的mod作为依赖管理方案,而是走系统包管理器的方式,所以要先安装startdde的编译依赖。

    sudo pacman -Sy golang-github-linuxdeepin-go-dbus-factory golang-deepin-gir golang-deepin-lib golang-deepin-dde-api go git jq golang-golang-x-net golang-github-linuxdeepin-go-x11-client

    这些包会被安装到系统的/usr/share/gocode目录下。还需要手动go get一个依赖到本地的GOPATH中。

    go get -v github.com/cryptix/wav

    设置GOPATH

    为了方便以后的开发,可以将GOPATH环境变量定义到~/.xprofile等文件中,或者shell的配置文件。例如我使用的zsh:

    export GOPATH=$HOME/Develop/Go:/usr/share/gocode
    export PATH=$HOME/Develop/Go/bin:$PATH

    设置项目目录

    go要求项目目录必须在GOPATH中,所以要将startdde放到GOPATH的pkg.deepin.io/dde/目录下,但是GOPATH每次进入不方便,可以采用软链的形式将startdde的目录链接到GOPATH下。

    cd ~/Develop/Deepin
    git clone https://github.com/linuxdeepin/startdde
    mkdir -p ~/Develop/Go/src/pkg.deepin.io/dde/
    ln -sf ~/Develop/Deepin/startdde ~/Develop/Go/src/pkg.deepin.io/dde/startdde

    这样就可以在一个方便的目录进行开发了。

    vscode开发工具

    我个人推荐使用vscode当作开发工具,打开vscode安装go的插件,打开startdde目录,vscode会提示安装一些go的工具,选择全部安装即可。

    Monday, July 27, 2020

    本来打算7月份给dde添加github action验证,但是被各种事情耽误了,然后发现麒麟居然抢在我前面部署了全套的github action,这不能忍,赶紧把dde的github action也提上日程。并且打算听肥肥猫大佬的话,在aur给dde弄一套commit构建包,这样就可以在arch上使用比testing仓库更testing的dde了!

    github actions是github官方出的持续集成功能,以前大家在github上的项目都使用的第三方的Travis CI或者自建jenkins构建,但是github被微软收购以后,微软为了表现出给社区和用户的诚意,将大量github的付费功能免费公开给开发者使用,希望能将github打造成开发者中心,于是在2019年微软推出了免费的github actions,每个项目都可以免费使用官方提供的持续集成和持续部署功能,这对第三方业务无疑是个巨大的打击,虽然Travis CI和jenkins等方式仍然有一定的市场,但是对于中小项目的开源项目,使用官方提供的功能无疑是方便的。

    github actions的配置十分简单,只需要几个简单的步骤就可以实现构建、执行和测试代码。并且可以使用Linux、Windows和MacOS环境,机器性能也十分强劲,编译速度非常的快。

    这是给dde-launcher的一份基础配置,需要将配置文件放在.github/workflows/目录下,以build.yaml文件名保存。

    name: CI Build

    on:
    push:
    branches:
    - UOS

    pull_request:
    branches:
    - UOS

    jobs:
    archlinux:
    name: Archlinux Build Check
    runs-on: ubuntu-latest
    container: docker.io/library/archlinux:latest
    steps:
    - name: Checkout branch
    uses: actions/checkout@v2
    - name: Refresh pacman repository
    run: pacman -Syy
    - name: Install build dependencies
    run: pacman -S --noconfirm base-devel cmake ninja qt5-tools deepin-qt-dbus-factory dtkwidget
    - name: CMake & Make
    run: |
    mkdir build
    cd build
    cmake ../ -G Ninja
    ninja

    介绍一下配置文件吧,name是设置ci的名字,github允许有多个ci存在,可以做不同的事情,例如部署三个ci,一个做语法检查,一个做静态检查,一个做编译检查。name就是用来在界面上显示的。on是设置ci对哪些事件感兴趣,在这里我设置了push和pull_request,当发生push和pull request时,这个ci就会被启动,执行接下来的jobs的内容。jobs里是可以设置多个任务的,同样name字段也是用来展示本次动作的名称。runs-on是设置该job工作的环境,ubuntu-latest是linux环境,container是指使用哪个docker容器,github actions是可以使用docker的,也可以将自己的ci配置共享给其他人使用。run就是执行命令了,在配置文件中我手动运行了刷新仓库和编译项目所需的命令。job的steps可以理解成shell中一次动作的执行,uses是使用其他人封装好的命令,run则是执行本地命令。

    可以看出github actions的配置是十分简单的,并且构建速度也非常的快,并且构建环境是使用的arch linux环境,为什么要选择arch作为ci的基础构建环境呢,原因当然不是因为和肥肥猫有py交易,arch上的dde更新速度很快,并且很多用户都使用arch+dde的方式使用linux,deepin自己维护的发行版因为基础仓库更新较慢,不适合一些用户,所以为了能让dde被更多的人接受和使用,在arch上及时更新dde是十分有必要的。所以才选择actions的环境为arch linux。