Sorry for my english. I am writing in C language simple editor.
I can not understand how to implement autocompletion words using GtkSourceCompletion.
static void set_completion(Page *page)
{
GtkSourceCompletionWords *words = gtk_source_completion_words_new("words_current_page", NULL);
gtk_source_completion_words_register(words, GTK_TEXT_BUFFER(page->buffer));
GtkSourceCompletion *comp = gtk_source_view_get_completion(GTK_SOURCE_VIEW(page->text_edit));
GtkSourceCompletionContext *context = gtk_source_completion_create_context(comp, NULL);
GtkSourceCompletionProvider *provider;
gtk_source_completion_add_provider(comp, provider, NULL);
}
I try, but all very confusing.
Please tell me how to do it.
Some explainations:
You need to consider the GtkSourceCompletionWords as a GtkSourceCompletionProvider, with the macro GTK_SOURCE_COMPLETION_PROVIDER(words) and add it as a provider for the completion:
GtkSourceCompletion *comp = gtk_source_view_get_completion(GTK_SOURCE_VIEW(page->text_edit));
gtk_source_completion_add_provider(comp,GTK_SOURCE_COMPLETION_PROVIDER(words),NULL);
Before to add it as provider, the GtkSourceCompletionWords needs to be registered with the buffer of the GtkSourceView:
GtkSourceCompletionWords *words = gtk_source_completion_words_new("wds_current_page", NULL);
gtk_source_completion_words_register(words, GTK_TEXT_BUFFER(page->buffer));
You can get the buffer with:
GtkTextBuffer * buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(page->text_edit));
You also can create the buffer independently and pass it as argument for the creation of the GtkSourceView:
GtkSourceBuffer * sBuf = gtk_source_buffer_new(NULL);
GtkWidget * sview = gtk_source_view_new_with_buffer(sBuf);
Try this code:
static void set_completion(Page *page)
{
GtkSourceCompletionWords *words = gtk_source_completion_words_new("words_current_page", NULL);
gtk_source_completion_words_register(words, GTK_TEXT_BUFFER(page->buffer));
GtkSourceCompletion *comp = gtk_source_view_get_completion(GTK_SOURCE_VIEW(page->text_edit));
gtk_source_completion_add_provider(comp, GTK_SOURCE_COMPLETION_PROVIDER(words), NULL);
}
Related
I'm a beginner at Tcl C API and I'm trying to understand how to use it. I have this code that gets a tcl list from get_my_list proc and then I iterate over it to dispatch some info, in this case, info related to attributes A, B and C that I get with get_attr_info proc. When I run it in a very simple example that basically has only this code, everything works perfectly, but when I add this lib in a big tcl project, eventually it crashes. I suspect that it's due to bad usage of reference counting of tcl objects, I mean, their lifetimes. What could I be doing wrong in the example below? I'm using Tcl 8.6.
Tcl_Obj* Get_Info(Tcl_Interp *interp, const char* info, const char* attr) {
char cmd[256];
sprintf(cmd, "get_attr_info %s %s", info, attr);
Tcl_Eval(interp, cmd);
return Tcl_GetObjResult(interp);
}
static int Copy_Info(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
Tcl_Eval(interp, "get_my_list");
Tcl_Obj *const my_list = Tcl_GetObjResult(interp);
int my_list_size;
Tcl_ListObjLength(interp, my_list, &my_list_size);
Tcl_IncrRefCount(my_list);
for (int i = 0; i < my_list_size; ++i) {
Tcl_Obj* current_info_obj;
Tcl_ListObjIndex(interp, my_list, i, ¤t_info_obj);
const char* current_info_ctr = Tcl_GetStringFromObj(current_info_obj, NULL);
/* getting info A */
Tcl_Obj* info_a_obj = Get_Info(current_info_ctr, "A");
const char* info_a = Tcl_GetStringFromObj(info_a_obj, NULL);
Copy_Info_A(info_a);
/* getting info B */
Tcl_Obj* info_b_obj = Get_Info(current_info_ctr, "B");
const char* info_b = Tcl_GetStringFromObj(info_b_obj, NULL);
Copy_Info_B(info_b);
/* getting info C */
Tcl_Obj* info_c_obj = Get_Info(current_info_ctr, "C");
const char* info_c = Tcl_GetStringFromObj(info_c_obj, NULL);
Copy_Info_C(info_c);
}
Tcl_DecrRefCount(my_list);
Tcl_FreeResult(interp);
return TCL_OK;
}
The tricky bit is that you call Tcl_Eval() inside Get_Info(), which can do all sorts of things with reference count management of values that you're not holding your own reference to, including shimmering away the list representation of the value you're holding a reference to in my_list, which can pull the rug out from under its elements. In particular, the object referred to in current_info_obj must have its reference count incremented from after the Tcl_ListObjIndex() to the end of the loop body.
// ...
for (int i = 0; i < my_list_size; ++i) {
Tcl_Obj* current_info_obj;
Tcl_ListObjIndex(interp, my_list, i, ¤t_info_obj);
// HOLD THE REFERENCE; IT OWNS THE current_info_ctr STRING FOR US
Tcl_IncrRefCount(current_info_obj);
const char* current_info_ctr = Tcl_GetStringFromObj(current_info_obj, NULL);
/* getting info A */
Tcl_Obj* info_a_obj = Get_Info(current_info_ctr, "A");
const char* info_a = Tcl_GetStringFromObj(info_a_obj, NULL);
Copy_Info_A(info_a);
/* getting info B */
Tcl_Obj* info_b_obj = Get_Info(current_info_ctr, "B");
const char* info_b = Tcl_GetStringFromObj(info_b_obj, NULL);
Copy_Info_B(info_b);
/* getting info C */
Tcl_Obj* info_c_obj = Get_Info(current_info_ctr, "C");
const char* info_c = Tcl_GetStringFromObj(info_c_obj, NULL);
Copy_Info_C(info_c);
// RELEASE THE REFERENCE
Tcl_DecrRefCount(current_info_obj);
}
// ...
Improving your code
You can also do a short-cut, and use Tcl_GetString(objPtr) in place of Tcl_GetStringFromObj(objPtr, NULL). You might put that inside Get_Info. You probably also ought to consider switching to using Tcl_EvalObjv(), as that's a faster API (it avoids a level of parsing), though a more complex one to use.
const char *Get_Info(Tcl_Interp *interp, Tcl_Obj* info, const char* attr) {
Tcl_Obj *argv[3], *result;
argv[0] = Tcl_NewStringObj("get_attr_info", -1); // cacheable
argv[1] = info;
argv[2] = Tcl_NewStringObj(attr, -1);
Tcl_IncrRefCount(argv[0]);
Tcl_IncrRefCount(argv[1]);
Tcl_IncrRefCount(argv[2]);
// It's very bad form to omit error handling
if (Tcl_EvalObjv(interp, 3, argv, 0) != TCL_OK) {
Tcl_Panic("problem: %s", Tcl_GetString(Tcl_GetObjResult(interp)));
}
result = Tcl_GetObjResult(interp);
Tcl_DecrRefCount(argv[0]);
Tcl_DecrRefCount(argv[1]);
Tcl_DecrRefCount(argv[2]);
return Tcl_GetString(result);
}
There are cases where it's possible to reduce the amount of reference count handling. Don't worry about doing that to start with! Better to definitely avoid crashes!
Tcl_EvalObjv is (effectively) what Tcl_Eval calls to actually dispatch a command after parsing in interactive mode, and it's what the bytecode engine calls to evaluate any non-inlined command. It's much more efficient than parsing a string into words.
Could anyone help me? I have programming skills in C and I'm trying to program gui's using gtk. I wish, from firing an action (a callback function) from a widget (eg a button), I can change any condition or characteristic belonging to any other widget. Ie something like allow full visibility from within the callback function as if all variables in all gui widgets (say a single main application window) were global. How can I address the closest way to accomplish this? So far, the steps I tried to discover underlying concepts in programming with gtk were frustrating me, when I try to make something more complex than simple Hello World tutorial.I also tried using:
/* out of main */
struct data_widgets
{
struct data_widgets * myp;
gchar **loc ; // LOCAL name
gchar **rem ; // REMOTE name
gchar **pmte ; // Plain message to encrypt filename
gchar **lem ; // Local encrypted message filename
gchar **emr ; // Encrypted message received filename
gchar **pmr ; // Plain message received filename
gchar **lopk ; // Local owner public key filename
gchar **crpk ; // Current remote public key filename
};
int main(int argc, char *argv[])
{
gchar loc_str[100] = "*"; /* LOCAL name for filechoose filter */
gchar rem_str[100] = "*"; /* REMOTE name idem */
gchar pmte_str[100]= "plainmsgtoencrypt"; /* Plain message to encrypt filename */
gchar lem_str[100] = "localencmsg"; /* Local encrypted message filename */
gchar emr_str[100] = "encmsgreceiv"; /* Encrypted message received filename */
gchar pmr_str[100] = "plainreceiv"; /* Plain message received filename */
gchar lopk_str[100]= "locownpubkey"; /* Local owner public key filename */
gchar crpk_str[100]= "remotpubkey"; /* Current remote public key filename */
struct data_widgets mydata;
mydata.loc = &loc_str;
mydata.rem = &rem_str;
mydata.pmte = &pmte_str;
mydata.lem = &lem_str;
mydata.emr = &emr_str;
mydata.pmr = &pmr_str;
mydata.lopk = &lopk_str;
mydata.crpk = &crpk_str;
mydata.myp = &mydata;
/* in main */
....
/* in my callback */
struct data_widgets *pp = (struct data_widgets *) data;
/*passing gpointer data as &mydata.myp, and doing (*pp)->(any pointer) this try fail*/
From what I understood you want to access widgets from within the callback without having to carry around a bunch of globals. You have some option.
You can pack data and widgets inside a single struct and pass it as user_data to the callback.
struct snapshot {
struct data_widgets data;
GtkWidget *entry;
GtkWidget *box;
GtkWidget *label;
GtkWidget *whatever;
};
/* Now fill and use the above struct as user_data */
The GtkWidget fields should be initialized in the code you use to create the UI stuff.
You can also set a name for each relevant widget with gtk_widget_set_name() (Glade automatically sets a name on every element). Once you need a widget, just get it with gtk_widget_get_name().
static void a_callback(GtkWidget *widget, gpointer user_data)
GtkWidget *an_entry = NULL;
GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
if (gtk_widget_is_toplevel(toplevel))
an_entry = gtk_widget_get_name(toplevel, "name of the entry");
g_return_if_fail(an_entry != NULL);
/* ... do something with an_entry ... */
}
You can also traverse the widget hierarchy as if it was a DOM or directly bind your data to the widgets with g_object_set_data() or any valid mixture of the above.
Addendum
With g_object_set_data() you can attach arbitrary data to any GObject instance, e.g.:
gchar *text;
/* Bind some data to widget */
g_object_set_data(G_OBJECT(widget), "pmte", "plainmsgtoencrypt");
g_object_set_data(G_OBJECT(widget), "lem", "localencmsg");
text = g_object_get_data(G_OBJECT(widget), "pmte");
g_print("%s\n", text); /* Print "plainmsgtoencrypt" */
g_free(text);
text = g_object_get_data(G_OBJECT(widget), "lme");
g_print("%s\n", text); /* Print "localencmsg" */
g_free(text);
Code cleanup
Your code is messy in many ways: I suggest you forget what you learnt for C and restart from zero. Your data has one level of indirection more than what it is needed, myp is bogus, you are specifying size of arrays and initializing it.
Answering your comment: the following code is self-contained and does not throw the error you see.
#include <gtk/gtk.h>
struct data_widgets {
gchar **crpk;
};
void callback(GtkWidget *widget, gpointer user_data) {
struct data_widgets *data = user_data;
g_print("%s\n", data->crpk); /* Prints remotpubkey */
}
int main(int argc, char *argv[]) {
gchar crpk_str[100] = "remotpubkey";
struct data_widgets mydata;
mydata.crpk = &crpk_str;
callback(NULL, &mydata);
return 0;
}
The same code, cleaned up in a sane way:
#include <gtk/gtk.h>
typedef struct {
gchar *crpk;
} data_t;
void callback(GtkWidget *widget, gpointer user_data) {
data_t *data = user_data;
g_print("%s\n", data->crpk); /* Prints remotpubkey */
}
int main() {
data_t mydata;
mydata.crpk = "remotpubkey";
callback(NULL, &mydata);
return 0;
}
I am trying to create a flume-thrift client in c (c_glib) but have trouble creating the gobject that shall be sent to the server. I get the following error at the line in main.c:
`GLib-GObject-WARNING **: IA__g_object_new_valist: object class `ThriftFlumeEventType' has no property named `timestamp'`
The code in flume_types.h and flume_types.c is autogenerated from thrift. Tell me if you need to see more code. I am thankful for all the help I can get!
Parts of the code in flume_types.h:
struct _ThriftFlumeEvent
{
ThriftStruct parent;
/* public */
gint64 timestamp;
gboolean __isset_timestamp;
Priority priority;
gboolean __isset_priority;
GByteArray * body;
gboolean __isset_body;
gint64 nanos;
gboolean __isset_nanos;
gchar * host;
gboolean __isset_host;
GHashTable * fields;
gboolean __isset_fields;
};
typedef struct _ThriftFlumeEvent ThriftFlumeEvent;
GType thrift_flume_event_get_type (void);
#define TYPE_THRIFT_FLUME_EVENT (thrift_flume_event_get_type())
Parts of the code in flume_types.c:
void
thrift_flume_event_instance_init (ThriftFlumeEvent * object)
{
printf("thrift_flume_event_instance_init");
/* satisfy -Wall */
THRIFT_UNUSED_VAR (object);
object->timestamp = 0;
object->__isset_timestamp = FALSE;
object->__isset_priority = FALSE;
object->body = NULL;
object->__isset_body = FALSE;
object->nanos = 0;
object->__isset_nanos = FALSE;
object->host = NULL;
object->__isset_host = FALSE;
object->fields = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
object->__isset_fields = FALSE;
}
GType
thrift_flume_event_get_type (void)
{
static GType type = 0;
if (type == 0)
{
static const GTypeInfo type_info =
{
sizeof (ThriftFlumeEventClass),
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) thrift_flume_event_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (ThriftFlumeEvent),
0, /* n_preallocs */
(GInstanceInitFunc) thrift_flume_event_instance_init,
NULL, /* value_table */
};
type = g_type_register_static (THRIFT_TYPE_STRUCT,
"ThriftFlumeEventType",
&type_info, 0);
type.timestamp;
}
return type;
}
Parts of the code in main.c:
gpointer eventObj = g_object_new(TYPE_THRIFT_FLUME_EVENT,
"timestamp", 0,
"__isset_timestamp", 0,
"priority", 0,
"__isset_priority", 0,
"body", 0,
"__isset_body", 0,
"nanos", 0,
"__isset_nanos", 0,
"fields", 0,
"__isset_fields", 0,
0);
This is changing in Thrift 0.9.2: Objects generated by the C (GLib) compiler to represent Thrift structs will now expose their members as GObject properties, obviating the risky (and poor) practice of modifying an object's instance structure directly.
Starting with 0.9.2 the preferred way to initialize a struct object will be essentially what the poster originally expected:
ThriftFlumeEvent *event =
g_object_new (TYPE_THRIFT_FLUME_EVENT,
"timestamp", (gint64)t_stamp.tv_sec * 1000,
"priority", priority,
...
NULL);
Note the __isset_ fields are managed by the object itself and should not be set directly.
This was the solution to the problem:
ThriftFlumeEvent *event = g_object_new(TYPE_THRIFT_FLUME_EVENT, 0);
event->timestamp = (gint64)t_stamp.tv_sec * 1000;
event->__isset_timestamp = TRUE;
event->priority = priority;
event->__isset_priority = TRUE;
...
GObject properties are NOT C struct members. You need to install them via g_object_install_property in your class init function https://developer.gnome.org/gobject/stable/gobject-The-Base-Object-Type.html . You also need to derive object from GObject (or from any struct that is derived from a GObject).
Note: derived in C means, that it has to have the parent as its first member so it can be cast seamlessly (NOT a pointer to a GObject!)
You should read a book on the topic, it can get quite complex.
I'm developing an application that records audio files with GStreamer.
One feature of this app is to display a GTK dialog with a label
that contains information about the file recording process (name, type and size).
code:
static int timeout_id = -1;
static GtkWidget *file_label, *type_label, *size_label;
static gboolean timeout_cb(gpointer data)
{
GFile *session_file;
GFileInfo *info;
session_file = g_file_new_for_path (path);
info = g_file_query_info (session_file,
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
G_FILE_ATTRIBUTE_STANDARD_SIZE,
G_FILE_QUERY_INFO_NONE,
NULL,
NULL);
if (info != NULL) {
/* name */
const gchar *display_name = g_file_info_get_attribute_string (info,
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
gtk_label_set_text (GTK_LABEL (file_label), display_name);
/* type */
const gchar *type = g_file_info_get_attribute_string (info,
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
gtk_label_set_text (GTK_LABEL (type_label), type);
/* size */
guint64 size = g_file_info_get_attribute_uint64 (info,
G_FILE_ATTRIBUTE_STANDARD_SIZE);
gchar *tmp = g_format_size_full (size, G_FORMAT_SIZE_LONG_FORMAT);
gtk_label_set_text (GTK_LABEL (size_label), tmp);
g_free (tmp);
g_object_unref (info);
}
g_object_unref (file);
return TRUE;
}
void run_status_window(Record *record)
{
timeout_id = g_timeout_add(500, (GSourceFunc) timeout_cb, record);
}
I'm use queries for file information and attributes and calling this at 500 ms intervals.
My question is how can optimise this feature because the name and type aren't likely to change during the recording process.
Thanks
I'm currently building a program which needs to interface with the d-bus. I'm using the glib dbus library. I have a method that returns a dbus dictionary type, like this:
array [
dict entry(
string "Metadata"
variant array [
dict entry(
string "mpris:artUrl"
variant string "http://open.spotify.com/thumb/05e9ad92c22953e6c778536613605b67faa5a095"
)
dict entry(
string "mpris:length"
variant uint64 238000000
)
My question is, how on earth do I get this in my C program? I've tried the usual `dbus_g_proxy_connect_signal´ with a registered marshaller without much luck!
Edit: I've added some sample code (Which is not working, but does compile)
#include <string.h>
#include <glib.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
#define DBUS_SERVICE "com.spotify.qt"
#define DBUS_PATH "/"
#define DBUS_INTERFACE "org.freedesktop.MediaPlayer2"
#define DBUS_TYPE_G_STRING_VALUE_HASHTABLE (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
//Global bus connection
DBusGConnection *bus;
DBusGProxy *proxy;
//Main gloop
GMainLoop *loop = NULL;
//Callback function.
static void callbackfunc(DBusGProxy *player_proxy, GHashTable *table){
GValue *value;
/* fetch values from hash table */
value = (GValue *) g_hash_table_lookup(table, "artist");
if (value != NULL && G_VALUE_HOLDS_STRING(value)) {
g_print("\nArtist: %s\n",g_value_get_string(value));
}
value = (GValue *) g_hash_table_lookup(table, "album");
if (value != NULL && G_VALUE_HOLDS_STRING(value)) {
g_print("\nAlbum: %s\n",g_value_get_string(value));
}
value = (GValue *) g_hash_table_lookup(table, "title");
if (value != NULL && G_VALUE_HOLDS_STRING(value)) {
g_print("\nTitle: %s\n",g_value_get_string(value));
}
}
int main (int argc, char **argv){
GError *error = NULL;
g_type_init ();
/* Get (on) the bus :p */
bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
if (bus == NULL) {
g_printerr("Failed to open connection to bus: %s", error->message);
g_error_free(error);
return -1;
}
/* Create a proxy object for the bus driver */
proxy = dbus_g_proxy_new_for_name (bus,
DBUS_SERVICE,
DBUS_PATH,
DBUS_INTERFACE);
if (!proxy) {
g_printerr("Couldn't connect: %s", error->message);
g_error_free(error);
return -1;
}
/* Create the main loop instance */
loop = g_main_loop_new (NULL, FALSE);
dbus_g_proxy_add_signal(proxy, "GetMetadata",
DBUS_TYPE_G_STRING_VALUE_HASHTABLE, G_TYPE_INVALID);
dbus_g_proxy_connect_signal(proxy, "GetMetadata",
G_CALLBACK(callbackfunc), NULL, NULL);
g_print("Going into main function\n");
/* Main loop */
g_main_loop_run (loop);
return 0;
}
I'm going to port my code to use GIO rather than glib-dbus, I did how ever manage to get it working with glib-dbus using this:
if (dbus_g_proxy_call(p_proxy_md, "GetMetadata", NULL, G_TYPE_INVALID, DBUS_TYPE_G_STRING_VALUE_HASHTABLE, &table, G_TYPE_INVALID)) {
value = (GValue *) g_hash_table_lookup(table, "xesam:title");
sprintf(currentTrack.trackname,"%s",g_value_get_string(value));
value = (GValue *) g_hash_table_lookup(table, "xesam:album");
sprintf(currentTrack.album,"%s",g_value_get_string(value));
tmp = g_hash_table_lookup(table, "xesam:artist");
if (tmp != NULL)
{
GStrv strv = g_value_get_boxed(g_hash_table_lookup(table, "xesam:artist"));
sprintf(currentTrack.artist,"%s",*strv);
}
}
sprintf(notifybody,"By %s on %s",currentTrack.artist,currentTrack.album);
music_noti = notify_notification_new(currentTrack.trackname,notifybody, NULL);
notify_notification_set_timeout(music_noti,1500);
notify_notification_set_icon_from_pixbuf(music_noti, notifyicon);
notify_notification_show(music_noti, NULL);
notify_uninit();
}
Without using GLIB or any external library, the best way I've found is outlined in this post.
It requires knowing the structure of the datatype ahead of time, which is a bit annoying. However, you can use dbus-monitor to see what DBUS is sending first. Then you have to make an iterator for each level of the array. See the DBUS message documentation for how to use the iterators.