Xfce漫游(4) - 进入桌面环境

书接上文,在连接到dbus之后,xfce4-session就进入事件循环了,而在之前的几步被跳过了。Xfconf是管理各种设置项的,其实就是管理设置项并基于dbus让其他进程能访问整个桌面的设置的进程。顺便一提,xfconfd是个systemd单元而不是xfce4-session手动启动的。总之我们还是关心一下桌面绘制出来的流程吧。

会话恢复或新会话

上回看到了bus_acquired的行为,它首先是创建了实例并把接口信息注册到DBus中。之后的步骤中从xfconf加载了会话(xfsm_manager_load (*manager, channel);),一步步走到xfsm_manager_load_settings

  session_loaded = xfsm_manager_load_session (manager, channel);

  if (session_loaded)
    {
      xfsm_verbose ("Session \"%s\" loaded successfully.\n\n", manager->session_name);
      manager->failsafe_mode = FALSE;
    }
  else
    {
      gchar *errorstr = NULL;

      if (!xfsm_manager_load_failsafe (manager, channel, &errorstr))
        {
          /* FIXME: migrate this into the splash screen somehow so the
           * window doesn't look ugly (right now no WM is running, so it
           * won't have window decorations). */
          xfce_message_dialog (NULL, _("Session Manager Error"),
                               "dialog-error", _("Unable to load a failsafe session"),
                               errorstr,
                               XFCE_BUTTON_TYPE_MIXED, "application-exit", _("_Quit"), GTK_RESPONSE_ACCEPT, NULL);
          g_free (errorstr);
          exit (EXIT_FAILURE);
        }
      manager->failsafe_mode = TRUE;
    }
}

代码大意就是读取~/.cache/sessions/xfce4-session-<uuid>中的会话,如果无就failsafe模式加载默认会话。我用了这么久xfce从来不保存会话,所以都是进入了failsafe模式,继续看load_failsafe,其内容大致就是将conf中一个FailSafe方案都推入manager->pending_properties队列中,这个方案的内容是:

  • xfwm4: Xfce4的窗口管理器
  • xfsettingsd: 管理系统设置
  • xfce4-panel: 面板
  • Thunar --daemon: 文件管理器的daemon
  • xfdesktop: 桌面

当然,如果保存了会话的话,会话中每个保存了的程序都会附有更加详细的信息,程序就按照那里的内容读取。

接下来就是调用xfsm_manager_restart (*manager);启动会话队列中的程序了,兜兜转转之下:

void
xfsm_startup_session_continue (XfsmManager *manager)
{
  GQueue *pending_properties = xfsm_manager_get_queue (manager, XFSM_MANAGER_QUEUE_PENDING_PROPS);
  gboolean client_started = FALSE;

  /* try to start some clients.  if we fail to start anything in the current
   * priority group, move right to the next one.  if we *did* start something,
   * the failed/registered handlers will take care of moving us on to the
   * next priority group */
  while (client_started == FALSE && g_queue_peek_head (pending_properties) != NULL)
    client_started = xfsm_startup_session_next_prio_group (manager);

代码的大致意思就是不断从队列弹出,然后启动它。根据如上所述,队列中应该是有5个元素,因此就启动了它们。

应用程序自启动

但是实际上他还需要启动输入法、redshift以及其他用户自定义的自启动程序等。这些东西一般位于~/.config/autostart/etc/xdg/autostart底下,属于XDG Autostart的管理的部分之一。

之前略过了ENABLE_X11之下的内容,因为代码编辑器没认出这个宏把他标灰色了= = 漏了个init_display没看,反正快进到sm_init,这里向XSM和ICE注册了manager。这俩又是啥。。这就得去找libSM和libICE了,两个都是Xorg提供的库,重点关注第一个就行了,后者是辅助session manager库的。

总之从代码看,当Sm client连入时,会调用sm_new_client。sm client一般指的是一个包含需要在X display上进行显示的进程,不过也不一定,比如各种什么什么d。sm client的功能有:

  • 建立与关闭到sm server的连接
  • 修改callback
  • 设定、删除、修改会话管理器属性
  • 与用户交互
  • 进行"Save Yourself"系列操作(将自己保存到会话文件)

总之xfce session manager会为每个client都创建一个XfsmClient,它们各自对应DBus connection中的一个对象。之前当会话启动时,从那个队列中不断启动程序时,像xfwm这样的程序就会作为client加入到session manager,于是调用sm_new_client。新client沿用manager的dbus连接,并在那里创建表示自身的新对象。根据协议,当连接建立后,会立刻调用regist client对应的callback。兜兜转转后来到这里:

  if ((previous_id != NULL || manager->failsafe_mode)
      && manager->state == XFSM_MANAGER_STARTUP)
    {
      /* Only continue the startup if the previous_id matched one of
       * the starting_properties. If there was no match above,
       * previous_id will be NULL here.  We don't need to continue when
       * in failsafe mode because in that case the failsafe session is
       * started all at once.
       */
      if (manager->failsafe_mode)
        {
          if (--manager->failsafe_clients_pending == 0)
            g_queue_clear (manager->starting_properties);
        }
      if (g_queue_peek_head (manager->starting_properties) == NULL)
        xfsm_startup_session_continue (manager);
    }

这里会多次调用xfsm_startup_session_continue。当队列空时,表示优先级高的程序都已启动,最后完成自启动程序的启动:

  if (G_UNLIKELY (client_started == FALSE && g_queue_peek_head (pending_properties) == NULL))
    {
      /* we failed to start anything, and we don't have anything else,
       * to start, so just move on to the autostart items and signal
       * the manager that we're finished */
      xfsm_verbose ("Nothing started and nothing to start, moving to autostart items\n");
      xfsm_startup_autostart (manager);
      xfsm_manager_signal_startup_done (manager);
    }
}

顺着带autostart的函数稍微探索一下之后,就能找到读取与执行自启动文件的代码。

posted @ 2025-04-25 04:45  Notify-ctrl  阅读(123)  评论(0)    收藏  举报