Как выйти из программы X11 без ошибок

у меня есть довольно простой "Hello World" в X11 в конце вопроса. Но когда он выходит, я получаю сообщения об ошибках времени выполнения ниже:

$ ./xtest
XIO:  fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
      after 9 requests (7 known processed) with 0 events remaining.

поэтому я попытался справиться с wmDeleteMessage себя, и я смог остановить окно от закрытия, поэтому я знаю, что правильно понимаю событие. Чем я добавил XDestroyWindow() к обработке событий, и я получаю новые ошибки.

X Error of failed request:  BadWindow (invalid Window parameter)
  Major opcode of failed request:  4 (X_DestroyWindow)
  Resource id in failed request:  0x130
  Serial number of failed request:  12
  Current serial number in output stream:  12

похоже, я пытаюсь уничтожить уже разрушенное окно, но если я достану XDestroyWindow() это остается живым на моем экране.

Ниже приведен мой код с попыткой уничтожить обработчик окна. Как выйти без ошибок?

#include<X11/Xlib.h>
#include <iostream>

int main()
{
  Display *display;
    if(!(display=XOpenDisplay(NULL))) 
    {
      std::cerr << "ERROR: could not open displayn";
      return 1;
    }

  int screen = DefaultScreen(display);
  Window rootwind = RootWindow(display, screen);
  Colormap cmap = DefaultColormap(display, screen);      
  Atom wmDeleteMessage = XInternAtom(display, "WM_DELETE_WINDOW", False);

  int blackColor = BlackPixel(display, screen);
  int whiteColor = WhitePixel(display, screen);

  Window w = XCreateSimpleWindow(display, rootwind, 0, 0, 200, 100, 0, blackColor, blackColor);
  XMapWindow(display, w);
  XSetWMProtocols(display, w, &wmDeleteMessage, 1);
  bool running = true;
  while(running) 
  {
    XEvent e;
    XNextEvent(display, &e);      
    switch  (e.type) 
    {
      case ClientMessage:
        if(e.xclient.data.l[0] == wmDeleteMessage) 
        {
          std::cout << "Shutting down now!!!" << std::endl;
          XDestroyWindow(display,e.xdestroywindow.window);
          running=false;
          break;
        }
        break;
    }
  }

    XCloseDisplay(display);
    return 0;
}

обновление

изменить строки :

   std::cout << "Shutting down now!!!" << std::endl;
        XDestroyWindow(display,w);

что мне не нравится, потому что я планирую иметь больше, чем окно, но сейчас я вернемся к первому сообщению об ошибке:

XIO:  fatal IO error 11 (Resource temporarily unavailable) on X server ":0"
      after 9 requests (7 known processed) with 0 events remaining.

обновление

пробовал изменить много вещей вокруг, как иметь цикл запускается из XPending (). Решил запустить чужой Привет, мир и у меня такая же проблема с их кодом. Должно быть, что-то не так с моей установкой.

обновление По-видимому, у многих людей есть эта проблема. У Google ftk была эта проблема, и они исправили ее в своем изменение входа. Они называют FTK_QUIT (), который, как я предполагаю, похож на Exit (). Поэтому я положил свое возвращение прямо туда внутри петли, и это решило проблему. Не знаю, почему но это случилось. исправленный код:

  case ClientMessage:
    if(e.xclient.data.l[0] == wmDeleteMessage) 
    {
      XDestroyWindow(display,e.xclient.window);
      XCloseDisplay(display);
      return 0;
    }

все равно даст правильный ответ кому-то, кто может объяснить, почему и если возможно переместить оператор возврата (вместе с XCloseDisplay) вне цикла.


цикл событий должен выглядеть так, чтобы выйти правильно:

  XEvent e;
  do
  {
    XNextEvent(display, &e);      
    if(e.type == ClientMessage && e.xclient.data.l[0] == wmDeleteMessage) 
    {
      XDestroyWindow(display,e.xclient.window);
      break;    
    }
    //...
  }while (XPending(display) > 0)
  XCloseDisplay(display);
  return 0;

при запуске в switch инструкция код не работает. Даже если он выходит из цикла без вызова другой функции X. The if заявление, поставленных перед вашим switch оператор исправляет проблему, не возвращаясь из программы внутри цикла.

3 ответов


решение этой проблемы очень простое:

вы должны использовать правильный элемент структуры с XDestroyWindow (функция).

из-за стандарта реализации структур событий X11 они очень похожи друг на друга. Каждая структура начинается с члена "типа", и первые члены практически всегда одинаковы.

Теперь предположим:

int = 4 bytes
Bool = 4 bytes
unsigned long = 8 bytes
Display* = 8 bytes
Window = 4 bytes

Если вы называете XDestroyWindow() С Эл.xdestroywindow.окно, вы будете в 28 байтах от начала структуры событий, в то время как если вы используете Эл.xclient.окно, у вас будет 24 байт.

Так как вы собираетесь назвать XDestroyWindow () с неправильным аргументом окна он потерпит неудачу. Вместо этого, если вы называете это с помощью Эл.xdestroywindow.событие (что составляет 24 байта от начала структуры событий), адрес будет правильным и функция будет корректно работать.

Если вы посмотрите сами на Xlib.h файл, Вы заметите, что две структуры имеют окно элемент расположен по-разному.

заявил Это, помните, что Xlib был разработан в течение многих лет, и многие программисты каждый день работают с ним, поэтому, если есть таинственная ошибка, это, вероятно, не в Xlib. В качестве последнего намека я хочу сказать вам: если вы хотите продвинуться дальше в программировании Xlib, всегда берите заголовочные файлы в качестве основной ссылки, а затем руководство по системе, а затем все остальное.

единственная ошибка с вашим кодом в конце:

XDestroyWindow(display,e.xdestroywindow.window);

, который должен быть изменен на этот:

XDestroyWindow(display,e.xclient.window);

вместо использования переключатель хорошо, и является наиболее реализованным, без каких-либо проблем с кодом X11.

Примечание: я сам протестировал ваш код, изменив только эту строку, а затем выполнив различные тесты, распечатав результат. The XDestroyWindow() строка наверняка является единственной ошибкой.


просто позвони XDestroyWindow() перед XCloseDisplay().

Edit:

Извините, я не понял XSetWMProtocols вещь. Теперь я прочитал об этом. Я думаю, вы обращаетесь не к тому члену профсоюза.

XDestroyWindow(дисплей, e.xdestroywindow.окно);

вероятно, должно быть:

XDestroyWindow(display,e.xclient.window);

у меня была та же проблема, и после копания в документации Xlib и многих экспериментов я думаю, что знаю ответ на ваш вопрос, и я могу объяснить его вам.

когда вы называете XCreateWindow или XCreateSimpleWindow а то XMapWindow, вы поручаете X-серверу создать окно и отобразить его на экране. После отправки этих команд из локального буфера на сервер (путем вызова XFlush или любая функция, которая запрашивает некоторые данные с сервера, поскольку она неявно сбрасывает командный буфер), X-сервер отображает ваше окно. Тогда это работа оконного менеджера, чтобы прикрепить все украшения к вашему окну, например, некоторые границы, заголовка, меню окна и кнопки для сворачивания/разворачивания/закрытия окна.

теперь отображается ваше окно, и через некоторое время вы можете решить уничтожить его с помощью XDestroyWindow и закройте соединение с X-сервером, вызвав XCloseDisplay, и все будет хорошо, никаких ошибок.

проблема что, когда пользователь нажимает на что X в строке заголовка вашего окна это не работа X-сервера для его обработки, а работа оконного менеджера (X-сервер ничего не знает об этих украшениях, и ему все равно). Обычная реакция оконного менеджера, когда пользователь закрывает окно верхнего уровня программы для уничтожить окно и закрыть соединение с X-сервером, потому что это то, что ожидало бы большинство пользователей. Ваша программа может по-прежнему выполняется вне экрана, но окно верхнего уровня обычно связано с подключением X-сервера оконным менеджером.

поэтому, когда диспетчер окон уничтожает ваше окно, вы не можете вызвать XDestroyWindow, потому что окно уже уничтожено и его Window недопустимый дескриптор. Вы получите сообщение об ошибке BadWindow. Вы также не можете позвонить XCloseDisplay, потому что соединение с X-сервером уже закрыто, и это вызовет XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ошибка многие пользователи испытывают от приложений чьи авторы этого не знали. Это распространенная ошибка, потому что, с одной стороны, вам рекомендуется убирать за собой, но, с другой стороны, документация вводит в заблуждение о том, как это должно быть сделано правильно.

существует соглашение о том, как X Server и Window Manager должны сотрудничать, которое также охватывает ответ на команды пользователя, чтобы закрыть окно верхнего уровня. Есть расширение к протоколу X, который обрабатывает его. Вот как на Xlib документация объясняет это:

клиенты, обычно с несколькими окнами верхнего уровня, чье соединение с сервером должно пережить удаление некоторых из их окон верхнего уровня, должны включать atom WM_DELETE_WINDOW на WM_PROTOCOLS свойство в каждом таком окне. Они получат ClientMessage событие, как описано выше которого