目录
前言
1 weston框架下输入管理流程
2 按键适配处理分析
3 亮灭屏分析
3.1 destop层面下的分析
3.2 compositor层面下的分析
4 总结
前言
在weston框架下,支持的输入设备通常是标准设备,如:键盘、鼠标、触摸屏等。若要支持我们自定义的键盘,需要在weston框架下做适配。
1 weston框架下输入管理流程
该部分我们参考ariesjzj大神的《输入管理》章节部分,理解了第一部分之后,基于该部分在第二章中阐述适配的过程。
Weston中的输入管理模块与libinput对接,它实现了两大部分的功能:一是对输入设备的维护,二是对输入事件的处理。对于输入事件既会在Weston中做处理,也会传给相应的client。从事件处理模型上来看,libinput的主循环监听udev monitor fd,它主要用于监听设备的添加删除事件。如果有设备添加,会打开该设备并把fd加入到libinput的主循环上。另一方面,Weston中会将libinput的epoll fd加入主循环。这样形成级联的epoll,无论是udev monitor还是input device的fd有事件来,都会通知到Weston和libinput的主循环。这些事件通过libinput中的事件缓冲队列存储,而Weston会作为消费者从中拿事件并根据事件类型进行处理。
2 按键适配处理分析
weston在嵌入式设备中运行,常采用的命令为:weston --tty=1 --backend=drm-backend.so ,后端采取的是drm对接显示硬件。drm-backend.so来自于weston/libweston/compositor_drm.c
drm_backend_create
udev_input_init -> process_events(input);
-> udev_input_enable
wl_event_loop_add_fd 将input设备添加到epoll中去监控
在udev_input_enable 中将输入设备的fd加入到epoll循环中,如果该设备信号可读,则触发回调函数:libinput_source_dispatch
libinput_source_dispatch
udev_input_dispatch
process_events(input)
第二个epoll循环:
while ((event = libinput_get_event(input->libinput))) {
process_event(event);
libinput_event_destroy(event);
}
在process_event中处理了udev和evdev事件:
process_event(struct libinput_event *event)
{
if (udev_input_process_event(event)) //设备add和remove
return;
if (evdev_device_process_event(event)) //设备数据读取处理
return;
}
evdev_device_process_event中处理了按键、鼠标、触摸事件,以按键处理为例:
evdev_device_process_event
handle_keyboard_key //按键事件处理
notify_key
在notify_key中可以分析出,按键按下之后,屏幕就会被唤醒。如果在此处进行按键键值替换,就可以实现自定义的按键亮屏。
weston_log("key is: %d",key);
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
weston_compositor_idle_inhibit(compositor);
} else {
weston_compositor_idle_release(compositor);
}
3 亮灭屏分析
weston框架下实现亮灭屏应该从用户层面分析,而非底层。比如用户层面的灭屏步骤中包含:LCD屏幕下电、焦点失能、上锁等一系列的操作,若只是实现了简单的LCD屏幕下电并不能真正的实现灭屏操作。
3.1 destop层面下的分析
那么首先我们从用户层面分析亮灭屏的操作,在/weston/desktop-shell/shell.c中,通过wet_shell_init初始化了亮灭屏的操作。如下所示:
shell->idle_listener.notify = idle_handler;//熄屏信号的回调函数
wl_signal_add(&ec->idle_signal, &shell->idle_listener);
shell->wake_listener.notify = wake_handler;//亮屏信号的回调函数
wl_signal_add(&ec->wake_signal, &shell->wake_listener);
idle_handler的实现为:
static void
idle_handler(struct wl_listener *listener, void *data)
{
struct desktop_shell *shell =
container_of(listener, struct desktop_shell, idle_listener);
struct weston_seat *seat;
wl_list_for_each(seat, &shell->compositor->seat_list, link)
weston_seat_break_desktop_grabs(seat);
shell_fade(shell, FADE_OUT);
/* lock() is called from shell_fade_done_for_output() */
}
其中shell_fade最终实现了lock操作
shell_fade
shell_fade_done_for_output
lock(shell);
lock中实现的操作
static void
lock(struct desktop_shell *shell)
{
struct workspace *ws = get_current_workspace(shell);
if (shell->locked) {
weston_compositor_sleep(shell->compositor);
return;
}
shell->locked = true;
/* Hide all surfaces by removing the fullscreen, panel and
* toplevel layers. This way nothing else can show or receive
* input events while we are locked. */
weston_layer_unset_position(&shell->panel_layer); //移除panel
weston_layer_unset_position(&shell->fullscreen_layer); //移除fullscreen
if (shell->showing_input_panels)
weston_layer_unset_position(&shell->input_panel_layer); //不会接收到输入事件
weston_layer_unset_position(&ws->layer);
weston_layer_set_position(&shell->lock_layer, //锁屏
WESTON_LAYER_POSITION_LOCK);
weston_compositor_sleep(shell->compositor); //进入睡眠状态
/* Remove the keyboard focus on all seats. This will be
* restored to the workspace's saved state via
* restore_focus_state when the compositor is unlocked */
unfocus_all_seats(shell); //焦点使能
/* TODO: disable bindings that should not work while locked. */
/* All this must be undone in resume_desktop(). */
}
所以上述的lock才是真正的实现了灭屏的一系列操作。
3.2 compositor层面下的分析
首先分析weston/compositor/main.c函数
weston_compositor_create
wl_event_loop_add_timer(loop, idle_handler, ec);
使用wl_event_loop_add_timer创建了一个定时器事件,定时器触发compositor中的idle_handler。
idle_handler的实现为:
static int
idle_handler(void *data)
{
struct weston_compositor *compositor = data;
if (compositor->idle_inhibit)
return 1;
compositor->state = WESTON_COMPOSITOR_IDLE;
wl_signal_emit(&compositor->idle_signal, compositor); //发送idle_signal信号
return 1;
}
所示wl_signal_emit发送WESTON_COMPOSITOR_IDLE信号,3.1节中的desktop-shell收到信号之后就执行完整的灭屏操作。
继续分析main.c中的内容,其中有一段:
if (idle_time < 0)
weston_config_section_get_int(section, "idle-time", &idle_time, -1);
if (idle_time < 0)
idle_time = 300; /* default idle timeout, in seconds */
ec->idle_time = idle_time;
ec->default_pointer_grab = NULL;
ec->exit = handle_exit;
.
.
.
weston_compositor_wake(ec);
该事件作用是什么呢?如果你对weston有比较深的了解,就会知道在weston默认灭屏事件为5分钟。上述的代码就是为了实现所述的功能。
首先设置了一个idle_time事件300,然后传递到weston_compositor_wake(ec)中去,weston_compositor_wake中的内容:
WL_EXPORT void
weston_compositor_wake(struct weston_compositor *compositor)
{
uint32_t old_state = compositor->state;
/* The state needs to be changed before emitting the wake
* signal because that may try to schedule a repaint which
* will not work if the compositor is still sleeping */
compositor->state = WESTON_COMPOSITOR_ACTIVE;
switch (old_state) { //开始时候,如果处于熄屏的各种状态,则唤醒;因为刚开机不需要灭屏
case WESTON_COMPOSITOR_SLEEPING:
case WESTON_COMPOSITOR_IDLE:
case WESTON_COMPOSITOR_OFFSCREEN:
weston_compositor_dpms(compositor, WESTON_DPMS_ON);
wl_signal_emit(&compositor->wake_signal, compositor);
/* fall through */
default: //开机之后,开启5分钟的定时灭屏操作
wl_event_source_timer_update(compositor->idle_source,
compositor->idle_time * 1000);
}
}
4 总结
如果需要灭屏,则状态为WESTON_COMPOSITOR_SLEEPING;WESTON_COMPOSITOR_IDLE;WESTON_COMPOSITOR_OFFSCREEN;执行
compositor->state = WESTON_COMPOSITOR_IDLE;
wl_signal_emit(&compositor->idle_signal, compositor);
如果需要亮屏,则执行唤醒操作:
weston_compositor_wake(ec);
自定义输入按键实现过程是一种 "自底向上" 的过程,上层destop-shell需要亮灭屏的操作是由底层的按键触发实现的。