如何设置 X 属性以使用电子创建桌面状态栏?
How to set X properties in order to create a desktop status bar with electron?
我希望我的 window 经理 (xmonad) 将我的 electron 应用程序作为桌面状态栏来管理:它必须在任何工作区都可用,并且在屏幕上有一个预留位置(例如在顶部)
为了实现这一点,我创建了一个这样的 BrowserWindows :
mainWindow = new BrowserWindow({
x:0,
y:0,
width:1024,
height: 30,
frame: false,
title: 'electron-status-bar',
type: 'dock'
});
我的栏在任何工作区中都可见,并且在其他工作区上方 window。
但它仍然没有预留位置,因此与其他 windows 有重叠。
我用xprop
和dzen2比较(实际状态栏完美运行),dzen2有这些属性:
_NET_WM_STRUT(CARDINAL) = 0, 0, 0, 34
_NET_WM_STRUT_PARTIAL(CARDINAL) = 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 899
实际上,管理重叠的 xmonad 插件 (ManageDock) 正在观察这两个属性以计算 window 个位置。
有一种方法可以在我的电子应用程序中设置此类属性吗?
这是一个解决方案,它说明了如何实现这一点,结构很不漂亮。
将使用此库:https://github.com/sidorares/node-x11
const x11 = require( 'x11' );
var X;
使用 electron,我们创建了一个浏览器 window,带有任意 window 标题。
mainWindow = new BrowserWindow(
x: 0,
y: 0,
frame: false,
type: 'dock',
title: 'myTitle'
}
这里有一个限制:此 window 名称必须是唯一的,因为它将用于检索 window id(将用于应用 属性)
需要两个函数:使用其 ID 检索 window 名称和使用其名称检索 window ID:
var getWindowName = function( wid ) {
return new Promise( function( resolve, reject ) {
X.InternAtom(false, '_NET_WM_NAME', function (wmNameErr, wmNameAtom) {
X.InternAtom(false, 'UTF8_STRING', function (utf8Err, utf8Atom) {
X.GetProperty(0, wid, wmNameAtom, utf8Atom, 0, 10000000, function(err, nameProp) {
if( err ) {
reject( err );
}
resolve( nameProp.data.toString() );
});
});
});
});
}
var getWindowId = function (name) {
return new Promise( function( resolve, reject ) {
x11.createClient(function( err, display ) {
X = display.client;
var root = display.screen[0].root;
X.QueryTree(root, function(err, tree) {
tree.children.map( function( id ) {
let prop = getWindowName( id ).then( function( n ) {
if( n === name ) {
resolve( id );
}
})
} );
})
});
});
}
要获得 window id,我们必须从根检索所有 windows 并在它们上循环。对于每一个,该函数将它们的名称与搜索到的名称进行比较。
我们假设 getWindowId
函数将在起点调用一次,因此我们在内部实例化了 X 客户端,但在实际应用中不应该这样。
最后,我们需要一个函数来设置 _NET_WM_STRUT_PARTIAL
属性 :
var setStrutValues = function (wid,
left, right, top, bottom,
left_start_y, left_end_y, right_start_y, right_end_y,
top_start_x, top_end_x, bottom_start_x, bottom_end_x ) {
var values = new Buffer( 4 * 12 );
values.writeUInt32LE(left ,0*4 );
values.writeUInt32LE(right ,1*4 );
values.writeUInt32LE(top ,2*4 );
values.writeUInt32LE(bottom ,3*4 );
values.writeUInt32LE(left_start_y ,4*4 );
values.writeUInt32LE(left_end_y ,5*4 );
values.writeUInt32LE(right_start_y ,6*4 );
values.writeUInt32LE(right_end_y ,7*4 );
values.writeUInt32LE(top_start_x ,8*4 );
values.writeUInt32LE(top_end_x ,9*4 );
values.writeUInt32LE(bottom_start_x ,10*4 );
values.writeUInt32LE(bottom_end_x ,11*4 );
X.InternAtom( false, '_NET_WM_STRUT_PARTIAL', function( err, strutAtom ) {
X.ChangeProperty(0, wid, strutAtom, X.atoms.CARDINAL, 32, values) ;
} );
}
利用所有这些,我们可以做到:
getWindowId( 'myTitle' ).then( function( wid ) {
setStrutValues( wid, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
} )
我希望我的 window 经理 (xmonad) 将我的 electron 应用程序作为桌面状态栏来管理:它必须在任何工作区都可用,并且在屏幕上有一个预留位置(例如在顶部)
为了实现这一点,我创建了一个这样的 BrowserWindows :
mainWindow = new BrowserWindow({
x:0,
y:0,
width:1024,
height: 30,
frame: false,
title: 'electron-status-bar',
type: 'dock'
});
我的栏在任何工作区中都可见,并且在其他工作区上方 window。 但它仍然没有预留位置,因此与其他 windows 有重叠。
我用xprop
和dzen2比较(实际状态栏完美运行),dzen2有这些属性:
_NET_WM_STRUT(CARDINAL) = 0, 0, 0, 34
_NET_WM_STRUT_PARTIAL(CARDINAL) = 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 899
实际上,管理重叠的 xmonad 插件 (ManageDock) 正在观察这两个属性以计算 window 个位置。
有一种方法可以在我的电子应用程序中设置此类属性吗?
这是一个解决方案,它说明了如何实现这一点,结构很不漂亮。
将使用此库:https://github.com/sidorares/node-x11
const x11 = require( 'x11' );
var X;
使用 electron,我们创建了一个浏览器 window,带有任意 window 标题。
mainWindow = new BrowserWindow(
x: 0,
y: 0,
frame: false,
type: 'dock',
title: 'myTitle'
}
这里有一个限制:此 window 名称必须是唯一的,因为它将用于检索 window id(将用于应用 属性)
需要两个函数:使用其 ID 检索 window 名称和使用其名称检索 window ID:
var getWindowName = function( wid ) {
return new Promise( function( resolve, reject ) {
X.InternAtom(false, '_NET_WM_NAME', function (wmNameErr, wmNameAtom) {
X.InternAtom(false, 'UTF8_STRING', function (utf8Err, utf8Atom) {
X.GetProperty(0, wid, wmNameAtom, utf8Atom, 0, 10000000, function(err, nameProp) {
if( err ) {
reject( err );
}
resolve( nameProp.data.toString() );
});
});
});
});
}
var getWindowId = function (name) {
return new Promise( function( resolve, reject ) {
x11.createClient(function( err, display ) {
X = display.client;
var root = display.screen[0].root;
X.QueryTree(root, function(err, tree) {
tree.children.map( function( id ) {
let prop = getWindowName( id ).then( function( n ) {
if( n === name ) {
resolve( id );
}
})
} );
})
});
});
}
要获得 window id,我们必须从根检索所有 windows 并在它们上循环。对于每一个,该函数将它们的名称与搜索到的名称进行比较。
我们假设 getWindowId
函数将在起点调用一次,因此我们在内部实例化了 X 客户端,但在实际应用中不应该这样。
最后,我们需要一个函数来设置 _NET_WM_STRUT_PARTIAL
属性 :
var setStrutValues = function (wid,
left, right, top, bottom,
left_start_y, left_end_y, right_start_y, right_end_y,
top_start_x, top_end_x, bottom_start_x, bottom_end_x ) {
var values = new Buffer( 4 * 12 );
values.writeUInt32LE(left ,0*4 );
values.writeUInt32LE(right ,1*4 );
values.writeUInt32LE(top ,2*4 );
values.writeUInt32LE(bottom ,3*4 );
values.writeUInt32LE(left_start_y ,4*4 );
values.writeUInt32LE(left_end_y ,5*4 );
values.writeUInt32LE(right_start_y ,6*4 );
values.writeUInt32LE(right_end_y ,7*4 );
values.writeUInt32LE(top_start_x ,8*4 );
values.writeUInt32LE(top_end_x ,9*4 );
values.writeUInt32LE(bottom_start_x ,10*4 );
values.writeUInt32LE(bottom_end_x ,11*4 );
X.InternAtom( false, '_NET_WM_STRUT_PARTIAL', function( err, strutAtom ) {
X.ChangeProperty(0, wid, strutAtom, X.atoms.CARDINAL, 32, values) ;
} );
}
利用所有这些,我们可以做到:
getWindowId( 'myTitle' ).then( function( wid ) {
setStrutValues( wid, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
} )