gpephoneedtion中采用gconf实现本机设置,如待机界面的设置。之不过在gonf的基础上封了叫 libsetting 的一层。libsetting只不过是调用了goconf的函数进行简单封装。很多的开源linux手机都采用了gconf作为本机设置,一般是gconf-dbus,如openmoko。
gconf类似window的注册表,个人觉得conf主要用两方面的应用。
1、保存本机信息。关机后重启仍保存
2、关键字key对应的值改变后,所有注册了该关键字的回调函数(包括本进程里的,注:一个关键字可以被注册多个回调函数)都会马上被调用执行 。
一般我们只关心客户端,服务器只需启动,我们用它就行,不管它的原理。$V_ROOT/bin/dbus-daemon --config-file=$V_ROOT/etc/dbus-1/session.conf --print-address
一例子如下(2个客户端的):
/* controller.c */
#include
#include
void entry_activated_callback(GtkWidget *entry, gpointer user_data)
{
GConfClient *client;
gchar *str;
client = GCONF_CLIENT(user_data);
str = gtk_editable_get_chars(GTK_EDITABLE(entry),0,-1);
gconf_client_set_string(client,"/extra/test/directory/key",str,NULL);
g_free(str);
}
int main(int argc,char **argv)
{
GtkWidget *window;
GtkWidget *entry;
GConfClient *client;
gtk_init(&argc,&argv);
gconf_init(argc,argv,NULL);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
entry = gtk_entry_new();
gtk_container_add(GTK_CONTAINER(window),entry);
//client = gconf_client_new();
client = gconf_client_get_default ();
gconf_client_add_dir(client,"/extra/test/directory",GCONF_CLIENT_PRELOAD_NONE,NULL);
gtk_signal_connect(GTK_OBJECT(entry),"activate",GTK_SIGNAL_FUNC(entry_activated_callback),client);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
/* view.c */
#include
#include
void key_changed_callback(GConfClient *client,guint cnxn_id,const gchar*key,GConfValue *value,gboolean is_default,gpointer user_data)
{
GtkWidget *label;
GError *error = NULL;
label = GTK_WIDGET(user_data);
if(value == NULL)
{
gtk_label_set(GTK_LABEL(label),"unset");
}
else
{
if(value->type == GCONF_VALUE_STRING)
{
gtk_label_set(GTK_LABEL(label),gconf_client_get_string (client, key, &error));
}
else
{
gtk_label_set(GTK_LABEL(label),"wrong type");
}
}
}
int main(int argc ,char **argv)
{
GtkWidget *window;
GtkWidget *label;
GConfClient *client;
gchar *str;
gtk_init(&argc,&argv);
gconf_init(argc,argv,NULL);
//client = gconf_client_new();
client = gconf_client_get_default();
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
str = gconf_client_get_string(client,"/extra/test/directory/key",NULL);
label = gtk_label_new(str?str:"unset");
if(str)
g_free(str);
gtk_container_add(GTK_CONTAINER(window),label);
gconf_client_add_dir(client,"extra/test/directory",GCONF_CLIENT_PRELOAD_NONE,NULL);//不可少,存放key的路径
gconf_client_notify_add(client,"extra/test/directory/key",key_changed_callback,label,NULL,NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
一般用#define KEY "extra/test/directory/key"
编译
[sbox-ms007: /scratchbox/my/gconf] > ls
controller.c view.c
[sbox-ms007: /scratchbox/my/gconf] > gcc -o controller controller.c `pkg-config --cflags --libs gtk+-2.0 gconf-2.0`
[sbox-ms007: /scratchbox/my/gconf] > gcc -o view view.c `pkg-config --cflags --libs gtk+-2.0 gconf-2.0`
[sbox-ms007: /scratchbox/my/gconf] > ls
controller controller.c view view.c
[sbox-ms007: /scratchbox/my/gconf] >
可以用gconf_client_dir_exists (client, key, NULL);判断该关键字是否存在
另外~newren/tutorials/developing-with-gnome/html/apd.html
有2个例子,glade工具生成的,
gconf-dbus源码包下也有例子。其他的一些见
另注:maemo里
#include
#include
#include /* strcmp */
/* As per maemo Coding Style and Guidelines document, we use the
/apps/Maemo/ -prefix.
NOTE: There is no central registry (as of this moment) that you
could check that your application name doesn't collide with
other application names, so caution is advised! */
#define SERVICE_GCONF_ROOT "/apps/Maemo/platdev_ex"
/* We define the names of the keys symbolically so that we may change
them later if necessary, and so that the GConf "root directory" for
our application will be automatically prefixed to the paths. */
#define SERVICE_KEY_CONNECTION \
SERVICE_GCONF_ROOT "/connection"
#define SERVICE_KEY_CONNECTIONPARAMS \
SERVICE_GCONF_ROOT "/connectionparams"
/**
* Callback called when a key in watched directory changes.
* Prototype for the callback must be compatible with
* GConfClientNotifyFunc (for ref).
*
* It will find out which key changed (using strcmp, since the same
* callback is used to track both keys) and the display the new value
* of the key.
*
* The changed key/value pair will be communicated in the entry
* parameter. userData will be NULL (can be set on notify_add [in
* main]). Normally the application state would be carried within the
* userData parameter, so that this callback could then modify the
* view based on the change. Since this program does not have a state,
* there is little that we can do within the function (it will abort
* the program on errors though).
*/
static void keyChangeCallback(GConfClient* client,
guint cnxn_id,
GConfEntry* entry,
gpointer userData) {
/* This will hold the pointer to the value. */
const GConfValue* value = NULL;
/* This will hold a pointer to the name of the key that changed. */
const gchar* keyname = NULL;
/* This will hold a dynamically allocated human-readable
representation of the changed value. */
gchar* strValue = NULL;
g_print(PROGNAME ": keyChangeCallback invoked.\n");
/* Get a pointer to the key (this is not a copy). */
keyname = gconf_entry_get_key(entry);
/* It will be quite fatal if after change we cannot retrieve even
the name for the gconf entry, so we error out here. */
if (keyname == NULL) {
g_error(PROGNAME ": Couldn't get the key name!\n");
/* Application terminates. */
}
/* Get a pointer to the value from changed entry. */
value = gconf_entry_get_value(entry);
/* If we get a NULL as the value, it means that the value either has
not been set, or is at default. As a precaution we assume that
this cannot ever happen, and will abort if it does.
NOTE: A real program should be more resilient in this case, but
the problem is: what is the correct action in this case?
This is not always simple to decide.
NOTE: You can trip this assert with 'make primekeys', since that
will first remove all the keys (which causes the CB to
be invoked, and abort here). */
g_assert(value != NULL);
/* Check that it looks like a valid type for the value. */
if (!GCONF_VALUE_TYPE_VALID(value->type)) {
g_error(PROGNAME ": Invalid type for gconfvalue!\n");
}
/* Create a human readable representation of the value. Since this
will be a new string created just for us, we'll need to be
careful and free it later. */
strValue = gconf_value_to_string(value);
/* Print out a message (depending on which of the tracked keys
change. */
if (strcmp(keyname, SERVICE_KEY_CONNECTION) == 0) {
g_print(PROGNAME ": Connection type setting changed: [%s]\n",
strValue);
} else if (strcmp(keyname, SERVICE_KEY_CONNECTIONPARAMS) == 0) {
g_print(PROGNAME ": Connection params setting changed: [%s]\n",
strValue);
} else {
g_print(PROGNAME ":Unknown key: %s (value: [%s])\n", keyname,
strValue);
}
/* Free the string representation of the value. */
g_free(strValue);
g_print(PROGNAME ": keyChangeCallback done.\n");
}
/**
* Utility to retrieve a string key and display it.
* (Just as a small refresher on the API.)
*/
static void dispStringKey(GConfClient* client,
const gchar* keyname) {
/* This will hold the string value of the key. It will be
dynamically allocated for us, so we need to release it ourselves
when done (before returning). */
gchar* valueStr = NULL;
/* We're not interested in the errors themselves (the last
parameter), but the function will return NULL if there is one,
so we just end in that case. */
valueStr = gconf_client_get_string(client, keyname, NULL);
if (valueStr == NULL) {
g_error(PROGNAME ": No string value for %s. Quitting\n", keyname);
/* Application terminates. */
}
g_print(PROGNAME ": Value for key '%s' is set to '%s'\n",
keyname, valueStr);
/* Normally one would want to use the value for something beyond
just displaying it, but since this code doesn't, we release the
allocated value string. */
g_free(valueStr);
}
/**
* The main application.
*
* 1) Initialize the GType/GObject system.
* 2) Attach to GConf system (gconfd)
* 3) Retrieve the two keys (just to print them out)
* 4) Register the application configuration directory for possible
* notifications.
* 5) Register the callback to be used on changes.
* 6) Start mainloop (and stay there forever).
*
* Note that this program does not terminate by itself!
*
* You could add g_main_loop_quit to do that from the callback,
* but since the callback does not have access to the mainloop object,
* you'd need to either:
* a) Pass the mainloop object as user-specified data (trivial, but
* somewhat wrong by design).
* b) Create an application state, and put the reference to the
* mainloop object there. Then pass the application state as the
* user specified data to the callback (better design, but out of
* scope for this simple program).
*/
int main (int argc, char** argv) {
/* Will hold reference to the GConfClient object. */
GConfClient* client = NULL;
/* Initialize this to NULL so that we'll know whether an error
occurred or not (and we don't have an existing GError object
anyway at this point). */
GError* error = NULL;
/* This will hold a reference to the mainloop object. */
GMainLoop* mainloop = NULL;
g_print(PROGNAME ":main Starting.\n");
/* Must be called to initialize GType system. The API reference for
gconf_client_get_default() insists.
NOTE: Using gconf_init() is deprecated! */
g_type_init();
/* Create a new mainloop structure that we'll use. Use default
context (NULL) and set the 'running' flag to FALSE. */
mainloop = g_main_loop_new(NULL, FALSE);
if (mainloop == NULL) {
g_error(PROGNAME ": Failed to create mainloop!\n");
}
/* Create a new GConfClient object using the default settings. */
client = gconf_client_get_default();
if (client == NULL) {
g_error(PROGNAME ": Failed to create GConfClient!\n");
}
g_print(PROGNAME ":main GType and GConfClient initialized.\n");
/* Display the starting values for the two keys. */
dispStringKey(client, SERVICE_KEY_CONNECTION);
dispStringKey(client, SERVICE_KEY_CONNECTIONPARAMS);
/**
* Register directory to watch for changes. This will then tell
* GConf to watch for changes in this namespace, and cause the
* "value-changed"-signal to be emitted. We won't be using that
* mechanism, but will opt to a more modern (and potentially more
* scalable solution). The directory needs to be added to the
* watch list in either case.
*
* When adding directories, you can sometimes optimize your program
* performance by asking GConfClient to preload some (or all) keys
* under a specific directory. This is done via the preload_type
* parameter (we use GCONF_CLIENT_PRELOAD_NONE below). Since our
* program will only listen for changes, we don't want to use extra
* memory to keep the keys cached.
*
* Parameters:
* - client: GConf-client object
* - SERVICEPATH: the name of the GConf namespace to follow
* - GCONF_CLIENT_PRELOAD_NONE: do not preload any of contents
* - error: where to store the pointer to allocated GError on
* errors.
*/
gconf_client_add_dir(client,
SERVICE_GCONF_ROOT,
GCONF_CLIENT_PRELOAD_NONE,
&error);
if (error != NULL) {
g_error(PROGNAME ": Failed to add a watch to GCClient: %s\n",
error->message);
/* Normally we'd also release the allocated GError, but since
this program will terminate on g_error, we won't do that.
Hence the next line is commented. */
/* g_error_free(error); */
/* When you want to release the error if it has been allocated,
or just continue if not, use g_clear_error(&error); */
}
g_print(PROGNAME ":main Added " SERVICE_GCONF_ROOT ".\n");
/* Register our interest (in the form of a callback function) for
any changes under the namespace that we just added.
Parameters:
- client: GConfClient object.
- SERVICEPATH: namespace under which we can get notified for
changes.
- gconf_notify_func: callback that will be called on changes.
- NULL: user-data pointer (not used here).
- NULL: function to call on user-data when notify is removed or
GConfClient destroyed. NULL for none (since we don't
have user-data anyway).
- error: return location for an allocated GError.
Returns:
guint: an ID for this notification so that we could remove it
later with gconf_client_notify_remove(). We're not going
to use it so we don't store it anywhere. */
gconf_client_notify_add(client, SERVICE_GCONF_ROOT,
keyChangeCallback, NULL, NULL, &error);
if (error != NULL) {
g_error(PROGNAME ": Failed to add register the callback: %s\n",
error->message);
/* Program terminates. */
}
g_print(PROGNAME ":main CB registered & starting main loop\n");
/* Start the main loop. */
g_main_loop_run(mainloop);
/* Main loop finished.
NOTE: Without modifications, this program will never actually
reach this point, since the main loop is never
terminated. */
g_print(PROGNAME ":main Out of main loop (shouldn't happen)\n");
/* Release the mainloop object. */
g_main_loop_unref(mainloop);
/* Release the gconfclient since we're done now. This would also run
the freeing function that we could have passed on notify_add-
registration above, but since we didn't have a need for one,
no free'ers will be run here (for us at least). */
g_object_unref(client);
g_print(PROGNAME ":main Ending\n");
return 0;
}
其Makefile如下:
# This is the Makefile for the GConf key watch example.
# The default target will build the application.
#
# There are also two special targets:
# primekeys : populate the GConf parameters with default values
# clearkeys : remote all of the application GConf keys (recursively)
# dumpkeys : list all keys for this application (recursively)
#
# In order to use the targets, the GConf daemon will need to be
# running in your system (af-sb-init.sh). The daemon is running
# at all times on the device.
# Define a variable for this so that the GConf root may be changed
gconf_root := /apps/Maemo/platdev_ex
# pkg-config packages that we'll need
pkg_packages := glib-2.0 gconf-2.0
PKG_CFLAGS := $(shell pkg-config --cflags $(pkg_packages))
PKG_LDFLAGS := $(shell pkg-config --libs $(pkg_packages))
# Additional flags for the compiler:
# -g : Add debugging symbols
# -Wall : Enable most gcc warnings
ADD_CFLAGS := -g -Wall
# Combine user supplied, additional, and pkg-config flags
CFLAGS := $(PKG_CFLAGS) $(ADD_CFLAGS) $(CFLAGS)
LDFLAGS := $(PKG_LDFLAGS) $(LDFLAGS)
# Default targets
targets := gconf-key-watch
.PHONY: all phony primekeys clearkeys dumpkeys
all: $(targets)
# We define a define (PROGNAME) so that we can (or rename the program
# later if necessary).
gconf-key-watch: gconf-key-watch.c
$(CC) $(CFLAGS) -DPROGNAME=\"$@\" $^ -o $@ $(LDFLAGS)
# This will setup the keys into default values.
# It will first do a clear to remove any existing keys.
primekeys: clearkeys
gconftool-2 --set --type string \
$(gconf_root)/connection btcomm0
gconftool-2 --set --type string \
$(gconf_root)/connectionparams 9600,8,N,1
# Remove all application keys
clearkeys:
@gconftool-2 --recursive-unset $(gconf_root)
# Dump all application keys
dumpkeys:
@echo Keys under $(gconf_root):
@gconftool-2 --recursive-list $(gconf_root)
clean:
$(RM) $(targets)
阅读(3037) | 评论(0) | 转发(0) |