Archive:Development/Tutorials/Session Management (zh CN)

From KDE TechBase


Template:TutorialBrowser (zh CN)

关于KDE和X11的会话管理

从KDE 1.0起,遗留的X11R4和ICCCM会话管理协议就被支持着。Legacy applications that define the WM_COMMAND property or support the WM_SAVE_YOURSELF protocol will be restarted with the specified command. 窗口坐标会以最佳效果恢复。

从KDE 2.0起,X11R6会话管理标准,XSMP也被广泛支持和使用。该标准的官方文档可以从X Consortium的FTP服务器上下载 ftp.x.org。与其他遗留协议不同,新的X11R6会话管理允许在登出后保存应用无关设置。例如对一个文本编辑器,可以保存已加载的文件名,并会您再次登录加载它们。另一项新协议的主要的应用是支持干净和安全的注销流程,即使用户决定下一次不恢复会话。该协议使应用与用户之间的交互变得可能,特别是在一些丢失数据的危险情况,如果有必要的话可以取消关机进程。

更多阅读

doc.trolltech.com,有更多关于会话管理功能和QT API的介绍.

KDE里, KApplicationKMainWindow类对程序员隐藏了许多不必要的细节。基本上,一个 KApplication为你管理一个 KConfig 配置对象(通过 KApplication::sessionConfig()) ,这样你的应用就可以保存一些会话专用数据了。

Please read the respective class documentation, especially the one of KMainWindow, for a detailed interface description. With the advanced functionality in KMainWindow, it's really just a matter of a few lines to get even a multi-window application to retains its state between different user sessions.

在你的应用中实现会话管理

这里只是一个概要描述。详细内容见相关文档。

实现会话管理并不难。如果你的窗口从KMainWindow继承,你只要做两件事:

  • 实现几个KMainWindow的虚函数。
  • 在main()添加会话管理。

就这样。

重写KMainWindow的虚函数

KMainWindow will automatically save its position, geometry and positions of toolbars and menubar on logout - and restore it on the next startup.

For every other data that your application needs to restore a session, you have to write the code for saving and restoring yourself. However, KMainWindow makes this task easy. You can just re-implement the following functions:

  • saveProperties(): This function is called only when the application is closed by the session manager (and not, when the application is closed by the user). To save the data that you need to restore the session, reimplement this function. (For a text editor for example, that would be the list of loaded files) Note that no user interaction is allowed in this function! (For example, you may not display any dialog!)
  • readProperties(): 下次登录是读入额外数据,重写这个函数。

另外,queryClose()也会让你有所兴趣。这个函数一直在窗口关闭之前被调用, 或是用户调用或是会话管理器调用。通常,你可以在这里提醒用户应用或窗口在退出关闭时有未保存的数据(例如: 跳出一个对话框提醒"保存变更" 或"忽略变更")。然而,对有些会话管理来说,退出前要用户确认并不是件好事,你也可以避免它的发生。注意:saveProperties()queryClose()之前或之后调用并不起决定作用!

To save your application-wide properties (data that is only needed once per application, and not for each main window instance) reimplement saveGlobalProperties() and it's counterpart readGlobalProperties. Normally, you don't need these functions.

给你的main()函数添加会话管理

While KMainWindow::saveProperties() (and also KMainWindow::queryClose()) will be called automatically, KMainWindow::readProperties() will not. You have to add some code to your main() function to implement session restoring.

如果你的应用有一个主窗口,MyWindow,他继承与 KMainWindow (或从 KXmlGuiWindow, 他继承于 KMainWindow)。在你的main()函数内,要加上下列代码来创建/恢复窗口:

KApplication app;
if ( app.isSessionRestored() ) {
  kRestoreMainWindows< MyWindow >();
} else {
  // 像往常一样创建缺省应用
  // 例如:
  MyWindow * window = new MyWindow();
  // #会被替换为一个数字以确保在应用系统内唯一:
  window->setObjectName("MyWindow#");
  window->show();
}
return app.exec();

kRestoreMainWindows<>() 会(在堆上)创建as many instances of your main windows as have existed in the last session and call KMainWindow::restore() with the correct arguments. 注意QWidget::show()是隐式调用的。

关于setObjectName("MyWindow#"): 为让会话管理和窗口管理的正常工作,所有的应用程序主窗口应该有一个各不相同的名称。如果你不这样做,KMainWindow会创建一个唯一的名称,但它建议明确传递一个能描述窗口类型的名称。如果能够有同类型的几个窗口,请将'#'(散列值)加到名称上,同时KMainWindow将会用数字替代,使这个名称在应用中唯一。例如, for a mail client which has one main window showing the mails and folders, and which can also have one or more windows for composing mails, the name for the folders window should be e.g. "mainwindow" and for the composer windows "composer#".

这样你就可以简单的恢复所有应用的顶层窗口了。

他也同样适用于一个应用中的其他各类顶层窗口(只要从KMainWindow继承就行)。如果你的主窗口有三个类:childMW1, childMW2 and childMW3:

KApplication app;
if ( app.isSessionRestored() ) {
  kRestoreMainWindows< childMW1, childMW2, childMW3 >();
} else {
  // 像往常一样创建缺省应用
  // 例如:
  childMW1* window1 = new childMW1();
  childMW2* window2 = new childMW2();
  childMW3* window3 = new childMW3();
  // #会被替换为一个数字以确保在应用系统内唯一:
  window1->setObjectName("type1mainWindow#");
  window2->setObjectName("type2mainWindow#");
  window3->setObjectName("type3mainWindow#");
  window1->show();
  window2->show();
  window3->show();
}
return app.exec();

当前,kRestoreMainWindows<>() 函数模板提供了至多三个参数。

附录: KDE会话管理的架构

在KDE中,会话管理服务器称为KSMServer,它是在KDEBbase包的一部分。 KSMServer服务器与与KDE的窗口管理器KWin相互作用,以保存和还原窗口的几何尺寸和执行旧会话管理。为了使会话管理有效,KSMSserver必须是X登录过程的最后一个进程。这会自动在startkde脚本的末尾执行。

初始作者: Matthias Ettrich