Is there a good way to copy a Gtk widget? - c

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).

Related

Release a pointer to a Direct2D Factory COM object in C [d2d1.h]

The problem
I am following a guide from the Microsoft Documentation and the examples there are given in C++. I could've just used the default samples in C++, but I wanted to further understand how the API works so I decided to rewrite the default C++ sample in C.
The problem I encountered is that I can easily call D2D1CreateFactory and create an ID2D1Factory, though when I was previously reading the documentation, it was stated that you have to always release the COM object after you've used it and don't need it anymore. The fact is that in C++ there's an inherited method Release from IUnknown. In C though there's no even a lpVtbl, which as far as I understand is usually needed for that purpose. The ID2D1Factory is just provided as a typedef and is an incomplete type.
And now I'm stuck, because I don't know how to release pointer. I've spent a couple of hours searching for ways to do that in C.
Is it even possible?
The header file: d2d1.h
The Code
Window Procedure simplified:
switch (uMessage)
{
case WM_CREATE:
{
HRESULT hResult = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &IID_ID2D1Factory, NULL, &pFactory);
if (FAILED(hResult))
{
return -1;
}
return 0;
}
...
}
Obviously pFactory is of an ID2D1Factory* type in global scope. It is zero-initialized by default (if that helps).

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.

Gtk signal with multiple arguments

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.

Create widget array using Qt Designer?

In Qt Designer I'm creating multiple labels (for instance):
my_label1
my_label2
my_label3
...
my_label n
Then if I want to hide them I do this:
ui->my_label1->hide();
ui->my_label2->hide();
ui->my_label3->hide();
...
ui->my_labeln->hide();
However I would like to define the labels like
my_label[n]
So then I would be able to do this:
for(i=0;i<n;i++)
{
ui->my_label[n]->hide();
}
I read that I can define the widget like:
QLabel* my_label[5];
but is there any way to do the same from Qt Designer?
Thanks in advance!
Finally I decided to do direct assignment:
QLabel* my_label_array[5];
my_label_array[0] = ui->my_label1;
my_label_array[1] = ui->my_label2;
my_label_array[2] = ui->my_label3;
my_label_array[3] = ui->my_label4;
my_label_array[4] = ui->my_label5;
Then I can do for instance:
for(idx=0;idx<6;idx++) my_label_array[idx]->show();
for(idx=0;idx<6;idx++) my_label_array[idx]->hide();
for(idx=0;idx<6;idx++) my_label_array[idx]->setEnabled(1);
for(idx=0;idx<6;idx++) my_label_array[idx]->setDisabled(1);
etc...
Then I was able to perform iterations. I believe is not the cleanest way to do it but given my basic knowledge of Qt is ok for me.
Thank you very much for your answers and your support! This is a great site with great people.
Instead of creating an explicit array, you may be able to name your widgets using a particular scheme and then use QObject::findChildren() on the parent widget to get a list of the widgets you are after.
If you only want to hide widgets, you can put all the widgets you want to hide in an invisible QFrame (set frameShape to NoFrame) and hide them all by calling setVisible(false) on the QFrame. This may cause some unwanted side effects with layouts so you may have to tweak some size policy settings.
In case you are wanting to hide controls so that you can simulate a wizard type UI, you may want to check into QStackedWidget.
I have another dirty workaround for this:
in header file
// .hpp
class UiBlabla : public QWidget {
...
QLabel** labels;
};
in source file
// constructor
ui->setupUi(this);
labels = new QLabel*[10]{ui->label_0, ui->label_1, ui->label_2, ui->label_3,
ui->label_4, ui->label_5, ui->label_6,
ui->label_7, ui->label_8, ui->label_9};
I haven't seen anything in QtDesigner to do that, but there are a couple of relatively easy ways to get that behavior.
1) Simply store the my_labelx pointers (from QtDesigner) in an array (or better, a QVector):
QVector<QLabel*> my_labels;
my_labels.push_back(ui->my_label1);
my_labels.push_back(ui->my_label2);
Then you can iterate through the QVector.
for(int i=0; i < my_labels.size(); ++i) {
my_labels[i]-> hide();
}
// or with QFOREACH
foreach(QLabel* label, my_labels)
label->hide();
There is a little setup needed in terms of adding all the labels to the QVector, but on the plus side you only do that once.
2) Depending on the layout of your gui, you could have all your labels be children of a container object and iterate through the children

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