среда, 21 августа 2013 г.

Понятие виджетов GNOME/GTK+

Попробуем коротко описать понятие виджета GTK. При изучении программирования на GTK необходимо понимать, что такое "программирование на Си в объектно-ориентированной манере". Речь идет не о объектном Си (языке программирования Objective C), а о об написании программ на "обычном" языке Си, но держа при этом написании в уме основные концепции ООП.

Объектно-ориентированный Си

  • Объектно-ориентированное программирование - это всего лишь метод организации данных и кодов. Библиотеки GNOME и GTK+ написаны на С, и их API состоит только из вызовов функций С. Тем не менее, код написан в объектно-ориентироанном стиле. Объектная ориентация не является частью языка С и ее пришлось имитировать. Имеется несколько характеристик объектов, относящихся к GNOME и GTK+, самыми важными из которых следует считать инкапсуляцию, наследование и методы.
  • Доступ к инкапсулированной информации может быть получен только посредством обращений к функциям, специально разработанным для этих целей. Эти функции называются методами.
  • Код, описывающий объект, называтся классом. Класс, из которого образуется другой класс, называется базовым. Все классы изначально происходят из GtkObject. Каждая структура включает в виде первого элемента полную структуру своего базового класса.
  • Для создания нового объекта используется метод. Все создающие объект функции имеют в своем имени слово new. Обычно функции, создающие  какой-либо виджет (кнопку, чекбокс и т.п.), возвращает указатель на структуру GtkWidget, а не структуру кнопки или чекбокса. Это возможно благодаря полиморфизму. Полиморфизм означает, что любой объект может рассматриваться в качестве одного из своих базовых классов.
  • Когда вызывается метод для работы с существующим объектом, адрес этого объекта передается как первый аргумент.
  • Методы всех классов в иерархии вызываются при использовании специальных макросов приведения типов данных. Для каждого виджета в GNOME и GTK+ имеется макрос приведения типов данных. Эти макросы делают несколько больше, чем просто приведение типов: во время работы приложения удостоверяют правильность приведения типов.
При программировании на  GTK важно понятие о событиях и их диспетчеризации.

 Последовательность диспетчеризации событий.

  • Происходит событие.
  • Соответствующая информация отправляутся менеджеру окон.
  • Менеджер окон имеет адрес очереди событий для каждого окна. Он преобразовывает полученные данные в стандартный для Х формат и ставит их в очередь, связанную с окном в которое послано событие.
  • Главный цикл приложения  использует низкоуровневую функцию системы Х для чтения событий из очереди. По идентификатору окна, присланному вместе с сообщением, программа определяет, какой из виджетов должен получить сигнал. Затем однп из функций GTK+ преобразует информацию в сигнал и передает его виджету.
  • Для каждого виджета существует функция, которая получает все поступающие сигналы.
  • Виджет просматривает список функций обратного вызова, которые связаны с определенным сигналом, и вызывает все эти функции.
Для создания сигнала можно применять функции g_signal_emit() g_signal_emit_by_name(). Соответствующие функции с префиксом gtk_ вместо g_ устарели и не рекомендуются для применения в "свежем" коде.Каждая функция обратного вызова имеет два общих параметра, но многие из функций имеют еще дополнительные параметры. Прототип самой простой функции обратного вызова выглядит так: 
void cb(GtkWidget*, gpointer); 
Если имеются дополнительные параметры, то они вставляются между двумя параметрами этого прототипа. Также кроме пустого типа могут возвращаться типы gint и boolean. На самом нижнем уровне создание события - это создание события Xevent. Xevent содержит тег, идентифицирующий окно, для которого это событие предназначено. Каждому событию соответствует своя структура. Каждая структура определена в виде двух частей. Первая - это собственно сама структура, а вторая - оператор typedef для этой структуры. Имена различаются только первым символом: имя структуры начинается символом подчеркивания.GdkEvent - это объединение нескольких структур событий. Чтобы облегчить задачу определения типа события и соответствующей ей структуры, первым полем во всех структурах является поле type. Для доступа к данным события напрямую можно выполнить приведение типа объединения к типу структуры. Какое именно приведение надовыполнить определяем из поля type.Информация о каждом событии содержится в структуре GSignalQuery. Ее поля заполняются с помощью функции g_signal_query().
typedef struct {
    guint signal_id;
    const gchar *signal_name;
    GType itype;
    GSignalFlags signal_flags;
    GType return_type; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */
    guint n_params;
    const GType *param_types; /* mangled with G_SIGNAL_TYPE_STATIC_SCOPE flag */
} GSignalQuery;
У каждого виджета есть внутренние установки, которые прикладная программа может читать или записывать.Приложению необходим интерфейс для обращения к этим установкам (аргументам)  внутри указанного виджета. То есть, чтобы прочитать или записать одно из этих значений, программа должна знать имя виджета, имя переменной и тип данных этой переменной. Итак, каждый аргумент имеет тип данных и права чтения/записи. Большинство аргументов имеют права и чтения и записи.Есть два способа установить значение аргументв внутри виджета.Есть фунции, закрепленные к определенному аргументу, который можно изменять с помощью этой функции. Соответственно есть фукция для чтения этого аргумента.Второй способ заключается в использовании структуры GtkArg, у которой три поля: GtkType - определяет тип данных, указательна строку, определяющую имя аргумента, и объединение различных типов данных.Когда виджет рождается и проходит свой путь от шаблона бит в памяти до графического объекта на экране, то происходят процессы создания, реализации, преобразования и отображения. При уничтожении виджета происходят: скрывание, уничтожение соответствия, деактивизация и разрушения. Виджет может скрываться и появляться вновь. При перемещении из одного окна в другое происходят уничтожение реализации, а потом реализация.Указанным этапам соответствуют такие функции:
*_new()
gtk_widget_destroy()
gtk_widget_unref()
gtk_widget_show()
gtk_widget_hide()
gtk_widget_map()
gtk_widget_unmap()
gtk_widget_realize()
gtk_widget_unrealize()
У виджетов есть также до пяти так называемых стилей (состояний):
GTK_STATE_NORMAL
GTK_STATE_ACTIVE
GTK_STATE_PRELIGHT
GTK_STATE_SELECTED
GTK_STATE_INSENSITIVE
Для первого "философского" понимания, что такое виджет GTK - этого достаточно.

четверг, 8 августа 2013 г.

Строковые типы в Windows

В Windows существует возможность писать код, который будет откомпилирован и корректно работать со строками или в ANSI представлении или юникоде, в зависимости от значения переменной _UNICODE. Рассмотрим это на примере.
char* string1 = "ANSI string";// не зависит от значения _UNICODE
wchar_t* string2 = L"UNICODE string";// не зависит от значения _UNICODE
LPTSTR string3=_T("or ANSI or UNICODE string"); // зависит от значения _UNICODE
LPTSTR string4=TEXT("or ANSI or UNICODE string"); // то же самое
LPTSTR -это макрос, который во время работы препроцессора раскрывается либо в wchar_t* либо в char*, в зависимости от _UNICODE. То же самое относится к макросам _T и TEXT - они раскрываются в L либо в "ничего".
Приведем таблицу соответсвия некоторых таких макросов и типов, а также наиболее типичных функций, работающих со строками. Имена типов комбинируются из достаточно простых и понятных составляющих:
LP означает long pointer,
C - constant,
STR - string,
WSTR - wide character string
, но все равно можно легко запутаться, поэтому эта табличка будет полезна:
В первой колонке написаны макросы которые раскрываются в значения во второй колонке, если мы работаем с ANSI строками или в значения в третей колонке, если мы работаем с юникодом. Вобщем, если мы хотим писать "универсальный" код, нам надо вместо функций или типов пользоваться соответствующими макросами.
 Более обильная информация по подобной теме представлена в MSDN в разделе Generic-Text Routine Mappings.