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:
parent
84f5e94c08
commit
3bcd8b6615
6 changed files with 2080 additions and 76 deletions
1
AUTHORS
1
AUTHORS
|
@ -69,3 +69,4 @@ Code from other projects:
|
|||
GTK+/ GtkEntry, Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
Modified by the GTK+ Team and others 1997-2000
|
||||
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>
|
||||
|
|
|
@ -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
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
|
@ -21,7 +21,13 @@
|
|||
#include <glib/gi18n.h>
|
||||
|
||||
#if HAVE_UNIQUE
|
||||
typedef gpointer MidoriAppInstance;
|
||||
#define MidoriAppInstanceNull NULL
|
||||
#include <unique/unique.h>
|
||||
#else
|
||||
typedef gint MidoriAppInstance;
|
||||
#define MidoriAppInstanceNull -1
|
||||
#include "socket.h"
|
||||
#endif
|
||||
|
||||
typedef struct _NotifyNotification NotifyNotification;
|
||||
|
@ -54,7 +60,7 @@ struct _MidoriApp
|
|||
KatzeArray* extensions;
|
||||
KatzeArray* browsers;
|
||||
|
||||
gpointer instance;
|
||||
MidoriAppInstance instance;
|
||||
|
||||
/* libnotify handling */
|
||||
gchar* program_notify_send;
|
||||
|
@ -383,6 +389,74 @@ midori_app_class_init (MidoriAppClass* class)
|
|||
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
|
||||
static UniqueResponse
|
||||
midori_browser_message_received_cb (UniqueApp* instance,
|
||||
|
@ -391,98 +465,94 @@ midori_browser_message_received_cb (UniqueApp* instance,
|
|||
guint timestamp,
|
||||
MidoriApp* app)
|
||||
{
|
||||
UniqueResponse response;
|
||||
MidoriBrowser* browser;
|
||||
gchar** uris;
|
||||
MidoriNewPage open_external_pages_in;
|
||||
gboolean first;
|
||||
gboolean success;
|
||||
GdkScreen* screen = unique_message_data_get_screen (message);
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case UNIQUE_ACTIVATE:
|
||||
gtk_window_set_screen (GTK_WINDOW (app->browser),
|
||||
unique_message_data_get_screen (message));
|
||||
gtk_window_present (GTK_WINDOW (app->browser));
|
||||
response = UNIQUE_RESPONSE_OK;
|
||||
success = midori_app_command_received (app, "activate", NULL, screen);
|
||||
break;
|
||||
case UNIQUE_NEW:
|
||||
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),
|
||||
unique_message_data_get_screen (message));
|
||||
gtk_widget_show (GTK_WIDGET (browser));
|
||||
response = UNIQUE_RESPONSE_OK;
|
||||
success = midori_app_command_received (app, "new", NULL, screen);
|
||||
break;
|
||||
case UNIQUE_OPEN:
|
||||
gtk_window_set_screen (GTK_WINDOW (app->browser),
|
||||
unique_message_data_get_screen (message));
|
||||
gtk_window_present (GTK_WINDOW (app->browser));
|
||||
uris = unique_message_data_get_uris (message);
|
||||
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;
|
||||
}
|
||||
{
|
||||
gchar** uris = unique_message_data_get_uris (message);
|
||||
success = midori_app_command_received (app, "open", uris, screen);
|
||||
/* g_strfreev (uris); */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
response = UNIQUE_RESPONSE_FAIL;
|
||||
success = FALSE;
|
||||
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
|
||||
|
||||
static gpointer
|
||||
static MidoriAppInstance
|
||||
midori_app_create_instance (MidoriApp* app,
|
||||
const gchar* name)
|
||||
{
|
||||
#if HAVE_UNIQUE
|
||||
gpointer instance;
|
||||
MidoriAppInstance instance;
|
||||
GdkDisplay* display;
|
||||
gchar* display_name;
|
||||
gchar* instance_name;
|
||||
guint i, n;
|
||||
#if !HAVE_UNIQUE
|
||||
gboolean exists;
|
||||
GIOChannel* channel;
|
||||
#endif
|
||||
|
||||
if (!name)
|
||||
name = "midori";
|
||||
|
||||
#if HAVE_UNIQUE
|
||||
if (!(display = gdk_display_get_default ()))
|
||||
return NULL;
|
||||
return MidoriAppInstanceNull;
|
||||
|
||||
display_name = g_strdup (gdk_display_get_name (display));
|
||||
n = strlen (display_name);
|
||||
|
@ -490,15 +560,24 @@ midori_app_create_instance (MidoriApp* app,
|
|||
if (display_name[i] == ':' || display_name[i] == '.')
|
||||
display_name[i] = '_';
|
||||
instance_name = g_strdup_printf ("de.twotoasts.%s_%s", name, display_name);
|
||||
|
||||
#if HAVE_UNIQUE
|
||||
instance = unique_app_new (instance_name, NULL);
|
||||
g_free (instance_name);
|
||||
g_free (display_name);
|
||||
g_signal_connect (instance, "message-received",
|
||||
G_CALLBACK (midori_browser_message_received_cb), app);
|
||||
return instance;
|
||||
#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
|
||||
|
||||
g_free (instance_name);
|
||||
g_free (display_name);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -514,7 +593,7 @@ midori_app_init (MidoriApp* app)
|
|||
app->extensions = NULL;
|
||||
app->browsers = katze_array_new (MIDORI_TYPE_BROWSER);
|
||||
|
||||
app->instance = NULL;
|
||||
app->instance = MidoriAppInstanceNull;
|
||||
|
||||
midori_app_init_libnotify (app);
|
||||
}
|
||||
|
@ -535,7 +614,11 @@ midori_app_finalize (GObject* object)
|
|||
katze_object_assign (app->extensions, NULL);
|
||||
katze_object_assign (app->browsers, NULL);
|
||||
|
||||
#if HAVE_UNIQUE
|
||||
katze_object_assign (app->instance, NULL);
|
||||
#else
|
||||
sock_cleanup ();
|
||||
#endif
|
||||
|
||||
if (app->libnotify_module)
|
||||
{
|
||||
|
@ -663,9 +746,6 @@ midori_app_new (void)
|
|||
* Use the "name" property if you want to run more
|
||||
* 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
|
||||
**/
|
||||
gboolean
|
||||
|
@ -673,11 +753,13 @@ midori_app_instance_is_running (MidoriApp* app)
|
|||
{
|
||||
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);
|
||||
#if HAVE_UNIQUE
|
||||
if (app->instance)
|
||||
return unique_app_is_running (app->instance);
|
||||
#else
|
||||
return g_object_get_data (G_OBJECT (app), "sock-exists") != NULL;
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -710,6 +792,12 @@ midori_app_instance_send_activate (MidoriApp* app)
|
|||
if (response == UNIQUE_RESPONSE_OK)
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
if (app->instance > -1)
|
||||
{
|
||||
send_open_command (app->instance, "activate", NULL);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -740,6 +828,12 @@ midori_app_instance_send_new_browser (MidoriApp* app)
|
|||
if (response == UNIQUE_RESPONSE_OK)
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
if (app->instance > -1)
|
||||
{
|
||||
send_open_command (app->instance, "new", NULL);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -779,6 +873,12 @@ midori_app_instance_send_uris (MidoriApp* app,
|
|||
if (response == UNIQUE_RESPONSE_OK)
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
if (app->instance > -1)
|
||||
{
|
||||
send_open_command (app->instance, "open", uris);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
|
1766
midori/socket.c
Normal file
1766
midori/socket.c
Normal file
File diff suppressed because it is too large
Load diff
128
midori/socket.h
Normal file
128
midori/socket.h
Normal 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__ */
|
|
@ -10,7 +10,7 @@ obj.target = 'midori'
|
|||
obj.includes = '. ..'
|
||||
obj.find_sources_in_dirs ('.', excludes=['main.c'])
|
||||
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.install_path = None
|
||||
|
||||
|
|
11
wscript
11
wscript
|
@ -199,6 +199,16 @@ def configure (conf):
|
|||
conf.env['docs'] = option_enabled ('docs')
|
||||
|
||||
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'))
|
||||
|
||||
if conf.find_program ('rsvg-convert', var='RSVG_CONVERT'):
|
||||
|
@ -249,7 +259,6 @@ def configure (conf):
|
|||
print '''
|
||||
Localization: %(nls)s (intltool)
|
||||
Icon optimizations: %(icons)s (rsvg-convert)
|
||||
Single instance: %(unique)s (unique)
|
||||
Persistent history: %(sqlite)s (sqlite3)
|
||||
|
||||
IDN support: %(libidn)s (libidn)
|
||||
|
|
Loading…
Reference in a new issue