Ejemplo n.º 1
0
int main(int argc, char **argv)
{
    xcb_connection_t *connection = xcb_connect(NULL, &wm_conf.default_screen_num);
    if (xcb_connection_has_error(connection)) {
        fprintf(stderr, "failed to open display\n");
        exit(1);
    }

    init_wm_conf();
    init_conf_dir();
    wm_conf.connection = connection;

    const xcb_setup_t *setup = xcb_get_setup(connection);
    int num_screens = xcb_setup_roots_length(setup);
    fprintf(stderr, "init: num_screens = %d\n", num_screens);
    fprintf(stderr, "init: default_screen_num = %d\n", wm_conf.default_screen_num);

    xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
    wm_conf.screen = screen;
    xcb_window_t root_window = screen->root;

    xcb_grab_server(connection);
    xcb_flush(connection);

    xcb_event_handlers_t *event_handlers = &wm_conf.event_handlers;
    xcb_event_handlers_init(connection, event_handlers);
    set_exclusive_error_handler(event_handlers, handle_startup_error);
    /* Try to get substructure redirect events from root window.
     * This will cause an error if a window manager is already running.
     */
    const uint32_t sub_redirect = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;
    xcb_change_window_attributes(connection,
                                 root_window,
                                 XCB_CW_EVENT_MASK,
                                 &sub_redirect);

    /* Need to xcb_flush to validate error handler */
    xcb_aux_sync(connection);

    /* Process all errors in the queue if any */
    xcb_event_poll_for_event_loop(event_handlers);

    scan_windows();

    xinerama_test();

    set_exclusive_error_handler(event_handlers, handle_error);
    set_event_handlers(event_handlers);

    /* Allocate the key symbols */
    wm_conf.key_syms = xcb_key_symbols_alloc(connection);

    fprintf(stderr, "selecting events from root window\n");
    const uint32_t root_win_event_mask = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT |
        XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
        XCB_EVENT_MASK_ENTER_WINDOW |
        XCB_EVENT_MASK_LEAVE_WINDOW |
        XCB_EVENT_MASK_STRUCTURE_NOTIFY |
        XCB_EVENT_MASK_PROPERTY_CHANGE |
        XCB_EVENT_MASK_BUTTON_PRESS |
        XCB_EVENT_MASK_BUTTON_RELEASE |
        XCB_EVENT_MASK_FOCUS_CHANGE;
    xcb_change_window_attributes(connection, root_window, XCB_CW_EVENT_MASK, &root_win_event_mask);

    xcb_ungrab_server(connection);
    xcb_flush(connection);

    wm_conf.repl_server = repl_server_init();
    load_init_scheme();

    fprintf(stderr, "entering event loop\n");
    event_loop();

    xcb_disconnect(connection);

    return 0;
}
Ejemplo n.º 2
0
Archivo: unagi.c Proyecto: ehntoo/unagi
int
main(int argc, char **argv)
{
  memset(&globalconf, 0, sizeof(globalconf));

  globalconf.connection = xcb_connect(NULL, &globalconf.screen_nbr);
  if(xcb_connection_has_error(globalconf.connection))
    fatal("Cannot open display");

  /* Get the root window */
  globalconf.screen = xcb_aux_get_screen(globalconf.connection,
					 globalconf.screen_nbr);

  /* Set up signal handlers and function called on normal exit */
  struct sigaction sa;
  sigemptyset(&sa.sa_mask);
  sa.sa_handler = exit_on_signal;
  sa.sa_flags = 0;

  sigaction(SIGHUP, &sa, NULL);
  sigaction(SIGINT, &sa, NULL);
  sigaction(SIGTERM, &sa, NULL);

  atexit(exit_cleanup);

  /**
   * First round-trip
   */

  /* Send requests for EWMH atoms initialisation */
  xcb_intern_atom_cookie_t *ewmh_cookies = atoms_init();

  parse_command_line_parameters(argc, argv);

  /* Prefetch the extensions data */
  xcb_prefetch_extension_data(globalconf.connection, &xcb_composite_id);
  xcb_prefetch_extension_data(globalconf.connection, &xcb_damage_id);
  xcb_prefetch_extension_data(globalconf.connection, &xcb_xfixes_id);

  /* Initialise errors handlers */
  xcb_event_handlers_init(globalconf.connection, &globalconf.evenths);
  event_init_start_handlers();

  /* Pre-initialisation of the rendering backend */
  if(!rendering_load())
    {
      free(ewmh_cookies);
      fatal("Can't initialise rendering backend");
    }

  /* Get replies for EWMH atoms initialisation */
  if(!atoms_init_finalise(ewmh_cookies))
    /* No need to  free ewmh_cookies in case of  error as it's already
       handles by xcb-ewmh when getting the replies */
    fatal("Cannot initialise atoms");

  /* First check whether there is already a Compositing Manager (ICCCM) */
  xcb_get_selection_owner_cookie_t wm_cm_owner_cookie =
    xcb_ewmh_get_wm_cm_owner(&globalconf.ewmh, globalconf.screen_nbr);

  /**
   * Second round-trip
   */

  /* Initialise   extensions   based   on   the  cache   and   perform
     initialisation of the rendering backend */
  display_init_extensions();
  if(!(*globalconf.rendering->init)())
    return EXIT_FAILURE;

  /* Check ownership for WM_CM_Sn before actually claiming it (ICCCM) */
  xcb_window_t wm_cm_owner_win;
  if(xcb_ewmh_get_wm_cm_owner_reply(&globalconf.ewmh, wm_cm_owner_cookie,
				    &wm_cm_owner_win, NULL) &&
     wm_cm_owner_win != XCB_NONE)
    fatal("A compositing manager is already active (window=%jx)",
	  (uintmax_t) wm_cm_owner_win);

  /* Now send requests to register the CM */
  display_register_cm();
  
  /**
   * Third round-trip
   */

  /* Check  extensions  version   and  finish  initialisation  of  the
     rendering backend */
  display_init_extensions_finalise();
  if(!(*globalconf.rendering->init_finalise)())
    return EXIT_FAILURE;

  /* All the plugins given in the configuration file */
  plugin_load_all();

  /* Validate  errors   and  get  PropertyNotify   needed  to  acquire
     _NET_WM_CM_Sn ownership */
  xcb_aux_sync(globalconf.connection);
  xcb_event_poll_for_event_loop(&globalconf.evenths);

  globalconf.keysyms = xcb_key_symbols_alloc(globalconf.connection);
  xcb_get_modifier_mapping_cookie_t key_mapping_cookie =
    xcb_get_modifier_mapping_unchecked(globalconf.connection);

  /* Finish CM X registration */
  if(!display_register_cm_finalise())
    fatal("Could not acquire _NET_WM_CM_Sn ownership");

  /**
   * Last initialisation round-trip
   */

  /* Grab the server before performing redirection and get the tree of
     windows  to ensure  there  won't  be anything  else  at the  same
     time */
  xcb_grab_server(globalconf.connection);

  /* Now redirect windows and add existing windows */
  display_init_redirect();

  /* Validate errors handlers during redirect */
  xcb_aux_sync(globalconf.connection);
  xcb_event_poll_for_event_loop(&globalconf.evenths);

  /* Manage existing windows */
  display_init_redirect_finalise();

  xcb_ungrab_server(globalconf.connection);

  /* Check the  plugin requirements  which will disable  plugins which
     don't meet the requirements */
  plugin_check_requirements();

  /* Get the lock masks reply of the request previously sent */ 
  key_lock_mask_get_reply(key_mapping_cookie);

  /* Initialise normal errors and events handlers */
  event_init_handlers();

  xcb_generic_event_t *event;

  /* Flush existing  requests before  the loop as  DamageNotify events
     may have been received in the meantime */
  xcb_flush(globalconf.connection);
  globalconf.do_repaint = true;

  /* Main event and error loop */
  do
    {
      /* Block until an event is received */
      event = xcb_wait_for_event(globalconf.connection);

      /* Check X connection to avoid SIGSEGV */
      if(xcb_connection_has_error(globalconf.connection))
	 fatal("X connection invalid");

      xcb_event_handle(&globalconf.evenths, event);
      free(event);

      /* Then process all remaining events in the queue because before
	 painting, all the DamageNotify have to be received */
      xcb_event_poll_for_event_loop(&globalconf.evenths);

      /* Now paint the windows */
      if(globalconf.do_repaint)
	{
	  window_t *windows = NULL;
	  for(plugin_t *plugin = globalconf.plugins; plugin; plugin = plugin->next)
	    if(plugin->enable && plugin->vtable->render_windows &&
	       (windows = (*plugin->vtable->render_windows)()))
	      break;

	  if(!windows)
	    windows = globalconf.windows;

	  window_paint_all(windows);
	  xcb_aux_sync(globalconf.connection);
	}

      globalconf.do_repaint = false;
    }
  while(true);

  return EXIT_SUCCESS;
}