Gtk signal with multiple arguments - c

Context
After writing a simple application using a GtkEntry widget to process textual commands from user I would like to do some design changes.
As of now I use signal hook on key-press. If key(s) are a specified value, then show command line and process various actions on entry widget. Like e.g.
Ctrl+a: move cursor to start of input.
Ctrl+u: delete text before the cursor.
...
As well as parsing commands and saving/loading history.
I am not satisfied with how this is stitched together. The command parsing becomes a subset of:
main_window -> mode_check -> command_line_act -> parse_cmd+execute
As I see it one good approach would be to write a new widget using GtkEntry as base – and send signals on command enter. All of the internals like Ctrl+... and history handled by the new widget.
Signals emitted from new widget being e.g.:
"cmdline-abort"
"cmdline-cmd"
...
Status
Have written the base for this but I am at a hault when it comes to emitting signals with more then one argument.
I have:
gtk_signal_emit(obj, sig, 0, command)
|
+---- string.
but would like, (for now at least, most likely more/other down the line.):
gtk_signal_emit(obj, sig, 0, command, length)
gtk_emit_signal Typo fixed. Thanks to jku.. Also, now using g_signal_
In widget code:
static void
cmdline_class_init(CmdlineClass *klass)
{
With one argument I am using g_signal_new() as:
cmdline_signals[CMDLINE_CMD] = g_signal_new(
"cmdline-cmd",
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET(CmdlineClass, cmdline),
NULL,
NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
1,
G_TYPE_STRING
);
And as I see it, for two arguments, should change it to something like:
cmdline_signals[CMDLINE_CMD] = g_signal_new(
"cmdline-cmd",
G_TYPE_FROM_CLASS(klass),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET(CmdlineClass, cmdline),
NULL,
NULL,
g_cclosure_user_marshal_VOID__STRING_INT,
G_TYPE_NONE,
2,
G_TYPE_STRING,
G_TYPE_INT
);
Trouble in the garden
Using glib-genmarshal to generate marshals with marshal.list holding:
VOID:STRING,INT
This works, but gives me a warning upon compile time as:
warning: ISO C forbids conversion of object pointer to function pointer type
Caused by this code generated by glib-genmarshal:
typedef void (*GMarshalFunc_VOID__STRING_INT) (gpointer data1,
gpointer arg_1,
gint arg_2,
gpointer data2);
register GMarshalFunc_VOID__STRING_INT callback;
/* GCC Warnig: conversion of object pointer to function => */
callback = (GMarshalFunc_VOID__STRING_INT) (
marshal_data ?
marshal_data :
cc->callback
);
Question
Is this the wrong approach? Is there some way to fix the conversion error? Etc.
As a note: I am fairly new to Gtk, and Gui programming in general.
Side point
There are some deprecations I also wonder if could affect the code / should be avoided:
GtkSignalMarshaller, does this indicate anything about the status of GSignalCMarshaller?
GtkCallbackMarshal, does this indicate anything about the use of marshalers in general?

This warning does appear (with -pedantic) on some signal marshalling code, and not just in your code. As far as I can see you are not doing anything wrong though -- except for using gtk_signal_emit() (I assume you meant that and not gtk_emit_signal() which does not exist as far as I know): you should not use any gtk_signal-prefixed code: that stuff is all deprecated. See the reference for details. Use GObject instead: g_signal_emit() or g_signal_emit_by_name() should work for you.
The signal marshaller deprecations you mention are about this same thing: GObject handles everything related to this now (and has for a long time already).
As practical advice: Often adding things to signal signatures is not worth the trouble, and this might be the case for you as well: maybe your signal does not need the command string at all, and the signal handler could just query it with your_object_get_command()?
Practical advice #2: Consider using GTK+ 3 for new code. Not having all that deprecated stuff around confusing everyone is just lovely.

Related

customizing completion of GtkComboBoxText

How can I customize the completion of a GtkComboBoxText with both a "static" aspect and a "dynamic" one? The static aspect is because some entries are known and added to the combo-box-text at construction time with gtk_combo_box_text_append_text. The dynamic aspect is because I also need to complete thru some callback function(s), that is to complete dynamically -after creation of the GtkComboBoxText widget- once several characters has been typed.
My application uses Boehm's GC (except for GTK objects of course) like Guile or SCM or Bigloo are doing. It can be seen as an experimental persistent dynamic-typed programming language implementation with an integrated editor coded on and for Debian/Linux/x86-64 with the system GTK3.21 library, it is coded in C99 (some of which is generated) and is compiled with GCC6.
(I don't care about non-Linux systems, GTK3 libraries older than GTK3.20, GCC compiler older that GCC6)
question details
I'm entering (inputting into the GtkComboBoxText) either a name, or an object-id.
The name is C-identifier-like but starts with a letter and cannot end with an underscore. For example, comment, if, the_GUI, the_system, payload_json, or x1 are valid names (but _a0bcd or foobar_ are invalid names, because they start or end with an underscore). I currently have a big dozen of names, but I could have a few thousands of them. So it would be reasonable to offer a completion once only a single or perhaps two letters has been typed, and completion for names can happen statically because they are not many of them (so I feel reasonable to call gtk_combo_box_append_text for each name).
The object-id starts with an underscore followed by a digit and has exactly 18 alphanumeric (sort-of random) characters. For example, _5Hf0fFKvRVa71ZPM0, _8261sbF1f9ohzu2Iu, _0BV96V94PJIn9si1K are possible object-ids. Actually it is 96 almost random bits (probably only 294 are possible). The object-id plays the role of UUIDs (in the sense that it is assumed to be world-wide unique for distinct objects) but has a C friendly syntax. I currently have a few dozen of objects-ids, but I could have a few hundred of thousands (or maybe a million) of them. But given a prefix of four characters like _6S3 or _22z, I am assuming that only a reasonable number (probably at most a dozen, and surely no more than a thousand) object-ids exist in my application with that prefix. Of course it would be unreasonable to register (statically) a priori all the object ids (the completion has to happen after four characters have been typed, and should happen dynamically).
So I want a completion that works both on names (e.g. typing one letter perhaps followed by another alphanum character should be enough to propose a completion of at most a hundred choices), and on object-ids (typing four characters like _826 should be enough to trigger a completion of probably at most a few dozen choices, perhaps a thousand ones if unlucky).
Hence typing the three keys p a tab would offer completion with a few names like payload_json or payload_vectval etc... and typing the five keys _ 5 H f tab would offer completion with very few object-ids, notably _5Hf0fFKvRVa71ZPM0
sample incomplete code
So far I coded the following:
static GtkWidget *
mom_objectentry (void)
{
GtkWidget *obent = gtk_combo_box_text_new_with_entry ();
gtk_widget_set_size_request (obent, 30, 10);
mo_value_t namsetv = mo_named_objects_set ();
I have Boehm-garbage-collected values, and mo_value_t is a pointer to any of them. Values can be tagged integers, pointers to strings, objects, or tuples or sets of objects. So namesetv now contains the set of named objects (probably less than a few thousand of named objects).
int nbnam = mo_set_size (namsetv);
MOM_ASSERTPRINTF (nbnam > 0, "bad nbnam");
mo_value_t *namarr = mom_gc_alloc (nbnam * sizeof (mo_value_t));
int cntnam = 0;
for (int ix = 0; ix < nbnam; ix++)
{
mo_objref_t curobr = mo_set_nth (namsetv, ix);
mo_value_t curnamv = mo_objref_namev (curobr);
if (mo_dyncast_string (curnamv))
namarr[cntnam++] = curnamv;
}
qsort (namarr, cntnam, sizeof (mo_value_t), mom_obname_cmp);
for (int ix = 0; ix < cntnam; ix++)
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (obent),
mo_string_cstr (namarr[ix]));
at this point I have sorted all the (few thousands at most) names and added "statically" them using gtk_combo_box_text_append_text.
GtkWidget *combtextent = gtk_bin_get_child (GTK_BIN (obent));
MOM_ASSERTPRINTF (GTK_IS_ENTRY (combtextent), "bad combtextent");
MOM_ASSERTPRINTF (gtk_entry_get_completion (GTK_ENTRY (combtextent)) ==
NULL, "got completion in combtextent");
I noticed with a bit of surprise that gtk_entry_get_completion (GTK_ENTRY (combtextent)) is null.
But I am stuck here. I am thinking of:
Having some mom_set_complete_objectid(const char*prefix) which given a prefix like "_47n" of at least four characters would return a garbage collected mo_value_t representing the set of objects with that prefix. This is very easy to code for me, and is nearly done.
Make my own local GtkEntryCompletion* mycompl = ..., which would complete like I want. Then I would put it in the text entry combtextent of my gtk-combo-box-text using gtk_entry_set_completion(GTK_ENTRY(combtextent), mycompl);
Should it use the entries added with gtk_combo_box_text_append_text for the "static" name completion role? How should I dynamically complete using the dynamic set value returned from my mom_set_complete_objectid; given some object-pointer obr and some char bufid[20]; I am easily and quickly able to fill it with the object-id of that object obr with mo_cstring_from_hi_lo_ids(bufid, obr->mo_ob_hid, obr->mo_ob_loid)..
I don't know how to code the above. For reference, I am now just returning the combo-box-text:
// if the entered text starts with a letter, I want it to be
// completed with the appended text above if the entered text starts
// with an undersore, then a digit, then two alphanum (like _0BV or
// _6S3 for example), I want to call a completion function.
#warning objectentry: what should I code here?
return obent;
} /* end mom_objectentry */
Is my approach the right one?
The mom_objectentry function above is used to fill modal dialogs with short lifetime.
I am favoring simple code over efficiency. Actually, my code is temporary (I'm hoping to bootstrap my language, and generate all its C code!) and in practice I'll probably have only a few hundred names and at most a few dozen of thousands of object-ids. So performance is not very important, but simplicity of coding (some conceptually "throw away" code) is more important.
I don't want (if possible) to add my own GTK classes. I prefer using existing GTK classes and widgets, customizing them with GTK signals and callbacks.
context
My application is an experimental persistent programming language and implementation with a near Scheme or Python (or JavaScript, ignoring the prototype aspect, ...) semantics but with a widely different (not yet implemented in september 7th, 2016) syntax (to be shown & input in GTK widgets), using the Boehm garbage collector for values (including objects, sets, tuples, strings...)... Values (including objects) are generally persistent (except the GTK related data : the application starts with a nearly empty window). The entire language heap is persisted in JSON-like syntax in some Sqlite "database" (generated at application exit) dumped into _momstate.sql which is re-loaded at application startup. Object-ids are useful to show object references to the user in GTK widgets, for persistence, and to generate C code related to the objects (e.g. the object of id _76f7e2VcL8IJC1hq6 could be related to a mo_76f7e2VcL8IJC1hq6 identifier in some generated C code; this is partly why I have my object-id format instead of using UUIDs).
PS. My C code is GPLv3 free software and available on github. It is the MELT monitor, branch expjs, commit e2b3b99ef66394...
NB: The objects mentioned here are implicitly my language objects, not GTK objects. The all have a unique object-id, and some but not most of them are named.
I will not show exact code on how to do it because I never did GTK & C only GTK & Python, but it should be fine as the functions in C and Python functions can easily be translated.
OP's approach is actually the right one, so I will try to fill in the gaps. As the amount of static options is limited probably won't change to much it indeed makes sense to add them using gtk_combo_box_text_append which will add them to the internal model of the GtkComboBoxText.
Thats covers the static part, for the dynamic part it would be perfect if we could just store this static model and replace it with a temporay model using gtk_combo_box_set_model() when a _ was found at the start of the string. But we shouldn't do this as the documentation says:
You should not call gtk_combo_box_set_model() or attempt to pack more cells into this combo box via its GtkCellLayout interface.
So we need to work around this, one way of doing this is by adding a GtkEntryCompletion to the entry of the GtkComboBoxText. This will make the entry attempt to complete the current string based on its current model. As an added bonus it can also add all the character all options have in common like this:
As we don't want to load all the dynamic options before hand I think the best approach will be to connect a changed listener to the GtkEntry, this way we can load the dynamic options when we have a underscore and some characters.
As the GtkEntryCompletion uses a GtkListStore internally, we can reuse part of the code Nominal Animal provided in his answer. The main difference being: the connect is done on the GtkEntry and the replacing of GtkComboText with GtkEntryCompletion inside the populator. Then everything should be fine, I wish I would be able to write decent C then I would have provided you with code but this will have to do.
Edit: A small demo in Python with GTK3
import gi
gi.require_version('Gtk', '3.0')
import gi.repository.Gtk as Gtk
class CompletingComboBoxText(Gtk.ComboBoxText):
def __init__(self, static_options, populator, **kwargs):
# Set up the ComboBox with the Entry
Gtk.ComboBoxText.__init__(self, has_entry=True, **kwargs)
# Store the populator reference in the object
self.populator = populator
# Create the completion
completion = Gtk.EntryCompletion(inline_completion=True)
# Specify that we want to use the first col of the model for completion
completion.set_text_column(0)
completion.set_minimum_key_length(2)
# Set the completion model to the combobox model such that we can also autocomplete these options
self.static_options_model = self.get_model()
completion.set_model(self.static_options_model)
# The child of the combobox is the entry if 'has_entry' was set to True
entry = self.get_child()
entry.set_completion(completion)
# Set the active option of the combobox to 0 (which is an empty field)
self.set_active(0)
# Fill the model with the static options (could also be used for a history or something)
for option in static_options:
self.append_text(option)
# Connect a listener to adjust the model when the user types something
entry.connect("changed", self.update_completion, True)
def update_completion(self, entry, editable):
# Get the current content of the entry
text = entry.get_text()
# Get the completion which needs to be updated
completion = entry.get_completion()
if text.startswith("_") and len(text) >= completion.get_minimum_key_length():
# Fetch the options from the populator for a given text
completion_options = self.populator(text)
# Create a temporary model for the completion and fill it
dynamic_model = Gtk.ListStore.new([str])
for completion_option in completion_options:
dynamic_model.append([completion_option])
completion.set_model(dynamic_model)
else:
# Restore the default static options
completion.set_model(self.static_options_model)
def demo():
# Create the window
window = Gtk.Window()
# Add some static options
fake_static_options = [
"comment",
"if",
"the_GUI",
"the_system",
"payload_json",
"x1",
"payload_json",
"payload_vectval"
]
# Add the the Combobox
ccb = CompletingComboBoxText(fake_static_options, dynamic_option_populator)
window.add(ccb)
# Show it
window.show_all()
Gtk.main()
def dynamic_option_populator(text):
# Some fake returns for the populator
fake_dynamic_options = [
"_5Hf0fFKvRVa71ZPM0",
"_8261sbF1f9ohzu2Iu",
"_0BV96V94PJIn9si1K",
"_0BV1sbF1f9ohzu2Iu",
"_0BV0fFKvRVa71ZPM0",
"_0Hf0fF4PJIn9si1Ks",
"_6KvRVa71JIn9si1Kw",
"_5HKvRVa71Va71ZPM0",
"_8261sbF1KvRVa71ZP",
"_0BKvRVa71JIn9si1K",
"_0BV1KvRVa71ZPu2Iu",
"_0BV0fKvRVa71ZZPM0",
"_0Hf0fF4PJIbF1f9oh",
"_61sbFV0fFKn9si1Kw",
"_5Hf0fFKvRVa71ozu2",
]
# Only return those that start with the text
return [fake_dynamic_option for fake_dynamic_option in fake_dynamic_options if fake_dynamic_option.startswith(text)]
if __name__ == '__main__':
demo()
Gtk.main()
Here is my suggestion:
Use a GtkListStore to contain a list of GTK-managed strings (essentially, copies of your identifier string) that match the current prefix string.
(As documented for gtk_list_store_set(), a G_TYPE_STRING item is copied. I consider the overhead of the extra copy acceptable here; it should not affect real-world performance much anyway, I think, and in return, GTK+ will manage the reference counting for us.)
The above is implemented in a GTK+ callback function, which gets an extra pointer as payload (set at the time the GUI is created or activated; I suggest you use some structure to keep references you need to generate the matches). The callback is connected to the combobox popup signal, so that it gets called whenever the list is expanded.
Note that as B8vrede noted in a comment, a GtkComboBoxText should not be modified via its model; that is why one should/must use a GtkComboBox instead.
Practical example
For simplicity, let's assume all the data you need to find or generate all known identifiers matched against is held in a structure, say
struct generator {
/* Whatever data you need to generate prefix matches */
};
and the combo box populator helper function is then something like
static void combo_box_populator(GtkComboBox *combobox, gpointer genptr)
{
struct generator *const generator = genptr;
GtkListStore *combo_list = GTK_LIST_STORE(gtk_combo_box_get_model(combobox));
GtkWidget *entry = gtk_bin_get_child(GTK_BIN(combobox));
const char *prefix = gtk_entry_get_text(GTK_ENTRY(entry));
const size_t prefix_len = (prefix) ? strlen(prefix) : 0;
GtkTreeIter iterator;
/* Clear the current store */
gtk_list_store_clear(combo_list);
/* Initialize the list iterator */
gtk_tree_model_get_iter_first(GTK_TREE_MODEL(combo_list), &iterator);
/* Find all you want to have in the combo box;
for each const char *match, do:
*/
gtk_list_store_append(combo_list, &iterator);
gtk_list_store_set(combo_list, &iterator, 0, match, -1);
/* Note that the string pointed to by match is copied;
match is not referred to after the _set() returns.
*/
}
When the UI is built or activated, you need to ensure the GtkComboBox has an entry (so the user can write text into it), and a GtkListStore model:
struct generator *generator;
GtkWidget *combobox;
GtkListStore *combo_list;
combo_list = gtk_list_store_new(1, G_TYPE_STRING);
combobox = gtk_combo_box_new_with_model_and_entry(GTK_TREE_MODEL(combo_list));
gtk_combo_box_set_id_column(GTK_COMBO_BOX(combobox), 0);
gtk_combo_box_set_entry_text_column(GTK_COMBO_BOX(combobox), 0);
gtk_combo_box_set_button_sensitivity(GTK_COMBO_BOX(combobox), GTK_SENSITIVITY_ON);
g_signal_connect(combobox, "popup", G_CALLBACK(combo_box_populator), generator);
On my system, the default pop-up accelerator is Alt+Down, but I assume you've already changed that to Tab.
I have a crude working example here (a .tar.xz tarball, CC0): it reads lines from standard input, and lists the ones matching the user prefix in reverse order in the combo box list (when popped-up). If the entry is empty, the combobox will contain all input lines. I didn't change the default accelerators, so instead of Tab, try Alt+Down.
I also have the same example, but using GtkComboBoxText instead, here (also CC0). This does not use a GtkListStore model, but uses gtk_combo_box_text_remove_all() and gtk_combo_box_text_append_text() functions to manipulate the list contents directly. (There is just a few different lines in the two examples.) Unfortunately, the documentation is not explicit whether this interface references or copies the strings. Although copying is the only option that makes sense, and this can be verified from the current Gtk+ sources, the lack of explicit documentation makes me hesitant.
Comparing the two examples I linked to above (both grab some 500 random words from /usr/share/dict/words if you compile and run it with make), I don't see any speed difference. Both use the same naïve way of picking prefix matches from a linked list, which means the two methods (GtkComboBox + model, or GtkComboBoxText) should be about equally fast.
On my own machine, both get annoyingly slow with more than 1000 or so matches in the popup; with just a hundred or less matches, it feels instantaneous. This, to me, indicates that the slow/naïve way of picking prefix matches from a linked list is not the culprit (because the entire list is traversed in both cases), but that the GTK+ combo boxes are just not designed for large lists. (The slowdown is definitely much, much worse than linear.)

Create Direct3DEx interface from C doesn't work

i have to admit that i have really strange issue, which im not able to solve by my self. Im trying from few days without success.
My goal is to use Direct3DEx interfaces from C (not C++). I cant use Direct3D because i have to deal with shared resource handles with surfaces from different d3ddevices.
I have no any problems with creating IDirect3DEx from C++, works perfectly. For example this code works as expected
IDirect3D9Ex* m_d3d;
Direct3DCreate9Ex(D3D_SDK_VERSION, &m_d3d);
UINT c = m_d3d->GetAdapterCount();
m_d3d->Release();
Now im trying to do exactly the same from C,
my code is:
void *pd3dll = (void *) LoadLibrary("d3d9.dll");
UINT count;
IDirect3D9Ex *pDirect3D9ExInterface;
HRESULT hr;
typedef HRESULT (WINAPI *Direct3DCreate9Ex_t)(UINT SDKVersion, IDirect3D9Ex **ppD3D);
Direct3DCreate9Ex_t Direct3DCreate9ExFunc;
Direct3DCreate9ExFunc = (Direct3DCreate9Ex_t) GetProcAddress((HMODULE) pd3dll, "Direct3DCreate9Ex");
hr = Direct3DCreate9ExFunc(D3D_SDK_VERSION, &pDirect3D9ExInterface);
if (SUCCEEDED(hr))
{
count = IDirect3D9Ex_GetAdapterCount(pDirect3D9ExInterface); //crash
IDirect3D9Ex_Release(pDirect3D9ExInterface);
}
i dont see absolutly any reason why this piece of code doesnt work.
Please notice that code line:
hr = Direct3DCreate9ExFunc(D3D_SDK_VERSION, &pDirect3D9ExInterface);
returns S_OK, and when im checking pDirect3D9ExInterface pointer under debuger it looks like a valid pointer.
But this line of code:
count = IDirect3D9Ex_GetAdapterCount(pDirect3D9ExInterface); //crash
causes my program to crash. When im switching my DirectX9 to debug mode, on VS output window i see after crash, something like this:
Direct3D9: (ERROR) :Invalid initialization function specified. RegisterSoftwareDevice fails.
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
Additionaly if i change this C code to Direct3D initialization (no Direct3DEx) than works without any problems.
What im doing wrong? Where is the catch?
thanks in advance
Jakub
This seems to be due to a bug in the definition of the d3d9.h header file.
A function seems to be left out of the IDirect3D9Ex interface that appears in the IDirect3D9 interface (IDirect3D9Ex inherits from IDirect3D9).
In c++ this still works because of inheritance and virtual functions working correctly, in c, it doesn't correctly pick up the inheritance due to the way their v-tables are constructed.
Below I've commented out the line that needs to be added to fix this issue (in d3d9.h at line 2044):
DECLARE_INTERFACE_(IDirect3D9Ex, IDirect3D9)
{
/*** IUnknown methods ***/
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObj) PURE;
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
STDMETHOD_(ULONG,Release)(THIS) PURE;
/*** IDirect3D9 methods ***/
//Add this here: STDMETHOD(RegisterSoftwareDevice)(THIS_ void* pInitializeFunction) PURE;
STDMETHOD_(UINT, GetAdapterCount)(THIS) PURE;
STDMETHOD(GetAdapterIdentifier)(THIS_ UINT Adapter,DWORD Flags,D3DADAPTER_IDENTIFIER9* pIdentifier) PURE;
STDMETHOD_(UINT, GetAdapterModeCount)(THIS_ UINT Adapter,D3DFORMAT Format) PURE;
STDMETHOD(EnumAdapterModes)(THIS_ UINT Adapter,D3DFORMAT Format,UINT Mode,D3DDISPLAYMODE* pMode) PURE;
You can double check that the functions line up correctly with the returned interface by loading the d3d9.dll symbols from the MS servers and comparing the names in the v-table with the values reported. In the image below, the left hand side is the v-table before being fixed, and the right hand side is the v-table after being fixed.
To get the symbol's from the MS symbol servers:
start the application and place a breakpoint after LoadLibrary("d3d9.dll") has been called
open up the 'Modules' window (from the menu bar Debug->Windows->Modules)
Find d3d9.dll in the modules list (try typing d3d9.dll to quickly go to it)
Right-click on d3d9.dll and click on Load Symbols From->Microsoft Symbol Servers
Wait a few seconds for it to download and load the symbols, addresses should then resolve to useful names.

D-Bus how to create and send a Dict?

I have a process which exposes a method to DBus with one of the arguments taking the following type signature a{sv}:
Dict of {String, Variant}
The libDBus documentation for dbus_message_append_args fails to provide adequate reference for this. Some information appears in the specification under container-types, specifically:
A DICT_ENTRY works exactly like a struct, but rather than parentheses
it uses curly braces, and it has more restrictions. The restrictions
are: it occurs only as an array element type; it has exactly two
single complete types inside the curly braces; the first single
complete type (the "key") must be a basic type rather than a container
type. Implementations must not accept dict entries outside of arrays,
must not accept dict entries with zero, one, or more than two fields,
and must not accept dict entries with non-basic-typed keys. A dict
entry is always a key-value pair.
On attempting to append a dict I receive the following error message:
type dict_entry isn't supported yet in dbus_message_append_args_valist
Although I'm actually using dbus_message_append_args(I guess the error message is somewhat off).
There are two other alternatives to dbus_message_append_args() using either:
dbus_message_iter_append_basic()
and
dbus_message_iter_append_fixed_array()
While I can create an empty Dict container with the following:
const char * container_d_sig = "{sv}";
DBusMessageIter iter, sub;
dbus_message_iter_init_append(msg, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, container_d_sig, &sub);
dbus_message_iter_close_container(&iter, &sub);
Neither of the append methods appear to support adding a struct. Not sure what to try here...
First, about D-Bus libraries: you talk about dbus-glib in several places but the functions you refer to are not part of dbus-glib but libdbus. If you are still trying to find the best way to use D-Bus, I suggest you forget both of these: libdbus is very low-level (it's documentation even starts with "If you use this low-level API directly, you're signing up for some pain") and dbus-glib is deprecated. The best D-Bus API currently is GDBus which is part of GLib GIO: it's a far better designed API than either of the other two, well tested and supported.
Now, as for the actual question, documentation for dbus_message_append_args() does say it quite clearly:
To append variable-length basic types, or any more complex value, you
have to use an iterator rather than this function.
In other words you should use dbus_message_iter_open_container() to prepare the iterator until it is pointing to somewhere where you can use dbus_message_iter_append_basic(). Note that in your example the dictionary is a container, the dictionary entry is a container and the variant is a container... In other words it gets pretty complex quite fast. If you really want to do it, look at e.g. Connman code for examples.
As I mentioned, the sane route is GDBus. There creating even much more complex signatures is pretty easy as you can use the GVariantBuilder API:
GVariantBuilder builder;
g_variant_builder_init (&builder, G_VARIANT_TYPE("a{sv}"));
g_variant_builder_add (&builder, "{sv}", "name1", my_variant);
/* Now use the builder results with g_dbus_connection_call()
or g_dbus_proxy_call() */
I know this question was asked awhile ago, but I had a very similar question recently, and after several hours of trial and error this is some code I came up with that works for me. Hopefully it helps someone else...
DBusMessage* testMessage()
{
DBusMessage* mssg = dbus_message_new_signal("/fi/w1/wpa_supplicant1/Interfaces/0", "fi.w1.wpa_supplicant1.Interface", "PropertiesChanged");
DBusMessageIter iter, aIter;
dbus_message_iter_init_append(mssg, &iter);
if (!dbus_message_iter_open_container(&iter, 'a', "{sv}", &aIter))
return nullptr;
DBusMessageIter eIter;
if (!dbus_message_iter_open_container(&aIter, 'e', NULL, &eIter)) {
dbus_message_iter_abandon_container_if_open(&iter, &aIter);
return nullptr;
}
const char* key = "test key";
dbus_message_iter_append_basic(&eIter, 's', static_cast<void*>(&key));
DBusMessageIter vIter;
if (!dbus_message_iter_open_container(&eIter, 'v', "i", &vIter)) {
dbus_message_iter_abandon_container_if_open(&aIter, &eIter);
dbus_message_iter_abandon_container_if_open(&iter, &aIter);
return nullptr;
}
dbus_int32_t val = 42;
dbus_message_iter_append_basic(&vIter, 'i', static_cast<void*>(&val));
dbus_message_iter_close_container(&eIter, &vIter);
dbus_message_iter_close_container(&aIter, &eIter);
dbus_message_iter_close_container(&iter, &aIter);
return mssg;
}
This is C++ but should be pretty easy to adapt for C. The returned message has a signature of a{sv}. The dbus docs are helpful-ish.

Is there a good way to copy a Gtk widget?

Is there a way, using the Gtk library in C, to clone a Gtk button (for instance), and pack it somewhere else in the app. I know you can't pack the same widget twice. And that this code obviously wouldn't work, but shows what happens when I attempt a shallow copy of the button:
GtkButton *a = g_object_new(GTK_TYPE_BUTTON, "label", "o_0", NULL);
GtkButton *b = g_memdup(a, sizeof *a);
gtk_box_pack_start_defaults(GTK_BOX(vbox), GTK_WIDGET(b));
There is surrounding code which creates a vbox and packs it in a window and runs gtk_main(). This will result in these hard to understand error messages:
(main:6044): Gtk-CRITICAL **: gtk_widget_hide: assertion `GTK_IS_WIDGET (widget)' failed
(main:6044): Gtk-CRITICAL **: gtk_widget_realize: assertion `GTK_WIDGET_ANCHORED (widget) || GTK_IS_INVISIBLE (widget)' failed
**
Gtk:ERROR:/build/buildd/gtk+2.0-2.18.3/gtk/gtkwidget.c:8431:gtk_widget_real_map: assertion failed: (GTK_WIDGET_REALIZED (widget))
Along the same lines, if I were to write my own GObject (not necessarily a Gtk widget), is there a good way to write a copy constructor. Im thinking it should be an interface with optional hooks and based mostly on the properties, handling the class's hierarchy in some way.
I'd want to do this:
GtkButton *b = copyable_copy(COPYABLE(a));
If GtkButton could use a theoretical copyable interface.
I don't think so. As far as I know, there's no guarantee that widgets keep all their state in properties, that you can access from the outside. If a widget "hides" state by not exporting it, there's no way you can copy it from the outside.
Technically, widgets can just include fields in their core struct that you don't see from outside of the implementation, so you can't even copy the bits using a dumb memcpy(), unless you're willing to specify the byte-count by counting manually and using a literal.
That being said, it's also quite possible that enough widgets expose enough state through properties that a copy would still function, and perhaps only exhibit minor glitches. It would certainly be a pretty cool hack. I would recommend asking the core GTK+ developers directly, perhaps on the gtk-devel-list mailing list.
A clone throught properties is a viable solution:
GObject *
g_object_clone(GObject *src)
{
GObject *dst;
GParameter *params;
GParamSpec **specs;
guint n, n_specs, n_params;
specs = g_object_class_list_properties(G_OBJECT_GET_CLASS(src), &n_specs);
params = g_new0(GParameter, n_specs);
n_params = 0;
for (n = 0; n < n_specs; ++n)
if (strcmp(specs[n]->name, "parent") &&
(specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE) {
params[n_params].name = g_intern_string(specs[n]->name);
g_value_init(&params[n_params].value, specs[n]->value_type);
g_object_get_property(src, specs[n]->name, &params[n_params].value);
++ n_params;
}
dst = g_object_newv(G_TYPE_FROM_INSTANCE(src), n_params, params);
g_free(specs);
g_free(params);
return dst;
}
Cloning a widget is not that trivial though, but the above approach is usable in most cases (on a GtkButton for sure).
I'd not care that much of states not exposed with properties (all proper widgets should be fully defined by properties to be usable with GtkBuilder) but a lot of corner cases will make a robust cloning quite difficult (interfaces and containers being the first ones that come to my mind).

Does this function IOHIDManagerRegisterDeviceMatchingCallback operate under the cocoa environment?

I am struggling to implement an HID control with a Mac : I cannot send the expected function as depicted here below:
IOHIDManagerRegisterDeviceMatchingCallback( gIOHIDManagerRef, Handle_DeviceMatchingCallback, NULL );
with : gIOHIDManagerRef -> the valid HID manager dedicated to this routine
Handle_DeviceMatchingCallback --> the routine that will be called back when the HID
device is attached to the USB port
NUUL --> not used here, contain data from the USB
The issue is that Handle_DeviceMatchingCallback must be a pointer to the routine, but how can I send a pointer ?
On the other hand, all the examples , from the Apple source, are based on C, not on cocoa.
Well, does that means that I must rework my program in C ??? Or is it possible to have fraction of the program in C under the cocoa environment?
Sorry for so "stupid" question queries, but, although I have some background in the field of electronic an programming, I am very newbees with cocoa.
Your comments will be very appreciated !
Michael
Objective-C is mostly a super-set of C. In order to combine C and Objective-C code, you simply compile your C code as if it were Objective-C code. The easiest way to do this in Xcode is to ensure the file in question has a .m extension.
To route handling back to the Objective-C world, you need a pointer to an Obj-C object. Many callback-based APIs allow you to provide a generic pointer (void *) that they then pass back to you when they callback. This argument has several common names:
context or ctx
refcon (for "reference constant")
userData
userInfo
If the callback API does not allow this, you'll need some uglier way to dispatch the callback to your object, such as a global pointer or a lookup table.
The API you're using does let you provide a context pointer. When it calls back to your code, it provides you with the pointer you used when you registered for the callback. Here is an example of registering the callback from an object of type MyObjCClass (see the -registerMatching method below) and then using the context pointer to route the callback back to the object that registered the callback for handling (see the Handle_DeviceMatchingCallback function's use of the context pointer).
/*! #file C-ObjC-Callbacks.m
* Demonstrates routing a C callback to an Obj-C object
* using the callback's context pointer.
*/
#import <Cocoa/Cocoa.h>
#import <IOKit/hid/IOHIDManager.h>
// Global HID manager reference.
IOHIDManagerRef gIOHIDManager;
// HID callback
void Handle_DeviceMatchingCallback(void *context,
IOReturn result,
void *sender,
IOHIDDeviceRef device);
#interface MyObjCClass : NSObject {
}
- (void)registerMatching;
- (void)handleMatchingDevice:(IOHIDDeviceRef)device
sender:(void *)sender
result:(IOReturn)result;
#end
#implementation MyObjCClass
- (void)registerMatching {
// Assume gIOHIDManager has already been created.
// Set up a device matching callback, providing a pointer to |self| as the context.
IOHIDManagerRegisterDeviceMatchingCallback(gIOHIDManager,
Handle_DeviceMatchingCallback,
(void *)self);
}
- (void)handleMatchingDevice:(IOHIDDeviceRef)device
sender:(void *)sender
result:(IOReturn)result {
// Do something...
}
#end
void
Handle_DeviceMatchingCallback(void *context,
IOReturn result,
void *sender,
IOHIDDeviceRef device); {
MyObjCClass *const myObject = (MyObjCClass *const)context;
[myObject handleMatchingDevice:device sender:sender result:result];
}
Handle_DeviceMatchingCallback must be a pointer to the routine, but how
can I send a pointer ?
If you want to pass in a function functionName, you can pass it as
&functionName.
On the other hand, all the examples , from the Apple source, are based on
C, not on cocoa. Well, does that means that I must rework my program in C
??? Or is it possible to have fraction of the program in C under the cocoa
environment?
You can mix C and Objective-C at will. As long as you pass it a function,
and not a method attached to an object, it should work.

Resources