diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 90825e2392b2d70e43c7a25b8a3752299a933894 (patch) | |
tree | e33aa27f02b74604afbfd0ea4f1cfca8833d882a /dcopc | |
download | tdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.tar.gz tdebindings-90825e2392b2d70e43c7a25b8a3752299a933894.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdebindings@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'dcopc')
-rw-r--r-- | dcopc/Makefile.am | 20 | ||||
-rw-r--r-- | dcopc/configure.in.in | 5 | ||||
-rw-r--r-- | dcopc/dcopc.c | 1579 | ||||
-rw-r--r-- | dcopc/dcopc.h | 143 | ||||
-rw-r--r-- | dcopc/dcopobject.c | 301 | ||||
-rw-r--r-- | dcopc/dcopobject.h | 93 | ||||
-rw-r--r-- | dcopc/glib.m4 | 196 | ||||
-rw-r--r-- | dcopc/glibtest.c | 133 | ||||
-rw-r--r-- | dcopc/global.h | 75 | ||||
-rw-r--r-- | dcopc/gtk.m4 | 197 | ||||
-rw-r--r-- | dcopc/marshal.c | 420 | ||||
-rw-r--r-- | dcopc/marshal.h | 93 | ||||
-rw-r--r-- | dcopc/util.c | 137 | ||||
-rw-r--r-- | dcopc/util.h | 73 |
14 files changed, 3465 insertions, 0 deletions
diff --git a/dcopc/Makefile.am b/dcopc/Makefile.am new file mode 100644 index 00000000..362994b5 --- /dev/null +++ b/dcopc/Makefile.am @@ -0,0 +1,20 @@ +AM_CFLAGS = $(GLIB_CFLAGS) $(GTK_CFLAGS) +AM_CXXFLAGS = $(GLIB_CFLAGS) $(GTK_CFLAGS) + +INCLUDES = -I$(top_srcdir)/ $(X_INCLUDES) + +lib_LTLIBRARIES = libdcopc.la + +libdcopc_la_SOURCES = dcopc.c marshal.c dcopobject.c +libdcopc_la_LIBADD = -lSM -lICE $(GTK_LIBS) $(GLIB_LIBS) +libdcopc_la_LDFLAGS = -version-info 1:0 $(X_LDFLAGS) -lICE -no-undefined + +include_HEADERS = dcopc.h marshal.h dcopobject.h util.h +includedir = $(prefix)/include/dcopc + +noinst_HEADERS = global.h + +check_PROGRAMS = glibtest + +glibtest_SOURCES = glibtest.c +glibtest_LDADD = libdcopc.la diff --git a/dcopc/configure.in.in b/dcopc/configure.in.in new file mode 100644 index 00000000..9c1458ee --- /dev/null +++ b/dcopc/configure.in.in @@ -0,0 +1,5 @@ +dnl if test "$GTK_CONFIG" = "no"; then + DO_NOT_COMPILE="$DO_NOT_COMPILE dcopc" +dnl fi +dnl +dnl AC_CHECK_GETHOSTNAME diff --git a/dcopc/dcopc.c b/dcopc/dcopc.c new file mode 100644 index 00000000..fcb51e2b --- /dev/null +++ b/dcopc/dcopc.c @@ -0,0 +1,1579 @@ +/* +Copyright (c) 2000 Simon Hausmann <hausmann@kde.org> +Copyright (c) 2000 Lars Knoll <knoll@kde.org> +Copyright (c) 1999 Preston Brown <pbrown@kde.org> +Copyright (c) 1999, 2000 Matthias Ettrich <ettrich@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include <config.h> + +#include "global.h" +#include "dcopc.h" +#include "dcopobject.h" + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> + +typedef struct _DcopClientMessage DcopClientMessage; + +struct _DcopClientMessage +{ + int opcode; + CARD32 key; + dcop_data *data; +}; + +typedef struct _DcopClientPrivate DcopClientPrivate; + +struct _DcopClientPrivate +{ + gchar *app_id; + IceConn ice_conn; + gint major_opcode; + gint major_version, minor_version; + gchar *vendor, *release; + gboolean registered; + gchar *sender_id; + + gchar *default_object; + + CARD32 key; + CARD32 current_key; + + GList *transaction_list; + gboolean transaction; + gint32 transaction_id; + + int opcode; + + guint post_message_timer; + GList *messages; +}; + +struct _DcopClientTransaction +{ + gint32 id; + CARD32 key; + gchar *sender_id; +}; + +int DCOPAuthCount = 1; +const char *DCOPAuthNames[] = {"MIT-MAGIC-COOKIE-1"}; + +extern IcePoAuthStatus _IcePoMagicCookie1Proc (IceConn, void **, int, int, int, void *, int *, void **, char **); +extern IcePaAuthStatus _IcePaMagicCookie1Proc (IceConn, void **, int, int, void *, int *, void **, char **); + +IcePoAuthProc DCOPClientAuthProcs[] = {_IcePoMagicCookie1Proc}; +IcePaAuthProc DCOPServerAuthProcs[] = {_IcePaMagicCookie1Proc}; + +enum reply_status +{ Pending, Ok, Rejected, Failed }; + +typedef struct _reply_struct reply_struct; + +struct _reply_struct +{ + gint status; + gchar **reply_type; + dcop_data **reply_data; + guint reply_id; +}; + +static void reply_struct_init( reply_struct *s ) +{ + s->status = Pending; + s->reply_type = 0; + s->reply_data = 0; + s->reply_id = 0; +} + +#define P ((DcopClientPrivate *)(client->priv)) +#define ERR( emsg ) \ + { \ + if ( dcop_client_free_error_msg ) \ + g_free( dcop_client_error_msg ); \ + dcop_client_error_msg = (gchar *)emsg; \ + dcop_client_free_error_msg = FALSE; \ + } + +#define CLIENT_CLASS(obj) DCOP_CLIENT_CLASS(GTK_OBJECT(obj)->klass) + +static gchar *dcop_client_server_address = 0; +static gchar *dcop_client_error_msg = 0; +static gboolean dcop_client_free_error_msg; + +/* don't use the glib types for args here, as this is an ICE callback (Simon)*/ +void dcop_process_message( IceConn ice_conn, IcePointer client_object, + int opcode, unsigned long length, Bool swap, + IceReplyWaitInfo *replyWait, + Bool *replyWaitRet ); + +gchar *dcop_client_normalize_function_signature( const gchar *fun ); + +static IcePoVersionRec DCOPVersions[] = { + { DCOPVersionMajor, DCOPVersionMinor, dcop_process_message + } +}; + +static unsigned int dcop_client_count = 0; +static GtkObjectClass *parent_class = 0; + +static void dcop_client_class_init(DcopClientClass *klass); +static void dcop_client_init(DcopClient *client); + +static gboolean dcop_client_real_process ( DcopClient *client, const char *fun, dcop_data *data, + char **reply_type, dcop_data **reply_data ); + +GtkType +dcop_client_get_type(void) +{ + static GtkType dcop_client_type = 0; + if (!dcop_client_type) + { + static const GtkTypeInfo dcop_client_info = + { + (gchar *)"DcopClient", + sizeof(DcopClient), + sizeof(DcopClientClass), + (GtkClassInitFunc)dcop_client_class_init, + (GtkObjectInitFunc)dcop_client_init, + 0, + 0, + 0 + }; + dcop_client_type = gtk_type_unique(GTK_TYPE_OBJECT, &dcop_client_info); + } + return dcop_client_type; +} + +static void dcop_client_destroy( GtkObject *obj ); +static void dcop_init(void); +static void dcop_shutdown(void); + +void +dcop_client_class_init(DcopClientClass *klass) +{ + GtkObjectClass *object_class; + object_class = (GtkObjectClass *)klass; + + parent_class = (GtkObjectClass *)gtk_type_class(gtk_object_get_type()); + + object_class->destroy = dcop_client_destroy; + klass->process = dcop_client_real_process; +} + +void +dcop_client_init(DcopClient *client) +{ + DcopClientPrivate *p; +/* tststs :-) C++ hackers :-) (Simon)*/ +/* p = new GtkDcopClientPrivate;*/ + p = g_new( DcopClientPrivate, 1 ); + + p->app_id = 0; + p->ice_conn = 0; + p->major_opcode = p->major_version = p->minor_version = 0; + p->vendor = p->release = 0; + p->registered = FALSE; + p->sender_id = 0; + p->key = 0; + p->current_key = 0; + p->post_message_timer = 0; + p->messages = 0; + p->default_object = 0; + p->transaction_list = 0; + p->transaction = FALSE; + p->transaction_id = 0; + p->opcode = 0; + + client->priv = p; + + if ( dcop_client_count == 0 ) + dcop_init(); + + dcop_client_count++; +} + +void dcop_client_destroy( GtkObject *obj ) +{ + DcopClient *client = DCOP_CLIENT(obj); + + g_message( "dcop_client_destructor()\n" ); + + if ( P->ice_conn && IceConnectionStatus( P->ice_conn ) == IceConnectAccepted ) + dcop_client_detach( client ); + + if ( P->post_message_timer != 0 ) + g_source_remove( P->post_message_timer ); + + { + GList *it = g_list_first( P->messages ); + while ( it ) + { + DcopClientMessage *msg = (DcopClientMessage *)it->data; + dcop_data_deref( msg->data ); + g_free( msg ); + it = g_list_next( it ); + } + g_list_free( P->messages ); + } + + { + GList *it = g_list_first( P->transaction_list ); + while ( it ) + { + g_free( ((DcopClientTransaction *)it->data)->sender_id ); + g_free( (DcopClientTransaction *)it ); + it = g_list_next( it ); + } + + g_list_free( P->transaction_list ); + } + + g_free( P->app_id ); + g_free( P->vendor ); + g_free( P->release ); + g_free( P->sender_id ); + + g_free( P ); + + if ( !--dcop_client_count ) + dcop_shutdown(); + + parent_class->destroy(GTK_OBJECT(client)); +} + + +void dcop_init() +{ + g_message( "dcop_init\n" ); + dcop_client_free_error_msg = FALSE; +} + +void dcop_shutdown() +{ + g_message( "dcop_shutdown\n" ); + dcop_free( dcop_client_server_address ); + + if ( dcop_client_free_error_msg ) + dcop_free( dcop_client_error_msg ); +} + +DcopClient *dcop_client_new() +{ + return (DcopClient *) gtk_type_new(dcop_client_get_type()); +} + +void dcop_client_set_server_address( const gchar *addr ) +{ + dcop_string_copy( dcop_client_server_address, addr ); +} + +/* SM DUMMY */ +#include <X11/SM/SMlib.h> +static gboolean HostBasedAuthProc ( char* hostname) +{ + /* we don't need any security here, as this is only a hack to + * get the protocol number we want for DCOP. We don't use the SM + * connection in any way */ + return True; +} + +static Status NewClientProc ( SmsConn c, SmPointer p, unsigned long*l, SmsCallbacks*cb, char**s ) +{ + return 0; +} + +static void dcop_client_registerXSM() +{ + char errormsg[256]; + if (!SmsInitialize ((char *)("SAMPLE-SM"), (char *)("1.0"), + NewClientProc, NULL, + HostBasedAuthProc, 256, errormsg)) + { + g_error( "register xsm failed"); + exit( 1 ); + } +} + +/* hack*/ +extern int _IceLastMajorOpcode; + +static void dcop_client_xsm_check() +{ + if ( _IceLastMajorOpcode < 1 ) + /* hack to enforce the correct ICE major opcode for DCOP*/ + dcop_client_registerXSM(); +} + +static gboolean dcop_client_attach_internal( DcopClient *client, gboolean anonymous ) +{ + gboolean bClearServerAddr = FALSE; + gchar *fname = 0; + const gchar *dcopSrvEnv = 0; + gchar *dcopSrv = 0; + gchar *dcopServerFileContent = 0; + glong dcopServerFileContentSize = 0; + ssize_t bytesRead = 0; + gchar *newLine = 0; + FILE *f = 0; + gchar errBuf[1024]; + gint setupstat; + + g_message( "dcop_client_attach\n" ); + + if ( dcop_client_is_attached( client ) ) + dcop_client_detach( client ); + + dcop_client_xsm_check(); + + if ( ( P->major_opcode = IceRegisterForProtocolSetup( (char *)("DCOP"), + (char *)(DCOPVendorString), + (char *)(DCOPReleaseString), + 1, DCOPVersions, + DCOPAuthCount, + (char **)(DCOPAuthNames), + DCOPClientAuthProcs, 0 ) ) < 0 ) + { + ERR( "Communications could not be established." ); + return FALSE; + } + else + { + g_message( "dcop: major opcode is %d\n", P->major_opcode ); + } + + if ( !dcop_client_server_address ) + { + dcopSrvEnv = getenv( "DCOPSERVER" ); + if ( !dcopSrvEnv || strlen( dcopSrvEnv ) == 0 ) + { + char hostName[255]; + + fname = g_strdup( getenv( "HOME" ) ); + fname = (gchar *)g_realloc( fname, strlen( fname ) + 1 + 13 ); + strcat( fname, "/.DCOPserver_" ); + + if ( gethostname( hostName, 255 ) == 0 ) + { + fname = (gchar *)g_realloc( fname, strlen( fname ) + 1 + strlen( hostName ) ); + strcat( fname, hostName ); + } + else + { + fname = (gchar *)g_realloc( fname, strlen( fname ) + 1 + 9 ); + strcat( fname, "localhost" ); + } + + f = fopen( fname, "r" ); + + if ( f == NULL ) /* try .DCOPServer_hostname_display (for KDE > 2.0) */ + { + char *i; + char *display = getenv( "DISPLAY" ); + gchar *display_real = g_strdup( display ); + gchar *disppos; + + /* dcopserver per display, not per screen */ + if ( ( disppos = strchr( display_real, '.' ) ) > strchr( display_real, ':' ) && disppos != NULL ) + (*disppos) = '\0'; + + while((i = strchr(display_real, ':')) != NULL) + *i = '_'; + + fname = (gchar *)g_realloc( fname, strlen( fname ) + 1 + 1 + strlen( display_real ) ); + strcat( fname, "_" ); + strcat( fname, display_real ); + + g_free( display_real ); + + f = fopen( fname, "r" ); + + if ( f == NULL ) + { + g_free( fname ); + ERR( "Cannot open ~/.DCOPserver" ); + return FALSE; + } + } + + fseek( f, 0L, SEEK_END ); + + dcopServerFileContentSize = ftell( f ); + + if ( dcopServerFileContentSize == 0L ) + { + g_free( fname ); + ERR( "Invalid ~/.DCOPserver" ); + return FALSE; + } + + fseek( f, 0L, SEEK_SET ); + + dcopServerFileContent = (gchar *)g_malloc( dcopServerFileContentSize ); + + bytesRead = fread( (void *)dcopServerFileContent, sizeof(gchar), dcopServerFileContentSize, f ); + + if ( bytesRead != dcopServerFileContentSize ) + { + g_free( fname ); + g_free( dcopServerFileContent ); + fclose( f ); + ERR( "Cannot read ~/.DCOPserver" ); + return FALSE; + } + + newLine = strchr( dcopServerFileContent, '\n' ); + + if ( newLine == NULL ) + { + g_free( fname ); + g_free( dcopServerFileContent ); + fclose( f ); + ERR( "Invalid ~/.DCOPserver" ); + return FALSE; + } + + *newLine = '\0'; + + fclose( f ); + g_free( fname ); + + dcopSrv = g_strdup( dcopServerFileContent ); + + g_free( dcopServerFileContent ); + } + else + dcopSrv = g_strdup( dcopSrvEnv ); + + if ( dcopSrv == NULL ) + { + ERR( "Cannot determine dcop server address." ); + return FALSE; + } + + g_message( "dcop server address is : %s\n", dcopSrv ); + + dcop_client_server_address = dcopSrv; + + bClearServerAddr = TRUE; + + } + + if ( ( P->ice_conn = IceOpenConnection( (char *)( dcop_client_server_address ), + (IcePointer)( client ), False, P->major_opcode, + sizeof( errBuf ), errBuf ) ) == NULL ) + { + if ( bClearServerAddr ) + dcop_free( dcop_client_server_address ); + ERR( g_strdup( errBuf ) ); + dcop_client_free_error_msg = TRUE; + return FALSE; + + } + + IceSetShutdownNegotiation( P->ice_conn, False ); + + setupstat = IceProtocolSetup( P->ice_conn, P->major_opcode, (IcePointer *)client, False, + &(P->major_version), &(P->minor_version), + &(P->vendor), &(P->release), sizeof( errBuf ), errBuf ); + + if ( setupstat == IceProtocolSetupFailure || + setupstat == IceProtocolSetupIOError ) + { + IceCloseConnection( P->ice_conn ); + + if ( bClearServerAddr ) + dcop_free( dcop_client_server_address ); + + ERR( g_strdup( errBuf ) ); + dcop_client_free_error_msg = TRUE; + return FALSE; + } + else if ( setupstat == IceProtocolAlreadyActive ) + { + if ( bClearServerAddr ) + dcop_free( dcop_client_server_address ); + + ERR( "Internal error in IceOpenConnection" ); + return FALSE; + } + + if ( IceConnectionStatus( P->ice_conn ) != IceConnectAccepted ) + { + if ( bClearServerAddr ) + dcop_free( dcop_client_server_address ); + + ERR( "DCOP server did not accept the connection" ); + return FALSE; + } + + if ( anonymous ) + dcop_client_register_as( client, "anonymous", TRUE ); + + return TRUE; +} + +gboolean dcop_client_attach( DcopClient *client ) +{ + if ( !dcop_client_attach_internal( client, TRUE ) ) + if ( !dcop_client_attach_internal( client, TRUE ) ) + return FALSE; /* try two times!*/ + + return TRUE; +} + +gboolean dcop_client_detach( DcopClient *client ) +{ + int status; + + g_message( "dcop_client_detach\n" ); + + if ( P->ice_conn ) + { + IceProtocolShutdown( P->ice_conn, P->major_opcode ); + status = IceCloseConnection( P->ice_conn ); + if ( status != IceClosedNow ) + { + ERR( "error detaching from DCOP server" ); + return FALSE; + } + else + P->ice_conn = 0L; + } + + P->registered = FALSE; + + return TRUE; +} + +gboolean dcop_client_is_attached( DcopClient *client ) +{ + if ( !P->ice_conn ) + return FALSE; + + return (IceConnectionStatus( P->ice_conn ) == IceConnectAccepted ); +} + +const gchar *dcop_client_register_as( DcopClient *client, const gchar *app_id, gboolean add_pid /* = TRUE */ ) +{ + gchar *result = 0; + + gchar *id = g_strdup( app_id ); + gchar pid[64]; + gint pid_len = 0; + + dcop_data *data = 0; + gchar *reply_type = 0; + dcop_data *reply_data = 0; + + g_message( "dcop_client_register_as %s\n", app_id ); + + if ( dcop_client_is_registered( client ) ) + dcop_client_detach( client ); + + if ( !dcop_client_is_attached( client ) ) + if ( !dcop_client_attach_internal( client, FALSE ) ) + return result; /*try two times*/ + + if ( add_pid ) + { + pid_len = g_snprintf( pid, sizeof( pid ), "-%d", getpid() ); + id = (gchar *)g_realloc( id, strlen( id ) + 1 + pid_len ); + strcat( id, pid ); + } + + + g_message( "trying to register as %s\n", id ); + + data = dcop_data_ref( dcop_data_new() ); + + dcop_marshal_string( data, id ); + + if ( dcop_client_call( client, "DCOPServer", "", "registerAs(QCString)", data, + &reply_type, + &reply_data ) ) + { + dcop_data_reset( reply_data ); + dcop_demarshal_string( reply_data, &result ); + + dcop_data_deref( reply_data ); + g_free( reply_type ); + } + + dcop_string_assign( P->app_id, result ); + + P->registered = ( P->app_id != NULL && strlen( P->app_id ) > 0 ); + + if ( P->registered ) + g_message( "we are registered as %s\n", P->app_id ); + else + g_message( "registration failed\n" ); + + dcop_data_deref( data ); + + g_free( id ); + + return result; +} + +gboolean dcop_client_is_registered( DcopClient *client ) +{ + return P->registered; +} + +const gchar *dcop_client_app_id( DcopClient *client ) +{ + return P->app_id; +} + +int dcop_client_socket( DcopClient *client ) +{ + if ( P->ice_conn ) + return IceConnectionNumber( P->ice_conn ); + else + return 0; +} + +gboolean dcop_client_send( DcopClient *client, + const gchar *rem_app, const gchar *rem_obj, const gchar *rem_fun, + dcop_data *data ) +{ + struct DCOPMsg *pMsg = 0; + dcop_data *hdata = 0; + gchar *func = 0; + gboolean res = TRUE; + + g_message( "dcop_client_send( %s, %s, %s )\n", rem_app, rem_obj, rem_fun); + + if ( !dcop_client_is_attached( client ) ) + return FALSE; + + if ( strcmp( P->app_id, rem_app ) == 0 ) + { + gchar *reply_type = 0; + dcop_data *reply_data = 0; + + if ( !dcop_client_receive( client, rem_app, rem_obj, rem_fun, data, &reply_type, &reply_data ) ) + g_warning( "dcop failure in app %s:\n object '%s' has no function '%s'", rem_app, rem_obj, rem_fun ); + + return TRUE; + } + + hdata = dcop_data_ref( dcop_data_new() ); + + dcop_marshal_string( hdata, P->app_id ); + dcop_marshal_string( hdata, rem_app ); + dcop_marshal_string( hdata, rem_obj ); + + func = dcop_client_normalize_function_signature( rem_fun ); + dcop_marshal_string( hdata, func ); + + dcop_marshal_uint32( hdata, data->size ); + + IceGetHeader( P->ice_conn, P->major_opcode, DCOPSend, sizeof(struct DCOPMsg), struct DCOPMsg, pMsg ); + + pMsg->key = 1; /* DCOPSend always uses the magic key 1*/ + pMsg->length += hdata->size + data->size; + + IceSendData( P->ice_conn, hdata->size, hdata->ptr ); + IceSendData( P->ice_conn, data->size, data->ptr ); + + /* IceFlush( P->ice_conn ); + */ + if ( IceConnectionStatus( P->ice_conn ) != IceConnectAccepted ) + res = FALSE; + + g_free( func ); + + return res; +} + +static gboolean dcop_client_call_internal( DcopClient *client, + const gchar *rem_app, const gchar *rem_obj, const gchar *rem_fun, + dcop_data *data, + gchar **reply_type, dcop_data **reply_data, + gint minor_opcode ) +{ + gboolean success = FALSE; + struct DCOPMsg *pMsg = 0; + dcop_data *hdata = 0; + gchar *func = 0; + IceReplyWaitInfo waitInfo; + reply_struct reply; + gboolean readyRet; + IceProcessMessagesStatus status; + CARD32 old_current_key = 0; + + reply_struct_init( &reply ); + + if ( !dcop_client_is_attached( client ) ) + return FALSE; + + old_current_key = P->current_key; + if ( !P->current_key ) + P->current_key = P->key; /* no key, yet, initiate new call*/ + + hdata = dcop_data_ref( dcop_data_new() ); + + dcop_marshal_string( hdata, P->app_id ); + dcop_marshal_string( hdata, rem_app ); + dcop_marshal_string( hdata, rem_obj ); + + func = dcop_client_normalize_function_signature( rem_fun ); + dcop_marshal_string( hdata, func ); + + dcop_marshal_uint32( hdata, data->size ); + + IceGetHeader( P->ice_conn, P->major_opcode, minor_opcode, + sizeof(struct DCOPMsg), struct DCOPMsg, pMsg ); + + pMsg->key = P->current_key; + pMsg->length += hdata->size + data->size; + + IceSendData( P->ice_conn, hdata->size, hdata->ptr ); + IceSendData( P->ice_conn, data->size, data->ptr ); + + if ( IceConnectionStatus( P->ice_conn ) != IceConnectAccepted ) + { + dcop_data_deref( hdata ); + g_free( func ); + P->current_key = old_current_key; + return FALSE; + } + + IceFlush( P->ice_conn ); + + waitInfo.sequence_of_request = IceLastSentSequenceNumber( P->ice_conn ); + waitInfo.major_opcode_of_request = P->major_opcode; + waitInfo.minor_opcode_of_request = minor_opcode; + reply.reply_type = reply_type; + reply.reply_data = reply_data; + waitInfo.reply = (IcePointer)&reply; + + readyRet = False; + + do + { + status = IceProcessMessages( P->ice_conn, &waitInfo, &readyRet ); + if ( status == IceProcessMessagesIOError ) + { + IceCloseConnection( P->ice_conn ); + dcop_data_deref( hdata ); + g_free( func ); + P->current_key = old_current_key; + return FALSE; + } + } while ( !readyRet ); + + dcop_data_deref( hdata ); + + success = reply.status == Ok; + + g_free( func ); + + P->current_key = old_current_key; + return success; +} + +gboolean dcop_client_call( DcopClient *client, + const gchar *rem_app, const gchar *rem_obj, const gchar *rem_fun, + dcop_data *data, + gchar **reply_type, dcop_data **reply_data ) +{ + return dcop_client_call_internal( client, rem_app, rem_obj, rem_fun, data, + reply_type, reply_data, DCOPCall ); +} + +gboolean dcop_client_is_application_registered( DcopClient *client, const gchar *app ) +{ + gchar *reply_type = 0; + dcop_data *reply_data = 0; + dcop_data *data = dcop_data_ref( dcop_data_new() ); + gboolean res = FALSE; + + dcop_marshal_string( data, app ); + + if ( dcop_client_call( client, "DCOPServer", "", "isApplicationRegistered(QCString)", data, &reply_type, &reply_data ) ) + { + dcop_data_reset( reply_data ); + dcop_demarshal_boolean( reply_data, &res ); + } + + g_free( reply_type ); + if ( reply_data ) + dcop_data_deref( reply_data ); + dcop_data_deref( data ); + + return res; +} + +GList *dcop_client_registered_applications( DcopClient *client ) +{ + GList *res = 0; + dcop_data *data = 0; + dcop_data *reply_data = 0; + gchar *reply_type = 0; + + data = dcop_data_ref( dcop_data_new() ); + + if ( dcop_client_call( client, "DCOPServer", "", "registeredApplications()", data, + &reply_type, &reply_data ) ) + { + fprintf( stderr, "reply type is %s\n", reply_type ); + dcop_data_reset( reply_data ); + dcop_demarshal_stringlist( reply_data, &res ); + dcop_data_deref( reply_data ); + } + + g_free( reply_type ); + dcop_data_deref( data ); + return res; +} + +extern GHashTable *object_dict; + +GList *g_temp_object_list = 0; + +static void dcop_client_receive_list_objects_internal( gpointer key, gpointer val, gpointer user_data ) +{ + gchar *nam = (gchar *)key; + DcopObject *obj = (DcopObject *)val; + DcopClient *client = (DcopClient *)user_data; + const gchar *id = DCOP_ID( obj ); + + if ( id && strlen( id ) > 0 ) + { + if ( P->default_object && + strcmp( id, P->default_object ) == 0 ) + g_temp_object_list = g_list_append( g_temp_object_list, (gchar *)"default" ); + + g_temp_object_list = g_list_append( g_temp_object_list, (gchar *)id ); + } +} + +gboolean dcop_client_receive( DcopClient *client, + const gchar *app, const gchar *obj, const gchar *fun, + dcop_data *data, + gchar **reply_type, dcop_data **reply_data ) +{ + DcopObject *o; + + g_message( "dcop_client_receive app=%s obj=%s fun=%s\n", app, obj, fun); + + if ( obj && strcmp( obj, "DCOPClient" ) == 0 ) + { + if ( strcmp( fun, "objects()" ) == 0 ) + { + GList *list = 0; + + *reply_type = strdup( "QCStringList" ); + *reply_data = dcop_data_ref( dcop_data_new() ); + + if ( object_dict ) + { + /* + GList *it = g_list_first( object_list ); + + while ( it ) + { + if ( it->data ) + { + const gchar *id; + o = (DcopObject *)it->data; + id = DCOP_ID(o); + if ( id && strlen( id ) > 0 ) + { + if ( P->default_object && + strcmp( id, P->default_object ) == 0 ) + list = g_list_append( list, (gchar *)"default" ); + + list = g_list_append( list, (gchar *)id ); + } + } + it = g_list_next( it ); + } + */ + g_temp_object_list = 0; + + g_hash_table_foreach( object_dict, dcop_client_receive_list_objects_internal, client ); + + list = g_temp_object_list; + } + + dcop_marshal_stringlist( *reply_data, list ); + /* important: only "free" (return to internal allocator) the list*/ + /* itself, not it's data, as that data are either static strings*/ + /* or strings already owned by someone else*/ + g_list_free( list ); + return TRUE; + } + + if ( CLIENT_CLASS(client)->process( client, fun, data, reply_type, reply_data ) ) + return TRUE; + } + + if ( !obj || strlen( obj ) == 0 || strcmp( obj, "default" ) == 0 ) + if ( P->default_object && strlen( P->default_object ) != 0 ) + { + o = dcop_object_lookup( P->default_object ); + if ( o && DCOP_OBJECT_CLASS(GTK_OBJECT(o)->klass)->process( o, fun, data, reply_type, reply_data ) ) + return TRUE; + } + + if ( obj && obj[ strlen( obj ) - 1 ] == '*' ) + { + gchar *partial_id = (gchar *)g_malloc( strlen( obj ) - 1 ); + GList *match_list = 0; + + strncpy( partial_id, obj, strlen( obj ) - 1 ); + + match_list = dcop_object_match( partial_id ); + + if ( match_list ) + { + GList *it = g_list_first( match_list ); + + while ( it ) + { + o = (DcopObject *)it->data; + + if ( !DCOP_OBJECT_CLASS(GTK_OBJECT(o)->klass)->process( o, fun, data, reply_type, reply_data ) ) + { + g_list_free( match_list ); + g_free( partial_id ); + return FALSE; + } + + it = g_list_next( it ); + } + + g_list_free( match_list ); + } + + g_free( partial_id ); + return TRUE; + } + + /* ### proxy support + */ + o = dcop_object_lookup( obj ); + if ( !o ) + return FALSE; + return DCOP_OBJECT_CLASS(GTK_OBJECT(o)->klass)->process( o, fun, data, reply_type, reply_data ); +} + +static inline gboolean is_ident_char( gchar x ) +{ /* Avoid bug in isalnum */ + return x == '_' || (x >= '0' && x <= '9') || + (x >= 'a' && x <= 'z') || (x >= 'A' && x <= 'Z'); +} + +gchar *dcop_client_normalize_function_signature( const gchar *fun ) +{ + gchar *result; + size_t len = strlen( fun ); + const gchar *from; + gchar *to, *first; + gchar last; + + if ( len == 0 ) + return g_strdup( fun ); + + result = (gchar *)g_malloc( len + 1 ); + + from = fun; + first = to = result; + last = 0; + + while ( 42 ) + { + while ( *from && isspace( *from ) ) + from++; + if ( last && is_ident_char( last ) && is_ident_char( *from ) ) + *to++ = 0x20; + while ( *from && !isspace( *from ) ) + { + last = *from++; + *to++ = last; + } + if ( !*from ) + break; + } + if ( to > first && *(to-1) == 0x20 ) + to--; + *to = '\0'; + result = (gchar *)g_realloc( result, (int)((long)to - (long)result) + 1 ); + return result; +} + +const gchar *dcop_client_sender_id( DcopClient *client ) +{ + return P->sender_id; +} + +gboolean dcop_client_process( DcopClient *client, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ) +{ + return CLIENT_CLASS( client )->process( client, fun, data, reply_type, reply_data ); +} + +gboolean dcop_client_real_process( DcopClient *client, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ) +{ + /* empty default implementation*/ + return FALSE; +} + +void dcop_client_process_socket_data( DcopClient *client ) +{ + IceProcessMessagesStatus status; + + g_message( "dcop_client_process_socket_data\n" ); + + status = IceProcessMessages( P->ice_conn, 0, 0 ); + + g_message( "dcop_client_process_socket_data : messages processed\n" ); + + if ( status == IceProcessMessagesIOError ) + { + IceCloseConnection( P->ice_conn ); + g_message( "error receiving data from the DCOP server.\n" ); + return; + } +} + +const gchar *dcop_client_error_message() +{ + return dcop_client_error_msg; +} + +void dcop_process_internal( DcopClient *client, int opcode, CARD32 key, dcop_data *data_received, gboolean can_post ); + +/* don't use the glib types for args here, as this is an ICE callback (Simon)*/ +void dcop_process_message( IceConn ice_conn, IcePointer client_object, + int opcode, unsigned long length, Bool swap, + IceReplyWaitInfo *replyWait, + Bool *replyWaitRet ) +{ + struct DCOPMsg *pMsg = 0; + DcopClient *client = (DcopClient *)client_object; + void *data_received; + dcop_data *tmp_stream = 0; + unsigned int id; + char *called_app = 0; + char *app = 0; + char *obj = 0; + char *fun = 0; + CARD32 key; + + IceReadMessageHeader( ice_conn, sizeof( struct DCOPMsg ), struct DCOPMsg, pMsg ); + + key = pMsg->key; + if ( P->key == 0 ) + P->key = key; /* received a key from the server*/ + + data_received = g_malloc( length ); + IceReadData( ice_conn, length, data_received ); + + tmp_stream = dcop_data_ref( dcop_data_new() ); + dcop_data_assign( tmp_stream, (char *)data_received, length ); + + P->opcode = opcode; + + switch ( opcode ) + { + case DCOPReplyFailed: + if ( replyWait ) + { + ((reply_struct *)replyWait->reply)->status = Failed; + *replyWaitRet = True; + break; + } + else + { + g_warning( "dcop error: received an unexpected DCOPReplyFailed opcode.\n" ); + break; + } + case DCOPReply: + if ( replyWait ) + { + ((reply_struct *)replyWait->reply)->status = Ok; + + dcop_demarshal_string( tmp_stream, &called_app ); + dcop_demarshal_string( tmp_stream, &app ); + dcop_demarshal_string( tmp_stream, ((reply_struct *)replyWait->reply)->reply_type ); + dcop_demarshal_data( tmp_stream, ((reply_struct *)replyWait->reply)->reply_data ); + + *replyWaitRet = True; + break; + } + else + { + g_warning( "dcop error: received an unexpected DCOPReply.\n" ); + break; + } + case DCOPReplyWait: + if ( replyWait ) + { + dcop_demarshal_string( tmp_stream, &called_app ); + dcop_demarshal_string( tmp_stream, &app ); + dcop_demarshal_uint32( tmp_stream, &id ); + + ((reply_struct *)replyWait->reply)->reply_id = id; + + break; + } + else + { + g_warning( "dcop error: received an unexpected DCOPReplyWait.\n" ); + break; + } + case DCOPReplyDelayed: + if ( replyWait ) + { + ((reply_struct *)replyWait->reply)->status = Ok; + + dcop_demarshal_string( tmp_stream, &called_app ); + dcop_demarshal_string( tmp_stream, &app ); + dcop_demarshal_uint32( tmp_stream, &id ); + dcop_demarshal_string( tmp_stream, ((reply_struct *)replyWait->reply)->reply_type ); + dcop_demarshal_data( tmp_stream, ((reply_struct *)replyWait->reply)->reply_data ); + + if ( id != ((reply_struct *)replyWait->reply)->reply_id ) + { + ((reply_struct *)replyWait->reply)->status = Failed; + g_warning( "dcop error: received a wrong sequence id for DCOPReplyDelayed.\n" ); + } + + *replyWaitRet = True; + + break; + } + else + { + g_message( "dcop error: received an unexpeced DCOPReplyDelayed.\n" ); + break; + } + case DCOPCall: + case DCOPFind: + case DCOPSend: + dcop_process_internal( client, opcode, key, tmp_stream, TRUE ); + break; + } + + dcop_data_deref( tmp_stream ); + + g_free( called_app ); + g_free( app ); +} + +static gboolean dcop_client_process_post_messages_internal( gpointer data ) +{ + DcopClient *client = DCOP_CLIENT( data ); + GList *it = 0; + + g_message( "dcop_client_process_post_messages_internal" ); + + if ( g_list_length( P->messages ) == 0 ) + return FALSE; + + it = g_list_first( P->messages ); + while ( it ) + { + DcopClientMessage *msg = (DcopClientMessage *)it->data; + it = g_list_next( it ); + + g_assert( msg ); + + if ( P->current_key && msg->key != P->current_key ) + continue; + + P->messages = g_list_remove( P->messages, msg ); + dcop_process_internal( client, msg->opcode, msg->key, msg->data, FALSE ); + dcop_data_deref( msg->data ); + g_free( msg ); + } + + if ( g_list_length( P->messages ) == 0 ) + return FALSE; + + return TRUE; +} + +void dcop_process_internal( DcopClient *client, int opcode, CARD32 key, dcop_data *data_received, gboolean can_post ) +{ + gchar *app = 0; + gchar *obj = 0; + gchar *fun = 0; + char *reply_type = 0; + dcop_data *reply_data = 0; + gboolean b = FALSE; + CARD32 old_current_key = 0; + dcop_data *data = 0; + dcop_data *reply = 0; + struct DCOPMsg *pMsg = 0; + + dcop_free( P->sender_id ); + dcop_demarshal_string( data_received, &P->sender_id ); + dcop_demarshal_string( data_received, &app ); + dcop_demarshal_string( data_received, &obj ); + dcop_demarshal_string( data_received, &fun ); + dcop_demarshal_data( data_received, &data ); + + if ( can_post && P->current_key && key != P->current_key ) + { + DcopClientMessage *msg = g_new( DcopClientMessage, 1 ); + g_message( "posting message with key %i", key ); + msg->opcode = opcode; + msg->key = key; + msg->data = dcop_data_ref( data_received ); + P->messages = g_list_append( P->messages, msg ); + if ( P->post_message_timer != 0 ) + g_source_remove( P->post_message_timer ); + P->post_message_timer = g_timeout_add( 0, dcop_client_process_post_messages_internal, client ); + return; + } + + old_current_key = P->current_key; + if ( opcode != DCOPSend ) /* DCOPSend doesn't change the current key*/ + P->current_key = key; + + if ( opcode == DCOPFind ) + { + /* #### b = dcop_client_find( app, obj, fun, data, &reply_type, &reply_data ); */ + } + else + b = dcop_client_receive( client, app, obj, fun, data, &reply_type, &reply_data ); + + if ( opcode == DCOPSend ) + { + g_free( app ); + g_free( obj ); + g_free( fun ); + if ( data ) + dcop_data_deref( data ); + g_free( reply_type ); + if ( reply_data ) + dcop_data_deref( reply_data ); + return; + } + + P->current_key = old_current_key; + + reply = dcop_data_ref( dcop_data_new() ); + + if ( P->transaction_id ) + { + dcop_marshal_string( reply, P->app_id ); + dcop_marshal_string( reply, P->sender_id ); + dcop_marshal_uint32( reply, (guint32)P->transaction_id ); + + IceGetHeader( P->ice_conn, P->major_opcode, DCOPReplyWait, + sizeof( struct DCOPMsg ), struct DCOPMsg, pMsg ); + + pMsg->key = key; + pMsg->length += reply->size; + + IceSendData( P->ice_conn, reply->size, reply->ptr ); + + dcop_data_deref( reply ); + g_free( app ); + g_free( obj ); + g_free( fun ); + dcop_data_deref( data ); + return; + } + + if ( !b ) + { + g_warning( "dcop failure in app %s:\n object '%s' has no function '%s'", app, obj, fun ); + + dcop_marshal_string( reply, P->app_id ); + dcop_marshal_string( reply, P->sender_id ); + + IceGetHeader( P->ice_conn, P->major_opcode, DCOPReplyFailed, + sizeof( struct DCOPMsg ), struct DCOPMsg, pMsg ); + pMsg->key = key; + pMsg->length += reply->size; + IceSendData( P->ice_conn, reply->size, reply->ptr ); + + dcop_data_deref( reply ); + g_free( app ); + g_free( obj ); + g_free( fun ); + dcop_data_deref( data ); + return; + } + + if ( !reply_data ) + reply_data = dcop_data_ref( dcop_data_new() ); + + dcop_marshal_string( reply, P->app_id ); + dcop_marshal_string( reply, P->sender_id ); + dcop_marshal_string( reply, reply_type ); + dcop_marshal_uint32( reply, reply_data->size ); + + IceGetHeader( P->ice_conn, P->major_opcode, DCOPReply, + sizeof( struct DCOPMsg ), struct DCOPMsg, pMsg ); + + pMsg->key = key; + pMsg->length += reply->size + reply_data->size; + /* use IceSendData not IceWriteData to avoid a copy. Output buffer + shouldn't need to be flushed. */ + IceSendData( P->ice_conn, reply->size, reply->ptr ); + IceSendData( P->ice_conn, reply_data->size, reply_data->ptr ); + + dcop_data_deref( reply ); + g_free( app ); + g_free( obj ); + g_free( fun ); + dcop_data_deref( data ); + dcop_data_deref( reply_data ); +} + +void dcop_client_set_default_object( DcopClient *client, const gchar *obj_id ) +{ + dcop_string_copy( P->default_object, obj_id ); +} + +const gchar *dcop_client_default_object( DcopClient *client ) +{ + return P->default_object; +} + +DcopClientTransaction *dcop_client_begin_transaction( DcopClient *client ) +{ + DcopClientTransaction *transaction = 0; + + if ( P->opcode == DCOPSend ) + return 0; + + P->transaction = TRUE; + transaction = g_new( DcopClientTransaction, 1 ); + transaction->sender_id = g_strdup( P->sender_id ); + + if ( !P->transaction_id ) + P->transaction_id++; + + transaction->id = ++(P->transaction_id); + transaction->key = P->current_key; + + P->transaction_list = g_list_append( P->transaction_list, transaction ); + + return transaction; +} + +gint32 dcop_client_transaction_id( DcopClient *client ) +{ + if ( P->transaction ) + return P->transaction_id; + else + return 0; +} + +void dcop_client_end_transaction( DcopClient *client, DcopClientTransaction *trans, gchar *reply_type, dcop_data *reply_data ) +{ + struct DCOPMsg *pMsg = 0; + dcop_data *data = 0; + + if ( !trans ) + return; + + if ( !dcop_client_is_attached( client ) ) + return; + + if ( !P->transaction_list ) + { + g_warning( "dcop_client_end_transaction: no pending transactions!" ); + return; + } + + if ( !g_list_find( P->transaction_list, trans ) ) + { + g_warning( "dcop_client_end_transaction: unknown transaction!" ); + return; + } + + P->transaction_list = g_list_remove( P->transaction_list, trans ); + + data = dcop_data_ref( dcop_data_new() ); + + dcop_data_ref( reply_data ); + + dcop_marshal_string( data, P->app_id ); + dcop_marshal_string( data, trans->sender_id ); + dcop_marshal_uint32( data, (guint32)trans->id ); + dcop_marshal_string( data, reply_type ); + dcop_marshal_data( data, reply_data ); + + IceGetHeader( P->ice_conn, P->major_opcode, DCOPReplyDelayed, sizeof( struct DCOPMsg ), struct DCOPMsg, pMsg ); + + pMsg->key = trans->key; + pMsg->length += data->size; + + IceSendData( P->ice_conn, data->size, data->ptr ); + + dcop_data_deref( data ); + dcop_data_deref( reply_data ); + + g_free( trans->sender_id ); + g_free( trans ); +} + +void dcop_client_emit_dcop_signal( DcopClient *client, + const gchar *object, const gchar *signal, dcop_data *data ) +{ + gchar *normalized_signal_name = dcop_client_normalize_function_signature( signal ); + gchar *signame = g_strdup( object ); + + signame = (gchar *)g_realloc( signame, strlen( object ) + 1 + 1 + strlen( normalized_signal_name ) ); + strcat( signame, "#" ); + strcat( signame, normalized_signal_name ); + + dcop_client_send( client, "DCOPServer", "emit", signame, data ); + + g_free( signame ); +} + +gboolean dcop_client_connect_dcop_signal( DcopClient *client, + const gchar *sender, const gchar *sender_obj, + const gchar *signal, + const gchar *receiver_obj, const gchar *slot, + gboolean _volatile ) +{ + gchar *reply_type = 0; + dcop_data *reply_data = 0; + dcop_data *data = dcop_data_ref( dcop_data_new() ); + guint8 ivolatile = _volatile ? 1 : 0; + gchar *normalized_signame = dcop_client_normalize_function_signature( signal ); + gchar *normalized_slotname = dcop_client_normalize_function_signature( slot ); + guint8 result = 0; + + dcop_marshal_string( data, sender ); + dcop_marshal_string( data, sender_obj ); + dcop_marshal_string( data, normalized_signame ); + dcop_marshal_string( data, receiver_obj ); + dcop_marshal_string( data, normalized_slotname ); + dcop_marshal_uint8( data, ivolatile ); + + if ( dcop_client_call( client, "DCOPServer", "", "connectSignal(QCString,QCString,QCString,QCString,QCString,bool)", data, &reply_type, &reply_data ) == FALSE ) + { + g_free( normalized_signame ); + g_free( normalized_slotname ); + dcop_data_deref( data ); + return FALSE; + } + + if ( reply_type == NULL || strcmp( reply_type, "bool" ) != 0 || + reply_data == NULL ) + { + g_free( normalized_signame ); + g_free( normalized_slotname ); + dcop_data_deref( data ); + if ( reply_data != NULL ) + dcop_data_deref( reply_data ); + return FALSE; + } + + dcop_data_reset( reply_data ); + dcop_demarshal_uint8( reply_data, &result ); + + g_free( normalized_signame ); + g_free( normalized_slotname ); + dcop_data_deref( data ); + dcop_data_deref( reply_data ); + + if ( result == 0 ) + return FALSE; + + return TRUE; +} + +gboolean dcop_client_disconnect_dcop_signal( DcopClient *client, + const gchar *sender, const gchar *sender_obj, + const gchar *signal, + const gchar *receiver_obj, const gchar *slot ) +{ + gchar *reply_type = 0; + dcop_data *reply_data = 0; + dcop_data *data = dcop_data_ref( dcop_data_new() ); + gchar *normalized_signame = dcop_client_normalize_function_signature( signal ); + gchar *normalized_slotname = dcop_client_normalize_function_signature( slot ); + guint8 result = 0; + + dcop_marshal_string( data, sender ); + dcop_marshal_string( data, sender_obj ); + dcop_marshal_string( data, normalized_signame ); + dcop_marshal_string( data, receiver_obj ); + dcop_marshal_string( data, normalized_slotname ); + + if ( dcop_client_call( client, "DCOPServer", "", "disconnectSignal(QCString,QCString,QCString,QCString,QCString)", data, &reply_type, &reply_data ) == FALSE ) + { + g_free( normalized_signame ); + g_free( normalized_slotname ); + dcop_data_deref( data ); + return FALSE; + } + + if ( reply_type == NULL || strcmp( reply_type, "bool" ) != 0 || + reply_data == NULL ) + { + g_free( normalized_signame ); + g_free( normalized_slotname ); + dcop_data_deref( data ); + if ( reply_data != NULL ) + dcop_data_deref( reply_data ); + return FALSE; + } + + dcop_data_reset( reply_data ); + dcop_demarshal_uint8( reply_data, &result ); + + g_free( normalized_signame ); + g_free( normalized_slotname ); + dcop_data_deref( data ); + dcop_data_deref( reply_data ); + + if ( result == 0 ) + return FALSE; + + return TRUE; +} + +void dcop_client_set_daemon_mode( DcopClient *client, gboolean daemon ) +{ + gchar *reply_type = 0; + dcop_data *reply_data = 0; + dcop_data *data = dcop_data_ref( dcop_data_new() ); + guint8 idaemon = daemon ? 1 : 0; + dcop_marshal_uint8( data, idaemon ); + + dcop_client_call( client, "DCOPServer", "", "setDaemonMode(bool)", data, &reply_type, &reply_data ); + + if ( reply_data != NULL ) + dcop_data_deref( reply_data ); + + dcop_data_deref( data ); + + dcop_free( reply_type ); +} diff --git a/dcopc/dcopc.h b/dcopc/dcopc.h new file mode 100644 index 00000000..beda5ec0 --- /dev/null +++ b/dcopc/dcopc.h @@ -0,0 +1,143 @@ +/* +Copyright (c) 2000 Simon Hausmann <hausmann@kde.org> +Copyright (c) 2000 Lars Knoll <knoll@kde.org> +Copyright (c) 1999 Preston Brown <pbrown@kde.org> +Copyright (c) 1999, 2000 Matthias Ettrich <ettrich@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef __dcopc_h__ +#define __dcopc_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <X11/ICE/ICElib.h> + +#include <dcopc/marshal.h> +#include <dcopc/util.h> + +#include <gtk/gtk.h> + +#define DCOP_TYPE_CLIENT (dcop_client_get_type()) +#define DCOP_CLIENT(obj) GTK_CHECK_CAST((obj), DCOP_TYPE_CLIENT, DcopClient) +#define DCOP_CLIENT_CLASS(klass) GTK_CHECK_CLASS_CAST((klass), DCOP_TYPE_CLIENT, DcopClientClass) +#define DCOP_IS_CLIENT(obj) GTK_CHECK_TYPE((obj), DCOP_TYPE_CLIENT) +#define DCOP_IS_CLIENT_CLASS(klass) GTK_CHECK_CLASS_TYPE((klass), DCOP_TYPE_CLIENT) + +typedef struct _DcopClient DcopClient; +typedef struct _DcopClientClass DcopClientClass; + +struct _DcopClient +{ + GtkObject obj; + void *priv; +}; + +struct _DcopClientClass +{ + GtkObjectClass parent_class; + + gboolean (*process) ( DcopClient *client, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ); +}; + +typedef struct _DcopClientTransaction DcopClientTransaction; + +extern GtkType dcop_client_get_type( void ); + +extern DcopClient *dcop_client_new( void ); + +void dcop_client_set_server_address( const gchar *addr ); + +gboolean dcop_client_attach( DcopClient *client ); + +gboolean dcop_client_detach( DcopClient *client ); + +gboolean dcop_client_is_attached( DcopClient *client ); + +const char *dcop_client_register_as( DcopClient *client, const gchar *app_id, gboolean add_pid /* = TRUE */ ); + +gboolean dcop_client_is_registered( DcopClient *client ); + +const gchar *dcop_client_app_id( DcopClient *client ); + +int dcop_client_socket( DcopClient *client ); + +gboolean dcop_client_send( DcopClient *client, + const gchar *rem_app, const gchar *rem_obj, const gchar *rem_fun, + dcop_data *data ); + +gboolean dcop_client_call( DcopClient *client, + const gchar *rem_app, const gchar *rem_obj, const gchar *rem_fun, + dcop_data *data, + gchar **reply_type, dcop_data **reply_data ); + +DcopClientTransaction *dcop_client_begin_transaction( DcopClient *client ); + +void dcop_client_end_transaction( DcopClient *client, DcopClientTransaction *transaction, gchar *reply_type, dcop_data *reply_data ); + +gint32 dcop_client_transaction_id( DcopClient *client ); + +gboolean dcop_client_is_application_registered( DcopClient *client, const gchar *rem_app ); + +GList *dcop_client_registered_applications( DcopClient *client ); + +gboolean dcop_client_receive( DcopClient *client, + const gchar *app, const gchar *obj, const gchar *fun, + dcop_data *data, + gchar **reply_type, dcop_data **reply_data ); + +gchar *dcop_client_normalize_function_signature( const gchar *fun ); + +const gchar *dcop_client_sender_id( DcopClient *client ); + +void dcop_client_set_default_object( DcopClient *client, const gchar *obj_id ); + +const gchar *dcop_client_default_object( DcopClient *client ); + +gboolean dcop_client_process ( DcopClient *client, const char *gfun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ); + +void dcop_client_process_socket_data( DcopClient *client ); + +const gchar *dcop_client_error_message(); + +void dcop_client_emit_dcop_signal( DcopClient *client, + const gchar *object, const gchar *signal, dcop_data *data ); + +gboolean dcop_client_connect_dcop_signal( DcopClient *client, + const gchar *sender, const gchar *sender_obj, + const gchar *signal, + const gchar *receiver_obj, const gchar *slot, + gboolean _volatile ); + +gboolean dcop_client_disconnect_dcop_signal( DcopClient *client, + const gchar *sender, const gchar *sender_obj, + const gchar *signal, + const gchar *receiver_obj, const gchar *slot ); + +void dcop_client_set_daemon_mode( DcopClient *client, gboolean daemon ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dcopc/dcopobject.c b/dcopc/dcopobject.c new file mode 100644 index 00000000..ff9d5309 --- /dev/null +++ b/dcopc/dcopobject.c @@ -0,0 +1,301 @@ +/* +Copyright (c) 2000 Simon Hausmann <hausmann@kde.org> +Copyright (c) 2000 Lars Knoll <knoll@kde.org> +Copyright (c) 1999 Preston Brown <pbrown@kde.org> +Copyright (c) 1999, 2000 Matthias Ettrich <ettrich@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "dcopobject.h" +#include "global.h" +#include "dcopc.h" + +#include <string.h> +#include <stdlib.h> + +#define OBJECT_CLASS(obj) DCOP_OBJECT_CLASS(GTK_OBJECT(obj)->klass) + +typedef struct _DcopObjectPrivate DcopObjectPrivate; + +struct _DcopObjectPrivate +{ + gchar *id; +}; + +/* initialization */ +static void dcop_object_class_init(DcopObjectClass *klass); + +static void dcop_object_init(DcopObject *part); + +/* GtkObject methods */ +static void dcop_object_destroy(GtkObject *object); + +static GtkObjectClass *parent_class = 0; + +GHashTable *object_dict = 0; + +GtkType dcop_object_get_type(void) +{ + static GtkType dcop_object_type = 0; + if (!dcop_object_type) + { + static const GtkTypeInfo dcop_object_info = + { + (gchar *)"DcopObject", + sizeof(DcopObject), + sizeof(DcopObjectClass), + (GtkClassInitFunc)dcop_object_class_init, + (GtkObjectInitFunc)dcop_object_init, + 0, + 0, + 0 + }; + dcop_object_type = gtk_type_unique(GTK_TYPE_OBJECT, &dcop_object_info); + } + return dcop_object_type; +} + +gboolean dcop_object_real_process( DcopObject *obj, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ); + +gboolean dcop_object_real_process_dynamic( DcopObject *obj, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ); + +GList *dcop_object_real_functions( DcopObject *obj ); + +GList *dcop_object_real_interfaces( DcopObject *obj ); + +void dcop_object_class_init(DcopObjectClass *klass) +{ + GtkObjectClass *object_class; + object_class = (GtkObjectClass *)klass; + + parent_class = (GtkObjectClass *)gtk_type_class(gtk_object_get_type()); + + object_class->destroy = dcop_object_destroy; + + klass->process = dcop_object_real_process; + klass->process_dynamic = dcop_object_real_process_dynamic; + klass->functions = dcop_object_real_functions; + klass->interfaces = dcop_object_real_interfaces; + + g_message( "dcop_object_class_init(DcopObjectClass *klass)\n"); +} + +void dcop_object_init(DcopObject *obj) +{ + DcopObjectPrivate *d; + /* eheh :-) (Simon)*/ +/* d = new DcopObjectPrivate();*/ + d = g_new( DcopObjectPrivate, 1 ); + d->id = 0; + obj->data = d; + + /* register a unique id*/ + { + gchar n[1024]; + g_snprintf( n, sizeof( n ), "%p", obj ); + dcop_object_set_id( obj, n ); /* also registers the object at the object_dict*/ + } + + g_message( "dcop_object_init(DcopObject *obj)\n"); +} + +DcopObject *dcop_object_new (void) +{ + DcopObject *obj = DCOP_OBJECT( gtk_type_new(dcop_object_get_type()) ); + + return obj; +} + +void dcop_object_destroy( GtkObject *obj ) +{ + DcopObject *o = DCOP_OBJECT(obj); + DcopObjectPrivate *d = (DcopObjectPrivate *)o->data; + + g_message( "dcop_object_destructor %s\n", DCOP_ID(o) ); + + g_assert( object_dict ); + g_assert( d->id ); + + g_hash_table_remove( object_dict, d->id ); + + if ( g_hash_table_size( object_dict ) == 0 ) + { + g_hash_table_destroy( object_dict ); + object_dict = 0; + } + + g_free(d->id); + /* Lars, you hack to much C++ :-))) (Simon)*/ +/* delete d;*/ + g_free( d ); + + parent_class->destroy(obj); +} + +void dcop_object_set_id( DcopObject *obj, const gchar *id ) +{ + DcopObjectPrivate *d = (DcopObjectPrivate *) obj->data; + + if ( !object_dict ) + object_dict = g_hash_table_new( g_str_hash, g_str_equal ); + + if ( d->id ) + g_hash_table_remove( object_dict, d->id ); + + dcop_string_copy( d->id, id ); + + g_assert( d->id ); + + g_hash_table_insert( object_dict, d->id, obj ); +} + +const gchar *dcop_object_get_id( DcopObject *obj) +{ + return ((DcopObjectPrivate *) obj->data)->id; +} + +gboolean dcop_object_process( DcopObject *obj, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ) +{ + return OBJECT_CLASS(obj)->process( obj, fun, data, reply_type, reply_data ); +} + +gboolean dcop_object_process_dynamic( DcopObject *obj, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ) +{ + return OBJECT_CLASS(obj)->process_dynamic( obj, fun, data, reply_type, reply_data ); +} + +gboolean dcop_object_real_process( DcopObject *obj, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ) +{ + GList *strlist = 0; + DcopObjectClass *klass = OBJECT_CLASS(obj); + + if ( strcmp( fun, "interfaces()" ) == 0 ) + { + *reply_type = g_strdup( "QCStringList" ); + *reply_data = dcop_data_ref( dcop_data_new() ); + strlist = klass->interfaces( obj ); + + dcop_marshal_stringlist( *reply_data, strlist ); + + dcop_list_free( strlist ); + return TRUE; + } + else if ( strcmp( fun, "functions()" ) == 0 ) + { + *reply_type = strdup( "QCStringList" ); + *reply_data = dcop_data_ref( dcop_data_new() ); + strlist = klass->functions( obj ); + + dcop_marshal_stringlist( *reply_data, strlist ); + + dcop_list_free( strlist ); + return TRUE; + } + return klass->process_dynamic( obj, fun, data, reply_type, reply_data ); +} + +gboolean dcop_object_real_process_dynamic( DcopObject *client, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ) +{ + /* empty default implementation*/ + return FALSE; +} + +GList *dcop_object_functions( DcopObject *obj ) +{ + return OBJECT_CLASS(obj)->functions( obj ); +} + +GList *dcop_object_interfaces( DcopObject *obj ) +{ + return OBJECT_CLASS(obj)->interfaces( obj ); +} + +GList *dcop_object_real_functions( DcopObject *client ) +{ + GList *res = 0; + res = g_list_append( res, g_strdup( "QCStringList interfaces()" ) ); + res = g_list_append( res, g_strdup( "QCStringList functions()" ) ); + return res; +} + +GList *dcop_object_real_interfaces( DcopObject *client ) +{ + GList *res = 0; + res = g_list_append( res, g_strdup( "DCOPObject" ) ); + return res; +} + +DcopObject *dcop_object_lookup( const gchar *name ) +{ + DcopObject *res = 0; + + if ( !object_dict || !name ) + return NULL; + + return (DcopObject *)g_hash_table_lookup( object_dict, name ); +} + +gchar *g_partial_id = 0; +size_t g_id_len = 0; + +static void dcop_object_match_internal( gpointer key, gpointer val, gpointer user_data ) +{ + GList **lst = (GList **)user_data; + gchar *nam = (gchar *)key; + DcopObjectPrivate *d = ((DcopObject *)val)->data; + + if ( strncmp( d->id, g_partial_id, g_id_len ) == 0 ) + *lst = g_list_append( *lst, (DcopObject *)val ); +} + +GList *dcop_object_match( const gchar *partial_id ) +{ + GList *res = 0; + GList *it = 0; + size_t id_len = strlen( partial_id ); + + if ( !object_dict ) + return res; + + g_hash_table_foreach( object_dict, dcop_object_match_internal, &res ); + + /* + if ( !object_list) + return res; + + it = g_list_first( object_list ); + + while ( it ) + { + DcopObjectPrivate *d = (DcopObjectPrivate *)((DcopObject *)it->data)->data; + + if ( strncmp( d->id, partial_id, id_len ) == 0 ) + res = g_list_append( res, (DcopObject *)it->data ); + + it = g_list_next( it ); + } + */ + return res; +} diff --git a/dcopc/dcopobject.h b/dcopc/dcopobject.h new file mode 100644 index 00000000..fff64bdc --- /dev/null +++ b/dcopc/dcopobject.h @@ -0,0 +1,93 @@ +/* +Copyright (c) 2000 Simon Hausmann <hausmann@kde.org> +Copyright (c) 2000 Lars Knoll <knoll@kde.org> +Copyright (c) 1999 Preston Brown <pbrown@kde.org> +Copyright (c) 1999, 2000 Matthias Ettrich <ettrich@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef __dcopc_dcopobject_h__ +#define __dcopc_dcopobject_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <X11/ICE/ICElib.h> + +#include <dcopc/marshal.h> +#include <dcopc/util.h> + +#include <gtk/gtk.h> + +#define DCOP_TYPE_OBJECT (dcop_object_get_type()) +#define DCOP_OBJECT(obj) GTK_CHECK_CAST((obj), DCOP_TYPE_OBJECT, DcopObject) +#define DCOP_OBJECT_CLASS(klass) GTK_CHECK_CLASS_CAST((klass), DCOP_TYPE_OBJECT, DcopObjectClass) +#define DCOP_IS_OBJECT(obj) GTK_CHECK_TYPE((obj), DCOP_TYPE_OBJECT) +#define DCOP_IS_OBJECT_CLASS(klass) GTK_CHECK_CLASS_TYPE((klass), DCOP_TYPE_OBJECT) +#define DCOP_ID(obj) (dcop_object_get_id(obj)) + +typedef struct _DcopObject DcopObject; +typedef struct _DcopObjectClass DcopObjectClass; + +struct _DcopObject +{ + GtkObject obj; + void *data; +}; + +struct _DcopObjectClass +{ + GtkObjectClass parent_class; + + gboolean (*process) ( DcopObject *obj, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ); + gboolean (*process_dynamic) ( DcopObject *obj, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ); + + GList *(*functions) ( DcopObject *obj ); + GList *(*interfaces) ( DcopObject *obj ); +}; + +GtkType dcop_object_get_type(void); + +DcopObject *dcop_object_new( void ); + +void dcop_object_set_id( DcopObject *obj, const gchar *id ); +const gchar *dcop_object_get_id( DcopObject *obj); + +gboolean dcop_object_process( DcopObject *obj, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ); + +gboolean dcop_object_process_dynamic( DcopObject *obj, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ); + +GList *dcop_object_functions( DcopObject *obj ); + +GList *dcop_object_interfaces( DcopObject *obj ); + +DcopObject *dcop_object_lookup( const gchar *name ); + +GList *dcop_object_match( const gchar *partial_id ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dcopc/glib.m4 b/dcopc/glib.m4 new file mode 100644 index 00000000..b8094bbf --- /dev/null +++ b/dcopc/glib.m4 @@ -0,0 +1,196 @@ +# Configure paths for GLIB +# Owen Taylor 97-11-3 + +dnl AM_PATH_GLIB([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) +dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if "gmodule" or +dnl gthread is specified in MODULES, pass to glib-config +dnl +AC_DEFUN(AM_PATH_GLIB, +[dnl +dnl Get the cflags and libraries from the glib-config script +dnl +AC_ARG_WITH(glib-prefix,[ --with-glib-prefix=PFX Prefix where GLIB is installed (optional)], + glib_config_prefix="$withval", glib_config_prefix="") +AC_ARG_WITH(glib-exec-prefix,[ --with-glib-exec-prefix=PFX Exec prefix where GLIB is installed (optional)], + glib_config_exec_prefix="$withval", glib_config_exec_prefix="") +AC_ARG_ENABLE(glibtest, [ --disable-glibtest Do not try to compile and run a test GLIB program], + , enable_glibtest=yes) + + if test x$glib_config_exec_prefix != x ; then + glib_config_args="$glib_config_args --exec-prefix=$glib_config_exec_prefix" + if test x${GLIB_CONFIG+set} != xset ; then + GLIB_CONFIG=$glib_config_exec_prefix/bin/glib-config + fi + fi + if test x$glib_config_prefix != x ; then + glib_config_args="$glib_config_args --prefix=$glib_config_prefix" + if test x${GLIB_CONFIG+set} != xset ; then + GLIB_CONFIG=$glib_config_prefix/bin/glib-config + fi + fi + + for module in . $4 + do + case "$module" in + gmodule) + glib_config_args="$glib_config_args gmodule" + ;; + gthread) + glib_config_args="$glib_config_args gthread" + ;; + esac + done + + AC_PATH_PROG(GLIB_CONFIG, glib-config, no) + min_glib_version=ifelse([$1], ,0.99.7,$1) + AC_MSG_CHECKING(for GLIB - version >= $min_glib_version) + no_glib="" + if test "$GLIB_CONFIG" = "no" ; then + no_glib=yes + else + GLIB_CFLAGS=`$GLIB_CONFIG $glib_config_args --cflags` + GLIB_LIBS=`$GLIB_CONFIG $glib_config_args --libs` + glib_config_major_version=`$GLIB_CONFIG $glib_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + glib_config_minor_version=`$GLIB_CONFIG $glib_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + glib_config_micro_version=`$GLIB_CONFIG $glib_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_glibtest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GLIB_CFLAGS" + LIBS="$GLIB_LIBS $LIBS" +dnl +dnl Now check if the installed GLIB is sufficiently new. (Also sanity +dnl checks the results of glib-config to some extent +dnl + rm -f conf.glibtest + AC_TRY_RUN([ +#include <glib.h> +#include <stdio.h> +#include <stdlib.h> + +int +main () +{ + int major, minor, micro; + char *tmp_version; + + system ("touch conf.glibtest"); + + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = g_strdup("$min_glib_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_glib_version"); + exit(1); + } + + if ((glib_major_version != $glib_config_major_version) || + (glib_minor_version != $glib_config_minor_version) || + (glib_micro_version != $glib_config_micro_version)) + { + printf("\n*** 'glib-config --version' returned %d.%d.%d, but GLIB (%d.%d.%d)\n", + $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version, + glib_major_version, glib_minor_version, glib_micro_version); + printf ("*** was found! If glib-config was correct, then it is best\n"); + printf ("*** to remove the old version of GLIB. You may also be able to fix the error\n"); + printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); + printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); + printf("*** required on your system.\n"); + printf("*** If glib-config was wrong, set the environment variable GLIB_CONFIG\n"); + printf("*** to point to the correct copy of glib-config, and remove the file config.cache\n"); + printf("*** before re-running configure\n"); + } + else if ((glib_major_version != GLIB_MAJOR_VERSION) || + (glib_minor_version != GLIB_MINOR_VERSION) || + (glib_micro_version != GLIB_MICRO_VERSION)) + { + printf("*** GLIB header files (version %d.%d.%d) do not match\n", + GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); + printf("*** library (version %d.%d.%d)\n", + glib_major_version, glib_minor_version, glib_micro_version); + } + else + { + if ((glib_major_version > major) || + ((glib_major_version == major) && (glib_minor_version > minor)) || + ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of GLIB (%d.%d.%d) was found.\n", + glib_major_version, glib_minor_version, glib_micro_version); + printf("*** You need a version of GLIB newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** GLIB is always available from ftp://ftp.gtk.org.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the glib-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of GLIB, but you can also set the GLIB_CONFIG environment to point to the\n"); + printf("*** correct copy of glib-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + } + return 1; +} +],, no_glib=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + if test "x$no_glib" = x ; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$GLIB_CONFIG" = "no" ; then + echo "*** The glib-config script installed by GLIB could not be found" + echo "*** If GLIB was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the GLIB_CONFIG environment variable to the" + echo "*** full path to glib-config." + else + if test -f conf.glibtest ; then + : + else + echo "*** Could not run GLIB test program, checking why..." + CFLAGS="$CFLAGS $GLIB_CFLAGS" + LIBS="$LIBS $GLIB_LIBS" + AC_TRY_LINK([ +#include <glib.h> +#include <stdio.h> +], [ return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding GLIB or finding the wrong" + echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" + echo "***" + echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that" + echo "*** came with the system with the command" + echo "***" + echo "*** rpm --erase --nodeps gtk gtk-devel" ], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means GLIB was incorrectly installed" + echo "*** or that you have moved GLIB since it was installed. In the latter case, you" + echo "*** may want to edit the glib-config script: $GLIB_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + GLIB_CFLAGS="" + GLIB_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GLIB_CFLAGS) + AC_SUBST(GLIB_LIBS) + rm -f conf.glibtest +]) diff --git a/dcopc/glibtest.c b/dcopc/glibtest.c new file mode 100644 index 00000000..b2473e66 --- /dev/null +++ b/dcopc/glibtest.c @@ -0,0 +1,133 @@ +/* +Copyright (c) 2000 Simon Hausmann <hausmann@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include <dcopc/dcopc.h> +#include <dcopc/dcopobject.h> +#include <stdio.h> +#include <glib.h> + +#define C( call ) \ + if ( !call ) \ + { \ + fprintf( stderr, "dcop error: %s\n", dcop_client_error_message() ); \ + return 1; \ + } + +gboolean dcop_socket_notify( GIOChannel *chan, GIOCondition condition, gpointer data ) +{ + DcopClient *client = (DcopClient *)data; + fprintf( stderr, "dcop_socket_notify\n" ); + dcop_client_process_socket_data( client ); +} + +gboolean (*old_process_func) ( DcopObject *obj, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ); + +gboolean my_obj_process( DcopObject *obj, const gchar *fun, dcop_data *data, + gchar **reply_type, dcop_data **reply_data ) +{ + if ( strcmp( fun, "doExit()" ) == 0 ) + { + gtk_main_quit(); + return TRUE; + } + if ( strcmp( fun, "mySlot()" ) == 0 ) + { + g_message( "mySlot called!" ); + return TRUE; + } + + return old_process_func( obj, fun, data, reply_type, reply_data ); +} + +GList *(*old_functions_func)( DcopObject *obj ) = 0; + +GList *my_obj_functions( DcopObject *obj ) +{ + GList *res = old_functions_func( obj ); + res = g_list_append( res, g_strdup( "doExit()" ) ); + res = g_list_append( res, g_strdup( "mySlot()" ) ); + return res; +} + +GList *(*old_interfaces_func)( DcopObject *obj ) = 0; + +GList *my_obj_interfaces( DcopObject *obj ) +{ + GList *res = old_interfaces_func( obj ); + res = g_list_append( res, g_strdup( "MyObj" ) ); + return res; +} + +int main( int argc, char **argv ) +{ + DcopClient *c; + dcop_data *d; + dcop_data *reply; + char *reply_type; + GIOChannel *chan; + DcopObject *obj; + + gtk_init( &argc, &argv ); + + c = dcop_client_new(); + + C( dcop_client_register_as( c, "dcoptest", False ) ); + + chan = g_io_channel_unix_new( dcop_client_socket( c ) ); + g_io_channel_ref( chan ); + + g_io_add_watch( chan, G_IO_IN, dcop_socket_notify, c ); + + obj = dcop_object_new(); + dcop_object_set_id( obj, "myServer" ); + + old_process_func = DCOP_OBJECT_CLASS( GTK_OBJECT( obj )->klass )->process; + old_functions_func = DCOP_OBJECT_CLASS( GTK_OBJECT( obj )->klass )->functions; + old_interfaces_func = DCOP_OBJECT_CLASS( GTK_OBJECT( obj )->klass )->interfaces; + + DCOP_OBJECT_CLASS( GTK_OBJECT( obj )->klass )->process = my_obj_process; + DCOP_OBJECT_CLASS( GTK_OBJECT( obj )->klass )->functions = my_obj_functions; + DCOP_OBJECT_CLASS( GTK_OBJECT( obj )->klass )->interfaces = my_obj_interfaces; + + if ( dcop_client_connect_dcop_signal( c, dcop_client_app_id( c ), "myServer", + "mySignal()", + "myServer", "mySlot()", FALSE ) == FALSE ) + g_message( "error connecting dcop signal :-(" ); + + d = dcop_data_ref( dcop_data_new() ); + + dcop_client_emit_dcop_signal( c, "myServer", "mySignal()", d ); + + dcop_data_deref( d ); + + dcop_client_set_daemon_mode( c, TRUE ); + + gtk_main(); + + g_io_channel_unref( chan ); + + C( dcop_client_detach( c ) ); + + gtk_object_unref( GTK_OBJECT( c ) ); + + return 0; +} diff --git a/dcopc/global.h b/dcopc/global.h new file mode 100644 index 00000000..387a4945 --- /dev/null +++ b/dcopc/global.h @@ -0,0 +1,75 @@ +/* +Copyright (c) 1999 Preston Brown <pbrown@kde.org> +Copyright (c) 1999, 2000 Matthias Ettrich <ettrich@kde.org> +Copyright (c) 2000 Simon Hausmann <hausmann@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef __global_h__ +#define __global_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "util.h" + +/* sometimes __STDC__ is defined, but to 0. The hateful X headers + ask for '#if __STDC__', so they become confused. */ +#if defined(__STDC__) +#if !__STDC__ +#undef __STDC__ +#define __STDC__ 1 +#endif +#endif + +#include <X11/Xlib.h> +#include <X11/Xmd.h> +#include <X11/ICE/ICElib.h> + +#include <X11/ICE/ICEutil.h> +#include <X11/ICE/ICEmsg.h> +#include <X11/ICE/ICEproto.h> + + +#define DCOPVendorString "KDE" +#define DCOPReleaseString "2.0" +#define DCOPVersionMajor 2 +#define DCOPVersionMinor 0 + +#define DCOPSend 1 +#define DCOPCall 2 +#define DCOPReply 3 +#define DCOPReplyFailed 4 +#define DCOPReplyWait 5 +#define DCOPReplyDelayed 6 +#define DCOPFind 7 + +struct DCOPMsg { + CARD8 majorOpcode; + CARD8 minorOpcode; + CARD8 data[2]; + CARD32 length B32; + CARD32 key; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dcopc/gtk.m4 b/dcopc/gtk.m4 new file mode 100644 index 00000000..af4c0855 --- /dev/null +++ b/dcopc/gtk.m4 @@ -0,0 +1,197 @@ +# Configure paths for GTK+ +# Owen Taylor 97-11-3 + +dnl AM_PATH_GTK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) +dnl Test for GTK, and define GTK_CFLAGS and GTK_LIBS +dnl +AC_DEFUN(AM_PATH_GTK, +[dnl +dnl Get the cflags and libraries from the gtk-config script +dnl +AC_ARG_WITH(gtk-prefix,[ --with-gtk-prefix=PFX Prefix where GTK is installed (optional)], + gtk_config_prefix="$withval", gtk_config_prefix="") +AC_ARG_WITH(gtk-exec-prefix,[ --with-gtk-exec-prefix=PFX Exec prefix where GTK is installed (optional)], + gtk_config_exec_prefix="$withval", gtk_config_exec_prefix="") +AC_ARG_ENABLE(gtktest, [ --disable-gtktest Do not try to compile and run a test GTK program], + , enable_gtktest=yes) + + for module in . $4 + do + case "$module" in + gthread) + gtk_config_args="$gtk_config_args gthread" + ;; + esac + done + + if test x$gtk_config_exec_prefix != x ; then + gtk_config_args="$gtk_config_args --exec-prefix=$gtk_config_exec_prefix" + if test x${GTK_CONFIG+set} != xset ; then + GTK_CONFIG=$gtk_config_exec_prefix/bin/gtk-config + fi + fi + if test x$gtk_config_prefix != x ; then + gtk_config_args="$gtk_config_args --prefix=$gtk_config_prefix" + if test x${GTK_CONFIG+set} != xset ; then + GTK_CONFIG=$gtk_config_prefix/bin/gtk-config + fi + fi + + AC_PATH_PROG(GTK_CONFIG, gtk-config, no) + min_gtk_version=ifelse([$1], ,0.99.7,$1) + AC_MSG_CHECKING(for GTK - version >= $min_gtk_version) + no_gtk="" + if test "$GTK_CONFIG" = "no" ; then + no_gtk=yes + else + GTK_CFLAGS=`$GTK_CONFIG $gtk_config_args --cflags` + GTK_LIBS=`$GTK_CONFIG $gtk_config_args --libs` + gtk_config_major_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + gtk_config_minor_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + gtk_config_micro_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_gtktest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$GTK_LIBS $LIBS" + AC_LANG_SAVE + AC_LANG_C +dnl +dnl Now check if the installed GTK is sufficiently new. (Also sanity +dnl checks the results of gtk-config to some extent +dnl + rm -f conf.gtktest + AC_TRY_RUN([ +#include <gtk/gtk.h> +#include <stdio.h> +#include <stdlib.h> + +int +main () +{ + int major, minor, micro; + char *tmp_version; + + system ("touch conf.gtktest"); + + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = g_strdup("$min_gtk_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_gtk_version"); + exit(1); + } + + if ((gtk_major_version != $gtk_config_major_version) || + (gtk_minor_version != $gtk_config_minor_version) || + (gtk_micro_version != $gtk_config_micro_version)) + { + printf("\n*** 'gtk-config --version' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", + $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, + gtk_major_version, gtk_minor_version, gtk_micro_version); + printf ("*** was found! If gtk-config was correct, then it is best\n"); + printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); + printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); + printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); + printf("*** required on your system.\n"); + printf("*** If gtk-config was wrong, set the environment variable GTK_CONFIG\n"); + printf("*** to point to the correct copy of gtk-config, and remove the file config.cache\n"); + printf("*** before re-running configure\n"); + } +#if defined (GTK_MAJOR_VERSION) && defined (GTK_MINOR_VERSION) && defined (GTK_MICRO_VERSION) + else if ((gtk_major_version != GTK_MAJOR_VERSION) || + (gtk_minor_version != GTK_MINOR_VERSION) || + (gtk_micro_version != GTK_MICRO_VERSION)) + { + printf("*** GTK+ header files (version %d.%d.%d) do not match\n", + GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); + printf("*** library (version %d.%d.%d)\n", + gtk_major_version, gtk_minor_version, gtk_micro_version); + } +#endif /* defined (GTK_MAJOR_VERSION) ... */ + else + { + if ((gtk_major_version > major) || + ((gtk_major_version == major) && (gtk_minor_version > minor)) || + ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", + gtk_major_version, gtk_minor_version, gtk_micro_version); + printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the gtk-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of GTK+, but you can also set the GTK_CONFIG environment to point to the\n"); + printf("*** correct copy of gtk-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + } + return 1; +} +],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + AC_LANG_RESTORE + fi + fi + if test "x$no_gtk" = x ; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$GTK_CONFIG" = "no" ; then + echo "*** The gtk-config script installed by GTK could not be found" + echo "*** If GTK was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the GTK_CONFIG environment variable to the" + echo "*** full path to gtk-config." + else + if test -f conf.gtktest ; then + : + else + echo "*** Could not run GTK test program, checking why..." + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + AC_TRY_LINK([ +#include <gtk/gtk.h> +#include <stdio.h> +], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding GTK or finding the wrong" + echo "*** version of GTK. If it is not finding GTK, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" + echo "***" + echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that" + echo "*** came with the system with the command" + echo "***" + echo "*** rpm --erase --nodeps gtk gtk-devel" ], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means GTK was incorrectly installed" + echo "*** or that you have moved GTK since it was installed. In the latter case, you" + echo "*** may want to edit the gtk-config script: $GTK_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + GTK_CFLAGS="" + GTK_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GTK_CFLAGS) + AC_SUBST(GTK_LIBS) + rm -f conf.gtktest +]) diff --git a/dcopc/marshal.c b/dcopc/marshal.c new file mode 100644 index 00000000..e0de9296 --- /dev/null +++ b/dcopc/marshal.c @@ -0,0 +1,420 @@ +/* +Copyright (c) 2000 Simon Hausmann <hausmann@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "marshal.h" + +#include <glib.h> + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +dcop_data *dcop_data_new() +{ + dcop_data *res = g_new( dcop_data, 1 ); + + res->ptr = 0; + res->size = 0; + res->cur = 0; + res->ref = 0; + + return res; +} + +void dcop_data_destroy( dcop_data *data ) +{ + g_assert( data->ref == 0 ); + + g_free( data->ptr ); + + g_free( data ); +} + +dcop_data *dcop_data_copy( dcop_data *data ) +{ + dcop_data *res = dcop_data_new(); + res->ptr = (char *)g_malloc( data->size ); + res->size = data->size; + dcop_data_reset( res ); + memcpy( res->ptr, data->ptr, data->size ); + return res; +} + +static gboolean dcop_data_check_size( dcop_data *data, unsigned int size ) +{ + if ( data->size - ( data->cur - data->ptr ) < size ) + return FALSE; + return TRUE; +} + +gboolean dcop_marshal_raw( dcop_data *data, const void *ptr, unsigned int size ) +{ + unsigned int relptr = data->cur - data->ptr; + + data->ptr = (char *)g_realloc( data->ptr, data->size + size ); + + if ( data->ptr == 0 ) + return FALSE; + + data->cur = data->ptr + relptr; + + memcpy( data->cur, ptr, size ); + + data->cur += size; + data->size += size; + + return TRUE; +} + +gboolean dcop_marshal_uint32( dcop_data *data, unsigned int val ) +{ + unsigned char buf[4]; + + g_assert( sizeof( unsigned int ) == 4 ); + + buf[0] = val; + buf[1] = val >> 8; + buf[2] = val >> 16; + buf[3] = val >> 24; + + return dcop_marshal_raw( data, buf, 4 ); +} + +gboolean dcop_demarshal_uint32( dcop_data *data, unsigned int *val ) +{ + g_assert( sizeof( unsigned int ) == 4 ); + + if ( !dcop_data_check_size( data, 4 ) ) + return FALSE; + + *val = (data->cur[3] << 24) | + (data->cur[2] << 16) | + (data->cur[1] << 8) | + data->cur[0]; + data->cur += 4; + + return TRUE; +} + +gboolean dcop_marshal_string( dcop_data *data, const gchar *str ) +{ + size_t l = 0; + + if ( str ) + l = strlen( str ) + 1; + + if( !dcop_marshal_uint32( data, l ) ) + return FALSE; + + if ( str ) + return dcop_marshal_raw( data, str, l ); + else + return TRUE; +} + +gboolean dcop_demarshal_string( dcop_data *data, gchar **str ) +{ + unsigned int l = 0; + gchar *res = 0; + + g_assert( str ); + + if ( !dcop_demarshal_uint32( data, &l ) ) + return FALSE; + + if ( !dcop_data_check_size( data, l ) ) + return FALSE; + + res = (char *)g_malloc( l ); + memcpy( res, data->cur, l ); + data->cur += l; + + *str = res; + + return TRUE; +} + + +gboolean dcop_marshal_string16( dcop_data *data, const gchar *str ) +{ + size_t l = 0; + size_t c = 0; + char *tmp = 0; + const char *src = str; + char *dst = 0; + + if ( str ) + l = strlen( str ) * 2; + else + { + /* null marker*/ + guint32 s = 0xffffffff; + return dcop_marshal_uint32( data, s ); + } + + if( !dcop_marshal_uint32( data, l ) ) + return FALSE; + + if ( str ) + { + dst = tmp = (char *)g_malloc( l ); + c = strlen( str ); + + while ( c-- ) + { + *dst++ = 0; + *dst++ = *src++; + } + + dcop_marshal_raw( data, tmp, l ); + + g_free( tmp ); + } + return TRUE; +} + +gboolean dcop_demarshal_string16( dcop_data *data, gchar **str ) +{ + unsigned int l = 0; + unsigned int size = 0; + char *res = 0; + char *p = 0; + + assert( str ); + + if ( !dcop_demarshal_uint32( data, &l ) ) + return FALSE; + + /* null marker*/ + if ( l == 0xffffffff ) + { + *str = 0; + return TRUE; + } + + if ( !dcop_data_check_size( data, l ) ) + return FALSE; + + size = ( l / 2 ); + + p = res = (char *)g_malloc( size + 1 ); + + while( size-- ) + { + data->cur++; + *p++ = *data->cur++; + } + + *p = '\0'; + + *str = res; + + return TRUE; +} + +gboolean dcop_marshal_bytearray( dcop_data *data, const gchar *str, size_t size ) +{ + if( !dcop_marshal_uint32( data, size ) ) + return FALSE; + + if ( str ) + return dcop_marshal_raw( data, str, size ); + else + return TRUE; +} + +gboolean dcop_demarshal_bytearray( dcop_data *data, gchar **str, size_t *size ) +{ + unsigned int l = 0; + gchar *res = 0; + + g_assert( str ); + + if ( !dcop_demarshal_uint32( data, &l ) ) + return FALSE; + + if ( !dcop_data_check_size( data, l ) ) + return FALSE; + + res = (char *)g_malloc( l ); + memcpy( res, data->cur, l ); + data->cur += l; + + *str = res; + *size = l; + + return TRUE; +} + + + +gboolean dcop_marshal_data( dcop_data *data, dcop_data *other ) +{ + if ( !dcop_marshal_uint32( data, other->size ) ) + return FALSE; + + return dcop_marshal_raw( data, other->ptr, other->size ); +} + +gboolean dcop_demarshal_data( dcop_data *data, dcop_data **other ) +{ + dcop_data *res = dcop_data_new(); + char *tmp = 0; + unsigned int l = 0; + + if ( !dcop_demarshal_uint32( data, &l ) ) + return FALSE; + + if ( !dcop_data_check_size( data, l ) ) + return FALSE; + + tmp = (char *)malloc( l ); + + memcpy( tmp, data->cur, l ); + data->cur += l; + + dcop_data_assign( res, tmp, l ); + dcop_data_ref( res ); + + *other = res; + return True; +} + +gboolean dcop_marshal_stringlist( dcop_data *data, GList *list ) +{ + GList *it = g_list_first( list ); + + if ( !dcop_marshal_uint32( data, g_list_length( list ) ) ) + return FALSE; + + while ( it ) + { + if ( !dcop_marshal_string( data, (gchar *)it->data ) ) + return FALSE; + it = g_list_next( it ); + } + return TRUE; +} + +gboolean dcop_demarshal_stringlist( dcop_data *data, GList**list ) +{ + unsigned int count = 0; + GList *res = 0; + unsigned int i = 0; + gchar *str = 0; + + *list = 0; + + if ( !dcop_demarshal_uint32( data, &count ) ) + return FALSE; + + for ( i = 0; i < count; ++i ) + { + if ( !dcop_demarshal_string( data, &str ) ) + { + dcop_list_free( res ); + return FALSE; + } + res = g_list_append( res, str ); + } + *list = res; + return TRUE; +} + +gboolean dcop_marshal_stringlist16( dcop_data *data, GList *list ) +{ + GList *it = g_list_first( list ); + + if ( !dcop_marshal_uint32( data, g_list_length( list ) ) ) + return False; + + while ( it ) + { + if ( !dcop_marshal_string16( data, (gchar *)it->data ) ) + return FALSE; + it = g_list_next( it ); + } + return TRUE; +} + +gboolean dcop_demarshal_stringlist16( dcop_data *data, GList **list ) +{ + unsigned int count = 0; + GList *res = 0; + unsigned int i = 0; + char *str = 0; + + *list = 0; + + if ( !dcop_demarshal_uint32( data, &count ) ) + return FALSE; + + for ( i = 0; i < count; ++i ) + { + if ( !dcop_demarshal_string16( data, &str ) ) + { + dcop_list_free( res ); + return FALSE; + } + res = g_list_append( res, str ); + } + *list = res; + return TRUE; +} + +void dcop_data_assign( dcop_data *data, char *d, unsigned int size ) +{ + data->ptr = data->cur = d; + data->size = size; +} + +gboolean dcop_marshal_boolean( dcop_data *data, gboolean val ) +{ + guint8 i = (guint8)val; + return dcop_marshal_uint8( data, i ); +} + +gboolean dcop_demarshal_boolean( dcop_data *data, gboolean *val ) +{ + guint8 i; + if ( !dcop_demarshal_uint8( data, &i ) ) + return FALSE; + *val = (gboolean)i; + return TRUE; +} + +gboolean dcop_marshal_uint8( dcop_data *data, guint8 val ) +{ + return dcop_marshal_raw( data, &val, 1 ); +} + +gboolean dcop_demarshal_uint8( dcop_data *data, guint8 *val ) +{ + if ( !dcop_data_check_size( data, 1 ) ) + return FALSE; + + *val = *data->cur++; + return TRUE; +} + +dcop_data *dcop_data_ref( dcop_data *data ) { data->ref++; return data; } +void dcop_data_deref( dcop_data *data ) { if ( !--data->ref ) dcop_data_destroy( data ); } +void dcop_data_reset( dcop_data *data ) { data->cur = data->ptr; } diff --git a/dcopc/marshal.h b/dcopc/marshal.h new file mode 100644 index 00000000..a5065627 --- /dev/null +++ b/dcopc/marshal.h @@ -0,0 +1,93 @@ +/* +Copyright (c) 2000 Simon Hausmann <hausmann@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef __dcopc_marshal_h__ +#define __dcopc_marshal_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <X11/ICE/ICElib.h> + +#include <dcopc/util.h> +#include <stdlib.h> + +typedef struct _dcop_data dcop_data; + +struct _dcop_data +{ + char *ptr; + unsigned int size; + char *cur; + unsigned int ref; +}; + +/* remember to call ref() after this one! */ +dcop_data *dcop_data_new(); + +/* do not call directly! use deref! */ +void dcop_data_destroy( dcop_data *data ); + +void dcop_data_assign( dcop_data *data, char *d, unsigned int size ); + +dcop_data *dcop_data_ref( dcop_data *data ); +void dcop_data_deref( dcop_data *data ); + +dcop_data *dcop_data_copy( dcop_data *data ); + +void dcop_data_reset( dcop_data *data ); + +gboolean dcop_marshal_raw( dcop_data *data, const void *ptr, unsigned int size ); + +gboolean dcop_marshal_uint32( dcop_data *data, unsigned int val ); +gboolean dcop_demarshal_uint32( dcop_data *data, unsigned int *val ); + +gboolean dcop_marshal_string( dcop_data *data, const gchar *str ); +gboolean dcop_demarshal_string( dcop_data *data, gchar **str ); + +/* works only for ascii! */ +gboolean dcop_marshal_string16( dcop_data *data, const gchar *str ); +gboolean dcop_demarshal_string16( dcop_data *data, gchar **str ); + +gboolean dcop_marshal_bytearray( dcop_data *data, const gchar *str, size_t size ); +gboolean dcop_demarshal_bytearray( dcop_data *data, gchar **str, size_t *size ); + +gboolean dcop_marshal_data( dcop_data *data, dcop_data *other ); +gboolean dcop_demarshal_data( dcop_data *data, dcop_data **other ); + +gboolean dcop_marshal_stringlist( dcop_data *data, GList *list ); +gboolean dcop_demarshal_stringlist( dcop_data *data, GList **list ); + +gboolean dcop_marshal_stringlist16( dcop_data *data, GList *list ); +gboolean dcop_demarshal_stringlist16( dcop_data *data, GList **list ); + +gboolean dcop_marshal_boolean( dcop_data *data, gboolean val ); +gboolean dcop_demarshal_boolean( dcop_data *data, gboolean *val ); + +gboolean dcop_marshal_uint8( dcop_data *data, guint8 val ); +gboolean dcop_demarshal_uint8( dcop_data *data, guint8 *val ); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/dcopc/util.c b/dcopc/util.c new file mode 100644 index 00000000..f69549c5 --- /dev/null +++ b/dcopc/util.c @@ -0,0 +1,137 @@ +/* +Copyright (c) 2000 Simon Hausmann <hausmann@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "util.h" + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <stdio.h> + +void dcop_stringlist_destroy( dcop_stringlist *list ) +{ + dcop_list_item *it = list->root; + while ( it ) + { + free( (char *)it->data ); + it = it->next; + } + dcop_list_destroy( list ); +} + +void dcop_stringlist_append( dcop_stringlist *list, const char *str ) +{ + dcop_list_append( list, strdup( str ) ); +} + +dcop_list *dcop_list_new() +{ + dcop_list *res = (dcop_list *)malloc( sizeof( dcop_list ) ); + res->root = NULL; + return res; +} + +void dcop_list_destroy( dcop_list *list ) +{ + dcop_list_item *it = list->root; + while ( it ) + { + dcop_list_item *tmp = it; + it = it->next; + free( tmp ); + } + free( list ); +} + +dcop_list_item *dcop_list_item_new() +{ + dcop_list_item *res = malloc( sizeof( dcop_list ) ); + res->prev = res->next = NULL; + return res; +} + +dcop_list_item *dcop_list_append( dcop_list *list, void *data ) +{ + dcop_list_item *it = list->root; + dcop_list_item *res = dcop_list_item_new(); + + if ( it == NULL ) + list->root = res; + else + { + while ( it->next != NULL ) + it = it->next; + + it->next = res; + res->prev = it; + } + + res->data = data; + return res; +} + +gboolean dcop_list_remove( dcop_list *list, void *data ) +{ + dcop_list_item *it = list->root; + + if ( it == NULL ) + return False; + + if ( it->data == data ) + { + list->root = it->next; + if ( list->root ) + list->root->prev = NULL; + + free( it ); + + return True; + } + + it = it->next; + + while ( it != NULL ) + { + if ( it->data == data ) + { + it->prev->next = it->next; + if ( it->next ) + it->next->prev = it->prev; + free( it ); + return True; + } + it = it->next; + } + + return False; +} + +unsigned int dcop_list_count( dcop_list *list ) +{ + unsigned int res = 0; + dcop_list_item *it = list->root; + while ( it ) + { + res++; + it = it->next; + } + return res; +} diff --git a/dcopc/util.h b/dcopc/util.h new file mode 100644 index 00000000..38d89f0f --- /dev/null +++ b/dcopc/util.h @@ -0,0 +1,73 @@ +/* +Copyright (c) 2000 Simon Hausmann <hausmann@kde.org> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef __dcopc_util_h__ +#define __dcopc_util_h__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <X11/ICE/ICElib.h> +#include <gtk/gtk.h> + +#define dcop_free( o ) \ + { \ + g_free( o ); \ + o = 0; \ + } + +#define dcop_string_assign( s, val ) \ + { \ + dcop_free( s ); \ + if ( val != NULL ) \ + s = val; \ + } + +#define dcop_string_copy( s, val ) \ + { \ + dcop_free( s ); \ + if( val != NULL ) \ + s = g_strdup( val ); \ + } + +#define dcop_string_assing( s, val ) \ + { \ + dcop_free( s ); \ + if ( val != NULL ) \ + s = val; \ + } + +#define dcop_list_free( lst ) \ + { \ + GList *it = g_list_first( lst ); \ + while ( it ) \ + { \ + g_free( it->data ); \ + it = g_list_next( it ); \ + } \ + g_list_free( lst ); \ + } + +#ifdef __cplusplus +} +#endif + +#endif |