when use ncurses in multi-threaded , the terminal garbled [duplicate] - c

This question already has an answer here:
Why has no one written a threadsafe branch of the ncurses library?
(1 answer)
Closed 5 years ago.
When I use ncurses write a library management system, terminals garbled when multi-threaded,my layout has three windows.
1.My code named ncurses.c
#include <stdio.h>
#include <ncurses.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
typedef struct _WIN_struct {
int startx, starty;
int height, width;
} WIN;
WIN winTitle; /* title win */
WIN winMenu; /* Main menu win */
WIN winNews; /* win news */
WINDOW *create_newwin(int height, int width, int starty, int startx) {
WINDOW *local_win;
local_win = newwin(height, width, starty, startx);
box(local_win, 0, 0);
wrefresh(local_win);
return local_win;
}
char *getTimeNow() {
time_t rawtime;
struct tm *timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
return asctime(timeinfo);
}
void *threadfunc_title(void *p) {
WINDOW *windowTitle;
windowTitle = create_newwin(winTitle.height, winTitle.width, winTitle.starty, winTitle.startx);
/* show title and time */
for (;;) {
mvwprintw(windowTitle, winTitle.height/2, winTitle.width/2 - 10, "%s", "Library Management System");
mvwprintw(windowTitle, winTitle.height-2, winTitle.width-30, "%s", getTimeNow());
wrefresh(windowTitle);
sleep(1);
}
}
void *threadfunc_menu(void *p) {
WINDOW *windowMenu;
windowMenu = create_newwin(winMenu.height, winMenu.width, winMenu.starty, winMenu.startx);
for (;;) {
/* now do nothing */
sleep(1);
}
}
void *threadfunc_news(void *p) {
WINDOW *windowNews;
windowNews = create_newwin(winNews.height, winNews.width, winNews.starty, winNews.startx);
for (;;) {
wprintw(windowNews, "%d. %s,%s", getTimeNow(), 1, "a borrow a book from c");
wrefresh(windowNews);
wclear(windowNews);
sleep(5);
}
}
void initWin(WIN *p_win, int height, int width, int starty, int startx) {
p_win->height = height;
p_win->width = width;
p_win->starty = starty;
p_win->startx = startx;
}
int main(int argc, char *argv[])
{
pthread_t pidTitle;
pthread_t pidMenu;
pthread_t pidNews;
initscr();
start_color();
cbreak();
keypad(stdscr, TRUE);
noecho();
/* init location */
initWin(&winTitle, LINES*0.2, COLS, 0 , 0);
initWin(&winMenu, LINES*0.7, COLS*0.7, LINES*0.25, 0);
initWin(&winNews, LINES*0.7, COLS*0.2, LINES*0.25, COLS*0.7);
pthread_create(&pidTitle, NULL, threadfunc_title, NULL);
pthread_create(&pidMenu, NULL, threadfunc_menu, NULL);
pthread_create(&pidNews, NULL, threadfunc_news, NULL);
pthread_join(pidTitle, NULL);
pthread_join(pidMenu, NULL);
pthread_join(pidNews, NULL);
endwin();
return 0;
}
2.Three threads for three windows, thread_func_xxx() is pthread_create() third parameter.
3.Compile and Run
$ gcc ncurses.c -lncurses -lpthread -o ncurses
$ ./ncurses
then, I get terminal garbled.
ps:
1.I have changed -lncurses to -lncursesw, but no effect.
2.if you don not have installed ncurses, you can follow this.

short: the example won't work because the lower-level functions used to update the screen share data which isn't mutex'd. If you compile ncurses with the pthread option, that improves the re-entrancy of the higher-level functions and adds some mutexes, it's possible to use multiple threads.

Related

Create a System Tray Icon in Linux without GTK/QT

I need to create a Tray Icon for my application using purely the Xlib. After some searching, reading the XEmbed documentation and some stuff on SO, this is what the code looks like so far (mostly copy & paste). I understand what it does, but not why. It is creating a tray icon appearantly, but only 1px wide in my mate-panels area. What am I doing wrong? Why is it not the size of a normal tray icon?
Here is my code:
#include <X11/Xutil.h>
#include <string.h>
#define MIN(A, B) ((A) < (B) ? (A) : (B))
/* --------- XEMBED and systray stuff */
#define SYSTEM_TRAY_REQUEST_DOCK 0
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
static int trapped_error_code = 0;
static int (*old_error_handler) (Display *, XErrorEvent *);
static int
error_handler(Display *display, XErrorEvent *error) {
trapped_error_code = error->error_code;
return 0;
}
void
trap_errors(void) {
trapped_error_code = 0;
old_error_handler = XSetErrorHandler(error_handler);
}
int
untrap_errors(void) {
XSetErrorHandler(old_error_handler);
return trapped_error_code;
}
void
send_systray_message(Display* dpy, long message, long data1, long data2, long data3) {
XEvent ev;
Atom selection_atom = XInternAtom (dpy,"_NET_SYSTEM_TRAY_S0",False);
Window tray = XGetSelectionOwner (dpy,selection_atom);
if ( tray != None)
XSelectInput (dpy,tray,StructureNotifyMask);
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = tray;
ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
ev.xclient.format = 32;
ev.xclient.data.l[0] = CurrentTime;
ev.xclient.data.l[1] = message;
ev.xclient.data.l[2] = data1; // <--- your window is only here
ev.xclient.data.l[3] = data2;
ev.xclient.data.l[4] = data3;
trap_errors();
XSendEvent(dpy, tray, False, NoEventMask, &ev);
XSync(dpy, False);
usleep(10000);
if (untrap_errors()) {
/* Handle errors */
}
}
/* ------------ Regular X stuff */
int
main(int argc, char **argv) {
int width, height;
XWindowAttributes wa;
XEvent ev;
Display *dpy;
int screen;
Window root, win;
/* init */
if (!(dpy=XOpenDisplay(NULL)))
return 1;
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
if(!XGetWindowAttributes(dpy, root, &wa))
return 1;
width = height = MIN(wa.width, wa.height);
/* create window */
win = XCreateSimpleWindow(dpy, root, 0, 0, width, height, 0, 0, 0x7F7F997F);
send_systray_message(dpy, SYSTEM_TRAY_REQUEST_DOCK, win, 0, 0); // pass win only once
XMapWindow(dpy, win);
XSync(dpy, False);
/* run */
while(1) {
while(XPending(dpy)) {
XNextEvent(dpy, &ev); /* just waiting until we error because window closed */
}
}
}
I am thankful for everything that will point me in the right direction, even if its just some documentation that I have not found so far.

How to fork a child proccess without stalling parent process in C

My GTK+2/C application uses Opencv library to grab frames continuously from the web camera feed and there's a UI button, which should calculate some information by grabbing a frames upon clicking.
This button click calculation takes 1-2 seconds and depend on the system resources. (on Raspberry pi, it takes 3-5 seconds)
Previously all functionalities (viewing + calculations) were inside the same main process. However when doing the calculation, whole app (video feed) used to freeze until the completion if the calculation.
I have implemented fork()to make child processes and keep the interprocess communications via pipe() to update the UI with calculated data.
However now the lagging time got lot bigger like 5-6 seconds.
below shows the sample code.
Is there any particular way to avoid this kind of lagging of the main process?
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
#include <diamond_calcs.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/videodev.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <opencv/cv.h>
#include <opencv/cxcore.h>
#include "highgui.h"
#include <X11/Xlib.h>
/* declaring the opencv capture variable */
CvCapture* capture, *fm_capture;
GdkPixbuf* pix;
IplImage* frame, *frame_sized;
gboolean expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data);
gboolean timeout(gpointer data);
gboolean autoon_clicked_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data[]);
// This function grabs a frame and recording some values. also this is the function called by the child process also.
gboolean frame_grabber(void)
{
/* setting up the edge ditection */
IplImage *frame_bgr;
if(frame){
//frame_bgr = cvQueryFrame( capture );
frame_bgr = frame_sized;
}
else{
frame_bgr = cvLoadImage("./data/media/novideo.png", 1);
}
/* Converting Color SPACE to greyscale */
int y_pos, x_pos;
int counter=0;
typedef enum { false, true } bool;
bool col_break = false;
for(int y=0;y<frame_bgr->height;y++)
{
for(int x=0;x<frame_bgr->width;x++)
{
CvScalar color = cvGet2D(frame_bgr, y, x);
if(color.val[0]<color_filter_thres){
if (y_pos == y){
counter++;
}
x_pos = x;
y_pos = y;
if (counter > 2){
//printf("top: %i, %i \n", x_pos, y_pos);
col_break = true;
break;
}
}
}
if (col_break){
break;
}
}
ruler_top_cal_preset = y_pos;
/* bottom ruler - scanning backwards*/
int y_pos_bot, x_pos_bot;
int counter_bot=0;
bool col_break2 = false;
for(int y_b=frame_bgr->height-1;y_b>0;y_b--)
{
for(int x_b=frame_bgr->width-1;x_b>0;x_b--)
{
CvScalar color_bot = cvGet2D(frame_bgr, y_b, x_b);
if(color_bot.val[0]<color_filter_thres){
if (y_pos_bot == y_b){
counter_bot++;
}
x_pos_bot = x_b;
y_pos_bot = y_b;
if (counter_bot > 2){
//printf("bottom: %i, %i \n", x_pos_bot, y_pos_bot);
col_break2 = true;
break;
}
}
}
if (col_break2){
break;
}
}
ruler_bottom_cal_preset = y_pos_bot;
dfactor_preset = ruler_bottom_cal_preset - ruler_top_cal_preset;
}
/*
* main
*
* Program begins here
*/
//####### Lot of processes going inside main, ignore it, just focus on the program flow
int main( int argc, char **argv )
{
/* variables structs to load the gtk_ based widgets and windows */
GtkBuilder *builder;
GtkWidget *window, *event_box, *drawing_area;
GError *error = NULL;
GError *error_settings = NULL;
GtkButton *button;
GtkLabel *label;
/* Init GTK+ */
gtk_init( &argc, &argv );
/* Create new GtkBuilder object */
builder = gtk_builder_new();
/* Load UI from file. If error occurs, report it and quit application. */
if( ! gtk_builder_add_from_file( builder, "file_glade.glade", &error ) )
{
g_warning( "%s", error->message );
g_free( error );
return( 1 );
}
/* Get main window pointer from UI */
window = GTK_WIDGET( gtk_builder_get_object( builder, "window1" ) );
/* creating the drawing area */
drawing_area = gtk_drawing_area_new();
gtk_container_add (GTK_CONTAINER(event_box), drawing_area);
gtk_widget_show (drawing_area);
/* connects the draw (expose-event) with the handler */
g_signal_connect (drawing_area, "expose-event",
G_CALLBACK (expose_event_callback), NULL);
gtk_label_set(labels[0], "Min :");
//####### Here goes the calculation clicking
gtk_signal_connect (GTK_OBJECT (gtk_builder_get_object( builder, "autoon_button" )), "clicked",
GTK_SIGNAL_FUNC (autoon_clicked_cb), labels);
/* Show window. All other widgets are automatically shown by GtkBuilder */
gtk_widget_show( window );
/* load last saved values */
file_load( spinners );
//#######
int fd;
if((fd = open("/dev/video0", O_RDONLY)) == -1){
printf("NO CAP\n");
capture = NULL;
}
else{
capture = cvCreateCameraCapture(0);
cvSetCaptureProperty(capture, CV_CAP_PROP_BRIGHTNESS, brght);
cvSetCaptureProperty(capture, CV_CAP_PROP_CONTRAST,contra);
cvSetCaptureProperty(capture, CV_CAP_PROP_SATURATION, satu);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 800);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 600);
// ## remove the forking from here and add that to the expose function
pid_t pID1 = vfork();
if (pID1 == 0) // child process
{
g_timeout_add (15, timeout, drawing_area);
//_exit(0);
}
else if ( pID1 < 0 ){
printf("Failed to fork video overlay child process \n");
exit(1);
}
}
/* Destroy builder, since we don't need it anymore */
g_object_unref( G_OBJECT( builder ) );
//g_object_unref( G_OBJECT( settings_builder ) );
//g_object_unref( G_OBJECT( about_builder ) );
/* Start main loop */
gtk_main();
return( 0 );
}
/* This function runs every x seconds and making the video feed */
/*
* Function: expose_event_callback
* --------------------
* When the widget is exposed of force to expose ths function handler will run to generate the video feed
*
* returns: none
*/
gboolean
expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
/* Capture a single frame from the video stream */
if (capture){
frame = cvQueryFrame( capture );
frame_sized = frame;
pix = gdk_pixbuf_new_from_data((guchar*) frame->imageData,
GDK_COLORSPACE_RGB, FALSE, frame->depth, frame->width,
frame->height, (frame->widthStep), NULL, NULL);
}
else{
printf("You've done it\n");
pix = gdk_pixbuf_new_from_file("./data/media/novideo.png", NULL);
}
/* putting the generated pix buff to the correct layout (GTK widget) */
gdk_draw_pixbuf(widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE (widget)], pix, 0, 0, 0, 0,
-1, -1, GDK_RGB_DITHER_NONE, 0, 0); /* Other possible values are GDK_RGB_DITHER_MAX, GDK_RGB_DITHER_NORMAL */
return TRUE;
}
/*
* Function: timeout
* --------------------
* This function runs inbetween given time period. It calls the required functions to generate video and drawing
*
* returns: none
*/
gboolean timeout(gpointer data)
{
/* DEBUG print */
//printf("Time out Hello: %d\n", rand());
/* Redraws the Widget. Widget will call for the callback function again */
gtk_widget_queue_draw (data);
/* Starting the drawing function */
//ofdra(data,NULL);
return TRUE;
}
gboolean autoon_clicked_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data[])
{
char display1_entry_text[100];
int x = 1;
int pfds[2];
pipe(pfds);
pid_t pID = fork();
if (pID == 0) // child process
{
double ytops[10];
double ybots[10];
double min_diam;
double max_diam;
double avg_diam;
clock_t t1, t2,end_t; // clocking for debugging purposes
t2 = clock();
for(int i=0;i<15;i++)
{
//measure_clicked_callback(widget, NULL, data);
frame_grabber();
ytops[i] = ruler_top_cal_preset;
ybots[i] = ruler_bottom_cal_preset;
t1 = clock();
float x = (float)(t1-t2);
float y = x/CLOCKS_PER_SEC;
float z = y*1000;
t2 = t1;
}
/* sorting arrays for ascending order */
if(ybots && ytops){
array_sorter(ybots);
array_sorter(ytops);
min_diam = (ybots[0]-ytops[9])/scale_factor;
max_diam = (ybots[9]-ytops[0])/scale_factor;
avg_diam = (min_diam+max_diam)/2;
}
sprintf(display1_entry_text0,"Min : %.3g",min_diam);
write(pfds[1], display1_entry_text0, 100);
_exit(0);
}
else if(pID <0){
printf("Failed to fork \n");
exit(1);
}
else{
//parent process
char buf[100];
read(fpds[0], buf, 100);
//updates the gtk interface with read value
gtk_lable_set(data[0], buf);
wait(NULL);
}
return TRUE;
}
**Note I have pasted this code from the actual whole code, also this will not run. Pasted only here for give some idea about what I'm trying to achieve.
It looks like you have blocking read and wait calls in your parent process. In other words, despite the fact that you spawn a child process to perform the calculations, you still block your parent process till the child process completes. No parallelism is achieved.
I would suggest having a worker thread in the process that would do the calculations and notify the main thread when the results are available.
In the parent process/thread you should make the read end of the pipe non-blocking and register it with the event loop. Once the read end becomes ready for read, read all data in non-blocking mode.
Set a signal handler for SIGCHLD and call wait in it to release the child process resources.

Edit the amount of colors available in a picture plotting program. It's written in C with Xlib

I'm a fortran programmer working with a program written in C (which I have Little to no experience with).
I have a program written in fortan that creates an image in the form of a multidimentional array of pixels with their X value, Y value, and RGB values (0-4 for each color). It then passes the array, the size of the array in the x and y dimensions, the color map containing all the colors arranged in a spectrum, and the number of colors in the spectrum to a program written in C that is supposed to plot the image using Xlib.
The program works when I pass a particular one color map with 125 colors (5 values for red/green/blue) but when I try to increase the amount of colors I pass to the C program I exceed some sort of limit and the program shuts down. How do I raise the limit in the C source code?
Here is the program:
#define USEPIXMAP /* sets drawing into background pixmap of window */
#include "putras.h"
#include <stdlib.h>
static unsigned def_map[256];
void putras_(int *pixel_values, int *arrayx, int *arrayy,
int *colormap_entries, int *colormap_size)
{
extern Colormap cmap;
extern Window window;
extern Display *dpy;
extern XColor color;
extern XWindowAttributes window_attr;
extern GC gc;
extern XGCValues gcv;
extern Pixmap pixmap;
static int call_flag = 0;
char *display_name=NULL;
char *dummy;
unsigned pixel;
int i, j;
XPoint *pointarray[256];
unsigned arraylen[256];
unsigned maxlen[256];
int remain_len;
if(call_flag == 0) {
/* THis only gets done on the first call to putras */
call_flag = 1;
if( (dpy = XOpenDisplay(display_name) ) == NULL){
fprintf(stderr,"Error: Couldn't open display\n");
exit(1);
}
XGetWindowAttributes(dpy, RootWindow(dpy,DefaultScreen(dpy)),
&window_attr);
window=XCreateSimpleWindow(dpy, RootWindow(dpy, DefaultScreen(dpy)), 0, 0,
*arrayx, *arrayy,window_attr.border_width,
BlackPixel(dpy, DefaultScreen(dpy)),
WhitePixel(dpy, DefaultScreen(dpy)));
#ifdef USEPIXMAP
pixmap=XCreatePixmap(dpy, window, *arrayx, *arrayy,
DefaultDepth(dpy,DefaultScreen(dpy)) );
XMapWindow(dpy, window);
XClearWindow(dpy, window);
XCopyArea(dpy, window, pixmap, DefaultGC(dpy, DefaultScreen(dpy)),
0,0,*arrayx, *arrayy, 0,0);
XFlush(dpy);
#else
XMapWindow(dpy, window);
#endif
cmap=DefaultColormap(dpy,DefaultScreen(dpy));
color.flags=DoRed|DoBlue|DoGreen;
for (i=0;i<(*colormap_size);i++){
color.pixel= colormap_entries[4*i];
j = color.pixel;
color.red=colormap_entries[4*i+1];
color.green=colormap_entries[4*i+2];
color.blue=colormap_entries[4*i+3];
XAllocColor(dpy, cmap, &color);
def_map[j] = color.pixel;
}
gc = XCreateGC(dpy, window, 0, NULL);
} /* Endif - first time through */
/* The following gets done on each call */
for (i=0; i<256; i++){
pointarray[i]=(XPoint *)malloc((*arrayx)*(*arrayy)/128*sizeof(XPoint));
maxlen[i]=(*arrayx)*(*arrayy)/128 -1;
arraylen[i]=0;
}
for (j=0; j<(*arrayy); j++) {
for (i=0; i<(*arrayx); i++) {
/*pixel = def_map[pixel_values[j * (*arrayx) + i]];*/
pixel=pixel_values[j*(*arrayx)+i];
/*pixel=1;*/
if (arraylen[pixel]==maxlen[pixel]) {
pointarray[pixel]= (XPoint *)realloc(pointarray[pixel],
2*maxlen[pixel]*sizeof(XPoint));
maxlen[pixel]=2*maxlen[pixel];
}
pointarray[pixel][arraylen[pixel]].x=i;
pointarray[pixel][(arraylen[pixel])++].y=j;
} /* end for loop*/
} /* end for loop*/
for (i=0; i<256; i++) {
XSetForeground(dpy, gc, def_map[i]);/*dpy,gc,i);*/
if (arraylen[i]>=MAXPOINT) {
for (j=0; j<=(arraylen[i]/MAXPOINT); j++) {
remain_len=(arraylen[i]-MAXPOINT*j);
#ifdef USEPIXMAP
XDrawPoints(dpy, pixmap, gc,(pointarray[i]+j*MAXPOINT),
((remain_len<MAXPOINT)?remain_len:MAXPOINT),
CoordModeOrigin);
#else
XDrawPoints(dpy, window, gc,(pointarray[i]+j*MAXPOINT),
((remain_len<MAXPOINT)?remain_len:MAXPOINT),
CoordModeOrigin);
#endif
} /* end for loop */
} else {
#ifdef USEPIXMAP
XDrawPoints(dpy, pixmap, gc, pointarray[i], arraylen[i],
CoordModeOrigin);
#else
XDrawPoints(dpy, window, gc, pointarray[i], arraylen[i],
CoordModeOrigin);
#endif
} /* end if */
} /* end for loop 256 */
#ifdef USEPIXMAP
XSetWindowBackgroundPixmap(dpy, window, pixmap);
XClearWindow(dpy, window);
#endif
XFlush(dpy);
for (i=0; i<256;i++)
free(pointarray[i]);
return;
}
void unmap(void)
{
/* extern Pixmap pmap; */
extern Window window;
extern Display *dpy;
/* int width, height; */
XUnmapWindow(dpy, window);
XFlush(dpy);
return;
}
void remap(void)
{
extern Window window;
extern Display *dpy;
XMapRaised(dpy, window);
XFlush(dpy);
return;
}

Calling GTK_MAIN under Pthread(secondary thread) in C code

This is in my continuation of GTK understanding::
Is it right to call GTK_MAIN() under pthread from Main?? sample code ::
from main i call dispInit(argc, argv); from which i call g_thread_create(main_callback, NULL, FALSE, NULL);
** also i have not included g_idle_add in this code..this is just a reference code.
Please guide
#include <stdio.h>
#include <glib.h>
#include <gtk/gtk.h>
//#include "dispimage.h"
#include <windows.h>
#define sleep(n) Sleep(1000 * n)
GtkWidget* window;
void dispInit(int argc, char* argv[]);
void dispInfoPage(char* fileName, int duration);
gpointer main_callback(gpointer data)
{
gtk_main();
return 0;
}
void dispInit(int argc, char* argv[])
{
gdk_threads_init();
gdk_threads_enter();
printf("Initializing the display library\n");
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_resize(GTK_WINDOW(window), 640, 480);
gtk_window_set_default_size(GTK_WINDOW(window), 640, 480);
gtk_widget_realize( window );
gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
g_thread_create(main_callback, NULL, FALSE, NULL);
gdk_threads_leave();
}
void dispInfoPage(char* fileName, int duration)
{
int index;
gdk_threads_enter();
printf("Initializing dispInfoPage\n");
destroyWidget();
printf("Initializing dispInfoPage1\n");
GtkWidget *image;
image = gtk_image_new_from_file(fileName);
printf("Initializing dispInfoPage2\n");
gtk_container_add(GTK_CONTAINER(window), image);
gtk_widget_show(image);
gtk_widget_show(window);
printf("Initializing dispInfoPage4\n");
printf("Initializing dispInfoPage5\n");
gdk_threads_leave();
printf("Initializing dispInfoPage6\n");
}
void destroyWidget()
{
GList *children, *iter;
struct WidgetsAlive *temp, *prev, *next, *depTemp;
children = gtk_container_get_children(GTK_CONTAINER(window));
for(iter = children; iter != NULL; iter = g_list_next(iter)){
gtk_container_remove(GTK_CONTAINER(window),GTK_WIDGET(iter->data));
printf("Deleting Widget\n");
}
g_list_free(iter);
g_list_free(children);
}
int dispTextPage(char* fileName, int isJustifyCenter)
{
int index;
GtkWidget *textv;
GdkWindow *textv_window;
GdkPixmap *pixmap = NULL;
GtkTextBuffer *textBuffer;
gdk_threads_enter();
GdkColor color;
char debugBuf[128] = { '\0' };
char newfName[100]={'\0'};
char ext[4]={'\0'};
char temp[100]={'\0'};
int i;
FILE * fd;
destroyWidget();
textBuffer = gtk_text_buffer_new(NULL);
textv = gtk_text_view_new_with_buffer(textBuffer);
gtk_text_view_set_left_margin(GTK_TEXT_VIEW(textv), 22);
gtk_text_view_set_right_margin(GTK_TEXT_VIEW(textv), 20);
gtk_text_view_set_pixels_above_lines(GTK_TEXT_VIEW(textv),1);
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textv), GTK_WRAP_CHAR);
if (isJustifyCenter == 1)
{
gtk_text_view_set_justification(GTK_TEXT_VIEW(textv), GTK_JUSTIFY_CENTER);
}
else
{
gtk_text_view_set_justification(GTK_TEXT_VIEW(textv), GTK_JUSTIFY_LEFT);
}
gtk_text_view_set_editable(GTK_TEXT_VIEW(textv), FALSE);
gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(textv), FALSE);
printf("tttt0");
gtk_container_add(GTK_CONTAINER(window), textv);
printf("tttt1");
textv_window = gtk_text_view_get_window (GTK_TEXT_VIEW (textv),
GTK_TEXT_WINDOW_TEXT);
gdk_color_parse ("#68604d", &color);
pixmap = gdk_pixmap_create_from_xpm ((GdkDrawable *) textv_window, NULL,
&color, fileName);
gdk_window_set_back_pixmap (textv_window, pixmap, FALSE);
g_object_unref(pixmap);
textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textv));
gtk_text_buffer_create_tag (textBuffer, "Red", "foreground", "Red", NULL);
gtk_text_buffer_create_tag (textBuffer, "RedBold","foreground", "Red",NULL);
gtk_text_buffer_create_tag(textBuffer, "gray_bg", "background", "gray", NULL);
gtk_text_buffer_create_tag(textBuffer, "italic", "style", PANGO_STYLE_ITALIC, NULL);
gtk_text_buffer_create_tag(textBuffer, "bold","weight", PANGO_WEIGHT_BOLD, NULL);
gtk_text_buffer_create_tag (textBuffer, "RedFontWeight", "weight", 1000,NULL);
gtk_text_buffer_create_tag (textBuffer, "RedBoldFontWeight","weight", 1000,NULL);
gtk_widget_show(textv);
gtk_widget_show(window);
gdk_threads_leave();
return index;
}
void *fsmThread_RunFunction()
{
int pollMsgRetVal = -1;
printf("Now enter into for image");
dispInfoPage("../images/givefp.gif",1);
sleep(5);
dispInfoPage("../images/bootup.gif",1);
sleep(5);
dispInfoPage("../images/givefp.gif",1);
sleep(5);
dispInfoPage("../images/bootup.gif",1);
sleep(5);
printf("Now enter into for disptext");
dispTextPage("",0);
printf("Now exit for disptext");
}
int main(int argc, char *argv[])
{
GThread *fsmThreadId;
GError *error = NULL;
g_thread_init(NULL);
dispInit(argc, argv);
dispInfoPage("../images/bootup.gif",1);
sleep(5);
printf("Now creat ethread ");
fsmThreadId = g_thread_create(fsmThread_RunFunction,NULL,TRUE,&error);
if (error) {
fflush(stderr);
exit(1);
}
g_thread_join(fsmThreadId);
sleep(2);
printf("ENd of main");
return 0;
}
The short answer: yes, you can call gtk_main() from a thread other than the main C thread, as long as you consistently call all GTK API functions from the same thread throughout the lifetime of the process. More details follow.
According to the documentation, GTK and GDK are not thread-safe (they cannot be concurrently called from multiple threads), but they are thread-aware — they provide locking functions such as gdk_threads_enter and gdk_threads_leave that can be used to synchronize GTK calls accross multiple threads. However, the documentation goes on to say that "with the Win32 backend, GDK and GTK+ calls should not be attempted from multiple threads at all." So, if you care about portability to Windows, you will want to avoid attempting to call GTK API calls from multiple threads. Additionally, GTK 3 completely deprecated the use of the threading locks.
There is, however, one way to safely call into GTK from multiple threads that works on all architectures: place the GTK calls in a function and pass it as callback to g_idle_add (without any special locking) — from any thread. It will schedule the callback to be invoked by the GTK main loop, in whatever thread is running it. This is documented at the end of the description section of the documentation, above the start of the details section.
A word on terminology: the word "main thread" in C normally refers to the thread that runs the C main() function. In a GTK context, the "main thread" often confusingly refers to the thread running the GTK main loop. While the two can be (and typically are) one and the same, GTK doesn't really care what thread you call the main loop from, as long as you call all GTK functions (including gtk_main) from the same one. To avoid confusion, it is best to refer to this thread as the GTK thread, the main loop thread, or the GUI thread.

how to add Xorg event handing in g_main_loop

I have a lightweight application that catches Xorg and dbus events. In order to do this I initialized dbus loop and started g_main_loop, but I don't know how to add Xorg event handling in a natural way:
GMainLoop * mainloop = NULL;
mainloop = g_main_loop_new(NULL,FALSE);
dbus_g_thread_init ();
dbus_init();
// <<<<<<<<<<<<<<<<<<<<<<<<<
//1 way using timeout
//g_timeout_add(100, kbdd_default_iter, mainloop);
//2nd way using pthread
//GThread * t = g_thread_create(kbdd_default_loop, NULL, FALSE, NULL);
//>>>>>>>>>>>>>>>>>>>>>>>>>>>
g_main_loop_run(mainloop);
in default iter I'm checking if there is waiting X-event and handle them.
Both ways seems bad, first because I have unneeded calls for checking event, second because I make an additional thread and have to make additional locks.
P.S. I know I can use gtk lib, but I don't want to have dependencies on any toolkit.
If you want to add Xorg event handling to the main loop without using a timeout (which as you state is wasteful), you'll need to add a source that polls the X connection. For that, you'll need to get below the Xlib abstraction layer to get the underlying X connection file descriptor. That's what the complete program below does. It is an adaptation of C. Tronche's excellent X11 tutorial to use the glib main loop for polling. I also drew from "Foundations of GTK+ Development" by Andrew Krause.
If this doesn't seem very "natural", that's because I doubt there is a very "natural" way to do this - you're really re-implementing a core part of GDK here.
/* needed to break into 'Display' struct internals. */
#define XLIB_ILLEGAL_ACCESS
#include <X11/Xlib.h> // Every Xlib program must include this
#include <assert.h> // I include this to test return values the lazy way
#include <glib.h>
typedef struct _x11_source {
GSource source;
Display *dpy;
Window w;
} x11_source_t;
static gboolean
x11_fd_prepare(GSource *source,
gint *timeout)
{
*timeout = -1;
return FALSE;
}
static gboolean
x11_fd_check (GSource *source)
{
return TRUE;
}
static gboolean
x11_fd_dispatch(GSource* source, GSourceFunc callback, gpointer user_data)
{
static gint counter = 0;
Display *dpy = ((x11_source_t*)source)->dpy;
Window window = ((x11_source_t*)source)->w;
XEvent e;
while (XCheckWindowEvent(dpy,
window,
EnterWindowMask,
&e))
{
if (e.type == EnterNotify)
g_print("We're in!!! (%d)\n", ++counter);
}
return TRUE;
}
static gboolean
msg_beacon(gpointer data)
{
static gint counter = 0;
g_print("Beacon %d\n", ++counter);
return TRUE;
}
int
main()
{
Display *dpy = XOpenDisplay(NULL);
assert(dpy);
int blackColor = BlackPixel(dpy, DefaultScreen(dpy));
int whiteColor = WhitePixel(dpy, DefaultScreen(dpy));
Window w = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0,
200, 100, 0, blackColor, blackColor);
XSelectInput(dpy, w, StructureNotifyMask | EnterWindowMask);
XMapWindow(dpy, w);
for (;;) {
XEvent e;
XNextEvent(dpy, &e);
if (e.type == MapNotify)
break;
}
GMainLoop *mainloop = NULL;
mainloop = g_main_loop_new(NULL, FALSE);
/* beacon to demonstrate we're not blocked. */
g_timeout_add(300, msg_beacon, mainloop);
GPollFD dpy_pollfd = {dpy->fd,
G_IO_IN | G_IO_HUP | G_IO_ERR,
0};
GSourceFuncs x11_source_funcs = {
x11_fd_prepare,
x11_fd_check,
x11_fd_dispatch,
NULL, /* finalize */
NULL, /* closure_callback */
NULL /* closure_marshal */
};
GSource *x11_source =
g_source_new(&x11_source_funcs, sizeof(x11_source_t));
((x11_source_t*)x11_source)->dpy = dpy;
((x11_source_t*)x11_source)->w = w;
g_source_add_poll(x11_source, &dpy_pollfd);
g_source_attach(x11_source, NULL);
g_main_loop_run(mainloop);
return 0;
}

Resources