Siêu thị PDFTải ngay đi em, trời tối mất

Thư viện tri thức trực tuyến

Kho tài liệu với 50,000+ tài liệu học thuật

© 2023 Siêu thị PDF - Kho tài liệu học thuật hàng đầu Việt Nam

apress foundations_of gtk plus development 2007 phần 5 pdf
PREMIUM
Số trang
65
Kích thước
1.8 MB
Định dạng
PDF
Lượt xem
1630

apress foundations_of gtk plus development 2007 phần 5 pdf

Nội dung xem thử

Mô tả chi tiết

206 CHAPTER 6 ■ USING GLIB

case 0:

gtk_init (&argc, &argv);

setup_app (parent_to_child, child_to_parent, pid);

break;

default:

gtk_init (&argc, &argv);

setup_app (child_to_parent, parent_to_child, pid);

}

gtk_main ();

return 0;

}

/* Set up the GUI aspects of each window and setup IO channel watches. */

static void

setup_app (gint input[],

gint output[],

gint pid)

{

GtkWidget *window, *entry;

GIOChannel *channel_read, *channel_write;

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

entry = gtk_entry_new ();

gtk_container_add (GTK_CONTAINER (window), entry);

gtk_container_set_border_width (GTK_CONTAINER (window), 10);

gtk_widget_set_size_request (window, 200, -1);

gtk_widget_show_all (window);

/* Close the unnecessary pipes for the given process. */

close (input[1]);

close (output[0]);

/* Create read and write channels out of the remaining pipes. */

channel_read = g_io_channel_unix_new (input[0]);

channel_write = g_io_channel_unix_new (output[1]);

if (channel_read == NULL || channel_write == NULL)

g_error ("Error: The GIOChannels could not be created!\n");

/* Watch the read channel for changes. This will send the appropriate data. */

if (!g_io_add_watch (channel_read, G_IO_IN | G_IO_HUP,

iochannel_read, (gpointer) entry))

g_error ("Error: Read watch could not be added to the GIOChannel!\n");

7931ch06.fm Page 206 Wednesday, March 7, 2007 8:52 PM

CHAPTER 6 ■ USING GLIB 207

signal_id = g_signal_connect (G_OBJECT (entry), "changed",

G_CALLBACK (entry_changed),

(gpointer) channel_write);

/* Set the window title depending on the process identifier. */

if (pid == 0)

gtk_window_set_title (GTK_WINDOW (window), "Child Process");

else

gtk_window_set_title (GTK_WINDOW (window), "Parent Process");

}

/* Read the message from the pipe and set the text to the GtkEntry. */

static gboolean

iochannel_read (GIOChannel *channel,

GIOCondition condition,

GtkEntry *entry)

{

GIOStatus ret_value;

gchar *message;

gsize length;

/* The pipe has died unexpectedly, so exit the application. */

if (condition & G_IO_HUP)

g_error ("Error: The pipe has died!\n");

/* Read the data that has been sent through the pipe. */

ret_value = g_io_channel_read_line (channel, &message, &length, NULL, NULL);

if (ret_value == G_IO_STATUS_ERROR)

g_error ("Error: The line could not be read!\n");

/* Synchronize the GtkEntry text, blocking the changed signal. Otherwise, an

* infinite loop of communication would ensue. */

g_signal_handler_block ((gpointer) entry, signal_id);

message[length-1] = 0;

gtk_entry_set_text (entry, message);

g_signal_handler_unblock ((gpointer) entry, signal_id);

return TRUE;

}

/* Write the new contents of the GtkEntry to the write IO channel. */

static void

entry_changed (GtkEditable *entry,

GIOChannel *channel)

7931ch06.fm Page 207 Wednesday, March 7, 2007 8:52 PM

208 CHAPTER 6 ■ USING GLIB

{

gchar *text;

gsize length;

GIOStatus ret_value;

text = g_strconcat (gtk_entry_get_text (GTK_ENTRY (entry)), "\n", NULL);

/* Write the text to the channel so that the other process will get it. */

ret_value = g_io_channel_write_chars (channel, text, -1, &length, NULL);

if (ret_value = G_IO_STATUS_ERROR)

g_error ("Error: The changes could not be written to the pipe!\n");

else

g_io_channel_flush (channel, NULL);

}

Setting Up IO Channels

If you are working on a UNIX-like machine, you can use the pipe() function to create new file

descriptors. In Listing 6-9, two pairs of pipes are set up: one for sending messages from the par￾ent to the child and one for sending messages in the other direction. Two GIOChannels can then

be created from these file descriptors by calling the following function on each.

After the pipes are created, the application is forked with fork(). If the fork is successful,

the application is set up for both the child and the parent process.

Within setup_app(), we begin by closing the pipes that are not needed by the child or par￾ent applications with close(). Each process will only need one read and one write pipe in order

to send and receive messages.

Next, we use the two remaining pipes in each application and set up a GIOChannel for each.

We will use channel_read to receive data from the other process and channel_write to send the

new content of the GtkEntry.

channel_read = g_io_channel_unix_new (input[0]);

channel_write = g_io_channel_unix_new (output[1]);

After initializing your IO channels, you need to set up a watch on channel_read. The watch

will monitor the channel for the specified events, which is setup with g_io_add_watch().

guint g_io_add_watch (GIOChannel *channel,

GIOCondition condition,

GIOFunc func,

gpointer data);

7931ch06.fm Page 208 Wednesday, March 7, 2007 8:52 PM

CHAPTER 6 ■ USING GLIB 209

The second parameter of g_io_add_watch() adds one or more events that should be

watched. You need to make sure to set up the correct conditions with each channel. You will

never get a G_IO_IN event from a channel used for writing data, so monitoring for that event is

useless. Possible values for the GIOCondition enumeration follow; these can be piped to the

condition parameter of g_io_add_watch():

• G_IO_IN: Read data is pending.

• G_IO_OUT: Data can be written without the worry of blocking.

• G_IO_PRI: Read data is pending and urgent.

• G_IO_ERR: An error has occurred.

• G_IO_HUP: The connection has been hung up or broken.

• G_IO_NVAL: An invalid request has occurred because the file descriptor is not open.

When one of the specified conditions occurs, the GIOFunc callback function is called. The

last parameter gives data that will be passed to the callback function. IO channel callback func￾tions receive three parameters: the GIOChannel, the condition that occurred, and the data

passed from g_io_add_watch(). TRUE should always be returned from the callback function

unless you want it to be removed. The function prototype follows:

gboolean (*GIOFunc) (GIOChannel *source, GIOCondition condition, gpointer data);

Reading from and writing to a GIOChannel is done in the same manner regardless of whether

it is a file or a pipe. Therefore, the g_io_channel_read_(*) and g_io_channel_write_*() func￾tions covered in the previous section can still be used.

Many of the GIOChannel functions provide two ways to check for errors. The first is the

GError structure that we have used in past chapters. Secondly, many functions return a

GIOStatus value, which will report one of the following four values:

• G_IO_STATUS_ERROR: Some type of error has occurred. You should still track errors even if

you are checking for this value.

• G_IO_STATUS_NORMAL: The action was successfully completed.

• G_IO_STATUS_EOF: The end of the file has been reached.

• G_IO_STATUS_AGAIN: Resources are temporarily unavailable. You should try again later.

7931ch06.fm Page 209 Wednesday, March 7, 2007 8:52 PM

210 CHAPTER 6 ■ USING GLIB

Depending on the GIOStatus value, you should either continue or give an error message.

The only exception is G_IO_STATUS_AGAIN, in which case you should return to poll() in the

main loop and wait for the file descriptor to become ready.

To send the data to the read buffer, you need to flush the write buffer of the GIOChannel

with g_io_channel_flush(). This function, along with all of the functions in this section, can

cause an error of the type GIOChannelError.

GIOStatus g_io_channel_flush (GIOChannel *channel,

GError **error);

Spawning Processes

The GIOChannel example in the previous section used pipe() and fork() to set up the commu￾nication between the applications. However, this example is not cross-platform, because some

commands will not be supported on Microsoft Windows.

To spawn processes in a way supported by multiple platforms, GLib provides three func￾tions. Since all three work in a similar way, we will only talk about the following function,

g_spawn_async_with_pipes():

gboolean g_spawn_async_with_pipes (const gchar *working_directory,

gchar **argv,

gchar **envp,

GSpawnFlags flags,

GSpawnChildSetupFunc child_setup,

gpointer data,

GPid *child_pid,

gint *standard_input,

gint *standard_output,

gint *standard_error,

GError **error);

This function asynchronously runs a child program, which means that the program will

continue to run even if the child has not exited. The first parameter specifies the working direc￾tory for the child process or NULL to set it as the parent’s working directory.

The argv list is a NULL-terminated array of strings. The first string in this list is the name of the

application, followed by any additional parameters. This application must be a full path unless

you use the G_SPAWN_SEARCH_PATH flag, which will be shown later. Another NULL-terminated array

of strings is envp, each in the form KEY=VALUE. These will be set as the child’s environment

variables.

7931ch06.fm Page 210 Wednesday, March 7, 2007 8:52 PM

CHAPTER 6 ■ USING GLIB 211

You can then specify one or more of the following GSpawnFlags:

• G_SPAWN_LEAVE_DESCRIPTORS_OPEN: The child will inherit the open file descriptors of the

parent. If this flag is not set, all file descriptors except the standard input, output, and

error will be closed.

• G_SPAWN_DO_NOT_REAP_CHILD: Stop the child from automatically becoming reaped. If you

do not call waitpid() or handle SIGCHLD, it will become a zombie.

• G_SPAWN_SEARCH_PATH: If this flag is set, argv[0] will be searched for in the user’s path if it

is not an absolute location.

• G_SPAWN_STDOUT_TO_DEV_NULL: Discard the standard output from the child. If this flag is

not set, it will go to the same location as the parent’s standard output.

• G_SPAWN_STDERR_TO_DEV_NULL: Discard the standard error from the child.

• G_SPAWN_CHILD_INHERITS_STDIN: If this flag is not set, the standard input for the child is

attached to /dev/null. You can use this flag so the child will inherit the standard input of

the parent.

• G_SPAWN_FILE_AND_ARGV_ZERO: Use the first argument as the executable and only pass the

remaining strings as the actual arguments. If this flag is not set, argv[0] will also be

passed to the executable.

The next parameter of g_spawn_async_with_pipes() is the GSpawnChildSetupFunc callback

function that will be run after GLib sets up pipes but before calling exec(). This function

accepts the data parameter from g_spawn_async_with_pipes().

The next four parameters allow you to retrieve information about the new child process.

These are the child’s process identifier, standard input, standard output, and standard error.

Any of these four parameters can be set to NULL if you want to ignore it.

If the application was successfully launched, g_spawn_async_with_pipes() will return

TRUE. Otherwise, the error will be set under the GSpawnError domain, and it will return FALSE.

When you are finished with a GPid, you should use g_spawn_close_pid() to close it. This is

especially important when spawning processes on Microsoft Windows.

void g_spawn_close_pid (GPid pid);

7931ch06.fm Page 211 Wednesday, March 7, 2007 8:52 PM

Tải ngay đi em, còn do dự, trời tối mất!