Copy libsylph socket.c as fallback for single instance libunique

This socket code makes single instance a mandatory feature assuming
if libunique is not available we can use sockets.
A bit of refactoring of MidoriApp is involved to make the command
logic independant of the nature of the instance handling.
This commit is contained in:
Christian Dywan 2009-06-15 23:58:19 +02:00
parent 84f5e94c08
commit 3bcd8b6615
6 changed files with 2080 additions and 76 deletions

View file

@ -69,3 +69,4 @@ Code from other projects:
GTK+/ GtkEntry, Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald GTK+/ GtkEntry, Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
Modified by the GTK+ Team and others 1997-2000 Modified by the GTK+ Team and others 1997-2000
libSoup/ CookieJarText, Copyright (C) 2008 Xan Lopez <xan@gnome.org>, Dan Winship <danw@gnome.org> libSoup/ CookieJarText, Copyright (C) 2008 Xan Lopez <xan@gnome.org>, Dan Winship <danw@gnome.org>
libSylph, Copyright 1999-2008 Hiroyuki Yamamoto, Copyright 2006-2009 Enrico Tröger <enrico.troeger@uvena.de>

View file

@ -1,5 +1,5 @@
/* /*
Copyright (C) 2008 Christian Dywan <christian@twotoasts.de> Copyright (C) 2008-2009 Christian Dywan <christian@twotoasts.de>
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -21,7 +21,13 @@
#include <glib/gi18n.h> #include <glib/gi18n.h>
#if HAVE_UNIQUE #if HAVE_UNIQUE
typedef gpointer MidoriAppInstance;
#define MidoriAppInstanceNull NULL
#include <unique/unique.h> #include <unique/unique.h>
#else
typedef gint MidoriAppInstance;
#define MidoriAppInstanceNull -1
#include "socket.h"
#endif #endif
typedef struct _NotifyNotification NotifyNotification; typedef struct _NotifyNotification NotifyNotification;
@ -54,7 +60,7 @@ struct _MidoriApp
KatzeArray* extensions; KatzeArray* extensions;
KatzeArray* browsers; KatzeArray* browsers;
gpointer instance; MidoriAppInstance instance;
/* libnotify handling */ /* libnotify handling */
gchar* program_notify_send; gchar* program_notify_send;
@ -383,6 +389,74 @@ midori_app_class_init (MidoriAppClass* class)
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
} }
static gboolean
midori_app_command_received (MidoriApp* app,
const gchar* command,
gchar** uris,
GdkScreen* screen)
{
if (g_str_equal (command, "activate"))
{
gtk_window_set_screen (GTK_WINDOW (app->browser), screen);
gtk_window_present (GTK_WINDOW (app->browser));
return TRUE;
}
else if (g_str_equal (command, "new"))
{
MidoriBrowser* browser = midori_app_create_browser (app);
midori_app_add_browser (app, browser);
/* FIXME: Should open the homepage according to settings */
midori_browser_add_uri (browser, "");
midori_browser_activate_action (browser, "Location");
gtk_window_set_screen (GTK_WINDOW (app->browser), screen);
gtk_widget_show (GTK_WIDGET (browser));
return TRUE;
}
else if (g_str_equal (command, "open"))
{
gtk_window_set_screen (GTK_WINDOW (app->browser), screen);
gtk_window_present (GTK_WINDOW (app->browser));
if (!uris)
return FALSE;
else
{
MidoriBrowser* browser;
MidoriNewPage open_external_pages_in;
gboolean first;
g_object_get (app->settings, "open-external-pages-in",
&open_external_pages_in, NULL);
if (open_external_pages_in == MIDORI_NEW_PAGE_WINDOW)
{
browser = midori_app_create_browser (app);
midori_app_add_browser (app, browser);
gtk_window_set_screen (GTK_WINDOW (app->browser), screen);
gtk_widget_show (GTK_WIDGET (browser));
}
else
browser = app->browser;
first = (open_external_pages_in == MIDORI_NEW_PAGE_CURRENT);
while (*uris)
{
gchar* fixed_uri = sokoke_magic_uri (*uris, NULL);
if (first)
{
midori_browser_set_current_uri (browser, fixed_uri);
first = FALSE;
}
else
midori_browser_set_current_page (browser,
midori_browser_add_uri (browser, fixed_uri));
g_free (fixed_uri);
uris++;
}
return TRUE;
}
}
return FALSE;
}
#if HAVE_UNIQUE #if HAVE_UNIQUE
static UniqueResponse static UniqueResponse
midori_browser_message_received_cb (UniqueApp* instance, midori_browser_message_received_cb (UniqueApp* instance,
@ -391,98 +465,94 @@ midori_browser_message_received_cb (UniqueApp* instance,
guint timestamp, guint timestamp,
MidoriApp* app) MidoriApp* app)
{ {
UniqueResponse response; gboolean success;
MidoriBrowser* browser; GdkScreen* screen = unique_message_data_get_screen (message);
gchar** uris;
MidoriNewPage open_external_pages_in;
gboolean first;
switch (command) switch (command)
{ {
case UNIQUE_ACTIVATE: case UNIQUE_ACTIVATE:
gtk_window_set_screen (GTK_WINDOW (app->browser), success = midori_app_command_received (app, "activate", NULL, screen);
unique_message_data_get_screen (message));
gtk_window_present (GTK_WINDOW (app->browser));
response = UNIQUE_RESPONSE_OK;
break; break;
case UNIQUE_NEW: case UNIQUE_NEW:
browser = midori_app_create_browser (app); success = midori_app_command_received (app, "new", NULL, screen);
midori_app_add_browser (app, browser);
/* FIXME: Should open the homepage according to settings */
midori_browser_add_uri (browser, "");
midori_browser_activate_action (browser, "Location");
gtk_window_set_screen (GTK_WINDOW (app->browser),
unique_message_data_get_screen (message));
gtk_widget_show (GTK_WIDGET (browser));
response = UNIQUE_RESPONSE_OK;
break; break;
case UNIQUE_OPEN: case UNIQUE_OPEN:
gtk_window_set_screen (GTK_WINDOW (app->browser), {
unique_message_data_get_screen (message)); gchar** uris = unique_message_data_get_uris (message);
gtk_window_present (GTK_WINDOW (app->browser)); success = midori_app_command_received (app, "open", uris, screen);
uris = unique_message_data_get_uris (message); /* g_strfreev (uris); */
if (!uris)
response = UNIQUE_RESPONSE_FAIL;
else
{
g_object_get (app->settings, "open-external-pages-in",
&open_external_pages_in, NULL);
if (open_external_pages_in == MIDORI_NEW_PAGE_WINDOW)
{
browser = midori_app_create_browser (app);
midori_app_add_browser (app, browser);
gtk_window_set_screen (GTK_WINDOW (app->browser),
unique_message_data_get_screen (message));
gtk_widget_show (GTK_WIDGET (browser));
}
else
browser = app->browser;
first = (open_external_pages_in == MIDORI_NEW_PAGE_CURRENT);
while (*uris)
{
gchar* fixed_uri = sokoke_magic_uri (*uris, NULL);
if (first)
{
midori_browser_set_current_uri (browser, fixed_uri);
first = FALSE;
}
else
midori_browser_set_current_page (browser,
midori_browser_add_uri (browser, fixed_uri));
g_free (fixed_uri);
uris++;
}
/* g_strfreev (uris); */
response = UNIQUE_RESPONSE_OK;
}
break; break;
}
default: default:
response = UNIQUE_RESPONSE_FAIL; success = FALSE;
break; break;
} }
return response; return success ? UNIQUE_RESPONSE_OK : UNIQUE_RESPONSE_FAIL;
}
#else
static gboolean
midori_app_io_channel_watch_cb (GIOChannel* channel,
GIOCondition condition,
MidoriApp* app)
{
GdkScreen* screen = gtk_widget_get_screen (GTK_WIDGET (app->browser));
gint fd, sock;
gchar buf[4096];
struct sockaddr_in caddr;
guint caddr_len = sizeof(caddr);
fd = app->instance;
sock = accept (fd, (struct sockaddr *)&caddr, &caddr_len);
while (fd_gets (sock, buf, sizeof (buf)) != -1)
{
if (strncmp (buf, "activate", 8) == 0)
{
midori_app_command_received (app, "open", NULL, screen);
}
else if (strncmp (buf, "new", 3) == 0)
{
midori_app_command_received (app, "new", NULL, screen);
}
else if (strncmp (buf, "open", 4) == 0)
{
while (fd_gets (sock, buf, sizeof (buf)) != -1 && *buf != '.')
{
gchar** uris = g_strsplit (g_strstrip (buf), "\n", 2);
midori_app_command_received (app, "open", uris, screen);
g_strfreev (uris);
}
}
}
gtk_window_present (GTK_WINDOW (app->browser));
fd_close (sock);
return TRUE;
} }
#endif #endif
static gpointer static MidoriAppInstance
midori_app_create_instance (MidoriApp* app, midori_app_create_instance (MidoriApp* app,
const gchar* name) const gchar* name)
{ {
#if HAVE_UNIQUE MidoriAppInstance instance;
gpointer instance;
GdkDisplay* display; GdkDisplay* display;
gchar* display_name; gchar* display_name;
gchar* instance_name; gchar* instance_name;
guint i, n; guint i, n;
#if !HAVE_UNIQUE
gboolean exists;
GIOChannel* channel;
#endif #endif
if (!name) if (!name)
name = "midori"; name = "midori";
#if HAVE_UNIQUE
if (!(display = gdk_display_get_default ())) if (!(display = gdk_display_get_default ()))
return NULL; return MidoriAppInstanceNull;
display_name = g_strdup (gdk_display_get_name (display)); display_name = g_strdup (gdk_display_get_name (display));
n = strlen (display_name); n = strlen (display_name);
@ -490,15 +560,24 @@ midori_app_create_instance (MidoriApp* app,
if (display_name[i] == ':' || display_name[i] == '.') if (display_name[i] == ':' || display_name[i] == '.')
display_name[i] = '_'; display_name[i] = '_';
instance_name = g_strdup_printf ("de.twotoasts.%s_%s", name, display_name); instance_name = g_strdup_printf ("de.twotoasts.%s_%s", name, display_name);
#if HAVE_UNIQUE
instance = unique_app_new (instance_name, NULL); instance = unique_app_new (instance_name, NULL);
g_free (instance_name);
g_free (display_name);
g_signal_connect (instance, "message-received", g_signal_connect (instance, "message-received",
G_CALLBACK (midori_browser_message_received_cb), app); G_CALLBACK (midori_browser_message_received_cb), app);
return instance;
#else #else
return NULL; instance = socket_init (instance_name, sokoke_set_config_dir (NULL), &exists);
g_object_set_data (G_OBJECT (app), "sock-exists",
exists ? (gpointer)0xdeadbeef : NULL);
channel = g_io_channel_unix_new (instance);
g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR,
(GIOFunc)midori_app_io_channel_watch_cb, app);
#endif #endif
g_free (instance_name);
g_free (display_name);
return instance;
} }
static void static void
@ -514,7 +593,7 @@ midori_app_init (MidoriApp* app)
app->extensions = NULL; app->extensions = NULL;
app->browsers = katze_array_new (MIDORI_TYPE_BROWSER); app->browsers = katze_array_new (MIDORI_TYPE_BROWSER);
app->instance = NULL; app->instance = MidoriAppInstanceNull;
midori_app_init_libnotify (app); midori_app_init_libnotify (app);
} }
@ -535,7 +614,11 @@ midori_app_finalize (GObject* object)
katze_object_assign (app->extensions, NULL); katze_object_assign (app->extensions, NULL);
katze_object_assign (app->browsers, NULL); katze_object_assign (app->browsers, NULL);
#if HAVE_UNIQUE
katze_object_assign (app->instance, NULL); katze_object_assign (app->instance, NULL);
#else
sock_cleanup ();
#endif
if (app->libnotify_module) if (app->libnotify_module)
{ {
@ -663,9 +746,6 @@ midori_app_new (void)
* Use the "name" property if you want to run more * Use the "name" property if you want to run more
* than one instance. * than one instance.
* *
* If Midori was built without single instance support
* this function will always return %FALSE.
*
* Return value: %TRUE if an instance is already running * Return value: %TRUE if an instance is already running
**/ **/
gboolean gboolean
@ -673,11 +753,13 @@ midori_app_instance_is_running (MidoriApp* app)
{ {
g_return_val_if_fail (MIDORI_IS_APP (app), FALSE); g_return_val_if_fail (MIDORI_IS_APP (app), FALSE);
if (!app->instance) if (app->instance == MidoriAppInstanceNull)
app->instance = midori_app_create_instance (app, app->name); app->instance = midori_app_create_instance (app, app->name);
#if HAVE_UNIQUE #if HAVE_UNIQUE
if (app->instance) if (app->instance)
return unique_app_is_running (app->instance); return unique_app_is_running (app->instance);
#else
return g_object_get_data (G_OBJECT (app), "sock-exists") != NULL;
#endif #endif
return FALSE; return FALSE;
} }
@ -710,6 +792,12 @@ midori_app_instance_send_activate (MidoriApp* app)
if (response == UNIQUE_RESPONSE_OK) if (response == UNIQUE_RESPONSE_OK)
return TRUE; return TRUE;
} }
#else
if (app->instance > -1)
{
send_open_command (app->instance, "activate", NULL);
return TRUE;
}
#endif #endif
return FALSE; return FALSE;
} }
@ -740,6 +828,12 @@ midori_app_instance_send_new_browser (MidoriApp* app)
if (response == UNIQUE_RESPONSE_OK) if (response == UNIQUE_RESPONSE_OK)
return TRUE; return TRUE;
} }
#else
if (app->instance > -1)
{
send_open_command (app->instance, "new", NULL);
return TRUE;
}
#endif #endif
return FALSE; return FALSE;
} }
@ -779,6 +873,12 @@ midori_app_instance_send_uris (MidoriApp* app,
if (response == UNIQUE_RESPONSE_OK) if (response == UNIQUE_RESPONSE_OK)
return TRUE; return TRUE;
} }
#else
if (app->instance > -1)
{
send_open_command (app->instance, "open", uris);
return TRUE;
}
#endif #endif
return FALSE; return FALSE;
} }

1766
midori/socket.c Normal file

File diff suppressed because it is too large Load diff

128
midori/socket.h Normal file
View file

@ -0,0 +1,128 @@
/*
Copyright 1999-2008 Hiroyuki Yamamoto
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
See the file COPYING for the full license text.
*/
#ifndef __SYLPH_SOCKET_H__
#define __SYLPH_SOCKET_H__
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <glib.h>
#if HAVE_NETDB_H
# include <netdb.h>
#endif
typedef struct _SockInfo SockInfo;
#if USE_SSL
# include <openssl/ssl.h>
#endif
typedef enum
{
CONN_READY,
CONN_LOOKUPSUCCESS,
CONN_ESTABLISHED,
CONN_LOOKUPFAILED,
CONN_FAILED
} ConnectionState;
typedef gint (*SockConnectFunc) (SockInfo *sock,
gpointer data);
typedef gboolean (*SockFunc) (SockInfo *sock,
GIOCondition condition,
gpointer data);
struct _SockInfo
{
gint sock;
#if USE_SSL
SSL *ssl;
#else
gpointer ssl;
#endif
GIOChannel *sock_ch;
gchar *hostname;
gushort port;
ConnectionState state;
gboolean nonblock;
gpointer data;
SockFunc callback;
GIOCondition condition;
};
void send_open_command (gint sock, const gchar *command,
gchar **args);
gint socket_init (const gchar *instance_name,
const gchar *config_dir, gboolean *exists);
gint sock_cleanup (void);
gint sock_set_io_timeout (guint sec);
gint sock_set_nonblocking_mode (SockInfo *sock, gboolean nonblock);
gboolean sock_is_nonblocking_mode (SockInfo *sock);
gboolean sock_has_read_data (SockInfo *sock);
guint sock_add_watch (SockInfo *sock, GIOCondition condition,
SockFunc func, gpointer data);
struct hostent *my_gethostbyname (const gchar *hostname);
SockInfo *sock_connect (const gchar *hostname, gushort port);
#ifdef G_OS_UNIX
gint sock_connect_async (const gchar *hostname, gushort port,
SockConnectFunc func, gpointer data);
gint sock_connect_async_cancel (gint id);
#endif
/* Basic I/O functions */
gint sock_printf (SockInfo *sock, const gchar *format, ...)
G_GNUC_PRINTF(2, 3);
gint sock_read (SockInfo *sock, gchar *buf, gint len);
gint sock_write (SockInfo *sock, const gchar *buf, gint len);
gint sock_write_all (SockInfo *sock, const gchar *buf, gint len);
gint sock_gets (SockInfo *sock, gchar *buf, gint len);
gint sock_getline (SockInfo *sock, gchar **line);
gint sock_puts (SockInfo *sock, const gchar *buf);
gint sock_peek (SockInfo *sock, gchar *buf, gint len);
gint sock_close (SockInfo *sock);
/* Functions to directly work on FD. They are needed for pipes */
gint fd_connect_inet (gushort port);
gint fd_open_inet (gushort port);
gint fd_connect_unix (const gchar *path);
gint fd_open_unix (const gchar *path);
gint fd_accept (gint sock);
gint fd_read (gint sock, gchar *buf, gint len);
gint fd_write (gint sock, const gchar *buf, gint len);
gint fd_write_all (gint sock, const gchar *buf, gint len);
gint fd_gets (gint sock, gchar *buf, gint len);
gint fd_getline (gint sock, gchar **line);
gint fd_close (gint sock);
/* Functions for SSL */
#if USE_SSL
gint ssl_read (SSL *ssl, gchar *buf, gint len);
gint ssl_write (SSL *ssl, const gchar *buf, gint len);
gint ssl_write_all (SSL *ssl, const gchar *buf, gint len);
gint ssl_gets (SSL *ssl, gchar *buf, gint len);
gint ssl_getline (SSL *ssl, gchar **line);
gint ssl_peek (SSL *ssl, gchar *buf, gint len);
void ssl_done_socket (SockInfo *sockinfo);
#endif
#endif /* __SYLPH_SOCKET_H__ */

View file

@ -10,7 +10,7 @@ obj.target = 'midori'
obj.includes = '. ..' obj.includes = '. ..'
obj.find_sources_in_dirs ('.', excludes=['main.c']) obj.find_sources_in_dirs ('.', excludes=['main.c'])
obj.add_marshal_file ('marshal.list', 'midori_cclosure_marshal') obj.add_marshal_file ('marshal.list', 'midori_cclosure_marshal')
obj.uselib = 'UNIQUE LIBSOUP LIBIDN GIO GTK SQLITE WEBKIT LIBXML HILDON' obj.uselib = 'UNIQUE LIBSOUP LIBIDN GIO GTK SQLITE WEBKIT LIBXML WS2_32 OPENSSL HILDON'
obj.uselib_local = 'katze' obj.uselib_local = 'katze'
obj.install_path = None obj.install_path = None

11
wscript
View file

@ -199,6 +199,16 @@ def configure (conf):
conf.env['docs'] = option_enabled ('docs') conf.env['docs'] = option_enabled ('docs')
conf.check (header_name='unistd.h') conf.check (header_name='unistd.h')
if not conf.env['HAVE_UNIQUE']:
if Options.platform == 'win32':
conf.check (lib='ws2_32')
check_pkg ('openssl', mandatory=False)
conf.define ('USE_SSL', [0,1][conf.env['HAVE_OPENSSL'] == 1])
conf.define ('HAVE_NETDB_H', [0,1][conf.check (header_name='netdb.h')])
conf.check (header_name='sys/wait.h')
conf.check (header_name='sys/select.h')
conf.check (function_name='inet_aton')
conf.check (function_name='inet_addr')
conf.define ('HAVE_OSX', int(sys.platform == 'darwin')) conf.define ('HAVE_OSX', int(sys.platform == 'darwin'))
if conf.find_program ('rsvg-convert', var='RSVG_CONVERT'): if conf.find_program ('rsvg-convert', var='RSVG_CONVERT'):
@ -249,7 +259,6 @@ def configure (conf):
print ''' print '''
Localization: %(nls)s (intltool) Localization: %(nls)s (intltool)
Icon optimizations: %(icons)s (rsvg-convert) Icon optimizations: %(icons)s (rsvg-convert)
Single instance: %(unique)s (unique)
Persistent history: %(sqlite)s (sqlite3) Persistent history: %(sqlite)s (sqlite3)
IDN support: %(libidn)s (libidn) IDN support: %(libidn)s (libidn)