[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[et-mgmt-tools][PATCH]:virt-viewer: Load "Send key" menu from XML file



Attached patch modifies virt-viewer so that it acquires the "Send key"
menu contents from an xml file and allows user to load a browsed for
keymap def file while running.

Patch is based on hg tip, changeset: 44:92da1556bbf9

Signed-off-by: Pat Campbell <plc novell com>


diff -r 92da1556bbf9 src/Makefile.am
--- a/src/Makefile.am	Fri Nov 28 07:24:56 2008 -0500
+++ b/src/Makefile.am	Tue Dec 16 13:34:01 2008 -0700
@@ -4,9 +4,12 @@
 gladedir = $(pkgdatadir)/ui
 glade_DATA = viewer.glade about.glade auth.glade
 
-EXTRA_DIST = $(glade_DATA)
+keymapdir = $(pkgdatadir)/keymaps
+keymap_DATA = default.xml 
 
-virt_viewer_SOURCES = main.c viewer.h
+EXTRA_DIST = $(glade_DATA) $(keymap_DATA)
+
+virt_viewer_SOURCES = main.c sendkey.c viewer.h
 virt_viewer_LDADD = \
 	@GTKVNC_LIBS@ \
 	@GTK2_LIBS@ \
@@ -23,4 +26,5 @@
 	@LIBVIRT_CFLAGS@ \
 	@LIBVIRT_GLIB_CFLAGS@ \
 	@WARN_CFLAGS@ \
-	-DGLADE_DIR="\"$(gladedir)\""
+	-DGLADE_DIR="\"$(gladedir)\"" \
+	-DKEYMAPS_DIR="\"$(keymapdir)\""
diff -r 92da1556bbf9 src/default.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/default.xml	Tue Dec 16 13:34:01 2008 -0700
@@ -0,0 +1,135 @@
+<?xml version="1.0"?>
+
+<!DOCTYPE keymap [
+<!ELEMENT keymap (item)*>
+<!ELEMENT item (label,keys)*>
+<!ELEMENT label (#PCDATA)>
+<!ELEMENT keys (key)+>
+<!ELEMENT key (#PCDATA)>
+<!ATTLIST keymap id CDATA #REQUIRED>
+<!ATTLIST item type (menu|separator) #REQUIRED>
+]>
+
+<keymap id="virt-viewer, Send Key menu keymap">
+    <!-- See /usr/include/gtk2.0/gdk/gdkkeysyms.h for valid key names -->
+	<item type="menu">
+		<label>Ctrl+Alt+_Del</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>Delete</key>
+        </keys>
+    </item>
+	<item type="menu">
+		<label>Ctrl+Alt+_BackSpace</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>BackSpace</key>
+        </keys>
+    </item>
+	<item type="separator"/>
+	<item type="menu">
+		<label>Ctrl+Alt+F_1</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>F1</key>
+        </keys>
+    </item>
+	<item type="menu">
+		<label>Ctrl+Alt+F_2</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>F2</key>
+        </keys>
+    </item>
+    <item type="menu">
+		<label>Ctrl+Alt+F_3</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>F3</key>
+        </keys>
+    </item>
+    <item type="menu">
+		<label>Ctrl+Alt+F_4</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>F4</key>
+        </keys>
+    </item>
+    <item type="menu">
+		<label>Ctrl+Alt+F_5</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>F5</key>
+        </keys>
+    </item>
+    <item type="menu">
+		<label>Ctrl+Alt+F_6</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>F6</key>
+        </keys>
+    </item>
+    <item type="menu">
+		<label>Ctrl+Alt+F_7</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>F7</key>
+        </keys>
+    </item>
+    <item type="menu">
+		<label>Ctrl+Alt+F_8</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>F8</key>
+        </keys>
+    </item>
+    <item type="menu">
+		<label>Ctrl+Alt+F_9</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>F9</key>
+        </keys>
+    </item>
+    <item type="menu">
+		<label>Ctrl+Alt+F1_0</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>F10</key>
+        </keys>
+    </item>
+    <item type="menu">
+		<label>Ctrl+Alt+F11</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>F11</key>
+        </keys>
+    </item>
+    <item type="menu">
+		<label>Ctrl+Alt+F12</label>
+        <keys>
+            <key>Control_L</key>
+            <key>Alt_L</key>
+            <key>F12</key>
+        </keys>
+    </item>
+	<item type="separator"/>
+	<item type="menu">
+		<label>_PrintScreen</label>
+        <keys>
+            <key>Print</key>
+        </keys>
+    </item>
+</keymap>
diff -r 92da1556bbf9 src/main.c
--- a/src/main.c	Fri Nov 28 07:24:56 2008 -0500
+++ b/src/main.c	Tue Dec 16 13:34:01 2008 -0700
@@ -71,35 +71,6 @@
 };
 
 
-#define MAX_KEY_COMBO 3
-struct  keyComboDef {
-	guint keys[MAX_KEY_COMBO];
-	guint nkeys;
-	const char *label;
-};
-
-static const struct keyComboDef keyCombos[] = {
-        { { GDK_Control_L, GDK_Alt_L, GDK_Delete }, 3, "Ctrl+Alt+_Del"},
-        { { GDK_Control_L, GDK_Alt_L, GDK_BackSpace }, 3, "Ctrl+Alt+_Backspace"},
-        { {}, 0, "" },
-        { { GDK_Control_L, GDK_Alt_L, GDK_F1 }, 3, "Ctrl+Alt+F_1"},
-        { { GDK_Control_L, GDK_Alt_L, GDK_F2 }, 3, "Ctrl+Alt+F_2"},
-        { { GDK_Control_L, GDK_Alt_L, GDK_F3 }, 3, "Ctrl+Alt+F_3"},
-        { { GDK_Control_L, GDK_Alt_L, GDK_F4 }, 3, "Ctrl+Alt+F_4"},
-        { { GDK_Control_L, GDK_Alt_L, GDK_F5 }, 3, "Ctrl+Alt+F_5"},
-        { { GDK_Control_L, GDK_Alt_L, GDK_F6 }, 3, "Ctrl+Alt+F_6"},
-        { { GDK_Control_L, GDK_Alt_L, GDK_F7 }, 3, "Ctrl+Alt+F_7"},
-        { { GDK_Control_L, GDK_Alt_L, GDK_F8 }, 3, "Ctrl+Alt+F_8"},
-        { { GDK_Control_L, GDK_Alt_L, GDK_F5 }, 3, "Ctrl+Alt+F_9"},
-        { { GDK_Control_L, GDK_Alt_L, GDK_F6 }, 3, "Ctrl+Alt+F1_0"},
-        { { GDK_Control_L, GDK_Alt_L, GDK_F7 }, 3, "Ctrl+Alt+F11"},
-        { { GDK_Control_L, GDK_Alt_L, GDK_F8 }, 3, "Ctrl+Alt+F12"},
-        { {}, 0, "" },
-        { { GDK_Print }, 1, "_PrintScreen"},
-};
-
-
-
 typedef struct VirtViewer {
 	char *uri;
 	virConnectPtr conn;
@@ -109,6 +80,9 @@
 	GladeXML *glade;
 	GtkWidget *window;
 	GtkWidget *vnc;
+	GtkWidget *menubar;
+	GtkWidget *menu_send;
+	char *menu_send_text;
 	int active;
 
 	gboolean accelEnabled;
@@ -120,6 +94,8 @@
 	int reconnect;
 	int direct;
 	int verbose;
+
+	SendKeyItems sendKeyItems;
 } VirtViewer;
 
 typedef struct VirtViewerSize {
@@ -405,12 +381,13 @@
         GtkWidget *label = gtk_bin_get_child(GTK_BIN(menu));
         const char *text = gtk_label_get_label(GTK_LABEL(label));
 	DEBUG_LOG("Woo\n");
-        for (i = 0 ; i < (sizeof(keyCombos)/sizeof(keyCombos[0])) ; i++) {
-                if (!strcmp(text, keyCombos[i].label)) {
+        for (i = 0 ; i < viewer->sendKeyItems.cnt; i++) {
+                struct keyComboDef *kp = viewer->sendKeyItems.keyCombos[i];
+                if (!strcmp(text, kp->label)) {
                         DEBUG_LOG("Sending key combo %s\n", gtk_label_get_text(GTK_LABEL(label)));
                         vnc_display_send_keys(VNC_DISPLAY(viewer->vnc),
-                                              keyCombos[i].keys,
-                                              keyCombos[i].nkeys);
+                                              kp->keys,
+                                              kp->nkeys);
                         return;
                 }
         }
@@ -446,6 +423,83 @@
 
 		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
 		viewer_save_screenshot(viewer->vnc, filename);
+		g_free (filename);
+	}
+
+	gtk_widget_destroy (dialog);
+}
+
+static void viewer_menu_build_sendkey(VirtViewer *viewer, const char *filename)
+{
+	GtkWidget *sendkey;
+	GtkWidget *menu;
+	GtkWidget *label;
+	int i;
+
+	build_keyCombos(&viewer->sendKeyItems, filename, viewer->verbose);
+	gtk_widget_destroy (viewer->menu_send);
+
+	sendkey = gtk_menu_item_new();
+	label = g_object_new(GTK_TYPE_ACCEL_LABEL, NULL);
+	gtk_label_set_text_with_mnemonic(GTK_LABEL(label), viewer->menu_send_text);
+	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+
+	gtk_container_add(GTK_CONTAINER(sendkey), label);
+	gtk_accel_label_set_accel_widget(GTK_ACCEL_LABEL(label), sendkey);
+	gtk_widget_show(label);
+
+	menu = gtk_menu_new();
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(sendkey), menu);
+
+	for (i = 0; i < viewer->sendKeyItems.cnt; i++) {
+		GtkWidget *key;
+		struct keyComboDef *kp = viewer->sendKeyItems.keyCombos[i];
+
+		if (kp->nkeys) {
+			key = gtk_menu_item_new_with_mnemonic(kp->label);
+			gtk_menu_append(GTK_MENU(menu), key);
+			g_signal_connect(key, "activate", GTK_SIGNAL_FUNC(viewer_menu_send), viewer);
+		} else {
+			gtk_menu_append(GTK_MENU(menu), gtk_separator_menu_item_new());
+		}
+	}
+
+	viewer->menu_send = sendkey;
+	gtk_menu_bar_insert(GTK_MENU_BAR(viewer->menubar), viewer->menu_send, SEND_KEY_MENU);
+	gtk_widget_show_all(viewer->menu_send);
+}
+
+
+static void viewer_menu_file_sendkey(GtkWidget *menu G_GNUC_UNUSED, VirtViewer *viewer G_GNUC_UNUSED)
+{
+	GtkWidget *dialog;
+
+	dialog = gtk_file_chooser_dialog_new ("Load SendKey",
+					      NULL,
+					      GTK_FILE_CHOOSER_ACTION_OPEN,
+					      GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+					      GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+					      NULL);
+again:
+	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+		char *filename;
+
+		filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+		if (sendkey_xml_validate(filename) == -1) {
+			GtkWidget *msg_dialog = gtk_message_dialog_new (GTK_WINDOW(dialog),
+					GTK_DIALOG_DESTROY_WITH_PARENT,
+					GTK_MESSAGE_ERROR,
+					GTK_BUTTONS_CLOSE,
+					"Invalid send key XML format: '%s'",
+					filename);
+			gtk_dialog_run (GTK_DIALOG (msg_dialog));
+			gtk_widget_destroy (msg_dialog);
+			g_free (filename);
+			goto again;
+		}
+		else {
+			viewer_menu_build_sendkey(viewer, filename);
+		}
 		g_free (filename);
 	}
 
@@ -979,12 +1033,14 @@
 	      gboolean waitvm,
 	      gboolean reconnect,
 	      gboolean verbose,
+	      const char *keymapfile,
 	      GtkWidget *container)
 {
 	VirtViewer *viewer;
 	GtkWidget *notebook;
 	GtkWidget *scroll;
 	GtkWidget *align;
+	GtkWidget *widget;
 
 	viewer = g_new0(VirtViewer, 1);
 
@@ -1015,6 +1071,8 @@
 				      G_CALLBACK(viewer_menu_file_quit), viewer);
 	glade_xml_signal_connect_data(viewer->glade, "viewer_menu_file_screenshot",
 				      G_CALLBACK(viewer_menu_file_screenshot), viewer);
+	glade_xml_signal_connect_data(viewer->glade, "viewer_menu_file_sendkey",
+				      G_CALLBACK(viewer_menu_file_sendkey), viewer);
 	glade_xml_signal_connect_data(viewer->glade, "viewer_menu_view_fullscreen",
 				      G_CALLBACK(viewer_menu_view_fullscreen), viewer);
 	glade_xml_signal_connect_data(viewer->glade, "viewer_menu_view_scale",
@@ -1030,6 +1088,12 @@
         vnc_display_set_pointer_grab(VNC_DISPLAY(viewer->vnc), TRUE);
 	vnc_display_set_force_size(VNC_DISPLAY(viewer->vnc), FALSE);
 	//vnc_display_set_scaling(VNC_DISPLAY(viewer->vnc), TRUE);
+
+	viewer->menubar = glade_xml_get_widget(viewer->glade,"top-menu");
+	viewer->menu_send = glade_xml_get_widget(viewer->glade,"menu-send");
+	widget = gtk_bin_get_child(GTK_BIN(viewer->menu_send));
+	viewer->menu_send_text = strdup(gtk_label_get_label(GTK_LABEL(widget)));
+	viewer_menu_build_sendkey(viewer, keymapfile);
 
         g_signal_connect(GTK_OBJECT(viewer->vnc), "vnc-connected",
 			 GTK_SIGNAL_FUNC(viewer_connected), viewer);
@@ -1110,6 +1174,7 @@
 	GError *error = NULL;
 	int ret;
 	char *uri = NULL;
+	char *keymapfile = NULL;
 	gchar **args = NULL;
 	gboolean print_version = FALSE;
 	gboolean verbose = FALSE;
@@ -1132,6 +1197,8 @@
 		  "reconnect to domain upon restart", NULL },
   	     	{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &args,
 		  NULL, "DOMAIN-NAME|ID|UUID" },
+		{ "keymap", 'k', 0, G_OPTION_ARG_STRING, &keymapfile,
+		  "keymap descriptor file", "filename"},
   		{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
 	};
 
@@ -1158,7 +1225,7 @@
 		return 1;
 	}
 
-	ret = viewer_start (uri, args[0], direct, waitvm, reconnect, verbose, NULL);
+	ret = viewer_start (uri, args[0], direct, waitvm, reconnect, verbose, keymapfile, NULL);
 	if (ret != 0)
 		return ret;
 
diff -r 92da1556bbf9 src/sendkey.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sendkey.c	Tue Dec 16 13:34:01 2008 -0700
@@ -0,0 +1,417 @@
+/*
+ * sendkey.c: Reads keymap XML definition file populating keyComboDef
+ *           structures for send key menu
+ *
+ * Copyright (C) 2008 Novell,
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Pat Campbell <plc novell com>
+ */
+
+#include <config.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libxml/xpath.h>
+
+#include "viewer.h"
+
+#define ITEM_PATH "//keymap/item"
+#define ROOT   "keymap"
+#define ITEM   "item"
+#define TYPE   "type"
+#define MENU   "menu"
+#define SEP    "separator"
+#define LABEL  "label"
+#define KEYS   "keys"
+#define KEY    "key"
+
+static int verbose = 0;
+
+static int create_keyCombos(SendKeyItems * sendKeyItems, xmlXPathContextPtr ctxt)
+{
+	xmlXPathObjectPtr obj;
+	xmlNodePtr relnode;
+	SendKeyItems old_sendKeyItems;
+
+	if (ctxt == NULL) {
+		fprintf(stderr,"Invalid parser context to %s", __func__);
+		goto error;
+	}
+	relnode = ctxt->node;
+
+	/*
+	 * Determine number of items
+	 */
+	obj = xmlXPathEval((xmlChar *)ITEM_PATH, ctxt);
+	if ((obj == NULL) || (obj->type != XPATH_NODESET)) {
+		xmlXPathFreeObject(obj);
+		fprintf(stderr, "Error obj NULL or type not a NODESET");
+		goto error;
+	}
+	old_sendKeyItems.keyCombos = sendKeyItems->keyCombos;
+	old_sendKeyItems.cnt = sendKeyItems->cnt;
+
+	sendKeyItems->cnt = xmlXPathNodeSetGetLength(obj->nodesetval);
+	if (sendKeyItems->cnt) {
+		sendKeyItems->keyCombos = calloc(sendKeyItems->cnt, sizeof(struct keyComboDef *));
+		if (!sendKeyItems->keyCombos) {
+			sendKeyItems->keyCombos = old_sendKeyItems.keyCombos;
+			sendKeyItems->cnt = old_sendKeyItems.cnt;
+		}
+		else if (old_sendKeyItems.keyCombos) {
+			int i;
+			for (i = 0; i < old_sendKeyItems.cnt; i++) {
+				free(old_sendKeyItems.keyCombos[i]->keys);
+				free(old_sendKeyItems.keyCombos[i]->label);
+			}
+			free(old_sendKeyItems.keyCombos);
+		}
+	}
+	ctxt->node = relnode;
+	xmlXPathFreeObject(obj);
+error:
+	return(sendKeyItems->cnt);
+}
+
+static void build_keyComboDef(SendKeyItems *sendKeyItems, guint *keys, int  cnt, const char * label)
+{
+	int i;
+	struct keyComboDef *kp;
+
+	kp = (struct keyComboDef*)calloc(sizeof(guint *) + sizeof(guint) + sizeof(char *), 1);
+	if (!kp)
+		return;
+
+	if (keys) {
+		kp->keys = (guint *)malloc((sizeof(guint) * cnt) );
+		if (!kp->keys) {
+			free(kp);
+			return;
+		}
+		for(i=0; i<cnt; i++) {
+			kp->keys[i] = keys[i];
+		}
+	}
+	if (label) {
+		kp->label = strdup(label);
+	}
+	else {
+		kp->label = strdup("Unknown");
+	}
+	kp->nkeys = cnt;
+
+	for (i = 0; i < sendKeyItems->cnt; i++) {
+		if ( sendKeyItems->keyCombos[i] == NULL) {
+			sendKeyItems->keyCombos[i] = kp;
+			break;
+		}
+	}
+}
+
+static char *trim(char *str)
+{
+	char * p = str;
+
+	p += strlen(str);
+
+	/* trim trailing */
+	while(p != str) {
+		if (*p == '\n' || *p == '\t' || *p == ' ' || *p == '\0') {
+			*p = '\0';
+			p--;
+			continue;
+		}
+		break;
+	}
+	/* trim leading */
+	p = str;
+	while(p != '\0') {
+		if (*p == '\n' || *p == '\t' || *p == ' ') {
+			p++;
+			continue;
+		}
+		break;
+	}
+	if (p != str) {
+		memcpy(str, p, strlen(p) + 1);
+	}
+	return(str);
+}
+
+static void process_keys(SendKeyItems *sendKeyItems, xmlDocPtr xml, xmlXPathContextPtr ctxt,
+		xmlNode * node, char *label)
+{
+	xmlNode *n;
+	int cnt = 0;
+	int i = 0;
+	guint * keys;
+	xmlXPathObjectPtr obj;
+	char *str;
+
+	if (!node || !node->children) return;
+
+	/*
+	 * get number of keys
+	 */
+	for(n=node->children; n; n=n->next) {
+		if (n->type != XML_ELEMENT_NODE) continue;
+		cnt++;
+	}
+
+	if (cnt) {
+		keys = malloc(sizeof(guint) * cnt);
+		if (keys) {
+			for(i = 0, n=node->children; n; n=n->next) {
+				if (n->type != XML_ELEMENT_NODE) continue;
+				obj = xmlXPathEval(xmlGetNodePath(n), ctxt);
+				str = (char *)xmlNodeListGetString(xml, obj->nodesetval->nodeTab[0]->xmlChildrenNode, 1);
+				trim(str);
+				keys[i] = gdk_keyval_from_name(str);
+				if (keys[i] == 0) {
+					if (verbose) {
+						fprintf(stderr, "virt-viewer: Could not get keyval for %s:%s, ignoring\n",
+							str, label);
+					}
+					free(keys);
+					sendKeyItems->cnt--;
+					return;
+				}
+				i++;
+			}
+			build_keyComboDef(sendKeyItems, keys, cnt, label);
+		}
+	}
+}
+
+static void process_item(SendKeyItems * sendKeyItems, xmlDocPtr xml,
+		xmlXPathContextPtr ctxt, xmlNode * node)
+{
+	xmlNode *n;
+	xmlXPathObjectPtr obj;
+	xmlChar *type;
+	char *label = NULL;
+
+	if (!node) return;
+
+	type = xmlGetProp(node, (xmlChar*)"type");
+	if (!type) return;
+
+	if (xmlStrncmp((const xmlChar*)MENU, type, strlen(MENU)) == 0) {
+		for(n=node->children; n; n=n->next) {
+			if (n->type != XML_ELEMENT_NODE) continue;
+			if (xmlStrncmp((const xmlChar*)LABEL, n->name, strlen(LABEL)) == 0) {
+				obj = xmlXPathEval(xmlGetNodePath(n), ctxt);
+				if (!obj) return;
+				label = (char *)xmlNodeListGetString(xml, obj->nodesetval->nodeTab[0]->xmlChildrenNode, 1);
+			}
+			else if (xmlStrncmp((const xmlChar*)KEYS, n->name, strlen(KEYS)) == 0) {
+				process_keys(sendKeyItems, xml, ctxt, n, label);
+			}
+		}
+	}
+	else if (xmlStrncmp((const xmlChar*)SEP, type, strlen(SEP)) == 0) {
+		build_keyComboDef(sendKeyItems, NULL, 0, "");
+	}
+}
+
+/*
+ * Default keymap when xml definition file can't be found
+ */
+#define MAX_KEYS 3
+struct  defaultKeyComboDef {
+	guint keys[MAX_KEYS];
+	guint nkeys;
+	const char *label;
+};
+static const struct defaultKeyComboDef defaultKeyCombos[] = {
+	{ { GDK_Control_L, GDK_Alt_L, GDK_Delete }, 3, "Ctrl+Alt+_Del"},
+	{ { GDK_Control_L, GDK_Alt_L, GDK_BackSpace }, 3, "Ctrl+Alt+_Backspace"},
+	{ {}, 0, "" },
+	{ { GDK_Control_L, GDK_Alt_L, GDK_F1 }, 3, "Ctrl+Alt+F_1"},
+	{ { GDK_Control_L, GDK_Alt_L, GDK_F2 }, 3, "Ctrl+Alt+F_2"},
+	{ { GDK_Control_L, GDK_Alt_L, GDK_F3 }, 3, "Ctrl+Alt+F_3"},
+	{ { GDK_Control_L, GDK_Alt_L, GDK_F4 }, 3, "Ctrl+Alt+F_4"},
+	{ { GDK_Control_L, GDK_Alt_L, GDK_F5 }, 3, "Ctrl+Alt+F_5"},
+	{ { GDK_Control_L, GDK_Alt_L, GDK_F6 }, 3, "Ctrl+Alt+F_6"},
+	{ { GDK_Control_L, GDK_Alt_L, GDK_F7 }, 3, "Ctrl+Alt+F_7"},
+	{ { GDK_Control_L, GDK_Alt_L, GDK_F8 }, 3, "Ctrl+Alt+F_8"},
+	{ { GDK_Control_L, GDK_Alt_L, GDK_F9 }, 3, "Ctrl+Alt+F_9"},
+	{ { GDK_Control_L, GDK_Alt_L, GDK_F10 }, 3, "Ctrl+Alt+F1_0"},
+	{ { GDK_Control_L, GDK_Alt_L, GDK_F11 }, 3, "Ctrl+Alt+F11"},
+	{ { GDK_Control_L, GDK_Alt_L, GDK_F12 }, 3, "Ctrl+Alt+F12"},
+	{ {}, 0, "" },
+	{ { GDK_Print }, 1, "_PrintScreen"},
+};
+
+static void makeDefaultKeyCombos(SendKeyItems * sendKeyItems)
+{
+	int i;
+	guint *keys;
+
+	sendKeyItems->cnt = (sizeof(defaultKeyCombos)/sizeof(defaultKeyCombos[0]));
+	sendKeyItems->keyCombos = calloc(sendKeyItems->cnt, sizeof(struct keyComboDef *));
+	if (!sendKeyItems->keyCombos) {
+		sendKeyItems->cnt = 0;
+		return;
+	}
+
+	for (i = 0 ; i < (sizeof(defaultKeyCombos)/sizeof(defaultKeyCombos[0])) ; i++) {
+		keys = (guint *)defaultKeyCombos[i].keys;
+		build_keyComboDef(sendKeyItems, keys, defaultKeyCombos[i].nkeys, defaultKeyCombos[i].label);
+	}
+}
+
+
+int build_keyCombos(SendKeyItems * sendKeyItems, const char *filename, int set_verbose)
+{
+	xmlDocPtr xml = NULL;
+	xmlParserCtxtPtr pctxt = NULL;
+	xmlXPathContextPtr ctxt = NULL;
+	xmlNode *root_element = NULL;
+	xmlNode *node;
+	struct stat sbuf;
+
+	verbose = set_verbose;
+	pctxt = xmlNewParserCtxt();
+	if (!pctxt || !pctxt->sax)
+		goto error;
+
+	if (filename == NULL)
+		filename = g_strdup_printf("%s/default.xml", KEYMAPS_DIR);
+
+	if(stat(filename, &sbuf) != 0) {
+		if (verbose)
+			fprintf(stderr, "%s(): could not stat file:%s \n", __FUNCTION__, filename);
+		goto error;
+	}
+
+	xml = xmlCtxtReadFile(pctxt, filename, NULL,
+			     XML_PARSE_NOENT | XML_PARSE_NONET |
+			     XML_PARSE_NOWARNING);
+	if (!xml) {
+		if (verbose)
+			fprintf(stderr, "%s(): could not read file:%s \n", __FUNCTION__, filename);
+		goto error;
+	}
+
+	ctxt = xmlXPathNewContext(xml);
+	if (!ctxt)
+		goto error;
+
+	root_element = xmlDocGetRootElement(xml);
+	if (!root_element) {
+		if (verbose)
+			fprintf(stderr, "%s(): could not locate root element\n", __FUNCTION__);
+		goto error;
+	}
+
+	if (!create_keyCombos(sendKeyItems, ctxt)) {
+		if (verbose)
+			fprintf(stderr, "%s(): could not create XML based keyCombos structure \n", __FUNCTION__);
+		goto error;
+	}
+
+	for (node=root_element; node; node=node->next) {
+		if (node->type != XML_ELEMENT_NODE) continue;
+		if (node->children)
+		{
+			xmlNode *n;
+			for(n=node->children; n; n=n->next) {
+				if (n->type != XML_ELEMENT_NODE) continue;
+				if (xmlStrncmp((const xmlChar*)ITEM, n->name, strlen(ITEM)) == 0) {
+					process_item(sendKeyItems, xml, ctxt, n);
+				}
+			}
+		}
+	}
+
+ error:
+	if (ctxt)
+		xmlXPathFreeContext(ctxt);
+	if (xml)
+		xmlFreeDoc(xml);
+	if (pctxt)
+		xmlFreeParserCtxt(pctxt);
+	if (sendKeyItems->keyCombos == NULL)
+		makeDefaultKeyCombos(sendKeyItems);
+	return(sendKeyItems->cnt);
+}
+
+int sendkey_xml_validate(const char * filename)
+{
+	xmlDocPtr doc = NULL;
+	xmlParserCtxtPtr pctxt = NULL;
+	xmlXPathContextPtr ctxt = NULL;
+	xmlNode *root_element = NULL;
+	int ret = -1;
+
+	pctxt = xmlNewParserCtxt();
+	if (!pctxt || !pctxt->sax) {
+		if (verbose)
+			fprintf(stderr, "%s(): failed to allocate parser context \n", __FUNCTION__);
+		goto error;
+	}
+
+	doc = xmlCtxtReadFile(pctxt, filename, NULL, XML_PARSE_DTDVALID);
+	if (!doc) {
+		if (verbose)
+			fprintf(stderr, "%s(): could not read file:%s \n", __FUNCTION__, filename);
+		goto error;
+	}
+	if (pctxt->valid == 0) {
+		if (verbose)
+			fprintf(stderr, "%s(): Failed to validate :%s \n", __FUNCTION__, filename);
+		goto error;
+	}
+
+	ctxt = xmlXPathNewContext(doc);
+	if (!ctxt) {
+		if (verbose)
+			fprintf(stderr, "%s(): Failed to allocate path context\n", __FUNCTION__);
+		goto error;
+	}
+
+	root_element = xmlDocGetRootElement(doc);
+	if (!root_element) {
+		if (verbose)
+			fprintf(stderr, "%s(): could not locate root element\n", __FUNCTION__);
+		goto error;
+	}
+
+	if (xmlStrncmp((const xmlChar*)ROOT, root_element->name, strlen(ROOT)) != 0) {
+		if (verbose)
+			fprintf(stderr, "%s(): Incorrect root element name:%s\n", __FUNCTION__,
+					root_element->name);
+		goto error;
+	}
+	ret = 0;
+
+error:
+	if (ctxt)
+		xmlXPathFreeContext(ctxt);
+	if (doc)
+		xmlFreeDoc(doc);
+	if (pctxt)
+		xmlFreeParserCtxt(pctxt);
+	return(ret);
+
+}
diff -r 92da1556bbf9 src/viewer.glade
--- a/src/viewer.glade	Fri Nov 28 07:24:56 2008 -0500
+++ b/src/viewer.glade	Tue Dec 16 13:34:01 2008 -0700
@@ -25,6 +25,14 @@
                         <property name="label" translatable="yes">Screenshot</property>
                         <property name="use_underline">True</property>
                         <signal name="activate" handler="viewer_menu_file_screenshot"/>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkMenuItem" id="menu-file-sendkey">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Send key</property>
+                        <property name="use_underline">True</property>
+                        <signal name="activate" handler="viewer_menu_file_sendkey"/>
                       </widget>
                     </child>
                     <child>
@@ -78,141 +86,6 @@
                 <property name="visible">True</property>
                 <property name="label" translatable="yes">_Send key</property>
                 <property name="use_underline">True</property>
-                <child>
-                  <widget class="GtkMenu" id="menu5">
-                    <property name="visible">True</property>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-cad">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+_Del</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="cad"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-cab">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+_Backspace</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="cab"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkSeparatorMenuItem" id="separatormenuitem2">
-                        <property name="visible">True</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-caf1">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+F_1</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="caf1"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-caf2">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+F_2</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="caf2"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-caf3">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+F_3</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="caf3"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-caf4">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+F_4</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="caf4"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-caf5">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+F_5</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="caf5"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-caf6">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+F_6</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-caf7">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+F_7</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="caf7"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-caf8">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+F_8</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="caf8"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-caf9">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+F_9</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="caf9"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-caf10">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+F1_0</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="caf10"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-caf11">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+F11</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="caf11"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-caf12">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Ctrl+Alt+F12</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="caf12"/>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkSeparatorMenuItem" id="separatormenuitem3">
-                        <property name="visible">True</property>
-                      </widget>
-                    </child>
-                    <child>
-                      <widget class="GtkMenuItem" id="menu-send-print">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">_PrintScreen</property>
-                        <property name="use_underline">True</property>
-                        <signal name="activate" handler="viewer_menu_send" object="printscreen"/>
-                      </widget>
-                    </child>
-                  </widget>
-                </child>
               </widget>
             </child>
             <child>
diff -r 92da1556bbf9 src/viewer.h
--- a/src/viewer.h	Fri Nov 28 07:24:56 2008 -0500
+++ b/src/viewer.h	Tue Dec 16 13:34:01 2008 -0700
@@ -29,6 +29,21 @@
 			 gboolean waitvm,
 			 gboolean reconnect,
 			 gboolean verbose,
+			 const char *keymapfile,
 			 GtkWidget *container);
 
+typedef struct  keyComboDef {
+	guint *keys;
+	guint nkeys;
+	char *label;
+}KeyComboDef;
+
+typedef struct sendKeyItems {
+	int cnt;
+	struct keyComboDef **keyCombos;
+}SendKeyItems;
+
+int build_keyCombos(SendKeyItems *, const char *, int);
+int sendkey_xml_validate(const char * filename);
+
 #endif /* VIEWER_H */
diff -r 92da1556bbf9 virt-viewer.spec.in
--- a/virt-viewer.spec.in	Fri Nov 28 07:24:56 2008 -0500
+++ b/virt-viewer.spec.in	Tue Dec 16 13:34:01 2008 -0700
@@ -81,6 +81,7 @@
 %{_datadir}/%{name}/ui/auth.glade
 %{_datadir}/%{name}/ui/about.glade
 %{_datadir}/%{name}/ui/viewer.glade
+%{_datadir}/%{name}/keymaps/default.xml
 %{_mandir}/man1/%{name}*
 
 %if %{_with_plugin}

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]