As the picture shows,when in the long connection mode,the server recv and send,the client send and recv.And my question is:
Can I only just use the send in the client and just use the recv in the server?
The test code:
The server:
//#include "stdafx.h"
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
int main(int argc, char* argv[])
{
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0)
{
return 0;
}
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (slisten == INVALID_SOCKET)
{
printf("socket error !");
return 0;
}
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);
sin.sin_addr.S_un.S_addr = INADDR_ANY;//
if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf("bind error !");
}
if (listen(slisten, 30) == SOCKET_ERROR)
{
printf("listen error !");
return 0;
}
SOCKET sClient;
sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);
char revData[255];
while (true)
{
printf("waitting...\n");
sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
if (sClient == INVALID_SOCKET)
{
printf("accept error !");
continue;
}
printf("receive a connection:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
char * sendData = "R\n";
//
while (1)
{
int ret = recv(sClient, revData, 255, 0);
if (ret > 0)
{
revData[ret] = 0x00;
printf(revData);
//new add code
//send(sClient, sendData, strlen(sendData), 0);
}
else
break;
}
closesocket(sClient);
}
closesocket(slisten);
WSACleanup();
return 0;
}
The client:
//#include "stdafx.h"
#include <WINSOCK2.H>
#include <STDIO.H>
#pragma comment(lib,"ws2_32.lib")
int main(int argc, char* argv[])
{
WORD sockVersion = MAKEWORD(2, 2);
WSADATA data;
if (WSAStartup(sockVersion, &data) != 0)
{
return 0;
}
SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sclient == INVALID_SOCKET)
{
printf("invalid socket !");
return 0;
}
sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8888);
serAddr.sin_addr.S_un.S_addr = inet_addr("10.92.1.148");
if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
{
printf("connect error !");
closesocket(sclient);
return 0;
}
char * sendData = "T\n";
int cnt = 0;
char recData[255];
while (1)
{
send(sclient, sendData, strlen(sendData), 0);
//new add code
//int ret = recv(sclient, recData, 255, 0);
//if (ret > 0)
//{
// recData[ret] = 0x00;
// printf(recData);
//}
}
printf("cnt=%d\n",cnt);
closesocket(sclient);
WSACleanup();
return 0;
}
The code is wrong when I test.While when I add the new code,the program can run.The new code is the code after the // as the above .So I think just have send in one side and recv in another side maybe wrong.It have to have a loop.Is it right?Must I have a loop(request and response loop in the picture)?
Related
I am working on a VPN app in swift 5. We are using NEVPNManager to handle all VPN configs. One of the features we would like is to measure the user's usage data while they are connected to our VPN. How can we do this ?
NEVPNManager doesn't offer any method that fulfil your requirement. Following is the solution is personally use in application.
Solution: Search for the suitable Network Interface and start reading the In and Out bytes.
en0 refers to Wifi
pdp_ip refers to Cellular network
+ (NSDictionary *) DataCounters{
struct ifaddrs *addrs;
const struct ifaddrs *cursor;
u_int32_t WiFiSent = 0;
u_int32_t WiFiReceived = 0;
u_int32_t WWANSent = 0;
u_int32_t WWANReceived = 0;
if (getifaddrs(&addrs) == 0)
{
cursor = addrs;
while (cursor != NULL)
{
if (cursor->ifa_addr->sa_family == AF_LINK)
{
// name of interfaces:
// en0 is WiFi
// pdp_ip0 is WWAN
NSString *name = [NSString stringWithFormat:#"%s",cursor->ifa_name];
if ([name hasPrefix:#"en"])
{
const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data;
if(ifa_data != NULL)
{
WiFiSent += ifa_data->ifi_obytes;
WiFiReceived += ifa_data->ifi_ibytes;
}
}
if ([name hasPrefix:#"pdp_ip"])
{
const struct if_data *ifa_data = (struct if_data *)cursor->ifa_data;
if(ifa_data != NULL)
{
WWANSent += ifa_data->ifi_obytes;
WWANReceived += ifa_data->ifi_ibytes;
}
}
}
cursor = cursor->ifa_next;
}
freeifaddrs(addrs);
}
return #{DataCounterKeyWiFiSent:[NSNumber numberWithUnsignedInt:WiFiSent],
DataCounterKeyWiFiReceived:[NSNumber numberWithUnsignedInt:WiFiReceived],
DataCounterKeyWWANSent:[NSNumber numberWithUnsignedInt:WWANSent],
DataCounterKeyWWANReceived:[NSNumber numberWithUnsignedInt:WWANReceived]};}
This code takes a file from dialogo_chosser and adds in a gtk_tree_view...
I would take more files from one gtkfilechosser and add them in a gtk_tree_view...
I saw that you must enter this function:
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE)
but I do not know how to take the selected files :(
I ask "politely" a small example for this solution
my code is:
#include "header.h"
#include <string.h>
#include <gtk/gtk.h>
GtkWidget *list;
GtkWidget *win;
char *filename;
void Add_Items_List(GtkWidget *widget, gpointer data)
{
GtkListStore *store;
GtkTreeIter iter;
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, filename, -1);
}
void Dialog_Chooser(GtkWidget *widget, gpointer gst)
{
GtkWidget *dialog;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
GtkFileChooser *chooser;
gint res;
dialog = gtk_file_chooser_dialog_new("Open File", GTK_WINDOW(win), action,
"Cancel", GTK_RESPONSE_CANCEL,
"Open", GTK_RESPONSE_ACCEPT, NULL);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if(res == GTK_RESPONSE_ACCEPT){
chooser = GTK_FILE_CHOOSER(dialog);
filename = gtk_file_chooser_get_filename(chooser);
Add_Items_List(NULL, NULL);
g_free(filename);
}
gtk_widget_destroy(dialog);
}
void Delete_Item_List(GtkWidget *widget, gpointer selection)
{
GtkTreeModel *model;
GtkTreeIter iter;
model = gtk_tree_view_get_model(GTK_TREE_VIEW(list));
if(gtk_tree_selection_get_selected(GTK_TREE_SELECTION(selection), &model, &iter)){
gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
}
}
void Delete_All_Items_List(GtkWidget *widget, gpointer selection)
{
GtkListStore *store;
GtkTreeIter iter;
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
gtk_list_store_clear(store);
}
void Inizializes_The_List(GtkWidget *list)
{
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
GtkListStore *store;
renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes("Lenguages", renderer, "text", 0, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
store = gtk_list_store_new(1, G_TYPE_STRING);
gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store));
g_object_unref(store);
}
void Add_Lista(GtkWidget *list, const gchar *str)
{
GtkListStore *store;
GtkTreeIter iter;
store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(list)));
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, str, -1);
}
int main(int argc, char **argv)
{
GtkWidget *Button_remove;
GtkWidget *button_remove_all;
GtkWidget *button_chosser;
GtkWidget *sw;
GtkWidget *hbox;
GtkWidget *vbox;
GtkTreeSelection *selection;
gtk_init(&argc, &argv);
win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(win), "Simple chosser list");
gtk_window_set_default_size(GTK_WINDOW(win), 200, 200);
gtk_container_set_border_width(GTK_CONTAINER(win), 10);
sw = gtk_scrolled_window_new(NULL, NULL);
list = gtk_tree_view_new();
gtk_container_add(GTK_CONTAINER(sw), list);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start(GTK_BOX(vbox), sw, TRUE, TRUE, 5);
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
Button_remove = gtk_button_new_with_label("Delete");
button_remove_all = gtk_button_new_with_label("Delte All");
button_chosser = gtk_button_new_with_label("List");
gtk_box_pack_start(GTK_BOX(hbox), Button_remove, FALSE, TRUE, 3);
gtk_box_pack_start(GTK_BOX(hbox), button_remove_all, FALSE, TRUE, 3);
gtk_box_pack_start(GTK_BOX(hbox), button_chosser, FALSE, TRUE, 3);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 3);
gtk_container_add(GTK_CONTAINER(win), vbox);
Inizializes_The_List(list);
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
g_signal_connect(G_OBJECT(button_chosser), "clicked", G_CALLBACK(Dialog_Chooser), NULL);
g_signal_connect(Button_remove, "clicked", G_CALLBACK(Delete_Item_List), selection);
g_signal_connect(button_remove_all, "clicked", G_CALLBACK(Delete_All_Items_List), selection);
g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(destroy), NULL);
gtk_widget_show_all(win);
gtk_main();
return 0;
}
ps: use gtk+3 on ubuntu 16.04
For now, I have found this solution:
void Dialog_Chooser(GtkWidget *widget, gpointer gst)
{
GtkWidget *dialog;
GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN;
GtkFileChooser *chooser;
gint res;
dialog = gtk_file_chooser_dialog_new("Open File", GTK_WINDOW(win), action, "Cancel",
GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL);
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if(res == GTK_RESPONSE_ACCEPT){
GSList *filenamepus;
chooser = GTK_FILE_CHOOSER(dialog);
//filename = gtk_file_chooser_get_filename(chooser);
filenamepus = gtk_file_chooser_get_filenames(chooser);
int nIndex;
GSList *node;
for(nIndex = 0; node = g_slist_nth(filenamepus, nIndex); nIndex++){
filename = (char *) node->data; //g_slist_nth(filenamepus, nIndex);
Add_Items_List(NULL, NULL);
//g_print ("%s\n", filename); //(char *) node->data);
}
//Add_Items_List(NULL, NULL);
g_free(filename);
}
gtk_widget_destroy(dialog);
}
If anyone knows a better solution, I would still love to hear it.
In my project I need to detect multiple gestures, I made a .gbd file with 2 continuous gestures. I can detect the continuous gesture when the .gbd file had one gesture. When there is 2 gestures I am unable to read any one gesture. Do any one know the reason? Here I post my code. I used Body basics example from sdk, and added necessary functions separately to avoid memory leakage.
//separate function to initialize database, vgb frame source and vgb frame reader
void CBodyBasics::InitializeVGB()
{
HRESULT hr;
std::wstring sDbFile = L"ContinuousGestures.gbd";
hr = CreateVisualGestureBuilderDatabaseInstanceFromFile(sDbFile.c_str(), &m_pGestureDatabase);
if (SUCCEEDED(hr))
{
OutputDebugString(L"Success DB\n");
}
else
{
OutputDebugString(L"Failure DB\n");
}
for (int i = 0; i < BODY_COUNT; i++)
{
// Source
hr = CreateVisualGestureBuilderFrameSource(m_pKinectSensor, 0, &m_pVGBFrameSource[i]);
if (SUCCEEDED(hr))
{
OutputDebugString(L"Source created\n");
}
else
{
OutputDebugString(L"Soure creation failed\n");
}
// Reader
hr = m_pVGBFrameSource[i]->OpenReader(&m_pVGBFrameReader[i]);
if (SUCCEEDED(hr))
{
OutputDebugString(L"reader opened\n");
}
else
{
OutputDebugString(L"No reader\n");
}
}
}
//function to find the available gesture count, add the available gestures to source
void CBodyBasics::CheckGestureMultiple()
{
HRESULT hr;
hr = m_pGestureDatabase->get_AvailableGesturesCount(&iGestureCount);
//gesture count
if (SUCCEEDED(hr))
{
OutputDebugString(L"gesture #\n");
}
else
{
OutputDebugString(L"0 gesture\n");
}
StringCchPrintf(smessage, _countof(smessage), L"Gesture Count %d \n", iGestureCount);
OutputDebugString(smessage);
hr = m_pGestureDatabase->get_AvailableGestures(iGestureCount, m_pgesturelist);
//gesture list
if (SUCCEEDED(hr) && m_pgesturelist != nullptr)
{
OutputDebugString(L"received available gestures\n");
GestureType mtype;
WCHAR sName[260];
for (int i = 0; i < iGestureCount; ++i)
{
hr = m_pgesturelist[i]->get_GestureType(&mtype);
//gesture type
if (SUCCEEDED(hr))
{
OutputDebugString(L"gesture type\n");
if (mtype == GestureType_Discrete)
{
OutputDebugString(L"discrete\n");
}
else if (mtype == GestureType_Continuous)
{
OutputDebugString(L"continuous\n");
}
}
else
{
OutputDebugString(L"no gesture type\n");
}
hr = m_pgesturelist[i]->get_Name(260, sName);
//gesture name
if (SUCCEEDED(hr))
{
OutputDebugString(L"gesture name\n");
StringCchPrintf(smessage, _countof(smessage), L"%s \t %d \n", sName, i);
OutputDebugString(smessage);
}
else
{
OutputDebugString(L"no name\n");
}
}
}
else
{
OutputDebugString(L"not received gestures\n");
}
for (int i = 0; i < BODY_COUNT; ++i)
{
//add gestures to the source
hr = m_pVGBFrameSource[i]->AddGestures(iGestureCount, m_pgesturelist);
if (SUCCEEDED(hr))
{
OutputDebugString(L"Gesture added\n");
}
else
{
OutputDebugString(L"not added\n");
}
}
}
//function to read the vgb frame and process if the gesture is detected
void CBodyBasics::ReadVGBFrameMultiple(int t_bodyCount)
{
HRESULT hr;
for (int i = 0; i < t_bodyCount; i++)
{
hr = m_pVGBFrameReader[i]->CalculateAndAcquireLatestFrame(&m_pVGBFrame);
if (SUCCEEDED(hr) && m_pVGBFrame != nullptr)
{
OutputDebugString(L"vgb frame\n");
BOOLEAN bGestureTracked = false;
hr = m_pVGBFrame->get_IsTrackingIdValid(&bGestureTracked);
if (SUCCEEDED(hr) && bGestureTracked)
{
OutputDebugString(L"valid gesture id and gesture tracked\n");
GestureType gesturetype;
m_pgesturelist[i]->get_GestureType(&gesturetype);
switch (gesturetype)
{
case GestureType::GestureType_Discrete:
hr = m_pVGBFrame->get_DiscreteGestureResult(m_pgesturelist[i], &m_pDiscreteResult);
if (SUCCEEDED(hr) && m_pDiscreteResult != nullptr)
{
OutputDebugString(L"discrete result\n");
BOOLEAN bDetected = false;
hr = m_pDiscreteResult->get_Detected(&bDetected);
if (SUCCEEDED(hr) && bDetected)
{
OutputDebugString(L"gesture detected\n");
StringCchPrintf(smessage, _countof(smessage), L"gesture detected %d\n", bDetected);
OutputDebugString(smessage);
float confidence = 0.0f;
hr = m_pDiscreteResult->get_Confidence(&confidence);
if (SUCCEEDED(hr) && confidence != 0.0f)
{
OutputDebugString(L"confidence is detected \t");
//if (confidence > 0.3f)
//{
StringCchPrintf(smessage, _countof(smessage), L"confidence value is %f\n", confidence);
OutputDebugString(smessage);
//}
}
else
{
OutputDebugString(L"no confidence\n");
}
}
else
{
OutputDebugString(L"gesture not detected\n");
}
}
else
{
OutputDebugString(L"no discrete result\n");
}
case GestureType::GestureType_Continuous:
hr = m_pVGBFrame->get_ContinuousGestureResult(m_pgesturelist[i], &m_pContinousResult);
if (SUCCEEDED(hr) && m_pContinousResult != nullptr)
{
OutputDebugString(L"continuous gesture\n");
WCHAR gesturename[100];
hr = m_pgesturelist[i]->get_Name(100, gesturename);
//if (gesturename == L"SwipeLeft")
//{
float progress = 0.0f;
OutputDebugString(L"get progress of continuous gesture \t");
hr = m_pContinousResult->get_Progress(&progress);
if (SUCCEEDED(hr) && progress != 0.0f)
{
StringCchPrintf(smessage, _countof(smessage), L"progress value is %f\n", progress);
OutputDebugString(smessage);
}
//}
}
else
{
OutputDebugString(L"no continuous gesture\n");
}
default:
break;
}
}
else
{
OutputDebugString(L"invalid gesture id\n");
}
}
else
{
OutputDebugString(L"no frame\n");
}
}
}
Is there wrong in my code? Do I need to modify my code? Can anyone help me?
I want to zero-out the contents of an UnsafeMutablePointer in Swift.
In C you usually have something like this:
void freeSecure(void *buffer, uint64_t size) {
// Create volatile pointer to make sure that the code won't be optimized away
volatile uint8_t *ptr = buffer;
for (uint64_t i = 0; i < size; i++) ptr[i] = 0x00;
free(buffer);
}
How can I achieve the same thing in Swift?
// Is extension of `UnsafeMutablePointer`
public func KC_dealloc(allocated: Int) {
if num == 0 {
self.destroy()
self.dealloc(allocated)
return
}
let byteCount = sizeof(Memory) * allocated
let ptr = UnsafeMutablePointer<UInt8>(self) // volatile???
for var i = 0; i < byteCount; i++ {
ptr[i] = 0x00
}
self.destroy()
self.dealloc(allocated)
}
Okay, I asked the same question in the Apple-developer-forum and some guy there pointed me to the memset_s-function which does what I want.
So my Swift-code should look like this:
// Is extension of `UnsafeMutablePointer`
public func KC_dealloc(allocated: Int) {
if num == 0 {
self.destroy()
self.dealloc(allocated)
return
}
let byteCount = sizeof(Memory) * allocated
let ptr = UnsafeMutablePointer<UInt8>(self) // volatile???
memset_s(ptr, byteCount, 0x00, byteCount) // Defined in C11
self.destroy()
self.dealloc(allocated)
}
I need to be able to explore a GTK GUI's structure programmatically. I have the GtkWidget and I want to find any children of that widget. Now I know that GtkContainer's have a function to find children and that GtkContainer is derived from GtkWidget.
Is there anyway I can check if a widget is a GtkContainer and then perform the cast? If not, is there any other way I can discover the GtkWidget's that are children of the one I have?
Yes, there are macros for every GObject type to check whether an object is of that type:
if(GTK_IS_CONTAINER(widget)) {
GList *children = gtk_container_get_children(GTK_CONTAINER(widget));
...
}
If the widget is a GtkBin it has only one child. In that case, the following is simpler than dealing with a GList:
if(GTK_IS_BIN(widget)) {
GtkWidget *child = gtk_bin_get_child(GTK_BIN(widget));
...
}
In the following code I have implemented find_child function which recursively searches for the widget by name. Ideas build on the answer of #ptomato and from the following PHP example:
#include <gtk/gtk.h>
GtkWidget*
find_child(GtkWidget* parent, const gchar* name)
{
if (g_strcasecmp(gtk_widget_get_name((GtkWidget*)parent), (gchar*)name) == 0) {
return parent;
}
if (GTK_IS_BIN(parent)) {
GtkWidget *child = gtk_bin_get_child(GTK_BIN(parent));
return find_child(child, name);
}
if (GTK_IS_CONTAINER(parent)) {
GList *children = gtk_container_get_children(GTK_CONTAINER(parent));
while ((children = g_list_next(children)) != NULL) {
GtkWidget* widget = find_child(children->data, name);
if (widget != NULL) {
return widget;
}
}
}
return NULL;
}
int
main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
GtkWidget *frame = gtk_frame_new(NULL);
GtkWidget *vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
GtkWidget *textView = gtk_text_view_new();
GtkWidget *hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
GtkWidget *button1 = gtk_button_new_with_label("button1");
gtk_widget_set_name(button1, "btn1");
GtkWidget *button2 = gtk_button_new_with_label("button2");
gtk_widget_set_name(button2, "btn2");
gtk_window_set_title(GTK_WINDOW(window), "Hello");
gtk_container_set_border_width(GTK_CONTAINER(window), 10);
gtk_window_set_default_size(GTK_WINDOW(window), 450, 400);
gtk_container_add(GTK_CONTAINER(window), frame);
gtk_container_add(GTK_CONTAINER(frame), vbox1);
gtk_box_pack_start(GTK_BOX(vbox1), textView, 1, 1, 0);
gtk_box_pack_start(GTK_BOX(vbox1), hbox1, 0, 1, 0);
gtk_box_pack_start(GTK_BOX(hbox1), button1, 0, 1, 0);
gtk_box_pack_start(GTK_BOX(hbox1), button2, 0, 1, 0);
gtk_widget_show_all(window);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
GtkWidget* child = find_child(window, "btn2");
if (child == button2) {
g_print("found it!\n");
} else {
g_print("not found it!\n");
}
gtk_main();
return 0;
}
I created these functions that are based on the same principal as the accepted answer.
In find_child_by_index, depth is equal to the amount of indices you need to pass. The first index is for the children of parent, the second index is for the grandchildren and so forth.
void print_children_helper(GtkWidget* parent, int indent_size, int depth)
{
for (int i = 0; i < depth * indent_size; i++)
printf(" ");
printf("%s\n", gtk_widget_get_name(parent));
GList* children = NULL;
if (GTK_IS_CONTAINER(parent))
children = gtk_container_get_children(GTK_CONTAINER(parent));
while (children != NULL)
{
print_children(children->data, indent_size, depth + 1);
children = children->next;
}
}
void print_children(GtkWidget* parent, int indent_size)
{
print_children_helper(parent, indent_size, 0);
}
GtkWidget* find_child_by_name(GtkWidget* parent, const gchar* name)
{
if (g_strcmp0(gtk_widget_get_name(parent), name) == 0)
return parent;
GList* children = NULL;
if (GTK_IS_CONTAINER(parent))
children = gtk_container_get_children(GTK_CONTAINER(parent));
while (children != NULL)
{
GtkWidget* widget = find_child_by_name(children->data, name);
if (widget != NULL)
return widget;
children = children->next;
}
return NULL;
}
GtkWidget* find_child_by_index(GtkWidget* parent, int depth, ...)
{
va_list argp;
va_start(argp, depth);
for (int i = 0; i < depth; i++)
{
int index = va_arg(argp, int);
GList* children = NULL;
if (GTK_IS_CONTAINER(parent))
children = gtk_container_get_children(GTK_CONTAINER(parent));
for (int j = 0; j < index; j++)
if (children != NULL)
children = children->next;
if (children != NULL)
parent = children->data;
else
return NULL;
}
va_end(argp);
return parent;
}
A different approach is needed if using GTK4 as GtkContainer no longer exists. See migration guide
A simple function traversing the widget heirarchy:
void print_widget_names(GtkWidget* parent, int level) {
for (int i=0; i < level; i++) {
g_print(" ");
}
level++;
g_print("%s\n", gtk_widget_get_name(GTK_WIDGET(parent)));
GtkWidget *widget = gtk_widget_get_first_child(GTK_WIDGET(parent));
GtkWidget *next;
if (widget != NULL) {
print_widget_names(widget, level);
while ((next = gtk_widget_get_next_sibling(widget)) != NULL) {
widget = next;
print_widget_names(widget, level);
}
}
}