How can I, using GtkClipboard, read and write to a clipboard? As an example, please show me how to get the current clipboard content and print it to console.
I tried this to get and print what is currently in the clipboard, but it doesn't work:
GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
gtk_clipboard_request_text(clip, (GtkClipboardTextReceivedFunc)print_clip, NULL);
Everything compiles without any warnings, but print_clip() function is never reached. Maybe I should use another function, like gtk_clipboard_wait_for_text()? Please help me, what am I supposed to do?
I use Linux/X11, if it matters. Also, I use GTK+3, not GTK+2 or some other release.
Ok, I've got a working example:
#include <gtk/gtk.h>
void clipboard_callback(GtkClipboard *clip, const gchar *text, gpointer data)
{
g_print("Now we're in clipboard_callback function.\n");
gtk_main_quit();
}
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
gtk_clipboard_request_text(clip, clipboard_callback, NULL);
gtk_main();
return 0;
}
The only thing that I need now is to somehow exit clipboard_callback() without calling gtk_main_quit(), since that closes an application.
One should really use gtk_clipboard_wait_for_text() instead of gtk_clipboard_request_text().
For example, this is how it should be done:
GtkClipboard *clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
gchar *text = gtk_clipboard_wait_for_text(clip);
You can use below code from this link.
#include <gdk/gdk.h>
#include <gtk/gtk.h>
// This callback is invoked when the clipboard contents have been
// received. The text contents of the clipboard will be in UTF-8 in
// the `text` parameter.
void text_request_callback(GtkClipboard *clipboard,
const gchar *text,
gpointer data)
{
// To demonstrate setting a new value into the clipboard, we
// choose some text.
const gchar* new_clipboard_text = "Clipboard test 1";
if(text == 0 || g_utf8_collate(text, new_clipboard_text) == 0)
{
// If the program was already run, and the clipboard contains
// our string already, use a different string. This way when
// you run the program multiple times in a row, you'll see the
// string changing.
new_clipboard_text = "Clipboard test 2";
}
// This sets the text. I'm passing -1 because I'm lazy -- the
// function will call strlen on the string to figure out how long
// it is.
gtk_clipboard_set_text(clipboard, new_clipboard_text, -1);
// Display the content and the contents of the variable we passed
// in.
printf("Clipboard text was %s, value is %8X\n",
text, *(int*)data);
// Now that we've monkeyed with the clipboard, our job is done
// here.
gtk_main_quit();
}
int main(int argc, char** argv)
{
// Standard boilerplate: initialize the toolkit.
gtk_init(&argc, &argv);
// Get a handle to the given clipboard. You can also ask for
// GDK_SELECTION_PRIMARY (the X "primary selection") or
// GDK_SELECTION_SECONDARY.
GtkClipboard* clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
// This is just an arbitrary value to pass through to the
// callback. You could pass a pointer to a local struct or
// something similar if that was useful to you.
int value = 0xDECAFBAD;
// There are more complex things you can place in the clipboard,
// but this demonstrates text. The callback will be invoked when
// the clipboard contents has been received.
//
// For a much simpler method of getting the text in the clipboard,
// see gtk_clipboard_wait_for_text(), which is used in the example
// program clipboard_watch.
gtk_clipboard_request_text(clipboard, text_request_callback, &value);
// We have to run the GTK main loop so that the events required to
// fetch the clipboard contents can be processed.
gtk_main();
return 0;
}
Related
I am trying to create a GUI program using Glade and GTK+ 3 to write set and write configuration data to a custom microchip. I am trying to implement a feature to save/load previous configurations into my GUI. After saving to a file and loading, some of my callback functions now cause a segfault. One example being a callback for a "global enable" checkbox.
I am currently trying to read data from my file and using that data to update the state of the GUI (as well as global variables used for configuring the IC). I update my checkbox as follows:
/* Global widget handles */
GtkWidget* GEN_CB_h;
GtkWidget* Neg_Pol_CB_h;
GtkWidget* Save_File_Name_Box_h;
GtkWidget* Save_File_Button_h:
GtkWidget* Load_File_Button_h;
//more widgets here
/* Global configuration variables */
char gen;
char neg_pol;
//more variables here
/* Write data to a configuration file. */
void on_Save_Config_Button_clicked()
{
GtkEntry* save_file = GTK_ENTRY(Save_File_Box_h);
const gchar* filename = gtk_entry_get_text(save_file);
FILE* fd = fopen((const char*)filename, "w");
if(!fd)
{
perror("Failed to open file\n");
exit(EXIT_FAILURE);
}
fwrite(&gen, sizeof(gen), 1, fd);
fwrite(&neg_pol, sizeof(neg_pol), 1, fd);
//more variables written here
fclose(fd);
g_printf("File saved to: %s\n", filename);
}
/* Load data from a stored configuration file */
void on_Load_File_Button_selection_changed()
{
GtkFileChooser* file = GTK_FILE_CHOOSER(Load_File_Box_h);
gchar* filename = gtk_file_chooser_get_filename(file);
FILE* fd = fopen((const char*)filename, "r");
if(!fd)
{
perror("Failed to open file\n");
exit(EXIT_FAILURE);
}
fread(&gen, sizeof(gen), 1, fd);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(GEN_CB_h), gen);
fread(&neg_pol, sizeof(neg_pol), 1, fd);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(neg_pol_cb), neg_pol);
/* read more data and update more GUI elements here */
}
/* Callback for negative polarity bit checkbox */
void on_Neg_Pol_CB_toggled()
{
GtkToggleButton* neg_pol_cb = GTK_TOGGLE_BUTTON(Neg_Pol_CB_h);
neg_pol = (char)gtk_toggle_button_get_active(neg_pol_cb);
printf("Neg pol toggled: %s\n", (neg_pol) ? "ON":"OFF");
}
/* Callback for global enable bit checkbox */
void on_GEN_CB_toggled()
{
printf("gen_cb = %p\n", GEN_CB_h); //print before cast for debugging
GtkToggleButton* gen_cb = GTK_TOGGLE_BUTTON(GEN_CB_h);
gen = (char)gtk_toggle_button_get_active(gen_cb);
printf("GEN toggled: %s\n", (gen) ? "ON":"OFF");
}
int main(int argc, char *argv[])
{
GtkBuilder *builder;
GtkWidget *window;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
gtk_builder_add_from_file (builder, "CFD.glade", NULL);
window = GTK_WIDGET(gtk_builder_get_object(builder, "window_main"));
GEN_CB_h = GTK_WIDGET(gtk_builder_get_object(builder, "GEN_CB"));
Neg_Pol_CB_h = GTK_WIDGET(gtk_builder_get_object(builder, "Neg_Pol_CB"));
Save_File_Box_h = GTK_WIDGET(gtk_builder_get_object(builder, "Save_File_Name_Box"));
Load_File_Box_h = GTK_WIDGET(gtk_builder_get_object(builder, "Load_File_Button"));
Save_File_Button_h = GTK_WIDGET(gtk_builder_get_object(builder, "Save_Config_Button"));
//create more widgets here
gen = 1;
neg_pol = 0; //positive polarity
//set more variables here
gtk_builder_connect_signals(builder, NULL);
printf("connect returned\n");
g_object_unref(builder);
printf("unref returned\n");
gtk_widget_show(window);
printf("show returned\n");
gtk_main();
return 0;
}
The issue I am having is that after loading a new configuration (i.e. triggering my Load_File_Button callback) my GEN_CB callback triggers a segfault on this line:
GtkToggleButton* gen_cb = GTK_TOGGLE_BUTTON(GEN_CB_h);
I used GDB to see what the cause of the segfault was and it reported it as:
Thread 1 "cfd_gui" received signal SIGSEGV, Segmentation fault.
0x00007ffff7395ea0 in g_type_check_instance_cast () from /usr/lib/libgobject-2.0.so.0
I also included a printf statement to check and see if anything was happening to the pointer between loads and found that the pointer value is being modified after this line is executed:
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(GEN_CB_h), gen);
I am still new to GTK3 so I am probably using something wrong but have not been able to figure it out. Here are the outputs of my printf debug statements:
gen_cb = 0x55cd1aa04240
GEN toggled: OFF
Loaded configuration from file: /home/borabutt/github/CFD-RPI-Test/src/C/gui/test.dat
gen_cb = 0x55ea7bb68240
The first line shows the pointer to GEN_CB_h before configuration data is loaded. Then as can clearly be seen, the pointer value is changed after the configuration data is loaded. My investigations have shown this change occurs after setting the state of the checkbox as shown above.
I need to be able to update the state of many checkboxes and combo boxes to properly reflect the loaded state from the file. Right now the GUI works completely fine until I load data from a file. Any help and insight is appreciated.
EDIT:
I should note that I included the Neg_Pol_CB callback because this function does not cause a segfault after loading configuration data, while the GEN_CB callback does.
I got it solved. Turns out the code I was editing/building on my laptop was out of date with what was on my github (github code is what I posted here). I thought I pulled but apparently not. I had a line of code where I was writing/reading the wrong data element size to the file:
fwrite(&gen, sizeof(&gen), 11, fd);
...
fread(&gen, sizeof(&gen), 11, fd);
Two mistakes, I was accidentally reading/writing sizeof(&gen) instead of sizeof(gen) and I was also reading/writing 11 data elements instead of one. This caused me to overwrite some other pointers obviously. I'll work on updating all of my callbacks to match the signatures, but it all seems to be working now.
I have the following code:
gpointer w[3];
GtkWidget *menu_item = gtk_menu_item_new();
w[0] = menu_item;
menu_item = gtk_menu_item_new();
w[1] = menu_item;
GtkTextBuffer *buffer = gtk_text_buffer_new(NULL);
w[2] = buffer;
This is all good till now. Let's now connect a signal:
g_signal_connect(w[0], "activate", G_CALLBACK(runner), w);
runner function is declared as:
void runner(gpointer root, gpointer w[]);
Testing the values of w array before entering runner and while in it shows that they (the values) are different. I need them to be the same. How can I accomplish that, and why they aren't identical? Also, segfault occurs.
I created a small program that is bare bones of the original one and that is supposed to recreate the conditions such that the problem occurs. Oddly enough, it runs fine.
#include <gtk/gtk.h>
void carry(gpointer root, gpointer a[])
{
g_print("\n");
g_print("%d\n", root);
g_print("%d\n", a[0]);
g_print("%d\n", a[1]);
g_print("%d\n", a[2]);
}
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
GtkWidget *menu_item;
GtkTextBuffer *buffer;
gpointer abc[3];
menu_item = gtk_menu_item_new();
abc[0] = menu_item;
g_print("%d\t%d\n", menu_item, abc[0]);
menu_item = gtk_menu_item_new();
abc[1] = menu_item;
g_print("%d\t%d\n", menu_item, abc[1]);
buffer = gtk_text_buffer_new(NULL);
abc[2] = buffer;
g_print("%d\t%d\n", buffer, abc[2]);
g_signal_connect(abc[2], "modified-changed", G_CALLBACK(carry), abc);
gtk_text_buffer_set_modified(abc[2], TRUE);
gtk_main();
return 0;
}
Which means that something else is problematic. I'll try something else now, like commenting lines and leaving only the relevant ones.
I didn't comment any lines yet, but I tried putting g_print in both the caller and the callee.
This is an output:
1162863440 1162863440
1162864736 1162864736
1163320992 1163320992
1162863440
-2
1162668992
973486176
The first three lines compare the original values with their copies in the array (in the sense of g_print("%d\t%d\n", menu_item, abc[0]); from the code above). As you can see, everything is assigned correctly. After a new line, we check those same values in the callee. root, the first parameter, always has the correct value. So there's no problem with that. abc[0] in the callee always has the value of -2. Seriously, every time I run the program it is -2. Other two (abc[1] and abc[2]) always have some garbage random values, but they change every time I run the program unlike abc[0].
I hope this will help in diagnosing and fixing the problem.
I tried passing both abc[0] and abc normally through a function (func(arg0, arg1, ...) instead of using g_signal_connect()) and there is no problem whatsoever.
This all can mean only one thing: g_signal_connect is messing with my values. It changes them for some unknown reason.
I guess I'll have to use a struct.
You're not supposed to use gpointers everywhere. A gpointer is a void *, so you're pretty much disabling all the type checking the compiler could do for you. Use GtkWidget * instead, and do proper casts using G_OBJECT(), GTK_TEXT_BUFFER() etc. macros.
You should also use typed callback arguments, as they appear in the documentation for each signal. For example for the activate signal:
void
user_function (GtkMenuItem *menuitem,
gpointer user_data)
And if you want to pass several items in the user-data field, pass a pointer or pointer to a structure instead of an array of pointers.
And if you have a segfault, well, just use a debugger to check where the problem is.
I wrote a simple program module to ask a user for a profile name. To do that I create windoww with entry widget, and two buttons (Ok and Cancel) organized in a grid. When user enters a profile name that already exists it informs him of that fact by creating dialog with "ok" button, and after he presses it, it goes back to picking a profile name (the window was not hidden nor destroyed in the meantime). The problem is that when I create a profile, and then spam the ok button (by placing something heavy on enter key and going to make tea) on both profile name chooser and the dialog (making a simple loop with creation and destruction of a dialog) the memory usage of the program increases.
TL;DR
Simply creating and destroying gtk window (and dialog) seems to cause a memory leak. Leaving app in a loop made it increase it's memory usage by ~1900% (from 10mb to 200mb).
No, I didn't test for memory leaks using apps designed for it.
Yes, I've set G_SLICE=always-malloc.
Yes, there is another thread running in the background of the program (but I'm sure it doesn't cause any leaks)
I can post screens from Windows Performance Monitor if you want more info on what happens in the memory.
The question is - is it a memory leak caused by me, or is it GTK's fault (I heard it has a lazy policy of memory management, but after some time memory usage drops from 200mb to 140mb and stays there)?
Here's the code:
// This callback racts to the ok and cancel buttons. If input was correcs
// or the user pressed cancel it destroys the window. Else it show error
// prompt. The showing error prompt seems to be the problem here.
void pickNameButtCB(GtkWidget *button, gpointer *call)
{
GtkWidget *window = gtk_widget_get_toplevel(button);
if( *((char*)call) == 'k')
{
GList *entryBase = gtk_container_get_children(GTK_CONTAINER(gtk_bin_get_child(GTK_BIN(window)))), *entry = entryBase;
for(size_t i=g_list_length(entry); i>0 && !GTK_IS_ENTRY(entry->data); --i)
entry = g_list_next(entry);
if(gtk_entry_get_text_length(GTK_ENTRY(entry->data)) > 0)
{
const char *temp = gtk_entry_get_text(GTK_ENTRY(entry->data));
char path[266];
strcpy(path, settingsDir);
strcat(path, temp);
strcat(path, ".prof");
if(settProfExists(path))
{
g_list_free(entryBase);
showError(GTK_WINDOW(window), GTK_MESSAGE_ERROR, "Profile with that name already exists!");
return;
}
// nothing here executes as well
}
else
{
/** doesn't execute when the memory leak happens */
}
g_list_free(entryBase);
}
gtk_widget_destroy(window);
gtk_main_quit();
}
void showError(GtkWindow *parent, GtkMessageType type, const char *str)
{
GtkWidget *window = gtk_message_dialog_new(parent, GTK_DIALOG_DESTROY_WITH_PARENT, type, GTK_BUTTONS_OK, str);
g_signal_connect_swapped(window, "response", G_CALLBACK(gtk_widget_destroy), window);
gtk_dialog_run(GTK_DIALOG(window));
}
bool settProfExists(const char *path)
{
if(fileExists(path))
return true;
return false;
}
bool fileExists(const char *path)
{
struct stat info;
errno = 0;
if((stat(path, &info)) != 0)
if(errno == ENOENT)
return false;
return true;
}
Your code is too incomplete to find the root cause.
This line especially is doesn't make sense. We're missing the definition of entry and you're trying to do several operations on the same line (*entry = entryBase;).
GList *entryBase = gtk_container_get_children(GTK_CONTAINER(gtk_bin_get_child(GTK_BIN(window)))), *entry = entryBase;
The leak may however be in functions you call for which you don't provide the code (settProfExists, newProfile). So please provide a minimal compilable example that reproduces the problem.
As for the style, there are several errors: you're traversing a list the way you'd do with an array. See how is implemented GList and you'll see that this is silly (hint: look at entry->prev and entry->next):
for(size_t i=g_list_length(entry); i>0 && !GTK_IS_ENTRY(entry->data); --i)
entry = g_list_next(entry);
Then an architectural problem: don't try to inspect your UI to guess where are the widgets, just create a structure, and pass you call parameter and the GtkEntry you're interested in, in a structure with the gpointer data argument of the callback.
You should also not make paths by hand: you're using a fixed length array that may not be long enough. Use the portable g_build_path provided by the GLib (and free the path with g_free after use), that will handle for you Windows/Linux directories separators.
For your dialog, as you run gtk_run_dialog, you may just directly call gtk_destroy_widget afterwards instead of connecting a signal:
GtkWidget *window = gtk_message_dialog_new(parent, GTK_DIALOG_DESTROY_WITH_PARENT, type, GTK_BUTTONS_OK, str);
gtk_dialog_run(GTK_DIALOG(window));
gtk_widget_destroy(window);
I have a library written in C with glib/gobject. It produces significant number of debugging information via g_debug() call. This info is very helpful for troubleshooting, however I do not want it to be shown, when library is included with actual application. So, basically I need a way to control/filter amount of debugging information and I could not figure out how it supposed to work with glib. Could someone point me in the right direction, please?
You could try setting G_DEBUG environment variable as mentioned in the GLib developer site. Please refer to Environment variable section under Running and debugging GLib Applications in http://developer.gnome.org/glib/2.28/glib-running.html.
EDIT: Update to set the logger in the code.
You can use g_log_set_handler ( http://developer.gnome.org/glib/2.29/glib-Message-Logging.html#g-log-set-handler ) to do this in your code. Initially you can set the log handler to a dummy function which display nothings & then you can set the log handler to g_log_default_handler based on the argument passed for set appropriate log levels. To set the log levels above a set level you will need to manipulate GLogLevelFlags values as per your need.
Hope the below code sample will provide some pointers
#include <glib.h>
#include <stdio.h>
#include <string.h>
#define G_LOG_DOMAIN ((gchar*) 0)
static void _dummy(const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer user_data )
{
/* Dummy does nothing */
return ;
}
int main(int argc, char **argv)
{
/* Set dummy for all levels */
g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_MASK, _dummy, NULL);
/* Set default handler based on argument for appropriate log level */
if ( argc > 1)
{
/* If -vv passed set to ONLY debug */
if(!strncmp("-vv", argv[1], 3))
{
g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, g_log_default_handler, NULL);
}
/* If -v passed set to ONLY info */
else if(!strncmp("-v", argv[1], 2))
{
g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, g_log_default_handler, NULL);
}
/* For everything else, set to back to default*/
else
{
g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_MASK, g_log_default_handler, NULL);
}
}
else /* If no arguments then set to ONLY warning & critical levels */
{
g_log_set_handler(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING| G_LOG_LEVEL_CRITICAL, g_log_default_handler, NULL);
}
g_warning("This is warning\n");
g_message("This is message\n");
g_debug("This is debug\n");
g_critical("This is critical\n");
g_log(NULL, G_LOG_LEVEL_INFO , "This is info\n");
return 0;
}
Hope this helps!
I implemented custom log handler and here is how it turned out:
void custom_log_handler (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
{
gint debug_level = GPOINTER_TO_INT (user_data);
/* filter out messages depending on debugging level */
if ((log_level & G_LOG_LEVEL_DEBUG) && debug_level < MyLogLevel_DEBUG) {
return;
}
else if ((log_level & G_LOG_LEVEL_INFO) && debug_level < MyLogLevel_INFO) {
return;
}
g_printf ("%s\n", message);
}
int main(int argc, char *argv[])
{
...
if (verbose) {
g_log_set_handler (NULL, G_LOG_LEVEL_MASK, custom_log_handler, GINT_TO_POINTER (MyLogLevel_DEBUG));
}
else {
g_log_set_handler (NULL, G_LOG_LEVEL_MASK, custom_log_handler, GINT_TO_POINTER (MyLogLevel_NORMAL));
}
...
}
I hope it will be helpful to somebody :-)
You can control whether to print debug (log) messages with setting the G_MESSAGES_DEBUG environment variable when running your application.
The easiest is to use $ G_MESSAGES_DEBUG=all ./your-app when you need debugging (log) messages to be printed.
However, when G_MESSAGES_DEBUG=all glib libraries itself print debug (log) messages too which you may not need. So, predefine G_LOG_DOMAIN as a separate custom log domain string for your application and set G_MESSAGES_DEBUG to the same string when running. For example, use -DG_LOG_DOMAIN=\"my-app\" among compiler flags and run application with $ G_MESSAGES_DEBUG="my-app" ./your-app.
I am trying to create a multi-thread, jpg rotation program but I am having problems getting g_thread to work.
int processUserRequest (UserRequest *uRequest,
char * const* argv, int argc, int optind){
struct RotationData CurData;
CurData.argv=argv;
CurData.argc=argc;
CurData.optind=optind;
CurData.uRequest=uRequest;
gpointer user_data = &CurData;
int transform = FALSE;
int max_files = argc - optind;
int i;
gpointer data=&i;
GThreadPool *pool;
if(!g_thread_supported())
g_thread_init(NULL);
pool = g_thread_pool_new(MultiThreadRotation,user_data, 5, TRUE, NULL);
for(i=0;i
{
g_thread_pool_push(pool, &data,NULL);
}
//g_thread_pool_free (pool, TRUE,TRUE);
//Create a montage file
transform = createMontageFile (uRequest);
return transform;
}
The function MultiThreadRotation is suppose to be called by g_thread_pool_push, but it is not being good once. Can anyone help, I am quite the novice.
Also, I thought about outputting the error from g_thread_pool_push, how would you output a GError *error message?
First off, in the code you pasted, there's a bug in the for statement.
Assuming that's fixed, here are a few remarks.
I'm not sure why this is failing, but you can get some indication from the GError's "message" member, which is a human-readable C string you can use with printf() or whatever you like. Unfortunately, you've set the GError arguments to NULL in the g_thread_*() calls.
This routine leaks the thread pool; you should call g_thread_pool_free() before exiting it.
If you're doing other threading in your program, and you care about performance, you should think carefully about whether you want these threads to be exclusive or shared. That's set with the argument to g_thread_pool_new() which you've set to TRUE (exclusive).