📄 playeripc.cpp
字号:
/* ***** BEGIN LICENSE BLOCK ***** * Source last modified: $Id: playeripc.cpp,v 1.6.2.8 2004/11/23 00:24:25 rggammon Exp $ * * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved. * * The contents of this file, and the files included with this file, * are subject to the current version of the RealNetworks Public * Source License (the "RPSL") available at * http://www.helixcommunity.org/content/rpsl unless you have licensed * the file under the current version of the RealNetworks Community * Source License (the "RCSL") available at * http://www.helixcommunity.org/content/rcsl, in which case the RCSL * will apply. You may also obtain the license terms directly from * RealNetworks. You may not use this file except in compliance with * the RPSL or, if you have a valid RCSL with RealNetworks applicable * to this file, the RCSL. Please see the applicable RPSL or RCSL for * the rights, obligations and limitations governing use of the * contents of the file. * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL") in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your version of * this file only under the terms of the GPL, and not to allow others * to use your version of this file under the terms of either the RPSL * or RCSL, indicate your decision by deleting the provisions above * and replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient may * use your version of this file under the terms of any one of the * RPSL, the RCSL or the GPL. * * This file is part of the Helix DNA Technology. RealNetworks is the * developer of the Original Code and owns the copyrights in the * portions it created. * * This file, and the files included with this file, is distributed * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET * ENJOYMENT OR NON-INFRINGEMENT. * * Technology Compatibility Kit Test Suite(s) Location: * http://www.helixcommunity.org/content/tck * * Contributor(s): * * ***** END LICENSE BLOCK ***** */#include "hlxclib/memory.h"#include "hlxclib/string.h"#include "hlxclib/stdio.h"#include "hlxclib/ctype.h"#include "hlxclib/errno.h"#include <unistd.h>#include <sys/time.h>#include "hlxclib/sys/types.h"#include "embeddedapp.h"#include <gtk/gtk.h>#include <glib.h>#include "embddef.h"#include "hxplayer.h"#define COMMAND_BUFFER_SIZE 16384// Avoid using helix-level constructs by defining these:#define HXR_OK 0x00000000 #define HXR_FAIL 0x80004005typedef guint HX_RESULT;#define PLAYER_IPC_VERSION 1struct { GIOChannel* embedded_command_channel; GIOChannel* embedded_callbacks_channel; gint buf_pos; gchar buf[COMMAND_BUFFER_SIZE]; guint sequence; // old RN code called this ProtocolNumber GList* console_attributes_list;} g_playeripc;gboolean playeripc_handle_command(GIOChannel *channel, const char *command);gboolean playeripc_parse_commands(GIOChannel *channel, GIOCondition condition, gpointer data);static gbooleanhandle_ipc_error(GIOChannel*, GIOCondition, gpointer){ /* A broken pipe will not happen here -- see the EOF handler in playeripc_parse_commands */ gtk_main_quit(); return FALSE; // remove event}gbooleanplayeripc_init(int command_fd, int callbacks_fd){ GError *error = NULL; memset(&g_playeripc, 0, sizeof(g_playeripc)); if(command_fd >= 0) { g_playeripc.embedded_command_channel = g_io_channel_unix_new(command_fd); g_return_val_if_fail(g_playeripc.embedded_command_channel != NULL, FALSE); g_io_channel_set_encoding(g_playeripc.embedded_command_channel, NULL, &error); if(error) { g_warning(error->message); g_free(error); } g_io_channel_set_buffered(g_playeripc.embedded_command_channel, FALSE); } if(callbacks_fd >= 0) { g_playeripc.embedded_callbacks_channel = g_io_channel_unix_new(callbacks_fd); g_return_val_if_fail(g_playeripc.embedded_callbacks_channel != NULL, FALSE); g_io_channel_set_encoding(g_playeripc.embedded_callbacks_channel, NULL, &error); if(error) { g_warning(error->message); g_free(error); } g_io_channel_set_buffered(g_playeripc.embedded_callbacks_channel, FALSE); } g_io_add_watch(g_playeripc.embedded_command_channel, G_IO_IN, playeripc_parse_commands, NULL ); g_io_add_watch(g_playeripc.embedded_command_channel, (GIOCondition)(G_IO_ERR | G_IO_HUP), handle_ipc_error, NULL ); return TRUE;}/* Parser for plugin IPC protocol */gbooleanplayeripc_parse_commands(GIOChannel *channel, GIOCondition condition, gpointer){ GIOStatus status; gsize bytes_read; GError* error = NULL; char c = 0; int fd, result = 0; fd_set fds_read, fds_exception; struct timeval timeout; if(condition != G_IO_IN) { g_warning("playeripc_parse_commands: condition is %d", condition); return TRUE; // don't remove event source } fd = g_io_channel_unix_get_fd(channel); /* Read from the command fd up to the first '\n' command */ /* We parse one character at a time because the SetStream command does its own thing with reading, and we don't want to eat its data */ do { status = g_io_channel_read_chars(channel, &c, 1, &bytes_read, &error); if(error) { g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "g_io_channel_read_chars: %s", error->message); g_free(error); } switch(status) { case G_IO_STATUS_ERROR: case G_IO_STATUS_EOF: gtk_main_quit(); return FALSE; // remove event case G_IO_STATUS_AGAIN: continue; case G_IO_STATUS_NORMAL: g_assert(bytes_read == 1); g_assert(c != '\0'); g_playeripc.buf[g_playeripc.buf_pos++] = c; break; default: g_assert(FALSE); /* not reached */ } FD_ZERO(&fds_read); FD_ZERO(&fds_exception); FD_SET(fd, &fds_read); FD_SET(fd, &fds_exception); /* Return immediately */ timeout.tv_sec = 0; timeout.tv_usec = 0; result = select(fd + 1, &fds_read, NULL, &fds_exception, &timeout); if(FD_ISSET(fd, &fds_exception) || result < 0) { /* This should never happen. A closed fd will not cause this path to be called. */ g_warning("Exception in playeripc_parse_commands"); break; } /* Read until there's no more data, or we get a newline */ } while(c != '\n' && FD_ISSET(fd, &fds_read)); if(c == '\n') { g_assert(g_playeripc.buf[g_playeripc.buf_pos - 1] == '\n'); g_playeripc.buf[g_playeripc.buf_pos - 1] = '\0'; printf("playeripc: Got command %s\n", g_playeripc.buf); playeripc_handle_command(channel, g_playeripc.buf); g_playeripc.buf_pos = 0; } return TRUE; // don't remove the event source.}/* RGG: GLib needs one of these... Interval is in ms, in keeping with glib standards */static gbooleanrecv_with_timeout(GIOChannel* channel, gchar* buf, gsize len, guint interval){ fd_set fds_read, fds_exception; int fd; int result; struct timeval timeout; int interval_sec, interval_usec; guint pos = 0; gboolean ret = TRUE; interval_sec = interval / 1000; interval_usec = (interval % 1000) * 1000; fd = g_io_channel_unix_get_fd(channel); do { FD_ZERO(&fds_read); FD_ZERO(&fds_exception); FD_SET(fd, &fds_read); FD_SET(fd, &fds_exception); /* XXXRGG: FIXME: Right now, the timeout gets reset each time data is received. Don't rely on select() to update timeout. */ timeout.tv_sec = interval_sec; timeout.tv_usec = interval_usec; result = select(fd + 1, &fds_read, NULL, &fds_exception, &timeout); if(result == 0) { /* timeout */ g_warning("Timed out in recv_with_timeout with %d bytes", pos - 1); ret = FALSE; } else if(FD_ISSET(fd, &fds_exception) || result < 0) { g_warning("Exception in recv_with_timeout"); ret = FALSE; } if(FD_ISSET(fd, &fds_read)) { /* Receive data */ for(;;) { result = read(fd, buf + pos, len - pos); if(result < 0) { if(errno == EINTR || errno == EAGAIN) { continue; } else { perror("read"); ret = FALSE; } } else if(result == 0) { g_warning("Lost connection to plugin"); /* Connection closed */ ret = FALSE; } else { pos += result; } break; } } } while(ret && pos < len); return ret;}static voidsend_ipc(GIOChannel *channel, const gchar* output, gsize size){ GIOStatus status; GError *error = NULL; gsize bytes_written; gsize total_written = 0; do { // XXXRGG: Need a timeout here. status = g_io_channel_write_chars(channel, output + total_written, size - total_written, &bytes_written, &error); if(error) { g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "g_io_channel_write_chars: %s", error->message); g_free(error); } switch(status) { case G_IO_STATUS_ERROR: case G_IO_STATUS_EOF: gtk_main_quit(); return; case G_IO_STATUS_AGAIN: break; case G_IO_STATUS_NORMAL: total_written += bytes_written; break; default: g_assert(FALSE); /* not reached */ } } while((total_written < size) || (status == G_IO_STATUS_AGAIN));}static voidsend_reply(GIOChannel *channel, const char *format, ...){ gchar *command; gsize len; va_list args; va_start(args, format); command = g_strdup_vprintf(format, args); len = strlen(command) + 1; /* We need to add a newline. We could reallocate the string with an extra character. Instead, we replace the '\0' (send_ipc doesn't need a null-terminated string). */ command[len - 1] = '\n'; send_ipc(channel, command, len); g_free(command); va_end(args);}/* This function will modify the string it is passed */static gchar*strunquote(gchar* str){ gchar* end; gchar* pos; if(str[0] == '"') { end = strrchr(str, '"'); if(end && end != str) { pos = end + 1; while(*pos) { if(!isspace(*pos)) { /* There are trailing characters after the closing quote */ return str; } } str++; // get rid of leading quote *end = '\0'; // get rid of trailing quote } } return str;}static voidwindow_attributes_set_defaults(HXEmbeddedWindowAttributes *attr){ /* See: http://service.real.com/help/library/guides/realone/ScriptingGuide/HTML/realscript.htm */ attr->autogotourl = FALSE; attr->autostart = FALSE; attr->backgroundcolor = g_strdup("black"); attr->center = FALSE; attr->console = g_strdup("_unique"); attr->controls = HX_CONTROLS_ALL; attr->controls_string = NULL; attr->name_flags = HX_NAME_NONE; attr->name = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -