From 438d9fdbd3e0be04de933705917d508a02b7c04b Mon Sep 17 00:00:00 2001
From: Marty Jack <martyj@linux.local>
Date: Sat, 20 Feb 2010 16:23:57 -0500
Subject: [PATCH 5/9] Fix failure to react to keyboard map changes initiated outside the plugin
- Occurred when setxkbmap was run, or when HAL configured the keyboard at X startup
- Caused by failure to process the NewKeyboard event
- Caused by dropping events due to faulty code to read them
- Cosmetic change, the tooltip now the Xkb Group name rather than Xkb Symbol name
---
src/plugins/xkb/xkb-plugin.c | 92 +++++++++--------
src/plugins/xkb/xkb.c | 236 +++++++++++++++++++++--------------------
src/plugins/xkb/xkb.h | 7 +-
3 files changed, 173 insertions(+), 162 deletions(-)
diff --git a/src/plugins/xkb/xkb-plugin.c b/src/plugins/xkb/xkb-plugin.c
index f49a77d..80a14ba 100644
--- a/src/plugins/xkb/xkb-plugin.c
+++ b/src/plugins/xkb/xkb-plugin.c
@@ -1,18 +1,23 @@
-/*
-//====================================================================
-// xfce4-xkb-plugin - XFCE4 Xkb Layout Indicator panel plugin
-// -------------------------------------------------------------------
-// Alexander Iliev <sasoiliev@mamul.org>
-// 20-Feb-04
-// -------------------------------------------------------------------
-// Parts of this code belong to Michael Glickman <wmalms@yahooo.com>
-// and his program wmxkb.
-// WARNING: DO NOT BOTHER Michael Glickman WITH QUESTIONS ABOUT THIS
-// PROGRAM!!! SEND INSTEAD EMAILS TO <sasoiliev@mamul.org>
-//====================================================================
-*/
-
-/* Modified by Hong Jen Yee (PCMan) <pcman.tw@gmail.com> on 2008-04-06 for lxpanel */
+/**
+ * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Originally derived from xfce4-xkb-plugin, Copyright 2004 Alexander Iliev,
+ * which credits Michael Glickman. */
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -49,38 +54,45 @@ void xkb_redraw(XkbPlugin * xkb)
if (xkb->display_type == IMAGE)
{
int size = xkb->plugin->panel->icon_size;
- char * group_name = (char *) xkb_get_current_group_name_lowercase(xkb);
- char * filename = g_strdup_printf("%s/%s.png", FLAGSDIR, group_name);
- GdkPixbuf * unscaled_pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
- g_free(filename);
- g_free(group_name);
-
- if (unscaled_pixbuf != NULL)
+ char * group_name = (char *) xkb_get_current_symbol_name_lowercase(xkb);
+ if (group_name != NULL)
{
- /* Loaded successfully. */
- int width = gdk_pixbuf_get_width(unscaled_pixbuf);
- int height = gdk_pixbuf_get_height(unscaled_pixbuf);
- GdkPixbuf * pixbuf = gdk_pixbuf_scale_simple(unscaled_pixbuf, size * width / height, size, GDK_INTERP_BILINEAR);
- if (pixbuf != NULL)
+ char * filename = g_strdup_printf("%s/%s.png", FLAGSDIR, group_name);
+ GdkPixbuf * unscaled_pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
+ g_free(filename);
+ g_free(group_name);
+
+ if (unscaled_pixbuf != NULL)
{
- gtk_image_set_from_pixbuf(GTK_IMAGE(xkb->image), pixbuf);
- g_object_unref(G_OBJECT(pixbuf));
- gtk_widget_hide(xkb->label);
- gtk_widget_show(xkb->image);
- gtk_widget_set_tooltip_text(xkb->btn, xkb_get_current_group_name(xkb));
- valid_image = TRUE;
+ /* Loaded successfully. */
+ int width = gdk_pixbuf_get_width(unscaled_pixbuf);
+ int height = gdk_pixbuf_get_height(unscaled_pixbuf);
+ GdkPixbuf * pixbuf = gdk_pixbuf_scale_simple(unscaled_pixbuf, size * width / height, size, GDK_INTERP_BILINEAR);
+ if (pixbuf != NULL)
+ {
+ gtk_image_set_from_pixbuf(GTK_IMAGE(xkb->image), pixbuf);
+ g_object_unref(G_OBJECT(pixbuf));
+ gtk_widget_hide(xkb->label);
+ gtk_widget_show(xkb->image);
+ gtk_widget_set_tooltip_text(xkb->btn, xkb_get_current_group_name(xkb));
+ valid_image = TRUE;
+ }
+ g_object_unref(unscaled_pixbuf);
}
- g_object_unref(unscaled_pixbuf);
}
}
/* Set the label. */
if ((xkb->display_type == TEXT) || ( ! valid_image))
{
- panel_draw_label_text(xkb->plugin->panel, xkb->label, (char *) xkb_get_current_group_name(xkb), TRUE, TRUE);
- gtk_widget_hide(xkb->image);
- gtk_widget_show(xkb->label);
- gtk_widget_set_tooltip_text(xkb->btn, NULL);
+ char * group_name = (char *) xkb_get_current_symbol_name(xkb);
+ if (group_name != NULL)
+ {
+ panel_draw_label_text(xkb->plugin->panel, xkb->label, (char *) group_name, TRUE, TRUE);
+ gtk_widget_hide(xkb->image);
+ gtk_widget_show(xkb->label);
+ gtk_widget_set_tooltip_text(xkb->btn, xkb_get_current_group_name(xkb));
+ }
}
}
@@ -196,10 +208,6 @@ static int xkb_constructor(Plugin * plugin, char ** fp)
/* Initialize the XKB interface. */
xkb_mechanism_constructor(xkb);
- /* Initialize a channel to listen for XKB events. */
- GIOChannel * channel = g_io_channel_unix_new(xkb_get_connection_number(xkb));
- xkb->source_id = g_io_add_watch(channel, G_IO_IN | G_IO_PRI, (GIOFunc) xkb_gio_callback, (gpointer) xkb);
-
/* Connect signals. */
g_signal_connect(xkb->btn, "button-press-event", G_CALLBACK(xkb_button_press_event), xkb);
g_signal_connect(xkb->btn, "scroll-event", G_CALLBACK(xkb_scroll_event), xkb);
diff --git a/src/plugins/xkb/xkb.c b/src/plugins/xkb/xkb.c
index 5bb0c39..898a931 100644
--- a/src/plugins/xkb/xkb.c
+++ b/src/plugins/xkb/xkb.c
@@ -1,18 +1,23 @@
-/*
-// ====================================================================
-// xfce4-xkb-plugin - XFCE4 Xkb Layout Indicator panel plugin
-// -------------------------------------------------------------------
-// Alexander Iliev <sasoiliev@mamul.org>
-// 20-Feb-04
-// -------------------------------------------------------------------
-// Parts of this code belong to Michael Glickman <wmalms@yahooo.com>
-// and his program wmxkb.
-// WARNING: DO NOT BOTHER Michael Glickman WITH QUESTIONS ABOUT THIS
-// PROGRAM!!! SEND INSTEAD EMAILS TO <sasoiliev@mamul.org>
-//====================================================================
-*/
-
-/* Modified by Hong Jen Yee (PCMan) <pcman.tw@gmail.com> on 2008-04-06 for lxpanel */
+/**
+ * Copyright (c) 2010 LxDE Developers, see the file AUTHORS for details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Originally derived from xfce4-xkb-plugin, Copyright 2004 Alexander Iliev,
+ * which credits Michael Glickman. */
#include "xkb.h"
@@ -26,9 +31,13 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <glib.h>
+/* The X Keyboard Extension: Library Specification
+ * http://www.xfree86.org/current/XKBlib.pdf */
+
static void xkb_enter_locale_by_process(XkbPlugin * xkb);
static void refresh_group_xkb(XkbPlugin * xkb);
-static int do_init_xkb(XkbPlugin * xkb);
+static int initialize_keyboard_description(XkbPlugin * xkb);
+static GdkFilterReturn xkb_event_filter(GdkXEvent * xevent, GdkEvent * event, XkbPlugin * xkb);
/* Insert a process and its layout into the hash table. */
static void xkb_enter_locale_by_process(XkbPlugin * xkb)
@@ -56,60 +65,65 @@ int xkb_get_group_count(XkbPlugin * xkb)
return xkb->group_count;
}
+/* Get the current group name. */
+const char * xkb_get_current_group_name(XkbPlugin * xkb)
+{
+ return xkb->group_names[xkb->current_group_xkb_no];
+}
+
/* Convert a group number to a symbol name. */
const char * xkb_get_symbol_name_by_res_no(XkbPlugin * xkb, int n)
{
return xkb->symbol_names[n];
}
-/* Get the current group name. */
-const char * xkb_get_current_group_name(XkbPlugin * xkb)
+/* Get the current symbol name. */
+const char * xkb_get_current_symbol_name(XkbPlugin * xkb)
{
return xkb_get_symbol_name_by_res_no(xkb, xkb->current_group_xkb_no);
}
-/* Get the current group name converted to lowercase. */
-const char * xkb_get_current_group_name_lowercase(XkbPlugin * xkb)
+/* Get the current symbol name converted to lowercase. */
+const char * xkb_get_current_symbol_name_lowercase(XkbPlugin * xkb)
{
- const char * tmp = xkb_get_current_group_name(xkb);
- return g_utf8_strdown(tmp, -1);
+ const char * tmp = xkb_get_current_symbol_name(xkb);
+ return ((tmp != NULL) ? g_utf8_strdown(tmp, -1) : NULL);
}
/* Refresh current group number from Xkb state. */
static void refresh_group_xkb(XkbPlugin * xkb)
{
XkbStateRec xkb_state;
- XkbGetState(xkb->dsp, xkb->device_id, &xkb_state);
+ XkbGetState(GDK_DISPLAY(), XkbUseCoreKbd, &xkb_state);
xkb->current_group_xkb_no = xkb_state.group;
}
-/* Initialize the Xkb structures. */
-static int do_init_xkb(XkbPlugin * xkb)
+/* Initialize the keyboard description initially or after a NewKeyboard event. */
+static int initialize_keyboard_description(XkbPlugin * xkb)
{
- /* Create hash table. */
- xkb->group_hash_table = g_hash_table_new(g_direct_hash, NULL);
-
- /* Initialize the Xkb extension. */
- int major, minor, opcode;
- Bool status = XkbQueryExtension(xkb->dsp, &opcode,
- &xkb->base_event_code, &xkb->base_error_code, &major, &minor);
-
- /* Use the core keyboard. */
- xkb->device_id = XkbUseCoreKbd;
+ /* Free the strings. */
+ int i;
+ for (i = 0; i < XkbNumKbdGroups; i += 1)
+ {
+ g_free(xkb->group_names[i]);
+ g_free(xkb->symbol_names[i]);
+ xkb->group_names[i] = NULL;
+ xkb->symbol_names[i] = NULL;
+ }
/* Allocate a keyboard description structure. */
+ int status = False;
XkbDescRec * kbd_desc_ptr = XkbAllocKeyboard();
if (kbd_desc_ptr == NULL)
{
ERR("Failed to get keyboard description\n");
goto HastaLaVista;
}
- kbd_desc_ptr->dpy = xkb->dsp;
/* Fetch information into the keyboard description. */
- XkbGetControls(xkb->dsp, XkbAllControlsMask, kbd_desc_ptr);
- XkbGetNames(xkb->dsp, XkbSymbolsNameMask, kbd_desc_ptr);
- XkbGetNames(xkb->dsp, XkbGroupNamesMask, kbd_desc_ptr);
+ XkbGetControls(GDK_DISPLAY(), XkbAllControlsMask, kbd_desc_ptr);
+ XkbGetNames(GDK_DISPLAY(), XkbSymbolsNameMask, kbd_desc_ptr);
+ XkbGetNames(GDK_DISPLAY(), XkbGroupNamesMask, kbd_desc_ptr);
if (kbd_desc_ptr->names == NULL)
{
@@ -137,12 +151,11 @@ static int do_init_xkb(XkbPlugin * xkb)
/* Determine the group names. Trim off text beginning at a '('. */
const Atom * tmp_group_source = kbd_desc_ptr->names->groups;
- int i;
for (i = 0; i < xkb->group_count; i++)
{
if (tmp_group_source[i] != None)
{
- char * ptr = XGetAtomName(xkb->dsp, tmp_group_source[i]);
+ char * ptr = XGetAtomName(GDK_DISPLAY(), tmp_group_source[i]);
xkb->group_names[i] = ptr;
if ((ptr != NULL) && ((ptr = strchr(ptr, '('))) != NULL)
*ptr = '\0';
@@ -153,7 +166,7 @@ static int do_init_xkb(XkbPlugin * xkb)
Atom sym_name_atom = kbd_desc_ptr->names->symbols;
char * sym_name;
if ((sym_name_atom == None)
- || ((sym_name = XGetAtomName(xkb->dsp, sym_name_atom)) == NULL))
+ || ((sym_name = XGetAtomName(GDK_DISPLAY(), sym_name_atom)) == NULL))
goto HastaLaVista;
/* Parse and store symbol names. */
@@ -190,83 +203,106 @@ static int do_init_xkb(XkbPlugin * xkb)
{
xkb->group_count = 2;
xkb->symbol_names[1] = xkb->symbol_names[0];
- xkb->symbol_names[0] = strdup("us");
- xkb->group_names[0] = strdup("US/ASCII");
- xkb->group_names[1] = strdup("Japanese");
+ xkb->symbol_names[0] = g_strdup("us");
+ xkb->group_names[0] = g_strdup("US/ASCII");
+ xkb->group_names[1] = g_strdup("Japanese");
}
else if (count < xkb->group_count)
{
/* Ensure that the names are fully initialized. */
int j = count, k = xkb->group_count;
while(--j >= 0) xkb->symbol_names[--k] = xkb->symbol_names[j];
- while(--k >= 0) xkb->symbol_names[k] = strdup("en_US");
+ while(--k >= 0) xkb->symbol_names[k] = g_strdup("en_US");
}
- /* Enxure that the names are fully initialized. */
+ /* Ensure that the names are fully initialized. */
for (i = 0; i < xkb->group_count; i++)
{
if (xkb->symbol_names[i] == NULL)
{
ERR("\nGroup Symbol %i is undefined, set to 'U/A' !\n", i+1);
- xkb->symbol_names[i] = strdup("U/A");
+ xkb->symbol_names[i] = g_strdup("U/A");
}
}
+ /* Create or recreate hash table.
+ * The layout that was associated to the windows may or may not be at the same group number,
+ * and worse, may no longer exist, which there is no meaningful way to deal with. */
+ if (xkb->group_hash_table != NULL)
+ g_hash_table_destroy(xkb->group_hash_table);
+ xkb->group_hash_table = g_hash_table_new(g_direct_hash, NULL);
+
status = True;
HastaLaVista:
if (kbd_desc_ptr != NULL)
XkbFreeKeyboard(kbd_desc_ptr, 0, True);
+
return status;
}
+/* GDK event filter that receives events from all windows and the Xkb extension. */
+static GdkFilterReturn xkb_event_filter(GdkXEvent * xevent, GdkEvent * event, XkbPlugin * xkb)
+{
+ XEvent * ev = (XEvent *) xevent;
+
+ if (ev->xany.type == xkb->base_event_code + XkbEventCode)
+ {
+ /* Xkb event. */
+ XkbEvent * xkbev = (XkbEvent *) ev;
+ if (xkbev->any.xkb_type == XkbNewKeyboardNotify)
+ {
+ initialize_keyboard_description(xkb);
+ refresh_group_xkb(xkb);
+ xkb_redraw(xkb);
+ xkb_enter_locale_by_process(xkb);
+ }
+ else if (xkbev->any.xkb_type == XkbStateNotify)
+ {
+ if (xkbev->state.group != xkb->current_group_xkb_no)
+ {
+ /* Switch to the new group and redraw the display. */
+ xkb->current_group_xkb_no = xkbev->state.group;
+ refresh_group_xkb(xkb);
+ xkb_redraw(xkb);
+ xkb_enter_locale_by_process(xkb);
+ }
+ }
+ }
+ return GDK_FILTER_CONTINUE;
+}
+
/* Initialize the Xkb interface. */
void xkb_mechanism_constructor(XkbPlugin * xkb)
{
- /* Enable the Xkb extension on all clients. */
- XkbIgnoreExtension(False);
-
- /* Open the display. */
- int major = XkbMajorVersion;
- int minor = XkbMinorVersion;
- char * display_name = "";
- int event_code;
- int error_rtrn;
- int reason_rtrn;
- xkb->dsp = XkbOpenDisplay(display_name, &event_code, &error_rtrn, &major, &minor, &reason_rtrn);
-
- switch (reason_rtrn)
+ /* Initialize Xkb extension. */
+ int opcode;
+ int maj = XkbMajorVersion;
+ int min = XkbMinorVersion;
+ if ((XkbLibraryVersion(&maj, &min))
+ && (XkbQueryExtension(GDK_DISPLAY(), &opcode, &xkb->base_event_code, &xkb->base_error_code, &maj, &min)))
{
- case XkbOD_BadLibraryVersion:
- ERR("Bad XKB library version.\n");
- return;
- case XkbOD_ConnectionRefused:
- ERR("Connection to X server refused.\n");
- return;
- case XkbOD_BadServerVersion:
- ERR("Bad X server version.\n");
- return;
- case XkbOD_NonXkbServer:
- ERR("XKB not present.\n");
- return;
- case XkbOD_Success:
- break;
- }
+ /* Read the keyboard description. */
+ initialize_keyboard_description(xkb);
- /* Initialize our mechanism. */
- if (do_init_xkb(xkb) != True)
- return;
+ /* Establish GDK event filter. */
+ gdk_window_add_filter(NULL, (GdkFilterFunc) xkb_event_filter, (gpointer) xkb);
- /* Specify events we will receive. */
- XkbSelectEventDetails(xkb->dsp, xkb->device_id, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask);
+ /* Specify events we will receive. */
+ XkbSelectEvents(GDK_DISPLAY(), XkbUseCoreKbd, XkbNewKeyboardNotifyMask, XkbNewKeyboardNotifyMask);
+ XkbSelectEventDetails(GDK_DISPLAY(), XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask);
- /* Get current state. */
- refresh_group_xkb(xkb);
+ /* Get current state. */
+ refresh_group_xkb(xkb);
+ }
}
/* Deallocate resources associated with Xkb interface. */
void xkb_mechanism_destructor(XkbPlugin * xkb)
{
+ /* Remove event filter. */
+ gdk_window_remove_filter(NULL, (GdkFilterFunc) xkb_event_filter, xkb);
+
/* Free group and symbol name memory. */
int i;
for (i = 0; i < xkb->group_count; i++)
@@ -283,21 +319,11 @@ void xkb_mechanism_destructor(XkbPlugin * xkb)
}
}
- /* Close the display. */
- XCloseDisplay(xkb->dsp);
- xkb->dsp = NULL;
-
/* Destroy the hash table. */
g_hash_table_destroy(xkb->group_hash_table);
xkb->group_hash_table = NULL;
}
-/* Return the connection number for the display. */
-int xkb_get_connection_number(XkbPlugin * xkb)
-{
- return ConnectionNumber(xkb->dsp);
-}
-
/* Set the layout to the next layout. */
int xkb_change_group(XkbPlugin * xkb, int increment)
{
@@ -307,33 +333,13 @@ int xkb_change_group(XkbPlugin * xkb, int increment)
if (next_group >= xkb->group_count) next_group = 0;
/* Execute the change. */
- XkbLockGroup(xkb->dsp, xkb->device_id, next_group);
+ XkbLockGroup(GDK_DISPLAY(), XkbUseCoreKbd, next_group);
refresh_group_xkb(xkb);
xkb_redraw(xkb);
xkb_enter_locale_by_process(xkb);
return 1;
}
-/* Callback when activity detected on the Xkb channel. */
-gboolean xkb_gio_callback(GIOChannel * source, GIOCondition condition, gpointer data)
-{
- XkbPlugin * xkb = (XkbPlugin *) data;
-
- XkbEvent evnt;
- XNextEvent(xkb->dsp, &evnt.core);
- if ((evnt.type == xkb->base_event_code)
- && (evnt.any.xkb_type == XkbStateNotify)
- && (evnt.state.group != xkb->current_group_xkb_no))
- {
- /* Switch to the new group and redraw the display. */
- xkb->current_group_xkb_no = evnt.state.group;
- refresh_group_xkb(xkb);
- xkb_redraw(xkb);
- xkb_enter_locale_by_process(xkb);
- }
- return TRUE;
-}
-
/* React to change of focus by switching to the application's layout or the default layout. */
void xkb_active_window_changed(XkbPlugin * xkb, gint pid)
{
@@ -345,7 +351,7 @@ void xkb_active_window_changed(XkbPlugin * xkb, gint pid)
if (new_group_xkb_no < xkb->group_count)
{
- XkbLockGroup(xkb->dsp, xkb->device_id, new_group_xkb_no);
+ XkbLockGroup(GDK_DISPLAY(), XkbUseCoreKbd, new_group_xkb_no);
refresh_group_xkb(xkb);
}
}
diff --git a/src/plugins/xkb/xkb.h b/src/plugins/xkb/xkb.h
index 9265198..20c7ed3 100644
--- a/src/plugins/xkb/xkb.h
+++ b/src/plugins/xkb/xkb.h
@@ -49,10 +49,8 @@ typedef struct {
GtkWidget * per_app_default_layout_menu; /* Combo box of all available layouts */
/* Mechanism. */
- Display * dsp; /* Handle to X display */
int base_event_code; /* Result of initializing Xkb extension */
int base_error_code;
- int device_id; /* Keyboard device ID (always "core keyboard") */
int current_group_xkb_no; /* Current layout */
int group_count; /* Count of groups as returned by Xkb */
char * group_names[XkbNumKbdGroups]; /* Group names as returned by Xkb */
@@ -67,12 +65,11 @@ extern int xkb_get_current_group_xkb_no(XkbPlugin * xkb);
extern int xkb_get_group_count(XkbPlugin * xkb);
extern const char * xkb_get_symbol_name_by_res_no(XkbPlugin * xkb, int group_res_no);
extern const char * xkb_get_current_group_name(XkbPlugin * xkb);
-extern const char * xkb_get_current_group_name_lowercase(XkbPlugin * xkb);
+extern const char * xkb_get_current_symbol_name(XkbPlugin * xkb);
+extern const char * xkb_get_current_symbol_name_lowercase(XkbPlugin * xkb);
extern void xkb_mechanism_constructor(XkbPlugin * xkb);
extern void xkb_mechanism_destructor(XkbPlugin * xkb);
-extern int xkb_get_connection_number(XkbPlugin * xkb);
extern int xkb_change_group(XkbPlugin * xkb, int increment);
-extern gboolean xkb_gio_callback(GIOChannel * source, GIOCondition condition, gpointer data);
extern void xkb_active_window_changed(XkbPlugin * xkb, GPid pid);
#endif
--
1.6.6.1