Proper way of building Gtk system tray in c++ - c++

int main(int argc, char *argv[])
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "GtkStatusIcon Example");
gtk_widget_set_size_request (window, 200, -1);
set try icon file
GtkStatusIcon *trayIcon = gtk_status_icon_new_from_file ("/root/Desktop/icon.png");
set popup menu for tray icon
GtkWidget *menu, *menuItemView, *menuItemExit;
menu = gtk_menu_new();
menuItemView = gtk_menu_item_new_with_label ("View");
menuItemExit = gtk_menu_item_new_with_label ("Exit");
g_signal_connect (G_OBJECT (menuItemView), "activate", G_CALLBACK (trayView), window);
g_signal_connect (G_OBJECT (menuItemExit), "activate", G_CALLBACK (trayExit), NULL);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuItemView);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuItemExit);
gtk_widget_show_all (menu);
}

//gcc trayicon.c -o trayicon pkg-config --cflags --libs gtk+-2.0.
#include <gtk/gtk.h>
static void trayView(GtkMenuItem *item, gpointer user_data);
static void trayExit(GtkMenuItem *item, gpointer user_data);
static void trayIconActivated(GObject *trayIcon, gpointer data);
static void trayIconPopup(GtkStatusIcon *status_icon, guint button, guint32 activate_time, gpointer popUpMenu);
static void destroy (GtkWidget*, gpointer);
static gboolean delete_event (GtkWidget*, GdkEvent*, gpointer);
static gboolean window_state_event (GtkWidget *widget, gdkEventWindowState *event, gpointer user_data);
int main(int argc, char *argv[])
{
gtk_init (&argc, &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "GtkStatusIcon Example");
gtk_widget_set_size_request (window, 200, -1);
//set try icon file
GtkStatusIcon *trayIcon = gtk_status_icon_new_from_file ("/root/Desktop/icon.png");
//set popup menu for tray icon
GtkWidget *menu, *menuItemView, *menuItemExit;
menu = gtk_menu_new();
menuItemView = gtk_menu_item_new_with_label ("View");
menuItemExit = gtk_menu_item_new_with_label ("Exit");
g_signal_connect (G_OBJECT (menuItemView), "activate", G_CALLBACK (trayView), window);
g_signal_connect (G_OBJECT (menuItemExit), "activate", G_CALLBACK (trayExit), NULL);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuItemView);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuItemExit);
gtk_widget_show_all (menu);
//set tooltip
gtk_status_icon_set_tooltip (trayIcon, "MsgWatcherGTK");
//connect handlers for mouse events
g_signal_connect(GTK_STATUS_ICON (trayIcon), "activate", GTK_SIGNAL_FUNC (trayIconActivated), window);
g_signal_connect(GTK_STATUS_ICON (trayIcon), "popup-menu", GTK_SIGNAL_FUNC (trayIconPopup), menu);
gtk_status_icon_set_visible(trayIcon, FALSE); //set icon initially invisible
GtkWidget *menuBar, *menuItemTopLvl, *mainMenu, *mainMenuItemExit;
menuBar = gtk_menu_bar_new ();
menuItemTopLvl = gtk_menu_item_new_with_label ("Menu");
gtk_menu_shell_append (GTK_MENU_SHELL (menuBar), menuItemTopLvl);
mainMenu = gtk_menu_new ();
gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuItemTopLvl), mainMenu);
mainMenuItemExit = gtk_menu_item_new_with_label ("Quit");
g_signal_connect (G_OBJECT (mainMenuItemExit), "activate", G_CALLBACK (trayExit), NULL);
gtk_menu_shell_append (GTK_MENU_SHELL (mainMenu), mainMenuItemExit);
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);
g_signal_connect (G_OBJECT (window), "delete_event", G_CALLBACK (delete_event), trayIcon);
g_signal_connect (G_OBJECT (window), "window-state-event", G_CALLBACK (window_state_event), trayIcon);
gtk_container_add (GTK_CONTAINER (window), menuBar);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
static void trayView(GtkMenuItem *item, gpointer window)
{
gtk_widget_show(GTK_WIDGET(window));
gtk_window_deiconify(GTK_WINDOW(window));
}
static void trayExit(GtkMenuItem *item, gpointer user_data)
{
printf("exit");
gtk_main_quit();
}
static void trayIconActivated(GObject *trayIcon, gpointer window)
{
gtk_widget_show(GTK_WIDGET(window));
gtk_window_deiconify(GTK_WINDOW(window));
}
static void trayIconPopup(GtkStatusIcon *status_icon, guint button, guint32 activate_time, gpointer popUpMenu)
{
gtk_menu_popup(GTK_MENU(popUpMenu), NULL, NULL, gtk_status_icon_position_menu, status_icon, button, activate_time);
}
static void destroy (GtkWidget *window, gpointer data)
{
gtk_main_quit ();
}
static gboolean delete_event (GtkWidget *window, GdkEvent *event, gpointer data)
{
return FALSE;
}
static gboolean window_state_event (GtkWidget *widget, GdkEventWindowState *event, gpointer trayIcon)
{
if(event->changed_mask == GDK_WINDOW_STATE_ICONIFIED && (event->new_window_state == GDK_WINDOW_STATE_ICONIFIED || event->new_window_state == (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_MAXIMIZED)))
{
gtk_widget_hide (GTK_WIDGET(widget));
gtk_status_icon_set_visible(GTK_STATUS_ICON(trayIcon), TRUE);
}
else if(event->changed_mask == GDK_WINDOW_STATE_WITHDRAWN && (event->new_window_state == GDK_WINDOW_STATE_ICONIFIED || event->new_window_state == (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_MAXIMIZED)))
{
gtk_status_icon_set_visible(GTK_STATUS_ICON(trayIcon), FALSE);
}
return TRUE;
}

Related

GTK3 Detect user resizing window

This is some example code from the Gnome website:
#include <gtk/gtk.h>
static void resizechange() {
printf("User resized window!\n");
}
static void
activate (GApplication *app,
gpointer user_data)
{
GtkWidget *widget;
widget = gtk_application_window_new (GTK_APPLICATION (app));
gtk_widget_show (widget);
}
int
main (int argc, char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gnome.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
Is there a way that the resizechange() function could be run when the user resizes the program window, so I can act upon this?
Can this be done with events or callbacks?
You can do that by connecting to the configure-event signal of your widget.
However, your callback must respect the function signature stated in the documentation, so instead of:
static void resizechange()
you will have:
static gboolean resizechange (GtkWidget *widget, GdkEvent *event, gpointer user_data)

Set Cell in GtkTreeView to edit mode programmatically

I currently write an application that has a GtkTreeView with a GtkCellRendererText which property editable is set to true. When double clicking an item, I can edit it. Now I want to be able to add an empty row and immediately start editing it. I tried using gtk_tree_view_set_cursor_on_cell with start_editing set to true. It selects the row, but it does not start editing. I put together a small example (please not that I do not have any error checking in place as its just a small example).
#include <gtk/gtk.h>
GtkListStore *store;
GtkWidget *window;
GtkWidget *view;
GtkCellRenderer *renderer;
GtkWidget *button;
GtkWidget *vbox;
void sig_inserted(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter)
{
// Set cursor on cell with start_editing = TRUE
gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(view), path, gtk_tree_view_get_column(GTK_TREE_VIEW(view), 0), renderer, TRUE);
}
void button_clicked(GtkButton *button, GdkEvent *event, gpointer user_data)
{
// Add empty row to liststore
GtkTreeIter iter;
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, "", -1);
}
int main (int argc, char **argv)
{
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "delete_event", gtk_main_quit, NULL);
view = gtk_tree_view_new ();
// Create renderer and set editable to TRUE
renderer = gtk_cell_renderer_text_new ();
GValue val = G_VALUE_INIT;
g_value_init(&val, G_TYPE_BOOLEAN);
g_value_set_boolean(&val, TRUE);
g_object_set_property(G_OBJECT(renderer), "editable", &val);
g_value_unset(&val);
// Insert Text column
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (view),
-1,
"Name",
renderer,
"text", 0,
NULL);
store = gtk_list_store_new (1, G_TYPE_STRING);
// Add test item
GtkTreeIter iter;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
0, "Test",
-1);
gtk_tree_view_set_model (GTK_TREE_VIEW (view), GTK_TREE_MODEL(store));
vbox = gtk_vbox_new(0,0);
button = gtk_button_new_with_label("Add edit item");
gtk_box_pack_start(GTK_BOX(vbox), view, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, TRUE, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_widget_show_all (window);
g_signal_connect(G_OBJECT(store), "row-inserted", G_CALLBACK(sig_inserted), NULL);
g_signal_connect(G_OBJECT(button), "button-release-event", G_CALLBACK(button_clicked), NULL);
gtk_main ();
return 0;
}
Compile it with g++ (as I do not comply with all C needs) using
g++ -o tree tree.cc `pkg-config --libs --cflags gtk+-2.0`
It would also work with Gtk3 I think as nothing seems to have changed in the things I use.
Can somebody point me out why it does not start editing?
gtk_list_store_set cancels editing of a cell. Commenting out this line makes everything work.
It can be found this with a little modification to code:
void sig_inserted(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter)
{
GtkTreeViewColumn * col = gtk_tree_view_get_column(GTK_TREE_VIEW(view), 0);
// Set cursor on cell with start_editing = TRUE
g_message ("sig_inserted", __LINE__);
gtk_tree_view_set_cursor_on_cell(GTK_TREE_VIEW(view), path, col, renderer, TRUE);
}
void button_clicked(GtkButton *button, GdkEvent *event, gpointer user_data)
{
// Add empty row to liststore
GtkTreeIter iter;
g_message ("Clicked");
gtk_list_store_append(store, &iter);
g_message ("Appended");
gtk_list_store_set(store, &iter, 0, "x", -1);
g_message ("Set");
}
void
estart (GtkCellRenderer *renderer,
GtkCellEditable *editable,
gchar *path,
gpointer user_data)
{
g_message ("renderer: start edit");
}
void
ecancel (GtkCellRenderer *renderer,
gpointer user_data)
{
g_message ("renderer: cancel edit");
}
And connecting to renderers signals:
g_signal_connect(G_OBJECT(renderer), "editing-started", G_CALLBACK(estart), NULL);
g_signal_connect(G_OBJECT(renderer), "editing-canceled", G_CALLBACK(ecancel), NULL);
Give the following output:
** Message: Clicked
** Message: sig_inserted
** Message: renderer: start edit
** Message: Appended
** Message: renderer: cancel edit
** Message: Set

Dereferencing a String Vector in C++ when passing to GTK callback

I have this code which is trying to pass a vector to a callback function:
static void displayvecchoices( GtkWidget *widget, gpointer data ) {
std::vector<std::string> vecp = *(std::vector<std::string> *)(data);
std::cout<<"vec: "<<vecp[0]<<std::endl;
}
int main(int argc, char *argv[] ) {
GtkWidget *window;
GtkWidget *display;
gtk_init(&argc, &argv);
window = gtk_dialog_new ();
g_signal_connect (window, "destroy", G_CALLBACK (destroy), NULL);
gtk_window_fullscreen (GTK_WINDOW(window));
std::vector<std::string> vec;
vec.push_back("1");
display = gtk_button_new_with_label ("Display");
g_signal_connect_swapped (display, "clicked", G_CALLBACK (displayvecchoices), &vec);
gtk_widget_set_can_default (display, TRUE);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), display, TRUE, TRUE, 0);
gtk_widget_grab_default (display);
gtk_widget_show (display);
gtk_main();
return 0;
}
When the button display is clicked, I get an error of 'bad alloc' and the program crashes.
When I try this:
std::vector<std::string>* vecp = (std::vector<std::string> *)(data);
std::cout<<"vec: "<<(*vecp)[0]<<std::endl;
It prints out vec: but no element and the size is said to be 18446744073706420840 of the vector.
It looks, your callback arguments are swapped:
you should either use g_signal_connect_object instead of g_signal_connect_swapped or
change displayvecchoices declaration to
static void displayvecchoices(gpointer data, GtkWidget *widget)

Compilation for GTK+ using OpenGL

Context: I am learning development of GUI using GTK+. I also wanted to draw lines and circles on the GUI. So I started with the tutorials and I am stuck with the part of GtkGLArea. I am following the code given in the GTK+ documentation
The error:
glTrial.cpp:32:13: error: variable or field ‘on_realize’ declared void
on_realize (GtkGLarea *area)
^
glTrial.cpp:32:13: error: ‘GtkGLarea’ was not declared in this scope
glTrial.cpp:32:24: error: ‘area’ was not declared in this scope
on_realize (GtkGLarea *area)
I believe I am not compiling properly and the compiler is not able to find correct headers.
Compilation:
g++ -std=c++14 \`pkg-config --cflags gtk+-3.0\` -o glTrial glTrial.cpp \`pkg-config --libs gtk+-3.0\`
The code:
#include <gtk/gtk.h>
#include <gtkgl-2.0/gtkgl/gdkgl.h>
#include <gtkgl-2.0/gtkgl/gtkglarea.h>
static void
print_hello (GtkWidget *widget,
gpointer user_data)
{
g_print ("Hello World\n");
}
static gboolean
render (GtkGLArea *area, GdkGLContext *context)
{
// inside this function it's safe to use GL; the given
// #GdkGLContext has been made current to the drawable
// surface used by the #GtkGLArea and the viewport has
// already been set to be the size of the allocation
// we can start by clearing the buffer
//glClearColor (0, 0, 0, 0);
// glClear (GL_COLOR_BUFFER_BIT);
// draw your object
// draw_an_object ();
// we completed our drawing; the draw commands will be
// flushed at the end of the signal emission chain, and
// the buffers will be drawn on the window
return TRUE;
}
static void
on_realize (GtkGLarea *area)
{
// We need to make the context current if we want to
// call GL API
gtk_gl_area_make_current (area);
// If there were errors during the initialization or
// when trying to make the context current, this
// function will return a #GError for you to catch
if (gtk_gl_area_get_error (area) != NULL)
return;
// You can also use gtk_gl_area_set_error() in order
// to show eventual initialization errors on the
// GtkGLArea widget itself
GError *internal_error = NULL;
init_buffer_objects (&error);
if (error != NULL)
{
gtk_gl_area_set_error (area, error);
g_error_free (error);
return;
}
init_shaders (&error);
if (error != NULL)
{
gtk_gl_area_set_error (area, error);
g_error_free (error);
return;
}
}
static void
activate (GtkApplication* app,
gpointer user_data)
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *button;
GtkWidget *gl_area =gtk_gl_area_new();
/* Create a new window, and set its title */
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Window");
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
// gtk_window_set_default_size(GTK_WINDOW(window), 200, 200);
/* Here we construct the container that is going to pack the buttons*/
grid = gtk_grid_new();
/* Pack the container in the window */
gtk_container_add (GTK_CONTAINER (window), grid);
button = gtk_button_new_with_label ("Quit");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 2, 1);
button = gtk_button_new_with_label ("Hello");
g_signal_connect_swapped (button, "clicked", G_CALLBACK (print_hello), NULL);
gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 2, 1);
/* Trial for GL area*/
g_signal_connect (gl_area, "render", G_CALLBACK(render), NULL);
gtk_grid_attach (GTK_GRID (grid), gl_area, 0, 2, 10, 10);
gtk_widget_show_all (window);
}
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
g_application_run (G_APPLICATION (app), argc, argv);
// app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
According to a fast google, you are looking for GtkGLArea, note the uppercase A.
– derhass
you need:
sudo apt install *epoxy*
and
c++ t.c --target=arm-linux-gnu `pkg-config --libs --cflags gtk+-3.0 epoxy ` -o op

Unable to pass argument to GTK callback

When the program is initially run, the print statements, print a valid hex code corresponding to the pointer. However, when I click on the screen, and the handleClick method is called through the 'clicked' callback, 0x0 is printed to the screen. What happened? Why has my board object suddenly become null?
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include "board.h"
void printBoard(Board *board);
void handleClick(GtkWidget *widget, GdkEventButton *event, cairo_t *cr, gpointer data);
gboolean draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data)
{
Board *temp = (Board *)data;
printf("%p\n",temp);
return TRUE;
}
void handleClick (GtkWidget *widget, GdkEventButton *event, cairo_t *cr, gpointer data)
{
Board *temp = (Board *)data;
printf("%p\n",temp);
}
void start(Board *newBoard)
{
GtkWidget *window;
GtkWidget *da;
GtkWidget *frame;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
char string[40];
snprintf(string, sizeof(string), "Connect %d-%d",newBoard->k,newBoard->n);
gtk_window_set_default_size (GTK_WINDOW(window), 400, 400);
gtk_window_move(GTK_WINDOW(window), 100, 100);
g_signal_connect (GTK_WINDOW(window), "destroy", G_CALLBACK (gtk_main_quit), NULL);
da = gtk_drawing_area_new ();
gtk_widget_set_size_request (da, 500, 500);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (window), frame);
gtk_container_add (GTK_CONTAINER (frame), da);
gtk_widget_set_events (da, gtk_widget_get_events (da)
| GDK_BUTTON_PRESS_MASK);
g_signal_connect (da, "draw",
G_CALLBACK (draw_cb), newBoard);
g_signal_connect (da, "button-press-event",
G_CALLBACK (handleClick), newBoard);
gtk_widget_show_all (window);
}
The prototype of the button-press-event signal handler is the following according to the reference manual.
gboolean user_function (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
If you remove cairo_t *cr parameter from the handleClick function data will be ok.
As Szilard said, you're using the wrong prototype for the handleClick function.
The button-press-event signal handler has the following prototype:
gboolean user_function (GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
To fix your mistakes, you need to:
remove thecairo_t *cr parameter. It was receiving the value of data.
fix event type which is GdkEvent *, not GdkEventButton *
fix the return value, which is a boolean, not void, and which is important to determine if the event is propagated or not.