PageRenderTime 14ms CodeModel.GetById 38ms app.highlight 94ms RepoModel.GetById 1ms app.codeStats 0ms

/libgxim/gximmisc.c

https://bitbucket.org/tagoh/libgxim
C | 3748 lines | 3086 code | 568 blank | 94 comment | 427 complexity | 9ea8c823d030f144d3f31c6845184b52 MD5 | raw file
Possible License(s): LGPL-2.1
   1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
   2/* 
   3 * gximmisc.c
   4 * Copyright (C) 2008-2011 Akira TAGOH
   5 * 
   6 * Authors:
   7 *   Akira TAGOH  <akira@tagoh.org>
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation; either
  12 * version 2 of the License, or (at your option) any later version.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the
  21 * Free Software Foundation, Inc., 51 Franklin Street, Fifth
  22 * Floor, Boston, MA  02110-1301  USA
  23 */
  24#ifdef HAVE_CONFIG_H
  25#include "config.h"
  26#endif
  27
  28#ifdef HAVE_STRING_H
  29#include <string.h>
  30#endif
  31#ifdef HAVE_STDINT_H
  32#include <stdint.h>
  33#endif
  34#include <gdk/gdkprivate.h>
  35#include <gdk/gdkkeysyms.h>
  36#include <gdk/gdkx.h>
  37#include "gximattr.h"
  38#include "gximerror.h"
  39#include "gximmessages.h"
  40#include "gximmisc.h"
  41#include "gximprotocol.h"
  42
  43#define N_REALLOC_NESTED_LIST	16
  44
  45static GXimMessages *master_message = NULL;
  46
  47/*
  48 * Private functions
  49 */
  50static gint
  51g_xim_gdkevent_translate_event_type(GdkEvent *event)
  52{
  53	switch (event->type) {
  54	    case GDK_NOTHING:
  55	    case GDK_DELETE:
  56		    goto unsupported;
  57	    case GDK_DESTROY:
  58		    return DestroyNotify;
  59	    case GDK_EXPOSE:
  60		    return Expose;
  61	    case GDK_MOTION_NOTIFY:
  62		    return MotionNotify;
  63	    case GDK_BUTTON_PRESS:
  64	    case GDK_2BUTTON_PRESS:
  65	    case GDK_3BUTTON_PRESS:
  66		    return ButtonPress;
  67	    case GDK_BUTTON_RELEASE:
  68		    return ButtonRelease;
  69	    case GDK_KEY_PRESS:
  70		    return KeyPress;
  71	    case GDK_KEY_RELEASE:
  72		    return KeyRelease;
  73	    case GDK_ENTER_NOTIFY:
  74		    return EnterNotify;
  75	    case GDK_LEAVE_NOTIFY:
  76		    return LeaveNotify;
  77	    case GDK_FOCUS_CHANGE:
  78		    if (event->focus_change.in)
  79			    return FocusIn;
  80		    else
  81			    return FocusOut;
  82	    case GDK_CONFIGURE:
  83		    return ConfigureNotify;
  84	    case GDK_MAP:
  85		    return MapNotify;
  86	    case GDK_UNMAP:
  87		    return UnmapNotify;
  88	    case GDK_PROPERTY_NOTIFY:
  89		    return PropertyNotify;
  90	    case GDK_SELECTION_CLEAR:
  91		    return SelectionClear;
  92	    case GDK_SELECTION_REQUEST:
  93		    return SelectionRequest;
  94	    case GDK_SELECTION_NOTIFY:
  95		    return SelectionNotify;
  96	    case GDK_PROXIMITY_IN:
  97	    case GDK_PROXIMITY_OUT:
  98	    case GDK_DRAG_ENTER:
  99	    case GDK_DRAG_LEAVE:
 100	    case GDK_DRAG_MOTION:
 101	    case GDK_DRAG_STATUS:
 102	    case GDK_DROP_START:
 103	    case GDK_DROP_FINISHED:
 104		    goto unsupported;
 105	    case GDK_CLIENT_EVENT:
 106		    return ClientMessage;
 107	    case GDK_VISIBILITY_NOTIFY:
 108		    return VisibilityNotify;
 109	    case GDK_NO_EXPOSE:
 110		    return NoExpose;
 111	    case GDK_SCROLL:
 112		    return ButtonPress;
 113	    case GDK_WINDOW_STATE:
 114	    case GDK_SETTING:
 115	    case GDK_OWNER_CHANGE:
 116	    case GDK_GRAB_BROKEN:
 117	    default:
 118	    unsupported:
 119		    break;
 120	}
 121
 122	return 0;
 123}
 124
 125static GdkEventType
 126g_xim_xevent_translate_event_type(gint type)
 127{
 128	switch (type & 0x7f) {
 129	    case KeyPress:
 130		    return GDK_KEY_PRESS;
 131	    case KeyRelease:
 132		    return GDK_KEY_RELEASE;
 133	    case ButtonPress:
 134		    return GDK_BUTTON_PRESS;
 135	    case ButtonRelease:
 136		    return GDK_BUTTON_RELEASE;
 137	    case MotionNotify:
 138		    return GDK_MOTION_NOTIFY;
 139	    case EnterNotify:
 140		    return GDK_ENTER_NOTIFY;
 141	    case LeaveNotify:
 142		    return GDK_LEAVE_NOTIFY;
 143	    case FocusIn:
 144	    case FocusOut:
 145		    return GDK_FOCUS_CHANGE;
 146	    case KeymapNotify:
 147		    goto unsupported;
 148	    case Expose:
 149	    case GraphicsExpose:
 150		    return GDK_EXPOSE;
 151	    case NoExpose:
 152		    return GDK_NO_EXPOSE;
 153	    case VisibilityNotify:
 154		    return GDK_VISIBILITY_NOTIFY;
 155	    case CreateNotify:
 156		    goto unsupported;
 157	    case DestroyNotify:
 158		    return GDK_DESTROY;
 159	    case UnmapNotify:
 160		    return GDK_UNMAP;
 161	    case MapNotify:
 162		    return GDK_MAP;
 163	    case MapRequest:
 164	    case ReparentNotify:
 165		    goto unsupported;
 166	    case ConfigureNotify:
 167		    return GDK_CONFIGURE;
 168	    case ConfigureRequest:
 169	    case GravityNotify:
 170	    case ResizeRequest:
 171	    case CirculateNotify:
 172	    case CirculateRequest:
 173		    goto unsupported;
 174	    case PropertyNotify:
 175		    return GDK_PROPERTY_NOTIFY;
 176	    case SelectionClear:
 177		    return GDK_SELECTION_CLEAR;
 178	    case SelectionRequest:
 179		    return GDK_SELECTION_REQUEST;
 180	    case SelectionNotify:
 181		    return GDK_SELECTION_NOTIFY;
 182	    case ColormapNotify:
 183		    goto unsupported;
 184	    case ClientMessage:
 185		    return GDK_CLIENT_EVENT;
 186	    case MappingNotify:
 187		    goto unsupported;
 188	    default:
 189	    unsupported:
 190		    break;
 191	}
 192
 193	return GDK_NOTHING;
 194}
 195
 196static const gchar *
 197g_xim_gdkevent_type_name(gint type)
 198{
 199	static const gchar *event_names =
 200		"\0"
 201		"KeyPress\0"
 202		"KeyRelease\0"
 203		"ButtonPress\0"
 204		"ButtonRelease\0"
 205		"MotionNotify\0"
 206		"EnterNotify\0"
 207		"LeaveNotify\0"
 208		"FocusIn\0"
 209		"FocusOut\0"
 210		"KeymapNotify\0"
 211		"Expose\0"
 212		"GraphicsExpose\0"
 213		"NoExpose\0"
 214		"VisibilityNotify\0"
 215		"CreateNotify\0"
 216		"DestroyNotify\0"
 217		"UnmapNotify\0"
 218		"MapNotify\0"
 219		"ReparentNotify\0"
 220		"ConfigureNotify\0"
 221		"ConfigureRequest\0"
 222		"GravityNotify\0"
 223		"ResizeRequest\0"
 224		"CirculateNotify\0"
 225		"CirculateRequest\0"
 226		"PropertyNotify\0"
 227		"SelectionClear\0"
 228		"SelectionRequest\0"
 229		"SelectionNotify\0"
 230		"ColormapNotify\0"
 231		"ClientMessage\0"
 232		"MappingNotify\0";
 233	static guint type2pos[LASTEvent];
 234	static gboolean initialized = FALSE;
 235
 236	if (!initialized) {
 237		memset(type2pos, 0, sizeof (guint) * (LASTEvent - 1));
 238		type2pos[KeyPress] = 1;
 239		type2pos[KeyRelease] = 10;
 240		type2pos[ButtonPress] = 21;
 241		type2pos[ButtonRelease] = 33;
 242		type2pos[MotionNotify] = 47;
 243		type2pos[EnterNotify] = 60;
 244		type2pos[LeaveNotify] = 72;
 245		type2pos[FocusIn] = 84;
 246		type2pos[FocusOut] = 92;
 247		type2pos[KeymapNotify] = 101;
 248		type2pos[Expose] = 114;
 249		type2pos[GraphicsExpose] = 121;
 250		type2pos[NoExpose] = 136;
 251		type2pos[VisibilityNotify] = 145;
 252		type2pos[CreateNotify] = 162;
 253		type2pos[DestroyNotify] = 175;
 254		type2pos[UnmapNotify] = 189;
 255		type2pos[MapNotify] = 201;
 256		type2pos[MapRequest] = 211;
 257		type2pos[ReparentNotify] = 226;
 258		type2pos[ConfigureNotify] = 242;
 259		type2pos[ConfigureRequest] = 259;
 260		type2pos[GravityNotify] = 273;
 261		type2pos[ResizeRequest] = 287;
 262		type2pos[CirculateNotify] = 303;
 263		type2pos[CirculateRequest] = 320;
 264		type2pos[PropertyNotify] = 335;
 265		type2pos[SelectionClear] = 350;
 266		type2pos[SelectionRequest] = 367;
 267		type2pos[SelectionNotify] = 383;
 268		type2pos[ColormapNotify] = 398;
 269		type2pos[ClientMessage] = 412;
 270		type2pos[MappingNotify] = 426;
 271
 272		initialized = TRUE;
 273	}
 274
 275	return (&event_names[type2pos[type]])[0] == 0 ? "<UnknownEvent>" : &event_names[type2pos[type]];
 276}
 277
 278static GXimNestedListNode *
 279g_xim_nested_list_node_new(void)
 280{
 281	GXimNestedListNode *retval;
 282
 283	retval = g_new0(GXimNestedListNode, 1);
 284	G_XIM_CHECK_ALLOC (retval, NULL);
 285
 286	retval->vtype = G_XIM_TYPE_INVALID;
 287
 288	return retval;
 289}
 290
 291static GXimNestedListNode *
 292g_xim_nested_list_node_copy(GXimNestedListNode *node)
 293{
 294	GXimNestedListNode *retval;
 295	GType gtype;
 296
 297	g_return_val_if_fail (node != NULL, NULL);
 298
 299	gtype = g_xim_value_type_to_gtype(node->vtype);
 300	g_return_val_if_fail (gtype != G_TYPE_INVALID, NULL);
 301
 302	retval = g_xim_nested_list_node_new();
 303	retval->vtype = node->vtype;
 304	retval->name = g_strdup(node->name);
 305	retval->value = g_xim_copy_by_gtype(gtype, node->value);
 306
 307	return retval;
 308}
 309
 310static void
 311g_xim_nested_list_node_free(GXimNestedListNode *node)
 312{
 313	GType gtype;
 314
 315	if (node == NULL)
 316		return;
 317
 318	gtype = g_xim_value_type_to_gtype(node->vtype);
 319	if (gtype == G_TYPE_INVALID)
 320		g_warning("Invalid NestedList node for %s to be freed", node->name);
 321	g_free(node->name);
 322	g_xim_free_by_gtype(gtype, node->value);
 323
 324	g_free(node);
 325}
 326
 327/*
 328 * Public functions
 329 */
 330void
 331g_xim_init(void)
 332{
 333	const gchar *env;
 334	gchar **tokens;
 335	gint i;
 336
 337	if (master_message == NULL) {
 338		master_message = g_xim_messages_new();
 339		G_XIM_CHECK_ALLOC_WITH_NO_RET (master_message);
 340
 341		g_object_set(G_OBJECT (master_message), "master", TRUE, NULL);
 342	}
 343	env = g_getenv("LIBGXIM_DEBUG");
 344	if (env) {
 345		tokens = g_strsplit(env, ",", 0);
 346		for (i = 0; tokens && tokens[i] != NULL; i++) {
 347			g_xim_messages_enable_filter(master_message, tokens[i]);
 348		}
 349		g_xim_messages_activate(master_message, TRUE);
 350	}
 351}
 352
 353void
 354g_xim_finalize(void)
 355{
 356	g_object_unref(master_message);
 357}
 358
 359GDataStreamByteOrder
 360g_xim_get_byte_order(void)
 361{
 362	gint i = 1;
 363	gchar *p = (gchar *)&i;
 364
 365	if (*p == 1)
 366		return G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN;
 367
 368	return G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN;
 369}
 370
 371GXimValueType
 372g_xim_gtype_to_value_type(GType gtype)
 373{
 374	switch (gtype) {
 375	    case G_TYPE_CHAR:
 376	    case G_TYPE_UCHAR:
 377		    return G_XIM_TYPE_BYTE;
 378	    case G_TYPE_INT:
 379	    case G_TYPE_UINT:
 380		    return G_XIM_TYPE_WORD;
 381	    case G_TYPE_LONG:
 382	    case G_TYPE_ULONG:
 383		    return G_XIM_TYPE_LONG;
 384	    case G_TYPE_STRING:
 385		    return G_XIM_TYPE_CHAR;
 386	    case G_TYPE_BOXED:
 387	    default:
 388		    if (g_type_is_a(gtype, G_TYPE_XIM_STYLES)) {
 389			    return G_XIM_TYPE_XIMSTYLES;
 390		    } else if (g_type_is_a(gtype, GDK_TYPE_WINDOW)) {
 391			    return G_XIM_TYPE_WINDOW;
 392		    } else if (g_type_is_a(gtype, G_TYPE_XIM_NESTEDLIST)) {
 393			    return G_XIM_TYPE_NESTEDLIST;
 394		    } else if (g_type_is_a(gtype, G_TYPE_XIM_RECTANGLE)) {
 395			    return G_XIM_TYPE_XRECTANGLE;
 396		    } else if (g_type_is_a(gtype, G_TYPE_XIM_POINT)) {
 397			    return G_XIM_TYPE_XPOINT;
 398		    } else if (g_type_is_a(gtype, G_TYPE_XIM_FONTSET)) {
 399			    return G_XIM_TYPE_XFONTSET;
 400		    } else if (g_type_is_a(gtype, G_TYPE_XIM_SEP_NESTEDLIST)) {
 401			    return G_XIM_TYPE_SEPARATOR;
 402		    }
 403
 404		    g_warning("Unsupported object type: %s",
 405			      g_type_name(gtype));
 406		    break;
 407	}
 408
 409	return G_XIM_TYPE_INVALID;
 410}
 411
 412GType
 413g_xim_value_type_to_gtype(GXimValueType vtype)
 414{
 415	switch (vtype) {
 416	    case G_XIM_TYPE_SEPARATOR:
 417		    return G_TYPE_XIM_SEP_NESTEDLIST;
 418	    case G_XIM_TYPE_BYTE:
 419		    return G_TYPE_UCHAR;
 420	    case G_XIM_TYPE_WORD:
 421		    return G_TYPE_UINT;
 422	    case G_XIM_TYPE_LONG:
 423		    return G_TYPE_ULONG;
 424	    case G_XIM_TYPE_CHAR:
 425		    return G_TYPE_STRING;
 426	    case G_XIM_TYPE_WINDOW:
 427		    return GDK_TYPE_WINDOW;
 428	    case G_XIM_TYPE_XIMSTYLES:
 429		    return G_TYPE_XIM_STYLES;
 430	    case G_XIM_TYPE_XRECTANGLE:
 431		    return G_TYPE_XIM_RECTANGLE;
 432	    case G_XIM_TYPE_XPOINT:
 433		    return G_TYPE_XIM_POINT;
 434	    case G_XIM_TYPE_XFONTSET:
 435		    return G_TYPE_XIM_FONTSET;
 436	    case G_XIM_TYPE_HOTKEYTRIGGERS:
 437	    case G_XIM_TYPE_HOTKEYSTATE:
 438	    case G_XIM_TYPE_STRINGCONVERSION:
 439	    case G_XIM_TYPE_PREEDITSTATE:
 440	    case G_XIM_TYPE_RESETSTATE:
 441		    break;
 442	    case G_XIM_TYPE_NESTEDLIST:
 443		    return G_TYPE_XIM_NESTEDLIST;
 444	    case G_XIM_TYPE_INVALID:
 445		    break;
 446	    case G_XIM_TYPE_PADDING:
 447	    case G_XIM_TYPE_AUTO_PADDING:
 448	    case G_XIM_TYPE_MARKER_N_BYTES_1:
 449	    case G_XIM_TYPE_MARKER_N_BYTES_2:
 450	    case G_XIM_TYPE_MARKER_N_BYTES_4:
 451	    case G_XIM_TYPE_MARKER_N_ITEMS_2:
 452		    break;
 453	    case G_XIM_TYPE_STR:
 454		    return G_TYPE_XIM_STR;
 455	    case G_XIM_TYPE_GSTRING:
 456		    return G_TYPE_GSTRING;
 457	    case G_XIM_TYPE_PREEDIT_CARET:
 458		    return G_TYPE_XIM_PREEDIT_CARET;
 459	    case G_XIM_TYPE_PREEDIT_DRAW:
 460		    return G_TYPE_XIM_PREEDIT_DRAW;
 461	    case G_XIM_TYPE_GDKEVENT:
 462		    return GDK_TYPE_EVENT;
 463	    case G_XIM_TYPE_XIMTEXT:
 464		    return G_TYPE_XIM_TEXT;
 465	    case G_XIM_TYPE_HOTKEY_TRIGGER:
 466		    return G_TYPE_XIM_HOTKEY_TRIGGER;
 467	    case G_XIM_TYPE_PIXMAP:
 468		    return GDK_TYPE_PIXMAP;
 469	    case G_XIM_TYPE_STATUS_DRAW:
 470		    return G_TYPE_XIM_STATUS_DRAW;
 471	    case G_XIM_TYPE_LIST_OF_IMATTR:
 472	    case G_XIM_TYPE_LIST_OF_ICATTR:
 473	    case G_XIM_TYPE_LIST_OF_IMATTRIBUTE:
 474	    case G_XIM_TYPE_LIST_OF_ICATTRIBUTE:
 475	    case G_XIM_TYPE_LIST_OF_EXT:
 476	    case G_XIM_TYPE_LIST_OF_STRING:
 477	    case G_XIM_TYPE_LIST_OF_STR:
 478	    case G_XIM_TYPE_LIST_OF_ENCODINGINFO:
 479	    case G_XIM_TYPE_LIST_OF_BYTE:
 480	    case G_XIM_TYPE_LIST_OF_CARD16:
 481	    case G_XIM_TYPE_LIST_OF_HOTKEY_TRIGGER:
 482	    default:
 483		    break;
 484	}
 485
 486	return G_TYPE_INVALID;
 487}
 488
 489const gchar *
 490g_xim_value_type_name(GXimValueType vtype)
 491{
 492	static const gchar vtype_name[] =
 493		"\0"
 494		"SeparatorofNestedList\0"
 495		"CARD8\0"
 496		"CARD16\0"
 497		"CARD32\0"
 498		"STRING8\0"
 499		"Window\0"
 500		"XIMStyles\0"
 501		"XRectangle\0"
 502		"XPoint\0"
 503		"XFontSet\0"
 504		"XIMHotKeyTriggers\0"
 505		"XIMHotKeyState\0"
 506		"XIMStringConversion\0"
 507		"XIMPreeditState\0"
 508		"XIMResetState\0"
 509		"NestedList\0"
 510		"<Invalid>\0"
 511		"Padding\0"
 512		"AutoPadding\0"
 513		"n-bytes-marker[CARD8]\0"
 514		"n-bytes-marker[CARD16]\0"
 515		"n-bytes-marker[CARD32]\0"
 516		"n-items-marker[CARD16]\0"
 517		"STR\0"
 518		"GString\0"
 519		"GXimPreeditCaret\0"
 520		"GXimPreeditDraw\0"
 521		"GdkEvent\0"
 522		"GXimText\0"
 523		"GXimHotkeyTrigger\0"
 524		"Pixmap\0"
 525		"GXimStatusDraw\0"
 526		"LISTofXIMATTR\0"
 527		"LISTofXICATTR\0"
 528		"LISTofXIMATTRIBUTE\0"
 529		"LISTofXICATTRIBUTE\0"
 530		"LISTofEXT\0"
 531		"LISTofSTRING\0"
 532		"LISTofSTR\0"
 533		"LISTofENCODINGINFO\0"
 534		"LISTofBYTE\0"
 535		"LISTofCARD16\0"
 536		"LISTofXIMTRIGGERKEY\0";
 537	static guint type2pos[LAST_VALUE_TYPE];
 538	static gboolean initialized = FALSE;
 539	static gchar tmp[256];
 540
 541	if (!initialized) {
 542		memset(type2pos, 0, sizeof (guint) * (LAST_VALUE_TYPE - 1));
 543		type2pos[G_XIM_TYPE_SEPARATOR] = 1;
 544		type2pos[G_XIM_TYPE_BYTE] = 23;
 545		type2pos[G_XIM_TYPE_WORD] = 29;
 546		type2pos[G_XIM_TYPE_LONG] = 36;
 547		type2pos[G_XIM_TYPE_CHAR] = 43;
 548		type2pos[G_XIM_TYPE_WINDOW] = 51;
 549		type2pos[G_XIM_TYPE_XIMSTYLES] = 58;
 550		type2pos[G_XIM_TYPE_XRECTANGLE] = 68;
 551		type2pos[G_XIM_TYPE_XPOINT] = 79;
 552		type2pos[G_XIM_TYPE_XFONTSET] = 86;
 553		type2pos[G_XIM_TYPE_HOTKEYTRIGGERS] = 95;
 554		type2pos[G_XIM_TYPE_HOTKEYSTATE] = 113;
 555		type2pos[G_XIM_TYPE_STRINGCONVERSION] = 128;
 556		type2pos[G_XIM_TYPE_PREEDITSTATE] = 148;
 557		type2pos[G_XIM_TYPE_RESETSTATE] = 164;
 558		type2pos[G_XIM_TYPE_NESTEDLIST] = 178;
 559		type2pos[G_XIM_TYPE_INVALID] = 189;
 560		type2pos[G_XIM_TYPE_PADDING] = 199;
 561		type2pos[G_XIM_TYPE_AUTO_PADDING] = 207;
 562		type2pos[G_XIM_TYPE_MARKER_N_BYTES_1] = 219;
 563		type2pos[G_XIM_TYPE_MARKER_N_BYTES_2] = 241;
 564		type2pos[G_XIM_TYPE_MARKER_N_BYTES_4] = 264;
 565		type2pos[G_XIM_TYPE_MARKER_N_ITEMS_2] = 287;
 566		type2pos[G_XIM_TYPE_STR] = 310;
 567		type2pos[G_XIM_TYPE_GSTRING] = 314;
 568		type2pos[G_XIM_TYPE_PREEDIT_CARET] = 322;
 569		type2pos[G_XIM_TYPE_PREEDIT_DRAW] = 339;
 570		type2pos[G_XIM_TYPE_GDKEVENT] = 355;
 571		type2pos[G_XIM_TYPE_XIMTEXT] = 364;
 572		type2pos[G_XIM_TYPE_HOTKEY_TRIGGER] = 373;
 573		type2pos[G_XIM_TYPE_PIXMAP] = 391;
 574		type2pos[G_XIM_TYPE_STATUS_DRAW] = 398;
 575		type2pos[G_XIM_TYPE_LIST_OF_IMATTR] = 413;
 576		type2pos[G_XIM_TYPE_LIST_OF_ICATTR] = 427;
 577		type2pos[G_XIM_TYPE_LIST_OF_IMATTRIBUTE] = 441;
 578		type2pos[G_XIM_TYPE_LIST_OF_ICATTRIBUTE] = 460;
 579		type2pos[G_XIM_TYPE_LIST_OF_EXT] = 479;
 580		type2pos[G_XIM_TYPE_LIST_OF_STRING] = 489;
 581		type2pos[G_XIM_TYPE_LIST_OF_STR] = 502;
 582		type2pos[G_XIM_TYPE_LIST_OF_ENCODINGINFO] = 512;
 583		type2pos[G_XIM_TYPE_LIST_OF_BYTE] = 531;
 584		type2pos[G_XIM_TYPE_LIST_OF_CARD16] = 542;
 585		type2pos[G_XIM_TYPE_LIST_OF_HOTKEY_TRIGGER] = 555;
 586	}
 587
 588	if (vtype >= LAST_VALUE_TYPE ||
 589	    type2pos[vtype] == 0) {
 590		snprintf(tmp, 255, "0x%x", vtype);
 591
 592		return tmp;
 593	}
 594
 595	return &vtype_name[type2pos[vtype]];
 596}
 597
 598const gchar *
 599g_xim_protocol_name(guint16 major_opcode)
 600{
 601	static const gchar op2str[] = {
 602		"\0"
 603		"XIM_CONNECT\0"
 604		"XIM_CONNECT_REPLY\0"
 605		"XIM_DISCONNECT\0"
 606		"XIM_DISCONNECT_REPLY\0"
 607		"\0"
 608		"\0"
 609		"\0"
 610		"\0"
 611		"\0"
 612		"XIM_AUTH_REQUIRED\0"
 613		"XIM_AUTH_REPLY\0"
 614		"XIM_AUTH_NEXT\0"
 615		"XIM_AUTH_SETUP\0"
 616		"XIM_AUTH_NG\0"
 617		"\0"
 618		"\0"
 619		"\0"
 620		"\0"
 621		"\0"
 622		"XIM_ERROR\0"
 623		"\0"
 624		"\0"
 625		"\0"
 626		"\0"
 627		"\0"
 628		"\0"
 629		"\0"
 630		"\0"
 631		"\0"
 632		"XIM_OPEN\0"
 633		"XIM_OPEN_REPLY\0"
 634		"XIM_CLOSE\0"
 635		"XIM_CLOSE_REPLY\0"
 636		"XIM_REGISTER_TRIGGERKEYS\0"
 637		"XIM_TRIGGER_NOTIFY\0"
 638		"XIM_TRIGGER_NOTIFY_REPLY\0"
 639		"XIM_SET_EVENT_MASK\0"
 640		"XIM_ENCODING_NEGOTIATION\0"
 641		"XIM_ENCODING_NEGOTIATION_REPLY\0"
 642		"XIM_QUERY_EXTENSION\0"
 643		"XIM_QUERY_EXTENSION_REPLY\0"
 644		"XIM_SET_IM_VALUES\0"
 645		"XIM_SET_IM_VALUES_REPLY\0"
 646		"XIM_GET_IM_VALUES\0"
 647		"XIM_GET_IM_VALUES_REPLY\0"
 648		"\0"
 649		"\0"
 650		"\0"
 651		"\0"
 652		"XIM_CREATE_IC\0"
 653		"XIM_CREATE_IC_REPLY\0"
 654		"XIM_DESTROY_IC\0"
 655		"XIM_DESTROY_IC_REPLY\0"
 656		"XIM_SET_IC_VALUES\0"
 657		"XIM_SET_IC_VALUES_REPLY\0"
 658		"XIM_GET_IC_VALUES\0"
 659		"XIM_GET_IC_VALUES_REPLY\0"
 660		"XIM_SET_IC_FOCUS\0"
 661		"XIM_UNSET_IC_FOCUS\0"
 662		"XIM_FORWARD_EVENT\0"
 663		"XIM_SYNC\0"
 664		"XIM_SYNC_REPLY\0"
 665		"XIM_COMMIT\0"
 666		"XIM_RESET_IC\0"
 667		"XIM_RESET_IC_REPLY\0"
 668		"\0"
 669		"\0"
 670		"\0"
 671		"\0"
 672		"XIM_GEOMETRY\0"
 673		"XIM_STR_CONVERSION\0"
 674		"XIM_STR_CONVERSION_REPLY\0"
 675		"XIM_PREEDIT_START\0"
 676		"XIM_PREEDIT_START_REPLY\0"
 677		"XIM_PREEDIT_DRAW\0"
 678		"XIM_PREEDIT_CARET\0"
 679		"XIM_PREEDIT_CARET_REPLY\0"
 680		"XIM_PREEDIT_DONE\0"
 681		"XIM_STATUS_START\0"
 682		"XIM_STATUS_DRAW\0"
 683		"XIM_STATUS_DONE\0"
 684		"XIM_PREEDITSTATE\0"
 685	};
 686	static gsize opindexes[] = {
 687		0, 1, 13, 31, 46, 67, 68, 69, 70, 71,
 688		72, 90, 105, 119, 134, 146, 147, 148, 149, 150,
 689		151, 161, 162, 163, 164, 165, 166, 167, 168, 169,
 690		170, 179, 194, 204, 220, 245, 264, 289, 308, 333,
 691		364, 384, 410, 428, 452, 470, 494, 495, 496, 497,
 692		498, 512, 532, 547, 568, 586, 610, 628, 652, 669,
 693		688, 706, 715, 730, 741, 754, 773, 774, 775, 776,
 694		777, 790, 809, 834, 852, 876, 893, 911, 935, 952,
 695		969, 985, 1001, 1018,
 696	};
 697
 698	if (major_opcode >= LAST_XIM_EVENTS)
 699		return NULL;
 700
 701	return &op2str[opindexes[major_opcode]];
 702}
 703
 704GdkWindow *
 705g_xim_get_window(GdkDisplay      *dpy,
 706		 GdkNativeWindow  window)
 707{
 708	GdkWindow *retval;
 709	guint32 error_code;
 710
 711	g_xim_error_push();
 712
 713	retval = gdk_window_lookup_for_display(dpy, window);
 714	if (retval == NULL ||
 715	    !GDK_IS_WINDOW (retval) ||
 716	    GDK_WINDOW_DESTROYED (retval)) {
 717		if (retval)
 718			gdk_window_destroy(retval);
 719		retval = gdk_window_foreign_new_for_display(dpy, window);
 720	}
 721
 722	error_code = g_xim_error_pop();
 723	if (G_XIM_ERROR_DECODE_X_ERROR_CODE (error_code) != 0) {
 724		g_printerr("Unable to convert the native window to GdkWindow: %p",
 725			   G_XIM_NATIVE_WINDOW_TO_POINTER (window));
 726	}
 727
 728	return retval != NULL ? g_object_ref(retval) : NULL;
 729}
 730
 731GdkPixmap *
 732g_xim_get_pixmap(GdkDisplay      *dpy,
 733		 GdkNativeWindow  window)
 734{
 735	GdkPixmap *retval;
 736
 737	retval = gdk_pixmap_lookup_for_display(dpy, window);
 738	if (retval == NULL ||
 739	    !GDK_IS_PIXMAP (retval)) {
 740		if (retval)
 741			g_object_unref(retval);
 742		retval = gdk_pixmap_foreign_new_for_display(dpy, window);
 743	}
 744
 745	return retval;
 746}
 747
 748GdkWindow *
 749g_xim_get_selection_owner(GdkDisplay *display,
 750			  GdkAtom     selection)
 751{
 752	Window xwindow;
 753	GdkWindow *retval;
 754
 755	g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
 756	g_return_val_if_fail (selection != GDK_NONE, NULL);
 757
 758	if (display->closed)
 759		return NULL;
 760
 761	xwindow = XGetSelectionOwner(GDK_DISPLAY_XDISPLAY (display),
 762				     gdk_x11_atom_to_xatom_for_display(display,
 763								       selection));
 764	if (xwindow == None)
 765		return NULL;
 766
 767	retval = g_xim_get_window(display, (GdkNativeWindow)xwindow);
 768	/* just decrease a counter to not mind unref outside this function */
 769	g_object_unref(retval);
 770
 771	return retval;
 772}
 773
 774GdkWindow *
 775g_xim_lookup_xim_server(GdkDisplay *dpy,
 776			GdkAtom     atom_server,
 777			gboolean   *is_valid)
 778{
 779	GdkAtom atom_xim_servers, atom_type, *atom_prop = NULL;
 780	gint format, bytes, i;
 781	GdkWindow *retval = NULL;
 782	guint32 error_code;
 783
 784	g_return_val_if_fail (atom_server != GDK_NONE, NULL);
 785	g_return_val_if_fail (is_valid != NULL, NULL);
 786
 787	atom_xim_servers = gdk_atom_intern_static_string("XIM_SERVERS");
 788
 789	g_xim_error_push();
 790	gdk_property_get(gdk_screen_get_root_window(gdk_display_get_default_screen(dpy)),
 791			 atom_xim_servers, GDK_SELECTION_TYPE_ATOM,
 792			 0, 8192, FALSE,
 793			 &atom_type, &format, &bytes,
 794			 (guchar **)(uintptr_t)&atom_prop);
 795	error_code = g_xim_error_pop();
 796	if (error_code != 0) {
 797		*is_valid = FALSE;
 798		return NULL;
 799	}
 800	if (atom_type != GDK_SELECTION_TYPE_ATOM ||
 801	    format != 32) {
 802		*is_valid = FALSE;
 803		return NULL;
 804	}
 805
 806	for (i = 0; i < (bytes / sizeof (gulong)); i++) {
 807		if (atom_prop[i] == atom_server) {
 808			retval = g_xim_get_selection_owner(dpy, atom_server);
 809			break;
 810		}
 811	}
 812	g_free(atom_prop);
 813	*is_valid = TRUE;
 814
 815	return retval;
 816}
 817
 818GdkWindow *
 819g_xim_lookup_xim_server_from_string(GdkDisplay  *dpy,
 820				    const gchar *server_name,
 821				    gboolean    *is_valid)
 822{
 823	GdkWindow *retval;
 824	GdkAtom atom_server;
 825
 826	g_return_val_if_fail (server_name != NULL, NULL);
 827
 828	atom_server = g_xim_get_server_atom(server_name);
 829	retval = g_xim_lookup_xim_server(dpy, atom_server, is_valid);
 830
 831	return retval;
 832}
 833
 834GdkAtom
 835g_xim_get_server_atom(const gchar *server_name)
 836{
 837	gchar *s;
 838	GdkAtom retval;
 839
 840	s = g_strdup_printf("@server=%s", server_name);
 841	retval = gdk_atom_intern(s, FALSE);
 842	g_free(s);
 843
 844	return retval;
 845}
 846
 847gpointer
 848g_xim_copy_by_gtype(GType    gtype,
 849		    gpointer value)
 850{
 851	gpointer retval;
 852
 853	if (G_TYPE_IS_BOXED (gtype))
 854		retval = g_boxed_copy(gtype, value);
 855	else if (G_TYPE_IS_OBJECT (gtype))
 856		retval = g_object_ref(value);
 857	else if (gtype == G_TYPE_STRING)
 858		retval = g_strdup(value);
 859	else
 860		retval = value;
 861
 862	return retval;
 863}
 864
 865void
 866g_xim_free_by_gtype(GType    gtype,
 867		    gpointer value)
 868{
 869	if (G_TYPE_IS_BOXED (gtype))
 870		g_boxed_free(gtype, value);
 871	else if (G_TYPE_IS_OBJECT (gtype))
 872		g_object_unref(value);
 873	else if (gtype == G_TYPE_STRING)
 874		g_free(value);
 875}
 876
 877#if 0
 878/* GXimStrConv */
 879GXimStrConvText *
 880g_xim_str_conv_text_new(const gchar *string,
 881			guint16      length)
 882{
 883	GXimStrConvText *retval;
 884
 885	g_return_val_if_fail (string != NULL, NULL);
 886
 887	retval = g_new0(GXimStrConvText, 1);
 888	G_XIM_CHECK_ALLOC (retval, NULL);
 889
 890	retval->string = g_strndup(string, length);
 891	retval->length = length;
 892
 893	return retval;
 894}
 895
 896GXimStrConvText *
 897g_xim_str_conv_text_new_full(const gchar *string,
 898			     guint16      length,
 899			     guint16      feedback)
 900{
 901	GXimStrConvText *retval = g_xim_str_conv_text_new(string, length);
 902
 903	if (retval)
 904		g_xim_str_conv_set_feedback(retval, feedback);
 905
 906	return retval;
 907}
 908
 909void
 910g_xim_str_conv_text_free(GXimStrConvText *text)
 911{
 912	g_return_if_fail (text != NULL);
 913
 914	g_free(text->string);
 915	g_free(text);
 916}
 917
 918void
 919g_xim_str_conv_set_feedback(GXimStrConvText *text,
 920			    guint16          feedback)
 921{
 922	g_return_if_fail (text != NULL);
 923
 924	text->feedback = feedback;
 925}
 926
 927guint16
 928g_xim_str_conv_get_feedback(GXimStrConvText *text)
 929{
 930	g_return_val_if_fail (text != NULL, 0);
 931
 932	return text->feedback;
 933}
 934#endif
 935
 936/* XIMStyles */
 937GType
 938g_xim_styles_get_type(void)
 939{
 940	static volatile gsize type_id_volatile = 0;
 941
 942	if (g_once_init_enter(&type_id_volatile)) {
 943		GType type_id;
 944
 945		type_id = g_boxed_type_register_static(g_intern_static_string("GXimStyles"),
 946						       g_xim_styles_copy,
 947						       g_xim_styles_free);
 948		g_once_init_leave(&type_id_volatile, type_id);
 949	}
 950
 951	return type_id_volatile;
 952}
 953
 954GQuark
 955g_xim_styles_get_error_quark(void)
 956{
 957	static GQuark quark = 0;
 958
 959	if (!quark)
 960		quark = g_quark_from_static_string("g-xim-styles-error");
 961
 962	return quark;
 963}
 964
 965GXimStyles *
 966g_xim_styles_new(void)
 967{
 968	GXimStyles *retval = g_new0(GXimStyles, 1);
 969
 970	G_XIM_CHECK_ALLOC (retval, NULL);
 971
 972	retval->count_styles = 0;
 973	retval->supported_styles = NULL;
 974
 975	return retval;
 976}
 977
 978gboolean
 979g_xim_styles_append(GXimStyles  *styles,
 980		    GXimStyle    style,
 981		    GError     **error)
 982{
 983	g_return_val_if_fail (styles != NULL, FALSE);
 984
 985	return g_xim_styles_insert(styles, styles->count_styles, style, error);
 986}
 987
 988gboolean
 989g_xim_styles_insert(GXimStyles  *styles,
 990		    guint        index_,
 991		    GXimStyle    style,
 992		    GError     **error)
 993{
 994	gboolean retval = TRUE;
 995
 996	g_return_val_if_fail (styles != NULL, FALSE);
 997	g_return_val_if_fail (error != NULL, FALSE);
 998
 999	if (styles->count_styles <= index_) {
1000		gpointer data;
1001
1002		data = g_realloc(styles->supported_styles,
1003				 sizeof (GXimStyle) * (index_ + 1));
1004		G_XIM_GERROR_CHECK_ALLOC (data,
1005					  error, G_XIM_STYLES_ERROR,
1006					  FALSE);
1007
1008		styles->supported_styles = data;
1009		styles->count_styles = index_ + 1;
1010	}
1011	styles->supported_styles[index_] = style;
1012
1013	return retval;
1014}
1015
1016gpointer
1017g_xim_styles_copy(gpointer boxed)
1018{
1019	GXimStyles *retval, *orig = boxed;
1020
1021	if (boxed == NULL)
1022		return NULL;
1023
1024	retval = g_new(GXimStyles, 1);
1025	G_XIM_CHECK_ALLOC (retval, NULL);
1026
1027	retval->count_styles = orig->count_styles;
1028	retval->supported_styles = g_new(GXimStyle, sizeof (GXimStyle) * retval->count_styles);
1029	G_XIM_CHECK_ALLOC (retval->supported_styles, NULL);
1030
1031	memcpy(retval->supported_styles,
1032	       orig->supported_styles,
1033	       sizeof (GXimStyle) * retval->count_styles);
1034
1035	return retval;
1036}
1037
1038void
1039g_xim_styles_free(gpointer boxed)
1040{
1041	GXimStyles *s = boxed;
1042
1043	if (boxed == NULL)
1044		return;
1045
1046	g_free(s->supported_styles);
1047	g_free(s);
1048}
1049
1050gsize
1051g_xim_styles_put_to_stream(GXimStyles    *styles,
1052			   GXimProtocol  *proto,
1053			   GCancellable  *cancellable,
1054			   GError       **error)
1055{
1056	gsize retval = 0;
1057	guint16 i;
1058
1059	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
1060	g_return_val_if_fail (styles != NULL, 0);
1061	g_return_val_if_fail (error != NULL, 0);
1062
1063	retval = g_xim_protocol_send_format(proto, cancellable, error, 2,
1064					    G_XIM_TYPE_WORD, styles->count_styles,
1065					    G_XIM_TYPE_PADDING, 2);
1066	if (*error)
1067		return 0;
1068	/* XIMStyle */
1069	for (i = 0; i < styles->count_styles; i++) {
1070		retval += g_xim_protocol_send_format(proto, cancellable, error, 1,
1071						     G_XIM_TYPE_LONG, styles->supported_styles[i]);
1072		if (*error)
1073			return 0;
1074	}
1075
1076	return retval;
1077}
1078
1079gpointer
1080g_xim_styles_get_from_stream(GXimProtocol      *proto,
1081			     GDataInputStream  *stream,
1082			     GCancellable      *cancellable,
1083			     GError           **error)
1084{
1085	GXimStyles *retval;
1086	guint16 i;
1087	GXimStyle style;
1088
1089	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), NULL);
1090	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
1091	g_return_val_if_fail (error != NULL, NULL);
1092
1093	retval = g_xim_styles_new();
1094	G_XIM_CHECK_ALLOC (retval, NULL);
1095
1096	if (!g_xim_protocol_read_format(proto, stream, cancellable, error,
1097					2,
1098					G_XIM_TYPE_WORD, &retval->count_styles,
1099					G_XIM_TYPE_PADDING, 2)) {
1100		g_xim_styles_free(retval);
1101		return NULL;
1102	}
1103	retval->supported_styles = g_new0(GXimStyle, retval->count_styles);
1104	G_XIM_GERROR_CHECK_ALLOC (retval->supported_styles, error,
1105				  G_XIM_PROTOCOL_ERROR, NULL);
1106
1107	for (i = 0; i < retval->count_styles; i++) {
1108		if (!g_xim_protocol_read_format(proto, stream, cancellable, error,
1109						1,
1110						G_XIM_TYPE_LONG, &style)) {
1111			/* keep the values as much as possible */
1112			retval->count_styles = i;
1113			G_XIM_GERROR_RESET_NOTICE_FLAG (*error);
1114			G_XIM_GERROR_SET_NOTICE_FLAG (*error,
1115						      G_XIM_NOTICE_WARNING);
1116			break;
1117		}
1118		if (!g_xim_styles_insert(retval, i, style, error)) {
1119			retval->count_styles = i;
1120			G_XIM_GERROR_RESET_NOTICE_FLAG (*error);
1121			G_XIM_GERROR_SET_NOTICE_FLAG (*error,
1122						      G_XIM_NOTICE_WARNING);
1123			break;
1124		}
1125	}
1126
1127	return retval;
1128}
1129
1130/* XRectangle */
1131GType
1132g_xim_rectangle_get_type(void)
1133{
1134	static volatile gsize type_id_volatile = 0;
1135
1136	if (g_once_init_enter(&type_id_volatile)) {
1137		GType type_id;
1138
1139		type_id = g_boxed_type_register_static(g_intern_static_string("GXimRectangle"),
1140						       g_xim_rectangle_copy,
1141						       g_xim_rectangle_free);
1142		g_once_init_leave(&type_id_volatile, type_id);
1143	}
1144
1145	return type_id_volatile;
1146}
1147
1148gpointer
1149g_xim_rectangle_new(void)
1150{
1151	return g_new0(GXimRectangle, 1);
1152}
1153
1154gpointer
1155g_xim_rectangle_copy(gpointer boxed)
1156{
1157	GXimRectangle *retval, *val = boxed;
1158
1159	if (boxed == NULL)
1160		return NULL;
1161
1162	retval = g_xim_rectangle_new();
1163	G_XIM_CHECK_ALLOC (retval, NULL);
1164
1165	retval->x = val->x;
1166	retval->y = val->y;
1167	retval->width = val->width;
1168	retval->height = val->height;
1169
1170	return retval;
1171}
1172
1173void
1174g_xim_rectangle_free(gpointer boxed)
1175{
1176	g_free(boxed);
1177}
1178
1179gsize
1180g_xim_rectangle_put_to_stream(GXimRectangle  *rectangle,
1181			      GXimProtocol   *proto,
1182			      GCancellable   *cancellable,
1183			      GError        **error)
1184{
1185	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
1186	g_return_val_if_fail (rectangle != NULL, 0);
1187	g_return_val_if_fail (error != NULL, 0);
1188
1189	return g_xim_protocol_send_format(proto, cancellable, error, 4,
1190					  G_XIM_TYPE_WORD, rectangle->x,
1191					  G_XIM_TYPE_WORD, rectangle->y,
1192					  G_XIM_TYPE_WORD, rectangle->width,
1193					  G_XIM_TYPE_WORD, rectangle->height);
1194}
1195
1196gpointer
1197g_xim_rectangle_get_from_stream(GXimProtocol      *proto,
1198				GDataInputStream  *stream,
1199				GCancellable      *cancellable,
1200				GError           **error)
1201{
1202	GXimRectangle *retval;
1203	guint16 x, y, width, height;
1204
1205	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), NULL);
1206	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
1207	g_return_val_if_fail (error != NULL, NULL);
1208
1209	if (!g_xim_protocol_read_format(proto, stream, cancellable, error,
1210					4,
1211					G_XIM_TYPE_WORD, &x,
1212					G_XIM_TYPE_WORD, &y,
1213					G_XIM_TYPE_WORD, &width,
1214					G_XIM_TYPE_WORD, &height))
1215		return NULL;
1216
1217	retval = g_xim_rectangle_new();
1218	G_XIM_GERROR_CHECK_ALLOC (retval, error,
1219				  G_XIM_PROTOCOL_ERROR, NULL);
1220
1221	retval->x = x;
1222	retval->y = y;
1223	retval->width = width;
1224	retval->height = height;
1225
1226	return retval;
1227}
1228
1229/* XPoint */
1230GType
1231g_xim_point_get_type(void)
1232{
1233	static volatile gsize type_id_volatile = 0;
1234
1235	if (g_once_init_enter(&type_id_volatile)) {
1236		GType type_id;
1237
1238		type_id = g_boxed_type_register_static(g_intern_static_string("GXimPoint"),
1239						       g_xim_point_copy,
1240						       g_xim_point_free);
1241		g_once_init_leave(&type_id_volatile, type_id);
1242	}
1243
1244	return type_id_volatile;
1245}
1246
1247gpointer
1248g_xim_point_new(void)
1249{
1250	return g_new0(GXimPoint, 1);
1251}
1252
1253gpointer
1254g_xim_point_copy(gpointer boxed)
1255{
1256	GXimPoint *retval, *val = boxed;
1257
1258	if (boxed == NULL)
1259		return NULL;
1260
1261	retval = g_xim_point_new();
1262	G_XIM_CHECK_ALLOC (retval, NULL);
1263
1264	retval->x = val->x;
1265	retval->y = val->y;
1266
1267	return retval;
1268}
1269
1270void
1271g_xim_point_free(gpointer boxed)
1272{
1273	g_free(boxed);
1274}
1275
1276gsize
1277g_xim_point_put_to_stream(GXimPoint     *point,
1278			  GXimProtocol  *proto,
1279			  GCancellable  *cancellable,
1280			  GError       **error)
1281{
1282	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
1283	g_return_val_if_fail (point != NULL, 0);
1284	g_return_val_if_fail (error != NULL, 0);
1285
1286	return g_xim_protocol_send_format(proto, cancellable, error, 2,
1287					  G_XIM_TYPE_WORD, point->x,
1288					  G_XIM_TYPE_WORD, point->y);
1289}
1290
1291gpointer
1292g_xim_point_get_from_stream(GXimProtocol      *proto,
1293			    GDataInputStream  *stream,
1294			    GCancellable      *cancellable,
1295			    GError           **error)
1296{
1297	GXimPoint *retval;
1298	guint16 x, y;
1299
1300	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), NULL);
1301	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
1302	g_return_val_if_fail (error != NULL, NULL);
1303
1304	if (!g_xim_protocol_read_format(proto, stream, cancellable, error,
1305					2,
1306					G_XIM_TYPE_WORD, &x,
1307					G_XIM_TYPE_WORD, &y))
1308		return NULL;
1309
1310	retval = g_xim_point_new();
1311	G_XIM_GERROR_CHECK_ALLOC (retval, error,
1312				  G_XIM_PROTOCOL_ERROR, NULL);
1313
1314	retval->x = x;
1315	retval->y = y;
1316
1317	return retval;
1318}
1319
1320/* XFontSet */
1321GType
1322g_xim_fontset_get_type(void)
1323{
1324	static volatile gsize type_id_volatile = 0;
1325
1326	if (g_once_init_enter(&type_id_volatile)) {
1327		GType type_id;
1328
1329		type_id = g_boxed_type_register_static(g_intern_static_string("GXimFontSet"),
1330						       g_xim_fontset_copy,
1331						       g_xim_fontset_free);
1332		g_once_init_leave(&type_id_volatile, type_id);
1333	}
1334
1335	return type_id_volatile;
1336}
1337
1338gpointer
1339g_xim_fontset_copy(gpointer boxed)
1340{
1341	GString *retval, *val = boxed;
1342
1343	if (boxed == NULL)
1344		return NULL;
1345
1346	retval = g_string_sized_new(val->len);
1347	G_XIM_CHECK_ALLOC (retval, NULL);
1348
1349	g_string_append(retval, val->str);
1350
1351	return retval;
1352}
1353
1354void
1355g_xim_fontset_free(gpointer boxed)
1356{
1357	if (boxed == NULL)
1358		return;
1359
1360	g_string_free(boxed, TRUE);
1361}
1362
1363gsize
1364g_xim_fontset_put_to_stream(GXimFontSet   *fontset,
1365			    GXimProtocol  *proto,
1366			    GCancellable  *cancellable,
1367			    GError       **error)
1368{
1369	g_return_val_if_fail (fontset != NULL, 0);
1370	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
1371	g_return_val_if_fail (error != NULL, 0);
1372
1373	return g_xim_protocol_send_format(proto, cancellable, error, 1,
1374					  G_XIM_TYPE_GSTRING, fontset);
1375}
1376
1377gpointer
1378g_xim_fontset_get_from_stream(GXimProtocol      *proto,
1379			      GDataInputStream  *stream,
1380			      GCancellable      *cancellable,
1381			      GError           **error)
1382{
1383	GXimFontSet *retval = NULL;
1384
1385	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), NULL);
1386	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
1387	g_return_val_if_fail (error != NULL, NULL);
1388
1389	if (!g_xim_protocol_read_format(proto, stream, cancellable, error,
1390					1,
1391					G_XIM_TYPE_GSTRING, &retval))
1392		return NULL;
1393
1394	return retval;
1395}
1396
1397/* GString */
1398gsize
1399g_xim_gstring_put_to_stream(GString            *string,
1400			    GDataOutputStream  *stream,
1401			    GCancellable       *cancellable,
1402			    GError            **error)
1403{
1404	gint i;
1405	gsize retval = 2;
1406
1407	g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), 0);
1408	g_return_val_if_fail (string != NULL, 0);
1409	g_return_val_if_fail (string->len <= 0xffff, 0);
1410	g_return_val_if_fail (error != NULL, 0);
1411
1412	g_data_output_stream_put_uint16(stream, string->len, cancellable, error);
1413	if (*error)
1414		return 0;
1415	for (i = 0; i < string->len; i++) {
1416		g_data_output_stream_put_byte(stream, string->str[i], cancellable, error);
1417		if (*error)
1418			return 0;
1419		retval++;
1420	}
1421
1422	return retval;
1423}
1424
1425gpointer
1426g_xim_gstring_get_from_stream(GDataInputStream  *stream,
1427			      GCancellable      *cancellable,
1428			      GError           **error)
1429{
1430	GString *retval = NULL;
1431	gsize size, avail, read = 2, i;
1432
1433	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
1434	g_return_val_if_fail (error != NULL, NULL);
1435
1436	size = g_data_input_stream_read_uint16(stream, cancellable, error);
1437	if (*error)
1438		return NULL;
1439	if ((avail = g_buffered_input_stream_get_buffer_size(G_BUFFERED_INPUT_STREAM (stream))) < size) {
1440		g_set_error(error, G_XIM_PROTOCOL_ERROR,
1441			    G_XIM_PROTOCOL_ERROR_INVALID_PACKETS_RECEIVED | G_XIM_NOTICE_ERROR,
1442			    "Unable to compose a string with the remaining packets: %" G_GSIZE_FORMAT " for %" G_GSIZE_FORMAT,
1443			    size, avail);
1444		return NULL;
1445	}
1446	retval = g_string_sized_new(size);
1447	G_XIM_GERROR_CHECK_ALLOC (retval, error,
1448				  G_XIM_PROTOCOL_ERROR, NULL);
1449
1450	for (i = 0; i < size; i++) {
1451		gchar c;
1452
1453		c = g_data_input_stream_read_byte(stream, cancellable, error);
1454		if (*error)
1455			goto fail;
1456		g_string_append_c(retval, c);
1457		read++;
1458	}
1459
1460	return retval;
1461  fail:
1462	if (retval)
1463		g_string_free(retval, TRUE);
1464
1465	return NULL;
1466}
1467
1468/* STRING */
1469GType
1470g_xim_string_get_type(void)
1471{
1472	static volatile gsize type_id_volatile = 0;
1473
1474	if (g_once_init_enter(&type_id_volatile)) {
1475		GType type_id;
1476
1477		type_id = g_boxed_type_register_static(g_intern_static_string("GXimString"),
1478						       g_xim_string_copy,
1479						       g_xim_string_free);
1480		g_once_init_leave(&type_id_volatile, type_id);
1481	}
1482
1483	return type_id_volatile;
1484}
1485
1486gpointer
1487g_xim_string_new(void)
1488{
1489	GString *retval = g_string_new(NULL);
1490
1491	return retval;
1492}
1493
1494gpointer
1495g_xim_string_copy(gpointer boxed)
1496{
1497	GString *retval, *orig = boxed;
1498
1499	if (boxed == NULL)
1500		return NULL;
1501
1502	retval = g_string_sized_new(orig->len);
1503	G_XIM_CHECK_ALLOC (retval, NULL);
1504
1505	g_string_append(retval, orig->str);
1506
1507	return retval;
1508}
1509
1510void
1511g_xim_string_free(gpointer boxed)
1512{
1513	if (boxed == NULL)
1514		return;
1515
1516	g_string_free(boxed, TRUE);
1517}
1518
1519const gchar *
1520g_xim_string_get_string(const GXimString *string)
1521{
1522	g_return_val_if_fail (string != NULL, NULL);
1523
1524	return ((GString *)string)->str;
1525}
1526
1527gsize
1528g_xim_string_get_length(GXimString *string)
1529{
1530	GString *str = (GString *)string;
1531
1532	g_return_val_if_fail (string != NULL, 0);
1533
1534	return str->len;
1535}
1536
1537gsize
1538g_xim_string_put_to_stream(GXimString         *string,
1539			   GDataOutputStream  *stream,
1540			   GCancellable       *cancellable,
1541			   GError            **error)
1542{
1543	gsize retval = 2, i;
1544	GString *str = (GString *)string;
1545
1546	g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), 0);
1547	g_return_val_if_fail (string != NULL, 0);
1548	g_return_val_if_fail (error != NULL, 0);
1549
1550	/* length of string in bytes */
1551	g_data_output_stream_put_uint16(stream,
1552					str->len,
1553					cancellable,
1554					error);
1555	if (*error)
1556		return 0;
1557	/* LIST of LPCE */
1558	for (i = 0; i < str->len; i++) {
1559		g_data_output_stream_put_byte(stream,
1560					      str->str[i],
1561					      cancellable,
1562					      error);
1563		if (*error)
1564			return 0;
1565
1566		retval++;
1567	}
1568	/* padding */
1569	for (i = 0; i < g_xim_protocol_n_pad4 (2 + str->len); i++) {
1570		g_data_output_stream_put_byte(stream, 0, cancellable, error);
1571		if (*error)
1572			return 0;
1573		retval++;
1574	}
1575
1576	return retval;
1577}
1578
1579gpointer
1580g_xim_string_get_from_stream(GDataInputStream  *stream,
1581			     GCancellable      *cancellable,
1582			     GError           **error)
1583{
1584	guint16 n, i;
1585	GString *str = NULL;
1586	GInputStream *base_stream;
1587
1588	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
1589	g_return_val_if_fail (error != NULL, NULL);
1590
1591	n = g_data_input_stream_read_uint16(stream, cancellable, error);
1592	if (*error)
1593		return NULL;
1594	str = g_string_sized_new(n);
1595	G_XIM_GERROR_CHECK_ALLOC (str, error,
1596				  G_XIM_PROTOCOL_ERROR, NULL);
1597
1598	for (i = 0; i < n; i++) {
1599		guint8 c;
1600
1601		c = g_data_input_stream_read_byte(stream, cancellable, error);
1602		if (*error)
1603			goto fail;
1604		g_string_append_c(str, c);
1605	}
1606	/* skip padding */
1607	base_stream = g_filter_input_stream_get_base_stream(G_FILTER_INPUT_STREAM (stream));
1608	g_seekable_seek(G_SEEKABLE (base_stream),
1609			g_xim_protocol_n_pad4 (2 + n),
1610			G_SEEK_CUR, cancellable, error);
1611
1612	return str;
1613  fail:
1614	if (str)
1615		g_string_free(str, TRUE);
1616
1617	return NULL;
1618}
1619
1620/* STR */
1621GType
1622g_xim_str_get_type(void)
1623{
1624	static volatile gsize type_id_volatile = 0;
1625
1626	if (g_once_init_enter(&type_id_volatile)) {
1627		GType type_id;
1628
1629		type_id = g_boxed_type_register_static(g_intern_static_string("GXimStr"),
1630						       g_xim_str_copy,
1631						       g_xim_str_free);
1632		g_once_init_leave(&type_id_volatile, type_id);
1633	}
1634
1635	return type_id_volatile;
1636}
1637
1638gpointer
1639g_xim_str_new(void)
1640{
1641	GString *retval = g_string_new(NULL);
1642
1643	return retval;
1644}
1645
1646gpointer
1647g_xim_str_copy(gpointer boxed)
1648{
1649	GString *retval, *orig = boxed;
1650
1651	g_return_val_if_fail (boxed != NULL, NULL);
1652
1653	retval = g_string_sized_new(orig->len);
1654	G_XIM_CHECK_ALLOC (retval, NULL);
1655
1656	g_string_append(retval, orig->str);
1657
1658	return retval;
1659}
1660
1661void
1662g_xim_str_free(gpointer boxed)
1663{
1664	if (boxed == NULL)
1665		return;
1666
1667	g_string_free(boxed, TRUE);
1668}
1669
1670const gchar *
1671g_xim_str_get_string(const GXimStr *string)
1672{
1673	g_return_val_if_fail (string != NULL, NULL);
1674
1675	return ((GString *)string)->str;
1676}
1677
1678gsize
1679g_xim_str_get_length(const GXimStr *string)
1680{
1681	const GString *str = (const GString *)string;
1682
1683	g_return_val_if_fail (string != NULL, 0);
1684
1685	return str->len;
1686}
1687
1688GXimStr *
1689g_xim_str_append(GXimStr     *string,
1690		 const gchar *val)
1691{
1692	g_return_val_if_fail (string != NULL, NULL);
1693	g_return_val_if_fail (val != NULL, string);
1694
1695	return g_xim_str_append_len(string, val, strlen(val));
1696}
1697
1698GXimStr *
1699g_xim_str_append_len(GXimStr     *string,
1700		     const gchar *val,
1701		     gssize       len)
1702{
1703	g_return_val_if_fail (string != NULL, NULL);
1704	g_return_val_if_fail (val != NULL, string);
1705
1706	if (len < 0)
1707		len = strlen(val);
1708
1709	return (GXimStr *)g_string_append_len((GString *)string,
1710					      val,
1711					      len);
1712}
1713
1714gsize
1715g_xim_str_put_to_stream(GXimStr            *string,
1716			GDataOutputStream  *stream,
1717			GCancellable       *cancellable,
1718			GError            **error)
1719{
1720	gsize retval = 1, i;
1721	GString *str = (GString *)string;
1722
1723	g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), 0);
1724	g_return_val_if_fail (string != NULL, 0);
1725	g_return_val_if_fail (str->len < 0x100, 0);
1726	g_return_val_if_fail (error != NULL, 0);
1727
1728	/* length of string in bytes */
1729	g_data_output_stream_put_byte(stream,
1730				      str->len,
1731				      cancellable,
1732				      error);
1733	if (*error)
1734		return 0;
1735	/* STRING8 */
1736	for (i = 0; i < str->len; i++) {
1737		g_data_output_stream_put_byte(stream,
1738					      str->str[i],
1739					      cancellable,
1740					      error);
1741		if (*error)
1742			return 0;
1743
1744		retval++;
1745	}
1746
1747	return retval;
1748}
1749
1750gpointer
1751g_xim_str_get_from_stream(GDataInputStream  *stream,
1752			  GCancellable      *cancellable,
1753			  GError           **error)
1754{
1755	guint8 n, i;
1756	GString *str = NULL;
1757
1758	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
1759	g_return_val_if_fail (error != NULL, NULL);
1760
1761	n = g_data_input_stream_read_byte(stream, cancellable, error);
1762	if (*error)
1763		return NULL;
1764	str = g_string_sized_new(n);
1765	G_XIM_GERROR_CHECK_ALLOC (str, error,
1766				  G_XIM_PROTOCOL_ERROR, NULL);
1767
1768	for (i = 0; i < n; i++) {
1769		guint8 c;
1770
1771		c = g_data_input_stream_read_byte(stream, cancellable, error);
1772		if (*error)
1773			goto fail;
1774		g_string_append_c(str, c);
1775	}
1776
1777	return str;
1778  fail:
1779	if (str)
1780		g_string_free(str, TRUE);
1781
1782	return NULL;
1783}
1784
1785/* ENCODINGINFO */
1786GType
1787g_xim_encodinginfo_get_type(void)
1788{
1789	static volatile gsize type_id_volatile = 0;
1790
1791	if (g_once_init_enter(&type_id_volatile)) {
1792		GType type_id;
1793
1794		type_id = g_boxed_type_register_static(g_intern_static_string("ENCODINGINFO"),
1795						       g_xim_encodinginfo_copy,
1796						       g_xim_encodinginfo_free);
1797		g_once_init_leave(&type_id_volatile, type_id);
1798	}
1799
1800	return type_id_volatile;
1801}
1802
1803gpointer
1804g_xim_encodinginfo_new(void)
1805{
1806	GString *retval = g_string_new(NULL);
1807
1808	return retval;
1809}
1810
1811gpointer
1812g_xim_encodinginfo_copy(gpointer boxed)
1813{
1814	GString *retval, *orig = boxed;
1815
1816	g_return_val_if_fail (boxed != NULL, NULL);
1817
1818	retval = g_string_sized_new(orig->len);
1819	G_XIM_CHECK_ALLOC (retval, NULL);
1820
1821	g_string_append(retval, orig->str);
1822
1823	return retval;
1824}
1825
1826void
1827g_xim_encodinginfo_free(gpointer boxed)
1828{
1829	if (boxed == NULL)
1830		return;
1831
1832	g_string_free(boxed, TRUE);
1833}
1834
1835const gchar *
1836g_xim_encodinginfo_get_string(const GXimEncodingInfo *encoding)
1837{
1838	g_return_val_if_fail (encoding != NULL, NULL);
1839
1840	return ((GString *)encoding)->str;
1841}
1842
1843gsize
1844g_xim_encodinginfo_get_length(GXimEncodingInfo *encoding)
1845{
1846	GString *str = (GString *)encoding;
1847
1848	g_return_val_if_fail (encoding != NULL, 0);
1849
1850	return str->len;
1851}
1852
1853gsize
1854g_xim_encodinginfo_put_to_stream(GXimEncodingInfo   *encoding,
1855				 GDataOutputStream  *stream,
1856				 GCancellable       *cancellable,
1857				 GError            **error)
1858{
1859	gsize retval = 2, i;
1860	GString *str = (GString *)encoding;
1861
1862	g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), 0);
1863	g_return_val_if_fail (encoding != NULL, 0);
1864	g_return_val_if_fail (error != NULL, 0);
1865
1866	/* length of string in bytes */
1867	g_data_output_stream_put_uint16(stream,
1868					str->len,
1869					cancellable,
1870					error);
1871	if (*error)
1872		return 0;
1873	/* STRING8 */
1874	for (i = 0; i < str->len; i++) {
1875		g_data_output_stream_put_byte(stream,
1876					      str->str[i],
1877					      cancellable,
1878					      error);
1879		if (*error)
1880			return 0;
1881
1882		retval++;
1883	}
1884	/* padding */
1885	for (i = 0; i < g_xim_protocol_n_pad4 (2 + str->len); i++) {
1886		g_data_output_stream_put_byte(stream, 0, cancellable, error);
1887		if (*error)
1888			return 0;
1889		retval++;
1890	}
1891
1892	return retval;
1893}
1894
1895gpointer
1896g_xim_encodinginfo_get_from_stream(GDataInputStream  *stream,
1897				   GCancellable      *cancellable,
1898				   GError           **error)
1899{
1900	guint16 n, i;
1901	GString *str = NULL;
1902	GInputStream *base_stream;
1903
1904	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
1905	g_return_val_if_fail (error != NULL, NULL);
1906
1907	n = g_data_input_stream_read_uint16(stream, cancellable, error);
1908	if (*error)
1909		return NULL;
1910	str = g_string_sized_new(n);
1911	G_XIM_GERROR_CHECK_ALLOC (str, error,
1912				  G_XIM_PROTOCOL_ERROR, NULL);
1913
1914	for (i = 0; i < n; i++) {
1915		guint8 c;
1916
1917		c = g_data_input_stream_read_byte(stream, cancellable, error);
1918		if (*error)
1919			goto fail;
1920		g_string_append_c(str, c);
1921	}
1922	/* skip padding */
1923	base_stream = g_filter_input_stream_get_base_stream(G_FILTER_INPUT_STREAM (stream));
1924	g_seekable_seek(G_SEEKABLE (base_stream),
1925			g_xim_protocol_n_pad4 (2 + n),
1926			G_SEEK_CUR, cancellable, error);
1927
1928	return str;
1929  fail:
1930	if (str)
1931		g_string_free(str, TRUE);
1932
1933	return NULL;
1934}
1935
1936/* ATTR */
1937GType
1938g_xim_raw_attr_get_type(void)
1939{
1940	static volatile gsize type_id_volatile = 0;
1941
1942	if (g_once_init_enter(&type_id_volatile)) {
1943		GType type_id;
1944
1945		type_id = g_boxed_type_register_static(g_intern_static_string("GXimRawAttr"),
1946						       g_xim_raw_attr_copy,
1947						       g_xim_raw_attr_free);
1948		g_once_init_leave(&type_id_volatile, type_id);
1949	}
1950
1951	return type_id_volatile;
1952}
1953
1954gpointer
1955g_xim_raw_attr_new(void)
1956{
1957	GXimRawAttr *retval;
1958
1959	retval = g_new0(GXimRawAttr, 1);
1960	G_XIM_CHECK_ALLOC (retval, NULL);
1961
1962	retval->base.vtype = G_XIM_TYPE_INVALID;
1963
1964	return retval;
1965}
1966
1967gpointer
1968g_xim_raw_attr_new_with_value(guint16        id,
1969			      GString       *name,
1970			      GXimValueType  vtype)
1971{
1972	GXimRawAttr *retval;
1973
1974	g_return_val_if_fail (vtype != G_XIM_TYPE_INVALID, NULL);
1975	g_return_val_if_fail (name != NULL, NULL);
1976
1977	retval = g_xim_raw_attr_new();
1978	G_XIM_CHECK_ALLOC (retval, NULL);
1979
1980	g_xim_raw_attr_set_name(retval, name);
1981	retval->base.id = id;
1982	retval->base.vtype = vtype;
1983
1984	return retval;
1985}
1986
1987void
1988g_xim_raw_attr_set_name(GXimRawAttr *attr,
1989			GString     *name)
1990{
1991	g_return_if_fail (attr != NULL);
1992	g_return_if_fail (name != NULL);
1993	g_return_if_fail (name->len > 0);
1994
1995	if (attr->attribute_name)
1996		g_string_free(attr->attribute_name, TRUE);
1997
1998	attr->attribute_name = g_string_sized_new(name->len);
1999	G_XIM_CHECK_ALLOC_WITH_NO_RET (attr->attribute_name);
2000
2001	g_string_append(attr->attribute_name, name->str);
2002}
2003
2004void
2005g_xim_raw_attr_clear(GXimRawAttr *attr)
2006{
2007	g_return_if_fail (attr != NULL);
2008
2009	attr->base.vtype = G_XIM_TYPE_INVALID;
2010	g_string_free(attr->attribute_name, TRUE);
2011	attr->attribute_name = NULL;
2012}
2013
2014gpointer
2015g_xim_raw_attr_copy(gpointer boxed)
2016{
2017	GXimRawAttr *retval, *orig;
2018
2019	if (boxed == NULL)
2020		return NULL;
2021
2022	orig = boxed;
2023	retval = g_xim_raw_attr_new_with_value(orig->base.id,
2024					       orig->attribute_name,
2025					       orig->base.vtype);
2026
2027	return retval;
2028}
2029
2030void
2031g_xim_raw_attr_free(gpointer boxed)
2032{
2033	if (boxed == NULL)
2034		return;
2035
2036	g_xim_raw_attr_clear(boxed);
2037	g_free(boxed);
2038}
2039
2040gsize
2041g_xim_raw_attr_put_to_stream(GXimRawAttr   *attr,
2042			     GXimProtocol  *proto,
2043			     GCancellable  *cancellable,
2044			     GError       **error)
2045{
2046	g_return_val_if_fail (attr != NULL, 0);
2047	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
2048	g_return_val_if_fail (error != NULL, 0);
2049
2050	return g_xim_protocol_send_format(proto, cancellable, error, 4,
2051					  G_XIM_TYPE_WORD, attr->base.id,
2052					  G_XIM_TYPE_WORD, attr->base.vtype,
2053					  /* G_XIM_TYPE_GSTRING puts the size as CARD16 first then STRING8 */
2054					  G_XIM_TYPE_GSTRING, attr->attribute_name,
2055					  G_XIM_TYPE_AUTO_PADDING, 2);
2056}
2057
2058gpointer
2059g_xim_raw_attr_get_from_stream(GXimProtocol      *proto,
2060			       GDataInputStream  *stream,
2061			       GCancellable      *cancellable,
2062			       GError           **error)
2063{
2064	GXimRawAttr *retval;
2065	guint16 id;
2066	GXimValueType vtype = 0;
2067	GString *name = NULL;
2068
2069	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), NULL);
2070	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
2071	g_return_val_if_fail (error != NULL, NULL);
2072
2073	if (!g_xim_protocol_read_format(proto, stream, cancellable, error,
2074					4,
2075					G_XIM_TYPE_WORD, &id,
2076					G_XIM_TYPE_WORD, &vtype,
2077					G_XIM_TYPE_GSTRING, &name,
2078					G_XIM_TYPE_AUTO_PADDING, 2))
2079		return NULL;
2080	retval = g_xim_raw_attr_new_with_value(id, name, vtype);
2081
2082	return retval;
2083}
2084
2085/* ATTRIBUTE */
2086GType
2087g_xim_attribute_get_type(void)
2088{
2089	static volatile gsize type_id_volatile = 0;
2090
2091	if (g_once_init_enter(&type_id_volatile)) {
2092		GType type_id;
2093
2094		type_id = g_boxed_type_register_static(g_intern_static_string("GXimAttribute"),
2095						       g_xim_attribute_copy,
2096						       g_xim_attribute_free);
2097		g_once_init_leave(&type_id_volatile, type_id);
2098	}
2099
2100	return type_id_volatile;
2101}
2102
2103gpointer
2104g_xim_attribute_new(void)
2105{
2106	GXimAttribute *retval;
2107
2108	retval = g_new0(GXimAttribute, 1);
2109	G_XIM_CHECK_ALLOC (retval, NULL);
2110
2111	retval->vtype = G_XIM_TYPE_INVALID;
2112
2113	return retval;
2114}
2115
2116gpointer
2117g_xim_attribute_new_with_value(guint16       id,
2118			       GXimValueType vtype,
2119			       gpointer      value)
2120{
2121	GXimAttribute *retval;
2122
2123	g_return_val_if_fail (vtype != G_XIM_TYPE_INVALID, NULL);
2124
2125	retval = g_xim_attribute_new();
2126	G_XIM_CHECK_ALLOC (retval, NULL);
2127
2128	g_xim_attribute_set(retval, id, vtype, value);
2129
2130	return retval;
2131}
2132
2133void
2134g_xim_attribute_set(GXimAttribute *attr,
2135		    guint16        id,
2136		    GXimValueType  vtype,
2137		    gpointer       value)
2138{
2139	GType gtype;
2140
2141	g_return_if_fail (attr != NULL);
2142	g_return_if_fail (vtype != G_XIM_TYPE_INVALID);
2143
2144	gtype = g_xim_value_type_to_gtype(vtype);
2145	g_return_if_fail (gtype != G_TYPE_INVALID);
2146
2147	g_xim_attribute_clear(attr);
2148	attr->id = id;
2149	attr->vtype = vtype;
2150	if (vtype == G_XIM_TYPE_WORD)
2151		attr->v.i = GPOINTER_TO_UINT (value);
2152	else if (vtype == G_XIM_TYPE_LONG)
2153		attr->v.l = (gulong)value;
2154	else
2155		attr->v.pointer = g_xim_copy_by_gtype(gtype, value);
2156}
2157
2158void
2159g_xim_attribute_clear(GXimAttribute *attr)
2160{
2161	GType gtype;
2162
2163	g_return_if_fail (attr != NULL);
2164
2165	if (attr->vtype == G_XIM_TYPE_INVALID)
2166		return;
2167
2168	gtype = g_xim_value_type_to_gtype(attr->vtype);
2169	g_return_if_fail (gtype != G_TYPE_INVALID);
2170
2171	g_xim_free_by_gtype(gtype, attr->v.pointer);
2172	attr->v.pointer = NULL;
2173	attr->vtype = G_XIM_TYPE_INVALID;
2174}
2175
2176gpointer
2177g_xim_attribute_copy(gpointer boxed)
2178{
2179	GXimAttribute *retval, *orig;
2180
2181	if (boxed == NULL)
2182		return NULL;
2183
2184	orig = boxed;
2185	retval = g_xim_attribute_new();
2186	G_XIM_CHECK_ALLOC (retval, NULL);
2187
2188	g_xim_attribute_set(retval, orig->id, orig->vtype, orig->v.pointer);
2189
2190	return retval;
2191}
2192
2193void
2194g_xim_attribute_free(gpointer boxed)
2195{
2196	if (boxed == NULL)
2197		return;
2198
2199	g_xim_attribute_clear(boxed);
2200	g_free(boxed);
2201}
2202
2203gsize
2204g_xim_attribute_put_to_stream(GXimAttribute *attr,
2205			      GXimProtocol  *proto,
2206			      GCancellable  *cancellable,
2207			      GError       **error)
2208{
2209	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
2210	g_return_val_if_fail (attr != NULL, 0);
2211	g_return_val_if_fail (error != NULL, 0);
2212
2213	return g_xim_protocol_send_format(proto, cancellable, error, 4,
2214					  G_XIM_TYPE_WORD, attr->id,
2215					  G_XIM_TYPE_MARKER_N_BYTES_2, attr->vtype,
2216					  attr->vtype, attr->v.pointer,
2217					  G_XIM_TYPE_AUTO_PADDING, 0);
2218}
2219
2220/* NESTEDLIST */
2221GType
2222g_xim_nested_list_get_type(void)
2223{
2224	static volatile gsize type_id_volatile = 0;
2225
2226	if (g_once_init_enter(&type_id_volatile)) {
2227		GType type_id;
2228
2229		type_id = g_boxed_type_register_static(g_intern_static_string("NESTEDLIST"),
2230						       g_xim_nested_list_copy,
2231						       g_xim_nested_list_free);
2232		g_once_init_leave(&type_id_volatile, type_id);
2233	}
2234
2235	return type_id_volatile;
2236}
2237
2238gpointer
2239g_xim_nested_list_new(GXimAttr *attr,
2240		      guint     n_nodes)
2241{
2242	GXimNestedList *retval;
2243
2244	retval = g_new0(GXimNestedList, 1);
2245	G_XIM_CHECK_ALLOC (retval, NULL);
2246
2247	retval->attr = g_object_ref(attr);
2248	if (n_nodes > 0) {
2249		retval->nodes = g_new0(GXimNestedListNode *, n_nodes);
2250		G_XIM_CHECK_ALLOC (retval->nodes, NULL);
2251	}
2252	retval->allocated_len = n_nodes;
2253
2254	return retval;
2255}
2256
2257gpointer
2258g_xim_nested_list_copy(gpointer boxed)
2259{
2260	GXimNestedList *retval, *orig = boxed;
2261	guint16 i;
2262
2263	if (boxed == NULL)
2264		return NULL;
2265
2266	retval = g_xim_nested_list_new(orig->attr, orig->n_nodes);
2267	G_XIM_CHECK_ALLOC (retval, NULL);
2268
2269	for (i = 0; i < orig->n_nodes; i++) {
2270		retval->nodes[i] = g_xim_nested_list_node_copy(orig->nodes[i]);
2271		G_XIM_CHECK_ALLOC_WITH_CODE (retval->nodes[i],
2272					     {retval->n_nodes = i; g_xim_nested_list_free(retval);},
2273					     NULL);
2274	}
2275	retval->n_nodes = orig->n_nodes;
2276
2277	return retval;
2278}
2279
2280void
2281g_xim_nested_list_free(gpointer boxed)
2282{
2283	GXimNestedList *list = boxed;
2284	guint16 i;
2285
2286	if (boxed == NULL)
2287		return;
2288
2289	for (i = 0; i < list->n_nodes; i++) {
2290		GXimNestedListNode *node;
2291
2292		node = list->nodes[i];
2293		g_xim_nested_list_node_free(node);
2294	}
2295	g_object_unref(list->attr);
2296	g_free(list->nodes);
2297	g_free(list);
2298}
2299
2300gboolean
2301g_xim_nested_list_append(GXimNestedList *list,
2302			 const gchar    *name,
2303			 gpointer        value)
2304{
2305	GXimNestedListNode *node, *tmp;
2306	GXimValueType vtype;
2307	GType gtype;
2308
2309	g_return_val_if_fail (list != NULL, FALSE);
2310	g_return_val_if_fail (name != NULL, FALSE);
2311
2312	if (list->n_nodes == list->allocated_len) {
2313		gpointer data;
2314
2315		data = (gpointer)g_realloc(list->nodes,
2316					   sizeof (gpointer) * (list->allocated_len + N_REALLOC_NESTED_LIST));
2317		G_XIM_CHECK_ALLOC (data, FALSE);
2318
2319		list->nodes = data;
2320		list->allocated_len += N_REALLOC_NESTED_LIST;
2321	}
2322	gtype = g_xim_attr_get_gtype_by_name(list->attr, name);
2323	g_return_val_if_fail (gtype != G_TYPE_INVALID, FALSE);
2324
2325	vtype = g_xim_gtype_to_value_type(gtype);
2326	g_return_val_if_fail (vtype != G_XIM_TYPE_INVALID, FALSE);
2327
2328	tmp = g_xim_nested_list_node_new();
2329	G_XIM_CHECK_ALLOC (tmp, FALSE);
2330
2331	tmp->vtype = vtype;
2332	tmp->name = (gchar *)name;
2333	tmp->value = value;
2334
2335	node = g_xim_nested_list_node_copy(tmp);
2336	G_XIM_CHECK_ALLOC_WITH_CODE (node, g_free(tmp), FALSE);
2337	g_free(tmp);
2338
2339	list->nodes[list->n_nodes] = node;
2340	list->n_nodes++;
2341
2342	return TRUE;
2343}
2344
2345gboolean
2346g_xim_nested_list_foreach(GXimNestedList *list,
2347			  GXimNestedFunc  func,
2348			  gpointer        data)
2349{
2350	guint16 i;
2351
2352	g_return_val_if_fail (list != NULL, FALSE);
2353	g_return_val_if_fail (func != NULL, FALSE);
2354
2355	for (i = 0; i < list->n_nodes; i++) {
2356		GXimNestedListNode *node = list->nodes[i];
2357
2358		if (func(node, data))
2359			break;
2360	}
2361
2362	return TRUE;
2363}
2364
2365gsize
2366g_xim_nested_list_put_to_stream(GXimNestedList  *list,
2367				GXimProtocol    *proto,
2368				GCancellable    *cancellable,
2369				GError         **error)
2370{
2371	gsize retval = 0;
2372	guint16 i;
2373
2374	g_return_val_if_fail (list != NULL, 0);
2375	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
2376	g_return_val_if_fail (error != NULL, 0);
2377
2378	for (i = 0; i < list->n_nodes; i++) {
2379		GXimNestedListNode *node;
2380		gint16 attr_id;
2381
2382		node = list->nodes[i];
2383		attr_id = g_xim_attr_get_attribute_id(list->attr, node->name);
2384		if (attr_id < 0) {
2385			g_xim_messages_warning(G_XIM_PROTOCOL_GET_IFACE (proto)->message,
2386					       "No attribute id available for %s in %s",
2387					       node->name, g_type_name(G_TYPE_FROM_INSTANCE (list->attr)));
2388			continue;
2389		}
2390		retval += g_xim_protocol_send_format(proto, cancellable, error, 3,
2391						     G_XIM_TYPE_WORD, attr_id,
2392						     G_XIM_TYPE_MARKER_N_BYTES_2, node->vtype,
2393						     node->vtype, node->value);
2394	}
2395
2396	return retval;
2397}
2398
2399/* SeparatorofNestedList */
2400GType
2401g_xim_sep_nested_list_get_type(void)
2402{
2403	static volatile gsize type_id_volatile = 0;
2404
2405	if (g_once_init_enter(&type_id_volatile)) {
2406		GType type_id;
2407
2408		type_id = g_boxed_type_register_static(g_intern_static_string("SeparatorofNestedList"),
2409						       g_xim_sep_nested_list_copy,
2410						       g_xim_sep_nested_list_free);
2411		g_once_init_leave(&type_id_volatile, type_id);
2412	}
2413
2414	return type_id_volatile;
2415}
2416
2417gpointer
2418g_xim_sep_nested_list_new(void)
2419{
2420	return g_new0(GXimSepNestedList, 1);
2421}
2422
2423gpointer
2424g_xim_sep_nested_list_copy(gpointer boxed)
2425{
2426	if (boxed == NULL)
2427		return NULL;
2428
2429	return g_xim_sep_nested_list_new();
2430}
2431
2432void
2433g_xim_sep_nested_list_free(gpointer boxed)
2434{
2435	g_free(boxed);
2436}
2437
2438/* EXT */
2439GType
2440g_xim_ext_get_type(void)
2441{
2442	static volatile gsize type_id_volatile = 0;
2443
2444	if (g_once_init_enter(&type_id_volatile)) {
2445		GType type_id;
2446
2447		type_id = g_boxed_type_register_static(g_intern_static_string("GXimExt"),
2448						       g_xim_ext_copy,
2449						       g_xim_ext_free);
2450		g_once_init_leave(&type_id_volatile, type_id);
2451	}
2452
2453	return type_id_volatile;
2454}
2455
2456gpointer
2457g_xim_ext_new(guint8       major_opcode,
2458	      guint8       minor_opcode,
2459	      const gchar *name)
2460{
2461	GXimExt *retval;
2462
2463	retval = g_new0(GXimExt, 1);
2464	G_XIM_CHECK_ALLOC (retval, NULL);
2465
2466	retval->major_opcode = major_opcode;
2467	retval->minor_opcode = minor_opcode;
2468	retval->name = g_string_new(name);
2469
2470	return retval;
2471}
2472
2473gpointer
2474g_xim_ext_copy(gpointer boxed)
2475{
2476	GXimExt *orig = boxed;
2477
2478	if (boxed == NULL)
2479		return NULL;
2480
2481	return g_xim_ext_new(orig->major_opcode,
2482			     orig->minor_opcode,
2483			     orig->name->str);
2484}
2485
2486void
2487g_xim_ext_free(gpointer boxed)
2488{
2489	GXimExt *ext = boxed;
2490
2491	if (boxed == NULL)
2492		return;
2493
2494	g_string_free(ext->name, TRUE);
2495	g_free(ext);
2496}
2497
2498gsize
2499g_xim_ext_put_to_stream(GXimExt       *ext,
2500			GXimProtocol  *proto,
2501			GCancellable  *cancellable,
2502			GError       **error)
2503{
2504	g_return_val_if_fail (ext != NULL, 0);
2505	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
2506	g_return_val_if_fail (error != NULL, 0);
2507
2508	return g_xim_protocol_send_format(proto, cancellable, error, 4,
2509					  G_XIM_TYPE_BYTE, ext->major_opcode,
2510					  G_XIM_TYPE_BYTE, ext->minor_opcode,
2511					  G_XIM_TYPE_GSTRING, ext->name,
2512					  G_XIM_TYPE_AUTO_PADDING, 0);
2513}
2514
2515gpointer
2516g_xim_ext_get_from_stream(GXimProtocol      *proto,
2517			  GDataInputStream  *stream,
2518			  GCancellable      *cancellable,
2519			  GError           **error)
2520{
2521	GXimExt *retval;
2522	guint8 major, minor;
2523	GString *name;
2524
2525	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), NULL);
2526	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
2527	g_return_val_if_fail (error != NULL, NULL);
2528
2529	if (!g_xim_protocol_read_format(proto, stream, cancellable, error,
2530					4,
2531					G_XIM_TYPE_BYTE, &major,
2532					G_XIM_TYPE_BYTE, &minor,
2533					G_XIM_TYPE_GSTRING, &name,
2534					G_XIM_TYPE_AUTO_PADDING, 0))
2535		return NULL;
2536
2537	retval = g_xim_ext_new(major, minor, name->str);
2538	g_string_free(name, TRUE);
2539
2540	return retval;
2541}
2542
2543/* GXimText */
2544GType
2545g_xim_text_get_type(void)
2546{
2547	static volatile gsize type_id_volatile = 0;
2548
2549	if (g_once_init_enter(&type_id_volatile)) {
2550		GType type_id;
2551
2552		type_id = g_boxed_type_register_static(g_intern_static_string("GXimText"),
2553						       g_xim_text_copy,
2554						       g_xim_text_free);
2555		g_once_init_leave(&type_id_volatile, type_id);
2556	}
2557
2558	return type_id_volatile;
2559}
2560
2561gpointer
2562g_xim_text_new(void)
2563{
2564	return g_new0(GXimText, 1);
2565}
2566
2567gboolean
2568g_xim_text_set_mbstring(GXimText    *text,
2569			const gchar *string,
2570			gssize       length)
2571{
2572	g_return_val_if_fail (text != NULL, FALSE);
2573	g_return_val_if_fail (string != NULL, FALSE);
2574
2575	g_xim_text_clear_string(text);
2576	text->encoding_is_wchar = FALSE;
2577	if (length < 0)
2578		length = strlen(string);
2579	g_return_val_if_fail (length < 65536, FALSE);
2580	text->length = length;
2581	text->string.multi_byte = g_strdup(string);
2582	text->feedback = g_new0(GXimFeedback, length + 1);
2583
2584	return TRUE;
2585}
2586
2587gboolean
2588g_xim_text_set_wcstring(GXimText        *text,
2589			const gunichar2 *string,
2590			gssize           length)
2591{
2592	g_return_val_if_fail (text != NULL, FALSE);
2593	g_return_val_if_fail (string != NULL, FALSE);
2594	g_return_val_if_fail (length > 0 && length < 65536, FALSE);
2595
2596	g_xim_text_clear_string(text);
2597	text->encoding_is_wchar = TRUE;
2598	text->length = length;
2599	text->string.wide_char = g_new0(gunichar2, length + 1);
2600	G_XIM_CHECK_ALLOC (text->string.wide_char, FALSE);
2601
2602	memcpy(text->string.wide_char, string, sizeof(gunichar2) * length);
2603	text->string.wide_char[length] = 0;
2604	text->feedback = g_new0(GXimFeedback, length + 1);
2605
2606	return TRUE;
2607}
2608
2609void
2610g_xim_text_clear_string(GXimText *text)
2611{
2612	g_return_if_fail (text != NULL);
2613
2614	if (text->encoding_is_wchar) {
2615		g_free(text->string.wide_char);
2616	} else {
2617		g_free(text->string.multi_byte);
2618	}
2619	g_free(text->feedback);
2620}
2621
2622void
2623g_xim_text_set_feedback(GXimText     *text,
2624			GXimFeedback  feedback,
2625			gshort        position)
2626{
2627	g_return_if_fail (text != NULL);
2628	g_return_if_fail (text->length > position);
2629
2630	text->feedback[position] = feedback;
2631}
2632
2633GXimFeedback
2634g_xim_text_get_feedback(GXimText *text,
2635			gshort    position)
2636{
2637	g_return_val_if_fail (text != NULL, 0);
2638	g_return_val_if_fail (text->length > position, 0);
2639	g_return_val_if_fail (text->feedback != NULL, 0);
2640
2641	return text->feedback[position];
2642}
2643
2644gpointer
2645g_xim_text_copy(gpointer boxed)
2646{
2647	GXimText *retval, *orig;
2648
2649	if (boxed == NULL)
2650		return NULL;
2651	orig = boxed;
2652	retval = g_xim_text_new();
2653	G_XIM_CHECK_ALLOC (retval, NULL);
2654
2655	retval->length = orig->length;
2656	retval->encoding_is_wchar = orig->encoding_is_wchar;
2657	if (orig->encoding_is_wchar) {
2658		g_xim_text_set_wcstring(retval,
2659					orig->string.wide_char,
2660					orig->length);
2661	} else {
2662		g_xim_text_set_mbstring(retval,
2663					orig->string.multi_byte,
2664					orig->length);
2665	}
2666	g_return_val_if_fail (retval->feedback != NULL, NULL);
2667	g_return_val_if_fail (orig->feedback != NULL, NULL);
2668
2669	memcpy(retval->feedback, orig->feedback, sizeof (GXimFeedback) * orig->length);
2670
2671	return retval;
2672}
2673
2674void
2675g_xim_text_free(gpointer boxed)
2676{
2677	GXimText *text = boxed;
2678
2679	if (boxed == NULL)
2680		return;
2681	if (text->encoding_is_wchar)
2682		g_free(text->string.wide_char);
2683	else
2684		g_free(text->string.multi_byte);
2685	g_free(text->feedback);
2686
2687	g_free(text);
2688}
2689
2690gsize
2691g_xim_text_put_to_stream(GXimText      *text,
2692			 GXimProtocol  *proto,
2693			 GCancellable  *cancellable,
2694			 GError       **error)
2695{
2696	guint32 mask = 0;
2697	gsize retval;
2698	gboolean no_feedback = FALSE, no_string = FALSE;
2699	gint i, len;
2700
2701	g_return_val_if_fail (text != NULL, 0);
2702	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
2703	g_return_val_if_fail (error != NULL, 0);
2704
2705	if (text->length == 0 ||
2706	    (text->encoding_is_wchar && text->string.wide_char[0] == 0) ||
2707	    (!text->encoding_is_wchar && text->string.multi_byte[0] == 0))
2708		no_string = TRUE;
2709	if (text->feedback[0] == 0)
2710		no_feedback = TRUE;
2711
2712	if (no_string)
2713		mask |= (1L << 0);
2714	if (no_feedback)
2715		mask |= (1L << 1);
2716	retval = g_xim_protocol_send_format(proto, cancellable, error, 1,
2717					    G_XIM_TYPE_LONG, mask);
2718	if (*error)
2719		return 0;
2720	if (no_string)
2721		retval += g_xim_protocol_send_format(proto, cancellable, error, 2,
2722						     G_XIM_TYPE_WORD, 0,
2723						     G_XIM_TYPE_PADDING, 2);
2724	else
2725		retval += g_xim_protocol_send_format(proto, cancellable, error, 3,
2726						     G_XIM_TYPE_MARKER_N_BYTES_2, G_XIM_TYPE_CHAR,
2727						     G_XIM_TYPE_CHAR, text->string.multi_byte,
2728						     G_XIM_TYPE_AUTO_PADDING, 2);
2729	if (*error)
2730		return 0;
2731	if (no_feedback) {
2732		retval += g_xim_protocol_send_format(proto, cancellable, error, 2,
2733						     G_XIM_TYPE_WORD, 0,
2734						     G_XIM_TYPE_PADDING, 2);
2735	} else {
2736		for (len = 0; len < text->length; len++)
2737			if (text->feedback[len] == 0)
2738				break;
2739		retval += g_xim_protocol_send_format(proto, cancellable, error, 2,
2740						     G_XIM_TYPE_WORD, len * 4,
2741						     G_XIM_TYPE_PADDING, 2);
2742		if (*error)
2743			return 0;
2744		for (i = 0; i < len; i++) {
2745			guint32 val = 0;
2746
2747			if (text->feedback[i] & G_XIM_XIMReverse)
2748				val |= (1L << 0);
2749			if (text->feedback[i] & G_XIM_XIMUnderline)
2750				val |= (1L << 1);
2751			if (text->feedback[i] & G_XIM_XIMHighlight)
2752				val |= (1L << 2);
2753			if (text->feedback[i] & G_XIM_XIMPrimary)
2754				val |= (1L << 3);
2755			if (text->feedback[i] & G_XIM_XIMSecondary)
2756				val |= (1L << 4);
2757			if (text->feedback[i] & G_XIM_XIMTertiary)
2758				val |= (1L << 5);
2759			if (text->feedback[i] & G_XIM_XIMVisibleToForward)
2760				val |= (1L << 6);
2761			if (text->feedback[i] & G_XIM_XIMVisibleToBackward)
2762				val |= (1L << 7);
2763			if (text->feedback[i] & G_XIM_XIMVisibleToCenter)
2764				val |= (1L << 8);
2765			retval += g_xim_protocol_send_format(proto, cancellable, error, 1,
2766							     G_XIM_TYPE_LONG, val);
2767			if (*error)
2768				return 0;
2769		}
2770	}
2771
2772	return retval;
2773}
2774
2775gpointer
2776g_xim_text_get_from_stream(GXimProtocol      *proto,
2777			   GDataInputStream  *stream,
2778			   GCancellable      *cancellable,
2779			   GError           **error)
2780{
2781	GXimText *retval;
2782	guint32 mask;
2783	GString *string;
2784	guint16 length, i;
2785
2786	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), NULL);
2787	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
2788	g_return_val_if_fail (error != NULL, NULL);
2789
2790	if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 5,
2791					G_XIM_TYPE_LONG, &mask,
2792					G_XIM_TYPE_GSTRING, &string,
2793					G_XIM_TYPE_AUTO_PADDING, 2,
2794					G_XIM_TYPE_WORD, &length,
2795					G_XIM_TYPE_PADDING, 2))
2796		return NULL;
2797
2798	retval = g_xim_text_new();
2799	G_XIM_GERROR_CHECK_ALLOC (retval, error,
2800				  G_XIM_PROTOCOL_ERROR, NULL);
2801
2802	g_xim_text_set_mbstring(retval, string->str, string->len);
2803	g_string_free(string, TRUE);
2804	if ((mask & (1L << 1)) == 0) {
2805		if (length < 4 ||
2806		    (length % 4) != 0) {
2807			g_xim_messages_warning(G_XIM_PROTOCOL_GET_IFACE (proto)->message,
2808					       "The length of feedback isn't aligned to 4 bytes: %" G_GUINT16_FORMAT,
2809					       length);
2810		}
2811		length /= 4;
2812	} else {
2813		length = 0;
2814	}
2815	for (i = 0; i < length; i++) {
2816		guint32 val = 0, xval = 0;
2817
2818		if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 1,
2819						G_XIM_TYPE_LONG, &val)) {
2820			length = i;
2821			G_XIM_GERROR_RESET_NOTICE_FLAG (*error);
2822			G_XIM_GERROR_SET_NOTICE_FLAG (*error,
2823						      G_XIM_NOTICE_WARNING);
2824			break;
2825		}
2826		if (val & (1L << 0))
2827			xval |= G_XIM_XIMReverse;
2828		if (val & (1L << 1))
2829			xval |= G_XIM_XIMUnderline;
2830		if (val & (1L << 2))
2831			xval |= G_XIM_XIMHighlight;
2832		if (val & (1L << 3))
2833			xval |= G_XIM_XIMPrimary;
2834		if (val & (1L << 4))
2835			xval |= G_XIM_XIMSecondary;
2836		if (val & (1L << 5))
2837			xval |= G_XIM_XIMTertiary;
2838		if (val & (1L << 6))
2839			xval |= G_XIM_XIMVisibleToForward;
2840		if (val & (1L << 7))
2841			xval |= G_XIM_XIMVisibleToBackward;
2842		if (val & (1L << 8))
2843			xval |= G_XIM_XIMVisibleToCenter;
2844		g_xim_text_set_feedback(retval, xval, i);
2845	}
2846	if (mask & (1L << 0))
2847		retval->length = length;
2848
2849	return retval;
2850}
2851			 
2852/* GXimPreeditCaret */
2853GType
2854g_xim_preedit_caret_get_type(void)
2855{
2856	static volatile gsize type_id_volatile = 0;
2857
2858	if (g_once_init_enter(&type_id_volatile)) {
2859		GType type_id;
2860
2861		type_id = g_boxed_type_register_static(g_intern_static_string("GXimPreeditCaret"),
2862						       g_xim_preedit_caret_copy,
2863						       g_xim_preedit_caret_free);
2864		g_once_init_leave(&type_id_volatile, type_id);
2865	}
2866
2867	return type_id_volatile;
2868}
2869
2870gpointer
2871g_xim_preedit_caret_new(void)
2872{
2873	return g_new0(GXimPreeditCaret, 1);
2874}
2875
2876gpointer
2877g_xim_preedit_caret_copy(gpointer boxed)
2878{
2879	GXimPreeditCaret *retval, *orig;
2880
2881	if (boxed == NULL)
2882		return NULL;
2883	orig = boxed;
2884
2885	retval = g_xim_preedit_caret_new();
2886	G_XIM_CHECK_ALLOC (retval, NULL);
2887
2888	retval->position = orig->position;
2889	retval->direction = orig->direction;
2890	retval->style = orig->style;
2891
2892	return retval;
2893}
2894
2895void
2896g_xim_preedit_caret_free(gpointer boxed)
2897{
2898	g_free(boxed);
2899}
2900
2901gsize
2902g_xim_preedit_caret_put_to_stream(GXimPreeditCaret  *caret,
2903				  GXimProtocol      *proto,
2904				  GCancellable      *cancellable,
2905				  GError           **error)
2906{
2907	g_return_val_if_fail (caret != NULL, 0);
2908	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
2909	g_return_val_if_fail (error != NULL, 0);
2910
2911	return g_xim_protocol_send_format(proto, cancellable, error, 3,
2912					  G_XIM_TYPE_LONG, caret->position,
2913					  G_XIM_TYPE_LONG, caret->direction,
2914					  G_XIM_TYPE_LONG, caret->style);
2915}
2916
2917gpointer
2918g_xim_preedit_caret_get_from_stream(GXimProtocol      *proto,
2919				    GDataInputStream  *stream,
2920				    GCancellable      *cancellable,
2921				    GError           **error)
2922{
2923	GXimPreeditCaret *retval;
2924	gint32 position;
2925	GXimCaretDirection direction;
2926	GXimCaretStyle style;
2927
2928	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), NULL);
2929	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
2930	g_return_val_if_fail (error != NULL, NULL);
2931
2932	if (!g_xim_protocol_read_format(proto, stream, cancellable, error,
2933					3,
2934					G_XIM_TYPE_LONG, &position,
2935					G_XIM_TYPE_LONG, &direction,
2936					G_XIM_TYPE_LONG, &style))
2937		return NULL;
2938
2939	retval = g_xim_preedit_caret_new();
2940	G_XIM_GERROR_CHECK_ALLOC (retval, error,
2941				  G_XIM_PROTOCOL_ERROR, NULL);
2942
2943	retval->position = position;
2944	retval->direction = direction;
2945	retval->style = style;
2946
2947	return retval;
2948}
2949
2950/* GXimPreeditDraw */
2951GType
2952g_xim_preedit_draw_get_type(void)
2953{
2954	static volatile gsize type_id_volatile = 0;
2955
2956	if (g_once_init_enter(&type_id_volatile)) {
2957		GType type_id;
2958
2959		type_id = g_boxed_type_register_static(g_intern_static_string("GXimPreeditDraw"),
2960						       g_xim_preedit_draw_copy,
2961						       g_xim_preedit_draw_free);
2962		g_once_init_leave(&type_id_volatile, type_id);
2963	}
2964
2965	return type_id_volatile;
2966}
2967
2968gpointer
2969g_xim_preedit_draw_new(void)
2970{
2971	return g_new0(GXimPreeditDraw, 1);
2972}
2973
2974gpointer
2975g_xim_preedit_draw_copy(gpointer boxed)
2976{
2977	GXimPreeditDraw *retval, *orig = boxed;
2978
2979	if (boxed == NULL)
2980		return NULL;
2981
2982	retval = g_xim_preedit_draw_new();
2983	G_XIM_CHECK_ALLOC (retval, NULL);
2984
2985	retval->text = g_xim_text_copy(orig->text);
2986	retval->caret = orig->caret;
2987	retval->chg_first = orig->chg_first;
2988	retval->chg_length = orig->chg_length;
2989
2990	return retval;
2991}
2992
2993void
2994g_xim_preedit_draw_free(gpointer boxed)
2995{
2996	GXimPreeditDraw *draw = boxed;
2997
2998	if (boxed == NULL)
2999		return;
3000
3001	g_xim_text_free(draw->text);
3002	g_free(draw);
3003}
3004
3005gsize
3006g_xim_preedit_draw_put_to_stream(GXimPreeditDraw  *draw,
3007				 GXimProtocol     *proto,
3008				 GCancellable     *cancellable,
3009				 GError          **error)
3010{
3011	g_return_val_if_fail (draw != NULL, 0);
3012	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
3013	g_return_val_if_fail (error != NULL, 0);
3014
3015	return g_xim_protocol_send_format(proto, cancellable, error, 4,
3016					  G_XIM_TYPE_LONG, draw->caret,
3017					  G_XIM_TYPE_LONG, draw->chg_first,
3018					  G_XIM_TYPE_LONG, draw->chg_length,
3019					  G_XIM_TYPE_XIMTEXT, draw->text);
3020}
3021
3022gpointer
3023g_xim_preedit_draw_get_from_stream(GXimProtocol      *proto,
3024				   GDataInputStream  *stream,
3025				   GCancellable      *cancellable,
3026				   GError           **error)
3027{
3028	GXimPreeditDraw *retval;
3029	gint32 caret, chg_first, chg_length;
3030	GXimText *text;
3031
3032	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), NULL);
3033	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
3034	g_return_val_if_fail (error != NULL, NULL);
3035
3036	if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 4,
3037					G_XIM_TYPE_LONG, &caret,
3038					G_XIM_TYPE_LONG, &chg_first,
3039					G_XIM_TYPE_LONG, &chg_length,
3040					G_XIM_TYPE_XIMTEXT, &text))
3041		return NULL;
3042
3043	retval = g_xim_preedit_draw_new();
3044	G_XIM_GERROR_CHECK_ALLOC (retval, error,
3045				  G_XIM_PROTOCOL_ERROR, NULL);
3046
3047	retval->caret = caret;
3048	retval->chg_first = chg_first;
3049	retval->chg_length = chg_length;
3050	retval->text = text;
3051
3052	return retval;
3053}
3054
3055/* GXimStatusDraw */
3056GType
3057g_xim_status_draw_get_type(void)
3058{
3059	static volatile gsize type_id_volatile = 0;
3060
3061	if (g_once_init_enter(&type_id_volatile)) {
3062		GType type_id;
3063
3064		type_id = g_boxed_type_register_static(g_intern_static_string("GXimStatusDraw"),
3065						       g_xim_status_draw_copy,
3066						       g_xim_status_draw_free);
3067		g_once_init_leave(&type_id_volatile, type_id);
3068	}
3069
3070	return type_id_volatile;
3071}
3072
3073gpointer
3074g_xim_status_draw_new(void)
3075{
3076	GXimStatusDraw *retval;
3077
3078	retval = g_new0(GXimStatusDraw, 1);
3079
3080	return retval;
3081}
3082
3083gpointer
3084g_xim_status_draw_copy(gpointer boxed)
3085{
3086	GXimStatusDraw *retval, *orig = boxed;
3087
3088	if (boxed == NULL)
3089		return NULL;
3090
3091	retval = g_xim_status_draw_new();
3092	G_XIM_CHECK_ALLOC (retval, NULL);
3093
3094	switch (orig->type) {
3095	    case G_XIM_XIMTextType:
3096		    retval->data.text = g_xim_text_copy(orig->data.text);
3097		    break;
3098	    case G_XIM_XIMBitmapType:
3099		    retval->data.bitmap = g_object_ref(orig->data.bitmap);
3100		    break;
3101	    default:
3102		    g_xim_status_draw_free(retval);
3103		    return NULL;
3104	}
3105
3106	return retval;
3107}
3108
3109void
3110g_xim_status_draw_free(gpointer boxed)
3111{
3112	GXimStatusDraw *draw = boxed;
3113
3114	if (boxed == NULL)
3115		return;
3116
3117	switch (draw->type) {
3118	    case G_XIM_XIMTextType:
3119		    g_xim_text_free(draw->data.text);
3120		    break;
3121	    case G_XIM_XIMBitmapType:
3122		    if (draw->data.bitmap)
3123			    g_object_unref(draw->data.bitmap);
3124	    default:
3125		    break;
3126	}
3127	g_free(draw);
3128}
3129
3130gsize
3131g_xim_status_draw_put_to_stream(GXimStatusDraw  *draw,
3132				GXimProtocol    *proto,
3133				GCancellable    *cancellable,
3134				GError         **error)
3135{
3136	gsize retval;
3137
3138	g_return_val_if_fail (draw != NULL, 0);
3139	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
3140	g_return_val_if_fail (error != NULL, 0);
3141
3142	retval = g_xim_protocol_send_format(proto, cancellable, error, 1,
3143					    G_XIM_TYPE_LONG, draw->type);
3144	if (*error)
3145		return 0;
3146
3147	switch (draw->type) {
3148	    case G_XIM_XIMTextType:
3149		    retval += g_xim_protocol_send_format(proto, cancellable, error, 1,
3150							 G_XIM_TYPE_XIMTEXT, draw->data.text);
3151		    break;
3152	    case G_XIM_XIMBitmapType:
3153		    retval += g_xim_protocol_send_format(proto, cancellable, error, 1,
3154							 G_XIM_TYPE_PIXMAP, draw->data.bitmap);
3155		    break;
3156	    default:
3157		    g_set_error(error, G_XIM_PROTOCOL_ERROR,
3158				G_XIM_STD_ERROR_INVALID_ARGUMENT | G_XIM_NOTICE_BUG,
3159				"sending an Incomplete status draw object.");
3160		    return 0;
3161	}
3162
3163	return retval;
3164}
3165
3166gpointer
3167g_xim_status_draw_get_from_stream(GXimProtocol      *proto,
3168				  GDataInputStream  *stream,
3169				  GCancellable      *cancellable,
3170				  GError           **error)
3171{
3172	GXimStatusDraw *retval;
3173	GXimStatusDataType type = 0;
3174
3175	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), NULL);
3176	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
3177	g_return_val_if_fail (error != NULL, NULL);
3178
3179	if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 1,
3180					G_XIM_TYPE_LONG, &type))
3181		return NULL;
3182
3183	retval = g_xim_status_draw_new();
3184	G_XIM_GERROR_CHECK_ALLOC (retval, error, G_XIM_PROTOCOL_ERROR, NULL);
3185
3186	retval->type = type;
3187	switch (type) {
3188	    case G_XIM_XIMTextType:
3189		    if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 1,
3190						    G_XIM_TYPE_XIMTEXT, &retval->data.text))
3191			    goto fail;
3192		    break;
3193	    case G_XIM_XIMBitmapType:
3194		    if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 1,
3195						    G_XIM_TYPE_PIXMAP, &retval->data.bitmap))
3196			    goto fail;
3197		    break;
3198	    default:
3199		    g_set_error(error, G_XIM_PROTOCOL_ERROR,
3200				G_XIM_PROTOCOL_ERROR_INVALID_PACKETS_RECEIVED | G_XIM_NOTICE_ERROR,
3201				"Unknown drawable type %d for status", type);
3202	    fail:
3203		    g_xim_status_draw_free(retval);
3204
3205		    return NULL;
3206	}
3207
3208	return retval;
3209}
3210
3211/* GXimHotkeyTrigger */
3212GType
3213g_xim_hotkey_trigger_get_type(void)
3214{
3215	static volatile gsize type_id_volatile = 0;
3216
3217	if (g_once_init_enter(&type_id_volatile)) {
3218		GType type_id;
3219
3220		type_id = g_boxed_type_register_static(g_intern_static_string("GXimHotkeyTrigger"),
3221						       g_xim_hotkey_trigger_copy,
3222						       g_xim_hotkey_trigger_free);
3223		g_once_init_leave(&type_id_volatile, type_id);
3224	}
3225
3226	return type_id_volatile;
3227}
3228
3229gpointer
3230g_xim_hotkey_trigger_new(guint32 keysym,
3231			 guint32 modifier,
3232			 guint32 modifier_mask)
3233{
3234	GXimHotkeyTrigger *retval;
3235
3236	retval = g_new0(GXimHotkeyTrigger, 1);
3237	G_XIM_CHECK_ALLOC (retval, NULL);
3238
3239	retval->keysym = keysym;
3240	retval->modifier = modifier;
3241	retval->modifier_mask = modifier_mask;
3242
3243	return retval;
3244}
3245
3246gpointer
3247g_xim_hotkey_trigger_copy(gpointer boxed)
3248{
3249	GXimHotkeyTrigger *orig = boxed;
3250
3251	if (boxed == NULL)
3252		return NULL;
3253
3254	return g_xim_hotkey_trigger_new(orig->keysym,
3255					orig->modifier,
3256					orig->modifier_mask);
3257}
3258
3259void
3260g_xim_hotkey_trigger_free(gpointer boxed)
3261{
3262	if (boxed == NULL)
3263		return;
3264
3265	g_free(boxed);
3266}
3267
3268gsize
3269g_xim_hotkey_trigger_put_to_stream(GXimHotkeyTrigger  *hotkey,
3270				   GXimProtocol       *proto,
3271				   GCancellable       *cancellable,
3272				   GError            **error)
3273{
3274	g_return_val_if_fail (hotkey != NULL, 0);
3275	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
3276	g_return_val_if_fail (error != NULL, 0);
3277
3278	return g_xim_protocol_send_format(proto, cancellable, error, 3,
3279					  G_XIM_TYPE_LONG, hotkey->keysym,
3280					  G_XIM_TYPE_LONG, hotkey->modifier,
3281					  G_XIM_TYPE_LONG, hotkey->modifier_mask);
3282}
3283
3284gpointer
3285g_xim_hotkey_trigger_get_from_stream(GXimProtocol      *proto,
3286				     GDataInputStream  *stream,
3287				     GCancellable      *cancellable,
3288				     GError           **error)
3289{
3290	guint32 keysym, modifier, modifier_mask;
3291
3292	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), NULL);
3293	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
3294	g_return_val_if_fail (error != NULL, NULL);
3295
3296	if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 3,
3297					G_XIM_TYPE_LONG, &keysym,
3298					G_XIM_TYPE_LONG, &modifier,
3299					G_XIM_TYPE_LONG, &modifier_mask))
3300		return NULL;
3301
3302	return g_xim_hotkey_trigger_new(keysym, modifier, modifier_mask);
3303}
3304
3305/* GdkEvent */
3306GQuark
3307g_xim_gdkevent_get_error_quark(void)
3308{
3309	static GQuark quark = 0;
3310
3311	if (!quark)
3312		quark = g_quark_from_static_string("g-xim-gdkevent-error");
3313
3314	return quark;
3315}
3316
3317gsize
3318g_xim_gdkevent_put_to_stream(GdkEvent      *event,
3319			     GXimProtocol  *proto,
3320			     GCancellable  *cancellable,
3321			     GError       **error)
3322{
3323	gint xtype;
3324	gsize size = 0;
3325
3326	g_return_val_if_fail (event != NULL, 0);
3327	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), 0);
3328	g_return_val_if_fail (error != NULL, 0);
3329
3330	/* XXX: better move this into GXimTransport? */
3331	xtype = g_xim_gdkevent_translate_event_type(event);
3332	if (xtype == 0) {
3333		g_set_error(error, G_XIM_GDKEVENT_ERROR,
3334			    G_XIM_GDKEVENT_ERROR_UNSUPPORTED_EVENT | G_XIM_NOTICE_BUG,
3335			    "Unable to convert GdkEvent %d to any X event. this may be a libgxim bug. please report a bug.",
3336			    event->type);
3337		return 0;
3338	}
3339	/* No serial number provided in GdkEvent */
3340	size = g_xim_protocol_send_format(proto, cancellable, error, 2,
3341					  G_XIM_TYPE_WORD, 0,
3342					  G_XIM_TYPE_BYTE, xtype);
3343	if (*error)
3344		return 0;
3345
3346	switch (event->type) {
3347	    case GDK_DESTROY:
3348		    size += g_xim_protocol_send_format(proto, cancellable, error, 4,
3349						       G_XIM_TYPE_BYTE, 0, /* detail */
3350						       G_XIM_TYPE_WORD, 0, /* serial */
3351						       G_XIM_TYPE_WINDOW, event->any.window,
3352						       G_XIM_TYPE_WINDOW, event->any.window);
3353		    break;
3354	    case GDK_EXPOSE:
3355		    /* XXX: We may need to correct the rectangle area.
3356		     * because GTK+ modifies them.
3357		     */
3358		    size += g_xim_protocol_send_format(proto, cancellable, error, 9,
3359						       G_XIM_TYPE_BYTE, 0, /* detail */
3360						       G_XIM_TYPE_WORD, 0, /* serial */
3361						       G_XIM_TYPE_WINDOW, event->expose.window,
3362						       G_XIM_TYPE_WORD, event->expose.area.x,
3363						       G_XIM_TYPE_WORD, event->expose.area.y,
3364						       G_XIM_TYPE_WORD, event->expose.area.width,
3365						       G_XIM_TYPE_WORD, event->expose.area.height,
3366						       G_XIM_TYPE_WORD, event->expose.count,
3367						       G_XIM_TYPE_PADDING, 2);
3368		    break;
3369	    case GDK_MOTION_NOTIFY:
3370		    /* XXX: GTK+ doesn't deal with a child window. */
3371		    size += g_xim_protocol_send_format(proto, cancellable, error, 13,
3372						       G_XIM_TYPE_BYTE, event->motion.is_hint, /* detail */
3373						       G_XIM_TYPE_WORD, 0, /* serial */
3374						       G_XIM_TYPE_LONG, event->motion.time,
3375						       G_XIM_TYPE_WINDOW, gdk_screen_get_root_window(gdk_display_get_default_screen(gdk_drawable_get_display(event->motion.window))),
3376						       G_XIM_TYPE_WINDOW, event->motion.window,
3377						       G_XIM_TYPE_WINDOW, event->motion.window,
3378						       G_XIM_TYPE_WORD, (gint)event->motion.x_root,
3379						       G_XIM_TYPE_WORD, (gint)event->motion.y_root,
3380						       G_XIM_TYPE_WORD, (gint)event->motion.x,
3381						       G_XIM_TYPE_WORD, (gint)event->motion.y,
3382						       G_XIM_TYPE_WORD, event->motion.state,
3383						       G_XIM_TYPE_BYTE, 1, /* sameScreen */
3384						       G_XIM_TYPE_PADDING, 1);
3385		    break;
3386	    case GDK_BUTTON_PRESS:
3387	    case GDK_2BUTTON_PRESS:
3388	    case GDK_3BUTTON_PRESS:
3389	    case GDK_BUTTON_RELEASE:
3390		    /* XXX: GTK+ doesn't deal with a child window. */
3391		    size += g_xim_protocol_send_format(proto, cancellable, error, 13,
3392						       G_XIM_TYPE_BYTE, event->button.button, /* detail */
3393						       G_XIM_TYPE_WORD, 0, /* serial */
3394						       G_XIM_TYPE_LONG, event->button.time,
3395						       G_XIM_TYPE_WINDOW, gdk_screen_get_root_window(gdk_display_get_default_screen(gdk_drawable_get_display(event->button.window))),
3396						       G_XIM_TYPE_WINDOW, event->button.window,
3397						       G_XIM_TYPE_WINDOW, event->button.window,
3398						       G_XIM_TYPE_WORD, (gint)event->button.x_root,
3399						       G_XIM_TYPE_WORD, (gint)event->button.y_root,
3400						       G_XIM_TYPE_WORD, (gint)event->button.x,
3401						       G_XIM_TYPE_WORD, (gint)event->button.y,
3402						       G_XIM_TYPE_WORD, event->button.state,
3403						       G_XIM_TYPE_BYTE, 1, /* sameScreen */
3404						       G_XIM_TYPE_PADDING, 1);
3405		    break;
3406	    case GDK_KEY_PRESS:
3407	    case GDK_KEY_RELEASE:
3408		    /* XXX: GTK+ doesn't deal with a child window nor positions the event occurred on. */
3409		    size += g_xim_protocol_send_format(proto, cancellable, error, 13,
3410						       G_XIM_TYPE_BYTE, event->key.hardware_keycode, /* detail */
3411						       G_XIM_TYPE_WORD, 0, /* serial */
3412						       G_XIM_TYPE_LONG, event->key.time,
3413						       G_XIM_TYPE_WINDOW, gdk_screen_get_root_window(gdk_display_get_default_screen(gdk_drawable_get_display(event->key.window))),
3414						       G_XIM_TYPE_WINDOW, event->key.window,
3415						       G_XIM_TYPE_WINDOW, event->key.window,
3416						       G_XIM_TYPE_WORD, 0,
3417						       G_XIM_TYPE_WORD, 0,
3418						       G_XIM_TYPE_WORD, 0,
3419						       G_XIM_TYPE_WORD, 0,
3420						       G_XIM_TYPE_WORD, event->key.state,
3421						       G_XIM_TYPE_BYTE, 1, /* sameScreen */
3422						       G_XIM_TYPE_PADDING, 1);
3423		    break;
3424	    case GDK_ENTER_NOTIFY:
3425//		    return EnterNotify;
3426	    case GDK_LEAVE_NOTIFY:
3427//		    return LeaveNotify;
3428	    case GDK_FOCUS_CHANGE:
3429//		    if (event->focus_change.in)
3430//			    return FocusIn;
3431//		    else
3432//			    return FocusOut;
3433	    case GDK_CONFIGURE:
3434//		    return ConfigureNotify;
3435	    case GDK_MAP:
3436//		    return MapNotify;
3437	    case GDK_UNMAP:
3438//		    return UnmapNotify;
3439	    case GDK_PROPERTY_NOTIFY:
3440//		    return PropertyNotify;
3441	    case GDK_SELECTION_CLEAR:
3442//		    return SelectionClear;
3443	    case GDK_SELECTION_REQUEST:
3444//		    return SelectionRequest;
3445	    case GDK_SELECTION_NOTIFY:
3446//		    return SelectionNotify;
3447	    case GDK_CLIENT_EVENT:
3448//		    return ClientMessage;
3449	    case GDK_VISIBILITY_NOTIFY:
3450//		    return VisibilityNotify;
3451	    case GDK_NO_EXPOSE:
3452//		    return NoExpose;
3453	    case GDK_SCROLL:
3454//		    return ButtonPress;
3455	    default:
3456		    g_set_error(error, G_XIM_GDKEVENT_ERROR,
3457				G_XIM_GDKEVENT_ERROR_UNSUPPORTED_EVENT | G_XIM_NOTICE_BUG,
3458				"Not yet implemented for the event type %d",
3459				event->type);
3460		    break;
3461	}
3462
3463	if (*error)
3464		size = 0;
3465
3466	return size;
3467}
3468
3469gpointer
3470g_xim_gdkevent_get_from_stream(GXimProtocol      *proto,
3471			       GDataInputStream  *stream,
3472			       GCancellable      *cancellable,
3473			       GError           **error)
3474{
3475	GXimProtocolIface *iface;
3476	guint16 msb_serial, lsb_serial;
3477	gint xtype = 0;
3478	GdkEventType type;
3479	GdkEvent *retval;
3480
3481	g_return_val_if_fail (G_IS_XIM_PROTOCOL (proto), NULL);
3482	g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
3483	g_return_val_if_fail (error != NULL, NULL);
3484
3485	if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 2,
3486					G_XIM_TYPE_WORD, &msb_serial,
3487					G_XIM_TYPE_BYTE, &xtype))
3488		return NULL;
3489
3490	iface = G_XIM_PROTOCOL_GET_IFACE (proto);
3491	g_xim_messages_debug(iface->message, "proto/gdkevent",
3492			     "Event type: %s", g_xim_gdkevent_type_name(xtype));
3493
3494	type = g_xim_xevent_translate_event_type(xtype);
3495	retval = gdk_event_new(type);
3496	G_XIM_GERROR_CHECK_ALLOC (retval, error,
3497				  G_XIM_PROTOCOL_ERROR, NULL);
3498
3499	switch (type) {
3500	    case GDK_DESTROY:
3501		    G_STMT_START {
3502			    GdkWindow *ev, *window;
3503
3504			    if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 4,
3505							    G_XIM_TYPE_PADDING, 1, /* detail(unused) */
3506							    G_XIM_TYPE_WORD, &lsb_serial, /* serial */
3507							    G_XIM_TYPE_WINDOW, &ev,
3508							    G_XIM_TYPE_WINDOW, &window))
3509				    goto end;
3510			    if (ev != window) {
3511				    /* we don't deal with it */
3512				    g_set_error(error, G_XIM_PROTOCOL_ERROR,
3513						G_XIM_PROTOCOL_ERROR_INVALID_PACKETS_RECEIVED | G_XIM_NOTICE_ERROR,
3514						"Received different window for DestroyNotify: event: %p, window: %p",
3515						G_XIM_NATIVE_WINDOW_TO_POINTER (GDK_WINDOW_XID (ev)),
3516						G_XIM_NATIVE_WINDOW_TO_POINTER (GDK_WINDOW_XID (window)));
3517				    goto end;
3518			    }
3519			    retval->any.window = g_object_ref(ev);
3520		    } G_STMT_END;
3521		    break;
3522	    case GDK_EXPOSE:
3523		    G_STMT_START {
3524			    GdkWindow *window;
3525			    gint16 x, y, width, height, count;
3526
3527			    if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 9,
3528							    G_XIM_TYPE_PADDING, 1, /* detail(unused) */
3529							    G_XIM_TYPE_WORD, &lsb_serial, /* serial */
3530							    G_XIM_TYPE_WINDOW, &window,
3531							    G_XIM_TYPE_WORD, &x,
3532							    G_XIM_TYPE_WORD, &y,
3533							    G_XIM_TYPE_WORD, &width,
3534							    G_XIM_TYPE_WORD, &height,
3535							    G_XIM_TYPE_WORD, &count,
3536							    G_XIM_TYPE_PADDING, 2))
3537				    goto end;
3538			    retval->expose.window = g_object_ref(window);
3539			    retval->expose.area.x = x;
3540			    retval->expose.area.y = y;
3541			    retval->expose.area.width = width;
3542			    retval->expose.area.height = height;
3543			    retval->expose.count = count;
3544		    } G_STMT_END;
3545		    break;
3546	    case GDK_MOTION_NOTIFY:
3547		    G_STMT_START {
3548			    gint16 is_hint = 0, x_root, y_root, x, y;
3549			    guint16 state;
3550			    guint32 time;
3551			    GdkWindow *root, *ev, *window;
3552			    gboolean same_screen = FALSE;
3553
3554			    if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 13,
3555							    G_XIM_TYPE_BYTE, &is_hint, /* detail */
3556							    G_XIM_TYPE_WORD, &lsb_serial, /* serial */
3557							    G_XIM_TYPE_LONG, &time,
3558							    G_XIM_TYPE_WINDOW, &root,
3559							    G_XIM_TYPE_WINDOW, &ev,
3560							    G_XIM_TYPE_WINDOW, &window,
3561							    G_XIM_TYPE_WORD, &x_root,
3562							    G_XIM_TYPE_WORD, &y_root,
3563							    G_XIM_TYPE_WORD, &x,
3564							    G_XIM_TYPE_WORD, &y,
3565							    G_XIM_TYPE_WORD, &state,
3566							    G_XIM_TYPE_BYTE, &same_screen,
3567							    G_XIM_TYPE_PADDING, 1))
3568				    goto end;
3569			    if (!same_screen) {
3570				    g_set_error(error, G_XIM_GDKEVENT_ERROR,
3571						G_XIM_GDKEVENT_ERROR_UNSUPPORTED_EVENT | G_XIM_NOTICE_ERROR,
3572						"Event %d occurred on the different screen.",
3573						type);
3574				    goto end;
3575			    }
3576			    retval->motion.window = g_object_ref(ev);
3577			    retval->motion.time = time;
3578			    retval->motion.x = x;
3579			    retval->motion.y = y;
3580			    retval->motion.state = state;
3581			    retval->motion.is_hint = is_hint;
3582			    retval->motion.x_root = x_root;
3583			    retval->motion.y_root = y_root;
3584			    retval->motion.axes = NULL;
3585			    retval->motion.device = gdk_drawable_get_display(ev)->core_pointer;
3586		    } G_STMT_END;
3587		    break;
3588	    case GDK_BUTTON_PRESS:
3589	    case GDK_BUTTON_RELEASE:
3590		    G_STMT_START {
3591			    guint16 button = 0, state;
3592			    gint16 x_root, y_root, x, y;
3593			    guint32 time;
3594			    GdkWindow *root, *ev, *window;
3595			    gboolean same_screen = FALSE;
3596
3597			    if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 13,
3598							    G_XIM_TYPE_BYTE, &button, /* detail */
3599							    G_XIM_TYPE_WORD, &lsb_serial, /* serial */
3600							    G_XIM_TYPE_LONG, &time,
3601							    G_XIM_TYPE_WINDOW, &root,
3602							    G_XIM_TYPE_WINDOW, &ev,
3603							    G_XIM_TYPE_WINDOW, &window,
3604							    G_XIM_TYPE_WORD, &x_root,
3605							    G_XIM_TYPE_WORD, &y_root,
3606							    G_XIM_TYPE_WORD, &x,
3607							    G_XIM_TYPE_WORD, &y,
3608							    G_XIM_TYPE_WORD, &state,
3609							    G_XIM_TYPE_BYTE, &same_screen,
3610							    G_XIM_TYPE_PADDING, 1))
3611				    goto end;
3612			    if (!same_screen) {
3613				    g_set_error(error, G_XIM_GDKEVENT_ERROR,
3614						G_XIM_GDKEVENT_ERROR_UNSUPPORTED_EVENT | G_XIM_NOTICE_ERROR,
3615						"Event %d occurred on the different screen.",
3616						type);
3617				    goto end;
3618			    }
3619			    retval->button.window = g_object_ref(ev);
3620			    retval->button.time = time;
3621			    retval->button.x = x;
3622			    retval->button.y = y;
3623			    retval->button.state = state;
3624			    retval->button.button = button;
3625			    retval->button.x_root = x_root;
3626			    retval->button.y_root = y_root;
3627			    retval->button.axes = NULL;
3628			    retval->button.device = gdk_drawable_get_display(ev)->core_pointer;
3629		    } G_STMT_END;
3630		    break;
3631	    case GDK_KEY_PRESS:
3632	    case GDK_KEY_RELEASE:
3633		    G_STMT_START {
3634			    guint16 keycode = 0, state;
3635			    gint16 x_root, y_root, x, y;
3636			    guint32 time;
3637			    GdkWindow *root, *ev, *window;
3638			    gboolean same_screen = FALSE;
3639			    GdkDisplay *dpy;
3640			    GdkKeymap *keymap;
3641			    gunichar c = 0;
3642			    gchar buf[7];
3643
3644			    if (!g_xim_protocol_read_format(proto, stream, cancellable, error, 13,
3645							    G_XIM_TYPE_BYTE, &keycode, /* detail */
3646							    G_XIM_TYPE_WORD, &lsb_serial, /* serial */
3647							    G_XIM_TYPE_LONG, &time,
3648							    G_XIM_TYPE_WINDOW, &root,
3649							    G_XIM_TYPE_WINDOW, &ev,
3650							    G_XIM_TYPE_WINDOW, &window,
3651							    G_XIM_TYPE_WORD, &x_root,
3652							    G_XIM_TYPE_WORD, &y_root,
3653							    G_XIM_TYPE_WORD, &x,
3654							    G_XIM_TYPE_WORD, &y,
3655							    G_XIM_TYPE_WORD, &state,
3656							    G_XIM_TYPE_BYTE, &same_screen,
3657							    G_XIM_TYPE_PADDING, 1))
3658				    goto end;
3659			    if (!same_screen) {
3660				    g_set_error(error, G_XIM_GDKEVENT_ERROR,
3661						G_XIM_GDKEVENT_ERROR_UNSUPPORTED_EVENT | G_XIM_NOTICE_ERROR,
3662						"Event %d occurred on the different screen.",
3663						type);
3664				    goto end;
3665			    }
3666			    dpy = gdk_drawable_get_display(ev);
3667			    keymap = gdk_keymap_get_for_display(dpy);
3668			    retval->key.window = g_object_ref(ev);
3669			    retval->key.time = time;
3670			    retval->key.state = state;
3671			    retval->key.hardware_keycode = keycode;
3672			    // retval->key.group =;
3673			    retval->key.keyval = GDK_VoidSymbol;
3674
3675			    /* borrow code from gdkevents-x11.c */
3676			    gdk_keymap_translate_keyboard_state(keymap,
3677								retval->key.hardware_keycode,
3678								retval->key.state,
3679								retval->key.group,
3680								&retval->key.keyval,
3681								NULL, NULL, NULL);
3682			    // retval->key.is_modifier =;
3683			    retval->key.string = NULL;
3684			    if (retval->key.keyval != GDK_VoidSymbol)
3685				    c = gdk_keyval_to_unicode(retval->key.keyval);
3686			    if (c) {
3687				    gsize bytes_written;
3688				    gint len;
3689
3690				    /* Apply the control key - Taken from Xlib
3691				     */
3692				    if (retval->key.state & GDK_CONTROL_MASK) {
3693					    if ((c >= '@' && c < '\177') || c == ' ') {
3694						    c &= 0x1F;
3695					    } else if (c == '2') {
3696						    retval->key.string = g_memdup ("\0\0", 2);
3697						    retval->key.length = 1;
3698						    buf[0] = '\0';
3699						    goto end;
3700					    } else if (c >= '3' && c <= '7') {
3701						    c -= ('3' - '\033');
3702					    } else if (c == '8') {
3703						    c = '\177';
3704					    } else if (c == '/') {
3705						    c = '_' & 0x1F;
3706					    }
3707				    }
3708      
3709				    len = g_unichar_to_utf8 (c, buf);
3710				    buf[len] = '\0';
3711      
3712				    retval->key.string = g_locale_from_utf8 (buf, len,
3713									     NULL, &bytes_written,
3714									     NULL);
3715				    if (retval->key.string)
3716					    retval->key.length = bytes_written;
3717			    } else if (retval->key.keyval == GDK_Escape) {
3718				    retval->key.length = 1;
3719				    retval->key.string = g_strdup ("\033");
3720			    } else if (retval->key.keyval == GDK_Return ||
3721				       retval->key.keyval == GDK_KP_Enter) {
3722				    retval->key.length = 1;
3723				    retval->key.string = g_strdup ("\r");
3724			    }
3725			    if (!retval->key.string) {
3726				    retval->key.length = 0;
3727				    retval->key.string = g_strdup ("");
3728			    }
3729		    } G_STMT_END;
3730		    break;
3731	    default:
3732		    g_set_error(error, G_XIM_GDKEVENT_ERROR,
3733				G_XIM_GDKEVENT_ERROR_UNSUPPORTED_EVENT | G_XIM_NOTICE_BUG,
3734				"Noet yet implemented for the event type %d",
3735				type);
3736		    break;
3737	}
3738
3739  end:
3740	if (*error) {
3741		if (!G_XIM_GERROR_IS_RECOVERABLE (*error)) {
3742			gdk_event_free(retval);
3743			retval = NULL;
3744		}
3745	}
3746
3747	return retval;
3748}