LINUX.ORG.RU

Правильная передача указателей на ресурсы Gtk/ZeroMQ.


0

1

Учусь писать на Gtk и ZeroMQ одновременно. В данный момент код ужасен чуть более, чем полностью, однако есть вещь, которая меня интересует более остальных. При использовании обоих библиотек функциям-обработчикам событий надо передавать некоторые ресурсы, такие как, например, контекст и сокеты от ZeroMQ. В связи с этим появились три структуры-обертки для передачи этих параметров. Мне это кажется очень уродливым и хотелось бы узнать нормальное решение. (Почему-то очевидное «сделать глобальные статические ресурсы» кажется мне не менее уродливым) Заранее спасибо за помощь =)

#include <gtk/gtk.h>
#include <zmq.h>
#include <stdlib.h>
#include <string.h>

#define BOX_SPACING 5

typedef struct
{
	GtkWidget *widget[5];
} WidgetSet;

typedef struct
{
	void *res[5];
} ZMQResourcesSet;

typedef struct
{
	WidgetSet * controls;
	ZMQResourcesSet * zmq;
} ResList;

static gboolean deleteEvent(GtkWidget *widget, gpointer data)
{
	return FALSE;
}

static void destroyEvent (GtkWidget *widget, gpointer data)
{
	ZMQResourcesSet t = *((ZMQResourcesSet *)data);
	zmq_close(t.res[1]);
	zmq_term(t.res[0]);
	gtk_main_quit();
}

static void buttonClicked (GtkObject *widget, gpointer data)
{
	WidgetSet IOControls = *(((ResList*)data)->controls);
	ZMQResourcesSet zmqRes = *(((ResList*)data)->zmq);
	void * context = zmqRes.res[0];
	void * sender = zmqRes.res[1];
	zmq_msg_t request, reply;
	int replyLen;
	char *answ, *text = gtk_entry_get_text((struct GtkEntry*)(IOControls.widget[1]));
	

	/*Send a message to server*/
	zmq_msg_init_size(&request, strlen(text));
	memcpy(zmq_msg_data(&request), text, strlen(text));
	zmq_send(sender, &request, 0);
	zmq_msg_close(&request);

	/*Recieve a reply from server*/
	zmq_msg_init(&reply);
	zmq_recv(sender, &reply, 0);
	replyLen = zmq_msg_size(&reply);
	answ = malloc (sizeof(char*)*(replyLen + 1));
	memcpy(answ, zmq_msg_data(&reply), replyLen);
	zmq_msg_close(&reply);
	answ[replyLen] = '\0';

	/*Change label text*/
	gtk_label_set_text((struct GtkLabel*)(IOControls.widget[0]), answ);
}

int main(int argc, char ** argv)
{
	GtkWidget *window;
	GtkWidget *label, *button, *textEntry, *vbox, *hbox;
	WidgetSet IOControls;
	void *context, *sender;
	ZMQResourcesSet ZmqRes;
	ResList reses = {&IOControls, &ZmqRes};

	gtk_init (&argc, &argv);
	context = zmq_init(1);

	/*Socket*/
	sender = zmq_socket(context, ZMQ_REQ);
	zmq_connect(sender, "tcp://localhost:5555");
	ZmqRes.res[0] = context;
	ZmqRes.res[1] = sender;
	
	/*Window*/
	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	g_signal_connect (window, "delete_event", G_CALLBACK(deleteEvent), NULL);
	g_signal_connect (window, "destroy_event", G_CALLBACK(destroyEvent), (gpointer)&ZmqRes);

	/*Label (main text area)*/
	label = gtk_label_new("Some text");

	/*Text Entrie*/
	textEntry = gtk_entry_new();
	
	/*Button*/
	button = gtk_button_new_with_label("OK");
	IOControls.widget[0] = label;
	IOControls.widget[1] = textEntry;
	g_signal_connect(button, "clicked", G_CALLBACK(buttonClicked), (gpointer)&reses);

	/*Widgets packing*/
	vbox = gtk_vbox_new (FALSE, BOX_SPACING);
	hbox = gtk_hbox_new (FALSE, BOX_SPACING);
	gtk_box_pack_start(GTK_BOX(hbox), textEntry, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
	gtk_container_add(GTK_CONTAINER(window), vbox);


	/*Finaly let us show widgets*/
	gtk_widget_show  (label);
	gtk_widget_show  (button);
	gtk_widget_show  (textEntry);
	gtk_widget_show  (hbox);
	gtk_widget_show  (vbox);
	gtk_widget_show  (window);
	gtk_main ();

	return 0;
}


Последнее исправление: nethoroth (всего исправлений: 1)

уродливо оно потому, что вместо человечески обозванных полей в структурах используются неудобоваримые массивы

ananas ★★★★★
()

Убрать промежуточные

struct ResList {
    GtkWidget *widget[5];
    void *res[5];
} *reses;

g_signal_connect(,,, reses->widget); // принимать как (GtkWidget **)
g_signal_connect(,,, reses);

Можно сразу объявлять нормальный тип аргумента, а тип callback'а кастить, что уже делается в G_CALLBACK().

static void destroyEvent (GtkWidget *widget, void *res[];
static void buttonClicked (GtkObject *widget, ResList *reses);

В принципе ничего не мешает все время передавать одно и то же, суй везде reses и не будешь путаться что куда влетает.

Не по теме: глобальные статические они как раз для таких случаев.

arturpub ★★
()

ananas, arturpub, спасибо, это полезно было услышать)

nethoroth
() автор топика
Ответ на: комментарий от nethoroth

«Правильно» каждые 5 лет меняется. Используй то, что сейчас принесет пользу и не повредит в ближайшей перспективе.

arturpub ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.